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;
63 //#define toupper(c) ((c)&=~0x20)
64 #define toupper(c) ((c)&=0xDF)
65 #define tolower(c) ((c)|=0x20)
66 #define islower(c) ((unsigned char)c >= (unsigned char)'a' && (unsigned char)c <= (unsigned char)'z')
67 #define isdigit(c) ((unsigned char)c >= (unsigned char)'0' && (unsigned char)c <= (unsigned char)'9')
71 unsigned char byte[5];
78 #ifndef SDCC_STACK_AUTO
79 static BOOL lower_case;
80 static pfn_outputchar output_char;
83 static int charsOutputted;
86 /****************************************************************************/
88 #ifdef SDCC_STACK_AUTO
89 #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
91 #define OUTPUT_CHAR(c, p) _output_char (c)
92 static void _output_char( unsigned char c )
99 /*--------------------------------------------------------------------------*/
101 #ifdef SDCC_STACK_AUTO
102 static void output_digit( unsigned char n, BOOL lower_case, pfn_outputchar output_char, void* p )
104 register unsigned char c = n + (unsigned char)'0';
106 if (c > (unsigned char)'9')
108 c += (unsigned char)('A' - '0' - 10);
110 c += (unsigned char)('a' - 'A');
115 static void output_digit( unsigned char n )
117 register unsigned char c = n + (unsigned char)'0';
119 if (c > (unsigned char)'9')
121 c += (unsigned char)('A' - '0' - 10);
129 /*--------------------------------------------------------------------------*/
131 #ifdef SDCC_STACK_AUTO
132 #define OUTPUT_2DIGITS( B ) { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
133 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
135 output_digit( b>>4, lower_case, output_char, p );
136 output_digit( b&0x0F, lower_case, output_char, p );
139 #define OUTPUT_2DIGITS( B ) output_2digits( B )
140 static void output_2digits( unsigned char b )
142 output_digit( b>>4 );
143 output_digit( b&0x0F );
147 /*--------------------------------------------------------------------------*/
149 #if defined SDCC_STACK_AUTO
150 static void calculate_digit( value_t _AUTOMEM * value, unsigned char radix )
152 unsigned long ul = value->ul;
153 unsigned char _AUTOMEM * pb4 = &value->byte[4];
154 unsigned char i = 32;
158 *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
170 static void calculate_digit( unsigned char radix )
172 register unsigned long ul = value.ul;
173 register unsigned char b4 = value.byte[4];
174 register unsigned char i = 32;
179 b4 |= (ul >> 31) & 0x01;
195 /* This is a very inefficient but direct approach, since we have no math
196 library yet (e.g. log()).
197 It does most of the modifiers, but has some restrictions. E.g. the
198 abs(float) shouldn't be bigger than an unsigned long (that's
199 about 4294967295), but still makes it usefull for most real-life
203 #define DEFAULT_FLOAT_PRECISION 6
205 #ifdef SDCC_STACK_AUTO
206 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
208 output_float (float f, unsigned char reqWidth,
209 signed char reqDecimals,
210 BOOL left, BOOL zero, BOOL sign, BOOL space,
211 pfn_outputchar output_char, void* p)
213 unsigned char charsOutputted = 0;
214 #if defined (SDCC_mcs51)
215 char fpBuffer[16]; //mcs51 has only a small stack
220 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
222 output_float (float f, unsigned char reqWidth,
223 signed char reqDecimals,
224 BOOL left, BOOL zero, BOOL sign, BOOL space)
226 xdata char fpBuffer[128];
227 #endif //SDCC_STACK_AUTO
229 unsigned long integerPart;
233 unsigned char minWidth, i;
234 signed char exp = -128;
243 // this part is from Frank van der Hulst
245 for (exp = 0; f >= 10.0; exp++) f /=10.0;
246 for ( ; f < 1.0; exp--) f *=10.0;
249 OUTPUT_CHAR ('-', p);
252 OUTPUT_CHAR ('+', p);
262 // display some decimals as default
264 reqDecimals=DEFAULT_FLOAT_PRECISION;
268 for (i=reqDecimals; i>0; i--) {
275 decimalPart = f - integerPart;
277 // fill the buffer with the integerPart (in reversed order!)
278 while (integerPart) {
279 fpBuffer[fpBI++]='0' + integerPart%10;
283 // we need at least a 0
284 fpBuffer[fpBI++]='0';
287 // fill buffer with the decimalPart (in normal order)
290 for (i=reqDecimals; i>0; i--) {
292 // truncate the float
293 integerPart = decimalPart;
294 fpBuffer[fpBD++] = '0' + integerPart;
295 decimalPart -= integerPart;
298 minWidth=fpBI; // we need at least these
299 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
300 if (negative || sign || space)
301 minWidth++; // and maybe even this :)
303 if (!left && reqWidth>i) {
317 while (reqWidth-->minWidth)
322 while (reqWidth-->minWidth)
354 // output the integer part
357 OUTPUT_CHAR (fpBuffer[i], p);
360 // ouput the decimal part
362 OUTPUT_CHAR ('.', p);
364 while (reqDecimals--)
366 OUTPUT_CHAR (fpBuffer[i++], p);
370 if (left && reqWidth>minWidth) {
371 while (reqWidth-->minWidth)
378 OUTPUT_CHAR ('e', p);
380 OUTPUT_CHAR ('-', p);
383 OUTPUT_CHAR ('0'+exp/10, p);
384 OUTPUT_CHAR ('0'+exp%10, p);
386 #ifdef SDCC_STACK_AUTO
387 return charsOutputted;
390 #endif //SDCC_STACK_AUTO
394 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
400 BOOL signed_argument;
404 #ifdef SDCC_STACK_AUTO
413 signed char decimals;
414 unsigned char length;
417 #ifdef SDCC_STACK_AUTO
418 #define output_char pfn
425 // reset output chars
461 width = 10*width + (c - '0');
463 /* first character of width is a zero */
467 decimals = 10*decimals + (c-'0');
469 goto get_conversion_spec;
473 if (decimals==-1) decimals=0;
475 ; // duplicate, ignore
476 goto get_conversion_spec;
491 goto get_conversion_spec;
494 goto get_conversion_spec;
497 goto get_conversion_spec;
500 goto get_conversion_spec;
503 goto get_conversion_spec;
514 PTR = va_arg(ap,ptr_t);
519 length=NULL_STRING_LENGTH;
521 length = strlen(PTR);
524 length = strlen(PTR);
526 if ( decimals == -1 )
530 if ( ( !left_justify ) && (length < width) )
533 while( width-- != 0 )
535 OUTPUT_CHAR( ' ', p );
539 while ( (c = *PTR) && (decimals-- > 0))
545 if ( left_justify && (length < width))
548 while( width-- != 0 )
550 OUTPUT_CHAR( ' ', p );
556 PTR = va_arg(ap,ptr_t);
558 #if defined (SDCC_ds390)
560 unsigned char memtype = value.byte[3];
563 else if (memtype > 0x60)
565 else if (memtype > 0x40)
574 OUTPUT_2DIGITS( value.byte[2] );
575 OUTPUT_2DIGITS( value.byte[1] );
576 OUTPUT_2DIGITS( value.byte[0] );
577 #elif defined (SDCC_mcs51)
579 unsigned char memtype = value.byte[2];
582 else if (memtype > 0x60)
584 else if (memtype > 0x40)
593 if ((c != 'I' /* idata */) &&
594 (c != 'P' /* pdata */))
596 OUTPUT_2DIGITS( value.byte[1] );
598 OUTPUT_2DIGITS( value.byte[0] );
602 OUTPUT_2DIGITS( value.byte[1] );
603 OUTPUT_2DIGITS( value.byte[0] );
630 // nothing special, just output the character
635 if (float_argument) {
636 value.f=va_arg(ap,float);
649 // ignore b and l conversion spec for now
650 #ifdef SDCC_STACK_AUTO
651 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
652 zero_padding, prefix_sign, prefix_space);
654 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
655 zero_padding, prefix_sign, prefix_space);
656 #endif //SDCC_STACK_AUTO
658 } else if (radix != 0)
660 // Apperently we have to output an integral type
661 // with radix "radix"
662 unsigned char store[6];
663 unsigned char _AUTOMEM *pstore = &store[5];
665 // store value in byte[0] (LSB) ... byte[3] (MSB)
668 value.l = va_arg(ap,char);
669 if (!signed_argument)
674 else if (long_argument)
676 value.l = va_arg(ap,long);
680 value.l = va_arg(ap,int);
681 if (!signed_argument)
687 if ( signed_argument )
700 #if defined SDCC_STACK_AUTO
701 calculate_digit(&value, radix);
703 calculate_digit(radix);
707 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
712 *pstore = value.byte[4];
720 // default width. We set it to 1 to output
721 // at least one character in case the value itself
722 // is zero (i.e. length==0)
726 /* prepend spaces if needed */
727 if (!zero_padding && !left_justify)
729 while ( width > (unsigned char) (length+1) )
731 OUTPUT_CHAR( ' ', p );
736 if (signed_argument) // this now means the original value was negative
738 OUTPUT_CHAR( '-', p );
739 // adjust width to compensate for this character
742 else if (length != 0)
747 OUTPUT_CHAR( '+', p );
748 // adjust width to compensate for this character
751 else if (prefix_space)
753 OUTPUT_CHAR( ' ', p );
754 // adjust width to compensate for this character
759 /* prepend zeroes/spaces if needed */
761 while ( width-- > length )
763 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
767 /* spaces are appended after the digits */
774 /* output the digits */
781 value.byte[4] = *pstore >> 4;
785 value.byte[4] = *pstore & 0x0F;
787 #ifdef SDCC_STACK_AUTO
788 output_digit( value.byte[4], lower_case, output_char, p );
791 output_digit( value.byte[4] );
803 // nothing special, just output the character
808 return charsOutputted;
811 /****************************************************************************/