]> git.saurik.com Git - apple/security.git/blob - SecuritySNACCRuntime/compiler/core/snacc.c
Security-54.tar.gz
[apple/security.git] / SecuritySNACCRuntime / compiler / core / snacc.c
1 /*
2 * compiler/core/snacc.c---Compiles ASN.1 src files into an internal type tree.
3 * Imported type/value references are resolved if possible.
4 * Produces C or C++ encoder/decoder/print/free code and .h for
5 * data struct and prototypes.
6 * Generated C can be either ANSI or old style via macros.
7 * Produces values for OBJECT IDENTIFIERs, INTEGERs and BOOLEANs
8 *
9 * Mike Sample 1991/92
10 *
11 * NOTES
12 *
13 * See the README file for compiling tips. This should compile
14 * with ANSI or non-ANSI c compilers.
15 *
16 * each ASN.1 source file must contain a complete ASN.1 module:
17 * <ModName> DEFINITIONS ::= BEGIN ... END
18 *
19 * 91/09/04---modified to handle new data struct (ASN.1 generated)
20 * for module info. MS.
21 *
22 *
23 * Copyright (C) 1991, 1992 Michael Sample
24 * and the University of British Columbia
25 *
26 * This program is free software; you can redistribute it and/or modify
27 * it under the terms of the GNU General Public License as published by
28 * the Free Software Foundation; either version 2 of the License, or
29 * (at your option) any later version.
30 *
31 * This program and the associated libraries are distributed in the hope
32 * that they will be useful, but WITHOUT ANY WARRANTY; without even the
33 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
34 * PURPOSE. See the GNU General Public License and GNU Library General
35 * Public License for more details.
36 *
37 * INSERT_VDA_COMMENTS
38 *
39 * $Header: /cvs/Darwin/Security/SecuritySNACCRuntime/compiler/core/snacc.c,v 1.1 2001/06/20 21:27:59 dmitch Exp $
40 * $Log: snacc.c,v $
41 * Revision 1.1 2001/06/20 21:27:59 dmitch
42 * Adding missing snacc compiler files.
43 *
44 * Revision 1.1.1.1 1999/03/16 18:06:52 aram
45 * Originals from SMIME Free Library.
46 *
47 * Revision 1.10 1997/05/07 15:18:35 wan
48 * Added (limited) size constraints, bitstring and enumeration names to tables
49 *
50 * Revision 1.9 1997/02/16 15:12:21 rj
51 * made ``return *this after calling abort()'' a compile time option.
52 *
53 * Revision 1.8 1997/01/02 08:50:55 rj
54 * - use the TIME_WITH_SYS_TIME flag (checked and generated by configure)
55 * - do not silently ignore the -tcl option if not compiled for tcl code generation
56 *
57 * Revision 1.7 1995/09/07 19:13:39 rj
58 * new options -mA and -mC for snacc(1) that switch the names used between those defined in the ASN.1 files and those used in the generated C++ code.
59 * uses newly introduced enum MetaNameStyle.
60 *
61 * Revision 1.6 1995/08/17 15:00:13 rj
62 * the PDU flag belongs to the metacode, not only to the tcl interface. (type and variable named adjusted)
63 *
64 * Revision 1.5 1995/07/25 19:34:06 rj
65 * bug report address changed to protect an innocent's mailbox :-)
66 *
67 * snacc -h now prints the usage to stdout.
68 *
69 * allow for more than one PDU per .asn1 file set:
70 * - struct TclPDU becomes a linked list.
71 * - it gets a flag `used' to detect invalid command line arguments.
72 *
73 * code for idl backend added.
74 *
75 * by default, snacc now derives output file names from the .asn1 input file name instead of the module name.
76 *
77 * changed `_' to `-' in file names.
78 *
79 * Revision 1.4 1994/12/11 20:21:06 rj
80 * #include string(s).h
81 *
82 * Revision 1.3 1994/10/08 03:23:27 rj
83 * since i was still irritated by cpp standing for c++ and not the C preprocessor, i renamed them to cxx (which is one known suffix for C++ source files). since the standard #define is __cplusplus, cplusplus would have been the more obvious choice, but it is a little too long.
84 *
85 * code for meta structures added (provides information about the generated code itself).
86 *
87 * code for Tcl interface added (makes use of the above mentioned meta code).
88 *
89 * Revision 1.2 1994/09/01 00:44:31 rj
90 * snacc_config.h and other superfluous .h files removed. version string moved into a separate version.h file.
91 *
92 * Revision 1.1 1994/08/28 09:49:37 rj
93 * first check-in. for a list of changes to the snacc-1.1 distribution please refer to the ChangeLog.
94 *
95 */
96
97 #ifdef VDADER_RULES
98 /* Enables VDA's DER SUPPORT. If gVDADER_RULES == 1 then support is on,
99 * other wise it is off. Define _gVDADER_RULES so snacc.h does not
100 * redefine the global gVDADER_RULES with it's extern (avoids a compile
101 * time warning).
102 ** COMPILER EXECUTION FLAGS: "-D -C -u ../../../snaccVC/asn-useful.asn1
103 sm_vdatypes.asn sm_x501ud.asn sm_x411ub.asn sm_x411mtsas.asn
104 sm_x501if.asn sm_x520sa.asn sm_x509cmn.asn sm_x509af.asn
105 sm_x509ce.asn sm_cms.asn sm_ess.asn tst_email.asn
106 tst_email2.asn"
107 -D -C -u ../../../snaccVC/asn-useful.asn1 sm_vdatypes.asn sm_x501ud.asn sm_x411ub.asn sm_x411mtsas.asn sm_x501if.asn sm_x520sa.asn sm_x509cmn.asn sm_x509af.asn sm_x509ce.asn sm_cms.asn sm_ess.asn tst_email.asn tst_email2.asn
108 */
109 #define _gVDADER_RULES
110 int gVDADER_RULES=0;
111 #endif
112
113 #include "snacc.h"
114
115 #if TIME_WITH_SYS_TIME
116 # include <sys/time.h>
117 # include <time.h>
118 #else
119 # if HAVE_SYS_TIME_H
120 # include <sys/time.h>
121 # else
122 # include <time.h>
123 # endif
124 #endif
125
126 #if STDC_HEADERS || HAVE_STRING_H
127 #include <string.h>
128 #else
129 #include <strings.h>
130 #endif
131 #include <stdio.h>
132
133 #include "asn-incl.h"
134 #include "version.h"
135 #include "mem.h"
136 #include "asn1module.h"
137 #include "exports.h"
138 #include "parser.h" /* for parser (ech!) globals */
139 #include "dependency.h"
140 #include "link-types.h"
141 #include "link-values.h"
142 #include "err-chk.h"
143 #include "print.h"
144 #include "recursive.h"
145 #include "define.h"
146 #include "normalize.h"
147 #include "do-macros.h"
148 #include "snacc-util.h"
149 #if META
150 #include "meta.h"
151 #endif
152
153 #include "str-util.h"
154
155 #include "c-gen/rules.h" /* for c file generation */
156 #include "c-gen/type-info.h"
157 #include "c-gen/gen-code.h"
158
159 #include "c++-gen/rules.h" /* for c++ file generation */
160 #include "c++-gen/types.h"
161 #include "c++-gen/gen-code.h"
162
163 #include "gen-tbls.h" /* for type table generation */
164
165 #if IDL
166 #include "idl-gen/rules.h"
167 #include "idl-gen/types.h"
168 #include "idl-gen/gen-code.h"
169 #endif
170
171
172 /* prototypes for this file's routines */
173
174 Module *ParseAsn1File PROTO ((char *fileName));
175
176 void GenCCode PROTO ((ModuleList *allMods, long int longJmpVal, int genTypes, int genEncoders, int genDecoders, int genPrinters, int genValues, int genFree));
177
178 void GenCxxCode PROTO ((ModuleList *allMods, long int longJmpVal, int genTypes, int genEncoders, int genDecoders, int genPrinters, int genValues, int genFree, if_META (MetaNameStyle genMeta COMMA MetaPDU *meta_pdus COMMA) if_TCL (int genTcl COMMA) int novolatilefuncs));
179
180 void GenIDLCode PROTO ((ModuleList *allMods, long int longJmpVal, int genTypes, int genPrinters, int genValues, int genFree));
181
182 int ModNamesUnique PROTO ((ModuleList *m));
183
184 Module *usefulTypeModG = NULL;
185 static char versionG[] = VERSION;
186 static char releasedateG[] = RELDATE;
187 static char bugreportaddressG[] = BUGREPADDR;
188 int maxFileNameLenG = -1; /* values > 2 are considered valid */
189 /* this is used in back_ends/c_gen/str_util.c */
190
191 void
192 Usage PARAMS ((prgName, fp),
193 char *prgName _AND_
194 FILE *fp)
195 {
196 fprintf (fp, "\nUsage: %s ", prgName);
197 fprintf (fp, "[-h] [-P] [-t] [-v] [-e] [-d] [-p] [-f]\n");
198 #if IDL
199 fprintf (fp, " [-c | -C | -[T|O] <table output file> | -idl ]\n");
200 #else
201 fprintf (fp, " [-c | -C | -[T|O] <table output file>]\n");
202 #endif
203 fprintf (fp, " [-u <useful types ASN.1 file>]\n");
204 fprintf (fp, " [-mm] [-mf <max file name length>]\n");
205 fprintf (fp, " [-l <neg number>]\n");
206 #if META
207 fprintf (fp, " [-meta <type list>] [-mA | -mC]\n");
208 #if TCL
209 fprintf (fp, " [-tcl <type list>]\n");
210 #endif
211 #endif
212 fprintf (fp, " <ASN.1 file list>\n\n");
213 fprintf (fp, " -h prints this msg\n");
214 fprintf (fp, " -c generate C encoders and decoders (default)\n");
215 fprintf (fp, " -C generate C++ encoders and decoders\n");
216 fprintf (fp, " -novolat for broken C++ compilers: return *this after calling abort()\n");
217 fprintf (fp, " -T <filename> write a type table file for the ASN.1 modules to file filename\n");
218 fprintf (fp, " -O <filename> writes the type table file in the original (<1.3b2) format\n");
219 #if IDL
220 fprintf (fp, " -idl generate CORBA IDL\n");
221 #endif
222 fprintf (fp, " -u <filename> specifies the ASN.1 file with definition of the useful types\n");
223 fprintf (fp, " (i.e. PrintableString). See the useful.asn1 file (in the\n");
224 fprintf (fp, " snacc/asn1specs/ directory).\n");
225 fprintf (fp, " -P print the parsed ASN.1 modules to stdout from their parse trees\n");
226 fprintf (fp, " (helpful debugging)\n");
227 fprintf (fp, " -t generate type definitions\n");
228 fprintf (fp, " -v generate value definitions (limited)\n");
229 fprintf (fp, " -e generate encode routines\n");
230 fprintf (fp, " -d generate decode routines\n");
231 fprintf (fp, " -p generate print routines\n");
232 fprintf (fp, " -f generate hierarchical free routines (C only)\n");
233 fprintf (fp, " note: if none of -t -v -e -d -p -f are given, all are generated.\n");
234 fprintf (fp, " These do not affect type tables.\n");
235
236
237 fprintf (fp, " -mm mangle output file name into module name (by default, the output file\n");
238 fprintf (fp, " inherits the input file's name, with only the suffix replaced)\n");
239 fprintf (fp, " -mf <num> num is maximum file name length for the generated source files\n");
240
241 fprintf (fp, " -l <neg num> where to start error longjmp values decending from (obscure).\n");
242
243 #if META
244 fprintf (fp, " -meta <type list> generate meta code that describes the generated types. Implies -C.\n");
245 fprintf (fp, " -mA metacode: use names as defined in the ASN.1 files.\n");
246 fprintf (fp, " -mC metacode: use names as used in the generated C++ files.\n");
247 #if TCL
248 fprintf (fp, " -tcl <type list> generate code for a Tcl interpreter. Implies -meta.\n");
249 #endif
250 fprintf (fp, " <type list> has the following syntax: <module>.<type>[,<module>.<type>[...]]\n");
251 fprintf (fp, " the types listed are the top level PDUs.\n");
252 #endif
253
254 fprintf (fp, "\nUse `-' as the ASN.1 source file name to parse stdin.\n\n");
255
256
257 fprintf (fp, "This ASN.1 compiler produces C or C++ BER encoders and decoders or type tables.\n");
258
259 fprintf (fp, "\nVersion %s, %s.\n", versionG, releasedateG);
260 #if 0
261 fprintf (fp, "Please send bug reports and comments to %s.\n\n", bugreportaddressG);
262 #else
263 fprintf (fp, "Please see %s for new versions and where to send bug reports and comments.\n\n", bugreportaddressG);
264 #endif
265
266 fprintf (fp, "Copyright (C) 1993 Michael Sample and UBC\n");
267 fprintf (fp, "Copyright (C) 1994, 1995 by Robert Joop and GMD FOKUS\n\n");
268
269 fprintf (fp, "This program is free software; you can redistribute it and/or modify\n");
270 fprintf (fp, "it under the terms of the GNU General Public License as published by\n");
271 fprintf (fp, "the Free Software Foundation; either version 2 of the License, or\n");
272 fprintf (fp, "(at your option) any later version.\n\n");
273
274 fprintf (fp, "This program is distributed in the hope that it will be useful,\n");
275 fprintf (fp, "but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
276 fprintf (fp, "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
277 fprintf (fp, "GNU General Public License for more details.\n\n");
278
279 /*
280 fprintf (fp, "You should have received a copy of the GNU General Public License\n");
281 fprintf (fp, "along with this program; if not, write to the Free Software\n");
282 fprintf (fp, "Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n");
283 */
284 }
285
286
287 typedef struct
288 {
289 char *fileName;
290 } SRC_FILE;
291
292
293 #if META
294 static MetaPDU *parse_type_list (arg)
295 char *arg;
296 {
297 MetaPDU *meta_pdus = NULL;
298 char *module;
299 for (module = strtok (arg, ".:"); module; module = strtok (NULL, ".:"))
300 {
301 MetaPDU *pdu = MT (MetaPDU);
302 char *type = strtok (NULL, " /,;");
303 if (!type)
304 {
305 fprintf (stderr, "usage: {-meta|-tcl} module.type[,module.type[...]]\n");
306 exit (1);
307 }
308 pdu->module = module;
309 pdu->type = type;
310 pdu->used = FALSE;
311
312 pdu->next = meta_pdus;
313 meta_pdus = pdu;
314 }
315 return meta_pdus;
316 }
317 #endif
318
319 int main PARAMS ((argc, argv),
320 int argc _AND_
321 char **argv)
322 {
323 int i, j, semErr;
324 int retVal;
325 int fd;
326 SRC_FILE *srcList;
327 int numSrcFiles;
328 ModuleList *allMods;
329 Module *currMod;
330 Module **tmpModHndl;
331 int currArg;
332 int argsProcessed;
333 char *usefulTypeModFileName;
334 FILE *fPtr;
335 int printModuleFlag = FALSE; /* default: Don't print */
336 int genTypeTbls = 0; /* default: Don't gen tbls */
337 char *tblFileName;
338 int genTypeCode = FALSE;
339 int genEncodeCode = FALSE;
340 int genDecodeCode = FALSE;
341 int genPrintCode = FALSE;
342 int genValueCode = FALSE;
343 int genFreeCode = FALSE;
344 #if META
345 MetaNameStyle genMetaCode = META_off;
346 MetaPDU *meta_pdus = NULL;
347 #if TCL
348 int genTclCode = FALSE;
349 #endif
350 #endif
351 int genCCode = FALSE; /* defaults to C if neither specified */
352 int genCxxCode = FALSE;
353 #if IDL
354 int genIDLCode = FALSE;
355 #endif
356 long longJmpVal = -100;
357 int novolatilefuncs = FALSE;
358
359 #ifdef YYDEBUG
360 /* prints yacc debugging info to stdout */
361 yydebug = 1;
362 #endif
363
364
365 if (argc <= 1)
366 {
367 Usage (argv[0], stderr);
368 exit (1);
369 }
370
371 srcList = (SRC_FILE*) Malloc ((argc -1) * sizeof (SRC_FILE));
372
373
374 /*
375 * parse cmd line args
376 */
377 numSrcFiles = 0;
378 usefulTypeModFileName = NULL;
379 for (currArg = 1; (currArg < argc); )
380 {
381 if ((argv[currArg][0] == '-') && (argv[currArg][1] != '\0'))
382 switch (argv[currArg][1])
383 {
384 #ifdef VDADER_RULES
385 case 'D':
386 gVDADER_RULES=1;
387 currArg++;
388 break;
389 #endif
390 case 'h':
391 Usage (argv[0], stdout);
392 exit (1);
393 break;
394
395 case 'P':
396 printModuleFlag = TRUE;
397 currArg++;
398 break;
399
400 case 'v':
401 genValueCode = TRUE;
402 currArg++;
403 break;
404
405 #if IDL
406 case 'i':
407 if (!strcmp (argv[currArg]+1, "idl"))
408 {
409 genIDLCode = TRUE;
410 currArg++;
411 }
412 else
413 goto error;
414 break;
415 #endif
416
417 case 't':
418 if (!strcmp (argv[currArg]+1, "tcl"))
419 {
420 #if TCL
421 meta_pdus = parse_type_list (argv[++currArg]);
422 genTclCode = TRUE;
423 if (!genMetaCode)
424 genMetaCode = META_backend_names;
425 genCxxCode = TRUE;
426 #else
427 goto error;
428 #endif
429 }
430 else
431 genTypeCode = TRUE;
432 currArg++;
433 break;
434
435 case 'e':
436 genEncodeCode = TRUE;
437 currArg++;
438 break;
439
440 case 'd':
441 genDecodeCode = TRUE;
442 currArg++;
443 break;
444
445 case 'p':
446 genPrintCode = TRUE;
447 currArg++;
448 break;
449
450 case 'f':
451 genFreeCode = TRUE;
452 currArg++;
453 break;
454
455 case 'C':
456 genCxxCode = TRUE;
457 currArg++;
458 break;
459
460 case 'n':
461 if (!strcmp (argv[currArg]+1, "novolat"))
462 {
463 novolatilefuncs = TRUE;
464 currArg++;
465 }
466 else
467 goto error;
468 break;
469
470 case 'c':
471 genCCode = TRUE;
472 currArg++;
473 break;
474
475 case 'u':
476 if (argv[currArg][2] != '\0') /* no space after -u */
477 {
478 usefulTypeModFileName = &argv[currArg][2];
479 currArg++;
480 }
481 else
482 {
483 usefulTypeModFileName = argv[currArg+1];
484 currArg += 2;
485 }
486 break;
487
488 case 'l':
489 if (argv[currArg][2] != '\0') /* no space after -l */
490 {
491 longJmpVal = atoi (&argv[currArg][2]);
492 currArg++;
493 }
494 else
495 {
496 longJmpVal = atoi (argv[currArg+1]);
497 currArg += 2;
498 }
499 break;
500
501 case 'T':
502 case 'O':
503 genTypeTbls = argv[currArg][1]=='T'?2:1;
504 if (argv[currArg][2] != '\0') /* no space after -T */
505 {
506 tblFileName = &argv[currArg][2];
507 currArg++;
508 }
509 else
510 {
511 tblFileName = argv[currArg+1];
512 currArg += 2;
513 }
514 break;
515
516
517 case 'm':
518 if (argv[currArg][2] == 'f')
519 {
520 if (argv[currArg][3] != '\0') /* no space after -mf */
521 {
522 maxFileNameLenG = atoi (&argv[currArg][3]);
523 currArg++;
524 }
525 else
526 {
527 maxFileNameLenG = atoi (argv[currArg+1]);
528 currArg += 2;
529 }
530 break;
531 }
532 #if META
533 else if (!strcmp (argv[currArg]+1, "meta"))
534 {
535 meta_pdus = parse_type_list (argv[++currArg]);
536 if (!genMetaCode)
537 genMetaCode = META_backend_names;
538 genCxxCode = TRUE;
539 currArg++;
540 break;
541 }
542 else if (!strcmp (argv[currArg]+1, "mA"))
543 {
544 genMetaCode = META_asn1_names;
545 genCxxCode = TRUE;
546 currArg++;
547 break;
548 }
549 else if (!strcmp (argv[currArg]+1, "mC"))
550 {
551 genMetaCode = META_backend_names;
552 genCxxCode = TRUE;
553 currArg++;
554 break;
555 }
556 #endif
557 else if (argv[currArg][2] == 'm')
558 {
559 keepbaseG = FALSE;
560 currArg++;
561 break;
562 }
563
564 /* else fall through to default error */
565
566 error:
567 default:
568 fprintf (stderr, "%s: ERROR---unknown cmd line option `%s'\n\n", argv[0], argv[currArg]);
569 Usage (argv[0], stderr);
570 exit (1);
571 }
572
573 else /* asn1srcFileName */
574 srcList[numSrcFiles++].fileName = argv[currArg++];
575
576 }
577
578
579 if (numSrcFiles == 0)
580 {
581 fprintf (stderr, "%s: ERROR---no ASN.1 source files were specified\n", argv[0]);
582 Usage (argv[0], stderr);
583 exit (1);
584 }
585
586
587 /*
588 * set default options
589 */
590 if (!(genTypeCode || genValueCode || genEncodeCode || genDecodeCode ||
591 genFreeCode || genPrintCode))
592 {
593 genTypeCode = TRUE;
594 genValueCode = TRUE;
595 genEncodeCode = TRUE;
596 genDecodeCode = TRUE;
597 genFreeCode = TRUE;
598 genPrintCode = TRUE;
599 }
600
601 else if (genCCode + genCxxCode + genTypeTbls
602 #if IDL
603 + genIDLCode
604 #endif
605 > 1)
606 {
607 fprintf (stderr, "%s: ERROR---Choose only one of the -c -C or -T options\n", argv[0]);
608 Usage (argv[0], stderr);
609 exit (1);
610 }
611
612 if (!genCCode && !genCxxCode && !genTypeTbls
613 #if IDL
614 && !genIDLCode
615 #endif
616 )
617 genCCode = TRUE; /* default to C if neither specified */
618
619
620 /*
621 * STEP 1
622 * parse 'useful' type module for linking purposes only (if given)
623 * the useful type encode, decode, print, free routines are
624 * already in the runtime library.
625 */
626 if (usefulTypeModFileName != NULL)
627 {
628 usefulTypeModG = ParseAsn1File (usefulTypeModFileName);
629
630 if (usefulTypeModG == NULL)
631 exit (1);
632 }
633 else
634 {
635 fprintf (stderr, " Hmmm, you didn't specify a useful types ASN.1 file with the `-u' option.\n");
636 fprintf (stderr, " I'll continue assuming your ASN.1 file(s) don't need any useful types.\n");
637 }
638
639
640 /*
641 * STEP 2---parse each ASN.1 src file
642 */
643 allMods = (ModuleList *)AsnListNew (sizeof (void*));
644 for (i = 0; i < numSrcFiles; i++)
645 {
646 currMod = ParseAsn1File (srcList[i].fileName);
647
648 if (currMod == NULL)
649 exit (1);
650
651 /*
652 * insert this module at the head of the list
653 * of already parsed (if any) modules
654 */
655 tmpModHndl = (Module **)AsnListAppend (allMods);
656 *tmpModHndl = currMod;
657
658 } /* end per src file for loop */
659
660
661 /*
662 * Check that the module names/oids are unique.
663 */
664 if (!ModNamesUnique (allMods))
665 {
666 fprintf (stderr, "Conflicting module names, cannot proceed.\n");
667 exit (1);
668 }
669
670
671
672 /*
673 * STEP 3
674 * Now that all files have been parsed,
675 * link local and locatable import type refs
676 */
677 if (LinkTypeRefs (allMods) < 0)
678 {
679 fprintf (stderr, "Type linking errors---cannot proceed\n");
680 exit (1);
681 }
682
683
684
685 /*
686 * STEP 4
687 * Parse constructed values now that types are all parsed
688 * and have been linked. Need type info to be able to
689 * parse values easily (elimitate ambiguity).
690 */
691 FOR_EACH_LIST_ELMT (currMod, allMods)
692 {
693 if (ParseValues (allMods, currMod) != 0)
694 fprintf (stderr, "WARNING: Value parsing error (s), attempting to continue\n");
695 }
696
697
698 /*
699 * STEP 5
700 * Value parsing may have defined some new values
701 * so can link local and locatable import value refs now.
702 */
703 if (LinkValueRefs (allMods) < 0)
704 {
705 fprintf (stderr, "Value linking errors---cannot proceed\n");
706 exit (1);
707 }
708
709
710
711 /*
712 * STEP 6
713 * process macros
714 * - adding type/value defs as nec
715 * - mark type defs with ANY DEFINED BY id if nec
716 * so they are put in the id to ANY type hash tbl.
717 */
718 semErr = 0;
719 FOR_EACH_LIST_ELMT (currMod, allMods)
720 {
721 ProcessMacros (currMod);
722 if (currMod->status == MOD_ERROR)
723 semErr = 1;
724 }
725 if (semErr)
726 exit (1);
727
728 /*
729 * STEP 7
730 * convert silly type constructs into
731 * a normal format, leaving behind pure type/value info
732 * eg: expand COMPONENTS OF refs, SELECTION types.
733 * boil down values into simplest rep. (eg OID -> ENC_OID)
734 */
735 semErr = 0;
736 FOR_EACH_LIST_ELMT (currMod, allMods)
737 {
738 NormalizeModule (currMod);
739 if (currMod->status == MOD_ERROR)
740 semErr = 1;
741 }
742 if (semErr)
743 exit (1);
744
745
746 /*
747 * STEP 8
748 * Mark recusive types. Currently the recursive information is
749 * not used elsewhere.
750 */
751 FOR_EACH_LIST_ELMT (currMod, allMods)
752 {
753 MarkRecursiveTypes (currMod);
754 }
755
756
757 /*
758 * STEP 9
759 * Check for errors in the ASN.1 modules.
760 * Check all modules and exit if errors were found
761 */
762 semErr = 0;
763 if (usefulTypeModG != NULL)
764 {
765 ErrChkModule (usefulTypeModG);
766 if (usefulTypeModG->status == MOD_ERROR)
767 semErr = 1;
768 }
769
770 FOR_EACH_LIST_ELMT (currMod, allMods)
771 {
772 ErrChkModule (currMod);
773 if (currMod->status == MOD_ERROR)
774 semErr = 1;
775 }
776
777
778 if (semErr)
779 exit (1);
780
781
782
783
784 /*
785 * exit if any sundry errors occurred at any point.
786 * smallErrG is set upon finding small errors that prevent code
787 * production but should not affect the other processing/error
788 * checking steps. This allows full display of errors.
789 */
790 if (smallErrG)
791 {
792 /*
793 * for debugging show "parsed" version of ASN.1 module if
794 * the print flag is set.
795 * Dumps each module to stdout. Printed from Module data struct
796 * print here before exiting otherwise print after sorting
797 */
798 if (printModuleFlag)
799 {
800 FOR_EACH_LIST_ELMT (currMod, allMods)
801 {
802 printf ("\n\n");
803 PrintModule (stdout, currMod);
804 }
805 }
806
807 exit (1);
808 }
809
810 /*
811 * STEP 10
812 * Make C/C++ typenames/routine names for enc/decode.
813 * Type/Value renaming will occur if name conflicts
814 * arise between modules.
815 *
816 * NOTE: this is done before sorting the types because
817 * the type sorting routine may use the 'isPtr'
818 * information to help order knots of recursive types.
819 */
820 if (genCCode)
821 FillCTypeInfo (&cRulesG, allMods);
822
823 else if (genCxxCode)
824 FillCxxTypeInfo (&cxxRulesG, allMods);
825
826 #if IDL
827 else if (genIDLCode)
828 FillIDLTypeInfo (&idlRulesG, allMods);
829 #endif
830
831
832 /*
833 * STEP 11
834 * Sort each typedef list such that independent types are
835 * before the types that depend on them
836 *
837 * modules remain in same order as given on command line
838 * (cmd line file order should be
839 * least dependent module-> most dependent module
840 * so that include file order in generated src is correct)
841 * (useful.asn1 is always considered 'first' if given)
842 */
843 SortAllDependencies (allMods);
844
845 /*
846 * for debugging show "parsed" version of ASN.1 module.
847 * dumps each module to stdout. Printed from Module data struct
848 * Shows the results of normalization and sorting.
849 */
850 if (printModuleFlag)
851 {
852 FOR_EACH_LIST_ELMT (currMod, allMods)
853 {
854 printf ("\n\n");
855 PrintModule (stdout, currMod);
856 }
857 }
858
859 /*
860 * Step 12
861 * Final Step: Code/Type Table generation
862 */
863 if (genCCode)
864 GenCCode (allMods, longJmpVal, genTypeCode, genValueCode, genEncodeCode, genDecodeCode, genPrintCode, genFreeCode);
865
866 else if (genCxxCode)
867 GenCxxCode (allMods, longJmpVal, genTypeCode, genValueCode, genEncodeCode, genDecodeCode, genPrintCode, genFreeCode, if_META (genMetaCode COMMA meta_pdus COMMA) if_TCL (genTclCode COMMA) novolatilefuncs);
868
869 else if (genTypeTbls)
870 GenTypeTbls (allMods, tblFileName, genTypeTbls);
871
872 #if IDL
873 else if (genIDLCode)
874 GenIDLCode (allMods, longJmpVal, genTypeCode, genValueCode, genPrintCode, genFreeCode);
875 #endif
876
877 return 0; /* keep make happy */
878
879 } /* end main */
880
881
882
883 /*
884 * Calls the yacc/lex parser given a the ASN.1 src file's filename.
885 * Returns a Module *for the given ASN.1 module. If the filename is
886 * "-" stdin is used.
887 */
888 Module *
889 ParseAsn1File PARAMS ((fileName),
890 char *fileName)
891 {
892 FILE *fPtr;
893 Module *retVal;
894 int parseResult;
895
896 /*
897 * Open input file for lexical analyzer/parser
898 * Use stdin if the filename is "-"
899 */
900 if (strcmp (fileName, "-") == 0)
901 if (keepbaseG)
902 {
903 fprintf (stderr, "ERROR---asn1 src file `%s' cannot be processed without output filename mangling\n", fileName);
904 return NULL;
905 }
906 else
907 fPtr = stdin;
908 else
909 fPtr = fopen (fileName, "r");
910
911 if (fPtr == NULL)
912 {
913 fprintf (stderr, "ERROR---asn1 src file `%s' cannot be opened for reading\n", fileName);
914 return NULL;
915 }
916
917 retVal = (Module *)Malloc (sizeof (Module));
918
919 /*
920 * Init Parser by giving it a ptr to the Module data struct
921 * to initialize/use, and the file name associtated with
922 * the given FILE *, fPtr (for error reporting).
923 * fPtr should be an opened FILE *to an ASN.1 source FILE
924 */
925 InitAsn1Parser (retVal, fileName, fPtr);
926
927
928 /*
929 * parse the current asn1 src file into the
930 * Module data struct
931 */
932 parseResult = yyparse();
933
934 if (parseResult != 0 || retVal->status == MOD_ERROR)
935 {
936 /* parser will print exact err msg */
937 fprintf (stderr, "Parsing errors---cannot proceed\n");
938 return NULL;
939 }
940
941 if (fPtr != stdin)
942 fclose (fPtr);
943
944 return retVal;
945
946 } /* ParseAsn1File */
947
948
949 /*
950 * Given the list of parsed, linked, normalized, error-checked and sorted
951 * modules, and some code generation flags, generates C code and
952 * writes it to files derived from each modules name. Each module
953 * gets 2 source files, one .h for data struct and prototypes, the other .c
954 * for the enc/dec/print/free routine code.
955 */
956 void
957 GenCCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDecoders, genPrinters, genFree),
958 ModuleList *allMods _AND_
959 long int longJmpVal _AND_
960 int genTypes _AND_
961 int genValues _AND_
962 int genEncoders _AND_
963 int genDecoders _AND_
964 int genPrinters _AND_
965 int genFree)
966 {
967 Module *currMod;
968 char *modBaseFileName;
969 FILE *cHdrFilePtr;
970 FILE *cSrcFilePtr;
971 DefinedObj *fNames;
972 int fNameConflict = FALSE;
973
974 /*
975 * Make names for each module's encoder/decoder src and hdr files
976 * so import references can be made via include files.
977 * If file names conflict, print error msg & exit.
978 */
979 fNames = NewObjList();
980 FOR_EACH_LIST_ELMT (currMod, allMods)
981 {
982 modBaseFileName = MakeBaseFileName (keepbaseG
983 ? currMod->asn1SrcFileName
984 : currMod->modId->name); /* shorten module name if necessary (SYSV etc) */
985 currMod->cHdrFileName = MakeCHdrFileName (modBaseFileName);
986 currMod->cSrcFileName = MakeCSrcFileName (modBaseFileName);
987
988 if (ObjIsDefined (fNames, currMod->cHdrFileName, StrObjCmp) ||
989 ObjIsDefined (fNames, currMod->cSrcFileName, StrObjCmp))
990 {
991 fprintf (stderr, "Ack! ERROR---file name conflict for generated source files with names `%s' and `%s'.\n\n", currMod->cHdrFileName, currMod->cSrcFileName);
992 fprintf (stderr, "This usually means the max file name length is truncating the file names.\n");
993 fprintf (stderr, "Try re-naming the modules with shorter names or increasing the argument to -mf option (if you are using it).\n");
994 fprintf (stderr, "This error can also be caused by 2 modules with the same names but different OBJECT IDENTIFIERs.");
995 fprintf (stderr, " Try renaming the modules to correct this.\n");
996 fNameConflict = TRUE;
997 }
998 else
999 {
1000 DefineObj (&fNames, currMod->cHdrFileName);
1001 DefineObj (&fNames, currMod->cSrcFileName);
1002 }
1003 Free (modBaseFileName);
1004 }
1005 if (fNameConflict)
1006 exit (1);
1007
1008 FreeDefinedObjs (&fNames);
1009 /*
1010 * make c files
1011 */
1012 FOR_EACH_LIST_ELMT (currMod, allMods)
1013 {
1014 cHdrFilePtr = fopen (currMod->cHdrFileName, "w");
1015 cSrcFilePtr = fopen (currMod->cSrcFileName, "w");
1016 if ((cSrcFilePtr == NULL) || (cHdrFilePtr == NULL))
1017 perror ("fopen");
1018 else
1019 {
1020 PrintCCode (cSrcFilePtr, cHdrFilePtr, allMods, currMod, &cRulesG, longJmpVal, genTypes, genValues, genEncoders, genDecoders, genPrinters, genFree);
1021
1022 fclose (cHdrFilePtr);
1023 fclose (cSrcFilePtr);
1024 }
1025 }
1026
1027 } /* GenCCode */
1028
1029
1030 /*
1031 * Given the list of parsed, linked, normalized, error-checked and sorted
1032 * modules, and some code generation flags, generates C++ code and
1033 * writes it to files derived from each modules name. Each module
1034 * gets 2 source files, one .h for data struct and prototypes, the other .C
1035 * for the enc/dec/print/free routine code.
1036 */
1037 void
1038 GenCxxCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genEncoders, genDecoders, genPrinters, genFree, if_META (genMeta COMMA meta_pdus COMMA) if_TCL (genTcl COMMA) novolatilefuncs),
1039 ModuleList *allMods _AND_
1040 long int longJmpVal _AND_
1041 int genTypes _AND_
1042 int genValues _AND_
1043 int genEncoders _AND_
1044 int genDecoders _AND_
1045 int genPrinters _AND_
1046 int genFree _AND_
1047 if_META (MetaNameStyle genMeta _AND_)
1048 if_META (MetaPDU *meta_pdus _AND_)
1049 if_TCL (int genTcl _AND_)
1050 int novolatilefuncs)
1051 {
1052 Module *currMod;
1053 char *modBaseFileName;
1054 FILE *hdrFilePtr;
1055 FILE *srcFilePtr;
1056 #ifdef _IBM_ENC_
1057 FILE *hdbFilePtr; /* 19.8.93 IBM-ENC */
1058 FILE *sdbFilePtr; /* 19.8.93 IBM-ENC */
1059 #endif /* _IBM_ENC_ */
1060 DefinedObj *fNames;
1061 int fNameConflict = FALSE;
1062
1063 #if META
1064 static const char metabasefn[] = "modules";
1065 Meta meta;
1066 #if TCL
1067 const MetaPDU *pdu;
1068 #endif
1069 #endif
1070
1071 /*
1072 * Make names for each module's encoder/decoder src and hdr files
1073 * so import references can be made via include files
1074 * check for truncation --> name conflicts & exit if nec
1075 */
1076 fNames = NewObjList();
1077 #if META
1078 if (genMeta)
1079 DefineObj (&fNames, meta.srcfn = MakeCxxSrcFileName (metabasefn));
1080 #endif
1081 FOR_EACH_LIST_ELMT (currMod, allMods)
1082 {
1083 modBaseFileName = MakeBaseFileName (keepbaseG
1084 ? currMod->asn1SrcFileName
1085 : currMod->modId->name); /* shorten module name if necessary (SYSV etc) */
1086 currMod->cxxHdrFileName = MakeCxxHdrFileName (modBaseFileName);
1087 currMod->cxxSrcFileName = MakeCxxSrcFileName (modBaseFileName);
1088 #ifdef _IBM_ENC_
1089 currMod->dbHdrFileName = MakedbHdrFileName (modBaseFileName); /* 19.8.93 IBM-ENC */
1090 currMod->dbSrcFileName = MakedbSrcFileName (modBaseFileName); /* 19.8.93 IBM-ENC */
1091 #endif /* _IBM_ENC_ */
1092 #if META
1093 {
1094 char *in, *out;
1095
1096 out = currMod->cxxname = (char *)malloc (strlen (in = currMod->modId->name)+1);
1097 do
1098 *out++ = *in == '-' ? '_' : *in;
1099 while (*in++);
1100 }
1101 #endif
1102
1103 if (ObjIsDefined (fNames, currMod->cxxHdrFileName, StrObjCmp) || ObjIsDefined (fNames, currMod->cxxSrcFileName, StrObjCmp))
1104 {
1105 fprintf (stderr, "Ack! ERROR---file name conflict for generated source files with names `%s' and `%s'.\n\n", currMod->cxxHdrFileName, currMod->cxxSrcFileName);
1106 fprintf (stderr, "This usually means the max file name length is truncating the file names.\n");
1107 fprintf (stderr, "Try re-naming the modules with shorter names or increasing the argument to -mf option (if you are using it).\n");
1108 fprintf (stderr, "This error can also be caused by 2 modules have the same names but different OBJECT IDENTIFIERs.");
1109 fprintf (stderr, " Try renaming the modules to correct this.\n");
1110 fNameConflict = TRUE;
1111 }
1112 else
1113 {
1114 DefineObj (&fNames, currMod->cxxHdrFileName);
1115 DefineObj (&fNames, currMod->cxxSrcFileName);
1116 }
1117 Free (modBaseFileName);
1118 }
1119 if (fNameConflict)
1120 exit (1);
1121
1122 FreeDefinedObjs (&fNames);
1123
1124 /*
1125 * make C++ files
1126 */
1127 #if META
1128 if (genMeta)
1129 {
1130 time_t now = time (NULL);
1131
1132 if (!(meta.srcfp = fopen (meta.srcfn, "w")))
1133 {
1134 perror ("fopen");
1135 exit (1);
1136 }
1137 fprintf (meta.srcfp, "// NOTE: this is a machine generated file--editing not recommended\n");
1138 fprintf (meta.srcfp, "//\n");
1139 fprintf (meta.srcfp, "// modules.C - reference to all modules and their types\n");
1140 fprintf (meta.srcfp, "//\n");
1141 fprintf (meta.srcfp, "// This file was generated by snacc on %s", ctime (&now));
1142 }
1143 #endif
1144 FOR_EACH_LIST_ELMT (currMod, allMods)
1145 {
1146 /*
1147 * create and fill .h file for module's data structs
1148 */
1149 hdrFilePtr = fopen (currMod->cxxHdrFileName, "w");
1150 srcFilePtr = fopen (currMod->cxxSrcFileName, "w");
1151 #ifndef _IBM_ENC_
1152 if ((hdrFilePtr == NULL) || (srcFilePtr == NULL))
1153 #else
1154 hdbFilePtr = fopen (currMod->dbHdrFileName, "w"); /* 19.8.93 IBM-ENC */
1155 sdbFilePtr = fopen (currMod->dbSrcFileName, "w"); /* 19.8.93 IBM-ENC */
1156 if ((hdrFilePtr == NULL) || (srcFilePtr == NULL) ||
1157 (hdbFilePtr == NULL) || (sdbFilePtr == NULL)) /* 19.8.93 IBM-ENC */
1158 #endif /* _IBM_ENC_ */
1159 perror ("fopen");
1160 else
1161 {
1162 PrintCxxCode (srcFilePtr, hdrFilePtr,
1163 if_IBM_ENC (sdbFilePtr COMMA hdbFilePtr COMMA /* 19.8.93 IBM-ENC */)
1164 if_META (genMeta COMMA &meta COMMA meta_pdus COMMA)
1165 allMods, currMod, &cxxRulesG, longJmpVal,
1166 genTypes, genValues, genEncoders, genDecoders, genPrinters, genFree,
1167 if_TCL (genTcl COMMA) novolatilefuncs);
1168
1169 fclose (hdrFilePtr);
1170 fclose (srcFilePtr);
1171 #ifdef _IBM_ENC_
1172 fclose (hdbFilePtr); /* 19.8.93 IBM-ENC */
1173 fclose (sdbFilePtr); /* 19.8.93 IBM-ENC */
1174 #endif /* _IBM_ENC_ */
1175 }
1176 }
1177 #if META
1178 if (genMeta)
1179 {
1180 fprintf (meta.srcfp, "\n");
1181 fprintf (meta.srcfp, "#ifndef META\n");
1182 fprintf (meta.srcfp, "#define META 1\n");
1183 fprintf (meta.srcfp, "#endif\n");
1184 if (meta_pdus)
1185 {
1186 for (pdu=meta_pdus; pdu; pdu=pdu->next)
1187 if (!pdu->used)
1188 fprintf (stderr, "warning: PDU %s.%s couldn't be found\n", pdu->module, pdu->type);
1189 }
1190 #if TCL
1191 fprintf (meta.srcfp, "#ifndef TCL\n");
1192 fprintf (meta.srcfp, "#define TCL META\n");
1193 fprintf (meta.srcfp, "#endif\n");
1194 #endif
1195 fprintf (meta.srcfp, "\n");
1196
1197 fprintf (meta.srcfp, "#include \"asn-incl.h\"\n");
1198 FOR_EACH_LIST_ELMT (currMod, allMods)
1199 fprintf (meta.srcfp, "#include \"%s\"\n", currMod->cxxHdrFileName);
1200 fprintf (meta.srcfp, "\n");
1201
1202 fprintf (meta.srcfp, "#if META\n\n");
1203
1204 fprintf (meta.srcfp, "const AsnModuleDesc *asnModuleDescs[] =\n");
1205 fprintf (meta.srcfp, "{\n");
1206 FOR_EACH_LIST_ELMT (currMod, allMods)
1207 fprintf (meta.srcfp, " &%sModuleDesc,\n", currMod->cxxname);
1208 fprintf (meta.srcfp, " NULL\n");
1209 fprintf (meta.srcfp, "};\n\n");
1210
1211 if (genTcl)
1212 {
1213 fprintf (meta.srcfp, "#if TCL\n\n");
1214
1215 fprintf (meta.srcfp, "// hack to avoid the neccessity to list -ltk -ltcl both before and after -lasn1tcl:\n");
1216 fprintf (meta.srcfp, "static int (*dummy)(Tcl_Interp *) = Tcl_AppInit;\n\n");
1217
1218 fprintf (meta.srcfp, "#endif // TCL\n\n");
1219 }
1220
1221 fprintf (meta.srcfp, "#endif // META\n");
1222
1223 fclose (meta.srcfp);
1224 }
1225 #endif
1226 } /* GenCxxCode */
1227
1228
1229 #if IDL
1230 /*
1231 * Given the list of parsed, linked, normalized, error-checked and sorted
1232 * modules, and some code generation flags, generates C++ code and
1233 * writes it to files derived from each modules name. Each module
1234 * gets 2 source files, one .h for data struct and prototypes, the other .C
1235 * for the enc/dec/print/free routine code.
1236 */
1237 void
1238 GenIDLCode PARAMS ((allMods, longJmpVal, genTypes, genValues, genPrinters, genFree),
1239 ModuleList *allMods _AND_
1240 long int longJmpVal _AND_
1241 int genTypes _AND_
1242 int genValues _AND_
1243 int genPrinters _AND_
1244 int genFree)
1245 {
1246 Module *currMod;
1247 char *modBaseFileName;
1248 FILE *idlFilePtr;
1249 DefinedObj *fNames;
1250 int fNameConflict = FALSE;
1251
1252 /*
1253 * Make names for each module's encoder/decoder src and hdr files
1254 * so import references can be made via include files
1255 * check for truncation --> name conflicts & exit if nec
1256 */
1257 fNames = NewObjList();
1258 FOR_EACH_LIST_ELMT (currMod, allMods)
1259 {
1260 modBaseFileName = MakeBaseFileName (keepbaseG
1261 ? currMod->asn1SrcFileName
1262 : currMod->modId->name); /* shorten module name if necessary (SYSV etc) */
1263 currMod->idlFileName = MakeIDLFileName (modBaseFileName);
1264 {
1265 char *in, *out;
1266
1267 out = currMod->idlname = (char *)malloc (strlen (in = currMod->modId->name)+1);
1268 do
1269 *out++ = *in == '-' ? '_' : *in;
1270 while (*in++);
1271 }
1272
1273 if (ObjIsDefined (fNames, currMod->idlFileName, StrObjCmp))
1274 {
1275 fprintf (stderr, "Ack! ERROR---file name conflict for generated source file with name `%s'.\n\n", currMod->idlFileName);
1276 fprintf (stderr, "This usually means the max file name length is truncating the file names.\n");
1277 fprintf (stderr, "Try re-naming the modules with shorter names or increasing the argument to -mf option (if you are using it).\n");
1278 fprintf (stderr, "This error can also be caused by 2 modules have the same names but different OBJECT IDENTIFIERs.");
1279 fprintf (stderr, " Try renaming the modules to correct this.\n");
1280 fNameConflict = TRUE;
1281 }
1282 else
1283 {
1284 DefineObj (&fNames, currMod->idlFileName);
1285 }
1286 Free (modBaseFileName);
1287 }
1288 if (fNameConflict)
1289 exit (1);
1290
1291 FreeDefinedObjs (&fNames);
1292
1293 /*
1294 * make C++ files
1295 */
1296 FOR_EACH_LIST_ELMT (currMod, allMods)
1297 {
1298 /*
1299 * create and fill .h file for module's data structs
1300 */
1301 idlFilePtr = fopen (currMod->idlFileName, "w");
1302 if (idlFilePtr == NULL)
1303 perror ("fopen");
1304 else
1305 {
1306 PrintIDLCode (idlFilePtr, allMods, currMod, &idlRulesG, longJmpVal, genValues);
1307
1308 fclose (idlFilePtr);
1309 }
1310 }
1311 } /* GenIDLCode */
1312 #endif /* IDL */
1313
1314
1315 /*
1316 * returns 1 if the module names and oid's are unique.
1317 * otherwise returns 0
1318 */
1319 int ModNamesUnique PARAMS ((mods),
1320 ModuleList *mods)
1321 {
1322 DefinedObj *names;
1323 DefinedObj *oids;
1324 Module *m;
1325 int retVal = 1;
1326
1327 names = NewObjList();
1328 oids = NewObjList();
1329
1330 FOR_EACH_LIST_ELMT (m, mods)
1331 {
1332 if (((m->modId->oid != NULL) &&
1333 ObjIsDefined (oids, m->modId->oid, OidObjCmp)))
1334 {
1335 /* oops, 2 modules have the same oid */
1336 PrintErrLoc (m->asn1SrcFileName, 1);
1337 fprintf (stderr, "ERROR---2 modules have the OBJECT IDENTIFIER `");
1338 PrintOid (stderr, m->modId->oid);
1339 fprintf (stderr, "'.\n");
1340 retVal = 0;
1341 }
1342 /* name is only signficant if oid is empty */
1343 else if ((m->modId->oid == NULL) &&
1344 (ObjIsDefined (names, m->modId->name, StrObjCmp)))
1345 {
1346 /* oops, 2 modules have the same name */
1347 PrintErrLoc (m->asn1SrcFileName, 1);
1348 fprintf (stderr, "ERROR---2 modules have the name `%s'\n", m->modId->name);
1349 retVal = 0;
1350 }
1351 else
1352 {
1353 DefineObj (&names, m->modId->name);
1354 if (m->modId->oid != NULL)
1355 DefineObj (&oids, m->modId->oid);
1356 }
1357 }
1358 FreeDefinedObjs (&names);
1359 FreeDefinedObjs (&oids);
1360 return retVal;
1361 } /* ModNamesUnique */