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