X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;f=draft.c;h=f8ca51bac004829fb9644e40ab7837aaf3f46e19;hb=d278baf216479f66715e079c74a8f2864d096bfc;hp=8d3e362dddb685d8ca02234c554e6b3e14ebf77b;hpb=4194d86d72358ea25b3d22c1d9188b133b9437d8;p=pdclib.old diff --git a/draft.c b/draft.c index 8d3e362..f8ca51b 100644 --- a/draft.c +++ b/draft.c @@ -1,16 +1,13 @@ -#include -#include #include -#include -#include -#include -#include -#include -#include #include +#include +#include +#include +/* These can be removed once integrated into PDCLIB make procedure */ #undef TEST #include +#include /* Using an integer's bits as flags for both the conversion flags and length modifiers. @@ -35,22 +32,118 @@ struct status_t { int base; /* base to which the value shall be converted */ - int_fast16_t flags; /* flags and length modifiers */ + int_fast32_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 */ + FILE * stream;/* for to-stream output */ }; +const char * parse_out( const char * spec, struct status_t * status, va_list ap ); +inline void test( size_t n, const char * expect, ... ); +int _PDCLIB_sprintf( char * buffer, size_t n, const char * format, va_list ap ); + +/* The following only for testing. */ +#include +#include + +int main( void ) +{ + puts( "- Signed min / max -\n" ); + test( SIZE_MAX, "%hhd", CHAR_MIN ); + test( SIZE_MAX, "%hhd", CHAR_MAX ); + test( SIZE_MAX, "%hhd", 0 ); + test( SIZE_MAX, "%hd", SHRT_MIN ); + test( SIZE_MAX, "%hd", SHRT_MAX ); + test( SIZE_MAX, "%hd", 0 ); + test( SIZE_MAX, "%d", INT_MIN ); + test( SIZE_MAX, "%d", INT_MAX ); + test( SIZE_MAX, "%d", 0 ); + test( SIZE_MAX, "%ld", LONG_MIN ); + test( SIZE_MAX, "%ld", LONG_MAX ); + test( SIZE_MAX, "%ld", 0l ); + 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 ); + test( SIZE_MAX, "%hu", (unsigned short)-1 ); + test( SIZE_MAX, "%u", UINT_MAX ); + test( SIZE_MAX, "%u", -1u ); + test( SIZE_MAX, "%lu", ULONG_MAX ); + 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, "%+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 ); + test( SIZE_MAX, "%10d", INT_MAX ); + test( SIZE_MAX, "%11d", INT_MIN ); + 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 ); + test( SIZE_MAX, "%-10d", INT_MAX ); + test( SIZE_MAX, "%-11d", INT_MIN ); + 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 ); + test( SIZE_MAX, "%010d", INT_MAX ); + test( SIZE_MAX, "%011d", INT_MIN ); + 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 ); + test( SIZE_MAX, "%-010d", INT_MAX ); + test( SIZE_MAX, "%-011d", INT_MIN ); + test( SIZE_MAX, "%-011d", INT_MAX ); + test( SIZE_MAX, "%-012d", INT_MIN ); + test( SIZE_MAX, "%-012d", INT_MAX ); + return 0; +} + /* x - the character to be delivered 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 ) status->s[status->i] = x; ++(status->i); } while ( 0 ) +#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 ) static void int2base( intmax_t value, struct status_t * status ) { @@ -86,7 +179,7 @@ static void int2base( intmax_t value, struct status_t * status ) preface[ preidx++ ] = ' '; } } - if ( ! ( ( status->flags & E_minus ) || ( status->flags & E_zero ) ) ) + if ( ! ( status->flags & ( E_minus | E_zero ) ) ) { while ( ( status->this + preidx ) < status->width ) { @@ -121,117 +214,19 @@ static void int2base( intmax_t value, struct status_t * status ) } else { - DELIVER( toupper( _PDCLIB_digits[ digit ] ) ); + DELIVER( _PDCLIB_Xdigits[ digit ] ); } } } -static void padwrap( intmax_t value, struct status_t * status ) +const char * parse_out( const char * spec, struct status_t * status, va_list ap ) { - if ( status->flags & E_char ) - { - value = (char)value; - } - else if ( status->flags & E_short ) - { - value = (short)value; - } - else if ( status->flags & E_long ) - { - value = (long)value; - } - else if ( status->flags & E_llong ) - { - value = (long long)value; - } - else if ( status->flags & E_ptrdiff ) - { - value = (ptrdiff_t)value; - } - else if ( ! ( status->flags & E_intmax ) ) + const char * orig_spec = spec; + if ( *(++spec) == '%' ) { - value = (int)value; - } - int2base( value, status ); - if ( status->flags & E_minus ) - { - while ( status->this < status->width ) - { - DELIVER( ' ' ); - ++(status->this); - } + DELIVER( *spec ); + return spec; } - if ( status->i >= status->n ) - { - status->s[status->n - 1] = '\0'; - } -} - -static void upadwrap( uintmax_t value, struct status_t * status ) -{ - if ( status->flags & E_char ) - { - value = (unsigned char)value; - } - else if ( status->flags & E_short ) - { - value = (unsigned short)value; - } - else if ( status->flags & E_long ) - { - value = (unsigned long)value; - } - else if ( status->flags & E_llong ) - { - value = (unsigned long long)value; - } - else if ( status->flags & E_size ) - { - value = (size_t)value; - } - else - { - value = (unsigned int)value; - } - status->flags |= E_unsigned; - ++(status->this); - if ( ( value / status->base ) != 0 ) - { - int2base( (intmax_t)(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, struct status_t * status, va_list ap ); - -void parse_out( const char * spec, struct status_t * status, va_list ap ) -{ - /* TODO: "%%" handled correctly? */ - /* Initializing status structure */ status->flags = 0; status->base = 0; @@ -309,7 +304,8 @@ void parse_out( const char * spec, struct status_t * status, va_list ap ) status->prec = (int)strtol( spec, &endptr, 10 ); if ( spec == endptr ) { - /* TODO: Decimal point but no number - bad conversion specifier. */ + /* Decimal point but no number - bad conversion specifier. */ + return orig_spec; } } } @@ -369,6 +365,7 @@ void parse_out( const char * spec, struct status_t * status, va_list ap ) break; case 'o': status->base = 8; + status->flags |= E_unsigned; break; case 'u': status->base = 10; @@ -379,8 +376,8 @@ void parse_out( const char * spec, struct status_t * status, va_list ap ) status->flags |= ( E_lower | E_unsigned ); break; case 'X': - status->flags = E_unsigned; status->base = 16; + status->flags |= E_unsigned; break; case 'f': case 'F': @@ -399,191 +396,161 @@ void parse_out( const char * spec, struct status_t * status, va_list ap ) case 'p': /* uint2base( 16, (intptr_t)value, true ) */ case 'n': - case '%': - // conversion specifier - /* TODO: May this be accompaigned by flags, width, precision, length modifier at all? */ break; default: - /* TODO: No conversion specifier. Bad conversion. */ - return; - } - switch ( status->flags ) - { - /* TODO */ + /* No conversion specifier. Bad conversion. */ + return orig_spec; } + + /* Do the actual output based on our findings */ if ( status->base != 0 ) { /* Integer conversions */ - switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_unsigned ) ) + /* TODO: Check for invalid flag combinations. */ + if ( status->flags & E_unsigned ) { - case E_char: - padwrap( (intmax_t)(char)va_arg( ap, int ), status ); - break; - case E_char | E_unsigned: - upadwrap( (uintmax_t)(unsigned char)va_arg( ap, int ), status ); - break; - case E_short: - padwrap( (intmax_t)(short)va_arg( ap, int ), status ); - break; - case E_short | E_unsigned: - upadwrap( (uintmax_t)(unsigned short)va_arg( ap, int ), status ); - break; - case 0: - padwrap( (intmax_t)va_arg( ap, int ), status ); - break; - case E_unsigned: - upadwrap( (uintmax_t)va_arg( ap, unsigned int ), status ); - break; - case E_long: - padwrap( (intmax_t)va_arg( ap, long ), status ); - break; - case E_long | E_unsigned: - upadwrap( (uintmax_t)va_arg( ap, unsigned long ), status ); - break; - case E_llong: - padwrap( (intmax_t)va_arg( ap, long long ), status ); - break; - case E_llong | E_unsigned: - upadwrap( (uintmax_t)va_arg( ap, unsigned long long ), status ); - break; + uintmax_t value; + switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_size ) ) + { + case E_char: + value = (uintmax_t)(unsigned char)va_arg( ap, int ); + break; + case E_short: + value = (uintmax_t)(unsigned short)va_arg( ap, int ); + break; + case 0: + value = (uintmax_t)va_arg( ap, unsigned int ); + break; + case E_long: + value = (uintmax_t)va_arg( ap, unsigned long ); + break; + case E_llong: + value = (uintmax_t)va_arg( ap, unsigned long long ); + break; + case E_size: + value = (uintmax_t)va_arg( ap, size_t ); + break; + } + ++(status->this); + if ( ( value / status->base ) != 0 ) + { + int2base( (intmax_t)(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( _PDCLIB_Xdigits[ digit ] ); + } + } + else + { + switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) ) + { + case E_char: + int2base( (intmax_t)(char)va_arg( ap, int ), status ); + break; + case E_short: + int2base( (intmax_t)(short)va_arg( ap, int ), status ); + break; + case 0: + int2base( (intmax_t)va_arg( ap, int ), status ); + break; + case E_long: + int2base( (intmax_t)va_arg( ap, long ), status ); + break; + case E_llong: + int2base( (intmax_t)va_arg( ap, long long ), status ); + break; + case E_ptrdiff: + int2base( (intmax_t)va_arg( ap, ptrdiff_t ), status ); + break; + case E_intmax: + int2base( va_arg( ap, intmax_t ), status ); + break; + } + } + if ( status->flags & E_minus ) + { + while ( status->this < status->width ) + { + DELIVER( ' ' ); + ++(status->this); + } + } + if ( status->i >= status->n ) + { + status->s[status->n - 1] = '\0'; } } + return ++spec; } -void parse_out_wrapper( const char * spec, struct status_t * status, ... ); - -void parse_out_wrapper( const char * spec, struct status_t * status, ... ) +inline void test( size_t n, const char * expect, ... ) { + char * buffer1 = malloc( 50 ); + char * buffer2 = malloc( 50 ); + int myrc; + int rc; va_list ap; - va_start( ap, status ); - parse_out( spec, status, ap ); - va_end( ap ); -} - -#define TESTCASE( _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 ); \ - padwrap( (intmax_t)_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 ); \ + va_start( ap, expect ); + myrc = _PDCLIB_sprintf( buffer1, n, expect, ap ); + rc = vsprintf( buffer2, expect, ap ); + if ( ( strcmp( buffer1, buffer2 ) != 0 ) || ( myrc != rc ) ) + { + printf( "Output '%s', RC %d\nExpect '%s', RC %d\n\n", buffer1, myrc, buffer2, rc ); } + free( buffer1 ); + free( buffer2 ); +} -#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( (uintmax_t)_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 _PDCLIB_sprintf( char * buffer, size_t n, const char * format, va_list ap ) +{ + struct status_t status = { 0, 0, n, 0, 0, buffer, 0, 0, NULL }; + while ( *format != '\0' ) + { + const char * rc; + if ( ( *format != '%' ) || ( ( rc = parse_out( format, &status, ap ) ) == format ) ) + { + /* No conversion specifier, print verbatim */ + buffer[ status.i++ ] = *format; + } + else + { + /* Continue parsing after conversion specifier */ + format = rc; + } } + buffer[ status.i ] = '\0'; + return status.i; +} -int main( void ) +#if 0 +int _PDCLIB_fprintf( FILE * stream, const char * format, va_list ap ) { - struct status_t status; - int rc; char * buffer = malloc( 50 ); - status.s = calloc( 50, 1 ); - status.i = 0; - status.n = SIZE_MAX; - puts( "- parse_out() -\n" ); - parse_out_wrapper( "d", &status, 1234 ); - puts( status.s ); - puts( "- Signed min / max -\n" ); - 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_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" ); - 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; + struct status_t status = { 0, 0, SIZE_MAX, 0, 0, /* stream->buffer */ buffer, 0, 0, stream }; + while ( *format != '\0' ) + { + const char * rc; + if ( ( *format != '%' ) || ( ( rc = parse_out( format, &status, ap ) ) == format ) ) + { + /* No conversion specifier, print verbatim */ + putc( *(format++), stream ); + } + else + { + /* Continue parsing after conversion specifier */ + format = rc; + } + } + return status.i; } +#endif