]> pd.if.org Git - pdclib/blobdiff - functions/_PDCLIB/scan.c
Some fixes to string scanning. First half of scanset scanning.
[pdclib] / functions / _PDCLIB / scan.c
index c392a5393727dabd7ebf36a15ae4ccc1c78d3ee5..63afff235e25281778b4bdc584ca42b1e8952596 100644 (file)
@@ -14,6 +14,7 @@
 #include <ctype.h>
 #include <string.h>
 #include <stddef.h>
+#include <limits.h>
 
 /* Using an integer's bits as flags for both the conversion flags and length
    modifiers.
@@ -37,7 +38,7 @@
    type:      integer type, used to get the correct type from the parameter
               stack as well as for cast target.
 */
-#define ASSIGN( case_cond, type ) \
+#define ASSIGN_VALUE_TO( case_cond, type ) \
     case case_cond: \
         *( va_arg( status->arg, type * ) ) = (type)( value * sign ); \
         break
@@ -86,6 +87,14 @@ 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 NOT_IN_SCANSET( const char * start_scanlist, const char * end_scanlist, bool negate_scanlist, int rc )
+{
+    // SOLAR
+    return true;
+}
+
+
 const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
 {
     /* generic input character */
@@ -263,20 +272,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;
                 }
@@ -298,6 +310,48 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                 return NULL;
             }
         }
+        case '[':
+        {
+            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 ( NOT_IN_SCANSET( spec, endspec, negative_scanlist, rc ) )
+                {
+                    break;
+                }
+                value_parsed = true;
+                *(c++) = rc;
+            }
+            if ( value_parsed )
+            {
+                *c = '\0';
+                ++status->n;
+                return ++endspec;
+            }
+            else
+            {
+                if ( status->n == 0 )
+                {
+                    status->n = -1;
+                }
+                return NULL;
+            }
+        }
         case 'p':
             status->base = 16;
             status->flags |= E_unsigned;
@@ -316,7 +370,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
     if ( status->base != -1 )
     {
         /* integer conversion */
-        uintmax_t value = 0;
+        uintmax_t value = 0;         /* absolute value read */
         bool prefix_parsed = false;
         int sign = 0;
         while ( ( status->this < status->width ) &&
@@ -428,7 +482,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
         {
             /* out of input before anything could be parsed - input error */
             /* FIXME: if first character does not match, value_parsed is not set - but it is NOT an input error */
-            if ( status->n == 0 )
+            if ( ( status->n == 0 ) && ( rc == EOF ) )
             {
                 status->n = -1;
             }
@@ -439,22 +493,22 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                                    E_intmax | E_size | E_ptrdiff |
                                    E_unsigned ) )
         {
-            ASSIGN( E_char, char );
-            ASSIGN( E_char | E_unsigned, unsigned char );
-            ASSIGN( E_short, short );
-            ASSIGN( E_short | E_unsigned, unsigned short );
-            ASSIGN( 0, int );
-            ASSIGN( E_unsigned, unsigned int );
-            ASSIGN( E_long, long );
-            ASSIGN( E_long | E_unsigned, unsigned long );
-            ASSIGN( E_llong, long long );
-            ASSIGN( E_llong | E_unsigned, unsigned long long );
-            ASSIGN( E_intmax, intmax_t );
-            ASSIGN( E_intmax | E_unsigned, uintmax_t );
-            ASSIGN( E_size, size_t );
-            /* ASSIGN( E_size | E_unsigned, unsigned size_t ); */
-            ASSIGN( E_ptrdiff, ptrdiff_t );
-            /* ASSIGN( E_ptrdiff | E_unsigned, unsigned ptrdiff_t ); */
+            ASSIGN_VALUE_TO( E_char, char );
+            ASSIGN_VALUE_TO( E_char | E_unsigned, unsigned char );
+            ASSIGN_VALUE_TO( E_short, short );
+            ASSIGN_VALUE_TO( E_short | E_unsigned, unsigned short );
+            ASSIGN_VALUE_TO( 0, int );
+            ASSIGN_VALUE_TO( E_unsigned, unsigned int );
+            ASSIGN_VALUE_TO( E_long, long );
+            ASSIGN_VALUE_TO( E_long | E_unsigned, unsigned long );
+            ASSIGN_VALUE_TO( E_llong, long long );
+            ASSIGN_VALUE_TO( E_llong | E_unsigned, unsigned long long );
+            ASSIGN_VALUE_TO( E_intmax, intmax_t );
+            ASSIGN_VALUE_TO( E_intmax | E_unsigned, uintmax_t );
+            ASSIGN_VALUE_TO( E_size, size_t );
+            /* ASSIGN_VALUE_TO( E_size | E_unsigned, unsigned size_t ); */
+            ASSIGN_VALUE_TO( E_ptrdiff, ptrdiff_t );
+            /* ASSIGN_VALUE_TO( E_ptrdiff | E_unsigned, unsigned ptrdiff_t ); */
             default:
                 puts( "UNSUPPORTED SCANF FLAG COMBINATION" );
                 return NULL; /* behaviour unspecified */