]> pd.if.org Git - pdclib/blobdiff - draft.c
Preliminary implementations for %c, %s, %p and %n.
[pdclib] / draft.c
diff --git a/draft.c b/draft.c
index 02c41fd5b11bd5ed7000a3d5cd5657ddedf0653e..1ae90c2088dccd94fd6f6e916535d4046cfef093 100644 (file)
--- a/draft.c
+++ b/draft.c
 #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_unsigned 1<<15
+#define E_intptr   1<<13
+#define E_double   1<<14
+#define E_lower    1<<15
+#define E_unsigned 1<<16
 
 struct status_t
 {
@@ -53,8 +54,6 @@ int _PDCLIB_sprintf( char * buffer, size_t n, const char * format, va_list ap );
 
 int main( void )
 {
-    int rc;
-    puts( "- Signed min / max -\n" );
     test( SIZE_MAX, "%hhd", CHAR_MIN );
     test( SIZE_MAX, "%hhd", CHAR_MAX );
     test( SIZE_MAX, "%hhd", 0 );
@@ -70,7 +69,6 @@ int main( void )
     test( SIZE_MAX, "%lld", LLONG_MIN );
     test( SIZE_MAX, "%lld", LLONG_MAX );
     test( SIZE_MAX, "%lld", 0ll );
-    puts( "- Unsigned min / max -\n" );
     test( SIZE_MAX, "%hhu", UCHAR_MAX );
     test( SIZE_MAX, "%hhu", (unsigned char)-1 );
     test( SIZE_MAX, "%hu", USHRT_MAX );
@@ -81,26 +79,23 @@ int main( void )
     test( SIZE_MAX, "%lu", -1ul );
     test( SIZE_MAX, "%llu", ULLONG_MAX );
     test( SIZE_MAX, "%llu", -1ull );
-    puts( "- Hex and Octal, normal and alternative, upper and lowercase -\n" );
     test( SIZE_MAX, "%X", UINT_MAX );
     test( SIZE_MAX, "%#X", -1u );
     test( SIZE_MAX, "%x", UINT_MAX );
     test( SIZE_MAX, "%#x", -1u );
     test( SIZE_MAX, "%o", UINT_MAX );
     test( SIZE_MAX, "%#o", -1u );
-    puts( "- Plus flag -\n" );
+    test( SIZE_MAX, "%.0#o", 0 );
     test( SIZE_MAX, "%+d", INT_MIN );
     test( SIZE_MAX, "%+d", INT_MAX );
     test( SIZE_MAX, "%+d", 0 );
     test( SIZE_MAX, "%+u", UINT_MAX );
     test( SIZE_MAX, "%+u", -1u );
-    puts( "- Space flag -\n" );
     test( SIZE_MAX, "% d", INT_MIN );
     test( SIZE_MAX, "% d", INT_MAX );
     test( SIZE_MAX, "% d", 0 );
     test( SIZE_MAX, "% u", UINT_MAX );
     test( SIZE_MAX, "% u", -1u );
-    puts( "- Field width -\n" );
     test( SIZE_MAX, "%9d", INT_MIN );
     test( SIZE_MAX, "%9d", INT_MAX );
     test( SIZE_MAX, "%10d", INT_MIN );
@@ -109,7 +104,6 @@ int main( void )
     test( SIZE_MAX, "%11d", INT_MAX );
     test( SIZE_MAX, "%12d", INT_MIN );
     test( SIZE_MAX, "%12d", INT_MAX );
-    puts( "- Field width (left bound) -\n" );
     test( SIZE_MAX, "%-9d", INT_MIN );
     test( SIZE_MAX, "%-9d", INT_MAX );
     test( SIZE_MAX, "%-10d", INT_MIN );
@@ -118,7 +112,6 @@ int main( void )
     test( SIZE_MAX, "%-11d", INT_MAX );
     test( SIZE_MAX, "%-12d", INT_MIN );
     test( SIZE_MAX, "%-12d", INT_MAX );
-    puts( "- Field width, zero padding -\n");
     test( SIZE_MAX, "%09d", INT_MIN );
     test( SIZE_MAX, "%09d", INT_MAX );
     test( SIZE_MAX, "%010d", INT_MIN );
@@ -127,7 +120,6 @@ int main( void )
     test( SIZE_MAX, "%011d", INT_MAX );
     test( SIZE_MAX, "%012d", INT_MIN );
     test( SIZE_MAX, "%012d", INT_MAX );
-    puts( "- Field width, zero padding (left bound) -\n" );
     test( SIZE_MAX, "%-09d", INT_MIN );
     test( SIZE_MAX, "%-09d", INT_MAX );
     test( SIZE_MAX, "%-010d", INT_MIN );
@@ -136,7 +128,6 @@ int main( void )
     test( SIZE_MAX, "%-011d", INT_MAX );
     test( SIZE_MAX, "%-012d", INT_MIN );
     test( SIZE_MAX, "%-012d", INT_MAX );
-    puts( "- Limited n -\n" );
     test( 8, "%9d", INT_MAX );
     test( 8, "%9d", INT_MIN );
     test( 9, "%9d", INT_MAX );
@@ -161,48 +152,30 @@ int main( void )
     test( 12, "%12d", INT_MIN );
     test( 13, "%12d", INT_MAX );
     test( 13, "%12d", INT_MIN );
-    puts( "- Precision (tbd) -\n" );
-    {
-        const char * format = "%030.20d";
-        printf( "glibc  '" );
-        rc = printf( format, INT_MAX );
-        printf( "', RC %d\n", rc );
-        test( SIZE_MAX, format, INT_MAX );
-    }
-    puts( "- vanilla -" );
-    printf( "No width, no precision:     %#x\n", 42 );
-    printf( "Width, no precision:        %#6x\n", 42 );
-    printf( "No width, precision:        %#.6x\n", 42 );
-    printf( "Big width, small precision: %#6.3x\n", 42 );
-    printf( "Small width, big precision: %#3.6x\n", 42 );
-    printf( "No width, no precision:     %#d\n", 42 );
-    printf( "Width, no precision:        %#6d\n", 42 );
-    printf( "No width, precision:        %#.6d\n", 42 );
-    printf( "Big width, small precision: %#6.3d\n", 42 );
-    printf( "Small width, big precision: %#3.6d\n", 42 );
-    puts( "- zero flag -" );
-    printf( "No width, no precision:     %#0x\n", 42 );
-    printf( "Width, no precision:        %#06x\n", 42 );
-    printf( "No width, precision:        %#0.6x\n", 42 );
-    printf( "Big width, small precision: %#06.3x\n", 42 );
-    printf( "Small width, big precision: %#03.6x\n", 42 );
-    printf( "No width, no precision:     %#0d\n", 42 );
-    printf( "Width, no precision:        %#06d\n", 42 );
-    printf( "No width, precision:        %#0.6d\n", 42 );
-    printf( "Big width, small precision: %#06.3d\n", 42 );
-    printf( "Small width, big precision: %#03.6d\n", 42 );
-    puts( "- plus flag -" );
-    printf( "No width, no precision:     %#+d\n", 42 );
-    printf( "Width, no precision:        %#+6d\n", 42 );
-    printf( "No width, precision:        %#+.6d\n", 42 );
-    printf( "Big width, small precision: %#+6.3d\n", 42 );
-    printf( "Small width, big precision: %#+3.6d\n", 42 );
-    puts( "- plus and zero flag -" );
-    printf( "No width, no precision:     %#+0d\n", 42 );
-    printf( "Width, no precision:        %#+06d\n", 42 );
-    printf( "No width, precision:        %#+0.6d\n", 42 );
-    printf( "Big width, small precision: %#+06.3d\n", 42 );
-    printf( "Small width, big precision: %#+03.6d\n", 42 );
+    test( SIZE_MAX, "%030.20d", INT_MAX );
+    test( SIZE_MAX, "%.6x", UINT_MAX );
+    test( SIZE_MAX, "%#6.3x", UINT_MAX );
+    test( SIZE_MAX, "%#3.6x", UINT_MAX );
+    test( SIZE_MAX, "%.6d", INT_MIN );
+    test( SIZE_MAX, "%6.3d", INT_MIN );
+    test( SIZE_MAX, "%3.6d", INT_MIN );
+    test( SIZE_MAX, "%#0.6x", UINT_MAX );
+    test( SIZE_MAX, "%#06.3x", UINT_MAX );
+    test( SIZE_MAX, "%#03.6x", UINT_MAX );
+    test( SIZE_MAX, "%#0.6d", INT_MAX );
+    test( SIZE_MAX, "%#06.3d", INT_MAX );
+    test( SIZE_MAX, "%#03.6d", INT_MAX );
+    test( SIZE_MAX, "%#+.6d", INT_MAX );
+    test( SIZE_MAX, "%#+6.3d", INT_MAX );
+    test( SIZE_MAX, "%#+3.6d", INT_MAX );
+    test( SIZE_MAX, "%+0.6d", INT_MAX );
+    test( SIZE_MAX, "%+06.3d", INT_MAX );
+    test( SIZE_MAX, "%+03.6d", INT_MAX );
+    test( SIZE_MAX, "- %d", INT_MAX );
+    test( SIZE_MAX, "- %d %% %d", INT_MAX, INT_MIN );
+    test( SIZE_MAX, "%c", 'x' );
+    test( SIZE_MAX, "%s", "abcdef" );
+    test( SIZE_MAX, "%p", 0xdeadbeef );
     return 0;
 }
 
@@ -212,7 +185,6 @@ int main( void )
    i - pointer to number of characters already delivered in this call
    n - pointer to maximum number of characters to be delivered in this call
    s - the buffer into which the character shall be delivered
-   TODO: Overruns.
 */
 #define DELIVER( x ) do { if ( status->i < status->n ) { if ( status->stream != NULL ) putc( x, status->stream ); else status->s[status->i] = x; } ++(status->i); } while ( 0 )
 
@@ -247,7 +219,7 @@ static void int2base( intmax_t value, struct status_t * status )
         if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) )
         {
             /* Octal / hexadecimal prefix for "%#" conversions */
-            preface[ preidx++ ] = '0'; /* TODO: For octal, standard states "extend the precision" */
+            preface[ preidx++ ] = '0';
             if ( status->base == 16 )
             {
                 preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X';
@@ -270,6 +242,8 @@ static void int2base( intmax_t value, struct status_t * status )
                 preface[ preidx++ ] = ' ';
             }
         }
