]> pd.if.org Git - pdclib/commitdiff
Temporary integration of _PDCLIB_print(), broken.
authorsolar <unknown>
Wed, 26 Apr 2006 09:34:21 +0000 (09:34 +0000)
committersolar <unknown>
Wed, 26 Apr 2006 09:34:21 +0000 (09:34 +0000)
functions/_PDCLIB/print.c [new file with mode: 0644]
functions/stdio/fopen.c
functions/stdio/getchar.c
functions/stdio/gets.c
functions/stdio/vfprintf.c
functions/stdio/vsnprintf.c
functions/stdio/vsprintf.c
includes/stdio.h
internals/_PDCLIB_int.h

diff --git a/functions/_PDCLIB/print.c b/functions/_PDCLIB/print.c
new file mode 100644 (file)
index 0000000..28cd4bc
--- /dev/null
@@ -0,0 +1,459 @@
+/* $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>
+
+/* 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_intptr   1<<13
+#define E_double   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 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 )
+
+/* This function recursively converts a given integer value to a given base
+   into a character string. Persistent information - like the number of digits
+   parsed so far - is recorded in a struct _PDCLIB_status_t, which allows to
+   avoid overwriting snprintf() limits, and enables the function to do the
+   necessary padding / prefixing of the character string eventually printed.
+*/
+static void int2base( intmax_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.
+    */
+    ++(status->this);
+    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.
+        */
+        /* At worst, we need two prefix characters (hex prefix). */
+        char preface[3] = "\0";
+        size_t preidx = 0;
+        if ( ( status->flags & E_alt ) && ( status->base == 16 || status->base == 8 ) )
+        {
+            /* Octal / hexadecimal prefix for "%#" conversions */
+            preface[ preidx++ ] = '0';
+            if ( status->base == 16 )
+            {
+                preface[ preidx++ ] = ( status->flags & E_lower ) ? 'x' : 'X';
+            }
+        }
+        if ( value < 0 )
+        {
+            /* Negative sign for negative values - at all times. */
+            preface[ preidx++ ] = '-';
+        }
+        else if ( ! ( status->flags & E_unsigned ) )
+        {
+            /* plus sign / extra space are only for unsigned conversions */
+            if ( status->flags & E_plus )
+            {
+                preface[ preidx++ ] = '+';
+            }
+            else if ( status->flags & E_space )
+            {
+                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
+               is requested. Leave space for any prefixes determined above.
+            */
+            /* The number of characters to be printed, plus prefixes if any. */
+            /* This line contained probably the most stupid, time-wasting bug
+               I've ever perpetrated. Greetings to Samface, DevL, and all
+               sceners at Breakpoint 2006.
+            */
+            size_t characters = preidx + ( ( status->this > status->prec ) ? status->this : status->prec );
+            if ( status->width > characters )
+            {
+                for ( int i = 0; i < status->width - characters; ++i )
+                {
+                    DELIVER( ' ' );
+                    ++(status->this);
+                }
+            }
+        }
+        /* Now we did the padding, do the prefixes (if any). */
+        preidx = 0;
+        while ( preface[ preidx ] != '\0' )
+        {
+            DELIVER( preface[ preidx++ ] );
+            ++(status->this);
+        }
+        if ( ( ! ( status->flags & E_minus ) ) && ( status->flags & E_zero ) )
+        {
+            /* If field is not left aligned, and zero padding is requested, do
+               so.
+            */
+            while ( status->this < status->width )
+            {
+                DELIVER( '0' );
+                ++(status->this);
+            }
+        }
+        /* Do the precision padding if necessary. */
+        for ( int i = 0; i < prec_pads; ++i )
+        {
+            DELIVER( '0' );
+        }
+        }
+    }
+    /* 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 ] );
+    }
+    }
+}
+
+/* This function is to be called with spec pointing to the leading '%' of a
+   printf() conversion specifier.
+*/
+const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status )
+{
+    const char * orig_spec = spec;
+    if ( *(++spec) == '%' )
+    {
+        DELIVER( *spec );
+        return ++spec;
+    }
+    /* Initializing status structure */
+    status->flags = 0;
+    status->base  = 0;
+    status->this  = 0;
+    status->width = 0;
+    status->prec  = 0;
+
+    /* First come 0..n flags */
+    do
+    {
+        switch ( *spec )
+        {
+            case '-':
+                status->flags |= E_minus;
+                ++spec;
+                break;
+            case '+':
+                status->flags |= E_plus;
+                ++spec;
+                break;
+            case '#':
+                status->flags |= E_alt;
+                ++spec;
+                break;
+            case ' ':
+                status->flags |= E_space;
+                ++spec;
+                break;
+            case '0':
+                status->flags |= E_zero;
+                ++spec;
+                break;
+            default:
+                status->flags |= E_done;
+                break;
+        }
+    } while ( ! ( status->flags & E_done ) );
+
+    /* Optional field width */
+    if ( *spec == '*' )
+    {
+        /* Retrieve width value from argument stack */
+        if ( ( status->width = va_arg( status->arg, int ) ) < 0 )
+        {
+            /* Negative value is '-' flag plus absolute value */
+            status->flags |= E_minus;
+            status->width *= -1;
+        }
+        ++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 );
+        }
+        else
+        {
+            char * endptr;
+            status->prec = (int)strtol( spec, &endptr, 10 );
+            if ( spec == endptr )
+            {
+                /* Decimal point but no number - bad conversion specifier. */
+                return orig_spec;
+            }
+            spec = endptr;
+        }
+        /* 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' )
+            {
+                status->flags |= E_char;
+                ++spec;
+            }
+            else
+            {
+                status->flags |= E_short;
+            }
+            break;
+        case 'l':
+            if ( *spec == 'l' )
+            {
+                status->flags |= E_llong;
+                ++spec;
+            }
+            else
+            {
+                status->flags |= E_long;
+            }
+            break;
+        case 'j':
+            status->flags |= E_intmax;
+            break;
+        case 'z':
+            status->flags |= E_size;
+            break;
+        case 't':
+            status->flags |= E_ptrdiff;
+            break;
+        case 'L':
+            status->flags |= E_double;
+            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: Flags, wide chars. */
+            DELIVER( va_arg( status->arg, int ) );
+            return ++spec;
+        case 's':
+            /* TODO: Flags, wide chars. */
+            {
+                char * s = va_arg( status->arg, char * );
+                while ( *s != '\0' )
+                {
+                    DELIVER( *(s++) );
+                }
+                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;
+            }
+            ++(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( 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->this < status->width )
+            {
+                DELIVER( ' ' );
+                ++(status->this);
+            }
+        }
+        if ( status->i >= status->n )
+        {
+            status->s[status->n - 1] = '\0';
+        }
+    }
+    return ++spec;
+}
index f22287da4669bf8b15441b8076089103aea2a5ad..244549c7e8d344e74b81e57f10f836b128b8facc 100644 (file)
@@ -12,7 +12,7 @@
 #ifndef REGTEST
 #include <_PDCLIB_glue.h>
 
