aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2008-06-18 16:30:42 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2008-06-18 16:30:42 +0000
commit55789c6646d1134c6e75380e66a953b676acfde9 (patch)
treea4a620ba29f029bae2deb09792cc893b7ea2c03f
parentab876cd107fe6ca274f58bae3264396745d8e5f9 (diff)
downloadbusybox-w32-55789c6646d1134c6e75380e66a953b676acfde9.tar.gz
busybox-w32-55789c6646d1134c6e75380e66a953b676acfde9.tar.bz2
busybox-w32-55789c6646d1134c6e75380e66a953b676acfde9.zip
hush: fix a bug with backslashes improperly handled in unquoted variables.
with previous patch: function old new delta parse_stream 1638 1758 +120 expand_on_ifs 97 174 +77 free_pipe 206 237 +31 setup_redirect 217 220 +3 setup_redirects 143 144 +1 done_word 698 688 -10 free_strings 38 - -38 expand_variables 1451 1403 -48 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 5/2 up/down: 232/-96) Total: 136 bytes
-rw-r--r--shell/hush.c166
1 files changed, 115 insertions, 51 deletions
diff --git a/shell/hush.c b/shell/hush.c
index f81203e2b..b83265899 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -227,8 +227,8 @@ typedef enum {
227 REDIRECT_IO = 5 227 REDIRECT_IO = 5
228} redir_type; 228} redir_type;
229 229
230/* The descrip member of this structure is only used to make debugging 230/* The descrip member of this structure is only used to make
231 * output pretty */ 231 * debugging output pretty */
232static const struct { 232static const struct {
233 int mode; 233 int mode;
234 signed char default_fd; 234 signed char default_fd;
@@ -283,8 +283,8 @@ struct p_context {
283}; 283};
284 284
285struct redir_struct { 285struct redir_struct {
286 struct redir_struct *next; /* pointer to the next redirect in the list */ 286 struct redir_struct *next;
287 redir_type type; /* type of redirection */ 287 smallint /*redir_type*/ rd_type;
288 int fd; /* file descriptor being redirected */ 288 int fd; /* file descriptor being redirected */
289 int dup; /* -1, or file descriptor being duplicated */ 289 int dup; /* -1, or file descriptor being duplicated */
290 char *rd_filename; /* filename */ 290 char *rd_filename; /* filename */
@@ -292,10 +292,10 @@ struct redir_struct {
292 292
293struct child_prog { 293struct child_prog {
294 pid_t pid; /* 0 if exited */ 294 pid_t pid; /* 0 if exited */
295 smallint is_stopped; /* is the program currently running? */
296 smallint subshell; /* flag, non-zero if group must be forked */
295 char **argv; /* program name and arguments */ 297 char **argv; /* program name and arguments */
296 struct pipe *group; /* if non-NULL, first in group or subshell */ 298 struct pipe *group; /* if non-NULL, first in group or subshell */
297 smallint subshell; /* flag, non-zero if group must be forked */
298 smallint is_stopped; /* is the program currently running? */
299 struct redir_struct *redirects; /* I/O redirections */ 299 struct redir_struct *redirects; /* I/O redirections */
300 struct pipe *family; /* pointer back to the child's parent pipe */ 300 struct pipe *family; /* pointer back to the child's parent pipe */
301}; 301};
@@ -346,7 +346,13 @@ typedef struct {
346 smallint o_glob; 346 smallint o_glob;
347 smallint nonnull; 347 smallint nonnull;
348 smallint has_empty_slot; 348 smallint has_empty_slot;
349 smallint o_assignment; /* 0:maybe, 1:yes, 2:no */
349} o_string; 350} o_string;
351enum {
352 MAYBE_ASSIGNMENT = 0,
353 DEFINITELY_ASSIGNMENT = 1,
354 NOT_ASSIGNMENT = 2,
355};
350/* Used for initialization: o_string foo = NULL_O_STRING; */ 356/* Used for initialization: o_string foo = NULL_O_STRING; */
351#define NULL_O_STRING { NULL } 357#define NULL_O_STRING { NULL }
352 358
@@ -588,6 +594,19 @@ static int is_assignment(const char *s)
588 return *s == '='; 594 return *s == '=';
589} 595}
590 596
597/* Replace each \x with x in place, return ptr past NUL. */
598static char *unbackslash(char *src)
599{
600 char *dst = src;
601 while (1) {
602 if (*src == '\\')
603 src++;
604 if ((*dst++ = *src++) == '\0')
605 break;
606 }
607 return dst;
608}
609
591static char **add_malloced_strings_to_strings(char **strings, char **add) 610static char **add_malloced_strings_to_strings(char **strings, char **add)
592{ 611{
593 int i; 612 int i;
@@ -906,6 +925,19 @@ static void o_addstr(o_string *o, const char *str, int len)
906 o->data[o->length] = '\0'; 925 o->data[o->length] = '\0';
907} 926}
908 927
928static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len)
929{
930 while (len) {
931 o_addchr(o, *str);
932 if (*str++ == '\\'
933 && (*str != '*' && *str != '?' && *str != '[')
934 ) {
935 o_addchr(o, '\\');
936 }
937 len--;
938 }
939}
940
909/* My analysis of quoting semantics tells me that state information 941/* My analysis of quoting semantics tells me that state information
910 * is associated with a destination, not a source. 942 * is associated with a destination, not a source.
911 */ 943 */
@@ -1045,18 +1077,7 @@ static int o_get_last_ptr(o_string *o, int n)
1045} 1077}
1046 1078
1047/* o_glob performs globbing on last list[], saving each result 1079/* o_glob performs globbing on last list[], saving each result
1048 * as a new list[]. unbackslash() is just a helper */ 1080 * as a new list[]. */
1049static char *unbackslash(char *src)
1050{
1051 char *dst = src;
1052 while (1) {
1053 if (*src == '\\')
1054 src++;
1055 if ((*dst++ = *src++) == '\0')
1056 break;
1057 }
1058 return dst;
1059}
1060static int o_glob(o_string *o, int n) 1081static int o_glob(o_string *o, int n)
1061{ 1082{
1062 glob_t globdata; 1083 glob_t globdata;
@@ -1310,7 +1331,8 @@ static int setup_redirects(struct child_prog *prog, int squirrel[])
1310 } 1331 }
1311 if (redir->dup == -1) { 1332 if (redir->dup == -1) {
1312 char *p; 1333 char *p;
1313 mode = redir_table[redir->type].mode; 1334 mode = redir_table[redir->rd_type].mode;
1335//TODO: check redir to names like '\\'
1314 p = expand_string_to_string(redir->rd_filename); 1336 p = expand_string_to_string(redir->rd_filename);
1315 openfd = open_or_warn(p, mode); 1337 openfd = open_or_warn(p, mode);
1316 free(p); 1338 free(p);
@@ -1765,6 +1787,7 @@ static int run_pipe(struct pipe *pi)
1765 for (i = 0; is_assignment(argv[i]); i++) { 1787 for (i = 0; is_assignment(argv[i]); i++) {
1766 p = expand_string_to_string(argv[i]); 1788 p = expand_string_to_string(argv[i]);
1767 putenv(p); 1789 putenv(p);
1790//FIXME: do we leak p?!
1768 } 1791 }
1769 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { 1792 for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) {
1770 if (strcmp(argv[i], x->cmd) == 0) { 1793 if (strcmp(argv[i], x->cmd) == 0) {
@@ -2300,7 +2323,10 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
2300 while (1) { 2323 while (1) {
2301 int word_len = strcspn(str, ifs); 2324 int word_len = strcspn(str, ifs);
2302 if (word_len) { 2325 if (word_len) {
2303 o_addstr(output, str, word_len); 2326 if (output->o_quote || !output->o_glob)
2327 o_addQstr(output, str, word_len);
2328 else /* protect backslashes against globbing up :) */
2329 o_addstr_duplicate_backslash(output, str, word_len);
2304 str += word_len; 2330 str += word_len;
2305 } 2331 }
2306 if (!*str) /* EOL - do not finalize word */ 2332 if (!*str) /* EOL - do not finalize word */
@@ -2324,7 +2350,8 @@ static int expand_on_ifs(o_string *output, int n, const char *str)
2324static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) 2350static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2325{ 2351{
2326 /* or_mask is either 0 (normal case) or 0x80 2352 /* or_mask is either 0 (normal case) or 0x80
2327 * (expansion of right-hand side of assignment == 1-element expand) */ 2353 * (expansion of right-hand side of assignment == 1-element expand.
2354 * It will also do no globbing, and thus we must not backslash-quote!) */
2328 2355
2329 char first_ch, ored_ch; 2356 char first_ch, ored_ch;
2330 int i; 2357 int i;
@@ -2372,6 +2399,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2372 break; 2399 break;
2373 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ 2400 if (!(first_ch & 0x80)) { /* unquoted $* or $@ */
2374 while (global_argv[i]) { 2401 while (global_argv[i]) {
2402//see expand_on_ifs below - same??
2375 n = expand_on_ifs(output, n, global_argv[i]); 2403 n = expand_on_ifs(output, n, global_argv[i]);
2376 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1); 2404 debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, global_argc-1);
2377 if (global_argv[i++][0] && global_argv[i]) { 2405 if (global_argv[i++][0] && global_argv[i]) {
@@ -2429,9 +2457,9 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2429 arg[0] = first_ch & 0x7f; 2457 arg[0] = first_ch & 0x7f;
2430 if (isdigit(arg[0])) { 2458 if (isdigit(arg[0])) {
2431 i = xatoi_u(arg); 2459 i = xatoi_u(arg);
2432 val = NULL;
2433 if (i < global_argc) 2460 if (i < global_argc)
2434 val = global_argv[i]; 2461 val = global_argv[i];
2462 /* else val remains NULL: $N with too big N */
2435 } else 2463 } else
2436 val = lookup_param(arg); 2464 val = lookup_param(arg);
2437 arg[0] = first_ch; 2465 arg[0] = first_ch;
@@ -2442,11 +2470,16 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask)
2442 if (!(first_ch & 0x80)) { /* unquoted $VAR */ 2470 if (!(first_ch & 0x80)) { /* unquoted $VAR */
2443 debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote); 2471 debug_printf_expand("unquoted '%s', output->o_quote:%d\n", val, output->o_quote);
2444 if (val) { 2472 if (val) {
2473 /* unquoted var's contents should be globbed, so don't quote */
2474 smallint sv = output->o_quote;
2475 output->o_quote = 0;
2445 n = expand_on_ifs(output, n, val); 2476 n = expand_on_ifs(output, n, val);
2446 val = NULL; 2477 val = NULL;
2478 output->o_quote = sv;
2447 } 2479 }
2448 } else /* quoted $VAR, val will be appended below */ 2480 } else { /* quoted $VAR, val will be appended below */
2449 debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote); 2481 debug_printf_expand("quoted '%s', output->o_quote:%d\n", val, output->o_quote);
2482 }
2450 } 2483 }
2451 if (val) { 2484 if (val) {
2452 o_addQstr(output, val, strlen(val)); ///maybe q? 2485 o_addQstr(output, val, strlen(val)); ///maybe q?
@@ -2485,6 +2518,7 @@ static char **expand_variables(char **argv, int or_mask)
2485 2518
2486 if (or_mask & 0x100) { 2519 if (or_mask & 0x100) {
2487 output.o_quote = 1; 2520 output.o_quote = 1;
2521/* why? */
2488 output.o_glob = 1; 2522 output.o_glob = 1;
2489 } 2523 }
2490 2524
@@ -2687,7 +2721,7 @@ static int setup_redirect(struct p_context *ctx, int fd, redir_type style,
2687 child->redirects = redir; 2721 child->redirects = redir;
2688 } 2722 }
2689 2723
2690 redir->type = style; 2724 redir->rd_type = style;
2691 redir->fd = (fd == -1) ? redir_table[style].default_fd : fd; 2725 redir->fd = (fd == -1) ? redir_table[style].default_fd : fd;
2692 2726
2693 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip); 2727 debug_printf("Redirect type %d%s\n", redir->fd, redir_table[style].descrip);
@@ -2858,6 +2892,14 @@ static int done_word(o_string *word, struct p_context *ctx)
2858{ 2892{
2859 struct child_prog *child = ctx->child; 2893 struct child_prog *child = ctx->child;
2860 2894
2895 /* If this word wasn't an assignment, next ones definitely
2896 * can't be assignments. Even if they look like ones. */
2897 if (word->o_assignment != DEFINITELY_ASSIGNMENT) {
2898 word->o_assignment = NOT_ASSIGNMENT;
2899 } else {
2900 word->o_assignment = MAYBE_ASSIGNMENT;
2901 }
2902
2861 debug_printf_parse("done_word entered: '%s' %p\n", word->data, child); 2903 debug_printf_parse("done_word entered: '%s' %p\n", word->data, child);
2862 if (word->length == 0 && word->nonnull == 0) { 2904 if (word->length == 0 && word->nonnull == 0) {
2863 debug_printf_parse("done_word return 0: true null, ignored\n"); 2905 debug_printf_parse("done_word return 0: true null, ignored\n");
@@ -2867,6 +2909,7 @@ static int done_word(o_string *word, struct p_context *ctx)
2867 /* We do not glob in e.g. >*.tmp case. bash seems to glob here 2909 /* We do not glob in e.g. >*.tmp case. bash seems to glob here
2868 * only if run as "bash", not "sh" */ 2910 * only if run as "bash", not "sh" */
2869 ctx->pending_redirect->rd_filename = xstrdup(word->data); 2911 ctx->pending_redirect->rd_filename = xstrdup(word->data);
2912 word->o_assignment = NOT_ASSIGNMENT;
2870 debug_printf("word stored in rd_filename: '%s'\n", word->data); 2913 debug_printf("word stored in rd_filename: '%s'\n", word->data);
2871 } else { 2914 } else {
2872 if (child->group) { /* TODO: example how to trigger? */ 2915 if (child->group) { /* TODO: example how to trigger? */
@@ -2878,15 +2921,18 @@ static int done_word(o_string *word, struct p_context *ctx)
2878 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); 2921 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
2879 if (reserved_word(word, ctx)) { 2922 if (reserved_word(word, ctx)) {
2880 o_reset(word); 2923 o_reset(word);
2924 word->o_assignment = NOT_ASSIGNMENT;
2881 debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX)); 2925 debug_printf_parse("done_word return %d\n", (ctx->res_w == RES_SNTX));
2882 return (ctx->res_w == RES_SNTX); 2926 return (ctx->res_w == RES_SNTX);
2883 } 2927 }
2884 } 2928 }
2885 if (word->nonnull 2929 if (word->nonnull /* we saw "xx" or 'xx' */
2886 /* && word->data[0] != */ 2930 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
2931 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
2932 /* (otherwise it's "abc".... and is already safe) */
2887 ) { 2933 ) {
2888 /* Insert "empty variable" reference, this makes e.g. "", '', 2934 /* Insert "empty variable" reference, this makes
2889 * $empty"" etc to not disappear */ 2935 * e.g. "", $empty"" etc to not disappear */
2890 o_addchr(word, SPECIAL_VAR_SYMBOL); 2936 o_addchr(word, SPECIAL_VAR_SYMBOL);
2891 o_addchr(word, SPECIAL_VAR_SYMBOL); 2937 o_addchr(word, SPECIAL_VAR_SYMBOL);
2892 } 2938 }
@@ -3107,14 +3153,14 @@ static int process_command_subs(o_string *dest,
3107 continue; 3153 continue;
3108 } 3154 }
3109 while (eol_cnt) { 3155 while (eol_cnt) {
3110 o_addQchr(dest, '\n'); 3156 o_addchr(dest, '\n');
3111 eol_cnt--; 3157 eol_cnt--;
3112 } 3158 }
3113 /* Even unquoted `echo '\'` results in two backslashes 3159// /* Even unquoted `echo '\'` results in two backslashes
3114 * (which are converted into one by globbing later) */ 3160// * (which are converted into one by globbing later) */
3115 if (!dest->o_quote && ch == '\\') { 3161// if (!dest->o_quote && ch == '\\') {
3116 o_addchr(dest, ch); 3162// o_addchr(dest, ch);
3117 } 3163// }
3118 o_addQchr(dest, ch); 3164 o_addQchr(dest, ch);
3119 } 3165 }
3120 3166
@@ -3364,13 +3410,19 @@ static int handle_dollar(o_string *dest, struct in_str *input)
3364 return 0; 3410 return 0;
3365} 3411}
3366 3412
3367/* Return code is 0 for normal exit, 1 for syntax error */ 3413/* Scan input, call done_word() whenever full IFS delemited word was seen.
3414 * call done_pipe if '\n' was seen (and end_trigger != NULL)
3415 * Return if (non-quoted) char in end_trigger was seen; or on parse error. */
3416/* Return code is 0 if end_trigger char is met,
3417 * -1 on EOF (but if end_trigger == NULL then return 0)
3418 * 1 for syntax error */
3368static int parse_stream(o_string *dest, struct p_context *ctx, 3419static int parse_stream(o_string *dest, struct p_context *ctx,
3369 struct in_str *input, const char *end_trigger) 3420 struct in_str *input, const char *end_trigger)
3370{ 3421{
3371 int ch, m; 3422 int ch, m;
3372 int redir_fd; 3423 int redir_fd;
3373 redir_type redir_style; 3424 redir_type redir_style;
3425 int shadow_quote = dest->o_quote;
3374 int next; 3426 int next;
3375 3427
3376 /* Only double-quote state is handled in the state variable dest->o_quote. 3428 /* Only double-quote state is handled in the state variable dest->o_quote.
@@ -3385,13 +3437,14 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3385 ch = i_getch(input); 3437 ch = i_getch(input);
3386 if (ch != EOF) { 3438 if (ch != EOF) {
3387 m = charmap[ch]; 3439 m = charmap[ch];
3388 if (ch != '\n') 3440 if (ch != '\n') {
3389 next = i_peek(input); 3441 next = i_peek(input);
3442 }
3390 } 3443 }
3391 debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n", 3444 debug_printf_parse(": ch=%c (%d) m=%d quote=%d\n",
3392 ch, ch, m, dest->o_quote); 3445 ch, ch, m, dest->o_quote);
3393 if (m == CHAR_ORDINARY 3446 if (m == CHAR_ORDINARY
3394 || (m != CHAR_SPECIAL && dest->o_quote) 3447 || (m != CHAR_SPECIAL && shadow_quote)
3395 ) { 3448 ) {
3396 if (ch == EOF) { 3449 if (ch == EOF) {
3397 syntax("unterminated \""); 3450 syntax("unterminated \"");
@@ -3399,6 +3452,12 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3399 return 1; 3452 return 1;
3400 } 3453 }
3401 o_addQchr(dest, ch); 3454 o_addQchr(dest, ch);
3455 if (dest->o_assignment == MAYBE_ASSIGNMENT
3456 && ch == '='
3457 && is_assignment(dest->data)
3458 ) {
3459 dest->o_assignment = DEFINITELY_ASSIGNMENT;
3460 }
3402 continue; 3461 continue;
3403 } 3462 }
3404 if (m == CHAR_IFS) { 3463 if (m == CHAR_IFS) {
@@ -3416,11 +3475,12 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3416 } 3475 }
3417 } 3476 }
3418 if (end_trigger) { 3477 if (end_trigger) {
3419 if (!dest->o_quote && strchr(end_trigger, ch)) { 3478 if (!shadow_quote && strchr(end_trigger, ch)) {
3420 /* Special case: (...word) makes last word terminate, 3479 /* Special case: (...word) makes last word terminate,
3421 * as if ';' is seen */ 3480 * as if ';' is seen */
3422 if (ch == ')') { 3481 if (ch == ')') {
3423 done_word(dest, ctx); 3482 done_word(dest, ctx);
3483//err chk?
3424 done_pipe(ctx, PIPE_SEQ); 3484 done_pipe(ctx, PIPE_SEQ);
3425 } 3485 }
3426 if (ctx->res_w == RES_NONE) { 3486 if (ctx->res_w == RES_NONE) {
@@ -3431,9 +3491,16 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3431 } 3491 }
3432 if (m == CHAR_IFS) 3492 if (m == CHAR_IFS)
3433 continue; 3493 continue;
3494
3495 if (dest->o_assignment == MAYBE_ASSIGNMENT) {
3496 /* ch is a special char and thus this word
3497 * cannot be an assignment: */
3498 dest->o_assignment = NOT_ASSIGNMENT;
3499 }
3500
3434 switch (ch) { 3501 switch (ch) {
3435 case '#': 3502 case '#':
3436 if (dest->length == 0 && !dest->o_quote) { 3503 if (dest->length == 0 && !shadow_quote) {
3437 while (1) { 3504 while (1) {
3438 ch = i_peek(input); 3505 ch = i_peek(input);
3439 if (ch == EOF || ch == '\n') 3506 if (ch == EOF || ch == '\n')
@@ -3459,7 +3526,7 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3459 * an ! appearing in double quotes is escaped using 3526 * an ! appearing in double quotes is escaped using
3460 * a backslash. The backslash preceding the ! is not removed." 3527 * a backslash. The backslash preceding the ! is not removed."
3461 */ 3528 */
3462 if (dest->o_quote) { 3529 if (shadow_quote) { //NOT SURE dest->o_quote) {
3463 if (strchr("$`\"\\", next) != NULL) { 3530 if (strchr("$`\"\\", next) != NULL) {
3464 o_addqchr(dest, i_getch(input)); 3531 o_addqchr(dest, i_getch(input));
3465 } else { 3532 } else {
@@ -3487,18 +3554,23 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3487 } 3554 }
3488 if (ch == '\'') 3555 if (ch == '\'')
3489 break; 3556 break;
3490 o_addqchr(dest, ch); 3557 if (dest->o_assignment == NOT_ASSIGNMENT)
3558 o_addqchr(dest, ch);
3559 else
3560 o_addchr(dest, ch);
3491 } 3561 }
3492 break; 3562 break;
3493 case '"': 3563 case '"':
3494 dest->nonnull = 1; 3564 dest->nonnull = 1;
3495 dest->o_quote ^= 1; /* invert */ 3565 shadow_quote ^= 1; /* invert */
3566 if (dest->o_assignment == NOT_ASSIGNMENT)
3567 dest->o_quote ^= 1;
3496 break; 3568 break;
3497#if ENABLE_HUSH_TICK 3569#if ENABLE_HUSH_TICK
3498 case '`': { 3570 case '`': {
3499 //int pos = dest->length; 3571 //int pos = dest->length;
3500 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3572 o_addchr(dest, SPECIAL_VAR_SYMBOL);
3501 o_addchr(dest, dest->o_quote ? 0x80 | '`' : '`'); 3573 o_addchr(dest, shadow_quote /*or dest->o_quote??*/ ? 0x80 | '`' : '`');
3502 add_till_backquote(dest, input); 3574 add_till_backquote(dest, input);
3503 o_addchr(dest, SPECIAL_VAR_SYMBOL); 3575 o_addchr(dest, SPECIAL_VAR_SYMBOL);
3504 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); 3576 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
@@ -3585,14 +3657,6 @@ static int parse_stream(o_string *dest, struct p_context *ctx,
3585 bb_error_msg_and_die("BUG: unexpected %c\n", ch); 3657 bb_error_msg_and_die("BUG: unexpected %c\n", ch);
3586 } 3658 }
3587 } /* while (1) */ 3659 } /* while (1) */
3588 /* Complain if quote? No, maybe we just finished a command substitution
3589 * that was quoted. Example:
3590 * $ echo "`cat foo` plus more"
3591 * and we just got the EOF generated by the subshell that ran "cat foo"
3592 * The only real complaint is if we got an EOF when end_trigger != NULL,
3593 * that is, we were really supposed to get end_trigger, and never got
3594 * one before the EOF. Can't use the standard "syntax error" return code,
3595 * so that parse_stream_outer can distinguish the EOF and exit smoothly. */
3596 debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL)); 3660 debug_printf_parse("parse_stream return %d\n", -(end_trigger != NULL));
3597 if (end_trigger) 3661 if (end_trigger)
3598 return -1; 3662 return -1;