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