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 -------------------------------------------------------------------------*/
35 #define NULL_STRING "<NULL>"
36 #define NULL_STRING_LENGTH 6
39 /* XSPEC is defined in stdio.h and used here to place
40 auto variables in XSEG */
42 /****************************************************************************/
44 typedef char _generic *ptr_t;
50 //#define toupper(c) ((c)&=~0x20)
51 #define toupper(c) ((c)&=0xDF)
55 unsigned char byte[5];
63 static code char memory_id[] = "IXCP-";
65 static ptr_t output_ptr;
66 static bit output_to_string;
67 static bit lower_case;
70 /* this one NEEDS to be in data */
71 static data value_t value;
73 static unsigned short radix;
75 /****************************************************************************/
77 static void output_char( char c ) reentrant
89 /*--------------------------------------------------------------------------*/
91 static void output_digit( unsigned char n ) reentrant
93 output_char( n <= 9 ? '0'+n :
94 (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) );
97 /*--------------------------------------------------------------------------*/
99 static void output_2digits( unsigned char b ) reentrant
101 output_digit( b>>4 );
102 output_digit( b&0x0F );
105 /*--------------------------------------------------------------------------*/
107 static void calculate_digit( void )
111 for( i = 32; i != 0; i-- )
132 if (radix <= value.byte[4] )
134 value.byte[4] -= radix;
142 /* This is a very inefficient but direct approach, since we have no math
143 library yet (e.g. log()).
144 It does most of the modifiers, but has some restrictions. E.g. the
145 abs(float) shouldn't be bigger than an unsigned long (that's
146 about 4294967295), but still makes it usefull for most real-life
150 #define DEFAULT_FLOAT_PRECISION 6
152 static void output_float (float f, unsigned char reqWidth,
153 signed char reqDecimals,
154 bit left, bit zero, bit sign, bit space)
156 XSPEC char negative=0;
157 XSPEC long integerPart;
158 XSPEC float decimalPart;
159 XSPEC char fpBuffer[128];
160 XSPEC char fpBI=0, fpBD;
161 XSPEC unsigned char minWidth, i;
171 decimalPart=f-integerPart;
173 // fill the buffer with the integerPart (in reversed order!)
174 while (integerPart) {
175 fpBuffer[fpBI++]='0' + integerPart%10;
179 // we need at least a 0
180 fpBuffer[fpBI++]='0';
183 // display some decimals as default
185 reqDecimals=DEFAULT_FLOAT_PRECISION;
187 // fill buffer with the decimalPart (in normal order)
189 if (i=reqDecimals /* that's an assignment */) {
192 // truncate the float
193 integerPart=decimalPart;
194 fpBuffer[fpBD++]='0' + integerPart;
195 decimalPart-=integerPart;
199 minWidth=fpBI; // we need at least these
200 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
201 if (negative || sign || space)
202 minWidth++; // and maybe even this :)
204 if (!left && reqWidth>i) {
206 if (negative) output_char('-');
207 else if (sign) output_char('+');
208 else if (space) output_char(' ');
209 while (reqWidth-->minWidth)
212 while (reqWidth-->minWidth)
214 if (negative) output_char('-');
215 else if (sign) output_char('+');
216 else if (space) output_char (' ');
219 if (negative) output_char('-');
220 else if (sign) output_char('+');
221 else if (space) output_char(' ');
224 // output the integer part
227 output_char (fpBuffer[i]);
230 // ouput the decimal part
234 while (reqDecimals--)
235 output_char (fpBuffer[i++]);
238 if (left && reqWidth>minWidth) {
239 while (reqWidth-->minWidth)
245 /*--------------------------------------------------------------------------*/
247 int vsprintf (const char *buf, const char *format, va_list ap)
258 XSPEC unsigned char width;
259 XSPEC signed char decimals;
260 XSPEC unsigned char length;
266 output_to_string = 0;
270 output_to_string = 1;
306 width = 10*width + (c - '0');
308 /* first character of width is a zero */
312 decimals = 10*decimals + (c-'0');
314 goto get_conversion_spec;
318 if (decimals=-1) decimals=0;
320 ; // duplicate, ignore
321 goto get_conversion_spec;
324 lower_case = islower(c);
334 goto get_conversion_spec;
337 goto get_conversion_spec;
340 goto get_conversion_spec;
343 goto get_conversion_spec;
346 goto get_conversion_spec;
349 output_char( va_arg(ap,unsigned char) );
353 PTR = va_arg(ap,ptr_t);
358 length=NULL_STRING_LENGTH;
360 length = strlen(PTR);
363 length = strlen(PTR);
365 if ( ( !left_justify ) && (length < width) )
368 while( width-- != 0 )
375 output_char( *PTR++ );
377 if ( left_justify && (length < width))
380 while( width-- != 0 )
388 PTR = va_arg(ap,ptr_t);
391 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
395 output_2digits(value.byte[2]);
396 output_2digits(value.byte[1]);
397 output_2digits(value.byte[0]);
399 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
403 if ((value.byte[2] != 0x00 /* DSEG */) &&
404 (value.byte[2] != 0x03 /* SSEG */))
405 output_2digits( value.byte[1] );
406 output_2digits( value.byte[0] );
433 // nothing special, just output the character
438 if (float_argument) {
439 value.f=va_arg(ap,float);
450 // ignore b and l conversion spec for now
451 output_float(value.f, width, decimals, left_justify, zero_padding,
452 prefix_sign, prefix_space);
454 } else if (radix != 0)
456 // Apperently we have to output an integral type
457 // with radix "radix"
459 // store value in byte[0] (LSB) ... byte[3] (MSB)
462 value.l = va_arg(ap,char);
463 if (!signed_argument)
465 value.byte[1] = 0x00;
466 value.byte[2] = 0x00;
467 value.byte[3] = 0x00;
470 else if (long_argument)
472 value.l = va_arg(ap,long);
476 value.l = va_arg(ap,int);
477 if (!signed_argument)
479 value.byte[2] = 0x00;
480 value.byte[3] = 0x00;
484 if ( signed_argument )
495 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
503 mov a,_value+4 ; a = <msd>
505 orl b,a ; b = <msd><lsd>
509 mov a,_value+4 ; a = <lsd>
516 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
517 (value.byte[2] != 0) || (value.byte[3] != 0) );
521 // default width. We set it to 1 to output
522 // at least one character is case the value itself
523 // is zero (i.e. length==0)
527 /* prepend spaces if needed */
530 while ( width > length+1 )
537 if (signed_argument) // this now means the original value was negative
540 // adjust width to compensate for this character
543 else if (length != 0)
549 // adjust width to compensate for this character
552 else if (prefix_space)
555 // adjust width to compensate for this character
560 /* prepend zeroes/spaces if needed */
561 while ( width-- > length )
563 output_char( zero_padding ? '0' : ' ' );
566 /* output the digits */
573 pop acc ; a = <msd><lsd>
574 nop ; to disable the "optimizer"
577 anl a,#0x0F ; a = <msd>
581 anl a,#0x0F ; a = <lsd>
586 output_digit( value.byte[4] );
592 // nothing special, just output the character
597 // Copy \0 to the end of buf
598 // Modified by JB 17/12/99
599 if (output_to_string) output_char(0);
602 /*--------------------------------------------------------------------------*/
604 int vprintf (const char *format, va_list ap)
606 return vsprintf( 0, format, ap );