diff options
author | ZyX <kp-pav@yandex.ru> | 2017-11-02 10:44:20 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2017-11-06 01:17:38 +0300 |
commit | d98199de9c2969d430ba489187ffa02d8c489dea (patch) | |
tree | 3f7f12481bbe8dc9e176e53fc57e7ff319e62de3 /src | |
parent | 3ecb95298ffd9ef6ee681876f2d32553fd222b96 (diff) | |
download | rneovim-d98199de9c2969d430ba489187ffa02d8c489dea.tar.gz rneovim-d98199de9c2969d430ba489187ffa02d8c489dea.tar.bz2 rneovim-d98199de9c2969d430ba489187ffa02d8c489dea.zip |
charset: Refactor vim_str2nr
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/charset.c | 135 |
1 files changed, 88 insertions, 47 deletions
diff --git a/src/nvim/charset.c b/src/nvim/charset.c index c895d65eb7..5aebf90194 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1611,8 +1611,9 @@ bool vim_isblankline(char_u *lbuf) /// If maxlen > 0, check at a maximum maxlen chars. /// /// @param start -/// @param prep Returns type of number 0 = decimal, 'x' or 'X' is hex, -/// '0' = octal, 'b' or 'B' is bin +/// @param prep Returns guessed type of number 0 = decimal, 'x' or 'X' is +/// hexadecimal, '0' = octal, 'b' or 'B' is binary. When using +/// STR2NR_FORCE is always zero. /// @param len Returns the detected length of number. /// @param what Recognizes what number passed. /// @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) \ (!(maxlen == 0 || (int)((ptr) - (const char *)start) < maxlen)) int pre = 0; // default is decimal - bool negative = false; + const bool negative = (ptr[0] == '-'); + uvarnumber_T un = 0; - if (ptr[0] == '-') { - negative = true; + if (negative) { ptr++; } - // Recognize hex, octal and bin. - if ((what & (STR2NR_HEX|STR2NR_OCT|STR2NR_BIN)) - && !STRING_ENDED(ptr + 1) - && ptr[0] == '0' && ptr[1] != '8' && ptr[1] != '9') { + if (what & STR2NR_FORCE) { + // When forcing main consideration is skipping the prefix. Octal and decimal + // numbers have no prefixes to skip. pre is not set. + 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]; - + // Detect hexadecimal: 0x or 0X follwed by hex digit if ((what & STR2NR_HEX) && !STRING_ENDED(ptr + 2) && (pre == 'X' || pre == 'x') && ascii_isxdigit(ptr[2])) { - // hexadecimal ptr += 2; - } else if ((what & STR2NR_BIN) - && !STRING_ENDED(ptr + 2) - && (pre == 'B' || pre == 'b') - && ascii_isbdigit(ptr[2])) { - // binary + goto vim_str2nr_hex; + } + // Detect binary: 0b or 0B follwed by 0 or 1 + if ((what & STR2NR_BIN) + && !STRING_ENDED(ptr + 2) + && (pre == 'B' || pre == 'b') + && ascii_isbdigit(ptr[2])) { ptr += 2; - } else { - // decimal or octal, default is decimal - pre = 0; - - if (what & STR2NR_OCT - && !STRING_ENDED(ptr + 1) - && ('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'; - // 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; - } - } + goto vim_str2nr_bin; + } + // Detect octal number: zero followed by octal digits without '8' or '9' + pre = 0; + if (!(what & STR2NR_OCT) + || !('0' <= ptr[1] && ptr[1] <= '7')) { + goto vim_str2nr_dec; + } + for (int i = 2; !STRING_ENDED(ptr + i) && ascii_isdigit(ptr[i]); i++) { + if (ptr[i] > '7') { + goto vim_str2nr_dec; } } + pre = '0'; + goto vim_str2nr_oct; + } else { + goto vim_str2nr_dec; } // 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) \ do { \ while (!STRING_ENDED(ptr) && (cond)) { \ @@ -1688,18 +1718,29 @@ void vim_str2nr(const char_u *const start, int *const prep, int *const len, ptr++; \ } \ } while (0) - if (pre == 'B' || pre == 'b' || what == (STR2NR_BIN|STR2NR_FORCE)) { - // Binary number. - PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0')); - } else if (pre == '0' || what == (STR2NR_OCT|STR2NR_FORCE)) { - // Octal number. - PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0')); - } else if (pre == 'X' || pre == 'x' || what == (STR2NR_HEX|STR2NR_FORCE)) { - // Hexadecimal number. - PARSE_NUMBER(16, (ascii_isxdigit(*ptr)), (hex2nr(*ptr))); - } else { - // Decimal number. - PARSE_NUMBER(10, (ascii_isdigit(*ptr)), (*ptr - '0')); + switch (pre) { + case 'b': + case 'B': { +vim_str2nr_bin: + PARSE_NUMBER(2, (*ptr == '0' || *ptr == '1'), (*ptr - '0')); + break; + } + case '0': { +vim_str2nr_oct: + PARSE_NUMBER(8, ('0' <= *ptr && *ptr <= '7'), (*ptr - '0')); + break; + } + 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 |