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