aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-26 12:23:05 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-26 12:23:05 +0100
commit63ad7993845fbf59264e22295ae9c06250832119 (patch)
tree8907aa8c1819109955edf4b449a5045fd1f6441e
parent94576d2b972b3bd136fbe8057c95690ae36ea8c9 (diff)
downloadbusybox-w32-63ad7993845fbf59264e22295ae9c06250832119.tar.gz
busybox-w32-63ad7993845fbf59264e22295ae9c06250832119.tar.bz2
busybox-w32-63ad7993845fbf59264e22295ae9c06250832119.zip
bc: fix handling of comment/string interactions while buffering input
function old new delta zbc_lex_next 1965 1982 +17 zbc_num_divmod 150 156 +6 bc_read_line 411 394 -17 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 23/-17) Total: 6 bytes Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r--miscutils/bc.c112
1 files changed, 74 insertions, 38 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 9d04ddea3..f4e499f13 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -1147,23 +1147,6 @@ static void bc_vec_string(BcVec *v, size_t len, const char *str)
1147 bc_vec_pushZeroByte(v); 1147 bc_vec_pushZeroByte(v);
1148} 1148}
1149 1149
1150#if ENABLE_FEATURE_BC_SIGNALS && ENABLE_FEATURE_EDITING
1151static void bc_vec_concat(BcVec *v, const char *str)
1152{
1153 size_t len, slen;
1154
1155 if (v->len == 0) bc_vec_pushZeroByte(v);
1156
1157 slen = strlen(str);
1158 len = v->len + slen;
1159
1160 if (v->cap < len) bc_vec_grow(v, slen);
1161 strcpy(v->v + v->len - 1, str);
1162
1163 v->len = len;
1164}
1165#endif
1166
1167static void *bc_vec_item(const BcVec *v, size_t idx) 1150static void *bc_vec_item(const BcVec *v, size_t idx)
1168{ 1151{
1169 return v->v + v->size * idx; 1152 return v->v + v->size * idx;
@@ -2491,6 +2474,21 @@ static FAST_FUNC void bc_result_free(void *result)
2491 } 2474 }
2492} 2475}
2493 2476
2477#if ENABLE_FEATURE_BC_SIGNALS && ENABLE_FEATURE_EDITING
2478static void bc_vec_concat(BcVec *v, const char *str)
2479{
2480 size_t len, slen;
2481
2482 slen = strlen(str);
2483 len = v->len + slen + 1;
2484
2485 if (v->cap < len) bc_vec_grow(v, slen);
2486 strcpy(v->v + v->len, str);
2487
2488 v->len = len;
2489}
2490#endif
2491
2494static int bad_input_byte(char c) 2492static int bad_input_byte(char c)
2495{ 2493{
2496 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'? 2494 if ((c < ' ' && c != '\t' && c != '\r' && c != '\n') // also allow '\v' '\f'?
@@ -2887,7 +2885,7 @@ static void bc_lex_file(void)
2887static bool bc_lex_more_input(void) 2885static bool bc_lex_more_input(void)
2888{ 2886{
2889 BcParse *p = &G.prs; 2887 BcParse *p = &G.prs;
2890 size_t str; 2888 unsigned str; // bool for bc, string nest count for dc
2891 bool comment; 2889 bool comment;
2892 2890
2893 bc_vec_pop_all(&G.input_buffer); 2891 bc_vec_pop_all(&G.input_buffer);
@@ -2896,8 +2894,23 @@ static bool bc_lex_more_input(void)
2896 // with a backslash to the parser. The reason for that is because the parser 2894 // with a backslash to the parser. The reason for that is because the parser
2897 // treats a backslash+newline combo as whitespace, per the bc spec. In that 2895 // treats a backslash+newline combo as whitespace, per the bc spec. In that
2898 // case, and for strings and comments, the parser will expect more stuff. 2896 // case, and for strings and comments, the parser will expect more stuff.
2899 comment = false; 2897 //
2898 // bc cases to test interactively:
2899 // 1 #comment\ - prints "1<newline>" at once (comment is not continued)
2900 // 1 #comment/* - prints "1<newline>" at once
2901 // 1 #comment" - prints "1<newline>" at once
2902 // 1\#comment - error at once (\ is not a line continuation)
2903 // 1 + /*"*/2 - prints "3<newline>" at once
2904 // 1 + /*#*/2 - prints "3<newline>" at once
2905 // "str\" - prints "str\" at once
2906 // "str#" - prints "str#" at once
2907 // "str/*" - prints "str/*" at once
2908 // "str#\ - waits for second line
2909 // end" - ...prints "str#\<newline>end"
2910//This is way too complex, we duplicate comment/string logic of lexer
2911//TODO: switch to char-by-char input like hush does it
2900 str = 0; 2912 str = 0;
2913 comment = false; // stays always false for dc
2901 for (;;) { 2914 for (;;) {
2902 size_t prevlen = G.input_buffer.len; 2915 size_t prevlen = G.input_buffer.len;
2903 char *string; 2916 char *string;
@@ -2909,39 +2922,61 @@ static bool bc_lex_more_input(void)
2909 2922
2910 string = G.input_buffer.v + prevlen; 2923 string = G.input_buffer.v + prevlen;
2911 while (*string) { 2924 while (*string) {
2912 char c = *string; 2925 char c = *string++;
2913 if (!comment) { 2926#if ENABLE_BC
2914 if (string == G.input_buffer.v || string[-1] != '\\') { 2927 if (comment) {
2915 if (IS_BC) 2928 // We are in /**/ comment, exit only on "*/"
2916 str ^= (c == '"'); 2929 if (c == '*' && *string == '/') {
2917 else { 2930 comment = false;
2918 if (c == ']') 2931 string++;
2919 str -= 1;
2920 else if (c == '[')
2921 str += 1;
2922 }
2923 } 2932 }
2933 continue;
2924 } 2934 }
2925 string++; 2935#endif
2926 if (!str) { 2936 // We are not in /**/ comment
2937 if (str) {
2938 // We are in "string" (bc) or [string] (dc)
2939 if (IS_BC) {
2940 // bc strings have no escapes: \\ is not special,
2941 // \n is not, \" is not, \<newline> is not.
2942 str = (c != '"'); // clear flag when " is seen
2943 } else {
2944 // dc strings have no escapes as well, can nest
2945 if (c == ']')
2946 str--;
2947 if (c == '[')
2948 str++;
2949 }
2950 continue;
2951 }
2952 // We are not in a string or /**/ comment
2953
2954 // Is it a #comment? Return the string (can't have continuation)
2955 if (c == '#')
2956 goto return_string;
2957#if ENABLE_BC
2958 if (IS_BC) {
2959 // bc: is it a start of /**/ comment or string?
2927 if (c == '/' && *string == '*') { 2960 if (c == '/' && *string == '*') {
2928 comment = true; 2961 comment = true;
2929 string++; 2962 string++;
2930 continue; 2963 continue;
2931 } 2964 }
2932 if (c == '*' && *string == '/') { 2965 str = (c == '"'); // set flag if " is seen
2933 comment = false; 2966 continue;
2934 string++;
2935 }
2936 } 2967 }
2937 } 2968#endif
2969 // dc: is it a start of string?
2970 str = (c == '[');
2971 } // end of "check all chars in string" loop
2972
2938 if (str != 0 || comment) { 2973 if (str != 0 || comment) {
2939 G.input_buffer.len--; // backstep over the trailing NUL byte 2974 G.input_buffer.len--; // backstep over the trailing NUL byte
2940 continue; 2975 continue;
2941 } 2976 }
2942 2977
2943 // Check for backslash+newline. 2978 // Check for backslash+newline.
2944 // we do not check that last char is '\n' - 2979 // We do not check that last char is '\n' -
2945 // if it is not, then it's EOF, and looping back 2980 // if it is not, then it's EOF, and looping back
2946 // to bc_read_line() will detect it: 2981 // to bc_read_line() will detect it:
2947 string -= 2; 2982 string -= 2;
@@ -2952,6 +2987,7 @@ static bool bc_lex_more_input(void)
2952 2987
2953 break; 2988 break;
2954 } 2989 }
2990 return_string:
2955 2991
2956 p->lex_inbuf = G.input_buffer.v; 2992 p->lex_inbuf = G.input_buffer.v;
2957// bb_error_msg("G.input_buffer.len:%d '%s'", G.input_buffer.len, G.input_buffer.v); 2993// bb_error_msg("G.input_buffer.len:%d '%s'", G.input_buffer.len, G.input_buffer.v);