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 -------------------------------------------------------------------------*/
34 /****************************************************************************/
36 typedef char _generic *ptr_t;
42 //#define toupper(c) ((c)&=~0x20)
43 #define toupper(c) ((c)&=0xDF)
47 unsigned char byte[5];
55 static code char memory_id[] = "IXCP-";
57 static ptr_t output_ptr;
58 static bit output_to_string;
59 static bit lower_case;
62 /* this one NEEDS to be in data */
63 static data value_t value;
65 static xdata unsigned short radix;
67 /****************************************************************************/
69 static void output_char( char c ) reentrant
81 /*--------------------------------------------------------------------------*/
83 static void output_digit( unsigned char n ) reentrant
85 output_char( n <= 9 ? '0'+n : (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) );
88 /*--------------------------------------------------------------------------*/
90 static void output_2digits( unsigned char b ) reentrant
93 output_digit( b&0x0F );
96 /*--------------------------------------------------------------------------*/
98 static void calculate_digit( void )
102 for( i = 32; i != 0; i-- )
123 if (radix <= value.byte[4] )
125 value.byte[4] -= radix;
133 /* This is a very inefficient but direct approach, since we have no math
134 library yet (e.g. log()).
135 It does most of the modifiers, but has some restrictions. E.g. the
136 abs(float) shouldn't be bigger than an unsigned long (that's
137 about 4294967295), but still makes it usefull for most real-life
141 #define DEFAULT_FLOAT_PRECISION 6
143 static void output_float (float f, unsigned char reqWidth,
144 signed char reqDecimals,
145 bit left, bit zero, bit sign, bit space)
152 unsigned char minWidth, i;
162 decimalPart=f-integerPart;
164 // fill the buffer with the integerPart (in reversed order!)
165 while (integerPart) {
166 fpBuffer[fpBI++]='0' + integerPart%10;
170 // we need at least a 0
171 fpBuffer[fpBI++]='0';
174 // display some decimals as default
176 reqDecimals=DEFAULT_FLOAT_PRECISION;
178 // fill buffer with the decimalPart (in normal order)
180 if (i=reqDecimals /* that's an assignment */) {
183 // truncate the float
184 integerPart=decimalPart;
185 fpBuffer[fpBD++]='0' + integerPart;
186 decimalPart-=integerPart;
190 minWidth=fpBI; // we need at least these
191 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
192 if (negative || sign || space)
193 minWidth++; // and maybe even this :)
195 if (!left && reqWidth>i) {
197 if (negative) output_char('-');
198 else if (sign) output_char('+');
199 else if (space) output_char(' ');
200 while (reqWidth-->minWidth)
203 while (reqWidth-->minWidth)
205 if (negative) output_char('-');
206 else if (sign) output_char('+');
207 else if (space) output_char (' ');
210 if (negative) output_char('-');
211 else if (sign) output_char('+');
212 else if (space) output_char(' ');
215 // output the integer part
218 output_char (fpBuffer[i]);
221 // ouput the decimal part
225 while (reqDecimals--)
226 output_char (fpBuffer[i++]);
229 if (left && reqWidth>minWidth) {
230 while (reqWidth-->minWidth)
236 /*--------------------------------------------------------------------------*/
238 int vsprintf (const char *buf, const char *format, va_list ap)
250 signed char decimals;
251 unsigned char length;
257 output_to_string = 0;
261 output_to_string = 1;
291 width = 10*width + (c - '0');
293 /* first character of width is a zero */
297 decimals = 10*decimals + (c-'0');
299 goto get_conversion_spec;
303 if (decimals=-1) decimals=0;
305 ; // duplicate, ignore
306 goto get_conversion_spec;
309 lower_case = islower(c);
319 goto get_conversion_spec;
322 goto get_conversion_spec;
325 goto get_conversion_spec;
328 goto get_conversion_spec;
331 goto get_conversion_spec;
334 output_char( va_arg(ap,unsigned char) );
338 PTR = va_arg(ap,ptr_t);
340 length = strlen(PTR);
341 if ( ( !left_justify ) && (length < width) )
344 while( width-- != 0 )
351 output_char( *PTR++ );
353 if ( left_justify && (length < width))
356 while( width-- != 0 )
364 PTR = va_arg(ap,ptr_t);
366 #ifdef SDCC_MODEL_FLAT24
367 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
371 output_2digits(value.byte[2]);
372 output_2digits(value.byte[1]);
373 output_2digits(value.byte[0]);
375 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
379 if ((value.byte[2] != 0x00 /* DSEG */) && (value.byte[2] != 0x03 /* SSEG */))
380 output_2digits( value.byte[1] );
381 output_2digits( value.byte[0] );
408 // nothing special, just output the character
413 if (float_argument) {
414 value.f=va_arg(ap,float);
422 // ignore b and l conversion spec for now
423 output_float(value.f, width, decimals, left_justify, zero_padding,
424 prefix_sign, prefix_space);
426 } else if (radix != 0)
428 // Apperently we have to output an integral type
429 // with radix "radix"
431 // store value in byte[0] (LSB) ... byte[3] (MSB)
434 value.l = va_arg(ap,char);
435 if (!signed_argument)
437 value.byte[1] = 0x00;
438 value.byte[2] = 0x00;
439 value.byte[3] = 0x00;
442 else if (long_argument)
444 value.l = va_arg(ap,long);
448 value.l = va_arg(ap,int);
449 if (!signed_argument)
451 value.byte[2] = 0x00;
452 value.byte[3] = 0x00;
456 if ( signed_argument )
467 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
475 mov a,_value+4 ; a = <msd>
477 orl b,a ; b = <msd><lsd>
481 mov a,_value+4 ; a = <lsd>
488 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
489 (value.byte[2] != 0) || (value.byte[3] != 0) );
493 // default width. We set it to 1 to output
494 // at least one character is case the value itself
495 // is zero (i.e. length==0)
499 /* prepend spaces if needed */
502 while ( width > length+1 )
509 if (signed_argument) // this now means the original value was negative
512 // adjust width to compensate for this character
515 else if (length != 0)
521 // adjust width to compensate for this character
524 else if (prefix_space)
527 // adjust width to compensate for this character
532 /* prepend zeroes/spaces if needed */
533 while ( width-- > length )
535 output_char( zero_padding ? '0' : ' ' );
538 /* output the digits */
545 pop acc ; a = <msd><lsd>
546 nop ; to disable the "optimizer"
549 anl a,#0x0F ; a = <msd>
553 anl a,#0x0F ; a = <lsd>
558 output_digit( value.byte[4] );
564 // nothing special, just output the character
569 // Copy \0 to the end of buf
570 // Modified by JB 17/12/99
571 if (output_to_string) output_char(0);
574 /*--------------------------------------------------------------------------*/
576 int vprintf (const char *format, va_list ap)
578 return vsprintf( 0, format, ap );