mirror of
https://github.com/neovim/neovim.git
synced 2025-09-29 06:28:35 +00:00
charset: Refactor vim_str2nr
This commit is contained in:
@@ -1611,8 +1611,9 @@ bool vim_isblankline(char_u *lbuf)
|
|||||||
/// If maxlen > 0, check at a maximum maxlen chars.
|
/// If maxlen > 0, check at a maximum maxlen chars.
|
||||||
///
|
///
|
||||||
/// @param start
|
/// @param start
|
||||||
/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex,
|
/// @param prep Returns guessed type of number 0 = decimal, 'x' or 'X' is
|
||||||
/// '0' = octal, 'b' or 'B' is bin
|
/// hexadecimal, '0' = octal, 'b' or 'B' is binary. When using
|
||||||
|
/// STR2NR_FORCE is always zero.
|
||||||
/// @param len Returns the detected length of number.
|
/// @param len Returns the detected length of number.
|
||||||
/// @param what Recognizes what number passed.
|
/// @param what Recognizes what number passed.
|
||||||
/// @param nptr Returns the signed result.
|
/// @param nptr Returns the signed result.
|
||||||
@@ -1627,55 +1628,84 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
|
|||||||
#define STRING_ENDED(ptr) \
|
#define STRING_ENDED(ptr) \
|
||||||
(!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
|
(!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
|
||||||
int pre = 0; // default is decimal
|
int pre = 0; // default is decimal
|
||||||
bool negative = false;
|
const bool negative = (ptr[0] == '-');
|
||||||
|
uvarnumber_T un = 0;
|
||||||
|
|
||||||
if (ptr[0] == '-') {
|
if (negative) {
|
||||||
negative = true;
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recognize hex, octal and bin.
|
if (what & STR2NR_FORCE) {
|
||||||
if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
|
// When forcing main consideration is skipping the prefix. Octal and decimal
|
||||||
&& !STRING_ENDED(ptr + 1)
|
// numbers have no prefixes to skip. pre is not set.
|
||||||
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
|
switch ((unsigned)what & (~(unsigned)STR2NR_FORCE)) {
|
||||||
|
case STR2NR_HEX: {
|
||||||
|
if (!STRING_ENDED(ptr + 2)
|
||||||
|
&& ptr[0] == '0'
|
||||||
|
&& (ptr[1] == 'x' || ptr[1] == 'X')
|
||||||
|
&& ascii_isxdigit(ptr[2])) {
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
goto vim_str2nr_hex;
|
||||||
|
}
|
||||||
|
case STR2NR_BIN: {
|
||||||
|
if (!STRING_ENDED(ptr + 2)
|
||||||
|
&& ptr[0] == '0'
|
||||||
|
&& (ptr[1] == 'b' || ptr[1] == 'B')
|
||||||
|
&& ascii_isbdigit(ptr[2])) {
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
goto vim_str2nr_bin;
|
||||||
|
}
|
||||||
|
case STR2NR_OCT: {
|
||||||
|
goto vim_str2nr_oct;
|
||||||
|
}
|
||||||
|
case 0: {
|
||||||
|
goto vim_str2nr_dec;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
|
||||||
|
&& !STRING_ENDED(ptr + 1)
|
||||||
|
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
|
||||||
pre = ptr[1];
|
pre = ptr[1];
|
||||||
|
// Detect hexadecimal: 0x or 0X follwed by hex digit
|
||||||
if ((what & STR2NR_HEX)
|
if ((what & STR2NR_HEX)
|
||||||
&& !STRING_ENDED(ptr + 2)
|
&& !STRING_ENDED(ptr + 2)
|
||||||
&& (pre == 'X' || pre == 'x')
|
&& (pre == 'X' || pre == 'x')
|
||||||
&& ascii_isxdigit(ptr[2])) {
|
&& ascii_isxdigit(ptr[2])) {
|
||||||
// hexadecimal
|
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
} else if ((what & STR2NR_BIN)
|
goto vim_str2nr_hex;
|
||||||
&& !STRING_ENDED(ptr + 2)
|
}
|
||||||
&& (pre == 'B' || pre == 'b')
|
// Detect binary: 0b or 0B follwed by 0 or 1
|
||||||
&& ascii_isbdigit(ptr[2])) {
|
if ((what & STR2NR_BIN)
|
||||||
// binary
|
&& !STRING_ENDED(ptr + 2)
|
||||||
|
&& (pre == 'B' || pre == 'b')
|
||||||
|
&& ascii_isbdigit(ptr[2])) {
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
} else {
|
goto vim_str2nr_bin;
|
||||||
// decimal or octal, default is decimal
|
}
|
||||||
pre = 0;
|
// Detect octal number: zero followed by octal digits without '8' or '9'
|
||||||
|
pre = 0;
|
||||||
if (what & STR2NR_OCT
|
if (!(what & STR2NR_OCT)
|
||||||
&& !STRING_ENDED(ptr + 1)
|
|| !('0' <= ptr[1] && ptr[1] <= '7')) {
|
||||||
&& ('0' <= ptr[1] && ptr[1] <= '7')) {
|
goto vim_str2nr_dec;
|
||||||
// Assume octal now: what we already know is that string starts with
|
}
|
||||||
// zero and some octal digit.
|
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
|
||||||
pre = '0';
|
if (ptr[i] > '7') {
|
||||||
// Don’t interpret "0", "008" or "0129" as octal.
|
goto vim_str2nr_dec;
|
||||||
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
|
|
||||||
if (ptr[i] > '7') {
|
|
||||||
// Can’t be octal.
|
|
||||||
pre = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pre = '0';
|
||||||
|
goto vim_str2nr_oct;
|
||||||
|
} else {
|
||||||
|
goto vim_str2nr_dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
assert(false); // Should’ve used goto earlier.
|
||||||
#define PARSE_NUMBER(base, cond, conv) \
|
#define PARSE_NUMBER(base, cond, conv) \
|
||||||
do { \
|
do { \
|
||||||
while (!STRING_ENDED(ptr) && (cond)) { \
|
while (!STRING_ENDED(ptr) && (cond)) { \
|
||||||
@@ -1688,18 +1718,29 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
|
|||||||
ptr++; \
|
ptr++; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) {
|
switch (pre) {
|
||||||
// Binary number.
|
case 'b':
|
||||||
PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
|
case 'B': {
|
||||||
} else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) {
|
vim_str2nr_bin:
|
||||||
// Octal number.
|
PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
|
||||||
PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
|
break;
|
||||||
} else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) {
|
}
|
||||||
// Hexadecimal number.
|
case '0': {
|
||||||
PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
|
vim_str2nr_oct:
|
||||||
} else {
|
PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
|
||||||
// Decimal number.
|
break;
|
||||||
PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
|
}
|
||||||
|
case 0: {
|
||||||
|
vim_str2nr_dec:
|
||||||
|
PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x':
|
||||||
|
case 'X': {
|
||||||
|
vim_str2nr_hex:
|
||||||
|
PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#undef PARSE_NUMBER
|
#undef PARSE_NUMBER
|
||||||
|
|
||||||
|
@@ -31,55 +31,83 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
|
|||||||
#define STRING_ENDED(ptr) \
|
#define STRING_ENDED(ptr) \
|
||||||
(!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
|
(!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen))
|
||||||
int pre = 0; // default is decimal
|
int pre = 0; // default is decimal
|
||||||
bool negative = false;
|
const bool negative = (ptr[0] == '-');
|
||||||
|
uvarnumber_T un = 0;
|
||||||
|
|
||||||
if (ptr[0] == '-') {
|
if (negative) {
|
||||||
negative = true;
|
|
||||||
ptr++;
|
ptr++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recognize hex, octal and bin.
|
if (what & STR2NR_FORCE) {
|
||||||
if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
|
// When forcing main consideration is skipping the prefix. Octal and decimal
|
||||||
&& !STRING_ENDED(ptr + 1)
|
// numbers have no prefixes to skip. pre is not set.
|
||||||
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
|
switch ((unsigned)what & (~(unsigned)STR2NR_FORCE)) {
|
||||||
|
case STR2NR_HEX: {
|
||||||
|
if (!STRING_ENDED(ptr + 2)
|
||||||
|
&& ptr[0] == '0'
|
||||||
|
&& (ptr[1] == 'x' || ptr[1] == 'X')
|
||||||
|
&& ascii_isxdigit(ptr[2])) {
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
goto vim_str2nr_hex;
|
||||||
|
}
|
||||||
|
case STR2NR_BIN: {
|
||||||
|
if (!STRING_ENDED(ptr + 2)
|
||||||
|
&& ptr[0] == '0'
|
||||||
|
&& (ptr[1] == 'b' || ptr[1] == 'B')
|
||||||
|
&& ascii_isbdigit(ptr[2])) {
|
||||||
|
ptr += 2;
|
||||||
|
}
|
||||||
|
goto vim_str2nr_bin;
|
||||||
|
}
|
||||||
|
case STR2NR_OCT: {
|
||||||
|
goto vim_str2nr_oct;
|
||||||
|
}
|
||||||
|
case 0: {
|
||||||
|
goto vim_str2nr_dec;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN))
|
||||||
|
&& !STRING_ENDED(ptr + 1)
|
||||||
|
&& ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') {
|
||||||
pre = ptr[1];
|
pre = ptr[1];
|
||||||
|
// Detect hexadecimal: 0x or 0X follwed by hex digit
|
||||||
if ((what & STR2NR_HEX)
|
if ((what & STR2NR_HEX)
|
||||||
&& !STRING_ENDED(ptr + 2)
|
&& !STRING_ENDED(ptr + 2)
|
||||||
&& (pre == 'X' || pre == 'x')
|
&& (pre == 'X' || pre == 'x')
|
||||||
&& ascii_isxdigit(ptr[2])) {
|
&& ascii_isxdigit(ptr[2])) {
|
||||||
// hexadecimal
|
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
} else if ((what & STR2NR_BIN)
|
goto vim_str2nr_hex;
|
||||||
&& !STRING_ENDED(ptr + 2)
|
}
|
||||||
&& (pre == 'B' || pre == 'b')
|
// Detect binary: 0b or 0B follwed by 0 or 1
|
||||||
&& ascii_isbdigit(ptr[2])) {
|
if ((what & STR2NR_BIN)
|
||||||
// binary
|
&& !STRING_ENDED(ptr + 2)
|
||||||
|
&& (pre == 'B' || pre == 'b')
|
||||||
|
&& ascii_isbdigit(ptr[2])) {
|
||||||
ptr += 2;
|
ptr += 2;
|
||||||
} else {
|
goto vim_str2nr_bin;
|
||||||
// decimal or octal, default is decimal
|
}
|
||||||
pre = 0;
|
// Detect octal number: zero followed by octal digits without '8' or '9'
|
||||||
|
pre = 0;
|
||||||
if (what & STR2NR_OCT
|
if (!(what & STR2NR_OCT)) {
|
||||||
&& !STRING_ENDED(ptr + 1)
|
goto vim_str2nr_dec;
|
||||||
&& ('0' <= ptr[1] && ptr[1] <= '7')) {
|
}
|
||||||
// Assume octal now: what we already know is that string starts with
|
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
|
||||||
// zero and some octal digit.
|
if (ptr[i] > '7') {
|
||||||
pre = '0';
|
goto vim_str2nr_dec;
|
||||||
// Don’t interpret "0", "008" or "0129" as octal.
|
|
||||||
for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) {
|
|
||||||
if (ptr[i] > '7') {
|
|
||||||
// Can’t be octal.
|
|
||||||
pre = 0;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pre = '0';
|
||||||
|
goto vim_str2nr_oct;
|
||||||
|
} else {
|
||||||
|
goto vim_str2nr_dec;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
assert(false); // Should’ve used goto earlier.
|
||||||
#define PARSE_NUMBER(base, cond, conv) \
|
#define PARSE_NUMBER(base, cond, conv) \
|
||||||
do { \
|
do { \
|
||||||
while (!STRING_ENDED(ptr) && (cond)) { \
|
while (!STRING_ENDED(ptr) && (cond)) { \
|
||||||
@@ -92,18 +120,29 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len,
|
|||||||
ptr++; \
|
ptr++; \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) {
|
switch (pre) {
|
||||||
// Binary number.
|
case 'b':
|
||||||
PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
|
case 'B': {
|
||||||
} else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) {
|
vim_str2nr_bin:
|
||||||
// Octal number.
|
PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0'));
|
||||||
PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
|
break;
|
||||||
} else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) {
|
}
|
||||||
// Hexadecimal number.
|
case '0': {
|
||||||
PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
|
vim_str2nr_oct:
|
||||||
} else {
|
PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0'));
|
||||||
// Decimal number.
|
break;
|
||||||
PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
|
}
|
||||||
|
case 0: {
|
||||||
|
vim_str2nr_dec:
|
||||||
|
PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0'));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x':
|
||||||
|
case 'X': {
|
||||||
|
vim_str2nr_hex:
|
||||||
|
PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#undef PARSE_NUMBER
|
#undef PARSE_NUMBER
|
||||||
|
|
||||||
|
1
test/unit/charset/vim_str2nr_spec.lua
Normal file
1
test/unit/charset/vim_str2nr_spec.lua
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-- FIXME
|
Reference in New Issue
Block a user