diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2020-10-31 03:34:07 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2020-10-31 03:34:07 +0100 |
commit | d2241f59022c38d4b171e56eea42e216ecccfdd9 (patch) | |
tree | edb75c2530f493c9e3f193f346d8125fe79c107f | |
parent | 112453acf24520b4655f9f36da41d8ac591b1a60 (diff) | |
download | busybox-w32-d2241f59022c38d4b171e56eea42e216ecccfdd9.tar.gz busybox-w32-d2241f59022c38d4b171e56eea42e216ecccfdd9.tar.bz2 busybox-w32-d2241f59022c38d4b171e56eea42e216ecccfdd9.zip |
shell: better support of [[ ]] bashism
Still rather rudimentary for ash
function old new delta
binop 433 589 +156
check_operator 65 101 +36
done_word 736 769 +33
test_main 405 418 +13
parse_stream 2227 2238 +11
ops_texts 124 133 +9
ops_table 80 86 +6
run_pipe 1557 1562 +5
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 8/0 up/down: 269/0) Total: 269 bytes
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | coreutils/test.c | 82 | ||||
-rw-r--r-- | shell/ash.c | 15 | ||||
-rw-r--r-- | shell/hush.c | 57 | ||||
-rw-r--r-- | shell/hush_test/hush-test2/andor1.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-test2/andor1.tests | 7 | ||||
-rw-r--r-- | shell/hush_test/hush-test2/noglob1.right | 2 | ||||
-rwxr-xr-x | shell/hush_test/hush-test2/noglob1.tests | 3 | ||||
-rw-r--r-- | shell/hush_test/hush-test2/strops1.right | 8 | ||||
-rwxr-xr-x | shell/hush_test/hush-test2/strops1.tests | 15 | ||||
-rw-r--r-- | shell/hush_test/hush-test2/strops2.right | 6 | ||||
-rwxr-xr-x | shell/hush_test/hush-test2/strops2.tests | 12 | ||||
-rw-r--r-- | shell/hush_test/hush-test2/strops3.right | 7 | ||||
-rwxr-xr-x | shell/hush_test/hush-test2/strops3.tests | 13 |
13 files changed, 209 insertions, 24 deletions
diff --git a/coreutils/test.c b/coreutils/test.c index a08986130..ac7b546a3 100644 --- a/coreutils/test.c +++ b/coreutils/test.c | |||
@@ -76,6 +76,8 @@ | |||
76 | //usage: "1\n" | 76 | //usage: "1\n" |
77 | 77 | ||
78 | #include "libbb.h" | 78 | #include "libbb.h" |
79 | #include <regex.h> | ||
80 | #include <fnmatch.h> | ||
79 | 81 | ||
80 | /* This is a NOFORK applet. Be very careful! */ | 82 | /* This is a NOFORK applet. Be very careful! */ |
81 | 83 | ||
@@ -146,6 +148,14 @@ | |||
146 | 148 | ||
147 | #define TEST_DEBUG 0 | 149 | #define TEST_DEBUG 0 |
148 | 150 | ||
151 | #if ENABLE_TEST2 \ | ||
152 | || (ENABLE_ASH_BASH_COMPAT && ENABLE_ASH_TEST) \ | ||
153 | || (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) | ||
154 | # define BASH_TEST2 1 | ||
155 | #else | ||
156 | # define BASH_TEST2 0 | ||
157 | #endif | ||
158 | |||
149 | enum token { | 159 | enum token { |
150 | EOI, | 160 | EOI, |
151 | 161 | ||
@@ -184,6 +194,10 @@ enum token { | |||
184 | STRLT, | 194 | STRLT, |
185 | STRGT, | 195 | STRGT, |
186 | 196 | ||
197 | #if BASH_TEST2 | ||
198 | REGEX, | ||
199 | #endif | ||
200 | |||
187 | INTEQ, /* int ops */ | 201 | INTEQ, /* int ops */ |
188 | INTNE, | 202 | INTNE, |
189 | INTGE, | 203 | INTGE, |
@@ -257,6 +271,9 @@ static const char *const TOKSTR[] = { | |||
257 | "STRNE", | 271 | "STRNE", |
258 | "STRLT", | 272 | "STRLT", |
259 | "STRGT", | 273 | "STRGT", |
274 | #if BASH_TEST2 | ||
275 | "REGEX", | ||
276 | #endif | ||
260 | "INTEQ", | 277 | "INTEQ", |
261 | "INTNE", | 278 | "INTNE", |
262 | "INTGE", | 279 | "INTGE", |
@@ -320,6 +337,9 @@ static const struct operator_t ops_table[] = { | |||
320 | { /* "!=" */ STRNE , BINOP }, | 337 | { /* "!=" */ STRNE , BINOP }, |
321 | { /* "<" */ STRLT , BINOP }, | 338 | { /* "<" */ STRLT , BINOP }, |
322 | { /* ">" */ STRGT , BINOP }, | 339 | { /* ">" */ STRGT , BINOP }, |
340 | #if BASH_TEST2 | ||
341 | { /* "=~" */ REGEX , BINOP }, | ||
342 | #endif | ||
323 | { /* "-eq"*/ INTEQ , BINOP }, | 343 | { /* "-eq"*/ INTEQ , BINOP }, |
324 | { /* "-ne"*/ INTNE , BINOP }, | 344 | { /* "-ne"*/ INTNE , BINOP }, |
325 | { /* "-ge"*/ INTGE , BINOP }, | 345 | { /* "-ge"*/ INTGE , BINOP }, |
@@ -332,6 +352,10 @@ static const struct operator_t ops_table[] = { | |||
332 | { /* "!" */ UNOT , BUNOP }, | 352 | { /* "!" */ UNOT , BUNOP }, |
333 | { /* "-a" */ BAND , BBINOP }, | 353 | { /* "-a" */ BAND , BBINOP }, |
334 | { /* "-o" */ BOR , BBINOP }, | 354 | { /* "-o" */ BOR , BBINOP }, |
355 | #if BASH_TEST2 | ||
356 | { /* "&&" */ BAND , BBINOP }, | ||
357 | { /* "||" */ BOR , BBINOP }, | ||
358 | #endif | ||
335 | { /* "(" */ LPAREN , PAREN }, | 359 | { /* "(" */ LPAREN , PAREN }, |
336 | { /* ")" */ RPAREN , PAREN }, | 360 | { /* ")" */ RPAREN , PAREN }, |
337 | }; | 361 | }; |
@@ -365,6 +389,9 @@ static const char ops_texts[] ALIGN1 = | |||
365 | "!=" "\0" | 389 | "!=" "\0" |
366 | "<" "\0" | 390 | "<" "\0" |
367 | ">" "\0" | 391 | ">" "\0" |
392 | #if BASH_TEST2 | ||
393 | "=~" "\0" | ||
394 | #endif | ||
368 | "-eq" "\0" | 395 | "-eq" "\0" |
369 | "-ne" "\0" | 396 | "-ne" "\0" |
370 | "-ge" "\0" | 397 | "-ge" "\0" |
@@ -377,6 +404,10 @@ static const char ops_texts[] ALIGN1 = | |||
377 | "!" "\0" | 404 | "!" "\0" |
378 | "-a" "\0" | 405 | "-a" "\0" |
379 | "-o" "\0" | 406 | "-o" "\0" |
407 | #if BASH_TEST2 | ||
408 | "&&" "\0" | ||
409 | "||" "\0" | ||
410 | #endif | ||
380 | "(" "\0" | 411 | "(" "\0" |
381 | ")" "\0" | 412 | ")" "\0" |
382 | ; | 413 | ; |
@@ -397,6 +428,9 @@ struct test_statics { | |||
397 | const struct operator_t *last_operator; | 428 | const struct operator_t *last_operator; |
398 | gid_t *group_array; | 429 | gid_t *group_array; |
399 | int ngroups; | 430 | int ngroups; |
431 | #if BASH_TEST2 | ||
432 | bool bash_test2; | ||
433 | #endif | ||
400 | jmp_buf leaving; | 434 | jmp_buf leaving; |
401 | }; | 435 | }; |
402 | 436 | ||
@@ -408,6 +442,7 @@ extern struct test_statics *const test_ptr_to_statics; | |||
408 | #define last_operator (S.last_operator) | 442 | #define last_operator (S.last_operator) |
409 | #define group_array (S.group_array ) | 443 | #define group_array (S.group_array ) |
410 | #define ngroups (S.ngroups ) | 444 | #define ngroups (S.ngroups ) |
445 | #define bash_test2 (S.bash_test2 ) | ||
411 | #define leaving (S.leaving ) | 446 | #define leaving (S.leaving ) |
412 | 447 | ||
413 | #define INIT_S() do { \ | 448 | #define INIT_S() do { \ |
@@ -501,6 +536,20 @@ static enum token check_operator(const char *s) | |||
501 | n = index_in_strings(ops_texts, s); | 536 | n = index_in_strings(ops_texts, s); |
502 | if (n < 0) | 537 | if (n < 0) |
503 | return OPERAND; | 538 | return OPERAND; |
539 | |||
540 | #if BASH_TEST2 | ||
541 | if (ops_table[n].op_num == REGEX && !bash_test2) { | ||
542 | /* =~ is only for [[ ]] */ | ||
543 | return OPERAND; | ||
544 | } | ||
545 | if (ops_table[n].op_num == BAND || ops_table[n].op_num == BOR) { | ||
546 | /* [ ] accepts -a and -o but not && and || */ | ||
547 | /* [[ ]] accepts && and || but not -a and -o */ | ||
548 | if (bash_test2 == (s[0] == '-')) | ||
549 | return OPERAND; | ||
550 | } | ||
551 | #endif | ||
552 | |||
504 | last_operator = &ops_table[n]; | 553 | last_operator = &ops_table[n]; |
505 | return ops_table[n].op_num; | 554 | return ops_table[n].op_num; |
506 | } | 555 | } |
@@ -536,6 +585,29 @@ static int binop(void) | |||
536 | /*if (op->op_num == INTLT)*/ | 585 | /*if (op->op_num == INTLT)*/ |
537 | return val1 < val2; | 586 | return val1 < val2; |
538 | } | 587 | } |
588 | #if BASH_TEST2 | ||
589 | if (bash_test2) { | ||
590 | if (op->op_num == STREQ) { | ||
591 | val1 = fnmatch(opnd2, opnd1, 0); | ||
592 | return val1 == 0; | ||
593 | } | ||
594 | if (op->op_num == STRNE) { | ||
595 | val1 = fnmatch(opnd2, opnd1, 0); | ||
596 | return val1 != 0; | ||
597 | } | ||
598 | if (op->op_num == REGEX) { | ||
599 | regex_t re_buffer; | ||
600 | memset(&re_buffer, 0, sizeof(re_buffer)); | ||
601 | if (regcomp(&re_buffer, opnd2, REG_EXTENDED)) { // REG_NEWLINE? | ||
602 | /* Bad regex */ | ||
603 | longjmp(leaving, 2); /* [[ a =~ * ]]; echo $? - prints 2 (silently, no error msg) */ | ||
604 | } | ||
605 | val1 = regexec(&re_buffer, opnd1, 0, NULL, 0); | ||
606 | regfree(&re_buffer); | ||
607 | return val1 == 0; | ||
608 | } | ||
609 | } | ||
610 | #endif | ||
539 | if (is_str_op(op->op_num)) { | 611 | if (is_str_op(op->op_num)) { |
540 | val1 = strcmp(opnd1, opnd2); | 612 | val1 = strcmp(opnd1, opnd2); |
541 | if (op->op_num == STREQ) | 613 | if (op->op_num == STREQ) |
@@ -824,6 +896,9 @@ int test_main(int argc, char **argv) | |||
824 | { | 896 | { |
825 | int res; | 897 | int res; |
826 | const char *arg0; | 898 | const char *arg0; |
899 | #if BASH_TEST2 | ||
900 | bool bt2 = 0; | ||
901 | #endif | ||
827 | 902 | ||
828 | arg0 = bb_basename(argv[0]); | 903 | arg0 = bb_basename(argv[0]); |
829 | if ((ENABLE_TEST1 || ENABLE_TEST2 || ENABLE_ASH_TEST || ENABLE_HUSH_TEST) | 904 | if ((ENABLE_TEST1 || ENABLE_TEST2 || ENABLE_ASH_TEST || ENABLE_HUSH_TEST) |
@@ -840,6 +915,9 @@ int test_main(int argc, char **argv) | |||
840 | bb_simple_error_msg("missing ]]"); | 915 | bb_simple_error_msg("missing ]]"); |
841 | return 2; | 916 | return 2; |
842 | } | 917 | } |
918 | #if BASH_TEST2 | ||
919 | bt2 = 1; | ||
920 | #endif | ||
843 | } | 921 | } |
844 | argv[argc] = NULL; | 922 | argv[argc] = NULL; |
845 | } | 923 | } |
@@ -848,6 +926,10 @@ int test_main(int argc, char **argv) | |||
848 | /* We must do DEINIT_S() prior to returning */ | 926 | /* We must do DEINIT_S() prior to returning */ |
849 | INIT_S(); | 927 | INIT_S(); |
850 | 928 | ||
929 | #if BASH_TEST2 | ||
930 | bash_test2 = bt2; | ||
931 | #endif | ||
932 | |||
851 | res = setjmp(leaving); | 933 | res = setjmp(leaving); |
852 | if (res) | 934 | if (res) |
853 | goto ret; | 935 | goto ret; |
diff --git a/shell/ash.c b/shell/ash.c index 58da0a2a0..cfcc0b818 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -207,17 +207,17 @@ | |||
207 | #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT | 207 | #define IF_BASH_SUBSTR IF_ASH_BASH_COMPAT |
208 | /* BASH_TEST2: [[ EXPR ]] | 208 | /* BASH_TEST2: [[ EXPR ]] |
209 | * Status of [[ support: | 209 | * Status of [[ support: |
210 | * We replace && and || with -a and -o | 210 | * && and || work as they should |
211 | * = is glob match operator, not equality operator: STR = GLOB | ||
212 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
213 | * == same as = | ||
214 | * add =~ regex match operator: STR =~ REGEX | ||
211 | * TODO: | 215 | * TODO: |
212 | * singleword+noglob expansion: | 216 | * singleword+noglob expansion: |
213 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? | 217 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? |
214 | * [[ /bin/n* ]]; echo 0:$? | 218 | * [[ /bin/n* ]]; echo 0:$? |
215 | * -a/-o are not AND/OR ops! (they are just strings) | ||
216 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) | 219 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) |
217 | * = is glob match operator, not equality operator: STR = GLOB | 220 | * ( ) < > should not have special meaning |
218 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
219 | * == same as = | ||
220 | * add =~ regex match operator: STR =~ REGEX | ||
221 | */ | 221 | */ |
222 | #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) | 222 | #define BASH_TEST2 (ENABLE_ASH_BASH_COMPAT * ENABLE_ASH_TEST) |
223 | #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT | 223 | #define BASH_SOURCE ENABLE_ASH_BASH_COMPAT |
@@ -11823,7 +11823,8 @@ simplecmd(void) | |||
11823 | tokpushback = 1; | 11823 | tokpushback = 1; |
11824 | goto out; | 11824 | goto out; |
11825 | } | 11825 | } |
11826 | wordtext = (char *) (t == TAND ? "-a" : "-o"); | 11826 | /* pass "&&" or "||" to [[ ]] as literal args */ |
11827 | wordtext = (char *) (t == TAND ? "&&" : "||"); | ||
11827 | #endif | 11828 | #endif |
11828 | case TWORD: | 11829 | case TWORD: |
11829 | n = stzalloc(sizeof(struct narg)); | 11830 | n = stzalloc(sizeof(struct narg)); |
diff --git a/shell/hush.c b/shell/hush.c index bc6e6014f..7c1e1d748 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -84,13 +84,12 @@ | |||
84 | * [[ args ]] are CMD_SINGLEWORD_NOGLOB: | 84 | * [[ args ]] are CMD_SINGLEWORD_NOGLOB: |
85 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? | 85 | * v='a b'; [[ $v = 'a b' ]]; echo 0:$? |
86 | * [[ /bin/n* ]]; echo 0:$? | 86 | * [[ /bin/n* ]]; echo 0:$? |
87 | * = is glob match operator, not equality operator: STR = GLOB | ||
88 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
89 | * == same as = | ||
90 | * =~ is regex match operator: STR =~ REGEX | ||
87 | * TODO: | 91 | * TODO: |
88 | * &&/|| are AND/OR ops, -a/-o are not | ||
89 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) | 92 | * quoting needs to be considered (-f is an operator, "-f" and ""-f are not; etc) |
90 | * = is glob match operator, not equality operator: STR = GLOB | ||
91 | * (in GLOB, quoting is significant on char-by-char basis: a*cd"*") | ||
92 | * == same as = | ||
93 | * add =~ regex match operator: STR =~ REGEX | ||
94 | */ | 93 | */ |
95 | //config:config HUSH | 94 | //config:config HUSH |
96 | //config: bool "hush (68 kb)" | 95 | //config: bool "hush (68 kb)" |
@@ -651,14 +650,16 @@ struct command { | |||
651 | smallint cmd_type; /* CMD_xxx */ | 650 | smallint cmd_type; /* CMD_xxx */ |
652 | #define CMD_NORMAL 0 | 651 | #define CMD_NORMAL 0 |
653 | #define CMD_SUBSHELL 1 | 652 | #define CMD_SUBSHELL 1 |
654 | #if BASH_TEST2 || ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY | 653 | #if BASH_TEST2 |
655 | /* used for "[[ EXPR ]]", and to prevent word splitting and globbing in | 654 | /* used for "[[ EXPR ]]" */ |
656 | * "export v=t*" | 655 | # define CMD_TEST2_SINGLEWORD_NOGLOB 2 |
657 | */ | 656 | #endif |
658 | # define CMD_SINGLEWORD_NOGLOB 2 | 657 | #if ENABLE_HUSH_LOCAL || ENABLE_HUSH_EXPORT || ENABLE_HUSH_READONLY |
658 | /* used to prevent word splitting and globbing in "export v=t*" */ | ||
659 | # define CMD_SINGLEWORD_NOGLOB 3 | ||
659 | #endif | 660 | #endif |
660 | #if ENABLE_HUSH_FUNCTIONS | 661 | #if ENABLE_HUSH_FUNCTIONS |
661 | # define CMD_FUNCDEF 3 | 662 | # define CMD_FUNCDEF 4 |
662 | #endif | 663 | #endif |
663 | 664 | ||
664 | smalluint cmd_exitcode; | 665 | smalluint cmd_exitcode; |
@@ -4112,6 +4113,14 @@ static int done_word(struct parse_context *ctx) | |||
4112 | ctx->ctx_dsemicolon = 0; | 4113 | ctx->ctx_dsemicolon = 0; |
4113 | } else | 4114 | } else |
4114 | # endif | 4115 | # endif |
4116 | # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
4117 | if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB | ||
4118 | && strcmp(ctx->word.data, "]]") == 0 | ||
4119 | ) { | ||
4120 | /* allow "[[ ]] >file" etc */ | ||
4121 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | ||
4122 | } else | ||
4123 | # endif | ||
4115 | if (!command->argv /* if it's the first word... */ | 4124 | if (!command->argv /* if it's the first word... */ |
4116 | # if ENABLE_HUSH_LOOPS | 4125 | # if ENABLE_HUSH_LOOPS |
4117 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ | 4126 | && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ |
@@ -4146,11 +4155,13 @@ static int done_word(struct parse_context *ctx) | |||
4146 | (ctx->ctx_res_w == RES_SNTX)); | 4155 | (ctx->ctx_res_w == RES_SNTX)); |
4147 | return (ctx->ctx_res_w == RES_SNTX); | 4156 | return (ctx->ctx_res_w == RES_SNTX); |
4148 | } | 4157 | } |
4158 | # if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
4159 | if (strcmp(ctx->word.data, "[[") == 0) { | ||
4160 | command->cmd_type = CMD_TEST2_SINGLEWORD_NOGLOB; | ||
4161 | } else | ||
4162 | # endif | ||
4149 | # if defined(CMD_SINGLEWORD_NOGLOB) | 4163 | # if defined(CMD_SINGLEWORD_NOGLOB) |
4150 | if (0 | 4164 | if (0 |
4151 | # if BASH_TEST2 | ||
4152 | || strcmp(ctx->word.data, "[[") == 0 | ||
4153 | # endif | ||
4154 | /* In bash, local/export/readonly are special, args | 4165 | /* In bash, local/export/readonly are special, args |
4155 | * are assignments and therefore expansion of them | 4166 | * are assignments and therefore expansion of them |
4156 | * should be "one-word" expansion: | 4167 | * should be "one-word" expansion: |
@@ -4172,7 +4183,8 @@ static int done_word(struct parse_context *ctx) | |||
4172 | ) { | 4183 | ) { |
4173 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; | 4184 | command->cmd_type = CMD_SINGLEWORD_NOGLOB; |
4174 | } | 4185 | } |
4175 | /* fall through */ | 4186 | # else |
4187 | { /* empty block to pair "if ... else" */ } | ||
4176 | # endif | 4188 | # endif |
4177 | } | 4189 | } |
4178 | #endif /* HAS_KEYWORDS */ | 4190 | #endif /* HAS_KEYWORDS */ |
@@ -5354,9 +5366,15 @@ static struct pipe *parse_stream(char **pstring, | |||
5354 | if (ch != '\n') | 5366 | if (ch != '\n') |
5355 | next = i_peek_and_eat_bkslash_nl(input); | 5367 | next = i_peek_and_eat_bkslash_nl(input); |
5356 | 5368 | ||
5357 | is_special = "{}<>;&|()#" /* special outside of "str" */ | 5369 | is_special = "{}<>&|();#" /* special outside of "str" */ |
5358 | "$\"" IF_HUSH_TICK("`") /* always special */ | 5370 | "$\"" IF_HUSH_TICK("`") /* always special */ |
5359 | SPECIAL_VAR_SYMBOL_STR; | 5371 | SPECIAL_VAR_SYMBOL_STR; |
5372 | #if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
5373 | if (ctx.command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) { | ||
5374 | /* In [[ ]], {}<>&|() are not special */ | ||
5375 | is_special += 8; | ||
5376 | } else | ||
5377 | #endif | ||
5360 | /* Are { and } special here? */ | 5378 | /* Are { and } special here? */ |
5361 | if (ctx.command->argv /* word [word]{... - non-special */ | 5379 | if (ctx.command->argv /* word [word]{... - non-special */ |
5362 | || ctx.word.length /* word{... - non-special */ | 5380 | || ctx.word.length /* word{... - non-special */ |
@@ -6953,7 +6971,7 @@ static char **expand_strvec_to_strvec(char **argv) | |||
6953 | return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); | 6971 | return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); |
6954 | } | 6972 | } |
6955 | 6973 | ||
6956 | #if defined(CMD_SINGLEWORD_NOGLOB) | 6974 | #if defined(CMD_SINGLEWORD_NOGLOB) || defined(CMD_TEST2_SINGLEWORD_NOGLOB) |
6957 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) | 6975 | static char **expand_strvec_to_strvec_singleword_noglob(char **argv) |
6958 | { | 6976 | { |
6959 | return expand_variables(argv, EXP_FLAG_SINGLEWORD); | 6977 | return expand_variables(argv, EXP_FLAG_SINGLEWORD); |
@@ -9133,6 +9151,11 @@ static NOINLINE int run_pipe(struct pipe *pi) | |||
9133 | } | 9151 | } |
9134 | 9152 | ||
9135 | /* Expand the rest into (possibly) many strings each */ | 9153 | /* Expand the rest into (possibly) many strings each */ |
9154 | #if defined(CMD_TEST2_SINGLEWORD_NOGLOB) | ||
9155 | if (command->cmd_type == CMD_TEST2_SINGLEWORD_NOGLOB) | ||
9156 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | ||
9157 | else | ||
9158 | #endif | ||
9136 | #if defined(CMD_SINGLEWORD_NOGLOB) | 9159 | #if defined(CMD_SINGLEWORD_NOGLOB) |
9137 | if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) | 9160 | if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) |
9138 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); | 9161 | argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); |
diff --git a/shell/hush_test/hush-test2/andor1.right b/shell/hush_test/hush-test2/andor1.right new file mode 100644 index 000000000..038c7a681 --- /dev/null +++ b/shell/hush_test/hush-test2/andor1.right | |||
@@ -0,0 +1,6 @@ | |||
1 | 1:YES | ||
2 | 2:no | ||
3 | 3:YES | ||
4 | 4:YES | ||
5 | 5:no | ||
6 | 6:no | ||
diff --git a/shell/hush_test/hush-test2/andor1.tests b/shell/hush_test/hush-test2/andor1.tests new file mode 100755 index 000000000..c449de7e6 --- /dev/null +++ b/shell/hush_test/hush-test2/andor1.tests | |||
@@ -0,0 +1,7 @@ | |||
1 | e='' | ||
2 | [[ a && b ]] && echo 1:YES | ||
3 | [[ a && '' ]] || echo 2:no | ||
4 | [[ a || b ]] && echo 3:YES | ||
5 | [[ '' || b ]] && echo 4:YES | ||
6 | [[ "" || "$e" ]] || echo 5:no | ||
7 | [[ "" || $e ]] || echo 6:no | ||
diff --git a/shell/hush_test/hush-test2/noglob1.right b/shell/hush_test/hush-test2/noglob1.right new file mode 100644 index 000000000..d0c3f1d8e --- /dev/null +++ b/shell/hush_test/hush-test2/noglob1.right | |||
@@ -0,0 +1,2 @@ | |||
1 | 1:YES:0 | ||
2 | 2:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/noglob1.tests b/shell/hush_test/hush-test2/noglob1.tests new file mode 100755 index 000000000..963bacbd3 --- /dev/null +++ b/shell/hush_test/hush-test2/noglob1.tests | |||
@@ -0,0 +1,3 @@ | |||
1 | v='*.tests' | ||
2 | [[ *.tests ]]; echo 1:YES:$? | ||
3 | [[ $v ]]; echo 2:YES:$? | ||
diff --git a/shell/hush_test/hush-test2/strops1.right b/shell/hush_test/hush-test2/strops1.right new file mode 100644 index 000000000..590496301 --- /dev/null +++ b/shell/hush_test/hush-test2/strops1.right | |||
@@ -0,0 +1,8 @@ | |||
1 | 1:YES:0 | ||
2 | 2:YES:0 | ||
3 | 3:YES:0 | ||
4 | 4:YES:0 | ||
5 | 5:YES:0 | ||
6 | 6:YES:0 | ||
7 | 7:YES:0 | ||
8 | 8:no:1 | ||
diff --git a/shell/hush_test/hush-test2/strops1.tests b/shell/hush_test/hush-test2/strops1.tests new file mode 100755 index 000000000..bb24e2a2f --- /dev/null +++ b/shell/hush_test/hush-test2/strops1.tests | |||
@@ -0,0 +1,15 @@ | |||
1 | v='*.z' | ||
2 | [[ a.z = *.z ]]; echo 1:YES:$? | ||
3 | [[ a.z == $v ]]; echo 2:YES:$? | ||
4 | |||
5 | # wildcards can match a slash | ||
6 | [[ a/b = a*b ]]; echo 3:YES:$? | ||
7 | [[ a/b == a?b ]]; echo 4:YES:$? | ||
8 | |||
9 | # wildcards can match a leading dot | ||
10 | [[ a/.b = a/*b ]]; echo 5:YES:$? | ||
11 | [[ a/.b == a/?b ]]; echo 6:YES:$? | ||
12 | |||
13 | # wildcards can be escaped | ||
14 | [[ abc = a*c ]]; echo 7:YES:$? | ||
15 | [[ abc == a\*c ]]; echo 8:no:$? | ||
diff --git a/shell/hush_test/hush-test2/strops2.right b/shell/hush_test/hush-test2/strops2.right new file mode 100644 index 000000000..8ddb4b0f0 --- /dev/null +++ b/shell/hush_test/hush-test2/strops2.right | |||
@@ -0,0 +1,6 @@ | |||
1 | 1:ERR2:2 | ||
2 | 2:YES:0 | ||
3 | 3:YES:0 | ||
4 | 4:YES:0 | ||
5 | 5:no:1 | ||
6 | 6:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/strops2.tests b/shell/hush_test/hush-test2/strops2.tests new file mode 100755 index 000000000..ab325bc9f --- /dev/null +++ b/shell/hush_test/hush-test2/strops2.tests | |||
@@ -0,0 +1,12 @@ | |||
1 | # malformed regex | ||
2 | [[ a =~ * ]]; echo 1:ERR2:$? | ||
3 | |||
4 | [[ a/b =~ a.b ]]; echo 2:YES:$? | ||
5 | [[ a/b =~ /*b ]]; echo 3:YES:$? | ||
6 | |||
7 | v='[]b.-]' | ||
8 | [[ a/.b] =~ $v ]]; echo 4:YES:$? | ||
9 | |||
10 | v=']b.-' | ||
11 | [[ a/.b] =~ $v ]]; echo 5:no:$? | ||
12 | [[ a/.b] =~ [$v] ]]; echo 6:YES:$? | ||
diff --git a/shell/hush_test/hush-test2/strops3.right b/shell/hush_test/hush-test2/strops3.right new file mode 100644 index 000000000..14cc04fdc --- /dev/null +++ b/shell/hush_test/hush-test2/strops3.right | |||
@@ -0,0 +1,7 @@ | |||
1 | 1:YES:0 | ||
2 | 2:YES:0 | ||
3 | 3:no:1 | ||
4 | 4:YES:0 | ||
5 | 2u:YES:0 | ||
6 | 3u:YES:0 | ||
7 | 4u:YES:0 | ||
diff --git a/shell/hush_test/hush-test2/strops3.tests b/shell/hush_test/hush-test2/strops3.tests new file mode 100755 index 000000000..927476671 --- /dev/null +++ b/shell/hush_test/hush-test2/strops3.tests | |||
@@ -0,0 +1,13 @@ | |||
1 | # regex should accept '+' operator | ||
2 | [[ abcdef =~ a[b-z]+ ]]; echo 1:YES:$? | ||
3 | |||
4 | # newline matches by "match any" patterns | ||
5 | v=' | ||
6 | ' | ||
7 | [[ "$v" =~ . ]]; echo 2:YES:$? | ||
8 | [[ "$v" =~ "[$v]" ]]; echo 3:no:$? # hmm bash does return 1... why? | ||
9 | [[ "$v" =~ [^a] ]]; echo 4:YES:$? | ||
10 | # should work even without quotes: | ||
11 | [[ $v =~ . ]]; echo 2u:YES:$? | ||
12 | [[ $v =~ [$v] ]]; echo 3u:YES:$? | ||
13 | [[ $v =~ [^a] ]]; echo 4u:YES:$? | ||