Line data Source code
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 0 : usage()
88 : {
89 0 : fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname);
90 0 : 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 256 : cdesc (i)
109 : int i;
110 : {
111 256 : static char xbuf[16];
112 :
113 256 : if (i == ' ')
114 : return "SPC";
115 255 : else if (ISPRINT (i))
116 : {
117 94 : xbuf[0] = i;
118 94 : xbuf[1] = '\0';
119 94 : return (xbuf);
120 : }
121 161 : else if (i == CTLESC)
122 : return "CTLESC";
123 160 : else if (i == CTLNUL)
124 : return "CTLNUL";
125 159 : else if (i == '\033') /* ASCII */
126 : return "ESC";
127 :
128 158 : xbuf[0] = '\\';
129 158 : xbuf[2] = '\0';
130 :
131 158 : switch (i)
132 : {
133 : #ifdef __STDC__
134 1 : case '\a': xbuf[1] = 'a'; break;
135 1 : 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 1 : case '\b': xbuf[1] = 'b'; break;
141 1 : case '\f': xbuf[1] = 'f'; break;
142 1 : case '\n': xbuf[1] = 'n'; break;
143 1 : case '\r': xbuf[1] = 'r'; break;
144 1 : case '\t': xbuf[1] = 't'; break;
145 151 : 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 0 : for (i = 0; i < N_WFLAGS; i++)
158 0 : if (f == wordflags[i].flag)
159 0 : return (wordflags[i].fstr);
160 : return ((char *)NULL);
161 : }
162 :
163 : static void
164 11 : addcstr (str, flag)
165 : char *str;
166 : int flag;
167 : {
168 11 : char *s, *fstr;
169 11 : unsigned char uc;
170 :
171 66 : for (s = str; s && *s; s++)
172 : {
173 55 : uc = *s;
174 :
175 55 : if (debug)
176 : {
177 0 : fstr = getcstr (flag);
178 0 : fprintf(stderr, "added %s for character %s\n", fstr, cdesc(uc));
179 : }
180 :
181 55 : lsyntax[uc] |= flag;
182 : }
183 11 : }
184 :
185 : static void
186 4 : addcchar (c, flag)
187 : unsigned char c;
188 : int flag;
189 : {
190 4 : char *fstr;
191 :
192 4 : if (debug)
193 : {
194 0 : fstr = getcstr (flag);
195 0 : fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c));
196 : }
197 4 : lsyntax[c] |= flag;
198 4 : }
199 :
200 : static void
201 1 : addblanks ()
202 : {
203 1 : register int i;
204 1 : unsigned char uc;
205 :
206 257 : for (i = 0; i < SYNSIZE; i++)
207 : {
208 256 : 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 256 : if (isblank (uc))
212 2 : lsyntax[uc] |= CBLANK;
213 : }
214 1 : }
215 :
216 : /* load up the correct flag values in lsyntax */
217 : static void
218 1 : load_lsyntax ()
219 : {
220 : /* shell metacharacters */
221 1 : addcstr (shell_meta_chars, CSHMETA);
222 :
223 : /* shell word break characters */
224 1 : addcstr (shell_break_chars, CSHBRK);
225 :
226 1 : addcchar ('`', CBACKQ);
227 :
228 1 : addcstr (shell_quote_chars, CQUOTE);
229 :
230 1 : addcchar (CTLESC, CSPECL);
231 1 : addcchar (CTLNUL, CSPECL);
232 :
233 1 : addcstr (shell_exp_chars, CEXP);
234 :
235 1 : addcstr (slashify_in_quotes, CBSDQUOTE);
236 1 : addcstr (slashify_in_here_document, CBSHDOC);
237 :
238 1 : addcstr (shell_glob_chars, CGLOB);
239 :
240 : #if defined (EXTENDED_GLOB)
241 1 : addcstr (ext_glob_chars, CXGLOB);
242 : #endif
243 :
244 1 : addcstr (shell_quote_chars, CXQUOTE);
245 1 : addcchar ('\\', CXQUOTE);
246 :
247 1 : addcstr ("@*#?-$!", CSPECVAR); /* omits $0...$9 and $_ */
248 :
249 1 : addcstr ("-=?+", CSUBSTOP); /* OP in ${paramOPword} */
250 :
251 1 : addblanks ();
252 1 : }
253 :
254 : static void
255 256 : dump_lflags (fp, ind)
256 : FILE *fp;
257 : int ind;
258 : {
259 256 : int xflags, first, i;
260 :
261 256 : xflags = lsyntax[ind];
262 256 : first = 1;
263 :
264 256 : if (xflags == 0)
265 228 : fputs (wordflags[0].fstr, fp);
266 : else
267 : {
268 420 : for (i = 1; i < N_WFLAGS; i++)
269 392 : if (xflags & wordflags[i].flag)
270 : {
271 61 : if (first)
272 : first = 0;
273 : else
274 33 : putc ('|', fp);
275 61 : fputs (wordflags[i].fstr, fp);
276 : }
277 : }
278 256 : }
279 :
280 : static void
281 256 : wcomment (fp, i)
282 : FILE *fp;
283 : int i;
284 : {
285 256 : fputs ("\t\t/* ", fp);
286 :
287 256 : fprintf (fp, "%s", cdesc(i));
288 :
289 256 : fputs (" */", fp);
290 256 : }
291 :
292 : static void
293 1 : dump_lsyntax (fp)
294 : FILE *fp;
295 : {
296 1 : int i;
297 :
298 1 : fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE);
299 1 : fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE);
300 :
301 257 : for (i = 0; i < SYNSIZE; i++)
302 : {
303 256 : putc ('\t', fp);
304 256 : dump_lflags (fp, i);
305 256 : putc (',', fp);
306 256 : wcomment (fp, i);
307 256 : putc ('\n', fp);
308 : }
309 :
310 1 : fprintf (fp, "};\n");
311 1 : }
312 :
313 : int
314 1 : main(argc, argv)
315 : int argc;
316 : char **argv;
317 : {
318 1 : int opt, i;
319 1 : char *filename;
320 1 : FILE *fp;
321 :
322 1 : if ((progname = strrchr (argv[0], '/')) == 0)
323 0 : progname = argv[0];
324 : else
325 1 : progname++;
326 :
327 1 : filename = (char *)NULL;
328 1 : debug = 0;
329 :
330 2 : while ((opt = getopt (argc, argv, "do:")) != EOF)
331 : {
332 1 : switch (opt)
333 : {
334 0 : case 'd':
335 0 : debug = 1;
336 0 : break;
337 1 : case 'o':
338 1 : filename = optarg;
339 1 : break;
340 0 : default:
341 0 : usage();
342 : }
343 : }
344 :
345 1 : argc -= optind;
346 1 : argv += optind;
347 :
348 1 : if (filename)
349 : {
350 1 : fp = fopen (filename, "w");
351 1 : if (fp == 0)
352 : {
353 0 : fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno));
354 0 : exit (1);
355 : }
356 : }
357 : else
358 : {
359 0 : filename = "stdout";
360 0 : fp = stdout;
361 : }
362 :
363 :
364 257 : for (i = 0; i < SYNSIZE; i++)
365 256 : lsyntax[i] = CWORD;
366 :
367 1 : load_lsyntax ();
368 :
369 1 : fprintf (fp, "%s\n", preamble);
370 1 : fprintf (fp, "%s\n", includes);
371 :
372 1 : dump_lsyntax (fp);
373 :
374 1 : if (fp != stdout)
375 1 : fclose (fp);
376 1 : 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 */
|