diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-26 12:23:05 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-26 12:23:05 +0100 |
commit | 63ad7993845fbf59264e22295ae9c06250832119 (patch) | |
tree | 8907aa8c1819109955edf4b449a5045fd1f6441e | |
parent | 94576d2b972b3bd136fbe8057c95690ae36ea8c9 (diff) | |
download | busybox-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.c | 112 |
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 | ||
1151 | static 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 | |||
1167 | static void *bc_vec_item(const BcVec *v, size_t idx) | 1150 | static 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 | ||
2478 | static 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 | |||
2494 | static int bad_input_byte(char c) | 2492 | static 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) | |||
2887 | static bool bc_lex_more_input(void) | 2885 | static 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); |