aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--miscutils/bc.c64
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)
2976static BC_STATUS zbc_lex_number(BcLex *l, char start) 2976static 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}