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 -------------------------------------------------------------------------*/
37 #define NULL_STRING "<NULL>"
38 #define NULL_STRING_LENGTH 6
41 /* XSPEC is defined in stdio.h and used here to place
42 auto variables in XSEG */
44 /****************************************************************************/
46 typedef char _generic *ptr_t;
52 //#define toupper(c) ((c)&=~0x20)
53 #define toupper(c) ((c)&=0xDF)
57 unsigned char byte[5];
65 static code char memory_id[] = "IXCP-";
67 static ptr_t output_ptr;
68 static bit output_to_string;
69 static bit lower_case;
72 /* this one NEEDS to be in data */
73 static data value_t value;
75 static unsigned char radix;
77 // jwk: TODO: this makes the whole dammed thing nonreentrent
78 static int charsOutputted;
80 /****************************************************************************/
82 static void output_char( char c ) reentrant
95 /*--------------------------------------------------------------------------*/
97 static void output_digit( unsigned char n ) reentrant
99 output_char( n <= 9 ? '0'+n :
100 (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)) );
103 /*--------------------------------------------------------------------------*/
105 static void output_2digits( unsigned char b ) reentrant
107 output_digit( b>>4 );
108 output_digit( b&0x0F );
111 /*--------------------------------------------------------------------------*/
113 static void calculate_digit( void )
117 for( i = 32; i != 0; i-- )
138 if (radix <= value.byte[4] )
140 value.byte[4] -= radix;
148 /* This is a very inefficient but direct approach, since we have no math
149 library yet (e.g. log()).
150 It does most of the modifiers, but has some restrictions. E.g. the
151 abs(float) shouldn't be bigger than an unsigned long (that's
152 about 4294967295), but still makes it usefull for most real-life
156 #define DEFAULT_FLOAT_PRECISION 6
158 static void output_float (float f, unsigned char reqWidth,
159 signed char reqDecimals,
160 bit left, bit zero, bit sign, bit space)
167 unsigned char minWidth, i;
177 decimalPart=f-integerPart;
179 // fill the buffer with the integerPart (in reversed order!)
180 while (integerPart) {
181 fpBuffer[fpBI++]='0' + integerPart%10;
185 // we need at least a 0
186 fpBuffer[fpBI++]='0';
189 // display some decimals as default
191 reqDecimals=DEFAULT_FLOAT_PRECISION;
193 // fill buffer with the decimalPart (in normal order)
195 if (i=reqDecimals /* that's an assignment */) {
198 // truncate the float
199 integerPart=decimalPart;
200 fpBuffer[fpBD++]='0' + integerPart;
201 decimalPart-=integerPart;
205 minWidth=fpBI; // we need at least these
206 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
207 if (negative || sign || space)
208 minWidth++; // and maybe even this :)
210 if (!left && reqWidth>i) {
212 if (negative) output_char('-');
213 else if (sign) output_char('+');
214 else if (space) output_char(' ');
215 while (reqWidth-->minWidth)
218 while (reqWidth-->minWidth)
220 if (negative) output_char('-');
221 else if (sign) output_char('+');
222 else if (space) output_char (' ');
225 if (negative) output_char('-');
226 else if (sign) output_char('+');
227 else if (space) output_char(' ');
230 // output the integer part
233 output_char (fpBuffer[i]);
236 // ouput the decimal part
240 while (reqDecimals--)
241 output_char (fpBuffer[i++]);
244 if (left && reqWidth>minWidth) {
245 while (reqWidth-->minWidth)
251 /*--------------------------------------------------------------------------*/
253 int vsprintf (const char *buf, const char *format, va_list ap)
265 signed char decimals;
266 unsigned char length;
269 // reset output chars
275 output_to_string = 0;
279 output_to_string = 1;
315 width = 10*width + (c - '0');
317 /* first character of width is a zero */
321 decimals = 10*decimals + (c-'0');
323 goto get_conversion_spec;
327 if (decimals=-1) decimals=0;
329 ; // duplicate, ignore
330 goto get_conversion_spec;
333 lower_case = islower(c);
343 goto get_conversion_spec;
346 goto get_conversion_spec;
349 goto get_conversion_spec;
352 goto get_conversion_spec;
355 goto get_conversion_spec;
358 output_char( va_arg(ap,int) );
362 PTR = va_arg(ap,ptr_t);
367 length=NULL_STRING_LENGTH;
369 length = strlen(PTR);
372 length = strlen(PTR);
374 if ( ( !left_justify ) && (length < width) )
377 while( width-- != 0 )
384 output_char( *PTR++ );
386 if ( left_justify && (length < width))
389 while( width-- != 0 )
397 PTR = va_arg(ap,ptr_t);
400 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]] );
404 output_2digits(value.byte[2]);
405 output_2digits(value.byte[1]);
406 output_2digits(value.byte[0]);
408 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]] );
412 if ((value.byte[2] != 0x00 /* DSEG */) &&
413 (value.byte[2] != 0x03 /* SSEG */))
414 output_2digits( value.byte[1] );
415 output_2digits( value.byte[0] );
442 // nothing special, just output the character
447 if (float_argument) {
448 value.f=va_arg(ap,float);
459 // ignore b and l conversion spec for now
460 output_float(value.f, width, decimals, left_justify, zero_padding,
461 prefix_sign, prefix_space);
463 } else if (radix != 0)
465 // Apperently we have to output an integral type
466 // with radix "radix"
468 // store value in byte[0] (LSB) ... byte[3] (MSB)
471 value.l = va_arg(ap,char);
472 if (!signed_argument)
474 value.byte[1] = 0x00;
475 value.byte[2] = 0x00;
476 value.byte[3] = 0x00;
479 else if (long_argument)
481 value.l = va_arg(ap,long);
485 value.l = va_arg(ap,int);
486 if (!signed_argument)
488 value.byte[2] = 0x00;
489 value.byte[3] = 0x00;
493 if ( signed_argument )
504 //jwk20000814: do this at least once, e.g.: printf ("%d", (int)0);
512 mov a,_value+4 ; a = <msd>
514 orl b,a ; b = <msd><lsd>
518 mov a,_value+4 ; a = <lsd>
525 } while( (value.byte[0] != 0) || (value.byte[1] != 0) ||
526 (value.byte[2] != 0) || (value.byte[3] != 0) );
530 // default width. We set it to 1 to output
531 // at least one character is case the value itself
532 // is zero (i.e. length==0)
536 /* prepend spaces if needed */
539 while ( width > length+1 )
546 if (signed_argument) // this now means the original value was negative
549 // adjust width to compensate for this character
552 else if (length != 0)
558 // adjust width to compensate for this character
561 else if (prefix_space)
564 // adjust width to compensate for this character
569 /* prepend zeroes/spaces if needed */
570 while ( width-- > length )
572 output_char( zero_padding ? '0' : ' ' );
575 /* output the digits */
582 pop acc ; a = <msd><lsd>
583 nop ; to disable the "optimizer"
586 anl a,#0x0F ; a = <msd>
590 anl a,#0x0F ; a = <lsd>
595 output_digit( value.byte[4] );
601 // nothing special, just output the character
606 // Copy \0 to the end of buf
607 // Modified by JB 17/12/99
608 if (output_to_string) {
610 return charsOutputted-1;
612 return charsOutputted;
616 /*--------------------------------------------------------------------------*/
618 int vprintf (const char *format, va_list ap)
620 return vsprintf( 0, format, ap );