comparison src/strings.c @ 33148:7bc10151ce81 v9.0.1856

patch 9.0.1856: issues with formatting positional arguments Commit: https://github.com/vim/vim/commit/aa90d4f031f73a34aaef5746931ea746849a2231 Author: Christ van Willegen <cvwillegen@gmail.com> Date: Sun Sep 3 17:22:37 2023 +0200 patch 9.0.1856: issues with formatting positional arguments Problem: issues with formatting positional arguments Solution: fix them, add tests and documentation closes: #12140 closes: #12985 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Christ van Willegen <cvwillegen@gmail.com> Tentatively fix message_test. Check NULL ptr.
author Christian Brabandt <cb@256bit.org>
date Sun, 03 Sep 2023 17:30:05 +0200
parents 0bdb1f8a17c1
children 5da7208ea315
comparison
equal deleted inserted replaced
33147:288d4aa3e263 33148:7bc10151ce81
2249 2249
2250 /* Types that can be used in a format string 2250 /* Types that can be used in a format string
2251 */ 2251 */
2252 static int 2252 static int
2253 format_typeof( 2253 format_typeof(
2254 const char *type, 2254 const char *type)
2255 int usetvs UNUSED)
2256 { 2255 {
2257 // allowed values: \0, h, l, L 2256 // allowed values: \0, h, l, L
2258 char length_modifier = '\0'; 2257 char length_modifier = '\0';
2259 2258
2260 // current conversion specifier character 2259 // current conversion specifier character
2283 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; 2282 case 'U': fmt_spec = 'u'; length_modifier = 'l'; break;
2284 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; 2283 case 'O': fmt_spec = 'o'; length_modifier = 'l'; break;
2285 default: break; 2284 default: break;
2286 } 2285 }
2287 2286
2288 # if defined(FEAT_EVAL)
2289 if (usetvs)
2290 {
2291 switch (fmt_spec)
2292 {
2293 case 'd': case 'u': case 'o': case 'x': case 'X':
2294 if (length_modifier == '\0')
2295 length_modifier = 'L';
2296 }
2297 }
2298 # endif
2299
2300 // get parameter value, do initial processing 2287 // get parameter value, do initial processing
2301 switch (fmt_spec) 2288 switch (fmt_spec)
2302 { 2289 {
2303 // '%' and 'c' behave similar to 's' regarding flags and field 2290 // '%' and 'c' behave similar to 's' regarding flags and field
2304 // widths 2291 // widths
2328 // argument is never negative) 2315 // argument is never negative)
2329 2316
2330 if (fmt_spec == 'p') 2317 if (fmt_spec == 'p')
2331 return TYPE_POINTER; 2318 return TYPE_POINTER;
2332 else if (fmt_spec == 'b' || fmt_spec == 'B') 2319 else if (fmt_spec == 'b' || fmt_spec == 'B')
2333 return TYPE_UNSIGNEDINT; 2320 return TYPE_UNSIGNEDLONGLONGINT;
2334 else if (fmt_spec == 'd') 2321 else if (fmt_spec == 'd')
2335 { 2322 {
2336 // signed 2323 // signed
2337 switch (length_modifier) 2324 switch (length_modifier)
2338 { 2325 {
2377 2364
2378 static char * 2365 static char *
2379 format_typename( 2366 format_typename(
2380 const char *type) 2367 const char *type)
2381 { 2368 {
2382 switch (format_typeof(type, FALSE)) 2369 switch (format_typeof(type))
2383 { 2370 {
2384 case TYPE_INT: 2371 case TYPE_INT:
2385 return _(typename_int); 2372 return _(typename_int);
2386 2373
2387 case TYPE_LONGINT: 2374 case TYPE_LONGINT:
2465 } 2452 }
2466 } 2453 }
2467 } 2454 }
2468 else 2455 else
2469 { 2456 {
2470 if (format_typeof(type, FALSE) != format_typeof((*ap_types)[arg - 1], FALSE)) 2457 if (format_typeof(type) != format_typeof((*ap_types)[arg - 1]))
2471 { 2458 {
2472 semsg(_( e_positional_arg_num_type_inconsistent_str_str), arg, format_typename(type), format_typename((*ap_types)[arg - 1])); 2459 semsg(_( e_positional_arg_num_type_inconsistent_str_str), arg, format_typename(type), format_typename((*ap_types)[arg - 1]));
2473 return FAIL; 2460 return FAIL;
2474 } 2461 }
2475 } 2462 }
2782 skip_to_arg( 2769 skip_to_arg(
2783 const char **ap_types, 2770 const char **ap_types,
2784 va_list ap_start, 2771 va_list ap_start,
2785 va_list *ap, 2772 va_list *ap,
2786 int *arg_idx, 2773 int *arg_idx,
2787 int *arg_cur) 2774 int *arg_cur,
2775 const char *fmt)
2788 { 2776 {
2789 int arg_min = 0; 2777 int arg_min = 0;
2790 2778
2791 if (*arg_cur + 1 == *arg_idx) 2779 if (*arg_cur + 1 == *arg_idx)
2792 { 2780 {
2807 arg_min = *arg_cur; 2795 arg_min = *arg_cur;
2808 } 2796 }
2809 2797
2810 for (*arg_cur = arg_min; *arg_cur < *arg_idx - 1; ++*arg_cur) 2798 for (*arg_cur = arg_min; *arg_cur < *arg_idx - 1; ++*arg_cur)
2811 { 2799 {
2812 const char *p = ap_types[*arg_cur]; 2800 const char *p;
2813 2801
2814 int fmt_type = format_typeof(p, TRUE); 2802 if (ap_types == NULL || ap_types[*arg_cur] == NULL)
2803 {
2804 semsg(e_aptypes_is_null_str_nr, fmt, *arg_cur);
2805 return;
2806 }
2807
2808 p = ap_types[*arg_cur];
2809
2810 int fmt_type = format_typeof(p);
2815 2811
2816 // get parameter value, do initial processing 2812 // get parameter value, do initial processing
2817 switch (fmt_type) 2813 switch (fmt_type)
2818 { 2814 {
2819 case TYPE_PERCENT: 2815 case TYPE_PERCENT:
3022 3018
3023 j = 3019 j =
3024 # if defined(FEAT_EVAL) 3020 # if defined(FEAT_EVAL)
3025 tvs != NULL ? tv_nr(tvs, &arg_idx) : 3021 tvs != NULL ? tv_nr(tvs, &arg_idx) :
3026 # endif 3022 # endif
3027 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3023 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3024 &arg_cur, fmt),
3028 va_arg(ap, int)); 3025 va_arg(ap, int));
3029 3026
3030 if (j >= 0) 3027 if (j >= 0)
3031 min_field_width = j; 3028 min_field_width = j;
3032 else 3029 else
3082 3079
3083 j = 3080 j =
3084 # if defined(FEAT_EVAL) 3081 # if defined(FEAT_EVAL)
3085 tvs != NULL ? tv_nr(tvs, &arg_idx) : 3082 tvs != NULL ? tv_nr(tvs, &arg_idx) :
3086 # endif 3083 # endif
3087 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3084 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3085 &arg_cur, fmt),
3088 va_arg(ap, int)); 3086 va_arg(ap, int));
3089 3087
3090 if (j >= 0) 3088 if (j >= 0)
3091 precision = j; 3089 precision = j;
3092 else 3090 else
3155 3153
3156 j = 3154 j =
3157 # if defined(FEAT_EVAL) 3155 # if defined(FEAT_EVAL)
3158 tvs != NULL ? tv_nr(tvs, &arg_idx) : 3156 tvs != NULL ? tv_nr(tvs, &arg_idx) :
3159 # endif 3157 # endif
3160 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3158 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3159 &arg_cur, fmt),
3161 va_arg(ap, int)); 3160 va_arg(ap, int));
3162 3161
3163 // standard demands unsigned char 3162 // standard demands unsigned char
3164 uchar_arg = (unsigned char)j; 3163 uchar_arg = (unsigned char)j;
3165 str_arg = (char *)&uchar_arg; 3164 str_arg = (char *)&uchar_arg;
3170 case 'S': 3169 case 'S':
3171 str_arg = 3170 str_arg =
3172 # if defined(FEAT_EVAL) 3171 # if defined(FEAT_EVAL)
3173 tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) : 3172 tvs != NULL ? tv_str(tvs, &arg_idx, &tofree) :
3174 # endif 3173 # endif
3175 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3174 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3175 &arg_cur, fmt),
3176 va_arg(ap, char *)); 3176 va_arg(ap, char *));
3177 3177
3178 if (str_arg == NULL) 3178 if (str_arg == NULL)
3179 { 3179 {
3180 str_arg = "[NULL]"; 3180 str_arg = "[NULL]";
3267 ptr_arg = 3267 ptr_arg =
3268 # if defined(FEAT_EVAL) 3268 # if defined(FEAT_EVAL)
3269 tvs != NULL ? (void *)tv_str(tvs, &arg_idx, 3269 tvs != NULL ? (void *)tv_str(tvs, &arg_idx,
3270 NULL) : 3270 NULL) :
3271 # endif 3271 # endif
3272 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3272 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3273 &arg_cur, fmt),
3273 va_arg(ap, void *)); 3274 va_arg(ap, void *));
3274 3275
3275 if (ptr_arg != NULL) 3276 if (ptr_arg != NULL)
3276 arg_sign = 1; 3277 arg_sign = 1;
3277 } 3278 }
3280 bin_arg = 3281 bin_arg =
3281 # if defined(FEAT_EVAL) 3282 # if defined(FEAT_EVAL)
3282 tvs != NULL ? 3283 tvs != NULL ?
3283 (uvarnumber_T)tv_nr(tvs, &arg_idx) : 3284 (uvarnumber_T)tv_nr(tvs, &arg_idx) :
3284 # endif 3285 # endif
3285 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3286 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3287 &arg_cur, fmt),
3286 va_arg(ap, uvarnumber_T)); 3288 va_arg(ap, uvarnumber_T));
3287 3289
3288 if (bin_arg != 0) 3290 if (bin_arg != 0)
3289 arg_sign = 1; 3291 arg_sign = 1;
3290 } 3292 }
3298 // char and short arguments are passed as int. 3300 // char and short arguments are passed as int.
3299 int_arg = 3301 int_arg =
3300 # if defined(FEAT_EVAL) 3302 # if defined(FEAT_EVAL)
3301 tvs != NULL ? tv_nr(tvs, &arg_idx) : 3303 tvs != NULL ? tv_nr(tvs, &arg_idx) :
3302 # endif 3304 # endif
3303 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3305 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3306 &arg_cur, fmt),
3304 va_arg(ap, int)); 3307 va_arg(ap, int));
3305 3308
3306 if (int_arg > 0) 3309 if (int_arg > 0)
3307 arg_sign = 1; 3310 arg_sign = 1;
3308 else if (int_arg < 0) 3311 else if (int_arg < 0)
3311 case 'l': 3314 case 'l':
3312 long_arg = 3315 long_arg =
3313 # if defined(FEAT_EVAL) 3316 # if defined(FEAT_EVAL)
3314 tvs != NULL ? tv_nr(tvs, &arg_idx) : 3317 tvs != NULL ? tv_nr(tvs, &arg_idx) :
3315 # endif 3318 # endif
3316 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3319 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3320 &arg_cur, fmt),
3317 va_arg(ap, long int)); 3321 va_arg(ap, long int));
3318 3322
3319 if (long_arg > 0) 3323 if (long_arg > 0)
3320 arg_sign = 1; 3324 arg_sign = 1;
3321 else if (long_arg < 0) 3325 else if (long_arg < 0)
3324 case 'L': 3328 case 'L':
3325 llong_arg = 3329 llong_arg =
3326 # if defined(FEAT_EVAL) 3330 # if defined(FEAT_EVAL)
3327 tvs != NULL ? tv_nr(tvs, &arg_idx) : 3331 tvs != NULL ? tv_nr(tvs, &arg_idx) :
3328 # endif 3332 # endif
3329 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3333 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3334 &arg_cur, fmt),
3330 va_arg(ap, varnumber_T)); 3335 va_arg(ap, varnumber_T));
3331 3336
3332 if (llong_arg > 0) 3337 if (llong_arg > 0)
3333 arg_sign = 1; 3338 arg_sign = 1;
3334 else if (llong_arg < 0) 3339 else if (llong_arg < 0)
3346 uint_arg = 3351 uint_arg =
3347 # if defined(FEAT_EVAL) 3352 # if defined(FEAT_EVAL)
3348 tvs != NULL ? (unsigned) 3353 tvs != NULL ? (unsigned)
3349 tv_nr(tvs, &arg_idx) : 3354 tv_nr(tvs, &arg_idx) :
3350 # endif 3355 # endif
3351 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3356 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3357 &arg_cur, fmt),
3352 va_arg(ap, unsigned int)); 3358 va_arg(ap, unsigned int));
3353 3359
3354 if (uint_arg != 0) 3360 if (uint_arg != 0)
3355 arg_sign = 1; 3361 arg_sign = 1;
3356 break; 3362 break;
3358 ulong_arg = 3364 ulong_arg =
3359 # if defined(FEAT_EVAL) 3365 # if defined(FEAT_EVAL)
3360 tvs != NULL ? (unsigned long) 3366 tvs != NULL ? (unsigned long)
3361 tv_nr(tvs, &arg_idx) : 3367 tv_nr(tvs, &arg_idx) :
3362 # endif 3368 # endif
3363 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3369 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3370 &arg_cur, fmt),
3364 va_arg(ap, unsigned long int)); 3371 va_arg(ap, unsigned long int));
3365 3372
3366 if (ulong_arg != 0) 3373 if (ulong_arg != 0)
3367 arg_sign = 1; 3374 arg_sign = 1;
3368 break; 3375 break;
3370 ullong_arg = 3377 ullong_arg =
3371 # if defined(FEAT_EVAL) 3378 # if defined(FEAT_EVAL)
3372 tvs != NULL ? (uvarnumber_T) 3379 tvs != NULL ? (uvarnumber_T)
3373 tv_nr(tvs, &arg_idx) : 3380 tv_nr(tvs, &arg_idx) :
3374 # endif 3381 # endif
3375 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3382 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3383 &arg_cur, fmt),
3376 va_arg(ap, uvarnumber_T)); 3384 va_arg(ap, uvarnumber_T));
3377 3385
3378 if (ullong_arg != 0) 3386 if (ullong_arg != 0)
3379 arg_sign = 1; 3387 arg_sign = 1;
3380 break; 3388 break;
3572 3580
3573 f = 3581 f =
3574 # if defined(FEAT_EVAL) 3582 # if defined(FEAT_EVAL)
3575 tvs != NULL ? tv_float(tvs, &arg_idx) : 3583 tvs != NULL ? tv_float(tvs, &arg_idx) :
3576 # endif 3584 # endif
3577 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx, &arg_cur), 3585 (skip_to_arg(ap_types, ap_start, &ap, &arg_idx,
3586 &arg_cur, fmt),
3578 va_arg(ap, double)); 3587 va_arg(ap, double));
3579 3588
3580 abs_f = f < 0 ? -f : f; 3589 abs_f = f < 0 ? -f : f;
3581 3590
3582 if (fmt_spec == 'g' || fmt_spec == 'G') 3591 if (fmt_spec == 'g' || fmt_spec == 'G')