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;
215 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
217 output_float (float f, unsigned char reqWidth,
218 signed char reqDecimals,
219 BOOL left, BOOL zero, BOOL sign, BOOL space)
221 #endif //SDCC_STACK_AUTO
223 unsigned long integerPart;
227 unsigned char minWidth, i;
236 // this part is from Frank van der Hulst
239 for (exp = 0; f >= 10.0; exp++) f /=10.0;
240 for ( ; f < 1.0; exp--) f *=10.0;
243 OUTPUT_CHAR ('-', p);
246 OUTPUT_CHAR ('+', p);
249 #ifdef SDCC_STACK_AUTO
250 charsOutputted += OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
252 OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
254 OUTPUT_CHAR ('e', p);
256 OUTPUT_CHAR ('-', p);
259 OUTPUT_CHAR ('0'+exp/10, p);
260 OUTPUT_CHAR ('0'+exp%10, p);
261 #ifdef SDCC_STACK_AUTO
262 return charsOutputted;
265 #endif //SDCC_STACK_AUTO
270 decimalPart=f-integerPart;
272 // fill the buffer with the integerPart (in reversed order!)
273 while (integerPart) {
274 fpBuffer[fpBI++]='0' + integerPart%10;
278 // we need at least a 0
279 fpBuffer[fpBI++]='0';
282 // display some decimals as default
284 reqDecimals=DEFAULT_FLOAT_PRECISION;
286 // fill buffer with the decimalPart (in normal order)
289 for (i=reqDecimals; i>1; i--) {
291 // truncate the float
292 integerPart=decimalPart;
293 fpBuffer[fpBD++]='0' + integerPart;
294 decimalPart-=integerPart;
298 // truncate the float
299 integerPart = decimalPart + 0.5;
300 fpBuffer[fpBD++] = '0' + integerPart;
303 minWidth=fpBI; // we need at least these
304 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
305 if (negative || sign || space)
306 minWidth++; // and maybe even this :)
308 if (!left && reqWidth>i) {
322 while (reqWidth-->minWidth)
327 while (reqWidth-->minWidth)
359 // output the integer part
362 OUTPUT_CHAR (fpBuffer[i], p);
365 // ouput the decimal part
367 OUTPUT_CHAR ('.', p);
369 while (reqDecimals--)
371 OUTPUT_CHAR (fpBuffer[i++], p);
375 if (left && reqWidth>minWidth) {
376 while (reqWidth-->minWidth)
381 #ifdef SDCC_STACK_AUTO
382 return charsOutputted;
385 #endif //SDCC_STACK_AUTO
389 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
395 BOOL signed_argument;
399 #ifdef SDCC_STACK_AUTO
408 signed char decimals;
409 unsigned char length;
412 #ifdef SDCC_STACK_AUTO
413 #define output_char pfn
420 // reset output chars
456 width = 10*width + (c - '0');
458 /* first character of width is a zero */
462 decimals = 10*decimals + (c-'0');
464 goto get_conversion_spec;
468 if (decimals=-1) decimals=0;
470 ; // duplicate, ignore
471 goto get_conversion_spec;
486 goto get_conversion_spec;
489 goto get_conversion_spec;
492 goto get_conversion_spec;
495 goto get_conversion_spec;
498 goto get_conversion_spec;
501 OUTPUT_CHAR( va_arg(ap,int), p );
505 PTR = va_arg(ap,ptr_t);
510 length=NULL_STRING_LENGTH;
512 length = strlen(PTR);
515 length = strlen(PTR);
517 if ( decimals == -1 )
521 if ( ( !left_justify ) && (length < width) )
524 while( width-- != 0 )
526 OUTPUT_CHAR( ' ', p );
530 while ( (c = *PTR) && (decimals-- > 0))
536 if ( left_justify && (length < width))
539 while( width-- != 0 )
541 OUTPUT_CHAR( ' ', p );
547 PTR = va_arg(ap,ptr_t);
549 #if defined (SDCC_ds390)
551 unsigned char memtype = value.byte[3];
554 else if (memtype > 0x60)
556 else if (memtype > 0x40)
565 OUTPUT_2DIGITS( value.byte[2] );
566 OUTPUT_2DIGITS( value.byte[1] );
567 OUTPUT_2DIGITS( value.byte[0] );
568 #elif defined (SDCC_mcs51)
570 unsigned char memtype = value.byte[2];
573 else if (memtype > 0x60)
575 else if (memtype > 0x40)
584 if ((c != 'I' /* idata */) &&
585 (c != 'P' /* pdata */))
587 OUTPUT_2DIGITS( value.byte[1] );
589 OUTPUT_2DIGITS( value.byte[0] );
593 OUTPUT_2DIGITS( value.byte[1] );
594 OUTPUT_2DIGITS( value.byte[0] );
621 // nothing special, just output the character
626 if (float_argument) {
627 value.f=va_arg(ap,float);
640 // ignore b and l conversion spec for now
641 #ifdef SDCC_STACK_AUTO
642 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
643 zero_padding, prefix_sign, prefix_space);
645 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
646 zero_padding, prefix_sign, prefix_space);
647 #endif //SDCC_STACK_AUTO
649 } else if (radix != 0)
651 // Apperently we have to output an integral type
652 // with radix "radix"
653 unsigned char store[6];
654 unsigned char _AUTOMEM *pstore = &store[5];
656 // store value in byte[0] (LSB) ... byte[3] (MSB)
659 value.l = va_arg(ap,char);
660 if (!signed_argument)
665 else if (long_argument)
667 value.l = va_arg(ap,long);
671 value.l = va_arg(ap,int);
672 if (!signed_argument)
678 if ( signed_argument )
691 #if defined SDCC_STACK_AUTO
692 calculate_digit(&value, radix);
694 calculate_digit(radix);
698 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
703 *pstore = value.byte[4];
711 // default width. We set it to 1 to output
712 // at least one character in case the value itself
713 // is zero (i.e. length==0)
717 /* prepend spaces if needed */
718 if (!zero_padding && !left_justify)
720 while ( width > (unsigned char) (length+1) )
722 OUTPUT_CHAR( ' ', p );
727 if (signed_argument) // this now means the original value was negative
729 OUTPUT_CHAR( '-', p );
730 // adjust width to compensate for this character
733 else if (length != 0)
738 OUTPUT_CHAR( '+', p );
739 // adjust width to compensate for this character
742 else if (prefix_space)
744 OUTPUT_CHAR( ' ', p );
745 // adjust width to compensate for this character
750 /* prepend zeroes/spaces if needed */
752 while ( width-- > length )
754 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
758 /* spaces are appended after the digits */
765 /* output the digits */
772 value.byte[4] = *pstore >> 4;
776 value.byte[4] = *pstore & 0x0F;
778 #ifdef SDCC_STACK_AUTO
779 output_digit( value.byte[4], lower_case, output_char, p );
782 output_digit( value.byte[4] );
794 // nothing special, just output the character
799 return charsOutputted;
802 /****************************************************************************/