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 #if defined (SDCC_mcs51) && defined (SDCC_MODEL_SMALL) && !defined (SDCC_STACK_AUTO)
46 # define MEM_SPACE_BUF __idata
47 # define MEM_SPACE_BUF_PP __idata
49 # define MEM_SPACE_BUF
50 # define MEM_SPACE_BUF_PP _AUTOMEM
53 /****************************************************************************/
55 //typedef char * ptr_t;
71 //#define toupper(c) ((c)&=~0x20)
72 #define toupper(c) ((c)&=0xDF)
73 #define tolower(c) ((c)|=0x20)
74 #define islower(c) ((unsigned char)c >= (unsigned char)'a' && (unsigned char)c <= (unsigned char)'z')
75 #define isdigit(c) ((unsigned char)c >= (unsigned char)'0' && (unsigned char)c <= (unsigned char)'9')
79 unsigned char byte[5];
86 #ifndef SDCC_STACK_AUTO
87 static BOOL lower_case;
88 static pfn_outputchar output_char;
91 static int charsOutputted;
94 /****************************************************************************/
96 #ifdef SDCC_STACK_AUTO
97 #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
99 #define OUTPUT_CHAR(c, p) _output_char (c)
100 static void _output_char( unsigned char c )
107 /*--------------------------------------------------------------------------*/
109 #ifdef SDCC_STACK_AUTO
110 static void output_digit( unsigned char n, BOOL lower_case, pfn_outputchar output_char, void* p )
112 register unsigned char c = n + (unsigned char)'0';
114 if (c > (unsigned char)'9')
116 c += (unsigned char)('A' - '0' - 10);
118 c += (unsigned char)('a' - 'A');
123 static void output_digit( unsigned char n )
125 register unsigned char c = n + (unsigned char)'0';
127 if (c > (unsigned char)'9')
129 c += (unsigned char)('A' - '0' - 10);
137 /*--------------------------------------------------------------------------*/
139 #ifdef SDCC_STACK_AUTO
140 #define OUTPUT_2DIGITS( B ) { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
141 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
143 output_digit( b>>4, lower_case, output_char, p );
144 output_digit( b&0x0F, lower_case, output_char, p );
147 #define OUTPUT_2DIGITS( B ) output_2digits( B )
148 static void output_2digits( unsigned char b )
150 output_digit( b>>4 );
151 output_digit( b&0x0F );
155 /*--------------------------------------------------------------------------*/
157 #if defined SDCC_STACK_AUTO
158 static void calculate_digit( value_t _AUTOMEM * value, unsigned char radix )
160 unsigned long ul = value->ul;
161 unsigned char _AUTOMEM * pb4 = &value->byte[4];
162 unsigned char i = 32;
166 *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
178 static void calculate_digit( unsigned char radix )
180 register unsigned long ul = value.ul;
181 register unsigned char b4 = value.byte[4];
182 register unsigned char i = 32;
187 b4 |= (ul >> 31) & 0x01;
203 /* This is a very inefficient but direct approach, since we have no math
204 library yet (e.g. log()).
205 It does most of the modifiers, but has some restrictions. E.g. the
206 abs(float) shouldn't be bigger than an unsigned long (that's
207 about 4294967295), but still makes it usefull for most real-life
211 #define DEFAULT_FLOAT_PRECISION 6
213 #ifdef SDCC_STACK_AUTO
214 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
216 output_float (float f, unsigned char reqWidth,
217 signed char reqDecimals,
218 BOOL left, BOOL zero, BOOL sign, BOOL space,
219 pfn_outputchar output_char, void* p)
221 unsigned char charsOutputted = 0;
222 #if defined (SDCC_mcs51)
223 char fpBuffer[16]; //mcs51 has only a small stack
228 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
230 output_float (float f, unsigned char reqWidth,
231 signed char reqDecimals,
232 BOOL left, BOOL zero, BOOL sign, BOOL space)
234 __xdata char fpBuffer[128];
235 #endif //SDCC_STACK_AUTO
237 unsigned long integerPart;
241 unsigned char minWidth, i;
242 signed char exp = -128;
251 // this part is from Frank van der Hulst
253 for (exp = 0; f >= 10.0; exp++) f /=10.0;
254 for ( ; f < 1.0; exp--) f *=10.0;
257 OUTPUT_CHAR ('-', p);
260 OUTPUT_CHAR ('+', p);
270 // display some decimals as default
272 reqDecimals=DEFAULT_FLOAT_PRECISION;
276 for (i=reqDecimals; i>0; i--) {
283 decimalPart = f - integerPart;
285 // fill the buffer with the integerPart (in reversed order!)
286 while (integerPart) {
287 fpBuffer[fpBI++]='0' + integerPart%10;
291 // we need at least a 0
292 fpBuffer[fpBI++]='0';
295 // fill buffer with the decimalPart (in normal order)
298 for (i=reqDecimals; i>0; i--) {
300 // truncate the float
301 integerPart = decimalPart;
302 fpBuffer[fpBD++] = '0' + integerPart;
303 decimalPart -= integerPart;
306 minWidth=fpBI; // we need at least these
307 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
308 if (negative || sign || space)
309 minWidth++; // and maybe even this :)
311 if (!left && reqWidth>i) {
325 while (reqWidth-->minWidth)
330 while (reqWidth-->minWidth)
362 // output the integer part
365 OUTPUT_CHAR (fpBuffer[i], p);
368 // ouput the decimal part
370 OUTPUT_CHAR ('.', p);
372 while (reqDecimals--)
374 OUTPUT_CHAR (fpBuffer[i++], p);
378 if (left && reqWidth>minWidth) {
379 while (reqWidth-->minWidth)
386 OUTPUT_CHAR ('e', p);
388 OUTPUT_CHAR ('-', p);
391 OUTPUT_CHAR ('0'+exp/10, p);
392 OUTPUT_CHAR ('0'+exp%10, p);
394 #ifdef SDCC_STACK_AUTO
395 return charsOutputted;
398 #endif //SDCC_STACK_AUTO
402 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
408 BOOL signed_argument;
412 #ifdef SDCC_STACK_AUTO
421 signed char decimals;
422 unsigned char length;
425 #ifdef SDCC_STACK_AUTO
426 #define output_char pfn
433 // reset output chars
469 width = 10*width + (c - '0');
471 /* first character of width is a zero */
475 decimals = 10*decimals + (c-'0');
477 goto get_conversion_spec;
481 if (decimals==-1) decimals=0;
483 ; // duplicate, ignore
484 goto get_conversion_spec;
499 goto get_conversion_spec;
502 goto get_conversion_spec;
505 goto get_conversion_spec;
508 goto get_conversion_spec;
511 goto get_conversion_spec;
522 PTR = va_arg(ap,ptr_t);
527 length=NULL_STRING_LENGTH;
529 length = strlen(PTR);
532 length = strlen(PTR);
534 if ( decimals == -1 )
538 if ( ( !left_justify ) && (length < width) )
541 while( width-- != 0 )
543 OUTPUT_CHAR( ' ', p );
547 while ( (c = *PTR) && (decimals-- > 0))
553 if ( left_justify && (length < width))
556 while( width-- != 0 )
558 OUTPUT_CHAR( ' ', p );
564 PTR = va_arg(ap,ptr_t);
566 #if defined (SDCC_ds390)
568 unsigned char memtype = value.byte[3];
571 else if (memtype > 0x60)
573 else if (memtype > 0x40)
582 OUTPUT_2DIGITS( value.byte[2] );
583 OUTPUT_2DIGITS( value.byte[1] );
584 OUTPUT_2DIGITS( value.byte[0] );
585 #elif defined (SDCC_mcs51)
587 unsigned char memtype = value.byte[2];
590 else if (memtype > 0x60)
592 else if (memtype > 0x40)
601 if ((c != 'I' /* idata */) &&
602 (c != 'P' /* pdata */))
604 OUTPUT_2DIGITS( value.byte[1] );
606 OUTPUT_2DIGITS( value.byte[0] );
610 OUTPUT_2DIGITS( value.byte[1] );
611 OUTPUT_2DIGITS( value.byte[0] );
638 // nothing special, just output the character
643 if (float_argument) {
644 value.f=va_arg(ap,float);
657 // ignore b and l conversion spec for now
658 #ifdef SDCC_STACK_AUTO
659 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
660 zero_padding, prefix_sign, prefix_space);
662 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
663 zero_padding, prefix_sign, prefix_space);
664 #endif //SDCC_STACK_AUTO
666 } else if (radix != 0)
668 // Apparently we have to output an integral type
669 // with radix "radix"
670 unsigned char MEM_SPACE_BUF store[6];
671 unsigned char MEM_SPACE_BUF_PP *pstore = &store[5];
673 // store value in byte[0] (LSB) ... byte[3] (MSB)
676 value.l = va_arg(ap,char);
677 if (!signed_argument)
682 else if (long_argument)
684 value.l = va_arg(ap,long);
688 value.l = va_arg(ap,int);
689 if (!signed_argument)
695 if ( signed_argument )
708 #if defined SDCC_STACK_AUTO
709 calculate_digit(&value, radix);
711 calculate_digit(radix);
715 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
720 *pstore = value.byte[4];
728 // default width. We set it to 1 to output
729 // at least one character in case the value itself
730 // is zero (i.e. length==0)
734 /* prepend spaces if needed */
735 if (!zero_padding && !left_justify)
737 while ( width > (unsigned char) (length+1) )
739 OUTPUT_CHAR( ' ', p );
744 if (signed_argument) // this now means the original value was negative
746 OUTPUT_CHAR( '-', p );
747 // adjust width to compensate for this character
750 else if (length != 0)
755 OUTPUT_CHAR( '+', p );
756 // adjust width to compensate for this character
759 else if (prefix_space)
761 OUTPUT_CHAR( ' ', p );
762 // adjust width to compensate for this character
767 /* prepend zeroes/spaces if needed */
769 while ( width-- > length )
771 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
775 /* spaces are appended after the digits */
782 /* output the digits */
789 value.byte[4] = *pstore >> 4;
793 value.byte[4] = *pstore & 0x0F;
795 #ifdef SDCC_STACK_AUTO
796 output_digit( value.byte[4], lower_case, output_char, p );
799 output_digit( value.byte[4] );
811 // nothing special, just output the character
816 return charsOutputted;
819 /****************************************************************************/