diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-04 22:47:50 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2009-04-04 22:47:50 +0000 |
commit | 9aa7d6fdc5554480b9cb4fc740ce3f1d2b734555 (patch) | |
tree | 3f822f617f914908f77f509321159b8ed4444a61 /shell | |
parent | 42e78b978fce494f3f9c1cd629fbf06f9b8ea11c (diff) | |
download | busybox-w32-9aa7d6fdc5554480b9cb4fc740ce3f1d2b734555.tar.gz busybox-w32-9aa7d6fdc5554480b9cb4fc740ce3f1d2b734555.tar.bz2 busybox-w32-9aa7d6fdc5554480b9cb4fc740ce3f1d2b734555.zip |
hush: preparatory patch for NOMMU-safe { list } handling.
function old new delta
o_addblock - 58 +58
o_addstr_with_NUL - 27 +27
builtin_exit 47 49 +2
run_list 2020 2018 -2
o_addstrauto 27 - -27
parse_stream 1508 1461 -47
o_addstr 58 - -58
------------------------------------------------------------------------------
(add/remove: 2/2 grow/shrink: 1/2 up/down: 87/-134) Total: -47 bytes
Diffstat (limited to 'shell')
-rw-r--r-- | shell/hush.c | 291 |
1 files changed, 200 insertions, 91 deletions
diff --git a/shell/hush.c b/shell/hush.c index c38420240..ac3480578 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -73,10 +73,18 @@ | |||
73 | #if ENABLE_HUSH_CASE | 73 | #if ENABLE_HUSH_CASE |
74 | #include <fnmatch.h> | 74 | #include <fnmatch.h> |
75 | #endif | 75 | #endif |
76 | |||
77 | #include "math.h" | 76 | #include "math.h" |
78 | 77 | ||
79 | #define HUSH_VER_STR "0.92" | 78 | #ifdef WANT_TO_TEST_NOMMU |
79 | # undef BB_MMU | ||
80 | # undef USE_FOR_NOMMU | ||
81 | # undef USE_FOR_MMU | ||
82 | # define BB_MMU 0 | ||
83 | # define USE_FOR_NOMMU(...) __VA_ARGS__ | ||
84 | # define USE_FOR_MMU(...) | ||
85 | #endif | ||
86 | |||
87 | #define HUSH_VER_STR "0.93" | ||
80 | 88 | ||
81 | #if defined SINGLE_APPLET_MAIN | 89 | #if defined SINGLE_APPLET_MAIN |
82 | /* STANDALONE does not make sense, and won't compile */ | 90 | /* STANDALONE does not make sense, and won't compile */ |
@@ -298,6 +306,45 @@ typedef enum reserved_style { | |||
298 | RES_SNTX | 306 | RES_SNTX |
299 | } reserved_style; | 307 | } reserved_style; |
300 | 308 | ||
309 | typedef struct o_string { | ||
310 | char *data; | ||
311 | int length; /* position where data is appended */ | ||
312 | int maxlen; | ||
313 | /* Protect newly added chars against globbing | ||
314 | * (by prepending \ to *, ?, [, \) */ | ||
315 | smallint o_escape; | ||
316 | smallint o_glob; | ||
317 | smallint nonnull; | ||
318 | smallint has_empty_slot; | ||
319 | smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ | ||
320 | } o_string; | ||
321 | enum { | ||
322 | MAYBE_ASSIGNMENT = 0, | ||
323 | DEFINITELY_ASSIGNMENT = 1, | ||
324 | NOT_ASSIGNMENT = 2, | ||
325 | WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */ | ||
326 | }; | ||
327 | /* Used for initialization: o_string foo = NULL_O_STRING; */ | ||
328 | #define NULL_O_STRING { NULL } | ||
329 | |||
330 | /* I can almost use ordinary FILE*. Is open_memstream() universally | ||
331 | * available? Where is it documented? */ | ||
332 | typedef struct in_str { | ||
333 | const char *p; | ||
334 | /* eof_flag=1: last char in ->p is really an EOF */ | ||
335 | char eof_flag; /* meaningless if ->p == NULL */ | ||
336 | char peek_buf[2]; | ||
337 | #if ENABLE_HUSH_INTERACTIVE | ||
338 | smallint promptme; | ||
339 | smallint promptmode; /* 0: PS1, 1: PS2 */ | ||
340 | #endif | ||
341 | FILE *file; | ||
342 | int (*get) (struct in_str *); | ||
343 | int (*peek) (struct in_str *); | ||
344 | } in_str; | ||
345 | #define i_getch(input) ((input)->get(input)) | ||
346 | #define i_peek(input) ((input)->peek(input)) | ||
347 | |||
301 | struct redir_struct { | 348 | struct redir_struct { |
302 | struct redir_struct *next; | 349 | struct redir_struct *next; |
303 | char *rd_filename; /* filename */ | 350 | char *rd_filename; /* filename */ |
@@ -311,8 +358,11 @@ struct command { | |||
311 | int assignment_cnt; /* how many argv[i] are assignments? */ | 358 | int assignment_cnt; /* how many argv[i] are assignments? */ |
312 | smallint is_stopped; /* is the command currently running? */ | 359 | smallint is_stopped; /* is the command currently running? */ |
313 | smallint grp_type; /* GRP_xxx */ | 360 | smallint grp_type; /* GRP_xxx */ |
314 | struct pipe *group; /* if non-NULL, this "prog" is {} group, | 361 | struct pipe *group; /* if non-NULL, this "command" is { list }, |
315 | * subshell, or a compound statement */ | 362 | * ( list ), or a compound statement */ |
363 | #if !BB_MMU | ||
364 | char *group_as_string; | ||
365 | #endif | ||
316 | char **argv; /* command name and arguments */ | 366 | char **argv; /* command name and arguments */ |
317 | struct redir_struct *redirects; /* I/O redirections */ | 367 | struct redir_struct *redirects; /* I/O redirections */ |
318 | }; | 368 | }; |
@@ -354,6 +404,9 @@ struct parse_context { | |||
354 | struct command *command; | 404 | struct command *command; |
355 | /* last redirect in command->redirects list */ | 405 | /* last redirect in command->redirects list */ |
356 | struct redir_struct *pending_redirect; | 406 | struct redir_struct *pending_redirect; |
407 | #if !BB_MMU | ||
408 | o_string as_string; | ||
409 | #endif | ||
357 | #if HAS_KEYWORDS | 410 | #if HAS_KEYWORDS |
358 | smallint ctx_res_w; | 411 | smallint ctx_res_w; |
359 | smallint ctx_inverted; /* "! cmd | cmd" */ | 412 | smallint ctx_inverted; /* "! cmd | cmd" */ |
@@ -389,45 +442,6 @@ struct variable { | |||
389 | smallint flg_read_only; | 442 | smallint flg_read_only; |
390 | }; | 443 | }; |
391 | 444 | ||
392 | typedef struct o_string { | ||
393 | char *data; | ||
394 | int length; /* position where data is appended */ | ||
395 | int maxlen; | ||
396 | /* Protect newly added chars against globbing | ||
397 | * (by prepending \ to *, ?, [, \) */ | ||
398 | smallint o_escape; | ||
399 | smallint o_glob; | ||
400 | smallint nonnull; | ||
401 | smallint has_empty_slot; | ||
402 | smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ | ||
403 | } o_string; | ||
404 | enum { | ||
405 | MAYBE_ASSIGNMENT = 0, | ||
406 | DEFINITELY_ASSIGNMENT = 1, | ||
407 | NOT_ASSIGNMENT = 2, | ||
408 | WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */ | ||
409 | }; | ||
410 | /* Used for initialization: o_string foo = NULL_O_STRING; */ | ||
411 | #define NULL_O_STRING { NULL } | ||
412 | |||
413 | /* I can almost use ordinary FILE*. Is open_memstream() universally | ||
414 | * available? Where is it documented? */ | ||
415 | typedef struct in_str { | ||
416 | const char *p; | ||
417 | /* eof_flag=1: last char in ->p is really an EOF */ | ||
418 | char eof_flag; /* meaningless if ->p == NULL */ | ||
419 | char peek_buf[2]; | ||
420 | #if ENABLE_HUSH_INTERACTIVE | ||
421 | smallint promptme; | ||
422 | smallint promptmode; /* 0: PS1, 1: PS2 */ | ||
423 | #endif | ||
424 | FILE *file; | ||
425 | int (*get) (struct in_str *); | ||
426 | int (*peek) (struct in_str *); | ||
427 | } in_str; | ||
428 | #define i_getch(input) ((input)->get(input)) | ||
429 | #define i_peek(input) ((input)->peek(input)) | ||
430 | |||
431 | enum { | 445 | enum { |
432 | BC_BREAK = 1, | 446 | BC_BREAK = 1, |
433 | BC_CONTINUE = 2, | 447 | BC_CONTINUE = 2, |
@@ -1359,6 +1373,11 @@ static void o_free(o_string *o) | |||
1359 | memset(o, 0, sizeof(*o)); | 1373 | memset(o, 0, sizeof(*o)); |
1360 | } | 1374 | } |
1361 | 1375 | ||
1376 | static ALWAYS_INLINE void o_free_unsafe(o_string *o) | ||
1377 | { | ||
1378 | free(o->data); | ||
1379 | } | ||
1380 | |||
1362 | static void o_grow_by(o_string *o, int len) | 1381 | static void o_grow_by(o_string *o, int len) |
1363 | { | 1382 | { |
1364 | if (o->length + len > o->maxlen) { | 1383 | if (o->length + len > o->maxlen) { |
@@ -1376,7 +1395,7 @@ static void o_addchr(o_string *o, int ch) | |||
1376 | o->data[o->length] = '\0'; | 1395 | o->data[o->length] = '\0'; |
1377 | } | 1396 | } |
1378 | 1397 | ||
1379 | static void o_addstr(o_string *o, const char *str, int len) | 1398 | static void o_addblock(o_string *o, const char *str, int len) |
1380 | { | 1399 | { |
1381 | o_grow_by(o, len); | 1400 | o_grow_by(o, len); |
1382 | memcpy(&o->data[o->length], str, len); | 1401 | memcpy(&o->data[o->length], str, len); |
@@ -1384,12 +1403,19 @@ static void o_addstr(o_string *o, const char *str, int len) | |||
1384 | o->data[o->length] = '\0'; | 1403 | o->data[o->length] = '\0'; |
1385 | } | 1404 | } |
1386 | 1405 | ||
1387 | static void o_addstrauto(o_string *o, const char *str) | 1406 | #if !BB_MMU |
1407 | static void o_addstr(o_string *o, const char *str) | ||
1408 | { | ||
1409 | o_addblock(o, str, strlen(str)); | ||
1410 | } | ||
1411 | #endif | ||
1412 | |||
1413 | static void o_addstr_with_NUL(o_string *o, const char *str) | ||
1388 | { | 1414 | { |
1389 | o_addstr(o, str, strlen(str) + 1); | 1415 | o_addblock(o, str, strlen(str) + 1); |
1390 | } | 1416 | } |
1391 | 1417 | ||
1392 | static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len) | 1418 | static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) |
1393 | { | 1419 | { |
1394 | while (len) { | 1420 | while (len) { |
1395 | o_addchr(o, *str); | 1421 | o_addchr(o, *str); |
@@ -1438,7 +1464,7 @@ static void o_addQchr(o_string *o, int ch) | |||
1438 | static void o_addQstr(o_string *o, const char *str, int len) | 1464 | static void o_addQstr(o_string *o, const char *str, int len) |
1439 | { | 1465 | { |
1440 | if (!o->o_escape) { | 1466 | if (!o->o_escape) { |
1441 | o_addstr(o, str, len); | 1467 | o_addblock(o, str, len); |
1442 | return; | 1468 | return; |
1443 | } | 1469 | } |
1444 | while (len) { | 1470 | while (len) { |
@@ -1447,7 +1473,7 @@ static void o_addQstr(o_string *o, const char *str, int len) | |||
1447 | int ordinary_cnt = strcspn(str, "*?[\\"); | 1473 | int ordinary_cnt = strcspn(str, "*?[\\"); |
1448 | if (ordinary_cnt > len) /* paranoia */ | 1474 | if (ordinary_cnt > len) /* paranoia */ |
1449 | ordinary_cnt = len; | 1475 | ordinary_cnt = len; |
1450 | o_addstr(o, str, ordinary_cnt); | 1476 | o_addblock(o, str, ordinary_cnt); |
1451 | if (ordinary_cnt == len) | 1477 | if (ordinary_cnt == len) |
1452 | return; | 1478 | return; |
1453 | str += ordinary_cnt; | 1479 | str += ordinary_cnt; |
@@ -1582,7 +1608,7 @@ static int o_glob(o_string *o, int n) | |||
1582 | char **argv = globdata.gl_pathv; | 1608 | char **argv = globdata.gl_pathv; |
1583 | o->length = pattern - o->data; /* "forget" pattern */ | 1609 | o->length = pattern - o->data; /* "forget" pattern */ |
1584 | while (1) { | 1610 | while (1) { |
1585 | o_addstrauto(o, *argv); | 1611 | o_addstr_with_NUL(o, *argv); |
1586 | n = o_save_ptr_helper(o, n); | 1612 | n = o_save_ptr_helper(o, n); |
1587 | argv++; | 1613 | argv++; |
1588 | if (!*argv) | 1614 | if (!*argv) |
@@ -1635,7 +1661,14 @@ static char **o_finalize_list(o_string *o, int n) | |||
1635 | static int process_command_subs(o_string *dest, const char *s); | 1661 | static int process_command_subs(o_string *dest, const char *s); |
1636 | #endif | 1662 | #endif |
1637 | static char *expand_string_to_string(const char *str); | 1663 | static char *expand_string_to_string(const char *str); |
1638 | static int parse_stream_dquoted(o_string *dest, struct in_str *input, int dquote_end); | 1664 | #if BB_MMU |
1665 | #define parse_stream_dquoted(ctx, dest, input, dquote_end) \ | ||
1666 | parse_stream_dquoted(dest, input, dquote_end) | ||
1667 | #endif | ||
1668 | static int parse_stream_dquoted(struct parse_context *ctx, | ||
1669 | o_string *dest, | ||
1670 | struct in_str *input, | ||
1671 | int dquote_end); | ||
1639 | 1672 | ||
1640 | /* expand_strvec_to_strvec() takes a list of strings, expands | 1673 | /* expand_strvec_to_strvec() takes a list of strings, expands |
1641 | * all variable references within and returns a pointer to | 1674 | * all variable references within and returns a pointer to |
@@ -1657,7 +1690,7 @@ static int expand_on_ifs(o_string *output, int n, const char *str) | |||
1657 | if (output->o_escape || !output->o_glob) | 1690 | if (output->o_escape || !output->o_glob) |
1658 | o_addQstr(output, str, word_len); | 1691 | o_addQstr(output, str, word_len); |
1659 | else /* protect backslashes against globbing up :) */ | 1692 | else /* protect backslashes against globbing up :) */ |
1660 | o_addstr_duplicate_backslash(output, str, word_len); | 1693 | o_addblock_duplicate_backslash(output, str, word_len); |
1661 | str += word_len; | 1694 | str += word_len; |
1662 | } | 1695 | } |
1663 | if (!*str) /* EOL - do not finalize word */ | 1696 | if (!*str) /* EOL - do not finalize word */ |
@@ -1701,7 +1734,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1701 | #if ENABLE_SH_MATH_SUPPORT | 1734 | #if ENABLE_SH_MATH_SUPPORT |
1702 | char arith_buf[sizeof(arith_t)*3 + 2]; | 1735 | char arith_buf[sizeof(arith_t)*3 + 2]; |
1703 | #endif | 1736 | #endif |
1704 | o_addstr(output, arg, p - arg); | 1737 | o_addblock(output, arg, p - arg); |
1705 | debug_print_list("expand_vars_to_list[1]", output, n); | 1738 | debug_print_list("expand_vars_to_list[1]", output, n); |
1706 | arg = ++p; | 1739 | arg = ++p; |
1707 | p = strchr(p, SPECIAL_VAR_SYMBOL); | 1740 | p = strchr(p, SPECIAL_VAR_SYMBOL); |
@@ -1825,7 +1858,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1825 | o_string dest = NULL_O_STRING; | 1858 | o_string dest = NULL_O_STRING; |
1826 | 1859 | ||
1827 | setup_string_in_str(&input, arg); | 1860 | setup_string_in_str(&input, arg); |
1828 | parse_stream_dquoted(&dest, &input, EOF); | 1861 | parse_stream_dquoted(NULL, &dest, &input, EOF); |
1829 | //bb_error_msg("'%s' -> '%s'", arg, dest.data); | 1862 | //bb_error_msg("'%s' -> '%s'", arg, dest.data); |
1830 | exp_str = expand_string_to_string(dest.data); | 1863 | exp_str = expand_string_to_string(dest.data); |
1831 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); | 1864 | //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); |
@@ -1958,7 +1991,7 @@ static int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) | |||
1958 | debug_print_list("expand_vars_to_list[a]", output, n); | 1991 | debug_print_list("expand_vars_to_list[a]", output, n); |
1959 | /* this part is literal, and it was already pre-quoted | 1992 | /* this part is literal, and it was already pre-quoted |
1960 | * if needed (much earlier), do not use o_addQstr here! */ | 1993 | * if needed (much earlier), do not use o_addQstr here! */ |
1961 | o_addstrauto(output, arg); | 1994 | o_addstr_with_NUL(output, arg); |
1962 | debug_print_list("expand_vars_to_list[b]", output, n); | 1995 | debug_print_list("expand_vars_to_list[b]", output, n); |
1963 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ | 1996 | } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ |
1964 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ | 1997 | && !(ored_ch & 0x80) /* and all vars were not quoted. */ |
@@ -2148,6 +2181,10 @@ static void free_pipe(struct pipe *pi, int indent) | |||
2148 | debug_printf_clean("%s end group\n", indenter(indent)); | 2181 | debug_printf_clean("%s end group\n", indenter(indent)); |
2149 | command->group = NULL; | 2182 | command->group = NULL; |
2150 | } | 2183 | } |
2184 | #if !BB_MMU | ||
2185 | free(command->group_as_string); | ||
2186 | command->group_as_string = NULL; | ||
2187 | #endif | ||
2151 | for (r = command->redirects; r; r = rnext) { | 2188 | for (r = command->redirects; r; r = rnext) { |
2152 | debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); | 2189 | debug_printf_clean("%s redirect %d%s", indenter(indent), r->fd, redir_table[r->rd_type].descrip); |
2153 | if (r->dup == -1) { | 2190 | if (r->dup == -1) { |
@@ -2215,9 +2252,7 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2215 | char **argv, int assignment_cnt, | 2252 | char **argv, int assignment_cnt, |
2216 | char **argv_expanded) | 2253 | char **argv_expanded) |
2217 | { | 2254 | { |
2218 | int rcode; | ||
2219 | char **new_env; | 2255 | char **new_env; |
2220 | const struct built_in_command *x; | ||
2221 | 2256 | ||
2222 | /* Case when we are here: ... | var=val | ... */ | 2257 | /* Case when we are here: ... | var=val | ... */ |
2223 | if (!argv[assignment_cnt]) | 2258 | if (!argv[assignment_cnt]) |
@@ -2251,12 +2286,17 @@ static void pseudo_exec_argv(nommu_save_t *nommu_save, | |||
2251 | * easier to waste a few CPU cycles than it is to figure out | 2286 | * easier to waste a few CPU cycles than it is to figure out |
2252 | * if this is one of those cases. | 2287 | * if this is one of those cases. |
2253 | */ | 2288 | */ |
2254 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { | 2289 | { |
2255 | if (strcmp(argv[0], x->cmd) == 0) { | 2290 | int rcode; |
2256 | debug_printf_exec("running builtin '%s'\n", argv[0]); | 2291 | const struct built_in_command *x; |
2257 | rcode = x->function(argv); | 2292 | for (x = bltins; x != &bltins[ARRAY_SIZE(bltins)]; x++) { |
2258 | fflush(NULL); | 2293 | if (strcmp(argv[0], x->cmd) == 0) { |
2259 | _exit(rcode); | 2294 | debug_printf_exec("running builtin '%s'\n", |
2295 | argv[0]); | ||
2296 | rcode = x->function(argv); | ||
2297 | fflush(NULL); | ||
2298 | _exit(rcode); | ||
2299 | } | ||
2260 | } | 2300 | } |
2261 | } | 2301 | } |
2262 | #endif | 2302 | #endif |
@@ -2320,8 +2360,8 @@ static void pseudo_exec(nommu_save_t *nommu_save, | |||
2320 | * since this process is about to exit */ | 2360 | * since this process is about to exit */ |
2321 | _exit(rcode); | 2361 | _exit(rcode); |
2322 | #else | 2362 | #else |
2323 | //TODO: re-exec "hush -c command->group_as_a_string" | 2363 | bb_error_msg_and_die("NOMMU TODO: re-exec '%s'", |
2324 | bb_error_msg_and_die("nested lists are not supported on NOMMU"); | 2364 | command->group_as_string); |
2325 | #endif | 2365 | #endif |
2326 | } | 2366 | } |
2327 | 2367 | ||
@@ -3587,6 +3627,13 @@ static int reserved_word(o_string *word, struct parse_context *ctx) | |||
3587 | old = ctx->stack; | 3627 | old = ctx->stack; |
3588 | old->command->group = ctx->list_head; | 3628 | old->command->group = ctx->list_head; |
3589 | old->command->grp_type = GRP_NORMAL; | 3629 | old->command->grp_type = GRP_NORMAL; |
3630 | #if !BB_MMU | ||
3631 | o_addstr(&old->as_string, ctx->as_string.data); | ||
3632 | o_free_unsafe(&ctx->as_string); | ||
3633 | old->command->group_as_string = xstrdup(old->as_string.data); | ||
3634 | debug_printf_parse("pop, remembering as:'%s'\n", | ||
3635 | old->command->group_as_string); | ||
3636 | #endif | ||
3590 | *ctx = *old; /* physical copy */ | 3637 | *ctx = *old; /* physical copy */ |
3591 | free(old); | 3638 | free(old); |
3592 | } | 3639 | } |
@@ -3739,7 +3786,13 @@ static int redirect_opt_num(o_string *o) | |||
3739 | return num; | 3786 | return num; |
3740 | } | 3787 | } |
3741 | 3788 | ||
3742 | static struct pipe *parse_stream(struct in_str *input, int end_trigger); | 3789 | #if BB_MMU |
3790 | #define parse_stream(pstring, input, end_trigger) \ | ||
3791 | parse_stream(input, end_trigger) | ||
3792 | #endif | ||
3793 | static struct pipe *parse_stream(char **pstring, | ||
3794 | struct in_str *input, | ||
3795 | int end_trigger); | ||
3743 | static void parse_and_run_string(const char *s); | 3796 | static void parse_and_run_string(const char *s); |
3744 | 3797 | ||
3745 | #if ENABLE_HUSH_TICK | 3798 | #if ENABLE_HUSH_TICK |
@@ -3864,15 +3917,33 @@ static int parse_group(o_string *dest, struct parse_context *ctx, | |||
3864 | endch = ')'; | 3917 | endch = ')'; |
3865 | command->grp_type = GRP_SUBSHELL; | 3918 | command->grp_type = GRP_SUBSHELL; |
3866 | } | 3919 | } |
3867 | pipe_list = parse_stream(input, endch); | 3920 | { |
3868 | /* empty ()/{} or parse error? */ | 3921 | #if !BB_MMU |
3869 | if (!pipe_list || pipe_list == ERR_PTR) { | 3922 | char *as_string = NULL; |
3870 | syntax(NULL); | 3923 | #endif |
3871 | debug_printf_parse("parse_group return 1: " | 3924 | pipe_list = parse_stream(&as_string, input, endch); |
3872 | "parse_stream returned %p\n", pipe_list); | 3925 | #if !BB_MMU |
3873 | return 1; | 3926 | if (as_string) |
3927 | o_addstr(&ctx->as_string, as_string); | ||
3928 | #endif | ||
3929 | /* empty ()/{} or parse error? */ | ||
3930 | if (!pipe_list || pipe_list == ERR_PTR) { | ||
3931 | #if !BB_MMU | ||
3932 | free(as_string); | ||
3933 | #endif | ||
3934 | syntax(NULL); | ||
3935 | debug_printf_parse("parse_group return 1: " | ||
3936 | "parse_stream returned %p\n", pipe_list); | ||
3937 | return 1; | ||
3938 | } | ||
3939 | command->group = pipe_list; | ||
3940 | #if !BB_MMU | ||
3941 | as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */ | ||
3942 | command->group_as_string = as_string; | ||
3943 | debug_printf_parse("end of group, remembering as:'%s'\n", | ||
3944 | command->group_as_string); | ||
3945 | #endif | ||
3874 | } | 3946 | } |
3875 | command->group = pipe_list; | ||
3876 | debug_printf_parse("parse_group return 0\n"); | 3947 | debug_printf_parse("parse_group return 0\n"); |
3877 | return 0; | 3948 | return 0; |
3878 | /* command remains "open", available for possible redirects */ | 3949 | /* command remains "open", available for possible redirects */ |
@@ -4151,14 +4222,24 @@ static int handle_dollar(o_string *dest, struct in_str *input) | |||
4151 | return 0; | 4222 | return 0; |
4152 | } | 4223 | } |
4153 | 4224 | ||
4154 | static int parse_stream_dquoted(o_string *dest, | 4225 | #if BB_MMU |
4155 | struct in_str *input, int dquote_end) | 4226 | #define parse_stream_dquoted(ctx, dest, input, dquote_end) \ |
4227 | parse_stream_dquoted(dest, input, dquote_end) | ||
4228 | #endif | ||
4229 | static int parse_stream_dquoted(struct parse_context *ctx, | ||
4230 | o_string *dest, | ||
4231 | struct in_str *input, | ||
4232 | int dquote_end) | ||
4156 | { | 4233 | { |
4157 | int ch; | 4234 | int ch; |
4158 | int next; | 4235 | int next; |
4159 | 4236 | ||
4160 | again: | 4237 | again: |
4161 | ch = i_getch(input); | 4238 | ch = i_getch(input); |
4239 | #if !BB_MMU | ||
4240 | if (ctx && ch != EOF) | ||
4241 | o_addchr(&ctx->as_string, ch); | ||
4242 | #endif | ||
4162 | if (ch == dquote_end) { /* may be only '"' or EOF */ | 4243 | if (ch == dquote_end) { /* may be only '"' or EOF */ |
4163 | dest->nonnull = 1; | 4244 | dest->nonnull = 1; |
4164 | if (dest->o_assignment == NOT_ASSIGNMENT) | 4245 | if (dest->o_assignment == NOT_ASSIGNMENT) |
@@ -4237,15 +4318,13 @@ static int parse_stream_dquoted(o_string *dest, | |||
4237 | * reset parsing machinery and start parsing anew, | 4318 | * reset parsing machinery and start parsing anew, |
4238 | * or return ERR_PTR. | 4319 | * or return ERR_PTR. |
4239 | */ | 4320 | */ |
4240 | static struct pipe *parse_stream(struct in_str *input, int end_trigger) | 4321 | static struct pipe *parse_stream(char **pstring, |
4322 | struct in_str *input, | ||
4323 | int end_trigger) | ||
4241 | { | 4324 | { |
4242 | struct parse_context ctx; | 4325 | struct parse_context ctx; |
4243 | o_string dest = NULL_O_STRING; | 4326 | o_string dest = NULL_O_STRING; |
4244 | int redir_fd; | ||
4245 | int next; | ||
4246 | int is_in_dquote; | 4327 | int is_in_dquote; |
4247 | int ch; | ||
4248 | redir_type redir_style; | ||
4249 | 4328 | ||
4250 | /* Double-quote state is handled in the state variable is_in_dquote. | 4329 | /* Double-quote state is handled in the state variable is_in_dquote. |
4251 | * A single-quote triggers a bypass of the main loop until its mate is | 4330 | * A single-quote triggers a bypass of the main loop until its mate is |
@@ -4268,15 +4347,18 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4268 | while (1) { | 4347 | while (1) { |
4269 | const char *is_ifs; | 4348 | const char *is_ifs; |
4270 | const char *is_special; | 4349 | const char *is_special; |
4350 | int ch; | ||
4351 | int next; | ||
4352 | int redir_fd; | ||
4353 | redir_type redir_style; | ||
4271 | 4354 | ||
4272 | if (is_in_dquote) { | 4355 | if (is_in_dquote) { |
4273 | if (parse_stream_dquoted(&dest, input, '"')) { | 4356 | if (parse_stream_dquoted(&ctx, &dest, input, '"')) { |
4274 | goto parse_error; | 4357 | goto parse_error; |
4275 | } | 4358 | } |
4276 | /* We reached closing '"' */ | 4359 | /* We reached closing '"' */ |
4277 | is_in_dquote = 0; | 4360 | is_in_dquote = 0; |
4278 | } | 4361 | } |
4279 | next = '\0'; | ||
4280 | ch = i_getch(input); | 4362 | ch = i_getch(input); |
4281 | debug_printf_parse(": ch=%c (%d) escape=%d\n", | 4363 | debug_printf_parse(": ch=%c (%d) escape=%d\n", |
4282 | ch, ch, dest.o_escape); | 4364 | ch, ch, dest.o_escape); |
@@ -4287,8 +4369,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4287 | } | 4369 | } |
4288 | o_free(&dest); | 4370 | o_free(&dest); |
4289 | done_pipe(&ctx, PIPE_SEQ); | 4371 | done_pipe(&ctx, PIPE_SEQ); |
4290 | /* If we got nothing... */ | ||
4291 | pi = ctx.list_head; | 4372 | pi = ctx.list_head; |
4373 | /* If we got nothing... */ | ||
4374 | // TODO: test script consisting of just "&" | ||
4292 | if (pi->num_cmds == 0 | 4375 | if (pi->num_cmds == 0 |
4293 | IF_HAS_KEYWORDS( && pi->res_word == RES_NONE) | 4376 | IF_HAS_KEYWORDS( && pi->res_word == RES_NONE) |
4294 | ) { | 4377 | ) { |
@@ -4296,12 +4379,18 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4296 | pi = NULL; | 4379 | pi = NULL; |
4297 | } | 4380 | } |
4298 | debug_printf_parse("parse_stream return %p\n", pi); | 4381 | debug_printf_parse("parse_stream return %p\n", pi); |
4382 | #if !BB_MMU | ||
4383 | debug_printf_parse("as_string '%s'\n", ctx.as_string.data); | ||
4384 | if (pstring) | ||
4385 | *pstring = ctx.as_string.data; | ||
4386 | else | ||
4387 | o_free_unsafe(&ctx.as_string); | ||
4388 | #endif | ||
4299 | return pi; | 4389 | return pi; |
4300 | } | 4390 | } |
4301 | if (ch != '\n') { | 4391 | #if !BB_MMU |
4302 | next = i_peek(input); | 4392 | o_addchr(&ctx.as_string, ch); |
4303 | } | 4393 | #endif |
4304 | |||
4305 | is_ifs = strchr(G.ifs, ch); | 4394 | is_ifs = strchr(G.ifs, ch); |
4306 | is_special = strchr("<>;&|(){}#'" /* special outside of "str" */ | 4395 | is_special = strchr("<>;&|(){}#'" /* special outside of "str" */ |
4307 | "\\$\"" USE_HUSH_TICK("`") /* always special */ | 4396 | "\\$\"" USE_HUSH_TICK("`") /* always special */ |
@@ -4356,6 +4445,13 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4356 | "end_trigger char found\n", | 4445 | "end_trigger char found\n", |
4357 | ctx.list_head); | 4446 | ctx.list_head); |
4358 | o_free(&dest); | 4447 | o_free(&dest); |
4448 | #if !BB_MMU | ||
4449 | debug_printf_parse("as_string '%s'\n", ctx.as_string.data); | ||
4450 | if (pstring) | ||
4451 | *pstring = ctx.as_string.data; | ||
4452 | else | ||
4453 | o_free_unsafe(&ctx.as_string); | ||
4454 | #endif | ||
4359 | return ctx.list_head; | 4455 | return ctx.list_head; |
4360 | } | 4456 | } |
4361 | } | 4457 | } |
@@ -4368,6 +4464,11 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4368 | dest.o_assignment = NOT_ASSIGNMENT; | 4464 | dest.o_assignment = NOT_ASSIGNMENT; |
4369 | } | 4465 | } |
4370 | 4466 | ||
4467 | next = '\0'; | ||
4468 | if (ch != '\n') { | ||
4469 | next = i_peek(input); | ||
4470 | } | ||
4471 | |||
4371 | switch (ch) { | 4472 | switch (ch) { |
4372 | case '#': | 4473 | case '#': |
4373 | if (dest.length == 0) { | 4474 | if (dest.length == 0) { |
@@ -4601,6 +4702,9 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4601 | debug_print_tree(pctx->list_head, 0); | 4702 | debug_print_tree(pctx->list_head, 0); |
4602 | free_pipe_list(pctx->list_head, 0); | 4703 | free_pipe_list(pctx->list_head, 0); |
4603 | debug_printf_clean("freed list %p\n", pctx->list_head); | 4704 | debug_printf_clean("freed list %p\n", pctx->list_head); |
4705 | #if !BB_MMU | ||
4706 | o_free_unsafe(&pctx->as_string); | ||
4707 | #endif | ||
4604 | IF_HAS_KEYWORDS(p2 = pctx->stack;) | 4708 | IF_HAS_KEYWORDS(p2 = pctx->stack;) |
4605 | if (pctx != &ctx) { | 4709 | if (pctx != &ctx) { |
4606 | free(pctx); | 4710 | free(pctx); |
@@ -4612,8 +4716,13 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4612 | /* If we are not in top-level parse, we return, | 4716 | /* If we are not in top-level parse, we return, |
4613 | * our caller will propagate error. | 4717 | * our caller will propagate error. |
4614 | */ | 4718 | */ |
4615 | if (end_trigger != ';') | 4719 | if (end_trigger != ';') { |
4720 | #if !BB_MMU | ||
4721 | if (pstring) | ||
4722 | *pstring = NULL; | ||
4723 | #endif | ||
4616 | return ERR_PTR; | 4724 | return ERR_PTR; |
4725 | } | ||
4617 | /* Discard cached input, force prompt */ | 4726 | /* Discard cached input, force prompt */ |
4618 | input->p = NULL; | 4727 | input->p = NULL; |
4619 | USE_HUSH_INTERACTIVE(input->promptme = 1;) | 4728 | USE_HUSH_INTERACTIVE(input->promptme = 1;) |
@@ -4621,7 +4730,7 @@ static struct pipe *parse_stream(struct in_str *input, int end_trigger) | |||
4621 | } | 4730 | } |
4622 | } | 4731 | } |
4623 | 4732 | ||
4624 | /* Execiting from string: eval, sh -c '...' | 4733 | /* Executing from string: eval, sh -c '...' |
4625 | * or from file: /etc/profile, . file, sh <script>, sh (intereactive) | 4734 | * or from file: /etc/profile, . file, sh <script>, sh (intereactive) |
4626 | * end_trigger controls how often we stop parsing | 4735 | * end_trigger controls how often we stop parsing |
4627 | * NUL: parse all, execute, return | 4736 | * NUL: parse all, execute, return |
@@ -4632,7 +4741,7 @@ static void parse_and_run_stream(struct in_str *inp, int end_trigger) | |||
4632 | while (1) { | 4741 | while (1) { |
4633 | struct pipe *pipe_list; | 4742 | struct pipe *pipe_list; |
4634 | 4743 | ||
4635 | pipe_list = parse_stream(inp, end_trigger); | 4744 | pipe_list = parse_stream(NULL, inp, end_trigger); |
4636 | if (!pipe_list) /* EOF */ | 4745 | if (!pipe_list) /* EOF */ |
4637 | break; | 4746 | break; |
4638 | debug_print_tree(pipe_list, 0); | 4747 | debug_print_tree(pipe_list, 0); |