-static const FILE * _PDCLIB_filelist = NULL;
+static FILE * _PDCLIB_filelist = NULL;
 
 static int filemode( char const * const mode )
 {
index a98f6d708fb0d9bd25fe749f8a4446c492292521..0aef0c3463dbadf1af24cc9b98cfe71b04b702fa 100644 (file)
@@ -10,7 +10,7 @@
 
 #ifndef REGTEST
 
-int getchar( void )
+int (getchar)( void )
 {
     return fgetc( stdin );
 }
index 4aa45ff0117d2011ca102e79f16e08d5c3dc8900..27575223581ef8fa1f8ce1b9e52740ec21cc0f5f 100644 (file)
@@ -7,6 +7,7 @@
 */
 
 #include <stdio.h>
+#include <stdint.h>
 
 #ifndef REGTEST
 
index 12a09097e1fc52e4ec4dc93d9c0843875d1fa19e..3656843602dfd76e14e95ec5abdae3b0ef8af1d8 100644 (file)
@@ -8,13 +8,30 @@
 
 #include <stdio.h>
 #include <stdarg.h>
+#include <stdint.h>
 
 #ifndef REGTEST
 
 int vfprintf( FILE * _PDCLIB_restrict stream, const char * _PDCLIB_restrict format, va_list arg )
 {
-    /* TODO: Implement using vsnprintf() writing to file buffer */
-    return 0;
+    /* TODO: This function should interpret format as multibyte characters.  */
+    /* Members: base, flags, n, i, this, s, width, prec, stream, arg         */
+    struct _PDCLIB_status_t status = { 0, 0, SIZE_MAX, 0, 0, NULL, 0, 0, stream, arg };
+    while ( *format != '\0' )
+    {
+        const char * rc;
+        if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
+        {
+            /* No conversion specifier, print verbatim */
+            putc( *(format++), stream );
+        }
+        else
+        {
+            /* Continue parsing after conversion specifier */
+            format = rc;
+        }
+    }
+    return status.i;
 }
 
 #endif
index 08f235530a68a8b843e53c06422bef19146b746a..84ad51dc462d41a7e14c4b4a747a3ec076e1d2dc 100644 (file)
 
 #ifndef REGTEST
 
-int vsnprintf( char * str, size_t size, const char * format, _PDCLIB_va_list arg )
+int vsnprintf( char * s, size_t n, const char * format, _PDCLIB_va_list arg )
 {
-    /* TODO: This function should interpret format as multibyte characters. */
-    /* TODO: Implement */
-    return 0;
+    /* TODO: This function should interpret format as multibyte characters.  */
+    /* Members: base, flags, n, i, this, s, width, prec, stream, arg         */
+    struct _PDCLIB_status_t status = { 0, 0, n, 0, 0, s, 0, 0, NULL, arg };
+    while ( *format != '\0' )
+    {
+        const char * rc;
+        if ( ( *format != '%' ) || ( ( rc = _PDCLIB_print( format, &status ) ) == format ) )
+        {
+            /* No conversion specifier, print verbatim */
+            s[ status.i++ ] = *(format++);
+        }
+        else
+        {
+            /* Continue parsing after conversion specifier */
+            format = rc;
+        }
+    }
+    s[ status.i ] = '\0';
+    return status.i;
 }
 
 #endif
index 27e41d8cf715b01a14f4c4691968e695747a0d3c..c93f5cd38ac22f910c0497a09d45bc90b6ae4032 100644 (file)
@@ -12,7 +12,9 @@
 
 #ifndef REGTEST
 
-int vsprintf( char * str, const char * format, _PDCLIB_va_list arg )
+int foo = SIZE_MAX;
+
+int vsprintf( char * str, const char * format, va_list arg )
 {
     return vsnprintf( str, SIZE_MAX, format, arg );
 }
index 05d5b6e8a46dd77103176574ccb7d816d9d6aa21..f8232cdda355b35bcd8908988e17099be2630f1b 100644 (file)
@@ -44,6 +44,9 @@ typedef struct _PDCLIB_file_t FILE;
 #define SEEK_END 2
 #define SEEK_SET 4
 
+#define stdin NULL
+#define stdout NULL
+
 /* Operations on files */
 
 /* Remove the given file.
index 5e7d84035e8b0a8ca84d542b21ad485879fc3ffb..f3252e1e8b80c1d91c154caea270773a1488e6f1 100644 (file)
@@ -261,7 +261,7 @@ typedef unsigned _PDCLIB_intmax _PDCLIB_uintmax_t;
 #define _PDCLIB_FRW      8
 #define _PDCLIB_FBIN    16
 
-struct
+struct _PDCLIB_file_t
 {
     _PDCLIB_fd_t            handle;   /* OS-specific file descriptor */
     _PDCLIB_fpos_t          position; /* file position indicator */
@@ -270,21 +270,7 @@ struct
     int                     status;   /* misc. status bits */
   /*mbstate_t               mbstate;    multibyte parse state - TODO: Unmask. */
     struct _PDCLIB_file_t * next;     /* provisions for linked list handling */
-} _PDCLIB_file_t;
-
-/* -------------------------------------------------------------------------- */
-/* Declaration of helper functions (implemented in functions/_PDCLIB).        */
-/* -------------------------------------------------------------------------- */
-
-/* This is the main function called by atoi(), atol() and atoll().            */
-_PDCLIB_intmax_t _PDCLIB_atomax( const char * s );
-
-/* Two helper functions used by strtol(), strtoul() and long long variants.   */
-const char * _PDCLIB_strtox_prelim( const char * p, char * sign, int * base );
-_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, _PDCLIB_uintmax_t error, _PDCLIB_uintmax_t limval, _PDCLIB_uintmax_t limdigit, char * sign );
-
-/* Digits array used by various integer conversion functions in <stdlib.h>    */
-extern char _PDCLIB_digits[];
+};
 
 /* -------------------------------------------------------------------------- */
 /* Internal data types                                                        */
