1 /*-------------------------------------------------------------------------
2 printf_large.c - formatted output conversion
4 Written By - Martijn van Balen aed@iae.nl (1999)
5 Added %f By - johan.knol@iduna.nl (2000)
6 Refactored by - Maarten Brock (2004)
8 This library is free software; you can redistribute it and/or
9 modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 In other words, you are welcome to use, share and improve this program.
23 You are forbidden to forbid anyone else to use, share and improve
24 what you give them. Help stamp out software-hoarding!
25 -------------------------------------------------------------------------*/
41 #define NULL_STRING "<NULL>"
42 #define NULL_STRING_LENGTH 6
45 /****************************************************************************/
47 //typedef char * ptr_t;
54 //#define toupper(c) ((c)&=~0x20)
55 #define toupper(c) ((c)&=0xDF)
59 unsigned char byte[5];
66 static const char memory_id[] = "IXCP-";
68 #ifndef SDCC_STACK_AUTO
69 static BOOL lower_case;
70 static pfn_outputchar output_char;
75 /****************************************************************************/
77 #ifdef SDCC_STACK_AUTO
78 static void output_digit( unsigned char n, BOOL lower_case, pfn_outputchar output_char, void* p )
80 static void output_digit( unsigned char n )
83 output_char( n <= 9 ? '0'+n :
84 (lower_case ? n+(char)('a'-10) : n+(char)('A'-10)), p );
87 /*--------------------------------------------------------------------------*/
89 #ifdef SDCC_STACK_AUTO
90 #define OUTPUT_2DIGITS( B ) output_2digits( B, lower_case, output_char, p )
91 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
93 output_digit( b>>4, lower_case, output_char, p );
94 output_digit( b&0x0F, lower_case, output_char, p );
97 #define OUTPUT_2DIGITS( B ) output_2digits( B )
98 static void output_2digits( unsigned char b )
100 output_digit( b>>4 );
101 output_digit( b&0x0F );
105 /*--------------------------------------------------------------------------*/
107 #if defined SDCC_STACK_AUTO
108 static void calculate_digit( value_t* value, unsigned char radix )
112 for( i = 32; i != 0; i-- )
114 value->byte[4] = (value->byte[4] << 1) | ((value->ul >> 31) & 0x01);
117 if (radix <= value->byte[4] )
119 value->byte[4] -= radix;
125 static void calculate_digit( unsigned char radix )
129 for( i = 32; i != 0; i-- )
131 value.byte[4] = (value.byte[4] << 1) | ((value.ul >> 31) & 0x01);
134 if (radix <= value.byte[4] )
136 value.byte[4] -= radix;
145 /* This is a very inefficient but direct approach, since we have no math
146 library yet (e.g. log()).
147 It does most of the modifiers, but has some restrictions. E.g. the
148 abs(float) shouldn't be bigger than an unsigned long (that's
149 about 4294967295), but still makes it usefull for most real-life
153 #define DEFAULT_FLOAT_PRECISION 6
155 #ifdef SDCC_STACK_AUTO
156 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
157 static int output_float (float f, unsigned char reqWidth,
158 signed char reqDecimals,
159 BOOL left, BOOL zero, BOOL sign, BOOL space,
160 pfn_outputchar output_char, void* p)
162 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
163 static int output_float (float f, unsigned char reqWidth,
164 signed char reqDecimals,
165 BOOL left, BOOL zero, BOOL sign, BOOL space)
169 unsigned long integerPart;
173 unsigned char minWidth, i;
174 int charsOutputted=0;
183 // this part is from Frank van der Hulst
186 for (exp = 0; f >= 10.0; exp++) f /=10.0;
187 for ( ; f < 1.0; exp--) f *=10.0;
190 output_char ('-', p);
194 output_char ('+', p);
198 charsOutputted += OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
199 output_char ('e', p);
202 output_char ('-', p);
206 output_char ('0'+exp/10, p);
207 output_char ('0'+exp%10, p);
209 return charsOutputted;
214 decimalPart=f-integerPart;
216 // fill the buffer with the integerPart (in reversed order!)
217 while (integerPart) {
218 fpBuffer[fpBI++]='0' + integerPart%10;
222 // we need at least a 0
223 fpBuffer[fpBI++]='0';
226 // display some decimals as default
228 reqDecimals=DEFAULT_FLOAT_PRECISION;
230 // fill buffer with the decimalPart (in normal order)
232 if (i=reqDecimals /* that's an assignment */) {
235 // truncate the float
236 integerPart=decimalPart;
237 fpBuffer[fpBD++]='0' + integerPart;
238 decimalPart-=integerPart;
242 minWidth=fpBI; // we need at least these
243 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
244 if (negative || sign || space)
245 minWidth++; // and maybe even this :)
247 if (!left && reqWidth>i) {
264 while (reqWidth-->minWidth)
270 while (reqWidth-->minWidth)
309 // output the integer part
312 output_char (fpBuffer[i], p);
316 // ouput the decimal part
318 output_char ('.', p);
321 while (reqDecimals--)
323 output_char (fpBuffer[i++], p);
328 if (left && reqWidth>minWidth) {
329 while (reqWidth-->minWidth)
335 return charsOutputted;
339 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
345 BOOL signed_argument;
349 #ifdef SDCC_STACK_AUTO
358 signed char decimals;
359 unsigned char length;
362 #ifdef SDCC_STACK_AUTO
363 #define output_char pfn
370 // reset output chars
407 width = 10*width + (c - '0');
409 /* first character of width is a zero */
413 decimals = 10*decimals + (c-'0');
415 goto get_conversion_spec;
419 if (decimals=-1) decimals=0;
421 ; // duplicate, ignore
422 goto get_conversion_spec;
425 lower_case = islower(c);
435 goto get_conversion_spec;
438 goto get_conversion_spec;
441 goto get_conversion_spec;
444 goto get_conversion_spec;
447 goto get_conversion_spec;
450 output_char( va_arg(ap,int), p );
455 PTR = va_arg(ap,ptr_t);
460 length=NULL_STRING_LENGTH;
462 length = strlen(PTR);
465 length = strlen(PTR);
467 if ( decimals == -1 )
471 if ( ( !left_justify ) && (length < width) )
474 while( width-- != 0 )
476 output_char( ' ', p );
481 while ( *PTR && (decimals-- > 0))
483 output_char( *PTR++, p );
487 if ( left_justify && (length < width))
490 while( width-- != 0 )
492 output_char( ' ', p );
499 PTR = va_arg(ap,ptr_t);
502 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]], p );
506 OUTPUT_2DIGITS( value.byte[2] );
507 OUTPUT_2DIGITS( value.byte[1] );
508 OUTPUT_2DIGITS( value.byte[0] );
509 charsOutputted += 10;
511 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]], p );
515 if ((value.byte[2] != 0x00 /* DSEG */) &&
516 (value.byte[2] != 0x03 /* SSEG */))
518 OUTPUT_2DIGITS( value.byte[1] );
521 OUTPUT_2DIGITS( value.byte[0] );
549 // nothing special, just output the character
555 if (float_argument) {
556 value.f=va_arg(ap,float);
570 // ignore b and l conversion spec for now
571 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
572 zero_padding, prefix_sign, prefix_space);
574 } else if (radix != 0)
576 // Apperently we have to output an integral type
577 // with radix "radix"
578 unsigned char store[6];
579 unsigned char _AUTOMEM *pstore = &store[5];
581 // store value in byte[0] (LSB) ... byte[3] (MSB)
584 value.l = va_arg(ap,char);
585 if (!signed_argument)
590 else if (long_argument)
592 value.l = va_arg(ap,long);
596 value.l = va_arg(ap,int);
597 if (!signed_argument)
603 if ( signed_argument )
616 #if defined SDCC_STACK_AUTO
617 calculate_digit(&value, radix);
619 calculate_digit(radix);
623 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
628 *pstore = value.byte[4];
636 // default width. We set it to 1 to output
637 // at least one character in case the value itself
638 // is zero (i.e. length==0)
642 /* prepend spaces if needed */
643 if (!zero_padding && !left_justify)
645 while ( width > (unsigned char) (length+1) )
647 output_char( ' ', p );
653 if (signed_argument) // this now means the original value was negative
655 output_char( '-', p );
657 // adjust width to compensate for this character
660 else if (length != 0)
665 output_char( '+', p );
667 // adjust width to compensate for this character
670 else if (prefix_space)
672 output_char( ' ', p );
674 // adjust width to compensate for this character
679 /* prepend zeroes/spaces if needed */
681 while ( width-- > length )
683 output_char( zero_padding ? '0' : ' ', p );
688 /* spaces are appended after the digits */
695 /* output the digits */
702 value.byte[4] = *pstore >> 4;
706 value.byte[4] = *pstore & 0x0F;
708 #ifdef SDCC_STACK_AUTO
709 output_digit( value.byte[4], lower_case, output_char, p );
711 output_digit( value.byte[4] );
725 // nothing special, just output the character
731 return charsOutputted;
734 /****************************************************************************/