aboutsummaryrefslogtreecommitdiff
path: root/shell/ash.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/ash.c')
-rw-r--r--shell/ash.c83
1 files changed, 52 insertions, 31 deletions
diff --git a/shell/ash.c b/shell/ash.c
index d8becc37a..16783f2e8 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -6296,13 +6296,14 @@ parse_sub_pattern(char *arg, int inquotes)
6296#endif /* ENABLE_ASH_BASH_COMPAT */ 6296#endif /* ENABLE_ASH_BASH_COMPAT */
6297 6297
6298static const char * 6298static const char *
6299subevalvar(char *p, char *str, int strloc, int subtype, 6299subevalvar(char *p, char *varname, int strloc, int subtype,
6300 int startloc, int varflags, int quotes, struct strlist *var_str_list) 6300 int startloc, int varflags, int quotes, struct strlist *var_str_list)
6301{ 6301{
6302 struct nodelist *saveargbackq = argbackq; 6302 struct nodelist *saveargbackq = argbackq;
6303 char *startp; 6303 char *startp;
6304 char *loc; 6304 char *loc;
6305 char *rmesc, *rmescend; 6305 char *rmesc, *rmescend;
6306 char *str;
6306 IF_ASH_BASH_COMPAT(const char *repl = NULL;) 6307 IF_ASH_BASH_COMPAT(const char *repl = NULL;)
6307 IF_ASH_BASH_COMPAT(int pos, len, orig_len;) 6308 IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
6308 int saveherefd = herefd; 6309 int saveherefd = herefd;
@@ -6310,6 +6311,9 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6310 int zero; 6311 int zero;
6311 char *(*scan)(char*, char*, char*, char*, int, int); 6312 char *(*scan)(char*, char*, char*, char*, int, int);
6312 6313
6314 //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d",
6315 // p, varname, strloc, subtype, startloc, varflags, quotes);
6316
6313 herefd = -1; 6317 herefd = -1;
6314 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, 6318 argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0,
6315 var_str_list); 6319 var_str_list);
@@ -6320,11 +6324,15 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6320 6324
6321 switch (subtype) { 6325 switch (subtype) {
6322 case VSASSIGN: 6326 case VSASSIGN:
6323 setvar(str, startp, 0); 6327 setvar(varname, startp, 0);
6324 amount = startp - expdest; 6328 amount = startp - expdest;
6325 STADJUST(amount, expdest); 6329 STADJUST(amount, expdest);
6326 return startp; 6330 return startp;
6327 6331
6332 case VSQUESTION:
6333 varunset(p, varname, startp, varflags);
6334 /* NOTREACHED */
6335
6328#if ENABLE_ASH_BASH_COMPAT 6336#if ENABLE_ASH_BASH_COMPAT
6329 case VSSUBSTR: 6337 case VSSUBSTR:
6330 loc = str = stackblock() + strloc; 6338 loc = str = stackblock() + strloc;
@@ -6385,11 +6393,8 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6385 STADJUST(amount, expdest); 6393 STADJUST(amount, expdest);
6386 return loc; 6394 return loc;
6387#endif 6395#endif
6388
6389 case VSQUESTION:
6390 varunset(p, str, startp, varflags);
6391 /* NOTREACHED */
6392 } 6396 }
6397
6393 resetloc = expdest - (char *)stackblock(); 6398 resetloc = expdest - (char *)stackblock();
6394 6399
6395 /* We'll comeback here if we grow the stack while handling 6400 /* We'll comeback here if we grow the stack while handling
@@ -6423,13 +6428,14 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6423 6428
6424 if (!repl) { 6429 if (!repl) {
6425 repl = parse_sub_pattern(str, varflags & VSQUOTE); 6430 repl = parse_sub_pattern(str, varflags & VSQUOTE);
6431 //bb_error_msg("repl:'%s'", repl);
6426 if (!repl) 6432 if (!repl)
6427 repl = nullstr; 6433 repl = nullstr;
6428 } 6434 }
6429 6435
6430 /* If there's no pattern to match, return the expansion unmolested */ 6436 /* If there's no pattern to match, return the expansion unmolested */
6431 if (str[0] == '\0') 6437 if (str[0] == '\0')
6432 return 0; 6438 return NULL;
6433 6439
6434 len = 0; 6440 len = 0;
6435 idx = startp; 6441 idx = startp;
@@ -6437,6 +6443,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6437 while (idx < end) { 6443 while (idx < end) {
6438 try_to_match: 6444 try_to_match:
6439 loc = scanright(idx, rmesc, rmescend, str, quotes, 1); 6445 loc = scanright(idx, rmesc, rmescend, str, quotes, 1);
6446 //bb_error_msg("scanright('%s'):'%s'", str, loc);
6440 if (!loc) { 6447 if (!loc) {
6441 /* No match, advance */ 6448 /* No match, advance */
6442 char *restart_detect = stackblock(); 6449 char *restart_detect = stackblock();
@@ -6475,6 +6482,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6475 idx = loc; 6482 idx = loc;
6476 } 6483 }
6477 6484
6485 //bb_error_msg("repl:'%s'", repl);
6478 for (loc = (char*)repl; *loc; loc++) { 6486 for (loc = (char*)repl; *loc; loc++) {
6479 char *restart_detect = stackblock(); 6487 char *restart_detect = stackblock();
6480 if (quotes && *loc == '\\') { 6488 if (quotes && *loc == '\\') {
@@ -6510,6 +6518,7 @@ subevalvar(char *p, char *str, int strloc, int subtype,
6510 STPUTC('\0', expdest); 6518 STPUTC('\0', expdest);
6511 startp = (char *)stackblock() + startloc; 6519 startp = (char *)stackblock() + startloc;
6512 memmove(startp, (char *)stackblock() + workloc, len + 1); 6520 memmove(startp, (char *)stackblock() + workloc, len + 1);
6521 //bb_error_msg("startp:'%s'", startp);
6513 amount = expdest - (startp + len); 6522 amount = expdest - (startp + len);
6514 STADJUST(-amount, expdest); 6523 STADJUST(-amount, expdest);
6515 return startp; 6524 return startp;
@@ -6810,7 +6819,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list)
6810 */ 6819 */
6811 STPUTC('\0', expdest); 6820 STPUTC('\0', expdest);
6812 patloc = expdest - (char *)stackblock(); 6821 patloc = expdest - (char *)stackblock();
6813 if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, 6822 if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype,
6814 startloc, varflags, 6823 startloc, varflags,
6815//TODO: | EXP_REDIR too? All other such places do it too 6824//TODO: | EXP_REDIR too? All other such places do it too
6816 /* quotes: */ flags & (EXP_FULL | EXP_CASE), 6825 /* quotes: */ flags & (EXP_FULL | EXP_CASE),
@@ -11114,8 +11123,11 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11114 USTPUTC('\\', out); 11123 USTPUTC('\\', out);
11115 } 11124 }
11116#endif 11125#endif
11117 if (dblquote && c != '\\' 11126 /* Backslash is retained if we are in "str" and next char isn't special */
11118 && c != '`' && c != '$' 11127 if (dblquote
11128 && c != '\\'
11129 && c != '`'
11130 && c != '$'
11119 && (c != '"' || eofmark != NULL) 11131 && (c != '"' || eofmark != NULL)
11120 ) { 11132 ) {
11121 USTPUTC(CTLESC, out); 11133 USTPUTC(CTLESC, out);
@@ -11187,7 +11199,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs)
11187 } else { 11199 } else {
11188 /* 11200 /*
11189 * unbalanced parens 11201 * unbalanced parens
11190 * (don't 2nd guess - no error) 11202 * (don't 2nd guess - no error)
11191 */ 11203 */
11192 pungetc(); 11204 pungetc();
11193 USTPUTC(')', out); 11205 USTPUTC(')', out);
@@ -11380,8 +11392,6 @@ parsesub: {
11380 unsigned char subtype; 11392 unsigned char subtype;
11381 int typeloc; 11393 int typeloc;
11382 int flags; 11394 int flags;
11383 char *p;
11384 static const char types[] ALIGN1 = "}-+?=";
11385 11395
11386 c = pgetc(); 11396 c = pgetc();
11387 if (c > 255 /* PEOA or PEOF */ 11397 if (c > 255 /* PEOA or PEOF */
@@ -11394,7 +11404,8 @@ parsesub: {
11394#endif 11404#endif
11395 USTPUTC('$', out); 11405 USTPUTC('$', out);
11396 pungetc(); 11406 pungetc();
11397 } else if (c == '(') { /* $(command) or $((arith)) */ 11407 } else if (c == '(') {
11408 /* $(command) or $((arith)) */
11398 if (pgetc() == '(') { 11409 if (pgetc() == '(') {
11399#if ENABLE_SH_MATH_SUPPORT 11410#if ENABLE_SH_MATH_SUPPORT
11400 PARSEARITH(); 11411 PARSEARITH();
@@ -11406,6 +11417,7 @@ parsesub: {
11406 PARSEBACKQNEW(); 11417 PARSEBACKQNEW();
11407 } 11418 }
11408 } else { 11419 } else {
11420 /* $VAR, $<specialchar>, ${...}, or PEOA/PEOF */
11409 USTPUTC(CTLVAR, out); 11421 USTPUTC(CTLVAR, out);
11410 typeloc = out - (char *)stackblock(); 11422 typeloc = out - (char *)stackblock();
11411 USTPUTC(VSNORMAL, out); 11423 USTPUTC(VSNORMAL, out);
@@ -11415,76 +11427,85 @@ parsesub: {
11415 if (c == '#') { 11427 if (c == '#') {
11416 c = pgetc(); 11428 c = pgetc();
11417 if (c == '}') 11429 if (c == '}')
11418 c = '#'; 11430 c = '#'; /* ${#} - same as $# */
11419 else 11431 else
11420 subtype = VSLENGTH; 11432 subtype = VSLENGTH; /* ${#VAR} */
11421 } else 11433 } else {
11422 subtype = 0; 11434 subtype = 0;
11435 }
11423 } 11436 }
11424 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { 11437 if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) {
11438 /* $[{[#]]NAME[}] */
11425 do { 11439 do {
11426 STPUTC(c, out); 11440 STPUTC(c, out);
11427 c = pgetc(); 11441 c = pgetc();
11428 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); 11442 } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c));
11429 } else if (isdigit(c)) { 11443 } else if (isdigit(c)) {
11444 /* $[{[#]]NUM[}] */
11430 do { 11445 do {
11431 STPUTC(c, out); 11446 STPUTC(c, out);
11432 c = pgetc(); 11447 c = pgetc();
11433 } while (isdigit(c)); 11448 } while (isdigit(c));
11434 } else if (is_special(c)) { 11449 } else if (is_special(c)) {
11450 /* $[{[#]]<specialchar>[}] */
11435 USTPUTC(c, out); 11451 USTPUTC(c, out);
11436 c = pgetc(); 11452 c = pgetc();
11437 } else { 11453 } else {
11438 badsub: 11454 badsub:
11439 raise_error_syntax("bad substitution"); 11455 raise_error_syntax("bad substitution");
11440 } 11456 }
11441 if (c != '}' && subtype == VSLENGTH) 11457 if (c != '}' && subtype == VSLENGTH) {
11458 /* ${#VAR didn't end with } */
11442 goto badsub; 11459 goto badsub;
11460 }
11443 11461
11444 STPUTC('=', out); 11462 STPUTC('=', out);
11445 flags = 0; 11463 flags = 0;
11446 if (subtype == 0) { 11464 if (subtype == 0) {
11465 /* ${VAR...} but not $VAR or ${#VAR} */
11466 /* c == first char after VAR */
11447 switch (c) { 11467 switch (c) {
11448 case ':': 11468 case ':':
11449 c = pgetc(); 11469 c = pgetc();
11450#if ENABLE_ASH_BASH_COMPAT 11470#if ENABLE_ASH_BASH_COMPAT
11451 if (c == ':' || c == '$' || isdigit(c)) { 11471 if (c == ':' || c == '$' || isdigit(c)) {
11452 pungetc();
11453 subtype = VSSUBSTR; 11472 subtype = VSSUBSTR;
11454 break; 11473 pungetc();
11474 break; /* "goto do_pungetc" is bigger (!) */
11455 } 11475 }
11456#endif 11476#endif
11457 flags = VSNUL; 11477 flags = VSNUL;
11458 /*FALLTHROUGH*/ 11478 /*FALLTHROUGH*/
11459 default: 11479 default: {
11460 p = strchr(types, c); 11480 static const char types[] ALIGN1 = "}-+?=";
11481 const char *p = strchr(types, c);
11461 if (p == NULL) 11482 if (p == NULL)
11462 goto badsub; 11483 goto badsub;
11463 subtype = p - types + VSNORMAL; 11484 subtype = p - types + VSNORMAL;
11464 break; 11485 break;
11486 }
11465 case '%': 11487 case '%':
11466 case '#': { 11488 case '#': {
11467 int cc = c; 11489 int cc = c;
11468 subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; 11490 subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT);
11469 c = pgetc(); 11491 c = pgetc();
11470 if (c == cc) 11492 if (c != cc)
11471 subtype++; 11493 goto do_pungetc;
11472 else 11494 subtype++;
11473 pungetc();
11474 break; 11495 break;
11475 } 11496 }
11476#if ENABLE_ASH_BASH_COMPAT 11497#if ENABLE_ASH_BASH_COMPAT
11477 case '/': 11498 case '/':
11478 subtype = VSREPLACE; 11499 subtype = VSREPLACE;
11479 c = pgetc(); 11500 c = pgetc();
11480 if (c == '/') 11501 if (c != '/')
11481 subtype++; /* VSREPLACEALL */ 11502 goto do_pungetc;
11482 else 11503 subtype++; /* VSREPLACEALL */
11483 pungetc();
11484 break; 11504 break;
11485#endif 11505#endif
11486 } 11506 }
11487 } else { 11507 } else {
11508 do_pungetc:
11488 pungetc(); 11509 pungetc();
11489 } 11510 }
11490 if (dblquote || arinest) 11511 if (dblquote || arinest)