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 static void output_float (float f, unsigned char reqWidth,
163 signed char reqDecimals,
164 bit left, bit zero, bit sign, bit space)
171 unsigned char minWidth, i;
181 decimalPart=f-integerPart;
183 // fill the buffer with the integerPart (in reversed order!)
184 while (integerPart) {
185 fpBuffer[fpBI++]='0' + integerPart%10;
189 // we need at least a 0
190 fpBuffer[fpBI++]='0';
193 // display some decimals as default
195 reqDecimals=DEFAULT_FLOAT_PRECISION;
197 // fill buffer with the decimalPart (in normal order)
199 if (i=reqDecimals /* that's an assignment */) {
202 // truncate the float
203 integerPart=decimalPart;
204 fpBuffer[fpBD++]='0' + integerPart;
205 decimalPart-=integerPart;
209 minWidth=fpBI; // we need at least these
210 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
211 if (negative || sign || space)
212 minWidth++; // and maybe even this :)
214 if (!left && reqWidth>i) {
216 if (negative) output_char('-');
217 else if (sign) output_char('+');
218 else if (space) output_char(' ');
219 while (reqWidth-->minWidth)
222 while (reqWidth-->minWidth)
224 if (negative) output_char('-');
225 else if (sign) output_char('+');
226 else if (space) output_char (' ');
229 if (negative) output_char('-');
230 else if (sign) output_char('+');
231 else if (space) output_char(' ');
234 // output the integer part
237 output_char (fpBuffer[i]);
240 // ouput the decimal part
244 while (reqDecimals--)
245 output_char (fpBuffer[i++]);
248 if (left && reqWidth>minWidth) {
249 while (reqWidth-->minWidth)
255 /*--------------------------------------------------------------------------*/
257 int vsprintf (const char *buf, char *format, va_list ap)
259 static bit left_justify;
260 static bit zero_padding;
261 static bit prefix_sign;
262 static bit prefix_space;
263 static bit signed_argument;
264 static bit char_argument;
265 static bit long_argument;
266 static bit float_argument;
269 signed char decimals;
270 unsigned char length;
273 // reset output chars
279 output_to_string = 0;
283 output_to_string = 1;
319 width = 10*width + (c - '0');
321 /* first character of width is a zero */
325 decimals = 10*decimals + (c-'0');
327 goto get_conversion_spec;
331 if (decimals=-1) decimals=0;
333 ; // duplicate, ignore
334 goto get_conversion_spec;
337 lower_case = islower(c);
347 goto get_conversion_spec;
350 goto get_conversion_spec;
353 goto get_conversion_spec;
356 goto get_conversion_spec;
359 goto get_conversion_spec;
362 output_char( va_arg(ap,int) );
366 PTR = va_arg(ap,ptr_t);
371 length=NULL_STRING_LENGTH;
373 length = strlen(PTR);
376 length = strlen(PTR);
378 if ( ( !left_justify ) && (length < width) )
381 while( width-- != 0 )
388 output_char( *PTR++ );
390 if ( left_justify && (length < width))
393 while( width-- != 0 )
401 PTR = va_arg(ap,ptr_t);
404 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
408 output_2digits(value.byte[2]);
409 output_2digits(value.byte[1]);
410 output_2digits(value.byte[0]);
412 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
416 if ((value.byte[2] != 0x00 /* DSEG */) &&
417 (value.byte[2] != 0x03 /* SSEG */))
418 output_2digits( value.byte[1] );
419 output_2digits( value.byte[0] );
446 // nothing special, just output the character
451 if (float_argument) {
452 value.f=va_arg(ap,float);
463 // ignore b and l conversion spec for now
464 output_float(value.f, width, decimals, left_justify, zero_padding,
465 prefix_sign, prefix_space);
467 } else if (radix != 0)
469 // Apperently we have to output an integral type
470 // with radix "radix"
472 // store value in byte[0] (LSB) ... byte[3] (MSB)
475 value.l = va_arg(ap,char);
476 if (!signed_argument)
478 value.byte[1] = 0x00;
479 value.byte[2] = 0x00;
480 value.byte[3] = 0x00;
483 else if (long_argument)
485 value.l = va_arg(ap,long);
489 value.l = va_arg(ap,int);
490 if (!signed_argument)
492 value.byte[2] = 0x00;
493 value.byte[3] = 0x00;
497 if ( signed_argument )
508 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
516 mov a,_value+4 ; a = <msd>
518 orl b,a ; b = <msd><lsd>
522 mov a,_value+4 ; a = <lsd>
529 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
530 (value.byte[2] != 0) || (value.byte[3] != 0) );
534 // default width. We set it to 1 to output
535 // at least one character is case the value itself
536 // is zero (i.e. length==0)
540 /* prepend spaces if needed */
543 while ( width > length+1 )
550 if (signed_argument) // this now means the original value was negative
553 // adjust width to compensate for this character
556 else if (length != 0)
562 // adjust width to compensate for this character
565 else if (prefix_space)
568 // adjust width to compensate for this character
573 /* prepend zeroes/spaces if needed */
574 while ( width-- > length )
576 output_char( zero_padding ? '0' : ' ' );
579 /* output the digits */
586 pop acc ; a = <msd><lsd>
587 nop ; to disable the "optimizer"
590 anl a,#0x0F ; a = <msd>
594 anl a,#0x0F ; a = <lsd>
599 output_digit( value.byte[4] );
605 // nothing special, just output the character
610 // Copy \0 to the end of buf
611 // Modified by JB 17/12/99
612 if (output_to_string) {
614 return charsOutputted-1;
616 return charsOutputted;
620 /*--------------------------------------------------------------------------*/
622 int vprintf (const char *format, va_list ap)
624 return vsprintf( 0, format, ap );