aboutsummaryrefslogtreecommitdiff
path: root/shell/hush.c
diff options
context:
space:
mode:
Diffstat (limited to 'shell/hush.c')
-rw-r--r--shell/hush.c117
1 files changed, 115 insertions, 2 deletions
diff --git a/shell/hush.c b/shell/hush.c
index 1aa0a400d..27092c12f 100644
--- a/shell/hush.c
+++ b/shell/hush.c
@@ -384,6 +384,7 @@
384#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT 384#define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT
385#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT 385#define BASH_SUBSTR ENABLE_HUSH_BASH_COMPAT
386#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT 386#define BASH_SOURCE ENABLE_HUSH_BASH_COMPAT
387#define BASH_DOLLAR_SQUOTE ENABLE_HUSH_BASH_COMPAT
387#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT 388#define BASH_HOSTNAME_VAR ENABLE_HUSH_BASH_COMPAT
388#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT 389#define BASH_EPOCH_VARS ENABLE_HUSH_BASH_COMPAT
389#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) 390#define BASH_TEST2 (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST)
@@ -4919,6 +4920,101 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign
4919} 4920}
4920#endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */ 4921#endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */
4921 4922
4923#if BASH_DOLLAR_SQUOTE
4924/* Return code: 1 for "found and parsed", 0 for "seen something else" */
4925# if BB_MMU
4926#define parse_dollar_squote(as_string, dest, input) \
4927 parse_dollar_squote(dest, input)
4928#define as_string NULL
4929# endif
4930static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_str *input)
4931{
4932 int start;
4933 int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */
4934 debug_printf_parse("parse_dollar_squote entered: ch='%c'\n", ch);
4935 if (ch != '\'')
4936 return 0;
4937
4938 dest->has_quoted_part = 1;
4939 start = dest->length;
4940
4941 ch = i_getch(input); /* eat ' */
4942 nommu_addchr(as_string, ch);
4943 while (1) {
4944 ch = i_getch(input);
4945 nommu_addchr(as_string, ch);
4946 if (ch == EOF) {
4947 syntax_error_unterm_ch('\'');
4948 return 0;
4949 }
4950 if (ch == '\'')
4951 break;
4952 if (ch == SPECIAL_VAR_SYMBOL) {
4953 /* Convert raw ^C to corresponding special variable reference */
4954 o_addchr(dest, SPECIAL_VAR_SYMBOL);
4955 o_addchr(dest, SPECIAL_VAR_QUOTED_SVS);
4956 /* will addchr() another SPECIAL_VAR_SYMBOL (see after the if() block) */
4957 } else if (ch == '\\') {
4958 static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567";
4959
4960 ch = i_getch(input);
4961 nommu_addchr(as_string, ch);
4962 if (strchr(C_escapes, ch)) {
4963 char buf[4];
4964 char *p = buf;
4965 int cnt = 2;
4966
4967 buf[0] = ch;
4968 if ((unsigned char)(ch - '0') <= 7) { /* \ooo */
4969 do {
4970 ch = i_peek(input);
4971 if ((unsigned char)(ch - '0') > 7)
4972 break;
4973 *++p = ch = i_getch(input);
4974 nommu_addchr(as_string, ch);
4975 } while (--cnt != 0);
4976 } else if (ch == 'x') { /* \xHH */
4977 do {
4978 ch = i_peek(input);
4979 if (!isxdigit(ch))
4980 break;
4981 *++p = ch = i_getch(input);
4982 nommu_addchr(as_string, ch);
4983 } while (--cnt != 0);
4984 if (cnt == 2) { /* \x but next char is "bad" */
4985 ch = 'x';
4986 goto unrecognized;
4987 }
4988 } /* else simple seq like \\ or \t */
4989 *++p = '\0';
4990 p = buf;
4991 ch = bb_process_escape_sequence((void*)&p);
4992 //bb_error_msg("buf:'%s' ch:%x", buf, ch);
4993 if (ch == '\0')
4994 continue; /* bash compat: $'...\0...' emits nothing */
4995 } else { /* unrecognized "\z": encode both chars unless ' or " */
4996 if (ch != '\'' && ch != '"') {
4997 unrecognized:
4998 o_addqchr(dest, '\\');
4999 }
5000 }
5001 } /* if (\...) */
5002 o_addqchr(dest, ch);
5003 }
5004
5005 if (dest->length == start) {
5006 /* $'', $'\0', $'\000\x00' and the like */
5007 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5008 o_addchr(dest, SPECIAL_VAR_SYMBOL);
5009 }
5010
5011 return 1;
5012# undef as_string
5013}
5014#else
5015# define parse_dollar_squote(as_string, dest, input) 0
5016#endif /* BASH_DOLLAR_SQUOTE */
5017
4922/* Return code: 0 for OK, 1 for syntax error */ 5018/* Return code: 0 for OK, 1 for syntax error */
4923#if BB_MMU 5019#if BB_MMU
4924#define parse_dollar(as_string, dest, input, quote_mask) \ 5020#define parse_dollar(as_string, dest, input, quote_mask) \
@@ -4931,7 +5027,7 @@ static int parse_dollar(o_string *as_string,
4931{ 5027{
4932 int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */ 5028 int ch = i_peek_and_eat_bkslash_nl(input); /* first character after the $ */
4933 5029
4934 debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); 5030 debug_printf_parse("parse_dollar entered: ch='%c' quote_mask:0x%x\n", ch, quote_mask);
4935 if (isalpha(ch)) { 5031 if (isalpha(ch)) {
4936 make_var: 5032 make_var:
4937 ch = i_getch(input); 5033 ch = i_getch(input);
@@ -5247,6 +5343,8 @@ static int encode_string(o_string *as_string,
5247 goto again; 5343 goto again;
5248 } 5344 }
5249 if (ch == '$') { 5345 if (ch == '$') {
5346 //if (parse_dollar_squote(as_string, dest, input))
5347 // goto again;
5250 if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { 5348 if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) {
5251 debug_printf_parse("encode_string return 0: " 5349 debug_printf_parse("encode_string return 0: "
5252 "parse_dollar returned 0 (error)\n"); 5350 "parse_dollar returned 0 (error)\n");
@@ -5723,6 +5821,8 @@ static struct pipe *parse_stream(char **pstring,
5723 o_addchr(&ctx.word, ch); 5821 o_addchr(&ctx.word, ch);
5724 continue; /* get next char */ 5822 continue; /* get next char */
5725 case '$': 5823 case '$':
5824 if (parse_dollar_squote(&ctx.as_string, &ctx.word, input))
5825 continue; /* get next char */
5726 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { 5826 if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) {
5727 debug_printf_parse("parse_stream parse error: " 5827 debug_printf_parse("parse_stream parse error: "
5728 "parse_dollar returned 0 (error)\n"); 5828 "parse_dollar returned 0 (error)\n");
@@ -5850,7 +5950,6 @@ static struct pipe *parse_stream(char **pstring,
5850 if (ctx.ctx_res_w == RES_MATCH) 5950 if (ctx.ctx_res_w == RES_MATCH)
5851 goto case_semi; 5951 goto case_semi;
5852#endif 5952#endif
5853
5854 case '}': 5953 case '}':
5855 /* proper use of this character is caught by end_trigger: 5954 /* proper use of this character is caught by end_trigger:
5856 * if we see {, we call parse_group(..., end_trigger='}') 5955 * if we see {, we call parse_group(..., end_trigger='}')
@@ -6166,6 +6265,8 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int
6166 continue; 6265 continue;
6167 } 6266 }
6168 if (ch == '$') { 6267 if (ch == '$') {
6268 if (parse_dollar_squote(NULL, &dest, &input))
6269 continue;
6169 if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) { 6270 if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) {
6170 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__); 6271 debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__);
6171 goto ret; 6272 goto ret;
@@ -6365,6 +6466,18 @@ static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p)
6365/* ${var/[/]pattern[/repl]} helpers */ 6466/* ${var/[/]pattern[/repl]} helpers */
6366static char *strstr_pattern(char *val, const char *pattern, int *size) 6467static char *strstr_pattern(char *val, const char *pattern, int *size)
6367{ 6468{
6469 int sz = strcspn(pattern, "*?[\\");
6470 if (pattern[sz] == '\0') {
6471 /* Optimization for trivial patterns.
6472 * Testcase for very slow replace (performs about 22k replaces):
6473 * x=::::::::::::::::::::::
6474 * x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;x=$x$x;echo ${#x}
6475 * echo "${x//:/|}"
6476 */
6477 *size = sz;
6478 return strstr(val, pattern);
6479 }
6480
6368 while (1) { 6481 while (1) {
6369 char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF); 6482 char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF);
6370 debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end); 6483 debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end);