diff options
Diffstat (limited to 'src/nvim/strings.c')
-rw-r--r-- | src/nvim/strings.c | 176 |
1 files changed, 110 insertions, 66 deletions
diff --git a/src/nvim/strings.c b/src/nvim/strings.c index a439d11818..01bd610292 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -17,11 +17,13 @@ #include "nvim/eval/typval_defs.h" #include "nvim/ex_docmd.h" #include "nvim/garray.h" -#include "nvim/gettext.h" +#include "nvim/garray_defs.h" +#include "nvim/gettext_defs.h" #include "nvim/globals.h" #include "nvim/macros_defs.h" #include "nvim/math.h" #include "nvim/mbyte.h" +#include "nvim/mbyte_defs.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/option.h" @@ -30,6 +32,10 @@ #include "nvim/types_defs.h" #include "nvim/vim_defs.h" +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "strings.c.generated.h" +#endif + static const char e_cannot_mix_positional_and_non_positional_str[] = N_("E1500: Cannot mix positional and non-positional arguments: %s"); static const char e_fmt_arg_nr_unused_str[] @@ -179,21 +185,17 @@ char *vim_strnsave_unquoted(const char *const string, const size_t length) char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newline) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *d; - char *escaped_string; size_t l; - int csh_like; - bool fish_like; // Only csh and similar shells expand '!' within single quotes. For sh and // the like we must not put a backslash before it, it will be taken // literally. If do_special is set the '!' will be escaped twice. // Csh also needs to have "\n" escaped twice when do_special is set. - csh_like = csh_like_shell(); + int csh_like = csh_like_shell(); // Fish shell uses '\' as an escape character within single quotes, so '\' // itself must be escaped to get a literal '\'. - fish_like = fish_like_shell(); + bool fish_like = fish_like_shell(); // First count the number of extra bytes required. size_t length = strlen(string) + 3; // two quotes and a trailing NUL @@ -225,8 +227,8 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli } // Allocate memory for the result and fill it. - escaped_string = xmalloc(length); - d = escaped_string; + char *escaped_string = xmalloc(length); + char *d = escaped_string; // add opening quote #ifdef MSWIN @@ -297,9 +299,7 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli char *vim_strsave_up(const char *string) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *p1; - - p1 = xstrdup(string); + char *p1 = xstrdup(string); vim_strup(p1); return p1; } @@ -335,36 +335,41 @@ void vim_strup(char *p) char *strcase_save(const char *const orig, bool upper) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *res = xstrdup(orig); + // Calculate the initial length and allocate memory for the result + size_t orig_len = strlen(orig); + // +1 for the null terminator + char *res = xmalloc(orig_len + 1); + // Index in the result string + size_t res_index = 0; + // Current position in the original string + const char *p = orig; - char *p = res; while (*p != NUL) { - int c = utf_ptr2char(p); - int l = utf_ptr2len(p); - if (c == 0) { - // overlong sequence, use only the first byte - c = (uint8_t)(*p); - l = 1; - } - int uc = upper ? mb_toupper(c) : mb_tolower(c); - - // Reallocate string when byte count changes. This is rare, - // thus it's OK to do another malloc()/free(). - int newl = utf_char2len(uc); - if (newl != l) { - // TODO(philix): use xrealloc() in strcase_save() - char *s = xmalloc(strlen(res) + (size_t)(1 + newl - l)); - memcpy(s, res, (size_t)(p - res)); - STRCPY(s + (p - res) + newl, p + l); - p = s + (p - res); - xfree(res); - res = s; - } - - utf_char2bytes(uc, p); - p += newl; - } - + CharInfo char_info = utf_ptr2CharInfo(p); + int c = char_info.value < 0 ? (uint8_t)(*p) : char_info.value; + int newc = upper ? mb_toupper(c) : mb_tolower(c); + // Cast to size_t to avoid mixing types in arithmetic + size_t newl = (size_t)utf_char2len(newc); + + // Check if there's enough space in the allocated memory + if (res_index + newl > orig_len) { + // Need more space: allocate extra space for the new character and the null terminator + size_t new_size = res_index + newl + 1; + res = xrealloc(res, new_size); + // Adjust the original length to the new size, minus the null terminator + orig_len = new_size - 1; + } + + // Write the possibly new character into the result string + utf_char2bytes(newc, res + res_index); + // Move the index in the result string + res_index += newl; + // Move to the next character in the original string + p += char_info.len; + } + + // Null-terminate the result string + res[res_index] = NUL; return res; } @@ -372,9 +377,7 @@ char *strcase_save(const char *const orig, bool upper) void del_trailing_spaces(char *ptr) FUNC_ATTR_NONNULL_ALL { - char *q; - - q = ptr + strlen(ptr); + char *q = ptr + strlen(ptr); while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V) { *q = NUL; } @@ -461,9 +464,6 @@ char *vim_strchr(const char *const string, const int c) // Sort an array of strings. -#ifdef INCLUDE_GENERATED_DECLARATIONS -# include "strings.c.generated.h" -#endif static int sort_compare(const void *s1, const void *s2) FUNC_ATTR_NONNULL_ALL { @@ -1357,9 +1357,13 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st assert(n <= SIZE_MAX - str_l); str_l += n; } else { - size_t min_field_width = 0, precision = 0; - int zero_padding = 0, precision_specified = 0, justify_left = 0; - int alternate_form = 0, force_sign = 0; + size_t min_field_width = 0; + size_t precision = 0; + bool zero_padding = false; + bool precision_specified = false; + bool justify_left = false; + bool alternate_form = false; + bool force_sign = false; // if both ' ' and '+' flags appear, ' ' flag should be ignored int space_for_positive = 1; @@ -1424,17 +1428,17 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st while (true) { switch (*p) { case '0': - zero_padding = 1; p++; continue; + zero_padding = true; p++; continue; case '-': - justify_left = 1; p++; continue; + justify_left = true; p++; continue; // if both '0' and '-' flags appear, '0' should be ignored case '+': - force_sign = 1; space_for_positive = 0; p++; continue; + force_sign = true; space_for_positive = 0; p++; continue; case ' ': - force_sign = 1; p++; continue; + force_sign = true; p++; continue; // if both ' ' and '+' flags appear, ' ' should be ignored case '#': - alternate_form = 1; p++; continue; + alternate_form = true; p++; continue; case '\'': p++; continue; default: @@ -1469,7 +1473,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st min_field_width = (size_t)j; } else { min_field_width = (size_t)-j; - justify_left = 1; + justify_left = true; } } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we treat @@ -1485,7 +1489,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st // parse precision if (*p == '.') { p++; - precision_specified = 1; + precision_specified = true; if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we @@ -1520,7 +1524,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (j >= 0) { precision = (size_t)j; } else { - precision_specified = 0; + precision_specified = false; precision = 0; } } @@ -1775,7 +1779,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st // '0' flag should be ignored. This is so with Solaris 2.6, Digital // UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. if (precision_specified) { - zero_padding = 0; + zero_padding = false; } if (fmt_spec == 'd') { @@ -1863,8 +1867,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st && !(zero_padding_insertion_ind < str_arg_l && tmp[zero_padding_insertion_ind] == '0')) { // assure leading zero for alternate-form octal numbers - if (!precision_specified - || precision < num_of_digits + 1) { + if (!precision_specified || precision < num_of_digits + 1) { // precision is increased to force the first character to be // zero, except if a zero value is formatted with an explicit // precision of zero @@ -1895,7 +1898,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case 'G': { // floating point char format[40]; - int remove_trailing_zeroes = false; + bool remove_trailing_zeroes = false; double f = (tvs ? tv_float(tvs, &arg_idx) @@ -1921,12 +1924,12 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st force_sign, space_for_positive), sizeof(tmp)); str_arg_l = strlen(tmp); - zero_padding = 0; + zero_padding = false; } else if (xisnan(f)) { // Not a number: nan or NAN memmove(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan", 4); str_arg_l = 3; - zero_padding = 0; + zero_padding = false; } else { // Regular float number format[0] = '%'; @@ -2012,8 +2015,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st default: // unrecognized conversion specifier, keep format string as-is - zero_padding = 0; // turn zero padding off for non-numeric conversion - justify_left = 1; + zero_padding = false; // turn zero padding off for non-numeric conversion + justify_left = true; min_field_width = 0; // reset flags // discard the unrecognized conversion, just keep @@ -2163,6 +2166,47 @@ int kv_do_printf(StringBuilder *str, const char *fmt, ...) return printed; } +String arena_printf(Arena *arena, const char *fmt, ...) + FUNC_ATTR_PRINTF(2, 3) +{ + size_t remaining = 0; + char *buf = NULL; + if (arena) { + if (!arena->cur_blk) { + arena_alloc_block(arena); + } + + // happy case, we can fit the printed string in the rest of the current + // block (one pass): + remaining = arena->size - arena->pos; + buf = arena->cur_blk + arena->pos; + } + + va_list ap; + va_start(ap, fmt); + int printed = vsnprintf(buf, remaining, fmt, ap); + va_end(ap); + + if (printed < 0) { + return (String)STRING_INIT; + } + + // printed string didn't fit, allocate and try again + if ((size_t)printed >= remaining) { + buf = arena_alloc(arena, (size_t)printed + 1, false); + va_start(ap, fmt); + printed = vsnprintf(buf, (size_t)printed + 1, fmt, ap); + va_end(ap); + if (printed < 0) { + return (String)STRING_INIT; + } + } else { + arena->pos += (size_t)printed + 1; + } + + return cbuf_as_string(buf, (size_t)printed); +} + /// Reverse text into allocated memory. /// /// @return the allocated string. @@ -2224,7 +2268,7 @@ char *strrep(const char *src, const char *what, const char *rep) } /// Implementation of "byteidx()" and "byteidxcomp()" functions -static void byteidx_common(typval_T *argvars, typval_T *rettv, int comp) +static void byteidx_common(typval_T *argvars, typval_T *rettv, bool comp) { rettv->vval.v_number = -1; |