commit 8ce5bc05bcf9b263a65eb6e8d6bae0e610a88b16
parent 593a3857b992c85038276eb0e4c8aa20d796f3de
Author: tjg <tjg>
Date: Mon, 1 Oct 2001 12:54:26 +0000
Bug: it's no longer possible to use parentheses to sneak a word that
needs quoting past the "quoting detector", so `fn x { echo $(x.y) }'
now works both in the current rc and its descendants.
Diffstat:
9 files changed, 44 insertions(+), 38 deletions(-)
diff --git a/ChangeLog b/ChangeLog
@@ -694,10 +694,15 @@ Changes since rc-1.5b2
Bug: you can't pass a short to a stdargs function!
-
2001-09-27
Documentation: we don't consider that `.' failing to search path is
a bug.
Bug: the ^A bug is fixed.
+
+2001-10-01
+
+ Bug: it's no longer possible to use parentheses to sneak a word that
+ needs quoting past the "quoting detector", so `fn x { echo $(x.y) }'
+ now works both in the current rc and its descendants.
diff --git a/footobar.c b/footobar.c
@@ -52,8 +52,6 @@ static bool Tconv(Format *f, int ignore) {
return FALSE;
}
switch (n->type) {
- case nWord: fmtprint(f, "%S", n->u[0].s); break;
- case nQword: fmtprint(f, "%#S", n->u[0].s); break;
case nBang: fmtprint(f, "!%T", n->u[0].p); break;
case nCase: fmtprint(f, "case %T", n->u[0].p); break;
case nNowait: fmtprint(f, "%T&", n->u[0].p); break;
@@ -73,11 +71,14 @@ static bool Tconv(Format *f, int ignore) {
case nLappend: fmtprint(f, "(%T %T)", n->u[0].p, n->u[1].p); break;
case nForin: fmtprint(f, "for(%T in %T)%T", n->u[0].p, n->u[1].p, n->u[2].p); break;
case nVarsub: fmtprint(f, "$%T(%T)", n->u[0].p, n->u[1].p); break;
+ case nWord:
+ fmtprint(f, quotep(n->u[0].s) ? "%#S" : "%S", n->u[0].s);
+ break;
case nCount: case nFlat: case nVar: {
char *lp = "", *rp = "";
Node *n0 = n->u[0].p;
- if (n0->type != nWord && n0->type != nQword)
+ if (n0->type != nWord)
lp = "(", rp = ")";
switch (n->type) {
diff --git a/heredoc.c b/heredoc.c
@@ -82,14 +82,14 @@ static Node *parseheredoc(char *s) {
while ((c = *s++) != '\0' && c != '$')
;
*--s = '\0';
- node = mk(nQword, begin, NULL);
+ node = mk(nWord, begin, NULL);
break;
}
case '$': {
char *begin = ++s, *var;
c = *s++;
if (c == '$') {
- node = mk(nQword, "$", NULL);
+ node = mk(nWord, "$", NULL);
c = *s;
} else {
size_t len = 0;
@@ -129,7 +129,7 @@ extern int heredoc(int end) {
char *s = readheredoc(here->name);
if (dead)
return FALSE;
- n->u[2].p = here->quoted ? mk(nQword, s, NULL) : parseheredoc(s);
+ n->u[2].p = here->quoted ? mk(nWord, s, NULL, FALSE) : parseheredoc(s);
n->u[0].i = rHerestring;
} while ((here = here->n) != NULL);
}
@@ -140,7 +140,7 @@ extern int heredoc(int end) {
extern int qdoc(Node *name, Node *n) {
Hq *new, **prev;
- if (name->type != nWord && name->type != nQword) {
+ if (name->type != nWord) {
yyerror("eof-marker not a single literal word");
flushu();
return FALSE;
@@ -149,7 +149,7 @@ extern int qdoc(Node *name, Node *n) {
;
*prev = new = nnew(Hq);
new->name = name->u[0].s;
- new->quoted = (name->type == nQword);
+ new->quoted = name->u[2].i;
new->doc = n;
new->n = NULL;
return TRUE;
diff --git a/lex.c b/lex.c
@@ -69,6 +69,16 @@ enum filedescriptors {
UNSET = -9, CLOSED = -1
};
+/* does this string require quoting? */
+extern bool quotep(char *s) {
+ unsigned char c;
+
+ while ((c = *s++))
+ if (nw[c])
+ return TRUE;
+ return FALSE;
+}
+
extern int yylex() {
static bool dollar = FALSE;
bool saw_meta = FALSE;
@@ -147,6 +157,7 @@ top: while ((c = gchar()) == ' ' || c == '\t')
} else {
y->word.m = NULL;
}
+ y->word.q = FALSE;
return WORD;
}
if (c == '`' || c == '!' || c == '@' || c == '~' || c == '$' || c == '\'') {
@@ -179,7 +190,8 @@ top: while ((c = gchar()) == ' ' || c == '\t')
case '\'':
w = RW;
i = 0;
- do {
+ /* double ' to quote it, like this: 'how''s it going?' */
+ while ((c = gchar()) != '\'' || (c = gchar()) == '\'') {
buf[i++] = c;
if (c == '\n')
print_prompt2();
@@ -190,11 +202,12 @@ top: while ((c = gchar()) == ' ' || c == '\t')
}
if (i >= bufsize)
buf = realbuf = erealloc(buf, bufsize *= 2);
- } while ((c = gchar()) != '\'' || (c = gchar()) == '\''); /* quote "'" thus: 'how''s it going?' */
+ }
ugchar(c);
buf[i] = '\0';
y->word.w = ncpy(buf);
y->word.m = NULL;
+ y->word.q = TRUE;
return WORD;
case '\\':
if ((c = gchar()) == '\n') {
diff --git a/parse.y b/parse.y
@@ -124,7 +124,7 @@ first : comword
| first '^' sword { $$ = mk(nConcat,$1,$3); }
sword : comword
- | keyword { $$ = mk(nWord,$1, NULL); }
+ | keyword { $$ = mk(nWord, $1, NULL, FALSE); }
word : sword
| word '^' sword { $$ = mk(nConcat,$1,$3); }
@@ -139,7 +139,7 @@ comword : '$' sword { $$ = mk(nVar,$2); }
| BACKBACK word sword { $$ = mk(nBackq,$2,$3); }
| '(' nlwords ')' { $$ = $2; }
| REDIR brace { $$ = mk(nNmpipe,$1.type,$1.fd,$2); }
- | WORD { $$ = ($1.w[0] == '\'') ? mk(nQword, $1.w+1, NULL) : mk(nWord,$1.w, $1.m); }
+ | WORD { $$ = mk(nWord, $1.w, $1.m, $1.q); }
keyword : FOR { $$ = "for"; }
| IN { $$ = "in"; }
@@ -166,7 +166,7 @@ optnl : /* empty */
%%
void initparse() {
- star = treecpy(mk(nVar,mk(nWord,"*",NULL)), ealloc);
- nolist = treecpy(mk(nVar,mk(nWord,"ifs",NULL)), ealloc);
+ star = treecpy(mk(nVar, mk(nWord,"*", NULL, FALSE)), ealloc);
+ nolist = treecpy(mk(nVar, mk(nWord,"ifs", NULL, FALSE)), ealloc);
}
diff --git a/rc.1 b/rc.1
@@ -1933,17 +1933,6 @@ The
notation for flattening should allow for using an arbitrary
separating character, not just space.
.PP
-It is usually possible to use parentheses to defeat
-free caret insertion; that is, to use
-.Cr $(x.y)
-as a synonym for
-.Cr $'x.y' .
-However, the former syntax is not correctly handled in functions
-exported to the environment: a function defined using this syntax will
-not work properly in descendant
-.I rc
-processes.
-.PP
List definitions in exported functions are "noisier" than they need to be.
.PP
If both
@@ -1960,11 +1949,6 @@ but such elements will be split at the colon in descendant
.I rc
processes.
.PP
-The
-.Cr .
-command should search
-.Cr $path .
-.PP
Extra parentheses around a
.Cr ~
expression or a
diff --git a/rc.h b/rc.h
@@ -29,8 +29,8 @@ typedef struct Format Format;
typedef union Edata Edata;
typedef enum nodetype {
- nAndalso, nAssign, nBackq, nBang, nBody, nCbody, nNowait, nBrace, nConcat,
- nCount, nElse, nFlat, nDup, nEpilog, nNewfn, nForin, nIf, nQword,
+ nAndalso, nAssign, nBackq, nBang, nBody, nCbody, nNowait, nBrace,
+ nConcat, nCount, nElse, nFlat, nDup, nEpilog, nNewfn, nForin, nIf,
nOrelse, nPipe, nPre, nRedir, nRmfn, nArgs, nSubshell, nCase,
nSwitch, nMatch, nVar, nVarsub, nWhile, nWord, nLappend, nNmpipe
} nodetype;
@@ -97,6 +97,7 @@ struct Redir {
struct Word {
char *w, *m;
+ bool q;
};
struct Rq {
@@ -279,6 +280,7 @@ extern bool rcrc;
/* lex.c */
+extern bool quotep(char *);
extern int yylex(void);
extern void inityy(void);
extern void yyerror(const char *);
diff --git a/tree.c b/tree.c
@@ -18,10 +18,11 @@ extern Node *mk(int /*nodetype*/ t,...) {
n->u[1].i = va_arg(ap, int);
n->u[2].i = va_arg(ap, int);
break;
- case nWord: case nQword:
- n = nalloc(offsetof(Node, u[2]));
+ case nWord:
+ n = nalloc(offsetof(Node, u[3]));
n->u[0].s = va_arg(ap, char *);
n->u[1].s = va_arg(ap, char *);
+ n->u[2].i = va_arg(ap, int);
break;
case nBang: case nNowait:
case nCount: case nFlat: case nRmfn: case nSubshell:
@@ -79,7 +80,7 @@ extern Node *treecpy(Node *s, void *(*alloc)(size_t)) {
n->u[1].i = s->u[1].i;
n->u[2].i = s->u[2].i;
break;
- case nWord: case nQword:
+ case nWord:
n = (*alloc)(offsetof(Node, u[2]));
n->u[0].s = strcpy((char *) (*alloc)(strlen(s->u[0].s) + 1), s->u[0].s);
if (s->u[1].s != NULL) {
@@ -138,7 +139,7 @@ extern void treefree(Node *s) {
/* NOTREACHED */
case nDup:
break;
- case nWord: case nQword:
+ case nWord:
efree(s->u[0].s);
efree(s->u[1].s);
break;
diff --git a/trip.rc b/trip.rc
@@ -444,7 +444,7 @@ if (whatis printenv >/dev/null>[2=1]) {
} else
printenv=()
-if (~ $#printenv 1 && !~ `` $nl {$printenv | grep fn___2d__2d__2d} 'fn___2d__2d__2d={for(i in $*)a|[2=3]b >>c <<<''e''&f >[2=1]}')
+if (~ $#printenv 1 && !~ `` $nl {$printenv | grep fn___2d__2d__2d} 'fn___2d__2d__2d={for(i in $*)a|[2=3]b >>c <<<e&f >[2=1]}')
fail protect_env
fn --- {replace}