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