mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
vim-patch:9.0.1856: issues with formatting positional arguments (#25013)
Problem: issues with formatting positional arguments
Solution: fix them, add tests and documentation
closes: vim/vim#12140
closes: vim/vim#12985
Tentatively fix message_test. Check NULL ptr.
aa90d4f031
Co-authored-by: Christ van Willegen <cvwillegen@gmail.com>
This commit is contained in:
parent
c50951a4d0
commit
c431d820e7
9
runtime/doc/builtin.txt
generated
9
runtime/doc/builtin.txt
generated
@ -5132,8 +5132,13 @@ printf({fmt}, {expr1} ...) *printf()*
|
|||||||
than the field width, the field is expanded to contain
|
than the field width, the field is expanded to contain
|
||||||
the conversion result.
|
the conversion result.
|
||||||
The 'h' modifier indicates the argument is 16 bits.
|
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 a long
|
||||||
The 'L' modifier indicates the argument is 64 bits.
|
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
|
Generally, these modifiers are not useful. They are
|
||||||
ignored when type is known from the argument.
|
ignored when type is known from the argument.
|
||||||
|
|
||||||
|
9
runtime/lua/vim/_meta/vimfn.lua
generated
9
runtime/lua/vim/_meta/vimfn.lua
generated
@ -6115,8 +6115,13 @@ function vim.fn.prevnonblank(lnum) end
|
|||||||
--- than the field width, the field is expanded to contain
|
--- than the field width, the field is expanded to contain
|
||||||
--- the conversion result.
|
--- the conversion result.
|
||||||
--- The 'h' modifier indicates the argument is 16 bits.
|
--- 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 a long
|
||||||
--- The 'L' modifier indicates the argument is 64 bits.
|
--- 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
|
--- Generally, these modifiers are not useful. They are
|
||||||
--- ignored when type is known from the argument.
|
--- ignored when type is known from the argument.
|
||||||
---
|
---
|
||||||
|
@ -7393,8 +7393,13 @@ M.funcs = {
|
|||||||
than the field width, the field is expanded to contain
|
than the field width, the field is expanded to contain
|
||||||
the conversion result.
|
the conversion result.
|
||||||
The 'h' modifier indicates the argument is 16 bits.
|
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 a long
|
||||||
The 'L' modifier indicates the argument is 64 bits.
|
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
|
Generally, these modifiers are not useful. They are
|
||||||
ignored when type is known from the argument.
|
ignored when type is known from the argument.
|
||||||
|
|
||||||
|
@ -32,33 +32,35 @@
|
|||||||
#include "nvim/types.h"
|
#include "nvim/types.h"
|
||||||
#include "nvim/vim.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");
|
= 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");
|
= 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");
|
= 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");
|
= 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");
|
= 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");
|
= N_("E1405: Invalid format specifier: %s");
|
||||||
|
static const char e_aptypes_is_null_str_nr[]
|
||||||
|
= "E1408: Internal error: ap_types or ap_types[idx] is NULL: %s: %d";
|
||||||
|
|
||||||
static char typename_unknown[] = N_("unknown");
|
static const char typename_unknown[] = N_("unknown");
|
||||||
static char typename_int[] = N_("int");
|
static const char typename_int[] = N_("int");
|
||||||
static char typename_longint[] = N_("long int");
|
static const char typename_longint[] = N_("long int");
|
||||||
static char typename_longlongint[] = N_("long long int");
|
static const char typename_longlongint[] = N_("long long int");
|
||||||
static char typename_signedsizet[] = N_("signed size_t");
|
static const char typename_signedsizet[] = N_("signed size_t");
|
||||||
static char typename_unsignedint[] = N_("unsigned int");
|
static const char typename_unsignedint[] = N_("unsigned int");
|
||||||
static char typename_unsignedlongint[] = N_("unsigned long int");
|
static const char typename_unsignedlongint[] = N_("unsigned long int");
|
||||||
static char typename_unsignedlonglongint[] = N_("unsigned long long int");
|
static const char typename_unsignedlonglongint[] = N_("unsigned long long int");
|
||||||
static char typename_sizet[] = N_("size_t");
|
static const char typename_sizet[] = N_("size_t");
|
||||||
static char typename_pointer[] = N_("pointer");
|
static const char typename_pointer[] = N_("pointer");
|
||||||
static char typename_percent[] = N_("percent");
|
static const char typename_percent[] = N_("percent");
|
||||||
static char typename_char[] = N_("char");
|
static const char typename_char[] = N_("char");
|
||||||
static char typename_string[] = N_("string");
|
static const char typename_string[] = N_("string");
|
||||||
static char typename_float[] = N_("float");
|
static const char typename_float[] = N_("float");
|
||||||
|
|
||||||
/// Copy up to `len` bytes of `string` into newly allocated memory and
|
/// 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
|
/// 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
|
/// 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
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
// allowed values: \0, h, l, L
|
// allowed values: \0, h, l, L
|
||||||
@ -800,19 +802,6 @@ static int format_typeof(const char *type, bool usetvs)
|
|||||||
break;
|
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
|
// get parameter value, do initial processing
|
||||||
switch (fmt_spec) {
|
switch (fmt_spec) {
|
||||||
// '%' and 'c' behave similar to 's' regarding flags and field
|
// '%' 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') {
|
if (fmt_spec == 'p') {
|
||||||
return TYPE_POINTER;
|
return TYPE_POINTER;
|
||||||
} else if (fmt_spec == 'b' || fmt_spec == 'B') {
|
} else if (fmt_spec == 'b' || fmt_spec == 'B') {
|
||||||
return TYPE_UNSIGNEDINT;
|
return TYPE_UNSIGNEDLONGLONGINT;
|
||||||
} else if (fmt_spec == 'd') {
|
} else if (fmt_spec == 'd') {
|
||||||
// signed
|
// signed
|
||||||
switch (length_modifier) {
|
switch (length_modifier) {
|
||||||
@ -893,7 +882,7 @@ static int format_typeof(const char *type, bool usetvs)
|
|||||||
static char *format_typename(const char *type)
|
static char *format_typename(const char *type)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
switch (format_typeof(type, false)) {
|
switch (format_typeof(type)) {
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
return _(typename_int);
|
return _(typename_int);
|
||||||
case TYPE_LONGINT:
|
case TYPE_LONGINT:
|
||||||
@ -960,7 +949,7 @@ static int adjust_types(const char ***ap_types, int arg, int *num_posarg, const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} 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,
|
semsg(_(e_positional_arg_num_type_inconsistent_str_str), arg,
|
||||||
format_typename(type), format_typename((*ap_types)[arg - 1]));
|
format_typename(type), format_typename((*ap_types)[arg - 1]));
|
||||||
return FAIL;
|
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,
|
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)
|
FUNC_ATTR_NONNULL_ARG(3, 4, 5)
|
||||||
{
|
{
|
||||||
int arg_min = 0;
|
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)++) {
|
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];
|
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
|
// get parameter value, do initial processing
|
||||||
switch (fmt_type) {
|
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
|
const int j = (tvs
|
||||||
? (int)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, int)));
|
||||||
|
|
||||||
if (j >= 0) {
|
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
|
const int j = (tvs
|
||||||
? (int)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, int)));
|
||||||
|
|
||||||
if (j >= 0) {
|
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': {
|
case 'c': {
|
||||||
const int j = (tvs
|
const int j = (tvs
|
||||||
? (int)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, int)));
|
||||||
|
|
||||||
// standard demands unsigned char
|
// 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':
|
case 'S':
|
||||||
str_arg = (tvs
|
str_arg = (tvs
|
||||||
? tv_str(tvs, &arg_idx, &tofree)
|
? 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 *)));
|
va_arg(ap, const char *)));
|
||||||
|
|
||||||
if (!str_arg) {
|
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') {
|
if (fmt_spec == 'p') {
|
||||||
ptr_arg = (tvs
|
ptr_arg = (tvs
|
||||||
? tv_ptr(tvs, &arg_idx)
|
? 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 *)));
|
va_arg(ap, void *)));
|
||||||
|
|
||||||
if (ptr_arg) {
|
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':
|
case '\0':
|
||||||
arg = (tvs
|
arg = (tvs
|
||||||
? (int)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, int)));
|
||||||
break;
|
break;
|
||||||
case 'h':
|
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)
|
arg = (int16_t)
|
||||||
(tvs
|
(tvs
|
||||||
? (int)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, int)));
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
arg = (tvs
|
arg = (tvs
|
||||||
? (long)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, long)));
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
arg = (tvs
|
arg = (tvs
|
||||||
? (long long)tv_nr(tvs, &arg_idx) // NOLINT(runtime/int)
|
? (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)
|
va_arg(ap, long long))); // NOLINT(runtime/int)
|
||||||
break;
|
break;
|
||||||
case 'z': // implementation-defined, usually ptrdiff_t
|
case 'z': // implementation-defined, usually ptrdiff_t
|
||||||
arg = (tvs
|
arg = (tvs
|
||||||
? (ptrdiff_t)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, ptrdiff_t)));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1737,32 +1740,37 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st
|
|||||||
case '\0':
|
case '\0':
|
||||||
uarg = (tvs
|
uarg = (tvs
|
||||||
? (unsigned)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, unsigned)));
|
||||||
break;
|
break;
|
||||||
case 'h':
|
case 'h':
|
||||||
uarg = (uint16_t)
|
uarg = (uint16_t)
|
||||||
(tvs
|
(tvs
|
||||||
? (unsigned)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, unsigned)));
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
uarg = (tvs
|
uarg = (tvs
|
||||||
? (unsigned long)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, unsigned long)));
|
||||||
break;
|
break;
|
||||||
case 'L':
|
case 'L':
|
||||||
uarg = (tvs
|
uarg = (tvs
|
||||||
? (unsigned long long)tv_nr(tvs, &arg_idx) // NOLINT(runtime/int)
|
? (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)
|
va_arg(ap, unsigned long long))); // NOLINT(runtime/int)
|
||||||
break;
|
break;
|
||||||
case 'z':
|
case 'z':
|
||||||
uarg = (tvs
|
uarg = (tvs
|
||||||
? (size_t)tv_nr(tvs, &arg_idx)
|
? (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)));
|
va_arg(ap, size_t)));
|
||||||
break;
|
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
|
double f = (tvs
|
||||||
? tv_float(tvs, &arg_idx)
|
? 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)));
|
va_arg(ap, double)));
|
||||||
|
|
||||||
double abs_f = f < 0 ? -f : f;
|
double abs_f = f < 0 ? -f : f;
|
||||||
|
@ -208,6 +208,7 @@ describe('vim_snprintf()', function()
|
|||||||
a('three one two', buf, bsize, '%3$s %1$s %2$s', 'one', 'two', 'three')
|
a('three one two', buf, bsize, '%3$s %1$s %2$s', 'one', 'two', 'three')
|
||||||
a('1234567', buf, bsize, '%1$d', i(1234567))
|
a('1234567', buf, bsize, '%1$d', i(1234567))
|
||||||
a('deadbeef', buf, bsize, '%1$x', u(0xdeadbeef))
|
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('001100', buf, bsize, '%1$0.*2$b', u(12), i(6))
|
||||||
a('one two', buf, bsize, '%1$s %2$s', 'one', 'two')
|
a('one two', buf, bsize, '%1$s %2$s', 'one', 'two')
|
||||||
a('001100', buf, bsize, '%06b', u(12))
|
a('001100', buf, bsize, '%06b', u(12))
|
||||||
|
Loading…
Reference in New Issue
Block a user