]> pd.if.org Git - pdclib/blobdiff - draft.c
More tests, unsigned fixes.
[pdclib] / draft.c
diff --git a/draft.c b/draft.c
index c5f7ad78b5c6eec47108cc2753fa4d65335ee456..027f70bd3700196f0a88d54caae3f2f59837e1cb 100644 (file)
--- a/draft.c
+++ b/draft.c
 /* Using an integer's bits as flags for both the conversion flags and length
    modifiers.
 */
-#define E_minus   1<<0
-#define E_plus    1<<1
-#define E_alt     1<<2
-#define E_space   1<<3
-#define E_zero    1<<4
-#define E_done    1<<5
-#define E_char    1<<6
-#define E_short   1<<7
-#define E_long    1<<8
-#define E_llong   1<<9
-#define E_intmax  1<<10
-#define E_size    1<<11
-#define E_ptrdiff 1<<12
-#define E_double  1<<13
-#define E_lower   1<<14
-#define E_term    1<<15
+#define E_minus    1<<0
+#define E_plus     1<<1
+#define E_alt      1<<2
+#define E_space    1<<3
+#define E_zero     1<<4
+#define E_done     1<<5
+#define E_char     1<<6
+#define E_short    1<<7
+#define E_long     1<<8
+#define E_llong    1<<9
+#define E_intmax   1<<10
+#define E_size     1<<11
+#define E_ptrdiff  1<<12
+#define E_double   1<<13
+#define E_lower    1<<14
+#define E_usigned  1<<15
 
 void parse_out( const char * spec, va_list ap );
 
 struct status_t
 {
-    int    base;  /* base to which the value shall be converted              */
-    int    flags; /* flags and length modifiers                              */
-    size_t n;     /* maximum number of characters to be written              */
-    size_t i;     /* number of characters already written                    */
-    size_t this;  /* number of output chars in the current conversion        */
-    char * s;     /* target buffer                                           */
-    size_t width; /* width of current field                                  */
-    int    prec;  /* precision of current field                              */
-};
-
-union value_t
-{
-      int8_t  int8;
-     uint8_t uint8;
-     int16_t  int16;
-    uint16_t uint16;
-     int32_t  int32;
-    uint32_t uint32;
-     int64_t  int64;
-    uint64_t uint64; 
+    int          base;  /* base to which the value shall be converted              */
+    int_fast16_t flags; /* flags and length modifiers                              */
+    size_t       n;     /* maximum number of characters to be written              */
+    size_t       i;     /* number of characters already written                    */
+    size_t       this;  /* number of output chars in the current conversion        */
+    char *       s;     /* target buffer                                           */
+    size_t       width; /* width of current field                                  */
+    size_t       prec;  /* precision of current field                              */
 };
 
 /* x - the character to be delivered
@@ -65,11 +53,6 @@ union value_t
 */
 #define DELIVER( x ) do { if ( status->i < status->n ) status->s[status->i] = x; ++(status->i); } while ( 0 )
 
-/* TODO: Left / right alignment - requires track-keeping of width and printed chars.
-   "Father function", die für right alignment "tail recursive" gerufen wird, und
-   "after" für left alignment? Parameter als struct?
-*/
-
 static void int2base( intmax_t value, struct status_t * status )
 {
     ++(status->this);
@@ -93,7 +76,7 @@ static void int2base( intmax_t value, struct status_t * status )
         {
             preface[ preidx++ ] = '-';
         }
-        else
+        else if ( ! ( status->flags & E_usigned ) )
         {
             if ( status->flags & E_plus )
             {
@@ -161,6 +144,41 @@ static void padwrap( intmax_t value, struct status_t * status )
     }
 }
 
+static void upadwrap( uintmax_t value, struct status_t * status )
+{
+    status->flags |= E_usigned;
+    ++(status->this);
+    if ( ( value / status->base ) != 0 )
+    {
+        int2base( value / status->base, status );
+    }
+    int digit = value % status->base;
+    if ( digit < 0 )
+    {
+        digit *= -1;
+    }
+    if ( status->flags & E_lower )
+    {
+        DELIVER( _PDCLIB_digits[ digit ] );
+    }
+    else
+    {
+        DELIVER( toupper( _PDCLIB_digits[ digit ] ) );
+    }
+    if ( status->flags & E_minus )
+    {
+        while ( status->this < status->width )
+        {
+            DELIVER( ' ' );
+            ++(status->this);
+        }
+    }
+    if ( status->i >= status->n )
+    {
+        status->s[status->n - 1] = '\0';
+    }
+}
+
 void parse_out( const char * spec, va_list ap )
 {
     /* TODO: '%' handled correctly? */
@@ -316,38 +334,8 @@ void parse_out( const char * spec, va_list ap )
     }
 }
 
