diff options
author | Ron Yorston <rmy@pobox.com> | 2020-02-25 11:52:36 +0000 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2020-02-25 11:52:36 +0000 |
commit | 5e69872105e69980e5feb0b071a442cd423c59f5 (patch) | |
tree | 78fd5194d36e518e658f4f58635d6fc85515b778 | |
parent | e2a5b8e5e936891142cb630d145e67882711fd13 (diff) | |
parent | 1555895b4af44ce47fe2365aec82e8e67c685f08 (diff) | |
download | busybox-w32-5e69872105e69980e5feb0b071a442cd423c59f5.tar.gz busybox-w32-5e69872105e69980e5feb0b071a442cd423c59f5.tar.bz2 busybox-w32-5e69872105e69980e5feb0b071a442cd423c59f5.zip |
Merge branch 'busybox' into merge
-rw-r--r-- | shell/ash.c | 390 |
1 files changed, 183 insertions, 207 deletions
diff --git a/shell/ash.c b/shell/ash.c index 690796740..47ad85440 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -1925,7 +1925,7 @@ makestrspace(size_t newlen, char *p) | |||
1925 | } | 1925 | } |
1926 | 1926 | ||
1927 | static char * | 1927 | static char * |
1928 | stack_nputstr(const char *s, size_t n, char *p) | 1928 | stnputs(const char *s, size_t n, char *p) |
1929 | { | 1929 | { |
1930 | p = makestrspace(n, p); | 1930 | p = makestrspace(n, p); |
1931 | p = (char *)mempcpy(p, s, n); | 1931 | p = (char *)mempcpy(p, s, n); |
@@ -1935,7 +1935,7 @@ stack_nputstr(const char *s, size_t n, char *p) | |||
1935 | static char * | 1935 | static char * |
1936 | stack_putstr(const char *s, char *p) | 1936 | stack_putstr(const char *s, char *p) |
1937 | { | 1937 | { |
1938 | return stack_nputstr(s, strlen(s), p); | 1938 | return stnputs(s, strlen(s), p); |
1939 | } | 1939 | } |
1940 | 1940 | ||
1941 | static char * | 1941 | static char * |
@@ -3032,7 +3032,7 @@ updatepwd(const char *dir) | |||
3032 | else { | 3032 | else { |
3033 | if (absdrive) { | 3033 | if (absdrive) { |
3034 | if (!relpath) | 3034 | if (!relpath) |
3035 | new = stack_nputstr(dir, 2, new); | 3035 | new = stnputs(dir, 2, new); |
3036 | cdcomppath += 2; | 3036 | cdcomppath += 2; |
3037 | dir += 2; | 3037 | dir += 2; |
3038 | } | 3038 | } |
@@ -6566,6 +6566,7 @@ static int substr_atoi(const char *s) | |||
6566 | #define EXP_WORD 0x40 /* expand word in parameter expansion */ | 6566 | #define EXP_WORD 0x40 /* expand word in parameter expansion */ |
6567 | #define EXP_QUOTED 0x100 /* expand word in double quotes */ | 6567 | #define EXP_QUOTED 0x100 /* expand word in double quotes */ |
6568 | #define EXP_KEEPNUL 0x200 /* do not skip NUL characters */ | 6568 | #define EXP_KEEPNUL 0x200 /* do not skip NUL characters */ |
6569 | #define EXP_DISCARD 0x400 /* discard result of expansion */ | ||
6569 | 6570 | ||
6570 | /* | 6571 | /* |
6571 | * rmescape() flags | 6572 | * rmescape() flags |
@@ -6983,13 +6984,15 @@ removerecordregions(int endoff) | |||
6983 | } | 6984 | } |
6984 | 6985 | ||
6985 | static char * | 6986 | static char * |
6986 | exptilde(char *startp, char *p, int flag) | 6987 | exptilde(char *startp, int flag) |
6987 | { | 6988 | { |
6988 | unsigned char c; | 6989 | unsigned char c; |
6989 | char *name; | 6990 | char *name; |
6990 | struct passwd *pw; | 6991 | struct passwd *pw; |
6991 | const char *home; | 6992 | const char *home; |
6993 | char *p; | ||
6992 | 6994 | ||
6995 | p = startp; | ||
6993 | name = p + 1; | 6996 | name = p + 1; |
6994 | 6997 | ||
6995 | while ((c = *++p) != '\0') { | 6998 | while ((c = *++p) != '\0') { |
@@ -7008,6 +7011,8 @@ exptilde(char *startp, char *p, int flag) | |||
7008 | } | 7011 | } |
7009 | } | 7012 | } |
7010 | done: | 7013 | done: |
7014 | if (flag & EXP_DISCARD) | ||
7015 | goto out; | ||
7011 | *p = '\0'; | 7016 | *p = '\0'; |
7012 | if (*name == '\0') { | 7017 | if (*name == '\0') { |
7013 | home = lookupvar("HOME"); | 7018 | home = lookupvar("HOME"); |
@@ -7017,13 +7022,13 @@ exptilde(char *startp, char *p, int flag) | |||
7017 | goto lose; | 7022 | goto lose; |
7018 | home = pw->pw_dir; | 7023 | home = pw->pw_dir; |
7019 | } | 7024 | } |
7025 | *p = c; | ||
7020 | if (!home) | 7026 | if (!home) |
7021 | goto lose; | 7027 | goto lose; |
7022 | *p = c; | ||
7023 | strtodest(home, flag | EXP_QUOTED); | 7028 | strtodest(home, flag | EXP_QUOTED); |
7029 | out: | ||
7024 | return p; | 7030 | return p; |
7025 | lose: | 7031 | lose: |
7026 | *p = c; | ||
7027 | return startp; | 7032 | return startp; |
7028 | } | 7033 | } |
7029 | 7034 | ||
@@ -7132,6 +7137,9 @@ expbackq(union node *cmd, int flag) | |||
7132 | int startloc; | 7137 | int startloc; |
7133 | struct stackmark smark; | 7138 | struct stackmark smark; |
7134 | 7139 | ||
7140 | if (flag & EXP_DISCARD) | ||
7141 | goto out; | ||
7142 | |||
7135 | INT_OFF; | 7143 | INT_OFF; |
7136 | startloc = expdest - (char *)stackblock(); | 7144 | startloc = expdest - (char *)stackblock(); |
7137 | pushstackmark(&smark, startloc); | 7145 | pushstackmark(&smark, startloc); |
@@ -7174,64 +7182,57 @@ expbackq(union node *cmd, int flag) | |||
7174 | (int)((dest - (char *)stackblock()) - startloc), | 7182 | (int)((dest - (char *)stackblock()) - startloc), |
7175 | (int)((dest - (char *)stackblock()) - startloc), | 7183 | (int)((dest - (char *)stackblock()) - startloc), |
7176 | stackblock() + startloc)); | 7184 | stackblock() + startloc)); |
7185 | |||
7186 | out: | ||
7187 | argbackq = argbackq->next; | ||
7177 | } | 7188 | } |
7178 | 7189 | ||
7190 | /* expari needs it */ | ||
7191 | static char *argstr(char *p, int flag); | ||
7192 | |||
7179 | #if ENABLE_FEATURE_SH_MATH | 7193 | #if ENABLE_FEATURE_SH_MATH |
7180 | /* | 7194 | /* |
7181 | * Expand arithmetic expression. Backup to start of expression, | 7195 | * Expand arithmetic expression. Backup to start of expression, |
7182 | * evaluate, place result in (backed up) result, adjust string position. | 7196 | * evaluate, place result in (backed up) result, adjust string position. |
7183 | */ | 7197 | */ |
7184 | static void | 7198 | static char * |
7185 | expari(int flag) | 7199 | expari(char *start, int flag) |
7186 | { | 7200 | { |
7187 | char *p, *start; | 7201 | struct stackmark sm; |
7188 | int begoff; | 7202 | int begoff; |
7203 | int endoff; | ||
7189 | int len; | 7204 | int len; |
7205 | arith_t result; | ||
7206 | char *p; | ||
7190 | 7207 | ||
7191 | /* ifsfree(); */ | 7208 | p = stackblock(); |
7192 | 7209 | begoff = expdest - p; | |
7193 | /* | 7210 | p = argstr(start, flag & EXP_DISCARD); |
7194 | * This routine is slightly over-complicated for | ||
7195 | * efficiency. Next we scan backwards looking for the | ||
7196 | * start of arithmetic. | ||
7197 | */ | ||
7198 | start = stackblock(); | ||
7199 | p = expdest - 1; | ||
7200 | *p = '\0'; | ||
7201 | p--; | ||
7202 | while (1) { | ||
7203 | int esc; | ||
7204 | |||
7205 | while ((unsigned char)*p != CTLARI) { | ||
7206 | p--; | ||
7207 | #if DEBUG | ||
7208 | if (p < start) { | ||
7209 | ash_msg_and_raise_error("missing CTLARI (shouldn't happen)"); | ||
7210 | } | ||
7211 | #endif | ||
7212 | } | ||
7213 | |||
7214 | esc = esclen(start, p); | ||
7215 | if (!(esc % 2)) { | ||
7216 | break; | ||
7217 | } | ||
7218 | 7211 | ||
7219 | p -= esc + 1; | 7212 | if (flag & EXP_DISCARD) |
7220 | } | 7213 | goto out; |
7221 | 7214 | ||
7222 | begoff = p - start; | 7215 | start = stackblock(); |
7216 | endoff = expdest - start; | ||
7217 | start += begoff; | ||
7218 | STADJUST(start - expdest, expdest); | ||
7223 | 7219 | ||
7224 | removerecordregions(begoff); | 7220 | removerecordregions(begoff); |
7225 | 7221 | ||
7226 | expdest = p; | ||
7227 | |||
7228 | if (flag & QUOTES_ESC) | 7222 | if (flag & QUOTES_ESC) |
7229 | rmescapes(p + 1, 0, NULL); | 7223 | rmescapes(start, 0, NULL); |
7230 | 7224 | ||
7231 | len = cvtnum(ash_arith(p + 1), flag); | 7225 | pushstackmark(&sm, endoff); |
7226 | result = ash_arith(start); | ||
7227 | popstackmark(&sm); | ||
7228 | |||
7229 | len = cvtnum(result, flag); | ||
7232 | 7230 | ||
7233 | if (!(flag & EXP_QUOTED)) | 7231 | if (!(flag & EXP_QUOTED)) |
7234 | recordregion(begoff, begoff + len, 0); | 7232 | recordregion(begoff, begoff + len, 0); |
7233 | |||
7234 | out: | ||
7235 | return p; | ||
7235 | } | 7236 | } |
7236 | #endif | 7237 | #endif |
7237 | 7238 | ||
@@ -7243,8 +7244,8 @@ static char *evalvar(char *p, int flags); | |||
7243 | * characters to allow for further processing. Otherwise treat | 7244 | * characters to allow for further processing. Otherwise treat |
7244 | * $@ like $* since no splitting will be performed. | 7245 | * $@ like $* since no splitting will be performed. |
7245 | */ | 7246 | */ |
7246 | static void | 7247 | static char * |
7247 | argstr(char *p, int flags) | 7248 | argstr(char *p, int flag) |
7248 | { | 7249 | { |
7249 | static const char spclchars[] ALIGN1 = { | 7250 | static const char spclchars[] ALIGN1 = { |
7250 | '=', | 7251 | '=', |
@@ -7255,51 +7256,56 @@ argstr(char *p, int flags) | |||
7255 | CTLVAR, | 7256 | CTLVAR, |
7256 | CTLBACKQ, | 7257 | CTLBACKQ, |
7257 | #if ENABLE_FEATURE_SH_MATH | 7258 | #if ENABLE_FEATURE_SH_MATH |
7259 | CTLARI, | ||
7258 | CTLENDARI, | 7260 | CTLENDARI, |
7259 | #endif | 7261 | #endif |
7260 | '\0' | 7262 | '\0' |
7261 | }; | 7263 | }; |
7262 | const char *reject = spclchars; | 7264 | const char *reject = spclchars; |
7263 | int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; | 7265 | int breakall = (flag & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; |
7264 | int inquotes; | 7266 | int inquotes; |
7265 | size_t length; | 7267 | size_t length; |
7266 | int startloc; | 7268 | int startloc; |
7267 | 7269 | ||
7268 | if (!(flags & EXP_VARTILDE)) { | 7270 | reject += !!(flag & EXP_VARTILDE2); |
7269 | reject += 2; | 7271 | reject += flag & EXP_VARTILDE ? 0 : 2; |
7270 | } else if (flags & EXP_VARTILDE2) { | ||
7271 | reject++; | ||
7272 | } | ||
7273 | inquotes = 0; | 7272 | inquotes = 0; |
7274 | length = 0; | 7273 | length = 0; |
7275 | if (flags & EXP_TILDE) { | 7274 | if (flag & EXP_TILDE) { |
7276 | char *q; | 7275 | flag &= ~EXP_TILDE; |
7277 | |||
7278 | flags &= ~EXP_TILDE; | ||
7279 | tilde: | 7276 | tilde: |
7280 | q = p; | 7277 | if (*p == '~') |
7281 | if (*q == '~') | 7278 | p = exptilde(p, flag); |
7282 | p = exptilde(p, q, flags); | ||
7283 | } | 7279 | } |
7284 | start: | 7280 | start: |
7285 | startloc = expdest - (char *)stackblock(); | 7281 | startloc = expdest - (char *)stackblock(); |
7286 | for (;;) { | 7282 | for (;;) { |
7283 | int end; | ||
7287 | unsigned char c; | 7284 | unsigned char c; |
7288 | 7285 | ||
7289 | length += strcspn(p + length, reject); | 7286 | length += strcspn(p + length, reject); |
7287 | end = 0; | ||
7290 | c = p[length]; | 7288 | c = p[length]; |
7291 | if (c) { | 7289 | if (!(c & 0x80) |
7292 | if (!(c & 0x80) | 7290 | IF_FEATURE_SH_MATH(|| c == CTLENDARI) |
7293 | IF_FEATURE_SH_MATH(|| c == CTLENDARI) | 7291 | || c == CTLENDVAR |
7294 | ) { | 7292 | ) { |
7295 | /* c == '=' || c == ':' || c == CTLENDARI */ | 7293 | /* |
7296 | length++; | 7294 | * c == '=' || c == ':' || c == '\0' || |
7297 | } | 7295 | * c == CTLENDARI || c == CTLENDVAR |
7296 | */ | ||
7297 | length++; | ||
7298 | /* c == '\0' || c == CTLENDARI || c == CTLENDVAR */ | ||
7299 | end = !!((c - 1) & 0x80); | ||
7298 | } | 7300 | } |
7299 | if (length > 0) { | 7301 | if (length > 0 && !(flag & EXP_DISCARD)) { |
7300 | int newloc; | 7302 | int newloc; |
7301 | expdest = stack_nputstr(p, length, expdest); | 7303 | char *q; |
7302 | newloc = expdest - (char *)stackblock(); | 7304 | |
7305 | q = stnputs(p, length, expdest); | ||
7306 | q[-1] &= end - 1; | ||
7307 | expdest = q - (flag & EXP_WORD ? end : 0); | ||
7308 | newloc = q - (char *)stackblock() - end; | ||
7303 | if (breakall && !inquotes && newloc > startloc) { | 7309 | if (breakall && !inquotes && newloc > startloc) { |
7304 | recordregion(startloc, newloc, 0); | 7310 | recordregion(startloc, newloc, 0); |
7305 | } | 7311 | } |
@@ -7308,15 +7314,12 @@ argstr(char *p, int flags) | |||
7308 | p += length + 1; | 7314 | p += length + 1; |
7309 | length = 0; | 7315 | length = 0; |
7310 | 7316 | ||
7317 | if (end) | ||
7318 | break; | ||
7319 | |||
7311 | switch (c) { | 7320 | switch (c) { |
7312 | case '\0': | ||
7313 | goto breakloop; | ||
7314 | case '=': | 7321 | case '=': |
7315 | if (flags & EXP_VARTILDE2) { | 7322 | flag |= EXP_VARTILDE2; |
7316 | p--; | ||
7317 | continue; | ||
7318 | } | ||
7319 | flags |= EXP_VARTILDE2; | ||
7320 | reject++; | 7323 | reject++; |
7321 | /* fall through */ | 7324 | /* fall through */ |
7322 | case ':': | 7325 | case ':': |
@@ -7328,20 +7331,15 @@ argstr(char *p, int flags) | |||
7328 | goto tilde; | 7331 | goto tilde; |
7329 | } | 7332 | } |
7330 | continue; | 7333 | continue; |
7331 | } | ||
7332 | |||
7333 | switch (c) { | ||
7334 | case CTLENDVAR: /* ??? */ | ||
7335 | goto breakloop; | ||
7336 | case CTLQUOTEMARK: | 7334 | case CTLQUOTEMARK: |
7337 | /* "$@" syntax adherence hack */ | 7335 | /* "$@" syntax adherence hack */ |
7338 | if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { | 7336 | if (!inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { |
7339 | p = evalvar(p + 1, flags | EXP_QUOTED) + 1; | 7337 | p = evalvar(p + 1, flag | EXP_QUOTED) + 1; |
7340 | goto start; | 7338 | goto start; |
7341 | } | 7339 | } |
7342 | inquotes ^= EXP_QUOTED; | 7340 | inquotes ^= EXP_QUOTED; |
7343 | addquote: | 7341 | addquote: |
7344 | if (flags & QUOTES_ESC) { | 7342 | if (flag & QUOTES_ESC) { |
7345 | p--; | 7343 | p--; |
7346 | length++; | 7344 | length++; |
7347 | startloc++; | 7345 | startloc++; |
@@ -7353,22 +7351,20 @@ argstr(char *p, int flags) | |||
7353 | goto addquote; | 7351 | goto addquote; |
7354 | case CTLVAR: | 7352 | case CTLVAR: |
7355 | TRACE(("argstr: evalvar('%s')\n", p)); | 7353 | TRACE(("argstr: evalvar('%s')\n", p)); |
7356 | p = evalvar(p, flags | inquotes); | 7354 | p = evalvar(p, flag | inquotes); |
7357 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); | 7355 | TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); |
7358 | goto start; | 7356 | goto start; |
7359 | case CTLBACKQ: | 7357 | case CTLBACKQ: |
7360 | expbackq(argbackq->n, flags | inquotes); | 7358 | expbackq(argbackq->n, flag | inquotes); |
7361 | argbackq = argbackq->next; | ||
7362 | goto start; | 7359 | goto start; |
7363 | #if ENABLE_FEATURE_SH_MATH | 7360 | #if ENABLE_FEATURE_SH_MATH |
7364 | case CTLENDARI: | 7361 | case CTLARI: |
7365 | p--; | 7362 | p = expari(p, flag | inquotes); |
7366 | expari(flags | inquotes); | ||
7367 | goto start; | 7363 | goto start; |
7368 | #endif | 7364 | #endif |
7369 | } | 7365 | } |
7370 | } | 7366 | } |
7371 | breakloop: ; | 7367 | return p - 1; |
7372 | } | 7368 | } |
7373 | 7369 | ||
7374 | static char * | 7370 | static char * |
@@ -7493,26 +7489,27 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) | |||
7493 | ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); | 7489 | ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); |
7494 | } | 7490 | } |
7495 | 7491 | ||
7496 | static const char * | 7492 | static char * |
7497 | subevalvar(char *p, char *varname, int strloc, int subtype, | 7493 | subevalvar(char *start, char *str, int strloc, |
7498 | int startloc, int varflags, int flag) | 7494 | int startloc, int varflags, int flag) |
7499 | { | 7495 | { |
7500 | struct nodelist *saveargbackq = argbackq; | 7496 | int subtype = varflags & VSTYPE; |
7501 | int quotes = flag & QUOTES_ESC; | 7497 | int quotes = flag & QUOTES_ESC; |
7502 | char *startp; | 7498 | char *startp; |
7503 | char *loc; | 7499 | char *loc; |
7504 | char *rmesc, *rmescend; | 7500 | char *rmesc, *rmescend; |
7505 | char *str; | 7501 | long amount; |
7506 | int amount, resetloc; | 7502 | int resetloc; |
7507 | int argstr_flags; | 7503 | int argstr_flags; |
7508 | IF_BASH_PATTERN_SUBST(int workloc;) | 7504 | IF_BASH_PATTERN_SUBST(int workloc;) |
7509 | IF_BASH_PATTERN_SUBST(int slash_pos;) | 7505 | IF_BASH_PATTERN_SUBST(int slash_pos;) |
7510 | IF_BASH_PATTERN_SUBST(char *repl;) | 7506 | IF_BASH_PATTERN_SUBST(char *repl;) |
7511 | int zero; | 7507 | int zero; |
7512 | char *(*scan)(char*, char*, char*, char*, int, int); | 7508 | char *(*scan)(char*, char*, char*, char*, int, int); |
7509 | char *p; | ||
7513 | 7510 | ||
7514 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", | 7511 | //bb_error_msg("subevalvar(start:'%s',str:'%s',strloc:%d,startloc:%d,varflags:%x,quotes:%d)", |
7515 | // p, varname, strloc, subtype, startloc, varflags, quotes); | 7512 | // start, str, strloc, startloc, varflags, quotes); |
7516 | 7513 | ||
7517 | #if BASH_PATTERN_SUBST | 7514 | #if BASH_PATTERN_SUBST |
7518 | /* For "${v/pattern/repl}", we must find the delimiter _before_ | 7515 | /* For "${v/pattern/repl}", we must find the delimiter _before_ |
@@ -7522,7 +7519,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7522 | repl = NULL; | 7519 | repl = NULL; |
7523 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { | 7520 | if (subtype == VSREPLACE || subtype == VSREPLACEALL) { |
7524 | /* Find '/' and replace with NUL */ | 7521 | /* Find '/' and replace with NUL */ |
7525 | repl = p; | 7522 | repl = start; |
7526 | /* The pattern can't be empty. | 7523 | /* The pattern can't be empty. |
7527 | * IOW: if the first char after "${v//" is a slash, | 7524 | * IOW: if the first char after "${v//" is a slash, |
7528 | * it does not terminate the pattern - it's the first char of the pattern: | 7525 | * it does not terminate the pattern - it's the first char of the pattern: |
@@ -7547,17 +7544,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7547 | } | 7544 | } |
7548 | } | 7545 | } |
7549 | #endif | 7546 | #endif |
7550 | argstr_flags = EXP_TILDE; | 7547 | argstr_flags = (flag & EXP_DISCARD) | EXP_TILDE; |
7551 | if (subtype != VSASSIGN | 7548 | if (!str |
7552 | && subtype != VSQUESTION | ||
7553 | #if BASH_SUBSTR | 7549 | #if BASH_SUBSTR |
7554 | && subtype != VSSUBSTR | 7550 | && subtype != VSSUBSTR |
7555 | #endif | 7551 | #endif |
7556 | ) { | 7552 | ) { |
7557 | /* EXP_CASE keeps CTLESC's */ | 7553 | /* EXP_CASE keeps CTLESC's */ |
7558 | argstr_flags = EXP_TILDE | EXP_CASE; | 7554 | argstr_flags |= EXP_CASE; |
7559 | } | 7555 | } |
7560 | argstr(p, argstr_flags); | 7556 | p = argstr(start, argstr_flags); |
7557 | |||
7561 | //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc); | 7558 | //bb_error_msg("str0:'%s'", (char *)stackblock() + strloc); |
7562 | #if BASH_PATTERN_SUBST | 7559 | #if BASH_PATTERN_SUBST |
7563 | slash_pos = -1; | 7560 | slash_pos = -1; |
@@ -7565,32 +7562,34 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7565 | slash_pos = expdest - ((char *)stackblock() + strloc); | 7562 | slash_pos = expdest - ((char *)stackblock() + strloc); |
7566 | STPUTC('/', expdest); | 7563 | STPUTC('/', expdest); |
7567 | //bb_error_msg("repl+1:'%s'", repl + 1); | 7564 | //bb_error_msg("repl+1:'%s'", repl + 1); |
7568 | argstr(repl + 1, EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */ | 7565 | p = argstr(repl + 1, (flag & EXP_DISCARD) | EXP_TILDE); /* EXP_TILDE: echo "${v/x/~}" expands ~ ! */ |
7569 | *repl = '/'; | 7566 | *repl = '/'; |
7570 | } | 7567 | } |
7571 | #endif | 7568 | #endif |
7572 | STPUTC('\0', expdest); | 7569 | if (flag & EXP_DISCARD) |
7573 | argbackq = saveargbackq; | 7570 | return p; |
7571 | |||
7574 | startp = (char *)stackblock() + startloc; | 7572 | startp = (char *)stackblock() + startloc; |
7575 | //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc); | 7573 | //bb_error_msg("str1:'%s'", (char *)stackblock() + strloc); |
7576 | 7574 | ||
7577 | switch (subtype) { | 7575 | switch (subtype) { |
7578 | case VSASSIGN: | 7576 | case VSASSIGN: |
7579 | setvar0(varname, startp); | 7577 | setvar0(str, startp); |
7580 | amount = startp - expdest; | 7578 | |
7581 | STADJUST(amount, expdest); | 7579 | loc = startp; |
7582 | return startp; | 7580 | goto out; |
7583 | 7581 | ||
7584 | case VSQUESTION: | 7582 | case VSQUESTION: |
7585 | varunset(p, varname, startp, varflags); | 7583 | varunset(start, str, startp, varflags); |
7586 | /* NOTREACHED */ | 7584 | /* NOTREACHED */ |
7587 | 7585 | ||
7588 | #if BASH_SUBSTR | 7586 | #if BASH_SUBSTR |
7589 | case VSSUBSTR: { | 7587 | case VSSUBSTR: { |
7590 | int pos, len, orig_len; | 7588 | int pos, len, orig_len; |
7591 | char *colon; | 7589 | char *colon; |
7590 | char *vstr; | ||
7592 | 7591 | ||
7593 | loc = str = stackblock() + strloc; | 7592 | loc = vstr = stackblock() + strloc; |
7594 | 7593 | ||
7595 | /* Read POS in ${var:POS:LEN} */ | 7594 | /* Read POS in ${var:POS:LEN} */ |
7596 | colon = strchr(loc, ':'); | 7595 | colon = strchr(loc, ':'); |
@@ -7599,12 +7598,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7599 | if (colon) *colon = ':'; | 7598 | if (colon) *colon = ':'; |
7600 | 7599 | ||
7601 | /* Read LEN in ${var:POS:LEN} */ | 7600 | /* Read LEN in ${var:POS:LEN} */ |
7602 | len = str - startp - 1; | 7601 | len = vstr - startp - 1; |
7603 | /* *loc != '\0', guaranteed by parser */ | 7602 | /* *loc != '\0', guaranteed by parser */ |
7604 | if (quotes) { | 7603 | if (quotes) { |
7605 | char *ptr; | 7604 | char *ptr; |
7606 | /* Adjust the length by the number of escapes */ | 7605 | /* Adjust the length by the number of escapes */ |
7607 | for (ptr = startp; ptr < (str - 1); ptr++) { | 7606 | for (ptr = startp; ptr < (vstr - 1); ptr++) { |
7608 | if ((unsigned char)*ptr == CTLESC) { | 7607 | if ((unsigned char)*ptr == CTLESC) { |
7609 | len--; | 7608 | len--; |
7610 | ptr++; | 7609 | ptr++; |
@@ -7642,19 +7641,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7642 | if ((unsigned)len > (orig_len - pos)) | 7641 | if ((unsigned)len > (orig_len - pos)) |
7643 | len = orig_len - pos; | 7642 | len = orig_len - pos; |
7644 | 7643 | ||
7645 | for (str = startp; pos; str++, pos--) { | 7644 | for (vstr = startp; pos; vstr++, pos--) { |
7646 | if (quotes && (unsigned char)*str == CTLESC) | 7645 | if (quotes && (unsigned char)*vstr == CTLESC) |
7647 | str++; | 7646 | vstr++; |
7648 | } | 7647 | } |
7649 | for (loc = startp; len; len--) { | 7648 | for (loc = startp; len; len--) { |
7650 | if (quotes && (unsigned char)*str == CTLESC) | 7649 | if (quotes && (unsigned char)*vstr == CTLESC) |
7651 | *loc++ = *str++; | 7650 | *loc++ = *vstr++; |
7652 | *loc++ = *str++; | 7651 | *loc++ = *vstr++; |
7653 | } | 7652 | } |
7654 | *loc = '\0'; | 7653 | *loc = '\0'; |
7655 | amount = loc - expdest; | 7654 | goto out; |
7656 | STADJUST(amount, expdest); | ||
7657 | return loc; | ||
7658 | } | 7655 | } |
7659 | #endif /* BASH_SUBSTR */ | 7656 | #endif /* BASH_SUBSTR */ |
7660 | } | 7657 | } |
@@ -7720,7 +7717,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7720 | 7717 | ||
7721 | /* If there's no pattern to match, return the expansion unmolested */ | 7718 | /* If there's no pattern to match, return the expansion unmolested */ |
7722 | if (str[0] == '\0') | 7719 | if (str[0] == '\0') |
7723 | return NULL; | 7720 | goto out1; |
7724 | 7721 | ||
7725 | len = 0; | 7722 | len = 0; |
7726 | idx = startp; | 7723 | idx = startp; |
@@ -7801,9 +7798,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7801 | startp = (char *)stackblock() + startloc; | 7798 | startp = (char *)stackblock() + startloc; |
7802 | memmove(startp, (char *)stackblock() + workloc, len + 1); | 7799 | memmove(startp, (char *)stackblock() + workloc, len + 1); |
7803 | //bb_error_msg("startp:'%s'", startp); | 7800 | //bb_error_msg("startp:'%s'", startp); |
7804 | amount = expdest - (startp + len); | 7801 | loc = startp + len; |
7805 | STADJUST(-amount, expdest); | 7802 | goto out; |
7806 | return startp; | ||
7807 | } | 7803 | } |
7808 | #endif /* BASH_PATTERN_SUBST */ | 7804 | #endif /* BASH_PATTERN_SUBST */ |
7809 | 7805 | ||
@@ -7824,10 +7820,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
7824 | loc = startp + (str - loc) - 1; | 7820 | loc = startp + (str - loc) - 1; |
7825 | } | 7821 | } |
7826 | *loc = '\0'; | 7822 | *loc = '\0'; |
7827 | amount = loc - expdest; | 7823 | } else |
7828 | STADJUST(amount, expdest); | 7824 | loc = str - 1; |
7829 | } | 7825 | |
7830 | return loc; | 7826 | out: |
7827 | amount = loc - expdest; | ||
7828 | STADJUST(amount, expdest); | ||
7829 | out1: | ||
7830 | /* Remove any recorded regions beyond start of variable */ | ||
7831 | removerecordregions(startloc); | ||
7832 | |||
7833 | return p; | ||
7831 | } | 7834 | } |
7832 | 7835 | ||
7833 | /* | 7836 | /* |
@@ -7852,7 +7855,14 @@ varvalue(char *name, int varflags, int flags, int quoted) | |||
7852 | ssize_t len = 0; | 7855 | ssize_t len = 0; |
7853 | int sep; | 7856 | int sep; |
7854 | int subtype = varflags & VSTYPE; | 7857 | int subtype = varflags & VSTYPE; |
7855 | int discard = subtype == VSPLUS || subtype == VSLENGTH; | 7858 | int discard = (subtype == VSPLUS || subtype == VSLENGTH) | (flags & EXP_DISCARD); |
7859 | |||
7860 | if (!subtype) { | ||
7861 | if (discard) | ||
7862 | return -1; | ||
7863 | |||
7864 | raise_error_syntax("bad substitution"); | ||
7865 | } | ||
7856 | 7866 | ||
7857 | flags |= EXP_KEEPNUL; | 7867 | flags |= EXP_KEEPNUL; |
7858 | flags &= discard ? ~QUOTES_ESC : ~0; | 7868 | flags &= discard ? ~QUOTES_ESC : ~0; |
@@ -7969,6 +7979,7 @@ varvalue(char *name, int varflags, int flags, int quoted) | |||
7969 | 7979 | ||
7970 | if (discard) | 7980 | if (discard) |
7971 | STADJUST(-len, expdest); | 7981 | STADJUST(-len, expdest); |
7982 | |||
7972 | return len; | 7983 | return len; |
7973 | } | 7984 | } |
7974 | 7985 | ||
@@ -7981,18 +7992,16 @@ evalvar(char *p, int flag) | |||
7981 | { | 7992 | { |
7982 | char varflags; | 7993 | char varflags; |
7983 | char subtype; | 7994 | char subtype; |
7984 | int quoted; | ||
7985 | char *var; | 7995 | char *var; |
7986 | int patloc; | 7996 | int patloc; |
7987 | int startloc; | 7997 | int startloc; |
7988 | ssize_t varlen; | 7998 | ssize_t varlen; |
7999 | int discard; | ||
8000 | int quoted; | ||
7989 | 8001 | ||
7990 | varflags = (unsigned char) *p++; | 8002 | varflags = (unsigned char) *p++; |
7991 | subtype = varflags & VSTYPE; | 8003 | subtype = varflags & VSTYPE; |
7992 | 8004 | ||
7993 | if (!subtype) | ||
7994 | raise_error_syntax("bad substitution"); | ||
7995 | |||
7996 | quoted = flag & EXP_QUOTED; | 8005 | quoted = flag & EXP_QUOTED; |
7997 | var = p; | 8006 | var = p; |
7998 | startloc = expdest - (char *)stackblock(); | 8007 | startloc = expdest - (char *)stackblock(); |
@@ -8003,56 +8012,43 @@ evalvar(char *p, int flag) | |||
8003 | if (varflags & VSNUL) | 8012 | if (varflags & VSNUL) |
8004 | varlen--; | 8013 | varlen--; |
8005 | 8014 | ||
8006 | if (subtype == VSPLUS) { | 8015 | discard = varlen < 0 ? EXP_DISCARD : 0; |
8007 | varlen = -1 - varlen; | ||
8008 | goto vsplus; | ||
8009 | } | ||
8010 | 8016 | ||
8011 | if (subtype == VSMINUS) { | 8017 | switch (subtype) { |
8012 | vsplus: | 8018 | case VSPLUS: |
8013 | if (varlen < 0) { | 8019 | discard ^= EXP_DISCARD; |
8014 | argstr( | 8020 | /* fall through */ |
8015 | p, | 8021 | case 0: |
8016 | flag | EXP_TILDE | EXP_WORD | 8022 | case VSMINUS: |
8017 | ); | 8023 | p = argstr(p, flag | EXP_TILDE | EXP_WORD | (discard ^ EXP_DISCARD)); |
8018 | goto end; | ||
8019 | } | ||
8020 | goto record; | 8024 | goto record; |
8021 | } | ||
8022 | 8025 | ||
8023 | if (subtype == VSASSIGN || subtype == VSQUESTION) { | 8026 | case VSASSIGN: |
8024 | if (varlen >= 0) | 8027 | case VSQUESTION: |
8028 | p = subevalvar(p, var, 0, startloc, varflags, | ||
8029 | (flag & ~QUOTES_ESC) | (discard ^ EXP_DISCARD)); | ||
8030 | |||
8031 | if ((flag | ~discard) & EXP_DISCARD) | ||
8025 | goto record; | 8032 | goto record; |
8026 | 8033 | ||
8027 | subevalvar(p, var, 0, subtype, startloc, varflags, | ||
8028 | flag & ~QUOTES_ESC); | ||
8029 | varflags &= ~VSNUL; | 8034 | varflags &= ~VSNUL; |
8030 | /* | 8035 | subtype = VSNORMAL; |
8031 | * Remove any recorded regions beyond | ||
8032 | * start of variable | ||
8033 | */ | ||
8034 | removerecordregions(startloc); | ||
8035 | goto again; | 8036 | goto again; |
8036 | } | 8037 | } |
8037 | 8038 | ||
8038 | if (varlen < 0 && uflag) | 8039 | if ((discard & ~flag) && uflag) |
8039 | varunset(p, var, 0, 0); | 8040 | varunset(p, var, 0, 0); |
8040 | 8041 | ||
8041 | if (subtype == VSLENGTH) { | 8042 | if (subtype == VSLENGTH) { |
8043 | p++; | ||
8044 | if (flag & EXP_DISCARD) | ||
8045 | return p; | ||
8042 | cvtnum(varlen > 0 ? varlen : 0, flag); | 8046 | cvtnum(varlen > 0 ? varlen : 0, flag); |
8043 | goto record; | 8047 | goto really_record; |
8044 | } | 8048 | } |
8045 | 8049 | ||
8046 | if (subtype == VSNORMAL) { | 8050 | if (subtype == VSNORMAL) |
8047 | record: | 8051 | goto record; |
8048 | if (quoted) { | ||
8049 | quoted = *var == '@' && shellparam.nparam; | ||
8050 | if (!quoted) | ||
8051 | goto end; | ||
8052 | } | ||
8053 | recordregion(startloc, expdest - (char *)stackblock(), quoted); | ||
8054 | goto end; | ||
8055 | } | ||
8056 | 8052 | ||
8057 | #if DEBUG | 8053 | #if DEBUG |
8058 | switch (subtype) { | 8054 | switch (subtype) { |
@@ -8073,46 +8069,29 @@ evalvar(char *p, int flag) | |||
8073 | } | 8069 | } |
8074 | #endif | 8070 | #endif |
8075 | 8071 | ||
8076 | if (varlen >= 0) { | 8072 | flag |= discard; |
8073 | if (!(flag & EXP_DISCARD)) { | ||
8077 | /* | 8074 | /* |
8078 | * Terminate the string and start recording the pattern | 8075 | * Terminate the string and start recording the pattern |
8079 | * right after it | 8076 | * right after it |
8080 | */ | 8077 | */ |
8081 | STPUTC('\0', expdest); | 8078 | STPUTC('\0', expdest); |
8082 | patloc = expdest - (char *)stackblock(); | ||
8083 | if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, | ||
8084 | startloc, varflags, flag)) { | ||
8085 | int amount = expdest - ( | ||
8086 | (char *)stackblock() + patloc - 1 | ||
8087 | ); | ||
8088 | STADJUST(-amount, expdest); | ||
8089 | } | ||
8090 | /* Remove any recorded regions beyond start of variable */ | ||
8091 | removerecordregions(startloc); | ||
8092 | goto record; | ||
8093 | } | 8079 | } |
8094 | 8080 | ||
8095 | varlen = 0; | 8081 | patloc = expdest - (char *)stackblock(); |
8082 | p = subevalvar(p, NULL, patloc, startloc, varflags, flag); | ||
8096 | 8083 | ||
8097 | end: | 8084 | record: |
8098 | if (subtype != VSNORMAL) { /* skip to end of alternative */ | 8085 | if ((flag | discard) & EXP_DISCARD) |
8099 | int nesting = 1; | 8086 | return p; |
8100 | for (;;) { | 8087 | |
8101 | unsigned char c = *p++; | 8088 | really_record: |
8102 | if (c == CTLESC) | 8089 | if (quoted) { |
8103 | p++; | 8090 | quoted = *var == '@' && shellparam.nparam; |
8104 | else if (c == CTLBACKQ) { | 8091 | if (!quoted) |
8105 | if (varlen >= 0) | 8092 | return p; |
8106 | argbackq = argbackq->next; | ||
8107 | } else if (c == CTLVAR) { | ||
8108 | if ((*p++ & VSTYPE) != VSNORMAL) | ||
8109 | nesting++; | ||
8110 | } else if (c == CTLENDVAR) { | ||
8111 | if (--nesting == 0) | ||
8112 | break; | ||
8113 | } | ||
8114 | } | ||
8115 | } | 8093 | } |
8094 | recordregion(startloc, expdest - (char *)stackblock(), quoted); | ||
8116 | return p; | 8095 | return p; |
8117 | } | 8096 | } |
8118 | 8097 | ||
@@ -8533,13 +8512,11 @@ expandarg(union node *arg, struct arglist *arglist, int flag) | |||
8533 | STARTSTACKSTR(expdest); | 8512 | STARTSTACKSTR(expdest); |
8534 | TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); | 8513 | TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); |
8535 | argstr(arg->narg.text, flag); | 8514 | argstr(arg->narg.text, flag); |
8536 | p = _STPUTC('\0', expdest); | ||
8537 | expdest = p - 1; | ||
8538 | if (arglist == NULL) { | 8515 | if (arglist == NULL) { |
8539 | /* here document expanded */ | 8516 | /* here document expanded */ |
8540 | goto out; | 8517 | goto out; |
8541 | } | 8518 | } |
8542 | p = grabstackstr(p); | 8519 | p = grabstackstr(expdest); |
8543 | TRACE(("expandarg: p:'%s'\n", p)); | 8520 | TRACE(("expandarg: p:'%s'\n", p)); |
8544 | exparg.lastp = &exparg.list; | 8521 | exparg.lastp = &exparg.list; |
8545 | /* | 8522 | /* |
@@ -8600,7 +8577,6 @@ casematch(union node *pattern, char *val) | |||
8600 | argbackq = pattern->narg.backquote; | 8577 | argbackq = pattern->narg.backquote; |
8601 | STARTSTACKSTR(expdest); | 8578 | STARTSTACKSTR(expdest); |
8602 | argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); | 8579 | argstr(pattern->narg.text, EXP_TILDE | EXP_CASE); |
8603 | STACKSTRNUL(expdest); | ||
8604 | ifsfree(); | 8580 | ifsfree(); |
8605 | result = patmatch(stackblock(), val); | 8581 | result = patmatch(stackblock(), val); |
8606 | popstackmark(&smark); | 8582 | popstackmark(&smark); |
@@ -11076,7 +11052,6 @@ evalcommand(union node *cmd, int flags) | |||
11076 | fs.fd[0] = cmdentry.u.index; | 11052 | fs.fd[0] = cmdentry.u.index; |
11077 | jp = makejob(/*cmd,*/ 1); | 11053 | jp = makejob(/*cmd,*/ 1); |
11078 | spawn_forkshell(&fs, jp, cmd, FORK_FG); | 11054 | spawn_forkshell(&fs, jp, cmd, FORK_FG); |
11079 | TRACE(("forked child exited with %d\n", status)); | ||
11080 | break; | 11055 | break; |
11081 | } | 11056 | } |
11082 | #else | 11057 | #else |
@@ -11087,7 +11062,6 @@ evalcommand(union node *cmd, int flags) | |||
11087 | jp = makejob(/*cmd,*/ 1); | 11062 | jp = makejob(/*cmd,*/ 1); |
11088 | if (forkshell(jp, cmd, FORK_FG) != 0) { | 11063 | if (forkshell(jp, cmd, FORK_FG) != 0) { |
11089 | /* parent */ | 11064 | /* parent */ |
11090 | TRACE(("forked child exited with %d\n", status)); | ||
11091 | break; | 11065 | break; |
11092 | } | 11066 | } |
11093 | /* child */ | 11067 | /* child */ |
@@ -11114,6 +11088,8 @@ evalcommand(union node *cmd, int flags) | |||
11114 | } /* switch */ | 11088 | } /* switch */ |
11115 | 11089 | ||
11116 | status = waitforjob(jp); | 11090 | status = waitforjob(jp); |
11091 | if (jp) | ||
11092 | TRACE(("forked child exited with %d\n", status)); | ||
11117 | FORCE_INT_ON; | 11093 | FORCE_INT_ON; |
11118 | 11094 | ||
11119 | out: | 11095 | out: |