[HEADERS]
[reactos.git] / irc / ArchBlackmann / ssprintf.cpp
1 // ssprintf.cpp
2
3 #include <malloc.h>
4 #include <math.h>
5 #include <float.h>
6 #include <assert.h>
7 #include "ssprintf.h"
8
9 #ifdef _MSC_VER
10 #define alloca _alloca
11 #endif//_MSC_VER
12
13 typedef __int64 LONGLONG;
14 typedef unsigned __int64 ULONGLONG;
15
16 typedef struct {
17 unsigned int mantissa:23;
18 unsigned int exponent:8;
19 unsigned int sign:1;
20 } ieee_float_t;
21
22 typedef struct {
23 unsigned int mantissal:32;
24 unsigned int mantissah:20;
25 unsigned int exponent:11;
26 unsigned int sign:1;
27 } ieee_double_t;
28
29 typedef struct {
30 unsigned int mantissal:32;
31 unsigned int mantissah:32;
32 unsigned int exponent:15;
33 unsigned int sign:1;
34 unsigned int empty:16;
35 } ieee_long_double_t;
36
37 std::string ssprintf ( const char* fmt, ... )
38 {
39 va_list arg;
40 va_start(arg, fmt);
41 std::string f = ssvprintf ( fmt, arg );
42 va_end(arg);
43 return f;
44 }
45
46 #define ZEROPAD 1 /* pad with zero */
47 #define SIGN 2 /* unsigned/signed long */
48 #define PLUS 4 /* show plus */
49 #define SPACE 8 /* space if plus */
50 #define LEFT 16 /* left justified */
51 #define SPECIAL 32 /* 0x */
52 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
53 #define ZEROTRUNC 128 /* truncate zero 's */
54
55
56 static int skip_atoi(const char **s)
57 {
58 int i=0;
59
60 while (isdigit(**s))
61 i = i*10 + *((*s)++) - '0';
62 return i;
63 }
64
65
66 static int do_div(LONGLONG *n,int base)
67 {
68 int __res = ((ULONGLONG) *n) % (unsigned) base;
69 *n = ((ULONGLONG) *n) / (unsigned) base;
70 return __res;
71 }
72
73
74 static bool number(std::string& f, LONGLONG num, int base, int size, int precision ,int type)
75 {
76 char c,sign,tmp[66];
77 const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
78 int i;
79
80 if (type & LARGE)
81 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
82 if (type & LEFT)
83 type &= ~ZEROPAD;
84 if (base < 2 || base > 36)
85 return 0;
86 c = (type & ZEROPAD) ? '0' : ' ';
87 sign = 0;
88 if (type & SIGN) {
89 if (num < 0) {
90 sign = '-';
91 num = -num;
92 size--;
93 } else if (type & PLUS) {
94 sign = '+';
95 size--;
96 } else if (type & SPACE) {
97 sign = ' ';
98 size--;
99 }
100 }
101 if (type & SPECIAL) {
102 if (base == 16)
103 size -= 2;
104 else if (base == 8)
105 size--;
106 }
107 i = 0;
108 if (num == 0)
109 tmp[i++]='0';
110 else while (num != 0)
111 tmp[i++] = digits[do_div(&num,base)];
112 if (i > precision)
113 precision = i;
114 size -= precision;
115 if (!(type&(ZEROPAD+LEFT)))
116 while(size-->0)
117 f += ' ';
118 if (sign)
119 f += sign;
120 if (type & SPECIAL)
121 {
122 if (base==8)
123 f += '0';
124 else if (base==16)
125 {
126 f += '0';
127 f += digits[33];
128 }
129 }
130 if (!(type & LEFT))
131 {
132 while (size-- > 0)
133 f += c;
134 }
135 while (i < precision--)
136 {
137 f += '0';
138 }
139 while (i-- > 0)
140 {
141 f += tmp[i];
142 }
143 while (size-- > 0)
144 {
145 f += ' ';
146 }
147 return true;
148 }
149
150
151 static bool numberf(std::string& f, double __n, char exp_sign, int size, int precision, int type)
152 {
153 double exponent = 0.0;
154 double e;
155 long ie;
156
157 //int x;
158 char *buf, *tmp;
159 int i = 0;
160 int j = 0;
161 //int k = 0;
162
163 double frac, intr;
164 double p;
165 char sign;
166 char c;
167 char ro = 0;
168 int result;
169
170 union
171 {
172 double* __n;
173 ieee_double_t* n;
174 } n;
175
176 n.__n = &__n;
177
178 if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
179 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
180 exponent = ie/3.321928;
181 }
182
183 if ( exp_sign == 'g' || exp_sign == 'G' ) {
184 type |= ZEROTRUNC;
185 if ( exponent < -4 || fabs(exponent) >= precision )
186 exp_sign -= 2; // g -> e and G -> E
187 }
188
189 if ( exp_sign == 'e' || exp_sign == 'E' ) {
190 frac = modf(exponent,&e);
191 if ( frac > 0.5 )
192 e++;
193 else if ( frac < -0.5 )
194 e--;
195
196 result = numberf(f,__n/pow(10.0L,e),'f',size-4, precision, type);
197 if (result < 0)
198 return false;
199 f += exp_sign;
200 size--;
201 ie = (long)e;
202 type = LEFT | PLUS;
203 if ( ie < 0 )
204 type |= SIGN;
205
206 result = number(f,ie, 10,2, 2,type );
207 if (result < 0)
208 return false;
209 return true;
210 }
211
212 if ( exp_sign == 'f' ) {
213 buf = (char*)alloca(4096);
214 if (type & LEFT) {
215 type &= ~ZEROPAD;
216 }
217
218 c = (type & ZEROPAD) ? '0' : ' ';
219 sign = 0;
220 if (type & SIGN) {
221 if (__n < 0) {
222 sign = '-';
223 __n = fabs(__n);
224 size--;
225 } else if (type & PLUS) {
226 sign = '+';
227 size--;
228 } else if (type & SPACE) {
229 sign = ' ';
230 size--;
231 }
232 }
233
234 frac = modf(__n,&intr);
235
236 // # flags forces a . and prevents trucation of trailing zero's
237
238 if ( precision > 0 ) {
239 //frac = modfl(__n,&intr);
240 i = precision-1;
241 while ( i >= 0 ) {
242 frac*=10.0L;
243 frac = modf(frac, &p);
244 buf[i] = (int)p + '0';
245 i--;
246 }
247 i = precision;
248 size -= precision;
249
250 ro = 0;
251 if ( frac > 0.5 ) {
252 ro = 1;
253 }
254
255 if ( precision >= 1 || type & SPECIAL) {
256 buf[i++] = '.';
257 size--;
258 }
259 }
260
261 if ( intr == 0.0 ) {
262 buf[i++] = '0';
263 size--;
264 }
265 else {
266 while ( intr > 0.0 ) {
267 p = intr;
268 intr/=10.0L;
269 modf(intr, &intr);
270
271 p -= 10.0*intr;
272
273 buf[i++] = (int)p + '0';
274 size--;
275 }
276 }
277
278 j = 0;
279 while ( j < i && ro == 1) {
280 if ( buf[j] >= '0' && buf[j] <= '8' ) {
281 buf[j]++;
282 ro = 0;
283 }
284 else if ( buf[j] == '9' ) {
285 buf[j] = '0';
286 }
287 j++;
288 }
289 if ( ro == 1 )
290 buf[i++] = '1';
291
292 buf[i] = 0;
293
294 size -= precision;
295 if (!(type&(ZEROPAD+LEFT)))
296 {
297 while(size-->0)
298 f += ' ';
299 }
300 if (sign)
301 {
302 f += sign;
303 }
304
305 if (!(type&(ZEROPAD+LEFT)))
306 while(size-->0)
307 {
308 f += ' ';
309 }
310 if (type & SPECIAL) {
311 }
312
313 if (!(type & LEFT))
314 while (size-- > 0)
315 {
316 f += c;
317 }
318
319 tmp = buf;
320 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
321 {
322 j = 0;
323 while ( j < i && ( *tmp == '0' || *tmp == '.' ))
324 {
325 tmp++;
326 i--;
327 }
328 }
329 // else
330 // while (i < precision--)
331 // putc('0', f);
332 while (i-- > 0)
333 {
334 f += tmp[i];
335 }
336 while (size-- > 0)
337 {
338 f += ' ';
339 }
340 }
341 return true;
342 }
343
344
345 static bool numberfl(std::string& f, long double __n, char exp_sign, int size, int precision, int type)
346 {
347 long double exponent = 0.0;
348 long double e;
349 long ie;
350
351 //int x;
352 char *buf, *tmp;
353 int i = 0;
354 int j = 0;
355 //int k = 0;
356
357 long double frac, intr;
358 long double p;
359 char sign;
360 char c;
361 char ro = 0;
362
363 int result;
364
365 union
366 {
367 long double* __n;
368 ieee_long_double_t* n;
369 } n;
370
371 n.__n = &__n;
372
373 if ( exp_sign == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
374 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3fff);
375 exponent = ie/3.321928;
376 }
377
378 if ( exp_sign == 'g' || exp_sign == 'G' ) {
379 type |= ZEROTRUNC;
380 if ( exponent < -4 || fabs(exponent) >= precision )
381 exp_sign -= 2; // g -> e and G -> E
382 }
383
384 if ( exp_sign == 'e' || exp_sign == 'E' ) {
385 frac = modfl(exponent,&e);
386 if ( frac > 0.5 )
387 e++;
388 else if ( frac < -0.5 )
389 e--;
390
391 result = numberf(f,__n/powl(10.0L,e),'f',size-4, precision, type);
392 if (result < 0)
393 return false;
394 f += exp_sign;
395 size--;
396 ie = (long)e;
397 type = LEFT | PLUS;
398 if ( ie < 0 )
399 type |= SIGN;
400
401 result = number(f,ie, 10,2, 2,type );
402 if (result < 0)
403 return false;
404 return true;
405 }
406
407 if ( exp_sign == 'f' )
408 {
409
410 buf = (char*)alloca(4096);
411 if (type & LEFT)
412 {
413 type &= ~ZEROPAD;
414 }
415
416 c = (type & ZEROPAD) ? '0' : ' ';
417 sign = 0;
418 if (type & SIGN)
419 {
420 if (__n < 0)
421 {
422 sign = '-';
423 __n = fabs(__n);
424 size--;
425 } else if (type & PLUS)
426 {
427 sign = '+';
428 size--;
429 } else if (type & SPACE)
430 {
431 sign = ' ';
432 size--;
433 }
434 }
435
436 frac = modfl(__n,&intr);
437
438 // # flags forces a . and prevents trucation of trailing zero's
439 if ( precision > 0 )
440 {
441 //frac = modfl(__n,&intr);
442
443 i = precision-1;
444 while ( i >= 0 )
445 {
446 frac*=10.0L;
447 frac = modfl((long double)frac, &p);
448 buf[i] = (int)p + '0';
449 i--;
450 }
451 i = precision;
452 size -= precision;
453
454 ro = 0;
455 if ( frac > 0.5 )
456 {
457 ro = 1;
458 }
459
460 if ( precision >= 1 || type & SPECIAL)
461 {
462 buf[i++] = '.';
463 size--;
464 }
465 }
466
467 if ( intr == 0.0 )
468 {
469 buf[i++] = '0';
470 size--;
471 }
472 else
473 {
474 while ( intr > 0.0 )
475 {
476 p=intr;
477 intr/=10.0L;
478 modfl(intr, &intr);
479
480 p -= 10.0L*intr;
481
482 buf[i++] = (int)p + '0';
483 size--;
484 }
485 }
486
487 j = 0;
488 while ( j < i && ro == 1) {
489 if ( buf[j] >= '0' && buf[j] <= '8' )
490 {
491 buf[j]++;
492 ro = 0;
493 }
494 else if ( buf[j] == '9' )
495 {
496 buf[j] = '0';
497 }
498 j++;
499 }
500 if ( ro == 1 )
501 buf[i++] = '1';
502
503 buf[i] = 0;
504
505 size -= precision;
506 if (!(type&(ZEROPAD+LEFT)))
507 {
508 while(size-->0)
509 f += ' ';
510 }
511 if (sign)
512 {
513 f += sign;
514 }
515
516 if (!(type&(ZEROPAD+LEFT)))
517 {
518 while(size-->0)
519 f += ' ';
520 }
521 if (type & SPECIAL) {
522 }
523
524 if (!(type & LEFT))
525 while (size-- > 0)
526 {
527 f += c;
528 }
529 tmp = buf;
530 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) )
531 {
532 j = 0;
533 while ( j < i && ( *tmp == '0' || *tmp == '.' ))
534 {
535 tmp++;
536 i--;
537 }
538 }
539 // else
540 // while (i < precision--)
541 // putc( '0', f);
542 while (i-- > 0)
543 {
544 f += tmp[i];
545 }
546 while (size-- > 0)
547 {
548 f += ' ';
549 }
550 }
551 return true;
552 }
553
554 static int stringa(std::string& f, const char* s, int len, int field_width, int precision, int flags)
555 {
556 int i, done = 0;
557 if (s == NULL)
558 {
559 s = "<NULL>";
560 len = 6;
561 }
562 else
563 {
564 if (len == -1)
565 {
566 len = 0;
567 while ((unsigned int)len < (unsigned int)precision && s[len])
568 len++;
569 }
570 else
571 {
572 if ((unsigned int)len > (unsigned int)precision)
573 len = precision;
574 }
575 }
576 if (!(flags & LEFT))
577 while (len < field_width--)
578 {
579 f += ' ';
580 done++;
581 }
582 for (i = 0; i < len; ++i)
583 {
584 f += *s++;
585 done++;
586 }
587 while (len < field_width--)
588 {
589 f += ' ';
590 done++;
591 }
592 return done;
593 }
594
595 static int stringw(std::string& f, const wchar_t* sw, int len, int field_width, int precision, int flags)
596 {
597 int i, done = 0;
598 if (sw == NULL)
599 {
600 sw = L"<NULL>";
601 len = 6;
602 }
603 else
604 {
605 if (len == -1)
606 {
607 len = 0;
608 while ((unsigned int)len < (unsigned int)precision && sw[len])
609 len++;
610 }
611 else
612 {
613 if ((unsigned int)len > (unsigned int)precision)
614 len = precision;
615 }
616 }
617 if (!(flags & LEFT))
618 while (len < field_width--)
619 {
620 f += ' ';
621 done++;
622 }
623 for (i = 0; i < len; ++i)
624 {
625 #define MY_MB_CUR_MAX 1
626 char mb[MY_MB_CUR_MAX];
627 int mbcount, j;
628 mbcount = wctomb(mb, *sw++);
629 if (mbcount <= 0)
630 {
631 break;
632 }
633 for (j = 0; j < mbcount; j++)
634 {
635 f += mb[j];
636 done++;
637 }
638 }
639 while (len < field_width--)
640 {
641 f += ' ';
642 done++;
643 }
644 return done;
645 }
646
647 #define _isnanl _isnan
648 #define _finitel _finite
649
650 std::string ssvprintf ( const char *fmt, va_list args )
651 {
652 ULONGLONG num;
653 int base;
654 long double _ldouble;
655 double _double;
656 const char *s;
657 const wchar_t* sw;
658 int result;
659 std::string f;
660
661 int flags; /* flags to number() */
662
663 int field_width; /* width of output field */
664 int precision; /* min. # of digits for integers; max
665 number of chars for from string */
666 int qualifier = 0; /* 'h', 'l', 'L' or 'I64' for integer fields */
667
668 for (; *fmt ; ++fmt)
669 {
670 if (*fmt != '%')
671 {
672 f += *fmt;
673 continue;
674 }
675
676 /* process flags */
677 flags = 0;
678 repeat:
679 ++fmt; /* this also skips first '%' */
680 switch (*fmt) {
681 case '-': flags |= LEFT; goto repeat;
682 case '+': flags |= PLUS; goto repeat;
683 case ' ': flags |= SPACE; goto repeat;
684 case '#': flags |= SPECIAL; goto repeat;
685 case '0': flags |= ZEROPAD; goto repeat;
686 }
687
688 /* get field width */
689 field_width = -1;
690 if (isdigit(*fmt))
691 field_width = skip_atoi(&fmt);
692 else if (*fmt == '*') {
693 ++fmt;
694 /* it's the next argument */
695 field_width = va_arg(args, int);
696 if (field_width < 0) {
697 field_width = -field_width;
698 flags |= LEFT;
699 }
700 }
701
702 /* get the precision */
703 precision = -1;
704 if (*fmt == '.') {
705 ++fmt;
706 if (isdigit(*fmt))
707 precision = skip_atoi(&fmt);
708 else if (*fmt == '*') {
709 ++fmt;
710 /* it's the next argument */
711 precision = va_arg(args, int);
712 }
713 if (precision < 0)
714 precision = 0;
715 }
716
717 /* get the conversion qualifier */
718 qualifier = 0;
719 // %Z can be just stand alone or as size_t qualifier
720 if ( *fmt == 'Z' ) {
721 qualifier = *fmt;
722 switch ( *(fmt+1)) {
723 case 'o':
724 case 'b':
725 case 'X':
726 case 'x':
727 case 'd':
728 case 'i':
729 case 'u':
730 ++fmt;
731 break;
732 default:
733 break;
734 }
735 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
736 qualifier = *fmt;
737 ++fmt;
738 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
739 qualifier = *fmt;
740 fmt += 3;
741 }
742
743 // go fine with ll instead of L
744 if ( *fmt == 'l' ) {
745 ++fmt;
746 qualifier = 'L';
747 }
748
749 /* default base */
750 base = 10;
751
752 switch (*fmt) {
753 case 'c':
754 if (!(flags & LEFT))
755 while (--field_width > 0)
756 {
757 f += ' ';
758 }
759 if (qualifier == 'l' || qualifier == 'w')
760 {
761 f += (char)(unsigned char)(wchar_t) va_arg(args,int);
762 }
763 else
764 {
765 f += (char)(unsigned char) va_arg(args,int);
766 }
767 while (--field_width > 0)
768 {
769 f += ' ';
770 }
771 continue;
772
773 case 'C':
774 if (!(flags & LEFT))
775 while (--field_width > 0)
776 {
777 f += ' ';
778 }
779 if (qualifier == 'h')
780 {
781 f += (char)(unsigned char) va_arg(args,int);
782 }
783 else
784 {
785 f += (char)(unsigned char)(wchar_t) va_arg(args,int);
786 }
787 while (--field_width > 0)
788 {
789 f += ' ';
790 }
791 continue;
792
793 case 's':
794 if (qualifier == 'l' || qualifier == 'w') {
795 /* print unicode string */
796 sw = (const wchar_t*)va_arg(args, wchar_t *);
797 result = stringw(f, sw, -1, field_width, precision, flags);
798 } else {
799 /* print ascii string */
800 s = va_arg(args, char *);
801 result = stringa(f, s, -1, field_width, precision, flags);
802 }
803 if (result < 0)
804 {
805 assert(!"TODO FIXME handle error better");
806 return f;
807 }
808 continue;
809
810 case 'S':
811 if (qualifier == 'h') {
812 /* print ascii string */
813 s = va_arg(args, char *);
814 result = stringa(f, s, -1, field_width, precision, flags);
815 } else {
816 /* print unicode string */
817 sw = (const wchar_t*)va_arg(args, wchar_t *);
818 result = stringw(f, sw, -1, field_width, precision, flags);
819 }
820 if (result < 0)
821 {
822 assert(!"TODO FIXME handle error better");
823 return f;
824 }
825 continue;
826
827 /*case 'Z':
828 if (qualifier == 'w') {
829 // print counted unicode string
830 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
831 if ((pus == NULL) || (pus->Buffer == NULL)) {
832 sw = NULL;
833 len = -1;
834 } else {
835 sw = pus->Buffer;
836 len = pus->Length / sizeof(WCHAR);
837 }
838 result = stringw(f, sw, len, field_width, precision, flags);
839 } else {
840 // print counted ascii string
841 PANSI_STRING pas = va_arg(args, PANSI_STRING);
842 if ((pas == NULL) || (pas->Buffer == NULL)) {
843 s = NULL;
844 len = -1;
845 } else {
846 s = pas->Buffer;
847 len = pas->Length;
848 }
849 result = stringa(f, s, -1, field_width, precision, flags);
850 }
851 if (result < 0)
852 return -1;
853 continue;*/
854
855 case 'e':
856 case 'E':
857 case 'f':
858 case 'g':
859 case 'G':
860 if (qualifier == 'l' || qualifier == 'L' ) {
861 _ldouble = va_arg(args, long double);
862
863 if ( _isnanl(_ldouble) )
864 {
865 f += "Nan";
866 }
867 else if ( !_finitel(_ldouble) )
868 {
869 if ( _ldouble < 0 )
870 f += "-Inf";
871 else
872 f += "+Inf";
873 } else {
874 if ( precision == -1 )
875 precision = 6;
876 result = numberfl(f,_ldouble,*fmt,field_width,precision,flags);
877 if (result < 0)
878 {
879 assert(!"TODO FIXME handle error better");
880 return f;
881 }
882 }
883 } else {
884 _double = (double)va_arg(args, double);
885
886 if ( _isnan(_double) )
887 {
888 f += "Nan";
889 }
890 else if ( !_finite(_double) )
891 {
892 if ( _double < 0 )
893 f += "-Inf";
894 else
895 f += "+Inf";
896 }
897 else
898 {
899 if ( precision == -1 )
900 precision = 6;
901 result = numberf(f,_double,*fmt,field_width,precision,flags);
902 if (result < 0)
903 {
904 assert(!"TODO FIXME handle error better");
905 return f;
906 }
907 }
908 }
909 continue;
910
911 case 'p':
912 if (field_width == -1) {
913 field_width = 2*sizeof(void *);
914 flags |= ZEROPAD;
915 }
916 result = number(f,
917 (unsigned long) va_arg(args, void *), 16,
918 field_width, precision, flags);
919 if (result < 0)
920 {
921 assert(!"TODO FIXME handle error better");
922 return f;
923 }
924 continue;
925
926 case 'n':
927 if (qualifier == 'l') {
928 long * ip = va_arg(args, long *);
929 *ip = 0;
930 } else {
931 int * ip = va_arg(args, int *);
932 *ip = 0;
933 }
934 continue;
935
936 /* integer number formats - set up the flags and "break" */
937 case 'o':
938 base = 8;
939 break;
940
941 case 'b':
942 base = 2;
943 break;
944
945 case 'X':
946 flags |= LARGE;
947 case 'x':
948 base = 16;
949 break;
950
951 case 'd':
952 case 'i':
953 flags |= SIGN;
954 case 'u':
955 break;
956
957 default:
958 if (*fmt != '%')
959 {
960 f += '%';
961 }
962 if (*fmt)
963 {
964 f += *fmt;
965 }
966 else
967 --fmt;
968 continue;
969 }
970
971 if (qualifier == 'I')
972 num = va_arg(args, ULONGLONG);
973 else if (qualifier == 'l') {
974 if (flags & SIGN)
975 num = va_arg(args, long);
976 else
977 num = va_arg(args, unsigned long);
978 }
979 else if (qualifier == 'h') {
980 if (flags & SIGN)
981 num = va_arg(args, int);
982 else
983 num = va_arg(args, unsigned int);
984 }
985 else if (flags & SIGN)
986 num = va_arg(args, int);
987 else
988 num = va_arg(args, unsigned int);
989 result = number(f, num, base, field_width, precision, flags);
990 if (result < 0)
991 {
992 assert(!"TODO FIXME handle error better");
993 return f;
994 }
995 }
996 //putc('\0',f);
997 return f;
998 }