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 = n + (unsigned char)'0';
85 if (c > (unsigned char)'9')
87 c += (unsigned char)('A' - '0' - 10);
89 c += (unsigned char)('a' - 'A');
94 /*--------------------------------------------------------------------------*/
96 #ifdef SDCC_STACK_AUTO
97 #define OUTPUT_2DIGITS( B ) output_2digits( B, lower_case, output_char, p )
98 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
100 output_digit( b>>4, lower_case, output_char, p );
101 output_digit( b&0x0F, lower_case, output_char, p );
104 #define OUTPUT_2DIGITS( B ) output_2digits( B )
105 static void output_2digits( unsigned char b )
107 output_digit( b>>4 );
108 output_digit( b&0x0F );
112 /*--------------------------------------------------------------------------*/
114 #if defined SDCC_STACK_AUTO
115 static void calculate_digit( value_t _AUTOMEM * value, unsigned char radix )
117 unsigned long ul = value->ul;
118 unsigned char _AUTOMEM * pb4 = &value->byte[4];
119 unsigned char i = 32;
123 *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
135 static void calculate_digit( unsigned char radix )
137 register unsigned long ul = value.ul;
138 register unsigned char b4 = value.byte[4];
139 register unsigned char i = 32;
144 b4 |= (ul >> 31) & 0x01;
160 /* This is a very inefficient but direct approach, since we have no math
161 library yet (e.g. log()).
162 It does most of the modifiers, but has some restrictions. E.g. the
163 abs(float) shouldn't be bigger than an unsigned long (that's
164 about 4294967295), but still makes it usefull for most real-life
168 #define DEFAULT_FLOAT_PRECISION 6
170 #ifdef SDCC_STACK_AUTO
171 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
172 static int output_float (float f, unsigned char reqWidth,
173 signed char reqDecimals,
174 BOOL left, BOOL zero, BOOL sign, BOOL space,
175 pfn_outputchar output_char, void* p)
177 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
178 static int output_float (float f, unsigned char reqWidth,
179 signed char reqDecimals,
180 BOOL left, BOOL zero, BOOL sign, BOOL space)
184 unsigned long integerPart;
188 unsigned char minWidth, i;
189 int charsOutputted=0;
198 // this part is from Frank van der Hulst
201 for (exp = 0; f >= 10.0; exp++) f /=10.0;
202 for ( ; f < 1.0; exp--) f *=10.0;
205 output_char ('-', p);
209 output_char ('+', p);
213 charsOutputted += OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
214 output_char ('e', p);
217 output_char ('-', p);
221 output_char ('0'+exp/10, p);
222 output_char ('0'+exp%10, p);
224 return charsOutputted;
229 decimalPart=f-integerPart;
231 // fill the buffer with the integerPart (in reversed order!)
232 while (integerPart) {
233 fpBuffer[fpBI++]='0' + integerPart%10;
237 // we need at least a 0
238 fpBuffer[fpBI++]='0';
241 // display some decimals as default
243 reqDecimals=DEFAULT_FLOAT_PRECISION;
245 // fill buffer with the decimalPart (in normal order)
248 for (i=reqDecimals; i>1; i--) {
250 // truncate the float
251 integerPart=decimalPart;
252 fpBuffer[fpBD++]='0' + integerPart;
253 decimalPart-=integerPart;
257 // truncate the float
258 integerPart = decimalPart + 0.5;
259 fpBuffer[fpBD++] = '0' + integerPart;
262 minWidth=fpBI; // we need at least these
263 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
264 if (negative || sign || space)
265 minWidth++; // and maybe even this :)
267 if (!left && reqWidth>i) {
284 while (reqWidth-->minWidth)
290 while (reqWidth-->minWidth)
329 // output the integer part
332 output_char (fpBuffer[i], p);
336 // ouput the decimal part
338 output_char ('.', p);
341 while (reqDecimals--)
343 output_char (fpBuffer[i++], p);
348 if (left && reqWidth>minWidth) {
349 while (reqWidth-->minWidth)
355 return charsOutputted;
359 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
365 BOOL signed_argument;
369 #ifdef SDCC_STACK_AUTO
378 signed char decimals;
379 unsigned char length;
382 #ifdef SDCC_STACK_AUTO
383 #define output_char pfn
390 // reset output chars
427 width = 10*width + (c - '0');
429 /* first character of width is a zero */
433 decimals = 10*decimals + (c-'0');
435 goto get_conversion_spec;
439 if (decimals=-1) decimals=0;
441 ; // duplicate, ignore
442 goto get_conversion_spec;
445 lower_case = islower(c);
455 goto get_conversion_spec;
458 goto get_conversion_spec;
461 goto get_conversion_spec;
464 goto get_conversion_spec;
467 goto get_conversion_spec;
470 output_char( va_arg(ap,int), p );
475 PTR = va_arg(ap,ptr_t);
480 length=NULL_STRING_LENGTH;
482 length = strlen(PTR);
485 length = strlen(PTR);
487 if ( decimals == -1 )
491 if ( ( !left_justify ) && (length < width) )
494 while( width-- != 0 )
496 output_char( ' ', p );
501 while ( *PTR && (decimals-- > 0))
503 output_char( *PTR++, p );
507 if ( left_justify && (length < width))
510 while( width-- != 0 )
512 output_char( ' ', p );
519 PTR = va_arg(ap,ptr_t);
521 #if defined (SDCC_ds390)
523 unsigned char memtype = value.byte[3];
526 else if (memtype > 0x60)
528 else if (memtype > 0x40)
537 OUTPUT_2DIGITS( value.byte[2] );
538 OUTPUT_2DIGITS( value.byte[1] );
539 OUTPUT_2DIGITS( value.byte[0] );
540 charsOutputted += 10;
541 #elif defined (SDCC_mcs51)
543 unsigned char memtype = value.byte[2];
546 else if (memtype > 0x60)
548 else if (memtype > 0x40)
557 if ((c != 'I' /* idata */) &&
558 (c != 'P' /* pdata */))
560 OUTPUT_2DIGITS( value.byte[1] );
563 OUTPUT_2DIGITS( value.byte[0] );
568 OUTPUT_2DIGITS( value.byte[1] );
569 OUTPUT_2DIGITS( value.byte[0] );
597 // nothing special, just output the character
603 if (float_argument) {
604 value.f=va_arg(ap,float);
618 // ignore b and l conversion spec for now
619 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
620 zero_padding, prefix_sign, prefix_space);
622 } else if (radix != 0)
624 // Apperently we have to output an integral type
625 // with radix "radix"
626 unsigned char store[6];
627 unsigned char _AUTOMEM *pstore = &store[5];
629 // store value in byte[0] (LSB) ... byte[3] (MSB)
632 value.l = va_arg(ap,char);
633 if (!signed_argument)
638 else if (long_argument)
640 value.l = va_arg(ap,long);
644 value.l = va_arg(ap,int);
645 if (!signed_argument)
651 if ( signed_argument )
664 #if defined SDCC_STACK_AUTO
665 calculate_digit(&value, radix);
667 calculate_digit(radix);
671 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
676 *pstore = value.byte[4];
684 // default width. We set it to 1 to output
685 // at least one character in case the value itself
686 // is zero (i.e. length==0)
690 /* prepend spaces if needed */
691 if (!zero_padding && !left_justify)
693 while ( width > (unsigned char) (length+1) )
695 output_char( ' ', p );
701 if (signed_argument) // this now means the original value was negative
703 output_char( '-', p );
705 // adjust width to compensate for this character
708 else if (length != 0)
713 output_char( '+', p );
715 // adjust width to compensate for this character
718 else if (prefix_space)
720 output_char( ' ', p );
722 // adjust width to compensate for this character
727 /* prepend zeroes/spaces if needed */
729 while ( width-- > length )
731 output_char( zero_padding ? '0' : ' ', p );
736 /* spaces are appended after the digits */
743 /* output the digits */
750 value.byte[4] = *pstore >> 4;
754 value.byte[4] = *pstore & 0x0F;
756 #ifdef SDCC_STACK_AUTO
757 output_digit( value.byte[4], lower_case, output_char, p );
759 output_digit( value.byte[4] );
773 // nothing special, just output the character
779 return charsOutputted;
782 /****************************************************************************/