+        {
+        size_t prec_pads = ( status->prec > status->this ) ? ( status->prec - status->this ) : 0;
         if ( ! ( status->flags & ( E_minus | E_zero ) ) )
         {
             /* Space padding is only done if no zero padding or left alignment
@@ -286,7 +260,7 @@ static void int2base( intmax_t value, struct status_t * status )
                 for ( int i = 0; i < status->width - characters; ++i )
                 {
                     DELIVER( ' ' );
-                    ++(status->this); /* TODO: Probably have to do something so I still know how many zeroes are required, later. */
+                    ++(status->this);
                 }
             }
         }
@@ -300,7 +274,7 @@ static void int2base( intmax_t value, struct status_t * status )
         if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
         {
             /* If field is not left aligned, and zero padding is requested, do
-               so. TODO: This should include precision handling (probably).
+               so.
             */
             while ( status->this < status->width )
             {
@@ -308,6 +282,12 @@ static void int2base( intmax_t value, struct status_t * status )
                 ++(status->this);
             }
         }
+        /* Do the precision padding if necessary. */
+        for ( int i = 0; i < prec_pads; ++i )
+        {
+            DELIVER( '0' );
+        }
+        }
     }
     /* Recursion tail - print the current digit. */
     {
@@ -338,7 +318,7 @@ const char * parse_out( const char * spec, struct status_t * status )
     if ( *(++spec) == '%' )
     {
         DELIVER( *spec );
-        return spec;
+        return ++spec;
     }
     /* Initializing status structure */
     status->flags = 0;
@@ -422,7 +402,8 @@ const char * parse_out( const char * spec, struct status_t * status )
             }
             spec = endptr;
         }
