1 /*-----------------------------------------------------------------
2 printf_large.c - formatted output conversion
4 Copyright (C) 1999, Martijn van Balen <aed AT iae.nl>
5 Added %f By - <johan.knol AT iduna.nl> (2000)
6 Refactored by - Maarten Brock (2004)
8 This library is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
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
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this library; see the file COPYING. If not, write to the
20 Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
23 As a special exception, if you link this library with other files,
24 some of which are compiled with SDCC, to produce an executable,
25 this library does not by itself cause the resulting executable to
26 be covered by the GNU General Public License. This exception does
27 not however invalidate any other reasons why the executable file
28 might be covered by the GNU General Public License.
29 -------------------------------------------------------------------------*/
31 #if defined (__SDCC_ds390) || defined (__SDCC_USE_XSTACK) || defined (__SDCC_MODEL_HUGE)
45 #define NULL_STRING "<NULL>"
46 #define NULL_STRING_LENGTH 6
49 #if defined (__SDCC_mcs51) && defined (__SDCC_MODEL_SMALL) && !defined (__SDCC_STACK_AUTO)
50 # define MEM_SPACE_BUF __idata
51 # define MEM_SPACE_BUF_PP __idata
53 # define MEM_SPACE_BUF
54 # define MEM_SPACE_BUF_PP _AUTOMEM
57 /****************************************************************************/
59 //typedef const char * ptr_t;
60 #define ptr_t const char *
75 //#define toupper(c) ((c)&=~0x20)
76 #define toupper(c) ((c)&=0xDF)
77 #define tolower(c) ((c)|=0x20)
78 #define islower(c) ((unsigned char)c >= (unsigned char)'a' && (unsigned char)c <= (unsigned char)'z')
79 #define isdigit(c) ((unsigned char)c >= (unsigned char)'0' && (unsigned char)c <= (unsigned char)'9')
83 unsigned char byte
[5];
90 #ifndef __SDCC_STACK_AUTO
91 static _Bool lower_case
;
92 static pfn_outputchar output_char
;
95 static int charsOutputted
;
98 /****************************************************************************/
100 #ifdef __SDCC_STACK_AUTO
101 #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
103 #define OUTPUT_CHAR(c, p) _output_char (c)
105 _output_char (unsigned char c
)
112 /*--------------------------------------------------------------------------*/
114 #ifdef __SDCC_STACK_AUTO
116 output_digit (unsigned char n
, _Bool lower_case
, pfn_outputchar output_char
, void* p
)
118 register unsigned char c
= n
+ (unsigned char)'0';
120 if (c
> (unsigned char)'9')
122 c
+= (unsigned char)('A' - '0' - 10);
124 c
+= (unsigned char)('a' - 'A');
130 output_digit (unsigned char n
)
132 register unsigned char c
= n
+ (unsigned char)'0';
134 if (c
> (unsigned char)'9')
136 c
+= (unsigned char)('A' - '0' - 10);
144 /*--------------------------------------------------------------------------*/
146 #ifdef __SDCC_STACK_AUTO
147 #define OUTPUT_2DIGITS( B ) { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
149 output_2digits (unsigned char b
, _Bool lower_case
, pfn_outputchar output_char
, void* p
)
151 output_digit( b
>>4, lower_case
, output_char
, p
);
152 output_digit( b
&0x0F, lower_case
, output_char
, p
);
155 #define OUTPUT_2DIGITS( B ) output_2digits( B )
157 output_2digits (unsigned char b
)
159 output_digit( b
>>4 );
160 output_digit( b
&0x0F );
164 /*--------------------------------------------------------------------------*/
166 #if defined __SDCC_STACK_AUTO
168 calculate_digit (value_t _AUTOMEM
* value
, unsigned char radix
)
170 unsigned long ul
= value
->ul
;
171 unsigned char _AUTOMEM
* pb4
= &value
->byte
[4];
172 unsigned char i
= 32;
176 *pb4
= (*pb4
<< 1) | ((ul
>> 31) & 0x01);
189 calculate_digit (unsigned char radix
)
191 register unsigned long ul
= value
.ul
;
192 register unsigned char b4
= value
.byte
[4];
193 register unsigned char i
= 32;
198 b4
|= (ul
>> 31) & 0x01;
214 /* This is a very inefficient but direct approach, since we have no math
215 library yet (e.g. log()).
216 It does most of the modifiers, but has some restrictions. E.g. the
217 abs(float) shouldn't be bigger than an unsigned long (that's
218 about 4294967295), but still makes it useful for most real-life
222 #define DEFAULT_FLOAT_PRECISION 6
224 #ifdef __SDCC_STACK_AUTO
225 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P, output_char, p)
227 output_float (float f
, unsigned char reqWidth
,
228 signed char reqDecimals
,
229 _Bool left
, _Bool zero
, _Bool sign
, _Bool space
,
230 pfn_outputchar output_char
, void* p
)
232 unsigned char charsOutputted
= 0;
233 #if defined (__SDCC_mcs51)
234 char fpBuffer
[16]; //mcs51 has only a small stack
239 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
241 output_float (float f
, unsigned char reqWidth
,
242 signed char reqDecimals
,
243 _Bool left
, _Bool zero
, _Bool sign
, _Bool space
)
245 __xdata
char fpBuffer
[128];
246 #endif //__SDCC_STACK_AUTO
248 unsigned long integerPart
;
252 unsigned char minWidth
, i
;
253 signed char exp
= -128;
264 // this part is from Frank van der Hulst
266 for (exp
= 0; f
>= 10.0; exp
++) f
/=10.0;
267 for ( ; f
< 1.0; exp
--) f
*=10.0;
271 OUTPUT_CHAR ('-', p
);
277 OUTPUT_CHAR ('+', p
);
287 // display some decimals as default
289 reqDecimals
=DEFAULT_FLOAT_PRECISION
;
293 for (i
=reqDecimals
; i
>0; i
--)
301 decimalPart
= f
- integerPart
;
303 // fill the buffer with the integerPart (in reversed order!)
306 fpBuffer
[fpBI
++]='0' + integerPart
%10;
311 // we need at least a 0
312 fpBuffer
[fpBI
++]='0';
315 // fill buffer with the decimalPart (in normal order)
318 for (i
=reqDecimals
; i
>0; i
--)
321 // truncate the float
322 integerPart
= decimalPart
;
323 fpBuffer
[fpBD
++] = '0' + integerPart
;
324 decimalPart
-= integerPart
;
327 minWidth
=fpBI
; // we need at least these
328 minWidth
+=reqDecimals
?reqDecimals
+1:0; // maybe these
329 if (negative
|| sign
|| space
)
330 minWidth
++; // and maybe even this :)
332 if (!left
&& reqWidth
>i
)
348 while (reqWidth
-->minWidth
)
355 while (reqWidth
-->minWidth
)
389 // output the integer part
392 OUTPUT_CHAR (fpBuffer
[i
], p
);
395 // output the decimal part
398 OUTPUT_CHAR ('.', p
);
400 while (reqDecimals
--)
402 OUTPUT_CHAR (fpBuffer
[i
++], p
);
406 if (left
&& reqWidth
>minWidth
)
408 while (reqWidth
-->minWidth
)
416 OUTPUT_CHAR ('e', p
);
419 OUTPUT_CHAR ('-', p
);
422 OUTPUT_CHAR ('0'+exp
/10, p
);
423 OUTPUT_CHAR ('0'+exp
%10, p
);
425 #ifdef __SDCC_STACK_AUTO
426 return charsOutputted
;
429 #endif //__SDCC_STACK_AUTO
434 _print_format (pfn_outputchar pfn
, void* pvoid
, const char *format
, va_list ap
)
440 _Bool signed_argument
;
443 _Bool float_argument
;
444 #ifdef __SDCC_STACK_AUTO
457 #ifdef __SDCC_STACK_AUTO
458 #define output_char pfn
465 // reset output chars
505 width
= 10*width
+ c
- '0';
508 /* first character of width is a zero */
514 decimals
= 10*decimals
+ c
- '0';
516 goto get_conversion_spec
;
524 ; // duplicate, ignore
525 goto get_conversion_spec
;
540 goto get_conversion_spec
;
543 goto get_conversion_spec
;
546 goto get_conversion_spec
;
549 goto get_conversion_spec
;
550 // case '#': /* not supported */
551 case 'H': /* short */
552 case 'J': /* intmax_t */
553 case 'T': /* ptrdiff_t */
554 case 'Z': /* size_t */
555 goto get_conversion_spec
;
558 goto get_conversion_spec
;
569 PTR
= va_arg(ap
,ptr_t
);
575 length
=NULL_STRING_LENGTH
;
579 length
= strlen(PTR
);
582 length
= strlen(PTR
);
584 if ( decimals
== -1 )
588 if ( ( !left_justify
) && (length
< width
) )
591 while( width
-- != 0 )
593 OUTPUT_CHAR( ' ', p
);
597 while ( (c
= *PTR
) && (decimals
-- > 0))
603 if ( left_justify
&& (length
< width
))
606 while( width
-- != 0 )
608 OUTPUT_CHAR( ' ', p
);
614 PTR
= va_arg(ap
,ptr_t
);
616 #if defined (__SDCC_ds390)
618 unsigned char memtype
= value
.byte
[3];
621 else if (memtype
>= 0x60)
623 else if (memtype
>= 0x40)
632 OUTPUT_2DIGITS( value
.byte
[2] );
633 OUTPUT_2DIGITS( value
.byte
[1] );
634 OUTPUT_2DIGITS( value
.byte
[0] );
635 #elif defined (__SDCC_mcs51)
637 unsigned char memtype
= value
.byte
[2];
640 else if (memtype
>= 0x60)
642 else if (memtype
>= 0x40)
651 if ((c
!= 'I' /* idata */) &&
652 (c
!= 'P' /* pdata */))
654 OUTPUT_2DIGITS( value
.byte
[1] );
656 OUTPUT_2DIGITS( value
.byte
[0] );
657 #elif __STDC_ENDIAN_NATIVE__ == __STDC_ENDIAN_BIG__
660 OUTPUT_2DIGITS( value
.byte
[0] );
661 OUTPUT_2DIGITS( value
.byte
[1] );
665 OUTPUT_2DIGITS( value
.byte
[1] );
666 OUTPUT_2DIGITS( value
.byte
[0] );
693 // nothing special, just output the character
700 value
.f
= va_arg(ap
, float);
713 // ignore b and l conversion spec for now
714 #ifdef __SDCC_STACK_AUTO
715 charsOutputted
+= OUTPUT_FLOAT(value
.f
, width
, decimals
, left_justify
,
716 zero_padding
, prefix_sign
, prefix_space
);
718 OUTPUT_FLOAT(value
.f
, width
, decimals
, left_justify
,
719 zero_padding
, prefix_sign
, prefix_space
);
720 #endif //__SDCC_STACK_AUTO
725 // Apparently we have to output an integral type
726 // with radix "radix"
727 unsigned char MEM_SPACE_BUF store
[6];
728 unsigned char MEM_SPACE_BUF_PP
*pstore
= &store
[5];
730 // store value in byte[0] (LSB) ... byte[3] (MSB)
733 value
.l
= va_arg(ap
, char);
734 if (!signed_argument
)
739 else if (long_argument
)
741 value
.l
= va_arg(ap
, long);
745 value
.l
= va_arg(ap
, int);
746 if (!signed_argument
)
752 if ( signed_argument
)
765 #if defined __SDCC_STACK_AUTO
766 calculate_digit(&value
, radix
);
768 calculate_digit(radix
);
772 *pstore
= (value
.byte
[4] << 4) | (value
.byte
[4] >> 4) | *pstore
;
777 *pstore
= value
.byte
[4];
785 // default width. We set it to 1 to output
786 // at least one character in case the value itself
787 // is zero (i.e. length==0)
791 /* prepend spaces if needed */
792 if (!zero_padding
&& !left_justify
)
794 while ( width
> (unsigned char) (length
+1) )
796 OUTPUT_CHAR( ' ', p
);
801 if (signed_argument
) // this now means the original value was negative
803 OUTPUT_CHAR( '-', p
);
804 // adjust width to compensate for this character
807 else if (length
!= 0)
812 OUTPUT_CHAR( '+', p
);
813 // adjust width to compensate for this character
816 else if (prefix_space
)
818 OUTPUT_CHAR( ' ', p
);
819 // adjust width to compensate for this character
824 /* prepend zeroes/spaces if needed */
827 while ( width
-- > length
)
829 OUTPUT_CHAR( zero_padding
? '0' : ' ', p
);
834 /* spaces are appended after the digits */
841 /* output the digits */
848 value
.byte
[4] = *pstore
>> 4;
852 value
.byte
[4] = *pstore
& 0x0F;
854 #ifdef __SDCC_STACK_AUTO
855 output_digit( value
.byte
[4], lower_case
, output_char
, p
);
858 output_digit( value
.byte
[4] );
872 // nothing special, just output the character
877 return charsOutputted
;
880 /****************************************************************************/