X-Git-Url: https://pd.if.org/git/?a=blobdiff_plain;ds=sidebyside;f=draft.c;h=027f70bd3700196f0a88d54caae3f2f59837e1cb;hb=d7e10f676796abd6dab62adf54d5a8cbcbacaa3e;hp=fdda32d1fe8703840350c3b9ec593b53796cc529;hpb=7bcac73ac7bf61de3dd1bbeaf6071894c7805e7f;p=pdclib.old diff --git a/draft.c b/draft.c index fdda32d..027f70b 100644 --- a/draft.c +++ b/draft.c @@ -6,6 +6,7 @@ #include #include #include +#include #undef TEST #include @@ -13,35 +14,35 @@ /* 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 */ + 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 @@ -50,14 +51,9 @@ struct status_t s - the buffer into which the character shall be delivered TODO: Overruns. */ -#define DELIVER( x ) if ( status->i < status->n ) status->s[status->i] = x; ++(status->i) +#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( int value, struct status_t * status ) +static void int2base( intmax_t value, struct status_t * status ) { ++(status->this); if ( ( value / status->base ) != 0 ) @@ -80,7 +76,7 @@ static void int2base( int value, struct status_t * status ) { preface[ preidx++ ] = '-'; } - else + else if ( ! ( status->flags & E_usigned ) ) { if ( status->flags & E_plus ) { @@ -114,21 +110,24 @@ static void int2base( int value, struct status_t * status ) } } } - if ( value < 0 ) { - value *= -1; + int digit = value % status->base; + if ( digit < 0 ) + { + digit *= -1; } if ( status->flags & E_lower ) { - DELIVER( _PDCLIB_digits[ value % status->base ] ); + DELIVER( _PDCLIB_digits[ digit ] ); } else { - DELIVER( toupper( _PDCLIB_digits[ value % status->base ] ) ); + DELIVER( toupper( _PDCLIB_digits[ digit ] ) ); + } } } -static void padwrap( int value, struct status_t * status ) +static void padwrap( intmax_t value, struct status_t * status ) { int2base( value, status ); if ( status->flags & E_minus ) @@ -139,9 +138,44 @@ static void padwrap( int value, struct status_t * status ) ++(status->this); } } - if ( status->i == status->n ) + if ( status->i >= status->n ) { - status->s[status->i] = '\0'; + status->s[status->n - 1] = '\0'; + } +} + +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'; } } @@ -300,74 +334,126 @@ 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; \ status.prec = _prec; \ status.base = _base; \ status.this = 0; \ - memset( status.s, '\0', 20 ); \ + memset( status.s, '\0', 50 ); \ padwrap( _value, &status ); \ - printf( "Output '%s', RC %d \t- ", status.s, status.i ); \ rc = snprintf( buffer, _n, _expect, _value ); \ - printf( "Expect '%s', RC %d\n", buffer, rc ); + 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 ); \ + } \ + +#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; int rc; - char * buffer = malloc( 20 ); - status.s = malloc( 20 ); - 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" ); - TESTCASE( E_zero, 7, 7, 0, -65535, 16, "%07X" ); - 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" ); + int tmp; + char * buffer = malloc( 50 ); + status.s = malloc( 50 ); + 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; }