Sync with trunk r58740.
[reactos.git] / win32ss / drivers / font / ftfd / sprintf.c
1 /*
2 * PROGRAMMERS: David Welch
3 * Eric Kohl
4 *
5 * TODO:
6 * - Verify the implementation of '%Z'.
7 */
8
9 /*
10 * linux/lib/vsprintf.c
11 *
12 * Copyright (C) 1991, 1992 Linus Torvalds
13 */
14
15 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
16 /*
17 * Wirzenius wrote this portably, Torvalds fucked it up :-)
18 */
19
20 #include <ndk/ntndk.h>
21
22 #define ZEROPAD 1 /* pad with zero */
23 #define SIGN 2 /* unsigned/signed long */
24 #define PLUS 4 /* show plus */
25 #define SPACE 8 /* space if plus */
26 #define LEFT 16 /* left justified */
27 #define SPECIAL 32 /* 0x */
28 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
29 #define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
30 typedef struct {
31 unsigned int mantissal:32;
32 unsigned int mantissah:20;
33 unsigned int exponent:11;
34 unsigned int sign:1;
35 } double_t;
36
37 static
38 __inline
39 int
40 _isinf(double __x)
41 {
42 union
43 {
44 double* __x;
45 double_t* x;
46 } x;
47
48 x.__x = &__x;
49 return ( x.x->exponent == 0x7ff && ( x.x->mantissah == 0 && x.x->mantissal == 0 ));
50 }
51
52 static
53 __inline
54 int
55 _isnan(double __x)
56 {
57 union
58 {
59 double* __x;
60 double_t* x;
61 } x;
62 x.__x = &__x;
63 return ( x.x->exponent == 0x7ff && ( x.x->mantissah != 0 || x.x->mantissal != 0 ));
64 }
65
66
67 static
68 __inline
69 int
70 do_div(long long *n, int base)
71 {
72 int a;
73 a = ((unsigned long long) *n) % (unsigned) base;
74 *n = ((unsigned long long) *n) / (unsigned) base;
75 return a;
76 }
77
78
79 static int skip_atoi(const char **s)
80 {
81 int i=0;
82
83 while (isdigit(**s))
84 i = i*10 + *((*s)++) - '0';
85 return i;
86 }
87
88
89 static char *
90 number(char * buf, char * end, long long num, int base, int size, int precision, int type)
91 {
92 char c,sign,tmp[66];
93 const char *digits;
94 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
95 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
96 int i;
97
98 digits = (type & LARGE) ? large_digits : small_digits;
99 if (type & LEFT)
100 type &= ~ZEROPAD;
101 if (base < 2 || base > 36)
102 return 0;
103 c = (type & ZEROPAD) ? '0' : ' ';
104 sign = 0;
105 if (type & SIGN) {
106 if (num < 0) {
107 sign = '-';
108 num = -num;
109 size--;
110 } else if (type & PLUS) {
111 sign = '+';
112 size--;
113 } else if (type & SPACE) {
114 sign = ' ';
115 size--;
116 }
117 }
118
119 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
120 if (base == 16)
121 size -= 2;
122
123 }
124 i = 0;
125 if ((num == 0) && (precision !=0))
126 tmp[i++] = '0';
127 else while (num != 0)
128 tmp[i++] = digits[do_div(&num,base)];
129 if (i > precision)
130 precision = i;
131 size -= precision;
132 if (!(type&(ZEROPAD+LEFT))) {
133 while(size-->0) {
134 if (buf <= end)
135 *buf = ' ';
136 ++buf;
137 }
138 }
139 if (sign) {
140 if (buf <= end)
141 *buf = sign;
142 ++buf;
143 }
144
145 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
146 if (base==16) {
147 if (buf <= end)
148 *buf = '0';
149 ++buf;
150 if (buf <= end)
151 *buf = digits[33];
152 ++buf;
153 }
154 }
155
156 if (!(type & LEFT)) {
157 while (size-- > 0) {
158 if (buf <= end)
159 *buf = c;
160 ++buf;
161 }
162 }
163 while (i < precision--) {
164 if (buf <= end)
165 *buf = '0';
166 ++buf;
167 }
168 while (i-- > 0) {
169 if (buf <= end)
170 *buf = tmp[i];
171 ++buf;
172 }
173 while (size-- > 0) {
174 if (buf <= end)
175 *buf = ' ';
176 ++buf;
177 }
178
179 return buf;
180 }
181
182 static char *
183 numberf(char * buf, char * end, double num, int base, int size, int precision, int type)
184 {
185 char c,sign,tmp[66];
186 const char *digits;
187 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
188 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
189 int i;
190 long long x;
191
192 /* FIXME
193 the float version of number is direcly copy of number
194 */
195
196 digits = (type & LARGE) ? large_digits : small_digits;
197 if (type & LEFT)
198 type &= ~ZEROPAD;
199 if (base < 2 || base > 36)
200 return 0;
201 c = (type & ZEROPAD) ? '0' : ' ';
202 sign = 0;
203 if (type & SIGN) {
204 if (num < 0) {
205 sign = '-';
206 num = -num;
207 size--;
208 } else if (type & PLUS) {
209 sign = '+';
210 size--;
211 } else if (type & SPACE) {
212 sign = ' ';
213 size--;
214 }
215 }
216 if (type & SPECIAL) {
217 if (base == 16)
218 size -= 2;
219 else if (base == 8)
220 size--;
221 }
222 i = 0;
223 if (num == 0)
224 tmp[i++] = '0';
225 else while (num != 0)
226 {
227 x = num;
228 tmp[i++] = digits[do_div(&x,base)];
229 num=x;
230 }
231 if (i > precision)
232 precision = i;
233 size -= precision;
234 if (!(type&(ZEROPAD+LEFT))) {
235 while(size-->0) {
236 if (buf <= end)
237 *buf = ' ';
238 ++buf;
239 }
240 }
241 if (sign) {
242 if (buf <= end)
243 *buf = sign;
244 ++buf;
245 }
246 if (type & SPECIAL) {
247 if (base==8) {
248 if (buf <= end)
249 *buf = '0';
250 ++buf;
251 } else if (base==16) {
252 if (buf <= end)
253 *buf = '0';
254 ++buf;
255 if (buf <= end)
256 *buf = digits[33];
257 ++buf;
258 }
259 }
260 if (!(type & LEFT)) {
261 while (size-- > 0) {
262 if (buf <= end)
263 *buf = c;
264 ++buf;
265 }
266 }
267 while (i < precision--) {
268 if (buf <= end)
269 *buf = '0';
270 ++buf;
271 }
272 while (i-- > 0) {
273 if (buf <= end)
274 *buf = tmp[i];
275 ++buf;
276 }
277 while (size-- > 0) {
278 if (buf <= end)
279 *buf = ' ';
280 ++buf;
281 }
282 return buf;
283 }
284
285 static char*
286 string(char* buf, char* end, const char* s, int len, int field_width, int precision, int flags)
287 {
288 int i;
289 char c;
290
291 c = (flags & ZEROPAD) ? '0' : ' ';
292
293 if (s == NULL)
294 {
295 s = "<NULL>";
296 len = 6;
297 }
298 else
299 {
300 if (len == -1)
301 {
302 len = 0;
303 while ((unsigned int)len < (unsigned int)precision && s[len])
304 len++;
305 }
306 else
307 {
308 if ((unsigned int)len > (unsigned int)precision)
309 len = precision;
310 }
311 }
312 if (!(flags & LEFT))
313 while (len < field_width--)
314 {
315 if (buf <= end)
316 *buf = c;
317 ++buf;
318 }
319 for (i = 0; i < len; ++i)
320 {
321 if (buf <= end)
322 *buf = *s++;
323 ++buf;
324 }
325 while (len < field_width--)
326 {
327 if (buf <= end)
328 *buf = ' ';
329 ++buf;
330 }
331 return buf;
332 }
333
334 static char*
335 stringw(char* buf, char* end, const wchar_t* sw, int len, int field_width, int precision, int flags)
336 {
337 int i;
338 char c;
339
340 c = (flags & ZEROPAD) ? '0' : ' ';
341
342 if (sw == NULL)
343 {
344 sw = L"<NULL>";
345 len = 6;
346 }
347 else
348 {
349 if (len == -1)
350 {
351 len = 0;
352 while ((unsigned int)len < (unsigned int)precision && sw[len])
353 len++;
354 }
355 else
356 {
357 if ((unsigned int)len > (unsigned int)precision)
358 len = precision;
359 }
360 }
361 if (!(flags & LEFT))
362 while (len < field_width--)
363 {
364 if (buf <= end)
365 *buf = c;
366 buf++;
367 }
368 for (i = 0; i < len; ++i)
369 {
370 if (buf <= end)
371 *buf = (unsigned char)(*sw++);
372 buf++;
373 }
374 while (len < field_width--)
375 {
376 if (buf <= end)
377 *buf = ' ';
378 buf++;
379 }
380 return buf;
381 }
382
383 /*
384 * @implemented
385 */
386 int __cdecl _vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
387 {
388 int len;
389 unsigned long long num;
390 double _double;
391
392 int base;
393 char *str, *end;
394 const char *s;
395 const wchar_t *sw;
396
397 int flags; /* flags to number() */
398
399 int field_width; /* width of output field */
400 int precision; /* min. # of digits for integers; max
401 number of chars for from string */
402 int qualifier; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
403
404 /* clear the string buffer with zero so we do not need NULL terment it at end */
405
406 str = buf;
407 end = buf + cnt - 1;
408 if (end < buf - 1) {
409 end = ((char *) -1);
410 cnt = end - buf + 1;
411 }
412
413 for ( ; *fmt ; ++fmt) {
414 if (*fmt != '%') {
415 if (str <= end)
416 *str = *fmt;
417 ++str;
418 continue;
419 }
420
421 /* process flags */
422 flags = 0;
423 repeat:
424 ++fmt; /* this also skips first '%' */
425 switch (*fmt) {
426 case '-': flags |= LEFT; goto repeat;
427 case '+': flags |= PLUS; goto repeat;
428 case ' ': flags |= SPACE; goto repeat;
429 case '#': flags |= SPECIAL; goto repeat;
430 case '0': flags |= ZEROPAD; goto repeat;
431 }
432
433 /* get field width */
434 field_width = -1;
435 if (isdigit(*fmt))
436 field_width = skip_atoi(&fmt);
437 else if (*fmt == '*') {
438 ++fmt;
439 /* it's the next argument */
440 field_width = va_arg(args, int);
441 if (field_width < 0) {
442 field_width = -field_width;
443 flags |= LEFT;
444 }
445 }
446
447 /* get the precision */
448 precision = -1;
449 if (*fmt == '.') {
450 ++fmt;
451 if (isdigit(*fmt))
452 precision = skip_atoi(&fmt);
453 else if (*fmt == '*') {
454 ++fmt;
455 /* it's the next argument */
456 precision = va_arg(args, int);
457 }
458 if (precision < 0)
459 precision = 0;
460 }
461
462 /* get the conversion qualifier */
463 qualifier = -1;
464 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
465 qualifier = *fmt;
466 ++fmt;
467 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
468 qualifier = *fmt;
469 fmt += 3;
470 } else if (*fmt == 'I' && *(fmt+1) == '3' && *(fmt+2) == '2') {
471 qualifier = 'l';
472 fmt += 3;
473 } else if (*fmt == 'F' && *(fmt+1) == 'p') {
474 fmt += 1;
475 flags |= REMOVEHEX;
476 }
477
478 /* default base */
479 base = 10;
480
481 switch (*fmt) {
482 case 'c': /* finished */
483 if (qualifier == 'l' || qualifier == 'w') {
484 wchar_t sw1[2];
485 /* print unicode string */
486 sw1[0] = (wchar_t) va_arg(args, int);
487 sw1[1] = 0;
488 str = stringw(str, end, (wchar_t *)&sw1, -1, field_width, precision, flags);
489 } else {
490 char s1[2];
491 /* print ascii string */
492 s1[0] = ( unsigned char) va_arg(args, int);
493 s1[1] = 0;
494 str = string(str, end, (char *)&s1, -1, field_width, precision, flags);
495 }
496 continue;
497
498 case 'C': /* finished */
499 if (!(flags & LEFT))
500 while (--field_width > 0) {
501 if (str <= end)
502 *str = ' ';
503 ++str;
504 }
505 if (qualifier == 'h') {
506 if (str <= end)
507 *str = (unsigned char) va_arg(args, int);
508 ++str;
509 } else {
510 if (str <= end)
511 *str = (unsigned char)(wchar_t) va_arg(args, int);
512 ++str;
513 }
514 while (--field_width > 0) {
515 if (str <= end)
516 *str = ' ';
517 ++str;
518 }
519 continue;
520
521 case 's': /* finished */
522 if (qualifier == 'l' || qualifier == 'w') {
523 /* print unicode string */
524 sw = va_arg(args, wchar_t *);
525 str = stringw(str, end, sw, -1, field_width, precision, flags);
526 } else {
527 /* print ascii string */
528 s = va_arg(args, char *);
529 str = string(str, end, s, -1, field_width, precision, flags);
530 }
531 continue;
532
533 case 'S':
534 if (qualifier == 'h') {
535 /* print ascii string */
536 s = va_arg(args, char *);
537 str = string(str, end, s, -1, field_width, precision, flags);
538 } else {
539 /* print unicode string */
540 sw = va_arg(args, wchar_t *);
541 str = stringw(str, end, sw, -1, field_width, precision, flags);
542 }
543 continue;
544
545 case 'Z':
546 if (qualifier == 'w') {
547 /* print counted unicode string */
548 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
549 if ((pus == NULL) || (pus->Buffer == NULL)) {
550 sw = NULL;
551 len = -1;
552 } else {
553 sw = pus->Buffer;
554 len = pus->Length / sizeof(WCHAR);
555 }
556 str = stringw(str, end, sw, len, field_width, precision, flags);
557 } else {
558 /* print counted ascii string */
559 PANSI_STRING pus = va_arg(args, PANSI_STRING);
560 if ((pus == NULL) || (pus->Buffer == NULL)) {
561 s = NULL;
562 len = -1;
563 } else {
564 s = pus->Buffer;
565 len = pus->Length;
566 }
567 str = string(str, end, s, len, field_width, precision, flags);
568 }
569 continue;
570
571 case 'p':
572 if ((flags & LARGE) == 0)
573 flags |= LARGE;
574
575 if (field_width == -1) {
576 field_width = 2 * sizeof(void *);
577 flags |= ZEROPAD;
578 }
579 str = number(str, end,
580 (ULONG_PTR) va_arg(args, void *), 16,
581 field_width, precision, flags);
582 continue;
583
584 case 'n':
585 /* FIXME: What does C99 say about the overflow case here? */
586 if (qualifier == 'l') {
587 long * ip = va_arg(args, long *);
588 *ip = (str - buf);
589 } else {
590 int * ip = va_arg(args, int *);
591 *ip = (str - buf);
592 }
593 continue;
594
595 /* float number formats - set up the flags and "break" */
596 case 'e':
597 case 'E':
598 case 'f':
599 case 'g':
600 case 'G':
601 _double = (double)va_arg(args, double);
602 if ( _isnan(_double) ) {
603 s = "Nan";
604 len = 3;
605 while ( len > 0 ) {
606 if (str <= end)
607 *str = *s++;
608 ++str;
609 len --;
610 }
611 } else if ( _isinf(_double) < 0 ) {
612 s = "-Inf";
613 len = 4;
614 while ( len > 0 ) {
615 if (str <= end)
616 *str = *s++;
617 ++str;
618 len --;
619 }
620 } else if ( _isinf(_double) > 0 ) {
621 s = "+Inf";
622 len = 4;
623 while ( len > 0 ) {
624 if (str <= end)
625 *str = *s++;
626 ++str;
627 len --;
628 }
629 } else {
630 if ( precision == -1 )
631 precision = 6;
632 str = numberf(str, end, (int)_double, base, field_width, precision, flags);
633 }
634
635 continue;
636
637
638 /* integer number formats - set up the flags and "break" */
639 case 'o':
640 base = 8;
641 break;
642
643 case 'b':
644 base = 2;
645 break;
646
647 case 'X':
648 flags |= LARGE;
649 case 'x':
650 base = 16;
651 break;
652
653 case 'd':
654 case 'i':
655 flags |= SIGN;
656 case 'u':
657 break;
658
659 default:
660 if (*fmt) {
661 if (str <= end)
662 *str = *fmt;
663 ++str;
664 } else
665 --fmt;
666 continue;
667 }
668
669 if (qualifier == 'I')
670 num = va_arg(args, unsigned long long);
671 else if (qualifier == 'l') {
672 if (flags & SIGN)
673 num = va_arg(args, long);
674 else
675 num = va_arg(args, unsigned long);
676 }
677 else if (qualifier == 'h') {
678 if (flags & SIGN)
679 num = va_arg(args, int);
680 else
681 num = va_arg(args, unsigned int);
682 }
683 else {
684 if (flags & SIGN)
685 num = va_arg(args, int);
686 else
687 num = va_arg(args, unsigned int);
688 }
689 str = number(str, end, num, base, field_width, precision, flags);
690 }
691 if (str <= end)
692 *str = '\0';
693 else if (cnt > 0)
694 /* don't write out a null byte if the buf size is zero */
695 *end = '\0';
696 return str-buf;
697 }
698
699
700 /*
701 * @implemented
702 */
703 int sprintf(char * buf, const char *fmt, ...)
704 {
705 va_list args;
706 int i;
707
708 va_start(args, fmt);
709 i=_vsnprintf(buf,MAXLONG,fmt,args);
710 va_end(args);
711 return i;
712 }
713
714
715 /*
716 * @implemented
717 */
718 int _snprintf(char * buf, size_t cnt, const char *fmt, ...)
719 {
720 va_list args;
721 int i;
722
723 va_start(args, fmt);
724 i=_vsnprintf(buf,cnt,fmt,args);
725 va_end(args);
726 return i;
727 }
728
729
730 /*
731 * @implemented
732 */
733 int __cdecl vsprintf(char *buf, const char *fmt, va_list args)
734 {
735 return _vsnprintf(buf,MAXLONG,fmt,args);
736 }
737
738 /* EOF */