2 * COPYRIGHT: See COPYING in the top level directory
3 * PURPOSE: CRT's vsnprintf
4 * FILE: lib/sdk/crt/stdio/lnx_printf.c
5 * PROGRAMERS: David Welch
9 * - Verify the implementation of '%Z'.
13 * Parts from linux/lib/vsprintf.c
14 * Lars Wirzenius & Linus Torvalds
15 * Wirzenius wrote this portably, Torvalds fucked it up :-)
17 #ifndef USE_NEW_SPRINTF
23 #define ZEROPAD 1 /* pad with zero */
24 #define SIGN 2 /* unsigned/signed */
25 #define PLUS 4 /* show plus */
26 #define SPACE 8 /* space if plus */
27 #define LEFT 16 /* left justified */
28 #define SPECIAL 32 /* 0x */
29 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
30 #define ZEROTRUNC 128 /* truncate zero's */
31 #define REMOVEHEX 256 /* remove 0x from BASE 16 */
36 do_div(long long *n
, int base
)
39 a
= ((unsigned long long) *n
) % (unsigned) base
;
40 *n
= ((unsigned long long) *n
) / (unsigned) base
;
45 static int skip_atoi(const char **s
)
50 i
= i
*10 + *((*s
)++) - '0';
56 number(char * buf
, char * end
, long long num
, int base
, int size
, int precision
, int type
)
60 const char *small_digits
= "0123456789abcdefghijklmnopqrstuvwxyz";
61 const char *large_digits
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
64 digits
= (type
& LARGE
) ? large_digits
: small_digits
;
67 if (base
< 2 || base
> 36)
69 c
= (type
& ZEROPAD
) ? '0' : ' ';
76 } else if (type
& PLUS
) {
79 } else if (type
& SPACE
) {
85 if ((type
& SPECIAL
) && ((type
& REMOVEHEX
) == 0)) {
90 if ((num
== 0) && (precision
!=0))
93 tmp
[i
++] = digits
[do_div(&num
,base
)];
97 if (!(type
&(ZEROPAD
+LEFT
))) {
110 if ((type
& SPECIAL
) && ((type
& REMOVEHEX
) == 0)) {
121 if (!(type
& LEFT
)) {
128 while (i
< precision
--) {
148 unsigned int mantissal
:32;
149 unsigned int mantissah
:20;
150 unsigned int exponent
:11;
154 static __inline
void fracrnd(double *number
, int prec
)
156 /* Shifts fractional digits to decimal places and compares to round table */
157 /* Only suitable to determine the exponent with more precision, not for normal rounding */
158 /* Incoming numbers are expected to range from approx -10.0 to 10.0 */
159 int lpos
= 1, ubound
, sign
= 1;
160 long decimal
= abs((long)*number
);
161 double frac
= (*number
- decimal
) * 10;
180 ubound
= min(prec
, sizeof(rt
)/sizeof(*rt
) - 1);
181 while ((long)frac
% 10 != 0 && lpos
< ubound
)
186 if (abs((long)frac
) == rt
[lpos
])
188 *number
= sign
* (decimal
+ 1);
193 numberf(char * buf
, char * end
, double num
, char exp_sign
, int size
, int precision
, int type
)
195 double exponent
= 0.0;
204 double num2
, frac
, intr
;
207 char c
, sign
, digits
[66];
218 if ( exp_sign
== 'g' || exp_sign
== 'G' || exp_sign
== 'e' || exp_sign
== 'E' )
220 ie
= ((unsigned int)n
.n
->exponent
- (unsigned int)0x3ff);
223 exponent
= ie
/3.321928;
227 if ( exp_sign
== 'g' || exp_sign
== 'G' )
230 if ( exponent
< -4 || fabs(exponent
) >= precision
)
231 exp_sign
-= 2; // g -> e and G -> E
234 if (type
& SPECIAL
) precision
--;
237 if ( exp_sign
== 'e' || exp_sign
== 'E' )
241 /* Find a suitable exponent */
242 frac
= modf(exponent
, &e
);
243 num2
= num
/pow(10.0L, (long double)e
);
244 /* Check if rounding is possible */
245 fracrnd(&num2
, precision
);
246 if (num2
< 1.0 && num2
> -1.0)
250 else if (num2
<= -10.0 || num2
>= 10.0)
256 /* size-5 because "e+abc" is going to follow */
257 buf
= numberf(buf
, end
, num
/pow(10.0L,(long double)e
), 'f', size
-5, precision
, type
);
259 while(*(buf
-1) == ' ')
271 type
= LEFT
| SIGN
| PLUS
;
272 buf
= number(buf
, end
, ie
, 10, isize
, 3, type
);
276 if ( exp_sign
== 'f' )
281 c
= (type
& ZEROPAD
) ? '0' : ' ';
290 else if (type
& PLUS
)
295 else if (type
& SPACE
)
301 frac
= modf(num
,&intr
);
303 // # flags forces a . and prevents truncation of trailing zero's
310 frac
= modf(frac
, &p
);
311 digits
[i
] = (int)p
+ '0';
319 if ( precision
>= 1 || type
& SPECIAL
)
346 digits
[i
++] = (int)p
+ '0';
352 while ( j
< i
&& ro
== 1)
354 if ( digits
[j
] >= '0' && digits
[j
] <= '8' )
359 else if ( digits
[j
] == '9' )
370 if (!(type
& (ZEROPAD
+LEFT
)))
386 if (!(type
& (ZEROPAD
+LEFT
)))
407 if ( type
& ZEROTRUNC
&& ((type
& SPECIAL
) != SPECIAL
) )
410 while ( j
< i
&& ( *tmp
== '0' || *tmp
== '.' ))
433 string(char* buf
, char* end
, const char* s
, int len
, int field_width
, int precision
, int flags
)
438 c
= (flags
& ZEROPAD
) ? '0' : ' ';
450 while ((unsigned int)len
< (unsigned int)precision
&& s
[len
])
455 if ((unsigned int)len
> (unsigned int)precision
)
460 while (len
< field_width
--)
466 for (i
= 0; i
< len
; ++i
)
472 while (len
< field_width
--)
482 stringw(char* buf
, char* end
, const wchar_t* sw
, int len
, int field_width
, int precision
, int flags
)
487 c
= (flags
& ZEROPAD
) ? '0' : ' ';
499 while ((unsigned int)len
< (unsigned int)precision
&& sw
[len
])
504 if ((unsigned int)len
> (unsigned int)precision
)
509 while (len
< field_width
--)
515 for (i
= 0; i
< len
; ++i
)
518 *buf
= (unsigned char)(*sw
++);
521 while (len
< field_width
--)
533 int __cdecl
lnx_vsnprintf(char *buf
, size_t cnt
, const char *fmt
, va_list args
)
536 unsigned long long num
;
544 int flags
; /* flags to number() */
546 int field_width
; /* width of output field */
547 int precision
; /* min. # of digits for integers; max
548 number of chars for from string */
549 int qualifier
; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
558 for ( ; *fmt
; ++fmt
) {
569 ++fmt
; /* this also skips first '%' */
571 case '-': flags
|= LEFT
; goto repeat
;
572 case '+': flags
|= PLUS
; goto repeat
;
573 case ' ': flags
|= SPACE
; goto repeat
;
574 case '#': flags
|= SPECIAL
; goto repeat
;
575 case '0': flags
|= ZEROPAD
; goto repeat
;
578 /* get field width */
581 field_width
= skip_atoi(&fmt
);
582 else if (*fmt
== '*') {
584 /* it's the next argument */
585 field_width
= va_arg(args
, int);
586 if (field_width
< 0) {
587 field_width
= -field_width
;
592 /* get the precision */
597 precision
= skip_atoi(&fmt
);
598 else if (*fmt
== '*') {
600 /* it's the next argument */
601 precision
= va_arg(args
, int);
607 /* get the conversion qualifier */
609 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' || *fmt
== 'w') {
612 } else if (*fmt
== 'I' && *(fmt
+1) == '6' && *(fmt
+2) == '4') {
615 } else if (*fmt
== 'I' && *(fmt
+1) == '3' && *(fmt
+2) == '2') {
618 } else if (*fmt
== 'F' && *(fmt
+1) == 'p') {
627 case 'c': /* finished */
628 if (qualifier
== 'l' || qualifier
== 'w') {
630 /* print unicode string */
631 sw1
[0] = (wchar_t) va_arg(args
, int);
633 str
= stringw(str
, end
, (wchar_t *)&sw1
, -1, field_width
, precision
, flags
);
636 /* print ascii string */
637 s1
[0] = ( unsigned char) va_arg(args
, int);
639 str
= string(str
, end
, (char *)&s1
, -1, field_width
, precision
, flags
);
643 case 'C': /* finished */
645 while (--field_width
> 0) {
650 if (qualifier
== 'h') {
652 *str
= (unsigned char) va_arg(args
, int);
656 *str
= (unsigned char)(wchar_t) va_arg(args
, int);
659 while (--field_width
> 0) {
666 case 's': /* finished */
667 if (qualifier
== 'l' || qualifier
== 'w') {
668 /* print unicode string */
669 sw
= va_arg(args
, wchar_t *);
670 str
= stringw(str
, end
, sw
, -1, field_width
, precision
, flags
);
672 /* print ascii string */
673 s
= va_arg(args
, char *);
674 str
= string(str
, end
, s
, -1, field_width
, precision
, flags
);
679 if (qualifier
== 'h') {
680 /* print ascii string */
681 s
= va_arg(args
, char *);
682 str
= string(str
, end
, s
, -1, field_width
, precision
, flags
);
684 /* print unicode string */
685 sw
= va_arg(args
, wchar_t *);
686 str
= stringw(str
, end
, sw
, -1, field_width
, precision
, flags
);
691 if (qualifier
== 'w') {
692 /* print counted unicode string */
693 PUNICODE_STRING pus
= va_arg(args
, PUNICODE_STRING
);
694 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
699 len
= pus
->Length
/ sizeof(WCHAR
);
701 str
= stringw(str
, end
, sw
, len
, field_width
, precision
, flags
);
703 /* print counted ascii string */
704 PANSI_STRING pus
= va_arg(args
, PANSI_STRING
);
705 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
712 str
= string(str
, end
, s
, len
, field_width
, precision
, flags
);
717 if ((flags
& LARGE
) == 0)
720 if (field_width
== -1) {
721 field_width
= 2 * sizeof(void *);
724 str
= number(str
, end
,
725 (uintptr_t) va_arg(args
, void *), 16,
726 field_width
, precision
, flags
);
730 /* FIXME: What does C99 say about the overflow case here? */
731 if (qualifier
== 'l') {
732 long * ip
= va_arg(args
, long *);
735 int * ip
= va_arg(args
, int *);
740 /* float number formats - set up the flags and "break" */
746 _double
= (double)va_arg(args
, double);
747 if ( _isnan(_double
) ) {
756 } else if ( _isinf(_double
) < 0 ) {
765 } else if ( _isinf(_double
) > 0 ) {
775 if ( precision
== -1 )
777 str
= numberf(str
, end
, _double
, *fmt
, field_width
, precision
, flags
);
781 /* integer number formats - set up the flags and "break" */
812 if (qualifier
== 'I')
813 num
= va_arg(args
, unsigned long long);
814 else if (qualifier
== 'l') {
816 num
= va_arg(args
, long);
818 num
= va_arg(args
, unsigned long);
820 else if (qualifier
== 'h') {
822 num
= va_arg(args
, int);
824 num
= va_arg(args
, unsigned int);
828 num
= va_arg(args
, int);
830 num
= va_arg(args
, unsigned int);
832 str
= number(str
, end
, num
, base
, field_width
, precision
, flags
);
837 /* don't write out a null byte if the buf size is zero */
846 int lnx_sprintf(char * buf
, const char *fmt
, ...)
852 i
=lnx_vsnprintf(buf
,MAXLONG
,fmt
,args
);
861 int _snprintf(char * buf
, size_t cnt
, const char *fmt
, ...)
867 i
=_vsnprintf(buf
,cnt
,fmt
,args
);
876 int __cdecl
vsprintf(char *buf
, const char *fmt
, va_list args
)
878 return _vsnprintf(buf
,MAXLONG
,fmt
,args
);