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