mprintf: switch three number parsers to use strparse

Also add more const char pointers and reduced the scope for some
variables.

Closes #16628
This commit is contained in:
Daniel Stenberg 2025-03-08 22:51:09 +01:00
parent 8dca3b0656
commit f8e7a4df94
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -25,6 +25,7 @@
#include "curl_setup.h" #include "curl_setup.h"
#include "dynbuf.h" #include "dynbuf.h"
#include "curl_printf.h" #include "curl_printf.h"
#include "strparse.h"
#include "curl_memory.h" #include "curl_memory.h"
/* The last #include file should be: */ /* The last #include file should be: */
@ -134,7 +135,7 @@ enum {
struct va_input { struct va_input {
FormatType type; /* FormatType */ FormatType type; /* FormatType */
union { union {
char *str; const char *str;
void *ptr; void *ptr;
mp_intmax_t nums; /* signed */ mp_intmax_t nums; /* signed */
mp_uintmax_t numu; /* unsigned */ mp_uintmax_t numu; /* unsigned */
@ -150,7 +151,7 @@ struct outsegment {
int precision; /* precision OR precision parameter number */ int precision; /* precision OR precision parameter number */
unsigned int flags; unsigned int flags;
unsigned int input; /* input argument array index */ unsigned int input; /* input argument array index */
char *start; /* format string start to output */ const char *start; /* format string start to output */
size_t outlen; /* number of bytes from the format string to output */ size_t outlen; /* number of bytes from the format string to output */
}; };
@ -169,26 +170,19 @@ struct asprintf {
returns -1 if no valid number was provided. returns -1 if no valid number was provided.
*/ */
static int dollarstring(char *input, char **end) static int dollarstring(const char *p, const char **end)
{ {
if(ISDIGIT(*input)) { curl_off_t num;
int number = 0; if(Curl_str_number(&p, &num, MAX_PARAMETERS) ||
do { Curl_str_single(&p, '$') || !num)
if(number < MAX_PARAMETERS) {
number *= 10;
number += *input - '0';
}
input++;
} while(ISDIGIT(*input));
if(number && (number <= MAX_PARAMETERS) && ('$' == *input)) {
*end = ++input;
return number - 1;
}
}
return -1; return -1;
*end = p;
return (int)num - 1;
} }
#define is_arg_used(x,y) ((x)[(y)/8] & (1 << ((y)&7)))
#define mark_arg_used(x,y) ((x)[y/8] |= (unsigned char)(1 << ((y)&7)))
/* /*
* Parse the format string. * Parse the format string.
* *
@ -216,13 +210,8 @@ static int parsefmt(const char *format,
int *opieces, int *opieces,
int *ipieces, va_list arglist) int *ipieces, va_list arglist)
{ {
char *fmt = (char *)format; const char *fmt = format;
int param_num = 0; int param_num = 0;
int param;
int width;
int precision;
unsigned int flags;
FormatType type;
int max_param = -1; int max_param = -1;
int i; int i;
int ocount = 0; int ocount = 0;
@ -230,7 +219,7 @@ static int parsefmt(const char *format,
size_t outlen = 0; size_t outlen = 0;
struct outsegment *optr; struct outsegment *optr;
int use_dollar = DOLLAR_UNKNOWN; int use_dollar = DOLLAR_UNKNOWN;
char *start = fmt; const char *start = fmt;
/* clear, set a bit for each used input */ /* clear, set a bit for each used input */
memset(usedinput, 0, sizeof(usedinput)); memset(usedinput, 0, sizeof(usedinput));
@ -239,6 +228,11 @@ static int parsefmt(const char *format,
if(*fmt == '%') { if(*fmt == '%') {
struct va_input *iptr; struct va_input *iptr;
bool loopit = TRUE; bool loopit = TRUE;
FormatType type;
unsigned int flags = 0;
int width = 0;
int precision = 0;
int param = -1;
fmt++; fmt++;
outlen = (size_t)(fmt - start - 1); outlen = (size_t)(fmt - start - 1);
if(*fmt == '%') { if(*fmt == '%') {
@ -258,9 +252,6 @@ static int parsefmt(const char *format,
continue; /* while */ continue; /* while */
} }
flags = 0;
width = precision = 0;
if(use_dollar != DOLLAR_NOPE) { if(use_dollar != DOLLAR_NOPE) {
param = dollarstring(fmt, &fmt); param = dollarstring(fmt, &fmt);
if(param < 0) { if(param < 0) {
@ -275,8 +266,6 @@ static int parsefmt(const char *format,
else else
use_dollar = DOLLAR_USE; use_dollar = DOLLAR_USE;
} }
else
param = -1;
/* Handle the flags */ /* Handle the flags */
while(loopit) { while(loopit) {
@ -311,20 +300,15 @@ static int parsefmt(const char *format,
precision = -1; precision = -1;
} }
else { else {
bool is_neg = FALSE; bool is_neg;
curl_off_t num;
flags |= FLAGS_PREC; flags |= FLAGS_PREC;
precision = 0; is_neg = ('-' == *fmt);
if('-' == *fmt) { if(is_neg)
is_neg = TRUE;
fmt++; fmt++;
} if(Curl_str_number(&fmt, &num, INT_MAX))
while(ISDIGIT(*fmt)) {
int n = *fmt - '0';
if(precision > (INT_MAX - n) / 10)
return PFMT_PREC; return PFMT_PREC;
precision = precision * 10 + n; precision = (int)num;
fmt++;
}
if(is_neg) if(is_neg)
precision = -precision; precision = -precision;
} }
@ -390,18 +374,15 @@ static int parsefmt(const char *format,
flags |= FLAGS_PAD_NIL; flags |= FLAGS_PAD_NIL;
FALLTHROUGH(); FALLTHROUGH();
case '1': case '2': case '3': case '4': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': case '5': case '6': case '7': case '8': case '9': {
curl_off_t num;
flags |= FLAGS_WIDTH; flags |= FLAGS_WIDTH;
width = 0;
fmt--; fmt--;
do { if(Curl_str_number(&fmt, &num, INT_MAX))
int n = *fmt - '0';
if(width > (INT_MAX - n) / 10)
return PFMT_WIDTH; return PFMT_WIDTH;
width = width * 10 + n; width = (int)num;
fmt++;
} while(ISDIGIT(*fmt));
break; break;
}
case '*': /* read width from argument list */ case '*': /* read width from argument list */
flags |= FLAGS_WIDTHPARAM; flags |= FLAGS_WIDTHPARAM;
if(use_dollar == DOLLAR_USE) { if(use_dollar == DOLLAR_USE) {
@ -511,9 +492,8 @@ static int parsefmt(const char *format,
if(width < 0) if(width < 0)
width = param_num++; width = param_num++;
else { else {
/* if this identifies a parameter already used, this /* if this identifies a parameter already used, this is illegal */
is illegal */ if(is_arg_used(usedinput, width))
if(usedinput[width/8] & (1 << (width&7)))
return PFMT_WIDTHARG; return PFMT_WIDTHARG;
} }
if(width >= MAX_PARAMETERS) if(width >= MAX_PARAMETERS)
@ -523,16 +503,15 @@ static int parsefmt(const char *format,
in[width].type = FORMAT_WIDTH; in[width].type = FORMAT_WIDTH;
/* mark as used */ /* mark as used */
usedinput[width/8] |= (unsigned char)(1 << (width&7)); mark_arg_used(usedinput, width);
} }
if(flags & FLAGS_PRECPARAM) { if(flags & FLAGS_PRECPARAM) {
if(precision < 0) if(precision < 0)
precision = param_num++; precision = param_num++;
else { else {
/* if this identifies a parameter already used, this /* if this identifies a parameter already used, this is illegal */
is illegal */ if(is_arg_used(usedinput, precision))
if(usedinput[precision/8] & (1 << (precision&7)))
return PFMT_PRECARG; return PFMT_PRECARG;
} }
if(precision >= MAX_PARAMETERS) if(precision >= MAX_PARAMETERS)
@ -541,7 +520,7 @@ static int parsefmt(const char *format,
max_param = precision; max_param = precision;
in[precision].type = FORMAT_PRECISION; in[precision].type = FORMAT_PRECISION;
usedinput[precision/8] |= (unsigned char)(1 << (precision&7)); mark_arg_used(usedinput, precision);
} }
/* Handle the specifier */ /* Handle the specifier */
@ -556,7 +535,7 @@ static int parsefmt(const char *format,
iptr->type = type; iptr->type = type;
/* mark this input as used */ /* mark this input as used */
usedinput[param/8] |= (unsigned char)(1 << (param&7)); mark_arg_used(usedinput, param);
fmt++; fmt++;
optr = &out[ocount++]; optr = &out[ocount++];
@ -589,14 +568,14 @@ static int parsefmt(const char *format,
/* Read the arg list parameters into our data list */ /* Read the arg list parameters into our data list */
for(i = 0; i < max_param + 1; i++) { for(i = 0; i < max_param + 1; i++) {
struct va_input *iptr = &in[i]; struct va_input *iptr = &in[i];
if(!(usedinput[i/8] & (1 << (i&7)))) if(!is_arg_used(usedinput, i))
/* bad input */ /* bad input */
return PFMT_INPUTGAP; return PFMT_INPUTGAP;
/* based on the type, read the correct argument */ /* based on the type, read the correct argument */
switch(iptr->type) { switch(iptr->type) {
case FORMAT_STRING: case FORMAT_STRING:
iptr->val.str = va_arg(arglist, char *); iptr->val.str = va_arg(arglist, const char *);
break; break;
case FORMAT_INTPTR: case FORMAT_INTPTR:
@ -704,7 +683,7 @@ static int formatf(
unsigned int flags = optr->flags; unsigned int flags = optr->flags;
if(outlen) { if(outlen) {
char *str = optr->start; const char *str = optr->start;
for(; outlen && *str; outlen--) for(; outlen && *str; outlen--)
OUTCHAR(*str++); OUTCHAR(*str++);
if(optr->flags & FLAGS_SUBSTR) if(optr->flags & FLAGS_SUBSTR)
@ -873,7 +852,7 @@ number:
const char *str; const char *str;
size_t len; size_t len;
str = (char *)iptr->val.str; str = iptr->val.str;
if(!str) { if(!str) {
/* Write null string if there is space. */ /* Write null string if there is space. */
if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) { if(prec == -1 || prec >= (int) sizeof(nilstr) - 1) {