Revamp aliases - as dumb an idea as they are, if we're going

to have them, they should work as documented, not cause core
dumps, reference after free, incorrect replacements, failing
to implement alias after alias, ...

The big comment that ended:
	  This is a good idea ------- ***NOT***
and the hack it was describing are gone.

Note that most of this was from original CVS version 1.1
code (ie: came from the original import, even before 4.4-Lite
was merged.   That is, May 1994.  And no-one in 24.5 years
noticed (or at least complained about)  all the bugs (or at
least, most of them)).

With these changes, aliases ought to work (if you can call it
that) as they are expected to by POSIX.   Now if only we could
get POSIX to delete them (or make them optional)...

Changes partly inspired by similar changes made by FreeBSD,
(as was the previous change to alias.c, forgot ack in commit
log for that one, apologies) but done a little differently,
and perhaps with a slightly better outcome.
This commit is contained in:
kre 2018-12-03 06:40:26 +00:00
parent 1fdf28ef1f
commit 021ba5091c
8 changed files with 200 additions and 167 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: alias.c,v 1.19 2018/12/02 10:27:58 kre Exp $ */
/* $NetBSD: alias.c,v 1.20 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)alias.c 8.3 (Berkeley) 5/4/95";
#else
__RCSID("$NetBSD: alias.c,v 1.19 2018/12/02 10:27:58 kre Exp $");
__RCSID("$NetBSD: alias.c,v 1.20 2018/12/03 06:40:26 kre Exp $");
#endif
#endif /* not lint */
@ -61,7 +61,9 @@ STATIC void setalias(char *, char *);
STATIC int by_name(const void *, const void *);
STATIC void list_aliases(void);
STATIC int unalias(char *);
STATIC struct alias **freealias(struct alias **, int);
STATIC struct alias **hashalias(const char *);
STATIC size_t countaliases(void);
STATIC
void
@ -76,97 +78,80 @@ setalias(char *name, char *val)
ap = ckmalloc(sizeof (struct alias));
ap->name = savestr(name);
ap->flag = 0;
/*
* XXX - HACK: in order that the parser will not finish reading the
* alias value off the input before processing the next alias, we
* dummy up an extra space at the end of the alias. This is a crock
* and should be re-thought. The idea (if you feel inclined to help)
* is to avoid alias recursions. The mechanism used is: when
* expanding an alias, the value of the alias is pushed back on the
* input as a string and a pointer to the alias is stored with the
* string. The alias is marked as being in use. When the input
* routine finishes reading the string, it markes the alias not
* in use. The problem is synchronization with the parser. Since
* it reads ahead, the alias is marked not in use before the
* resulting token(s) is next checked for further alias sub. The
* H A C K is that we add a little fluff after the alias value
* so that the string will not be exhausted. This is a good
* idea ------- ***NOT***
*/
#ifdef notyet
ap->val = savestr(val);
#else /* hack */
{
int len = strlen(val);
ap->val = ckmalloc(len + 2);
memcpy(ap->val, val, len);
ap->val[len] = ' '; /* fluff */
ap->val[len+1] = '\0';
}
#endif
ap->next = *app;
*app = ap;
INTON;
}
STATIC struct alias **
freealias(struct alias **app, int force)
{
struct alias *ap = *app;
if (ap == NULL)
return app;
/*
* if the alias is currently in use (i.e. its
* buffer is being used by the input routine) we
* just null out the name instead of discarding it.
* If we encounter it later, when it is idle,
* we will finish freeing it then.
*
* Unless we want to simply free everything (INIT)
*/
if (ap->flag & ALIASINUSE && !force) {
*ap->name = '\0';
return &ap->next;
}
INTOFF;
*app = ap->next;
ckfree(ap->name);
ckfree(ap->val);
ckfree(ap);
INTON;
return app;
}
STATIC int
unalias(char *name)
{
struct alias *ap, **app;
app = hashalias(name);
for (ap = *app; ap; app = &(ap->next), ap = ap->next) {
while ((ap = *app) != NULL) {
if (equal(name, ap->name)) {
/*
* if the alias is currently in use (i.e. its
* buffer is being used by the input routine) we
* just null out the name instead of freeing it.
* We could clear it out later, but this situation
* is so rare that it hardly seems worth it.
*/
if (ap->flag & ALIASINUSE)
*ap->name = '\0';
else {
INTOFF;
*app = ap->next;
ckfree(ap->name);
ckfree(ap->val);
ckfree(ap);
INTON;
}
(void) freealias(app, 0);
return 0;
}
app = &ap->next;
}
return 1;
}
#ifdef mkinit
MKINIT void rmaliases(void);
MKINIT void rmaliases(int);
SHELLPROC {
rmaliases();
rmaliases(1);
}
#endif
void
rmaliases(void)
rmaliases(int force)
{
struct alias *ap, *tmp;
struct alias **app;
int i;
INTOFF;
for (i = 0; i < ATABSIZE; i++) {
ap = atab[i];
atab[i] = NULL;
while (ap) {
ckfree(ap->name);
ckfree(ap->val);
tmp = ap;
ap = ap->next;
ckfree(tmp);
}
app = &atab[i];
while (*app)
app = freealias(app, force);
}
INTON;
}
@ -176,12 +161,13 @@ lookupalias(const char *name, int check)
{
struct alias *ap = *hashalias(name);
for (; ap; ap = ap->next) {
while (ap != NULL) {
if (equal(name, ap->name)) {
if (check && (ap->flag & ALIASINUSE))
return NULL;
return ap;
}
ap = ap->next;
}
return NULL;
@ -214,12 +200,8 @@ list_aliases(void)
const struct alias **aliases;
const struct alias *ap;
n = 0;
for (i = 0; i < ATABSIZE; i++)
for (ap = atab[i]; ap != NULL; ap = ap->next)
if (ap->name[0] != '\0')
n++;
INTOFF;
n = countaliases();
aliases = ckmalloc(n * sizeof aliases[0]);
j = 0;
@ -227,6 +209,9 @@ list_aliases(void)
for (ap = atab[i]; ap != NULL; ap = ap->next)
if (ap->name[0] != '\0')
aliases[j++] = ap;
if (j != n)
error("Alias count botch");
INTON;
qsort(aliases, n, sizeof aliases[0], by_name);
@ -239,6 +224,34 @@ list_aliases(void)
ckfree(aliases);
}
/*
* Count how many aliases are defined (skipping any
* that have been deleted, but don't know it yet).
* Use this opportunity to clean up any of those
* zombies that are no longer needed.
*/
STATIC size_t
countaliases(void)
{
struct alias *ap, **app;
size_t n;
int i;
n = 0;
for (i = 0; i < ATABSIZE; i++)
for (app = &atab[i]; (ap = *app) != NULL;) {
if (ap->name[0] != '\0')
n++;
else {
app = freealias(app, 0);
continue;
}
app = &ap->next;
}
return n;
}
int
aliascmd(int argc, char **argv)
{
@ -277,12 +290,14 @@ unaliascmd(int argc, char **argv)
while ((i = nextopt("a")) != '\0') {
if (i == 'a') {
rmaliases();
rmaliases(0);
return 0;
}
}
(void)countaliases(); /* delete any dead ones */
for (i = 0; *argptr; argptr++)
i = unalias(*argptr);
i |= unalias(*argptr);
return i;
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: alias.h,v 1.8 2014/06/18 18:17:30 christos Exp $ */
/* $NetBSD: alias.h,v 1.9 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1993
@ -45,4 +45,4 @@ struct alias {
struct alias *lookupalias(const char *, int);
const char *alias_text(void *, const char *);
void rmaliases(void);
void rmaliases(int);

View File

@ -1,4 +1,4 @@
/* $NetBSD: eval.c,v 1.165 2018/11/30 23:22:45 kre Exp $ */
/* $NetBSD: eval.c,v 1.166 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)eval.c 8.9 (Berkeley) 6/8/95";
#else
__RCSID("$NetBSD: eval.c,v 1.165 2018/11/30 23:22:45 kre Exp $");
__RCSID("$NetBSD: eval.c,v 1.166 2018/12/03 06:40:26 kre Exp $");
#endif
#endif /* not lint */
@ -888,18 +888,11 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
varflag = 1;
/* Expand arguments, ignoring the initial 'name=value' ones */
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
char *p = argp->narg.text;
line_number = argp->narg.lineno;
if (varflag && is_name(*p)) {
do {
p++;
} while (is_in_name(*p));
if (*p == '=')
continue;
}
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
if (varflag && isassignment(argp->narg.text))
continue;
varflag = 0;
line_number = argp->narg.lineno;
expandarg(argp, &arglist, EXP_FULL | EXP_TILDE);
}
*arglist.lastp = NULL;
@ -908,15 +901,8 @@ evalcommand(union node *cmd, int flgs, struct backcmd *backcmd)
/* Now do the initial 'name=value' ones we skipped above */
varlist.lastp = &varlist.list;
for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) {
char *p = argp->narg.text;
line_number = argp->narg.lineno;
if (!is_name(*p))
break;
do
p++;
while (is_in_name(*p));
if (*p != '=')
if (!isassignment(argp->narg.text))
break;
expandarg(argp, &varlist, EXP_VARTILDE);
}

View File

@ -1,4 +1,4 @@
/* $NetBSD: input.c,v 1.63 2018/08/19 23:50:27 kre Exp $ */
/* $NetBSD: input.c,v 1.64 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)input.c 8.3 (Berkeley) 6/9/95";
#else
__RCSID("$NetBSD: input.c,v 1.63 2018/08/19 23:50:27 kre Exp $");
__RCSID("$NetBSD: input.c,v 1.64 2018/12/03 06:40:26 kre Exp $");
#endif
#endif /* not lint */
@ -168,7 +168,12 @@ pfgets(char *line, int len)
int
pgetc(void)
{
return pgetc_macro();
int c;
c = pgetc_macro();
if (c == PFAKE)
c = pgetc_macro();
return c;
}
@ -248,6 +253,8 @@ preadbuffer(void)
char savec;
while (parsefile->strpush) {
if (parsenleft == -1 && parsefile->strpush->ap != NULL)
return PFAKE;
popstring();
if (--parsenleft >= 0)
return (*parsenextc++);
@ -421,6 +428,12 @@ popstring(void)
struct strpush *sp = parsefile->strpush;
INTOFF;
if (sp->ap) {
if (parsenextc != sp->ap->val &&
(parsenextc[-1] == ' ' || parsenextc[-1] == '\t'))
checkkwd |= CHKALIAS;
sp->ap->flag &= ~ALIASINUSE;
}
parsenextc = sp->prevstring;
parsenleft = sp->prevnleft;
parselleft = sp->prevlleft;
@ -429,8 +442,6 @@ popstring(void)
sp->ap ? " from alias:'" : "", sp->ap ? sp->ap->name : "",
sp->ap ? "'" : "", parsenleft, parselleft, parsenleft, parsenextc));
if (sp->ap)
sp->ap->flag &= ~ALIASINUSE;
parsefile->strpush = sp->prev;
if (sp != &(parsefile->basestrpush))
ckfree(sp);

