charset: Some more refactoring of vim_str2nr

This commit is contained in:
ZyX
2017-10-29 01:17:00 +03:00
parent 47938e1e22
commit b574e95850
2 changed files with 32 additions and 48 deletions

View File

@@ -1656,18 +1656,19 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
// decimal or octal, default is decimal // decimal or octal, default is decimal
pre = 0; pre = 0;
if (what & STR2NR_OCT) { if (what & STR2NR_OCT
// Don't interpret "0", "08" or "0129" as octal. && !STRING_ENDED(ptr + 1)
for (int i = 1; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) { && ('0' <= ptr[1] && ptr[1] <= '7')) {
// Assume octal now: what we already know is that string starts with
// zero and some octal digit.
pre = '0';
// Dont interpret "0", "008" or "0129" as octal.
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
if (ptr[i] > '7') { if (ptr[i] > '7') {
// can't be octal // Cant be octal.
pre = 0; pre = 0;
break; break;
} }
if (ptr[i] >= '0') {
// assume octal
pre = '0';
}
} }
} }
} }
@@ -1675,51 +1676,32 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
// Do the string-to-numeric conversion "manually" to avoid sscanf quirks. // Do the string-to-numeric conversion "manually" to avoid sscanf quirks.
uvarnumber_T un = 0; uvarnumber_T un = 0;
#define PARSE_NUMBER(base, cond, conv) \
do { \
while (!STRING_ENDED(ptr) && (cond)) { \
/* avoid ubsan error for overflow */ \
if (un < UVARNUMBER_MAX / base) { \
un = base * un + (uvarnumber_T)(conv); \
} else { \
un = UVARNUMBER_MAX; \
} \
ptr++; \
} \
} while (0)
if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) { if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) {
// bin // Binary number.
while (!STRING_ENDED(ptr) && '0' <= *ptr && *ptr <= '1') { PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
// avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 2) {
un = 2 * un + (uvarnumber_T)(*ptr - '0');
} else {
un = UVARNUMBER_MAX;
}
ptr++;
}
} else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) { } else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) {
// octal // Octal number.
while (!STRING_ENDED(ptr) && '0' <= *ptr && *ptr <= '7') { PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
// avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 8) {
un = 8 * un + (uvarnumber_T)(*ptr - '0');
} else {
un = UVARNUMBER_MAX;
}
ptr++;
}
} else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) { } else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) {
// hex // Hexadecimal number.
while (!STRING_ENDED(ptr) && ascii_isxdigit(*ptr)) { PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
// avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 16) {
un = 16 * un + (uvarnumber_T)hex2nr(*ptr);
} else {
un = UVARNUMBER_MAX;
}
ptr++;
}
} else { } else {
// decimal // Decimal number.
while (!STRING_ENDED(ptr) && ascii_isdigit(*ptr)) { PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
// avoid ubsan error for overflow
if (un < UVARNUMBER_MAX / 10) {
un = 10 * un + (uvarnumber_T)(*ptr - '0');
} else {
un = UVARNUMBER_MAX;
}
ptr++;
}
} }
#undef PARSE_NUMBER
if (prep != NULL) { if (prep != NULL) {
*prep = pre; *prep = pre;

View File

@@ -77,6 +77,8 @@ static char *features[] = {
// clang-format off // clang-format off
static const int included_patches[] = { static const int included_patches[] = {
1229,
1230,
// 1026, // 1026,
1025, 1025,
1024, 1024,