X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=functions%2F_PDCLIB%2Fprint.c;h=9751e05ff9a7d0621789bcfb68642e5e66a68757;hb=2b197c4185ac95ec421fb85a472f13a4ff333587;hp=46c00d9eeb60e2ea88e392d12423eeb7bff49fe6;hpb=0143d4b7ba3754e7b46ff4f1438c380386c60a9a;p=fw%2Fpdclib diff --git a/functions/_PDCLIB/print.c b/functions/_PDCLIB/print.c index 46c00d9..9751e05 100644 --- a/functions/_PDCLIB/print.c +++ b/functions/_PDCLIB/print.c @@ -42,9 +42,8 @@ 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: ref. fputs() for a better way to buffer handling */ -#define DELIVER( x ) \ +#define PUT( x ) \ do { \ int character = x; \ if ( status->i < status->n ) { \ @@ -57,7 +56,10 @@ do { \ } while ( 0 ) -static void intformat( intmax_t value, struct _PDCLIB_status_t * status ) +typedef int32_t intfmt_t; +typedef uint32_t uintfmt_t; + +static void intformat( intfmt_t value, struct _PDCLIB_status_t * status ) { /* At worst, we need two prefix characters (hex prefix). */ char preface[3] = "\0"; @@ -105,7 +107,7 @@ static void intformat( intmax_t value, struct _PDCLIB_status_t * status ) { for ( size_t i = 0; i < status->width - characters; ++i ) { - DELIVER( ' ' ); + PUT( ' ' ); ++(status->current); } } @@ -114,7 +116,7 @@ static void intformat( intmax_t value, struct _PDCLIB_status_t * status ) preidx = 0; while ( preface[ preidx ] != '\0' ) { - DELIVER( preface[ preidx++ ] ); + PUT( preface[ preidx++ ] ); ++(status->current); } if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) ) @@ -124,14 +126,14 @@ static void intformat( intmax_t value, struct _PDCLIB_status_t * status ) */ while ( status->current < status->width ) { - DELIVER( '0' ); + PUT( '0' ); ++(status->current); } } /* Do the precision padding if necessary. */ for ( size_t i = 0; i < prec_pads; ++i ) { - DELIVER( '0' ); + PUT( '0' ); } } } @@ -145,45 +147,47 @@ static void intformat( intmax_t value, struct _PDCLIB_status_t * status ) output once the number of characters to be printed is known, which happens at the lowermost recursion level. */ -static void int2base( intmax_t value, struct _PDCLIB_status_t * status ) + +#define INT_MAX_WIDTH (sizeof(intfmt_t) * 8 + 2) / 3 + +static void int2base( intfmt_t value, struct _PDCLIB_status_t * status ) { - /* Registering the character being printed at the end of the function here - already so it will be taken into account when the deepestmost recursion - does the prefix / padding stuff. + char digits[INT_MAX_WIDTH + 1]; + char c, *d = &digits[sizeof(digits)]; + intfmt_t last_value = value; + + *--d = '\0'; + + do { + int digit = value % status->base; + + last_value = value; + value /= status->base; + + if (digit < 0) + digit = -digit; + + /* + Account for character in the output + */ + + ++(status->current); + if ( (status->flags & E_lower) ) + *--d = _PDCLIB_digits[digit]; + else + *--d = _PDCLIB_Xdigits[digit]; + } while (value != 0); + + /* We reached the last digit, and only now know how long the + number to be printed actually is. Now we have to do the sign, + prefix, width, and precision padding stuff before printing the + digits */ - ++(status->current); - if ( ( value / status->base ) != 0 ) - { - /* More digits to be done - recurse deeper */ - int2base( value / status->base, status ); - } - else - { - /* We reached the last digit, the deepest point of our recursion, and - only now know how long the number to be printed actually is. Now we - have to do the sign, prefix, width, and precision padding stuff - before printing the numbers while we resurface from the recursion. - */ - intformat( value, status ); - } - /* Recursion tail - print the current digit. */ - { - int digit = value % status->base; - if ( digit < 0 ) - { - digit *= -1; - } - if ( status->flags & E_lower ) - { - /* Lowercase letters. Same array used for strto...(). */ - DELIVER( _PDCLIB_digits[ digit ] ); - } - else - { - /* Uppercase letters. Array only used here, only 0-F. */ - DELIVER( _PDCLIB_Xdigits[ digit ] ); - } - } + + intformat( last_value, status ); + + while ( (c = *d++) ) + PUT(c); } @@ -193,7 +197,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status if ( *(++spec) == '%' ) { /* %% -> print single '%' */ - DELIVER( *spec ); + PUT( *spec ); return ++spec; } /* Initializing status structure */ @@ -326,7 +330,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status } break; case 'j': - /* j -> intmax_t, which might or might not be long long */ + /* j -> intfmt_t, which might or might not be long long */ status->flags |= E_intmax; break; case 'z': @@ -382,7 +386,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status break; case 'c': /* TODO: Flags, wide chars. */ - DELIVER( va_arg( status->arg, int ) ); + PUT( va_arg( status->arg, int ) ); return ++spec; case 's': /* TODO: Flags, wide chars. */ @@ -390,7 +394,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status char * s = va_arg( status->arg, char * ); while ( *s != '\0' ) { - DELIVER( *(s++) ); + PUT( *(s++) ); } return ++spec; } @@ -417,38 +421,38 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status /* TODO: Check for invalid flag combinations. */ if ( status->flags & E_unsigned ) { - uintmax_t value; + uintfmt_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( status->arg, int ); + value = (uintfmt_t)(unsigned char)va_arg( status->arg, int ); break; case E_short: - value = (uintmax_t)(unsigned short)va_arg( status->arg, int ); + value = (uintfmt_t)(unsigned short)va_arg( status->arg, int ); break; case 0: - value = (uintmax_t)va_arg( status->arg, unsigned int ); + value = (uintfmt_t)va_arg( status->arg, unsigned int ); break; case E_long: - value = (uintmax_t)va_arg( status->arg, unsigned long ); + value = (uintfmt_t)va_arg( status->arg, unsigned long ); break; case E_llong: - value = (uintmax_t)va_arg( status->arg, unsigned long long ); + value = (uintfmt_t)va_arg( status->arg, unsigned long long ); break; case E_size: - value = (uintmax_t)va_arg( status->arg, size_t ); + value = (uintfmt_t)va_arg( status->arg, size_t ); break; } ++(status->current); /* FIXME: The if clause means one-digit values do not get formatted */ - /* Was introduced originally to get value to "safe" levels re. uintmax_t. */ + /* Was introduced originally to get value to "safe" levels re. uintfmt_t. */ if ( ( value / status->base ) != 0 ) { - int2base( (intmax_t)(value / status->base), status ); + int2base( (intfmt_t)(value / status->base), status ); } else { - intformat( (intmax_t)value, status ); + intformat( (intfmt_t)value, status ); } int digit = value % status->base; if ( digit < 0 ) @@ -457,11 +461,11 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status } if ( status->flags & E_lower ) { - DELIVER( _PDCLIB_digits[ digit ] ); + PUT( _PDCLIB_digits[ digit ] ); } else { - DELIVER( _PDCLIB_Xdigits[ digit ] ); + PUT( _PDCLIB_Xdigits[ digit ] ); } } else @@ -469,25 +473,25 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status switch ( status->flags & ( E_char | E_short | E_long | E_llong | E_intmax ) ) { case E_char: - int2base( (intmax_t)(char)va_arg( status->arg, int ), status ); + int2base( (intfmt_t)(char)va_arg( status->arg, int ), status ); break; case E_short: - int2base( (intmax_t)(short)va_arg( status->arg, int ), status ); + int2base( (intfmt_t)(short)va_arg( status->arg, int ), status ); break; case 0: - int2base( (intmax_t)va_arg( status->arg, int ), status ); + int2base( (intfmt_t)va_arg( status->arg, int ), status ); break; case E_long: - int2base( (intmax_t)va_arg( status->arg, long ), status ); + int2base( (intfmt_t)va_arg( status->arg, long ), status ); break; case E_llong: - int2base( (intmax_t)va_arg( status->arg, long long ), status ); + int2base( (intfmt_t)va_arg( status->arg, long long ), status ); break; case E_ptrdiff: - int2base( (intmax_t)va_arg( status->arg, ptrdiff_t ), status ); + int2base( (intfmt_t)va_arg( status->arg, ptrdiff_t ), status ); break; case E_intmax: - int2base( va_arg( status->arg, intmax_t ), status ); + int2base( va_arg( status->arg, intfmt_t ), status ); break; } } @@ -495,7 +499,7 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status { while ( status->current < status->width ) { - DELIVER( ' ' ); + PUT( ' ' ); ++(status->current); } } @@ -508,10 +512,10 @@ const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status } #ifdef TEST -#include <_PDCLIB_test.h> +#define _PDCLIB_FILEID "_PDCLIB/print.c" +#define _PDCLIB_STRINGIO -#include -#include +#include <_PDCLIB_test.h> static int testprintf( char * buffer, const char * format, ... ) { @@ -539,13 +543,10 @@ static int testprintf( char * buffer, const char * format, ... ) #define TEST_CONVERSION_ONLY -#define TESTCASE_SPRINTF( x ) if ( strcmp( target, x ) == 0 ) {} \ - else { TEST_RESULTS += 1; printf( "FAILED: " __FILE__ ", line %d - \"%s\" != %s\n", __LINE__, target, #x ); } - int main( void ) { char target[100]; -#include "printf_testcases.incl" +#include "printf_testcases.h" return TEST_RESULTS; }