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.c916
1 files changed, 467 insertions, 449 deletions
diff --git a/src/nvim/strings.c b/src/nvim/strings.c
index 79a3db4843..11c1aa1760 100644
--- a/src/nvim/strings.c
+++ b/src/nvim/strings.c
@@ -1,28 +1,26 @@
// 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
+#include <assert.h>
#include <inttypes.h>
+#include <math.h>
#include <stdarg.h>
#include <stdbool.h>
#include <string.h>
-#include <math.h>
-#include <assert.h>
-#include "nvim/assert.h"
-#include "nvim/vim.h"
#include "nvim/ascii.h"
-#include "nvim/strings.h"
-#include "nvim/file_search.h"
+#include "nvim/assert.h"
#include "nvim/buffer.h"
#include "nvim/charset.h"
#include "nvim/diff.h"
#include "nvim/edit.h"
#include "nvim/eval.h"
+#include "nvim/eval/encode.h"
#include "nvim/ex_cmds.h"
#include "nvim/ex_docmd.h"
#include "nvim/ex_getln.h"
+#include "nvim/file_search.h"
#include "nvim/fileio.h"
-#include "nvim/func_attr.h"
#include "nvim/fold.h"
#include "nvim/func_attr.h"
#include "nvim/getchar.h"
@@ -35,8 +33,10 @@
#include "nvim/message.h"
#include "nvim/misc1.h"
#include "nvim/move.h"
-#include "nvim/option.h"
#include "nvim/ops.h"
+#include "nvim/option.h"
+#include "nvim/os/os.h"
+#include "nvim/os/shell.h"
#include "nvim/os_unix.h"
#include "nvim/path.h"
#include "nvim/quickfix.h"
@@ -44,12 +44,11 @@
#include "nvim/screen.h"
#include "nvim/search.h"
#include "nvim/spell.h"
+#include "nvim/strings.h"
#include "nvim/syntax.h"
#include "nvim/tag.h"
+#include "nvim/vim.h"
#include "nvim/window.h"
-#include "nvim/os/os.h"
-#include "nvim/os/shell.h"
-#include "nvim/eval/encode.h"
/// Copy "string" into newly allocated memory.
char_u *vim_strsave(const char_u *string)
@@ -84,8 +83,7 @@ char_u *vim_strsave_escaped(const char_u *string, const char_u *esc_chars)
* characters where rem_backslash() would remove the backslash.
* Escape the characters with "cc".
*/
-char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars,
- char_u cc, bool bsl)
+char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, char_u cc, bool bsl)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
/*
@@ -100,9 +98,10 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars,
p += l - 1;
continue;
}
- if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
- ++length; /* count a backslash */
- ++length; /* count an ordinary char */
+ if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) {
+ ++length; // count a backslash
+ }
+ ++length; // count an ordinary char
}
char_u *escaped_string = xmalloc(length);
@@ -112,11 +111,12 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars,
if (l > 1) {
memcpy(p2, p, l);
p2 += l;
- p += l - 1; /* skip multibyte char */
+ p += l - 1; // skip multibyte char
continue;
}
- if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p)))
+ if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) {
*p2++ = cc;
+ }
*p2++ = *p;
}
*p2 = NUL;
@@ -182,12 +182,11 @@ char *vim_strnsave_unquoted(const char *const string, const size_t length)
* When "do_newline" is false do not escape newline unless it is csh shell.
* Returns the result in allocated memory.
*/
-char_u *vim_strsave_shellescape(const char_u *string,
- bool do_special, bool do_newline)
+char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_newline)
FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL
{
- char_u *d;
- char_u *escaped_string;
+ char_u *d;
+ char_u *escaped_string;
size_t l;
int csh_like;
bool fish_like;
@@ -202,7 +201,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
// itself must be escaped to get a literal '\'.
fish_like = fish_like_shell();
- /* First count the number of extra bytes required. */
+ // First count the number of extra bytes required.
size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL
for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) {
#ifdef WIN32
@@ -217,12 +216,13 @@ char_u *vim_strsave_shellescape(const char_u *string,
}
if ((*p == '\n' && (csh_like || do_newline))
|| (*p == '!' && (csh_like || do_special))) {
- ++length; /* insert backslash */
- if (csh_like && do_special)
- ++length; /* insert backslash */
+ ++length; // insert backslash
+ if (csh_like && do_special) {
+ ++length; // insert backslash
+ }
}
if (do_special && find_cmdline_var(p, &l) >= 0) {
- ++length; /* insert backslash */
+ ++length; // insert backslash
p += l - 1;
}
if (*p == '\\' && fish_like) {
@@ -230,7 +230,7 @@ char_u *vim_strsave_shellescape(const char_u *string,
}
}
- /* Allocate memory for the result and fill it. */
+ // Allocate memory for the result and fill it.
escaped_string = xmalloc(length);
d = escaped_string;
@@ -264,15 +264,17 @@ char_u *vim_strsave_shellescape(const char_u *string,
if ((*p == '\n' && (csh_like || do_newline))
|| (*p == '!' && (csh_like || do_special))) {
*d++ = '\\';
- if (csh_like && do_special)
+ if (csh_like && do_special) {
*d++ = '\\';
+ }
*d++ = *p++;
continue;
}
if (do_special && find_cmdline_var(p, &l) >= 0) {
- *d++ = '\\'; /* insert backslash */
- while (--l != SIZE_MAX) /* copy the var */
+ *d++ = '\\'; // insert backslash
+ while (--l != SIZE_MAX) { // copy the var
*d++ = *p++;
+ }
continue;
}
if (*p == '\\' && fish_like) {
@@ -285,11 +287,11 @@ char_u *vim_strsave_shellescape(const char_u *string,
}
// add terminating quote and finish with a NUL
-# ifdef WIN32
+#ifdef WIN32
if (!p_ssl) {
*d++ = '"';
} else
-# endif
+#endif
*d++ = '\'';
*d = NUL;
@@ -384,11 +386,12 @@ char *strcase_save(const char *const orig, bool upper)
void del_trailing_spaces(char_u *ptr)
FUNC_ATTR_NONNULL_ALL
{
- char_u *q;
+ char_u *q;
q = ptr + STRLEN(ptr);
- while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V)
+ while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V) {
*q = NUL;
+ }
}
#if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP))
@@ -404,14 +407,16 @@ int vim_stricmp(const char *s1, const char *s2)
for (;; ) {
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
- if (i != 0)
- return i; /* this character different */
- if (*s1 == NUL)
- break; /* strings match until NUL */
+ if (i != 0) {
+ return i; // this character different
+ }
+ if (*s1 == NUL) {
+ break; // strings match until NUL
+ }
++s1;
++s2;
}
- return 0; /* strings match */
+ return 0; // strings match
}
#endif
@@ -428,15 +433,17 @@ int vim_strnicmp(const char *s1, const char *s2, size_t len)
while (len > 0) {
i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2);
- if (i != 0)
- return i; /* this character different */
- if (*s1 == NUL)
- break; /* strings match until NUL */
+ if (i != 0) {
+ return i; // this character different
+ }
+ if (*s1 == NUL) {
+ break; // strings match until NUL
+ }
++s1;
++s2;
--len;
}
- return 0; /* strings match */
+ return 0; // strings match
}
#endif
@@ -490,10 +497,13 @@ bool has_non_ascii(const char_u *s)
{
const char_u *p;
- if (s != NULL)
- for (p = s; *p != NUL; ++p)
- if (*p >= 128)
+ if (s != NULL) {
+ for (p = s; *p != NUL; ++p) {
+ if (*p >= 128) {
return true;
+ }
+ }
+ }
return false;
}
@@ -504,7 +514,7 @@ bool has_non_ascii_len(const char *const s, const size_t len)
{
if (s != NULL) {
for (size_t i = 0; i < len; i++) {
- if ((uint8_t) s[i] >= 128) {
+ if ((uint8_t)s[i] >= 128) {
return true;
}
}
@@ -527,7 +537,7 @@ char_u *concat_str(const char_u *restrict str1, const char_u *restrict str2)
static const char *const e_printf =
- N_("E766: Insufficient arguments for printf()");
+ N_("E766: Insufficient arguments for printf()");
/// Get number argument from idxp entry in tvs
///
@@ -606,15 +616,14 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp)
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT
{
#define OFF(attr) offsetof(union typval_vval_union, attr)
- STATIC_ASSERT(
- OFF(v_string) == OFF(v_list)
- && OFF(v_string) == OFF(v_dict)
- && OFF(v_string) == OFF(v_partial)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
- && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
- "Strings, dictionaries, lists and partials are expected to be pointers, "
- "so that all three of them can be accessed via v_string");
+ STATIC_ASSERT(OFF(v_string) == OFF(v_list)
+ && OFF(v_string) == OFF(v_dict)
+ && OFF(v_string) == OFF(v_partial)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict)
+ && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial),
+ "Strings, dictionaries, lists and partials are expected to be pointers, "
+ "so that all three of them can be accessed via v_string");
#undef OFF
const int idx = *idxp - 1;
if (tvs[idx].v_type == VAR_UNKNOWN) {
@@ -735,8 +744,8 @@ int vim_snprintf(char *str, size_t str_m, const char *fmt, ...)
// Return the representation of infinity for printf() function:
// "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF".
-static const char *infinity_str(bool positive, char fmt_spec,
- int force_sign, int space_for_positive)
+static const char *infinity_str(bool positive, char fmt_spec, int force_sign,
+ int space_for_positive)
{
static const char *table[] = {
"-inf", "inf", "+inf", " inf",
@@ -765,8 +774,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap)
///
/// @return Number of bytes excluding NUL byte that would be written to the
/// string if str_m was greater or equal to the return value.
-int vim_vsnprintf_typval(
- char *str, size_t str_m, const char *fmt, va_list ap, typval_T *const tvs)
+int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, typval_T *const tvs)
{
size_t str_l = 0;
bool str_avail = str_l < str_m;
@@ -800,7 +808,7 @@ int vim_vsnprintf_typval(
char length_modifier = '\0';
// temporary buffer for simple numeric->string conversion
-# define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable
+#define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable
char tmp[TMP_LEN];
// string address in case of string argument
@@ -832,15 +840,22 @@ int vim_vsnprintf_typval(
// parse flags
while (true) {
switch (*p) {
- case '0': zero_padding = 1; p++; continue;
- case '-': justify_left = 1; p++; continue;
- // if both '0' and '-' flags appear, '0' should be ignored
- case '+': force_sign = 1; space_for_positive = 0; p++; continue;
- case ' ': force_sign = 1; p++; continue;
- // if both ' ' and '+' flags appear, ' ' should be ignored
- case '#': alternate_form = 1; p++; continue;
- case '\'': p++; continue;
- default: break;
+ case '0':
+ zero_padding = 1; p++; continue;
+ case '-':
+ justify_left = 1; p++; continue;
+ // if both '0' and '-' flags appear, '0' should be ignored
+ case '+':
+ force_sign = 1; space_for_positive = 0; p++; continue;
+ case ' ':
+ force_sign = 1; p++; continue;
+ // if both ' ' and '+' flags appear, ' ' should be ignored
+ case '#':
+ alternate_form = 1; p++; continue;
+ case '\'':
+ p++; continue;
+ default:
+ break;
}
break;
}
@@ -905,444 +920,447 @@ int vim_vsnprintf_typval(
// common synonyms
switch (fmt_spec) {
- case 'i': fmt_spec = 'd'; break;
- case 'D': fmt_spec = 'd'; length_modifier = 'l'; break;
- case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
- case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
- default: break;
+ case 'i':
+ fmt_spec = 'd'; break;
+ case 'D':
+ fmt_spec = 'd'; length_modifier = 'l'; break;
+ case 'U':
+ fmt_spec = 'u'; length_modifier = 'l'; break;
+ case 'O':
+ fmt_spec = 'o'; length_modifier = 'l'; break;
+ default:
+ break;
}
switch (fmt_spec) {
- case 'b': case 'B':
- case 'd': case 'u': case 'o': case 'x': case 'X':
- if (tvs && length_modifier == '\0') {
- length_modifier = '2';
- }
+ case 'b':
+ case 'B':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'x':
+ case 'X':
+ if (tvs && length_modifier == '\0') {
+ length_modifier = '2';
+ }
}
// get parameter value, do initial processing
switch (fmt_spec) {
- // '%' and 'c' behave similar to 's' regarding flags and field widths
- case '%': case 'c': case 's': case 'S':
- str_arg_l = 1;
- switch (fmt_spec) {
- case '%':
- str_arg = p;
- break;
-
- case 'c': {
- const int j = tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int);
- // standard demands unsigned char
- uchar_arg = (unsigned char)j;
- str_arg = (char *)&uchar_arg;
- break;
- }
+ // '%' and 'c' behave similar to 's' regarding flags and field widths
+ case '%':
+ case 'c':
+ case 's':
+ case 'S':
+ str_arg_l = 1;
+ switch (fmt_spec) {
+ case '%':
+ str_arg = p;
+ break;
- case 's':
- case 'S':
- str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree)
- : va_arg(ap, const char *);
- if (!str_arg) {
- str_arg = "[NULL]";
- str_arg_l = 6;
- } else if (!precision_specified) {
- // make sure not to address string beyond the specified
- // precision
- str_arg_l = strlen(str_arg);
- } else if (precision == 0) {
- // truncate string if necessary as requested by precision
- str_arg_l = 0;
- } else {
- // memchr on HP does not like n > 2^31
- // TODO(elmart): check if this still holds / is relevant
- str_arg_l = (size_t)((char *)xmemscan(str_arg,
- NUL,
- MIN(precision,
- 0x7fffffff))
- - str_arg);
- }
- if (fmt_spec == 'S') {
- if (min_field_width != 0) {
- min_field_width += (strlen(str_arg)
- - mb_string2cells((char_u *)str_arg));
- }
- if (precision) {
- char_u *p1;
- size_t i = 0;
-
- for (p1 = (char_u *)str_arg; *p1;
- p1 += mb_ptr2len(p1)) {
- i += (size_t)utf_ptr2cells(p1);
- if (i > precision) {
- break;
- }
- }
- str_arg_l = (size_t)(p1 - (char_u *)str_arg);
+ case 'c': {
+ const int j = tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int);
+ // standard demands unsigned char
+ uchar_arg = (unsigned char)j;
+ str_arg = (char *)&uchar_arg;
+ break;
+ }
+
+ case 's':
+ case 'S':
+ str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree)
+ : va_arg(ap, const char *);
+ if (!str_arg) {
+ str_arg = "[NULL]";
+ str_arg_l = 6;
+ } else if (!precision_specified) {
+ // make sure not to address string beyond the specified
+ // precision
+ str_arg_l = strlen(str_arg);
+ } else if (precision == 0) {
+ // truncate string if necessary as requested by precision
+ str_arg_l = 0;
+ } else {
+ // memchr on HP does not like n > 2^31
+ // TODO(elmart): check if this still holds / is relevant
+ str_arg_l = (size_t)((char *)xmemscan(str_arg,
+ NUL,
+ MIN(precision,
+ 0x7fffffff))
+ - str_arg);
+ }
+ if (fmt_spec == 'S') {
+ if (min_field_width != 0) {
+ min_field_width += (strlen(str_arg)
+ - mb_string2cells((char_u *)str_arg));
+ }
+ if (precision) {
+ char_u *p1;
+ size_t i = 0;
+
+ for (p1 = (char_u *)str_arg; *p1;
+ p1 += mb_ptr2len(p1)) {
+ i += (size_t)utf_ptr2cells(p1);
+ if (i > precision) {
+ break;
}
}
- break;
-
- default:
- break;
+ str_arg_l = (size_t)(p1 - (char_u *)str_arg);
+ }
}
break;
- case 'd':
- case 'u':
- case 'b': case 'B':
- case 'o':
- case 'x': case 'X':
- case 'p': {
- // u, b, B, o, x, X and p conversion specifiers imply
- // the value is unsigned; d implies a signed value
-
- // 0 if numeric argument is zero (or if pointer is NULL for 'p'),
- // +1 if greater than zero (or non NULL for 'p'),
- // -1 if negative (unsigned argument is never negative)
- int arg_sign = 0;
-
- intmax_t arg = 0;
- uintmax_t uarg = 0;
-
- // only defined for p conversion
- const void *ptr_arg = NULL;
-
- if (fmt_spec == 'p') {
- ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *);
- if (ptr_arg) {
- arg_sign = 1;
- }
- } else if (fmt_spec == 'd') {
- // signed
- switch (length_modifier) {
- case '\0': {
- arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
- break;
- }
- case 'h': {
- // char and short arguments are passed as int16_t
- arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
- break;
- }
- case 'l': {
- arg = (tvs ? (long)tv_nr(tvs, &arg_idx) : va_arg(ap, long));
- break;
- }
- case '2': {
- arg = (
- tvs
+ default:
+ break;
+ }
+ break;
+
+ case 'd':
+ case 'u':
+ case 'b':
+ case 'B':
+ case 'o':
+ case 'x':
+ case 'X':
+ case 'p': {
+ // u, b, B, o, x, X and p conversion specifiers imply
+ // the value is unsigned; d implies a signed value
+
+ // 0 if numeric argument is zero (or if pointer is NULL for 'p'),
+ // +1 if greater than zero (or non NULL for 'p'),
+ // -1 if negative (unsigned argument is never negative)
+ int arg_sign = 0;
+
+ intmax_t arg = 0;
+ uintmax_t uarg = 0;
+
+ // only defined for p conversion
+ const void *ptr_arg = NULL;
+
+ if (fmt_spec == 'p') {
+ ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *);
+ if (ptr_arg) {
+ arg_sign = 1;
+ }
+ } else if (fmt_spec == 'd') {
+ // signed
+ switch (length_modifier) {
+ case '\0':
+ arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
+ break;
+ case 'h':
+ // char and short arguments are passed as int16_t
+ arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int));
+ break;
+ case 'l':
+ arg = (tvs ? (long)tv_nr(tvs, &arg_idx) : va_arg(ap, long));
+ break;
+ case '2':
+ arg = (
+ tvs
? (long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int)
: va_arg(ap, long long)); // NOLINT (runtime/int)
- break;
- }
- case 'z': {
- arg = (tvs
+ break;
+ case 'z':
+ arg = (tvs
? (ptrdiff_t)tv_nr(tvs, &arg_idx)
: va_arg(ap, ptrdiff_t));
- break;
- }
- }
- if (arg > 0) {
- arg_sign = 1;
- } else if (arg < 0) {
- arg_sign = -1;
- }
- } else {
- // unsigned
- switch (length_modifier) {
- case '\0': {
- uarg = (unsigned int)(tvs
+ break;
+ }
+ if (arg > 0) {
+ arg_sign = 1;
+ } else if (arg < 0) {
+ arg_sign = -1;
+ }
+ } else {
+ // unsigned
+ switch (length_modifier) {
+ case '\0':
+ uarg = (unsigned int)(tvs
? tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned int));
- break;
- }
- case 'h': {
- uarg = (uint16_t)(tvs
+ break;
+ case 'h':
+ uarg = (uint16_t)(tvs
? tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned int));
- break;
- }
- case 'l': {
- uarg = (tvs
+ break;
+ case 'l':
+ uarg = (tvs
? (unsigned long)tv_nr(tvs, &arg_idx)
: va_arg(ap, unsigned long));
- break;
- }
- case '2': {
- uarg = (uintmax_t)(unsigned long long)( // NOLINT (runtime/int)
- tvs
+ break;
+ case '2':
+ uarg = (uintmax_t)(unsigned long long)( // NOLINT (runtime/int)
+ tvs
? ((unsigned long long) // NOLINT (runtime/int)
tv_nr(tvs, &arg_idx))
: va_arg(ap, unsigned long long)); // NOLINT (runtime/int)
- break;
- }
- case 'z': {
- uarg = (tvs
+ break;
+ case 'z':
+ uarg = (tvs
? (size_t)tv_nr(tvs, &arg_idx)
: va_arg(ap, size_t));
- break;
- }
- }
- arg_sign = (uarg != 0);
+ break;
}
+ arg_sign = (uarg != 0);
+ }
- str_arg = tmp;
- str_arg_l = 0;
+ str_arg = tmp;
+ str_arg_l = 0;
- // For d, i, u, o, x, and X conversions, if precision is specified,
- // '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;
- }
+ // For d, i, u, o, x, and X conversions, if precision is specified,
+ // '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;
+ }
- if (fmt_spec == 'd') {
- if (force_sign && arg_sign >= 0) {
- tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
- }
- // leave negative numbers for snprintf to handle, to
- // avoid handling tricky cases like (short int)-32768
- } else if (alternate_form) {
- if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X'
- || fmt_spec == 'b' || fmt_spec == 'B')) {
- tmp[str_arg_l++] = '0';
- tmp[str_arg_l++] = fmt_spec;
- }
- // alternate form should have no effect for p * conversion, but ...
+ if (fmt_spec == 'd') {
+ if (force_sign && arg_sign >= 0) {
+ tmp[str_arg_l++] = space_for_positive ? ' ' : '+';
}
-
- zero_padding_insertion_ind = str_arg_l;
- if (!precision_specified) {
- precision = 1; // default precision is 1
+ // leave negative numbers for snprintf to handle, to
+ // avoid handling tricky cases like (short int)-32768
+ } else if (alternate_form) {
+ if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X'
+ || fmt_spec == 'b' || fmt_spec == 'B')) {
+ tmp[str_arg_l++] = '0';
+ tmp[str_arg_l++] = fmt_spec;
}
- if (precision == 0 && arg_sign == 0) {
- // when zero value is formatted with an explicit precision 0,
- // resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
- } else {
- switch (fmt_spec) {
- case 'p': { // pointer
- str_arg_l += (size_t)snprintf(tmp + str_arg_l,
- sizeof(tmp) - str_arg_l,
- "%p", ptr_arg);
- break;
- }
- case 'd': { // signed
- str_arg_l += (size_t)snprintf(tmp + str_arg_l,
- sizeof(tmp) - str_arg_l,
- "%" PRIdMAX, arg);
- break;
- }
- case 'b': case 'B': { // binary
- size_t bits = 0;
- for (bits = sizeof(uintmax_t) * 8; bits > 0; bits--) {
- if ((uarg >> (bits - 1)) & 0x1) {
- break;
- }
- }
+ // alternate form should have no effect for p * conversion, but ...
+ }
- while (bits > 0) {
- tmp[str_arg_l++] = ((uarg >> --bits) & 0x1) ? '1' : '0';
- }
- break;
- }
- default: { // unsigned
- // construct a simple format string for snprintf
- char f[] = "%" PRIuMAX;
- f[sizeof("%" PRIuMAX) - 1 - 1] = fmt_spec;
- assert(PRIuMAX[sizeof(PRIuMAX) - 1 - 1] == 'u');
- str_arg_l += (size_t)snprintf(tmp + str_arg_l,
- sizeof(tmp) - str_arg_l,
- f, uarg);
+ zero_padding_insertion_ind = str_arg_l;
+ if (!precision_specified) {
+ precision = 1; // default precision is 1
+ }
+ if (precision == 0 && arg_sign == 0) {
+ // when zero value is formatted with an explicit precision 0,
+ // resulting formatted string is empty (d, i, u, b, B, o, x, X, p)
+ } else {
+ switch (fmt_spec) {
+ case 'p': // pointer
+ str_arg_l += (size_t)snprintf(tmp + str_arg_l,
+ sizeof(tmp) - str_arg_l,
+ "%p", ptr_arg);
+ break;
+ case 'd': // signed
+ str_arg_l += (size_t)snprintf(tmp + str_arg_l,
+ sizeof(tmp) - str_arg_l,
+ "%" PRIdMAX, arg);
+ break;
+ case 'b':
+ case 'B': { // binary
+ size_t bits = 0;
+ for (bits = sizeof(uintmax_t) * 8; bits > 0; bits--) {
+ if ((uarg >> (bits - 1)) & 0x1) {
break;
}
}
- assert(str_arg_l < sizeof(tmp));
- // include the optional minus sign and possible "0x" in the region
- // before the zero padding insertion point
- if (zero_padding_insertion_ind < str_arg_l
- && tmp[zero_padding_insertion_ind] == '-') {
- zero_padding_insertion_ind++;
- }
- if (zero_padding_insertion_ind + 1 < str_arg_l
- && tmp[zero_padding_insertion_ind] == '0'
- && (tmp[zero_padding_insertion_ind + 1] == 'x'
- || tmp[zero_padding_insertion_ind + 1] == 'X'
- || tmp[zero_padding_insertion_ind + 1] == 'b'
- || tmp[zero_padding_insertion_ind + 1] == 'B')) {
- zero_padding_insertion_ind += 2;
+ while (bits > 0) {
+ tmp[str_arg_l++] = ((uarg >> --bits) & 0x1) ? '1' : '0';
}
+ break;
+ }
+ default: { // unsigned
+ // construct a simple format string for snprintf
+ char f[] = "%" PRIuMAX;
+ f[sizeof("%" PRIuMAX) - 1 - 1] = fmt_spec;
+ assert(PRIuMAX[sizeof(PRIuMAX) - 1 - 1] == 'u');
+ str_arg_l += (size_t)snprintf(tmp + str_arg_l,
+ sizeof(tmp) - str_arg_l,
+ f, uarg);
+ break;
+ }
}
+ assert(str_arg_l < sizeof(tmp));
- {
- size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
-
- if (alternate_form && fmt_spec == 'o'
- // unless zero is already the first character
- && !(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) {
- // precision is increased to force the first character to be
- // zero, except if a zero value is formatted with an explicit
- // precision of zero
- precision = num_of_digits + 1;
- }
- }
- // zero padding to specified precision?
- if (num_of_digits < precision) {
- number_of_zeros_to_pad = precision - num_of_digits;
- }
+ // include the optional minus sign and possible "0x" in the region
+ // before the zero padding insertion point
+ if (zero_padding_insertion_ind < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '-') {
+ zero_padding_insertion_ind++;
}
- // zero padding to specified minimal field width?
- if (!justify_left && zero_padding) {
- const int n = (int)(min_field_width - (str_arg_l
- + number_of_zeros_to_pad));
- if (n > 0) {
- number_of_zeros_to_pad += (size_t)n;
- }
+ if (zero_padding_insertion_ind + 1 < str_arg_l
+ && tmp[zero_padding_insertion_ind] == '0'
+ && (tmp[zero_padding_insertion_ind + 1] == 'x'
+ || tmp[zero_padding_insertion_ind + 1] == 'X'
+ || tmp[zero_padding_insertion_ind + 1] == 'b'
+ || tmp[zero_padding_insertion_ind + 1] == 'B')) {
+ zero_padding_insertion_ind += 2;
}
- break;
}
- case 'f':
- case 'F':
- case 'e':
- case 'E':
- case 'g':
- case 'G':
- {
- // floating point
- char format[40];
- int remove_trailing_zeroes = false;
-
- double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
- double abs_f = f < 0 ? -f : f;
-
- if (fmt_spec == 'g' || fmt_spec == 'G') {
- // can't use %g directly, cause it prints "1.0" as "1"
- if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) {
- fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
- } else {
- fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
- }
- remove_trailing_zeroes = true;
+ {
+ size_t num_of_digits = str_arg_l - zero_padding_insertion_ind;
+
+ if (alternate_form && fmt_spec == 'o'
+ // unless zero is already the first character
+ && !(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) {
+ // precision is increased to force the first character to be
+ // zero, except if a zero value is formatted with an explicit
+ // precision of zero
+ precision = num_of_digits + 1;
}
+ }
+ // zero padding to specified precision?
+ if (num_of_digits < precision) {
+ number_of_zeros_to_pad = precision - num_of_digits;
+ }
+ }
+ // zero padding to specified minimal field width?
+ if (!justify_left && zero_padding) {
+ const int n = (int)(min_field_width - (str_arg_l
+ + number_of_zeros_to_pad));
+ if (n > 0) {
+ number_of_zeros_to_pad += (size_t)n;
+ }
+ }
+ break;
+ }
- if (xisinf(f)
- || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) {
- xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec,
- force_sign, space_for_positive),
- sizeof(tmp));
- str_arg_l = strlen(tmp);
- zero_padding = 0;
- } 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;
- } else {
- // Regular float number
- format[0] = '%';
- size_t l = 1;
- if (force_sign) {
- format[l++] = space_for_positive ? ' ' : '+';
- }
- if (precision_specified) {
- size_t max_prec = TMP_LEN - 10;
+ case 'f':
+ case 'F':
+ case 'e':
+ case 'E':
+ case 'g':
+ case 'G': {
+ // floating point
+ char format[40];
+ int remove_trailing_zeroes = false;
+
+ double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double);
+ double abs_f = f < 0 ? -f : f;
+
+ if (fmt_spec == 'g' || fmt_spec == 'G') {
+ // can't use %g directly, cause it prints "1.0" as "1"
+ if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) {
+ fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f';
+ } else {
+ fmt_spec = fmt_spec == 'g' ? 'e' : 'E';
+ }
+ remove_trailing_zeroes = true;
+ }
- // make sure we don't get more digits than we have room for
- if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) {
- max_prec -= (size_t)log10(abs_f);
- }
- if (precision > max_prec) {
- precision = max_prec;
- }
- l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d",
- (int)precision);
- }
+ if (xisinf(f)
+ || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) {
+ xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec,
+ force_sign, space_for_positive),
+ sizeof(tmp));
+ str_arg_l = strlen(tmp);
+ zero_padding = 0;
+ } 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;
+ } else {
+ // Regular float number
+ format[0] = '%';
+ size_t l = 1;
+ if (force_sign) {
+ format[l++] = space_for_positive ? ' ' : '+';
+ }
+ if (precision_specified) {
+ size_t max_prec = TMP_LEN - 10;
- // Cast to char to avoid a conversion warning on Ubuntu 12.04.
- assert(l + 1 < sizeof(format));
- format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec);
- format[l + 1] = NUL;
+ // make sure we don't get more digits than we have room for
+ if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) {
+ max_prec -= (size_t)log10(abs_f);
+ }
+ if (precision > max_prec) {
+ precision = max_prec;
+ }
+ l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d",
+ (int)precision);
+ }
- str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f);
- assert(str_arg_l < sizeof(tmp));
+ // Cast to char to avoid a conversion warning on Ubuntu 12.04.
+ assert(l + 1 < sizeof(format));
+ format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec);
+ format[l + 1] = NUL;
- if (remove_trailing_zeroes) {
- int i;
- char *tp;
+ str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f);
+ assert(str_arg_l < sizeof(tmp));
- // using %g or %G: remove superfluous zeroes
- if (fmt_spec == 'f' || fmt_spec == 'F') {
- tp = tmp + str_arg_l - 1;
- } else {
- tp = (char *)vim_strchr((char_u *)tmp,
- fmt_spec == 'e' ? 'e' : 'E');
- if (tp) {
- // remove superfluous '+' and leading zeroes from exponent
- if (tp[1] == '+') {
- // change "1.0e+07" to "1.0e07"
- STRMOVE(tp + 1, tp + 2);
- str_arg_l--;
- }
- i = (tp[1] == '-') ? 2 : 1;
- while (tp[i] == '0') {
- // change "1.0e07" to "1.0e7"
- STRMOVE(tp + i, tp + i + 1);
- str_arg_l--;
- }
- tp--;
- }
- }
+ if (remove_trailing_zeroes) {
+ int i;
+ char *tp;
- if (tp != NULL && !precision_specified) {
- // remove trailing zeroes, but keep the one just after a dot
- while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') {
- STRMOVE(tp, tp + 1);
- tp--;
- str_arg_l--;
- }
+ // using %g or %G: remove superfluous zeroes
+ if (fmt_spec == 'f' || fmt_spec == 'F') {
+ tp = tmp + str_arg_l - 1;
+ } else {
+ tp = (char *)vim_strchr((char_u *)tmp,
+ fmt_spec == 'e' ? 'e' : 'E');
+ if (tp) {
+ // remove superfluous '+' and leading zeroes from exponent
+ if (tp[1] == '+') {
+ // change "1.0e+07" to "1.0e07"
+ STRMOVE(tp + 1, tp + 2);
+ str_arg_l--;
}
- } else {
- // Be consistent: some printf("%e") use 1.0e+12 and some
- // 1.0e+012; remove one zero in the last case.
- char *tp = (char *)vim_strchr((char_u *)tmp,
- fmt_spec == 'e' ? 'e' : 'E');
- if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0'
- && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) {
- STRMOVE(tp + 2, tp + 3);
+ i = (tp[1] == '-') ? 2 : 1;
+ while (tp[i] == '0') {
+ // change "1.0e07" to "1.0e7"
+ STRMOVE(tp + i, tp + i + 1);
str_arg_l--;
}
+ tp--;
}
}
- if (zero_padding && min_field_width > str_arg_l
- && (tmp[0] == '-' || force_sign)) {
- // Padding 0's should be inserted after the sign.
- number_of_zeros_to_pad = min_field_width - str_arg_l;
- zero_padding_insertion_ind = 1;
+
+ if (tp != NULL && !precision_specified) {
+ // remove trailing zeroes, but keep the one just after a dot
+ while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') {
+ STRMOVE(tp, tp + 1);
+ tp--;
+ str_arg_l--;
+ }
+ }
+ } else {
+ // Be consistent: some printf("%e") use 1.0e+12 and some
+ // 1.0e+012; remove one zero in the last case.
+ char *tp = (char *)vim_strchr((char_u *)tmp,
+ fmt_spec == 'e' ? 'e' : 'E');
+ if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0'
+ && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) {
+ STRMOVE(tp + 2, tp + 3);
+ str_arg_l--;
}
- str_arg = tmp;
- break;
}
+ }
+ if (zero_padding && min_field_width > str_arg_l
+ && (tmp[0] == '-' || force_sign)) {
+ // Padding 0's should be inserted after the sign.
+ number_of_zeros_to_pad = min_field_width - str_arg_l;
+ zero_padding_insertion_ind = 1;
+ }
+ str_arg = tmp;
+ break;
+ }
- default:
- // unrecognized conversion specifier, keep format string as-is
- zero_padding = 0; // turn zero padding off for non-numeric conversion
- justify_left = 1;
- min_field_width = 0; // reset flags
-
- // discard the unrecognized conversion, just keep
- // the unrecognized conversion character
- str_arg = p;
- str_arg_l = 0;
- if (*p) {
- str_arg_l++; // include invalid conversion specifier
- }
- // unchanged if not at end-of-string
- break;
+ default:
+ // unrecognized conversion specifier, keep format string as-is
+ zero_padding = 0; // turn zero padding off for non-numeric conversion
+ justify_left = 1;
+ min_field_width = 0; // reset flags
+
+ // discard the unrecognized conversion, just keep
+ // the unrecognized conversion character
+ str_arg = p;
+ str_arg_l = 0;
+ if (*p) {
+ str_arg_l++; // include invalid conversion specifier
+ }
+ // unchanged if not at end-of-string
+ break;
}
if (*p) {