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;
216 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
218 output_float (float f, unsigned char reqWidth,
219 signed char reqDecimals,
220 BOOL left, BOOL zero, BOOL sign, BOOL space)
222 xdata char fpBuffer[128];
223 #endif //SDCC_STACK_AUTO
225 unsigned long integerPart;
228 unsigned char minWidth, i;
237 // this part is from Frank van der Hulst
240 for (exp = 0; f >= 10.0; exp++) f /=10.0;
241 for ( ; f < 1.0; exp--) f *=10.0;
244 OUTPUT_CHAR ('-', p);
247 OUTPUT_CHAR ('+', p);
250 #ifdef SDCC_STACK_AUTO
251 charsOutputted += OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
253 OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
255 OUTPUT_CHAR ('e', p);
257 OUTPUT_CHAR ('-', p);
260 OUTPUT_CHAR ('0'+exp/10, p);
261 OUTPUT_CHAR ('0'+exp%10, p);
262 #ifdef SDCC_STACK_AUTO
263 return charsOutputted;
266 #endif //SDCC_STACK_AUTO
271 decimalPart=f-integerPart;
273 // fill the buffer with the integerPart (in reversed order!)
274 while (integerPart) {
275 fpBuffer[fpBI++]='0' + integerPart%10;
279 // we need at least a 0
280 fpBuffer[fpBI++]='0';
283 // display some decimals as default
285 reqDecimals=DEFAULT_FLOAT_PRECISION;
287 // fill buffer with the decimalPart (in normal order)
290 for (i=reqDecimals; i>1; i--) {
292 // truncate the float
293 integerPart=decimalPart;
294 fpBuffer[fpBD++]='0' + integerPart;
295 decimalPart-=integerPart;
299 // truncate the float
300 integerPart = decimalPart + 0.5;
301 fpBuffer[fpBD++] = '0' + 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)
382 #ifdef SDCC_STACK_AUTO
383 return charsOutputted;
386 #endif //SDCC_STACK_AUTO
390 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
396 BOOL signed_argument;
400 #ifdef SDCC_STACK_AUTO
409 signed char decimals;
410 unsigned char length;
413 #ifdef SDCC_STACK_AUTO
414 #define output_char pfn
421 // reset output chars
457 width = 10*width + (c - '0');
459 /* first character of width is a zero */
463 decimals = 10*decimals + (c-'0');
465 goto get_conversion_spec;
469 if (decimals=-1) decimals=0;
471 ; // duplicate, ignore
472 goto get_conversion_spec;
487 goto get_conversion_spec;
490 goto get_conversion_spec;
493 goto get_conversion_spec;
496 goto get_conversion_spec;
499 goto get_conversion_spec;
510 PTR = va_arg(ap,ptr_t);
515 length=NULL_STRING_LENGTH;
517 length = strlen(PTR);
520 length = strlen(PTR);
522 if ( decimals == -1 )
526 if ( ( !left_justify ) && (length < width) )
529 while( width-- != 0 )
531 OUTPUT_CHAR( ' ', p );
535 while ( (c = *PTR) && (decimals-- > 0))
541 if ( left_justify && (length < width))
544 while( width-- != 0 )
546 OUTPUT_CHAR( ' ', p );
552 PTR = va_arg(ap,ptr_t);
554 #if defined (SDCC_ds390)
556 unsigned char memtype = value.byte[3];
559 else if (memtype > 0x60)
561 else if (memtype > 0x40)
570 OUTPUT_2DIGITS( value.byte[2] );
571 OUTPUT_2DIGITS( value.byte[1] );
572 OUTPUT_2DIGITS( value.byte[0] );
573 #elif defined (SDCC_mcs51)
575 unsigned char memtype = value.byte[2];
578 else if (memtype > 0x60)
580 else if (memtype > 0x40)
589 if ((c != 'I' /* idata */) &&
590 (c != 'P' /* pdata */))
592 OUTPUT_2DIGITS( value.byte[1] );
594 OUTPUT_2DIGITS( value.byte[0] );
598 OUTPUT_2DIGITS( value.byte[1] );
599 OUTPUT_2DIGITS( value.byte[0] );
626 // nothing special, just output the character
631 if (float_argument) {
632 value.f=va_arg(ap,float);
645 // ignore b and l conversion spec for now
646 #ifdef SDCC_STACK_AUTO
647 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
648 zero_padding, prefix_sign, prefix_space);
650 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
651 zero_padding, prefix_sign, prefix_space);
652 #endif //SDCC_STACK_AUTO
654 } else if (radix != 0)
656 // Apperently we have to output an integral type
657 // with radix "radix"
658 unsigned char store[6];
659 unsigned char _AUTOMEM *pstore = &store[5];
661 // store value in byte[0] (LSB) ... byte[3] (MSB)
664 value.l = va_arg(ap,char);
665 if (!signed_argument)
670 else if (long_argument)
672 value.l = va_arg(ap,long);
676 value.l = va_arg(ap,int);
677 if (!signed_argument)
683 if ( signed_argument )
696 #if defined SDCC_STACK_AUTO
697 calculate_digit(&value, radix);
699 calculate_digit(radix);
703 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
708 *pstore = value.byte[4];
716 // default width. We set it to 1 to output
717 // at least one character in case the value itself
718 // is zero (i.e. length==0)
722 /* prepend spaces if needed */
723 if (!zero_padding && !left_justify)
725 while ( width > (unsigned char) (length+1) )
727 OUTPUT_CHAR( ' ', p );
732 if (signed_argument) // this now means the original value was negative
734 OUTPUT_CHAR( '-', p );
735 // adjust width to compensate for this character
738 else if (length != 0)
743 OUTPUT_CHAR( '+', p );
744 // adjust width to compensate for this character
747 else if (prefix_space)
749 OUTPUT_CHAR( ' ', p );
750 // adjust width to compensate for this character
755 /* prepend zeroes/spaces if needed */
757 while ( width-- > length )
759 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
763 /* spaces are appended after the digits */
770 /* output the digits */
777 value.byte[4] = *pstore >> 4;
781 value.byte[4] = *pstore & 0x0F;
783 #ifdef SDCC_STACK_AUTO
784 output_digit( value.byte[4], lower_case, output_char, p );
787 output_digit( value.byte[4] );
799 // nothing special, just output the character
804 return charsOutputted;
807 /****************************************************************************/