e470a18aaa4036c0578c0c2d72192b95c3410b3e
[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
371 if ( type & ZEROTRUNC && ((type & SPECIAL) != SPECIAL) ) {
372 j = 0;
373 while ( j < i && *tmp == L'0' ) {
374 tmp++;
375 i--;
376 }
377 if ( j < i && *tmp == L'.' ) {
378 tmp++;
379 i--;
380 }
381 }
382
383
384 // else
385 // while (i < precision--)
386 // putc('0', f);
387 while (i-- > 0)
388 {
389 if (putc(tmp[i],f) == EOF)
390 return -1;
391 done++;
392 }
393 while (size-- > 0)
394 {
395 if (putc(' ', f) == EOF)
396 return -1;
397 done++;
398 }
399 }
400 return done;
401 }
402
403
404
405
406 static int string(FILE *f, const char* s, int len, int field_width, int precision, int flags)
407 {
408 int i, done = 0;
409 if (s == NULL)
410 {
411 s = "<NULL>";
412 len = 6;
413 }
414 else
415 {
416 if (len == -1)
417 {
418 len = 0;
419 while ((unsigned int)len < (unsigned int)precision && s[len])
420 len++;
421 }
422 else
423 {
424 if ((unsigned int)len > (unsigned int)precision)
425 len = precision;
426 }
427 }
428 if (!(flags & LEFT))
429 while (len < field_width--)
430 {
431 if (putc(' ', f) == EOF)
432 return -1;
433 done++;
434 }
435 for (i = 0; i < len; ++i)
436 {
437 if (putc(*s++, f) == EOF)
438 return -1;
439 done++;
440 }
441 while (len < field_width--)
442 {
443 if (putc(' ', f) == EOF)
444 return -1;
445 done++;
446 }
447 return done;
448 }
449
450 static int stringw(FILE *f, const wchar_t* sw, int len, int field_width, int precision, int flags)
451 {
452 int i, done = 0;
453 char * mb;
454 if (sw == NULL)
455 {
456 sw = L"<NULL>";
457 len = 6;
458 }
459 else
460 {
461 if (len == -1)
462 {
463 len = 0;
464 while ((unsigned int)len < (unsigned int)precision && sw[len])
465 len++;
466 }
467 else
468 {
469 if ((unsigned int)len > (unsigned int)precision)
470 len = precision;
471 }
472 }
473 if (!(flags & LEFT))
474 while (len < field_width--)
475 {
476 if (putc(' ', f) == EOF)
477 return -1;
478 done++;
479 }
480 mb = malloc(MB_CUR_MAX * sizeof(char));
481 if(!mb)
482 return -1;
483 for (i = 0; i < len; ++i)
484 {
485 int mbcount, j;
486 mbcount = wctomb(mb, *sw++);
487 if (mbcount <= 0)
488 {
489 break;
490 }
491 for (j = 0; j < mbcount; j++)
492 {
493 if (putc(mb[j], f) == EOF)
494 {
495 free(mb);
496 return -1;
497 }
498 done++;
499 }
500 }
501 while (len < field_width--)
502 {
503 if (putc(' ', f) == EOF)
504 {
505 free(mb);
506 return -1;
507 }
508 done++;
509 }
510 free(mb);
511 return done;
512 }
513
514 int __vfprintf(FILE *f, const char *fmt, va_list args)
515 {
516 int len;
517 ULONGLONG num;
518 int base;
519 double _double;
520 const char *s;
521 const wchar_t *sw;
522 int result, done = 0;
523
524 int flags; /* flags to number() */
525
526 int field_width; /* width of output field */
527 int precision; /* min. # of digits for integers; max
528 number of chars for from string */
529 int qualifier = 0; /* 'h', 'l', 'L' or 'I64' for integer fields */
530
531 for (; *fmt ; ++fmt) {
532 if (*fmt != '%') {
533 if (putc(*fmt,f) == EOF)
534 return -1;
535 done++;
536 continue;
537 }
538
539 /* process flags */
540 flags = 0;
541 repeat:
542 ++fmt; /* this also skips first '%' */
543 switch (*fmt) {
544 case '-': flags |= LEFT; goto repeat;
545 case '+': flags |= PLUS; goto repeat;
546 case ' ': flags |= SPACE; goto repeat;
547 case '#': flags |= SPECIAL; goto repeat;
548 case '0': flags |= ZEROPAD; goto repeat;
549 }
550
551 /* get field width */
552 field_width = -1;
553 if (isdigit(*fmt))
554 field_width = skip_atoi(&fmt);
555 else if (*fmt == '*') {
556 ++fmt;
557 /* it's the next argument */
558 field_width = va_arg(args, int);
559 if (field_width < 0) {
560 field_width = -field_width;
561 flags |= LEFT;
562 }
563 }
564
565 /* get the precision */
566 precision = -1;
567 if (*fmt == '.') {
568 ++fmt;
569 if (isdigit(*fmt))
570 precision = skip_atoi(&fmt);
571 else if (*fmt == '*') {
572 ++fmt;
573 /* it's the next argument */
574 precision = va_arg(args, int);
575 }
576 if (precision < 0)
577 precision = 0;
578 }
579
580 /* get the conversion qualifier */
581 qualifier = 0;
582 // %Z can be just stand alone or as size_t qualifier
583 if ( *fmt == 'Z' ) {
584 qualifier = *fmt;
585 switch ( *(fmt+1)) {
586 case 'o':
587 case 'b':
588 case 'X':
589 case 'x':
590 case 'd':
591 case 'i':
592 case 'u':
593 ++fmt;
594 break;
595 default:
596 break;
597 }
598 } else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
599 qualifier = *fmt;
600 ++fmt;
601 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
602 qualifier = *fmt;
603 fmt += 3;
604 }
605
606 // go fine with ll instead of L
607 if ( *fmt == 'l' ) {
608 ++fmt;
609 qualifier = 'L';
610 }
611
612 /* default base */
613 base = 10;
614
615 switch (*fmt) {
616 case 'c':
617 if (!(flags & LEFT))
618 while (--field_width > 0)
619 {
620 if (putc(' ', f) == EOF)
621 return -1;
622 done++;
623 }
624 if (qualifier == 'l' || qualifier == 'w')
625 {
626 if (putc((unsigned char)(wchar_t) va_arg(args, int), f) == EOF)
627 return -1;
628 done++;
629 }
630 else
631 {
632 if (putc((unsigned char) va_arg(args, int), f) == EOF)
633 return -1;
634 done++;
635 }
636 while (--field_width > 0)
637 {
638 if (putc(' ', f) == EOF)
639 return -1;
640 done++;
641 }
642 continue;
643
644 case 'C':
645 if (!(flags & LEFT))
646 while (--field_width > 0)
647 {
648 if (putc(' ', f) == EOF)
649 return -1;
650 done++;
651 }
652 if (qualifier == 'h')
653 {
654 if (putc((unsigned char) va_arg(args, int), f) == EOF)
655 return -1;
656 done++;
657 }
658 else
659 {
660 if (putc((unsigned char)(wchar_t) va_arg(args, int), f) == EOF)
661 return -1;
662 done++;
663 }
664 while (--field_width > 0)
665 {
666 if (putc(' ', f) == EOF)
667 return -1;
668 done++;
669 }
670 continue;
671
672 case 's':
673 if (qualifier == 'l' || qualifier == 'w') {
674 /* print unicode string */
675 sw = va_arg(args, wchar_t *);
676 result = stringw(f, sw, -1, field_width, precision, flags);
677 } else {
678 /* print ascii string */
679 s = va_arg(args, char *);
680 result = string(f, s, -1, field_width, precision, flags);
681 }
682 if (result < 0)
683 return -1;
684 done += result;
685 continue;
686
687 case 'S':
688 if (qualifier == 'h') {
689 /* print ascii string */
690 s = va_arg(args, char *);
691 result = string(f, s, -1, field_width, precision, flags);
692 } else {
693 /* print unicode string */
694 sw = va_arg(args, wchar_t *);
695 result = stringw(f, sw, -1, field_width, precision, flags);
696 }
697 if (result < 0)
698 return -1;
699 done += result;
700 continue;
701
702 case 'Z':
703 if (qualifier == 'w') {
704 /* print counted unicode string */
705 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
706 if ((pus == NULL) || (pus->Buffer == NULL)) {
707 sw = NULL;
708 len = -1;
709 } else {
710 sw = pus->Buffer;
711 len = pus->Length / sizeof(WCHAR);
712 }
713 result = stringw(f, sw, len, field_width, precision, flags);
714 } else {
715 /* print counted ascii string */
716 PANSI_STRING pas = va_arg(args, PANSI_STRING);
717 if ((pas == NULL) || (pas->Buffer == NULL)) {
718 s = NULL;
719 len = -1;
720 } else {
721 s = pas->Buffer;
722 len = pas->Length;
723 }
724 result = string(f, s, -1, field_width, precision, flags);
725 }
726 if (result < 0)
727 return -1;
728 done += result;
729 continue;
730
731 case 'e':
732 case 'E':
733 case 'f':
734 case 'g':
735 case 'G':
736 _double = (double)va_arg(args, double);
737
738 if ( _isnan(_double) ) {
739 s = "Nan";
740 len = 3;
741 while ( len > 0 ) {
742 if (putc(*s++,f) == EOF)
743 return -1;
744 done++;
745 len --;
746 }
747 } else if ( _isinf(_double) < 0 ) {
748 s = "-Inf";
749 len = 4;
750 while ( len > 0 ) {
751 if (putc(*s++,f) == EOF)
752 return -1;
753 done++;
754 len --;
755 }
756 } else if ( _isinf(_double) > 0 ) {
757 s = "+Inf";
758 len = 4;
759 while ( len > 0 ) {
760 if (putc(*s++,f) == EOF)
761 return -1;
762 done++;
763 len --;
764 }
765 } else {
766 if ( precision == -1 )
767 precision = 6;
768 result = numberf(f,_double,*fmt,field_width,precision,flags);
769 if (result < 0)
770 return -1;
771 done += result;
772 }
773 continue;
774
775 case 'p':
776 if (field_width == -1) {
777 field_width = 2*sizeof(void *);
778 flags |= ZEROPAD;
779 }
780 result = number(f,
781 (unsigned long) va_arg(args, void *), 16,
782 field_width, precision, flags);
783 if (result < 0)
784 return -1;
785 done += result;
786 continue;
787
788 case 'n':
789 if (qualifier == 'l') {
790 long * ip = va_arg(args, long *);
791 *ip = 0;
792 } else {
793 int * ip = va_arg(args, int *);
794 *ip = 0;
795 }
796 continue;
797
798 /* integer number formats - set up the flags and "break" */
799 case 'o':
800 base = 8;
801 break;
802
803 case 'b':
804 base = 2;
805 break;
806
807 case 'X':
808 flags |= LARGE;
809 case 'x':
810 base = 16;
811 break;
812
813 case 'd':
814 case 'i':
815 flags |= SIGN;
816 case 'u':
817 break;
818
819 default:
820 if (*fmt != '%')
821 {
822 if (putc('%', f) == EOF)
823 return -1;
824 done++;
825 }
826 if (*fmt)
827 {
828 if (putc(*fmt, f) == EOF)
829 return -1;
830 done++;
831 }
832 else
833 --fmt;
834 continue;
835 }
836
837 if (qualifier == 'I')
838 num = va_arg(args, ULONGLONG);
839 else if (qualifier == 'l') {
840 if (flags & SIGN)
841 num = va_arg(args, long);
842 else
843 num = va_arg(args, unsigned long);
844 }
845 else if (qualifier == 'h') {
846 if (flags & SIGN)
847 num = va_arg(args, int);
848 else
849 num = va_arg(args, unsigned int);
850 }
851 else if (flags & SIGN)
852 num = va_arg(args, int);
853 else
854 num = va_arg(args, unsigned int);
855 result = number(f, num, base, field_width, precision, flags);
856 if (result < 0)
857 return -1;
858 done += result;
859 }
860 //putc('\0',f);
861 return done;
862 }
863
864 /* EOF */