1 /*-------------------------------------------------------------------------
2 vprintf.c - formatted output conversion
4 Written By - Martijn van Balen aed@iae.nl (1999)
5 Added %f By - johan.knol@iduna.nl (2000)
7 This program is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 2, or (at your option) any
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 In other words, you are welcome to use, share and improve this program.
22 You are forbidden to forbid anyone else to use, share and improve
23 what you give them. Help stamp out software-hoarding!
24 -------------------------------------------------------------------------*/
26 /* this module uses some global variables instead function parameters, so: */
27 #ifdef SDCC_STACK_AUTO
28 #warning "this module cannot yet be use as a reentrant one"
43 #define NULL_STRING "<NULL>"
44 #define NULL_STRING_LENGTH 6
47 /****************************************************************************/
49 //typedef char * ptr_t;
56 //#define toupper(c) ((c)&=~0x20)
57 #define toupper(c) ((c)&=0xDF)
61 unsigned char byte[5];
69 static code char memory_id[] = "IXCP-";
71 static ptr_t output_ptr;
72 static bit output_to_string;
73 static bit lower_case;
76 /* this one NEEDS to be in data */
77 static data value_t value;
79 static unsigned char radix;
81 // this makes the whole dammed thing nonreentrent
82 static int charsOutputted;
84 /****************************************************************************/
86 static void output_char( char c ) reentrant
99 /*--------------------------------------------------------------------------*/
101 static void output_digit( unsigned char n ) reentrant
103 output_char( n <= 9 ? '0'+n :
104 (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) );
107 /*--------------------------------------------------------------------------*/
109 static void output_2digits( unsigned char b ) reentrant
111 output_digit( b>>4 );
112 output_digit( b&0x0F );
115 /*--------------------------------------------------------------------------*/
117 static void calculate_digit( void )
121 for( i = 32; i != 0; i-- )
142 if (radix <= value.byte[4] )
144 value.byte[4] -= radix;
152 /* This is a very inefficient but direct approach, since we have no math
153 library yet (e.g. log()).
154 It does most of the modifiers, but has some restrictions. E.g. the
155 abs(float) shouldn't be bigger than an unsigned long (that's
156 about 4294967295), but still makes it usefull for most real-life
160 #define DEFAULT_FLOAT_PRECISION 6
162 static void output_float (float f, unsigned char reqWidth,
163 signed char reqDecimals,
164 bit left, bit zero, bit sign, bit space)
167 unsigned long integerPart;
171 unsigned char minWidth, i;
180 // this part is from Frank van der Hulst
183 for (exp = 0; f >= 10.0; exp++) f /=10.0;
184 for ( ; f < 1.0; exp--) f *=10.0;
193 output_float(f, 0, reqDecimals, 0, 0, 0, 0);
199 putchar ('0'+exp/10);
200 putchar ('0'+exp%10);
206 decimalPart=f-integerPart;
208 // fill the buffer with the integerPart (in reversed order!)
209 while (integerPart) {
210 fpBuffer[fpBI++]='0' + integerPart%10;
214 // we need at least a 0
215 fpBuffer[fpBI++]='0';
218 // display some decimals as default
220 reqDecimals=DEFAULT_FLOAT_PRECISION;
222 // fill buffer with the decimalPart (in normal order)
224 if (i=reqDecimals /* that's an assignment */) {
227 // truncate the float
228 integerPart=decimalPart;
229 fpBuffer[fpBD++]='0' + integerPart;
230 decimalPart-=integerPart;
234 minWidth=fpBI; // we need at least these
235 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
236 if (negative || sign || space)
237 minWidth++; // and maybe even this :)
239 if (!left && reqWidth>i) {
241 if (negative) output_char('-');
242 else if (sign) output_char('+');
243 else if (space) output_char(' ');
244 while (reqWidth-->minWidth)
247 while (reqWidth-->minWidth)
249 if (negative) output_char('-');
250 else if (sign) output_char('+');
251 else if (space) output_char (' ');
254 if (negative) output_char('-');
255 else if (sign) output_char('+');
256 else if (space) output_char(' ');
259 // output the integer part
262 output_char (fpBuffer[i]);
265 // ouput the decimal part
269 while (reqDecimals--)
270 output_char (fpBuffer[i++]);
273 if (left && reqWidth>minWidth) {
274 while (reqWidth-->minWidth)
280 /*--------------------------------------------------------------------------*/
282 int vsprintf (const char *buf, const char *format, va_list ap)
284 static bit left_justify;
285 static bit zero_padding;
286 static bit prefix_sign;
287 static bit prefix_space;
288 static bit signed_argument;
289 static bit char_argument;
290 static bit long_argument;
291 static bit float_argument;
294 signed char decimals;
295 unsigned char length;
298 // reset output chars
304 output_to_string = 0;
308 output_to_string = 1;
344 width = 10*width + (c - '0');
346 /* first character of width is a zero */
350 decimals = 10*decimals + (c-'0');
352 goto get_conversion_spec;
356 if (decimals=-1) decimals=0;
358 ; // duplicate, ignore
359 goto get_conversion_spec;
362 lower_case = islower(c);
372 goto get_conversion_spec;
375 goto get_conversion_spec;
378 goto get_conversion_spec;
381 goto get_conversion_spec;
384 goto get_conversion_spec;
387 output_char( va_arg(ap,int) );
391 PTR = va_arg(ap,ptr_t);
396 length=NULL_STRING_LENGTH;
398 length = strlen(PTR);
401 length = strlen(PTR);
403 if ( ( !left_justify ) && (length < width) )
406 while( width-- != 0 )
413 output_char( *PTR++ );
415 if ( left_justify && (length < width))
418 while( width-- != 0 )
426 PTR = va_arg(ap,ptr_t);
429 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
433 output_2digits(value.byte[2]);
434 output_2digits(value.byte[1]);
435 output_2digits(value.byte[0]);
437 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
441 if ((value.byte[2] != 0x00 /* DSEG */) &&
442 (value.byte[2] != 0x03 /* SSEG */))
443 output_2digits( value.byte[1] );
444 output_2digits( value.byte[0] );
471 // nothing special, just output the character
476 if (float_argument) {
477 value.f=va_arg(ap,float);
488 // ignore b and l conversion spec for now
489 output_float(value.f, width, decimals, left_justify, zero_padding,
490 prefix_sign, prefix_space);
492 } else if (radix != 0)
494 // Apperently we have to output an integral type
495 // with radix "radix"
497 // store value in byte[0] (LSB) ... byte[3] (MSB)
500 value.l = va_arg(ap,char);
501 if (!signed_argument)
503 value.byte[1] = 0x00;
504 value.byte[2] = 0x00;
505 value.byte[3] = 0x00;
508 else if (long_argument)
510 value.l = va_arg(ap,long);
514 value.l = va_arg(ap,int);
515 if (!signed_argument)
517 value.byte[2] = 0x00;
518 value.byte[3] = 0x00;
522 if ( signed_argument )
540 mov a,_value+4 ; a = <msd>
542 orl b,a ; b = <msd><lsd>
546 mov a,_value+4 ; a = <lsd>
553 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
554 (value.byte[2] != 0) || (value.byte[3] != 0) );
558 // default width. We set it to 1 to output
559 // at least one character is case the value itself
560 // is zero (i.e. length==0)
564 /* prepend spaces if needed */
565 if (!zero_padding && !left_justify)
567 while ( width > length+1 )
574 if (signed_argument) // this now means the original value was negative
577 // adjust width to compensate for this character
580 else if (length != 0)
586 // adjust width to compensate for this character
589 else if (prefix_space)
592 // adjust width to compensate for this character
597 /* prepend zeroes/spaces if needed */
599 while ( width-- > length )
601 output_char( zero_padding ? '0' : ' ' );
605 /* spaces are appended after the digits */
612 /* output the digits */
619 pop acc ; a = <msd><lsd>
620 nop ; to disable the "optimizer"
623 anl a,#0x0F ; a = <msd>
627 anl a,#0x0F ; a = <lsd>
632 output_digit( value.byte[4] );
641 // nothing special, just output the character
646 // Copy \0 to the end of buf
647 // Modified by JB 17/12/99
648 if (output_to_string) {
650 return charsOutputted-1;
652 return charsOutputted;
656 /*--------------------------------------------------------------------------*/
658 int vprintf (const char *format, va_list ap)
660 return vsprintf( 0, format, ap );