xref: /reactos/win32ss/drivers/font/ftfd/sprintf.c (revision 845faec4)
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 */
739