1 /* $Id: sprintf.c,v 1.10 2002/09/12 17:50:05 guido Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/rtl/sprintf.c
6 * PURPOSE: Single byte sprintf functions
7 * PROGRAMMERS: David Welch
13 * linux/lib/vsprintf.c
15 * Copyright (C) 1991, 1992 Linus Torvalds
18 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
20 * Wirzenius wrote this portably, Torvalds fucked it up :-)
23 #include <ddk/ntddk.h>
30 #include <internal/debug.h>
33 #define ZEROPAD 1 /* pad with zero */
34 #define SIGN 2 /* unsigned/signed long */
35 #define PLUS 4 /* show plus */
36 #define SPACE 8 /* space if plus */
37 #define LEFT 16 /* left justified */
38 #define SPECIAL 32 /* 0x */
39 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
42 #define do_div(n,base) ({ \
44 __res = ((unsigned long long) n) % (unsigned) base; \
45 n = ((unsigned long long) n) / (unsigned) base; \
49 static int skip_atoi(const char **s
)
54 i
= i
*10 + *((*s
)++) - '0';
60 number(char *buf
, char *end
, long long num
, int base
, int size
, int precision
, int type
)
64 const char small_digits
[] = "0123456789abcdefghijklmnopqrstuvwxyz";
65 const char large_digits
[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
68 digits
= (type
& LARGE
) ? large_digits
: small_digits
;
71 if (base
< 2 || base
> 36)
73 c
= (type
& ZEROPAD
) ? '0' : ' ';
80 } else if (type
& PLUS
) {
83 } else if (type
& SPACE
) {
98 tmp
[i
++] = digits
[do_div(num
,base
)];
102 if (!(type
&(ZEROPAD
+LEFT
))) {
114 if (type
& SPECIAL
) {
119 } else if (base
==16) {
128 if (!(type
& LEFT
)) {
135 while (i
< precision
--) {
154 int _vsnprintf(char *buf
, size_t cnt
, const char *fmt
, va_list args
)
157 unsigned long long num
;
163 int flags
; /* flags to number() */
165 int field_width
; /* width of output field */
166 int precision
; /* min. # of digits for integers; max
167 number of chars for from string */
168 int qualifier
; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
177 for ( ; *fmt
; ++fmt
) {
188 ++fmt
; /* this also skips first '%' */
190 case '-': flags
|= LEFT
; goto repeat
;
191 case '+': flags
|= PLUS
; goto repeat
;
192 case ' ': flags
|= SPACE
; goto repeat
;
193 case '#': flags
|= SPECIAL
; goto repeat
;
194 case '0': flags
|= ZEROPAD
; goto repeat
;
197 /* get field width */
200 field_width
= skip_atoi(&fmt
);
201 else if (*fmt
== '*') {
203 /* it's the next argument */
204 field_width
= va_arg(args
, int);
205 if (field_width
< 0) {
206 field_width
= -field_width
;
211 /* get the precision */
216 precision
= skip_atoi(&fmt
);
217 else if (*fmt
== '*') {
219 /* it's the next argument */
220 precision
= va_arg(args
, int);
226 /* get the conversion qualifier */
228 if (*fmt
== 'h' || *fmt
== 'l' || *fmt
== 'L' || *fmt
== 'w') {
231 } else if (*fmt
== 'I' && *(fmt
+1) == '6' && *(fmt
+2) == '4') {
240 case 'c': /* finished */
242 while (--field_width
> 0)
248 if (qualifier
== 'l' || qualifier
== 'w')
251 *str
= (unsigned char)(wchar_t) va_arg(args
, int);
257 *str
= (unsigned char) va_arg(args
, int);
260 while (--field_width
> 0)
268 case 'C': /* finished */
270 while (--field_width
> 0)
276 if (qualifier
== 'h')
279 *str
= (unsigned char) va_arg(args
, int);
285 *str
= (unsigned char)(wchar_t) va_arg(args
, int);
288 while (--field_width
> 0)
296 case 's': /* finished */
297 if (qualifier
== 'l' || qualifier
== 'w') {
298 /* print unicode string */
299 sw
= va_arg(args
, wchar_t *);
303 for (len
= 0; (unsigned int)len
< (unsigned int)precision
&& sw
[len
]; len
++);
306 while (len
< field_width
--)
312 for (i
= 0; i
< len
; ++i
)
315 *str
= (unsigned char)(*sw
);
319 while (len
< field_width
--)
326 /* print ascii string */
327 s
= va_arg(args
, char *);
331 for (len
= 0; (unsigned int)len
< (unsigned int)precision
&& s
[len
]; len
++);
334 while (len
< field_width
--)
340 for (i
= 0; i
< len
; ++i
)
347 while (len
< field_width
--)
357 if (qualifier
== 'h') {
358 /* print ascii string */
359 s
= va_arg(args
, char *);
363 for (len
= 0; (unsigned int)len
< (unsigned int)precision
&& s
[len
]; len
++);
366 while (len
< field_width
--)
372 for (i
= 0; i
< len
; ++i
)
379 while (len
< field_width
--)
386 /* print unicode string */
387 sw
= va_arg(args
, wchar_t *);
391 for (len
= 0; (unsigned int)len
< (unsigned int)precision
&& sw
[len
]; len
++);
394 while (len
< field_width
--)
400 for (i
= 0; i
< len
; ++i
)
403 *str
= (unsigned char)(*sw
);
407 while (len
< field_width
--)
417 if (qualifier
== 'w') {
418 /* print counted unicode string */
419 PUNICODE_STRING pus
= va_arg(args
, PUNICODE_STRING
);
420 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
430 for (i
= 0; pus
->Buffer
[i
] && i
< pus
->Length
/ sizeof(WCHAR
); i
++)
433 *str
= (unsigned char)(pus
->Buffer
[i
]);
438 /* print counted ascii string */
439 PANSI_STRING pus
= va_arg(args
, PANSI_STRING
);
440 if ((pus
== NULL
) || (pus
->Buffer
== NULL
)) {
450 for (i
= 0; pus
->Buffer
[i
] && i
< pus
->Length
; i
++)
453 *str
= pus
->Buffer
[i
];
461 if (field_width
== -1) {
462 field_width
= 2 * sizeof(void *);
465 str
= number(str
, end
,
466 (unsigned long) va_arg(args
, void *),
467 16, field_width
, precision
, flags
);
471 /* FIXME: What does C99 say about the overflow case here? */
472 if (qualifier
== 'l') {
473 long * ip
= va_arg(args
, long *);
476 int * ip
= va_arg(args
, int *);
481 /* integer number formats - set up the flags and "break" */
520 if (qualifier
== 'I')
521 num
= va_arg(args
, unsigned long long);
522 else if (qualifier
== 'l')
523 num
= va_arg(args
, unsigned long);
524 else if (qualifier
== 'h') {
526 num
= va_arg(args
, int);
528 num
= va_arg(args
, unsigned int);
532 num
= va_arg(args
, int);
534 num
= va_arg(args
, unsigned int);
536 str
= number(str
, end
, num
, base
, field_width
, precision
, flags
);
542 /* don't write out a null byte if the buf size is zero */
549 int sprintf(char * buf
, const char *fmt
, ...)
555 i
=_vsnprintf(buf
,INT_MAX
,fmt
,args
);
561 int _snprintf(char * buf
, size_t cnt
, const char *fmt
, ...)
567 i
=_vsnprintf(buf
,cnt
,fmt
,args
);
573 int vsprintf(char *buf
, const char *fmt
, va_list args
)
575 return _vsnprintf(buf
,INT_MAX
,fmt
,args
);