Bash-4.3 distribution sources and documentation
[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-2009 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
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation, either version 3 of the License, or
12    (at your option) any later version.
13
14    Bash is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18
19    You should have received a copy of the GNU General Public License
20    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
21 */
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         { CBLANK,       "CBLANK" },
66 };
67         
68 #define N_WFLAGS        (sizeof (wordflags) / sizeof (wordflags[0]))
69 #define SYNSIZE         256
70
71 int     lsyntax[SYNSIZE];
72 int     debug;
73 char    *progname;
74
75 char    preamble[] = "\
76 /*\n\
77  * This file was generated by mksyntax.  DO NOT EDIT.\n\
78  */\n\
79 \n";
80
81 char    includes[] = "\
82 #include \"config.h\"\n\
83 #include \"stdc.h\"\n\
84 #include \"syntax.h\"\n\n";
85
86 static void
87 usage()
88 {
89   fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname);
90   exit (2);
91 }
92
93 #ifdef INCLUDE_UNUSED
94 static int
95 getcflag (s)
96      char *s;
97 {
98   int i;
99
100   for (i = 0; i < N_WFLAGS; i++)
101     if (strcmp (s, wordflags[i].fstr) == 0)
102       return wordflags[i].flag;
103   return -1;
104 }
105 #endif
106
107 static char *
108 cdesc (i)
109      int i;
110 {
111   static char xbuf[16];
112
113   if (i == ' ')
114     return "SPC";
115   else if (ISPRINT (i))
116     {
117       xbuf[0] = i;
118       xbuf[1] = '\0';
119       return (xbuf);
120     }
121   else if (i == CTLESC)
122     return "CTLESC";
123   else if (i == CTLNUL)
124     return "CTLNUL";
125   else if (i == '\033')         /* ASCII */
126     return "ESC";
127
128   xbuf[0] = '\\';
129   xbuf[2] = '\0';
130     
131   switch (i)
132     {
133 #ifdef __STDC__
134     case '\a': xbuf[1] = 'a'; break;
135     case '\v': xbuf[1] = 'v'; break;
136 #else
137     case '\007': xbuf[1] = 'a'; break;
138     case 0x0B: xbuf[1] = 'v'; break;
139 #endif
140     case '\b': xbuf[1] = 'b'; break;
141     case '\f': xbuf[1] = 'f'; break;
142     case '\n': xbuf[1] = 'n'; break;
143     case '\r': xbuf[1] = 'r'; break;
144     case '\t': xbuf[1] = 't'; break;
145     default: sprintf (xbuf, "%d", i); break;
146     }
147
148   return xbuf;  
149 }
150
151 static char *
152 getcstr (f)
153      int f;
154 {
155   int i;
156
157   for (i = 0; i < N_WFLAGS; i++)
158     if (f == wordflags[i].flag)
159       return (wordflags[i].fstr);
160   return ((char *)NULL);
161 }
162
163 static void
164 addcstr (str, flag)
165      char *str;
166      int flag;
167 {
168   char *s, *fstr;
169   unsigned char uc;
170
171   for (s = str; s && *s; s++)
172     {
173       uc = *s;
174
175       if (debug)
176         {
177           fstr = getcstr (flag);
178           fprintf(stderr, "added %s for character %s\n", fstr, cdesc(uc));
179         }
180         
181       lsyntax[uc] |= flag;
182     }
183 }
184
185 static void
186 addcchar (c, flag)
187      unsigned char c;
188      int flag;
189 {
190   char *fstr;
191
192   if (debug)
193     {
194       fstr = getcstr (flag);
195       fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c));
196     }
197   lsyntax[c] |= flag;
198 }
199
200 static void
201 addblanks ()
202 {
203   register int i;
204   unsigned char uc;
205
206   for (i = 0; i < SYNSIZE; i++)
207     {
208       uc = i;
209       /* Since we don't call setlocale(), this defaults to the "C" locale, and
210          the default blank characters will be space and tab. */
211       if (isblank (uc))
212         lsyntax[uc] |= CBLANK;
213     }
214 }
215
216 /* load up the correct flag values in lsyntax */
217 static void
218 load_lsyntax ()
219 {
220   /* shell metacharacters */
221   addcstr (shell_meta_chars, CSHMETA);
222
223   /* shell word break characters */
224   addcstr (shell_break_chars, CSHBRK);
225
226   addcchar ('`', CBACKQ);
227
228   addcstr (shell_quote_chars, CQUOTE);
229
230   addcchar (CTLESC, CSPECL);
231   addcchar (CTLNUL, CSPECL);
232
233   addcstr (shell_exp_chars, CEXP);
234
235   addcstr (slashify_in_quotes, CBSDQUOTE);
236   addcstr (slashify_in_here_document, CBSHDOC);
237
238   addcstr (shell_glob_chars, CGLOB);
239
240 #if defined (EXTENDED_GLOB)
241   addcstr (ext_glob_chars, CXGLOB);
242 #endif
243
244   addcstr (shell_quote_chars, CXQUOTE);
245   addcchar ('\\', CXQUOTE);
246
247   addcstr ("@*#?-$!", CSPECVAR);        /* omits $0...$9 and $_ */
248
249   addcstr ("-=?+", CSUBSTOP);           /* OP in ${paramOPword} */
250
251   addblanks ();
252 }
253
254 static void
255 dump_lflags (fp, ind)
256      FILE *fp;
257      int ind;
258 {
259   int xflags, first, i;
260
261   xflags = lsyntax[ind];
262   first = 1;
263
264   if (xflags == 0)
265     fputs (wordflags[0].fstr, fp);
266   else
267     {
268       for (i = 1; i < N_WFLAGS; i++)
269         if (xflags & wordflags[i].flag)
270           {
271             if (first)
272               first = 0;
273             else
274               putc ('|', fp);
275             fputs (wordflags[i].fstr, fp);
276           }
277     }
278 }
279
280 static void
281 wcomment (fp, i)
282      FILE *fp;
283      int i;
284 {
285   fputs ("\t\t/* ", fp);
286
287   fprintf (fp, "%s", cdesc(i));
288       
289   fputs (" */", fp);
290 }
291
292 static void
293 dump_lsyntax (fp)
294      FILE *fp;
295 {
296   int i;
297
298   fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE);
299   fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE);
300
301   for (i = 0; i < SYNSIZE; i++)
302     {
303       putc ('\t', fp);
304       dump_lflags (fp, i);
305       putc (',', fp);
306       wcomment (fp, i);
307       putc ('\n', fp);
308     }
309
310   fprintf (fp, "};\n");
311 }
312
313 int
314 main(argc, argv)
315      int argc;
316      char **argv;
317 {
318   int opt, i;
319   char *filename;
320   FILE *fp;
321
322   if ((progname = strrchr (argv[0], '/')) == 0)
323     progname = argv[0];
324   else
325     progname++;
326
327   filename = (char *)NULL;
328   debug = 0;
329
330   while ((opt = getopt (argc, argv, "do:")) != EOF)
331     {
332       switch (opt)
333         {
334         case 'd':
335           debug = 1;
336           break;
337         case 'o':
338           filename = optarg;
339           break;
340         default:
341           usage();
342         }
343     }
344
345   argc -= optind;
346   argv += optind;
347
348   if (filename)
349     {
350       fp = fopen (filename, "w");
351       if (fp == 0)
352         {
353           fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno));
354           exit (1);
355         }
356     }
357   else
358     {
359       filename = "stdout";
360       fp = stdout;
361     }
362
363
364   for (i = 0; i < SYNSIZE; i++)
365     lsyntax[i] = CWORD;
366
367   load_lsyntax ();
368
369   fprintf (fp, "%s\n", preamble);
370   fprintf (fp, "%s\n", includes);
371
372   dump_lsyntax (fp);
373
374   if (fp != stdout)
375     fclose (fp);
376   exit (0);
377 }
378
379
380 #if !defined (HAVE_STRERROR)
381
382 #include <bashtypes.h>
383 #if defined (HAVE_SYS_PARAM_H)
384 #  include <sys/param.h>
385 #endif
386
387 #if defined (HAVE_UNISTD_H)
388 #  include <unistd.h>
389 #endif
390
391 /* Return a string corresponding to the error number E.  From
392    the ANSI C spec. */
393 #if defined (strerror)
394 #  undef strerror
395 #endif
396
397 char *
398 strerror (e)
399      int e;
400 {
401   static char emsg[40];
402 #if defined (HAVE_SYS_ERRLIST)
403   extern int sys_nerr;
404   extern char *sys_errlist[];
405
406   if (e > 0 && e < sys_nerr)
407     return (sys_errlist[e]);
408   else
409 #endif /* HAVE_SYS_ERRLIST */
410     {
411       sprintf (emsg, "Unknown system error %d", e);
412       return (&emsg[0]);
413     }
414 }
415 #endif /* HAVE_STRERROR */