mirror of https://github.com/n-hys/bash.git
416 lines
7.2 KiB
C
416 lines
7.2 KiB
C
/*
|
|
* 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 */
|