X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=device%2Flib%2Fvprintf.c;h=07b5cac365d817ece1ea3cd4df1cab459e40ef69;hb=3bd25d75bcad68055bb616dcc29dde8a2965965e;hp=1409507ed9b9026561691c2f1089dca4652a2163;hpb=75cfabdb04b00d77a0fb60edc94ea74052658c37;p=fw%2Fsdcc diff --git a/device/lib/vprintf.c b/device/lib/vprintf.c index 1409507e..07b5cac3 100644 --- a/device/lib/vprintf.c +++ b/device/lib/vprintf.c @@ -1,619 +1,50 @@ /*------------------------------------------------------------------------- vprintf.c - formatted output conversion - + Written By - Martijn van Balen aed@iae.nl (1999) - Added %f By - johan.knol@iduna.nl (2000) + Refactored by - Maarten Brock (2004) + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. - This program is free software; you can redistribute it and/or modify it - under the terms of the GNU General Public License as published by the - Free Software Foundation; either version 2, or (at your option) any - later version. - - This program is distributed in the hope that it will be useful, + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + In other words, you are welcome to use, share and improve this program. You are forbidden to forbid anyone else to use, share and improve - what you give them. Help stamp out software-hoarding! + what you give them. Help stamp out software-hoarding! -------------------------------------------------------------------------*/ -#define USE_FLOATS 1 #include -#include -#include #include -#define PTR value.p - -#ifdef SDCC_ds390 -#define NULL_STRING "" -#define NULL_STRING_LENGTH 6 -#endif - -/* XSPEC is defined in stdio.h and used here to place - auto variables in XSEG */ - -/****************************************************************************/ - -typedef char _generic *ptr_t; - -#ifdef toupper -#undef toupper -#endif - -//#define toupper(c) ((c)&=~0x20) -#define toupper(c) ((c)&=0xDF) - -typedef union -{ - unsigned char byte[5]; - long l; - unsigned long ul; - float f; - char _generic *p; -} value_t; - - -static code char memory_id[] = "IXCP-"; - -static ptr_t output_ptr; -static bit output_to_string; -static bit lower_case; -static bit lsd; - -/* this one NEEDS to be in data */ -static data value_t value; - -static unsigned short radix; - -// jwk: TODO: this makes the whole dammed thing nonreentrent -static int charsOutputted; - -/****************************************************************************/ - -static void output_char( char c ) reentrant -{ - if (output_to_string) - { - *output_ptr++ = c; - } - else - { - putchar( c ); - } - charsOutputted++; -} - -/*--------------------------------------------------------------------------*/ - -static void output_digit( unsigned char n ) reentrant +static void put_char_to_stdout( char c, void* p ) _REENTRANT { - output_char( n <= 9 ? '0'+n : - (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) ); + p; //make compiler happy + putchar( c ); } -/*--------------------------------------------------------------------------*/ - -static void output_2digits( unsigned char b ) reentrant +int vprintf (const char *format, va_list ap) { - output_digit( b>>4 ); - output_digit( b&0x0F ); + return _print_format( put_char_to_stdout, NULL, format, ap ); } - -/*--------------------------------------------------------------------------*/ -static void calculate_digit( void ) +int printf (const char *format, ...) { - unsigned char i; + va_list arg; + int i; - for( i = 32; i != 0; i-- ) - { -_asm - clr c - mov a,_value+0 - rlc a - mov _value+0,a - mov a,_value+1 - rlc a - mov _value+1,a - mov a,_value+2 - rlc a - mov _value+2,a - mov a,_value+3 - rlc a - mov _value+3,a - mov a,_value+4 - rlc a - mov _value+4,a -_endasm; + va_start (arg, format); + i = _print_format( put_char_to_stdout, NULL, format, arg ); + va_end (arg); - if (radix <= value.byte[4] ) - { - value.byte[4] -= radix; - value.byte[0]++; - } - } -} - -#if USE_FLOATS - -/* This is a very inefficient but direct approach, since we have no math - library yet (e.g. log()). - It does most of the modifiers, but has some restrictions. E.g. the - abs(float) shouldn't be bigger than an unsigned long (that's - about 4294967295), but still makes it usefull for most real-life - applications. -*/ - -#define DEFAULT_FLOAT_PRECISION 6 - -static void output_float (float f, unsigned char reqWidth, - signed char reqDecimals, - bit left, bit zero, bit sign, bit space) -{ - XSPEC char negative=0; - XSPEC long integerPart; - XSPEC float decimalPart; - XSPEC char fpBuffer[128]; - XSPEC char fpBI=0, fpBD; - XSPEC unsigned char minWidth, i; - - // save the sign - if (f<0) { - negative=1; - f=-f; - } - - // split the float - integerPart=f; - decimalPart=f-integerPart; - - // fill the buffer with the integerPart (in reversed order!) - while (integerPart) { - fpBuffer[fpBI++]='0' + integerPart%10; - integerPart /= 10; - } - if (!fpBI) { - // we need at least a 0 - fpBuffer[fpBI++]='0'; - } - - // display some decimals as default - if (reqDecimals==-1) - reqDecimals=DEFAULT_FLOAT_PRECISION; - - // fill buffer with the decimalPart (in normal order) - fpBD=fpBI; - if (i=reqDecimals /* that's an assignment */) { - do { - decimalPart *= 10.0; - // truncate the float - integerPart=decimalPart; - fpBuffer[fpBD++]='0' + integerPart; - decimalPart-=integerPart; - } while (--i); - } - - minWidth=fpBI; // we need at least these - minWidth+=reqDecimals?reqDecimals+1:0; // maybe these - if (negative || sign || space) - minWidth++; // and maybe even this :) - - if (!left && reqWidth>i) { - if (zero) { - if (negative) output_char('-'); - else if (sign) output_char('+'); - else if (space) output_char(' '); - while (reqWidth-->minWidth) - output_char ('0'); - } else { - while (reqWidth-->minWidth) - output_char (' '); - if (negative) output_char('-'); - else if (sign) output_char('+'); - else if (space) output_char (' '); - } - } else { - if (negative) output_char('-'); - else if (sign) output_char('+'); - else if (space) output_char(' '); - } - - // output the integer part - i=fpBI-1; - do { - output_char (fpBuffer[i]); - } while (i--); - - // ouput the decimal part - if (reqDecimals) { - output_char ('.'); - i=fpBI; - while (reqDecimals--) - output_char (fpBuffer[i++]); - } - - if (left && reqWidth>minWidth) { - while (reqWidth-->minWidth) - output_char(' '); - } -} -#endif - -/*--------------------------------------------------------------------------*/ - -int vsprintf (const char *buf, const char *format, va_list ap) -{ - bit left_justify; - bit zero_padding; - bit prefix_sign; - bit prefix_space; - bit signed_argument; - bit char_argument; - bit long_argument; - bit float_argument; - - XSPEC unsigned char width; - XSPEC signed char decimals; - XSPEC unsigned char length; - XSPEC char c; - - // reset output chars - charsOutputted=0; - - output_ptr = buf; - if ( !buf ) - { - output_to_string = 0; - } - else - { - output_to_string = 1; - } - -#ifdef SDCC_ds390 - if (format==0) { - format=NULL_STRING; - } -#endif - - while( c=*format++ ) - { - if ( c=='%' ) - { - left_justify = 0; - zero_padding = 0; - prefix_sign = 0; - prefix_space = 0; - signed_argument = 0; - radix = 0; - char_argument = 0; - long_argument = 0; - float_argument = 0; - width = 0; - decimals = -1; - -get_conversion_spec: - - c = *format++; - - if (c=='%') { - output_char(c); - continue; - } - - if (isdigit(c)) { - if (decimals==-1) { - width = 10*width + (c - '0'); - if (width == 0) { - /* first character of width is a zero */ - zero_padding = 1; - } - } else { - decimals = 10*decimals + (c-'0'); - } - goto get_conversion_spec; - } - - if (c=='.') { - if (decimals=-1) decimals=0; - else - ; // duplicate, ignore - goto get_conversion_spec; - } - - lower_case = islower(c); - if (lower_case) - { - c = toupper(c); - } - - switch( c ) - { - case '-': - left_justify = 1; - goto get_conversion_spec; - case '+': - prefix_sign = 1; - goto get_conversion_spec; - case ' ': - prefix_space = 1; - goto get_conversion_spec; - case 'B': - char_argument = 1; - goto get_conversion_spec; - case 'L': - long_argument = 1; - goto get_conversion_spec; - - case 'C': - output_char( va_arg(ap,unsigned char) ); - break; - - case 'S': - PTR = va_arg(ap,ptr_t); - -#ifdef SDCC_ds390 - if (PTR==0) { - PTR=NULL_STRING; - length=NULL_STRING_LENGTH; - } else { - length = strlen(PTR); - } -#else - length = strlen(PTR); -#endif - if ( ( !left_justify ) && (length < width) ) - { - width -= length; - while( width-- != 0 ) - { - output_char( ' ' ); - } - } - - while ( *PTR ) - output_char( *PTR++ ); - - if ( left_justify && (length < width)) - { - width -= length; - while( width-- != 0 ) - { - output_char( ' ' ); - } - } - break; - - case 'P': - PTR = va_arg(ap,ptr_t); - -#ifdef SDCC_ds390 - output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] ); - output_char(':'); - output_char('0'); - output_char('x'); - output_2digits(value.byte[2]); - output_2digits(value.byte[1]); - output_2digits(value.byte[0]); -#else - output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] ); - output_char(':'); - output_char('0'); - output_char('x'); - if ((value.byte[2] != 0x00 /* DSEG */) && - (value.byte[2] != 0x03 /* SSEG */)) - output_2digits( value.byte[1] ); - output_2digits( value.byte[0] ); -#endif - break; - - case 'D': - case 'I': - signed_argument = 1; - radix = 10; - break; - - case 'O': - radix = 8; - break; - - case 'U': - radix = 10; - break; - - case 'X': - radix = 16; - break; - - case 'F': - float_argument=1; - break; - - default: - // nothing special, just output the character - output_char( c ); - break; - } - - if (float_argument) { - value.f=va_arg(ap,float); -#if !USE_FLOATS - PTR=""; - while (c=*PTR++) - output_char (c); - // treat as long hex - //radix=16; - //long_argument=1; - //zero_padding=1; - //width=8; -#else - // ignore b and l conversion spec for now - output_float(value.f, width, decimals, left_justify, zero_padding, - prefix_sign, prefix_space); -#endif - } else if (radix != 0) - { - // Apperently we have to output an integral type - // with radix "radix" - - // store value in byte[0] (LSB) ... byte[3] (MSB) - if (char_argument) - { - value.l = va_arg(ap,char); - if (!signed_argument) - { - value.byte[1] = 0x00; - value.byte[2] = 0x00; - value.byte[3] = 0x00; - } - } - else if (long_argument) - { - value.l = va_arg(ap,long); - } - else // must be int - { - value.l = va_arg(ap,int); - if (!signed_argument) - { - value.byte[2] = 0x00; - value.byte[3] = 0x00; - } - } - - if ( signed_argument ) - { - if (value.l < 0) - value.l = -value.l; - else - signed_argument = 0; - } - - length=0; - lsd = 1; - - //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0); - do { - value.byte[4] = 0; - calculate_digit(); - -_asm - jb _lsd,1$ - pop b ; b = - mov a,_value+4 ; a = - swap a - orl b,a ; b = - push b - sjmp 2$ -1$: - mov a,_value+4 ; a = - push acc -2$: -_endasm; - - length++; - lsd = ~lsd; - } while( (value.byte[0] != 0) || (value.byte[1] != 0) || - (value.byte[2] != 0) || (value.byte[3] != 0) ); - - if (width == 0) - { - // default width. We set it to 1 to output - // at least one character is case the value itself - // is zero (i.e. length==0) - width=1; - } - - /* prepend spaces if needed */ - if (!zero_padding) - { - while ( width > length+1 ) - { - output_char( ' ' ); - width--; - } - } - - if (signed_argument) // this now means the original value was negative - { - output_char( '-' ); - // adjust width to compensate for this character - width--; - } - else if (length != 0) - { - // value > 0 - if (prefix_sign) - { - output_char( '+' ); - // adjust width to compensate for this character - width--; - } - else if (prefix_space) - { - output_char( ' ' ); - // adjust width to compensate for this character - width--; - } - } - - /* prepend zeroes/spaces if needed */ - while ( width-- > length ) - { - output_char( zero_padding ? '0' : ' ' ); - } - - /* output the digits */ - while( length-- ) - { - lsd = ~lsd; - -_asm - jb _lsd,3$ - pop acc ; a = - nop ; to disable the "optimizer" - push acc - swap a - anl a,#0x0F ; a = - sjmp 4$ -3$: - pop acc - anl a,#0x0F ; a = -4$: - mov _value+4,a -_endasm; - - output_digit( value.byte[4] ); - } - } - } - else - { - // nothing special, just output the character - output_char( c ); - } - } - - // Copy \0 to the end of buf - // Modified by JB 17/12/99 - if (output_to_string) { - output_char(0); - return charsOutputted-1; - } else { - return charsOutputted; - } -} - -/*--------------------------------------------------------------------------*/ - -int vprintf (const char *format, va_list ap) -{ - return vsprintf( 0, format, ap ); + return i; }