Fix pch usage in most of the rest of crt.lib. Stop the abuse of including io.h, stdio...
[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 == 'g' || exp_sign == 'G' || exp_sign == 'e' || exp_sign == 'E' ) {
215 ie = ((unsigned int)n.n->exponent - (unsigned int)0x3ff);
216 exponent = ie/3.321928;
217 }
218
219 if ( exp_sign == 'g' || exp_sign == 'G' ) {
220 type |= ZEROTRUNC;
221 if ( exponent < -4 || fabs(exponent) >= precision )
222 exp_sign -= 2; // g -> e and G -> E
223 else
224 exp_sign = 'f';
225 }
226
227 if ( exp_sign == 'e' || exp_sign == 'E' ) {
228 frac = modf(exponent,&e);
229 if ( frac > 0.5 )
230 e++;
231 else if ( frac < -0.5 )
232 e--;
233
234 result = numberf(f,__n/pow(10.0L,e),'f',size-4, precision, type);
235 if (result < 0)
236 return -1;
237 done += result;
238 if (putc( exp_sign,f) == EOF)
239 return -1;
240 done++;
241 size--;
242 ie = (long)e;
243 type = LEFT | PLUS;
244 if ( ie < 0 )
245 type |= SIGN;
246
247 result = number(f,ie, 10,2, 2,type );
248 if (result < 0)
249 return -1;
250 done += result;
251 return done;
252 }
253
254 if ( exp_sign == 'f' ) {
255 buf = alloca(4096);
256 if (type & LEFT) {
257 type &= ~ZEROPAD;
258 }
259
260 c = (type & ZEROPAD) ? '0' : ' ';
261 sign = 0;
262 if (type & SIGN) {
263 if (__n < 0) {
264 sign = '-';
265 __n = fabs(__n);
266 size--;
267 } else if (type & PLUS) {
268 sign = '+';
269 size--;
270 } else if (type & SPACE) {
271 sign = ' ';
272 size--;
273 }
274 }
275
276 frac = modf(__n,&intr);
277
278 // # flags forces a . and prevents trucation of trailing zero's
279
280 if ( precision > 0 ) {
281 //frac = modfl(__n,&intr);
282 i = precision-1;
283 while ( i >= 0 ) {
284 frac*=10.0L;
285 frac = modf(frac, &p);
286 buf[i] = (int)p + '0';
287 i--;
288 }
289 i = precision;
290 size -= precision;
291
292 ro = 0;
293 if ( frac > 0.5 ) {
294 ro = 1;
295 }
296
297 if ( precision >= 1 || type & SPECIAL) {
298 buf[i++] = '.';
299 size--;
300 }
301 }
302
303 if ( intr == 0.0 ) {
304 buf[i++] = '0';
305 size--;
306 }
307 else {
308 while ( intr > 0.0 ) {
309 p = intr;
310 intr/=10.0L;
311 modf(intr, &intr);
312
313 p -= 10.0*intr;
314
315 buf[i++] = (int)p + '0';
316 size--;
317 }
318 }
319
320 j = 0;
321 while ( j < i && ro == 1) {
322 if ( buf[j] >= '0' && buf[j] <= '8' ) {
323 buf[j]++;
324 ro = 0;
325 }
326 else if ( buf[j] == '9' ) {
327 buf[j] = '0';
328 }
329 j++;
330 }
331 if ( ro == 1 )
332 buf[i++] = '1';
333
334 buf[i] = 0;
335
336 size -= precision;
337 if (!(type&(ZEROPAD+LEFT)))
338 while(size-->0)
339 {
340 if (putc(' ',f) == EOF)
341 return -1;
342 done++;
343 }
344 if (sign)
345 {
346 if (putc( sign,f) == EOF)
347 return -1;
348 done++;
349 }
350
351 if (!(type&(ZEROPAD+LEFT)))
352 while(size-->0)
353 {
354 if (putc(' ',f) == EOF)
355 return -1;
356 done++;
357 }
358 if (type & SPECIAL) {
359 }
360
361 if (!(type & LEFT))
362 while (size-- > 0)
363 {
364 if (putc(c,f) == EOF)
365 return -1;
366 done++;
367 }
368
369 tmp = buf;
370 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) ) {
371 j = 0;
372 while ( j < i && ( *tmp == '0' || *tmp == '.' )) {
373 tmp++;
374 i--;
375 }
376 }
377 // else
378 // while (i < precision--)
379 // putc('0', f);
380 while (i-- > 0)
381 {
382 if (putc(tmp[i],f) == EOF)
383 return -1;
384 done++;
385 }
386 while (size-- > 0)
387 {
388 if (putc(' ', f) == EOF)
389 return -1;
390 done++;
391 }
392 }
393 return done;
394 }
395
396
397
398
399 static int string(FILE *f, const char* s, int len, int field_width, int precision, int flags)
400 {
401 int i, done = 0;
402 if (s == NULL)
403 {
404 s = "<NULL>";
405 len = 6;
406 }
407 else
408 {
409 if (len == -1)
410 {
411 len = 0;
412 while ((unsigned int)len < (unsigned int)precision && s[len])
413 len++;
414 }
415 else
416 {
417 if ((unsigned int)len > (unsigned int)precision)
418 len = precision;
419 }
420 }
421 if (!(flags & LEFT))
422 while (len < field_width--)
423 {
424 if (putc(' ', f) == EOF)
425 return -1;
426 done++;
427 }
428 for (i = 0; i < len; ++i)
429 {
430 if (putc(*s++, f) == EOF)
431 return -1;
432 done++;
433 }
434 while (len < field_width--)
435 {
436 if (putc(' ', f) == EOF)
437 return -1;
438 done++;
439 }
440 return done;
441 }
442
443 static int stringw(FILE *f, const wchar_t* sw, int len, int field_width, int precision, int flags)
444 {
445 int i, done = 0;
446 char * mb;
447 if (sw == NULL)
448 {
449 sw = L"<NULL>";
450 len = 6;
451 }
452 else
453 {
454 if (len == -1)
455 {
456 len = 0;
457 while ((unsigned int)len < (unsigned int)precision && sw[len])
458 len++;
459 }
460 else
461 {
462 if ((unsigned int)len > (unsigned int)precision)
463 len = precision;
464 }
465 }
466 if (!(flags & LEFT))
467 while (len < field_width--)
468 {
469 if (putc(' ', f) == EOF)
470 return -1;
471 done++;
472 }
473 mb = malloc(MB_CUR_MAX * sizeof(char));
474 if(!mb)
475 return -1;
476 for (i = 0; i < len; ++i)
477 {
478 int mbcount, j;
479 mbcount = wctomb(mb, *sw++);
480 if (mbcount <= 0)
481 {
482 break;
483 }
484 for (j = 0; j < mbcount; j++)
485 {
486 if (putc(mb[j], f) == EOF)
487 {
488 free(mb);
489 return -1;
490 }
491 done++;
492 }
493 }
494 while (len < field_width--)
495 {
496 if (putc(' ', f) == EOF)
497 {
498 free(mb);
499 return -1;
500 }
501 done++;
502 }
503 free(mb);
504 return done;
505 }
506
507 int __vfprintf(FILE *f, const char *fmt, va_list args)
508 {
509 int len;
510 ULONGLONG num;
511 int base;
512 double _double;
513 const char *s;
514 const wchar_t *sw;
515 int result, done = 0;
516
517 int flags; /* flags to number() */
518
519 int field_width; /* width of output field */
520 int precision; /* min. # of digits for integers; max
521 number of chars for from string */
522 int qualifier = 0; /* 'h', 'l', 'L' or 'I64' for integer fields */
523
524 for (; *fmt ; ++fmt) {
525 if (*fmt != '%') {
526 if (putc(*fmt,f) == EOF)
527 return -1;
528 done++;
529 continue;
530 }
531
532 /* process flags */
533 flags = 0;
534 repeat:
535 ++fmt; /* this also skips first '%' */
536 switch (*fmt) {
537 case '-': flags |= LEFT; goto repeat;
538 case '+': flags |= PLUS; goto repeat;
539 case ' ': flags |= SPACE; goto repeat;
540 case '#': flags |= SPECIAL; goto repeat;
541 case '0': flags |= ZEROPAD; goto repeat;
542 }
543
544 /* get field width */
545 field_width = -1;
546 if (isdigit(*fmt))
547 field_width = skip_atoi(&fmt);
548 else if (*fmt == '*') {
549 ++fmt;
550 /* it's the next argument */
551 field_width = va_arg(args, int);
552 if (field_width < 0) {
553 field_width = -field_width;
554 flags |= LEFT;
555 }
556 }
557
558 /* get the precision */
559 precision = -1;
560 if (*fmt == '.') {
561 ++fmt;
562 if (isdigit(*fmt))
563 precision = skip_atoi(&fmt);
564 else if (*fmt == '*') {
565 ++fmt;
566 /* it's the next argument */
567 precision = va_arg(args, int);
568 }
569 if (precision < 0)
570 precision = 0;
571 }
572
573 /* get the conversion qualifier */
574 qualifier = 0;
575 // %Z can be just stand alone or as size_t qualifier
576 if ( *fmt == 'Z' ) {
577 qualifier = *fmt;
578 switch ( *(fmt+1)) {
579 case 'o':
580 case 'b':
581 case 'X':
582 case 'x':
583 case 'd':
584 case 'i':
585 case 'u':
586 ++fmt;
587 break;
588 default:
589 break;
590 }
591 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
592 qualifier = *fmt;
593 ++fmt;
594 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
595 qualifier = *fmt;
596 fmt += 3;
597 }
598
599 // go fine with ll instead of L
600 if ( *fmt == 'l' ) {
601 ++fmt;
602 qualifier = 'L';
603 }
604
605 /* default base */
606 base = 10;
607
608 switch (*fmt) {
609 case 'c':
610 if (!(flags & LEFT))
611 while (--field_width > 0)
612 {
613 if (putc(' ', f) == EOF)
614 return -1;
615 done++;
616 }
617 if (qualifier == 'l' || qualifier == 'w')
618 {
619 if (putc((unsigned char)(wchar_t) va_arg(args, int), f) == EOF)
620 return -1;
621 done++;
622 }
623 else
624 {
625 if (putc((unsigned char) va_arg(args, int), f) == EOF)
626 return -1;
627 done++;
628 }
629 while (--field_width > 0)
630 {
631 if (putc(' ', f) == EOF)
632 return -1;
633 done++;
634 }
635 continue;
636
637 case 'C':
638 if (!(flags & LEFT))
639 while (--field_width > 0)
640 {
641 if (putc(' ', f) == EOF)
642 return -1;
643 done++;
644 }
645 if (qualifier == 'h')
646 {
647 if (putc((unsigned char) va_arg(args, int), f) == EOF)
648 return -1;
649 done++;
650 }
651 else
652 {
653 if (putc((unsigned char)(wchar_t) va_arg(args, int), f) == EOF)
654 return -1;
655 done++;
656 }
657 while (--field_width > 0)
658 {
659 if (putc(' ', f) == EOF)
660 return -1;
661 done++;
662 }
663 continue;
664
665 case 's':
666 if (qualifier == 'l' || qualifier == 'w') {
667 /* print unicode string */
668 sw = va_arg(args, wchar_t *);
669 result = stringw(f, sw, -1, field_width, precision, flags);
670 } else {
671 /* print ascii string */
672 s = va_arg(args, char *);
673 result = string(f, s, -1, field_width, precision, flags);
674 }
675 if (result < 0)
676 return -1;
677 done += result;
678 continue;
679
680 case 'S':
681 if (qualifier == 'h') {
682 /* print ascii string */
683 s = va_arg(args, char *);
684 result = string(f, s, -1, field_width, precision, flags);
685 } else {
686 /* print unicode string */
687 sw = va_arg(args, wchar_t *);
688 result = stringw(f, sw, -1, field_width, precision, flags);
689 }
690 if (result < 0)
691 return -1;
692 done += result;
693 continue;
694
695 case 'Z':
696 if (qualifier == 'w') {
697 /* print counted unicode string */
698 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
699 if ((pus == NULL) || (pus->Buffer == NULL)) {
700 sw = NULL;
701 len = -1;
702 } else {
703 sw = pus->Buffer;
704 len = pus->Length / sizeof(WCHAR);
705 }
706 result = stringw(f, sw, len, field_width, precision, flags);
707 } else {
708 /* print counted ascii string */
709 PANSI_STRING pas = va_arg(args, PANSI_STRING);
710 if ((pas == NULL) || (pas->Buffer == NULL)) {
711 s = NULL;
712 len = -1;
713 } else {
714 s = pas->Buffer;
715 len = pas->Length;
716 }
717 result = string(f, s, -1, field_width, precision, flags);
718 }
719 if (result < 0)
720 return -1;
721 done += result;
722 continue;
723
724 case 'e':
725 case 'E':
726 case 'f':
727 case 'g':
728 case 'G':
729 _double = (double)va_arg(args, double);
730
731 if ( _isnan(_double) ) {
732 s = "Nan";
733 len = 3;
734 while ( len > 0 ) {
735 if (putc(*s++,f) == EOF)
736 return -1;
737 done++;
738 len --;
739 }
740 } else if ( _isinf(_double) < 0 ) {
741 s = "-Inf";
742 len = 4;
743 while ( len > 0 ) {
744 if (putc(*s++,f) == EOF)
745 return -1;
746 done++;
747 len --;
748 }
749 } else if ( _isinf(_double) > 0 ) {
750 s = "+Inf";
751 len = 4;
752 while ( len > 0 ) {
753 if (putc(*s++,f) == EOF)
754 return -1;
755 done++;
756 len --;
757 }
758 } else {
759 if ( precision == -1 )
760 precision = 6;
761 result = numberf(f,_double,*fmt,field_width,precision,flags);
762 if (result < 0)
763 return -1;
764 done += result;
765 }
766 continue;
767
768 case 'p':
769 if (field_width == -1) {
770 field_width = 2*sizeof(void *);
771 flags |= ZEROPAD;
772 }
773 result = number(f,
774 (unsigned long) va_arg(args, void *), 16,
775 field_width, precision, flags);
776 if (result < 0)
777 return -1;
778 done += result;
779 continue;
780
781 case 'n':
782 if (qualifier == 'l') {
783 long * ip = va_arg(args, long *);
784 *ip = 0;
785 } else {
786 int * ip = va_arg(args, int *);
787 *ip = 0;
788 }
789 continue;
790
791 /* integer number formats - set up the flags and "break" */
792 case 'o':
793 base = 8;
794 break;
795
796 case 'b':
797 base = 2;
798 break;
799
800 case 'X':
801 flags |= LARGE;
802 case 'x':
803 base = 16;
804 break;
805
806 case 'd':
807 case 'i':
808 flags |= SIGN;
809 case 'u':
810 break;
811
812 default:
813 if (*fmt != '%')
814 {
815 if (putc('%', f) == EOF)
816 return -1;
817 done++;
818 }
819 if (*fmt)
820 {
821 if (putc(*fmt, f) == EOF)
822 return -1;
823 done++;
824 }
825 else
826 --fmt;
827 continue;
828 }
829
830 if (qualifier == 'I')
831 num = va_arg(args, ULONGLONG);
832 else if (qualifier == 'l') {
833 if (flags & SIGN)
834 num = va_arg(args, long);
835 else
836 num = va_arg(args, unsigned long);
837 }
838 else if (qualifier == 'h') {
839 if (flags & SIGN)
840 num = va_arg(args, int);
841 else
842 num = va_arg(args, unsigned int);
843 }
844 else if (flags & SIGN)
845 num = va_arg(args, int);
846 else
847 num = va_arg(args, unsigned int);
848 result = number(f, num, base, field_width, precision, flags);
849 if (result < 0)
850 return -1;
851 done += result;
852 }
853 //putc('\0',f);
854 return done;
855 }
856
857 /* EOF */