@@ -310,6 +296,21 @@ struct _PDCLIB_memnode_t
     struct _PDCLIB_memnode_t * next;
 };
 
+/* Status structure required by _PDCLIB_print(). */
+struct _PDCLIB_status_t
+{
+    int              base;  /* base to which the value shall be converted    */
+    _PDCLIB_int_fast32_t flags; /* flags and length modifiers                */
+    _PDCLIB_size_t   n;     /* maximum number of characters to be written    */
+    _PDCLIB_size_t   i;     /* number of characters already written          */
+    _PDCLIB_size_t   this;  /* output chars in the current conversion        */
+    char *           s;     /* target buffer                                 */
+    _PDCLIB_size_t   width; /* width of current field                        */
+    _PDCLIB_size_t   prec;  /* precision of current field                    */
+    struct _PDCLIB_file_t * stream;/* for to-stream output                   */
+    _PDCLIB_va_list  arg;   /* argument stack passed to the printf function  */
+};
+
 #if 0
 
 /* fpos_t, an object type (not an array!) capable of storing any position
@@ -321,3 +322,20 @@ typedef unsigned long long int  _PDCLIB_fpos_t;
 typedef int                     _PDCLIB_fd_t;
 
 #endif
+
+/* -------------------------------------------------------------------------- */
+/* Declaration of helper functions (implemented in functions/_PDCLIB).        */
+/* -------------------------------------------------------------------------- */
+
+/* This is the main function called by atoi(), atol() and atoll().            */
+_PDCLIB_intmax_t _PDCLIB_atomax( const char * s );
+
+/* Two helper functions used by strtol(), strtoul() and long long variants.   */
+const char * _PDCLIB_strtox_prelim( const char * p, char * sign, int * base );
+_PDCLIB_uintmax_t _PDCLIB_strtox_main( const char ** p, unsigned int base, _PDCLIB_uintmax_t error, _PDCLIB_uintmax_t limval, _PDCLIB_uintmax_t limdigit, char * sign );
+
+/* Digits array used by various integer conversion functions in <stdlib.h>    */
+extern char _PDCLIB_digits[];
+
+/* The worker for all printf() type of functions. */
+const char * _PDCLIB_print( const char * spec, struct _PDCLIB_status_t * status );