diff options
Diffstat (limited to 'mksyntax.c')
-rw-r--r-- | mksyntax.c | 415 |
1 files changed, 415 insertions, 0 deletions
diff --git a/mksyntax.c b/mksyntax.c new file mode 100644 index 0000000..0385686 --- /dev/null +++ b/mksyntax.c @@ -0,0 +1,415 @@ +/* + * 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> +#if defined (HAVE_SYS_PARAM_H) +# 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 */ |