[CRT]
[reactos.git] / reactos / lib / sdk / crt / stdio / lnx_sprintf.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PURPOSE: CRT's vsnprintf
4 * FILE: lib/sdk/crt/stdio/lnx_printf.c
5 * PROGRAMERS: David Welch
6 Eric Kohl
7 Gregor Schneider
8 * TODO:
9 * - Verify the implementation of '%Z'.
10 */
11
12 /*
13 * Parts from linux/lib/vsprintf.c
14 * Lars Wirzenius & Linus Torvalds
15 * Wirzenius wrote this portably, Torvalds fucked it up :-)
16 */
17 #ifndef USE_NEW_SPRINTF
18 #include <precomp.h>
19
20 #include <wchar.h>
21 #include <tchar.h>
22
23 #define ZEROPAD 1 /* pad with zero */
24 #define SIGN 2 /* unsigned/signed */
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 ZEROTRUNC 128 /* truncate zero's */
31 #define REMOVEHEX 256 /* remove 0x from BASE 16 */
32
33 static
34 __inline
35 int
36 do_div(long long *n, int base)
37 {
38 int a;
39 a = ((unsigned long long) *n) % (unsigned) base;
40 *n = ((unsigned long long) *n) / (unsigned) base;
41 return a;
42 }
43
44
45 static int skip_atoi(const char **s)
46 {
47 int i=0;
48
49 while (isdigit(**s))
50 i = i*10 + *((*s)++) - '0';
51 return i;
52 }
53
54
55 static char *
56 number(char * buf, char * end, long long num, int base, int size, int precision, int type)
57 {
58 char c,sign,tmp[66];
59 const char *digits;
60 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
61 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
62 int i;
63
64 digits = (type & LARGE) ? large_digits : small_digits;
65 if (type & LEFT)
66 type &= ~ZEROPAD;
67 if (base < 2 || base > 36)
68 return 0;
69 c = (type & ZEROPAD) ? '0' : ' ';
70 sign = 0;
71 if (type & SIGN) {
72 if (num < 0) {
73 sign = '-';
74 num = -num;
75 size--;
76 } else if (type & PLUS) {
77 sign = '+';
78 size--;
79 } else if (type & SPACE) {
80 sign = ' ';
81 size--;
82 }
83 }
84
85 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
86 if (base == 16)
87 size -= 2;
88 }
89 i = 0;
90 if ((num == 0) && (precision !=0))
91 tmp[i++] = '0';
92 else while (num != 0)
93 tmp[i++] = digits[do_div(&num,base)];
94 if (i > precision)
95 precision = i;
96 size -= precision;
97 if (!(type&(ZEROPAD+LEFT))) {
98 while(size-->0) {
99 if (buf <= end)
100 *buf = ' ';
101 ++buf;
102 }
103 }
104 if (sign) {
105 if (buf <= end)
106 *buf = sign;
107 ++buf;
108 }
109
110 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
111 if (base==16) {
112 if (buf <= end)
113 *buf = '0';
114 ++buf;
115 if (buf <= end)
116 *buf = digits[33];
117 ++buf;
118 }
119 }
120
121 if (!(type & LEFT)) {
122 while (size-- > 0) {
123 if (buf <= end)
124 *buf = c;
125 ++buf;
126 }
127 }
128 while (i < precision--) {
129 if (buf <= end)
130 *buf = '0';
131 ++buf;
132 }
133 while (i-- > 0) {
134 if (buf <= end)
135 *buf = tmp[i];
136 ++buf;
137 }
138 while (size-- > 0) {
139 if (buf <= end)
140 *buf = ' ';
141 ++buf;
142 }
143
144 return buf;
145 }
146
147 typedef struct {
148 unsigned int mantissal:32;
149 unsigned int mantissah:20;
150 unsigned int exponent:11;
151 unsigned int sign:1;
152 } ieee_double_t;
153
154 static __inline void fracrnd(double *number, int prec)
155 {
156 /* Shifts fractional digits to decimal places and compares to round table */
157 /* Only suitable to determine the exponent with more precision, not for normal rounding */
158 /* Incoming numbers are expected to range from approx -10.0 to 10.0 */
159 int lpos = 1, ubound, sign = 1;
160 long decimal = abs((long)*number);
161 double frac = (*number - decimal) * 10;
162 long rt[] =
163 {
164 0,
165 9,
166 99,
167 999,
168 9999,
169 99999,
170 999999,
171 9999999,
172 99999999,
173 999999999
174 };
175
176 if (*number < 0)
177 {
178 sign = -1;
179 }
180 ubound = min(prec, sizeof(rt)/sizeof(*rt) - 1);
181 while ((long)frac % 10 != 0 && lpos < ubound)
182 {
183 frac *= 10;
184 lpos++;
185 }
186 if (abs((long)frac) == rt[lpos])
187 {
188 *number = sign * (decimal + 1);
189 }
190 }
191
192 static char *
193 numberf(char * buf, char * end, double num, char exp_sign, int size, int precision, int type)
194 {
195 double exponent = 0.0;
196 double e = 0.0;
197 long ie;
198
199 int i = 0;
200 int j = 0;
201 int ro = 0;
202 int isize;
203
204 double num2, frac, intr;
205 double p;
206
207 char c, sign, digits[66];
208 char *tmp;
209
210 union
211 {
212 double* __n;
213 ieee_double_t* n;
214 } n;
215
216 n.__n = &num;
217
218 if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' )
219 {
220 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
221 if (num != 0.0)
222 {
223 exponent = ie/3.321928;
224 }
225 }
226
227 if ( exp_sign == 'g' || exp_sign == 'G' )
228 {
229 type |= ZEROTRUNC;
230 if ( exponent < -4 || fabs(exponent) >= precision )
231 exp_sign -= 2; // g -> e and G -> E
232 else
233 exp_sign = 'f';
234 if (type & SPECIAL) precision--;
235 }
236
237 if ( exp_sign == 'e' || exp_sign == 'E' )
238 {
239 if (num != 0.0)
240 {
241 /* Find a suitable exponent */
242 frac = modf(exponent, &e);
243 num2 = num/pow(10.0L, (long double)e);
244 /* Check if rounding is possible */
245 fracrnd(&num2, precision);
246 if (num2 < 1.0 && num2 > -1.0)
247 {
248 e--;
249 }
250 else if (num2 <= -10.0 || num2 >= 10.0)
251 {
252 e++;
253 }
254 }
255
256 /* size-5 because "e+abc" is going to follow */
257 buf = numberf(buf, end, num/pow(10.0L,(long double)e), 'f', size-5, precision, type);
258 isize = 4;
259 while(*(buf-1) == ' ')
260 {
261 isize++;
262 --buf;
263 }
264
265 if (buf <= end)
266 *buf = exp_sign;
267 ++buf;
268 size--;
269
270 ie = (long)e;
271 type = LEFT | SIGN | PLUS;
272 buf = number(buf, end, ie, 10, isize, 3, type);
273 return buf;
274 }
275
276 if ( exp_sign == 'f' )
277 {
278 if (type & LEFT)
279 type &= ~ZEROPAD;
280
281 c = (type & ZEROPAD) ? '0' : ' ';
282 sign = 0;
283
284 if (num < 0)
285 {
286 sign = '-';
287 num = fabs(num);
288 size--;
289 }
290 else if (type & PLUS)
291 {
292 sign = '+';
293 size--;
294 }
295 else if (type & SPACE)
296 {
297 sign = ' ';
298 size--;
299 }
300
301 frac = modf(num,&intr);
302
303 // # flags forces a . and prevents truncation of trailing zero's
304 if ( precision > 0 )
305 {
306 i = precision-1;
307 while ( i >= 0 )
308 {
309 frac*=10.0L;
310 frac = modf(frac, &p);
311 digits[i] = (int)p + '0';
312 i--;
313 }
314
315 i = precision;
316 size -= precision;
317 }
318
319 if ( precision >= 1 || type & SPECIAL)
320 {
321 digits[i++] = '.';
322 size--;
323 }
324
325 ro = 0;
326 if ( frac > 0.5 )
327 {
328 ro = 1;
329 }
330
331 if ( intr == 0.0 )
332 {
333 digits[i++] = '0';
334 size--;
335 }
336 else
337 {
338 while ( intr > 0.0 )
339 {
340 p = intr;
341 intr/=10.0L;
342 modf(intr, &intr);
343
344 p -= 10.0*intr;
345
346 digits[i++] = (int)p + '0';
347 size--;
348 }
349 }
350
351 j = 0;
352 while ( j < i && ro == 1)
353 {
354 if ( digits[j] >= '0' && digits[j] <= '8' )
355 {
356 digits[j]++;
357 ro = 0;
358 }
359 else if ( digits[j] == '9' )
360 {
361 digits[j] = '0';
362 }
363 j++;
364 }
365 if ( ro == 1 )
366 digits[i++] = '1';
367
368 digits[i] = 0;
369
370 if (!(type & (ZEROPAD+LEFT)))
371 {
372 while(size-->0)
373 {
374 if (buf <= end)
375 *buf = ' ';
376 ++buf;
377 }
378 }
379 if (sign)
380 {
381 if (buf <= end)
382 *buf = sign;
383 ++buf;
384 }
385
386 if (!(type & (ZEROPAD+LEFT)))
387 {
388 while(size-->0)
389 {
390 if (buf <= end)
391 *buf = ' ';
392 ++buf;
393 }
394 }
395
396 if (!(type & LEFT))
397 {
398 while (size-- > 0)
399 {
400 if (buf <= end)
401 *buf = c;
402 ++buf;
403 }
404 }
405
406 tmp = digits;
407 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
408 {
409 j = 0;
410 while ( j < i && ( *tmp == '0' || *tmp == '.' ))
411 {
412 tmp++;
413 i--;
414 }
415 }
416 while (i-- > 0)
417 {
418 if (buf <= end)
419 *buf = tmp[i];
420 ++buf;
421 }
422 while (size-- > 0)
423 {
424 if (buf <= end)
425 *buf = ' ';
426 buf++;
427 }
428 }
429 return buf;
430 }
431
432 static char*
433 string(char* buf, char* end, const char* s, int len, int field_width, int precision, int flags)
434 {
435 int i;
436 char c;
437
438 c = (flags & ZEROPAD) ? '0' : ' ';
439
440 if (s == NULL)
441 {
442 s = "<NULL>";
443 len = 6;
444 }
445 else
446 {
447 if (len == -1)
448 {
449 len = 0;
450 while ((unsigned int)len < (unsigned int)precision && s[len])
451 len++;
452 }
453 else
454 {
455 if ((unsigned int)len > (unsigned int)precision)
456 len = precision;
457 }
458 }
459 if (!(flags & LEFT))
460 while (len < field_width--)
461 {
462 if (buf <= end)
463 *buf = c;
464 ++buf;
465 }
466 for (i = 0; i < len; ++i)
467 {
468 if (buf <= end)
469 *buf = *s++;
470 ++buf;
471 }
472 while (len < field_width--)
473 {
474 if (buf <= end)
475 *buf = ' ';
476 ++buf;
477 }
478 return buf;
479 }
480
481 static char*
482 stringw(char* buf, char* end, const wchar_t* sw, int len, int field_width, int precision, int flags)
483 {
484 int i;
485 char c;
486
487 c = (flags & ZEROPAD) ? '0' : ' ';
488
489 if (sw == NULL)
490 {
491 sw = L"<NULL>";
492 len = 6;
493 }
494 else
495 {
496 if (len == -1)
497 {
498 len = 0;
499 while ((unsigned int)len < (unsigned int)precision && sw[len])
500 len++;
501 }
502 else
503 {
504 if ((unsigned int)len > (unsigned int)precision)
505 len = precision;
506 }
507 }
508 if (!(flags & LEFT))
509 while (len < field_width--)
510 {
511 if (buf <= end)
512 *buf = c;
513 buf++;
514 }
515 for (i = 0; i < len; ++i)
516 {
517 if (buf <= end)
518 *buf = (unsigned char)(*sw++);
519 buf++;
520 }
521 while (len < field_width--)
522 {
523 if (buf <= end)
524 *buf = ' ';
525 buf++;
526 }
527 return buf;
528 }
529
530 /*
531 * @implemented
532 */
533 int __cdecl lnx_vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
534 {
535 int len;
536 unsigned long long num;
537 double _double;
538
539 int base;
540 char *str, *end;
541 const char *s;
542 const wchar_t *sw;
543
544 int flags; /* flags to number() */
545
546 int field_width; /* width of output field */
547 int precision; /* min. # of digits for integers; max
548 number of chars for from string */
549 int qualifier; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
550
551 str = buf;
552 end = buf + cnt - 1;
553 if (end < buf - 1) {
554 end = ((char *) -1);
555 cnt = end - buf + 1;
556 }
557
558 for ( ; *fmt ; ++fmt) {
559 if (*fmt != '%') {
560 if (str <= end)
561 *str = *fmt;
562 ++str;
563 continue;
564 }
565
566 /* process flags */
567 flags = 0;
568 repeat:
569 ++fmt; /* this also skips first '%' */
570 switch (*fmt) {
571 case '-': flags |= LEFT; goto repeat;
572 case '+': flags |= PLUS; goto repeat;
573 case ' ': flags |= SPACE; goto repeat;
574 case '#': flags |= SPECIAL; goto repeat;
575 case '0': flags |= ZEROPAD; goto repeat;
576 }
577
578 /* get field width */
579 field_width = -1;
580 if (isdigit(*fmt))
581 field_width = skip_atoi(&fmt);
582 else if (*fmt == '*') {
583 ++fmt;
584 /* it's the next argument */
585 field_width = va_arg(args, int);
586 if (field_width < 0) {
587 field_width = -field_width;
588 flags |= LEFT;
589 }
590 }
591
592 /* get the precision */
593 precision = -1;
594 if (*fmt == '.') {
595 ++fmt;
596 if (isdigit(*fmt))
597 precision = skip_atoi(&fmt);
598 else if (*fmt == '*') {
599 ++fmt;
600 /* it's the next argument */
601 precision = va_arg(args, int);
602 }
603 if (precision < 0)
604 precision = 0;
605 }
606
607 /* get the conversion qualifier */
608 qualifier = -1;
609 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
610 qualifier = *fmt;
611 ++fmt;
612 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
613 qualifier = *fmt;
614 fmt += 3;
615 } else if (*fmt == 'I' && *(fmt+1) == '3' && *(fmt+2) == '2') {
616 qualifier = 'l';
617 fmt += 3;
618 } else if (*fmt == 'F' && *(fmt+1) == 'p') {
619 fmt += 1;
620 flags |= REMOVEHEX;
621 }
622
623 /* default base */
624 base = 10;
625
626 switch (*fmt) {
627 case 'c': /* finished */
628 if (qualifier == 'l' || qualifier == 'w') {
629 wchar_t sw1[2];
630 /* print unicode string */
631 sw1[0] = (wchar_t) va_arg(args, int);
632 sw1[1] = 0;
633 str = stringw(str, end, (wchar_t *)&sw1, -1, field_width, precision, flags);
634 } else {
635 char s1[2];
636 /* print ascii string */
637 s1[0] = ( unsigned char) va_arg(args, int);
638 s1[1] = 0;
639 str = string(str, end, (char *)&s1, -1, field_width, precision, flags);
640 }
641 continue;
642
643 case 'C': /* finished */
644 if (!(flags & LEFT))
645 while (--field_width > 0) {
646 if (str <= end)
647 *str = ' ';
648 ++str;
649 }
650 if (qualifier == 'h') {
651 if (str <= end)
652 *str = (unsigned char) va_arg(args, int);
653 ++str;
654 } else {
655 if (str <= end)
656 *str = (unsigned char)(wchar_t) va_arg(args, int);
657 ++str;
658 }
659 while (--field_width > 0) {
660 if (str <= end)
661 *str = ' ';
662 ++str;
663 }
664 continue;
665
666 case 's': /* finished */
667 if (qualifier == 'l' || qualifier == 'w') {
668 /* print unicode string */
669 sw = va_arg(args, wchar_t *);
670 str = stringw(str, end, sw, -1, field_width, precision, flags);
671 } else {
672 /* print ascii string */
673 s = va_arg(args, char *);
674 str = string(str, end, s, -1, field_width, precision, flags);
675 }
676 continue;
677
678 case 'S':
679 if (qualifier == 'h') {
680 /* print ascii string */
681 s = va_arg(args, char *);
682 str = string(str, end, s, -1, field_width, precision, flags);
683 } else {
684 /* print unicode string */
685 sw = va_arg(args, wchar_t *);
686 str = stringw(str, end, sw, -1, field_width, precision, flags);
687 }
688 continue;
689
690 case 'Z':
691 if (qualifier == 'w') {
692 /* print counted unicode string */
693 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
694 if ((pus == NULL) || (pus->Buffer == NULL)) {
695 sw = NULL;
696 len = -1;
697 } else {
698 sw = pus->Buffer;
699 len = pus->Length / sizeof(WCHAR);
700 }
701 str = stringw(str, end, sw, len, field_width, precision, flags);
702 } else {
703 /* print counted ascii string */
704 PANSI_STRING pus = va_arg(args, PANSI_STRING);
705 if ((pus == NULL) || (pus->Buffer == NULL)) {
706 s = NULL;
707 len = -1;
708 } else {
709 s = pus->Buffer;
710 len = pus->Length;
711 }
712 str = string(str, end, s, len, field_width, precision, flags);
713 }
714 continue;
715
716 case 'p':
717 if ((flags & LARGE) == 0)
718 flags |= LARGE;
719
720 if (field_width == -1) {
721 field_width = 2 * sizeof(void *);
722 flags |= ZEROPAD;
723 }
724 str = number(str, end,
725 (uintptr_t) va_arg(args, void *), 16,
726 field_width, precision, flags);
727 continue;
728
729 case 'n':
730 /* FIXME: What does C99 say about the overflow case here? */
731 if (qualifier == 'l') {
732 long * ip = va_arg(args, long *);
733 *ip = (str - buf);
734 } else {
735 int * ip = va_arg(args, int *);
736 *ip = (str - buf);
737 }
738 continue;
739
740 /* float number formats - set up the flags and "break" */
741 case 'e':
742 case 'E':
743 case 'f':
744 case 'g':
745 case 'G':
746 _double = (double)va_arg(args, double);
747 if ( _isnan(_double) ) {
748 s = "Nan";
749 len = 3;
750 while ( len > 0 ) {
751 if (str <= end)
752 *str = *s++;
753 ++str;
754 len --;
755 }
756 } else if ( _isinf(_double) < 0 ) {
757 s = "-Inf";
758 len = 4;
759 while ( len > 0 ) {
760 if (str <= end)
761 *str = *s++;
762 ++str;
763 len --;
764 }
765 } else if ( _isinf(_double) > 0 ) {
766 s = "+Inf";
767 len = 4;
768 while ( len > 0 ) {
769 if (str <= end)
770 *str = *s++;
771 ++str;
772 len --;
773 }
774 } else {
775 if ( precision == -1 )
776 precision = 6;
777 str = numberf(str, end, _double, *fmt, field_width, precision, flags);
778 }
779 continue;
780
781 /* integer number formats - set up the flags and "break" */
782 case 'o':
783 base = 8;
784 break;
785
786 case 'b':
787 base = 2;
788 break;
789
790 case 'X':
791 flags |= LARGE;
792 case 'x':
793 base = 16;
794 break;
795
796 case 'd':
797 case 'i':
798 flags |= SIGN;
799 case 'u':
800 break;
801
802 default:
803 if (*fmt) {
804 if (str <= end)
805 *str = *fmt;
806 ++str;
807 } else
808 --fmt;
809 continue;
810 }
811
812 if (qualifier == 'I')
813 num = va_arg(args, unsigned long long);
814 else if (qualifier == 'l') {
815 if (flags & SIGN)
816 num = va_arg(args, long);
817 else
818 num = va_arg(args, unsigned long);
819 }
820 else if (qualifier == 'h') {
821 if (flags & SIGN)
822 num = va_arg(args, int);
823 else
824 num = va_arg(args, unsigned int);
825 }
826 else {
827 if (flags & SIGN)
828 num = va_arg(args, int);
829 else
830 num = va_arg(args, unsigned int);
831 }
832 str = number(str, end, num, base, field_width, precision, flags);
833 }
834 if (str <= end)
835 *str = '\0';
836 else if (cnt > 0)
837 /* don't write out a null byte if the buf size is zero */
838 *end = '\0';
839 return str-buf;
840 }
841
842
843 /*
844 * @implemented
845 */
846 int lnx_sprintf(char * buf, const char *fmt, ...)
847 {
848 va_list args;
849 int i;
850
851 va_start(args, fmt);
852 i=lnx_vsnprintf(buf,MAXLONG,fmt,args);
853 va_end(args);
854 return i;
855 }
856
857 #if 0
858 /*
859 * @implemented
860 */
861 int _snprintf(char * buf, size_t cnt, const char *fmt, ...)
862 {
863 va_list args;
864 int i;
865
866 va_start(args, fmt);
867 i=_vsnprintf(buf,cnt,fmt,args);
868 va_end(args);
869 return i;
870 }
871
872
873 /*
874 * @implemented
875 */
876 int __cdecl vsprintf(char *buf, const char *fmt, va_list args)
877 {
878 return _vsnprintf(buf,MAXLONG,fmt,args);
879 }
880 #endif
881 /* EOF */
882 #endif