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