Skip to content

Commit

Permalink
stdio: improve scanf for floating point numbers
Browse files Browse the repository at this point in the history
Parse input string directly instead of copying it to a buffer unless
necessary.
Perform conversion once instead of twice.

JIRA: RTOS-868
  • Loading branch information
jmaksymowicz committed Nov 6, 2024
1 parent d98a10c commit d08f9f8
Showing 1 changed file with 40 additions and 27 deletions.
67 changes: 40 additions & 27 deletions stdio/scanf.c
Original file line number Diff line number Diff line change
Expand Up @@ -577,51 +577,64 @@ static int scanf_parse(char *ccltab, const char *inp, int *inr, char const *fmt0
nconversions++;
break;

case CT_FLOAT:
if (width == 0 || width > sizeof(buf) - 1) {
width = sizeof(buf) - 1;
}
case CT_FLOAT: {
union {
float f;
double d;
long double ld;
} res;

const char *srcbuf = inp;
if (width != 0 && width < *inr) {
/* TODO: handle larger widths */
if (width > sizeof(buf) - 1) {
return (nconversions != 0 ? nassigned : -1);
}

if (strtold(inp, &p) == 0 && (inp == p || errno == ERANGE)) {
return (nconversions != 0 ? nassigned : -1);
memcpy(buf, inp, width);
buf[width] = '\0';
srcbuf = buf;
}

if ((size_t)(p - inp) >= width) {
return (nconversions != 0 ? nassigned : -1);
int is_zero;
if ((flags & LONGDOUBLE) != 0) {
res.ld = strtold(srcbuf, &p);
is_zero = res.ld == 0;
}
else if ((flags & LONG) != 0) {
res.d = strtod(srcbuf, &p);
is_zero = res.d == 0;
}
else {
res.f = strtof(srcbuf, &p);
is_zero = res.f == 0;
}

width = p - inp;

p = buf;
while (width > 0) {
if (*inr <= 0) {
return (nconversions != 0 ? nassigned : -1);
}
*p++ = *inp++;
width--;
(*inr)--;
if (is_zero && (srcbuf == p)) {
return (nconversions != 0 ? nassigned : -1);
}

int consumed = p - srcbuf;
*inr -= consumed;
inp += consumed;
nread += consumed;
nconversions++;
if ((flags & SUPPRESS) == 0) {
*p = '\0';
if ((flags & LONGDOUBLE) != 0) {
long double res = strtold(buf, NULL);
*va_arg(ap, long double *) = res;
*va_arg(ap, long double *) = res.ld;
}
else if ((flags & LONG) != 0) {
double res = strtod(buf, NULL);
*va_arg(ap, double *) = res;
*va_arg(ap, double *) = res.d;
}
else {
float res = strtof(buf, NULL);
*va_arg(ap, float *) = res;
*va_arg(ap, float *) = res.f;
}

nassigned++;
}

nread += p - buf;
nconversions++;
break;
}

default:
break;
Expand Down

0 comments on commit d08f9f8

Please sign in to comment.