@@ -66,7 +66,7 @@ syntax.c syntax.h: mksyntax
signames.c: mksignames
./$^
-mksyntax: token.h
+mksyntax: parser.h token.h
$(HELPERS): %: %.c
$(COMPILE_FOR_BUILD) -o $@ $<
@@ -150,6 +150,7 @@ special codes defined in parser.h. The special codes are:
CTLVAR Variable substitution
CTLENDVAR End of variable substitution
CTLBACKQ Command substitution
+ CTLBACKQ|CTLQUOTE Command substitution inside double quotes
CTLESC Escape next character
A variable substitution contains the following elements:
@@ -169,13 +170,17 @@ stitution. The possible types are:
VSASSIGN ${var=text}
VSASSIGN|VSNUL ${var=text}
-The name of the variable comes next, terminated by an equals
-sign. If the type is not VSNORMAL, then the text field in the
-substitution follows, terminated by a CTLENDVAR byte.
+In addition, the type field will have the VSQUOTE flag set if the
+variable is enclosed in double quotes, or VSARITH set if the variable
+appears inside an $((...)) arithmetic expansion. The name of the
+variable comes next, terminated by an equals sign. If the type is not
+VSNORMAL, then the text field in the substitution follows, ter-
+minated by a CTLENDVAR byte.
Commands in back quotes are parsed and stored in a linked list.
The locations of these commands in the string are indicated by
-the CTLBACKQ character.
+CTLBACKQ and CTLBACKQ|CTLQUOTE characters, depending upon whether
+the back quotes were enclosed in double quotes.
The character CTLESC escapes the next character, so that in case
any of the CTL characters mentioned above appear in the input,
@@ -83,7 +83,7 @@
#define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */
/* Add CTLESC when necessary. */
-#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT)
+#define QUOTES_ESC (EXP_FULL | EXP_CASE)
/* Do not skip NUL characters. */
#define QUOTES_KEEPNUL EXP_TILDE
@@ -112,12 +112,12 @@ static struct arglist exparg;
STATIC void argstr(char *, int);
STATIC char *exptilde(char *, char *, int);
-STATIC void expbackq(union node *, int);
+STATIC void expbackq(union node *, int, int);
STATIC const char *subevalvar(char *, char *, int, int, int, int, int);
STATIC char *evalvar(char *, int);
STATIC size_t strtodest(const char *, const char *, int);
STATIC void memtodest(const char *, size_t, const char *, int);
-STATIC ssize_t varvalue(char *, int, int, int *);
+STATIC ssize_t varvalue(char *, int, int, int);
STATIC void expandmeta(struct strlist *, int);
#ifdef HAVE_GLOB
STATIC void addglob(const glob_t *);
@@ -243,15 +243,19 @@ argstr(char *p, int flag)
CTLESC,
CTLVAR,
CTLBACKQ,
+ CTLBACKQ | CTLQUOTE,
CTLENDARI,
0
};
const char *reject = spclchars;
- int c;
+ int c = 0;
+ int quotes = flag & QUOTES_ESC;
int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD;
int inquotes;
size_t length;
int startloc;
+ int prev;
+ int dolatstrhack;
if (!(flag & EXP_VARTILDE)) {
reject += 2;
@@ -273,6 +277,7 @@ start:
startloc = expdest - (char *)stackblock();
for (;;) {
length += strcspn(p + length, reject);
+ prev = c;
c = (signed char)p[length];
if (c && (!(c & 0x80) || c == CTLENDARI)) {
/* c == '=' || c == ':' || c == CTLENDARI */
@@ -316,15 +321,9 @@ start:
case CTLENDVAR: /* ??? */
goto breakloop;
case CTLQUOTEMARK:
- inquotes ^= EXP_QUOTED;
- /* "$@" syntax adherence hack */
- if (inquotes && !memcmp(p, dolatstr + 1,
- DOLATSTRLEN - 1)) {
- p = evalvar(p + 1, flag | inquotes) + 1;
- goto start;
- }
+ inquotes = !inquotes;
addquote:
- if (flag & QUOTES_ESC) {
+ if (quotes) {
p--;
length++;
startloc++;
@@ -333,27 +332,26 @@ addquote:
case CTLESC:
startloc++;
length++;
-
- /*
- * Quoted parameter expansion pattern: remove quote
- * unless inside inner quotes or we have a literal
- * backslash.
- */
- if (((flag | inquotes) & (EXP_QPAT | EXP_QUOTED)) ==
- EXP_QPAT && *p != '\\')
- break;
-
goto addquote;
case CTLVAR:
- p = evalvar(p, flag | inquotes);
+ /* "$@" syntax adherence hack */
+ dolatstrhack = !memcmp(p, dolatstr+1, DOLATSTRLEN-1) && !shellparam.nparam && quotes;
+ p = evalvar(p, flag);
+ if (dolatstrhack && prev == (char)CTLQUOTEMARK && *p == (char)CTLQUOTEMARK) {
+ expdest--;
+ inquotes = !inquotes;
+ p++;
+ }
goto start;
case CTLBACKQ:
- expbackq(argbackq->n, flag | inquotes);
+ c = 0;
+ case CTLBACKQ|CTLQUOTE:
+ expbackq(argbackq->n, c, quotes);
argbackq = argbackq->next;
goto start;
case CTLENDARI:
p--;
- expari(flag | inquotes);
+ expari(quotes);
goto start;
}
}
@@ -449,11 +447,12 @@ removerecordregions(int endoff)
* evaluate, place result in (backed up) result, adjust string position.
*/
void
-expari(int flag)
+expari(int quotes)
{
struct stackmark sm;
char *p, *start;
int begoff;
+ char flag;
int len;
intmax_t result;
@@ -468,42 +467,24 @@ expari(int flag)
p = expdest;
pushstackmark(&sm, p - start);
*--p = '\0';
- p--;
- do {
- int esc;
-
- while (*p != (char)CTLARI) {
- p--;
-#ifdef DEBUG
- if (p < start) {
- sh_error("missing CTLARI (shouldn't happen)");
- }
-#endif
- }
-
- esc = esclen(start, p);
- if (!(esc % 2)) {
- break;
- }
-
- p -= esc + 1;
- } while (1);
-
+ p = findstartchar(start, p, CTLARI, CTLENDARI);
begoff = p - start;
removerecordregions(begoff);
+ flag = p[1] & VSSYNTAX;
+
expdest = p;
- if (likely(flag & QUOTES_ESC))
- rmescapes(p + 1);
+ if (likely(quotes))
+ rmescapes(p + 2);
- result = arith(p + 1);
+ result = arith(p + 2);
popstackmark(&sm);
len = cvtnum(result);
- if (likely(!(flag & EXP_QUOTED)))
+ if (likely(!flag))
recordregion(begoff, begoff + len, 0);
}
@@ -513,7 +494,7 @@ expari(int flag)
*/
STATIC void
-expbackq(union node *cmd, int flag)
+expbackq(union node *cmd, int quoted, int quotes)
{
struct backcmd in;
int i;
@@ -521,7 +502,7 @@ expbackq(union node *cmd, int flag)
char *p;
char *dest;
int startloc;
- char const *syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX;
+ char const *syntax = quoted ? DQSYNTAX : BASESYNTAX;
struct stackmark smark;
INTOFF;
@@ -535,7 +516,7 @@ expbackq(union node *cmd, int flag)
if (i == 0)
goto read;
for (;;) {
- memtodest(p, i, syntax, flag & QUOTES_ESC);
+ memtodest(p, i, syntax, quotes);
read:
if (in.fd < 0)
break;
@@ -562,7 +543,7 @@ read:
STUNPUTC(dest);
expdest = dest;
- if (!(flag & EXP_QUOTED))
+ if (!quoted)
recordregion(startloc, dest - (char *)stackblock(), 0);
TRACE(("evalbackq: size=%d: \"%.*s\"\n",
(dest - (char *)stackblock()) - startloc,
@@ -639,9 +620,8 @@ scanright(
}
STATIC const char *
-subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int flag)
+subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varflags, int quotes)
{
- int quotes = flag & QUOTES_ESC;
char *startp;
char *loc;
struct nodelist *saveargbackq = argbackq;
@@ -651,8 +631,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, int startloc, int varfla
char *(*scan)(char *, char *, char *, char *, int , int);
argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ?
- (flag & (EXP_QUOTED | EXP_QPAT) ?
- EXP_QPAT : EXP_CASE) : 0));
+ EXP_CASE : 0));
STPUTC('\0', expdest);
argbackq = saveargbackq;
startp = stackblock() + startloc;
@@ -722,22 +701,25 @@ evalvar(char *p, int flag)
int startloc;
ssize_t varlen;
int easy;
+ int quotes;
int quoted;
+ quotes = flag & QUOTES_ESC;
varflags = *p++;
subtype = varflags & VSTYPE;
if (!subtype)
sh_error("Bad substitution");
- quoted = flag & EXP_QUOTED;
+ quoted = varflags & VSQUOTE;
var = p;
easy = (!quoted || (*var == '@' && shellparam.nparam));
+
startloc = expdest - (char *)stackblock();
p = strchr(p, '=') + 1;
again:
- varlen = varvalue(var, varflags, flag, "ed);
+ varlen = varvalue(var, varflags, flag, quoted);
if (varflags & VSNUL)
varlen--;
@@ -749,7 +731,8 @@ again:
if (subtype == VSMINUS) {
vsplus:
if (varlen < 0) {
- argstr(p, flag | EXP_TILDE | EXP_WORD);
+ argstr(p, flag | EXP_TILDE | EXP_WORD |
+ (quoted ? EXP_QUOTED : 0));
goto end;
}
goto record;
@@ -759,8 +742,7 @@ vsplus:
if (varlen >= 0)
goto record;
- subevalvar(p, var, 0, subtype, startloc, varflags,
- flag & ~QUOTES_ESC);
+ subevalvar(p, var, 0, subtype, startloc, varflags, 0);
varflags &= ~VSNUL;
/*
* Remove any recorded regions beyond
@@ -806,7 +788,7 @@ record:
STPUTC('\0', expdest);
patloc = expdest - (char *)stackblock();
if (subevalvar(p, NULL, patloc, subtype,
- startloc, varflags, flag) == 0) {
+ startloc, varflags, quotes) == 0) {
int amount = expdest - (
(char *)stackblock() + patloc - 1
);
@@ -823,7 +805,7 @@ end:
for (;;) {
if ((c = (signed char)*p++) == CTLESC)
p++;
- else if (c == CTLBACKQ) {
+ else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) {
if (varlen >= 0)
argbackq = argbackq->next;
} else if (c == CTLVAR) {
@@ -887,7 +869,7 @@ strtodest(p, syntax, quotes)
*/
STATIC ssize_t
-varvalue(char *name, int varflags, int flags, int *quotedp)
+varvalue(char *name, int varflags, int flags, int quoted)
{
int num;
char *p;
@@ -896,7 +878,6 @@ varvalue(char *name, int varflags, int flags, int *quotedp)
char sepc;
char **ap;
char const *syntax;
- int quoted = *quotedp;
int subtype = varflags & VSTYPE;
int discard = subtype == VSPLUS || subtype == VSLENGTH;
int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL;
@@ -942,7 +923,6 @@ numvar:
sep |= ifsset() ? ifsval()[0] : ' ';
param:
sepc = sep;
- *quotedp = !sepc;
if (!(ap = shellparam.p))
return -1;
while ((p = *ap++)) {
@@ -1644,7 +1624,6 @@ char *
_rmescapes(char *str, int flag)
{
char *p, *q, *r;
- unsigned inquotes;
int notescaped;
int globbing;
@@ -1674,24 +1653,23 @@ _rmescapes(char *str, int flag)
q = mempcpy(q, str, len);
}
}
- inquotes = 0;
globbing = flag & RMESCAPE_GLOB;
notescaped = globbing;
while (*p) {
if (*p == (char)CTLQUOTEMARK) {
- inquotes = ~inquotes;
p++;
notescaped = globbing;
continue;
}
+ if (*p == '\\') {
+ /* naked back slash */
+ notescaped = 0;
+ goto copy;
+ }
if (*p == (char)CTLESC) {
p++;
if (notescaped)
*q++ = '\\';
- } else if (*p == '\\' && !inquotes) {
- /* naked back slash */
- notescaped = 0;
- goto copy;
}
notescaped = globbing;
copy:
@@ -55,7 +55,6 @@ struct arglist {
#define EXP_VARTILDE 0x4 /* expand tildes in an assignment */
#define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */
#define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */
-#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */
#define EXP_VARTILDE2 0x40 /* expand tildes after colons only */
#define EXP_WORD 0x80 /* expand word in parameter expansion */
#define EXP_QUOTED 0x100 /* expand word in double quotes */
@@ -1375,7 +1375,6 @@ cmdputs(const char *s)
char *nextc;
signed char c;
int subtype = 0;
- int quoted = 0;
static const char vstype[VSTYPE + 1][4] = {
"", "}", "-", "+", "?", "=",
"%", "%%", "#", "##",
@@ -1397,11 +1396,11 @@ cmdputs(const char *s)
str = "${";
goto dostr;
case CTLENDVAR:
- str = "\"}" + !(quoted & 1);
- quoted >>= 1;
+ str = "}";
subtype = 0;
goto dostr;
case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
str = "$(...)";
goto dostr;
case CTLARI:
@@ -1411,14 +1410,11 @@ cmdputs(const char *s)
str = "))";
goto dostr;
case CTLQUOTEMARK:
- quoted ^= 1;
c = '"';
break;
case '=':
if (subtype == 0)
break;
- if ((subtype & VSTYPE) != VSNORMAL)
- quoted <<= 1;
str = vstype[subtype & VSTYPE];
if (subtype & VSNUL)
c = ':';
@@ -1446,9 +1442,6 @@ dostr:
USTPUTC(c, nextc);
}
}
- if (quoted & 1) {
- USTPUTC('"', nextc);
- }
*nextc = 0;
cmdnextc = nextc;
}
@@ -145,7 +145,8 @@ main(int argc, char **argv)
fprintf(hfile, "/* %s */\n", is_entry[i].comment);
}
putc('\n', hfile);
- fprintf(hfile, "#define SYNBASE %d\n", 130);
+ fprintf(hfile, "#define SYNBASE %d\n", 131);
+ fprintf(hfile, "#define PVSSYNTAX %d\n", -131);
fprintf(hfile, "#define PEOF %d\n\n", -130);
fprintf(hfile, "#define PEOA %d\n\n", -129);
putc('\n', hfile);
@@ -158,6 +159,7 @@ main(int argc, char **argv)
putc('\n', hfile);
/* Generate the syntax tables. */
+ fputs("#include \"parser.h\"\n\n", cfile);
fputs("#include \"shell.h\"\n", cfile);
fputs("#include \"syntax.h\"\n\n", cfile);
init();
@@ -170,7 +172,8 @@ main(int argc, char **argv)
add("$", "CVAR");
add("}", "CENDVAR");
add("<>();&| \t", "CSPCL");
- syntax[1] = "CSPCL";
+ syntax[0] = "0";
+ syntax[2] = "CSPCL";
print("basesyntax");
init();
fputs("\n/* syntax table used when in double quotes */\n", cfile);
@@ -182,6 +185,7 @@ main(int argc, char **argv)
add("}", "CENDVAR");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-]", "CCTL");
+ syntax[0] = "VSQUOTE";
print("dqsyntax");
init();
fputs("\n/* syntax table used when in single quotes */\n", cfile);
@@ -189,6 +193,7 @@ main(int argc, char **argv)
add("'", "CENDQUOTE");
/* ':/' for tilde expansion, '-' for [a\-x] pattern ranges */
add("!*?[=~:/-]\\", "CCTL");
+ syntax[0] = "0";
print("sqsyntax");
init();
fputs("\n/* syntax table used when in arithmetic */\n", cfile);
@@ -199,6 +204,7 @@ main(int argc, char **argv)
add("}", "CENDVAR");
add("(", "CLP");
add(")", "CRP");
+ syntax[0] = "VSARITH";
print("arisyntax");
filltable("0");
fputs("\n/* character classification table */\n", cfile);
@@ -223,7 +229,7 @@ filltable(char *dftval)
{
int i;
- for (i = 0 ; i < 258; i++)
+ for (i = 0 ; i < 259; i++)
syntax[i] = dftval;
}
@@ -238,10 +244,10 @@ init(void)
int ctl;
filltable("CWORD");
- syntax[0] = "CEOF";
- syntax[1] = "CIGN";
+ syntax[1] = "CEOF";
+ syntax[2] = "CIGN";
for (ctl = CTL_FIRST; ctl <= CTL_LAST; ctl++ )
- syntax[130 + ctl] = "CCTL";
+ syntax[131 + ctl] = "CCTL";
}
@@ -253,7 +259,7 @@ static void
add(char *p, char *type)
{
while (*p)
- syntax[(signed char)*p++ + 130] = type;
+ syntax[(signed char)*p++ + 131] = type;
}
@@ -271,7 +277,7 @@ print(char *name)
fprintf(hfile, "extern const char %s[];\n", name);
fprintf(cfile, "const char %s[] = {\n", name);
col = 0;
- for (i = 0 ; i < 258; i++) {
+ for (i = 0 ; i < 259; i++) {
if (i == 0) {
fputs(" ", cfile);
} else if ((i & 03) == 0) {
@@ -60,8 +60,7 @@
char nullstr[1]; /* zero length string */
const char spcstr[] = " ";
const char snlfmt[] = "%s\n";
-const char dolatstr[] = { CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=',
- CTLQUOTEMARK, '\0' };
+const char dolatstr[] = { CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' };
const char qchars[] = { CTLESC, CTLQUOTEMARK, 0 };
const char illnum[] = "Illegal number: %s";
const char homestr[] = "HOME";
@@ -40,7 +40,7 @@
extern const char snlfmt[];
extern const char spcstr[];
extern const char dolatstr[];
-#define DOLATSTRLEN 6
+#define DOLATSTRLEN 4
extern const char qchars[];
extern const char illnum[];
extern const char homestr[];
@@ -876,24 +876,18 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
size_t len;
struct nodelist *bqlist;
int quotef;
- int dblquote;
+ int nhere;
int varnest; /* levels of variables expansion */
int arinest; /* levels of arithmetic expansion */
int parenlevel; /* levels of parens in arithmetic */
- int dqvarnest; /* levels of variables expansion within double quotes */
int oldstyle;
- /* syntax before arithmetic */
- char const *uninitialized_var(prevsyntax);
- dblquote = 0;
- if (syntax == DQSYNTAX)
- dblquote = 1;
+ nhere = eofmark && syntax == SQSYNTAX;
quotef = 0;
bqlist = NULL;
varnest = 0;
arinest = 0;
parenlevel = 0;
- dqvarnest = 0;
STARTSTACKSTR(out);
loop: { /* for each line, until end of word */
@@ -922,7 +916,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
USTPUTC(c, out);
break;
case CCTL:
- if (eofmark == NULL || dblquote)
+ if (!nhere)
USTPUTC(CTLESC, out);
USTPUTC(c, out);
break;
@@ -937,13 +931,14 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs)
nlprompt();
} else {
if (
- dblquote &&
+ syntax != BASESYNTAX &&
c != '\\' && c != '`' &&
c != '$' && (
c != '"' ||
eofmark != NULL
)
) {
+ USTPUTC(CTLESC, out);
USTPUTC('\\', out);
}
USTPUTC(CTLESC, out);
@@ -960,16 +955,12 @@ quotemark:
break;
case CDQUOTE:
syntax = DQSYNTAX;
- dblquote = 1;
goto quotemark;
case CENDQUOTE:
if (eofmark && !varnest)
USTPUTC(c, out);
else {
- if (dqvarnest == 0) {
- syntax = BASESYNTAX;
- dblquote = 0;
- }
+ syntax = BASESYNTAX;
quotef++;
goto quotemark;
}
@@ -979,14 +970,18 @@ quotemark:
break;
case CENDVAR: /* '}' */
if (varnest > 0) {
- varnest--;
- if (dqvarnest > 0) {
- dqvarnest--;
+ const char *startchar = findstartchar((char *)stackblock(), out - 1, CTLVAR, CTLENDVAR);
+ char vstype = startchar[1] & VSTYPE;
+ char vssyntax = startchar[1] & VSSYNTAX;
+ const char *prevsyntax = vssyntax == (char)VSARITH ? ARISYNTAX : vssyntax == (char)VSQUOTE ? DQSYNTAX : BASESYNTAX;
+ if (syntax == (prevsyntax == BASESYNTAX || (vstype >= VSTRIM_FIRST && vstype <= VSTRIM_LAST) ? BASESYNTAX : DQSYNTAX)) {
+ syntax = prevsyntax;
+ varnest--;
+ USTPUTC(CTLENDVAR, out);
+ break;
}
- USTPUTC(CTLENDVAR, out);
- } else {
- USTPUTC(c, out);
}
+ USTPUTC(c, out);
break;
case CLP: /* '(' in arithmetic */
parenlevel++;
@@ -999,8 +994,10 @@ quotemark:
} else {
if (pgetc() == ')') {
USTPUTC(CTLENDARI, out);
- if (!--arinest)
- syntax = prevsyntax;
+ --arinest;
+
+ char type = findstartchar((char *)stackblock(), out - 1, CTLARI, CTLENDARI)[1] & VSSYNTAX;
+ syntax = type == (char)VSARITH ? ARISYNTAX : type == (char)VSQUOTE ? DQSYNTAX : BASESYNTAX;
} else {
/*
* unbalanced parens
@@ -1292,12 +1289,13 @@ varname:
badsub:
pungetc();
}
- *((char *)stackblock() + typeloc) = subtype;
+ const char *prevsyntax = syntax;
if (subtype != VSNORMAL) {
varnest++;
- if (dblquote)
- dqvarnest++;
+ syntax = syntax == BASESYNTAX || (subtype >= VSTRIM_FIRST && subtype <= VSTRIM_LAST) ? BASESYNTAX : DQSYNTAX;
}
+ subtype |= prevsyntax[PVSSYNTAX];
+ *((char *)stackblock() + typeloc) = subtype;
STPUTC('=', out);
}
goto parsesub_return;
@@ -1355,7 +1353,7 @@ parsebackq: {
continue;
}
if (pc != '\\' && pc != '`' && pc != '$'
- && (!dblquote || pc != '"'))
+ && (syntax == BASESYNTAX || pc != '"'))
STPUTC('\\', pout);
if (pc > PEOA) {
break;
@@ -1419,7 +1417,10 @@ done:
memcpy(out, str, savelen);
STADJUST(savelen, out);
}
- USTPUTC(CTLBACKQ, out);
+ if (syntax != BASESYNTAX)
+ USTPUTC(CTLBACKQ | CTLQUOTE, out);
+ else
+ USTPUTC(CTLBACKQ, out);
if (oldstyle)
goto parsebackq_oldreturn;
else
@@ -1431,11 +1432,10 @@ done:
*/
parsearith: {
- if (++arinest == 1) {
- prevsyntax = syntax;
- syntax = ARISYNTAX;
- }
+ ++arinest;
USTPUTC(CTLARI, out);
+ USTPUTC(VSTYPE | syntax[PVSSYNTAX], out);
+ syntax = ARISYNTAX;
goto parsearith_return;
}
@@ -1469,6 +1469,39 @@ endofname(const char *name)
}
+const char *
+findstartchar(const char *start, const char *p, char open, char close) {
+ int nest = 1;
+ const char *q;
+ for (;; ) {
+ int d;
+
+ --p;
+
+#if DEBUG
+ if (p < start)
+ sh_error("missing start char (shouldn't happen)");
+#endif
+
+ if (*p == open) {
+ if ((p[1] & VSTYPE) == VSNORMAL)
+ continue;
+
+ d = -1;
+ checkescapes:
+ for (q = p; q != start && q[-1] == (char)CTLESC; q--)
+ ;
+
+ if ((p - q) % 2 == 0 && !(nest += d))
+ return p;
+ } else if (*p == close) {
+ d = 1;
+ goto checkescapes;
+ }
+ }
+}
+
+
/*
* Called when an unexpected token is read during the parse. The argument
* is the token that is expected, or -1 if more than one type of token can
@@ -1543,7 +1576,7 @@ expandstr(const char *ps)
n.narg.text = wordtext;
n.narg.backquote = backquotelist;
- expandarg(&n, NULL, EXP_QUOTED);
+ expandarg(&n, NULL, 0);
return stackblock();
}
@@ -42,14 +42,19 @@
#define CTLVAR -126 /* variable defn */
#define CTLENDVAR -125
#define CTLBACKQ -124
+#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */
+/* CTLBACKQ | CTLQUOTE == -123 */
#define CTLARI -122 /* arithmetic expression */
#define CTLENDARI -121
#define CTLQUOTEMARK -120
#define CTL_LAST -120 /* last 'special' character */
-/* variable substitution byte (follows CTLVAR) */
+/* variable substitution byte (follows CTLVAR), values picked to be distinct from control characters */
#define VSTYPE 0x0f /* type of variable substitution */
#define VSNUL 0x10 /* colon--treat the empty string as unset */
+#define VSSYNTAX 0xc0
+#define VSQUOTE 0x40 /* inside double quotes--suppress splitting */
+#define VSARITH 0xc0 /* inside $((...)) arithmetic */
/* values of VSTYPE field */
#define VSNORMAL 0x1 /* normal variable: $var or ${var} */
@@ -57,10 +62,12 @@
#define VSPLUS 0x3 /* ${var+text} */
#define VSQUESTION 0x4 /* ${var?message} */
#define VSASSIGN 0x5 /* ${var=text} */
+#define VSTRIM_FIRST 0x6
#define VSTRIMRIGHT 0x6 /* ${var%pattern} */
#define VSTRIMRIGHTMAX 0x7 /* ${var%%pattern} */
#define VSTRIMLEFT 0x8 /* ${var#pattern} */
#define VSTRIMLEFTMAX 0x9 /* ${var##pattern} */
+#define VSTRIM_LAST 0x9
#define VSLENGTH 0xa /* ${#var} */
/* values of checkkwd variable */
@@ -88,6 +95,7 @@ const char *getprompt(void *);
const char *const *findkwd(const char *);
char *endofname(const char *);
const char *expandstr(const char *);
+const char *findstartchar(const char *, const char *, char, char);
static inline int
goodname(const char *p)
@@ -304,7 +304,7 @@ openhere(union node *redir)
p = redir->nhere.doc->narg.text;
if (redir->type == NXHERE) {
- expandarg(redir->nhere.doc, NULL, EXP_QUOTED);
+ expandarg(redir->nhere.doc, NULL, 0);
p = stackblock();
}
@@ -222,6 +222,7 @@ sharg(union node *arg, FILE *fp)
putc('}', fp);
break;
case CTLBACKQ:
+ case CTLBACKQ|CTLQUOTE:
putc('$', fp);
putc('(', fp);
shtree(bqlist->n, -1, NULL, fp);
@@ -314,6 +315,7 @@ trstring(char *s)
case CTLESC: c = 'e'; goto backslash;
case CTLVAR: c = 'v'; goto backslash;
case CTLBACKQ: c = 'q'; goto backslash;
+ case CTLBACKQ|CTLQUOTE: c = 'Q'; goto backslash;
backslash: putc('\\', tracefile);
putc(c, tracefile);
break;