-/*
-static void int2base( int value, int base, struct status_t * status )
-
-#define E_minus   1<<0
-#define E_plus    1<<1
-#define E_alt     1<<2
-#define E_space   1<<3
-#define E_zero    1<<4
-#define E_done    1<<5
-#define E_char    1<<6
-#define E_short   1<<7
-#define E_long    1<<8
-#define E_llong   1<<9
-#define E_intmax  1<<10
-#define E_size    1<<11
-#define E_ptrdiff 1<<12
-#define E_double  1<<13
-#define E_lower   1<<14
-
-        struct status_t
-{
-    int    flags; 
-    size_t n;     
-    size_t i;     
-    char * s;     
-    size_t width; 
-    size_t prec;  
-};
-*/
-
 #define TESTCASE( _flags, _n, _width, _prec, _value, _base, _expect ) \
-    status.flags = _flags | E_term; \
+    status.flags = _flags; \
     status.n = _n; \
     status.i = 0; \
     status.width = _width; \
@@ -362,6 +350,22 @@ static void int2base( int value, int base, struct status_t * status )
         printf( "Output '%s', RC %d\nExpect '%s', RC %d\n\n", status.s, status.i, buffer, rc ); \
     } \
 
+#define UTESTCASE( _flags, _n, _width, _prec, _value, _base, _expect ) \
+    status.flags = _flags; \
+    status.n = _n; \
+    status.i = 0; \
+    status.width = _width; \
+    status.prec = _prec; \
+    status.base = _base; \
+    status.this = 0; \
+    memset( status.s, '\0', 50 ); \
+    upadwrap( _value, &status ); \
+    rc = snprintf( buffer, _n, _expect, _value ); \
+    if ( ( strcmp( status.s, buffer ) != 0 ) || ( status.i != rc ) ) \
+{ \
+        printf( "Output '%s', RC %d\nExpect '%s', RC %d\n\n", status.s, status.i, buffer, rc ); \
+} \
+
 int main()
 {
     struct status_t status;
@@ -369,57 +373,87 @@ int main()
     int tmp;
     char * buffer = malloc( 50 );
     status.s = malloc( 50 );
-#if 0
-    TESTCASE( E_plus, 5, 0, 0, 1234, 10, "%+d" );
-    TESTCASE( E_space, 3, 0, 0, 1234, 10, "% d" );
-    TESTCASE( E_space, 3, 0, 0, -1234, 10, "% d" );
-    TESTCASE( E_plus, 3, 0, 0, -1234, 10, "%+d" );
-    TESTCASE( E_done, 4, 0, 0, 65535, 16, "%X" );
-    TESTCASE( E_lower | E_alt, 4, 0, 0, 65534, 16, "%#x" );
-    TESTCASE( E_done, 4, 0, 0, 62, 8, "%o" );
-    TESTCASE( E_alt, 4, 0, 0, 62, 8, "%#o" );
-    TESTCASE( E_done, 6, 6, 0, 1234, 10, "%6d" );
-    TESTCASE( E_minus, 6, 6, 0, 1234, 10, "%-6d" );
-    TESTCASE( E_minus, 6, 2, 0, 1234, 10, "%-2d" );
-    TESTCASE( E_done, 6, 2, 0, 1234, 10, "%2d" );
-    TESTCASE( E_zero, 6, 6, 0, -1234, 10, "%06d" );
-    /* TODO: These two are *unsigned* conversions! */
-    TESTCASE( E_zero, 7, 7, 0, -65535, 16, "%07X" );
-    TESTCASE( E_zero, 7, 7, 0, -65535, 10, "%07u" );
-
-    TESTCASE( E_zero | E_minus, 6, 6, 0, 1234, 10, "%-06d" );
-    TESTCASE( E_plus, 6, 6, 0, 1234, 10, "%+6d" );
-    TESTCASE( E_space, 6, 6, 0, 1234, 10, "% 6d" );
-    TESTCASE( E_space, 6, 6, 0, -1234, 10, "% 6d" );
-    TESTCASE( E_space | E_minus, 6, 6, 0, -1234, 10, "%- 6d" );
-#endif
-    puts( "--- Serious Tests ---\n" );
     puts( "- Signed min / max -\n" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, CHAR_MIN, 10, "%hhd" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, CHAR_MAX, 10, "%hhd" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, 0, 10, "%hhd" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, SHRT_MIN, 10, "%hd" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, SHRT_MAX, 10, "%hd" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, 0, 10, "%hd" );
+    TESTCASE( E_char, SIZE_MAX, 0, 0, CHAR_MIN, 10, "%hhd" );
+    TESTCASE( E_char, SIZE_MAX, 0, 0, CHAR_MAX, 10, "%hhd" );
+    TESTCASE( E_char, SIZE_MAX, 0, 0, 0, 10, "%hhd" );
+    TESTCASE( E_short, SIZE_MAX, 0, 0, SHRT_MIN, 10, "%hd" );
+    TESTCASE( E_short, SIZE_MAX, 0, 0, SHRT_MAX, 10, "%hd" );
+    TESTCASE( E_short, SIZE_MAX, 0, 0, 0, 10, "%hd" );
     TESTCASE( E_done, SIZE_MAX, 0, 0, INT_MIN, 10, "%d" );
     TESTCASE( E_done, SIZE_MAX, 0, 0, INT_MAX, 10, "%d" );
     TESTCASE( E_done, SIZE_MAX, 0, 0, 0, 10, "%d" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, LONG_MIN, 10, "%ld" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, LONG_MAX, 10, "%ld" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, 0l, 10, "%ld" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, LLONG_MIN, 10, "%lld" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, LLONG_MAX, 10, "%lld" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, 0ll, 10, "%lld" ); 
+    TESTCASE( E_long, SIZE_MAX, 0, 0, LONG_MIN, 10, "%ld" );
+    TESTCASE( E_long, SIZE_MAX, 0, 0, LONG_MAX, 10, "%ld" );
+    TESTCASE( E_long, SIZE_MAX, 0, 0, 0l, 10, "%ld" );
+    TESTCASE( E_llong, SIZE_MAX, 0, 0, LLONG_MIN, 10, "%lld" );
+    TESTCASE( E_llong, SIZE_MAX, 0, 0, LLONG_MAX, 10, "%lld" );
+    TESTCASE( E_llong, SIZE_MAX, 0, 0, 0ll, 10, "%lld" ); 
     puts( "- Unsigned min / max -\n" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, UCHAR_MAX, 10, "%hhu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, -1, 10, "%hhu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, USHRT_MAX, 10, "%hu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, -1, 10, "%hu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, UINT_MAX, 10, "%u" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, -1, 10, "%u" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, ULONG_MAX, 10, "%lu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, -1l, 10, "%lu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, ULLONG_MAX, 10, "%llu" );
-    TESTCASE( E_done, SIZE_MAX, 0, 0, -1ll, 10, "%llu" );
+    UTESTCASE( E_char, SIZE_MAX, 0, 0, UCHAR_MAX, 10, "%hhu" );
+    UTESTCASE( E_char, SIZE_MAX, 0, 0, (unsigned char)-1, 10, "%hhu" );
+    UTESTCASE( E_short, SIZE_MAX, 0, 0, USHRT_MAX, 10, "%hu" );
+    UTESTCASE( E_short, SIZE_MAX, 0, 0, (unsigned short)-1, 10, "%hu" );
+    UTESTCASE( E_done, SIZE_MAX, 0, 0, UINT_MAX, 10, "%u" );
+    UTESTCASE( E_done, SIZE_MAX, 0, 0, -1u, 10, "%u" );
+    UTESTCASE( E_long, SIZE_MAX, 0, 0, ULONG_MAX, 10, "%lu" );
+    UTESTCASE( E_long, SIZE_MAX, 0, 0, -1ul, 10, "%lu" );
+    UTESTCASE( E_llong, SIZE_MAX, 0, 0, ULLONG_MAX, 10, "%llu" );
+    UTESTCASE( E_llong, SIZE_MAX, 0, 0, -1ull, 10, "%llu" );
+    puts( "- Hex and Octal, normal and alternative, upper and lowercase -\n" );
+    UTESTCASE( E_done, SIZE_MAX, 0, 0, UINT_MAX, 16, "%X" );
+    UTESTCASE( E_alt, SIZE_MAX, 0, 0, -1u, 16, "%#X" );
+    UTESTCASE( E_done | E_lower, SIZE_MAX, 0, 0, UINT_MAX, 16, "%x" );
+    UTESTCASE( E_alt | E_lower, SIZE_MAX, 0, 0, -1u, 16, "%#x" );
+    UTESTCASE( E_done, SIZE_MAX, 0, 0, UINT_MAX, 8, "%o" );
+    UTESTCASE( E_alt, SIZE_MAX, 0, 0, -1u, 8, "%#o" );
+    puts( "- Plus flag -\n" );
+    TESTCASE( E_plus, SIZE_MAX, 0, 0, INT_MIN, 10, "%+d" );
+    TESTCASE( E_plus, SIZE_MAX, 0, 0, INT_MAX, 10, "%+d" );
+    TESTCASE( E_plus, SIZE_MAX, 0, 0, 0, 10, "%+d" );
+    UTESTCASE( E_plus, SIZE_MAX, 0, 0, UINT_MAX, 10, "%+u" );
+    UTESTCASE( E_plus, SIZE_MAX, 0, 0, -1u, 10, "%+u" );
+    puts( "- Space flag -\n" );
+    TESTCASE( E_space, SIZE_MAX, 0, 0, INT_MIN, 10, "% d" );
+    TESTCASE( E_space, SIZE_MAX, 0, 0, INT_MAX, 10, "% d" );
+    TESTCASE( E_space, SIZE_MAX, 0, 0, 0, 10, "% d" );
+    UTESTCASE( E_space, SIZE_MAX, 0, 0, UINT_MAX, 10, "% u" );
+    UTESTCASE( E_space, SIZE_MAX, 0, 0, -1u, 10, "% u" );
+    puts( "- Field width -\n" );
+    TESTCASE( E_done, SIZE_MAX, 9, 0, INT_MIN, 10, "%9d" );
+    TESTCASE( E_done, SIZE_MAX, 9, 0, INT_MAX, 10, "%9d" );
+    TESTCASE( E_done, SIZE_MAX, 10, 0, INT_MIN, 10, "%10d" );
+    TESTCASE( E_done, SIZE_MAX, 10, 0, INT_MAX, 10, "%10d" );
+    TESTCASE( E_done, SIZE_MAX, 11, 0, INT_MIN, 10, "%11d" );
+    TESTCASE( E_done, SIZE_MAX, 11, 0, INT_MAX, 10, "%11d" );
+    TESTCASE( E_done, SIZE_MAX, 12, 0, INT_MIN, 10, "%12d" );
+    TESTCASE( E_done, SIZE_MAX, 12, 0, INT_MAX, 10, "%12d" );
+    puts( "- Field width (left bound) -\n" );
+    TESTCASE( E_minus, SIZE_MAX, 9, 0, INT_MIN, 10, "%-9d" );
+    TESTCASE( E_minus, SIZE_MAX, 9, 0, INT_MAX, 10, "%-9d" );
+    TESTCASE( E_minus, SIZE_MAX, 10, 0, INT_MIN, 10, "%-10d" );
+    TESTCASE( E_minus, SIZE_MAX, 10, 0, INT_MAX, 10, "%-10d" );
+    TESTCASE( E_minus, SIZE_MAX, 11, 0, INT_MIN, 10, "%-11d" );
+    TESTCASE( E_minus, SIZE_MAX, 11, 0, INT_MAX, 10, "%-11d" );
+    TESTCASE( E_minus, SIZE_MAX, 12, 0, INT_MIN, 10, "%-12d" );
+    TESTCASE( E_minus, SIZE_MAX, 12, 0, INT_MAX, 10, "%-12d" );
+    puts( "- Field width, zero padding -\n");
+    TESTCASE( E_done | E_zero, SIZE_MAX, 9, 0, INT_MIN, 10, "%09d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 9, 0, INT_MAX, 10, "%09d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 10, 0, INT_MIN, 10, "%010d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 10, 0, INT_MAX, 10, "%010d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 11, 0, INT_MIN, 10, "%011d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 11, 0, INT_MAX, 10, "%011d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 12, 0, INT_MIN, 10, "%012d" );
+    TESTCASE( E_done | E_zero, SIZE_MAX, 12, 0, INT_MAX, 10, "%012d" );
+    puts( "- Field width, zero padding (left bound) -\n" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 9, 0, INT_MIN, 10, "%-09d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 9, 0, INT_MAX, 10, "%-09d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 10, 0, INT_MIN, 10, "%-010d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 10, 0, INT_MAX, 10, "%-010d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 11, 0, INT_MIN, 10, "%-011d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 11, 0, INT_MAX, 10, "%-011d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 12, 0, INT_MIN, 10, "%-012d" );
+    TESTCASE( E_minus | E_zero, SIZE_MAX, 12, 0, INT_MAX, 10, "%-012d" );
     return 0;
 }