summaryrefslogtreecommitdiffstats
path: root/bin/sh/expand.c
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2010-10-29 13:42:18 +0000
committerjilles <jilles@FreeBSD.org>2010-10-29 13:42:18 +0000
commit28ad180ab428c06679f4d2e8422bfb77ae2a926c (patch)
treea904801ee278e1d897c3118d8e675fd52f1a7856 /bin/sh/expand.c
parentb6cd17990d125d91ed9a1a32e708c186c2fd3945 (diff)
downloadFreeBSD-src-28ad180ab428c06679f4d2e8422bfb77ae2a926c.zip
FreeBSD-src-28ad180ab428c06679f4d2e8422bfb77ae2a926c.tar.gz
sh: Do IFS splitting on word in ${v+word} and ${v-word}.
The code is inspired by NetBSD sh somewhat, but different because we preserve the old Almquist/Bourne/Korn ability to have an unquoted part in a quoted ${v+word}. For example, "${v-"*"}" expands to $v as a single field if v is set, but generates filenames otherwise. Note that this is the only place where we split text literally from the script (the similar ${v=word} assigns to v and then expands $v). The parser must now add additional markers to allow the expansion code to know whether arbitrary characters in substitutions are quoted. Example: for i in ${$+a b c}; do echo $i; done Exp-run done by: pav (with some other sh(1) changes)
Diffstat (limited to 'bin/sh/expand.c')
-rw-r--r--bin/sh/expand.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/bin/sh/expand.c b/bin/sh/expand.c
index d33f0ac..13dc38a 100644
--- a/bin/sh/expand.c
+++ b/bin/sh/expand.c
@@ -216,7 +216,12 @@ argstr(char *p, int flag)
char c;
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */
int firsteq = 1;
+ int split_lit;
+ int lit_quoted;
+ split_lit = flag & EXP_SPLIT_LIT;
+ lit_quoted = flag & EXP_LIT_QUOTED;
+ flag &= ~(EXP_SPLIT_LIT | EXP_LIT_QUOTED);
if (*p == '~' && (flag & (EXP_TILDE | EXP_VARTILDE)))
p = exptilde(p, flag);
for (;;) {
@@ -225,17 +230,25 @@ argstr(char *p, int flag)
case CTLENDVAR:
goto breakloop;
case CTLQUOTEMARK:
+ lit_quoted = 1;
/* "$@" syntax adherence hack */
if (p[0] == CTLVAR && p[2] == '@' && p[3] == '=')
break;
if ((flag & EXP_FULL) != 0)
STPUTC(c, expdest);
break;
+ case CTLQUOTEEND:
+ lit_quoted = 0;
+ break;
case CTLESC:
if (quotes)
STPUTC(c, expdest);
c = *p++;
STPUTC(c, expdest);
+ if (split_lit && !lit_quoted)
+ recordregion(expdest - stackblock() -
+ (quotes ? 2 : 1),
+ expdest - stackblock(), 0);
break;
case CTLVAR:
p = evalvar(p, flag);
@@ -255,18 +268,21 @@ argstr(char *p, int flag)
* assignments (after the first '=' and after ':'s).
*/
STPUTC(c, expdest);
- if (flag & EXP_VARTILDE && *p == '~') {
- if (c == '=') {
- if (firsteq)
- firsteq = 0;
- else
- break;
- }
+ if (split_lit && !lit_quoted)
+ recordregion(expdest - stackblock() - 1,
+ expdest - stackblock(), 0);
+ if (flag & EXP_VARTILDE && *p == '~' &&
+ (c != '=' || firsteq)) {
+ if (c == '=')
+ firsteq = 0;
p = exptilde(p, flag);
}
break;
default:
STPUTC(c, expdest);
+ if (split_lit && !lit_quoted)
+ recordregion(expdest - stackblock() - 1,
+ expdest - stackblock(), 0);
}
}
breakloop:;
@@ -742,7 +758,8 @@ record:
case VSPLUS:
case VSMINUS:
if (!set) {
- argstr(p, flag);
+ argstr(p, flag | (flag & EXP_FULL ? EXP_SPLIT_LIT : 0) |
+ (varflags & VSQUOTE ? EXP_LIT_QUOTED : 0));
break;
}
if (easy)
@@ -1495,13 +1512,13 @@ rmescapes(char *str)
char *p, *q;
p = str;
- while (*p != CTLESC && *p != CTLQUOTEMARK) {
+ while (*p != CTLESC && *p != CTLQUOTEMARK && *p != CTLQUOTEEND) {
if (*p++ == '\0')
return;
}
q = p;
while (*p) {
- if (*p == CTLQUOTEMARK) {
+ if (*p == CTLQUOTEMARK || *p == CTLQUOTEEND) {
p++;
continue;
}
OpenPOWER on IntegriCloud