3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/stdio/swprintf.c
6 * PURPOSE: unicode sprintf functions
7 * PROGRAMMERS: David Welch
11 * - Verify the implementation of '%Z'.
15 * linux/lib/vsprintf.c
17 * Copyright (C) 1991, 1992 Linus Torvalds
20 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
22 * Wirzenius wrote this portably, Torvalds fucked it up :-)
25 #include <ddk/ntddk.h>
33 #include <ntdll/ntdll.h>
36 #define ZEROPAD 1 /* pad with zero */
37 #define SIGN 2 /* unsigned/signed long */
38 #define PLUS 4 /* show plus */
39 #define SPACE 8 /* space if plus */
40 #define LEFT 16 /* left justified */
41 #define SPECIAL 32 /* 0x */
42 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
45 #define do_div(n,base) ({ \
47 __res = ((unsigned long long) n) % (unsigned) base; \
48 n = ((unsigned long long) n) / (unsigned) base; \
52 static int skip_atoi(const wchar_t **s)
57 i = i*10 + *((*s)++) - L'0';
63 number(wchar_t * buf, wchar_t * end, long long num, int base, int size, int precision, int type)
65 wchar_t c, sign, tmp[66];
66 const wchar_t *digits;
67 const wchar_t *small_digits = L"0123456789abcdefghijklmnopqrstuvwxyz";
68 const wchar_t *large_digits = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
71 digits = (type & LARGE) ? large_digits : small_digits;
74 if (base < 2 || base > 36)
76 c = (type & ZEROPAD) ? L'0' : L' ';
83 } else if (type & PLUS) {
86 } else if (type & SPACE) {
100 else while (num != 0)
101 tmp[i++] = digits[do_div(num,base)];
105 if (!(type&(ZEROPAD+LEFT))) {
117 if (type & SPECIAL) {
122 } else if (base==16) {
131 if (!(type & LEFT)) {
138 while (i < precision--) {
157 string(wchar_t* buf, wchar_t* end, const char* s, int len, int field_width, int precision, int flags)
170 while (s[len] && (unsigned int)len < (unsigned int)precision)
175 if ((unsigned int)len > (unsigned int)precision)
180 while (len < field_width--)
186 for (i = 0; i < len; ++i)
192 while (len < field_width--)
202 stringw(wchar_t* buf, wchar_t* end, const wchar_t* sw, int len, int field_width, int precision, int flags)
215 while (sw[len] && (unsigned int)len < (unsigned int)precision)
220 if ((unsigned int)len > (unsigned int)precision)
225 while (len < field_width--)
231 for (i = 0; i < len; ++i)
237 while (len < field_width--)
247 int _vsnwprintf(wchar_t *buf, size_t cnt, const wchar_t *fmt, va_list args)
250 unsigned long long num;
252 wchar_t * str, * end;
256 int flags; /* flags to number() */
258 int field_width; /* width of output field */
259 int precision; /* min. # of digits for integers; max
260 number of chars for from string */
261 int qualifier; /* 'h', 'l', 'L', 'w' or 'I' for integer fields */
270 for ( ; *fmt ; ++fmt) {
281 ++fmt; /* this also skips first '%' */
283 case L'-': flags |= LEFT; goto repeat;
284 case L'+': flags |= PLUS; goto repeat;
285 case L' ': flags |= SPACE; goto repeat;
286 case L'#': flags |= SPECIAL; goto repeat;
287 case L'0': flags |= ZEROPAD; goto repeat;
290 /* get field width */
293 field_width = skip_atoi(&fmt);
294 else if (*fmt == L'*') {
296 /* it's the next argument */
297 field_width = va_arg(args, int);
298 if (field_width < 0) {
299 field_width = -field_width;
304 /* get the precision */
309 precision = skip_atoi(&fmt);
310 else if (*fmt == L'*') {
312 /* it's the next argument */
313 precision = va_arg(args, int);
319 /* get the conversion qualifier */
321 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
324 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
335 while (--field_width > 0) {
340 if (qualifier == 'h') {
342 *str = (wchar_t) va_arg(args, int);
346 *str = (wchar_t) va_arg(args, int);
349 while (--field_width > 0) {
358 while (--field_width > 0) {
363 if (qualifier == 'l' || qualifier == 'w') {
365 *str = (wchar_t) va_arg(args, int);
369 *str = (wchar_t) va_arg(args, int);
372 while (--field_width > 0) {
380 if (qualifier == 'h') {
381 /* print ascii string */
382 s = va_arg(args, char *);
383 str = string(str, end, s, -1, field_width, precision, flags);
385 /* print unicode string */
386 sw = va_arg(args, wchar_t *);
387 str = stringw(str, end, sw, -1, field_width, precision, flags);
392 if (qualifier == 'l' || qualifier == 'w') {
393 /* print unicode string */
394 sw = va_arg(args, wchar_t *);
395 str = stringw(str, end, sw, -1, field_width, precision, flags);
397 /* print ascii string */
398 s = va_arg(args, char *);
399 str = string(str, end, s, -1, field_width, precision, flags);
404 if (qualifier == 'h') {
405 /* print counted ascii string */
406 PANSI_STRING pus = va_arg(args, PANSI_STRING);
407 if ((pus == NULL) || (pus->Buffer == NULL)) {
414 str = string(str, end, s, len, field_width, precision, flags);
416 /* print counted unicode string */
417 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
418 if ((pus == NULL) || (pus->Buffer == NULL)) {
423 len = pus->Length / sizeof(WCHAR);
425 str = stringw(str, end, sw, len, field_width, precision, flags);
430 if (field_width == -1) {
431 field_width = 2*sizeof(void *);
434 str = number(str, end,
435 (unsigned long) va_arg(args, void *), 16,
436 field_width, precision, flags);
440 /* FIXME: What does C99 say about the overflow case here? */
441 if (qualifier == 'l') {
442 long * ip = va_arg(args, long *);
445 int * ip = va_arg(args, int *);
450 /* integer number formats - set up the flags and "break" */
486 if (qualifier == 'I')
487 num = va_arg(args, unsigned long long);
488 else if (qualifier == 'l')
489 num = va_arg(args, unsigned long);
490 else if (qualifier == 'h') {
492 num = va_arg(args, int);
494 num = va_arg(args, unsigned int);
498 num = va_arg(args, int);
500 num = va_arg(args, unsigned int);
502 str = number(str, end, num, base, field_width, precision, flags);
507 /* don't write out a null byte if the buf size is zero */
516 int swprintf(wchar_t *buf, const wchar_t *fmt, ...)
522 i=_vsnwprintf(buf,INT_MAX,fmt,args);
531 int _snwprintf(wchar_t *buf, size_t cnt, const wchar_t *fmt, ...)
537 i=_vsnwprintf(buf,cnt,fmt,args);
543 int vswprintf(wchar_t *buf, const wchar_t *fmt, va_list args)
545 return _vsnwprintf(buf,INT_MAX,fmt,args);