libs/libc/stdio/lib_sscanf.c: Fix conversion for format specifiers that appear right after a floating point format specifier

When performing a floating point conversion the parsing code could
consume more than required characters from the input buffer. This made
impossible to convert input of form "1.1K" using format "%f%c".

Fix the issue by advancing the input buffer with the actual characters
converted as a float point number.

Signed-off-by: Mihai Serban <mihai.serban@gmail.com>
This commit is contained in:
Mihai Serban 2018-10-03 18:56:46 +03:00 committed by Gregory Nutt
parent 300b26d1d8
commit b01e6e5f2a

View File

@ -778,6 +778,13 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
if (*buf) if (*buf)
{ {
FAR char *endptr;
int errsave;
#ifdef CONFIG_HAVE_DOUBLE
double dvalue;
#endif
float fvalue;
/* Skip over any white space before the real string */ /* Skip over any white space before the real string */
while (isspace(*buf)) while (isspace(*buf))
@ -791,30 +798,49 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
{ {
/* No... Guess a field width using some heuristics */ /* No... Guess a field width using some heuristics */
width = findwidth(buf, fmt); int tmpwidth = findwidth(buf, fmt);
width = MIN(sizeof(tmp) - 1, tmpwidth);
} }
/* Copy the real string into a temporary working buffer. */ /* Copy the real string into a temporary working buffer. */
strncpy(tmp, buf, width); strncpy(tmp, buf, width);
tmp[width] = '\0'; tmp[width] = '\0';
buf += width;
linfo("vsscanf: tmp[]=\"%s\"\n", tmp); linfo("vsscanf: tmp[]=\"%s\"\n", tmp);
/* Perform the floating point conversion */ /* Perform the floating point conversion */
/* Preserve the errno value */
errsave = get_errno();
set_errno(0);
#ifdef CONFIG_HAVE_DOUBLE
if (lflag)
{
/* Get the converted double value */
dvalue = strtod(tmp, &endptr);
}
else
#endif
{
fvalue = strtof(tmp, &endptr);
}
/* Check if the number was successfully converted */
if (tmp == endptr || get_errno() == ERANGE)
{
return count;
}
/* Move by the actual number of characters converted */
buf += (endptr - tmp);
set_errno(errsave);
if (!noassign) if (!noassign)
{ {
/* strtod always returns a double */
FAR char *endptr;
int errsave;
/* Preserve the errno value */
errsave = get_errno();
set_errno(0);
/* We have to check whether we need to return a float /* We have to check whether we need to return a float
* or a double. * or a double.
@ -823,18 +849,6 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
#ifdef CONFIG_HAVE_DOUBLE #ifdef CONFIG_HAVE_DOUBLE
if (lflag) if (lflag)
{ {
/* Get the converted double value */
double dvalue = strtod(tmp, &endptr);
/* Check if the number was successfully converted */
if (tmp == endptr || get_errno() == ERANGE)
{
return count;
}
set_errno(errsave);
/* Return the double value */ /* Return the double value */
@ -844,18 +858,6 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
else else
#endif #endif
{ {
/* Get the converted float value */
float fvalue = strtof(tmp, &endptr);
/* Check if the number was successfully converted */
if (tmp == endptr || get_errno() == ERANGE)
{
return count;
}
set_errno(errsave);
/* Return the float value */ /* Return the float value */