Hackfix and re-enable strtoull and wcstoull, see bug #3798.
[sdcc.git] / sdcc / device / lib / printf_large.c
blob174f70c6f929eb7b0eb24ba0ab3f874791d97345
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
11 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
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,
21 MA 02110-1301, USA.
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)
32 #define USE_FLOATS 1
33 #endif
35 #include <stdarg.h>
36 #include <string.h>
37 #include <ctype.h>
38 #include <stdio.h>
39 #include <stdbit.h>
40 #include <sdcc-lib.h>
42 #define PTR value.ptr
44 #ifdef __SDCC_ds390
45 #define NULL_STRING "<NULL>"
46 #define NULL_STRING_LENGTH 6
47 #endif
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
52 #else
53 # define MEM_SPACE_BUF
54 # define MEM_SPACE_BUF_PP _AUTOMEM
55 #endif
57 /****************************************************************************/
59 //typedef const char * ptr_t;
60 #define ptr_t const char *
62 #ifdef toupper
63 #undef toupper
64 #endif
65 #ifdef tolower
66 #undef tolower
67 #endif
68 #ifdef islower
69 #undef islower
70 #endif
71 #ifdef isdigit
72 #undef isdigit
73 #endif
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')
81 typedef union
83 unsigned char byte[5];
84 long l;
85 unsigned long ul;
86 float f;
87 const char *ptr;
88 } value_t;
90 #ifndef __SDCC_STACK_AUTO
91 static _Bool lower_case;
92 static pfn_outputchar output_char;
93 static void* p;
94 static value_t value;
95 static int charsOutputted;
96 #endif
98 /****************************************************************************/
100 #ifdef __SDCC_STACK_AUTO
101 #define OUTPUT_CHAR(c, p) { output_char (c, p); charsOutputted++; }
102 #else
103 #define OUTPUT_CHAR(c, p) _output_char (c)
104 static void
105 _output_char (unsigned char c)
107 output_char( c, p );
108 charsOutputted++;
110 #endif
112 /*--------------------------------------------------------------------------*/
114 #ifdef __SDCC_STACK_AUTO
115 static void
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);
123 if (lower_case)
124 c += (unsigned char)('a' - 'A');
126 output_char( c, p );
128 #else
129 static void
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);
137 if (lower_case)
138 c = tolower(c);
140 _output_char( c );
142 #endif
144 /*--------------------------------------------------------------------------*/
146 #ifdef __SDCC_STACK_AUTO
147 #define OUTPUT_2DIGITS( B ) { output_2digits( B, lower_case, output_char, p ); charsOutputted += 2; }
148 static void
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 );
154 #else
155 #define OUTPUT_2DIGITS( B ) output_2digits( B )
156 static void
157 output_2digits (unsigned char b)
159 output_digit( b>>4 );
160 output_digit( b&0x0F );
162 #endif
164 /*--------------------------------------------------------------------------*/
166 #if defined __SDCC_STACK_AUTO
167 static void
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);
177 ul <<= 1;
179 if (radix <= *pb4 )
181 *pb4 -= radix;
182 ul |= 1;
184 } while (--i);
185 value->ul = ul;
187 #else
188 static void
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;
197 b4 = (b4 << 1);
198 b4 |= (ul >> 31) & 0x01;
199 ul <<= 1;
201 if (radix <= b4 )
203 b4 -= radix;
204 ul |= 1;
206 } while (--i);
207 value.ul = ul;
208 value.byte[4] = b4;
210 #endif
212 #if USE_FLOATS
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
219 applications.
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)
226 static unsigned char
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
235 #else
236 char fpBuffer[128];
237 #endif
238 #else
239 #define OUTPUT_FLOAT(F, W, D, L, Z, S, P) output_float(F, W, D, L, Z, S, P)
240 static void
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
247 _Bool negative = 0;
248 unsigned long integerPart;
249 float rounding;
250 float decimalPart;
251 char fpBI=0, fpBD;
252 unsigned char minWidth, i;
253 signed char exp = -128;
255 // save the sign
256 if (f<0)
258 negative=1;
259 f=-f;
262 if (f>0x00ffffff)
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;
269 if (negative)
271 OUTPUT_CHAR ('-', p);
273 else
275 if (sign)
277 OUTPUT_CHAR ('+', p);
280 reqWidth = 0;
281 left = 0;
282 zero = 0;
283 sign = 0;
284 space = 0;
287 // display some decimals as default
288 if (reqDecimals==-1)
289 reqDecimals=DEFAULT_FLOAT_PRECISION;
291 // round the float
292 rounding = 0.5;
293 for (i=reqDecimals; i>0; i--)
295 rounding /= 10.0;
297 f += rounding;
299 // split the float
300 integerPart = f;
301 decimalPart = f - integerPart;
303 // fill the buffer with the integerPart (in reversed order!)
304 while (integerPart)
306 fpBuffer[fpBI++]='0' + integerPart%10;
307 integerPart /= 10;
309 if (!fpBI)
311 // we need at least a 0
312 fpBuffer[fpBI++]='0';
315 // fill buffer with the decimalPart (in normal order)
316 fpBD=fpBI;
318 for (i=reqDecimals; i>0; i--)
320 decimalPart *= 10.0;
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)
334 if (zero)
336 if (negative)
338 OUTPUT_CHAR('-', p);
340 else if (sign)
342 OUTPUT_CHAR('+', p);
344 else if (space)
346 OUTPUT_CHAR(' ', p);
348 while (reqWidth-->minWidth)
350 OUTPUT_CHAR('0', p);
353 else
355 while (reqWidth-->minWidth)
357 OUTPUT_CHAR(' ', p);
359 if (negative)
361 OUTPUT_CHAR('-', p);
363 else if (sign)
365 OUTPUT_CHAR('+', p);
367 else if (space)
369 OUTPUT_CHAR(' ', p);
373 else
375 if (negative)
377 OUTPUT_CHAR('-', p);
379 else if (sign)
381 OUTPUT_CHAR('+', p);
383 else if (space)
385 OUTPUT_CHAR(' ', p);
389 // output the integer part
390 i=fpBI-1;
391 do {
392 OUTPUT_CHAR (fpBuffer[i], p);
393 } while (i--);
395 // output the decimal part
396 if (reqDecimals)
398 OUTPUT_CHAR ('.', p);
399 i=fpBI;
400 while (reqDecimals--)
402 OUTPUT_CHAR (fpBuffer[i++], p);
406 if (left && reqWidth>minWidth)
408 while (reqWidth-->minWidth)
410 OUTPUT_CHAR(' ', p);
414 if (exp != -128)
416 OUTPUT_CHAR ('e', p);
417 if (exp<0)
419 OUTPUT_CHAR ('-', p);
420 exp = -exp;
422 OUTPUT_CHAR ('0'+exp/10, p);
423 OUTPUT_CHAR ('0'+exp%10, p);
425 #ifdef __SDCC_STACK_AUTO
426 return charsOutputted;
427 #else
428 return;
429 #endif //__SDCC_STACK_AUTO
431 #endif //USE_FLOATS
434 _print_format (pfn_outputchar pfn, void* pvoid, const char *format, va_list ap)
436 _Bool left_justify;
437 _Bool zero_padding;
438 _Bool prefix_sign;
439 _Bool prefix_space;
440 _Bool signed_argument;
441 _Bool char_argument;
442 _Bool long_argument;
443 _Bool float_argument;
444 #ifdef __SDCC_STACK_AUTO
445 _Bool lower_case;
446 value_t value;
447 int charsOutputted;
448 #endif
449 _Bool lsd;
451 unsigned char radix;
452 size_t width;
453 int decimals;
454 size_t length;
455 char c;
457 #ifdef __SDCC_STACK_AUTO
458 #define output_char pfn
459 #define p pvoid
460 #else
461 output_char = pfn;
462 p = pvoid;
463 #endif
465 // reset output chars
466 charsOutputted = 0;
468 #ifdef __SDCC_ds390
469 if (format==0)
471 format=NULL_STRING;
473 #endif
475 while( c=*format++ )
477 if ( c=='%' )
479 left_justify = 0;
480 zero_padding = 0;
481 prefix_sign = 0;
482 prefix_space = 0;
483 signed_argument = 0;
484 char_argument = 0;
485 long_argument = 0;
486 float_argument = 0;
487 radix = 0;
488 width = 0;
489 decimals = -1;
491 get_conversion_spec:
493 c = *format++;
495 if (c=='%')
497 OUTPUT_CHAR(c, p);
498 continue;
501 if (isdigit(c))
503 if (decimals==-1)
505 width = 10*width + c - '0';
506 if (width == 0)
508 /* first character of width is a zero */
509 zero_padding = 1;
512 else
514 decimals = 10*decimals + c - '0';
516 goto get_conversion_spec;
519 if (c=='.')
521 if (decimals==-1)
522 decimals=0;
523 else
524 ; // duplicate, ignore
525 goto get_conversion_spec;
528 if (islower(c))
530 c = toupper(c);
531 lower_case = 1;
533 else
534 lower_case = 0;
536 switch( c )
538 case '-':
539 left_justify = 1;
540 goto get_conversion_spec;
541 case '+':
542 prefix_sign = 1;
543 goto get_conversion_spec;
544 case ' ':
545 prefix_space = 1;
546 goto get_conversion_spec;
547 case 'B': /* byte */
548 char_argument = 1;
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;
556 case 'L': /* long */
557 long_argument = 1;
558 goto get_conversion_spec;
560 case 'C':
561 if( char_argument )
562 c = va_arg(ap,char);
563 else
564 c = va_arg(ap,int);
565 OUTPUT_CHAR( c, p );
566 break;
568 case 'S':
569 PTR = va_arg(ap,ptr_t);
571 #ifdef __SDCC_ds390
572 if (PTR==0)
574 PTR=NULL_STRING;
575 length=NULL_STRING_LENGTH;
577 else
579 length = strlen(PTR);
581 #else
582 length = strlen(PTR);
583 #endif
584 if ( decimals == -1 )
586 decimals = length;
588 if ( ( !left_justify ) && (length < width) )
590 width -= length;
591 while( width-- != 0 )
593 OUTPUT_CHAR( ' ', p );
597 while ( (c = *PTR) && (decimals-- > 0))
599 OUTPUT_CHAR( c, p );
600 PTR++;
603 if ( left_justify && (length < width))
605 width -= length;
606 while( width-- != 0 )
608 OUTPUT_CHAR( ' ', p );
611 break;
613 case 'P':
614 PTR = va_arg(ap,ptr_t);
616 #if defined (__SDCC_ds390)
618 unsigned char memtype = value.byte[3];
619 if (memtype >= 0x80)
620 c = 'C';
621 else if (memtype >= 0x60)
622 c = 'P';
623 else if (memtype >= 0x40)
624 c = 'I';
625 else
626 c = 'X';
628 OUTPUT_CHAR(c, p);
629 OUTPUT_CHAR(':', p);
630 OUTPUT_CHAR('0', p);
631 OUTPUT_CHAR('x', p);
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];
638 if (memtype >= 0x80)
639 c = 'C';
640 else if (memtype >= 0x60)
641 c = 'P';
642 else if (memtype >= 0x40)
643 c = 'I';
644 else
645 c = 'X';
647 OUTPUT_CHAR(c, p);
648 OUTPUT_CHAR(':', p);
649 OUTPUT_CHAR('0', p);
650 OUTPUT_CHAR('x', p);
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__
658 OUTPUT_CHAR('0', p);
659 OUTPUT_CHAR('x', p);
660 OUTPUT_2DIGITS( value.byte[0] );
661 OUTPUT_2DIGITS( value.byte[1] );
662 #else
663 OUTPUT_CHAR('0', p);
664 OUTPUT_CHAR('x', p);
665 OUTPUT_2DIGITS( value.byte[1] );
666 OUTPUT_2DIGITS( value.byte[0] );
667 #endif
668 break;
670 case 'D':
671 case 'I':
672 signed_argument = 1;
673 radix = 10;
674 break;
676 case 'O':
677 radix = 8;
678 break;
680 case 'U':
681 radix = 10;
682 break;
684 case 'X':
685 radix = 16;
686 break;
688 case 'F':
689 float_argument=1;
690 break;
692 default:
693 // nothing special, just output the character
694 OUTPUT_CHAR( c, p );
695 break;
698 if (float_argument)
700 value.f = va_arg(ap, float);
701 #if !USE_FLOATS
702 PTR="<NO FLOAT>";
703 while (c=*PTR++)
705 OUTPUT_CHAR (c, p);
707 // treat as long hex
708 //radix=16;
709 //long_argument=1;
710 //zero_padding=1;
711 //width=8;
712 #else
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);
717 #else
718 OUTPUT_FLOAT(value.f, width, decimals, left_justify,
719 zero_padding, prefix_sign, prefix_space);
720 #endif //__SDCC_STACK_AUTO
721 #endif //USE_FLOATS
723 else if (radix != 0)
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)
731 if (char_argument)
733 value.l = va_arg(ap, char);
734 if (!signed_argument)
736 value.l &= 0xFF;
739 else if (long_argument)
741 value.l = va_arg(ap, long);
743 else // must be int
745 value.l = va_arg(ap, int);
746 if (!signed_argument)
748 value.l &= 0xFFFF;
752 if ( signed_argument )
754 if (value.l < 0)
755 value.l = -value.l;
756 else
757 signed_argument = 0;
760 length=0;
761 lsd = 1;
763 do {
764 value.byte[4] = 0;
765 #if defined __SDCC_STACK_AUTO
766 calculate_digit(&value, radix);
767 #else
768 calculate_digit(radix);
769 #endif
770 if (!lsd)
772 *pstore = (value.byte[4] << 4) | (value.byte[4] >> 4) | *pstore;
773 pstore--;
775 else
777 *pstore = value.byte[4];
779 length++;
780 lsd = !lsd;
781 } while( value.ul );
783 if (width == 0)
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)
788 width = 1;
791 /* prepend spaces if needed */
792 if (!zero_padding && !left_justify)
794 while ( width > (unsigned char) (length+1) )
796 OUTPUT_CHAR( ' ', p );
797 width--;
801 if (signed_argument) // this now means the original value was negative
803 OUTPUT_CHAR( '-', p );
804 // adjust width to compensate for this character
805 width--;
807 else if (length != 0)
809 // value > 0
810 if (prefix_sign)
812 OUTPUT_CHAR( '+', p );
813 // adjust width to compensate for this character
814 width--;
816 else if (prefix_space)
818 OUTPUT_CHAR( ' ', p );
819 // adjust width to compensate for this character
820 width--;
824 /* prepend zeroes/spaces if needed */
825 if (!left_justify)
827 while ( width-- > length )
829 OUTPUT_CHAR( zero_padding ? '0' : ' ', p );
832 else
834 /* spaces are appended after the digits */
835 if (width > length)
836 width -= length;
837 else
838 width = 0;
841 /* output the digits */
842 while( length-- )
844 lsd = !lsd;
845 if (!lsd)
847 pstore++;
848 value.byte[4] = *pstore >> 4;
850 else
852 value.byte[4] = *pstore & 0x0F;
854 #ifdef __SDCC_STACK_AUTO
855 output_digit( value.byte[4], lower_case, output_char, p );
856 charsOutputted++;
857 #else
858 output_digit( value.byte[4] );
859 #endif
861 if (left_justify)
863 while (width-- > 0)
865 OUTPUT_CHAR(' ', p);
870 else
872 // nothing special, just output the character
873 OUTPUT_CHAR( c, p );
877 return charsOutputted;
880 /****************************************************************************/