/* * mksyntax.c - construct shell syntax table for fast char attribute lookup. */ /* Copyright (C) 2000-2009,2012,2022-2024 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 . */ /* assume C90/POSIX-1992 compilation environment if cross-compiling */ #ifndef CROSS_COMPILING # include #else # include #endif #include #include #include #include #include #include "chartypes.h" #include "syntax.h" #ifndef errno extern int errno; #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(void) { fprintf (stderr, "%s: usage: %s [-d] [-o filename]\n", progname, progname); exit (2); } #ifdef INCLUDE_UNUSED static int getcflag (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 (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) { case '\a': xbuf[1] = 'a'; break; case '\v': xbuf[1] = 'v'; break; 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 (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 (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 (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 (void) { 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 (void) { /* 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 (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 (FILE *fp, int i) { fputs ("\t\t/* ", fp); fprintf (fp, "%s", cdesc(i)); fputs (" */", fp); } static void dump_lsyntax (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(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); }