-        status->flags &= ! E_zero;
+        /* Having a precision cancels out any zero flag. */
+        status->flags ^= E_zero;
     }
 
     /* Optional length modifier
@@ -475,6 +456,7 @@ const char * parse_out( const char * spec, struct status_t * status )
     switch ( *spec )
     {
         case 'd':
+            /* FALLTHROUGH */
         case 'i':
             status->base = 10;
             break;
@@ -505,13 +487,30 @@ const char * parse_out( const char * spec, struct status_t * status )
         case 'A':
             break;
         case 'c':
-            break;
+            /* TODO: Flags, wide chars. */
+            DELIVER( va_arg( status->ap, int ) );
+            return ++spec;
         case 's':
-            break;
+            /* TODO: Flags, wide chars. */
+            {
+                char * s = va_arg( status->ap, char * );
+                while ( *s != '\0' )
+                {
+                    DELIVER( *(s++) );
+                }
+                return ++spec;
+            }
         case 'p':
-            /* uint2base( 16, (intptr_t)value, true ) */
-        case 'n':
+            /* TODO: E_long -> E_intptr */
+            status->base = 16;
+            status->flags |= ( E_lower | E_unsigned | E_alt | E_long );
             break;
+        case 'n':
+           {
+               int * val = va_arg( status->ap, int * );
+               *val = status->i;
+               return ++spec;
+           }
         default:
             /* No conversion specifier. Bad conversion. */
             return orig_spec;