Mercurial > vim
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') |