diff options
author | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 14:09:23 +1000 |
---|---|---|
committer | Nguyễn Thái Ngọc Duy <pclouds@gmail.com> | 2010-09-14 14:09:23 +1000 |
commit | ee7c9b2c212fc7db80cce945e094fc2601092283 (patch) | |
tree | 24e51b27dbc3e9ab0b00c5839a6822604c02187c /shell/ash.c | |
parent | f28d4b20905b5b1f52ffa52060a0c6caf4b055ba (diff) | |
parent | 99862cbfad9c36b4f8f4378c3a7a9f077c239f20 (diff) | |
download | busybox-w32-ee7c9b2c212fc7db80cce945e094fc2601092283.tar.gz busybox-w32-ee7c9b2c212fc7db80cce945e094fc2601092283.tar.bz2 busybox-w32-ee7c9b2c212fc7db80cce945e094fc2601092283.zip |
Merge remote branch 'origin/master'
Diffstat (limited to 'shell/ash.c')
-rw-r--r-- | shell/ash.c | 388 |
1 files changed, 189 insertions, 199 deletions
diff --git a/shell/ash.c b/shell/ash.c index 6d67a1f8a..0ff5adb04 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -88,7 +88,7 @@ | |||
88 | //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) | 88 | //applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) |
89 | //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) | 89 | //applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) |
90 | 90 | ||
91 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o | 91 | //kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o |
92 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o | 92 | //kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o |
93 | 93 | ||
94 | //config:config ASH | 94 | //config:config ASH |
@@ -1002,7 +1002,8 @@ sharg(union node *arg, FILE *fp) | |||
1002 | for (p = arg->narg.text; *p; p++) { | 1002 | for (p = arg->narg.text; *p; p++) { |
1003 | switch ((unsigned char)*p) { | 1003 | switch ((unsigned char)*p) { |
1004 | case CTLESC: | 1004 | case CTLESC: |
1005 | putc(*++p, fp); | 1005 | p++; |
1006 | putc(*p, fp); | ||
1006 | break; | 1007 | break; |
1007 | case CTLVAR: | 1008 | case CTLVAR: |
1008 | putc('$', fp); | 1009 | putc('$', fp); |
@@ -1011,8 +1012,10 @@ sharg(union node *arg, FILE *fp) | |||
1011 | if (subtype == VSLENGTH) | 1012 | if (subtype == VSLENGTH) |
1012 | putc('#', fp); | 1013 | putc('#', fp); |
1013 | 1014 | ||
1014 | while (*p != '=') | 1015 | while (*p != '=') { |
1015 | putc(*p++, fp); | 1016 | putc(*p, fp); |
1017 | p++; | ||
1018 | } | ||
1016 | 1019 | ||
1017 | if (subtype & VSNUL) | 1020 | if (subtype & VSNUL) |
1018 | putc(':', fp); | 1021 | putc(':', fp); |
@@ -2031,10 +2034,6 @@ extern struct globals_var *const ash_ptr_to_globals_var; | |||
2031 | # define optindval() (voptind.var_text + 7) | 2034 | # define optindval() (voptind.var_text + 7) |
2032 | #endif | 2035 | #endif |
2033 | 2036 | ||
2034 | |||
2035 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
2036 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
2037 | |||
2038 | #if ENABLE_ASH_GETOPTS | 2037 | #if ENABLE_ASH_GETOPTS |
2039 | static void FAST_FUNC | 2038 | static void FAST_FUNC |
2040 | getoptsreset(const char *value) | 2039 | getoptsreset(const char *value) |
@@ -2044,24 +2043,26 @@ getoptsreset(const char *value) | |||
2044 | } | 2043 | } |
2045 | #endif | 2044 | #endif |
2046 | 2045 | ||
2046 | /* math.h has these, otherwise define our private copies */ | ||
2047 | #if !ENABLE_SH_MATH_SUPPORT | ||
2048 | #define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) | ||
2049 | #define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) | ||
2047 | /* | 2050 | /* |
2048 | * Return of a legal variable name (a letter or underscore followed by zero or | 2051 | * Return the pointer to the first char which is not part of a legal variable name |
2049 | * more letters, underscores, and digits). | 2052 | * (a letter or underscore followed by letters, underscores, and digits). |
2050 | */ | 2053 | */ |
2051 | static char* FAST_FUNC | 2054 | static const char* |
2052 | endofname(const char *name) | 2055 | endofname(const char *name) |
2053 | { | 2056 | { |
2054 | char *p; | 2057 | if (!is_name(*name)) |
2055 | 2058 | return name; | |
2056 | p = (char *) name; | 2059 | while (*++name) { |
2057 | if (!is_name(*p)) | 2060 | if (!is_in_name(*name)) |
2058 | return p; | ||
2059 | while (*++p) { | ||
2060 | if (!is_in_name(*p)) | ||
2061 | break; | 2061 | break; |
2062 | } | 2062 | } |
2063 | return p; | 2063 | return name; |
2064 | } | 2064 | } |
2065 | #endif | ||
2065 | 2066 | ||
2066 | /* | 2067 | /* |
2067 | * Compares two strings up to the first = or '\0'. The first | 2068 | * Compares two strings up to the first = or '\0'. The first |
@@ -2244,9 +2245,10 @@ setvareq(char *s, int flags) | |||
2244 | static void | 2245 | static void |
2245 | setvar(const char *name, const char *val, int flags) | 2246 | setvar(const char *name, const char *val, int flags) |
2246 | { | 2247 | { |
2247 | char *p, *q; | 2248 | const char *q; |
2248 | size_t namelen; | 2249 | char *p; |
2249 | char *nameeq; | 2250 | char *nameeq; |
2251 | size_t namelen; | ||
2250 | size_t vallen; | 2252 | size_t vallen; |
2251 | 2253 | ||
2252 | q = endofname(name); | 2254 | q = endofname(name); |
@@ -2260,12 +2262,13 @@ setvar(const char *name, const char *val, int flags) | |||
2260 | } else { | 2262 | } else { |
2261 | vallen = strlen(val); | 2263 | vallen = strlen(val); |
2262 | } | 2264 | } |
2265 | |||
2263 | INT_OFF; | 2266 | INT_OFF; |
2264 | nameeq = ckmalloc(namelen + vallen + 2); | 2267 | nameeq = ckmalloc(namelen + vallen + 2); |
2265 | p = (char *)memcpy(nameeq, name, namelen) + namelen; | 2268 | p = memcpy(nameeq, name, namelen) + namelen; |
2266 | if (val) { | 2269 | if (val) { |
2267 | *p++ = '='; | 2270 | *p++ = '='; |
2268 | p = (char *)memcpy(p, val, vallen) + vallen; | 2271 | p = memcpy(p, val, vallen) + vallen; |
2269 | } | 2272 | } |
2270 | *p = '\0'; | 2273 | *p = '\0'; |
2271 | setvareq(nameeq, flags | VNOSAVE); | 2274 | setvareq(nameeq, flags | VNOSAVE); |
@@ -2491,12 +2494,13 @@ static const char *expandstr(const char *ps); | |||
2491 | #endif | 2494 | #endif |
2492 | 2495 | ||
2493 | static void | 2496 | static void |
2494 | setprompt(int whichprompt) | 2497 | setprompt_if(smallint do_set, int whichprompt) |
2495 | { | 2498 | { |
2496 | const char *prompt; | 2499 | const char *prompt; |
2497 | #if ENABLE_ASH_EXPAND_PRMT | 2500 | IF_ASH_EXPAND_PRMT(struct stackmark smark;) |
2498 | struct stackmark smark; | 2501 | |
2499 | #endif | 2502 | if (!do_set) |
2503 | return; | ||
2500 | 2504 | ||
2501 | needprompt = 0; | 2505 | needprompt = 0; |
2502 | 2506 | ||
@@ -5734,7 +5738,7 @@ ash_arith(const char *s) | |||
5734 | 5738 | ||
5735 | math_hooks.lookupvar = lookupvar; | 5739 | math_hooks.lookupvar = lookupvar; |
5736 | math_hooks.setvar = setvar2; | 5740 | math_hooks.setvar = setvar2; |
5737 | math_hooks.endofname = endofname; | 5741 | //math_hooks.endofname = endofname; |
5738 | 5742 | ||
5739 | INT_OFF; | 5743 | INT_OFF; |
5740 | result = arith(s, &errcode, &math_hooks); | 5744 | result = arith(s, &errcode, &math_hooks); |
@@ -6326,7 +6330,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6326 | flags &= ~EXP_TILDE; | 6330 | flags &= ~EXP_TILDE; |
6327 | tilde: | 6331 | tilde: |
6328 | q = p; | 6332 | q = p; |
6329 | if (*q == CTLESC && (flags & EXP_QWORD)) | 6333 | if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) |
6330 | q++; | 6334 | q++; |
6331 | if (*q == '~') | 6335 | if (*q == '~') |
6332 | p = exptilde(p, q, flags); | 6336 | p = exptilde(p, q, flags); |
@@ -6340,9 +6344,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6340 | c = p[length]; | 6344 | c = p[length]; |
6341 | if (c) { | 6345 | if (c) { |
6342 | if (!(c & 0x80) | 6346 | if (!(c & 0x80) |
6343 | #if ENABLE_SH_MATH_SUPPORT | 6347 | IF_SH_MATH_SUPPORT(|| c == CTLENDARI) |
6344 | || c == CTLENDARI | ||
6345 | #endif | ||
6346 | ) { | 6348 | ) { |
6347 | /* c == '=' || c == ':' || c == CTLENDARI */ | 6349 | /* c == '=' || c == ':' || c == CTLENDARI */ |
6348 | length++; | 6350 | length++; |
@@ -6389,8 +6391,8 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6389 | /* "$@" syntax adherence hack */ | 6391 | /* "$@" syntax adherence hack */ |
6390 | if (!inquotes | 6392 | if (!inquotes |
6391 | && memcmp(p, dolatstr, 4) == 0 | 6393 | && memcmp(p, dolatstr, 4) == 0 |
6392 | && ( p[4] == CTLQUOTEMARK | 6394 | && ( p[4] == (char)CTLQUOTEMARK |
6393 | || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK) | 6395 | || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) |
6394 | ) | 6396 | ) |
6395 | ) { | 6397 | ) { |
6396 | p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; | 6398 | p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; |
@@ -6425,8 +6427,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) | |||
6425 | #endif | 6427 | #endif |
6426 | } | 6428 | } |
6427 | } | 6429 | } |
6428 | breakloop: | 6430 | breakloop: ; |
6429 | ; | ||
6430 | } | 6431 | } |
6431 | 6432 | ||
6432 | static char * | 6433 | static char * |
@@ -6611,8 +6612,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, | |||
6611 | int zero; | 6612 | int zero; |
6612 | char *(*scan)(char*, char*, char*, char*, int, int); | 6613 | char *(*scan)(char*, char*, char*, char*, int, int); |
6613 | 6614 | ||
6614 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d", | 6615 | //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", |
6615 | // p, varname, strloc, subtype, startloc, varflags, quotes); | 6616 | // p, varname, strloc, subtype, startloc, varflags, quotes); |
6616 | 6617 | ||
6617 | herefd = -1; | 6618 | herefd = -1; |
6618 | argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, | 6619 | argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, |
@@ -7045,8 +7046,8 @@ evalvar(char *p, int flags, struct strlist *var_str_list) | |||
7045 | vsplus: | 7046 | vsplus: |
7046 | if (varlen < 0) { | 7047 | if (varlen < 0) { |
7047 | argstr( | 7048 | argstr( |
7048 | p, flags | EXP_TILDE | | 7049 | p, |
7049 | (quoted ? EXP_QWORD : EXP_WORD), | 7050 | flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), |
7050 | var_str_list | 7051 | var_str_list |
7051 | ); | 7052 | ); |
7052 | goto end; | 7053 | goto end; |
@@ -9870,7 +9871,7 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv) | |||
9870 | static int | 9871 | static int |
9871 | goodname(const char *p) | 9872 | goodname(const char *p) |
9872 | { | 9873 | { |
9873 | return !*endofname(p); | 9874 | return endofname(p)[0] == '\0'; |
9874 | } | 9875 | } |
9875 | 9876 | ||
9876 | 9877 | ||
@@ -11501,7 +11502,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11501 | startlinno = g_parsefile->linno; | 11502 | startlinno = g_parsefile->linno; |
11502 | bqlist = NULL; | 11503 | bqlist = NULL; |
11503 | quotef = 0; | 11504 | quotef = 0; |
11504 | oldstyle = 0; | ||
11505 | prevsyntax = 0; | 11505 | prevsyntax = 0; |
11506 | #if ENABLE_ASH_EXPAND_PRMT | 11506 | #if ENABLE_ASH_EXPAND_PRMT |
11507 | pssyntax = (syntax == PSSYNTAX); | 11507 | pssyntax = (syntax == PSSYNTAX); |
@@ -11517,159 +11517,156 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) | |||
11517 | STARTSTACKSTR(out); | 11517 | STARTSTACKSTR(out); |
11518 | loop: | 11518 | loop: |
11519 | /* For each line, until end of word */ | 11519 | /* For each line, until end of word */ |
11520 | { | 11520 | CHECKEND(); /* set c to PEOF if at end of here document */ |
11521 | CHECKEND(); /* set c to PEOF if at end of here document */ | 11521 | for (;;) { /* until end of line or end of word */ |
11522 | for (;;) { /* until end of line or end of word */ | 11522 | CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ |
11523 | CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ | 11523 | switch (SIT(c, syntax)) { |
11524 | switch (SIT(c, syntax)) { | 11524 | case CNL: /* '\n' */ |
11525 | case CNL: /* '\n' */ | 11525 | if (syntax == BASESYNTAX) |
11526 | if (syntax == BASESYNTAX) | 11526 | goto endword; /* exit outer loop */ |
11527 | goto endword; /* exit outer loop */ | 11527 | USTPUTC(c, out); |
11528 | USTPUTC(c, out); | 11528 | g_parsefile->linno++; |
11529 | g_parsefile->linno++; | 11529 | setprompt_if(doprompt, 2); |
11530 | if (doprompt) | 11530 | c = pgetc(); |
11531 | setprompt(2); | 11531 | goto loop; /* continue outer loop */ |
11532 | c = pgetc(); | 11532 | case CWORD: |
11533 | goto loop; /* continue outer loop */ | 11533 | USTPUTC(c, out); |
11534 | case CWORD: | 11534 | break; |
11535 | USTPUTC(c, out); | 11535 | case CCTL: |
11536 | break; | 11536 | if (eofmark == NULL || dblquote) |
11537 | case CCTL: | 11537 | USTPUTC(CTLESC, out); |
11538 | if (eofmark == NULL || dblquote) | ||
11539 | USTPUTC(CTLESC, out); | ||
11540 | #if ENABLE_ASH_BASH_COMPAT | 11538 | #if ENABLE_ASH_BASH_COMPAT |
11541 | if (c == '\\' && bash_dollar_squote) { | 11539 | if (c == '\\' && bash_dollar_squote) { |
11542 | c = decode_dollar_squote(); | 11540 | c = decode_dollar_squote(); |
11543 | if (c & 0x100) { | 11541 | if (c & 0x100) { |
11544 | USTPUTC('\\', out); | 11542 | USTPUTC('\\', out); |
11545 | c = (unsigned char)c; | 11543 | c = (unsigned char)c; |
11546 | } | ||
11547 | } | 11544 | } |
11545 | } | ||
11548 | #endif | 11546 | #endif |
11549 | USTPUTC(c, out); | 11547 | USTPUTC(c, out); |
11550 | break; | 11548 | break; |
11551 | case CBACK: /* backslash */ | 11549 | case CBACK: /* backslash */ |
11552 | c = pgetc_without_PEOA(); | 11550 | c = pgetc_without_PEOA(); |
11553 | if (c == PEOF) { | 11551 | if (c == PEOF) { |
11552 | USTPUTC(CTLESC, out); | ||
11553 | USTPUTC('\\', out); | ||
11554 | pungetc(); | ||
11555 | } else if (c == '\n') { | ||
11556 | setprompt_if(doprompt, 2); | ||
11557 | } else { | ||
11558 | #if ENABLE_ASH_EXPAND_PRMT | ||
11559 | if (c == '$' && pssyntax) { | ||
11554 | USTPUTC(CTLESC, out); | 11560 | USTPUTC(CTLESC, out); |
11555 | USTPUTC('\\', out); | 11561 | USTPUTC('\\', out); |
11556 | pungetc(); | 11562 | } |
11557 | } else if (c == '\n') { | ||
11558 | if (doprompt) | ||
11559 | setprompt(2); | ||
11560 | } else { | ||
11561 | #if ENABLE_ASH_EXPAND_PRMT | ||
11562 | if (c == '$' && pssyntax) { | ||
11563 | USTPUTC(CTLESC, out); | ||
11564 | USTPUTC('\\', out); | ||
11565 | } | ||
11566 | #endif | 11563 | #endif |
11567 | /* Backslash is retained if we are in "str" and next char isn't special */ | 11564 | /* Backslash is retained if we are in "str" and next char isn't special */ |
11568 | if (dblquote | 11565 | if (dblquote |
11569 | && c != '\\' | 11566 | && c != '\\' |
11570 | && c != '`' | 11567 | && c != '`' |
11571 | && c != '$' | 11568 | && c != '$' |
11572 | && (c != '"' || eofmark != NULL) | 11569 | && (c != '"' || eofmark != NULL) |
11573 | ) { | 11570 | ) { |
11574 | USTPUTC(CTLESC, out); | 11571 | USTPUTC(CTLESC, out); |
11575 | USTPUTC('\\', out); | 11572 | USTPUTC('\\', out); |
11576 | } | ||
11577 | if (SIT(c, SQSYNTAX) == CCTL) | ||
11578 | USTPUTC(CTLESC, out); | ||
11579 | USTPUTC(c, out); | ||
11580 | quotef = 1; | ||
11581 | } | 11573 | } |
11582 | break; | 11574 | if (SIT(c, SQSYNTAX) == CCTL) |
11583 | case CSQUOTE: | 11575 | USTPUTC(CTLESC, out); |
11584 | syntax = SQSYNTAX; | 11576 | USTPUTC(c, out); |
11577 | quotef = 1; | ||
11578 | } | ||
11579 | break; | ||
11580 | case CSQUOTE: | ||
11581 | syntax = SQSYNTAX; | ||
11585 | quotemark: | 11582 | quotemark: |
11586 | if (eofmark == NULL) { | 11583 | if (eofmark == NULL) { |
11587 | USTPUTC(CTLQUOTEMARK, out); | 11584 | USTPUTC(CTLQUOTEMARK, out); |
11585 | } | ||
11586 | break; | ||
11587 | case CDQUOTE: | ||
11588 | syntax = DQSYNTAX; | ||
11589 | dblquote = 1; | ||
11590 | goto quotemark; | ||
11591 | case CENDQUOTE: | ||
11592 | IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) | ||
11593 | if (eofmark != NULL && arinest == 0 | ||
11594 | && varnest == 0 | ||
11595 | ) { | ||
11596 | USTPUTC(c, out); | ||
11597 | } else { | ||
11598 | if (dqvarnest == 0) { | ||
11599 | syntax = BASESYNTAX; | ||
11600 | dblquote = 0; | ||
11588 | } | 11601 | } |
11589 | break; | 11602 | quotef = 1; |
11590 | case CDQUOTE: | ||
11591 | syntax = DQSYNTAX; | ||
11592 | dblquote = 1; | ||
11593 | goto quotemark; | 11603 | goto quotemark; |
11594 | case CENDQUOTE: | 11604 | } |
11595 | IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) | 11605 | break; |
11596 | if (eofmark != NULL && arinest == 0 | 11606 | case CVAR: /* '$' */ |
11597 | && varnest == 0 | 11607 | PARSESUB(); /* parse substitution */ |
11598 | ) { | 11608 | break; |
11599 | USTPUTC(c, out); | 11609 | case CENDVAR: /* '}' */ |
11600 | } else { | 11610 | if (varnest > 0) { |
11601 | if (dqvarnest == 0) { | 11611 | varnest--; |
11602 | syntax = BASESYNTAX; | 11612 | if (dqvarnest > 0) { |
11603 | dblquote = 0; | 11613 | dqvarnest--; |
11604 | } | ||
11605 | quotef = 1; | ||
11606 | goto quotemark; | ||
11607 | } | ||
11608 | break; | ||
11609 | case CVAR: /* '$' */ | ||
11610 | PARSESUB(); /* parse substitution */ | ||
11611 | break; | ||
11612 | case CENDVAR: /* '}' */ | ||
11613 | if (varnest > 0) { | ||
11614 | varnest--; | ||
11615 | if (dqvarnest > 0) { | ||
11616 | dqvarnest--; | ||
11617 | } | ||
11618 | c = CTLENDVAR; | ||
11619 | } | 11614 | } |
11620 | USTPUTC(c, out); | 11615 | c = CTLENDVAR; |
11621 | break; | 11616 | } |
11617 | USTPUTC(c, out); | ||
11618 | break; | ||
11622 | #if ENABLE_SH_MATH_SUPPORT | 11619 | #if ENABLE_SH_MATH_SUPPORT |
11623 | case CLP: /* '(' in arithmetic */ | 11620 | case CLP: /* '(' in arithmetic */ |
11624 | parenlevel++; | 11621 | parenlevel++; |
11625 | USTPUTC(c, out); | 11622 | USTPUTC(c, out); |
11626 | break; | 11623 | break; |
11627 | case CRP: /* ')' in arithmetic */ | 11624 | case CRP: /* ')' in arithmetic */ |
11628 | if (parenlevel > 0) { | 11625 | if (parenlevel > 0) { |
11629 | parenlevel--; | 11626 | parenlevel--; |
11630 | } else { | 11627 | } else { |
11631 | if (pgetc() == ')') { | 11628 | if (pgetc() == ')') { |
11632 | if (--arinest == 0) { | 11629 | if (--arinest == 0) { |
11633 | syntax = prevsyntax; | 11630 | syntax = prevsyntax; |
11634 | dblquote = (syntax == DQSYNTAX); | 11631 | dblquote = (syntax == DQSYNTAX); |
11635 | c = CTLENDARI; | 11632 | c = CTLENDARI; |
11636 | } | ||
11637 | } else { | ||
11638 | /* | ||
11639 | * unbalanced parens | ||
11640 | * (don't 2nd guess - no error) | ||
11641 | */ | ||
11642 | pungetc(); | ||
11643 | } | 11633 | } |
11634 | } else { | ||
11635 | /* | ||
11636 | * unbalanced parens | ||
11637 | * (don't 2nd guess - no error) | ||
11638 | */ | ||
11639 | pungetc(); | ||
11644 | } | 11640 | } |
11645 | USTPUTC(c, out); | 11641 | } |
11646 | break; | 11642 | USTPUTC(c, out); |
11643 | break; | ||
11647 | #endif | 11644 | #endif |
11648 | case CBQUOTE: /* '`' */ | 11645 | case CBQUOTE: /* '`' */ |
11649 | PARSEBACKQOLD(); | 11646 | PARSEBACKQOLD(); |
11650 | break; | 11647 | break; |
11651 | case CENDFILE: | 11648 | case CENDFILE: |
11652 | goto endword; /* exit outer loop */ | 11649 | goto endword; /* exit outer loop */ |
11653 | case CIGN: | 11650 | case CIGN: |
11654 | break; | 11651 | break; |
11655 | default: | 11652 | default: |
11656 | if (varnest == 0) { | 11653 | if (varnest == 0) { |
11657 | #if ENABLE_ASH_BASH_COMPAT | 11654 | #if ENABLE_ASH_BASH_COMPAT |
11658 | if (c == '&') { | 11655 | if (c == '&') { |
11659 | if (pgetc() == '>') | 11656 | if (pgetc() == '>') |
11660 | c = 0x100 + '>'; /* flag &> */ | 11657 | c = 0x100 + '>'; /* flag &> */ |
11661 | pungetc(); | 11658 | pungetc(); |
11662 | } | ||
11663 | #endif | ||
11664 | goto endword; /* exit outer loop */ | ||
11665 | } | 11659 | } |
11666 | IF_ASH_ALIAS(if (c != PEOA)) | 11660 | #endif |
11667 | USTPUTC(c, out); | 11661 | goto endword; /* exit outer loop */ |
11668 | } | 11662 | } |
11669 | c = pgetc_fast(); | 11663 | IF_ASH_ALIAS(if (c != PEOA)) |
11670 | } /* for (;;) */ | 11664 | USTPUTC(c, out); |
11671 | } | 11665 | } |
11666 | c = pgetc_fast(); | ||
11667 | } /* for (;;) */ | ||
11672 | endword: | 11668 | endword: |
11669 | |||
11673 | #if ENABLE_SH_MATH_SUPPORT | 11670 | #if ENABLE_SH_MATH_SUPPORT |
11674 | if (syntax == ARISYNTAX) | 11671 | if (syntax == ARISYNTAX) |
11675 | raise_error_syntax("missing '))'"); | 11672 | raise_error_syntax("missing '))'"); |
@@ -11907,6 +11904,8 @@ parsesub: { | |||
11907 | c = pgetc(); | 11904 | c = pgetc(); |
11908 | #if ENABLE_ASH_BASH_COMPAT | 11905 | #if ENABLE_ASH_BASH_COMPAT |
11909 | if (c == ':' || c == '$' || isdigit(c)) { | 11906 | if (c == ':' || c == '$' || isdigit(c)) { |
11907 | //TODO: support more general format ${v:EXPR:EXPR}, | ||
11908 | // where EXPR follows $(()) rules | ||
11910 | subtype = VSSUBSTR; | 11909 | subtype = VSSUBSTR; |
11911 | pungetc(); | 11910 | pungetc(); |
11912 | break; /* "goto do_pungetc" is bigger (!) */ | 11911 | break; /* "goto do_pungetc" is bigger (!) */ |
@@ -11934,6 +11933,9 @@ parsesub: { | |||
11934 | } | 11933 | } |
11935 | #if ENABLE_ASH_BASH_COMPAT | 11934 | #if ENABLE_ASH_BASH_COMPAT |
11936 | case '/': | 11935 | case '/': |
11936 | /* ${v/[/]pattern/repl} */ | ||
11937 | //TODO: encode pattern and repl separately. | ||
11938 | // Currently ${v/$var_with_slash/repl} is horribly broken | ||
11937 | subtype = VSREPLACE; | 11939 | subtype = VSREPLACE; |
11938 | c = pgetc(); | 11940 | c = pgetc(); |
11939 | if (c != '/') | 11941 | if (c != '/') |
@@ -12000,16 +12002,14 @@ parsebackq: { | |||
12000 | treatment to some slashes, and then push the string and | 12002 | treatment to some slashes, and then push the string and |
12001 | reread it as input, interpreting it normally. */ | 12003 | reread it as input, interpreting it normally. */ |
12002 | char *pout; | 12004 | char *pout; |
12003 | int pc; | ||
12004 | size_t psavelen; | 12005 | size_t psavelen; |
12005 | char *pstr; | 12006 | char *pstr; |
12006 | 12007 | ||
12007 | |||
12008 | STARTSTACKSTR(pout); | 12008 | STARTSTACKSTR(pout); |
12009 | for (;;) { | 12009 | for (;;) { |
12010 | if (needprompt) { | 12010 | int pc; |
12011 | setprompt(2); | 12011 | |
12012 | } | 12012 | setprompt_if(needprompt, 2); |
12013 | pc = pgetc(); | 12013 | pc = pgetc(); |
12014 | switch (pc) { | 12014 | switch (pc) { |
12015 | case '`': | 12015 | case '`': |
@@ -12019,8 +12019,7 @@ parsebackq: { | |||
12019 | pc = pgetc(); | 12019 | pc = pgetc(); |
12020 | if (pc == '\n') { | 12020 | if (pc == '\n') { |
12021 | g_parsefile->linno++; | 12021 | g_parsefile->linno++; |
12022 | if (doprompt) | 12022 | setprompt_if(doprompt, 2); |
12023 | setprompt(2); | ||
12024 | /* | 12023 | /* |
12025 | * If eating a newline, avoid putting | 12024 | * If eating a newline, avoid putting |
12026 | * the newline into the new character | 12025 | * the newline into the new character |
@@ -12183,9 +12182,7 @@ xxreadtoken(void) | |||
12183 | tokpushback = 0; | 12182 | tokpushback = 0; |
12184 | return lasttoken; | 12183 | return lasttoken; |
12185 | } | 12184 | } |
12186 | if (needprompt) { | 12185 | setprompt_if(needprompt, 2); |
12187 | setprompt(2); | ||
12188 | } | ||
12189 | startlinno = g_parsefile->linno; | 12186 | startlinno = g_parsefile->linno; |
12190 | for (;;) { /* until token or start of word found */ | 12187 | for (;;) { /* until token or start of word found */ |
12191 | c = pgetc_fast(); | 12188 | c = pgetc_fast(); |
@@ -12202,8 +12199,7 @@ xxreadtoken(void) | |||
12202 | break; /* return readtoken1(...) */ | 12199 | break; /* return readtoken1(...) */ |
12203 | } | 12200 | } |
12204 | startlinno = ++g_parsefile->linno; | 12201 | startlinno = ++g_parsefile->linno; |
12205 | if (doprompt) | 12202 | setprompt_if(doprompt, 2); |
12206 | setprompt(2); | ||
12207 | } else { | 12203 | } else { |
12208 | const char *p; | 12204 | const char *p; |
12209 | 12205 | ||
@@ -12249,9 +12245,7 @@ xxreadtoken(void) | |||
12249 | tokpushback = 0; | 12245 | tokpushback = 0; |
12250 | return lasttoken; | 12246 | return lasttoken; |
12251 | } | 12247 | } |
12252 | if (needprompt) { | 12248 | setprompt_if(needprompt, 2); |
12253 | setprompt(2); | ||
12254 | } | ||
12255 | startlinno = g_parsefile->linno; | 12249 | startlinno = g_parsefile->linno; |
12256 | for (;;) { /* until token or start of word found */ | 12250 | for (;;) { /* until token or start of word found */ |
12257 | c = pgetc_fast(); | 12251 | c = pgetc_fast(); |
@@ -12267,8 +12261,7 @@ xxreadtoken(void) | |||
12267 | case '\\': | 12261 | case '\\': |
12268 | if (pgetc() == '\n') { | 12262 | if (pgetc() == '\n') { |
12269 | startlinno = ++g_parsefile->linno; | 12263 | startlinno = ++g_parsefile->linno; |
12270 | if (doprompt) | 12264 | setprompt_if(doprompt, 2); |
12271 | setprompt(2); | ||
12272 | continue; | 12265 | continue; |
12273 | } | 12266 | } |
12274 | pungetc(); | 12267 | pungetc(); |
@@ -12394,8 +12387,7 @@ parsecmd(int interact) | |||
12394 | 12387 | ||
12395 | tokpushback = 0; | 12388 | tokpushback = 0; |
12396 | doprompt = interact; | 12389 | doprompt = interact; |
12397 | if (doprompt) | 12390 | setprompt_if(doprompt, doprompt); |
12398 | setprompt(doprompt); | ||
12399 | needprompt = 0; | 12391 | needprompt = 0; |
12400 | t = readtoken(); | 12392 | t = readtoken(); |
12401 | if (t == TEOF) | 12393 | if (t == TEOF) |
@@ -12419,10 +12411,8 @@ parseheredoc(void) | |||
12419 | heredoclist = NULL; | 12411 | heredoclist = NULL; |
12420 | 12412 | ||
12421 | while (here) { | 12413 | while (here) { |
12422 | if (needprompt) { | 12414 | setprompt_if(needprompt, 2); |
12423 | setprompt(2); | 12415 | readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, |
12424 | } | ||
12425 | readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, | ||
12426 | here->eofmark, here->striptabs); | 12416 | here->eofmark, here->striptabs); |
12427 | n = stzalloc(sizeof(struct narg)); | 12417 | n = stzalloc(sizeof(struct narg)); |
12428 | n->narg.type = NARG; | 12418 | n->narg.type = NARG; |