]> pd.if.org Git - pdclib/blobdiff - functions/_PDCLIB/scan.c
No more errors from _PDCLIB_scan tests. Yay...
[pdclib] / functions / _PDCLIB / scan.c
index 82e99fa4eaccc062ba8815b334c10c5e721b92c3..8aaabfb54696aaf4b6f28786ccd45c1ada2764af 100644 (file)
@@ -87,6 +87,44 @@ static void UNGET( int c, struct _PDCLIB_status_t * status )
 }
 
 
+/* Helper function to check if a character is part of a given scanset */
+static bool IN_SCANSET( const char * scanlist, const char * end_scanlist, int rc )
+{
+    // SOLAR
+    int previous = -1;
+    while ( scanlist != end_scanlist )
+    {
+        if ( ( *scanlist == '-' ) && ( previous != -1 ) )
+        {
+            /* possible scangroup ("a-z") */
+            if ( ++scanlist == end_scanlist )
+            {
+                /* '-' at end of scanlist does not describe a scangroup */
+                return rc == '-';
+            }
+            while ( ++previous <= (unsigned char)*scanlist )
+            {
+                if ( previous == rc )
+                {
+                    return true;
+                }
+            }
+            previous = -1;
+        }
+        else
+        {
+            /* not a scangroup, check verbatim */
+            if ( rc == (unsigned char)*scanlist )
+            {
+                return true;
+            }
+            previous = (unsigned char)(*scanlist++);
+        }
+    }
+    return false;
+}
+
+
 const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
 {
     /* generic input character */
@@ -264,20 +302,23 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
             {
                 if ( isspace( rc ) )
                 {
+                    UNGET( rc, status );
                     if ( value_parsed )
                     {
                         /* matching sequence terminated by whitespace */
                         *c = '\0';
-                        return spec;
+                        ++status->n;
+                        return ++spec;
                     }
                     else
                     {
-                        /* leading whitespace not counted against width */
-                        --(status->this);
+                        /* matching error */
+                        return NULL;
                     }
                 }
                 else
                 {
+                    /* match */
                     value_parsed = true;
                     *(c++) = rc;
                 }
@@ -300,8 +341,59 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
             }
         }
         case '[':
-            // TODO: SOLAR
-            break;
+        {
+            const char * endspec = spec;
+            bool negative_scanlist = false;
+            if ( *(++endspec) == '^' )
+            {
+                negative_scanlist = true;
+                ++endspec;
+            }
+            spec = endspec;
+            do
+            {
+                // TODO: This can run beyond a malformed format string
+                ++endspec;
+            } while ( *endspec != ']' );
+            // read according to scanlist, equiv. to %s above
+            char * c = va_arg( status->arg, char * );
+            while ( ( status->this < status->width ) && 
+                    ( ( rc = GET( status ) ) != EOF ) )
+            {
+                if ( negative_scanlist )
+                {
+                    if ( IN_SCANSET( spec, endspec, rc ) )
+                    {
+                        UNGET( rc, status );
+                        break;
+                    }
+                }
+                else
+                {
+                    if ( ! IN_SCANSET( spec, endspec, rc ) )
+                    {
+                        UNGET( rc, status );
+                        break;
+                    }
+                }
+                value_parsed = true;
+                *(c++) = rc;
+            }
+            if ( value_parsed )
+            {
+                *c = '\0';
+                ++status->n;
+                return ++endspec;
+            }
+            else
+            {
+                if ( rc == EOF )
+                {
+                    status->n = -1;
+                }
+                return NULL;
+            }
+        }
         case 'p':
             status->base = 16;
             status->flags |= E_unsigned;