mirror of
https://github.com/curl/curl.git
synced 2026-04-25 04:22:16 +03:00
mprintf: simplify parsefmt
- split out parse_flags() and parse_conversion() to reduce complexity from 57 to 30. Closes #21391
This commit is contained in:
parent
0838297ad1
commit
4e0bfd8cf7
1 changed files with 260 additions and 226 deletions
486
lib/mprintf.c
486
lib/mprintf.c
|
|
@ -169,6 +169,261 @@ static int dollarstring(const char *p, const char **end)
|
|||
#define PFMT_PRECARG 10 /* attempted to use same arg twice, for prec */
|
||||
#define PFMT_MANYSEGS 11 /* maxed out output segments */
|
||||
|
||||
static int parse_flags(const char **fmtp, unsigned int *flagsp, int use_dollar,
|
||||
int *precp, int *widthp)
|
||||
{
|
||||
const char *fmt = *fmtp;
|
||||
bool loopit = TRUE;
|
||||
unsigned int flags = 0;
|
||||
int width = 0;
|
||||
int precision = 0;
|
||||
|
||||
/* Handle the flags */
|
||||
do {
|
||||
switch(*fmt++) {
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
break;
|
||||
case '+':
|
||||
flags |= FLAGS_SHOWSIGN;
|
||||
break;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
flags &= ~(unsigned int)FLAGS_PAD_NIL;
|
||||
break;
|
||||
case '#':
|
||||
flags |= FLAGS_ALT;
|
||||
break;
|
||||
case '.':
|
||||
if('*' == *fmt) {
|
||||
/* The precision is picked from a specified parameter */
|
||||
flags |= FLAGS_PRECPARAM;
|
||||
fmt++;
|
||||
|
||||
if(use_dollar == DOLLAR_USE) {
|
||||
precision = dollarstring(fmt, &fmt);
|
||||
if(precision < 0)
|
||||
/* illegal combo */
|
||||
return PFMT_DOLLARPREC;
|
||||
}
|
||||
else
|
||||
/* get it from the next argument */
|
||||
precision = -1;
|
||||
}
|
||||
else {
|
||||
bool is_neg;
|
||||
curl_off_t num;
|
||||
flags |= FLAGS_PREC;
|
||||
is_neg = ('-' == *fmt);
|
||||
if(is_neg)
|
||||
fmt++;
|
||||
if(curlx_str_number(&fmt, &num, INT_MAX))
|
||||
return PFMT_PREC;
|
||||
precision = (int)num;
|
||||
if(is_neg)
|
||||
precision = -precision;
|
||||
}
|
||||
if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
|
||||
(FLAGS_PREC | FLAGS_PRECPARAM))
|
||||
/* it is not permitted to use both kinds of precision for the same
|
||||
argument */
|
||||
return PFMT_PRECMIX;
|
||||
break;
|
||||
case 'h':
|
||||
flags |= FLAGS_SHORT;
|
||||
break;
|
||||
#ifdef _WIN32
|
||||
case 'I':
|
||||
/* Non-ANSI integer extensions I32 I64 */
|
||||
if((fmt[0] == '3') && (fmt[1] == '2')) {
|
||||
flags |= FLAGS_LONG;
|
||||
fmt += 2;
|
||||
}
|
||||
else if((fmt[0] == '6') && (fmt[1] == '4')) {
|
||||
flags |= FLAGS_LONGLONG;
|
||||
fmt += 2;
|
||||
}
|
||||
else {
|
||||
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
#else
|
||||
flags |= FLAGS_LONG;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif /* _WIN32 */
|
||||
case 'l':
|
||||
if(flags & FLAGS_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
else
|
||||
flags |= FLAGS_LONG;
|
||||
break;
|
||||
case 'L':
|
||||
flags |= FLAGS_LONGDOUBLE;
|
||||
break;
|
||||
case 'q':
|
||||
flags |= FLAGS_LONGLONG;
|
||||
break;
|
||||
case 'z':
|
||||
/* the code below generates a warning if -Wunreachable-code is
|
||||
used */
|
||||
#if (SIZEOF_SIZE_T > SIZEOF_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
#else
|
||||
flags |= FLAGS_LONG;
|
||||
#endif
|
||||
break;
|
||||
case 'O':
|
||||
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
#else
|
||||
flags |= FLAGS_LONG;
|
||||
#endif
|
||||
break;
|
||||
case '0':
|
||||
if(!(flags & FLAGS_LEFT))
|
||||
flags |= FLAGS_PAD_NIL;
|
||||
FALLTHROUGH();
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': {
|
||||
curl_off_t num;
|
||||
flags |= FLAGS_WIDTH;
|
||||
fmt--;
|
||||
if(curlx_str_number(&fmt, &num, INT_MAX))
|
||||
return PFMT_WIDTH;
|
||||
width = (int)num;
|
||||
break;
|
||||
}
|
||||
case '*': /* read width from argument list */
|
||||
flags |= FLAGS_WIDTHPARAM;
|
||||
if(use_dollar == DOLLAR_USE) {
|
||||
width = dollarstring(fmt, &fmt);
|
||||
if(width < 0)
|
||||
/* illegal combo */
|
||||
return PFMT_DOLLARWIDTH;
|
||||
}
|
||||
else
|
||||
/* pick from the next argument */
|
||||
width = -1;
|
||||
break;
|
||||
default:
|
||||
loopit = FALSE;
|
||||
fmt--;
|
||||
break;
|
||||
} /* switch */
|
||||
} while(loopit); /* do */
|
||||
*flagsp = flags;
|
||||
*precp = precision;
|
||||
*widthp = width;
|
||||
*fmtp = fmt;
|
||||
return PFMT_OK;
|
||||
}
|
||||
|
||||
static bool parse_conversion(const char f, unsigned int *flagp,
|
||||
FormatType *typep)
|
||||
{
|
||||
unsigned int flags = *flagp;
|
||||
FormatType type;
|
||||
switch(f) {
|
||||
case 'S':
|
||||
flags = FLAGS_ALT;
|
||||
type = MTYPE_STRING;
|
||||
break;
|
||||
case 's':
|
||||
type = MTYPE_STRING;
|
||||
break;
|
||||
case 'n':
|
||||
type = MTYPE_INTPTR;
|
||||
break;
|
||||
case 'p':
|
||||
type = MTYPE_PTR;
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONG;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONG;
|
||||
else
|
||||
type = MTYPE_INT;
|
||||
break;
|
||||
case 'u':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags = FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'o':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags = FLAGS_OCTAL | FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'x':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags = FLAGS_HEX | FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'X':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags |= FLAGS_HEX | FLAGS_UPPER | FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'c':
|
||||
type = MTYPE_INT;
|
||||
flags |= FLAGS_CHAR;
|
||||
break;
|
||||
case 'f':
|
||||
type = MTYPE_DOUBLE;
|
||||
break;
|
||||
case 'e':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATE;
|
||||
break;
|
||||
case 'E':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATE | FLAGS_UPPER;
|
||||
break;
|
||||
case 'g':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATG;
|
||||
break;
|
||||
case 'G':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATG | FLAGS_UPPER;
|
||||
break;
|
||||
default:
|
||||
/* invalid instruction, disregard and continue */
|
||||
return TRUE;
|
||||
} /* switch */
|
||||
|
||||
*flagp |= flags;
|
||||
*typep = type;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
static int parsefmt(const char *format,
|
||||
struct outsegment *out,
|
||||
struct va_input *in,
|
||||
|
|
@ -192,12 +447,12 @@ static int parsefmt(const char *format,
|
|||
while(*fmt) {
|
||||
if(*fmt == '%') {
|
||||
struct va_input *iptr;
|
||||
bool loopit = TRUE;
|
||||
FormatType type;
|
||||
unsigned int flags = 0;
|
||||
int width = 0;
|
||||
int precision = 0;
|
||||
int param = -1;
|
||||
int rc;
|
||||
fmt++;
|
||||
outlen = (size_t)(fmt - start - 1);
|
||||
if(*fmt == '%') {
|
||||
|
|
@ -232,233 +487,12 @@ static int parsefmt(const char *format,
|
|||
use_dollar = DOLLAR_USE;
|
||||
}
|
||||
|
||||
/* Handle the flags */
|
||||
while(loopit) {
|
||||
switch(*fmt++) {
|
||||
case ' ':
|
||||
flags |= FLAGS_SPACE;
|
||||
break;
|
||||
case '+':
|
||||
flags |= FLAGS_SHOWSIGN;
|
||||
break;
|
||||
case '-':
|
||||
flags |= FLAGS_LEFT;
|
||||
flags &= ~(unsigned int)FLAGS_PAD_NIL;
|
||||
break;
|
||||
case '#':
|
||||
flags |= FLAGS_ALT;
|
||||
break;
|
||||
case '.':
|
||||
if('*' == *fmt) {
|
||||
/* The precision is picked from a specified parameter */
|
||||
flags |= FLAGS_PRECPARAM;
|
||||
fmt++;
|
||||
rc = parse_flags(&fmt, &flags, use_dollar, &precision, &width);
|
||||
if(rc)
|
||||
return rc;
|
||||
|
||||
if(use_dollar == DOLLAR_USE) {
|
||||
precision = dollarstring(fmt, &fmt);
|
||||
if(precision < 0)
|
||||
/* illegal combo */
|
||||
return PFMT_DOLLARPREC;
|
||||
}
|
||||
else
|
||||
/* get it from the next argument */
|
||||
precision = -1;
|
||||
}
|
||||
else {
|
||||
bool is_neg;
|
||||
curl_off_t num;
|
||||
flags |= FLAGS_PREC;
|
||||
is_neg = ('-' == *fmt);
|
||||
if(is_neg)
|
||||
fmt++;
|
||||
if(curlx_str_number(&fmt, &num, INT_MAX))
|
||||
return PFMT_PREC;
|
||||
precision = (int)num;
|
||||
if(is_neg)
|
||||
precision = -precision;
|
||||
}
|
||||
if((flags & (FLAGS_PREC | FLAGS_PRECPARAM)) ==
|
||||
(FLAGS_PREC | FLAGS_PRECPARAM))
|
||||
/* it is not permitted to use both kinds of precision for the same
|
||||
argument */
|
||||
return PFMT_PRECMIX;
|
||||
break;
|
||||
case 'h':
|
||||
flags |= FLAGS_SHORT;
|
||||
break;
|
||||
#ifdef _WIN32
|
||||
case 'I':
|
||||
/* Non-ANSI integer extensions I32 I64 */
|
||||
if((fmt[0] == '3') && (fmt[1] == '2')) {
|
||||
flags |= FLAGS_LONG;
|
||||
fmt += 2;
|
||||
}
|
||||
else if((fmt[0] == '6') && (fmt[1] == '4')) {
|
||||
flags |= FLAGS_LONGLONG;
|
||||
fmt += 2;
|
||||
}
|
||||
else {
|
||||
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
#else
|
||||
flags |= FLAGS_LONG;
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
#endif /* _WIN32 */
|
||||
case 'l':
|
||||
if(flags & FLAGS_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
else
|
||||
flags |= FLAGS_LONG;
|
||||
break;
|
||||
case 'L':
|
||||
flags |= FLAGS_LONGDOUBLE;
|
||||
break;
|
||||
case 'q':
|
||||
flags |= FLAGS_LONGLONG;
|
||||
break;
|
||||
case 'z':
|
||||
/* the code below generates a warning if -Wunreachable-code is
|
||||
used */
|
||||
#if (SIZEOF_SIZE_T > SIZEOF_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
#else
|
||||
flags |= FLAGS_LONG;
|
||||
#endif
|
||||
break;
|
||||
case 'O':
|
||||
#if (SIZEOF_CURL_OFF_T > SIZEOF_LONG)
|
||||
flags |= FLAGS_LONGLONG;
|
||||
#else
|
||||
flags |= FLAGS_LONG;
|
||||
#endif
|
||||
break;
|
||||
case '0':
|
||||
if(!(flags & FLAGS_LEFT))
|
||||
flags |= FLAGS_PAD_NIL;
|
||||
FALLTHROUGH();
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9': {
|
||||
curl_off_t num;
|
||||
flags |= FLAGS_WIDTH;
|
||||
fmt--;
|
||||
if(curlx_str_number(&fmt, &num, INT_MAX))
|
||||
return PFMT_WIDTH;
|
||||
width = (int)num;
|
||||
break;
|
||||
}
|
||||
case '*': /* read width from argument list */
|
||||
flags |= FLAGS_WIDTHPARAM;
|
||||
if(use_dollar == DOLLAR_USE) {
|
||||
width = dollarstring(fmt, &fmt);
|
||||
if(width < 0)
|
||||
/* illegal combo */
|
||||
return PFMT_DOLLARWIDTH;
|
||||
}
|
||||
else
|
||||
/* pick from the next argument */
|
||||
width = -1;
|
||||
break;
|
||||
default:
|
||||
loopit = FALSE;
|
||||
fmt--;
|
||||
break;
|
||||
} /* switch */
|
||||
} /* while */
|
||||
|
||||
switch(*fmt) {
|
||||
case 'S':
|
||||
flags |= FLAGS_ALT;
|
||||
FALLTHROUGH();
|
||||
case 's':
|
||||
type = MTYPE_STRING;
|
||||
break;
|
||||
case 'n':
|
||||
type = MTYPE_INTPTR;
|
||||
break;
|
||||
case 'p':
|
||||
type = MTYPE_PTR;
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONG;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONG;
|
||||
else
|
||||
type = MTYPE_INT;
|
||||
break;
|
||||
case 'u':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags |= FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'o':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags |= FLAGS_OCTAL | FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'x':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags |= FLAGS_HEX | FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'X':
|
||||
if(flags & FLAGS_LONGLONG)
|
||||
type = MTYPE_LONGLONGU;
|
||||
else if(flags & FLAGS_LONG)
|
||||
type = MTYPE_LONGU;
|
||||
else
|
||||
type = MTYPE_INTU;
|
||||
flags |= FLAGS_HEX | FLAGS_UPPER | FLAGS_UNSIGNED;
|
||||
break;
|
||||
case 'c':
|
||||
type = MTYPE_INT;
|
||||
flags |= FLAGS_CHAR;
|
||||
break;
|
||||
case 'f':
|
||||
type = MTYPE_DOUBLE;
|
||||
break;
|
||||
case 'e':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATE;
|
||||
break;
|
||||
case 'E':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATE | FLAGS_UPPER;
|
||||
break;
|
||||
case 'g':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATG;
|
||||
break;
|
||||
case 'G':
|
||||
type = MTYPE_DOUBLE;
|
||||
flags |= FLAGS_FLOATG | FLAGS_UPPER;
|
||||
break;
|
||||
default:
|
||||
/* invalid instruction, disregard and continue */
|
||||
if(parse_conversion(*fmt, &flags, &type))
|
||||
continue;
|
||||
} /* switch */
|
||||
|
||||
if(flags & FLAGS_WIDTHPARAM) {
|
||||
if(width < 0)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue