]> pd.if.org Git - pdclib/commitdiff
Intermediate debugging work on *scanf().
authorsolar <unknown>
Fri, 12 Mar 2010 11:08:56 +0000 (11:08 +0000)
committersolar <unknown>
Fri, 12 Mar 2010 11:08:56 +0000 (11:08 +0000)
functions/_PDCLIB/scan.c
functions/stdio/fscanf.c
functions/stdio/sscanf.c
functions/stdio/vfscanf.c
functions/stdio/vsscanf.c
internals/_PDCLIB_int.h

index f41079bd78ee98908e98642e14011ff3ac21718a..c392a5393727dabd7ebf36a15ae4ccc1c78d3ee5 100644 (file)
 #define E_unsigned   1<<16
 
 
+/* Helper macro for assigning a readily converted integer value to the correct
+   parameter type, used in a switch on status->flags (see E_* flags above).
+   case_cond: combination of the E_* flags above, used for the switch-case
+   type:      integer type, used to get the correct type from the parameter
+              stack as well as for cast target.
+*/
 #define ASSIGN( case_cond, type ) \
     case case_cond: \
         *( va_arg( status->arg, type * ) ) = (type)( value * sign ); \
         break
 
 
+/* Helper function to get a character from the string or stream, whatever is
+   used for input. When reading from a string, returns EOF on end-of-string
+   so that handling of the return value can be uniform for both streams and
+   strings.
+*/
 static int GET( struct _PDCLIB_status_t * status )
 {
-    ++(status->i);
-    ++(status->this);
+    int rc;
     if ( status->stream != NULL )
     {
-        return getc( status->stream );
+        rc = getc( status->stream );
     }
     else
     {
-        return ( *status->s == '\0' ) ? EOF : *((status->s)++);
+        rc = ( *status->s == '\0' ) ? EOF : (unsigned char)*((status->s)++);
+    }
+    if ( rc != EOF )
+    {
+        ++(status->i);
+        ++(status->this);
     }
+    return rc;
 }
 
 
+/* Helper function to put a read character back into the string or stream,
+   whatever is used for input.
+*/
 static void UNGET( int c, struct _PDCLIB_status_t * status )
 {
     if ( status->stream != NULL )
@@ -60,7 +79,7 @@ static void UNGET( int c, struct _PDCLIB_status_t * status )
     }
     else
     {
-        *(--(status->s)) = c;
+        --(status->s);
     }
     --(status->i);
     --(status->this);
@@ -79,7 +98,11 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
         switch ( rc )
         {
             case EOF:
-                /* matching failure */
+                /* input error */
+                if ( status->n == 0 )
+                {
+                    status->n = -1;
+                }
                 return NULL;
             case '%':
                 return ++spec;
@@ -204,16 +227,19 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
         case 'c':
         {
             char * c = va_arg( status->arg, char * );
+            /* for %c, default width is one */
             if ( status->width == SIZE_MAX )
             {
                 status->width = 1;
             }
+            /* reading until width reached or input exhausted */
             while ( ( status->this < status->width ) &&
                     ( ( rc = GET( status ) ) != EOF ) )
             {
                 *(c++) = rc;
                 value_parsed = true;
             }
+            /* width or input exhausted */
             if ( value_parsed )
             {
                 ++status->n;
@@ -221,7 +247,11 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
             }
             else
             {
-                /* FIXME: Need two kinds of "no match" here: zero width, and input error */
+                /* input error, no character read */
+                if ( status->n == 0 )
+                {
+                    status->n = -1;
+                }
                 return NULL;
             }
         }
@@ -235,11 +265,13 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                 {
                     if ( value_parsed )
                     {
+                        /* matching sequence terminated by whitespace */
                         *c = '\0';
                         return spec;
                     }
                     else
                     {
+                        /* leading whitespace not counted against width */
                         --(status->this);
                     }
                 }
@@ -258,6 +290,11 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
             }
             else
             {
+                /* input error, no character read */
+                if ( status->n == 0 )
+                {
+                    status->n = -1;
+                }
                 return NULL;
             }
         }
@@ -285,8 +322,23 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
         while ( ( status->this < status->width ) &&
                 ( ( rc = GET( status ) ) != EOF ) )
         {
-            if ( ! sign )
+            if ( isspace( rc ) )
+            {
+                if ( sign )
+                {
+                    /* matching sequence terminated by whitespace */
+                    UNGET( rc, status );
+                    break;
+                }
+                else
+                {
+                    /* leading whitespace not counted against width */
+                    status->this--;
+                }
+            }
+            else if ( ! sign )
             {
+                /* no sign parsed yet */
                 switch ( rc )
                 {
                     case '-':
@@ -296,6 +348,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                         sign = 1;
                         break;
                     default:
+                        /* not a sign; put back character */
                         sign = 1;
                         UNGET( rc, status );
                         break;
@@ -303,9 +356,11 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
             }
             else if ( ! prefix_parsed )
             {
+                /* no prefix (0x... for hex, 0... for octal) parsed yet */
                 prefix_parsed = true;
                 if ( rc != '0' )
                 {
+                    /* not a prefix; if base not yet set, set to decimal */
                     if ( status->base == 0 )
                     {
                         status->base = 10;
@@ -314,11 +369,14 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                 }
                 else
                 {
+                    /* starts with zero, so it might be a prefix. */
+                    /* check what follows next (might be 0x...) */
                     if ( ( status->this < status->width ) &&
                          ( ( rc = GET( status ) ) != EOF ) )
                     {
                         if ( tolower( rc ) == 'x' )
                         {
+                            /* 0x... would be prefix for hex base... */
                             if ( ( status->base == 0 ) ||
                                  ( status->base == 16 ) )
                             {
@@ -326,20 +384,29 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                             }
                             else
                             {
+                                /* ...unless already set to other value */
                                 UNGET( rc, status );
                                 value_parsed = true;
                             }
                         }
                         else
                         {
+                            /* 0... but not 0x.... would be octal prefix */
                             UNGET( rc, status );
                             if ( status->base == 0 )
                             {
                                 status->base = 8;
                             }
+                            /* in any case we have read a zero */
                             value_parsed = true;
                         }
                     }
+                    else
+                    {
+                        /* failed to read beyond the initial zero */
+                        value_parsed = true;
+                        break;
+                    }
                 }
             }
             else
@@ -348,6 +415,7 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                 if ( digitptr == NULL )
                 {
                     /* end of input item */
+                    UNGET( rc, status );
                     break;
                 }
                 value *= status->base;
@@ -355,12 +423,18 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
                 value_parsed = true;
             }
         }
-        /* width exceeded, EOF, read error, non-matching character */
+        /* width or input exhausted, or non-matching character */
         if ( ! value_parsed )
         {
-            /* matching error */
+            /* 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 )
+            {
+                status->n = -1;
+            }
             return NULL;
         }
+        /* convert value to target type and assign to parameter */
         switch ( status->flags & ( E_char | E_short | E_long | E_llong |
                                    E_intmax | E_size | E_ptrdiff |
                                    E_unsigned ) )
@@ -383,8 +457,9 @@ const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status )
             /* ASSIGN( E_ptrdiff | E_unsigned, unsigned ptrdiff_t ); */
             default:
                 puts( "UNSUPPORTED SCANF FLAG COMBINATION" );
-                return NULL;
+                return NULL; /* behaviour unspecified */
         }
+        ++(status->n);
         return ++spec;
     }
     /* TODO: Floats. */
index 17b0dca4c9add00de4e45f667628696d137f3c5e..da64a9d74e39b655d8e6715c51b81a677f155c88 100644 (file)
@@ -27,7 +27,2008 @@ int fscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format
 #include <_PDCLIB_test.h>
 
 #include <string.h>
