comerr: compile_et -emit option for parallel make
[openafs.git] / src / comerr / compile_et.c
1 /*
2  *
3  * Copyright 1986, 1987, 1988
4  * by MIT Student Information Processing Board.
5  *
6  * For copyright info, see "mit-sipb-cr.h".
7  *
8  */
9
10 #undef MEMORYLEAK
11 #include <afsconfig.h>
12 #include <afs/param.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #include "mit-sipb-cr.h"
18 #include "internal.h"
19 #include "compiler.h"
20
21 #ifndef lint
22 static const char copyright[] =
23     "Copyright 1987,1988 by MIT Student Information Processing Board";
24 #endif
25
26 extern char *current_token;
27 extern int table_number, current;
28 char buffer[BUFSIZ];
29 char *table_name = NULL;
30 FILE *hfile = NULL, *cfile = NULL, *msfile = NULL;
31 int version = 1;
32 int use_msf = 0;
33 int emit_source = 0;
34 int emit_header = 0;
35
36 /* lex stuff */
37 extern FILE *yyin;
38 extern FILE *yyout;
39 #ifdef AFS_AIX51_ENV
40 int yylineno = 0;
41 #else
42 extern int yylineno;
43 #endif
44
45 char *
46 xmalloc(unsigned int size)
47 {
48     char *p = malloc(size);
49     if (!p) {
50         perror(whoami);
51         exit(1);
52     }
53     return p;
54 }
55
56 static int
57 check_arg(char const *const *str_list, char const *arg)
58 {
59     while (*str_list)
60         if (!strcmp(arg, *str_list++))
61             return 1;
62     return 0;
63 }
64
65 static const char *const debug_args[] = {
66     "d",
67     "debug",
68     0,
69 };
70
71 static const char *const lang_args[] = {
72     "lang",
73     "language",
74     0,
75 };
76
77 static const char *const prefix_args[] = {
78     "p",
79     "prefix",
80     0,
81 };
82
83 static const char *const emit_args[] = {
84     "e",
85     "emit",
86     0,
87 };
88
89 static const char *const language_names[] = {
90     "C",
91     "K&R C",
92     "C++",
93     0,
94 };
95
96 static const char *const c_src_prolog[] = {
97     "#include <afsconfig.h>\n",
98     "#include <afs/param.h>\n",
99     "#include <afs/error_table.h>\n",
100     "static const char * const text[] = {\n",
101     0,
102 };
103
104 static const char *const krc_src_prolog[] = {
105     "#ifdef __STDC__\n",
106     "#define NOARGS void\n",
107     "#else\n",
108     "#define NOARGS\n",
109     "#define const\n",
110     "#endif\n\n",
111     "#include <afs/param.h>\n",
112     "#include <afs/error_table.h>\n",
113     "static const char * const text[] = {\n",
114     0,
115 };
116
117 static const char warning[] =
118     "/*\n * %s:\n * This file is automatically generated; please do not edit it.\n */\n";
119
120 static const char msf_warning[] =
121     "$ \n$ %s:\n$ This file is automatically generated; please do not edit it.\n$ \n$set 1\n";
122
123 /* pathnames */
124 char c_file[MAXPATHLEN];        /* output file */
125 char h_file[MAXPATHLEN];        /* output */
126 char msf_file[MAXPATHLEN];
127 char et_file[MAXPATHLEN];       /* full path to input file */
128
129 static void
130 usage(void)
131 {
132     fprintf(stderr,
133             "%s: usage: %s ERROR_TABLE [-debug] [-language LANG] [-h INCLUDE] [-p PREFIX] [-v VERSION] [-emit source|header]\n",
134             whoami, whoami);
135     exit(1);
136 }
137
138 static void
139 dup_err(char const *type, char const *one, char const *two)
140 {
141     fprintf(stderr, "%s: multiple %s specified: `%s' and `%s'\n", whoami,
142             type, one, two);
143     usage();
144 }
145
146 #include "AFS_component_version_number.c"
147
148 int
149 main(int argc, char **argv)
150 {
151     char *p, *ename;
152     char const *const *cpp;
153     int got_language = 0;
154     char *got_include = 0;
155     char *got_prefix = ".";
156     int got_emit = 0;
157     char lcname[6];
158
159 #ifdef  AFS_AIX32_ENV
160     /*
161      * The following signal action for AIX is necessary so that in case of a
162      * crash (i.e. core is generated) we can include the user's data section
163      * in the core dump. Unfortunately, by default, only a partial core is
164      * generated which, in many cases, isn't too useful.
165      */
166     struct sigaction nsa;
167
168     sigemptyset(&nsa.sa_mask);
169     nsa.sa_handler = SIG_DFL;
170     nsa.sa_flags = SA_FULLDUMP;
171     sigaction(SIGSEGV, &nsa, NULL);
172 #endif
173     /* argument parsing */
174     debug = 0;
175     filename = 0;
176     whoami = argv[0];
177     p = strrchr(whoami, '/');
178     if (p)
179         whoami = p + 1;
180     while (--argc) {
181         char *arg = *++argv;
182         if (arg[0] != '-') {
183             if (filename)
184                 dup_err("filenames", filename, arg);
185             filename = arg;
186         } else {
187             arg++;
188             if (check_arg(debug_args, arg))
189                 debug++;
190             else if (check_arg(lang_args, arg)) {
191                 got_language++;
192                 arg = *++argv;
193                 argc--;
194                 if (!arg)
195                     usage();
196                 if (language)
197                     dup_err("languanges", language_names[(int)language], arg);
198
199 #define check_lang(x,v) if (!strcasecmp(arg,x)) language = v
200                 check_lang("c", lang_C);
201                 check_lang("ansi_c", lang_C);
202                 check_lang("ansi-c", lang_C);
203                 check_lang("krc", lang_KRC);
204                 check_lang("kr_c", lang_KRC);
205                 check_lang("kr-c", lang_KRC);
206                 check_lang("k&r-c", lang_KRC);
207                 check_lang("k&r_c", lang_KRC);
208                 check_lang("c++", lang_CPP);
209                 check_lang("cplusplus", lang_CPP);
210                 check_lang("c-plus-plus", lang_CPP);
211 #undef check_lang
212
213                 if (!language) {
214                     fprintf(stderr, "%s: unknown language name `%s'\n",
215                             whoami, arg);
216                     fprintf(stderr, "\tpick one of: C K&R-C\n");
217                     exit(1);
218                 }
219             } else if (strcmp(arg, "h") == 0) {
220                 arg = *++argv;
221                 argc--;
222                 if (!arg)
223                     usage();
224                 got_include = arg;
225             } else if (check_arg(prefix_args, arg)) {
226                 arg = *++argv;
227                 argc--;
228                 if (!arg)
229                     usage();
230                 got_prefix = arg;
231             } else if (strcmp(arg, "v") == 0) {
232                 arg = *++argv;
233                 argc--;
234                 if (arg == NULL) {
235                     fprintf(stderr, "%s: -v option requires an argument\n",
236                             whoami);
237                     usage();
238                     exit(1);
239                 }
240                 version = atoi(arg);
241                 if (version != 1 && version != 2) {
242                     fprintf(stderr, "%s: unknown control argument -`%s'\n",
243                             whoami, arg);
244                     usage();
245                     exit(1);
246                 }
247                 if (version == 2)
248                     use_msf = 1;
249             } else if (check_arg(emit_args, arg)) {
250                 arg = *++argv;
251                 argc--;
252                 got_emit = 1;
253                 if (!strcasecmp(arg, "source")) {
254                     emit_source = 1;
255                 } else if (!strcasecmp(arg, "c")) {
256                     emit_source = 1;
257                 } else if (!strcasecmp(arg, "header")) {
258                     emit_header = 1;
259                 } else if (!strcasecmp(arg, "h")) {
260                     emit_header = 1;
261                 } else {
262                     fprintf(stderr, "%s: unknown emit argument - `%s'\n",
263                             whoami, arg);
264                     usage();
265                     exit(1);
266                 }
267             } else {
268                 fprintf(stderr, "%s: unknown control argument -`%s'\n",
269                         whoami, arg);
270                 usage();
271             }
272         }
273     }
274     if (!filename)
275         usage();
276     if (!got_language)
277         language = lang_C;
278     else if (language == lang_CPP) {
279         fprintf(stderr, "%s: Sorry, C++ support is not yet finished.\n",
280                 whoami);
281         exit(1);
282     }
283
284     if (!got_emit) {
285         emit_source = emit_header = 1; /* generate both by default */
286     }
287
288     p = strrchr(filename, '/');
289     if (p == NULL)
290         p = filename;
291     else
292         p++;
293     ename = xmalloc(strlen(p) + 5);
294     strcpy(ename, p);
295
296     /* Now, flush .et suffix if it exists.   */
297     p = strrchr(ename, '.');
298     if (p != NULL) {
299         if (strcmp(p, ".et") == 0)
300             *p = 0;
301     }
302
303     if (emit_source) {
304         if (use_msf) {
305             sprintf(msf_file, "%s.msf", ename);
306         } else {
307             sprintf(c_file, "%s.c", ename);
308         }
309     }
310     if (emit_header) {
311         if (got_include) {
312             sprintf(h_file, "%s.h", got_include);
313         } else {
314             sprintf(h_file, "%s.h", ename);
315         }
316     }
317     p = strrchr(filename, '.');
318     if (p == NULL) {
319         p = xmalloc(strlen(filename) + 4);
320         sprintf(p, "%s.et", filename);
321         filename = p;
322     }
323
324     sprintf(et_file, "%s/%s", got_prefix, filename);
325
326     yyin = fopen(et_file, "r");
327     if (!yyin) {
328         perror(et_file);
329         exit(1);
330     }
331
332     /* on NT, yyout is not initialized to stdout */
333     if (!yyout) {
334         yyout = stdout;
335     }
336
337     if (emit_header) {
338         hfile = fopen(h_file, "w");
339         if (hfile == NULL) {
340             perror(h_file);
341             exit(1);
342         }
343         fprintf(hfile, warning, h_file);
344     }
345     if (emit_header && got_include) {
346         char buffer[BUFSIZ];
347         char prolog_h_file[MAXPATHLEN];
348         FILE *prolog_hfile;
349         int count, written;
350
351         strcpy(prolog_h_file, got_prefix);
352         strcat(prolog_h_file, "/");
353         strcat(prolog_h_file, got_include);
354         strcat(prolog_h_file, ".p.h");
355         prolog_hfile = fopen(prolog_h_file, "r");
356         if (prolog_hfile) {
357             fprintf(stderr, "Including %s at beginning of %s file.\n",
358                     prolog_h_file, h_file);
359             fprintf(hfile, "/* Including %s at beginning of %s file. */\n\n",
360                     prolog_h_file, h_file);
361             do {
362                 count =
363                     fread(buffer, sizeof(char), sizeof(buffer), prolog_hfile);
364                 if (count == EOF) {
365                     perror(prolog_h_file);
366                     exit(1);
367                 }
368                 written = fwrite(buffer, sizeof(char), count, hfile);
369                 if (count != written) {
370                     perror(prolog_h_file);
371                     exit(1);
372                 }
373             } while (count > 0);
374             fprintf(hfile, "\n/* End of prolog file %s. */\n\n",
375                     prolog_h_file);
376         }
377     }
378
379     if (emit_source && use_msf) {
380         msfile = fopen(msf_file, "w");
381         if (msfile == NULL) {
382             perror(msf_file);
383             exit(1);
384         }
385         fprintf(msfile, msf_warning, msf_file);
386     } else if (emit_source) {
387         cfile = fopen(c_file, "w");
388         if (cfile == NULL) {
389             perror(c_file);
390             exit(1);
391         }
392         fprintf(cfile, warning, c_file);
393
394         /* prologue */
395         if (language == lang_C)
396             cpp = c_src_prolog;
397         else if (language == lang_KRC)
398             cpp = krc_src_prolog;
399         else
400             abort();
401         while (*cpp)
402             fputs(*cpp++, cfile);
403     }
404
405     /* parse it */
406     yyparse();
407     fclose(yyin);               /* bye bye input file */
408
409     if (!use_msf) {
410         if (cfile) {
411             fputs("    0\n};\n\n", cfile);
412             fprintf(cfile,
413                     "static const struct error_table et = { text, %ldL, %d };\n\n",
414                     (long int)table_number, current);
415             fputs("static struct et_list etlink = { 0, &et};\n\n", cfile);
416             fprintf(cfile, "void initialize_%s_error_table(void) {\n",
417                     table_name);
418             fputs("    afs_add_to_error_table(&etlink);\n", cfile);
419             fputs("}\n", cfile);
420             fclose(cfile);
421         }
422         if (hfile) {
423             fprintf(hfile, "extern void initialize_%s_error_table(void);\n",
424                     table_name);
425         }
426     } else {
427         if (hfile) {
428             fprintf(hfile, "#define initialize_%s_error_table(void)\n",
429                     table_name);
430         }
431     }
432
433     if (hfile) {
434         fprintf(hfile, "#define ERROR_TABLE_BASE_%s (%ldL)\n", table_name,
435                 (long int)table_number);
436         /* compatibility... */
437         fprintf(hfile, "\n/* for compatibility with older versions... */\n");
438         fprintf(hfile, "#define init_%s_err_tbl initialize_%s_error_table\n",
439                 table_name, table_name);
440         fprintf(hfile, "#define %s_err_base ERROR_TABLE_BASE_%s\n",
441                 table_name, table_name);
442         fprintf(hfile, "\n/* for compatibility with other users... */\n");
443         lcstring(lcname, table_name, sizeof(lcname));
444         fprintf(hfile, "#define ERROR_TABLE_BASE_%s (%ldL)\n", lcname,
445                 (long int)table_number);
446         fprintf(hfile, "#define init_%s_err_tbl initialize_%s_error_table\n",
447                 lcname, table_name);
448         fprintf(hfile,
449                 "#define initialize_%s_error_table initialize_%s_error_table\n",
450                 lcname, table_name);
451         fprintf(hfile, "#define %s_err_base ERROR_TABLE_BASE_%s\n", lcname,
452                 lcname);
453         fclose(hfile);          /* bye bye include file */
454     }
455     if (msfile)
456         fclose(msfile);
457     return 0;
458 }
459
460 void
461 yyerror(const char *s)
462 {
463     fputs(s, stderr);
464     fprintf(stderr, "\nLine number %d; last token was '%s'\n", yylineno,
465             current_token);
466 }