]> pd.if.org Git - pdclib/blobdiff - functions/_PDCLIB/print.c
Rename all files to match their primary symbol (avoids file conflicts in library...
[pdclib] / functions / _PDCLIB / print.c
diff --git a/functions/_PDCLIB/print.c b/functions/_PDCLIB/print.c
deleted file mode 100644 (file)
index 95fbe9c..0000000
+++ /dev/null
@@ -1,559 +0,0 @@
-/* $Id$ */
-
-/* _PDCLIB_print( const char *, struct _PDCLIB_status_t * )
-
-   This file is part of the Public Domain C Library (PDCLib).
-   Permission is granted to use, modify, and / or redistribute at will.
-*/
-
-#include <stdio.h>
-#include <stdint.h>
-#include <stdarg.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <stdbool.h>
-#include <limits.h>
-
-#ifndef REGTEST
-
-/* Using an integer's bits as flags for both the conversion flags and length
-   modifiers.
-*/
-/* FIXME: one too many flags to work on a 16-bit machine, join some (e.g. the
-          width flags) into a combined field.
-*/
-#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_intptr   (1<<13)
-#define E_ldouble  (1<<14)
-#define E_lower    (1<<15)
-#define E_unsigned (1<<16)
-
-/* This macro delivers a given character to either a memory buffer or a stream,
-   depending on the contents of 'status' (struct _PDCLIB_status_t).
-   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
-*/
-#define PUT( x ) \
-do { \
-    int character = x; \
-    if ( status->i < status->n ) { \
-        if ( status->stream != NULL ) \
-            putc_unlocked( character, status->stream ); \
-        else \
-            status->s[status->i] = character; \
-    } \
-    ++(status->i); \
-} while ( 0 )
-
-/* Maximum number of output characters = 
- *   number of bits in (u)intmax_t / number of bits per character in smallest 
- *   base. Smallest base is octal, 3 bits/char.
- *
- * Additionally require 2 extra characters for prefixes
- */
-static const size_t maxIntLen = sizeof(intmax_t) * CHAR_BIT / 3 + 1;
-
-static void int2base( uintmax_t value, struct _PDCLIB_status_t * status )
-{
-    char sign = 0;
-    if ( ! ( status->flags & E_unsigned ) ) 
-    {
-        intmax_t signval = (intmax_t) value;
-        bool negative = signval < 0;
-        value = signval < 0 ? -signval : signval;
-
-        if ( negative ) 
-        {
-            sign = '-';
-        } 
-        else if ( status->flags & E_plus ) 
-        {
-            sign = '+';
-        }
-        else if (status->flags & E_space )
-        {
-            sign = ' ';
-        }
-    }
-
-    // The user could theoretically ask for a silly buffer length here. 
-    // Perhaps after a certain size we should malloc? Or do we refuse to protect
-    // them from their own stupidity?
-    size_t bufLen = (status->width > maxIntLen ? status->width : maxIntLen) + 2;
-    char outbuf[bufLen];
-    char * outend = outbuf + bufLen;
-    int written = 0;
-
-    // Build up our output string - backwards
-    {
-        const char * digits = (status->flags & E_lower) ? 
-                                _PDCLIB_digits : _PDCLIB_Xdigits;
-        uintmax_t remaining = value;
-        if(status->prec != 0 || remaining != 0) do {
-            uintmax_t digit = remaining % status->base;
-            remaining /= status->base;
-
-            outend[-++written] = digits[digit];
-        } while(remaining != 0);
-    }
-
-    // Pad field out to the precision specification
-    while( (long) written < status->prec ) outend[-++written] = '0';
-
-    // If a field width specified, and zero padding was requested, then pad to
-    // the field width
-    unsigned padding = 0;
-    if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )    
-    {
-        while( written < (int) status->width ) 
-        {
-            outend[-++written] = '0';
-            padding++;
-        }
-    }
-
-    // Prefixes
-    if ( sign != 0 )
-    {
-        if ( padding == 0 ) written++;
-        outend[-written] = sign;
-    }
-    else if ( status->flags & E_alt )
-    {
-        switch ( status->base )
-        {
-            case 8:
-                if ( outend[-written] != '0' ) outend[-++written] = '0';
-                break;
-            case 16:
-                // No prefix if zero
-                if ( value == 0 ) break;
-
-                written += padding < 2 ? 2 - padding : 0;
-                outend[-written    ] = '0';
-                outend[-written + 1] = (status->flags & E_lower) ? 'x' : 'X';
-                break;
-            default:
-                break;
-        }
-    }
-
-    // Space padding to field width
-    if ( ! ( status->flags & ( E_minus | E_zero ) ) )
-    {
-        while( written < (int) status->width ) outend[-++written] = ' ';
-    }
-
-    // Write output
-    status->current = written;
-    while ( written )
-        PUT( outend[-written--] );
-}
-
-static void printstr( const char * str, struct _PDCLIB_status_t * status )
-{
-    if ( status->width == 0 || status->flags & E_minus )
-    {
-        // Simple case or left justification
-        while ( str[status->current] && 
-            ( status->prec < 0 || (long)status->current < status->prec ) )
-        {
-            PUT( str[status->current++] );
-        }
-
-        while( status->current < status->width ) 
-        {
-            PUT( ' ' );
-            status->current++;
-        }
-    } else {
-        // Right justification
-        size_t len = status->prec >= 0 ? strnlen( str, status->prec ) 
-                                       :  strlen( str );
-        int padding = status->width - len;
-        while((long)status->current < padding)
-        {
-            PUT( ' ' );
-            status->current++;
-        }
-
-        for( size_t i = 0; i != len; i++ )
-        {
-            PUT( str[i] );
-            status->current++;
-        }
-    }
-}
-
-static void printchar( char chr, struct _PDCLIB_status_t * status )
-{
-    if( ! ( status->flags & E_minus ) )
-    {
-        // Right justification
-        for( ; status->current + 1 < status->width; status->current++)
-        {
-            PUT( ' ' );
-        }
-        PUT( chr );
-        status->current++;
-    } else {
-        // Left justification
-        PUT( chr );
-        status->current++;
-
-        for( ; status->current < status->width; status->current++)
-        {
-            PUT( ' ' );
-        }
-    }
-}
-
-const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
-{
-    const char * orig_spec = spec;
-    if ( *(++spec) == '%' )
-    {
-        /* %% -> print single '%' */
-        PUT( *spec );
-        return ++spec;
-    }
-    /* Initializing status structure */
-    status->flags = 0;
-    status->base  = 0;
-    status->current  = 0;
-    status->width = 0;
-    status->prec  = EOF;
-
-    /* First come 0..n flags */
-    do
-    {
-        switch ( *spec )
-        {
-            case '-':
-                /* left-aligned output */
-                status->flags |= E_minus;
-                ++spec;
-                break;
-            case '+':
-                /* positive numbers prefixed with '+' */
-                status->flags |= E_plus;
-                ++spec;
-                break;
-            case '#':
-                /* alternative format (leading 0x for hex, 0 for octal) */
-                status->flags |= E_alt;
-                ++spec;
-                break;
-            case ' ':
-                /* positive numbers prefixed with ' ' */
-                status->flags |= E_space;
-                ++spec;
-                break;
-            case '0':
-                /* right-aligned padding done with '0' instead of ' ' */
-                status->flags |= E_zero;
-                ++spec;
-                break;
-            default:
-                /* not a flag, exit flag parsing */
-                status->flags |= E_done;
-                break;
-        }
-    } while ( ! ( status->flags & E_done ) );
-
-    /* Optional field width */
-    if ( *spec == '*' )
-    {
-        /* Retrieve width value from argument stack */
-        int width = va_arg( status->arg, int );
-        if ( width < 0 )
-        {
-            status->flags |= E_minus;
-            status->width = abs( width );
-        }
-        else
-        {
-            status->width = width;
-        }
-        ++spec;
-    }
-    else
-    {
-        /* If a width is given, strtol() will return its value. If not given,
-           strtol() will return zero. In both cases, endptr will point to the
-           rest of the conversion specifier - just what we need.
-        */
-        status->width = (int)strtol( spec, (char**)&spec, 10 );
-    }
-
-    /* Optional precision */
-    if ( *spec == '.' )
-    {
-        ++spec;
-        if ( *spec == '*' )
-        {
-            /* Retrieve precision value from argument stack. A negative value
-               is as if no precision is given - as precision is initalized to
-               EOF (negative), there is no need for testing for negative here.
-            */
-            status->prec = va_arg( status->arg, int );
-            ++spec;
-        }
-        else
-        {
-            status->prec = (int)strtol( spec, (char**) &spec, 10 );
-        }
-        /* Having a precision cancels out any zero flag. */
-        status->flags &= ~E_zero;
-    }
-
-    /* Optional length modifier
-       We step one character ahead in any case, and step back only if we find
-       there has been no length modifier (or step ahead another character if it
-       has been "hh" or "ll").
-    */
-    switch ( *(spec++) )
-    {
-        case 'h':
-            if ( *spec == 'h' )
-            {
-                /* hh -> char */
-                status->flags |= E_char;
-                ++spec;
-            }
-            else
-            {
-                /* h -> short */
-                status->flags |= E_short;
-            }
-            break;
-        case 'l':
-            if ( *spec == 'l' )
-            {
-                /* ll -> long long */
-                status->flags |= E_llong;
-                ++spec;
-            }
-            else
-            {
-                /* k -> long */
-                status->flags |= E_long;
-            }
-            break;
-        case 'j':
-            /* j -> intmax_t, which might or might not be long long */
-            status->flags |= E_intmax;
-            break;
-        case 'z':
-            /* z -> size_t, which might or might not be unsigned int */
-            status->flags |= E_size;
-            break;
-        case 't':
-            /* t -> ptrdiff_t, which might or might not be long */
-            status->flags |= E_ptrdiff;
-            break;
-        case 'L':
-            /* L -> long double */
-            status->flags |= E_ldouble;
-            break;
-        default:
-            --spec;
-            break;
-    }
-
-    /* Conversion specifier */
-    switch ( *spec )
-    {
-        case 'd':
-            /* FALLTHROUGH */
-        case 'i':
-            status->base = 10;
-            break;
-        case 'o':
-            status->base = 8;
-            status->flags |= E_unsigned;
-            break;
-        case 'u':
-            status->base = 10;
-            status->flags |= E_unsigned;
-            break;
-        case 'x':
-            status->base = 16;
-            status->flags |= ( E_lower | E_unsigned );
-            break;
-        case 'X':
-            status->base = 16;
-            status->flags |= E_unsigned;
-            break;
-        case 'f':
-        case 'F':
-        case 'e':
-        case 'E':
-        case 'g':
-        case 'G':
-            break;
-        case 'a':
-        case 'A':
-            break;
-        case 'c':
-            /* TODO: wide chars. */
-            printchar( va_arg( status->arg, int ), status );
-            return ++spec;
-        case 's':
-            /* TODO: wide chars. */
-            {
-                char * s = va_arg( status->arg, char * );
-                printstr( s, status );
-                return ++spec;
-            }
-        case 'p':
-            /* 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->arg, int * );
-               *val = status->i;
-               return ++spec;
-           }
-        default:
-            /* No conversion specifier. Bad conversion. */
-            return orig_spec;
-    }
-
-    /* Do the actual output based on our findings */
-    if ( status->base != 0 )
-    {
-        /* Integer conversions */
-        /* TODO: Check for invalid flag combinations. */
-        if ( status->flags & E_unsigned )
-        {
-            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( status->arg, int );
-                    break;
-                case E_short:
-                    value = (uintmax_t)(unsigned short)va_arg( status->arg, int );
-                    break;
-                case 0:
-                    value = (uintmax_t)va_arg( status->arg, unsigned int );
-                    break;
-                case E_long:
-                    value = (uintmax_t)va_arg( status->arg, unsigned long );
-                    break;
-                case E_llong:
-                    value = (uintmax_t)va_arg( status->arg, unsigned long long );
-                    break;
-                case E_size:
-                    value = (uintmax_t)va_arg( status->arg, size_t );
-                    break;
-            }
-            int2base( value, status );
-        }
-        else
-        {
-            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 );
-                    break;
-                case E_short:
-                    int2base( (intmax_t)(short)va_arg( status->arg, int ), status );
-                    break;
-                case 0:
-                    int2base( (intmax_t)va_arg( status->arg, int ), status );
-                    break;
-                case E_long:
-                    int2base( (intmax_t)va_arg( status->arg, long ), status );
-                    break;
-                case E_llong:
-                    int2base( (intmax_t)va_arg( status->arg, long long ), status );
-                    break;
-                case E_ptrdiff:
-                    int2base( (intmax_t)va_arg( status->arg, ptrdiff_t ), status );
-                    break;
-                case E_intmax:
-                    int2base( va_arg( status->arg, intmax_t ), status );
-                    break;
-            }
-        }
-        if ( status->flags & E_minus )
-        {
-            while ( status->current < status->width )
-            {
-                PUT( ' ' );
-                ++(status->current);
-            }
-        }
-        if ( status->i >= status->n && status->n > 0 )
-        {
-            status->s[status->n - 1] = '\0';
-        }
-    }
-    return ++spec;
-}
-
-#endif
-
-#ifdef TEST
-#define _PDCLIB_FILEID "_PDCLIB/print.c"
-#define _PDCLIB_STRINGIO
-
-#include <_PDCLIB_test.h>
-
-#ifndef REGTEST
-static int testprintf( char * buffer, const char * format, ... )
-{
-    /* Members: base, flags, n, i, current, s, width, prec, stream, arg      */
-    struct _PDCLIB_status_t status;
-    status.base = 0;
-    status.flags = 0;
-    status.n = 100;
-    status.i = 0;
-    status.current = 0;
-    status.s = buffer;
-    status.width = 0;
-    status.prec = 0;
-    status.stream = NULL;
-    va_start( status.arg, format );
-    memset( buffer, '\0', 100 );
-    if ( *(_PDCLIB_print( format, &status )) != '\0' )
-    {
-        printf( "_PDCLIB_print() did not return end-of-specifier on '%s'.\n", format );
-        ++TEST_RESULTS;
-    }
-    va_end( status.arg );
-    return status.i;
-}
-#endif
-
-#define TEST_CONVERSION_ONLY
-
-int main( void )
-{
-#ifndef REGTEST
-    char target[100];
-#include "printf_testcases.h"
-#endif
-    return TEST_RESULTS;
-}
-
-#endif