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)
233 for (i=reqDecimals; i>1; i--) {
235 // truncate the float
236 integerPart=decimalPart;
237 fpBuffer[fpBD++]='0' + integerPart;
238 decimalPart-=integerPart;
242 // truncate the float
243 integerPart = decimalPart + 0.5;
244 fpBuffer[fpBD++] = '0' + integerPart;
247 minWidth=fpBI; // we need at least these
248 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
249 if (negative || sign || space)
250 minWidth++; // and maybe even this :)
252 if (!left && reqWidth>i) {
269 while (reqWidth-->minWidth)
275 while (reqWidth-->minWidth)
314 // output the integer part
317 output_char (fpBuffer[i], p);
321 // ouput the decimal part
323 output_char ('.', p);
326 while (reqDecimals--)
328 output_char (fpBuffer[i++], p);
333 if (left && reqWidth>minWidth) {
334 while (reqWidth-->minWidth)
340 return charsOutputted;
344 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
350 BOOL signed_argument;
354 #ifdef SDCC_STACK_AUTO
363 signed char decimals;
364 unsigned char length;
367 #ifdef SDCC_STACK_AUTO
368 #define output_char pfn
375 // reset output chars
412 width = 10*width + (c - '0');
414 /* first character of width is a zero */
418 decimals = 10*decimals + (c-'0');
420 goto get_conversion_spec;
424 if (decimals=-1) decimals=0;
426 ; // duplicate, ignore
427 goto get_conversion_spec;
430 lower_case = islower(c);
440 goto get_conversion_spec;
443 goto get_conversion_spec;
446 goto get_conversion_spec;
449 goto get_conversion_spec;
452 goto get_conversion_spec;
455 output_char( va_arg(ap,int), p );
460 PTR = va_arg(ap,ptr_t);
465 length=NULL_STRING_LENGTH;
467 length = strlen(PTR);
470 length = strlen(PTR);
472 if ( decimals == -1 )
476 if ( ( !left_justify ) && (length < width) )
479 while( width-- != 0 )
481 output_char( ' ', p );
486 while ( *PTR && (decimals-- > 0))
488 output_char( *PTR++, p );
492 if ( left_justify && (length < width))
495 while( width-- != 0 )
497 output_char( ' ', p );
504 PTR = va_arg(ap,ptr_t);
507 output_char(memory_id[(value.byte[3] > 3) ? 4 : value.byte[3]], p );
511 OUTPUT_2DIGITS( value.byte[2] );
512 OUTPUT_2DIGITS( value.byte[1] );
513 OUTPUT_2DIGITS( value.byte[0] );
514 charsOutputted += 10;
516 output_char( memory_id[(value.byte[2] > 3) ? 4 : value.byte[2]], p );
520 if ((value.byte[2] != 0x00 /* DSEG */) &&
521 (value.byte[2] != 0x03 /* SSEG */))
523 OUTPUT_2DIGITS( value.byte[1] );
526 OUTPUT_2DIGITS( value.byte[0] );
554 // nothing special, just output the character
560 if (float_argument) {
561 value.f=va_arg(ap,float);
575 // ignore b and l conversion spec for now
576 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
577 zero_padding, prefix_sign, prefix_space);
579 } else if (radix != 0)
581 // Apperently we have to output an integral type
582 // with radix "radix"
583 unsigned char store[6];
584 unsigned char _AUTOMEM *pstore = &store[5];
586 // store value in byte[0] (LSB) ... byte[3] (MSB)
589 value.l = va_arg(ap,char);
590 if (!signed_argument)
595 else if (long_argument)
597 value.l = va_arg(ap,long);
601 value.l = va_arg(ap,int);
602 if (!signed_argument)
608 if ( signed_argument )
621 #if defined SDCC_STACK_AUTO
622 calculate_digit(&value, radix);
624 calculate_digit(radix);
628 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
633 *pstore = value.byte[4];
641 // default width. We set it to 1 to output
642 // at least one character in case the value itself
643 // is zero (i.e. length==0)
647 /* prepend spaces if needed */
648 if (!zero_padding && !left_justify)
650 while ( width > (unsigned char) (length+1) )
652 output_char( ' ', p );
658 if (signed_argument) // this now means the original value was negative
660 output_char( '-', p );
662 // adjust width to compensate for this character
665 else if (length != 0)
670 output_char( '+', p );
672 // adjust width to compensate for this character
675 else if (prefix_space)
677 output_char( ' ', p );
679 // adjust width to compensate for this character
684 /* prepend zeroes/spaces if needed */
686 while ( width-- > length )
688 output_char( zero_padding ? '0' : ' ', p );
693 /* spaces are appended after the digits */
700 /* output the digits */
707 value.byte[4] = *pstore >> 4;
711 value.byte[4] = *pstore & 0x0F;
713 #ifdef SDCC_STACK_AUTO
714 output_digit( value.byte[4], lower_case, output_char, p );
716 output_digit( value.byte[4] );
730 // nothing special, just output the character
736 return charsOutputted;
739 /****************************************************************************/