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-";
66 /****************************************************************************/
68 static void output_char( char c ) reentrant
80 /*--------------------------------------------------------------------------*/
82 static void output_digit( unsigned char n ) reentrant
84 output_char( n <= 9 ? '0'+n : (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) );
87 /*--------------------------------------------------------------------------*/
89 static void output_2digits( unsigned char b ) reentrant
92 output_digit( b&0x0F );
95 /*--------------------------------------------------------------------------*/
97 static void calculate_digit( void )
101 for( i = 32; i != 0; i-- )
122 if (radix <= value.byte[4] )
124 value.byte[4] -= radix;
132 /* This is a very inefficient but direct approach, since we have no math
133 library yet (e.g. log()).
134 It does most of the modifiers, but has some restrictions. E.g. the
135 abs(float) shouldn't be bigger than an unsigned long (that's
136 about 4294967295), but still makes it usefull for most real-life
140 #define DEFAULT_FLOAT_PRECISION 6
142 static void output_float (float f, unsigned char reqWidth,
143 signed char reqDecimals,
144 bit left, bit zero, bit sign, bit space)
151 unsigned char minWidth, i;
161 decimalPart=f-integerPart;
163 // fill the buffer with the integerPart (in reversed order!)
164 while (integerPart) {
165 fpBuffer[fpBI++]='0' + integerPart%10;
169 // we need at least a 0
170 fpBuffer[fpBI++]='0';
173 // display some decimals as default
175 reqDecimals=DEFAULT_FLOAT_PRECISION;
177 // fill buffer with the decimalPart (in normal order)
179 if (i=reqDecimals /* that's an assignment */) {
182 // truncate the float
183 integerPart=decimalPart;
184 fpBuffer[fpBD++]='0' + integerPart;
185 decimalPart-=integerPart;
189 minWidth=fpBI; // we need at least these
190 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
191 if (negative || sign || space)
192 minWidth++; // and maybe even this :)
194 if (!left && reqWidth>i) {
196 if (negative) output_char('-');
197 else if (sign) output_char('+');
198 else if (space) output_char(' ');
199 while (reqWidth-->minWidth)
202 while (reqWidth-->minWidth)
204 if (negative) output_char('-');
205 else if (sign) output_char('+');
206 else if (space) output_char (' ');
209 if (negative) output_char('-');
210 else if (sign) output_char('+');
211 else if (space) output_char(' ');
214 // output the integer part
217 output_char (fpBuffer[i]);
220 // ouput the decimal part
224 while (reqDecimals--)
225 output_char (fpBuffer[i++]);
228 if (left && reqWidth>minWidth) {
229 while (reqWidth-->minWidth)
235 /*--------------------------------------------------------------------------*/
237 int vsprintf (const char *buf, const char *format, va_list ap)
249 signed char decimals;
250 unsigned char length;
256 output_to_string = 0;
260 output_to_string = 1;
290 width = 10*width + (c - '0');
292 /* first character of width is a zero */
296 decimals = 10*decimals + (c-'0');
298 goto get_conversion_spec;
302 if (decimals=-1) decimals=0;
304 ; // duplicate, ignore
305 goto get_conversion_spec;
308 lower_case = islower(c);
318 goto get_conversion_spec;
321 goto get_conversion_spec;
324 goto get_conversion_spec;
327 goto get_conversion_spec;
330 goto get_conversion_spec;
333 output_char( va_arg(ap,unsigned char) );
337 PTR = va_arg(ap,ptr_t);
339 length = strlen(PTR);
340 if ( ( !left_justify ) && (length < width) )
343 while( width-- != 0 )
350 output_char( *PTR++ );
352 if ( left_justify && (length < width))
355 while( width-- != 0 )
363 PTR = va_arg(ap,ptr_t);
365 #ifdef SDCC_MODEL_FLAT24
366 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
370 output_2digits(value.byte[2]);
371 output_2digits(value.byte[1]);
372 output_2digits(value.byte[0]);
374 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
378 if ((value.byte[2] != 0x00 /* DSEG */) && (value.byte[2] != 0x03 /* SSEG */))
379 output_2digits( value.byte[1] );
380 output_2digits( value.byte[0] );
407 // nothing special, just output the character
412 if (float_argument) {
413 value.f=va_arg(ap,float);
421 // ignore b and l conversion spec for now
422 output_float(value.f, width, decimals, left_justify, zero_padding,
423 prefix_sign, prefix_space);
425 } else if (radix != 0)
427 // Apperently we have to output an integral type
428 // with radix "radix"
430 // store value in byte[0] (LSB) ... byte[3] (MSB)
433 value.l = va_arg(ap,char);
434 if (!signed_argument)
436 value.byte[1] = 0x00;
437 value.byte[2] = 0x00;
438 value.byte[3] = 0x00;
441 else if (long_argument)
443 value.l = va_arg(ap,long);
447 value.l = va_arg(ap,int);
448 if (!signed_argument)
450 value.byte[2] = 0x00;
451 value.byte[3] = 0x00;
455 if ( signed_argument )
466 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
474 mov a,_value+4 ; a = <msd>
476 orl b,a ; b = <msd><lsd>
480 mov a,_value+4 ; a = <lsd>
487 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
488 (value.byte[2] != 0) || (value.byte[3] != 0) );
492 // default width. We set it to 1 to output
493 // at least one character is case the value itself
494 // is zero (i.e. length==0)
498 /* prepend spaces if needed */
501 while ( width > length+1 )
508 if (signed_argument) // this now means the original value was negative
511 // adjust width to compensate for this character
514 else if (length != 0)
520 // adjust width to compensate for this character
523 else if (prefix_space)
526 // adjust width to compensate for this character
531 /* prepend zeroes/spaces if needed */
532 while ( width-- > length )
534 output_char( zero_padding ? '0' : ' ' );
537 /* output the digits */
544 pop acc ; a = <msd><lsd>
545 nop ; to disable the "optimizer"
548 anl a,#0x0F ; a = <msd>
552 anl a,#0x0F ; a = <lsd>
557 output_digit( value.byte[4] );
563 // nothing special, just output the character
568 // Copy \0 to the end of buf
569 // Modified by JB 17/12/99
570 if (output_to_string) output_char(0);
573 /*--------------------------------------------------------------------------*/
575 int vprintf (const char *format, va_list ap)
577 return vsprintf( 0, format, ap );