Commit 441d9ba2b03fa4a990dbd7de1601ac92dd557fa4

Sam Lantinga 2017-08-11T19:36:12

Fixed bug 3341 - SDL_sscanf() problem e_pluschauskas Why does SDL_sscanf() always returns the number of format specifiers and doesn't implements standard C library behavior?

diff --git a/src/stdlib/SDL_string.c b/src/stdlib/SDL_string.c
index fde92fc..4368994 100644
--- a/src/stdlib/SDL_string.c
+++ b/src/stdlib/SDL_string.c
@@ -78,7 +78,7 @@ SDL_ScanLong(const char *text, int radix, long *valuep)
         value += v;
         ++text;
     }
-    if (valuep) {
+    if (valuep && text > textstart) {
         if (negative && value) {
             *valuep = -value;
         } else {
@@ -114,7 +114,7 @@ SDL_ScanUnsignedLong(const char *text, int radix, unsigned long *valuep)
         value += v;
         ++text;
     }
-    if (valuep) {
+    if (valuep && text > textstart) {
         *valuep = value;
     }
     return (text - textstart);
@@ -146,7 +146,7 @@ SDL_ScanUintPtrT(const char *text, int radix, uintptr_t * valuep)
         value += v;
         ++text;
     }
-    if (valuep) {
+    if (valuep && text > textstart) {
         *valuep = value;
     }
     return (text - textstart);
@@ -183,7 +183,7 @@ SDL_ScanLongLong(const char *text, int radix, Sint64 * valuep)
         value += v;
         ++text;
     }
-    if (valuep) {
+    if (valuep && text > textstart) {
         if (negative && value) {
             *valuep = -value;
         } else {
@@ -219,7 +219,7 @@ SDL_ScanUnsignedLongLong(const char *text, int radix, Uint64 * valuep)
         value += v;
         ++text;
     }
-    if (valuep) {
+    if (valuep && text > textstart) {
         *valuep = value;
     }
     return (text - textstart);
@@ -251,7 +251,7 @@ SDL_ScanFloat(const char *text, double *valuep)
             ++text;
         }
     }
-    if (valuep) {
+    if (valuep && text > textstart) {
         if (negative && value) {
             *valuep = -value;
         } else {
@@ -1025,6 +1025,10 @@ SDL_vsscanf(const char *text, const char *fmt, va_list ap)
 {
     int retval = 0;
 
+    if (!text || !*text) {
+        return -1;
+    }
+
     while (*fmt) {
         if (*fmt == ' ') {
             while (SDL_isspace((unsigned char) *text)) {
@@ -1044,6 +1048,7 @@ SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                 DO_LONG,
                 DO_LONGLONG
             } inttype = DO_INT;
+            size_t advance;
             SDL_bool suppress = SDL_FALSE;
 
             ++fmt;
@@ -1131,8 +1136,9 @@ SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                         }
                     } else {
                         long value;
-                        text += SDL_ScanLong(text, radix, &value);
-                        if (!suppress) {
+                        advance = SDL_ScanLong(text, radix, &value);
+                        text += advance;
+                        if (advance && !suppress) {
                             switch (inttype) {
                             case DO_SHORT:
                                 {
@@ -1175,16 +1181,18 @@ SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                 case 'u':
                     if (inttype == DO_LONGLONG) {
                         Uint64 value;
-                        text += SDL_ScanUnsignedLongLong(text, radix, &value);
-                        if (!suppress) {
+                        advance = SDL_ScanUnsignedLongLong(text, radix, &value);
+                        text += advance;
+                        if (advance && !suppress) {
                             Uint64 *valuep = va_arg(ap, Uint64 *);
                             *valuep = value;
                             ++retval;
                         }
                     } else {
                         unsigned long value;
-                        text += SDL_ScanUnsignedLong(text, radix, &value);
-                        if (!suppress) {
+                        advance = SDL_ScanUnsignedLong(text, radix, &value);
+                        text += advance;
+                        if (advance && !suppress) {
                             switch (inttype) {
                             case DO_SHORT:
                                 {
@@ -1216,8 +1224,9 @@ SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                 case 'p':
                     {
                         uintptr_t value;
-                        text += SDL_ScanUintPtrT(text, 16, &value);
-                        if (!suppress) {
+                        advance = SDL_ScanUintPtrT(text, 16, &value);
+                        text += advance;
+                        if (advance && !suppress) {
                             void **valuep = va_arg(ap, void **);
                             *valuep = (void *) value;
                             ++retval;
@@ -1228,8 +1237,9 @@ SDL_vsscanf(const char *text, const char *fmt, va_list ap)
                 case 'f':
                     {
                         double value;
-                        text += SDL_ScanFloat(text, &value);
-                        if (!suppress) {
+                        advance = SDL_ScanFloat(text, &value);
+                        text += advance;
+                        if (advance && !suppress) {
                             float *valuep = va_arg(ap, float *);
                             *valuep = (float) value;
                             ++retval;