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;
60 //#define toupper(c) ((c)&=~0x20)
61 #define toupper(c) ((c)&=0xDF)
62 #define tolower(c) ((c)|=0x20)
63 #define isdigit(c) ((unsigned char)c >= (unsigned char)'0' && (unsigned char)c <= (unsigned char)'9')
67 unsigned char byte[5];
74 #ifndef SDCC_STACK_AUTO
75 static BOOL lower_case;
76 static pfn_outputchar output_char;
79 static int charsOutputted;
82 /****************************************************************************/
84 #ifdef SDCC_STACK_AUTO
85 #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
87 #define OUTPUT_CHAR(c, p) _output_char (c)
88 static void _output_char( unsigned char c )
95 /*--------------------------------------------------------------------------*/
97 #ifdef SDCC_STACK_AUTO
98 static void output_digit( unsigned char n, BOOL lower_case, pfn_outputchar output_char, void* p )
100 register unsigned char c = n + (unsigned char)'0';
102 if (c > (unsigned char)'9')
104 c += (unsigned char)('A' - '0' - 10);
106 c += (unsigned char)('a' - 'A');
111 static void output_digit( unsigned char n )
113 register unsigned char c = n + (unsigned char)'0';
115 if (c > (unsigned char)'9')
117 c += (unsigned char)('A' - '0' - 10);
125 /*--------------------------------------------------------------------------*/
127 #ifdef SDCC_STACK_AUTO
128 #define OUTPUT_2DIGITS( B ) { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
129 static void output_2digits( unsigned char b, BOOL lower_case, pfn_outputchar output_char, void* p )
131 output_digit( b>>4, lower_case, output_char, p );
132 output_digit( b&0x0F, lower_case, output_char, p );
135 #define OUTPUT_2DIGITS( B ) output_2digits( B )
136 static void output_2digits( unsigned char b )
138 output_digit( b>>4 );
139 output_digit( b&0x0F );
143 /*--------------------------------------------------------------------------*/
145 #if defined SDCC_STACK_AUTO
146 static void calculate_digit( value_t _AUTOMEM * value, unsigned char radix )
148 unsigned long ul = value->ul;
149 unsigned char _AUTOMEM * pb4 = &value->byte[4];
150 unsigned char i = 32;
154 *pb4 = (*pb4 << 1) | ((ul >> 31) & 0x01);
166 static void calculate_digit( unsigned char radix )
168 register unsigned long ul = value.ul;
169 register unsigned char b4 = value.byte[4];
170 register unsigned char i = 32;
175 b4 |= (ul >> 31) & 0x01;
191 /* This is a very inefficient but direct approach, since we have no math
192 library yet (e.g. log()).
193 It does most of the modifiers, but has some restrictions. E.g. the
194 abs(float) shouldn't be bigger than an unsigned long (that's
195 about 4294967295), but still makes it usefull for most real-life
199 #define DEFAULT_FLOAT_PRECISION 6
201 #ifdef SDCC_STACK_AUTO
202 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
204 output_float (float f, unsigned char reqWidth,
205 signed char reqDecimals,
206 BOOL left, BOOL zero, BOOL sign, BOOL space,
207 pfn_outputchar output_char, void* p)
209 unsigned char charsOutputted = 0;
211 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
213 output_float (float f, unsigned char reqWidth,
214 signed char reqDecimals,
215 BOOL left, BOOL zero, BOOL sign, BOOL space)
217 #endif //SDCC_STACK_AUTO
219 unsigned long integerPart;
223 unsigned char minWidth, i;
232 // this part is from Frank van der Hulst
235 for (exp = 0; f >= 10.0; exp++) f /=10.0;
236 for ( ; f < 1.0; exp--) f *=10.0;
239 OUTPUT_CHAR ('-', p);
242 OUTPUT_CHAR ('+', p);
245 #ifdef SDCC_STACK_AUTO
246 charsOutputted += OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
248 OUTPUT_FLOAT(f, 0, reqDecimals, 0, 0, 0, 0);
250 OUTPUT_CHAR ('e', p);
252 OUTPUT_CHAR ('-', p);
255 OUTPUT_CHAR ('0'+exp/10, p);
256 OUTPUT_CHAR ('0'+exp%10, p);
257 #ifdef SDCC_STACK_AUTO
258 return charsOutputted;
261 #endif //SDCC_STACK_AUTO
266 decimalPart=f-integerPart;
268 // fill the buffer with the integerPart (in reversed order!)
269 while (integerPart) {
270 fpBuffer[fpBI++]='0' + integerPart%10;
274 // we need at least a 0
275 fpBuffer[fpBI++]='0';
278 // display some decimals as default
280 reqDecimals=DEFAULT_FLOAT_PRECISION;
282 // fill buffer with the decimalPart (in normal order)
285 for (i=reqDecimals; i>1; i--) {
287 // truncate the float
288 integerPart=decimalPart;
289 fpBuffer[fpBD++]='0' + integerPart;
290 decimalPart-=integerPart;
294 // truncate the float
295 integerPart = decimalPart + 0.5;
296 fpBuffer[fpBD++] = '0' + integerPart;
299 minWidth=fpBI; // we need at least these
300 minWidth+=reqDecimals?reqDecimals+1:0; // maybe these
301 if (negative || sign || space)
302 minWidth++; // and maybe even this :)
304 if (!left && reqWidth>i) {
318 while (reqWidth-->minWidth)
323 while (reqWidth-->minWidth)
355 // output the integer part
358 OUTPUT_CHAR (fpBuffer[i], p);
361 // ouput the decimal part
363 OUTPUT_CHAR ('.', p);
365 while (reqDecimals--)
367 OUTPUT_CHAR (fpBuffer[i++], p);
371 if (left && reqWidth>minWidth) {
372 while (reqWidth-->minWidth)
377 #ifdef SDCC_STACK_AUTO
378 return charsOutputted;
381 #endif //SDCC_STACK_AUTO
385 int _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
391 BOOL signed_argument;
395 #ifdef SDCC_STACK_AUTO
404 signed char decimals;
405 unsigned char length;
408 #ifdef SDCC_STACK_AUTO
409 #define output_char pfn
416 // reset output chars
452 width = 10*width + (c - '0');
454 /* first character of width is a zero */
458 decimals = 10*decimals + (c-'0');
460 goto get_conversion_spec;
464 if (decimals=-1) decimals=0;
466 ; // duplicate, ignore
467 goto get_conversion_spec;
470 lower_case = islower(c);
480 goto get_conversion_spec;
483 goto get_conversion_spec;
486 goto get_conversion_spec;
489 goto get_conversion_spec;
492 goto get_conversion_spec;
495 OUTPUT_CHAR( va_arg(ap,int), p );
499 PTR = va_arg(ap,ptr_t);
504 length=NULL_STRING_LENGTH;
506 length = strlen(PTR);
509 length = strlen(PTR);
511 if ( decimals == -1 )
515 if ( ( !left_justify ) && (length < width) )
518 while( width-- != 0 )
520 OUTPUT_CHAR( ' ', p );
524 while ( *PTR && (decimals-- > 0))
526 OUTPUT_CHAR( *PTR++, p );
529 if ( left_justify && (length < width))
532 while( width-- != 0 )
534 OUTPUT_CHAR( ' ', p );
540 PTR = va_arg(ap,ptr_t);
542 #if defined (SDCC_ds390)
544 unsigned char memtype = value.byte[3];
547 else if (memtype > 0x60)
549 else if (memtype > 0x40)
558 OUTPUT_2DIGITS( value.byte[2] );
559 OUTPUT_2DIGITS( value.byte[1] );
560 OUTPUT_2DIGITS( value.byte[0] );
561 #elif defined (SDCC_mcs51)
563 unsigned char memtype = value.byte[2];
566 else if (memtype > 0x60)
568 else if (memtype > 0x40)
577 if ((c != 'I' /* idata */) &&
578 (c != 'P' /* pdata */))
580 OUTPUT_2DIGITS( value.byte[1] );
582 OUTPUT_2DIGITS( value.byte[0] );
586 OUTPUT_2DIGITS( value.byte[1] );
587 OUTPUT_2DIGITS( value.byte[0] );
614 // nothing special, just output the character
619 if (float_argument) {
620 value.f=va_arg(ap,float);
633 // ignore b and l conversion spec for now
634 #ifdef SDCC_STACK_AUTO
635 charsOutputted += OUTPUT_FLOAT(value.f, width, decimals, left_justify,
636 zero_padding, prefix_sign, prefix_space);
638 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
639 zero_padding, prefix_sign, prefix_space);
640 #endif //SDCC_STACK_AUTO
642 } else if (radix != 0)
644 // Apperently we have to output an integral type
645 // with radix "radix"
646 unsigned char store[6];
647 unsigned char _AUTOMEM *pstore = &store[5];
649 // store value in byte[0] (LSB) ... byte[3] (MSB)
652 value.l = va_arg(ap,char);
653 if (!signed_argument)
658 else if (long_argument)
660 value.l = va_arg(ap,long);
664 value.l = va_arg(ap,int);
665 if (!signed_argument)
671 if ( signed_argument )
684 #if defined SDCC_STACK_AUTO
685 calculate_digit(&value, radix);
687 calculate_digit(radix);
691 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
696 *pstore = value.byte[4];
704 // default width. We set it to 1 to output
705 // at least one character in case the value itself
706 // is zero (i.e. length==0)
710 /* prepend spaces if needed */
711 if (!zero_padding && !left_justify)
713 while ( width > (unsigned char) (length+1) )
715 OUTPUT_CHAR( ' ', p );
720 if (signed_argument) // this now means the original value was negative
722 OUTPUT_CHAR( '-', p );
723 // adjust width to compensate for this character
726 else if (length != 0)
731 OUTPUT_CHAR( '+', p );
732 // adjust width to compensate for this character
735 else if (prefix_space)
737 OUTPUT_CHAR( ' ', p );
738 // adjust width to compensate for this character
743 /* prepend zeroes/spaces if needed */
745 while ( width-- > length )
747 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
751 /* spaces are appended after the digits */
758 /* output the digits */
765 value.byte[4] = *pstore >> 4;
769 value.byte[4] = *pstore & 0x0F;
771 #ifdef SDCC_STACK_AUTO
772 output_digit( value.byte[4], lower_case, output_char, p );
775 output_digit( value.byte[4] );
787 // nothing special, just output the character
792 return charsOutputted;
795 /****************************************************************************/