2 * PROGRAMMERS: David Welch
6 * - Verify the implementation of '%Z'.
10 * linux/lib/vsprintf.c
12 * Copyright (C) 1991, 1992 Linus Torvalds
15 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
17 * Wirzenius wrote this portably, Torvalds fucked it up :-)
22 #define ZEROPAD 1 /* pad with zero */
23 #define SIGN 2 /* unsigned/signed long */
24 #define PLUS 4 /* show plus */
25 #define SPACE 8 /* space if plus */
26 #define LEFT 16 /* left justified */
27 #define SPECIAL 32 /* 0x */
28 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
29 #define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
31 unsigned int mantissal
:32;
32 unsigned int mantissah
:20;
33 unsigned int exponent
:11;
49 return ( x
.x
->exponent
== 0x7ff && ( x
.x
->mantissah
== 0 && x
.x
->mantissal
== 0 ));
63 return ( x
.x
->exponent
== 0x7ff && ( x
.x
->mantissah
!= 0 || x
.x
->mantissal
!= 0 ));
70 do_div(long long *n
, int base
)
73 a
= ((unsigned long long) *n
) % (unsigned) base
;
74 *n
= ((unsigned long long) *n
) / (unsigned) base
;
79 static int skip_atoi(const wchar_t **s
)
84 i
= i
*10 + *((*s
)++) - L
'0';
90 number(wchar_t * buf
, wchar_t * end
, long long num
, int base
, int size
, int precision
, int type
)
92 wchar_t c
, sign
, tmp
[66];
93 const wchar_t *digits
;
94 const wchar_t *small_digits
= L
"0123456789abcdefghijklmnopqrstuvwxyz";
95 const wchar_t *large_digits
= L
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
98 digits
= (type
& LARGE
) ? large_digits
: small_digits
;
101 if (base
< 2 || base
> 36)
103 c
= (type
& ZEROPAD
) ? L
'0' : L
' ';
110 } else if (type
& PLUS
) {
113 } else if (type
& SPACE
) {
119 if ((type
& SPECIAL
) && ((type
& REMOVEHEX
) == 0)) {
124 if ((num
== 0) && (precision
!=0))
126 else while (num
!= 0)
127 tmp
[i
++] = digits
[do_div(&num
,base
)];
131 if (!(type
&(ZEROPAD
+LEFT
))) {
144 if ((type
& SPECIAL
) && ((type
& REMOVEHEX
) == 0)) {
154 if (!(type
& LEFT
)) {
161 while (i
< precision
--) {
182 numberf(wchar_t * buf
, wchar_t * end
, double num
, int base
, int size
, int precision
, int type
)
184 wchar_t c
, sign
, tmp
[66];
185 const wchar_t *digits
;
186 const wchar_t *small_digits
= L
"0123456789abcdefghijklmnopqrstuvwxyz";
187 const wchar_t *large_digits
= L
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
192 the float version of number is direcly copy of number
196 digits
= (type
& LARGE
) ? large_digits
: small_digits
;
199 if (base
< 2 || base
> 36)
201 c
= (type
& ZEROPAD
) ? L
'0' : L
' ';
208 } else if (type
& PLUS
) {
211 } else if (type
& SPACE
) {
216 if (type
& SPECIAL
) {
225 else while (num
!= 0)
228 tmp
[i
++] = digits
[do_div(&x
,base
)];
234 if (!(type
&(ZEROPAD
+LEFT
))) {
246 if (type
& SPECIAL
) {
251 } else if (base
==16) {
260 if (!(type
& LEFT
)) {
267 while (i
< precision
--) {
286 string(wchar_t* buf
, wchar_t* end
, const char* s
, int len
, int field_width
, int precision
, int flags
)
291 c
= (flags
& ZEROPAD
) ? L
'0' : L
' ';
303 while ((unsigned int)len
< (unsigned int)precision
&& s
[len
])
308 if ((unsigned int)len
> (unsigned int)precision
)
313 while (len
< field_width
--)
319 for (i
= 0; i
< len
; ++i
)
325 while (len
< field_width
--)
335 stringw(wchar_t* buf
, wchar_t* end
, const wchar_t* sw
, int len
, int field_width
, int precision
, int flags
)
340 c
= (flags
& ZEROPAD
) ? L
'0' : L
' ';
352 while ((unsigned int)len
< (unsigned int)precision
&& sw
[len
])
357 if ((unsigned int)len
> (unsigned int)precision
)
362 while (len
< field_width
--)
368 for (i
= 0; i
< len
; ++i
)
374 while (len
< field_width
--)
386 int __cdecl
_vsnwprintf(wchar_t *buf
, size_t cnt
, const wchar_t *fmt
, va_list args
)
389 unsigned long long num
;
391 wchar_t * str
, * end
;
397 int flags
; /* flags to number() */
399 int field_width
; /* width of output field */
400 int precision
; /* min. # of digits for integers; max
401 number of chars for from string */
402 int qualifier
; /* 'h', 'l', 'L', 'w' or 'I' for integer fields */
407 end
= ((wchar_t *) -1);
411 for ( ; *fmt
; ++fmt
) {
422 ++fmt
; /* this also skips first '%' */
424 case L
'-': flags
|= LEFT
; goto repeat
;
425 case L
'+': flags
|= PLUS
; goto repeat
;
426 case L
' ': flags
|= SPACE
; goto repeat
;
427 case L
'#': flags
|= SPECIAL
; goto repeat
;
428 case L
'0': flags
|= ZEROPAD
; goto repeat
;
431 /* get field width */
434 field_width
= skip_atoi(&fmt
);
435 else if (*fmt
== L
'*') {
437 /* it's the next argument */
438 field_width
= va_arg(args
, int);
439 if (field_width
< 0) {
440 field_width
= -field_width
;
445 /* get the precision */
450 precision
= skip_atoi(&fmt
);
451 else if (*fmt
== L
'*') {
453 /* it's the next argument */
454 precision
= va_arg(args
, int);
460 /* get the conversion qualifier */
462 if (*fmt
== L
'h' || *fmt
== L
'l' || *fmt
== L
'L' || *fmt
== L
'w') {
465 } else if (*fmt
== L
'I' && *(fmt
+1) == L
'6' && *(fmt
+2) == L
'4') {
468 } else if (*fmt
== L
'I' && *(fmt
+1) == L
'3' && *(fmt
+2) == L
'2') {
471 } else if (*fmt
== L
'F' && *(fmt
+1) == L
'p') {
481 if (qualifier
== 'h' || qualifier
== 'w') {
483 /* print unicode string */
484 sw1
[0] = (wchar_t) va_arg(args
, int);
486 str
= stringw(str
, end
, (wchar_t *)&sw1
, -1, field_width
, precision
, flags
);
489 /* print ascii string */
490 s1
[0] = ( unsigned char) va_arg(args
, int);
492 str
= string(str
, end
, (char *)&s1
, -1, field_width
, precision
, flags
);
499 while (--field_width
> 0) {
504 if (qualifier
== 'l' || qualifier
== 'w') {
506 *str
= (wchar_t) va_arg(args
, int);
510 *str
= (wchar_t) va_arg(args
, int);
513 while (--field_width
> 0) {
521 if (qualifier
== 'h') {
522 /* print ascii string */
523 s
= va_arg(args
, char *);
524 str
= string(str
, end
, s
, -1, field_width
, precision
, flags
);
526 /* print unicode string */
527 sw
= va_arg(args
, wchar_t *);
528 str
= stringw(str
, end
, sw
, -1, field_width
, precision
, flags
);
533 if (qualifier
== 'l' || qualifier
== 'w') {
534 /* print unicode string */
535 sw
= va_arg(args
, wchar_t *);
536 str
= stringw(str
, end
, sw
, -1, field_width
, precision
, flags
);
538 /* print ascii string */
539 s
= va_arg(args
, char *);
540 str
= string(str
, end
, s
, -1, field_width
, precision
, flags
);
545 if (qualifier
== 'h') {
546 /* print counted ascii string */
547 PANSI_STRING pus
= va_arg(args
, PANSI_STRING
);
548 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
555 str
= string(str
, end
, s
, len
, field_width
, precision
, flags
);
557 /* print counted unicode string */
558 PUNICODE_STRING pus
= va_arg(args
, PUNICODE_STRING
);
559 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
564 len
= pus
->Length
/ sizeof(WCHAR
);
566 str
= stringw(str
, end
, sw
, len
, field_width
, precision
, flags
);
571 if ((flags
& LARGE
) == 0)
573 if (field_width
== -1) {
574 field_width
= 2*sizeof(void *);
577 str
= number(str
, end
,
578 (ULONG_PTR
) va_arg(args
, void *), 16,
579 field_width
, precision
, flags
);
583 /* FIXME: What does C99 say about the overflow case here? */
584 if (qualifier
== 'l') {
585 long * ip
= va_arg(args
, long *);
588 int * ip
= va_arg(args
, int *);
592 /* float number formats - set up the flags and "break" */
598 _double
= (double)va_arg(args
, double);
600 if ( _isnan(_double
) ) {
609 } else if ( _isinf(_double
) < 0 ) {
618 } else if ( _isinf(_double
) > 0 ) {
628 if ( precision
== -1 )
630 str
= numberf(str
, end
, _double
, base
, field_width
, precision
, flags
);
637 /* integer number formats - set up the flags and "break" */
668 if (qualifier
== L
'I')
669 num
= va_arg(args
, unsigned long long);
670 else if (qualifier
== L
'l') {
672 num
= va_arg(args
, long);
674 num
= va_arg(args
, unsigned long);
676 else if (qualifier
== L
'h') {
678 num
= va_arg(args
, int);
680 num
= va_arg(args
, unsigned int);
684 num
= va_arg(args
, int);
686 num
= va_arg(args
, unsigned int);
688 str
= number(str
, end
, num
, base
, field_width
, precision
, flags
);
693 /* don't write out a null byte if the buf size is zero */
702 int swprintf(wchar_t *buf
, const wchar_t *fmt
, ...)
708 i
=_vsnwprintf(buf
,MAXLONG
,fmt
,args
);
717 int __cdecl
_snwprintf(wchar_t *buf
, size_t cnt
, const wchar_t *fmt
, ...)
723 i
=_vsnwprintf(buf
,cnt
,fmt
,args
);
732 int __cdecl
vswprintf(wchar_t *buf
, const wchar_t *fmt
, va_list args
)
734 return _vsnwprintf(buf
,MAXLONG
,fmt
,args
);