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