aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/strings.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nvim/strings.c')
-rw-r--r--src/nvim/strings.c176
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;