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