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