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' */
34 do_div(long long *n
, int base
)
37 a
= ((unsigned long long) *n
) % (unsigned) base
;
38 *n
= ((unsigned long long) *n
) / (unsigned) base
;
43 static int skip_atoi(const char **s
)
48 i
= i
*10 + *((*s
)++) - '0';
54 number(char * buf
, char * end
, long long num
, int base
, int size
, int precision
, int type
)
58 const char *small_digits
= "0123456789abcdefghijklmnopqrstuvwxyz";
59 const char *large_digits
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
62 digits
= (type
& LARGE
) ? large_digits
: small_digits
;
65 if (base
< 2 || base
> 36)
67 c
= (type
& ZEROPAD
) ? '0' : ' ';
74 } else if (type
& PLUS
) {
77 } else if (type
& SPACE
) {
92 tmp
[i
++] = digits
[do_div(&num
,base
)];
96 if (!(type
&(ZEROPAD
+LEFT
))) {
108 if (type
& SPECIAL
) {
113 } else if (base
==16) {
122 if (!(type
& LEFT
)) {
129 while (i
< precision
--) {
148 string(char* buf
, char* end
, const char* s
, int len
, int field_width
, int precision
, int flags
)
161 while ((unsigned int)len
< (unsigned int)precision
&& s
[len
])
166 if ((unsigned int)len
> (unsigned int)precision
)
171 while (len
< field_width
--)
177 for (i
= 0; i
< len
; ++i
)
183 while (len
< field_width
--)
193 stringw(char* buf
, char* end
, const wchar_t* sw
, int len
, int field_width
, int precision
, int flags
)
206 while ((unsigned int)len
< (unsigned int)precision
&& sw
[len
])
211 if ((unsigned int)len
> (unsigned int)precision
)
216 while (len
< field_width
--)
222 for (i
= 0; i
< len
; ++i
)
225 *buf
= (unsigned char)(*sw
++);
228 while (len
< field_width
--)
240 int _vsnprintf(char *buf
, size_t cnt
, const char *fmt
, va_list args
)
243 unsigned long long num
;
249 int flags
; /* flags to number() */
251 int field_width
; /* width of output field */
252 int precision
; /* min. # of digits for integers; max
253 number of chars for from string */
254 int qualifier
; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
263 for ( ; *fmt
; ++fmt
) {
274 ++fmt
; /* this also skips first '%' */
276 case '-': flags
|= LEFT
; goto repeat
;
277 case '+': flags
|= PLUS
; goto repeat
;
278 case ' ': flags
|= SPACE
; goto repeat
;
279 case '#': flags
|= SPECIAL
; goto repeat
;
280 case '0': flags
|= ZEROPAD
; goto repeat
;
283 /* get field width */
286 field_width
= skip_atoi(&fmt
);
287 else if (*fmt
== '*') {
289 /* it's the next argument */
290 field_width
= va_arg(args
, int);
291 if (field_width
< 0) {
292 field_width
= -field_width
;
297 /* get the precision */
302 precision
= skip_atoi(&fmt
);
303 else if (*fmt
== '*') {
305 /* it's the next argument */
306 precision
= va_arg(args
, int);
312 /* get the conversion qualifier */
314 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' || *fmt
== 'w') {
317 } else if (*fmt
== 'I' && *(fmt
+1) == '6' && *(fmt
+2) == '4') {
326 case 'c': /* finished */
328 while (--field_width
> 0) {
333 if (qualifier
== 'l' || qualifier
== 'w') {
335 *str
= (unsigned char)(wchar_t) va_arg(args
, int);
339 *str
= (unsigned char) va_arg(args
, int);
342 while (--field_width
> 0) {
349 case 'C': /* finished */
351 while (--field_width
> 0) {
356 if (qualifier
== 'h') {
358 *str
= (unsigned char) va_arg(args
, int);
362 *str
= (unsigned char)(wchar_t) va_arg(args
, int);
365 while (--field_width
> 0) {
372 case 's': /* finished */
373 if (qualifier
== 'l' || qualifier
== 'w') {
374 /* print unicode string */
375 sw
= va_arg(args
, wchar_t *);
376 str
= stringw(str
, end
, sw
, -1, field_width
, precision
, flags
);
378 /* print ascii string */
379 s
= va_arg(args
, char *);
380 str
= string(str
, end
, s
, -1, field_width
, precision
, flags
);
385 if (qualifier
== 'h') {
386 /* print ascii string */
387 s
= va_arg(args
, char *);
388 str
= string(str
, end
, s
, -1, field_width
, precision
, flags
);
390 /* print unicode string */
391 sw
= va_arg(args
, wchar_t *);
392 str
= stringw(str
, end
, sw
, -1, field_width
, precision
, flags
);
397 if (qualifier
== 'w') {
398 /* print counted unicode string */
399 PUNICODE_STRING pus
= va_arg(args
, PUNICODE_STRING
);
400 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
405 len
= pus
->Length
/ sizeof(WCHAR
);
407 str
= stringw(str
, end
, sw
, len
, field_width
, precision
, flags
);
409 /* print counted ascii string */
410 PANSI_STRING pus
= va_arg(args
, PANSI_STRING
);
411 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
418 str
= string(str
, end
, s
, len
, field_width
, precision
, flags
);
423 if (field_width
== -1) {
424 field_width
= 2 * sizeof(void *);
427 str
= number(str
, end
,
428 (unsigned long) va_arg(args
, void *), 16,
429 field_width
, precision
, flags
);
433 /* FIXME: What does C99 say about the overflow case here? */
434 if (qualifier
== 'l') {
435 long * ip
= va_arg(args
, long *);
438 int * ip
= va_arg(args
, int *);
443 /* integer number formats - set up the flags and "break" */
479 if (qualifier
== 'I')
480 num
= va_arg(args
, unsigned long long);
481 else if (qualifier
== 'l') {
483 num
= va_arg(args
, long);
485 num
= va_arg(args
, unsigned long);
487 else if (qualifier
== 'h') {
489 num
= va_arg(args
, int);
491 num
= va_arg(args
, unsigned int);
495 num
= va_arg(args
, int);
497 num
= va_arg(args
, unsigned int);
499 str
= number(str
, end
, num
, base
, field_width
, precision
, flags
);
504 /* don't write out a null byte if the buf size is zero */
513 int sprintf(char * buf
, const char *fmt
, ...)
519 i
=_vsnprintf(buf
,MAXLONG
,fmt
,args
);
528 int _snprintf(char * buf
, size_t cnt
, const char *fmt
, ...)
534 i
=_vsnprintf(buf
,cnt
,fmt
,args
);
543 int vsprintf(char *buf
, const char *fmt
, va_list args
)
545 return _vsnprintf(buf
,MAXLONG
,fmt
,args
);