hush: implement $'str' bashism
function old new delta parse_dollar_squote - 441 +441 encode_then_expand_vararg 359 380 +21 parse_stream 2252 2271 +19 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 2/0 up/down: 481/0) Total: 481 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
		
							
								
								
									
										103
									
								
								shell/hush.c
									
									
									
									
									
								
							
							
						
						
									
										103
									
								
								shell/hush.c
									
									
									
									
									
								
							| @@ -384,6 +384,7 @@ | ||||
| #define BASH_PATTERN_SUBST ENABLE_HUSH_BASH_COMPAT | ||||
| #define BASH_SUBSTR        ENABLE_HUSH_BASH_COMPAT | ||||
| #define BASH_SOURCE        ENABLE_HUSH_BASH_COMPAT | ||||
| #define BASH_DOLLAR_SQUOTE ENABLE_HUSH_BASH_COMPAT | ||||
| #define BASH_HOSTNAME_VAR  ENABLE_HUSH_BASH_COMPAT | ||||
| #define BASH_EPOCH_VARS    ENABLE_HUSH_BASH_COMPAT | ||||
| #define BASH_TEST2         (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) | ||||
| @@ -4919,6 +4920,100 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign | ||||
| } | ||||
| #endif /* ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS */ | ||||
|  | ||||
| #if BASH_DOLLAR_SQUOTE | ||||
| /* Return code: 1 for "found and parsed", 0 for "seen something else" */ | ||||
| #if BB_MMU | ||||
| #define parse_dollar_squote(as_string, dest, input) \ | ||||
| 	parse_dollar_squote(dest, input) | ||||
| #define as_string NULL | ||||
| #endif | ||||
| static int parse_dollar_squote(o_string *as_string, o_string *dest, struct in_str *input) | ||||
| { | ||||
| 	int start; | ||||
| 	int ch = i_peek_and_eat_bkslash_nl(input);  /* first character after the $ */ | ||||
| 	debug_printf_parse("parse_dollar_squote entered: ch='%c'\n", ch); | ||||
| 	if (ch != '\'') | ||||
| 		return 0; | ||||
|  | ||||
| 	dest->has_quoted_part = 1; | ||||
| 	start = dest->length; | ||||
|  | ||||
| 	ch = i_getch(input); /* eat ' */ | ||||
| 	nommu_addchr(as_string, ch); | ||||
| 	while (1) { | ||||
| 		ch = i_getch(input); | ||||
| 		nommu_addchr(as_string, ch); | ||||
| 		if (ch == EOF) { | ||||
| 			syntax_error_unterm_ch('\''); | ||||
| 			return 0; | ||||
| 		} | ||||
| 		if (ch == '\'') | ||||
| 			break; | ||||
| 		if (ch == SPECIAL_VAR_SYMBOL) { | ||||
| 			/* Convert raw ^C to corresponding special variable reference */ | ||||
| 			o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||||
| 			o_addchr(dest, SPECIAL_VAR_QUOTED_SVS); | ||||
| 			/* will addchr() another SPECIAL_VAR_SYMBOL (see after the if() block) */ | ||||
| 		} else if (ch == '\\') { | ||||
| 			static const char C_escapes[] ALIGN1 = "nrbtfav""x\\01234567"; | ||||
|  | ||||
| 			ch = i_getch(input); | ||||
| 			nommu_addchr(as_string, ch); | ||||
| 			if (strchr(C_escapes, ch)) { | ||||
| 				char buf[4]; | ||||
| 				char *p = buf; | ||||
| 				int cnt = 2; | ||||
|  | ||||
| 				buf[0] = ch; | ||||
| 				if ((unsigned char)(ch - '0') <= 7) { /* \ooo */ | ||||
| 					do { | ||||
| 						ch = i_peek(input); | ||||
| 						if ((unsigned char)(ch - '0') > 7) | ||||
| 							break; | ||||
| 						*++p = ch = i_getch(input); | ||||
| 						nommu_addchr(as_string, ch); | ||||
| 					} while (--cnt != 0); | ||||
| 				} else if (ch == 'x') { /* \xHH */ | ||||
| 					do { | ||||
| 						ch = i_peek(input); | ||||
| 						if (!isxdigit(ch)) | ||||
| 							break; | ||||
| 						*++p = ch = i_getch(input); | ||||
| 						nommu_addchr(as_string, ch); | ||||
| 					} while (--cnt != 0); | ||||
| 					if (cnt == 2) { /* \x but next char is "bad" */ | ||||
| 						ch = 'x'; | ||||
| 						goto unrecognized; | ||||
| 					} | ||||
| 				} /* else simple seq like \\ or \t */ | ||||
| 				*++p = '\0'; | ||||
| 				p = buf; | ||||
| 				ch = bb_process_escape_sequence((void*)&p); | ||||
| 				//bb_error_msg("buf:'%s' ch:%x", buf, ch); | ||||
| 				if (ch == '\0') | ||||
| 					continue; /* bash compat: $'...\0...' emits nothing */ | ||||
| 			} else { /* unrecognized "\z": encode both chars unless ' or " */ | ||||
| 				if (ch != '\'' && ch != '"') { | ||||
|  unrecognized: | ||||
| 					o_addqchr(dest, '\\'); | ||||
| 				} | ||||
| 			} | ||||
| 		} /* if (\...) */ | ||||
| 		o_addqchr(dest, ch); | ||||
| 	} | ||||
|  | ||||
| 	if (dest->length == start) { | ||||
| 		/* $'', $'\0', $'\000\x00' and the like */ | ||||
| 		o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||||
| 		o_addchr(dest, SPECIAL_VAR_SYMBOL); | ||||
| 	} | ||||
|  | ||||
| 	return 1; | ||||
| } | ||||
| #else | ||||
| # #define parse_dollar_squote(as_string, dest, input) 0 | ||||
| #endif /* BASH_DOLLAR_SQUOTE */ | ||||
|  | ||||
| /* Return code: 0 for OK, 1 for syntax error */ | ||||
| #if BB_MMU | ||||
| #define parse_dollar(as_string, dest, input, quote_mask) \ | ||||
| @@ -4931,7 +5026,7 @@ static int parse_dollar(o_string *as_string, | ||||
| { | ||||
| 	int ch = i_peek_and_eat_bkslash_nl(input);  /* first character after the $ */ | ||||
|  | ||||
| 	debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); | ||||
| 	debug_printf_parse("parse_dollar entered: ch='%c' quote_mask:0x%x\n", ch, quote_mask); | ||||
| 	if (isalpha(ch)) { | ||||
|  make_var: | ||||
| 		ch = i_getch(input); | ||||
| @@ -5247,6 +5342,8 @@ static int encode_string(o_string *as_string, | ||||
| 		goto again; | ||||
| 	} | ||||
| 	if (ch == '$') { | ||||
| 		//if (parse_dollar_squote(as_string, dest, input)) | ||||
| 		//	goto again; | ||||
| 		if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { | ||||
| 			debug_printf_parse("encode_string return 0: " | ||||
| 					"parse_dollar returned 0 (error)\n"); | ||||
| @@ -5723,6 +5820,8 @@ static struct pipe *parse_stream(char **pstring, | ||||
| 			o_addchr(&ctx.word, ch); | ||||
| 			continue; /* get next char */ | ||||
| 		case '$': | ||||
| 			if (parse_dollar_squote(&ctx.as_string, &ctx.word, input)) | ||||
| 				continue; /* get next char */ | ||||
| 			if (!parse_dollar(&ctx.as_string, &ctx.word, input, /*quote_mask:*/ 0)) { | ||||
| 				debug_printf_parse("parse_stream parse error: " | ||||
| 					"parse_dollar returned 0 (error)\n"); | ||||
| @@ -6166,6 +6265,8 @@ static char *encode_then_expand_vararg(const char *str, int handle_squotes, int | ||||
| 			continue; | ||||
| 		} | ||||
| 		if (ch == '$') { | ||||
| 			if (parse_dollar_squote(NULL, &dest, &input)) | ||||
| 				continue; | ||||
| 			if (!parse_dollar(NULL, &dest, &input, /*quote_mask:*/ 0x80)) { | ||||
| 				debug_printf_parse("%s: error: parse_dollar returned 0 (error)\n", __func__); | ||||
| 				goto ret; | ||||
|   | ||||
							
								
								
									
										10
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash1.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash1.right
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| a	b | ||||
| $'a\tb' | ||||
| a | ||||
| b c | ||||
| def | ||||
| a'b c"d e\f | ||||
| a3b c3b e33f | ||||
| a\80b c08b | ||||
| a3b c30b | ||||
| x	y | ||||
							
								
								
									
										8
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash1.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										8
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash1.tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| echo $'a\tb' | ||||
| echo "$'a\tb'" | ||||
| echo $'a\nb' $'c\nd''ef' | ||||
| echo $'a\'b' $'c\"d' $'e\\f' | ||||
| echo $'a\63b' $'c\063b' $'e\0633f' | ||||
| echo $'a\80b' $'c\608b' | ||||
| echo $'a\x33b' $'c\x330b' | ||||
| echo $'x\x9y' | ||||
							
								
								
									
										6
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash2.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash2.right
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||||
| strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||||
| 80:\<5C> | ||||
| 81:\<5C> | ||||
| 82:\<5C> | ||||
| Done:0 | ||||
							
								
								
									
										10
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash2.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								shell/hush_test/hush-quoting/dollar_squote_bash2.tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| # Embedded NULs | ||||
| echo $'str\x00'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||||
| echo $'str\000'strstrstrstrstrstrstrstrstrstrstrstrstrstrstrstr | ||||
|  | ||||
| # The chars after '\' are hex 0x80,81,82... | ||||
| echo 80:$'\<5C>' | ||||
| echo 81:$'\<5C>' | ||||
| echo 82:$'\<5C>' | ||||
|  | ||||
| echo Done:$? | ||||
							
								
								
									
										1
									
								
								shell/hush_test/hush-vars/var_bash7.right
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								shell/hush_test/hush-vars/var_bash7.right
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| B | ||||
							
								
								
									
										1
									
								
								shell/hush_test/hush-vars/var_bash7.tests
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								shell/hush_test/hush-vars/var_bash7.tests
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | ||||
| x=AB; echo "${x#$'\x41'}" | ||||
		Reference in New Issue
	
	Block a user