diff options
author | Eric Andersen <andersen@codepoet.org> | 2002-04-13 12:33:41 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2002-04-13 12:33:41 +0000 |
commit | 4c9b68f0e013b0b7554a3278e078177f955d39f4 (patch) | |
tree | e3caabb50e0a205221c61100ced2d0a545ff39ed | |
parent | a66a43e8ef1e55c2415aa7084365cce3fb8f931a (diff) | |
download | busybox-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.c | 347 |
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 | ||
120 | typedef enum { | 124 | typedef 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 | ||
206 | struct pipe { | 215 | struct pipe { |
@@ -319,6 +328,7 @@ static void __syntax(char *file, int line) { | |||
319 | /* function prototypes for builtins */ | 328 | /* function prototypes for builtins */ |
320 | static int builtin_cd(struct child_prog *child); | 329 | static int builtin_cd(struct child_prog *child); |
321 | static int builtin_env(struct child_prog *child); | 330 | static int builtin_env(struct child_prog *child); |
331 | static int builtin_eval(struct child_prog *child); | ||
322 | static int builtin_exec(struct child_prog *child); | 332 | static int builtin_exec(struct child_prog *child); |
323 | static int builtin_exit(struct child_prog *child); | 333 | static int builtin_exit(struct child_prog *child); |
324 | static int builtin_export(struct child_prog *child); | 334 | static int builtin_export(struct child_prog *child); |
@@ -376,19 +386,22 @@ static int redirect_dup_num(struct in_str *input); | |||
376 | static int redirect_opt_num(o_string *o); | 386 | static int redirect_opt_num(o_string *o); |
377 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); | 387 | static int process_command_subs(o_string *dest, struct p_context *ctx, struct in_str *input, int subst_end); |
378 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); | 388 | static int parse_group(o_string *dest, struct p_context *ctx, struct in_str *input, int ch); |
379 | static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src); | 389 | static char *lookup_param(char *src); |
390 | static char *make_string(char **inp); | ||
380 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); | 391 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input); |
381 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); | 392 | static int parse_string(o_string *dest, struct p_context *ctx, const char *src); |
382 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); | 393 | static int parse_stream(o_string *dest, struct p_context *ctx, struct in_str *input0, int end_trigger); |
383 | /* setup: */ | 394 | /* setup: */ |
384 | static int parse_stream_outer(struct in_str *inp); | 395 | static int parse_stream_outer(struct in_str *inp, int flag); |
385 | static int parse_string_outer(const char *s); | 396 | static int parse_string_outer(const char *s, int flag); |
386 | static int parse_file_outer(FILE *f); | 397 | static int parse_file_outer(FILE *f); |
387 | /* job management: */ | 398 | /* job management: */ |
388 | static int checkjobs(struct pipe* fg_pipe); | 399 | static int checkjobs(struct pipe* fg_pipe); |
389 | static void insert_bg_job(struct pipe *pi); | 400 | static void insert_bg_job(struct pipe *pi); |
390 | static void remove_bg_job(struct pipe *pi); | 401 | static void remove_bg_job(struct pipe *pi); |
391 | /* local variable support */ | 402 | /* local variable support */ |
403 | static char **make_list_in(char **inp, char *name); | ||
404 | static char *insert_var_value(char *inp); | ||
392 | static char *get_local_var(const char *var); | 405 | static char *get_local_var(const char *var); |
393 | static void unset_local_var(const char *name); | 406 | static void unset_local_var(const char *name); |
394 | static int set_local_var(const char *s, int flg_export); | 407 | static 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 */ | ||
453 | static 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 */ |
441 | static int builtin_cd(struct child_prog *child) | 469 | static int builtin_cd(struct child_prog *child) |
@@ -1046,11 +1074,14 @@ static void restore_redirects(int squirrel[]) | |||
1046 | static void pseudo_exec(struct child_prog *child) | 1074 | static 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 | ||
1475 | static int run_list_real(struct pipe *pi) | 1522 | static 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" */ |
2230 | static void lookup_param(o_string *dest, struct p_context *ctx, o_string *src) | 2376 | static 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 */ |
2243 | static int handle_dollar(o_string *dest, struct p_context *ctx, struct in_str *input) | 2388 | static 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() */ |
2512 | int parse_stream_outer(struct in_str *inp) | 2662 | int 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 | ||
2531 | static int parse_string_outer(const char *s) | 2697 | static 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 | ||
2538 | static int parse_file_outer(FILE *f) | 2704 | static 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) | |||
2703 | final_return: | 2869 | final_return: |
2704 | return(opt?opt:last_return_code); | 2870 | return(opt?opt:last_return_code); |
2705 | } | 2871 | } |
2872 | |||
2873 | static 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 | |||
2910 | static 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 */ | ||
2951 | static 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 | } | ||