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 /* XSPEC is defined in stdio.h and used here to place
48 auto variables in XSEG */
50 /****************************************************************************/
52 typedef char _generic *ptr_t;
58 //#define toupper(c) ((c)&=~0x20)
59 #define toupper(c) ((c)&=0xDF)
63 unsigned char byte[5];
71 static code char memory_id[] = "IXCP-";
73 static ptr_t output_ptr;
74 static bit output_to_string;
75 static bit lower_case;
78 /* this one NEEDS to be in data */
79 static data value_t value;
81 static unsigned char radix;
83 // jwk: TODO: this makes the whole dammed thing nonreentrent
84 static int charsOutputted;
86 /****************************************************************************/
88 static void output_char( char c ) reentrant
101 /*--------------------------------------------------------------------------*/
103 static void output_digit( unsigned char n ) reentrant
105 output_char( n <= 9 ? '0'+n :
106 (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) );
109 /*--------------------------------------------------------------------------*/
111 static void output_2digits( unsigned char b ) reentrant
113 output_digit( b>>4 );
114 output_digit( b&0x0F );
117 /*--------------------------------------------------------------------------*/
119 static void calculate_digit( void )
123 for( i = 32; i != 0; i-- )
144 if (radix <= value.byte[4] )
146 value.byte[4] -= radix;
154 /* This is a very inefficient but direct approach, since we have no math
155 library yet (e.g. log()).
156 It does most of the modifiers, but has some restrictions. E.g. the
157 abs(float) shouldn't be bigger than an unsigned long (that's
158 about 4294967295), but still makes it usefull for most real-life
162 #define DEFAULT_FLOAT_PRECISION 6
164 static void output_float (float f, unsigned char reqWidth,
165 signed char reqDecimals,
166 bit left, bit zero, bit sign, bit space)
173 unsigned char minWidth, i;
183 decimalPart=f-integerPart;
185 // fill the buffer with the integerPart (in reversed order!)
186 while (integerPart) {
187 fpBuffer[fpBI++]='0' + integerPart%10;
191 // we need at least a 0
192 fpBuffer[fpBI++]='0';
195 // display some decimals as default
197 reqDecimals=DEFAULT_FLOAT_PRECISION;
199 // fill buffer with the decimalPart (in normal order)
201 if (i=reqDecimals /* that's an assignment */) {
204 // truncate the float
205 integerPart=decimalPart;
206 fpBuffer[fpBD++]='0' + integerPart;
207 decimalPart-=integerPart;
211 minWidth=fpBI; // we need at least these
212 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
213 if (negative || sign || space)
214 minWidth++; // and maybe even this :)
216 if (!left && reqWidth>i) {
218 if (negative) output_char('-');
219 else if (sign) output_char('+');
220 else if (space) output_char(' ');
221 while (reqWidth-->minWidth)
224 while (reqWidth-->minWidth)
226 if (negative) output_char('-');
227 else if (sign) output_char('+');
228 else if (space) output_char (' ');
231 if (negative) output_char('-');
232 else if (sign) output_char('+');
233 else if (space) output_char(' ');
236 // output the integer part
239 output_char (fpBuffer[i]);
242 // ouput the decimal part
246 while (reqDecimals--)
247 output_char (fpBuffer[i++]);
250 if (left && reqWidth>minWidth) {
251 while (reqWidth-->minWidth)
257 /*--------------------------------------------------------------------------*/
259 int vsprintf (const char *buf, const char *format, va_list ap)
261 static bit left_justify;
262 static bit zero_padding;
263 static bit prefix_sign;
264 static bit prefix_space;
265 static bit signed_argument;
266 static bit char_argument;
267 static bit long_argument;
268 static bit float_argument;
271 signed char decimals;
272 unsigned char length;
275 // reset output chars
281 output_to_string = 0;
285 output_to_string = 1;
321 width = 10*width + (c - '0');
323 /* first character of width is a zero */
327 decimals = 10*decimals + (c-'0');
329 goto get_conversion_spec;
333 if (decimals=-1) decimals=0;
335 ; // duplicate, ignore
336 goto get_conversion_spec;
339 lower_case = islower(c);
349 goto get_conversion_spec;
352 goto get_conversion_spec;
355 goto get_conversion_spec;
358 goto get_conversion_spec;
361 goto get_conversion_spec;
364 output_char( va_arg(ap,int) );
368 PTR = va_arg(ap,ptr_t);
373 length=NULL_STRING_LENGTH;
375 length = strlen(PTR);
378 length = strlen(PTR);
380 if ( ( !left_justify ) && (length < width) )
383 while( width-- != 0 )
390 output_char( *PTR++ );
392 if ( left_justify && (length < width))
395 while( width-- != 0 )
403 PTR = va_arg(ap,ptr_t);
406 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
410 output_2digits(value.byte[2]);
411 output_2digits(value.byte[1]);
412 output_2digits(value.byte[0]);
414 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
418 if ((value.byte[2] != 0x00 /* DSEG */) &&
419 (value.byte[2] != 0x03 /* SSEG */))
420 output_2digits( value.byte[1] );
421 output_2digits( value.byte[0] );
448 // nothing special, just output the character
453 if (float_argument) {
454 value.f=va_arg(ap,float);
465 // ignore b and l conversion spec for now
466 output_float(value.f, width, decimals, left_justify, zero_padding,
467 prefix_sign, prefix_space);
469 } else if (radix != 0)
471 // Apperently we have to output an integral type
472 // with radix "radix"
474 // store value in byte[0] (LSB) ... byte[3] (MSB)
477 value.l = va_arg(ap,char);
478 if (!signed_argument)
480 value.byte[1] = 0x00;
481 value.byte[2] = 0x00;
482 value.byte[3] = 0x00;
485 else if (long_argument)
487 value.l = va_arg(ap,long);
491 value.l = va_arg(ap,int);
492 if (!signed_argument)
494 value.byte[2] = 0x00;
495 value.byte[3] = 0x00;
499 if ( signed_argument )
510 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
518 mov a,_value+4 ; a = <msd>
520 orl b,a ; b = <msd><lsd>
524 mov a,_value+4 ; a = <lsd>
531 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
532 (value.byte[2] != 0) || (value.byte[3] != 0) );
536 // default width. We set it to 1 to output
537 // at least one character is case the value itself
538 // is zero (i.e. length==0)
542 /* prepend spaces if needed */
545 while ( width > length+1 )
552 if (signed_argument) // this now means the original value was negative
555 // adjust width to compensate for this character
558 else if (length != 0)
564 // adjust width to compensate for this character
567 else if (prefix_space)
570 // adjust width to compensate for this character
575 /* prepend zeroes/spaces if needed */
576 while ( width-- > length )
578 output_char( zero_padding ? '0' : ' ' );
581 /* output the digits */
588 pop acc ; a = <msd><lsd>
589 nop ; to disable the "optimizer"
592 anl a,#0x0F ; a = <msd>
596 anl a,#0x0F ; a = <lsd>
601 output_digit( value.byte[4] );
607 // nothing special, just output the character
612 // Copy \0 to the end of buf
613 // Modified by JB 17/12/99
614 if (output_to_string) {
616 return charsOutputted-1;
618 return charsOutputted;
622 /*--------------------------------------------------------------------------*/
624 int vprintf (const char *format, va_list ap)
626 return vsprintf( 0, format, ap );