diff options
author | Gregory Nutt <gnutt@nuttx.org> | 2013-10-21 10:41:15 -0600 |
---|---|---|
committer | Gregory Nutt <gnutt@nuttx.org> | 2013-10-21 10:41:15 -0600 |
commit | cc8ddac14c27f5d6f64c1947bb4042dd00be0e2c (patch) | |
tree | 553efdf3a07ae107f0169ac59ee6246691fe6dc2 | |
parent | 4ca39e19c87c9c97c834f148182a000ee3b3b41b (diff) | |
download | nuttx-cc8ddac14c27f5d6f64c1947bb4042dd00be0e2c.tar.gz nuttx-cc8ddac14c27f5d6f64c1947bb4042dd00be0e2c.tar.bz2 nuttx-cc8ddac14c27f5d6f64c1947bb4042dd00be0e2c.zip |
scanf() fixes from kfrolov: 1) sscanf() function hangs in the following example: sscanf(2, %u,%u,%u,%u, ...), 2) sscanf() returns incorrect number of parsed numbers if some arguments can't be parsed: sscanf(=2, %u,%u,%u,%u,...)==1 instead of 0, and 3) using of char* instead of const char* in vsscanf function leads to warnings from GCC.
-rw-r--r-- | nuttx/ChangeLog | 7 | ||||
-rw-r--r-- | nuttx/include/stdio.h | 2 | ||||
-rw-r--r-- | nuttx/libc/stdio/lib_sscanf.c | 69 |
3 files changed, 57 insertions, 21 deletions
diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index 663a2be10..9096caeaa 100644 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -5833,4 +5833,9 @@ by default in the demo configuration (2013-10-20). * arch/arm/src/sama5/chip/sam_tc.h: SAMA5D3 timer/counter register definition header file (2013-10-20). - + * libc/stdio/lib_sscanf.c: scanf() fixes from kfrolov: 1) sscanf() + function hangs in the following example: sscanf("2", "%u,%u,%u,%u", ...), + 2) sscanf() returns incorrect number of parsed numbers if some arguments + can't be parsed: sscanf("=2", "%u,%u,%u,%u",...)==1 instead of 0, and + 3) using of char* instead of const char* in vsscanf function leads to + warnings from GCC (2013-10-21). diff --git a/nuttx/include/stdio.h b/nuttx/include/stdio.h index eb977d38d..c250cffea 100644 --- a/nuttx/include/stdio.h +++ b/nuttx/include/stdio.h @@ -142,7 +142,7 @@ int vfprintf(FAR FILE *stream, const char *format, va_list ap); int vsprintf(FAR char *buf, const char *format, va_list ap); int avsprintf(FAR char **ptr, const char *fmt, va_list ap); int vsnprintf(FAR char *buf, size_t size, const char *format, va_list ap); -int vsscanf(char *buf, const char *s, va_list ap); +int vsscanf(FAR const char *buf, FAR const char *s, va_list ap); /* Operations on file descriptors including: * diff --git a/nuttx/libc/stdio/lib_sscanf.c b/nuttx/libc/stdio/lib_sscanf.c index ba323480f..97faa25e5 100644 --- a/nuttx/libc/stdio/lib_sscanf.c +++ b/nuttx/libc/stdio/lib_sscanf.c @@ -1,7 +1,7 @@ /**************************************************************************** * libc/stdio/lib_sscanf.c * - * Copyright (C) 2007, 2008, 2011-2012 Gregory Nutt. All rights reserved. + * Copyright (C) 2007, 2008, 2011-2013 Gregory Nutt. All rights reserved. * Author: Gregory Nutt <gnutt@nuttx.org> * * Redistribution and use in source and binary forms, with or without @@ -40,11 +40,13 @@ #include <nuttx/compiler.h> #include <sys/types.h> + #include <stdarg.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <ctype.h> +#include <errno.h> #include <debug.h> /**************************************************************************** @@ -61,12 +63,12 @@ * Private Function Prototypes ****************************************************************************/ -/**************************************************************************** +/************************************************************************** * Global Function Prototypes ****************************************************************************/ - -int vsscanf(char *buf, const char *fmt, va_list ap); - + +int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap); + /************************************************************************** * Global Constant Data **************************************************************************/ @@ -157,7 +159,7 @@ int sscanf(FAR const char *buf, FAR const char *fmt, ...) int count; va_start(ap, fmt); - count = vsscanf((FAR char*)buf, fmt, ap); + count = vsscanf((FAR const char*)buf, fmt, ap); va_end(ap); return count; } @@ -170,9 +172,9 @@ int sscanf(FAR const char *buf, FAR const char *fmt, ...) * ****************************************************************************/ -int vsscanf(FAR char *buf, FAR const char *fmt, va_list ap) +int vsscanf(FAR const char *buf, FAR const char *fmt, va_list ap) { - FAR char *bufstart; + FAR const char *bufstart; FAR char *tv; FAR const char *tc; bool lflag; @@ -438,12 +440,23 @@ int vsscanf(FAR char *buf, FAR const char *fmt, va_list ap) buf += width; if (!noassign) { -#ifdef SDCC char *endptr; - long tmplong = strtol(tmp, &endptr, base); -#else - long tmplong = strtol(tmp, NULL, base); -#endif + int errsave; + long tmplong; + + errsave = errno; + errno = 0; + tmplong = strtol(tmp, &endptr, base); + + /* Number can't be converted */ + + if (tmp == endptr || errno == ERANGE) + { + return count; + } + + errno = errsave; + /* We have to check whether we need to return a long * or an int. */ @@ -535,12 +548,24 @@ int vsscanf(FAR char *buf, FAR const char *fmt, va_list ap) if (!noassign) { /* strtod always returns a double */ -#ifdef SDCC + FAR char *endptr; - double_t dvalue = strtod(tmp,&endptr); -#else - double_t dvalue = strtod(tmp, NULL); -#endif + int errsave; + double_t dvalue; + + errsave = errno; + errno = 0; + dvalue = strtod(tmp, &endptr); + + /* Number can't be converted */ + + if (tmp == endptr || errno == ERANGE) + { + return count; + } + + errno = errsave; + /* We have to check whether we need to return a float * or a double. */ @@ -599,7 +624,7 @@ int vsscanf(FAR char *buf, FAR const char *fmt, va_list ap) fmt++; } - /* Its is not a conversion specifier */ + /* It is not a conversion specifier */ else if (*buf) { @@ -622,6 +647,12 @@ int vsscanf(FAR char *buf, FAR const char *fmt, va_list ap) buf++; } } + else + { + /* NULL terminator encountered */ + + break; + } } return count; |