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
48 # define MEM_SPACE_BUF
51 /****************************************************************************/
53 //typedef char * ptr_t;
69 //#define toupper(c) ((c)&=~0x20)
70 #define toupper(c) ((c)&=0xDF)
71 #define tolower(c) ((c)|=0x20)
72 #define islower(c) ((unsigned char)c >= (unsigned char)'a' && (unsigned char)c <= (unsigned char)'z')
73 #define isdigit(c) ((unsigned char)c >= (unsigned char)'0' && (unsigned char)c <= (unsigned char)'9')
77 unsigned char byte[5];
84 #ifndef SDCC_STACK_AUTO
85 static BOOL lower_case;
86 static pfn_outputchar output_char;
89 static int charsOutputted;
92 /****************************************************************************/
94 #ifdef SDCC_STACK_AUTO
95 #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
97 #define OUTPUT_CHAR(c, p) _output_char (c)
98 static void _output_char( unsigned char c )
105 /*--------------------------------------------------------------------------*/
107 #ifdef SDCC_STACK_AUTO
108 static void output_digit( unsigned char n, BOOL lower_case, pfn_outputchar output_char, void* p )
110 register unsigned char c = n + (unsigned char)'0';
112 if (c > (unsigned char)'9')
114 c += (unsigned char)('A' - '0' - 10);
116 c += (unsigned char)('a' - 'A');
121 static void output_digit( unsigned char n )
123 register unsigned char c = n + (unsigned char)'0';
125 if (c > (unsigned char)'9')
127 c += (unsigned char)('A' - '0' - 10);
135 /*--------------------------------------------------------------------------*/
137 #ifdef SDCC_STACK_AUTO
138 #define OUTPUT_2DIGITS( B ) { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
139 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
141 output_digit( b>>4, lower_case, output_char, p );
142 output_digit( b&0x0F, lower_case, output_char, p );
145 #define OUTPUT_2DIGITS( B ) output_2digits( B )
146 static void output_2digits( unsigned char b )
148 output_digit( b>>4 );
149 output_digit( b&0x0F );
153 /*--------------------------------------------------------------------------*/
155 #if defined SDCC_STACK_AUTO
156 static void calculate_digit( value_t _AUTOMEM * value, unsigned char radix )
158 unsigned long ul = value->ul;
159 unsigned char _AUTOMEM * pb4 = &value->byte[4];
160 unsigned char i = 32;
164 *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
176 static void calculate_digit( unsigned char radix )
178 register unsigned long ul = value.ul;
179 register unsigned char b4 = value.byte[4];
180 register unsigned char i = 32;
185 b4 |= (ul >> 31) & 0x01;
201 /* This is a very inefficient but direct approach, since we have no math
202 library yet (e.g. log()).
203 It does most of the modifiers, but has some restrictions. E.g. the
204 abs(float) shouldn't be bigger than an unsigned long (that's
205 about 4294967295), but still makes it usefull for most real-life
209 #define DEFAULT_FLOAT_PRECISION 6
211 #ifdef SDCC_STACK_AUTO
212 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
214 output_float (float f, unsigned char reqWidth,
215 signed char reqDecimals,
216 BOOL left, BOOL zero, BOOL sign, BOOL space,
217 pfn_outputchar output_char, void* p)
219 unsigned char charsOutputted = 0;
220 #if defined (SDCC_mcs51)
221 char fpBuffer[16]; //mcs51 has only a small stack
226 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
228 output_float (float f, unsigned char reqWidth,
229 signed char reqDecimals,
230 BOOL left, BOOL zero, BOOL sign, BOOL space)
232 __xdata char fpBuffer[128];
233 #endif //SDCC_STACK_AUTO
235 unsigned long integerPart;
239 unsigned char minWidth, i;
240 signed char exp = -128;
249 // this part is from Frank van der Hulst
251 for (exp = 0; f >= 10.0; exp++) f /=10.0;
252 for ( ; f < 1.0; exp--) f *=10.0;
255 OUTPUT_CHAR ('-', p);
258 OUTPUT_CHAR ('+', p);
268 // display some decimals as default
270 reqDecimals=DEFAULT_FLOAT_PRECISION;
274 for (i=reqDecimals; i>0; i--) {
281 decimalPart = f - integerPart;
283 // fill the buffer with the integerPart (in reversed order!)
284 while (integerPart) {
285 fpBuffer[fpBI++]='0' + integerPart%10;
289 // we need at least a 0
290 fpBuffer[fpBI++]='0';
293 // fill buffer with the decimalPart (in normal order)
296 for (i=reqDecimals; i>0; i--) {
298 // truncate the float
299 integerPart = decimalPart;
300 fpBuffer[fpBD++] = '0' + integerPart;
301 decimalPart -= integerPart;
304 minWidth=fpBI; // we need at least these
305 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
306 if (negative || sign || space)
307 minWidth++; // and maybe even this :)
309 if (!left && reqWidth>i) {
323 while (reqWidth-->minWidth)
328 while (reqWidth-->minWidth)
360 // output the integer part
363 OUTPUT_CHAR (fpBuffer[i], p);
366 // ouput the decimal part
368 OUTPUT_CHAR ('.', p);
370 while (reqDecimals--)
372 OUTPUT_CHAR (fpBuffer[i++], p);
376 if (left && reqWidth>minWidth) {
377 while (reqWidth-->minWidth)
384 OUTPUT_CHAR ('e', p);
386 OUTPUT_CHAR ('-', p);
389 OUTPUT_CHAR ('0'+exp/10, p);
390 OUTPUT_CHAR ('0'+exp%10, p);
392 #ifdef SDCC_STACK_AUTO
393 return charsOutputted;
396 #endif //SDCC_STACK_AUTO
400 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
406 BOOL signed_argument;
410 #ifdef SDCC_STACK_AUTO
419 signed char decimals;
420 unsigned char length;
423 #ifdef SDCC_STACK_AUTO
424 #define output_char pfn
431 // reset output chars
467 width = 10*width + (c - '0');
469 /* first character of width is a zero */
473 decimals = 10*decimals + (c-'0');
475 goto get_conversion_spec;
479 if (decimals==-1) decimals=0;
481 ; // duplicate, ignore
482 goto get_conversion_spec;
497 goto get_conversion_spec;
500 goto get_conversion_spec;
503 goto get_conversion_spec;
506 goto get_conversion_spec;
509 goto get_conversion_spec;
520 PTR = va_arg(ap,ptr_t);
525 length=NULL_STRING_LENGTH;
527 length = strlen(PTR);
530 length = strlen(PTR);
532 if ( decimals == -1 )
536 if ( ( !left_justify ) && (length < width) )
539 while( width-- != 0 )
541 OUTPUT_CHAR( ' ', p );
545 while ( (c = *PTR) && (decimals-- > 0))
551 if ( left_justify && (length < width))
554 while( width-- != 0 )
556 OUTPUT_CHAR( ' ', p );
562 PTR = va_arg(ap,ptr_t);
564 #if defined (SDCC_ds390)
566 unsigned char memtype = value.byte[3];
569 else if (memtype > 0x60)
571 else if (memtype > 0x40)
580 OUTPUT_2DIGITS( value.byte[2] );
581 OUTPUT_2DIGITS( value.byte[1] );
582 OUTPUT_2DIGITS( value.byte[0] );
583 #elif defined (SDCC_mcs51)
585 unsigned char memtype = value.byte[2];
588 else if (memtype > 0x60)
590 else if (memtype > 0x40)
599 if ((c != 'I' /* idata */) &&
600 (c != 'P' /* pdata */))
602 OUTPUT_2DIGITS( value.byte[1] );
604 OUTPUT_2DIGITS( value.byte[0] );
608 OUTPUT_2DIGITS( value.byte[1] );
609 OUTPUT_2DIGITS( value.byte[0] );
636 // nothing special, just output the character
641 if (float_argument) {
642 value.f=va_arg(ap,float);
655 // ignore b and l conversion spec for now
656 #ifdef SDCC_STACK_AUTO
657 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
658 zero_padding, prefix_sign, prefix_space);
660 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
661 zero_padding, prefix_sign, prefix_space);
662 #endif //SDCC_STACK_AUTO
664 } else if (radix != 0)
666 // Apparently we have to output an integral type
667 // with radix "radix"
668 unsigned char MEM_SPACE_BUF store[6];
669 unsigned char MEM_SPACE_BUF *pstore = &store[5];
671 // store value in byte[0] (LSB) ... byte[3] (MSB)
674 value.l = va_arg(ap,char);
675 if (!signed_argument)
680 else if (long_argument)
682 value.l = va_arg(ap,long);
686 value.l = va_arg(ap,int);
687 if (!signed_argument)
693 if ( signed_argument )
706 #if defined SDCC_STACK_AUTO
707 calculate_digit(&value, radix);
709 calculate_digit(radix);
713 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
718 *pstore = value.byte[4];
726 // default width. We set it to 1 to output
727 // at least one character in case the value itself
728 // is zero (i.e. length==0)
732 /* prepend spaces if needed */
733 if (!zero_padding && !left_justify)
735 while ( width > (unsigned char) (length+1) )
737 OUTPUT_CHAR( ' ', p );
742 if (signed_argument) // this now means the original value was negative
744 OUTPUT_CHAR( '-', p );
745 // adjust width to compensate for this character
748 else if (length != 0)
753 OUTPUT_CHAR( '+', p );
754 // adjust width to compensate for this character
757 else if (prefix_space)
759 OUTPUT_CHAR( ' ', p );
760 // adjust width to compensate for this character
765 /* prepend zeroes/spaces if needed */
767 while ( width-- > length )
769 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
773 /* spaces are appended after the digits */
780 /* output the digits */
787 value.byte[4] = *pstore >> 4;
791 value.byte[4] = *pstore & 0x0F;
793 #ifdef SDCC_STACK_AUTO
794 output_digit( value.byte[4], lower_case, output_char, p );
797 output_digit( value.byte[4] );
809 // nothing special, just output the character
814 return charsOutputted;
817 /****************************************************************************/