summaryrefslogtreecommitdiffstats
path: root/mksyntax.c
diff options
context:
space:
mode:
Diffstat (limited to 'mksyntax.c')
-rw-r--r--mksyntax.c415
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 */