d20a13ece43b2d35d72abf5cd1cbfc3eea4a27df
[reactos.git] / reactos / tools / rbuild / ssprintf.cpp
1 /*
2 * This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2 of the License, or
5 * (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software
14 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
15 */
16 #include "pch.h"
17
18 #include <malloc.h>
19 #include <math.h>
20 #include <float.h>
21 #include <assert.h>
22 #include "ssprintf.h"
23
24 #ifdef _MSC_VER
25 #define alloca _alloca
26 #endif//_MSC_VER
27
28 #ifdef _MSC_VER
29 typedef __int64 LONGLONG;
30 typedef unsigned __int64 ULONGLONG;
31 #else
32 typedef long long LONGLONG;
33 typedef unsigned long long ULONGLONG;
34 #endif
35
36 typedef struct {
37 unsigned int mantissa:23;
38 unsigned int exponent:8;
39 unsigned int sign:1;
40 } ieee_float_t;
41
42 typedef struct {
43 unsigned int mantissal:32;
44 unsigned int mantissah:20;
45 unsigned int exponent:11;
46 unsigned int sign:1;
47 } ieee_double_t;
48
49 typedef struct {
50 unsigned int mantissal:32;
51 unsigned int mantissah:32;
52 unsigned int exponent:15;
53 unsigned int sign:1;
54 unsigned int empty:16;
55 } ieee_long_double_t;
56
57 std::string
58 ssprintf ( const char* fmt, ... )
59 {
60 va_list arg;
61 va_start(arg, fmt);
62 std::string f = ssvprintf ( fmt, arg );
63 va_end(arg);
64 return f;
65 }
66
67 std::wstring
68 sswprintf ( const wchar_t* fmt, ... )
69 {
70 va_list arg;
71 va_start(arg, fmt);
72 std::wstring f = sswvprintf ( fmt, arg );
73 va_end(arg);
74 return f;
75 }
76
77 #define ZEROPAD 1 /* pad with zero */
78 #define SIGN 2 /* unsigned/signed long */
79 #define PLUS 4 /* show plus */
80 #define SPACE 8 /* space if plus */
81 #define LEFT 16 /* left justified */
82 #define SPECIAL 32 /* 0x */
83 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
84 #define ZEROTRUNC 128 /* truncate zero 's */
85
86
87 static int
88 skip_atoi(const char **s)
89 {
90 int i=0;
91
92 while (isdigit(**s))
93 i = i*10 + *((*s)++) - '0';
94 return i;
95 }
96
97 static int
98 skip_wtoi(const wchar_t **s)
99 {
100 int i=0;
101
102 while (iswdigit(**s))
103 i = i*10 + *((*s)++) - L'0';
104 return i;
105 }
106
107
108 static int
109 do_div(LONGLONG *n,int base)
110 {
111 int __res = ((ULONGLONG) *n) % (unsigned) base;
112 *n = ((ULONGLONG) *n) / (unsigned) base;
113 return __res;
114 }
115
116
117 static bool
118 number(std::string& f, LONGLONG num, int base, int size, int precision ,int type)
119 {
120 char c,sign,tmp[66];
121 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
122 int i;
123
124 if (type & LARGE)
125 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
126 if (type & LEFT)
127 type &= ~ZEROPAD;
128 if (base < 2 || base > 36)
129 return false;
130 c = (type & ZEROPAD) ? '0' : ' ';
131 sign = 0;
132 if (type & SIGN) {
133 if (num < 0) {
134 sign = '-';
135 num = -num;
136 size--;
137 } else if (type & PLUS) {
138 sign = '+';
139 size--;
140 } else if (type & SPACE) {
141 sign = ' ';
142 size--;
143 }
144 }
145 if (type & SPECIAL) {
146 if (base == 16)
147 size -= 2;
148 else if (base == 8)
149 size--;
150 }
151 i = 0;
152 if (num == 0)
153 tmp[i++]='0';
154 else while (num != 0)
155 tmp[i++] = digits[do_div(&num,base)];
156 if (i > precision)
157 precision = i;
158 size -= precision;
159 if (!(type&(ZEROPAD+LEFT)))
160 while(size-->0)
161 f += ' ';
162 if (sign)
163 f += sign;
164 if (type & SPECIAL)
165 {
166 if (base==8)
167 f += '0';
168 else if (base==16)
169 {
170 f += '0';
171 f += digits[33];
172 }
173 }
174 if (!(type & LEFT))
175 {
176 while (size-- > 0)
177 f += c;
178 }
179 while (i < precision--)
180 {
181 f += '0';
182 }
183 while (i-- > 0)
184 {
185 f += tmp[i];
186 }
187 while (size-- > 0)
188 {
189 f += ' ';
190 }
191 return true;
192 }
193
194 static bool
195 wnumber(std::wstring& f, LONGLONG num, int base, int size, int precision ,int type)
196 {
197 wchar_t c,sign,tmp[66];
198 const wchar_t *digits = L"0123456789abcdefghijklmnopqrstuvwxyz";
199 int i;
200
201 if (type & LARGE)
202 digits = L"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
203 if (type & LEFT)
204 type &= ~ZEROPAD;
205 if (base < 2 || base > 36)
206 return 0;
207 c = (type & ZEROPAD) ? L'0' : L' ';
208 sign = false;
209 if (type & SIGN) {
210 if (num < 0) {
211 sign = L'-';
212 num = -num;
213 size--;
214 } else if (type & PLUS) {
215 sign = L'+';
216 size--;
217 } else if (type & SPACE) {
218 sign = L' ';
219 size--;
220 }
221 }
222 if (type & SPECIAL) {
223 if (base == 16)
224 size -= 2;
225 else if (base == 8)
226 size--;
227 }
228 i = 0;
229 if (num == 0)
230 tmp[i++]=L'0';
231 else while (num != 0)
232 tmp[i++] = digits[do_div(&num,base)];
233 if (i > precision)
234 precision = i;
235 size -= precision;
236 if (!(type&(ZEROPAD+LEFT)))
237 while(size-->0)
238 f += L' ';
239 if (sign)
240 f += sign;
241 if (type & SPECIAL)
242 {
243 if (base==8)
244 f += L'0';
245 else if (base==16)
246 {
247 f += L'0';
248 f += digits[33];
249 }
250 }
251 if (!(type & LEFT))
252 {
253 while (size-- > 0)
254 f += c;
255 }
256 while (i < precision--)
257 {
258 f += L'0';
259 }
260 while (i-- > 0)
261 {
262 f += tmp[i];
263 }
264 while (size-- > 0)
265 {
266 f += L' ';
267 }
268 return true;
269 }
270
271
272 static bool
273 numberf(std::string& f, double __n, char exp_sign, int size, int precision, int type)
274 {
275 double exponent = 0.0;
276 double e;
277 long ie;
278
279 //int x;
280 char *buf, *tmp;
281 int i = 0;
282 int j = 0;
283 //int k = 0;
284
285 double frac, intr;
286 double p;
287 char sign;
288 char c;
289 char ro = 0;
290 int result;
291
292 union
293 {
294 double* __n;
295 ieee_double_t* n;
296 } n;
297
298 n.__n = &__n;
299
300 if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
301 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
302 exponent = ie/3.321928;
303 }
304
305 if ( exp_sign == 'g' || exp_sign == 'G' ) {
306 type |= ZEROTRUNC;
307 if ( exponent < -4 || fabs(exponent) >= precision )
308 exp_sign -= 2; // g -> e and G -> E
309 else
310 exp_sign = 'f';
311 }
312
313 if ( exp_sign == 'e' || exp_sign == 'E' ) {
314 frac = modf(exponent,&e);
315 if ( frac > 0.5 )
316 e++;
317 else if ( frac < -0.5 )
318 e--;
319
320 result = numberf(f,__n/pow(10.0L,e),'f',size-4, precision, type);
321 if (result < 0)
322 return false;
323 f += exp_sign;
324 size--;
325 ie = (long)e;
326 type = LEFT | PLUS;
327 if ( ie < 0 )
328 type |= SIGN;
329
330 result = number(f,ie, 10,2, 2,type );
331 if (result < 0)
332 return false;
333 return true;
334 }
335
336 if ( exp_sign == 'f' ) {
337 buf = (char*)alloca(4096);
338 if (type & LEFT) {
339 type &= ~ZEROPAD;
340 }
341
342 c = (type & ZEROPAD) ? '0' : ' ';
343 sign = 0;
344 if (type & SIGN) {
345 if (__n < 0) {
346 sign = '-';
347 __n = fabs(__n);
348 size--;
349 } else if (type & PLUS) {
350 sign = '+';
351 size--;
352 } else if (type & SPACE) {
353 sign = ' ';
354 size--;
355 }
356 }
357
358 frac = modf(__n,&intr);
359
360 // # flags forces a . and prevents trucation of trailing zero's
361
362 if ( precision > 0 ) {
363 //frac = modfl(__n,&intr);
364 i = precision-1;
365 while ( i >= 0 ) {
366 frac*=10.0L;
367 frac = modf(frac, &p);
368 buf[i] = (int)p + '0';
369 i--;
370 }
371 i = precision;
372 size -= precision;
373
374 ro = 0;
375 if ( frac > 0.5 ) {
376 ro = 1;
377 }
378
379 if ( precision >= 1 || type & SPECIAL) {
380 buf[i++] = '.';
381 size--;
382 }
383 }
384
385 if ( intr == 0.0 ) {
386 buf[i++] = '0';
387 size--;
388 }
389 else {
390 while ( intr > 0.0 ) {
391 p = intr;
392 intr/=10.0L;
393 modf(intr, &intr);
394
395 p -= 10.0*intr;
396
397 buf[i++] = (int)p + '0';
398 size--;
399 }
400 }
401
402 j = 0;
403 while ( j < i && ro == 1) {
404 if ( buf[j] >= '0' && buf[j] <= '8' ) {
405 buf[j]++;
406 ro = 0;
407 }
408 else if ( buf[j] == '9' ) {
409 buf[j] = '0';
410 }
411 j++;
412 }
413 if ( ro == 1 )
414 buf[i++] = '1';
415
416 buf[i] = 0;
417
418 size -= precision;
419 if (!(type&(ZEROPAD+LEFT)))
420 {
421 while(size-->0)
422 f += ' ';
423 }
424 if (sign)
425 {
426 f += sign;
427 }
428
429 if (!(type&(ZEROPAD+LEFT)))
430 while(size-->0)
431 {
432 f += ' ';
433 }
434 if (type & SPECIAL) {
435 }
436
437 if (!(type & LEFT))
438 while (size-- > 0)
439 {
440 f += c;
441 }
442
443 tmp = buf;
444 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
445 {
446 j = 0;
447 while ( j < i && ( *tmp == '0' || *tmp == '.' ))
448 {
449 tmp++;
450 i--;
451 }
452 }
453 // else
454 // while (i < precision--)
455 // putc('0', f);
456 while (i-- > 0)
457 {
458 f += tmp[i];
459 }
460 while (size-- > 0)
461 {
462 f += ' ';
463 }
464 }
465 return true;
466 }
467
468 static bool
469 wnumberf(std::wstring& f, double __n, wchar_t exp_sign, int size, int precision, int type)
470 {
471 double exponent = 0.0;
472 double e;
473 long ie;
474
475 int i = 0;
476 int j = 0;
477
478 double frac, intr;
479 double p;
480 wchar_t *buf, *tmp, sign, c, ro = 0;
481 int result;
482
483 union
484 {
485 double* __n;
486 ieee_double_t* n;
487 } n;
488
489 n.__n = &__n;
490
491 if ( exp_sign == L'g' || exp_sign == L'G' || exp_sign == L'e' || exp_sign == L'E' ) {
492 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
493 exponent = ie/3.321928;
494 }
495
496 if ( exp_sign == L'g' || exp_sign == L'G' )
497 {
498 type |= ZEROTRUNC;
499 if ( exponent < -4 || fabs(exponent) >= precision )
500 exp_sign -= 2; // g -> e and G -> E
501 else
502 exp_sign = L'f';
503 }
504
505 if ( exp_sign == L'e' || exp_sign == L'E' )
506 {
507 frac = modf(exponent,&e);
508 if ( frac > 0.5 )
509 e++;
510 else if ( frac < -0.5 )
511 e--;
512
513 result = wnumberf(f,__n/pow(10.0L,e),L'f',size-4, precision, type);
514 if (result < 0)
515 return false;
516 f += exp_sign;
517 size--;
518 ie = (long)e;
519 type = LEFT | PLUS;
520 if ( ie < 0 )
521 type |= SIGN;
522
523 result = wnumber(f,ie, 10,2, 2,type );
524 if (result < 0)
525 return false;
526 return true;
527 }
528
529 if ( exp_sign == L'f' )
530 {
531 buf = (wchar_t*)alloca(4096*sizeof(wchar_t));
532 if (type & LEFT)
533 type &= ~ZEROPAD;
534
535 c = (type & ZEROPAD) ? L'0' : L' ';
536 sign = 0;
537 if (type & SIGN)
538 {
539 if (__n < 0)
540 {
541 sign = L'-';
542 __n = fabs(__n);
543 size--;
544 }
545 else if (type & PLUS)
546 {
547 sign = L'+';
548 size--;
549 }
550 else if (type & SPACE)
551 {
552 sign = L' ';
553 size--;
554 }
555 }
556
557 frac = modf(__n,&intr);
558
559 // # flags forces a . and prevents trucation of trailing zero's
560
561 if ( precision > 0 ) {
562 //frac = modfl(__n,&intr);
563 i = precision-1;
564 while ( i >= 0 ) {
565 frac*=10.0L;
566 frac = modf(frac, &p);
567 buf[i] = (int)p + L'0';
568 i--;
569 }
570 i = precision;
571 size -= precision;
572
573 ro = 0;
574 if ( frac > 0.5 ) {
575 ro = 1;
576 }
577
578 if ( precision >= 1 || type & SPECIAL) {
579 buf[i++] = L'.';
580 size--;
581 }
582 }
583
584 if ( intr == 0.0 ) {
585 buf[i++] = L'0';
586 size--;
587 }
588 else {
589 while ( intr > 0.0 ) {
590 p = intr;
591 intr/=10.0L;
592 modf(intr, &intr);
593
594 p -= 10.0*intr;
595
596 buf[i++] = (int)p + L'0';
597 size--;
598 }
599 }
600
601 j = 0;
602 while ( j < i && ro == 1) {
603 if ( buf[j] >= L'0' && buf[j] <= L'8' ) {
604 buf[j]++;
605 ro = 0;
606 }
607 else if ( buf[j] == L'9' ) {
608 buf[j] = L'0';
609 }
610 j++;
611 }
612 if ( ro == 1 )
613 buf[i++] = L'1';
614
615 buf[i] = 0;
616
617 size -= precision;
618 if (!(type&(ZEROPAD+LEFT)))
619 {
620 while(size-->0)
621 f += L' ';
622 }
623 if (sign)
624 {
625 f += sign;
626 }
627
628 if (!(type&(ZEROPAD+LEFT)))
629 while(size-->0)
630 {
631 f += L' ';
632 }
633 if (type & SPECIAL) {
634 }
635
636 if (!(type & LEFT))
637 while (size-- > 0)
638 {
639 f += c;
640 }
641
642 tmp = buf;
643 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
644 {
645 j = 0;
646 while ( j < i && ( *tmp == L'0' || *tmp == L'.' ))
647 {
648 tmp++;
649 i--;
650 }
651 }
652 while (i-- > 0)
653 {
654 f += tmp[i];
655 }
656 while (size-- > 0)
657 {
658 f += L' ';
659 }
660 }
661 return true;
662 }
663
664 static bool
665 numberfl(std::string& f, long double __n, char exp_sign, int size, int precision, int type)
666 {
667 long double exponent = 0.0;
668 long double e;
669 long ie;
670
671 //int x;
672 char *buf, *tmp;
673 int i = 0;
674 int j = 0;
675 //int k = 0;
676
677 long double frac, intr;
678 long double p;
679 char sign;
680 char c;
681 char ro = 0;
682
683 int result;
684
685 union
686 {
687 long double* __n;
688 ieee_long_double_t* n;
689 } n;
690
691 n.__n = &__n;
692
693 if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
694 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3fff);
695 exponent = ie/3.321928;
696 }
697
698 if ( exp_sign == 'g' || exp_sign == 'G' ) {
699 type |= ZEROTRUNC;
700 if ( exponent < -4 || fabs(exponent) >= precision )
701 exp_sign -= 2; // g -> e and G -> E
702 else
703 exp_sign = 'f';
704 }
705
706 if ( exp_sign == 'e' || exp_sign == 'E' ) {
707 frac = modfl(exponent,&e);
708 if ( frac > 0.5 )
709 e++;
710 else if ( frac < -0.5 )
711 e--;
712
713 result = numberf(f,__n/powl(10.0L,e),'f',size-4, precision, type);
714 if (result < 0)
715 return false;
716 f += exp_sign;
717 size--;
718 ie = (long)e;
719 type = LEFT | PLUS;
720 if ( ie < 0 )
721 type |= SIGN;
722
723 result = number(f,ie, 10,2, 2,type );
724 if (result < 0)
725 return false;
726 return true;
727 }
728
729 if ( exp_sign == 'f' )
730 {
731
732 buf = (char*)alloca(4096);
733 if (type & LEFT)
734 {
735 type &= ~ZEROPAD;
736 }
737
738 c = (type & ZEROPAD) ? '0' : ' ';
739 sign = 0;
740 if (type & SIGN)
741 {
742 if (__n < 0)
743 {
744 sign = '-';
745 __n = fabs(__n);
746 size--;
747 } else if (type & PLUS)
748 {
749 sign = '+';
750 size--;
751 } else if (type & SPACE)
752 {
753 sign = ' ';
754 size--;
755 }
756 }
757
758 frac = modfl(__n,&intr);
759
760 // # flags forces a . and prevents trucation of trailing zero's
761 if ( precision > 0 )
762 {
763 //frac = modfl(__n,&intr);
764
765 i = precision-1;
766 while ( i >= 0 )
767 {
768 frac*=10.0L;
769 frac = modfl((long double)frac, &p);
770 buf[i] = (int)p + '0';
771 i--;
772 }
773 i = precision;
774 size -= precision;
775
776 ro = 0;
777 if ( frac > 0.5 )
778 {
779 ro = 1;
780 }
781
782 if ( precision >= 1 || type & SPECIAL)
783 {
784 buf[i++] = '.';
785 size--;
786 }
787 }
788
789 if ( intr == 0.0 )
790 {
791 buf[i++] = '0';
792 size--;
793 }
794 else
795 {
796 while ( intr > 0.0 )
797 {
798 p=intr;
799 intr/=10.0L;
800 modfl(intr, &intr);
801
802 p -= 10.0L*intr;
803
804 buf[i++] = (int)p + '0';
805 size--;
806 }
807 }
808
809 j = 0;
810 while ( j < i && ro == 1) {
811 if ( buf[j] >= '0' && buf[j] <= '8' )
812 {
813 buf[j]++;
814 ro = 0;
815 }
816 else if ( buf[j] == '9' )
817 {
818 buf[j] = '0';
819 }
820 j++;
821 }
822 if ( ro == 1 )
823 buf[i++] = '1';
824
825 buf[i] = 0;
826
827 size -= precision;
828 if (!(type&(ZEROPAD+LEFT)))
829 {
830 while(size-->0)
831 f += ' ';
832 }
833 if (sign)
834 {
835 f += sign;
836 }
837
838 if (!(type&(ZEROPAD+LEFT)))
839 {
840 while(size-->0)
841 f += ' ';
842 }
843 if (type & SPECIAL) {
844 }
845
846 if (!(type & LEFT))
847 while (size-- > 0)
848 {
849 f += c;
850 }
851 tmp = buf;
852 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
853 {
854 j = 0;
855 while ( j < i && ( *tmp == '0' || *tmp == '.' ))
856 {
857 tmp++;
858 i--;
859 }
860 }
861 while (i-- > 0)
862 {
863 f += tmp[i];
864 }
865 while (size-- > 0)
866 {
867 f += ' ';
868 }
869 }
870 return true;
871 }
872
873 static bool
874 wnumberfl(std::wstring& f, long double __n, wchar_t exp_sign, int size, int precision, int type)
875 {
876 long double exponent = 0.0;
877 long double e;
878 long ie;
879
880 wchar_t *buf, *tmp, sign, c, ro = 0;
881 int i = 0;
882 int j = 0;
883
884 long double frac, intr;
885 long double p;
886
887 int result;
888
889 union
890 {
891 long double* __n;
892 ieee_long_double_t* n;
893 } n;
894
895 n.__n = &__n;
896
897 if ( exp_sign == L'g' || exp_sign == L'G' || exp_sign == L'e' || exp_sign == L'E' ) {
898 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3fff);
899 exponent = ie/3.321928;
900 }
901
902 if ( exp_sign == L'g' || exp_sign == L'G' ) {
903 type |= ZEROTRUNC;
904 if ( exponent < -4 || fabs(exponent) >= precision )
905 exp_sign -= 2; // g -> e and G -> E
906 else
907 exp_sign = 'f';
908 }
909
910 if ( exp_sign == L'e' || exp_sign == L'E' ) {
911 frac = modfl(exponent,&e);
912 if ( frac > 0.5 )
913 e++;
914 else if ( frac < -0.5 )
915 e--;
916
917 result = wnumberf(f,__n/powl(10.0L,e),L'f',size-4, precision, type);
918 if (result < 0)
919 return false;
920 f += exp_sign;
921 size--;
922 ie = (long)e;
923 type = LEFT | PLUS;
924 if ( ie < 0 )
925 type |= SIGN;
926
927 result = wnumber(f,ie, 10,2, 2,type );
928 if (result < 0)
929 return false;
930 return true;
931 }
932
933 if ( exp_sign == L'f' )
934 {
935
936 buf = (wchar_t*)alloca(4096*sizeof(wchar_t));
937 if (type & LEFT)
938 {
939 type &= ~ZEROPAD;
940 }
941
942 c = (type & ZEROPAD) ? L'0' : L' ';
943 sign = 0;
944 if (type & SIGN)
945 {
946 if (__n < 0)
947 {
948 sign = L'-';
949 __n = fabs(__n);
950 size--;
951 } else if (type & PLUS)
952 {
953 sign = L'+';
954 size--;
955 } else if (type & SPACE)
956 {
957 sign = L' ';
958 size--;
959 }
960 }
961
962 frac = modfl(__n,&intr);
963
964 // # flags forces a . and prevents trucation of trailing zero's
965 if ( precision > 0 )
966 {
967 //frac = modfl(__n,&intr);
968
969 i = precision-1;
970 while ( i >= 0 )
971 {
972 frac*=10.0L;
973 frac = modfl((long double)frac, &p);
974 buf[i] = (int)p + L'0';
975 i--;
976 }
977 i = precision;
978 size -= precision;
979
980 ro = 0;
981 if ( frac > 0.5 )
982 {
983 ro = 1;
984 }
985
986 if ( precision >= 1 || type & SPECIAL)
987 {
988 buf[i++] = L'.';
989 size--;
990 }
991 }
992
993 if ( intr == 0.0 )
994 {
995 buf[i++] = L'0';
996 size--;
997 }
998 else
999 {
1000 while ( intr > 0.0 )
1001 {
1002 p=intr;
1003 intr/=10.0L;
1004 modfl(intr, &intr);
1005
1006 p -= 10.0L*intr;
1007
1008 buf[i++] = (int)p + L'0';
1009 size--;
1010 }
1011 }
1012
1013 j = 0;
1014 while ( j < i && ro == 1) {
1015 if ( buf[j] >= L'0' && buf[j] <= L'8' )
1016 {
1017 buf[j]++;
1018 ro = 0;
1019 }
1020 else if ( buf[j] == L'9' )
1021 {
1022 buf[j] = L'0';
1023 }
1024 j++;
1025 }
1026 if ( ro == 1 )
1027 buf[i++] = L'1';
1028
1029 buf[i] = 0;
1030
1031 size -= precision;
1032 if (!(type&(ZEROPAD+LEFT)))
1033 {
1034 while(size-->0)
1035 f += L' ';
1036 }
1037 if (sign)
1038 {
1039 f += sign;
1040 }
1041
1042 if (!(type&(ZEROPAD+LEFT)))
1043 {
1044 while(size-->0)
1045 f += L' ';
1046 }
1047 if (type & SPECIAL) {
1048 }
1049
1050 if (!(type & LEFT))
1051 while (size-- > 0)
1052 {
1053 f += c;
1054 }
1055 tmp = buf;
1056 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
1057 {
1058 j = 0;
1059 while ( j < i && ( *tmp == L'0' || *tmp == L'.' ))
1060 {
1061 tmp++;
1062 i--;
1063 }
1064 }
1065 while (i-- > 0)
1066 {
1067 f += tmp[i];
1068 }
1069 while (size-- > 0)
1070 {
1071 f += L' ';
1072 }
1073 }
1074 return true;
1075 }
1076
1077 static int
1078 do_string(std::string& f, const char* s, int len, int field_width, int precision, int flags)
1079 {
1080 int i, done = 0;
1081 if (s == NULL)
1082 {
1083 s = "<NULL>";
1084 len = 6;
1085 }
1086 else
1087 {
1088 if (len == -1)
1089 {
1090 len = 0;
1091 while ((unsigned int)len < (unsigned int)precision && s[len])
1092 len++;
1093 }
1094 else
1095 {
1096 if ((unsigned int)len > (unsigned int)precision)
1097 len = precision;
1098 }
1099 }
1100 if (!(flags & LEFT))
1101 while (len < field_width--)
1102 {
1103 f += ' ';
1104 done++;
1105 }
1106 for (i = 0; i < len; ++i)
1107 {
1108 f += *s++;
1109 done++;
1110 }
1111 while (len < field_width--)
1112 {
1113 f += ' ';
1114 done++;
1115 }
1116 return done;
1117 }
1118
1119 static int
1120 do_wstring(std::wstring& f, const wchar_t* s, int len, int field_width, int precision, int flags)
1121 {
1122 int i, done = 0;
1123 if (s == NULL)
1124 {
1125 s = L"<NULL>";
1126 len = 6;
1127 }
1128 else
1129 {
1130 if (len == -1)
1131 {
1132 len = 0;
1133 while ((unsigned int)len < (unsigned int)precision && s[len])
1134 len++;
1135 }
1136 else
1137 {
1138 if ((unsigned int)len > (unsigned int)precision)
1139 len = precision;
1140 }
1141 }
1142 if (!(flags & LEFT))
1143 while (len < field_width--)
1144 {
1145 f += L' ';
1146 done++;
1147 }
1148 for (i = 0; i < len; ++i)
1149 {
1150 f += *s++;
1151 done++;
1152 }
1153 while (len < field_width--)
1154 {
1155 f += L' ';
1156 done++;
1157 }
1158 return done;
1159 }
1160
1161 static int
1162 stringw(std::string& f, const wchar_t* sw, int len, int field_width, int precision, int flags)
1163 {
1164 int i, done = 0;
1165 if (sw == NULL)
1166 {
1167 sw = L"<NULL>";
1168 len = 6;
1169 }
1170 else
1171 {
1172 if (len == -1)
1173 {
1174 len = 0;
1175 while ((unsigned int)len < (unsigned int)precision && sw[len])
1176 len++;
1177 }
1178 else
1179 {
1180 if ((unsigned int)len > (unsigned int)precision)
1181 len = precision;
1182 }
1183 }
1184 if (!(flags & LEFT))
1185 while (len < field_width--)
1186 {
1187 f += ' ';
1188 done++;
1189 }
1190 for (i = 0; i < len; ++i)
1191 {
1192 #define MY_MB_CUR_MAX 1
1193 char mb[MY_MB_CUR_MAX];
1194 int mbcount, j;
1195 mbcount = wctomb(mb, *sw++);
1196 if (mbcount <= 0)
1197 {
1198 break;
1199 }
1200 for (j = 0; j < mbcount; j++)
1201 {
1202 f += mb[j];
1203 done++;
1204 }
1205 }
1206 while (len < field_width--)
1207 {
1208 f += ' ';
1209 done++;
1210 }
1211 return done;
1212 }
1213
1214 static int
1215 wstringa(std::wstring& f, const char* sa, int len, int field_width, int precision, int flags)
1216 {
1217 int i, done = 0;
1218 if (sa == NULL)
1219 {
1220 sa = "<NULL>";
1221 len = 6;
1222 }
1223 else
1224 {
1225 if (len == -1)
1226 {
1227 len = 0;
1228 while ((unsigned int)len < (unsigned int)precision && sa[len])
1229 len++;
1230 }
1231 else
1232 {
1233 if ((unsigned int)len > (unsigned int)precision)
1234 len = precision;
1235 }
1236 }
1237 if (!(flags & LEFT))
1238 while (len < field_width--)
1239 {
1240 f += L' ';
1241 done++;
1242 }
1243 for (i = 0; i < len;)
1244 {
1245 wchar_t w;
1246 int mbcount;
1247 mbcount = mbtowc(&w, sa, len-i);
1248 if (mbcount <= 0)
1249 break;
1250 f += w;
1251 done++;
1252 i += mbcount;
1253 }
1254 while (len < field_width--)
1255 {
1256 f += L' ';
1257 done++;
1258 }
1259 return done;
1260 }
1261
1262 #define _isnanl _isnan
1263 #define _finitel _finite
1264
1265 std::string
1266 ssvprintf ( const char *fmt, va_list args )
1267 {
1268 ULONGLONG num;
1269 int base;
1270 long double _ldouble;
1271 double _double;
1272 const char *s;
1273 const wchar_t* sw;
1274 int result;
1275 std::string f;
1276
1277 int flags; /* flags to number() */
1278
1279 int field_width; /* width of output field */
1280 int precision; /* min. # of digits for integers; max
1281 number of chars for from string */
1282 int qualifier = 0; /* 'h', 'l', 'L' or 'I64' for integer fields */
1283
1284 for (; *fmt ; ++fmt)
1285 {
1286 if (*fmt != '%')
1287 {
1288 f += *fmt;
1289 continue;
1290 }
1291
1292 /* process flags */
1293 flags = 0;
1294 repeat:
1295 ++fmt; /* this also skips first '%' */
1296 switch (*fmt) {
1297 case '-': flags |= LEFT; goto repeat;
1298 case '+': flags |= PLUS; goto repeat;
1299 case ' ': flags |= SPACE; goto repeat;
1300 case '#': flags |= SPECIAL; goto repeat;
1301 case '0': flags |= ZEROPAD; goto repeat;
1302 }
1303
1304 /* get field width */
1305 field_width = -1;
1306 if (isdigit(*fmt))
1307 field_width = skip_atoi(&fmt);
1308 else if (*fmt == '*') {
1309 ++fmt;
1310 /* it's the next argument */
1311 field_width = va_arg(args, int);
1312 if (field_width < 0) {
1313 field_width = -field_width;
1314 flags |= LEFT;
1315 }
1316 }
1317
1318 /* get the precision */
1319 precision = -1;
1320 if (*fmt == '.') {
1321 ++fmt;
1322 if (isdigit(*fmt))
1323 precision = skip_atoi(&fmt);
1324 else if (*fmt == '*') {
1325 ++fmt;
1326 /* it's the next argument */
1327 precision = va_arg(args, int);
1328 }
1329 if (precision < 0)
1330 precision = 0;
1331 }
1332
1333 /* get the conversion qualifier */
1334 qualifier = 0;
1335 // %Z can be just stand alone or as size_t qualifier
1336 if ( *fmt == 'Z' ) {
1337 qualifier = *fmt;
1338 switch ( *(fmt+1)) {
1339 case 'o':
1340 case 'b':
1341 case 'X':
1342 case 'x':
1343 case 'd':
1344 case 'i':
1345 case 'u':
1346 ++fmt;
1347 break;
1348 default:
1349 break;
1350 }
1351 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
1352 qualifier = *fmt;
1353 ++fmt;
1354 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
1355 qualifier = *fmt;
1356 fmt += 3;
1357 }
1358
1359 // go fine with ll instead of L
1360 if ( *fmt == 'l' ) {
1361 ++fmt;
1362 qualifier = 'L';
1363 }
1364
1365 /* default base */
1366 base = 10;
1367
1368 switch (*fmt) {
1369 case 'c':
1370 if (!(flags & LEFT))
1371 while (--field_width > 0)
1372 {
1373 f += ' ';
1374 }
1375 if (qualifier == 'l' || qualifier == 'w')
1376 {
1377 f += (char)(unsigned char)(wchar_t) va_arg(args,int);
1378 }
1379 else
1380 {
1381 f += (char)(unsigned char) va_arg(args,int);
1382 }
1383 while (--field_width > 0)
1384 {
1385 f += ' ';
1386 }
1387 continue;
1388
1389 case 'C':
1390 if (!(flags & LEFT))
1391 while (--field_width > 0)
1392 {
1393 f += ' ';
1394 }
1395 if (qualifier == 'h')
1396 {
1397 f += (char)(unsigned char) va_arg(args,int);
1398 }
1399 else
1400 {
1401 f += (char)(unsigned char)(wchar_t) va_arg(args,int);
1402 }
1403 while (--field_width > 0)
1404 {
1405 f += ' ';
1406 }
1407 continue;
1408
1409 case 's':
1410 if (qualifier == 'l' || qualifier == 'w') {
1411 /* print unicode string */
1412 sw = va_arg(args, wchar_t *);
1413 result = stringw(f, sw, -1, field_width, precision, flags);
1414 } else {
1415 /* print ascii string */
1416 s = va_arg(args, char *);
1417 result = do_string(f, s, -1, field_width, precision, flags);
1418 }
1419 if (result < 0)
1420 {
1421 assert(!"TODO FIXME handle error better");
1422 return f;
1423 }
1424 continue;
1425
1426 case 'S':
1427 if (qualifier == 'h') {
1428 /* print ascii string */
1429 s = va_arg(args, char *);
1430 result = do_string(f, s, -1, field_width, precision, flags);
1431 } else {
1432 /* print unicode string */
1433 sw = va_arg(args, wchar_t *);
1434 result = stringw(f, sw, -1, field_width, precision, flags);
1435 }
1436 if (result < 0)
1437 {
1438 assert(!"TODO FIXME handle error better");
1439 return f;
1440 }
1441 continue;
1442
1443 /*case 'Z':
1444 if (qualifier == 'w') {
1445 // print counted unicode string
1446 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
1447 if ((pus == NULL) || (pus->Buffer == NULL)) {
1448 sw = NULL;
1449 len = -1;
1450 } else {
1451 sw = pus->Buffer;
1452 len = pus->Length / sizeof(WCHAR);
1453 }
1454 result = stringw(f, sw, len, field_width, precision, flags);
1455 } else {
1456 // print counted ascii string
1457 PANSI_STRING pas = va_arg(args, PANSI_STRING);
1458 if ((pas == NULL) || (pas->Buffer == NULL)) {
1459 s = NULL;
1460 len = -1;
1461 } else {
1462 s = pas->Buffer;
1463 len = pas->Length;
1464 }
1465 result = string(f, s, -1, field_width, precision, flags);
1466 }
1467 if (result < 0)
1468 return -1;
1469 continue;*/
1470
1471 case 'e':
1472 case 'E':
1473 case 'f':
1474 case 'g':
1475 case 'G':
1476 if (qualifier == 'l' || qualifier == 'L' ) {
1477 _ldouble = va_arg(args, long double);
1478
1479 if ( _isnanl(_ldouble) )
1480 {
1481 f += "Nan";
1482 }
1483 else if ( !_finitel(_ldouble) )
1484 {
1485 if ( _ldouble < 0 )
1486 f += "-Inf";
1487 else
1488 f += "+Inf";
1489 } else {
1490 if ( precision == -1 )
1491 precision = 6;
1492 result = numberfl(f,_ldouble,*fmt,field_width,precision,flags);
1493 if (result < 0)
1494 {
1495 assert(!"TODO FIXME handle error better");
1496 return f;
1497 }
1498 }
1499 } else {
1500 _double = (double)va_arg(args, double);
1501
1502 if ( _isnan(_double) )
1503 {
1504 f += "Nan";
1505 }
1506 else if ( !_finite(_double) )
1507 {
1508 if ( _double < 0 )
1509 f += "-Inf";
1510 else
1511 f += "+Inf";
1512 }
1513 else
1514 {
1515 if ( precision == -1 )
1516 precision = 6;
1517 result = numberf(f,_double,*fmt,field_width,precision,flags);
1518 if (result < 0)
1519 {
1520 assert(!"TODO FIXME handle error better");
1521 return f;
1522 }
1523 }
1524 }
1525 continue;
1526
1527 case 'p':
1528 if (field_width == -1) {
1529 field_width = 2*sizeof(void *);
1530 flags |= ZEROPAD;
1531 }
1532 result = number(f,
1533 (unsigned long) va_arg(args, void *), 16,
1534 field_width, precision, flags);
1535 if (result < 0)
1536 {
1537 assert(!"TODO FIXME handle error better");
1538 return f;
1539 }
1540 continue;
1541
1542 case 'n':
1543 if (qualifier == 'l') {
1544 long * ip = va_arg(args, long *);
1545 *ip = 0;
1546 } else {
1547 int * ip = va_arg(args, int *);
1548 *ip = 0;
1549 }
1550 continue;
1551
1552 /* integer number formats - set up the flags and "break" */
1553 case 'o':
1554 base = 8;
1555 break;
1556
1557 case 'b':
1558 base = 2;
1559 break;
1560
1561 case 'X':
1562 flags |= LARGE;
1563 case 'x':
1564 base = 16;
1565 break;
1566
1567 case 'd':
1568 case 'i':
1569 flags |= SIGN;
1570 case 'u':
1571 break;
1572
1573 default:
1574 if (*fmt != '%')
1575 {
1576 f += '%';
1577 }
1578 if (*fmt)
1579 {
1580 f += *fmt;
1581 }
1582 else
1583 --fmt;
1584 continue;
1585 }
1586
1587 if (qualifier == 'I')
1588 num = va_arg(args, ULONGLONG);
1589 else if (qualifier == 'l') {
1590 if (flags & SIGN)
1591 num = va_arg(args, long);
1592 else
1593 num = va_arg(args, unsigned long);
1594 }
1595 else if (qualifier == 'h') {
1596 if (flags & SIGN)
1597 num = va_arg(args, int);
1598 else
1599 num = va_arg(args, unsigned int);
1600 }
1601 else if (flags & SIGN)
1602 num = va_arg(args, int);
1603 else
1604 num = va_arg(args, unsigned int);
1605 result = number(f, num, base, field_width, precision, flags);
1606 if (result < 0)
1607 {
1608 assert(!"TODO FIXME handle error better");
1609 return f;
1610 }
1611 }
1612 //putc('\0',f);
1613 return f;
1614 }
1615
1616 std::wstring
1617 sswvprintf ( const wchar_t* fmt, va_list args )
1618 {
1619 ULONGLONG num;
1620 int base;
1621 long double _ldouble;
1622 double _double;
1623 const wchar_t* s;
1624 const char* sa;
1625 int result;
1626 std::wstring f;
1627
1628 int flags; /* flags to number() */
1629
1630 int field_width; /* width of output field */
1631 int precision; /* min. # of digits for integers; max
1632 number of chars for from string */
1633 int qualifier = 0; /* 'h', 'l', 'L' or 'I64' for integer fields */
1634
1635 for (; *fmt ; ++fmt)
1636 {
1637 if (*fmt != L'%')
1638 {
1639 f += *fmt;
1640 continue;
1641 }
1642
1643 /* process flags */
1644 flags = 0;
1645 repeat:
1646 ++fmt; /* this also skips first '%' */
1647 switch (*fmt) {
1648 case L'-': flags |= LEFT; goto repeat;
1649 case L'+': flags |= PLUS; goto repeat;
1650 case L' ': flags |= SPACE; goto repeat;
1651 case L'#': flags |= SPECIAL; goto repeat;
1652 case L'0': flags |= ZEROPAD; goto repeat;
1653 }
1654
1655 /* get field width */
1656 field_width = -1;
1657 if (isdigit(*fmt))
1658 field_width = skip_wtoi(&fmt);
1659 else if (*fmt == L'*') {
1660 ++fmt;
1661 /* it's the next argument */
1662 field_width = va_arg(args, int);
1663 if (field_width < 0) {
1664 field_width = -field_width;
1665 flags |= LEFT;
1666 }
1667 }
1668
1669 /* get the precision */
1670 precision = -1;
1671 if (*fmt == L'.') {
1672 ++fmt;
1673 if (iswdigit(*fmt))
1674 precision = skip_wtoi(&fmt);
1675 else if (*fmt == L'*') {
1676 ++fmt;
1677 /* it's the next argument */
1678 precision = va_arg(args, int);
1679 }
1680 if (precision < 0)
1681 precision = 0;
1682 }
1683
1684 /* get the conversion qualifier */
1685 qualifier = 0;
1686 // %Z can be just stand alone or as size_t qualifier
1687 if ( *fmt == L'Z' ) {
1688 qualifier = *fmt;
1689 switch ( *(fmt+1)) {
1690 case L'o':
1691 case L'b':
1692 case L'X':
1693 case L'x':
1694 case L'd':
1695 case L'i':
1696 case L'u':
1697 ++fmt;
1698 break;
1699 default:
1700 break;
1701 }
1702 } else if (*fmt == L'h' || *fmt == L'l' || *fmt == L'L' || *fmt == L'w') {
1703 qualifier = *fmt;
1704 ++fmt;
1705 } else if (*fmt == L'I' && *(fmt+1) == L'6' && *(fmt+2) == L'4') {
1706 qualifier = *fmt;
1707 fmt += 3;
1708 }
1709
1710 // go fine with ll instead of L
1711 if ( *fmt == L'l' ) {
1712 ++fmt;
1713 qualifier = L'L';
1714 }
1715
1716 /* default base */
1717 base = 10;
1718
1719 switch (*fmt) {
1720 case L'c':
1721 if (!(flags & LEFT))
1722 while (--field_width > 0)
1723 {
1724 f += L' ';
1725 }
1726 if ( qualifier == L'h' )
1727 {
1728 f += (wchar_t)(char)(unsigned char) va_arg(args,int);
1729 }
1730 else
1731 {
1732 f += (wchar_t) va_arg(args,int);
1733 }
1734 while (--field_width > 0)
1735 {
1736 f += ' ';
1737 }
1738 continue;
1739
1740 case 'C':
1741 if (!(flags & LEFT))
1742 while (--field_width > 0)
1743 {
1744 f += L' ';
1745 }
1746 if (qualifier == L'l' || qualifier == L'w')
1747 {
1748 f += (wchar_t) va_arg(args,int);
1749 }
1750 else
1751 {
1752 f += (wchar_t)(char)(unsigned char) va_arg(args,int);
1753 }
1754 while (--field_width > 0)
1755 {
1756 f += L' ';
1757 }
1758 continue;
1759
1760 case 's':
1761 if (qualifier == L'h') {
1762 /* print ascii string */
1763 sa = va_arg(args, char *);
1764 result = wstringa(f, sa, -1, field_width, precision, flags);
1765 } else {
1766 /* print unicode string */
1767 s = va_arg(args, wchar_t *);
1768 result = do_wstring(f, s, -1, field_width, precision, flags);
1769 }
1770 if (result < 0)
1771 {
1772 assert(!"TODO FIXME handle error better");
1773 return f;
1774 }
1775 continue;
1776
1777 case 'S':
1778 if (qualifier == L'l' || qualifier == L'w') {
1779 /* print unicode string */
1780 s = va_arg(args, wchar_t *);
1781 result = do_wstring(f, s, -1, field_width, precision, flags);
1782 } else {
1783 /* print ascii string */
1784 sa = va_arg(args, char *);
1785 result = wstringa(f, sa, -1, field_width, precision, flags);
1786 }
1787 if (result < 0)
1788 {
1789 assert(!"TODO FIXME handle error better");
1790 return f;
1791 }
1792 continue;
1793
1794 case L'e':
1795 case L'E':
1796 case L'f':
1797 case L'g':
1798 case L'G':
1799 if (qualifier == L'l' || qualifier == L'L' )
1800 {
1801 _ldouble = va_arg(args, long double);
1802
1803 if ( _isnanl(_ldouble) )
1804 {
1805 f += L"Nan";
1806 }
1807 else if ( !_finitel(_ldouble) )
1808 {
1809 if ( _ldouble < 0 )
1810 f += L"-Inf";
1811 else
1812 f += L"+Inf";
1813 } else {
1814 if ( precision == -1 )
1815 precision = 6;
1816 result = wnumberfl(f,_ldouble,*fmt,field_width,precision,flags);
1817 if (result < 0)
1818 {
1819 assert(!"TODO FIXME handle error better");
1820 return f;
1821 }
1822 }
1823 } else {
1824 _double = (double)va_arg(args, double);
1825
1826 if ( _isnan(_double) )
1827 {
1828 f += L"Nan";
1829 }
1830 else if ( !_finite(_double) )
1831 {
1832 if ( _double < 0 )
1833 f += L"-Inf";
1834 else
1835 f += L"+Inf";
1836 }
1837 else
1838 {
1839 if ( precision == -1 )
1840 precision = 6;
1841 result = wnumberf(f,_double,*fmt,field_width,precision,flags);
1842 if (result < 0)
1843 {
1844 assert(!"TODO FIXME handle error better");
1845 return f;
1846 }
1847 }
1848 }
1849 continue;
1850
1851 case L'p':
1852 if (field_width == -1) {
1853 field_width = 2*sizeof(void *);
1854 flags |= ZEROPAD;
1855 }
1856 result = wnumber(f,
1857 (unsigned long) va_arg(args, void *), 16,
1858 field_width, precision, flags);
1859 if (result < 0)
1860 {
1861 assert(!"TODO FIXME handle error better");
1862 return f;
1863 }
1864 continue;
1865
1866 case L'n':
1867 if (qualifier == L'l') {
1868 long * ip = va_arg(args, long *);
1869 *ip = 0;
1870 } else {
1871 int * ip = va_arg(args, int *);
1872 *ip = 0;
1873 }
1874 continue;
1875
1876 /* integer number formats - set up the flags and "break" */
1877 case L'o':
1878 base = 8;
1879 break;
1880
1881 case L'b':
1882 base = 2;
1883 break;
1884
1885 case L'X':
1886 flags |= LARGE;
1887 case L'x':
1888 base = 16;
1889 break;
1890
1891 case L'd':
1892 case L'i':
1893 flags |= SIGN;
1894 case L'u':
1895 break;
1896
1897 default:
1898 if (*fmt != L'%')
1899 {
1900 f += L'%';
1901 }
1902 if (*fmt)
1903 {
1904 f += *fmt;
1905 }
1906 else
1907 --fmt;
1908 continue;
1909 }
1910
1911 if (qualifier == L'I')
1912 num = va_arg(args, ULONGLONG);
1913 else if (qualifier == L'l') {
1914 if (flags & SIGN)
1915 num = va_arg(args, long);
1916 else
1917 num = va_arg(args, unsigned long);
1918 }
1919 else if (qualifier == L'h') {
1920 if (flags & SIGN)
1921 num = va_arg(args, int);
1922 else
1923 num = va_arg(args, unsigned int);
1924 }
1925 else if (flags & SIGN)
1926 num = va_arg(args, int);
1927 else
1928 num = va_arg(args, unsigned int);
1929 result = wnumber(f, num, base, field_width, precision, flags);
1930 if (result < 0)
1931 {
1932 assert(!"TODO FIXME handle error better");
1933 return f;
1934 }
1935 }
1936 //putc('\0',f);
1937 return f;
1938 }