diff options
-rw-r--r-- | miscutils/bc.c | 64 |
1 files changed, 36 insertions, 28 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c index 6ab3a4252..5a4c92a1c 100644 --- a/miscutils/bc.c +++ b/miscutils/bc.c | |||
@@ -2976,29 +2976,40 @@ static void bc_lex_whitespace(BcLex *l) | |||
2976 | static BC_STATUS zbc_lex_number(BcLex *l, char start) | 2976 | static BC_STATUS zbc_lex_number(BcLex *l, char start) |
2977 | { | 2977 | { |
2978 | const char *buf = l->buf + l->i; | 2978 | const char *buf = l->buf + l->i; |
2979 | size_t len, hits = 0, bslashes = 0, i = 0, j; | 2979 | size_t len, bslashes, i, ccnt; |
2980 | char c = buf[i]; | 2980 | bool pt; |
2981 | bool last_pt, pt = start == '.'; | ||
2982 | 2981 | ||
2983 | last_pt = pt; | 2982 | pt = (start == '.'); |
2984 | l->t.t = BC_LEX_NUMBER; | 2983 | l->t.t = BC_LEX_NUMBER; |
2985 | 2984 | bslashes = 0; | |
2986 | while (c != 0 && (isdigit(c) || (c >= 'A' && c <= 'F') || | 2985 | ccnt = i = 0; |
2987 | (c == '.' && !pt) || (c == '\\' && buf[i + 1] == '\n'))) | 2986 | for (;;) { |
2988 | { | 2987 | char c = buf[i]; |
2989 | if (c != '\\') { | 2988 | if (c == '\0') |
2990 | last_pt = c == '.'; | 2989 | break; |
2991 | pt = pt || last_pt; | 2990 | if (c == '\\' && buf[i + 1] == '\n') { |
2991 | i += 2; | ||
2992 | bslashes++; | ||
2993 | continue; | ||
2992 | } | 2994 | } |
2993 | else { | 2995 | if (!isdigit(c) && (c < 'A' || c > 'F')) { |
2994 | ++i; | 2996 | if (c != '.') break; |
2995 | bslashes += 1; | 2997 | // if '.' was already seen, stop on second one: |
2998 | if (pt) break; | ||
2999 | pt = 1; | ||
2996 | } | 3000 | } |
2997 | 3001 | // buf[i] is one of "0-9A-F." | |
2998 | c = buf[++i]; | 3002 | i++; |
3003 | if (c != '.') | ||
3004 | ccnt = i; | ||
2999 | } | 3005 | } |
3006 | //i is buf[i] index of the first not-yet-parsed char | ||
3007 | l->i += i; | ||
3008 | |||
3009 | //ccnt is the number of chars in the number string, excluding possible | ||
3010 | //trailing "." and possible following trailing "\<newline>"(s). | ||
3011 | len = ccnt - bslashes * 2 + 1; // +1 byte for NUL termination | ||
3000 | 3012 | ||
3001 | len = i + !last_pt - bslashes * 2; | ||
3002 | // This check makes sense only if size_t is (much) larger than BC_MAX_NUM. | 3013 | // This check makes sense only if size_t is (much) larger than BC_MAX_NUM. |
3003 | if (SIZE_MAX > (BC_MAX_NUM | 0xff)) { | 3014 | if (SIZE_MAX > (BC_MAX_NUM | 0xff)) { |
3004 | if (len > BC_MAX_NUM) | 3015 | if (len > BC_MAX_NUM) |
@@ -3006,26 +3017,23 @@ static BC_STATUS zbc_lex_number(BcLex *l, char start) | |||
3006 | } | 3017 | } |
3007 | 3018 | ||
3008 | bc_vec_pop_all(&l->t.v); | 3019 | bc_vec_pop_all(&l->t.v); |
3009 | bc_vec_expand(&l->t.v, len + 1); | 3020 | bc_vec_expand(&l->t.v, 1 + len); |
3010 | bc_vec_push(&l->t.v, &start); | 3021 | bc_vec_push(&l->t.v, &start); |
3011 | 3022 | ||
3012 | for (buf -= 1, j = 1; j < len + hits * 2; ++j) { | 3023 | while (ccnt != 0) { |
3013 | |||
3014 | c = buf[j]; | ||
3015 | |||
3016 | // If we have hit a backslash, skip it. We don't have | 3024 | // If we have hit a backslash, skip it. We don't have |
3017 | // to check for a newline because it's guaranteed. | 3025 | // to check for a newline because it's guaranteed. |
3018 | if (hits < bslashes && c == '\\') { | 3026 | if (*buf == '\\') { |
3019 | ++hits; | 3027 | buf += 2; |
3020 | ++j; | 3028 | ccnt -= 2; |
3021 | continue; | 3029 | continue; |
3022 | } | 3030 | } |
3023 | 3031 | bc_vec_push(&l->t.v, buf); | |
3024 | bc_vec_push(&l->t.v, &c); | 3032 | buf++; |
3033 | ccnt--; | ||
3025 | } | 3034 | } |
3026 | 3035 | ||
3027 | bc_vec_pushZeroByte(&l->t.v); | 3036 | bc_vec_pushZeroByte(&l->t.v); |
3028 | l->i += i; | ||
3029 | 3037 | ||
3030 | RETURN_STATUS(BC_STATUS_SUCCESS); | 3038 | RETURN_STATUS(BC_STATUS_SUCCESS); |
3031 | } | 3039 | } |