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