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