View File

@ -1,4 +1,4 @@
/* $NetBSD: parser.c,v 1.155 2018/12/01 07:02:23 kre Exp $ */
/* $NetBSD: parser.c,v 1.156 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -37,7 +37,7 @@
#if 0
static char sccsid[] = "@(#)parser.c 8.7 (Berkeley) 5/16/95";
#else
__RCSID("$NetBSD: parser.c,v 1.155 2018/12/01 07:02:23 kre Exp $");
__RCSID("$NetBSD: parser.c,v 1.156 2018/12/03 06:40:26 kre Exp $");
#endif
#endif /* not lint */
@ -86,7 +86,6 @@ MKINIT struct parse_state parse_state;
union parse_state_p psp = { .c_current_parser = &parse_state };
static const struct parse_state init_parse_state = { /* all 0's ... */
.ps_noalias = 0,
.ps_heredoclist = NULL,
.ps_parsebackquote = 0,
.ps_doprompt = 0,
@ -184,7 +183,7 @@ list(int nlflag)
CTRACE(DBG_PARSE, ("list(%d): entered @%d\n",nlflag,plinno));
checkkwd = 2;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if (nlflag == 0 && tokendlist[peektoken()])
return NULL;
ntop = n1 = NULL;
@ -237,7 +236,7 @@ list(int nlflag)
else
tokpushback++;
checkkwd = 2;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if (!nlflag && tokendlist[peektoken()])
return ntop;
break;
@ -290,7 +289,7 @@ pipeline(void)
CTRACE(DBG_PARSE, ("pipeline: entered @%d\n", plinno));
negate = 0;
checkkwd = 2;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
while (readtoken() == TNOT) {
CTRACE(DBG_PARSE, ("pipeline: TNOT recognized\n"));
#ifndef BOGUS_NOT_COMMAND
@ -345,7 +344,7 @@ command(void)
CTRACE(DBG_PARSE, ("command: entered @%d\n", plinno));
checkkwd = 2;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
redir = NULL;
n1 = NULL;
rpp = &redir;
@ -389,7 +388,7 @@ command(void)
tokpushback++;
}
consumetoken(TFI);
checkkwd = 1;
checkkwd = CHKKWD | CHKALIAS;
break;
case TWHILE:
case TUNTIL:
@ -399,7 +398,7 @@ command(void)
consumetoken(TDO);
n1->nbinary.ch2 = list(0);
consumetoken(TDONE);
checkkwd = 1;
checkkwd = CHKKWD | CHKALIAS;
break;
case TFOR:
if (readtoken() != TWORD || quoteflag || ! goodname(wordtext))
@ -438,7 +437,7 @@ command(void)
if (lasttoken != TNL && lasttoken != TSEMI)
tokpushback++;
}
checkkwd = 2;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if ((t = readtoken()) == TDO)
t = TDONE;
else if (t == TBEGIN)
@ -447,7 +446,7 @@ command(void)
synexpect(TDO, 0);
n1->nfor.body = list(0);
consumetoken(t);
checkkwd = 1;
checkkwd = CHKKWD | CHKALIAS;
break;
case TCASE:
n1 = stalloc(sizeof(struct ncase));
@ -459,8 +458,7 @@ command(void)
if (lasttoken != TWORD || !equal(wordtext, "in"))
synexpect(-1, "in");
cpp = &n1->ncase.cases;
noalias = 1;
checkkwd = 2;
checkkwd = CHKNL | CHKKWD;
readtoken();
/*
* Both ksh and bash accept 'case x in esac'
@ -488,36 +486,32 @@ command(void)
if (lasttoken < TWORD)
synexpect(TWORD, 0);
*app = ap = makeword(startlinno);
checkkwd = 2;
checkkwd = CHKNL | CHKKWD;
if (readtoken() != TPIPE)
break;
app = &ap->narg.next;
readtoken();
}
noalias = 0;
if (lasttoken != TRP)
synexpect(TRP, 0);
cp->nclist.lineno = startlinno;
cp->nclist.body = list(0);
checkkwd = 2;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if ((t = readtoken()) != TESAC) {
if (t != TENDCASE && t != TCASEFALL) {
noalias = 0;
synexpect(TENDCASE, 0);
} else {
if (t == TCASEFALL)
cp->type = NCLISTCONT;
noalias = 1;
checkkwd = 2;
checkkwd = CHKNL | CHKKWD;
readtoken();
}
}
cpp = &cp->nclist.next;
}
noalias = 0;
*cpp = NULL;
checkkwd = 1;
checkkwd = CHKKWD | CHKALIAS;
break;
case TLP:
n1 = stalloc(sizeof(struct nredir));
@ -527,14 +521,14 @@ command(void)
if (n1->nredir.n == NULL)
synexpect(-1, 0);
consumetoken(TRP);
checkkwd = 1;
checkkwd = CHKKWD | CHKALIAS;
break;
case TBEGIN:
n1 = list(0);
if (posix && n1 == NULL)
synexpect(-1, 0);
consumetoken(TEND);
checkkwd = 1;
checkkwd = CHKKWD | CHKALIAS;
break;
case TBACKGND:
@ -621,6 +615,7 @@ simplecmd(union node **rpp, union node *redir)
union node *args, **app;
union node *n = NULL;
int line = 0;
int savecheckkwd;
#ifdef BOGUS_NOT_COMMAND
union node *n2;
int negate = 0;
@ -645,13 +640,17 @@ simplecmd(union node **rpp, union node *redir)
tokpushback++;
#endif
savecheckkwd = CHKALIAS;
for (;;) {
checkkwd = savecheckkwd;
if (readtoken() == TWORD) {
if (line == 0)
line = startlinno;
n = makeword(startlinno);
*app = n;
app = &n->narg.next;
if (savecheckkwd != 0 && !isassignment(wordtext))
savecheckkwd = 0;
} else if (lasttoken == TREDIR) {
if (line == 0)
line = startlinno;
@ -992,33 +991,29 @@ STATIC int
readtoken(void)
{
int t;
int savecheckkwd = checkkwd;
#ifdef DEBUG
int alreadyseen = tokpushback;
int savecheckkwd = checkkwd;
#endif
struct alias *ap;
top:
t = xxreadtoken();
if (checkkwd) {
/*
* eat newlines
*/
if (checkkwd == 2) {
checkkwd = 0;
while (t == TNL) {
readheredocs();
t = xxreadtoken();
}
} else
checkkwd = 0;
/*
* check for keywords and aliases
*/
if (t == TWORD && !quoteflag) {
const char *const *pp;
if (checkkwd & CHKNL) {
while (t == TNL) {
readheredocs();
t = xxreadtoken();
}
}
/*
* check for keywords and aliases
*/
if (t == TWORD && !quoteflag) {
const char *const *pp;
if (checkkwd & CHKKWD)
for (pp = parsekwd; *pp; pp++) {
if (**pp == *wordtext && equal(*pp, wordtext)) {
lasttoken = t = pp -
@ -1029,21 +1024,23 @@ readtoken(void)
goto out;
}
}
if (!noalias &&
(ap = lookupalias(wordtext, 1)) != NULL) {
VTRACE(DBG_PARSE,
("alias '%s' recognized -> <:%s:>\n",
wordtext, ap->val));
pushstring(ap->val, strlen(ap->val), ap);
checkkwd = savecheckkwd;
goto top;
}
if (checkkwd & CHKALIAS &&
(ap = lookupalias(wordtext, 1)) != NULL) {
VTRACE(DBG_PARSE,
("alias '%s' recognized -> <:%s:>\n",
wordtext, ap->val));
pushstring(ap->val, strlen(ap->val), ap);
goto top;
}
out:
checkkwd = (t == TNOT) ? savecheckkwd : 0;
}
VTRACE(DBG_PARSE, ("%stoken %s %s @%d\n", alreadyseen ? "reread " : "",
tokname[t], t == TWORD ? wordtext : "", plinno));
out:
if (t != TNOT)
checkkwd = 0;
VTRACE(DBG_PARSE, ("%stoken %s %s @%d (chkkwd %x->%x)\n",
alreadyseen ? "reread " : "", tokname[t],
t == TWORD ? wordtext : "", plinno, savecheckkwd, checkkwd));
return (t);
}
@ -1086,7 +1083,7 @@ xxreadtoken(void)
for (;;) { /* until token or start of word found */
c = pgetc_macro();
switch (c) {
case ' ': case '\t':
case ' ': case '\t': case PFAKE:
continue;
case '#':
while ((c = pgetc()) != '\n' && c != PEOF)
@ -1774,6 +1771,10 @@ readtoken1(int firstc, char const *syn, int magicq)
out = insert_elided_nl(out);
CHECKSTRSPACE(6, out); /* permit 6 calls to USTPUTC */
switch (syntax[c]) {
case CFAKE:
if (syntax == BASESYNTAX && varnest == 0)
break;
continue;
case CNL: /* '\n' */
if (syntax == BASESYNTAX && varnest == 0)
break; /* exit loop */
@ -2262,6 +2263,17 @@ goodname(const char *name)
return 1;
}
int
isassignment(const char *p)
{
if (!is_name(*p))
return 0;
while (*++p != '=')
if (*p == '\0' || !is_in_name(*p))
return 0;
return 1;
}
/*
* skip past any \n's, and leave lasttoken set to whatever follows
*/

View File

@ -1,4 +1,4 @@
/* $NetBSD: parser.h,v 1.25 2018/12/01 01:21:06 kre Exp $ */
/* $NetBSD: parser.h,v 1.26 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -74,6 +74,7 @@
union node *parsecmd(int);
void fixredir(union node *, const char *, int);
int goodname(const char *);
int isassignment(const char *);
const char *getprompt(void *);
const char *expandstr(char *, int);
@ -82,7 +83,6 @@ union node;
struct nodelist;
struct parse_state {
int ps_noalias; /* when set, don't handle aliases */
struct HereDoc *ps_heredoclist; /* list of here documents to read */
int ps_parsebackquote; /* nonzero inside backquotes */
int ps_doprompt; /* if set, prompt the user */
@ -90,7 +90,7 @@ struct parse_state {
int ps_lasttoken; /* last token read */
int ps_tokpushback; /* last token pushed back */
char *ps_wordtext; /* text of last word returned by readtoken */
int ps_checkkwd; /* 1 == check for kwds, 2 += eat newlines */
int ps_checkkwd; /* word expansion flags, see below */
struct nodelist *ps_backquotelist; /* list of cmdsubs to process */
union node *ps_redirnode; /* node for current redirect */
struct HereDoc *ps_heredoc; /* current heredoc << beign parsed */
@ -149,6 +149,13 @@ extern union parse_state_p psp;
#define funclinno (current_parser->ps_funclinno)
#define elided_nl (current_parser->ps_elided_nl)
/*
* Values that can be set in checkkwd
*/
#define CHKKWD 0x01 /* turn word into keyword (if it is) */
#define CHKNL 0x02 /* ignore leading \n's */
#define CHKALIAS 0x04 /* lookup words as aliases and ... */
/*
* NEOF is returned by parsecmd when it encounters an end of file. It
* must be distinct from NULL, so we use the address of a variable that

View File

@ -1,7 +1,7 @@
/* $NetBSD: syntax.c,v 1.6 2018/07/20 22:47:26 kre Exp $ */
/* $NetBSD: syntax.c,v 1.7 2018/12/03 06:40:26 kre Exp $ */
#include <sys/cdefs.h>
__RCSID("$NetBSD: syntax.c,v 1.6 2018/07/20 22:47:26 kre Exp $");
__RCSID("$NetBSD: syntax.c,v 1.7 2018/12/03 06:40:26 kre Exp $");
#include <limits.h>
#include "shell.h"
@ -12,12 +12,12 @@ __RCSID("$NetBSD: syntax.c,v 1.6 2018/07/20 22:47:26 kre Exp $");
#error initialisation assumes 'CWORD' is zero
#endif
#define ndx(ch) (ch + 1 - CHAR_MIN)
#define ndx(ch) (ch + 2 - CHAR_MIN)
#define set(ch, val) [ndx(ch)] = val,
#define set_range(s, e, val) [ndx(s) ... ndx(e)] = val,
/* syntax table used when not in quotes */
const char basesyntax[257] = { CEOF,
const char basesyntax[258] = { CFAKE, CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\\', CBACK)
@ -38,7 +38,7 @@ const char basesyntax[257] = { CEOF,
};
/* syntax table used when in double quotes */
const char dqsyntax[257] = { CEOF,
const char dqsyntax[258] = { CFAKE, CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\\', CBACK)
@ -60,7 +60,7 @@ const char dqsyntax[257] = { CEOF,
};
/* syntax table used when in single quotes */
const char sqsyntax[257] = { CEOF,
const char sqsyntax[258] = { CFAKE, CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\'', CSQUOTE)
@ -79,7 +79,7 @@ const char sqsyntax[257] = { CEOF,
};
/* syntax table used when in arithmetic */
const char arisyntax[257] = { CEOF,
const char arisyntax[258] = { CFAKE, CEOF,
set_range(CTL_FIRST, CTL_LAST, CCTL)
set('\n', CNL)
set('\\', CBACK)
@ -93,7 +93,7 @@ const char arisyntax[257] = { CEOF,
};
/* character classification table */
const char is_type[257] = { 0,
const char is_type[258] = { 0, 0,
set_range('0', '9', ISDIGIT)
set_range('a', 'z', ISLOWER)
set_range('A', 'Z', ISUPPER)

View File

@ -1,4 +1,4 @@
/* $NetBSD: syntax.h,v 1.10 2018/11/18 17:23:37 kre Exp $ */
/* $NetBSD: syntax.h,v 1.11 2018/12/03 06:40:26 kre Exp $ */
/*-
* Copyright (c) 1991, 1993
@ -50,6 +50,7 @@
#define CSPCL 11 /* these terminate a word */
#define CCTL 12 /* like CWORD, except it must be escaped */
#define CSBACK 13 /* a backslash in a single quote syntax */
#define CFAKE 14 /* a delimiter that does not exist */
/*
* note CSBACK == (CCTL|1)
* the code does not rely upon that, but keeping it allows a
@ -64,8 +65,9 @@
#define ISSPECL 020 /* the name of a special parameter */
#define ISSPACE 040 /* a white space character */
#define PEOF (CHAR_MIN - 1)
#define SYNBASE (-PEOF)
#define PEOF (CHAR_MIN - 1)
#define PFAKE (CHAR_MIN - 2)
#define SYNBASE (-PFAKE)
#define BASESYNTAX (basesyntax + SYNBASE)