mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00: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:
		
							
								
								
									
										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)) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 zeertzjq
					zeertzjq