123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356 |
- /* Small, noncompliant, not-full-featured printf implementation
- *
- *
- * Copyright (c) 2010, Ingo Korb
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * * Neither the name of Ingo Korb nor the
- * names of the contributors may be used to endorse or promote products
- * derived from this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- *
- * FIXME: Selection of output function should be more flexible
- */
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include "config.h"
- #include "uart.h"
- #define outfunc(x) uart_putc(x)
- #define FLAG_ZEROPAD 1
- #define FLAG_LEFTADJ 2
- #define FLAG_BLANK 4
- #define FLAG_FORCESIGN 8
- #define FLAG_WIDTH 16
- #define FLAG_LONG 32
- #define FLAG_UNSIGNED 64
- #define FLAG_NEGATIVE 128
- /* Digits used for conversion */
- static const char hexdigits[] = "0123456789abcdef";
- /* Temporary buffer used for numbers - just large enough for 32 bit in octal */
- static char buffer[12];
- /* Output string length */
- static unsigned int outlength;
- /* Output pointer */
- static char *outptr;
- static int maxlen;
- /* printf */
- static void outchar( char x )
- {
- if ( maxlen )
- {
- maxlen--;
- outfunc( x );
- outlength++;
- }
- }
- /* sprintf */
- static void outstr( char x )
- {
- if ( maxlen )
- {
- maxlen--;
- *outptr++ = x;
- outlength++;
- }
- }
- static int internal_nprintf( void ( *output_function )( char c ), const char *fmt, va_list ap )
- {
- unsigned int width;
- unsigned int flags;
- unsigned int base = 0;
- char *ptr = NULL;
- outlength = 0;
- while ( *fmt )
- {
- while ( 1 )
- {
- if ( *fmt == 0 )
- {
- goto end;
- }
- if ( *fmt == '%' )
- {
- fmt++;
- if ( *fmt != '%' )
- {
- break;
- }
- }
- output_function( *fmt++ );
- }
- flags = 0;
- width = 0;
- /* read all flags */
- do
- {
- if ( flags < FLAG_WIDTH )
- {
- switch ( *fmt )
- {
- case '0':
- flags |= FLAG_ZEROPAD;
- continue;
- case '-':
- flags |= FLAG_LEFTADJ;
- continue;
- case ' ':
- flags |= FLAG_BLANK;
- continue;
- case '+':
- flags |= FLAG_FORCESIGN;
- continue;
- }
- }
- if ( flags < FLAG_LONG )
- {
- if ( *fmt >= '0' && *fmt <= '9' )
- {
- unsigned char tmp = *fmt - '0';
- width = 10 * width + tmp;
- flags |= FLAG_WIDTH;
- continue;
- }
- if ( *fmt == 'h' )
- {
- continue;
- }
- if ( *fmt == 'l' )
- {
- flags |= FLAG_LONG;
- continue;
- }
- }
- break;
- }
- while ( *fmt++ );
- /* Strings */
- if ( *fmt == 'c' || *fmt == 's' )
- {
- switch ( *fmt )
- {
- case 'c':
- buffer[0] = va_arg( ap, int );
- ptr = buffer;
- break;
- case 's':
- ptr = va_arg( ap, char * );
- break;
- }
- goto output;
- }
- /* Numbers */
- switch ( *fmt )
- {
- case 'u':
- flags |= FLAG_UNSIGNED;
- case 'd':
- base = 10;
- break;
- case 'o':
- base = 8;
- flags |= FLAG_UNSIGNED;
- break;
- case 'p': // pointer
- output_function( '0' );
- output_function( 'x' );
- width -= 2;
- case 'x':
- case 'X':
- base = 16;
- flags |= FLAG_UNSIGNED;
- break;
- }
- unsigned int num;
- if ( !( flags & FLAG_UNSIGNED ) )
- {
- int tmp = va_arg( ap, int );
- if ( tmp < 0 )
- {
- num = -tmp;
- flags |= FLAG_NEGATIVE;
- }
- else
- {
- num = tmp;
- }
- }
- else
- {
- num = va_arg( ap, unsigned int );
- }
- /* Convert number into buffer */
- ptr = buffer + sizeof( buffer );
- *--ptr = 0;
- do
- {
- *--ptr = hexdigits[num % base];
- num /= base;
- }
- while ( num != 0 );
- /* Sign */
- if ( flags & FLAG_NEGATIVE )
- {
- output_function( '-' );
- width--;
- }
- else if ( flags & FLAG_FORCESIGN )
- {
- output_function( '+' );
- width--;
- }
- else if ( flags & FLAG_BLANK )
- {
- output_function( ' ' );
- width--;
- }
- output:
- /* left padding */
- if ( ( flags & FLAG_WIDTH ) && !( flags & FLAG_LEFTADJ ) )
- {
- while ( strlen( ptr ) < width )
- {
- if ( flags & FLAG_ZEROPAD )
- {
- output_function( '0' );
- }
- else
- {
- output_function( ' ' );
- }
- width--;
- }
- }
- /* data */
- while ( *ptr )
- {
- output_function( *ptr++ );
- if ( width )
- {
- width--;
- }
- }
- /* right padding */
- if ( flags & FLAG_WIDTH )
- {
- while ( width )
- {
- output_function( ' ' );
- width--;
- }
- }
- fmt++;
- }
- end:
- return outlength;
- }
- int printf( const char *format, ... )
- {
- va_list ap;
- int res;
- maxlen = -1;
- va_start( ap, format );
- res = internal_nprintf( outchar, format, ap );
- va_end( ap );
- return res;
- }
- int snprintf( char *str, size_t size, const char *format, ... )
- {
- va_list ap;
- int res;
- maxlen = size;
- outptr = str;
- va_start( ap, format );
- res = internal_nprintf( outstr, format, ap );
- va_end( ap );
- if ( res < size )
- {
- str[res] = 0;
- }
- return res;
- }
- /* Required for gcc compatibility */
- int puts( const char *str )
- {
- uart_puts( str );
- uart_putc( '\n' );
- return 0;
- }
- #undef putchar
- int putchar( int c )
- {
- uart_putc( c );
- return 0;
- }
|