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