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