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