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