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