X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=draft.c;h=570f305353b9352e07b51be7265c5ccb4e981ef7;hb=9b1e6c0a721f9358d9bbc76410e719a878e27edb;hp=02c41fd5b11bd5ed7000a3d5cd5657ddedf0653e;hpb=d5b3e08d993cb7b329b3b87da12770ad0becd02a;p=pdclib diff --git a/draft.c b/draft.c index 02c41fd..570f305 100644 --- a/draft.c +++ b/draft.c @@ -25,9 +25,10 @@ #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 { @@ -45,7 +46,8 @@ struct status_t const char * parse_out( const char * spec, struct status_t * status ); inline void test( size_t n, const char * expect, ... ); -int _PDCLIB_sprintf( char * buffer, size_t n, const char * format, va_list ap ); +int _PDCLIB_vsnprintf( char * buffer, size_t n, const char * format, va_list ap ); +int _PDCLIB_snprintf( char * s, size_t n, const char * format, ... ); /* The following only for testing. */ #include @@ -53,8 +55,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 +70,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 +80,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 +105,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 +113,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 +121,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 +129,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 +153,40 @@ int main( void ) test( 12, "%12d", INT_MIN ); test( 13, "%12d", INT_MAX ); test( 13, "%12d", INT_MIN ); - puts( "- Precision (tbd) -\n" ); + 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 ); { - const char * format = "%030.20d"; - printf( "glibc '" ); - rc = printf( format, INT_MAX ); - printf( "', RC %d\n", rc ); - test( SIZE_MAX, format, INT_MAX ); + char buffer[50]; + int val1, val2, val3, val4; + snprintf( buffer, SIZE_MAX, "123456%n789%n", &val1, &val2 ); + _PDCLIB_snprintf( buffer, SIZE_MAX, "123456%n789%n", &val3, &val4 ); + if ( ( val1 != val3 ) || ( val2 != val4 ) ) + { + printf( "Output %d/%d\nExpect %d/%d\n\n", val1, val2, val3, val4 ); + } } - 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 ); return 0; } @@ -212,7 +196,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 +230,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 +253,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 +271,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 +285,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 +293,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 +329,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 +413,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 +467,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 +498,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; @@ -616,7 +626,7 @@ inline void test( size_t n, const char * expect, ... ) int rc; va_list ap; va_start( ap, expect ); - myrc = _PDCLIB_sprintf( buffer1, n, expect, ap ); + myrc = _PDCLIB_vsnprintf( buffer1, n, expect, ap ); rc = vsnprintf( buffer2, n, expect, ap ); if ( ( strcmp( buffer1, buffer2 ) != 0 ) || ( myrc != rc ) ) { @@ -626,7 +636,7 @@ inline void test( size_t n, const char * expect, ... ) free( buffer2 ); } -int _PDCLIB_sprintf( char * buffer, size_t n, const char * format, va_list ap ) +int _PDCLIB_vsnprintf( char * buffer, size_t n, const char * format, va_list ap ) { struct status_t status = { 0, 0, n, 0, 0, buffer, 0, 0, NULL, ap }; while ( *format != '\0' ) @@ -647,6 +657,13 @@ int _PDCLIB_sprintf( char * buffer, size_t n, const char * format, va_list ap ) return status.i; } +int _PDCLIB_snprintf( char * s, size_t n, const char * format, ... ) +{ + va_list ap; + va_start( ap, format ); + return _PDCLIB_vsnprintf( s, n, format, ap ); +} + #if 0 int _PDCLIB_fprintf( FILE * stream, const char * format, va_list ap ) {