diff options
-rw-r--r-- | runtime/doc/builtin.txt | 9 | ||||
-rw-r--r-- | runtime/lua/vim/_meta/vimfn.lua | 9 | ||||
-rw-r--r-- | src/nvim/eval.lua | 9 | ||||
-rw-r--r-- | src/nvim/strings.c | 123 | ||||
-rw-r--r-- | test/unit/strings_spec.lua | 1 |
5 files changed, 88 insertions, 63 deletions
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt index 9510f12045..400cd27302 100644 --- a/runtime/doc/builtin.txt +++ b/runtime/doc/builtin.txt @@ -5132,8 +5132,13 @@ printf({fmt}, {expr1} ...) *printf()* than the field width, the field is expanded to contain the conversion result. The 'h' modifier indicates the argument is 16 bits. - The 'l' modifier indicates the argument is 32 bits. - The 'L' modifier indicates the argument is 64 bits. + The 'l' modifier indicates the argument is a long + integer. The size will be 32 bits or 64 bits + depending on your platform. + The "ll" modifier indicates the argument is 64 bits. + The b and B conversion specifiers never take a width + modifier and always assume their argument is a 64 bit + integer. Generally, these modifiers are not useful. They are ignored when type is known from the argument. diff --git a/runtime/lua/vim/_meta/vimfn.lua b/runtime/lua/vim/_meta/vimfn.lua index 3f891bdb45..6209ce0c73 100644 --- a/runtime/lua/vim/_meta/vimfn.lua +++ b/runtime/lua/vim/_meta/vimfn.lua @@ -6115,8 +6115,13 @@ function vim.fn.prevnonblank(lnum) end --- than the field width, the field is expanded to contain --- the conversion result. --- The 'h' modifier indicates the argument is 16 bits. ---- The 'l' modifier indicates the argument is 32 bits. ---- The 'L' modifier indicates the argument is 64 bits. +--- The 'l' modifier indicates the argument is a long +--- integer. The size will be 32 bits or 64 bits +--- depending on your platform. +--- The "ll" modifier indicates the argument is 64 bits. +--- The b and B conversion specifiers never take a width +--- modifier and always assume their argument is a 64 bit +--- integer. --- Generally, these modifiers are not useful. They are --- ignored when type is known from the argument. --- diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index f8d57eb6de..a9200d1f5f 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -7393,8 +7393,13 @@ M.funcs = { than the field width, the field is expanded to contain the conversion result. The 'h' modifier indicates the argument is 16 bits. - The 'l' modifier indicates the argument is 32 bits. - The 'L' modifier indicates the argument is 64 bits. + The 'l' modifier indicates the argument is a long + integer. The size will be 32 bits or 64 bits + depending on your platform. + The "ll" modifier indicates the argument is 64 bits. + The b and B conversion specifiers never take a width + modifier and always assume their argument is a 64 bit + integer. Generally, these modifiers are not useful. They are ignored when type is known from the argument. diff --git a/src/nvim/strings.c b/src/nvim/strings.c index ec770de4a0..b66dff3c18 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -32,33 +32,35 @@ #include "nvim/types.h" #include "nvim/vim.h" -static char e_cannot_mix_positional_and_non_positional_str[] +static const char e_cannot_mix_positional_and_non_positional_str[] = N_("E1400: Cannot mix positional and non-positional arguments: %s"); -static char e_fmt_arg_nr_unused_str[] +static const char e_fmt_arg_nr_unused_str[] = N_("E1401: format argument %d unused in $-style format: %s"); -static char e_positional_num_field_spec_reused_str_str[] +static const char e_positional_num_field_spec_reused_str_str[] = N_("E1402: Positional argument %d used as field width reused as different type: %s/%s"); -static char e_positional_nr_out_of_bounds_str[] +static const char e_positional_nr_out_of_bounds_str[] = N_("E1403: Positional argument %d out of bounds: %s"); -static char e_positional_arg_num_type_inconsistent_str_str[] +static const char e_positional_arg_num_type_inconsistent_str_str[] = N_("E1404: Positional argument %d type used inconsistently: %s/%s"); -static char e_invalid_format_specifier_str[] +static const char e_invalid_format_specifier_str[] = N_("E1405: Invalid format specifier: %s"); - -static char typename_unknown[] = N_("unknown"); -static char typename_int[] = N_("int"); -static char typename_longint[] = N_("long int"); -static char typename_longlongint[] = N_("long long int"); -static char typename_signedsizet[] = N_("signed size_t"); -static char typename_unsignedint[] = N_("unsigned int"); -static char typename_unsignedlongint[] = N_("unsigned long int"); -static char typename_unsignedlonglongint[] = N_("unsigned long long int"); -static char typename_sizet[] = N_("size_t"); -static char typename_pointer[] = N_("pointer"); -static char typename_percent[] = N_("percent"); -static char typename_char[] = N_("char"); -static char typename_string[] = N_("string"); -static char typename_float[] = N_("float"); +static const char e_aptypes_is_null_str_nr[] + = "E1408: Internal error: ap_types or ap_types[idx] is NULL: %s: %d"; + +static const char typename_unknown[] = N_("unknown"); +static const char typename_int[] = N_("int"); +static const char typename_longint[] = N_("long int"); +static const char typename_longlongint[] = N_("long long int"); +static const char typename_signedsizet[] = N_("signed size_t"); +static const char typename_unsignedint[] = N_("unsigned int"); +static const char typename_unsignedlongint[] = N_("unsigned long int"); +static const char typename_unsignedlonglongint[] = N_("unsigned long long int"); +static const char typename_sizet[] = N_("size_t"); +static const char typename_pointer[] = N_("pointer"); +static const char typename_percent[] = N_("percent"); +static const char typename_char[] = N_("char"); +static const char typename_string[] = N_("string"); +static const char typename_float[] = N_("float"); /// Copy up to `len` bytes of `string` into newly allocated memory and /// terminate with a NUL. The allocated memory always has size `len + 1`, even @@ -763,7 +765,7 @@ enum { }; /// Types that can be used in a format string -static int format_typeof(const char *type, bool usetvs) +static int format_typeof(const char *type) FUNC_ATTR_NONNULL_ALL { // allowed values: \0, h, l, L @@ -800,19 +802,6 @@ static int format_typeof(const char *type, bool usetvs) break; } - if (usetvs) { - switch (fmt_spec) { - case 'd': - case 'u': - case 'o': - case 'x': - case 'X': - if (length_modifier == '\0') { - length_modifier = 'L'; - } - } - } - // get parameter value, do initial processing switch (fmt_spec) { // '%' and 'c' behave similar to 's' regarding flags and field @@ -847,7 +836,7 @@ static int format_typeof(const char *type, bool usetvs) if (fmt_spec == 'p') { return TYPE_POINTER; } else if (fmt_spec == 'b' || fmt_spec == 'B') { - return TYPE_UNSIGNEDINT; + return TYPE_UNSIGNEDLONGLONGINT; } else if (fmt_spec == 'd') { // signed switch (length_modifier) { @@ -893,7 +882,7 @@ static int format_typeof(const char *type, bool usetvs) static char *format_typename(const char *type) FUNC_ATTR_NONNULL_ALL { - switch (format_typeof(type, false)) { + switch (format_typeof(type)) { case TYPE_INT: return _(typename_int); case TYPE_LONGINT: @@ -960,7 +949,7 @@ static int adjust_types(const char ***ap_types, int arg, int *num_posarg, const } } } else { - if (format_typeof(type, false) != format_typeof((*ap_types)[arg - 1], false)) { + if (format_typeof(type) != format_typeof((*ap_types)[arg - 1])) { semsg(_(e_positional_arg_num_type_inconsistent_str_str), arg, format_typename(type), format_typename((*ap_types)[arg - 1])); return FAIL; @@ -1239,7 +1228,7 @@ error: } static void skip_to_arg(const char **ap_types, va_list ap_start, va_list *ap, int *arg_idx, - int *arg_cur) + int *arg_cur, const char *fmt) FUNC_ATTR_NONNULL_ARG(3, 4, 5) { int arg_min = 0; @@ -1260,10 +1249,14 @@ static void skip_to_arg(const char **ap_types, va_list ap_start, va_list *ap, in } for (*arg_cur = arg_min; *arg_cur < *arg_idx - 1; (*arg_cur)++) { - assert(ap_types != NULL); + if (ap_types == NULL || ap_types[*arg_cur] == NULL) { + semsg(e_aptypes_is_null_str_nr, fmt, *arg_cur); + return; + } + const char *p = ap_types[*arg_cur]; - int fmt_type = format_typeof(p, true); + int fmt_type = format_typeof(p); // get parameter value, do initial processing switch (fmt_type) { @@ -1477,7 +1470,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st const int j = (tvs ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, int))); if (j >= 0) { @@ -1528,7 +1522,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st const int j = (tvs ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, int))); if (j >= 0) { @@ -1600,7 +1595,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case 'c': { const int j = (tvs ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, int))); // standard demands unsigned char @@ -1613,7 +1609,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case 'S': str_arg = (tvs ? tv_str(tvs, &arg_idx, &tofree) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, const char *))); if (!str_arg) { @@ -1684,7 +1681,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (fmt_spec == 'p') { ptr_arg = (tvs ? tv_ptr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, void *))); if (ptr_arg) { @@ -1696,7 +1694,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case '\0': arg = (tvs ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, int))); break; case 'h': @@ -1704,25 +1703,29 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st arg = (int16_t) (tvs ? (int)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, int))); break; case 'l': arg = (tvs ? (long)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, long))); break; case 'L': arg = (tvs ? (long long)tv_nr(tvs, &arg_idx) // NOLINT(runtime/int) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, long long))); // NOLINT(runtime/int) break; case 'z': // implementation-defined, usually ptrdiff_t arg = (tvs ? (ptrdiff_t)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, ptrdiff_t))); break; } @@ -1737,32 +1740,37 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st case '\0': uarg = (tvs ? (unsigned)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, unsigned))); break; case 'h': uarg = (uint16_t) (tvs ? (unsigned)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, unsigned))); break; case 'l': uarg = (tvs ? (unsigned long)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, unsigned long))); break; case 'L': uarg = (tvs ? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT(runtime/int) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, unsigned long long))); // NOLINT(runtime/int) break; case 'z': uarg = (tvs ? (size_t)tv_nr(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, size_t))); break; } @@ -1900,7 +1908,8 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st double f = (tvs ? tv_float(tvs, &arg_idx) - : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), + : (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, + &arg_cur, fmt), va_arg(ap, double))); double abs_f = f < 0 ? -f : f; diff --git a/test/unit/strings_spec.lua b/test/unit/strings_spec.lua index 04d11d8f04..6d7aceb4b2 100644 --- a/test/unit/strings_spec.lua +++ b/test/unit/strings_spec.lua @@ -208,6 +208,7 @@ describe('vim_snprintf()', function() a('three one two', buf, bsize, '%3$s %1$s %2$s', 'one', 'two', 'three') a('1234567', buf, bsize, '%1$d', i(1234567)) a('deadbeef', buf, bsize, '%1$x', u(0xdeadbeef)) + a('001100', buf, bsize, '%2$0*1$b', i(6), u(12)) a('001100', buf, bsize, '%1$0.*2$b', u(12), i(6)) a('one two', buf, bsize, '%1$s %2$s', 'one', 'two') a('001100', buf, bsize, '%06b', u(12)) |