Imported from ../bash-2.05.tar.gz.
[platform/upstream/bash.git] / mksyntax.c
1 /*
2  * mksyntax.c - construct shell syntax table for fast char attribute lookup.
3  */
4
5 /* Copyright (C) 2000 Free Software Foundation, Inc.
6
7    This file is part of GNU Bash, the Bourne Again SHell.
8
9    Bash is free software; you can redistribute it and/or modify it under
10    the terms of the GNU General Public License as published by the Free
11    Software Foundation; either version 2, or (at your option) any later
12    version.
13
14    Bash is distributed in the hope that it will be useful, but WITHOUT ANY
15    WARRANTY; without even the implied warranty of MERCHANTABILITY or
16    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
17    for more details.
18
19    You should have received a copy of the GNU General Public License along
20    with Bash; see the file COPYING.  If not, write to the Free Software
21    Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
22
23 #include "config.h"
24 #include <stdio.h>
25 #include "bashansi.h"
26 #include <ctype.h>
27 #include <errno.h>
28
29 #include "syntax.h"
30
31 extern int optind;
32 extern char *optarg;
33
34 #ifndef errno
35 extern int errno;
36 #endif
37
38 #ifndef HAVE_STRERROR
39 extern char *strerror();
40 #endif
41
42 struct wordflag {
43         int     flag;
44         char    *fstr;
45 } wordflags[] = {
46         { CWORD,        "CWORD" },
47         { CSHMETA,      "CSHMETA" },
48         { CSHBRK,       "CSHBRK" },
49         { CBACKQ,       "CBACKQ" },
50         { CQUOTE,       "CQUOTE" },
51         { CSPECL,       "CSPECL" },
52         { CEXP,         "CEXP" },
53         { CBSDQUOTE,    "CBSDQUOTE" },
54         { CBSHDOC,      "CBSHDOC" },
55         { CGLOB,        "CGLOB" },
56         { CXGLOB,       "CXGLOB" },
57         { CXQUOTE,      "CXQUOTE" },
58         { CSPECVAR,     "CSPECVAR" }
59 };
60         
61 #define N_WFLAGS        (sizeof (wordflags) / sizeof (wordflags[0]))
62 #define SYNSIZE         256
63
64 int     lsyntax[SYNSIZE];
65 int     debug;
66 char    *progname;
67
68 char    preamble[] = "\
69 /*\n\
70  * This file was generated by mksyntax.  DO NOT EDIT.\n\
71  */\n\
72 \n";
73
74 char    includes[] = "\
75 #include \"stdc.h\"\n\
76 #include \"syntax.h\"\n\n";
77
78 static void
79 usage()
80 {
81   fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname);
82   exit (2);
83 }
84
85 static int
86 getcflag (s)
87      char *s;
88 {
89   int i;
90
91   for (i = 0; i < N_WFLAGS; i++)
92     if (strcmp (s, wordflags[i].fstr) == 0)
93       return wordflags[i].flag;
94   return -1;
95 }
96
97 static char *
98 cdesc (i)
99      int i;
100 {
101   static char xbuf[16];
102
103   if (i == ' ')
104     return "SPC";
105   else if (isprint (i))
106     {
107       xbuf[0] = i;
108       xbuf[1] = '\0';
109       return (xbuf);
110     }
111   else if (i == CTLESC)
112     return "CTLESC";
113   else if (i == CTLNUL)
114     return "CTLNUL";
115   else if (i == '\033')         /* ASCII */
116     return "ESC";
117
118   xbuf[0] = '\\';
119   xbuf[2] = '\0';
120     
121   switch (i)
122     {
123     case '\a': xbuf[1] = 'a'; break;
124     case '\v': xbuf[1] = 'v'; break;
125     case '\b': xbuf[1] = 'b'; break;
126     case '\f': xbuf[1] = 'f'; break;
127     case '\n': xbuf[1] = 'n'; break;
128     case '\r': xbuf[1] = 'r'; break;
129     case '\t': xbuf[1] = 't'; break;
130     default: sprintf (xbuf, "%d", i); break;
131     }
132
133   return xbuf;  
134 }
135
136 static char *
137 getcstr (f)
138      int f;
139 {
140   int i;
141
142   for (i = 0; i < N_WFLAGS; i++)
143     if (f == wordflags[i].flag)
144       return (wordflags[i].fstr);
145   return ((char *)NULL);
146 }
147
148 static void
149 addcstr (str, flag)
150      char *str;
151      int flag;
152 {
153   unsigned char *s;
154   char *fstr;
155
156   for (s = (unsigned char *)str; s && *s; s++)
157     {
158       if (debug)
159         {
160           fstr = getcstr (flag);
161           fprintf(stderr, "added %s for character %s\n", fstr, cdesc(*s));
162         }
163         
164       lsyntax[*s] |= flag;
165     }
166 }
167
168 static void
169 addcchar (c, flag)
170      unsigned char c;
171      int flag;
172 {
173   char *fstr;
174
175   if (debug)
176     {
177       fstr = getcstr (flag);
178       fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c));
179     }
180   lsyntax[c] |= flag;
181 }
182
183 /* load up the correct flag values in lsyntax */
184 static void
185 load_lsyntax ()
186 {
187   /* shell metacharacters */
188   addcstr (shell_meta_chars, CSHMETA);
189
190   /* shell word break characters */
191   addcstr (shell_break_chars, CSHBRK);
192
193   addcchar ('`', CBACKQ);
194
195   addcstr (shell_quote_chars, CQUOTE);
196
197   addcchar (CTLESC, CSPECL);
198   addcchar (CTLNUL, CSPECL);
199
200   addcstr (shell_exp_chars, CEXP);
201
202   addcstr (slashify_in_quotes, CBSDQUOTE);
203   addcstr (slashify_in_here_document, CBSHDOC);
204
205   addcstr (shell_glob_chars, CGLOB);
206
207 #if defined (EXTENDED_GLOB)
208   addcstr (ext_glob_chars, CXGLOB);
209 #endif
210
211   addcstr (shell_quote_chars, CXQUOTE);
212   addcchar ('\\', CXQUOTE);
213
214   addcstr ("@*#?-$!", CSPECVAR);        /* omits $0...$9 and $_ */
215 }
216
217 static void
218 dump_lflags (fp, ind)
219      FILE *fp;
220      int ind;
221 {
222   int xflags, first, i;
223
224   xflags = lsyntax[ind];
225   first = 1;
226
227   if (xflags == 0)
228     fputs (wordflags[0].fstr, fp);
229   else
230     {
231       for (i = 1; i < N_WFLAGS; i++)
232         if (xflags & wordflags[i].flag)
233           {
234             if (first)
235               first = 0;
236             else
237               putc ('|', fp);
238             fputs (wordflags[i].fstr, fp);
239           }
240     }
241 }
242
243 static void
244 wcomment (fp, i)
245      FILE *fp;
246      int i;
247 {
248   fputs ("\t\t/* ", fp);
249
250   fprintf (fp, "%s", cdesc(i));
251       
252   fputs (" */", fp);
253 }
254
255 static void
256 dump_lsyntax (fp)
257      FILE *fp;
258 {
259   int i, cflag;
260   char *cstr;
261
262   fprintf (fp, "const int sh_syntaxtab[%d] = {\n", SYNSIZE);
263
264   for (i = 0; i < SYNSIZE; i++)
265     {
266       putc ('\t', fp);
267       dump_lflags (fp, i);
268       putc (',', fp);
269       wcomment (fp, i);
270       putc ('\n', fp);
271     }
272
273   fprintf (fp, "};\n");
274 }
275
276 main(argc, argv)
277      int argc;
278      char **argv;
279 {
280   int opt, i;
281   char *filename;
282   FILE *fp;
283
284   if ((progname = strrchr (argv[0], '/')) == 0)
285     progname = argv[0];
286   else
287     progname++;
288
289   filename = (char *)NULL;
290   debug = 0;
291
292   while ((opt = getopt (argc, argv, "do:")) != EOF)
293     {
294       switch (opt)
295         {
296         case 'd':
297           debug = 1;
298           break;
299         case 'o':
300           filename = optarg;
301           break;
302         default:
303           usage();
304         }
305     }
306
307   argc -= optind;
308   argv += optind;
309
310   if (filename)
311     {
312       fp = fopen (filename, "w");
313       if (fp == 0)
314         {
315           fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno));
316           exit (1);
317         }
318     }
319   else
320     {
321       filename = "stdout";
322       fp = stdout;
323     }
324
325
326   for (i = 0; i < SYNSIZE; i++)
327     lsyntax[i] = CWORD;
328
329   load_lsyntax ();
330
331   fprintf (fp, "%s\n", preamble);
332   fprintf (fp, "%s\n", includes);
333
334   dump_lsyntax (fp);
335
336   if (fp != stdout)
337     fclose (fp);
338   exit (0);
339 }
340
341
342 #if !defined (HAVE_STRERROR)
343
344 #include <bashtypes.h>
345 #ifndef _MINIX
346 #  include <sys/param.h>
347 #endif
348
349 #if defined (HAVE_UNISTD_H)
350 #  include <unistd.h>
351 #endif
352
353 /* Return a string corresponding to the error number E.  From
354    the ANSI C spec. */
355 #if defined (strerror)
356 #  undef strerror
357 #endif
358
359 char *
360 strerror (e)
361      int e;
362 {
363   static char emsg[40];
364 #if defined (HAVE_SYS_ERRLIST)
365   extern int sys_nerr;
366   extern char *sys_errlist[];
367
368   if (e > 0 && e < sys_nerr)
369     return (sys_errlist[e]);
370   else
371 #endif /* HAVE_SYS_ERRLIST */
372     {
373       sprintf (emsg, "Unknown system error %d", e);
374       return (&emsg[0]);
375     }
376 }
377 #endif /* HAVE_STRERROR */