]>
Commit | Line | Data |
---|---|---|
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 */ |