Merged in david_s5/nuttx/upstream_to_greg_scanfwidth (pull request #149)
Fixes sscan %sn where strlen(data) < n
This commit is contained in:
commit
db8863622b
@ -93,8 +93,7 @@ static int findwidth(FAR const char *buf, FAR const char *fmt)
|
||||
FAR const char *next = fmt + 1;
|
||||
|
||||
/* No... is there a space after the format? Or does the format string end
|
||||
* here?
|
||||
*/
|
||||
* here? */
|
||||
|
||||
if (isspace(*next) || *next == 0)
|
||||
{
|
||||
@ -103,15 +102,13 @@ static int findwidth(FAR const char *buf, FAR const char *fmt)
|
||||
return strcspn(buf, spaces);
|
||||
}
|
||||
|
||||
/* No.. Another possibility is the format character is followed by
|
||||
* some recognizable delimiting value.
|
||||
*/
|
||||
/* No.. Another possibility is the format character is followed by some
|
||||
* recognizable delimiting value. */
|
||||
|
||||
if (*next != '%')
|
||||
{
|
||||
/* If so we will say that the string ends there if we can find that
|
||||
* delimiter in the input string.
|
||||
*/
|
||||
* delimiter in the input string. */
|
||||
|
||||
FAR const char *ptr = strchr(buf, *next);
|
||||
if (ptr)
|
||||
@ -120,16 +117,14 @@ static int findwidth(FAR const char *buf, FAR const char *fmt)
|
||||
}
|
||||
}
|
||||
|
||||
/* No... the format has no delimiter and is back-to-back with the next
|
||||
* format (or is followed by a delimiter that does not exist in the
|
||||
* input string). At this point we just bail and Use the input up until
|
||||
* the first white space is encountered.
|
||||
*
|
||||
* NOTE: This means that values from the following format may be
|
||||
* concatenated with the first. This is a bug. We have no generic way of
|
||||
* determining the width of the data if there is no fieldwidth, no space
|
||||
* separating the input, and no usable delimiter character.
|
||||
*/
|
||||
/* No... the format has no delimiter and is back-to-back with the next format
|
||||
* (or is followed by a delimiter that does not exist in the input string).
|
||||
* At this point we just bail and Use the input up until the first white
|
||||
* space is encountered. NOTE: This means that values from the following
|
||||
* format may be concatenated with the first. This is a bug. We have no
|
||||
* generic way of determining the width of the data if there is no
|
||||
* fieldwidth, no space separating the input, and no usable delimiter
|
||||
* character. */
|
||||
|
||||
return strcspn(buf, spaces);
|
||||
}
|
||||
@ -149,7 +144,7 @@ static int findwidth(FAR const char *buf, FAR const char *fmt)
|
||||
int sscanf(FAR const char *buf, FAR const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int count;
|
||||
int count;
|
||||
|
||||
va_start(ap, fmt);
|
||||
count = vsscanf((FAR const char *)buf, fmt, ap);
|
||||
@ -168,34 +163,33 @@ int sscanf(FAR const char *buf, FAR const char *fmt, ...)
|
||||
int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
{
|
||||
FAR const char *bufstart;
|
||||
FAR char *tv;
|
||||
FAR char *tv;
|
||||
FAR const char *tc;
|
||||
bool lflag;
|
||||
bool noassign;
|
||||
int count;
|
||||
int width;
|
||||
int base = 10;
|
||||
char tmp[MAXLN];
|
||||
bool lflag;
|
||||
bool noassign;
|
||||
int count;
|
||||
int width;
|
||||
int fwidth;
|
||||
int base = 10;
|
||||
char tmp[MAXLN];
|
||||
|
||||
linfo("vsscanf: buf=\"%s\" fmt=\"%s\"\n", buf, fmt);
|
||||
|
||||
/* Remember the start of the input buffer. We will need this for %n
|
||||
* calculations.
|
||||
*/
|
||||
* calculations. */
|
||||
|
||||
bufstart = buf;
|
||||
|
||||
/* Parse the format, extracting values from the input buffer as needed */
|
||||
|
||||
count = 0;
|
||||
width = 0;
|
||||
count = 0;
|
||||
width = 0;
|
||||
noassign = false;
|
||||
lflag = false;
|
||||
lflag = false;
|
||||
|
||||
/* Loop until all characters in the fmt string have been processed. We
|
||||
* may have to continue loop after reaching the end the input data in
|
||||
* order to handle trailing %n format specifiers.
|
||||
*/
|
||||
/* Loop until all characters in the fmt string have been processed. We may
|
||||
* have to continue loop after reaching the end the input data in order to
|
||||
* handle trailing %n format specifiers. */
|
||||
|
||||
while (*fmt)
|
||||
{
|
||||
@ -244,27 +238,25 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
/* Process %s: String conversion */
|
||||
/* Process %s: String conversion */
|
||||
|
||||
if (*fmt == 's')
|
||||
{
|
||||
linfo("vsscanf: Performing string conversion\n");
|
||||
|
||||
/* Get a pointer to the char * value. We need to do this even
|
||||
* if we have reached the end of the input data in order to
|
||||
* update the 'ap' variable.
|
||||
*/
|
||||
/* Get a pointer to the char * value. We need to do this even if
|
||||
* we have reached the end of the input data in order to update
|
||||
* the 'ap' variable. */
|
||||
|
||||
tv = NULL; /* To avoid warnings about begin uninitialized */
|
||||
tv = NULL; /* To avoid warnings about begin uninitialized */
|
||||
if (!noassign)
|
||||
{
|
||||
tv = va_arg(ap, FAR char *);
|
||||
tv = va_arg(ap, FAR char *);
|
||||
tv[0] = '\0';
|
||||
}
|
||||
|
||||
/* But we only perform the data conversion is we still have
|
||||
* bytes remaining in the input data stream.
|
||||
*/
|
||||
/* But we only perform the data conversion is we still have bytes
|
||||
* remaining in the input data stream. */
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
@ -275,16 +267,21 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
buf++;
|
||||
}
|
||||
|
||||
/* Was a fieldwidth specified? */
|
||||
/* Guess a field width using some heuristics */
|
||||
|
||||
if (!width)
|
||||
fwidth = findwidth(buf, fmt);
|
||||
|
||||
/* Use the actual field's width if 1) no fieldwidth specified
|
||||
* or 2) the actual field's width is smaller than fieldwidth
|
||||
* specified */
|
||||
|
||||
if (!width || fwidth < width)
|
||||
{
|
||||
/* No... Guess a field width using some heuristics */
|
||||
|
||||
int tmpwidth = findwidth(buf, fmt);
|
||||
width = MIN(sizeof(tmp) - 1, tmpwidth);
|
||||
width = fwidth;
|
||||
}
|
||||
|
||||
width = MIN(sizeof(tmp) - 1, width);
|
||||
|
||||
/* Copy the string (if we are making an assignment) */
|
||||
|
||||
if (!noassign)
|
||||
@ -300,27 +297,25 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
/* Process %c: Character conversion */
|
||||
/* Process %c: Character conversion */
|
||||
|
||||
else if (*fmt == 'c')
|
||||
{
|
||||
linfo("vsscanf: Performing character conversion\n");
|
||||
|
||||
/* Get a pointer to the char * value. We need to do this even
|
||||
* if we have reached the end of the input data in order to
|
||||
* update the 'ap' variable.
|
||||
*/
|
||||
/* Get a pointer to the char * value. We need to do this even if
|
||||
* we have reached the end of the input data in order to update
|
||||
* the 'ap' variable. */
|
||||
|
||||
tv = NULL; /* To avoid warnings about beign uninitialized */
|
||||
tv = NULL; /* To avoid warnings about beign uninitialized */
|
||||
if (!noassign)
|
||||
{
|
||||
tv = va_arg(ap, FAR char *);
|
||||
tv = va_arg(ap, FAR char *);
|
||||
tv[0] = '\0';
|
||||
}
|
||||
|
||||
/* But we only perform the data conversion is we still have
|
||||
* bytes remaining in the input data stream.
|
||||
*/
|
||||
/* But we only perform the data conversion is we still have bytes
|
||||
* remaining in the input data stream. */
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
@ -343,33 +338,30 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
|
||||
/* Update the buffer pointer past the character(s) in the
|
||||
* input
|
||||
*/
|
||||
* input */
|
||||
|
||||
buf += width;
|
||||
}
|
||||
}
|
||||
|
||||
/* Process %d, %o, %b, %x, %u: Various integer conversions */
|
||||
/* Process %d, %o, %b, %x, %u: Various integer conversions */
|
||||
|
||||
else if (strchr("dobxu", *fmt))
|
||||
{
|
||||
FAR long *plong = NULL;
|
||||
FAR int *pint = NULL;
|
||||
FAR int *pint = NULL;
|
||||
bool sign;
|
||||
|
||||
linfo("vsscanf: Performing integer conversion\n");
|
||||
|
||||
/* Get a pointer to the integer value. We need to do this even
|
||||
* if we have reached the end of the input data in order to
|
||||
* update the 'ap' variable.
|
||||
*/
|
||||
* update the 'ap' variable. */
|
||||
|
||||
if (!noassign)
|
||||
{
|
||||
/* We have to check whether we need to return a long or an
|
||||
* int.
|
||||
*/
|
||||
* int. */
|
||||
|
||||
if (lflag)
|
||||
{
|
||||
@ -383,15 +375,14 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
/* But we only perform the data conversion if we still have
|
||||
* bytes remaining in the input data stream.
|
||||
*/
|
||||
/* But we only perform the data conversion if we still have bytes
|
||||
* remaining in the input data stream. */
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
FAR char *endptr;
|
||||
int errsave;
|
||||
long tmplong;
|
||||
int errsave;
|
||||
long tmplong;
|
||||
|
||||
/* Skip over any white space before the integer string */
|
||||
|
||||
@ -400,9 +391,8 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
buf++;
|
||||
}
|
||||
|
||||
/* The base of the integer conversion depends on the
|
||||
* specific conversion specification.
|
||||
*/
|
||||
/* The base of the integer conversion depends on the specific
|
||||
* conversion specification. */
|
||||
|
||||
sign = false;
|
||||
switch (*fmt)
|
||||
@ -438,9 +428,7 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
width = MIN(sizeof(tmp) - 1, tmpwidth);
|
||||
}
|
||||
|
||||
/* Copy the numeric string into a temporary working
|
||||
* buffer.
|
||||
*/
|
||||
/* Copy the numeric string into a temporary working buffer. */
|
||||
|
||||
strncpy(tmp, buf, width);
|
||||
tmp[width] = '\0';
|
||||
@ -475,9 +463,8 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
if (!noassign)
|
||||
{
|
||||
|
||||
/* We have to check whether we need to return a long
|
||||
* or an int.
|
||||
*/
|
||||
/* We have to check whether we need to return a long or
|
||||
* an int. */
|
||||
|
||||
if (lflag)
|
||||
{
|
||||
@ -487,8 +474,7 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
else
|
||||
{
|
||||
linfo("vsscanf: Return %ld to 0x%p\n",
|
||||
tmplong, pint);
|
||||
linfo("vsscanf: Return %ld to 0x%p\n", tmplong, pint);
|
||||
*pint = (int)tmplong;
|
||||
}
|
||||
|
||||
@ -497,48 +483,44 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
/* Process %a, %A, %f, %F, %e, %E, %g, and %G: Floating point
|
||||
* conversions
|
||||
*/
|
||||
/* Process %a, %A, %f, %F, %e, %E, %g, and %G: Floating point
|
||||
* conversions */
|
||||
|
||||
else if (strchr("aAfFeEgG", *fmt) != NULL)
|
||||
{
|
||||
#ifdef CONFIG_HAVE_DOUBLE
|
||||
FAR double_t *pd = NULL;
|
||||
#endif
|
||||
FAR float *pf = NULL;
|
||||
FAR float *pf = NULL;
|
||||
|
||||
linfo("vsscanf: Performing floating point conversion\n");
|
||||
|
||||
/* Get a pointer to the double value. We need to do this even
|
||||
* if we have reached the end of the input data in order to
|
||||
* update the 'ap' variable.
|
||||
*/
|
||||
/* Get a pointer to the double value. We need to do this even if
|
||||
* we have reached the end of the input data in order to update
|
||||
* the 'ap' variable. */
|
||||
|
||||
if (!noassign)
|
||||
{
|
||||
/* We have to check whether we need to return a float or a
|
||||
* double.
|
||||
*/
|
||||
* double. */
|
||||
|
||||
#ifdef CONFIG_HAVE_DOUBLE
|
||||
if (lflag)
|
||||
{
|
||||
pd = va_arg(ap, FAR double_t *);
|
||||
pd = va_arg(ap, FAR double_t *);
|
||||
*pd = 0.0;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
pf = va_arg(ap, FAR float *);
|
||||
pf = va_arg(ap, FAR float *);
|
||||
*pf = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_LIBC_FLOATINGPOINT
|
||||
/* But we only perform the data conversion is we still have
|
||||
* bytes remaining in the input data stream.
|
||||
*/
|
||||
/* But we only perform the data conversion is we still have bytes
|
||||
* remaining in the input data stream. */
|
||||
|
||||
if (*buf)
|
||||
{
|
||||
@ -573,14 +555,14 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
/* strtod always returns a double */
|
||||
|
||||
FAR char *endptr;
|
||||
int errsave;
|
||||
double_t dvalue;
|
||||
int errsave;
|
||||
double_t dvalue;
|
||||
|
||||
/* Preserve the errno value */
|
||||
|
||||
errsave = get_errno();
|
||||
set_errno(0);
|
||||
dvalue = strtod(tmp, &endptr);
|
||||
dvalue = strtod(tmp, &endptr);
|
||||
|
||||
/* Check if the number was successfully converted */
|
||||
|
||||
@ -591,18 +573,17 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
|
||||
set_errno(errsave);
|
||||
|
||||
/* We have to check whether we need to return a float
|
||||
* or a double.
|
||||
*/
|
||||
/* We have to check whether we need to return a float or
|
||||
* a double. */
|
||||
|
||||
#ifdef CONFIG_HAVE_DOUBLE
|
||||
# ifdef CONFIG_HAVE_DOUBLE
|
||||
if (lflag)
|
||||
{
|
||||
linfo("vsscanf: Return %f to %p\n", dvalue, pd);
|
||||
*pd = dvalue;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
# endif
|
||||
{
|
||||
linfo("vsscanf: Return %f to %p\n", dvalue, pf);
|
||||
*pf = (float)dvalue;
|
||||
@ -614,7 +595,7 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Process %n: Character count */
|
||||
/* Process %n: Character count */
|
||||
|
||||
else if (*fmt == 'n')
|
||||
{
|
||||
@ -622,7 +603,7 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
|
||||
if (!noassign)
|
||||
{
|
||||
size_t nchars = (size_t)(buf - bufstart);
|
||||
size_t nchars = (size_t) (buf - bufstart);
|
||||
|
||||
/* Note %n does not count as a conversion */
|
||||
|
||||
@ -639,14 +620,14 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
}
|
||||
|
||||
width = 0;
|
||||
width = 0;
|
||||
noassign = false;
|
||||
lflag = false;
|
||||
lflag = false;
|
||||
|
||||
fmt++;
|
||||
}
|
||||
|
||||
/* It is not a conversion specifier */
|
||||
/* It is not a conversion specifier */
|
||||
|
||||
else if (*buf)
|
||||
{
|
||||
@ -678,8 +659,7 @@ int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap)
|
||||
}
|
||||
|
||||
/* sscanf is required to return EOF if the input ends before the first
|
||||
* matching failure or conversion.
|
||||
*/
|
||||
* matching failure or conversion. */
|
||||
|
||||
return count ? count : EOF;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user