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