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 // jwk: TODO: 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 float output_floatE(float f, char decimals)
167 if (f < 0) { f = -f; sign = '-'; }
168 for (exp = 0; f >= 10.0; exp++) f /=10.0;
169 for ( ; f < 1.0; exp--) f *=10.0;
170 printf("%c%d.%d%fe%d\n", sign, decimals+2, decimals, f, exp);
173 static void output_float (float f, unsigned char reqWidth,
174 signed char reqDecimals,
175 bit left, bit zero, bit sign, bit space)
178 unsigned long integerPart;
182 unsigned char minWidth, i;
191 // this part is from Frank van der Hulst
194 for (exp = 0; f >= 10.0; exp++) f /=10.0;
195 for ( ; f < 1.0; exp--) f *=10.0;
204 output_float(f, 0, reqDecimals, 0, 0, 0, 0);
210 putchar ('0'+exp/10);
211 putchar ('0'+exp%10);
217 decimalPart=f-integerPart;
219 // fill the buffer with the integerPart (in reversed order!)
220 while (integerPart) {
221 fpBuffer[fpBI++]='0' + integerPart%10;
225 // we need at least a 0
226 fpBuffer[fpBI++]='0';
229 // display some decimals as default
231 reqDecimals=DEFAULT_FLOAT_PRECISION;
233 // fill buffer with the decimalPart (in normal order)
235 if (i=reqDecimals /* that's an assignment */) {
238 // truncate the float
239 integerPart=decimalPart;
240 fpBuffer[fpBD++]='0' + integerPart;
241 decimalPart-=integerPart;
245 minWidth=fpBI; // we need at least these
246 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
247 if (negative || sign || space)
248 minWidth++; // and maybe even this :)
250 if (!left && reqWidth>i) {
252 if (negative) output_char('-');
253 else if (sign) output_char('+');
254 else if (space) output_char(' ');
255 while (reqWidth-->minWidth)
258 while (reqWidth-->minWidth)
260 if (negative) output_char('-');
261 else if (sign) output_char('+');
262 else if (space) output_char (' ');
265 if (negative) output_char('-');
266 else if (sign) output_char('+');
267 else if (space) output_char(' ');
270 // output the integer part
273 output_char (fpBuffer[i]);
276 // ouput the decimal part
280 while (reqDecimals--)
281 output_char (fpBuffer[i++]);
284 if (left && reqWidth>minWidth) {
285 while (reqWidth-->minWidth)
291 /*--------------------------------------------------------------------------*/
293 int vsprintf (const char *buf, const char *format, va_list ap)
295 static bit left_justify;
296 static bit zero_padding;
297 static bit prefix_sign;
298 static bit prefix_space;
299 static bit signed_argument;
300 static bit char_argument;
301 static bit long_argument;
302 static bit float_argument;
305 signed char decimals;
306 unsigned char length;
309 // reset output chars
315 output_to_string = 0;
319 output_to_string = 1;
355 width = 10*width + (c - '0');
357 /* first character of width is a zero */
361 decimals = 10*decimals + (c-'0');
363 goto get_conversion_spec;
367 if (decimals=-1) decimals=0;
369 ; // duplicate, ignore
370 goto get_conversion_spec;
373 lower_case = islower(c);
383 goto get_conversion_spec;
386 goto get_conversion_spec;
389 goto get_conversion_spec;
392 goto get_conversion_spec;
395 goto get_conversion_spec;
398 output_char( va_arg(ap,int) );
402 PTR = va_arg(ap,ptr_t);
407 length=NULL_STRING_LENGTH;
409 length = strlen(PTR);
412 length = strlen(PTR);
414 if ( ( !left_justify ) && (length < width) )
417 while( width-- != 0 )
424 output_char( *PTR++ );
426 if ( left_justify && (length < width))
429 while( width-- != 0 )
437 PTR = va_arg(ap,ptr_t);
440 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
444 output_2digits(value.byte[2]);
445 output_2digits(value.byte[1]);
446 output_2digits(value.byte[0]);
448 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
452 if ((value.byte[2] != 0x00 /* DSEG */) &&
453 (value.byte[2] != 0x03 /* SSEG */))
454 output_2digits( value.byte[1] );
455 output_2digits( value.byte[0] );
482 // nothing special, just output the character
487 if (float_argument) {
488 value.f=va_arg(ap,float);
499 // ignore b and l conversion spec for now
500 output_float(value.f, width, decimals, left_justify, zero_padding,
501 prefix_sign, prefix_space);
503 } else if (radix != 0)
505 // Apperently we have to output an integral type
506 // with radix "radix"
508 // store value in byte[0] (LSB) ... byte[3] (MSB)
511 value.l = va_arg(ap,char);
512 if (!signed_argument)
514 value.byte[1] = 0x00;
515 value.byte[2] = 0x00;
516 value.byte[3] = 0x00;
519 else if (long_argument)
521 value.l = va_arg(ap,long);
525 value.l = va_arg(ap,int);
526 if (!signed_argument)
528 value.byte[2] = 0x00;
529 value.byte[3] = 0x00;
533 if ( signed_argument )
544 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
552 mov a,_value+4 ; a = <msd>
554 orl b,a ; b = <msd><lsd>
558 mov a,_value+4 ; a = <lsd>
565 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
566 (value.byte[2] != 0) || (value.byte[3] != 0) );
570 // default width. We set it to 1 to output
571 // at least one character is case the value itself
572 // is zero (i.e. length==0)
576 /* prepend spaces if needed */
579 while ( width > length+1 )
586 if (signed_argument) // this now means the original value was negative
589 // adjust width to compensate for this character
592 else if (length != 0)
598 // adjust width to compensate for this character
601 else if (prefix_space)
604 // adjust width to compensate for this character
609 /* prepend zeroes/spaces if needed */
610 while ( width-- > length )
612 output_char( zero_padding ? '0' : ' ' );
615 /* output the digits */
622 pop acc ; a = <msd><lsd>
623 nop ; to disable the "optimizer"
626 anl a,#0x0F ; a = <msd>
630 anl a,#0x0F ; a = <lsd>
635 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 );