[CMAKE]
[reactos.git] / lib / rtl / swprintf.c
1 #ifndef USE_NEW_SPRINTF
2 /*
3 * PROGRAMMERS: David Welch
4 * Eric Kohl
5 *
6 * TODO:
7 * - Verify the implementation of '%Z'.
8 */
9
10 /*
11 * linux/lib/vsprintf.c
12 *
13 * Copyright (C) 1991, 1992 Linus Torvalds
14 */
15
16 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
17 /*
18 * Wirzenius wrote this portably, Torvalds fucked it up :-)
19 */
20
21 #include <rtl.h>
22
23 #define ZEROPAD 1 /* pad with zero */
24 #define SIGN 2 /* unsigned/signed long */
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 REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
31 typedef struct {
32 unsigned int mantissal:32;
33 unsigned int mantissah:20;
34 unsigned int exponent:11;
35 unsigned int sign:1;
36 } double_t;
37
38 static
39 __inline
40 int
41 _isinf(double __x)
42 {
43 union
44 {
45 double* __x;
46 double_t* x;
47 } x;
48
49 x.__x = &__x;
50 return ( x.x->exponent == 0x7ff && ( x.x->mantissah == 0 && x.x->mantissal == 0 ));
51 }
52
53 static
54 __inline
55 int
56 _isnan(double __x)
57 {
58 union
59 {
60 double* __x;
61 double_t* x;
62 } x;
63 x.__x = &__x;
64 return ( x.x->exponent == 0x7ff && ( x.x->mantissah != 0 || x.x->mantissal != 0 ));
65 }
66
67
68 static
69 __inline
70 int
71 do_div(long long *n, int base)
72 {
73 int a;
74 a = ((unsigned long long) *n) % (unsigned) base;
75 *n = ((unsigned long long) *n) / (unsigned) base;
76 return a;
77 }
78
79
80 static int skip_atoi(const wchar_t **s)
81 {
82 int i=0;
83
84 while (iswdigit(**s))
85 i = i*10 + *((*s)++) - L'0';
86 return i;
87 }
88
89
90 static wchar_t *
91 number(wchar_t * buf, wchar_t * end, long long num, int base, int size, int precision, int type)
92 {
93 wchar_t c, sign, tmp[66];
94 const wchar_t *digits;
95 const wchar_t *small_digits = L"0123456789abcdefghijklmnopqrstuvwxyz";
96 const wchar_t *large_digits = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
97 int i;
98
99 digits = (type & LARGE) ? large_digits : small_digits;
100 if (type & LEFT)
101 type &= ~ZEROPAD;
102 if (base < 2 || base > 36)
103 return 0;
104 c = (type & ZEROPAD) ? L'0' : L' ';
105 sign = 0;
106 if (type & SIGN) {
107 if (num < 0) {
108 sign = L'-';
109 num = -num;
110 size--;
111 } else if (type & PLUS) {
112 sign = L'+';
113 size--;
114 } else if (type & SPACE) {
115 sign = ' ';
116 size--;
117 }
118 }
119
120 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
121 if (base == 16)
122 size -= 2;
123 }
124 i = 0;
125 if ((num == 0) && (precision !=0))
126 tmp[i++] = L'0';
127 else while (num != 0)
128 tmp[i++] = digits[do_div(&num,base)];
129 if (i > precision)
130 precision = i;
131 size -= precision;
132 if (!(type&(ZEROPAD+LEFT))) {
133 while(size-->0) {
134 if (buf <= end)
135 *buf = L' ';
136 ++buf;
137 }
138 }
139 if (sign) {
140 if (buf <= end)
141 *buf = sign;
142 ++buf;
143 }
144
145 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
146 if (base==16) {
147 if (buf <= end)
148 *buf = L'0';
149 ++buf;
150 if (buf <= end)
151 *buf = digits[33];
152 ++buf;
153 }
154 }
155 if (!(type & LEFT)) {
156 while (size-- > 0) {
157 if (buf <= end)
158 *buf = c;
159 ++buf;
160 }
161 }
162 while (i < precision--) {
163 if (buf <= end)
164 *buf = L'0';
165 ++buf;
166 }
167 while (i-- > 0) {
168 if (buf <= end)
169 *buf = tmp[i];
170 ++buf;
171 }
172 while (size-- > 0) {
173 if (buf <= end)
174 *buf = L' ';
175 ++buf;
176 }
177
178
179 return buf;
180 }
181
182 static wchar_t *
183 numberf(wchar_t * buf, wchar_t * end, double num, int base, int size, int precision, int type)
184 {
185 wchar_t c, sign, tmp[66];
186 const wchar_t *digits;
187 const wchar_t *small_digits = L"0123456789abcdefghijklmnopqrstuvwxyz";
188 const wchar_t *large_digits = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
189 int i;
190 long long x;
191
192 /* FIXME
193 the float version of number is direcly copy of number
194 */
195
196
197 digits = (type & LARGE) ? large_digits : small_digits;
198 if (type & LEFT)
199 type &= ~ZEROPAD;
200 if (base < 2 || base > 36)
201 return 0;
202 c = (type & ZEROPAD) ? L'0' : L' ';
203 sign = 0;
204 if (type & SIGN) {
205 if (num < 0) {
206 sign = L'-';
207 num = -num;
208 size--;
209 } else if (type & PLUS) {
210 sign = L'+';
211 size--;
212 } else if (type & SPACE) {
213 sign = ' ';
214 size--;
215 }
216 }
217 if (type & SPECIAL) {
218 if (base == 16)
219 size -= 2;
220 else if (base == 8)
221 size--;
222 }
223 i = 0;
224 if (num == 0)
225 tmp[i++] = L'0';
226 else while (num != 0)
227 {
228 x = num;
229 tmp[i++] = digits[do_div(&x,base)];
230 #ifndef _M_ARM // Missing __floatdidf in CeGCC 0.55 -- GCC 4.4
231 num = x;
232 #endif
233 }
234 if (i > precision)
235 precision = i;
236 size -= precision;
237 if (!(type&(ZEROPAD+LEFT))) {
238 while(size-->0) {
239 if (buf <= end)
240 *buf = L' ';
241 ++buf;
242 }
243 }
244 if (sign) {
245 if (buf <= end)
246 *buf = sign;
247 ++buf;
248 }
249 if (type & SPECIAL) {
250 if (base==8) {
251 if (buf <= end)
252 *buf = L'0';
253 ++buf;
254 } else if (base==16) {
255 if (buf <= end)
256 *buf = L'0';
257 ++buf;
258 if (buf <= end)
259 *buf = digits[33];
260 ++buf;
261 }
262 }
263 if (!(type & LEFT)) {
264 while (size-- > 0) {
265 if (buf <= end)
266 *buf = c;
267 ++buf;
268 }
269 }
270 while (i < precision--) {
271 if (buf <= end)
272 *buf = L'0';
273 ++buf;
274 }
275 while (i-- > 0) {
276 if (buf <= end)
277 *buf = tmp[i];
278 ++buf;
279 }
280 while (size-- > 0) {
281 if (buf <= end)
282 *buf = L' ';
283 ++buf;
284 }
285 return buf;
286 }
287
288 static wchar_t*
289 string(wchar_t* buf, wchar_t* end, const char* s, int len, int field_width, int precision, int flags)
290 {
291 int i;
292 wchar_t c;
293
294 c = (flags & ZEROPAD) ? L'0' : L' ';
295
296 if (s == NULL)
297 {
298 s = "<NULL>";
299 len = 6;
300 }
301 else
302 {
303 if (len == -1)
304 {
305 len = 0;
306 while ((unsigned int)len < (unsigned int)precision && s[len])
307 len++;
308 }
309 else
310 {
311 if ((unsigned int)len > (unsigned int)precision)
312 len = precision;
313 }
314 }
315 if (!(flags & LEFT))
316 while (len < field_width--)
317 {
318 if (buf <= end)
319 *buf = c;
320 ++buf;
321 }
322 for (i = 0; i < len; ++i)
323 {
324 if (buf <= end)
325 *buf = *s++;
326 ++buf;
327 }
328 while (len < field_width--)
329 {
330 if (buf <= end)
331 *buf = L' ';
332 ++buf;
333 }
334 return buf;
335 }
336
337 static wchar_t*
338 stringw(wchar_t* buf, wchar_t* end, const wchar_t* sw, int len, int field_width, int precision, int flags)
339 {
340 int i;
341 wchar_t c;
342
343 c = (flags & ZEROPAD) ? L'0' : L' ';
344
345 if (sw == NULL)
346 {
347 sw = L"<NULL>";
348 len = 6;
349 }
350 else
351 {
352 if (len == -1)
353 {
354 len = 0;
355 while ((unsigned int)len < (unsigned int)precision && sw[len])
356 len++;
357 }
358 else
359 {
360 if ((unsigned int)len > (unsigned int)precision)
361 len = precision;
362 }
363 }
364 if (!(flags & LEFT))
365 while (len < field_width--)
366 {
367 if (buf <= end)
368 *buf = c;
369 buf++;
370 }
371 for (i = 0; i < len; ++i)
372 {
373 if (buf <= end)
374 *buf = *sw++;
375 buf++;
376 }
377 while (len < field_width--)
378 {
379 if (buf <= end)
380 *buf = L' ';
381 buf++;
382 }
383 return buf;
384 }
385
386 /*
387 * @implemented
388 */
389 int __cdecl _vsnwprintf(wchar_t *buf, size_t cnt, const wchar_t *fmt, va_list args)
390 {
391 int len;
392 unsigned long long num;
393 int base;
394 wchar_t * str, * end;
395 const char *s;
396 const wchar_t *sw;
397 const wchar_t *ss;
398 double _double;
399
400 int flags; /* flags to number() */
401
402 int field_width; /* width of output field */
403 int precision; /* min. # of digits for integers; max
404 number of chars for from string */
405 int qualifier; /* 'h', 'l', 'L', 'w' or 'I' for integer fields */
406
407 str = buf;
408 end = buf + cnt - 1;
409 if (end < buf - 1) {
410 end = ((wchar_t *) -1);
411 cnt = end - buf + 1;
412 }
413
414 for ( ; *fmt ; ++fmt) {
415 if (*fmt != L'%') {
416 if (str <= end)
417 *str = *fmt;
418 ++str;
419 continue;
420 }
421
422 /* process flags */
423 flags = 0;
424 repeat:
425 ++fmt; /* this also skips first '%' */
426 switch (*fmt) {
427 case L'-': flags |= LEFT; goto repeat;
428 case L'+': flags |= PLUS; goto repeat;
429 case L' ': flags |= SPACE; goto repeat;
430 case L'#': flags |= SPECIAL; goto repeat;
431 case L'0': flags |= ZEROPAD; goto repeat;
432 }
433
434 /* get field width */
435 field_width = -1;
436 if (iswdigit(*fmt))
437 field_width = skip_atoi(&fmt);
438 else if (*fmt == L'*') {
439 ++fmt;
440 /* it's the next argument */
441 field_width = va_arg(args, int);
442 if (field_width < 0) {
443 field_width = -field_width;
444 flags |= LEFT;
445 }
446 }
447
448 /* get the precision */
449 precision = -1;
450 if (*fmt == L'.') {
451 ++fmt;
452 if (iswdigit(*fmt))
453 precision = skip_atoi(&fmt);
454 else if (*fmt == L'*') {
455 ++fmt;
456 /* it's the next argument */
457 precision = va_arg(args, int);
458 }
459 if (precision < 0)
460 precision = 0;
461 }
462
463 /* get the conversion qualifier */
464 qualifier = -1;
465 if (*fmt == L'l' && *(fmt+1) == L'l') {
466 qualifier = L'I';
467 fmt += 2;
468 } else if (*fmt == L'h' || *fmt == L'l' || *fmt == L'L' || *fmt == L'w') {
469 qualifier = *fmt;
470 ++fmt;
471 } else if (*fmt == L'I' && *(fmt+1) == L'6' && *(fmt+2) == L'4') {
472 qualifier = *fmt;
473 fmt += 3;
474 } else if (*fmt == L'I' && *(fmt+1) == L'3' && *(fmt+2) == L'2') {
475 qualifier = L'l';
476 fmt += 3;
477 } else if (*fmt == L'F' && *(fmt+1) == L'p') {
478 fmt += 1;
479 flags |= REMOVEHEX;
480 }
481
482 /* default base */
483 base = 10;
484
485 switch (*fmt) {
486 case L'c':
487 if (qualifier == 'h' || qualifier == 'w') {
488 wchar_t sw1[2];
489 /* print unicode string */
490 sw1[0] = (wchar_t) va_arg(args, int);
491 sw1[1] = 0;
492 str = stringw(str, end, (wchar_t *)&sw1, -1, field_width, precision, flags);
493 } else {
494 char s1[2];
495 /* print ascii string */
496 s1[0] = ( unsigned char) va_arg(args, int);
497 s1[1] = 0;
498 str = string(str, end, (char *)&s1, -1, field_width, precision, flags);
499 }
500
501 continue;
502
503 case L'C':
504 if (!(flags & LEFT))
505 while (--field_width > 0) {
506 if (str <= end)
507 *str = L' ';
508 ++str;
509 }
510 if (qualifier == 'l' || qualifier == 'w') {
511 if (str <= end)
512 *str = (wchar_t) va_arg(args, int);
513 ++str;
514 } else {
515 if (str <= end)
516 *str = (wchar_t) va_arg(args, int);
517 ++str;
518 }
519 while (--field_width > 0) {
520 if (str <= end)
521 *str = L' ';
522 ++str;
523 }
524 continue;
525
526 case L's':
527 if (qualifier == 'h') {
528 /* print ascii string */
529 s = va_arg(args, char *);
530 str = string(str, end, s, -1, field_width, precision, flags);
531 } else {
532 /* print unicode string */
533 sw = va_arg(args, wchar_t *);
534 str = stringw(str, end, sw, -1, field_width, precision, flags);
535 }
536 continue;
537
538 case L'S':
539 if (qualifier == 'l' || qualifier == 'w') {
540 /* print unicode string */
541 sw = va_arg(args, wchar_t *);
542 str = stringw(str, end, sw, -1, field_width, precision, flags);
543 } else {
544 /* print ascii string */
545 s = va_arg(args, char *);
546 str = string(str, end, s, -1, field_width, precision, flags);
547 }
548 continue;
549
550 case L'Z':
551 if (qualifier == 'h') {
552 /* print counted ascii string */
553 PANSI_STRING pus = va_arg(args, PANSI_STRING);
554 if ((pus == NULL) || (pus->Buffer == NULL)) {
555 s = NULL;
556 len = -1;
557 } else {
558 s = pus->Buffer;
559 len = pus->Length;
560 }
561 str = string(str, end, s, len, field_width, precision, flags);
562 } else {
563 /* print counted unicode string */
564 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
565 if ((pus == NULL) || (pus->Buffer == NULL)) {
566 sw = NULL;
567 len = -1;
568 } else {
569 sw = pus->Buffer;
570 len = pus->Length / sizeof(WCHAR);
571 }
572 str = stringw(str, end, sw, len, field_width, precision, flags);
573 }
574 continue;
575
576 case L'p':
577 if ((flags & LARGE) == 0)
578 flags |= LARGE;
579 if (field_width == -1) {
580 field_width = 2*sizeof(void *);
581 flags |= ZEROPAD;
582 }
583 str = number(str, end,
584 (ULONG_PTR) va_arg(args, void *), 16,
585 field_width, precision, flags);
586 continue;
587
588 case L'n':
589 /* FIXME: What does C99 say about the overflow case here? */
590 if (qualifier == 'l') {
591 long * ip = va_arg(args, long *);
592 *ip = (str - buf);
593 } else {
594 int * ip = va_arg(args, int *);
595 *ip = (str - buf);
596 }
597 continue;
598 /* float number formats - set up the flags and "break" */
599 case 'e':
600 case 'E':
601 case 'f':
602 case 'g':
603 case 'G':
604 _double = (double)va_arg(args, double);
605
606 if ( _isnan(_double) ) {
607 ss = L"Nan";
608 len = 3;
609 while ( len > 0 ) {
610 if (str <= end)
611 *str = *ss++;
612 ++str;
613 len --;
614 }
615 } else if ( _isinf(_double) < 0 ) {
616 ss = L"-Inf";
617 len = 4;
618 while ( len > 0 ) {
619 if (str <= end)
620 *str = *ss++;
621 ++str;
622 len --;
623 }
624 } else if ( _isinf(_double) > 0 ) {
625 ss = L"+Inf";
626 len = 4;
627 while ( len > 0 ) {
628 if (str <= end)
629 *str = *ss++;
630 ++str;
631 len --;
632 }
633 } else {
634 if ( precision == -1 )
635 precision = 6;
636 str = numberf(str, end, _double, base, field_width, precision, flags);
637 }
638
639 continue;
640
641
642
643 /* integer number formats - set up the flags and "break" */
644 case L'o':
645 base = 8;
646 break;
647
648 case L'b':
649 base = 2;
650 break;
651
652 case L'X':
653 flags |= LARGE;
654 case L'x':
655 base = 16;
656 break;
657
658 case L'd':
659 case L'i':
660 flags |= SIGN;
661 case L'u':
662 break;
663
664 default:
665 if (*fmt) {
666 if (str <= end)
667 *str = *fmt;
668 ++str;
669 } else
670 --fmt;
671 continue;
672 }
673
674 if (qualifier == L'I')
675 num = va_arg(args, unsigned long long);
676 else if (qualifier == L'l') {
677 if (flags & SIGN)
678 num = va_arg(args, long);
679 else
680 num = va_arg(args, unsigned long);
681 }
682 else if (qualifier == L'h') {
683 if (flags & SIGN)
684 num = va_arg(args, int);
685 else
686 num = va_arg(args, unsigned int);
687 }
688 else {
689 if (flags & SIGN)
690 num = va_arg(args, int);
691 else
692 num = va_arg(args, unsigned int);
693 }
694 str = number(str, end, num, base, field_width, precision, flags);
695 }
696 if (str <= end)
697 *str = L'\0';
698 else if (cnt > 0)
699 /* don't write out a null byte if the buf size is zero */
700 *end = L'\0';
701 return str-buf;
702 }
703
704
705 /*
706 * @implemented
707 */
708 int swprintf(wchar_t *buf, const wchar_t *fmt, ...)
709 {
710 va_list args;
711 int i;
712
713 va_start(args, fmt);
714 i=_vsnwprintf(buf,MAXLONG,fmt,args);
715 va_end(args);
716 return i;
717 }
718
719
720 /*
721 * @implemented
722 */
723 int __cdecl _snwprintf(wchar_t *buf, size_t cnt, const wchar_t *fmt, ...)
724 {
725 va_list args;
726 int i;
727
728 va_start(args, fmt);
729 i=_vsnwprintf(buf,cnt,fmt,args);
730 va_end(args);
731 return i;
732 }
733
734
735 /*
736 * @implemented
737 */
738 int __cdecl vswprintf(wchar_t *buf, const wchar_t *fmt, va_list args)
739 {
740 return _vsnwprintf(buf,MAXLONG,fmt,args);
741 }
742
743 /* EOF */
744 #endif