aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2009-04-10 13:49:10 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2009-04-10 13:49:10 +0000
commit0b677d833718ab6c46bd4790c662c67fba4f377a (patch)
treed4a9cc818a546476c0617f93f5efc13a6a7d2a15
parent1fd1ea4395e520694bd9f8b1dc9e60af6442946d (diff)
downloadbusybox-w32-0b677d833718ab6c46bd4790c662c67fba4f377a.tar.gz
busybox-w32-0b677d833718ab6c46bd4790c662c67fba4f377a.tar.bz2
busybox-w32-0b677d833718ab6c46bd4790c662c67fba4f377a.zip
hush: fix some TODOs. TODO in export builting: +250 bytes.
simplify unexpected EOF handling. function old new delta builtin_export 117 374 +257 o_reset_to_empty_unquoted - 21 +21 parse_stream 1926 1929 +3 syntax_error_unterm_ch 31 32 +1 handle_dollar 644 641 -3 parse_stream_dquoted 307 298 -9 add_till_backquote 106 97 -9 add_till_closing_paren 303 286 -17 o_reset 21 - -21 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 3/4 up/down: 282/-59) Total: 223 bytes
-rw-r--r--shell/hush.c127
-rw-r--r--shell/hush_test/hush-misc/export.right6
-rwxr-xr-xshell/hush_test/hush-misc/export.tests7
3 files changed, 89 insertions, 51 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 422fc63f6..e3dfa0673 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -701,12 +701,19 @@ static void syntax_error_at(unsigned lineno, const char *msg)
701 die_if_script(lineno, "syntax error at '%s'", msg); 701 die_if_script(lineno, "syntax error at '%s'", msg);
702} 702}
703 703
704/* It so happens that all such cases are totally fatal
705 * even if shell is interactive: EOF while looking for closing
706 * delimiter. There is nowhere to read stuff from after that,
707 * it's EOF! The only choice is to terminate.
708 */
709static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN;
704static void syntax_error_unterm_ch(unsigned lineno, char ch) 710static void syntax_error_unterm_ch(unsigned lineno, char ch)
705{ 711{
706 char msg[2]; 712 char msg[2];
707 msg[0] = ch; 713 msg[0] = ch;
708 msg[1] = '\0'; 714 msg[1] = '\0';
709 die_if_script(lineno, "syntax error: unterminated %s", msg); 715 die_if_script(lineno, "syntax error: unterminated %s", msg);
716 xfunc_die();
710} 717}
711 718
712static void syntax_error_unterm_str(unsigned lineno, const char *s) 719static void syntax_error_unterm_str(unsigned lineno, const char *s)
@@ -1433,7 +1440,7 @@ static void setup_string_in_str(struct in_str *i, const char *s)
1433 */ 1440 */
1434#define B_CHUNK (32 * sizeof(char*)) 1441#define B_CHUNK (32 * sizeof(char*))
1435 1442
1436static void o_reset(o_string *o) 1443static void o_reset_to_empty_unquoted(o_string *o)
1437{ 1444{
1438 o->length = 0; 1445 o->length = 0;
1439 o->o_quoted = 0; 1446 o->o_quoted = 0;
@@ -4043,7 +4050,7 @@ static int done_word(o_string *word, struct parse_context *ctx)
4043 ) { 4050 ) {
4044 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data); 4051 debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
4045 if (reserved_word(word, ctx)) { 4052 if (reserved_word(word, ctx)) {
4046 o_reset(word); 4053 o_reset_to_empty_unquoted(word);
4047 debug_printf_parse("done_word return %d\n", 4054 debug_printf_parse("done_word return %d\n",
4048 (ctx->ctx_res_w == RES_SNTX)); 4055 (ctx->ctx_res_w == RES_SNTX));
4049 return (ctx->ctx_res_w == RES_SNTX); 4056 return (ctx->ctx_res_w == RES_SNTX);
@@ -4099,7 +4106,7 @@ static int done_word(o_string *word, struct parse_context *ctx)
4099 } 4106 }
4100#endif 4107#endif
4101 4108
4102 o_reset(word); 4109 o_reset_to_empty_unquoted(word);
4103 4110
4104 debug_printf_parse("done_word return 0\n"); 4111 debug_printf_parse("done_word return 0\n");
4105 return 0; 4112 return 0;
@@ -4249,7 +4256,7 @@ static int redirect_opt_num(o_string *o)
4249 num = bb_strtou(o->data, NULL, 10); 4256 num = bb_strtou(o->data, NULL, 10);
4250 if (errno || num < 0) 4257 if (errno || num < 0)
4251 return -1; 4258 return -1;
4252 o_reset(o); 4259 o_reset_to_empty_unquoted(o);
4253 return num; 4260 return num;
4254} 4261}
4255 4262
@@ -4458,7 +4465,6 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4458 bb_error_msg("aha '%s' is a function, parsing it...", dest->data); 4465 bb_error_msg("aha '%s' is a function, parsing it...", dest->data);
4459 //command->fname = dest->data; 4466 //command->fname = dest->data;
4460 command->grp_type = GRP_FUNCTION; 4467 command->grp_type = GRP_FUNCTION;
4461//TODO: review every o_reset() location... do they handle all o_string fields correctly?
4462 memset(dest, 0, sizeof(*dest)); 4468 memset(dest, 0, sizeof(*dest));
4463 } 4469 }
4464#endif 4470#endif
@@ -4510,40 +4516,39 @@ static int parse_group(o_string *dest, struct parse_context *ctx,
4510 4516
4511#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT 4517#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT
4512/* Subroutines for copying $(...) and `...` things */ 4518/* Subroutines for copying $(...) and `...` things */
4513static int add_till_backquote(o_string *dest, struct in_str *input); 4519static void add_till_backquote(o_string *dest, struct in_str *input);
4514/* '...' */ 4520/* '...' */
4515static int add_till_single_quote(o_string *dest, struct in_str *input) 4521static void add_till_single_quote(o_string *dest, struct in_str *input)
4516{ 4522{
4517 while (1) { 4523 while (1) {
4518 int ch = i_getch(input); 4524 int ch = i_getch(input);
4519 if (ch == EOF) { 4525 if (ch == EOF) {
4520 syntax_error_unterm_ch('\''); 4526 syntax_error_unterm_ch('\'');
4521 return 1; 4527 /*xfunc_die(); - redundant */
4522 } 4528 }
4523 if (ch == '\'') 4529 if (ch == '\'')
4524 return 0; 4530 return;
4525 o_addchr(dest, ch); 4531 o_addchr(dest, ch);
4526 } 4532 }
4527} 4533}
4528/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ 4534/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */
4529static int add_till_double_quote(o_string *dest, struct in_str *input) 4535static void add_till_double_quote(o_string *dest, struct in_str *input)
4530{ 4536{
4531 while (1) { 4537 while (1) {
4532 int ch = i_getch(input); 4538 int ch = i_getch(input);
4533 if (ch == EOF) { 4539 if (ch == EOF) {
4534 syntax_error_unterm_ch('"'); 4540 syntax_error_unterm_ch('"');
4535 return 1; 4541 /*xfunc_die(); - redundant */
4536 } 4542 }
4537 if (ch == '"') 4543 if (ch == '"')
4538 return 0; 4544 return;
4539 if (ch == '\\') { /* \x. Copy both chars. */ 4545 if (ch == '\\') { /* \x. Copy both chars. */
4540 o_addchr(dest, ch); 4546 o_addchr(dest, ch);
4541 ch = i_getch(input); 4547 ch = i_getch(input);
4542 } 4548 }
4543 o_addchr(dest, ch); 4549 o_addchr(dest, ch);
4544 if (ch == '`') { 4550 if (ch == '`') {
4545 if (add_till_backquote(dest, input)) 4551 add_till_backquote(dest, input);
4546 return 1;
4547 o_addchr(dest, ch); 4552 o_addchr(dest, ch);
4548 continue; 4553 continue;
4549 } 4554 }
@@ -4564,22 +4569,22 @@ static int add_till_double_quote(o_string *dest, struct in_str *input)
4564 * Example Output 4569 * Example Output
4565 * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST 4570 * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST
4566 */ 4571 */
4567static int add_till_backquote(o_string *dest, struct in_str *input) 4572static void add_till_backquote(o_string *dest, struct in_str *input)
4568{ 4573{
4569 while (1) { 4574 while (1) {
4570 int ch = i_getch(input); 4575 int ch = i_getch(input);
4571 if (ch == EOF) { 4576 if (ch == EOF) {
4572 syntax_error_unterm_ch('`'); 4577 syntax_error_unterm_ch('`');
4573 return 1; 4578 /*xfunc_die(); - redundant */
4574 } 4579 }
4575 if (ch == '`') 4580 if (ch == '`')
4576 return 0; 4581 return;
4577 if (ch == '\\') { 4582 if (ch == '\\') {
4578 /* \x. Copy both chars unless it is \` */ 4583 /* \x. Copy both chars unless it is \` */
4579 int ch2 = i_getch(input); 4584 int ch2 = i_getch(input);
4580 if (ch2 == EOF) { 4585 if (ch2 == EOF) {
4581 syntax_error_unterm_ch('`'); 4586 syntax_error_unterm_ch('`');
4582 return 1; 4587 /*xfunc_die(); - redundant */
4583 } 4588 }
4584 if (ch2 != '`' && ch2 != '$' && ch2 != '\\') 4589 if (ch2 != '`' && ch2 != '$' && ch2 != '\\')
4585 o_addchr(dest, ch); 4590 o_addchr(dest, ch);
@@ -4600,14 +4605,14 @@ static int add_till_backquote(o_string *dest, struct in_str *input)
4600 * echo $(echo 'TEST)' BEST) TEST) BEST 4605 * echo $(echo 'TEST)' BEST) TEST) BEST
4601 * echo $(echo \(\(TEST\) BEST) ((TEST) BEST 4606 * echo $(echo \(\(TEST\) BEST) ((TEST) BEST
4602 */ 4607 */
4603static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl) 4608static void add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl)
4604{ 4609{
4605 int count = 0; 4610 int count = 0;
4606 while (1) { 4611 while (1) {
4607 int ch = i_getch(input); 4612 int ch = i_getch(input);
4608 if (ch == EOF) { 4613 if (ch == EOF) {
4609 syntax_error_unterm_ch(')'); 4614 syntax_error_unterm_ch(')');
4610 return 1; 4615 /*xfunc_die(); - redundant */
4611 } 4616 }
4612 if (ch == '(') 4617 if (ch == '(')
4613 count++; 4618 count++;
@@ -4623,14 +4628,12 @@ static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl
4623 } 4628 }
4624 o_addchr(dest, ch); 4629 o_addchr(dest, ch);
4625 if (ch == '\'') { 4630 if (ch == '\'') {
4626 if (add_till_single_quote(dest, input)) 4631 add_till_single_quote(dest, input);
4627 return 1;
4628 o_addchr(dest, ch); 4632 o_addchr(dest, ch);
4629 continue; 4633 continue;
4630 } 4634 }
4631 if (ch == '"') { 4635 if (ch == '"') {
4632 if (add_till_double_quote(dest, input)) 4636 add_till_double_quote(dest, input);
4633 return 1;
4634 o_addchr(dest, ch); 4637 o_addchr(dest, ch);
4635 continue; 4638 continue;
4636 } 4639 }
@@ -4639,13 +4642,12 @@ static int add_till_closing_paren(o_string *dest, struct in_str *input, bool dbl
4639 ch = i_getch(input); 4642 ch = i_getch(input);
4640 if (ch == EOF) { 4643 if (ch == EOF) {
4641 syntax_error_unterm_ch(')'); 4644 syntax_error_unterm_ch(')');
4642 return 1; 4645 /*xfunc_die(); - redundant */
4643 } 4646 }
4644 o_addchr(dest, ch); 4647 o_addchr(dest, ch);
4645 continue; 4648 continue;
4646 } 4649 }
4647 } 4650 }
4648 return 0;
4649} 4651}
4650#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ 4652#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */
4651 4653
@@ -4786,8 +4788,7 @@ static int handle_dollar(o_string *as_string,
4786# if !BB_MMU 4788# if !BB_MMU
4787 pos = dest->length; 4789 pos = dest->length;
4788# endif 4790# endif
4789 if (add_till_closing_paren(dest, input, true)) 4791 add_till_closing_paren(dest, input, true);
4790 return 1;
4791# if !BB_MMU 4792# if !BB_MMU
4792 if (as_string) { 4793 if (as_string) {
4793 o_addstr(as_string, dest->data + pos); 4794 o_addstr(as_string, dest->data + pos);
@@ -4805,8 +4806,7 @@ static int handle_dollar(o_string *as_string,
4805# if !BB_MMU 4806# if !BB_MMU
4806 pos = dest->length; 4807 pos = dest->length;
4807# endif 4808# endif
4808 if (add_till_closing_paren(dest, input, false)) 4809 add_till_closing_paren(dest, input, false);
4809 return 1;
4810# if !BB_MMU 4810# if !BB_MMU
4811 if (as_string) { 4811 if (as_string) {
4812 o_addstr(as_string, dest->data + pos); 4812 o_addstr(as_string, dest->data + pos);
@@ -4862,8 +4862,7 @@ static int parse_stream_dquoted(o_string *as_string,
4862 /* note: can't move it above ch == dquote_end check! */ 4862 /* note: can't move it above ch == dquote_end check! */
4863 if (ch == EOF) { 4863 if (ch == EOF) {
4864 syntax_error_unterm_ch('"'); 4864 syntax_error_unterm_ch('"');
4865 debug_printf_parse("parse_stream_dquoted return 1: unterminated \"\n"); 4865 /*xfunc_die(); - redundant */
4866 return 1;
4867 } 4866 }
4868 next = '\0'; 4867 next = '\0';
4869 if (ch != '\n') { 4868 if (ch != '\n') {
@@ -4872,11 +4871,9 @@ static int parse_stream_dquoted(o_string *as_string,
4872 debug_printf_parse(": ch=%c (%d) escape=%d\n", 4871 debug_printf_parse(": ch=%c (%d) escape=%d\n",
4873 ch, ch, dest->o_escape); 4872 ch, ch, dest->o_escape);
4874 if (ch == '\\') { 4873 if (ch == '\\') {
4875//TODO: check interactive behavior
4876 if (next == EOF) { 4874 if (next == EOF) {
4877 syntax_error("\\<eof>"); 4875 syntax_error("\\<eof>");
4878 debug_printf_parse("parse_stream_dquoted return 1: \\<eof>\n"); 4876 xfunc_die();
4879 return 1;
4880 } 4877 }
4881 /* bash: 4878 /* bash:
4882 * "The backslash retains its special meaning [in "..."] 4879 * "The backslash retains its special meaning [in "..."]
@@ -4904,8 +4901,7 @@ static int parse_stream_dquoted(o_string *as_string,
4904 //int pos = dest->length; 4901 //int pos = dest->length;
4905 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4902 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4906 o_addchr(dest, 0x80 | '`'); 4903 o_addchr(dest, 0x80 | '`');
4907 if (add_till_backquote(dest, input)) 4904 add_till_backquote(dest, input);
4908 return 1;
4909 o_addchr(dest, SPECIAL_VAR_SYMBOL); 4905 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4910 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); 4906 //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos);
4911 goto again; 4907 goto again;
@@ -4982,16 +4978,17 @@ static struct pipe *parse_stream(char **pstring,
4982 4978
4983 if (heredoc_cnt) { 4979 if (heredoc_cnt) {
4984 syntax_error_unterm_str("here document"); 4980 syntax_error_unterm_str("here document");
4985 goto parse_error; 4981 xfunc_die();
4986 } 4982 }
4987 if (done_word(&dest, &ctx)) { 4983 if (done_word(&dest, &ctx)) {
4988 goto parse_error; 4984 xfunc_die();
4989 } 4985 }
4990 o_free(&dest); 4986 o_free(&dest);
4991 done_pipe(&ctx, PIPE_SEQ); 4987 done_pipe(&ctx, PIPE_SEQ);
4992 pi = ctx.list_head; 4988 pi = ctx.list_head;
4993 /* If we got nothing... */ 4989 /* If we got nothing... */
4994// TODO: test script consisting of just "&" 4990 /* (this makes bare "&" cmd a no-op.
4991 * bash says: "syntax error near unexpected token '&'") */
4995 if (pi->num_cmds == 0 4992 if (pi->num_cmds == 0
4996 IF_HAS_KEYWORDS( && pi->res_word == RES_NONE) 4993 IF_HAS_KEYWORDS( && pi->res_word == RES_NONE)
4997 ) { 4994 ) {
@@ -5182,7 +5179,7 @@ static struct pipe *parse_stream(char **pstring,
5182 case '\\': 5179 case '\\':
5183 if (next == EOF) { 5180 if (next == EOF) {
5184 syntax_error("\\<eof>"); 5181 syntax_error("\\<eof>");
5185 goto parse_error; 5182 xfunc_die();
5186 } 5183 }
5187 o_addchr(&dest, '\\'); 5184 o_addchr(&dest, '\\');
5188 ch = i_getch(input); 5185 ch = i_getch(input);
@@ -5205,7 +5202,7 @@ static struct pipe *parse_stream(char **pstring,
5205 ch = i_getch(input); 5202 ch = i_getch(input);
5206 if (ch == EOF) { 5203 if (ch == EOF) {
5207 syntax_error_unterm_ch('\''); 5204 syntax_error_unterm_ch('\'');
5208 goto parse_error; 5205 /*xfunc_die(); - redundant */
5209 } 5206 }
5210 nommu_addchr(&ctx.as_string, ch); 5207 nommu_addchr(&ctx.as_string, ch);
5211 if (ch == '\'') 5208 if (ch == '\'')
@@ -5232,8 +5229,7 @@ static struct pipe *parse_stream(char **pstring,
5232#if !BB_MMU 5229#if !BB_MMU
5233 pos = dest.length; 5230 pos = dest.length;
5234#endif 5231#endif
5235 if (add_till_backquote(&dest, input)) 5232 add_till_backquote(&dest, input);
5236 goto parse_error;
5237#if !BB_MMU 5233#if !BB_MMU
5238 o_addstr(&ctx.as_string, dest.data + pos); 5234 o_addstr(&ctx.as_string, dest.data + pos);
5239 o_addchr(&ctx.as_string, '`'); 5235 o_addchr(&ctx.as_string, '`');
@@ -5976,7 +5972,8 @@ static int builtin_cd(char **argv)
5976 const char *newdir = argv[1]; 5972 const char *newdir = argv[1];
5977 if (newdir == NULL) { 5973 if (newdir == NULL) {
5978 /* bash does nothing (exitcode 0) if HOME is ""; if it's unset, 5974 /* bash does nothing (exitcode 0) if HOME is ""; if it's unset,
5979 * bash says "bash: cd: HOME not set" and does nothing (exitcode 1) 5975 * bash says "bash: cd: HOME not set" and does nothing
5976 * (exitcode 1)
5980 */ 5977 */
5981 newdir = getenv("HOME") ? : "/"; 5978 newdir = getenv("HOME") ? : "/";
5982 } 5979 }
@@ -6024,14 +6021,42 @@ static int builtin_exit(char **argv)
6024static int builtin_export(char **argv) 6021static int builtin_export(char **argv)
6025{ 6022{
6026 if (*++argv == NULL) { 6023 if (*++argv == NULL) {
6027 // TODO:
6028 // ash emits: export VAR='VAL'
6029 // bash: declare -x VAR="VAL"
6030 // (both also escape as needed (quotes, $, etc))
6031 char **e = environ; 6024 char **e = environ;
6032 if (e) 6025 if (e) {
6033 while (*e) 6026 while (*e) {
6027#if 0
6034 puts(*e++); 6028 puts(*e++);
6029#else
6030 /* ash emits: export VAR='VAL'
6031 * bash: declare -x VAR="VAL"
6032 * we follow ash example */
6033 const char *s = *e++;
6034 const char *p = strchr(s, '=');
6035
6036 if (!p) /* wtf? take next variable */
6037 continue;
6038 /* export var= */
6039 printf("export %.*s", (int)(p - s) + 1, s);
6040 s = p + 1;
6041 while (*s) {
6042 if (*s != '\'') {
6043 p = strchrnul(s, '\'');
6044 /* print 'xxxx' */
6045 printf("'%.*s'", (int)(p - s), s);
6046 if (*p == '\0')
6047 break;
6048 s = p;
6049 }
6050 /* s points to '; print ''...'''" */
6051 putchar('"');
6052 do putchar('\''); while (*++s == '\'');
6053 putchar('"');
6054 }
6055 putchar('\n');
6056#endif
6057 }
6058 fflush(stdout);
6059 }
6035 return EXIT_SUCCESS; 6060 return EXIT_SUCCESS;
6036 } 6061 }
6037 6062
diff --git a/shell/hush_test/hush-misc/export.right b/shell/hush_test/hush-misc/export.right
new file mode 100644
index 000000000..4df2e3858
--- /dev/null
+++ b/shell/hush_test/hush-misc/export.right
@@ -0,0 +1,6 @@
1export aaa1="'''"
2export aaa2=
3export aaa3="'''"'abc'
4export aaa4='def'"'''"
5export aaa5="'''"'abc'"'''"'def'"'''"
6Done
diff --git a/shell/hush_test/hush-misc/export.tests b/shell/hush_test/hush-misc/export.tests
new file mode 100755
index 000000000..87a27ecce
--- /dev/null
+++ b/shell/hush_test/hush-misc/export.tests
@@ -0,0 +1,7 @@
1export aaa1="'''"
2export aaa2=""
3export aaa3="'''abc"
4export aaa4="def'''"
5export aaa5="'''abc'''def'''"
6export | grep aaa.=
7echo Done