+#include <limits.h>
+#include <_PDCLIB_aux.h>
 
+#if 0
+#define CHECK_TRUE( a ) do { if ( a == 0 ) { fprintf( stderr, "Unexpected failure in " _PDCLIB_symbol2string( __LINE__ ) ": '" #a "' evaluated to false.\n" ); } } while ( 0 )
+#define CHECK_FALSE( a ) do { if ( a != 0 ) { fprintf( stderr, "Unexpected failure in " _PDCLIB_symbol2string( __LINE__ ) ": '" #a "' evaluated to true.\n" ); } } while ( 0 )
+#define CHECK_EQUAL( a, b ) do { int x = a; int y = b; if ( x != y ) { fprintf( stderr, "Mismatch in " _PDCLIB_symbol2string( __LINE__ ) ": result is %d, expected %d.\n", x, y ); } } while ( 0 )
+#define CHECK_FEQUAL( a, b, T, F ) do { T x = a; T y = b; if ( x != y ) { fprintf( stderr, "Mismatch in " _PDCLIB_symbol2string( __LINE__ ) ": result is " F ", expected " F ".\n", x, y ); } } while ( 0 )
+#endif
+
+#define CHECK_TRUE( a ) TESTCASE( a != 0 )
+#define CHECK_FALSE( a ) TESTCASE( a == 0 )
+#define CHECK_EQUAL( a, b ) do { int x = a; int y = b; TESTCASE( x == y ); } while ( 0 )
+#define CHECK_FEQUAL( a, b, T, F ) do { T x = a; T y = b; TESTCASE( x == y ); } while ( 0 )
+
+// literal matches, character matches, and basic integer matches
+void suite_one( void );
+// decimal integer matches
+void suite_two( void );
+// hexadecimal integer matches
+void suite_three( void );
+// octal integer matches
+void suite_four( void );
+// string matches
+void suite_five( void );
+
+int main()
+{
+    suite_one();
+    suite_two();
+    suite_three();
+    suite_four();
+    suite_five();
+}
+
+// literal matches, character matches, and basic integer matches
+void suite_one()
+{
+    FILE * file;
+    if ( ( file = fopen( "tmpfile", "wb+" ) ) == NULL )
+    {
+        puts( "Failed to open tmpfile for writing." );
+        return;
+    }
+    fprintf( file, "1234567890" );
+    fprintf( file, "1%c3-5+7%c9%c", 0, 0, -1 );
+    fprintf( file, "2 4 6 8 0%c", 255 );
+    fprintf( file, "1 \011 5%%%%  0" );
+    CHECK_EQUAL( ftell( file ), 40 );
+
+    // -----------------------------------------------------------------------
+    // Literal matching
+    // -----------------------------------------------------------------------
+    {
+    // matching six characters literally
+    // checking via %n
+    // should report six characters read
+    fseek( file, 0, SEEK_SET );
+    int n;
+    CHECK_EQUAL( fscanf( file, "123456%n", &n ), 0 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 6 );
+    }
+    {
+    // matching a character, three whitespace chars, and another character
+    // checking via %n
+    // should report five characters read
+    fseek( file, 30, SEEK_SET );
+    int n;
+    CHECK_EQUAL( fscanf( file, "1 5%n", &n ), 0 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 35 );
+    }
+    {
+    // matching three characters, not matching whitespaces, and matching another three characters
+    // checking via %n
+    // should report six characters matched
+    fseek( file, 0, SEEK_SET );
+    int n;
+    CHECK_EQUAL( fscanf( file, "123  456%n", &n ), 0 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 6 );
+    }
+    {
+    // matching a character, two '%' characters, and two whitespaces
+    // checking via %n
+    // should report five characters matched
+    fseek( file, 34, SEEK_SET );
+    int n;
+    CHECK_EQUAL( fscanf( file, "5%%%% %n", &n ), 0 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 39 );
+    }
+    {
+    // seeking to last character in file, trying to match that char and a whitespace
+    // checking via %n
+    // should report one character matched and EOF
+    fseek( file, -1, SEEK_END );
+    int n;
+    CHECK_EQUAL( fscanf( file, "0 %n", &n ), 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_TRUE( feof( file ) );
+    CHECK_FALSE( ferror( file ) );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+    {
+    // seeking to end of file, trying to match a -1
+    // checking via %n
+    // should report error, not executing %n
+    fseek( file, 0, SEEK_END );
+    int n = -1;
+    CHECK_EQUAL( fscanf( file, "\377%n", &n ), -1 );
+    CHECK_EQUAL( n, -1 );
+    CHECK_TRUE( feof( file ) );
+    CHECK_FALSE( ferror( file ) );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+
+    // -----------------------------------------------------------------------
+    // Character matching ('%c')
+    // -----------------------------------------------------------------------
+    {
+    // reading a char array of specified width, including zero bytes
+    // should report the characters read, no zero termination of the array
+    fseek( file, 10, SEEK_SET );
+    char buffer[ 8 ];
+    memset( buffer, '\177', 8 );
+    CHECK_EQUAL( fscanf( file, "%7c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "1\0003-5+7\177", 8 ) );
+    CHECK_EQUAL( ftell( file ), 17 );
+    }
+    {
+    // reading a char array of unspecified width when positioned at -1 value 
+    // should default to width one, read the -1 value, no zero termination of the array
+    fseek( file, 19, SEEK_SET );
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( fscanf( file, "%c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "\377\177", 2 ) );
+    CHECK_EQUAL( ftell( file ), 20 );
+    }
+    {
+    // reading a char array of specified width 1 when positioned at (non-space) whitespace
+    // should read the whitespace (literally), no zero termination of the array
+    fseek( file, 32, SEEK_SET );
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( fscanf( file, "%1c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "\011\177", 2 ) );
+    CHECK_EQUAL( ftell( file ), 33 );
+    }
+    {
+    // reading a char array of specified width 2 when positioned at last char of file
+    // should read the character, and report EOF
+    fseek( file, -1, SEEK_END );
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( fscanf( file, "%2c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "0\177", 2 ) );
+    CHECK_TRUE( feof( file ) );
+    CHECK_FALSE( ferror( file ) );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+    {
+    // reading a char array of specified width 1 when positioned at last char of file
+    // should read the character, and NOT report EOF
+    fseek( file, -1, SEEK_END );
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( fscanf( file, "%1c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "0\177", 2 ) );
+    CHECK_FALSE( feof( file ) );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+    {
+    // reading a char array of specified width 1 when positioned at EOF
+    // should report input error before any conversion (-1)
+    fseek( file, 0, SEEK_END );
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( fscanf( file, "%1c", buffer ), -1 );
+    CHECK_FALSE( memcmp( buffer, "\177\177", 2 ) );
+    CHECK_TRUE( feof( file ) );
+    CHECK_FALSE( ferror( file ) );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+
+    // -----------------------------------------------------------------------
+    // Integer matching ('%d')
+    // -----------------------------------------------------------------------
+    {
+    // reading a whitespace-terminated integer
+    fseek( file, 20, SEEK_SET );
+    int i;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 21 );
+    }
+    {
+    // reading a -1 terminated integer
+    fseek( file, 18, SEEK_SET );
+    int i;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 9 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 19 );
+    }
+    {
+    // reading a EOF terminated integer
+    fseek( file, -1, SEEK_END );
+    int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+    {
+    // trying to read an integer when positioned at whitespace
+    // should skip whitespaces
+    fseek( file, 32, SEEK_SET );
+    int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 5 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 35 );
+    }
+    {
+    // trying to read an integer when positioned at -1 value
+    // should report matching failure
+    fseek( file, 19, SEEK_SET );
+    int i = 0;
+    int n = -1;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 0 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, -1 );
+    CHECK_EQUAL( ftell( file ), 19 );
+    }
+    {
+    // trying to read an integer when positioned at EOF
+    // should report reading failure
+    fseek( file, 0, SEEK_END );
+    int i = 0;
+    int n = -1;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), -1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, -1 );
+    CHECK_EQUAL( ftell( file ), 40 );
+    }
+    {
+    // reading a '-'-prefixed integer
+    fseek( file, 13, SEEK_SET );
+    int i;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -5 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading a '+'-prefixed integer
+    fseek( file, 15, SEEK_SET );
+    int i;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 7 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 17 ); 
+    }
+
+    fclose( file );
+    remove( "tmpfile" );
+}
+
+// decimal integer matches
+void suite_two()
+{
+    FILE * file;
+    if ( ( file = fopen( "tmpfile", "wb+" ) ) == NULL )
+    {
+        puts( "Failed to open tmpfile for writing." );
+        return;
+    }
+    fprintf( file, "-0 +0 -128 +127 +255 -32768 +32767 +65535\n" );
+    fprintf( file, "-2147483648 +2147483647 +4294967295\n" );
+    fprintf( file, "-9223372036854775808 +9223372036854775807 +18446744073709551615\n" );
+    CHECK_EQUAL( ftell( file ), 142 );
+    {
+    // reading 0, d
+    fseek( file, 1, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, d
+    fseek( file, 0, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, d
+    fseek( file, 3, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -128, d
+    fseek( file, 6, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -128 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 10 );
+    }
+    {
+    // reading 127, d
+    fseek( file, 12, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading +127, d
+    fseek( file, 11, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading 0, u
+    fseek( file, 1, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, u
+    fseek( file, 0, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, u
+    fseek( file, 3, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading 127, u
+    fseek( file, 12, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading +127, u
+    fseek( file, 11, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading 255, u
+    fseek( file, 17, SEEK_SET );
+    unsigned char i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 255 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 20 );
+    }
+    {
+    // reading +255, u
+    fseek( file, 16, SEEK_SET );
+    unsigned char i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 255 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 20 );
+    }
+    {
+    // reading 0, i
+    fseek( file, 1, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, i
+    fseek( file, 0, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, i
+    fseek( file, 3, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -128, i
+    fseek( file, 6, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -128 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 10 );
+    }
+    {
+    // reading 127, i
+    fseek( file, 12, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading +127, i
+    fseek( file, 11, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 15 );
+    }
+    {
+    // reading 0, d
+    fseek( file, 1, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, d
+    fseek( file, 0, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, d
+    fseek( file, 3, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -32768, d
+    fseek( file, 21, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -32768 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 27 );
+    }
+    {
+    // reading 32767, d
+    fseek( file, 29, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 34 );
+    }
+    {
+    // reading +32767, d
+    fseek( file, 28, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 34 );
+    }
+    {
+    // reading 0, u
+    fseek( file, 1, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, u
+    fseek( file, 0, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, u
+    fseek( file, 3, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading 32767, u
+    fseek( file, 29, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 34 );
+    }
+    {
+    // reading +32767, u
+    fseek( file, 28, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 34 );
+    }
+    {
+    // reading 65535, u
+    fseek( file, 36, SEEK_SET );
+    unsigned short i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 41 );
+    }
+    {
+    // reading +65535, u
+    fseek( file, 35, SEEK_SET );
+    unsigned short i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 41 );
+    }
+    {
+    // reading 0, i
+    fseek( file, 1, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, i
+    fseek( file, 0, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, i
+    fseek( file, 3, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -32768, i
+    fseek( file, 21, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -32768 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 27 );
+    }
+    {
+    // reading 32767, i
+    fseek( file, 29, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 34 );
+    }
+    {
+    // reading +32767, i
+    fseek( file, 28, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 34 );
+    }
+    {
+    // reading 0, d
+    fseek( file, 1, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, d
+    fseek( file, 0, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, d
+    fseek( file, 3, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -2147483648, d
+    fseek( file, 42, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648 );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 53 );
+    }
+    {
+    // reading 2147483647, d
+    fseek( file, 55, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading +2147483647, d
+    fseek( file, 54, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading 0, u
+    fseek( file, 1, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, u
+    fseek( file, 0, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, u
+    fseek( file, 3, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading 2147483647, u
+    fseek( file, 55, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading +2147483647, u
+    fseek( file, 54, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading 4294967295, u
+    fseek( file, 67, SEEK_SET );
+    unsigned int i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%u" );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 77 );
+    }
+    {
+    // reading +4294967295, u
+    fseek( file, 66, SEEK_SET );
+    unsigned int i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%u%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%u" );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 77 );
+    }
+    {
+    // reading 0, i
+    fseek( file, 1, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, i
+    fseek( file, 0, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, i
+    fseek( file, 3, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -2147483648, i
+    fseek( file, 42, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648 );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 53 );
+    }
+    {
+    // reading 2147483647, i
+    fseek( file, 55, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading +2147483647, i
+    fseek( file, 54, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading 0, d
+    fseek( file, 1, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, d
+    fseek( file, 0, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, d
+    fseek( file, 3, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -2147483648, d
+    fseek( file, 42, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648l );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 53 );
+    }
+    {
+    // reading 2147483647, d
+    fseek( file, 55, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading +2147483647, d
+    fseek( file, 54, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading 0, u
+    fseek( file, 1, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ul );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, u
+    fseek( file, 0, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ul );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, u
+    fseek( file, 3, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ul );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading 2147483647, u
+    fseek( file, 55, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647ul );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading +2147483647, u
+    fseek( file, 54, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647ul );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading 4294967295, u
+    fseek( file, 67, SEEK_SET );
+    unsigned long i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295ul, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 77 );
+    }
+    {
+    // reading +4294967295, u
+    fseek( file, 66, SEEK_SET );
+    unsigned long i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295ul, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 77 );
+    }
+    {
+    // reading 0, i
+    fseek( file, 1, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, i
+    fseek( file, 0, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, i
+    fseek( file, 3, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -2147483648, i
+    fseek( file, 42, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648l );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 53 );
+    }
+    {
+    // reading 2147483647, i
+    fseek( file, 55, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading +2147483647, i
+    fseek( file, 54, SEEK_SET );
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 65 );
+    }
+    {
+    // reading 0, d
+    fseek( file, 1, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, d
+    fseek( file, 0, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, d
+    fseek( file, 3, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -9223372036854775808, d
+    fseek( file, 78, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lld%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, LLONG_MIN, signed long long, "%lld" ); // should be literal -9223372036854775808ll but GCC balks.
+    CHECK_EQUAL( i < 0ll, 1 );
+    CHECK_EQUAL( n, 20 );
+    CHECK_EQUAL( ftell( file ), 98 );
+    }
+    {
+    // reading 9223372036854775807, d
+    fseek( file, 100, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lld%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lld" );
+    CHECK_EQUAL( n, 19 );
+    CHECK_EQUAL( ftell( file ), 119 );
+    }
+    {
+    // reading +9223372036854775807, d
+    fseek( file, 99, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lld%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lld" );
+    CHECK_EQUAL( n, 20 );
+    CHECK_EQUAL( ftell( file ), 119 );
+    }
+    {
+    // reading 0, u
+    fseek( file, 1, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ull );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, u
+    fseek( file, 0, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ull );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, u
+    fseek( file, 3, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ull );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading 9223372036854775807, u
+    fseek( file, 100, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 19 );
+    CHECK_EQUAL( ftell( file ), 119 );
+    }
+    {
+    // reading +9223372036854775807, u
+    fseek( file, 99, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 20 );
+    CHECK_EQUAL( ftell( file ), 119 );
+    }
+    {
+    // reading 18446744073709551615, u
+    fseek( file, 121, SEEK_SET );
+    unsigned long long i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 20 );
+    CHECK_EQUAL( ftell( file ), 141 );
+    }
+    {
+    // reading +18446744073709551615, u
+    fseek( file, 120, SEEK_SET );
+    unsigned long long i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 21 );
+    CHECK_EQUAL( ftell( file ), 141 );
+    }
+    {
+    // reading 0, i
+    fseek( file, 1, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lli%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading -0, i
+    fseek( file, 0, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lli%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 2 );
+    }
+    {
+    // reading +0, i
+    fseek( file, 3, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lli%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -9223372036854775808, i
+    fseek( file, 78, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lli%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, LLONG_MIN, signed long long, "%lli" ); // should be literal -9223372036854775808ll but GCC balks.
+    CHECK_EQUAL( i < 0ll, 1 );
+    CHECK_EQUAL( n, 20 );
+    CHECK_EQUAL( ftell( file ), 98 );
+    }
+    {
+    // reading 9223372036854775807, i
+    fseek( file, 100, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lli%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lli" );
+    CHECK_EQUAL( n, 19 );
+    CHECK_EQUAL( ftell( file ), 119 );
+    }
+    {
+    // reading +9223372036854775807, i
+    fseek( file, 99, SEEK_SET );
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lli%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lli" );
+    CHECK_EQUAL( n, 20 );
+    CHECK_EQUAL( ftell( file ), 119 );
+    }
+    
+    fclose( file );
+    remove( "tmpfile" );
+}
+
+// hexadecimal integer matches
+void suite_three()
+{
+    FILE * file;
+    if ( ( file = fopen( "tmpfile", "wb+" ) ) == NULL )
+    {
+        puts( "Failed to open tmpfile for writing." );
+        return;
+    }
+    fprintf( file, "-0x0 -0x000 -0x7f 0x80 0xff -0x7fff 0x8000 0xffff -0x7fffffff 0x80000000 0xffffffff\n" );
+    fprintf( file, "-0x7fffffffffffffff 0x8000000000000000 0xffffffffffffffff -0x\n" );
+    CHECK_EQUAL( ftell( file ), 146 );
+    {
+    // reading 0, x
+    fseek( file, 3, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading -0x0, x
+    fseek( file, 0, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading -0x, x
+    fseek( file, -4, SEEK_END );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 145 );
+    }
+    {
+    // reading 0x000, x
+    fseek( file, 5, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 11 );
+    }
+    {
+    // reading 0x0, i
+    fseek( file, 0, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading 7f, x
+    fseek( file, 15, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 17 );
+    }
+    {
+    // reading -0x7f, x
+    fseek( file, 12, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -127, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 17 );
+    }
+    {
+    // reading 0x80, i
+    fseek( file, 18, SEEK_SET );
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -128, signed char, "%hd" );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 22 );
+    }
+    {
+    // reading ff, x
+    fseek( file, 25, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0xff );
+    CHECK_EQUAL( n, 2 );
+    CHECK_EQUAL( ftell( file ), 27 );
+    }
+    {
+    // reading 0xff, x
+    fseek( file, 23, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 255 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 27 );
+    }
+    {
+    // reading 0xff, i
+    fseek( file, 23, SEEK_SET );
+    signed char i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -1 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 27 );
+    }
+    {
+    // reading 0, x
+    fseek( file, 3, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading -0x0, x
+    fseek( file, 0, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading -0x, x
+    fseek( file, -4, SEEK_END );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 145 );
+    }
+    {
+    // reading 0x000, x
+    fseek( file, 5, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 11 );
+    }
+    {
+    // reading 0x0, i
+    fseek( file, 0, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading 7fff, x
+    fseek( file, 31, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 35 );
+    }
+    {
+    // reading -0x7fff, x
+    fseek( file, 28, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -32767, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 7 );
+    CHECK_EQUAL( ftell( file ), 35 );
+    }
+    {
+    // reading 0x8000, i
+    fseek( file, 36, SEEK_SET );
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -32768, signed short, "%hd" );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 42 );
+    }
+    {
+    // reading ffff, x
+    fseek( file, 45, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 49 );
+    }
+    {
+    // reading 0xffff, x
+    fseek( file, 43, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 49 );
+    }
+    {
+    // reading 0xffff, i
+    fseek( file, 43, SEEK_SET );
+    signed short i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hi%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -1, signed short, "%hd" );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 49 );
+    }
+    {
+    // reading 0, x
+    fseek( file, 3, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading -0x0, x
+    fseek( file, 0, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading -0x, x
+    fseek( file, -4, SEEK_END );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_EQUAL( ftell( file ), 145 );
+    }
+    {
+    // reading 0x000, x
+    fseek( file, 5, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 11 );
+    }
+    {
+    // reading 0x0, i
+    fseek( file, 0, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 4 );
+    }
+    {
+    // reading 7fffffff, x
+    fseek( file, 53, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 8 );
+    CHECK_EQUAL( ftell( file ), 61 );
+    }
+    {
+    // reading -0x7fffffff, x
+    fseek( file, 50, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -2147483647, unsigned int, "%u" );
+    CHECK_EQUAL( n, 11 );
+    CHECK_EQUAL( ftell( file ), 61 );
+    }
+    {
+    // reading 0x80000000, i
+    fseek( file, 62, SEEK_SET );
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 2147483647, signed int, "%d" ); // NOT overflowing, see strtol() specs.
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 72 );
+    }
+    {
+    // reading ffffffff, x
+    fseek( file, 75, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%d" );
+    CHECK_EQUAL( n, 8 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    {
+    // reading 0xffffffff, x
+    fseek( file, 73, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%x%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%d" );
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    {
+    // reading 0xffffffff, i
+    fseek( file, 73, SEEK_SET );
+    signed int i = 0;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%i%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 2147483647, signed int, "%d" ); // NOT overflowing; see strtol() specs.
+    CHECK_EQUAL( n, 10 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    fclose( file );
+    remove( "tmpfile" );    
+}
+
+// octal integer matches
+void suite_four()
+{
+    FILE * file;
+    if ( ( file = fopen( "tmpfile", "wb+" ) ) == NULL )
+    {
+        puts( "Failed to open tmpfile for writing." );
+        return;
+    }
+    fprintf( file, "+0000 -0000 +0177 +0377 -0377 +077777 +0177777 -0177777\n" );
+    fprintf( file, "+017777777777 +037777777777 -037777777777\n" );
+    fprintf( file, "+0777777777777777777777 +01777777777777777777777\n" );
+    fprintf( file, "-01777777777777777777777\n" );
+    CHECK_EQUAL( ftell( file ), 172 );
+    {
+    // reading 0, o
+    fseek( file, 4, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0u );
+    CHECK_EQUAL( n, 1 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading +0000, o
+    fseek( file, 0, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0u );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 5 );
+    }
+    {
+    // reading -0000, o
+    fseek( file, 6, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0u );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 11 );
+    }
+    {
+    // reading 0177, o
+    fseek( file, 13, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127u );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 17 );
+    }
+    {
+    // reading +0177, o
+    fseek( file, 12, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127u );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 17 );
+    }
+    {
+    // reading 0377, o
+    fseek( file, 19, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 255u, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 4 );
+    CHECK_EQUAL( ftell( file ), 23 );
+    }
+    {
+    // reading +0377, o
+    fseek( file, 18, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 255u, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 23 );
+    }
+    {
+    // reading -0377, o
+    fseek( file, 24, SEEK_SET );
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%hho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1u, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 5 );
+    CHECK_EQUAL( ftell( file ), 29 );
+    }
+    {
+    // reading 077777, o
+    fseek( file, 31, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767u );
+    CHECK_EQUAL( n, 6 );
+    CHECK_EQUAL( ftell( file ), 37 );
+    }
+    {
+    // reading +077777, o
+    fseek( file, 30, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767u );
+    CHECK_EQUAL( n, 7 );
+    CHECK_EQUAL( ftell( file ), 37 );
+    }
+    {
+    // reading 0177777, o
+    fseek( file, 39, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 65535u, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 7 );
+    CHECK_EQUAL( ftell( file ), 46 );
+    }
+    {
+    // reading +0177777, o
+    fseek( file, 38, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 65535u, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 8 );
+    CHECK_EQUAL( ftell( file ), 46 );
+    }
+    {
+    // reading -0177777, o
+    fseek( file, 47, SEEK_SET );
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%ho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1u, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 8 );
+    CHECK_EQUAL( ftell( file ), 55 );
+    }
+    {
+    // reading 017777777777, o
+    fseek( file, 57, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%o%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647u );
+    CHECK_EQUAL( n, 12 );
+    CHECK_EQUAL( ftell( file ), 69 );
+    }
+    {
+    // reading +017777777777, o
+    fseek( file, 56, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%o%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647u );
+    CHECK_EQUAL( n, 13 );
+    CHECK_EQUAL( ftell( file ), 69 );
+    }
+    {
+    // reading 037777777777, o
+    fseek( file, 71, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%o%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295u, unsigned int, "%u" );
+    CHECK_EQUAL( n, 12 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    {
+    // reading +037777777777, o
+    fseek( file, 70, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%o%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295u, unsigned int, "%u" );
+    CHECK_EQUAL( n, 13 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    {
+    // reading -037777777777, o
+    fseek( file, 84, SEEK_SET );
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%o%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1u, unsigned int, "%u" );
+    CHECK_EQUAL( n, 13 );
+    CHECK_EQUAL( ftell( file ), 97 );
+    }
+    {
+    // reading 017777777777, o
+    fseek( file, 57, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lo%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647lu );
+    CHECK_EQUAL( n, 12 );
+    CHECK_EQUAL( ftell( file ), 69 );
+    }
+    {
+    // reading +017777777777, o
+    fseek( file, 56, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lo%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647lu );
+    CHECK_EQUAL( n, 13 );
+    CHECK_EQUAL( ftell( file ), 69 );
+    }
+    {
+    // reading 037777777777, o
+    fseek( file, 71, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295lu, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 12 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    {
+    // reading +037777777777, o
+    fseek( file, 70, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295lu, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 13 );
+    CHECK_EQUAL( ftell( file ), 83 );
+    }
+    {
+    // reading -037777777777, o
+    fseek( file, 84, SEEK_SET );
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%lo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1lu, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 13 );
+    CHECK_EQUAL( ftell( file ), 97 );
+    }
+    {
+    // reading 0777777777777777777777, o
+    fseek( file, 99, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 22 );
+    CHECK_EQUAL( ftell( file ), 121 );
+    }
+    {
+    // reading +0777777777777777777777, o
+    fseek( file, 98, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 23 );
+    CHECK_EQUAL( ftell( file ), 121 );
+    }
+    {
+    // reading 01777777777777777777777, o
+    fseek( file, 123, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 23 );
+    CHECK_EQUAL( ftell( file ), 146 );
+    }
+    {
+    // reading +01777777777777777777777, o
+    fseek( file, 122, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 24 );
+    CHECK_EQUAL( ftell( file ), 146 );
+    }
+    {
+    // reading -01777777777777777777777, o
+    fseek( file, 147, SEEK_SET );
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( fscanf( file, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 24 );
+    CHECK_EQUAL( ftell( file ), 171 );
+    }
+    fclose( file );
+    remove( "tmpfile" );    
+}
+
+// string matches
+void suite_five()
+{
+    int const BUFSIZE = 1000;
+    FILE * file;
+    if ( ( file = fopen( "tmpfile", "wb+" ) ) == NULL )
+    {
+        puts( "Failed to open tmpfile for writing." );
+        return;
+    }
+    fprintf( file, "abcdefgh-ijklmnop[qrs%%uvw]xyz" );
+    CHECK_EQUAL( ftell( file ), 29 );
+    char buffer[ BUFSIZE ];
+    {
+    // reading abc
+    fseek( file, 0, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[abc]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_FALSE( memcmp( buffer, "abc", n + 1 ) );
+    CHECK_EQUAL( ftell( file ), 3 );
+    }
+    {
+    // reading a-c
+    fseek( file, 0, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[a-c]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_FALSE( memcmp( buffer, "abc", n + 1 ) );
+    CHECK_EQUAL( ftell( file ), 3 );
+    }
+    {
+    // reading a-h
+    fseek( file, 0, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[a-h]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 8 );
+    CHECK_FALSE( memcmp( buffer, "abcdefgh", n + 1 ) );
+    CHECK_EQUAL( ftell( file ), 8 );
+    }
+    {
+    // reading o-r, including [, seperate char
+    fseek( file, 15, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[[o-qr]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_FALSE( memcmp( buffer, "op[qr", n + 1 ) );
+    CHECK_EQUAL( ftell( file ), 20 );
+    }
+    {
+    // reading v-y, including ], two groups
+    fseek( file, 23, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[]v-wx-y]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_FALSE( memcmp( buffer, "vw]xy", n + 1 ) );
+    CHECK_EQUAL( ftell( file ), 28 );
+    }
+    {
+    // missing on first character
+    fseek( file, 0, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[b]%n", buffer, &n ), 0 );
+    CHECK_FALSE( memcmp( buffer, "", 1 ) );
+    CHECK_EQUAL( ftell( file ), 0 );
+    }
+    {
+    // eof while reading, two groups
+    fseek( file, 27, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[a-zA-Z]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_FALSE( memcmp( buffer, "yz", n + 1 ) );
+    CHECK_TRUE( feof( file ) );
+    CHECK_FALSE( ferror( file ) );
+    CHECK_EQUAL( ftell( file ), 29 );
+    }
+    {
+    // eof before reading
+    fseek( file, 29, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[a-z]%n", buffer, &n ), -1 );
+    CHECK_FALSE( memcmp( buffer, "", 1 ) );
+    CHECK_TRUE( feof( file ) );
+    CHECK_FALSE( ferror( file ) );
+    CHECK_EQUAL( ftell( file ), 29 );
+    }
+    {
+    // negation - [^...]
+    fseek( file, 0, SEEK_SET );
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( fscanf( file, "%[^d-f]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_FALSE( memcmp( buffer, "abc", 4 ) );
+    CHECK_EQUAL( ftell( file ), 3 );
+    }
+    fclose( file );
+    remove( "tmpfile" );    
+}
+
+#if 0
 char scanstring[] = "  1 23\00045\000\00067 ";
 
 void scantest( int testnr, FILE * fh, size_t position, char const * format, 
@@ -77,5 +2078,6 @@ int main( void )
 
     return TEST_RESULTS;
 }
+#endif
 
 #endif
index 368ae53a7f18f19c6436df0dcec44bcd395b72ef..b7011089e07ac171ed576bf3e1b90b6366683164 100644 (file)
 
 int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict format, ... )
 {
+    int rc;
     va_list ap;
     va_start( ap, format );
-    return vsscanf( s, format, ap );
+    rc = vsscanf( s, format, ap );
+    va_end( ap );
+    return rc;
 }
 
 #endif
@@ -23,10 +26,1577 @@ int sscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict forma
 #ifdef TEST
 #include <_PDCLIB_test.h>
 
-int main( void )
+#include <string.h>
+#include <limits.h>
+
+#define symbol2value( x ) #x
+#define symbol2string( x ) symbol2value( x )
+
+#define CHECK_TRUE( a ) do { if ( a == 0 ) { fprintf( stderr, "Unexpected failure in " symbol2string( __LINE__ ) ": '" #a "' evaluated to false.\n" ); rc += 1; } } while ( 0 )
+#define CHECK_FALSE( a ) do { if ( a != 0 ) { fprintf( stderr, "Unexpected failure in " symbol2string( __LINE__ ) ": '" #a "' evaluated to true.\n" ); rc += 1; } } while ( 0 )
+#define CHECK_EQUAL( a, b ) do { int x = a; int y = b; if ( x != y ) { fprintf( stderr, "Mismatch in " symbol2string( __LINE__ ) ": result is %d, expected %d.\n", x, y ); rc += 1; } } while ( 0 )
+#define CHECK_FEQUAL( a, b, T, F ) do { T x = a; T y = b; if ( x != y ) { fprintf( stderr, "Mismatch in " symbol2string( __LINE__ ) ": result is " F ", expected " F ".\n", x, y ); rc += 1; } } while ( 0 )
+
+// literal matches, character matches, and basic integer matches
+void suite_one( void );
+// decimal integer matches
+void suite_two( void );
+// hexadecimal integer matches
+void suite_three( void );
+// octal integer matches
+void suite_four( void );
+// string matches
+void suite_five( void );
+
+int main()
+{
+    suite_one();
+    suite_two();
+    suite_three();
+    suite_four();
+    suite_five();
+}
+
+// literal matches, character matches, and basic integer matches
+void suite_one()
+{
+    char const * string = "12345678901\0003-5+7\0009\3772 4 6 8 0\3771 \011 5%%  0";
+    CHECK_EQUAL( string[39], '0' );
+
+    // -----------------------------------------------------------------------
+    // Literal matching
+    // -----------------------------------------------------------------------
+    {
+    // matching six characters literally
+    // checking via %n
+    // should report six characters read
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "123456%n", &n ), 0 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // matching a character, three whitespace chars, and another character
+    // checking via %n
+    // should report five characters read
+    int n;
+    CHECK_EQUAL( sscanf( string + 30, "1 5%n", &n ), 0 );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // matching three characters, not matching whitespaces, and matching another three characters
+    // checking via %n
+    // should report six characters matched
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "123  456%n", &n ), 0 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // matching a character, two '%' characters, and two whitespaces
+    // checking via %n
+    // should report five characters matched
+    int n;
+    CHECK_EQUAL( sscanf( string + 34, "5%%%% %n", &n ), 0 );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // seeking to last character in file, trying to match that char and a whitespace
+    // checking via %n
+    // should report one character matched and EOF
+    int n;
+    CHECK_EQUAL( sscanf( string + 39, "0 %n", &n ), 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // seeking to end of file, trying to match a -1
+    // checking via %n
+    // should report error, not executing %n
+    int n = -1;
+    CHECK_EQUAL( sscanf( string + 0, "\377%n", &n ), 0 );
+    CHECK_EQUAL( n, -1 );
+    }
+
+    // -----------------------------------------------------------------------
+    // Character matching ('%c')
+    // -----------------------------------------------------------------------
+    {
+    // reading a char array of specified width, including zero bytes
+    // should report the characters read up to first zero
+    char buffer[ 8 ];
+    memset( buffer, '\177', 8 );
+    CHECK_EQUAL( sscanf( string + 10, "%7c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "1\177\177", 3 ) );
+    }
+    {
+    // reading a char array of unspecified width when positioned at -1 value 
+    // should default to width one, read the -1 value, no zero termination of the array
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( sscanf( string + 19, "%c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "\377\177", 2 ) );
+    }
+    {
+    // reading a char array of specified width 1 when positioned at (non-space) whitespace
+    // should read the whitespace (literally), no zero termination of the array
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( sscanf( string + 32, "%1c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "\011\177", 2 ) );
+    }
+    {
+    // reading a char array of specified width 2 when positioned at last char of file
+    // should read the character, and report EOF
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( sscanf( string + 39, "%2c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "0\177", 2 ) );
+    }
+    {
+    // reading a char array of specified width 1 when positioned at last char of file
+    // should read the character, and NOT report EOF
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( sscanf( string + 39, "%1c", buffer ), 1 );
+    CHECK_FALSE( memcmp( buffer, "0\177", 2 ) );
+    }
+    {
+    // reading a char array of specified width 1 when positioned at EOF
+    // should report input error before any conversion (-1)
+    char buffer[ 2 ];
+    memset( buffer, '\177', 2 );
+    CHECK_EQUAL( sscanf( string + 40, "%1c", buffer ), -1 );
+    CHECK_FALSE( memcmp( buffer, "\177\177", 2 ) );
+    }
+
+    // -----------------------------------------------------------------------
+    // Integer matching ('%d')
+    // -----------------------------------------------------------------------
+    {
+    // reading a whitespace-terminated integer
+    int i;
+    int n;
+    CHECK_EQUAL( sscanf( string + 20, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading a -1 terminated integer
+    int i;
+    int n;
+    CHECK_EQUAL( sscanf( string + 18, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 9 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading a EOF terminated integer
+    int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 39, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // trying to read an integer when positioned at whitespace
+    // should skip whitespaces
+    int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 32, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 5 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // trying to read an integer when positioned at -1 value
+    // should report matching failure
+    int i = 0;
+    int n = -1;
+    CHECK_EQUAL( sscanf( string + 19, "%d%n", &i, &n ), 0 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, -1 );
+    }
+    {
+    // trying to read an integer when positioned at EOF
+    // should report reading failure
+    int i = 0;
+    int n = -1;
+    CHECK_EQUAL( sscanf( string + 40, "%d%n", &i, &n ), -1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, -1 );
+    }
+    {
+    // reading a '-'-prefixed integer
+    int i;
+    int n;
+    CHECK_EQUAL( sscanf( string + 13, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -5 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading a '+'-prefixed integer
+    int i;
+    int n;
+    CHECK_EQUAL( sscanf( string + 15, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 7 );
+    CHECK_EQUAL( n, 2 );
+    }
+}
+
+// decimal integer matches
+void suite_two()
+{
+    char const * string = "-0 +0 -128 +127 +255 -32768 +32767 +65535\n"
+                          "-2147483648 +2147483647 +4294967295\n"
+                          "-9223372036854775808 +9223372036854775807\n"
+                          "+18446744073709551615\n";
+    CHECK_EQUAL( string[141], '\n' );
+    {
+    // reading 0, d
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, d
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, d
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -128, d
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 6, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -128 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 127, d
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 12, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading +127, d
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 11, "%hhd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 0, u
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, u
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, u
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading 127, u
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 12, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading +127, u
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 11, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 255, u
+    unsigned char i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 17, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 255 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading +255, u
+    unsigned char i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 16, "%hhu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 255 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 0, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -128, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 6, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -128 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 127, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 12, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading +127, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 11, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 0, d
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, d
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, d
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -32768, d
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 21, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -32768 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 32767, d
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 29, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading +32767, d
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 28, "%hd%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0, u
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, u
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, u
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading 32767, u
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 29, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading +32767, u
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 28, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 65535, u
+    unsigned short i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 36, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading +65535, u
+    unsigned short i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 35, "%hu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -32768, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 21, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -32768 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 32767, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 29, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading +32767, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 28, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0, d
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, d
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, d
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -2147483648, d
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 42, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648 );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 2147483647, d
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 55, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +2147483647, d
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 54, "%d%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0, u
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, u
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, u
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading 2147483647, u
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 55, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +2147483647, u
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 54, "%u%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 4294967295, u
+    unsigned int i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 67, "%u%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%u" );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +4294967295, u
+    unsigned int i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 66, "%u%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%u" );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -2147483648, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 42, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648 );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 2147483647, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 55, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +2147483647, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 54, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0, d
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, d
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, d
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -2147483648, d
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 42, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648l );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 2147483647, d
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 55, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +2147483647, d
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 54, "%ld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0, u
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ul );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, u
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ul );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, u
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ul );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading 2147483647, u
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 55, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647ul );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +2147483647, u
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 54, "%lu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647ul );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 4294967295, u
+    unsigned long i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 67, "%lu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295ul, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +4294967295, u
+    unsigned long i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 66, "%lu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295ul, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0, i
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, i
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, i
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0l );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -2147483648, i
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 42, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -2147483648l );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 2147483647, i
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 55, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading +2147483647, i
+    signed long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 54, "%li%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647l );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0, d
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%lld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, d
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%lld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, d
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%lld%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -9223372036854775808, d
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 78, "%lld%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, LLONG_MIN, signed long long, "%lld" ); // should be literal -9223372036854775808ll but GCC balks.
+    CHECK_EQUAL( i < 0ll, 1 );
+    CHECK_EQUAL( n, 20 );
+    }
+    {
+    // reading 9223372036854775807, d
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 100, "%lld%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lld" );
+    CHECK_EQUAL( n, 19 );
+    }
+    {
+    // reading +9223372036854775807, d
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 99, "%lld%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lld" );
+    CHECK_EQUAL( n, 20 );
+    }
+    {
+    // reading 0, u
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%llu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ull );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, u
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%llu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ull );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, u
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%llu%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ull );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading 9223372036854775807, u
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 100, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 19 );
+    }
+    {
+    // reading +9223372036854775807, u
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 99, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 20 );
+    }
+    {
+    // reading 18446744073709551615, u
+    unsigned long long i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 121, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 20 );
+    }
+    {
+    // reading +18446744073709551615, u
+    unsigned long long i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 120, "%llu%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615ull, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 21 );
+    }
+    {
+    // reading 0, i
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 1, "%lli%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0, i
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%lli%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading +0, i
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%lli%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0ll );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -9223372036854775808, i
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 78, "%lli%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, LLONG_MIN, signed long long, "%lli" ); // should be literal -9223372036854775808ll but GCC balks.
+    CHECK_EQUAL( i < 0ll, 1 );
+    CHECK_EQUAL( n, 20 );
+    }
+    {
+    // reading 9223372036854775807, i
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 100, "%lli%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lli" );
+    CHECK_EQUAL( n, 19 );
+    }
+    {
+    // reading +9223372036854775807, i
+    signed long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 99, "%lli%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807ll, signed long long, "%lli" );
+    CHECK_EQUAL( n, 20 );
+    }
+}
+
+// hexadecimal integer matches
+void suite_three()
+{
+    char const * string = "-0x0 -0x000 -0x7f 0x80 0xff -0x7fff 0x8000\n"
+                          "0xffff -0x7fffffff 0x80000000 0xffffffff\n"
+                          "-0x7fffffffffffffff 0x8000000000000000\n"
+                          "0xffffffffffffffff -0x\n";
+    CHECK_EQUAL( string[145], '\n' );
+    {
+    // reading 0, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0x0, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading -0x, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 142, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading 0x000, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 5, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0x0, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 7f, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 15, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127 );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading -0x7f, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 12, "%hhx%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -127, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading 0x80, i
+    signed char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 18, "%hhi%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -128, signed char, "%hd" );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading ff, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 25, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0xff );
+    CHECK_EQUAL( n, 2 );
+    }
+    {
+    // reading 0xff, x
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 23, "%hhx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 255 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 0xff, i
+    signed char i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 23, "%hhi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, -1 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 0, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0x0, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading -0x, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 142, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading 0x000, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 5, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0x0, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hi%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 7fff, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 31, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading -0x7fff, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 28, "%hx%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -32767, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 7 );
+    }
+    {
+    // reading 0x8000, i
+    signed short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 36, "%hi%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -32768, signed short, "%hd" );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading ffff, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 45, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 0xffff, x
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 43, "%hx%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 65535 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0xffff, i
+    signed short i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 43, "%hi%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -1, signed short, "%hd" );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 3, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading -0x0, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading -0x, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 142, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 3 );
+    }
+    {
+    // reading 0x000, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 5, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading 0x0, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%i%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0 );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading 7fffffff, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 53, "%x%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647 );
+    CHECK_EQUAL( n, 8 );
+    }
+    {
+    // reading -0x7fffffff, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 50, "%x%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, -2147483647, unsigned int, "%u" );
+    CHECK_EQUAL( n, 11 );
+    }
+    {
+    // reading 0x80000000, i
+    signed int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 62, "%i%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 2147483647, signed int, "%d" ); // NOT overflowing, see strtol() specs.
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading ffffffff, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 75, "%x%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%d" );
+    CHECK_EQUAL( n, 8 );
+    }
+    {
+    // reading 0xffffffff, x
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 73, "%x%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295, unsigned int, "%d" );
+    CHECK_EQUAL( n, 10 );
+    }
+    {
+    // reading 0xffffffff, i
+    signed int i = 0;
+    int n;
+    CHECK_EQUAL( sscanf( string + 73, "%i%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 2147483647, signed int, "%d" ); // NOT overflowing; see strtol() specs.
+    CHECK_EQUAL( n, 10 );
+    }
+}
+
+// octal integer matches
+void suite_four()
+{
+    char const * string = "+0000 -0000 +0177 +0377 -0377 +077777 +0177777\n"
+                          "-0177777 +017777777777 +037777777777\n"
+                          "-037777777777 +0777777777777777777777\n"
+                          "+01777777777777777777777\n"
+                          "-01777777777777777777777\n";
+    CHECK_EQUAL( string[171], '\n' );
+    {
+    // reading 0, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 4, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0u );
+    CHECK_EQUAL( n, 1 );
+    }
+    {
+    // reading +0000, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0u );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading -0000, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 6, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 0u );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading 0177, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 13, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127u );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading +0177, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 12, "%hho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 127u );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading 0377, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 19, "%hho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 255u, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 4 );
+    }
+    {
+    // reading +0377, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 18, "%hho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 255u, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading -0377, o
+    unsigned char i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 24, "%hho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1u, unsigned char, "%hhu" );
+    CHECK_EQUAL( n, 5 );
+    }
+    {
+    // reading 077777, o
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 31, "%ho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767u );
+    CHECK_EQUAL( n, 6 );
+    }
+    {
+    // reading +077777, o
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 30, "%ho%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 32767u );
+    CHECK_EQUAL( n, 7 );
+    }
+    {
+    // reading 0177777, o
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 39, "%ho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 65535u, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 7 );
+    }
+    {
+    // reading +0177777, o
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 38, "%ho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 65535u, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 8 );
+    }
+    {
+    // reading -0177777, o
+    unsigned short i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 47, "%ho%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1u, unsigned short, "%hu" );
+    CHECK_EQUAL( n, 8 );
+    }
+    {
+    // reading 017777777777, o
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 57, "%o%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647u );
+    CHECK_EQUAL( n, 12 );
+    }
+    {
+    // reading +017777777777, o
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 56, "%o%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647u );
+    CHECK_EQUAL( n, 13 );
+    }
+    {
+    // reading 037777777777, o
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 71, "%o%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295u, unsigned int, "%u" );
+    CHECK_EQUAL( n, 12 );
+    }
+    {
+    // reading +037777777777, o
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 70, "%o%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295u, unsigned int, "%u" );
+    CHECK_EQUAL( n, 13 );
+    }
+    {
+    // reading -037777777777, o
+    unsigned int i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 84, "%o%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1u, unsigned int, "%u" );
+    CHECK_EQUAL( n, 13 );
+    }
+    {
+    // reading 017777777777, o
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 57, "%lo%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647lu );
+    CHECK_EQUAL( n, 12 );
+    }
+    {
+    // reading +017777777777, o
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 56, "%lo%n", &i, &n ), 1 );
+    CHECK_EQUAL( i, 2147483647lu );
+    CHECK_EQUAL( n, 13 );
+    }
+    {
+    // reading 037777777777, o
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 71, "%lo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295lu, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 12 );
+    }
+    {
+    // reading +037777777777, o
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 70, "%lo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 4294967295lu, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 13 );
+    }
+    {
+    // reading -037777777777, o
+    unsigned long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 84, "%lo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1lu, unsigned long, "%lu" );
+    CHECK_EQUAL( n, 13 );
+    }
+    {
+    // reading 0777777777777777777777, o
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 99, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 22 );
+    }
+    {
+    // reading +0777777777777777777777, o
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 98, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 9223372036854775807llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 23 );
+    }
+    {
+    // reading 01777777777777777777777, o
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 123, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 23 );
+    }
+    {
+    // reading +01777777777777777777777, o
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 122, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 18446744073709551615llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 24 );
+    }
+    {
+    // reading -01777777777777777777777, o
+    unsigned long long i = -1;
+    int n;
+    CHECK_EQUAL( sscanf( string + 147, "%llo%n", &i, &n ), 1 );
+    CHECK_FEQUAL( i, 1llu, unsigned long long, "%llu" );
+    CHECK_EQUAL( n, 24 );
+    }
+}
+
+// string matches
+void suite_five()
 {
-    TESTCASE( NO_TESTDRIVER );
-    return TEST_RESULTS;
+    char const * string = "abcdefgh-ijklmnop[qrs%uvw]xyz";
+    CHECK_EQUAL( string[28], 'z' );
+    size_t const BUFSIZE = 29;
+    char buffer[ BUFSIZE ];
+    {
+    // reading abc
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%[abc]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_FALSE( memcmp( buffer, "abc", n + 1 ) );
+    }
+    {
+    // reading a-c
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%[a-c]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_FALSE( memcmp( buffer, "abc", n + 1 ) );
+    }
+    {
+    // reading a-h
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%[a-h]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 8 );
+    CHECK_FALSE( memcmp( buffer, "abcdefgh", n + 1 ) );
+    }
+    {
+    // reading o-r, including [, seperate char
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 15, "%[[o-qr]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_FALSE( memcmp( buffer, "op[qr", n + 1 ) );
+    }
+    {
+    // reading v-y, including ], two groups
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 23, "%[]v-wx-y]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 5 );
+    CHECK_FALSE( memcmp( buffer, "vw]xy", n + 1 ) );
+    }
+    {
+    // missing on first character
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%[b]%n", buffer, &n ), 0 );
+    CHECK_FALSE( memcmp( buffer, "", 1 ) );
+    }
+    {
+    // eof while reading, two groups
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 27, "%[a-zA-Z]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 2 );
+    CHECK_FALSE( memcmp( buffer, "yz", n + 1 ) );
+    }
+    {
+    // eof before reading
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 29, "%[a-z]%n", buffer, &n ), -1 );
+    CHECK_FALSE( memcmp( buffer, "", 1 ) );
+    }
+    {
+    // negation - [^...]
+    memset( buffer, '\0', BUFSIZE );
+    int n;
+    CHECK_EQUAL( sscanf( string + 0, "%[^d-f]%n", buffer, &n ), 1 );
+    CHECK_EQUAL( n, 3 );
+    CHECK_FALSE( memcmp( buffer, "abc", 4 ) );
+    }
 }
 
 #endif
index 0667c990828f7757c124da7b5257faf42b4a47e9..f5b1f3f8864743c1b88944634af6c59ccbdfdde3 100644 (file)
@@ -25,6 +25,7 @@ int vfscanf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict forma
     status.prec = 0;
     status.stream = stream;
     va_copy( status.arg, arg );
+    // FIXME: This whole shebang should operate on STREAM, not S...
     while ( *format != '\0' )
     {
         const char * rc;
index f33b8c418e6e9d8a12d3cbcd2ee955f9b0c85ed9..fd35889ab4d200ead2782f2a1e732c9b76fc97a7 100644 (file)
@@ -59,9 +59,14 @@ int vsscanf( const char * _PDCLIB_restrict s, const char * _PDCLIB_restrict form
         }
         else
         {
-            /* NULL return code indicates matching error */
+            /* NULL return code indicates input error */
             if ( rc == NULL )
             {
+                if ( status.n == 0 )
+                {
+                    /* input error before any conversion returns EOF */
+                    status.n = EOF;
+                }
                 break;
             }
             /* Continue parsing after conversion specifier */
index 9019f72b4993b6d83db7f0f14a062148c8bca559..a950cf2257b19f7e9425f27010f9de361e86a237 100644 (file)
@@ -319,14 +319,14 @@ struct _PDCLIB_status_t
     _PDCLIB_int_fast32_t flags; /* flags and length modifiers                */
     _PDCLIB_size_t   n;     /* print: maximum characters to be written       */
                             /* scan:  number matched conversion specifiers   */
-    _PDCLIB_size_t   i;     /* number of characters already written          */
-    _PDCLIB_size_t   this;  /* output chars in the current conversion        */
-    char *           s;     /* print: target buffer                          */
-                            /* scan:  source string                          */
-    _PDCLIB_size_t   width; /* width of current field                        */
-    _PDCLIB_size_t   prec;  /* precision of current field                    */
-    struct _PDCLIB_file_t * stream;/* for to-stream output                   */
-    _PDCLIB_va_list  arg;   /* argument stack passed to the printf function  */
+    _PDCLIB_size_t   i;     /* number of characters read/written             */
+    _PDCLIB_size_t   this;  /* chars read/written in the CURRENT conversion  */
+    char *           s;     /* *sprintf(): target buffer                     */
+                            /* *sscanf():  source string                     */
+    _PDCLIB_size_t   width; /* specified field width                         */
+    _PDCLIB_size_t   prec;  /* specified field precision                     */
+    struct _PDCLIB_file_t * stream; /* *fprintf() / *fscanf() stream         */
+    _PDCLIB_va_list  arg;   /* argument stack                                */
 };
 
 /* -------------------------------------------------------------------------- */
@@ -356,9 +356,11 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status
 /* The worker for all scanf() type of functions. The pointer spec should point
    to the introducing '%' of a conversion specifier. The status structure is to
    be that of the current scanf() function, of which the member stream will be
-   preserved, n, i, and s will be updated; and all others will be trashed by the
-   function.
-   Returns a pointer to the first character not parsed as conversion specifier.
+   preserved; n, i, and s will be updated; and all others will be trashed by
+   the function.
+   Returns a pointer to the first character not parsed as conversion specifier,
+   or NULL in case of error.
+   FIXME: Should distinguish between matching and input error
 */
 const char * _PDCLIB_scan( const char * spec, struct _PDCLIB_status_t * status );