summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2002-04-13 12:33:41 +0000
committerEric Andersen <andersen@codepoet.org>2002-04-13 12:33:41 +0000
commit4c9b68f0e013b0b7554a3278e078177f955d39f4 (patch)
treee3caabb50e0a205221c61100ced2d0a545ff39ed
parenta66a43e8ef1e55c2415aa7084365cce3fb8f931a (diff)
downloadbusybox-w32-4c9b68f0e013b0b7554a3278e078177f955d39f4.tar.gz
busybox-w32-4c9b68f0e013b0b7554a3278e078177f955d39f4.tar.bz2
busybox-w32-4c9b68f0e013b0b7554a3278e078177f955d39f4.zip
Nice patch from Wolfgang Denk <wd@denx.de> to provide hush with
shell loops (for, while, until) and control operators (||, &&)
-rw-r--r--shell/hush.c347
1 files changed, 308 insertions, 39 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 27afd3e7c..08b3b295f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -116,6 +116,10 @@
116#undef CONFIG_FEATURE_SH_FANCY_PROMPT 116#undef CONFIG_FEATURE_SH_FANCY_PROMPT
117#define BB_BANNER 117#define BB_BANNER
118#endif 118#endif
119#define SPECIAL_VAR_SYMBOL 03
120#define FLAG_EXIT_FROM_LOOP 1
121#define FLAG_PARSE_SEMICOLON (1 << 1) /* symbol ';' is special for parser */
122#define FLAG_REPARSING (1 << 2) /* >=2nd pass */
119 123
120typedef enum { 124typedef enum {
121 REDIRECT_INPUT = 1, 125 REDIRECT_INPUT = 1,
@@ -157,7 +161,8 @@ typedef enum {
157 RES_DO = 9, 161 RES_DO = 9,
158 RES_DONE = 10, 162 RES_DONE = 10,
159 RES_XXXX = 11, 163 RES_XXXX = 11,
160 RES_SNTX = 12 164 RES_IN = 12,
165 RES_SNTX = 13
161} reserved_style; 166} reserved_style;
162#define FLAG_END (1<<RES_NONE) 167#define FLAG_END (1<<RES_NONE)
163#define FLAG_IF (1<<RES_IF) 168#define FLAG_IF (1<<RES_IF)
@@ -170,6 +175,7 @@ typedef enum {
170#define FLAG_UNTIL (1<<RES_UNTIL) 175#define FLAG_UNTIL (1<<RES_UNTIL)
171#define FLAG_DO (1<<RES_DO) 176#define FLAG_DO (1<<RES_DO)
172#define FLAG_DONE (1<<RES_DONE) 177#define FLAG_DONE (1<<RES_DONE)
178#define FLAG_IN (1<<RES_IN)
173#define FLAG_START (1<<RES_XXXX) 179#define FLAG_START (1<<RES_XXXX)
174 180
175/* This holds pointers to the various results of parsing */ 181/* This holds pointers to the various results of parsing */
@@ -181,6 +187,7 @@ struct p_context {
181 reserved_style w; 187 reserved_style w;
182 int old_flag; /* for figuring out valid reserved words */ 188 int old_flag; /* for figuring out valid reserved words */
183 struct p_context *stack; 189 struct p_context *stack;
190 int type; /* define type of parser : ";$" common or special symbol */
184 /* How about quoting status? */ 191 /* How about quoting status? */
185}; 192};
186 193
@@ -201,6 +208,8 @@ struct child_prog {
201 glob_t glob_result; /* result of parameter globbing */ 208 glob_t glob_result; /* result of parameter globbing */
202 int is_stopped; /* is the program currently running? */ 209 int is_stopped; /* is the program currently running? */
203 struct pipe *family; /* pointer back to the child's parent pipe */ 210 struct pipe *family; /* pointer back to the child's parent pipe */
211 int sp; /* number of SPECIAL_VAR_SYMBOL */
212 int type;
204}; 213};
205 214
206struct pipe { 215struct pipe {
@@ -319,6 +328,7 @@ static void __syntax(char *file, int line) {
319/* function prototypes for builtins */ 328/* function prototypes for builtins */
320static int builtin_cd(struct child_prog *child); 329static int builtin_cd(struct child_prog *child);
321static int builtin_env(struct child_prog *child); 330static int builtin_env(struct child_prog *child);
331static int builtin_eval(struct child_prog *child);
322static int builtin_exec(struct child_prog *child); 332static int builtin_exec(struct child_prog *child);
323static int builtin_exit(struct child_prog *child); 333static int builtin_exit(struct child_prog *child);
324static int builtin_export(struct child_prog *child); 334static int builtin_export(struct child_prog *child);
@@ -376,19 +386,22 @@ static int redirect_dup_num(struct in_str *input);
376static int redirect_opt_num(o_string *o); 386static int redirect_opt_num(o_string *o);
377static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); 387static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end);
378static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); 388static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch);
379static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src); 389static char *lookup_param(char *src);
390static char *make_string(char **inp);
380static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); 391static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input);
381static int parse_string(o_string *dest, struct p_context *ctx, const char *src); 392static int parse_string(o_string *dest, struct p_context *ctx, const char *src);
382static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); 393static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger);
383/* setup: */ 394/* setup: */
384static int parse_stream_outer(struct in_str *inp); 395static int parse_stream_outer(struct in_str *inp, int flag);
385static int parse_string_outer(const char *s); 396static int parse_string_outer(const char *s, int flag);
386static int parse_file_outer(FILE *f); 397static int parse_file_outer(FILE *f);
387/* job management: */ 398/* job management: */
388static int checkjobs(struct pipe* fg_pipe); 399static int checkjobs(struct pipe* fg_pipe);
389static void insert_bg_job(struct pipe *pi); 400static void insert_bg_job(struct pipe *pi);
390static void remove_bg_job(struct pipe *pi); 401static void remove_bg_job(struct pipe *pi);
391/* local variable support */ 402/* local variable support */
403static char **make_list_in(char **inp, char *name);
404static char *insert_var_value(char *inp);
392static char *get_local_var(const char *var); 405static char *get_local_var(const char *var);
393static void unset_local_var(const char *name); 406static void unset_local_var(const char *name);
394static int set_local_var(const char *s, int flg_export); 407static int set_local_var(const char *s, int flg_export);
@@ -405,7 +418,7 @@ static struct built_in_command bltins[] = {
405 {"cd", "Change working directory", builtin_cd}, 418 {"cd", "Change working directory", builtin_cd},
406 {"continue", "Continue for, while or until loop", builtin_not_written}, 419 {"continue", "Continue for, while or until loop", builtin_not_written},
407 {"env", "Print all environment variables", builtin_env}, 420 {"env", "Print all environment variables", builtin_env},
408 {"eval", "Construct and run shell command", builtin_not_written}, 421 {"eval", "Construct and run shell command", builtin_eval},
409 {"exec", "Exec command, replacing this shell with the exec'd process", 422 {"exec", "Exec command, replacing this shell with the exec'd process",
410 builtin_exec}, 423 builtin_exec},
411 {"exit", "Exit from shell()", builtin_exit}, 424 {"exit", "Exit from shell()", builtin_exit},
@@ -436,6 +449,21 @@ static const char *set_cwd(void)
436 return cwd; 449 return cwd;
437} 450}
438 451
452/* built-in 'eval' handler */
453static int builtin_eval(struct child_prog *child)
454{
455 char *str = NULL;
456 int rcode = EXIT_SUCCESS;
457
458 if (child->argv[1]) {
459 str = make_string(child->argv + 1);
460 parse_string_outer(str, FLAG_EXIT_FROM_LOOP |
461 FLAG_PARSE_SEMICOLON);
462 free(str);
463 rcode = last_return_code;
464 }
465 return rcode;
466}
439 467
440/* built-in 'cd <path>' handler */ 468/* built-in 'cd <path>' handler */
441static int builtin_cd(struct child_prog *child) 469static int builtin_cd(struct child_prog *child)
@@ -1046,11 +1074,14 @@ static void restore_redirects(int squirrel[])
1046static void pseudo_exec(struct child_prog *child) 1074static void pseudo_exec(struct child_prog *child)
1047{ 1075{
1048 int i, rcode; 1076 int i, rcode;
1077 char *p;
1049 struct built_in_command *x; 1078 struct built_in_command *x;
1050 if (child->argv) { 1079 if (child->argv) {
1051 for (i=0; is_assignment(child->argv[i]); i++) { 1080 for (i=0; is_assignment(child->argv[i]); i++) {
1052 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]); 1081 debug_printf("pid %d environment modification: %s\n",getpid(),child->argv[i]);
1053 putenv(strdup(child->argv[i])); 1082 p = insert_var_value(child->argv[i]);
1083 putenv(strdup(p));
1084 if (p != child->argv[i]) free(p);
1054 } 1085 }
1055 child->argv+=i; /* XXX this hack isn't so horrible, since we are about 1086 child->argv+=i; /* XXX this hack isn't so horrible, since we are about
1056 to exit, and therefore don't need to keep data 1087 to exit, and therefore don't need to keep data
@@ -1317,6 +1348,7 @@ static int run_pipe_real(struct pipe *pi)
1317 int pipefds[2]; /* pipefds[0] is for reading */ 1348 int pipefds[2]; /* pipefds[0] is for reading */
1318 struct child_prog *child; 1349 struct child_prog *child;
1319 struct built_in_command *x; 1350 struct built_in_command *x;
1351 char *p;
1320 1352
1321 nextin = 0; 1353 nextin = 0;
1322 pi->pgrp = -1; 1354 pi->pgrp = -1;
@@ -1359,10 +1391,28 @@ static int run_pipe_real(struct pipe *pi)
1359 export_me=1; 1391 export_me=1;
1360 } 1392 }
1361 free(name); 1393 free(name);
1362 set_local_var(child->argv[i], export_me); 1394 p = insert_var_value(child->argv[i]);
1395 set_local_var(p, export_me);
1396 if (p != child->argv[i]) free(p);
1363 } 1397 }
1364 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */ 1398 return EXIT_SUCCESS; /* don't worry about errors in set_local_var() yet */
1365 } 1399 }
1400 for (i = 0; is_assignment(child->argv[i]); i++) {
1401 p = insert_var_value(child->argv[i]);
1402 putenv(strdup(p));
1403 if (p != child->argv[i]) {
1404 child->sp--;
1405 free(p);
1406 }
1407 }
1408 if (child->sp) {
1409 char * str = NULL;
1410
1411 str = make_string((child->argv + i));
1412 parse_string_outer(str, FLAG_EXIT_FROM_LOOP | FLAG_REPARSING);
1413 free(str);
1414 return last_return_code;
1415 }
1366 for (x = bltins; x->cmd; x++) { 1416 for (x = bltins; x->cmd; x++) {
1367 if (strcmp(child->argv[i], x->cmd) == 0 ) { 1417 if (strcmp(child->argv[i], x->cmd) == 0 ) {
1368 int squirrel[] = {-1, -1, -1}; 1418 int squirrel[] = {-1, -1, -1};
@@ -1378,9 +1428,6 @@ static int run_pipe_real(struct pipe *pi)
1378 * Is it really safe for inline use? Experimentally, 1428 * Is it really safe for inline use? Experimentally,
1379 * things seem to work with glibc. */ 1429 * things seem to work with glibc. */
1380 setup_redirects(child, squirrel); 1430 setup_redirects(child, squirrel);
1381 for (i=0; is_assignment(child->argv[i]); i++) {
1382 putenv(strdup(child->argv[i]));
1383 }
1384 child->argv+=i; /* XXX horrible hack */ 1431 child->argv+=i; /* XXX horrible hack */
1385 rcode = x->function(child); 1432 rcode = x->function(child);
1386 child->argv-=i; /* XXX restore hack so free() can work right */ 1433 child->argv-=i; /* XXX restore hack so free() can work right */
@@ -1474,19 +1521,97 @@ static int run_pipe_real(struct pipe *pi)
1474 1521
1475static int run_list_real(struct pipe *pi) 1522static int run_list_real(struct pipe *pi)
1476{ 1523{
1477 int rcode=0; 1524 char *save_name = NULL;
1525 char **list = NULL;
1526 char **save_list = NULL;
1527 struct pipe *rpipe;
1528 int flag_rep = 0;
1529 int save_num_progs;
1530 int rcode=0, flag_skip=1;
1531 int flag_restore = 0;
1478 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */ 1532 int if_code=0, next_if_code=0; /* need double-buffer to handle elif */
1479 reserved_style rmode, skip_more_in_this_rmode=RES_XXXX; 1533 reserved_style rmode, skip_more_in_this_rmode=RES_XXXX;
1480 for (;pi;pi=pi->next) { 1534 /* check syntax for "for" */
1535 for (rpipe = pi; rpipe; rpipe = rpipe->next) {
1536 if ((rpipe->r_mode == RES_IN ||
1537 rpipe->r_mode == RES_FOR) &&
1538 (rpipe->next == NULL)) {
1539 syntax();
1540 return 1;
1541 }
1542 if ((rpipe->r_mode == RES_IN &&
1543 (rpipe->next->r_mode == RES_IN &&
1544 rpipe->next->progs->argv != NULL))||
1545 (rpipe->r_mode == RES_FOR &&
1546 rpipe->next->r_mode != RES_IN)) {
1547 syntax();
1548 return 1;
1549 }
1550 }
1551 for (; pi; pi = (flag_restore != 0) ? rpipe : pi->next) {
1552 if (pi->r_mode == RES_WHILE || pi->r_mode == RES_UNTIL ||
1553 pi->r_mode == RES_FOR) {
1554 flag_restore = 0;
1555 if (!rpipe) {
1556 flag_rep = 0;
1557 rpipe = pi;
1558 }
1559 }
1481 rmode = pi->r_mode; 1560 rmode = pi->r_mode;
1482 debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode); 1561 debug_printf("rmode=%d if_code=%d next_if_code=%d skip_more=%d\n", rmode, if_code, next_if_code, skip_more_in_this_rmode);
1483 if (rmode == skip_more_in_this_rmode) continue; 1562 if (rmode == skip_more_in_this_rmode && flag_skip) {
1563 if (pi->followup == PIPE_SEQ) flag_skip=0;
1564 continue;
1565 }
1566 flag_skip = 1;
1484 skip_more_in_this_rmode = RES_XXXX; 1567 skip_more_in_this_rmode = RES_XXXX;
1485 if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code; 1568 if (rmode == RES_THEN || rmode == RES_ELSE) if_code = next_if_code;
1486 if (rmode == RES_THEN && if_code) continue; 1569 if (rmode == RES_THEN && if_code) continue;
1487 if (rmode == RES_ELSE && !if_code) continue; 1570 if (rmode == RES_ELSE && !if_code) continue;
1488 if (rmode == RES_ELIF && !if_code) continue; 1571 if (rmode == RES_ELIF && !if_code) continue;
1572 if (rmode == RES_FOR && pi->num_progs) {
1573 if (!list) {
1574 /* if no variable values after "in" we skip "for" */
1575 if (!pi->next->progs->argv) continue;
1576 /* create list of variable values */
1577 list = make_list_in(pi->next->progs->argv,
1578 pi->progs->argv[0]);
1579 save_list = list;
1580 save_name = pi->progs->argv[0];
1581 pi->progs->argv[0] = NULL;
1582 flag_rep = 1;
1583 }
1584 if (!(*list)) {
1585 free(pi->progs->argv[0]);
1586 free(save_list);
1587 list = NULL;
1588 flag_rep = 0;
1589 pi->progs->argv[0] = save_name;
1590 pi->progs->glob_result.gl_pathv[0] =
1591 pi->progs->argv[0];
1592 continue;
1593 } else {
1594 /* insert new value from list for variable */
1595 if (pi->progs->argv[0])
1596 free(pi->progs->argv[0]);
1597 pi->progs->argv[0] = *list++;
1598 pi->progs->glob_result.gl_pathv[0] =
1599 pi->progs->argv[0];
1600 }
1601 }
1602 if (rmode == RES_IN) continue;
1603 if (rmode == RES_DO) {
1604 if (!flag_rep) continue;
1605 }
1606 if ((rmode == RES_DONE)) {
1607 if (flag_rep) {
1608 flag_restore = 1;
1609 } else {
1610 rpipe = NULL;
1611 }
1612 }
1489 if (pi->num_progs == 0) continue; 1613 if (pi->num_progs == 0) continue;
1614 save_num_progs = pi->num_progs; /* save number of programs */
1490 rcode = run_pipe_real(pi); 1615 rcode = run_pipe_real(pi);
1491 debug_printf("run_pipe_real returned %d\n",rcode); 1616 debug_printf("run_pipe_real returned %d\n",rcode);
1492 if (rcode!=-1) { 1617 if (rcode!=-1) {
@@ -1513,8 +1638,13 @@ static int run_list_real(struct pipe *pi)
1513 debug_printf("checkjobs returned %d\n",rcode); 1638 debug_printf("checkjobs returned %d\n",rcode);
1514 } 1639 }
1515 last_return_code=rcode; 1640 last_return_code=rcode;
1641 pi->num_progs = save_num_progs; /* restore number of programs */
1516 if ( rmode == RES_IF || rmode == RES_ELIF ) 1642 if ( rmode == RES_IF || rmode == RES_ELIF )
1517 next_if_code=rcode; /* can be overwritten a number of times */ 1643 next_if_code=rcode; /* can be overwritten a number of times */
1644 if (rmode == RES_WHILE)
1645 flag_rep = !last_return_code;
1646 if (rmode == RES_UNTIL)
1647 flag_rep = last_return_code;
1518 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) || 1648 if ( (rcode==EXIT_SUCCESS && pi->followup==PIPE_OR) ||
1519 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) ) 1649 (rcode!=EXIT_SUCCESS && pi->followup==PIPE_AND) )
1520 skip_more_in_this_rmode=rmode; 1650 skip_more_in_this_rmode=rmode;
@@ -1898,6 +2028,7 @@ static void initialize_context(struct p_context *ctx)
1898 ctx->pipe=ctx->list_head; 2028 ctx->pipe=ctx->list_head;
1899 ctx->w=RES_NONE; 2029 ctx->w=RES_NONE;
1900 ctx->stack=NULL; 2030 ctx->stack=NULL;
2031 ctx->old_flag=0;
1901 done_command(ctx); /* creates the memory for working child */ 2032 done_command(ctx); /* creates the memory for working child */
1902} 2033}
1903 2034
@@ -1924,9 +2055,10 @@ int reserved_word(o_string *dest, struct p_context *ctx)
1924 { "elif", RES_ELIF, FLAG_THEN }, 2055 { "elif", RES_ELIF, FLAG_THEN },
1925 { "else", RES_ELSE, FLAG_FI }, 2056 { "else", RES_ELSE, FLAG_FI },
1926 { "fi", RES_FI, FLAG_END }, 2057 { "fi", RES_FI, FLAG_END },
1927 { "for", RES_FOR, FLAG_DO | FLAG_START }, 2058 { "for", RES_FOR, FLAG_IN | FLAG_START },
1928 { "while", RES_WHILE, FLAG_DO | FLAG_START }, 2059 { "while", RES_WHILE, FLAG_DO | FLAG_START },
1929 { "until", RES_UNTIL, FLAG_DO | FLAG_START }, 2060 { "until", RES_UNTIL, FLAG_DO | FLAG_START },
2061 { "in", RES_IN, FLAG_DO },
1930 { "do", RES_DO, FLAG_DONE }, 2062 { "do", RES_DO, FLAG_DONE },
1931 { "done", RES_DONE, FLAG_END } 2063 { "done", RES_DONE, FLAG_END }
1932 }; 2064 };
@@ -1939,13 +2071,20 @@ int reserved_word(o_string *dest, struct p_context *ctx)
1939 if (r->flag & FLAG_START) { 2071 if (r->flag & FLAG_START) {
1940 struct p_context *new = xmalloc(sizeof(struct p_context)); 2072 struct p_context *new = xmalloc(sizeof(struct p_context));
1941 debug_printf("push stack\n"); 2073 debug_printf("push stack\n");
2074 if (ctx->w == RES_IN || ctx->w == RES_FOR) {
2075 syntax();
2076 free(new);
2077 ctx->w = RES_SNTX;
2078 b_reset(dest);
2079 return 1;
2080 }
1942 *new = *ctx; /* physical copy */ 2081 *new = *ctx; /* physical copy */
1943 initialize_context(ctx); 2082 initialize_context(ctx);
1944 ctx->stack=new; 2083 ctx->stack=new;
1945 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) { 2084 } else if ( ctx->w == RES_NONE || ! (ctx->old_flag & (1<<r->code))) {
1946 syntax(); 2085 syntax();
1947 ctx->w = RES_SNTX; 2086 ctx->w = RES_SNTX;
1948 b_reset (dest); 2087 b_reset(dest);
1949 return 1; 2088 return 1;
1950 } 2089 }
1951 ctx->w=r->code; 2090 ctx->w=r->code;
@@ -1953,6 +2092,7 @@ int reserved_word(o_string *dest, struct p_context *ctx)
1953 if (ctx->old_flag & FLAG_END) { 2092 if (ctx->old_flag & FLAG_END) {
1954 struct p_context *old; 2093 struct p_context *old;
1955 debug_printf("pop stack\n"); 2094 debug_printf("pop stack\n");
2095 done_pipe(ctx,PIPE_SEQ);
1956 old = ctx->stack; 2096 old = ctx->stack;
1957 old->child->group = ctx->list_head; 2097 old->child->group = ctx->list_head;
1958 old->child->subshell = 0; 2098 old->child->subshell = 0;
@@ -1986,7 +2126,7 @@ static int done_word(o_string *dest, struct p_context *ctx)
1986 syntax(); 2126 syntax();
1987 return 1; /* syntax error, groups and arglists don't mix */ 2127 return 1; /* syntax error, groups and arglists don't mix */
1988 } 2128 }
1989 if (!child->argv) { 2129 if (!child->argv && (ctx->type & FLAG_PARSE_SEMICOLON)) {
1990 debug_printf("checking %s for reserved-ness\n",dest->data); 2130 debug_printf("checking %s for reserved-ness\n",dest->data);
1991 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX; 2131 if (reserved_word(dest,ctx)) return ctx->w==RES_SNTX;
1992 } 2132 }
@@ -2006,6 +2146,10 @@ static int done_word(o_string *dest, struct p_context *ctx)
2006 } else { 2146 } else {
2007 child->argv = glob_target->gl_pathv; 2147 child->argv = glob_target->gl_pathv;
2008 } 2148 }
2149 if (ctx->w == RES_FOR) {
2150 done_word(dest,ctx);
2151 done_pipe(ctx,PIPE_SEQ);
2152 }
2009 return 0; 2153 return 0;
2010} 2154}
2011 2155
@@ -2041,8 +2185,10 @@ static int done_command(struct p_context *ctx)
2041 prog->group = NULL; 2185 prog->group = NULL;
2042 prog->glob_result.gl_pathv = NULL; 2186 prog->glob_result.gl_pathv = NULL;
2043 prog->family = pi; 2187 prog->family = pi;
2188 prog->sp = 0;
2189 ctx->child = prog;
2190 prog->type = ctx->type;
2044 2191
2045 ctx->child=prog;
2046 /* but ctx->pipe and ctx->list_head remain unchanged */ 2192 /* but ctx->pipe and ctx->list_head remain unchanged */
2047 return 0; 2193 return 0;
2048} 2194}
@@ -2227,32 +2373,32 @@ static int parse_group(o_string *dest, struct p_context *ctx,
2227 2373
2228/* basically useful version until someone wants to get fancier, 2374/* basically useful version until someone wants to get fancier,
2229 * see the bash man page under "Parameter Expansion" */ 2375 * see the bash man page under "Parameter Expansion" */
2230static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src) 2376static char *lookup_param(char *src)
2231{ 2377{
2232 const char *p=NULL; 2378 char *p=NULL;
2233 if (src->data) { 2379 if (src) {
2234 p = getenv(src->data); 2380 p = getenv(src);
2235 if (!p) 2381 if (!p)
2236 p = get_local_var(src->data); 2382 p = get_local_var(src);
2237 } 2383 }
2238 if (p) parse_string(dest, ctx, p); /* recursion */ 2384 return p;
2239 b_free(src);
2240} 2385}
2241 2386
2242/* return code: 0 for OK, 1 for syntax error */ 2387/* return code: 0 for OK, 1 for syntax error */
2243static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) 2388static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input)
2244{ 2389{
2245 int i, advance=0; 2390 int i, advance=0;
2246 o_string alt=NULL_O_STRING;
2247 char sep[]=" "; 2391 char sep[]=" ";
2248 int ch = input->peek(input); /* first character after the $ */ 2392 int ch = input->peek(input); /* first character after the $ */
2249 debug_printf("handle_dollar: ch=%c\n",ch); 2393 debug_printf("handle_dollar: ch=%c\n",ch);
2250 if (isalpha(ch)) { 2394 if (isalpha(ch)) {
2395 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2396 ctx->child->sp++;
2251 while(ch=b_peek(input),isalnum(ch) || ch=='_') { 2397 while(ch=b_peek(input),isalnum(ch) || ch=='_') {
2252 b_getch(input); 2398 b_getch(input);
2253 b_addchr(&alt,ch); 2399 b_addchr(dest,ch);
2254 } 2400 }
2255 lookup_param(dest, ctx, &alt); 2401 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2256 } else if (isdigit(ch)) { 2402 } else if (isdigit(ch)) {
2257 i = ch-'0'; /* XXX is $0 special? */ 2403 i = ch-'0'; /* XXX is $0 special? */
2258 if (i<global_argc) { 2404 if (i<global_argc) {
@@ -2277,16 +2423,18 @@ static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *i
2277 advance = 1; 2423 advance = 1;
2278 break; 2424 break;
2279 case '{': 2425 case '{':
2426 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2427 ctx->child->sp++;
2280 b_getch(input); 2428 b_getch(input);
2281 /* XXX maybe someone will try to escape the '}' */ 2429 /* XXX maybe someone will try to escape the '}' */
2282 while(ch=b_getch(input),ch!=EOF && ch!='}') { 2430 while(ch=b_getch(input),ch!=EOF && ch!='}') {
2283 b_addchr(&alt,ch); 2431 b_addchr(dest,ch);
2284 } 2432 }
2285 if (ch != '}') { 2433 if (ch != '}') {
2286 syntax(); 2434 syntax();
2287 return 1; 2435 return 1;
2288 } 2436 }
2289 lookup_param(dest, ctx, &alt); 2437 b_addchr(dest, SPECIAL_VAR_SYMBOL);
2290 break; 2438 break;
2291 case '(': 2439 case '(':
2292 b_getch(input); 2440 b_getch(input);
@@ -2348,7 +2496,9 @@ int parse_stream(o_string *dest, struct p_context *ctx,
2348 b_addqchr(dest, ch, dest->quote); 2496 b_addqchr(dest, ch, dest->quote);
2349 } else { 2497 } else {
2350 if (m==2) { /* unquoted IFS */ 2498 if (m==2) { /* unquoted IFS */
2351 done_word(dest, ctx); 2499 if (done_word(dest, ctx)) {
2500 return 1;
2501 }
2352 /* If we aren't performing a substitution, treat a newline as a 2502 /* If we aren't performing a substitution, treat a newline as a
2353 * command separator. */ 2503 * command separator. */
2354 if (end_trigger != '\0' && ch=='\n') 2504 if (end_trigger != '\0' && ch=='\n')
@@ -2509,30 +2659,46 @@ void update_ifs_map(void)
2509 2659
2510/* most recursion does not come through here, the exeception is 2660/* most recursion does not come through here, the exeception is
2511 * from builtin_source() */ 2661 * from builtin_source() */
2512int parse_stream_outer(struct in_str *inp) 2662int parse_stream_outer(struct in_str *inp, int flag)
2513{ 2663{
2514 2664
2515 struct p_context ctx; 2665 struct p_context ctx;
2516 o_string temp=NULL_O_STRING; 2666 o_string temp=NULL_O_STRING;
2517 int rcode; 2667 int rcode;
2518 do { 2668 do {
2669 ctx.type = flag;
2519 initialize_context(&ctx); 2670 initialize_context(&ctx);
2520 update_ifs_map(); 2671 update_ifs_map();
2672 if (!(flag & FLAG_PARSE_SEMICOLON) || (flag & FLAG_REPARSING)) mapset(";$&|", 0);
2521 inp->promptmode=1; 2673 inp->promptmode=1;
2522 rcode = parse_stream(&temp, &ctx, inp, '\n'); 2674 rcode = parse_stream(&temp, &ctx, inp, '\n');
2523 done_word(&temp, &ctx); 2675 if (rcode != 1 && ctx.old_flag != 0) {
2524 done_pipe(&ctx,PIPE_SEQ); 2676 syntax();
2525 run_list(ctx.list_head); 2677 }
2678 if (rcode != 1 && ctx.old_flag == 0) {
2679 done_word(&temp, &ctx);
2680 done_pipe(&ctx,PIPE_SEQ);
2681 run_list(ctx.list_head);
2682 } else {
2683 if (ctx.old_flag != 0) {
2684 free(ctx.stack);
2685 b_reset(&temp);
2686 }
2687 temp.nonnull = 0;
2688 temp.quote = 0;
2689 inp->p = NULL;
2690 free_pipe_list(ctx.list_head,0);
2691 }
2526 b_free(&temp); 2692 b_free(&temp);
2527 } while (rcode != -1); /* loop on syntax errors, return on EOF */ 2693 } while (rcode != -1 && !(flag & FLAG_EXIT_FROM_LOOP)); /* loop on syntax errors, return on EOF */
2528 return 0; 2694 return 0;
2529} 2695}
2530 2696
2531static int parse_string_outer(const char *s) 2697static int parse_string_outer(const char *s, int flag)
2532{ 2698{
2533 struct in_str input; 2699 struct in_str input;
2534 setup_string_in_str(&input, s); 2700 setup_string_in_str(&input, s);
2535 return parse_stream_outer(&input); 2701 return parse_stream_outer(&input, flag);
2536} 2702}
2537 2703
2538static int parse_file_outer(FILE *f) 2704static int parse_file_outer(FILE *f)
@@ -2540,7 +2706,7 @@ static int parse_file_outer(FILE *f)
2540 int rcode; 2706 int rcode;
2541 struct in_str input; 2707 struct in_str input;
2542 setup_file_in_str(&input, f); 2708 setup_file_in_str(&input, f);
2543 rcode = parse_stream_outer(&input); 2709 rcode = parse_stream_outer(&input, FLAG_PARSE_SEMICOLON);
2544 return rcode; 2710 return rcode;
2545} 2711}
2546 2712
@@ -2630,7 +2796,7 @@ int hush_main(int argc, char **argv)
2630 { 2796 {
2631 global_argv = argv+optind; 2797 global_argv = argv+optind;
2632 global_argc = argc-optind; 2798 global_argc = argc-optind;
2633 opt = parse_string_outer(optarg); 2799 opt = parse_string_outer(optarg, FLAG_PARSE_SEMICOLON);
2634 goto final_return; 2800 goto final_return;
2635 } 2801 }
2636 break; 2802 break;
@@ -2703,3 +2869,106 @@ int hush_main(int argc, char **argv)
2703final_return: 2869final_return:
2704 return(opt?opt:last_return_code); 2870 return(opt?opt:last_return_code);
2705} 2871}
2872
2873static char *insert_var_value(char *inp)
2874{
2875 int res_str_len = 0;
2876 int len;
2877 int done = 0;
2878 char *p, *p1, *res_str = NULL;
2879
2880 while ((p = strchr(inp, SPECIAL_VAR_SYMBOL))) {
2881 if (p != inp) {
2882 len = p - inp;
2883 res_str = xrealloc(res_str, (res_str_len + len));
2884 strncpy((res_str + res_str_len), inp, len);
2885 res_str_len += len;
2886 }
2887 inp = ++p;
2888 p = strchr(inp, SPECIAL_VAR_SYMBOL);
2889 *p = '\0';
2890 if ((p1 = lookup_param(inp))) {
2891 len = res_str_len + strlen(p1);
2892 res_str = xrealloc(res_str, (1 + len));
2893 strcpy((res_str + res_str_len), p1);
2894 res_str_len = len;
2895 }
2896 *p = SPECIAL_VAR_SYMBOL;
2897 inp = ++p;
2898 done = 1;
2899 }
2900 if (done) {
2901 res_str = xrealloc(res_str, (1 + res_str_len + strlen(inp)));
2902 strcpy((res_str + res_str_len), inp);
2903 while ((p = strchr(res_str, '\n'))) {
2904 *p = ' ';
2905 }
2906 }
2907 return (res_str == NULL) ? inp : res_str;
2908}
2909
2910static char **make_list_in(char **inp, char *name)
2911{
2912 int len, i;
2913 int name_len = strlen(name);
2914 int n = 0;
2915 char **list;
2916 char *p1, *p2, *p3;
2917
2918 /* create list of variable values */
2919 list = xmalloc(sizeof(*list));
2920 for (i = 0; inp[i]; i++) {
2921 p3 = insert_var_value(inp[i]);
2922 p1 = p3;
2923 while (*p1) {
2924 if ((*p1 == ' ')) {
2925 p1++;
2926 continue;
2927 }
2928 if ((p2 = strchr(p1, ' '))) {
2929 len = p2 - p1;
2930 } else {
2931 len = strlen(p1);
2932 p2 = p1 + len;
2933 }
2934 /* we use n + 2 in realloc for list,because we add
2935 * new element and then we will add NULL element */
2936 list = xrealloc(list, sizeof(*list) * (n + 2));
2937 list[n] = xmalloc(2 + name_len + len);
2938 strcpy(list[n], name);
2939 strcat(list[n], "=");
2940 strncat(list[n], p1, len);
2941 list[n++][name_len + len + 1] = '\0';
2942 p1 = p2;
2943 }
2944 if (p3 != inp[i]) free(p3);
2945 }
2946 list[n] = NULL;
2947 return list;
2948}
2949
2950/* Make new string for parser */
2951static char * make_string(char ** inp)
2952{
2953 char *p;
2954 char *str = NULL;
2955 int n;
2956 int len = 2;
2957
2958 for (n = 0; inp[n]; n++) {
2959 p = insert_var_value(inp[n]);
2960 str = xrealloc(str, (len + strlen(p)));
2961 if (n) {
2962 strcat(str, " ");
2963 } else {
2964 *str = '\0';
2965 }
2966 strcat(str, p);
2967 len = strlen(str) + 3;
2968 if (p != inp[n]) free(p);
2969 }
2970 len = strlen(str);
2971 *(str + len) = '\n';
2972 *(str + len + 1) = '\0';
2973 return str;
2974}