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 -------------------------------------------------------------------------*/
27 #if defined (SDCC_ds390)
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 register unsigned char c;
87 c = n + (unsigned char)('a' - 10);
89 c = n + (unsigned char)('A' - 10);
93 /*--------------------------------------------------------------------------*/
95 #ifdef SDCC_STACK_AUTO
96 #define OUTPUT_2DIGITS( B ) output_2digits( B, lower_case, output_char, p )
97 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
99 output_digit( b>>4, lower_case, output_char, p );
100 output_digit( b&0x0F, lower_case, output_char, p );
103 #define OUTPUT_2DIGITS( B ) output_2digits( B )
104 static void output_2digits( unsigned char b )
106 output_digit( b>>4 );
107 output_digit( b&0x0F );
111 /*--------------------------------------------------------------------------*/
113 #if defined SDCC_STACK_AUTO
114 static void calculate_digit( value_t _AUTOMEM * value, unsigned char radix )
116 unsigned long ul = value->ul;
117 unsigned char _AUTOMEM * pb4 = &value->byte[4];
118 unsigned char i = 32;
122 *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
134 static void calculate_digit( unsigned char radix )
136 register unsigned long ul = value.ul;
137 register unsigned char b4 = value.byte[4];
138 register unsigned char i = 32;
143 b4 |= (ul >> 31) & 0x01;
159 /* This is a very inefficient but direct approach, since we have no math
160 library yet (e.g. log()).
161 It does most of the modifiers, but has some restrictions. E.g. the
162 abs(float) shouldn't be bigger than an unsigned long (that's
163 about 4294967295), but still makes it usefull for most real-life
167 #define DEFAULT_FLOAT_PRECISION 6
169 #ifdef SDCC_STACK_AUTO
170 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
171 static int output_float (float f, unsigned char reqWidth,
172 signed char reqDecimals,
173 BOOL left, BOOL zero, BOOL sign, BOOL space,
174 pfn_outputchar output_char, void* p)
176 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
177 static int output_float (float f, unsigned char reqWidth,
178 signed char reqDecimals,
179 BOOL left, BOOL zero, BOOL sign, BOOL space)
183 unsigned long integerPart;
187 unsigned char minWidth, i;
188 int charsOutputted=0;
197 // this part is from Frank van der Hulst
200 for (exp = 0; f >= 10.0; exp++) f /=10.0;
201 for ( ; f < 1.0; exp--) f *=10.0;
204 output_char ('-', p);
208 output_char ('+', p);
212 charsOutputted += OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
213 output_char ('e', p);
216 output_char ('-', p);
220 output_char ('0'+exp/10, p);
221 output_char ('0'+exp%10, p);
223 return charsOutputted;
228 decimalPart=f-integerPart;
230 // fill the buffer with the integerPart (in reversed order!)
231 while (integerPart) {
232 fpBuffer[fpBI++]='0' + integerPart%10;
236 // we need at least a 0
237 fpBuffer[fpBI++]='0';
240 // display some decimals as default
242 reqDecimals=DEFAULT_FLOAT_PRECISION;
244 // fill buffer with the decimalPart (in normal order)
247 for (i=reqDecimals; i>1; i--) {
249 // truncate the float
250 integerPart=decimalPart;
251 fpBuffer[fpBD++]='0' + integerPart;
252 decimalPart-=integerPart;
256 // truncate the float
257 integerPart = decimalPart + 0.5;
258 fpBuffer[fpBD++] = '0' + integerPart;
261 minWidth=fpBI; // we need at least these
262 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
263 if (negative || sign || space)
264 minWidth++; // and maybe even this :)
266 if (!left && reqWidth>i) {
283 while (reqWidth-->minWidth)
289 while (reqWidth-->minWidth)
328 // output the integer part
331 output_char (fpBuffer[i], p);
335 // ouput the decimal part
337 output_char ('.', p);
340 while (reqDecimals--)
342 output_char (fpBuffer[i++], p);
347 if (left && reqWidth>minWidth) {
348 while (reqWidth-->minWidth)
354 return charsOutputted;
358 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
364 BOOL signed_argument;
368 #ifdef SDCC_STACK_AUTO
377 signed char decimals;
378 unsigned char length;
381 #ifdef SDCC_STACK_AUTO
382 #define output_char pfn
389 // reset output chars
426 width = 10*width + (c - '0');
428 /* first character of width is a zero */
432 decimals = 10*decimals + (c-'0');
434 goto get_conversion_spec;
438 if (decimals=-1) decimals=0;
440 ; // duplicate, ignore
441 goto get_conversion_spec;
444 lower_case = islower(c);
454 goto get_conversion_spec;
457 goto get_conversion_spec;
460 goto get_conversion_spec;
463 goto get_conversion_spec;
466 goto get_conversion_spec;
469 output_char( va_arg(ap,int), p );
474 PTR = va_arg(ap,ptr_t);
479 length=NULL_STRING_LENGTH;
481 length = strlen(PTR);
484 length = strlen(PTR);
486 if ( decimals == -1 )
490 if ( ( !left_justify ) && (length < width) )
493 while( width-- != 0 )
495 output_char( ' ', p );
500 while ( *PTR && (decimals-- > 0))
502 output_char( *PTR++, p );
506 if ( left_justify && (length < width))
509 while( width-- != 0 )
511 output_char( ' ', p );
518 PTR = va_arg(ap,ptr_t);
520 #if defined (SDCC_ds390)
522 unsigned char memtype = value.byte[3];
525 else if (memtype > 0x60)
527 else if (memtype > 0x40)
536 OUTPUT_2DIGITS( value.byte[2] );
537 OUTPUT_2DIGITS( value.byte[1] );
538 OUTPUT_2DIGITS( value.byte[0] );
539 charsOutputted += 10;
540 #elif defined (SDCC_mcs51)
542 unsigned char memtype = value.byte[2];
545 else if (memtype > 0x60)
547 else if (memtype > 0x40)
556 if ((c != 'I' /* idata */) &&
557 (c != 'P' /* pdata */))
559 OUTPUT_2DIGITS( value.byte[1] );
562 OUTPUT_2DIGITS( value.byte[0] );
567 OUTPUT_2DIGITS( value.byte[1] );
568 OUTPUT_2DIGITS( value.byte[0] );
596 // nothing special, just output the character
602 if (float_argument) {
603 value.f=va_arg(ap,float);
617 // ignore b and l conversion spec for now
618 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
619 zero_padding, prefix_sign, prefix_space);
621 } else if (radix != 0)
623 // Apperently we have to output an integral type
624 // with radix "radix"
625 unsigned char store[6];
626 unsigned char _AUTOMEM *pstore = &store[5];
628 // store value in byte[0] (LSB) ... byte[3] (MSB)
631 value.l = va_arg(ap,char);
632 if (!signed_argument)
637 else if (long_argument)
639 value.l = va_arg(ap,long);
643 value.l = va_arg(ap,int);
644 if (!signed_argument)
650 if ( signed_argument )
663 #if defined SDCC_STACK_AUTO
664 calculate_digit(&value, radix);
666 calculate_digit(radix);
670 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
675 *pstore = value.byte[4];
683 // default width. We set it to 1 to output
684 // at least one character in case the value itself
685 // is zero (i.e. length==0)
689 /* prepend spaces if needed */
690 if (!zero_padding && !left_justify)
692 while ( width > (unsigned char) (length+1) )
694 output_char( ' ', p );
700 if (signed_argument) // this now means the original value was negative
702 output_char( '-', p );
704 // adjust width to compensate for this character
707 else if (length != 0)
712 output_char( '+', p );
714 // adjust width to compensate for this character
717 else if (prefix_space)
719 output_char( ' ', p );
721 // adjust width to compensate for this character
726 /* prepend zeroes/spaces if needed */
728 while ( width-- > length )
730 output_char( zero_padding ? '0' : ' ', p );
735 /* spaces are appended after the digits */
742 /* output the digits */
749 value.byte[4] = *pstore >> 4;
753 value.byte[4] = *pstore & 0x0F;
755 #ifdef SDCC_STACK_AUTO
756 output_digit( value.byte[4], lower_case, output_char, p );
758 output_digit( value.byte[4] );
772 // nothing special, just output the character
778 return charsOutputted;
781 /****************************************************************************/