| /* |
| * mksyntax.c - construct shell syntax table for fast char attribute lookup. |
| */ |
| |
| /* Copyright (C) 2000-2009 Free Software Foundation, Inc. |
| |
| This file is part of GNU Bash, the Bourne Again SHell. |
| |
| Bash is free software: you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation, either version 3 of the License, or |
| (at your option) any later version. |
| |
| Bash is distributed in the hope that it will be useful, |
| but WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| GNU General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with Bash. If not, see <http://www.gnu.org/licenses/>. |
| */ |
| |
| #include "config.h" |
| |
| #include <stdio.h> |
| #include "bashansi.h" |
| #include "chartypes.h" |
| #include <errno.h> |
| |
| #ifdef HAVE_UNISTD_H |
| # include <unistd.h> |
| #endif |
| |
| #include "syntax.h" |
| |
| extern int optind; |
| extern char *optarg; |
| |
| #ifndef errno |
| extern int errno; |
| #endif |
| |
| #ifndef HAVE_STRERROR |
| extern char *strerror(); |
| #endif |
| |
| struct wordflag { |
| int flag; |
| char *fstr; |
| } wordflags[] = { |
| { CWORD, "CWORD" }, |
| { CSHMETA, "CSHMETA" }, |
| { CSHBRK, "CSHBRK" }, |
| { CBACKQ, "CBACKQ" }, |
| { CQUOTE, "CQUOTE" }, |
| { CSPECL, "CSPECL" }, |
| { CEXP, "CEXP" }, |
| { CBSDQUOTE, "CBSDQUOTE" }, |
| { CBSHDOC, "CBSHDOC" }, |
| { CGLOB, "CGLOB" }, |
| { CXGLOB, "CXGLOB" }, |
| { CXQUOTE, "CXQUOTE" }, |
| { CSPECVAR, "CSPECVAR" }, |
| { CSUBSTOP, "CSUBSTOP" }, |
| { CBLANK, "CBLANK" }, |
| }; |
| |
| #define N_WFLAGS (sizeof (wordflags) / sizeof (wordflags[0])) |
| #define SYNSIZE 256 |
| |
| int lsyntax[SYNSIZE]; |
| int debug; |
| char *progname; |
| |
| char preamble[] = "\ |
| /*\n\ |
| * This file was generated by mksyntax. DO NOT EDIT.\n\ |
| */\n\ |
| \n"; |
| |
| char includes[] = "\ |
| #include \"config.h\"\n\ |
| #include \"stdc.h\"\n\ |
| #include \"syntax.h\"\n\n"; |
| |
| static void |
| usage() |
| { |
| fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname); |
| exit (2); |
| } |
| |
| #ifdef INCLUDE_UNUSED |
| static int |
| getcflag (s) |
| char *s; |
| { |
| int i; |
| |
| for (i = 0; i < N_WFLAGS; i++) |
| if (strcmp (s, wordflags[i].fstr) == 0) |
| return wordflags[i].flag; |
| return -1; |
| } |
| #endif |
| |
| static char * |
| cdesc (i) |
| int i; |
| { |
| static char xbuf[16]; |
| |
| if (i == ' ') |
| return "SPC"; |
| else if (ISPRINT (i)) |
| { |
| xbuf[0] = i; |
| xbuf[1] = '\0'; |
| return (xbuf); |
| } |
| else if (i == CTLESC) |
| return "CTLESC"; |
| else if (i == CTLNUL) |
| return "CTLNUL"; |
| else if (i == '\033') /* ASCII */ |
| return "ESC"; |
| |
| xbuf[0] = '\\'; |
| xbuf[2] = '\0'; |
| |
| switch (i) |
| { |
| #ifdef __STDC__ |
| case '\a': xbuf[1] = 'a'; break; |
| case '\v': xbuf[1] = 'v'; break; |
| #else |
| case '\007': xbuf[1] = 'a'; break; |
| case 0x0B: xbuf[1] = 'v'; break; |
| #endif |
| case '\b': xbuf[1] = 'b'; break; |
| case '\f': xbuf[1] = 'f'; break; |
| case '\n': xbuf[1] = 'n'; break; |
| case '\r': xbuf[1] = 'r'; break; |
| case '\t': xbuf[1] = 't'; break; |
| default: sprintf (xbuf, "%d", i); break; |
| } |
| |
| return xbuf; |
| } |
| |
| static char * |
| getcstr (f) |
| int f; |
| { |
| int i; |
| |
| for (i = 0; i < N_WFLAGS; i++) |
| if (f == wordflags[i].flag) |
| return (wordflags[i].fstr); |
| return ((char *)NULL); |
| } |
| |
| static void |
| addcstr (str, flag) |
| char *str; |
| int flag; |
| { |
| char *s, *fstr; |
| unsigned char uc; |
| |
| for (s = str; s && *s; s++) |
| { |
| uc = *s; |
| |
| if (debug) |
| { |
| fstr = getcstr (flag); |
| fprintf(stderr, "added %s for character %s\n", fstr, cdesc(uc)); |
| } |
| |
| lsyntax[uc] |= flag; |
| } |
| } |
| |
| static void |
| addcchar (c, flag) |
| unsigned char c; |
| int flag; |
| { |
| char *fstr; |
| |
| if (debug) |
| { |
| fstr = getcstr (flag); |
| fprintf (stderr, "added %s for character %s\n", fstr, cdesc(c)); |
| } |
| lsyntax[c] |= flag; |
| } |
| |
| static void |
| addblanks () |
| { |
| register int i; |
| unsigned char uc; |
| |
| for (i = 0; i < SYNSIZE; i++) |
| { |
| uc = i; |
| /* Since we don't call setlocale(), this defaults to the "C" locale, and |
| the default blank characters will be space and tab. */ |
| if (isblank (uc)) |
| lsyntax[uc] |= CBLANK; |
| } |
| } |
| |
| /* load up the correct flag values in lsyntax */ |
| static void |
| load_lsyntax () |
| { |
| /* shell metacharacters */ |
| addcstr (shell_meta_chars, CSHMETA); |
| |
| /* shell word break characters */ |
| addcstr (shell_break_chars, CSHBRK); |
| |
| addcchar ('`', CBACKQ); |
| |
| addcstr (shell_quote_chars, CQUOTE); |
| |
| addcchar (CTLESC, CSPECL); |
| addcchar (CTLNUL, CSPECL); |
| |
| addcstr (shell_exp_chars, CEXP); |
| |
| addcstr (slashify_in_quotes, CBSDQUOTE); |
| addcstr (slashify_in_here_document, CBSHDOC); |
| |
| addcstr (shell_glob_chars, CGLOB); |
| |
| #if defined (EXTENDED_GLOB) |
| addcstr (ext_glob_chars, CXGLOB); |
| #endif |
| |
| addcstr (shell_quote_chars, CXQUOTE); |
| addcchar ('\\', CXQUOTE); |
| |
| addcstr ("@*#?-$!", CSPECVAR); /* omits $0...$9 and $_ */ |
| |
| addcstr ("-=?+", CSUBSTOP); /* OP in ${paramOPword} */ |
| |
| addblanks (); |
| } |
| |
| static void |
| dump_lflags (fp, ind) |
| FILE *fp; |
| int ind; |
| { |
| int xflags, first, i; |
| |
| xflags = lsyntax[ind]; |
| first = 1; |
| |
| if (xflags == 0) |
| fputs (wordflags[0].fstr, fp); |
| else |
| { |
| for (i = 1; i < N_WFLAGS; i++) |
| if (xflags & wordflags[i].flag) |
| { |
| if (first) |
| first = 0; |
| else |
| putc ('|', fp); |
| fputs (wordflags[i].fstr, fp); |
| } |
| } |
| } |
| |
| static void |
| wcomment (fp, i) |
| FILE *fp; |
| int i; |
| { |
| fputs ("\t\t/* ", fp); |
| |
| fprintf (fp, "%s", cdesc(i)); |
| |
| fputs (" */", fp); |
| } |
| |
| static void |
| dump_lsyntax (fp) |
| FILE *fp; |
| { |
| int i; |
| |
| fprintf (fp, "int sh_syntabsiz = %d;\n", SYNSIZE); |
| fprintf (fp, "int sh_syntaxtab[%d] = {\n", SYNSIZE); |
| |
| for (i = 0; i < SYNSIZE; i++) |
| { |
| putc ('\t', fp); |
| dump_lflags (fp, i); |
| putc (',', fp); |
| wcomment (fp, i); |
| putc ('\n', fp); |
| } |
| |
| fprintf (fp, "};\n"); |
| } |
| |
| int |
| main(argc, argv) |
| int argc; |
| char **argv; |
| { |
| int opt, i; |
| char *filename; |
| FILE *fp; |
| |
| if ((progname = strrchr (argv[0], '/')) == 0) |
| progname = argv[0]; |
| else |
| progname++; |
| |
| filename = (char *)NULL; |
| debug = 0; |
| |
| while ((opt = getopt (argc, argv, "do:")) != EOF) |
| { |
| switch (opt) |
| { |
| case 'd': |
| debug = 1; |
| break; |
| case 'o': |
| filename = optarg; |
| break; |
| default: |
| usage(); |
| } |
| } |
| |
| argc -= optind; |
| argv += optind; |
| |
| if (filename) |
| { |
| fp = fopen (filename, "w"); |
| if (fp == 0) |
| { |
| fprintf (stderr, "%s: %s: cannot open: %s\n", progname, filename, strerror(errno)); |
| exit (1); |
| } |
| } |
| else |
| { |
| filename = "stdout"; |
| fp = stdout; |
| } |
| |
| |
| for (i = 0; i < SYNSIZE; i++) |
| lsyntax[i] = CWORD; |
| |
| load_lsyntax (); |
| |
| fprintf (fp, "%s\n", preamble); |
| fprintf (fp, "%s\n", includes); |
| |
| dump_lsyntax (fp); |
| |
| if (fp != stdout) |
| fclose (fp); |
| exit (0); |
| } |
| |
| |
| #if !defined (HAVE_STRERROR) |
| |
| #include <bashtypes.h> |
| #ifndef _MINIX |
| # include <sys/param.h> |
| #endif |
| |
| #if defined (HAVE_UNISTD_H) |
| # include <unistd.h> |
| #endif |
| |
| /* Return a string corresponding to the error number E. From |
| the ANSI C spec. */ |
| #if defined (strerror) |
| # undef strerror |
| #endif |
| |
| char * |
| strerror (e) |
| int e; |
| { |
| static char emsg[40]; |
| #if defined (HAVE_SYS_ERRLIST) |
| extern int sys_nerr; |
| extern char *sys_errlist[]; |
| |
| if (e > 0 && e < sys_nerr) |
| return (sys_errlist[e]); |
| else |
| #endif /* HAVE_SYS_ERRLIST */ |
| { |
| sprintf (emsg, "Unknown system error %d", e); |
| return (&emsg[0]); |
| } |
| } |
| #endif /* HAVE_STRERROR */ |