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