compile_et: Don't overflow input file buffer
[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
121 static void
122 usage(void)
123 {
124     fprintf(stderr,
125             "%s: usage: %s ERROR_TABLE [-debug] [-language LANG] [-h INCLUDE] [-p PREFIX] [-v VERSION] [-emit source|header]\n",
126             whoami, whoami);
127     exit(1);
128 }
129
130 static void
131 dup_err(char const *type, char const *one, char const *two)
132 {
133     fprintf(stderr, "%s: multiple %s specified: `%s' and `%s'\n", whoami,
134             type, one, two);
135     usage();
136 }
137
138 #include "AFS_component_version_number.c"
139
140 int
141 main(int argc, char **argv)
142 {
143     char *p, *ename;
144     char *et_file;
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     if (asprintf(&et_file, "%s/%s", got_prefix, filename) < 0) {
318         fprintf(stderr, "Couldn't allocate memory for filename\n");
319         exit(1);
320     }
321
322     yyin = fopen(et_file, "r");
323     if (!yyin) {
324         perror(et_file);
325         exit(1);
326     }
327
328     free(et_file);
329
330     /* on NT, yyout is not initialized to stdout */
331     if (!yyout) {
332         yyout = stdout;
333     }
334
335     if (emit_header) {
336         hfile = fopen(h_file, "w");
337         if (hfile == NULL) {
338             perror(h_file);
339             exit(1);
340         }
341         fprintf(hfile, warning, h_file);
342     }
343     if (emit_header && got_include) {
344         char buffer[BUFSIZ];
345         char prolog_h_file[MAXPATHLEN];
346         FILE *prolog_hfile;
347         int count, written;
348
349         strcpy(prolog_h_file, got_prefix);
350         strcat(prolog_h_file, "/");
351         strcat(prolog_h_file, got_include);
352         strcat(prolog_h_file, ".p.h");
353         prolog_hfile = fopen(prolog_h_file, "r");
354         if (prolog_hfile) {
355             fprintf(stderr, "Including %s at beginning of %s file.\n",
356                     prolog_h_file, h_file);
357             fprintf(hfile, "/* Including %s at beginning of %s file. */\n\n",
358                     prolog_h_file, h_file);
359             do {
360                 count =
361                     fread(buffer, sizeof(char), sizeof(buffer), prolog_hfile);
362                 if (count == EOF) {
363                     perror(prolog_h_file);
364                     exit(1);
365                 }
366                 written = fwrite(buffer, sizeof(char), count, hfile);
367                 if (count != written) {
368                     perror(prolog_h_file);
369                     exit(1);
370                 }
371             } while (count > 0);
372             fprintf(hfile, "\n/* End of prolog file %s. */\n\n",
373                     prolog_h_file);
374         }
375     }
376
377     if (emit_source && use_msf) {
378         msfile = fopen(msf_file, "w");
379         if (msfile == NULL) {
380             perror(msf_file);
381             exit(1);
382         }
383         fprintf(msfile, msf_warning, msf_file);
384     } else if (emit_source) {
385         cfile = fopen(c_file, "w");
386         if (cfile == NULL) {
387             perror(c_file);
388             exit(1);
389         }
390         fprintf(cfile, warning, c_file);
391
392         /* prologue */
393         if (language == lang_C)
394             cpp = c_src_prolog;
395         else if (language == lang_KRC)
396             cpp = krc_src_prolog;
397         else
398             abort();
399         while (*cpp)
400             fputs(*cpp++, cfile);
401     }
402
403     /* parse it */
404     yyparse();
405     fclose(yyin);               /* bye bye input file */
406
407     if (!use_msf) {
408         if (cfile) {
409             fputs("    0\n};\n\n", cfile);
410             fprintf(cfile,
411                     "static const struct error_table et = { text, %ldL, %d };\n\n",
412                     (long int)table_number, current);
413             fputs("static struct et_list etlink = { 0, &et};\n\n", cfile);
414             fprintf(cfile, "void initialize_%s_error_table(void) {\n",
415                     table_name);
416             fputs("    afs_add_to_error_table(&etlink);\n", cfile);
417             fputs("}\n", cfile);
418             fclose(cfile);
419         }
420         if (hfile) {
421             fprintf(hfile, "extern void initialize_%s_error_table(void);\n",
422                     table_name);
423         }
424     } else {
425         if (hfile) {
426             fprintf(hfile, "#define initialize_%s_error_table(void)\n",
427                     table_name);
428         }
429     }
430
431     if (hfile) {
432         fprintf(hfile, "#define ERROR_TABLE_BASE_%s (%ldL)\n", table_name,
433                 (long int)table_number);
434         /* compatibility... */
435         fprintf(hfile, "\n/* for compatibility with older versions... */\n");
436         fprintf(hfile, "#define init_%s_err_tbl initialize_%s_error_table\n",
437                 table_name, table_name);
438         fprintf(hfile, "#define %s_err_base ERROR_TABLE_BASE_%s\n",
439                 table_name, table_name);
440         fprintf(hfile, "\n/* for compatibility with other users... */\n");
441         lcstring(lcname, table_name, sizeof(lcname));
442         fprintf(hfile, "#define ERROR_TABLE_BASE_%s (%ldL)\n", lcname,
443                 (long int)table_number);
444         fprintf(hfile, "#define init_%s_err_tbl initialize_%s_error_table\n",
445                 lcname, table_name);
446         fprintf(hfile,
447                 "#define initialize_%s_error_table initialize_%s_error_table\n",
448                 lcname, table_name);
449         fprintf(hfile, "#define %s_err_base ERROR_TABLE_BASE_%s\n", lcname,
450                 lcname);
451         fclose(hfile);          /* bye bye include file */
452     }
453     if (msfile)
454         fclose(msfile);
455     return 0;
456 }
457
458 void
459 yyerror(const char *s)
460 {
461     fputs(s, stderr);
462     fprintf(stderr, "\nLine number %d; last token was '%s'\n", yylineno,
463             current_token);
464 }