xref: /openbmc/linux/drivers/firmware/efi/libstub/vsprintf.c (revision fb031937a86874e6d663542bdbd83e310c13610e)
12c7d1e30SArvind Sankar // SPDX-License-Identifier: GPL-2.0-only
22c7d1e30SArvind Sankar /* -*- linux-c -*- ------------------------------------------------------- *
32c7d1e30SArvind Sankar  *
42c7d1e30SArvind Sankar  *   Copyright (C) 1991, 1992 Linus Torvalds
52c7d1e30SArvind Sankar  *   Copyright 2007 rPath, Inc. - All Rights Reserved
62c7d1e30SArvind Sankar  *
72c7d1e30SArvind Sankar  * ----------------------------------------------------------------------- */
82c7d1e30SArvind Sankar 
92c7d1e30SArvind Sankar /*
10ce5e3f90SArvind Sankar  * Oh, it's a waste of space, but oh-so-yummy for debugging.
112c7d1e30SArvind Sankar  */
122c7d1e30SArvind Sankar 
132c7d1e30SArvind Sankar #include <stdarg.h>
142c7d1e30SArvind Sankar 
152c7d1e30SArvind Sankar #include <linux/compiler.h>
162c7d1e30SArvind Sankar #include <linux/ctype.h>
17*fb031937SArvind Sankar #include <linux/limits.h>
182c7d1e30SArvind Sankar #include <linux/string.h>
192c7d1e30SArvind Sankar 
202c7d1e30SArvind Sankar static int skip_atoi(const char **s)
212c7d1e30SArvind Sankar {
222c7d1e30SArvind Sankar 	int i = 0;
232c7d1e30SArvind Sankar 
242c7d1e30SArvind Sankar 	while (isdigit(**s))
252c7d1e30SArvind Sankar 		i = i * 10 + *((*s)++) - '0';
262c7d1e30SArvind Sankar 	return i;
272c7d1e30SArvind Sankar }
282c7d1e30SArvind Sankar 
29ce5e3f90SArvind Sankar /*
30ce5e3f90SArvind Sankar  * put_dec_full4 handles numbers in the range 0 <= r < 10000.
31ce5e3f90SArvind Sankar  * The multiplier 0xccd is round(2^15/10), and the approximation
32ce5e3f90SArvind Sankar  * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
33ce5e3f90SArvind Sankar  */
34ce5e3f90SArvind Sankar static
35ce5e3f90SArvind Sankar void put_dec_full4(char *buf, unsigned int r)
36ce5e3f90SArvind Sankar {
37ce5e3f90SArvind Sankar 	int i;
38ce5e3f90SArvind Sankar 
39ce5e3f90SArvind Sankar 	for (i = 0; i < 3; i++) {
40ce5e3f90SArvind Sankar 		unsigned int q = (r * 0xccd) >> 15;
41ce5e3f90SArvind Sankar 		*buf++ = '0' + (r - q * 10);
42ce5e3f90SArvind Sankar 		r = q;
43ce5e3f90SArvind Sankar 	}
44ce5e3f90SArvind Sankar 	*buf++ = '0' + r;
45ce5e3f90SArvind Sankar }
46ce5e3f90SArvind Sankar 
47ce5e3f90SArvind Sankar /* put_dec is copied from lib/vsprintf.c with small modifications */
48ce5e3f90SArvind Sankar 
49ce5e3f90SArvind Sankar /*
50ce5e3f90SArvind Sankar  * Call put_dec_full4 on x % 10000, return x / 10000.
51ce5e3f90SArvind Sankar  * The approximation x/10000 == (x * 0x346DC5D7) >> 43
52ce5e3f90SArvind Sankar  * holds for all x < 1,128,869,999.  The largest value this
53ce5e3f90SArvind Sankar  * helper will ever be asked to convert is 1,125,520,955.
54ce5e3f90SArvind Sankar  * (second call in the put_dec code, assuming n is all-ones).
55ce5e3f90SArvind Sankar  */
56ce5e3f90SArvind Sankar static
57ce5e3f90SArvind Sankar unsigned int put_dec_helper4(char *buf, unsigned int x)
58ce5e3f90SArvind Sankar {
59ce5e3f90SArvind Sankar 	unsigned int q = (x * 0x346DC5D7ULL) >> 43;
60ce5e3f90SArvind Sankar 
61ce5e3f90SArvind Sankar 	put_dec_full4(buf, x - q * 10000);
62ce5e3f90SArvind Sankar 	return q;
63ce5e3f90SArvind Sankar }
64ce5e3f90SArvind Sankar 
65ce5e3f90SArvind Sankar /* Based on code by Douglas W. Jones found at
66ce5e3f90SArvind Sankar  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
67ce5e3f90SArvind Sankar  * (with permission from the author).
68ce5e3f90SArvind Sankar  * Performs no 64-bit division and hence should be fast on 32-bit machines.
69ce5e3f90SArvind Sankar  */
70ce5e3f90SArvind Sankar static
71ce5e3f90SArvind Sankar int put_dec(char *buf, unsigned long long n)
72ce5e3f90SArvind Sankar {
73ce5e3f90SArvind Sankar 	unsigned int d3, d2, d1, q, h;
74ce5e3f90SArvind Sankar 	char *p = buf;
75ce5e3f90SArvind Sankar 
76ce5e3f90SArvind Sankar 	d1  = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
77ce5e3f90SArvind Sankar 	h   = (n >> 32);
78ce5e3f90SArvind Sankar 	d2  = (h      ) & 0xffff;
79ce5e3f90SArvind Sankar 	d3  = (h >> 16); /* implicit "& 0xffff" */
80ce5e3f90SArvind Sankar 
81ce5e3f90SArvind Sankar 	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
82ce5e3f90SArvind Sankar 	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
83ce5e3f90SArvind Sankar 	q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
84ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
85ce5e3f90SArvind Sankar 	p += 4;
86ce5e3f90SArvind Sankar 
87ce5e3f90SArvind Sankar 	q += 7671 * d3 + 9496 * d2 + 6 * d1;
88ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
89ce5e3f90SArvind Sankar 	p += 4;
90ce5e3f90SArvind Sankar 
91ce5e3f90SArvind Sankar 	q += 4749 * d3 + 42 * d2;
92ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
93ce5e3f90SArvind Sankar 	p += 4;
94ce5e3f90SArvind Sankar 
95ce5e3f90SArvind Sankar 	q += 281 * d3;
96ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
97ce5e3f90SArvind Sankar 	p += 4;
98ce5e3f90SArvind Sankar 
99ce5e3f90SArvind Sankar 	put_dec_full4(p, q);
100ce5e3f90SArvind Sankar 	p += 4;
101ce5e3f90SArvind Sankar 
102ce5e3f90SArvind Sankar 	/* strip off the extra 0's we printed */
103ce5e3f90SArvind Sankar 	while (p > buf && p[-1] == '0')
104ce5e3f90SArvind Sankar 		--p;
105ce5e3f90SArvind Sankar 
106ce5e3f90SArvind Sankar 	return p - buf;
107ce5e3f90SArvind Sankar }
108ce5e3f90SArvind Sankar 
1092c7d1e30SArvind Sankar #define ZEROPAD	1		/* pad with zero */
1102c7d1e30SArvind Sankar #define SIGN	2		/* unsigned/signed long */
1112c7d1e30SArvind Sankar #define PLUS	4		/* show plus */
1122c7d1e30SArvind Sankar #define SPACE	8		/* space if plus */
1132c7d1e30SArvind Sankar #define LEFT	16		/* left justified */
1142c7d1e30SArvind Sankar #define SMALL	32		/* Must be 32 == 0x20 */
1152c7d1e30SArvind Sankar #define SPECIAL	64		/* 0x */
1162c7d1e30SArvind Sankar 
117ce5e3f90SArvind Sankar static char *number(char *str, long long num, int base, int size, int precision,
1182c7d1e30SArvind Sankar 		    int type)
1192c7d1e30SArvind Sankar {
1202c7d1e30SArvind Sankar 	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
1212c7d1e30SArvind Sankar 	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
1222c7d1e30SArvind Sankar 
1232c7d1e30SArvind Sankar 	char tmp[66];
1242c7d1e30SArvind Sankar 	char c, sign, locase;
1252c7d1e30SArvind Sankar 	int i;
1262c7d1e30SArvind Sankar 
1272c7d1e30SArvind Sankar 	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
1282c7d1e30SArvind Sankar 	 * produces same digits or (maybe lowercased) letters */
1292c7d1e30SArvind Sankar 	locase = (type & SMALL);
1302c7d1e30SArvind Sankar 	if (type & LEFT)
1312c7d1e30SArvind Sankar 		type &= ~ZEROPAD;
1322c7d1e30SArvind Sankar 	c = (type & ZEROPAD) ? '0' : ' ';
1332c7d1e30SArvind Sankar 	sign = 0;
1342c7d1e30SArvind Sankar 	if (type & SIGN) {
1352c7d1e30SArvind Sankar 		if (num < 0) {
1362c7d1e30SArvind Sankar 			sign = '-';
1372c7d1e30SArvind Sankar 			num = -num;
1382c7d1e30SArvind Sankar 			size--;
1392c7d1e30SArvind Sankar 		} else if (type & PLUS) {
1402c7d1e30SArvind Sankar 			sign = '+';
1412c7d1e30SArvind Sankar 			size--;
1422c7d1e30SArvind Sankar 		} else if (type & SPACE) {
1432c7d1e30SArvind Sankar 			sign = ' ';
1442c7d1e30SArvind Sankar 			size--;
1452c7d1e30SArvind Sankar 		}
1462c7d1e30SArvind Sankar 	}
1472c7d1e30SArvind Sankar 	if (type & SPECIAL) {
1482c7d1e30SArvind Sankar 		if (base == 16)
1492c7d1e30SArvind Sankar 			size -= 2;
1502c7d1e30SArvind Sankar 		else if (base == 8)
1512c7d1e30SArvind Sankar 			size--;
1522c7d1e30SArvind Sankar 	}
1532c7d1e30SArvind Sankar 	i = 0;
1542c7d1e30SArvind Sankar 	if (num == 0)
1552c7d1e30SArvind Sankar 		tmp[i++] = '0';
156ce5e3f90SArvind Sankar 	else {
157ce5e3f90SArvind Sankar 		switch (base) {
158ce5e3f90SArvind Sankar 		case 10:
159ce5e3f90SArvind Sankar 			i += put_dec(&tmp[i], num);
160ce5e3f90SArvind Sankar 			break;
161ce5e3f90SArvind Sankar 		case 8:
162ce5e3f90SArvind Sankar 			while (num != 0) {
163ce5e3f90SArvind Sankar 				tmp[i++] = '0' + (num & 07);
164ce5e3f90SArvind Sankar 				num = (unsigned long long)num >> 3;
165ce5e3f90SArvind Sankar 			}
166ce5e3f90SArvind Sankar 			break;
167ce5e3f90SArvind Sankar 		case 16:
168ce5e3f90SArvind Sankar 			while (num != 0) {
169ce5e3f90SArvind Sankar 				tmp[i++] = digits[num & 0xf] | locase;
170ce5e3f90SArvind Sankar 				num = (unsigned long long)num >> 4;
171ce5e3f90SArvind Sankar 			}
172ce5e3f90SArvind Sankar 			break;
173ce5e3f90SArvind Sankar 		default:
174ce5e3f90SArvind Sankar 			unreachable();
175ce5e3f90SArvind Sankar 		}
176ce5e3f90SArvind Sankar 	}
177ce5e3f90SArvind Sankar 
1782c7d1e30SArvind Sankar 	if (i > precision)
1792c7d1e30SArvind Sankar 		precision = i;
1802c7d1e30SArvind Sankar 	size -= precision;
1812c7d1e30SArvind Sankar 	if (!(type & (ZEROPAD + LEFT)))
1822c7d1e30SArvind Sankar 		while (size-- > 0)
1832c7d1e30SArvind Sankar 			*str++ = ' ';
1842c7d1e30SArvind Sankar 	if (sign)
1852c7d1e30SArvind Sankar 		*str++ = sign;
1862c7d1e30SArvind Sankar 	if (type & SPECIAL) {
1872c7d1e30SArvind Sankar 		if (base == 8) {
1882c7d1e30SArvind Sankar 			*str++ = '0';
1892c7d1e30SArvind Sankar 		} else if (base == 16) {
1902c7d1e30SArvind Sankar 			*str++ = '0';
1912c7d1e30SArvind Sankar 			*str++ = ('X' | locase);
1922c7d1e30SArvind Sankar 		}
1932c7d1e30SArvind Sankar 	}
1942c7d1e30SArvind Sankar 	if (!(type & LEFT))
1952c7d1e30SArvind Sankar 		while (size-- > 0)
1962c7d1e30SArvind Sankar 			*str++ = c;
1972c7d1e30SArvind Sankar 	while (i < precision--)
1982c7d1e30SArvind Sankar 		*str++ = '0';
1992c7d1e30SArvind Sankar 	while (i-- > 0)
2002c7d1e30SArvind Sankar 		*str++ = tmp[i];
2012c7d1e30SArvind Sankar 	while (size-- > 0)
2022c7d1e30SArvind Sankar 		*str++ = ' ';
2032c7d1e30SArvind Sankar 	return str;
2042c7d1e30SArvind Sankar }
2052c7d1e30SArvind Sankar 
2063b835095SArvind Sankar static
2073b835095SArvind Sankar int get_flags(const char **fmt)
2083b835095SArvind Sankar {
2093b835095SArvind Sankar 	int flags = 0;
2103b835095SArvind Sankar 
2113b835095SArvind Sankar 	do {
2123b835095SArvind Sankar 		switch (**fmt) {
2133b835095SArvind Sankar 		case '-':
2143b835095SArvind Sankar 			flags |= LEFT;
2153b835095SArvind Sankar 			break;
2163b835095SArvind Sankar 		case '+':
2173b835095SArvind Sankar 			flags |= PLUS;
2183b835095SArvind Sankar 			break;
2193b835095SArvind Sankar 		case ' ':
2203b835095SArvind Sankar 			flags |= SPACE;
2213b835095SArvind Sankar 			break;
2223b835095SArvind Sankar 		case '#':
2233b835095SArvind Sankar 			flags |= SPECIAL;
2243b835095SArvind Sankar 			break;
2253b835095SArvind Sankar 		case '0':
2263b835095SArvind Sankar 			flags |= ZEROPAD;
2273b835095SArvind Sankar 			break;
2283b835095SArvind Sankar 		default:
2293b835095SArvind Sankar 			return flags;
2303b835095SArvind Sankar 		}
2313b835095SArvind Sankar 		++(*fmt);
2323b835095SArvind Sankar 	} while (1);
2333b835095SArvind Sankar }
2343b835095SArvind Sankar 
2353fbcf75bSArvind Sankar static
2363fbcf75bSArvind Sankar int get_int(const char **fmt, va_list *ap)
2373fbcf75bSArvind Sankar {
2383fbcf75bSArvind Sankar 	if (isdigit(**fmt))
2393fbcf75bSArvind Sankar 		return skip_atoi(fmt);
2403fbcf75bSArvind Sankar 	if (**fmt == '*') {
2413fbcf75bSArvind Sankar 		++(*fmt);
2423fbcf75bSArvind Sankar 		/* it's the next argument */
2433fbcf75bSArvind Sankar 		return va_arg(*ap, int);
2443fbcf75bSArvind Sankar 	}
2453fbcf75bSArvind Sankar 	return 0;
2463fbcf75bSArvind Sankar }
2473fbcf75bSArvind Sankar 
248dec61199SArvind Sankar static
249dec61199SArvind Sankar unsigned long long get_number(int sign, int qualifier, va_list *ap)
250dec61199SArvind Sankar {
251dec61199SArvind Sankar 	if (sign) {
252dec61199SArvind Sankar 		switch (qualifier) {
253dec61199SArvind Sankar 		case 'L':
254dec61199SArvind Sankar 			return va_arg(*ap, long long);
255dec61199SArvind Sankar 		case 'l':
256dec61199SArvind Sankar 			return va_arg(*ap, long);
257dec61199SArvind Sankar 		case 'h':
258dec61199SArvind Sankar 			return (short)va_arg(*ap, int);
259dec61199SArvind Sankar 		case 'H':
260dec61199SArvind Sankar 			return (signed char)va_arg(*ap, int);
261dec61199SArvind Sankar 		default:
262dec61199SArvind Sankar 			return va_arg(*ap, int);
263dec61199SArvind Sankar 		};
264dec61199SArvind Sankar 	} else {
265dec61199SArvind Sankar 		switch (qualifier) {
266dec61199SArvind Sankar 		case 'L':
267dec61199SArvind Sankar 			return va_arg(*ap, unsigned long long);
268dec61199SArvind Sankar 		case 'l':
269dec61199SArvind Sankar 			return va_arg(*ap, unsigned long);
270dec61199SArvind Sankar 		case 'h':
271dec61199SArvind Sankar 			return (unsigned short)va_arg(*ap, int);
272dec61199SArvind Sankar 		case 'H':
273dec61199SArvind Sankar 			return (unsigned char)va_arg(*ap, int);
274dec61199SArvind Sankar 		default:
275dec61199SArvind Sankar 			return va_arg(*ap, unsigned int);
276dec61199SArvind Sankar 		}
277dec61199SArvind Sankar 	}
278dec61199SArvind Sankar }
279dec61199SArvind Sankar 
2803fbcf75bSArvind Sankar int vsprintf(char *buf, const char *fmt, va_list ap)
2812c7d1e30SArvind Sankar {
2822c7d1e30SArvind Sankar 	int len;
283ce5e3f90SArvind Sankar 	unsigned long long num;
2842c7d1e30SArvind Sankar 	int i, base;
2852c7d1e30SArvind Sankar 	char *str;
2862c7d1e30SArvind Sankar 	const char *s;
2872c7d1e30SArvind Sankar 
2882c7d1e30SArvind Sankar 	int flags;		/* flags to number() */
2892c7d1e30SArvind Sankar 
2902c7d1e30SArvind Sankar 	int field_width;	/* width of output field */
2912c7d1e30SArvind Sankar 	int precision;		/* min. # of digits for integers; max
2922c7d1e30SArvind Sankar 				   number of chars for from string */
293ce5e3f90SArvind Sankar 	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
2942c7d1e30SArvind Sankar 
2953fbcf75bSArvind Sankar 	va_list args;
2963fbcf75bSArvind Sankar 
2973fbcf75bSArvind Sankar 	/*
2983fbcf75bSArvind Sankar 	 * We want to pass our input va_list to helper functions by reference,
2993fbcf75bSArvind Sankar 	 * but there's an annoying edge case. If va_list was originally passed
3003fbcf75bSArvind Sankar 	 * to us by value, we could just pass &ap down to the helpers. This is
3013fbcf75bSArvind Sankar 	 * the case on, for example, X86_32.
3023fbcf75bSArvind Sankar 	 * However, on X86_64 (and possibly others), va_list is actually a
3033fbcf75bSArvind Sankar 	 * size-1 array containing a structure. Our function parameter ap has
3043fbcf75bSArvind Sankar 	 * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
3053fbcf75bSArvind Sankar 	 * which is what will be expected by a function taking a va_list *
3063fbcf75bSArvind Sankar 	 * parameter.
3073fbcf75bSArvind Sankar 	 * One standard way to solve this mess is by creating a copy in a local
3083fbcf75bSArvind Sankar 	 * variable of type va_list and then passing a pointer to that local
3093fbcf75bSArvind Sankar 	 * copy instead, which is what we do here.
3103fbcf75bSArvind Sankar 	 */
3113fbcf75bSArvind Sankar 	va_copy(args, ap);
3123fbcf75bSArvind Sankar 
3132c7d1e30SArvind Sankar 	for (str = buf; *fmt; ++fmt) {
3143b835095SArvind Sankar 		if (*fmt != '%' || *++fmt == '%') {
3152c7d1e30SArvind Sankar 			*str++ = *fmt;
3162c7d1e30SArvind Sankar 			continue;
3172c7d1e30SArvind Sankar 		}
3182c7d1e30SArvind Sankar 
3192c7d1e30SArvind Sankar 		/* process flags */
3203b835095SArvind Sankar 		flags = get_flags(&fmt);
3212c7d1e30SArvind Sankar 
3222c7d1e30SArvind Sankar 		/* get field width */
3233fbcf75bSArvind Sankar 		field_width = get_int(&fmt, &args);
3242c7d1e30SArvind Sankar 		if (field_width < 0) {
3252c7d1e30SArvind Sankar 			field_width = -field_width;
3262c7d1e30SArvind Sankar 			flags |= LEFT;
3272c7d1e30SArvind Sankar 		}
3282c7d1e30SArvind Sankar 
3292c7d1e30SArvind Sankar 		/* get the precision */
3302c7d1e30SArvind Sankar 		precision = -1;
3312c7d1e30SArvind Sankar 		if (*fmt == '.') {
3322c7d1e30SArvind Sankar 			++fmt;
3333fbcf75bSArvind Sankar 			precision = get_int(&fmt, &args);
33477e48db0SArvind Sankar 			if (precision >= 0)
33577e48db0SArvind Sankar 				flags &= ~ZEROPAD;
33677e48db0SArvind Sankar 		}
3372c7d1e30SArvind Sankar 
3382c7d1e30SArvind Sankar 		/* get the conversion qualifier */
3392c7d1e30SArvind Sankar 		qualifier = -1;
34029a28066SArvind Sankar 		if (*fmt == 'h' || *fmt == 'l') {
3412c7d1e30SArvind Sankar 			qualifier = *fmt;
3422c7d1e30SArvind Sankar 			++fmt;
343ce5e3f90SArvind Sankar 			if (qualifier == *fmt) {
344ce5e3f90SArvind Sankar 				qualifier -= 'a'-'A';
345ce5e3f90SArvind Sankar 				++fmt;
346ce5e3f90SArvind Sankar 			}
3472c7d1e30SArvind Sankar 		}
3482c7d1e30SArvind Sankar 
3492c7d1e30SArvind Sankar 		switch (*fmt) {
3502c7d1e30SArvind Sankar 		case 'c':
3512c7d1e30SArvind Sankar 			if (!(flags & LEFT))
3522c7d1e30SArvind Sankar 				while (--field_width > 0)
3532c7d1e30SArvind Sankar 					*str++ = ' ';
3542c7d1e30SArvind Sankar 			*str++ = (unsigned char)va_arg(args, int);
3552c7d1e30SArvind Sankar 			while (--field_width > 0)
3562c7d1e30SArvind Sankar 				*str++ = ' ';
3572c7d1e30SArvind Sankar 			continue;
3582c7d1e30SArvind Sankar 
3592c7d1e30SArvind Sankar 		case 's':
360*fb031937SArvind Sankar 			if (precision < 0)
361*fb031937SArvind Sankar 				precision = INT_MAX;
3622c7d1e30SArvind Sankar 			s = va_arg(args, char *);
363*fb031937SArvind Sankar 			if (!s)
364*fb031937SArvind Sankar 				s = precision < 6 ? "" : "(null)";
3652c7d1e30SArvind Sankar 			len = strnlen(s, precision);
3662c7d1e30SArvind Sankar 
3672c7d1e30SArvind Sankar 			if (!(flags & LEFT))
3682c7d1e30SArvind Sankar 				while (len < field_width--)
3692c7d1e30SArvind Sankar 					*str++ = ' ';
3702c7d1e30SArvind Sankar 			for (i = 0; i < len; ++i)
3712c7d1e30SArvind Sankar 				*str++ = *s++;
3722c7d1e30SArvind Sankar 			while (len < field_width--)
3732c7d1e30SArvind Sankar 				*str++ = ' ';
3742c7d1e30SArvind Sankar 			continue;
3752c7d1e30SArvind Sankar 
3762c7d1e30SArvind Sankar 			/* integer number formats - set up the flags and "break" */
3772c7d1e30SArvind Sankar 		case 'o':
3782c7d1e30SArvind Sankar 			base = 8;
3792c7d1e30SArvind Sankar 			break;
3802c7d1e30SArvind Sankar 
3817c30fd79SArvind Sankar 		case 'p':
3827c30fd79SArvind Sankar 			if (precision < 0)
3837c30fd79SArvind Sankar 				precision = 2 * sizeof(void *);
3847c30fd79SArvind Sankar 			fallthrough;
3852c7d1e30SArvind Sankar 		case 'x':
3862c7d1e30SArvind Sankar 			flags |= SMALL;
3872c7d1e30SArvind Sankar 			fallthrough;
3882c7d1e30SArvind Sankar 		case 'X':
3892c7d1e30SArvind Sankar 			base = 16;
3902c7d1e30SArvind Sankar 			break;
3912c7d1e30SArvind Sankar 
3922c7d1e30SArvind Sankar 		case 'd':
3932c7d1e30SArvind Sankar 		case 'i':
3942c7d1e30SArvind Sankar 			flags |= SIGN;
3952c7d1e30SArvind Sankar 			fallthrough;
3962c7d1e30SArvind Sankar 		case 'u':
3977c30fd79SArvind Sankar 			base = 10;
3982c7d1e30SArvind Sankar 			break;
3992c7d1e30SArvind Sankar 
4002c7d1e30SArvind Sankar 		default:
4012c7d1e30SArvind Sankar 			*str++ = '%';
4022c7d1e30SArvind Sankar 			if (*fmt)
4032c7d1e30SArvind Sankar 				*str++ = *fmt;
4042c7d1e30SArvind Sankar 			else
4052c7d1e30SArvind Sankar 				--fmt;
4062c7d1e30SArvind Sankar 			continue;
4072c7d1e30SArvind Sankar 		}
4087c30fd79SArvind Sankar 		if (*fmt == 'p') {
4097c30fd79SArvind Sankar 			num = (unsigned long)va_arg(args, void *);
4102c7d1e30SArvind Sankar 		} else {
411dec61199SArvind Sankar 			num = get_number(flags & SIGN, qualifier, &args);
412ce5e3f90SArvind Sankar 		}
4132c7d1e30SArvind Sankar 		str = number(str, num, base, field_width, precision, flags);
4142c7d1e30SArvind Sankar 	}
4152c7d1e30SArvind Sankar 	*str = '\0';
4163fbcf75bSArvind Sankar 
4173fbcf75bSArvind Sankar 	va_end(args);
4183fbcf75bSArvind Sankar 
4192c7d1e30SArvind Sankar 	return str - buf;
4202c7d1e30SArvind Sankar }
4212c7d1e30SArvind Sankar 
4222c7d1e30SArvind Sankar int sprintf(char *buf, const char *fmt, ...)
4232c7d1e30SArvind Sankar {
4242c7d1e30SArvind Sankar 	va_list args;
4252c7d1e30SArvind Sankar 	int i;
4262c7d1e30SArvind Sankar 
4272c7d1e30SArvind Sankar 	va_start(args, fmt);
4282c7d1e30SArvind Sankar 	i = vsprintf(buf, fmt, args);
4292c7d1e30SArvind Sankar 	va_end(args);
4302c7d1e30SArvind Sankar 	return i;
4312c7d1e30SArvind Sankar }
432