diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/charset.c | |
parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-aucmd_textputpost.tar.gz rneovim-aucmd_textputpost.tar.bz2 rneovim-aucmd_textputpost.zip |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/charset.c')
-rw-r--r-- | src/nvim/charset.c | 492 |
1 files changed, 106 insertions, 386 deletions
diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 5aec9ccf9d..48a9808b31 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /// @file charset.c /// /// Code related to character sets. @@ -11,33 +8,26 @@ #include <limits.h> #include <stdlib.h> #include <string.h> +#include <sys/types.h> #include "auto/config.h" #include "klib/kvec.h" -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" #include "nvim/buffer_defs.h" #include "nvim/charset.h" #include "nvim/cursor.h" -#include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/garray.h" #include "nvim/globals.h" -#include "nvim/grid_defs.h" -#include "nvim/indent.h" #include "nvim/keycodes.h" -#include "nvim/macros.h" -#include "nvim/mark.h" +#include "nvim/macros_defs.h" #include "nvim/mbyte.h" -#include "nvim/memline.h" #include "nvim/memory.h" -#include "nvim/move.h" #include "nvim/option.h" #include "nvim/path.h" -#include "nvim/plines.h" -#include "nvim/pos.h" -#include "nvim/state.h" +#include "nvim/pos_defs.h" #include "nvim/strings.h" -#include "nvim/vim.h" +#include "nvim/vim_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "charset.c.generated.h" @@ -55,7 +45,7 @@ static bool chartab_initialized = false; ((chartab)[(unsigned)(c) >> 6] & (1ull << ((c) & 0x3f))) // Table used below, see init_chartab() for an explanation -static char_u g_chartab[256]; +static uint8_t g_chartab[256]; // Flags for g_chartab[]. #define CT_CELL_MASK 0x07 ///< mask: nr of display cells (1, 2 or 4) @@ -97,10 +87,6 @@ int init_chartab(void) int buf_init_chartab(buf_T *buf, int global) { int c; - int c2; - int i; - bool tilde; - bool do_isalpha; if (global) { // Set the default size for printable characters: @@ -119,19 +105,13 @@ int buf_init_chartab(buf_T *buf, int global) while (c < 256) { if (c >= 0xa0) { // UTF-8: bytes 0xa0 - 0xff are printable (latin1) - g_chartab[c++] = CT_PRINT_CHAR + 1; + // Also assume that every multi-byte char is a filename character. + g_chartab[c++] = (CT_PRINT_CHAR | CT_FNAME_CHAR) + 1; } else { // the rest is unprintable by default g_chartab[c++] = (dy_flags & DY_UHEX) ? 4 : 2; } } - - // Assume that every multi-byte char is a filename character. - for (c = 1; c < 256; c++) { - if (c >= 0xa0) { - g_chartab[c] |= CT_FNAME_CHAR; - } - } } // Init word char flags all to false @@ -145,7 +125,7 @@ int buf_init_chartab(buf_T *buf, int global) // Walk through the 'isident', 'iskeyword', 'isfname' and 'isprint' // options Each option is a list of characters, character numbers or // ranges, separated by commas, e.g.: "200-210,x,#-178,-" - for (i = global ? 0 : 3; i <= 3; i++) { + for (int i = global ? 0 : 3; i <= 3; i++) { const char *p; if (i == 0) { // first round: 'isident' @@ -162,8 +142,8 @@ int buf_init_chartab(buf_T *buf, int global) } while (*p) { - tilde = false; - do_isalpha = false; + bool tilde = false; + bool do_isalpha = false; if ((*p == '^') && (p[1] != NUL)) { tilde = true; @@ -175,7 +155,7 @@ int buf_init_chartab(buf_T *buf, int global) } else { c = mb_ptr2char_adv(&p); } - c2 = -1; + int c2 = -1; if ((*p == '-') && (p[1] != NUL)) { p++; @@ -286,7 +266,7 @@ void trans_characters(char *buf, int bufsize) if ((trs_len = utfc_ptr2len(buf)) > 1) { len -= trs_len; } else { - trs = (char *)transchar_byte((uint8_t)(*buf)); + trs = transchar_byte((uint8_t)(*buf)); trs_len = (int)strlen(trs); if (trs_len > 1) { @@ -321,15 +301,13 @@ size_t transstr_len(const char *const s, bool untab) while (*p) { const size_t l = (size_t)utfc_ptr2len(p); if (l > 1) { - int pcc[MAX_MCO + 1]; - pcc[0] = utfc_ptr2char(p, &pcc[1]); - - if (vim_isprintc(pcc[0])) { + if (vim_isprintc(utf_ptr2char(p))) { len += l; } else { - for (size_t i = 0; i < ARRAY_SIZE(pcc) && pcc[i]; i++) { + for (size_t off = 0; off < l; off += (size_t)utf_ptr2len(p + off)) { + int c = utf_ptr2char(p + off); char hexbuf[9]; - len += transchar_hex(hexbuf, pcc[i]); + len += transchar_hex(hexbuf, c); } } p += l; @@ -354,29 +332,29 @@ size_t transstr_len(const char *const s, bool untab) /// @param[in] untab remove tab characters /// /// @return length of the resulting string, without the NUL byte. -size_t transstr_buf(const char *const s, char *const buf, const size_t len, bool untab) +size_t transstr_buf(const char *const s, const ssize_t slen, char *const buf, const size_t buflen, + bool untab) FUNC_ATTR_NONNULL_ALL { const char *p = s; char *buf_p = buf; - char *const buf_e = buf_p + len - 1; + char *const buf_e = buf_p + buflen - 1; - while (*p != NUL && buf_p < buf_e) { + while ((slen < 0 || (p - s) < slen) && *p != NUL && buf_p < buf_e) { const size_t l = (size_t)utfc_ptr2len(p); if (l > 1) { if (buf_p + l > buf_e) { break; // Exceeded `buf` size. } - int pcc[MAX_MCO + 1]; - pcc[0] = utfc_ptr2char(p, &pcc[1]); - if (vim_isprintc(pcc[0])) { + if (vim_isprintc(utf_ptr2char(p))) { memmove(buf_p, p, l); buf_p += l; } else { - for (size_t i = 0; i < ARRAY_SIZE(pcc) && pcc[i]; i++) { + for (size_t off = 0; off < l; off += (size_t)utf_ptr2len(p + off)) { + int c = utf_ptr2char(p + off); char hexbuf[9]; // <up to 6 bytes>NUL - const size_t hexlen = transchar_hex(hexbuf, pcc[i]); + const size_t hexlen = transchar_hex(hexbuf, c); if (buf_p + hexlen > buf_e) { break; } @@ -388,7 +366,7 @@ size_t transstr_buf(const char *const s, char *const buf, const size_t len, bool } else if (*p == TAB && !untab) { *buf_p++ = *p++; } else { - const char *const tb = (const char *)transchar_byte((uint8_t)(*p++)); + const char *const tb = transchar_byte((uint8_t)(*p++)); const size_t tb_len = strlen(tb); if (buf_p + tb_len > buf_e) { break; // Exceeded `buf` size. @@ -416,7 +394,7 @@ char *transstr(const char *const s, bool untab) // multi-byte characters. const size_t len = transstr_len(s, untab) + 1; char *const buf = xmalloc(len); - transstr_buf(s, buf, len, untab); + transstr_buf(s, -1, buf, len, untab); return buf; } @@ -431,7 +409,7 @@ size_t kv_transstr(StringBuilder *str, const char *const s, bool untab) // multi-byte characters. const size_t len = transstr_len(s, untab); kv_ensure_space(*str, len + 1); - transstr_buf(s, str->items + str->size, len + 1, untab); + transstr_buf(s, -1, str->items + str->size, len + 1, untab); str->size += len; // do not include NUL byte return len; } @@ -445,7 +423,6 @@ char *str_foldcase(char *str, int orglen, char *buf, int buflen) FUNC_ATTR_NONNULL_RET { garray_T ga; - int i; int len = orglen; #define GA_CHAR(i) ((char *)ga.ga_data)[i] @@ -475,7 +452,7 @@ char *str_foldcase(char *str, int orglen, char *buf, int buflen) } // Make each character lower case. - i = 0; + int i = 0; while (STR_CHAR(i) != NUL) { int c = utf_ptr2char(STR_PTR(i)); int olen = utf_ptr2len(STR_PTR(i)); @@ -531,7 +508,7 @@ char *str_foldcase(char *str, int orglen, char *buf, int buflen) // Does NOT work for multi-byte characters, c must be <= 255. // Also doesn't work for the first byte of a multi-byte, "c" must be a // character! -static char_u transchar_charbuf[11]; +static uint8_t transchar_charbuf[11]; /// Translate a character into a printable one, leaving printable ASCII intact /// @@ -542,11 +519,10 @@ static char_u transchar_charbuf[11]; /// @return translated character into a static buffer. char *transchar(int c) { - return (char *)transchar_buf(curbuf, c); + return transchar_buf(curbuf, c); } -char_u *transchar_buf(const buf_T *buf, int c) - FUNC_ATTR_NONNULL_ALL +char *transchar_buf(const buf_T *buf, int c) { int i = 0; if (IS_SPECIAL(c)) { @@ -558,33 +534,46 @@ char_u *transchar_buf(const buf_T *buf, int c) } if ((!chartab_initialized && (c >= ' ' && c <= '~')) - || ((c <= 0xFF) && vim_isprintc_strict(c))) { + || ((c <= 0xFF) && vim_isprintc(c))) { // printable character - transchar_charbuf[i] = (char_u)c; + transchar_charbuf[i] = (uint8_t)c; transchar_charbuf[i + 1] = NUL; } else if (c <= 0xFF) { - transchar_nonprint(buf, transchar_charbuf + i, c); + transchar_nonprint(buf, (char *)transchar_charbuf + i, c); } else { transchar_hex((char *)transchar_charbuf + i, c); } - return transchar_charbuf; + return (char *)transchar_charbuf; +} + +/// Like transchar(), but called with a byte instead of a character. +/// +/// Checks for an illegal UTF-8 byte. Uses 'fileformat' of the current buffer. +/// +/// @param[in] c Byte to translate. +/// +/// @return pointer to translated character in transchar_charbuf. +char *transchar_byte(const int c) + FUNC_ATTR_WARN_UNUSED_RESULT +{ + return transchar_byte_buf(curbuf, c); } -/// Like transchar(), but called with a byte instead of a character +/// Like transchar_buf(), but called with a byte instead of a character. /// -/// Checks for an illegal UTF-8 byte. +/// Checks for an illegal UTF-8 byte. Uses 'fileformat' of "buf", unless it is NULL. /// /// @param[in] c Byte to translate. /// /// @return pointer to translated character in transchar_charbuf. -char_u *transchar_byte(const int c) +char *transchar_byte_buf(const buf_T *buf, const int c) FUNC_ATTR_WARN_UNUSED_RESULT { if (c >= 0x80) { - transchar_nonprint(curbuf, transchar_charbuf, c); - return transchar_charbuf; + transchar_nonprint(buf, (char *)transchar_charbuf, c); + return (char *)transchar_charbuf; } - return (char_u *)transchar(c); + return transchar_buf(buf, c); } /// Convert non-printable characters to 2..4 printable ones @@ -596,13 +585,12 @@ char_u *transchar_byte(const int c) /// at least 5 bytes (conversion result + NUL). /// @param[in] c Character to convert. NUL is assumed to be NL according to /// `:h NL-used-for-NUL`. -void transchar_nonprint(const buf_T *buf, char_u *charbuf, int c) - FUNC_ATTR_NONNULL_ALL +void transchar_nonprint(const buf_T *buf, char *charbuf, int c) { if (c == NL) { // we use newline in place of a NUL c = NUL; - } else if ((c == CAR) && (get_fileformat(buf) == EOL_MAC)) { + } else if (buf != NULL && c == CAR && get_fileformat(buf) == EOL_MAC) { // we use CR in place of NL in this case c = NL; } @@ -610,12 +598,12 @@ void transchar_nonprint(const buf_T *buf, char_u *charbuf, int c) if (dy_flags & DY_UHEX || c > 0x7f) { // 'display' has "uhex" - transchar_hex((char *)charbuf, c); + transchar_hex(charbuf, c); } else { // 0x00 - 0x1f and 0x7f charbuf[0] = '^'; // DEL displayed as ^? - charbuf[1] = (char_u)(c ^ 0x40); + charbuf[1] = (char)(uint8_t)(c ^ 0x40); charbuf[2] = NUL; } @@ -633,8 +621,8 @@ size_t transchar_hex(char *const buf, const int c) size_t i = 0; buf[i++] = '<'; - if (c > 255) { - if (c > 255 * 256) { + if (c > 0xFF) { + if (c > 0xFFFF) { buf[i++] = (char)nr2hex((unsigned)c >> 20); buf[i++] = (char)nr2hex((unsigned)c >> 16); } @@ -648,6 +636,17 @@ size_t transchar_hex(char *const buf, const int c) return i; } +/// Mirror text "str" for right-left displaying. +/// Only works for single-byte characters (e.g., numbers). +void rl_mirror_ascii(char *str, char *end) +{ + for (char *p1 = str, *p2 = (end ? end : str + strlen(str)) - 1; p1 < p2; p1++, p2--) { + char t = *p1; + *p1 = *p2; + *p2 = t; + } +} + /// Convert the lower 4 bits of byte "c" to its hex character /// /// Lower case letters are used to avoid the confusion of <F1> being 0xf1 or @@ -732,7 +731,7 @@ int ptr2cells(const char *p_in) /// @param s /// /// @return number of character cells. -int vim_strsize(char *s) +int vim_strsize(const char *s) { return vim_strnsize(s, MAXCOL); } @@ -746,7 +745,7 @@ int vim_strsize(char *s) /// @param len /// /// @return Number of character cells. -int vim_strnsize(char *s, int len) +int vim_strnsize(const char *s, int len) { assert(s != NULL); int size = 0; @@ -835,8 +834,10 @@ bool vim_iswordp_buf(const char *const p, buf_T *const buf) return vim_iswordc_buf(c, buf); } -/// Check that "c" is a valid file-name character. +/// Check that "c" is a valid file-name character as specified with the +/// 'isfname' option. /// Assume characters above 0x100 are valid (multi-byte). +/// To be used for commands like "gf". /// /// @param c character to check bool vim_isfilec(int c) @@ -845,6 +846,14 @@ bool vim_isfilec(int c) return c >= 0x100 || (c > 0 && (g_chartab[c] & CT_FNAME_CHAR)); } +/// Check if "c" is a valid file-name character, including characters left +/// out of 'isfname' to make "gf" work, such as comma, space, '@', etc. +bool vim_is_fname_char(int c) + FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +{ + return vim_isfilec(c) || c == ',' || c == ' ' || c == '@'; +} + /// Check that "c" is a valid file-name character or a wildcard character /// Assume characters above 0x100 are valid (multi-byte). /// Explicitly interpret ']' as a wildcard character as path_has_wildcard("]") @@ -861,7 +870,6 @@ bool vim_isfilec_or_wc(int c) } /// Check that "c" is a printable character. -/// Assume characters above 0x100 are printable for double-byte encodings. /// /// @param c character to check bool vim_isprintc(int c) @@ -873,316 +881,19 @@ bool vim_isprintc(int c) return c > 0 && (g_chartab[c] & CT_PRINT_CHAR); } -/// Strict version of vim_isprintc(c), don't return true if "c" is the head -/// byte of a double-byte character. -/// -/// @param c character to check -/// -/// @return true if "c" is a printable character. -bool vim_isprintc_strict(int c) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT -{ - if (c >= 0x100) { - return utf_printable(c); - } - return c > 0 && (g_chartab[c] & CT_PRINT_CHAR); -} - -/// Check that virtual column "vcol" is in the rightmost column of window "wp". -/// -/// @param wp window -/// @param vcol column number -bool in_win_border(win_T *wp, colnr_T vcol) - FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ARG(1) -{ - if (wp->w_width_inner == 0) { - // there is no border - return false; - } - int width1 = wp->w_width_inner - win_col_off(wp); // width of first line (after line number) - - if ((int)vcol < width1 - 1) { - return false; - } - - if ((int)vcol == width1 - 1) { - return true; - } - int width2 = width1 + win_col_off2(wp); // width of further lines - - if (width2 <= 0) { - return false; - } - return (vcol - width1) % width2 == width2 - 1; -} - -/// Get virtual column number of pos. -/// start: on the first position of this character (TAB, ctrl) -/// cursor: where the cursor is on this character (first char, except for TAB) -/// end: on the last position of this character (TAB, ctrl) -/// -/// This is used very often, keep it fast! -/// -/// @param wp -/// @param pos -/// @param start -/// @param cursor -/// @param end -void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end) -{ - char *ptr; // points to current char - char *posptr; // points to char at pos->col - int incr; - int head; - long *vts = wp->w_buffer->b_p_vts_array; - int ts = (int)wp->w_buffer->b_p_ts; - - colnr_T vcol = 0; - char *line = ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); // start of the line - - if (pos->col == MAXCOL) { - // continue until the NUL - posptr = NULL; - } else { - // In a few cases the position can be beyond the end of the line. - for (colnr_T i = 0; i < pos->col; i++) { - if (ptr[i] == NUL) { - pos->col = i; - break; - } - } - posptr = ptr + pos->col; - posptr -= utf_head_off(line, posptr); - } - - chartabsize_T cts; - init_chartabsize_arg(&cts, wp, pos->lnum, 0, line, line); - - // This function is used very often, do some speed optimizations. - // When 'list', 'linebreak', 'showbreak' and 'breakindent' are not set - // and there are no virtual text use a simple loop. - // Also use this when 'list' is set but tabs take their normal size. - if ((!wp->w_p_list || (wp->w_p_lcs_chars.tab1 != NUL)) - && !wp->w_p_lbr - && *get_showbreak_value(wp) == NUL - && !wp->w_p_bri - && !cts.cts_has_virt_text) { - for (;;) { - head = 0; - int c = (uint8_t)(*ptr); - - // make sure we don't go past the end of the line - if (c == NUL) { - // NUL at end of line only takes one column - incr = 1; - break; - } - - // A tab gets expanded, depending on the current column - if (c == TAB) { - incr = tabstop_padding(vcol, ts, vts); - } else { - // For utf-8, if the byte is >= 0x80, need to look at - // further bytes to find the cell width. - if (c >= 0x80) { - incr = utf_ptr2cells(ptr); - } else { - incr = g_chartab[c] & CT_CELL_MASK; - } - - // If a double-cell char doesn't fit at the end of a line - // it wraps to the next line, it's like this char is three - // cells wide. - if ((incr == 2) - && wp->w_p_wrap - && (MB_BYTE2LEN((uint8_t)(*ptr)) > 1) - && in_win_border(wp, vcol)) { - incr++; - head = 1; - } - } - - if ((posptr != NULL) && (ptr >= posptr)) { - // character at pos->col - break; - } - - vcol += incr; - MB_PTR_ADV(ptr); - } - } else { - for (;;) { - // A tab gets expanded, depending on the current column - // Other things also take up space. - head = 0; - incr = win_lbr_chartabsize(&cts, &head); - - // make sure we don't go past the end of the line - if (*cts.cts_ptr == NUL) { - // NUL at end of line only takes one column - incr = 1; - break; - } - - if ((posptr != NULL) && (cts.cts_ptr >= posptr)) { - // character at pos->col - break; - } - - cts.cts_vcol += incr; - MB_PTR_ADV(cts.cts_ptr); - } - vcol = cts.cts_vcol; - ptr = cts.cts_ptr; - } - clear_chartabsize_arg(&cts); - - if (start != NULL) { - *start = vcol + head; - } - - if (end != NULL) { - *end = vcol + incr - 1; - } - - if (cursor != NULL) { - // cursor is after inserted text - vcol += cts.cts_cur_text_width; - if ((*ptr == TAB) - && (State & MODE_NORMAL) - && !wp->w_p_list - && !virtual_active() - && !(VIsual_active && ((*p_sel == 'e') || ltoreq(*pos, VIsual)))) { - // cursor at end - *cursor = vcol + incr - 1; - } else { - // cursor at start - *cursor = vcol + head; - } - } -} - -/// Get virtual cursor column in the current window, pretending 'list' is off. -/// -/// @param posp -/// -/// @retujrn The virtual cursor column. -colnr_T getvcol_nolist(pos_T *posp) -{ - int list_save = curwin->w_p_list; - colnr_T vcol; - - curwin->w_p_list = false; - if (posp->coladd) { - getvvcol(curwin, posp, NULL, &vcol, NULL); - } else { - getvcol(curwin, posp, NULL, &vcol, NULL); - } - curwin->w_p_list = list_save; - return vcol; -} - -/// Get virtual column in virtual mode. -/// -/// @param wp -/// @param pos -/// @param start -/// @param cursor -/// @param end -void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *end) -{ - colnr_T col; - - if (virtual_active()) { - // For virtual mode, only want one value - getvcol(wp, pos, &col, NULL, NULL); - - colnr_T coladd = pos->coladd; - colnr_T endadd = 0; - - // Cannot put the cursor on part of a wide character. - char *ptr = ml_get_buf(wp->w_buffer, pos->lnum, false); - - if (pos->col < (colnr_T)strlen(ptr)) { - int c = utf_ptr2char(ptr + pos->col); - if ((c != TAB) && vim_isprintc(c)) { - endadd = (colnr_T)(char2cells(c) - 1); - if (coladd > endadd) { - // past end of line - endadd = 0; - } else { - coladd = 0; - } - } - } - col += coladd; - - if (start != NULL) { - *start = col; - } - - if (cursor != NULL) { - *cursor = col; - } - - if (end != NULL) { - *end = col + endadd; - } - } else { - getvcol(wp, pos, start, cursor, end); - } -} - -/// Get the leftmost and rightmost virtual column of pos1 and pos2. -/// Used for Visual block mode. -/// -/// @param wp -/// @param pos1 -/// @param pos2 -/// @param left -/// @param right -void getvcols(win_T *wp, pos_T *pos1, pos_T *pos2, colnr_T *left, colnr_T *right) -{ - colnr_T from1; - colnr_T from2; - colnr_T to1; - colnr_T to2; - - if (lt(*pos1, *pos2)) { - getvvcol(wp, pos1, &from1, NULL, &to1); - getvvcol(wp, pos2, &from2, NULL, &to2); - } else { - getvvcol(wp, pos2, &from1, NULL, &to1); - getvvcol(wp, pos1, &from2, NULL, &to2); - } - - if (from2 < from1) { - *left = from2; - } else { - *left = from1; - } - - if (to2 > to1) { - if ((*p_sel == 'e') && (from2 - 1 >= to1)) { - *right = from2 - 1; - } else { - *right = to2; - } - } else { - *right = to1; - } -} - /// skipwhite: skip over ' ' and '\t'. /// /// @param[in] p String to skip in. /// /// @return Pointer to character after the skipped whitespace. -char *skipwhite(const char *const p) +char *skipwhite(const char *p) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - return skipwhite_len(p, strlen(p)); + while (ascii_iswhite(*p)) { + p++; + } + return (char *)p; } /// Like `skipwhite`, but skip up to `len` characters. @@ -1337,7 +1048,7 @@ char *skiptowhite(const char *p) /// @param p /// /// @return Pointer to the next whitespace character. -char *skiptowhite_esc(char *p) +char *skiptowhite_esc(const char *p) FUNC_ATTR_PURE { while (*p != ' ' && *p != '\t' && *p != NUL) { @@ -1346,7 +1057,7 @@ char *skiptowhite_esc(char *p) } p++; } - return p; + return (char *)p; } /// Skip over text until '\n' or NUL. @@ -1431,14 +1142,14 @@ long getdigits_long(char **pp, bool strict, long def) /// Gets a int32_t number from a string. /// /// @see getdigits -int32_t getdigits_int32(char **pp, bool strict, long def) +int32_t getdigits_int32(char **pp, bool strict, int32_t def) { intmax_t number = getdigits(pp, strict, def); -#if SIZEOF_INTMAX_T > SIZEOF_INT32_T +#if SIZEOF_INTMAX_T > 4 if (strict) { assert(number >= INT32_MIN && number <= INT32_MAX); } else if (!(number >= INT32_MIN && number <= INT32_MAX)) { - return (int32_t)def; + return def; } #endif return (int32_t)number; @@ -1488,9 +1199,10 @@ bool vim_isblankline(char *lbuf) /// @param strict If true, fail if the number has unexpected trailing /// alphanumeric chars: *len is set to 0 and nothing else is /// returned. +/// @param overflow When not NULL, set to true for overflow. void vim_str2nr(const char *const start, int *const prep, int *const len, const int what, varnumber_T *const nptr, uvarnumber_T *const unptr, const int maxlen, - const bool strict) + const bool strict, bool *const overflow) FUNC_ATTR_NONNULL_ARG(1) { const char *ptr = start; @@ -1591,7 +1303,6 @@ void vim_str2nr(const char *const start, int *const prep, int *const len, const // Do the conversion manually to avoid sscanf() quirks. abort(); // Should’ve used goto earlier. - // -V:PARSE_NUMBER:560 #define PARSE_NUMBER(base, cond, conv) \ do { \ const char *const after_prefix = ptr; \ @@ -1614,6 +1325,9 @@ void vim_str2nr(const char *const start, int *const prep, int *const len, const un = (base) * un + digit; \ } else { \ un = UVARNUMBER_MAX; \ + if (overflow != NULL) { \ + *overflow = true; \ + } \ } \ ptr++; \ } \ @@ -1652,12 +1366,18 @@ vim_str2nr_proceed: // avoid ubsan error for overflow if (un > VARNUMBER_MAX) { *nptr = VARNUMBER_MIN; + if (overflow != NULL) { + *overflow = true; + } } else { *nptr = -(varnumber_T)un; } } else { if (un > VARNUMBER_MAX) { un = VARNUMBER_MAX; + if (overflow != NULL) { + *overflow = true; + } } *nptr = (varnumber_T)un; } |