aboutsummaryrefslogtreecommitdiff
path: root/shell
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-04 22:47:50 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-04 22:47:50 +0000
commit9aa7d6fdc5554480b9cb4fc740ce3f1d2b734555 (patch)
tree3f822f617f914908f77f509321159b8ed4444a61 /shell
parent42e78b978fce494f3f9c1cd629fbf06f9b8ea11c (diff)
downloadbusybox-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.c291
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
309typedef 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;
321enum {
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? */
332typedef 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
301struct redir_struct { 348struct 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
392typedef 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;
404enum {
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? */
415typedef 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
431enum { 445enum {
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
1376static ALWAYS_INLINE void o_free_unsafe(o_string *o)
1377{
1378 free(o->data);
1379}
1380
1362static void o_grow_by(o_string *o, int len) 1381static 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
1379static void o_addstr(o_string *o, const char *str, int len) 1398static 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
1387static void o_addstrauto(o_string *o, const char *str) 1406#if !BB_MMU
1407static void o_addstr(o_string *o, const char *str)
1408{
1409 o_addblock(o, str, strlen(str));
1410}
1411#endif
1412
1413static 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
1392static void o_addstr_duplicate_backslash(o_string *o, const char *str, int len) 1418static 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)
1438static void o_addQstr(o_string *o, const char *str, int len) 1464static 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)
1635static int process_command_subs(o_string *dest, const char *s); 1661static int process_command_subs(o_string *dest, const char *s);
1636#endif 1662#endif
1637static char *expand_string_to_string(const char *str); 1663static char *expand_string_to_string(const char *str);
1638static 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
1668static 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
3742static 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
3793static struct pipe *parse_stream(char **pstring,
3794 struct in_str *input,
3795 int end_trigger);
3743static void parse_and_run_string(const char *s); 3796static 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
4154static 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
4229static 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 */
4240static struct pipe *parse_stream(struct in_str *input, int end_trigger) 4321static 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);