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