xref: /openbmc/linux/drivers/firmware/efi/libstub/vsprintf.c (revision 6c4bcd8a46a98856c06ca3ba8a80f03a61e23960)
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*6c4bcd8aSArvind Sankar #include <linux/kernel.h>
18fb031937SArvind Sankar #include <linux/limits.h>
192c7d1e30SArvind Sankar #include <linux/string.h>
202c7d1e30SArvind Sankar 
21*6c4bcd8aSArvind Sankar static
22*6c4bcd8aSArvind Sankar int skip_atoi(const char **s)
232c7d1e30SArvind Sankar {
242c7d1e30SArvind Sankar 	int i = 0;
252c7d1e30SArvind Sankar 
262c7d1e30SArvind Sankar 	while (isdigit(**s))
272c7d1e30SArvind Sankar 		i = i * 10 + *((*s)++) - '0';
282c7d1e30SArvind Sankar 	return i;
292c7d1e30SArvind Sankar }
302c7d1e30SArvind Sankar 
31ce5e3f90SArvind Sankar /*
32ce5e3f90SArvind Sankar  * put_dec_full4 handles numbers in the range 0 <= r < 10000.
33ce5e3f90SArvind Sankar  * The multiplier 0xccd is round(2^15/10), and the approximation
34ce5e3f90SArvind Sankar  * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
35ce5e3f90SArvind Sankar  */
36ce5e3f90SArvind Sankar static
37*6c4bcd8aSArvind Sankar void put_dec_full4(char *end, unsigned int r)
38ce5e3f90SArvind Sankar {
39ce5e3f90SArvind Sankar 	int i;
40ce5e3f90SArvind Sankar 
41ce5e3f90SArvind Sankar 	for (i = 0; i < 3; i++) {
42ce5e3f90SArvind Sankar 		unsigned int q = (r * 0xccd) >> 15;
43*6c4bcd8aSArvind Sankar 		*--end = '0' + (r - q * 10);
44ce5e3f90SArvind Sankar 		r = q;
45ce5e3f90SArvind Sankar 	}
46*6c4bcd8aSArvind Sankar 	*--end = '0' + r;
47ce5e3f90SArvind Sankar }
48ce5e3f90SArvind Sankar 
49ce5e3f90SArvind Sankar /* put_dec is copied from lib/vsprintf.c with small modifications */
50ce5e3f90SArvind Sankar 
51ce5e3f90SArvind Sankar /*
52ce5e3f90SArvind Sankar  * Call put_dec_full4 on x % 10000, return x / 10000.
53ce5e3f90SArvind Sankar  * The approximation x/10000 == (x * 0x346DC5D7) >> 43
54ce5e3f90SArvind Sankar  * holds for all x < 1,128,869,999.  The largest value this
55ce5e3f90SArvind Sankar  * helper will ever be asked to convert is 1,125,520,955.
56ce5e3f90SArvind Sankar  * (second call in the put_dec code, assuming n is all-ones).
57ce5e3f90SArvind Sankar  */
58ce5e3f90SArvind Sankar static
59*6c4bcd8aSArvind Sankar unsigned int put_dec_helper4(char *end, unsigned int x)
60ce5e3f90SArvind Sankar {
61ce5e3f90SArvind Sankar 	unsigned int q = (x * 0x346DC5D7ULL) >> 43;
62ce5e3f90SArvind Sankar 
63*6c4bcd8aSArvind Sankar 	put_dec_full4(end, x - q * 10000);
64ce5e3f90SArvind Sankar 	return q;
65ce5e3f90SArvind Sankar }
66ce5e3f90SArvind Sankar 
67ce5e3f90SArvind Sankar /* Based on code by Douglas W. Jones found at
68ce5e3f90SArvind Sankar  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
69ce5e3f90SArvind Sankar  * (with permission from the author).
70ce5e3f90SArvind Sankar  * Performs no 64-bit division and hence should be fast on 32-bit machines.
71ce5e3f90SArvind Sankar  */
72ce5e3f90SArvind Sankar static
73*6c4bcd8aSArvind Sankar char *put_dec(char *end, unsigned long long n)
74ce5e3f90SArvind Sankar {
75ce5e3f90SArvind Sankar 	unsigned int d3, d2, d1, q, h;
76*6c4bcd8aSArvind Sankar 	char *p = end;
77ce5e3f90SArvind Sankar 
78ce5e3f90SArvind Sankar 	d1  = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
79ce5e3f90SArvind Sankar 	h   = (n >> 32);
80ce5e3f90SArvind Sankar 	d2  = (h      ) & 0xffff;
81ce5e3f90SArvind Sankar 	d3  = (h >> 16); /* implicit "& 0xffff" */
82ce5e3f90SArvind Sankar 
83ce5e3f90SArvind Sankar 	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
84ce5e3f90SArvind Sankar 	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
85ce5e3f90SArvind Sankar 	q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
86ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
87*6c4bcd8aSArvind Sankar 	p -= 4;
88ce5e3f90SArvind Sankar 
89ce5e3f90SArvind Sankar 	q += 7671 * d3 + 9496 * d2 + 6 * d1;
90ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
91*6c4bcd8aSArvind Sankar 	p -= 4;
92ce5e3f90SArvind Sankar 
93ce5e3f90SArvind Sankar 	q += 4749 * d3 + 42 * d2;
94ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
95*6c4bcd8aSArvind Sankar 	p -= 4;
96ce5e3f90SArvind Sankar 
97ce5e3f90SArvind Sankar 	q += 281 * d3;
98ce5e3f90SArvind Sankar 	q = put_dec_helper4(p, q);
99*6c4bcd8aSArvind Sankar 	p -= 4;
100ce5e3f90SArvind Sankar 
101ce5e3f90SArvind Sankar 	put_dec_full4(p, q);
102*6c4bcd8aSArvind Sankar 	p -= 4;
103ce5e3f90SArvind Sankar 
104ce5e3f90SArvind Sankar 	/* strip off the extra 0's we printed */
105*6c4bcd8aSArvind Sankar 	while (p < end && *p == '0')
106*6c4bcd8aSArvind Sankar 		++p;
107ce5e3f90SArvind Sankar 
108*6c4bcd8aSArvind Sankar 	return p;
109*6c4bcd8aSArvind Sankar }
110*6c4bcd8aSArvind Sankar 
111*6c4bcd8aSArvind Sankar static
112*6c4bcd8aSArvind Sankar char *number(char *end, unsigned long long num, int base, char locase)
113*6c4bcd8aSArvind Sankar {
114*6c4bcd8aSArvind Sankar 	/*
115*6c4bcd8aSArvind Sankar 	 * locase = 0 or 0x20. ORing digits or letters with 'locase'
116*6c4bcd8aSArvind Sankar 	 * produces same digits or (maybe lowercased) letters
117*6c4bcd8aSArvind Sankar 	 */
118*6c4bcd8aSArvind Sankar 
119*6c4bcd8aSArvind Sankar 	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
120*6c4bcd8aSArvind Sankar 	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
121*6c4bcd8aSArvind Sankar 
122*6c4bcd8aSArvind Sankar 	switch (base) {
123*6c4bcd8aSArvind Sankar 	case 10:
124*6c4bcd8aSArvind Sankar 		if (num != 0)
125*6c4bcd8aSArvind Sankar 			end = put_dec(end, num);
126*6c4bcd8aSArvind Sankar 		break;
127*6c4bcd8aSArvind Sankar 	case 8:
128*6c4bcd8aSArvind Sankar 		for (; num != 0; num >>= 3)
129*6c4bcd8aSArvind Sankar 			*--end = '0' + (num & 07);
130*6c4bcd8aSArvind Sankar 		break;
131*6c4bcd8aSArvind Sankar 	case 16:
132*6c4bcd8aSArvind Sankar 		for (; num != 0; num >>= 4)
133*6c4bcd8aSArvind Sankar 			*--end = digits[num & 0xf] | locase;
134*6c4bcd8aSArvind Sankar 		break;
135*6c4bcd8aSArvind Sankar 	default:
136*6c4bcd8aSArvind Sankar 		unreachable();
137*6c4bcd8aSArvind Sankar 	};
138*6c4bcd8aSArvind Sankar 
139*6c4bcd8aSArvind Sankar 	return end;
140ce5e3f90SArvind Sankar }
141ce5e3f90SArvind Sankar 
1422c7d1e30SArvind Sankar #define ZEROPAD	1		/* pad with zero */
1432c7d1e30SArvind Sankar #define SIGN	2		/* unsigned/signed long */
1442c7d1e30SArvind Sankar #define PLUS	4		/* show plus */
1452c7d1e30SArvind Sankar #define SPACE	8		/* space if plus */
1462c7d1e30SArvind Sankar #define LEFT	16		/* left justified */
1472c7d1e30SArvind Sankar #define SMALL	32		/* Must be 32 == 0x20 */
1482c7d1e30SArvind Sankar #define SPECIAL	64		/* 0x */
1492c7d1e30SArvind Sankar 
1503b835095SArvind Sankar static
1513b835095SArvind Sankar int get_flags(const char **fmt)
1523b835095SArvind Sankar {
1533b835095SArvind Sankar 	int flags = 0;
1543b835095SArvind Sankar 
1553b835095SArvind Sankar 	do {
1563b835095SArvind Sankar 		switch (**fmt) {
1573b835095SArvind Sankar 		case '-':
1583b835095SArvind Sankar 			flags |= LEFT;
1593b835095SArvind Sankar 			break;
1603b835095SArvind Sankar 		case '+':
1613b835095SArvind Sankar 			flags |= PLUS;
1623b835095SArvind Sankar 			break;
1633b835095SArvind Sankar 		case ' ':
1643b835095SArvind Sankar 			flags |= SPACE;
1653b835095SArvind Sankar 			break;
1663b835095SArvind Sankar 		case '#':
1673b835095SArvind Sankar 			flags |= SPECIAL;
1683b835095SArvind Sankar 			break;
1693b835095SArvind Sankar 		case '0':
1703b835095SArvind Sankar 			flags |= ZEROPAD;
1713b835095SArvind Sankar 			break;
1723b835095SArvind Sankar 		default:
1733b835095SArvind Sankar 			return flags;
1743b835095SArvind Sankar 		}
1753b835095SArvind Sankar 		++(*fmt);
1763b835095SArvind Sankar 	} while (1);
1773b835095SArvind Sankar }
1783b835095SArvind Sankar 
1793fbcf75bSArvind Sankar static
1803fbcf75bSArvind Sankar int get_int(const char **fmt, va_list *ap)
1813fbcf75bSArvind Sankar {
1823fbcf75bSArvind Sankar 	if (isdigit(**fmt))
1833fbcf75bSArvind Sankar 		return skip_atoi(fmt);
1843fbcf75bSArvind Sankar 	if (**fmt == '*') {
1853fbcf75bSArvind Sankar 		++(*fmt);
1863fbcf75bSArvind Sankar 		/* it's the next argument */
1873fbcf75bSArvind Sankar 		return va_arg(*ap, int);
1883fbcf75bSArvind Sankar 	}
1893fbcf75bSArvind Sankar 	return 0;
1903fbcf75bSArvind Sankar }
1913fbcf75bSArvind Sankar 
192dec61199SArvind Sankar static
193dec61199SArvind Sankar unsigned long long get_number(int sign, int qualifier, va_list *ap)
194dec61199SArvind Sankar {
195dec61199SArvind Sankar 	if (sign) {
196dec61199SArvind Sankar 		switch (qualifier) {
197dec61199SArvind Sankar 		case 'L':
198dec61199SArvind Sankar 			return va_arg(*ap, long long);
199dec61199SArvind Sankar 		case 'l':
200dec61199SArvind Sankar 			return va_arg(*ap, long);
201dec61199SArvind Sankar 		case 'h':
202dec61199SArvind Sankar 			return (short)va_arg(*ap, int);
203dec61199SArvind Sankar 		case 'H':
204dec61199SArvind Sankar 			return (signed char)va_arg(*ap, int);
205dec61199SArvind Sankar 		default:
206dec61199SArvind Sankar 			return va_arg(*ap, int);
207dec61199SArvind Sankar 		};
208dec61199SArvind Sankar 	} else {
209dec61199SArvind Sankar 		switch (qualifier) {
210dec61199SArvind Sankar 		case 'L':
211dec61199SArvind Sankar 			return va_arg(*ap, unsigned long long);
212dec61199SArvind Sankar 		case 'l':
213dec61199SArvind Sankar 			return va_arg(*ap, unsigned long);
214dec61199SArvind Sankar 		case 'h':
215dec61199SArvind Sankar 			return (unsigned short)va_arg(*ap, int);
216dec61199SArvind Sankar 		case 'H':
217dec61199SArvind Sankar 			return (unsigned char)va_arg(*ap, int);
218dec61199SArvind Sankar 		default:
219dec61199SArvind Sankar 			return va_arg(*ap, unsigned int);
220dec61199SArvind Sankar 		}
221dec61199SArvind Sankar 	}
222dec61199SArvind Sankar }
223dec61199SArvind Sankar 
224*6c4bcd8aSArvind Sankar static
225*6c4bcd8aSArvind Sankar char get_sign(long long *num, int flags)
226*6c4bcd8aSArvind Sankar {
227*6c4bcd8aSArvind Sankar 	if (!(flags & SIGN))
228*6c4bcd8aSArvind Sankar 		return 0;
229*6c4bcd8aSArvind Sankar 	if (*num < 0) {
230*6c4bcd8aSArvind Sankar 		*num = -(*num);
231*6c4bcd8aSArvind Sankar 		return '-';
232*6c4bcd8aSArvind Sankar 	}
233*6c4bcd8aSArvind Sankar 	if (flags & PLUS)
234*6c4bcd8aSArvind Sankar 		return '+';
235*6c4bcd8aSArvind Sankar 	if (flags & SPACE)
236*6c4bcd8aSArvind Sankar 		return ' ';
237*6c4bcd8aSArvind Sankar 	return 0;
238*6c4bcd8aSArvind Sankar }
239*6c4bcd8aSArvind Sankar 
2403fbcf75bSArvind Sankar int vsprintf(char *buf, const char *fmt, va_list ap)
2412c7d1e30SArvind Sankar {
242*6c4bcd8aSArvind Sankar 	/* The maximum space required is to print a 64-bit number in octal */
243*6c4bcd8aSArvind Sankar 	char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
244*6c4bcd8aSArvind Sankar 	char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
245*6c4bcd8aSArvind Sankar 	long long num;
246*6c4bcd8aSArvind Sankar 	int base;
2472c7d1e30SArvind Sankar 	char *str;
2482c7d1e30SArvind Sankar 	const char *s;
249*6c4bcd8aSArvind Sankar 	int len;
250*6c4bcd8aSArvind Sankar 	char sign;
2512c7d1e30SArvind Sankar 
2522c7d1e30SArvind Sankar 	int flags;		/* flags to number() */
2532c7d1e30SArvind Sankar 
2542c7d1e30SArvind Sankar 	int field_width;	/* width of output field */
2552c7d1e30SArvind Sankar 	int precision;		/* min. # of digits for integers; max
2562c7d1e30SArvind Sankar 				   number of chars for from string */
257ce5e3f90SArvind Sankar 	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
2582c7d1e30SArvind Sankar 
2593fbcf75bSArvind Sankar 	va_list args;
2603fbcf75bSArvind Sankar 
2613fbcf75bSArvind Sankar 	/*
2623fbcf75bSArvind Sankar 	 * We want to pass our input va_list to helper functions by reference,
2633fbcf75bSArvind Sankar 	 * but there's an annoying edge case. If va_list was originally passed
2643fbcf75bSArvind Sankar 	 * to us by value, we could just pass &ap down to the helpers. This is
2653fbcf75bSArvind Sankar 	 * the case on, for example, X86_32.
2663fbcf75bSArvind Sankar 	 * However, on X86_64 (and possibly others), va_list is actually a
2673fbcf75bSArvind Sankar 	 * size-1 array containing a structure. Our function parameter ap has
2683fbcf75bSArvind Sankar 	 * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
2693fbcf75bSArvind Sankar 	 * which is what will be expected by a function taking a va_list *
2703fbcf75bSArvind Sankar 	 * parameter.
2713fbcf75bSArvind Sankar 	 * One standard way to solve this mess is by creating a copy in a local
2723fbcf75bSArvind Sankar 	 * variable of type va_list and then passing a pointer to that local
2733fbcf75bSArvind Sankar 	 * copy instead, which is what we do here.
2743fbcf75bSArvind Sankar 	 */
2753fbcf75bSArvind Sankar 	va_copy(args, ap);
2763fbcf75bSArvind Sankar 
2772c7d1e30SArvind Sankar 	for (str = buf; *fmt; ++fmt) {
2783b835095SArvind Sankar 		if (*fmt != '%' || *++fmt == '%') {
2792c7d1e30SArvind Sankar 			*str++ = *fmt;
2802c7d1e30SArvind Sankar 			continue;
2812c7d1e30SArvind Sankar 		}
2822c7d1e30SArvind Sankar 
2832c7d1e30SArvind Sankar 		/* process flags */
2843b835095SArvind Sankar 		flags = get_flags(&fmt);
2852c7d1e30SArvind Sankar 
2862c7d1e30SArvind Sankar 		/* get field width */
2873fbcf75bSArvind Sankar 		field_width = get_int(&fmt, &args);
2882c7d1e30SArvind Sankar 		if (field_width < 0) {
2892c7d1e30SArvind Sankar 			field_width = -field_width;
2902c7d1e30SArvind Sankar 			flags |= LEFT;
2912c7d1e30SArvind Sankar 		}
2922c7d1e30SArvind Sankar 
293*6c4bcd8aSArvind Sankar 		if (flags & LEFT)
294*6c4bcd8aSArvind Sankar 			flags &= ~ZEROPAD;
295*6c4bcd8aSArvind Sankar 
2962c7d1e30SArvind Sankar 		/* get the precision */
2972c7d1e30SArvind Sankar 		precision = -1;
2982c7d1e30SArvind Sankar 		if (*fmt == '.') {
2992c7d1e30SArvind Sankar 			++fmt;
3003fbcf75bSArvind Sankar 			precision = get_int(&fmt, &args);
30177e48db0SArvind Sankar 			if (precision >= 0)
30277e48db0SArvind Sankar 				flags &= ~ZEROPAD;
30377e48db0SArvind Sankar 		}
3042c7d1e30SArvind Sankar 
3052c7d1e30SArvind Sankar 		/* get the conversion qualifier */
3062c7d1e30SArvind Sankar 		qualifier = -1;
30729a28066SArvind Sankar 		if (*fmt == 'h' || *fmt == 'l') {
3082c7d1e30SArvind Sankar 			qualifier = *fmt;
3092c7d1e30SArvind Sankar 			++fmt;
310ce5e3f90SArvind Sankar 			if (qualifier == *fmt) {
311ce5e3f90SArvind Sankar 				qualifier -= 'a'-'A';
312ce5e3f90SArvind Sankar 				++fmt;
313ce5e3f90SArvind Sankar 			}
3142c7d1e30SArvind Sankar 		}
3152c7d1e30SArvind Sankar 
316*6c4bcd8aSArvind Sankar 		sign = 0;
317*6c4bcd8aSArvind Sankar 
3182c7d1e30SArvind Sankar 		switch (*fmt) {
3192c7d1e30SArvind Sankar 		case 'c':
320*6c4bcd8aSArvind Sankar 			flags &= LEFT;
321*6c4bcd8aSArvind Sankar 			tmp[0] = (unsigned char)va_arg(args, int);
322*6c4bcd8aSArvind Sankar 			s = tmp;
323*6c4bcd8aSArvind Sankar 			precision = len = 1;
324*6c4bcd8aSArvind Sankar 			goto output;
3252c7d1e30SArvind Sankar 
3262c7d1e30SArvind Sankar 		case 's':
327*6c4bcd8aSArvind Sankar 			flags &= LEFT;
328fb031937SArvind Sankar 			if (precision < 0)
329fb031937SArvind Sankar 				precision = INT_MAX;
3302c7d1e30SArvind Sankar 			s = va_arg(args, char *);
331fb031937SArvind Sankar 			if (!s)
332fb031937SArvind Sankar 				s = precision < 6 ? "" : "(null)";
333*6c4bcd8aSArvind Sankar 			precision = len = strnlen(s, precision);
334*6c4bcd8aSArvind Sankar 			goto output;
3352c7d1e30SArvind Sankar 
3362c7d1e30SArvind Sankar 			/* integer number formats - set up the flags and "break" */
3372c7d1e30SArvind Sankar 		case 'o':
3382c7d1e30SArvind Sankar 			base = 8;
3392c7d1e30SArvind Sankar 			break;
3402c7d1e30SArvind Sankar 
3417c30fd79SArvind Sankar 		case 'p':
3427c30fd79SArvind Sankar 			if (precision < 0)
3437c30fd79SArvind Sankar 				precision = 2 * sizeof(void *);
3447c30fd79SArvind Sankar 			fallthrough;
3452c7d1e30SArvind Sankar 		case 'x':
3462c7d1e30SArvind Sankar 			flags |= SMALL;
3472c7d1e30SArvind Sankar 			fallthrough;
3482c7d1e30SArvind Sankar 		case 'X':
3492c7d1e30SArvind Sankar 			base = 16;
3502c7d1e30SArvind Sankar 			break;
3512c7d1e30SArvind Sankar 
3522c7d1e30SArvind Sankar 		case 'd':
3532c7d1e30SArvind Sankar 		case 'i':
3542c7d1e30SArvind Sankar 			flags |= SIGN;
3552c7d1e30SArvind Sankar 			fallthrough;
3562c7d1e30SArvind Sankar 		case 'u':
357*6c4bcd8aSArvind Sankar 			flags &= ~SPECIAL;
3587c30fd79SArvind Sankar 			base = 10;
3592c7d1e30SArvind Sankar 			break;
3602c7d1e30SArvind Sankar 
3612c7d1e30SArvind Sankar 		default:
3622c7d1e30SArvind Sankar 			*str++ = '%';
3632c7d1e30SArvind Sankar 			if (*fmt)
3642c7d1e30SArvind Sankar 				*str++ = *fmt;
3652c7d1e30SArvind Sankar 			else
3662c7d1e30SArvind Sankar 				--fmt;
3672c7d1e30SArvind Sankar 			continue;
3682c7d1e30SArvind Sankar 		}
3697c30fd79SArvind Sankar 		if (*fmt == 'p') {
3707c30fd79SArvind Sankar 			num = (unsigned long)va_arg(args, void *);
3712c7d1e30SArvind Sankar 		} else {
372dec61199SArvind Sankar 			num = get_number(flags & SIGN, qualifier, &args);
373ce5e3f90SArvind Sankar 		}
374*6c4bcd8aSArvind Sankar 
375*6c4bcd8aSArvind Sankar 		sign = get_sign(&num, flags);
376*6c4bcd8aSArvind Sankar 		if (sign)
377*6c4bcd8aSArvind Sankar 			--field_width;
378*6c4bcd8aSArvind Sankar 
379*6c4bcd8aSArvind Sankar 		s = number(tmp_end, num, base, flags & SMALL);
380*6c4bcd8aSArvind Sankar 		len = tmp_end - s;
381*6c4bcd8aSArvind Sankar 		/* default precision is 1 */
382*6c4bcd8aSArvind Sankar 		if (precision < 0)
383*6c4bcd8aSArvind Sankar 			precision = 1;
384*6c4bcd8aSArvind Sankar 		/* precision is minimum number of digits to print */
385*6c4bcd8aSArvind Sankar 		if (precision < len)
386*6c4bcd8aSArvind Sankar 			precision = len;
387*6c4bcd8aSArvind Sankar 		if (flags & SPECIAL) {
388*6c4bcd8aSArvind Sankar 			/*
389*6c4bcd8aSArvind Sankar 			 * For octal, a leading 0 is printed only if necessary,
390*6c4bcd8aSArvind Sankar 			 * i.e. if it's not already there because of the
391*6c4bcd8aSArvind Sankar 			 * precision.
392*6c4bcd8aSArvind Sankar 			 */
393*6c4bcd8aSArvind Sankar 			if (base == 8 && precision == len)
394*6c4bcd8aSArvind Sankar 				++precision;
395*6c4bcd8aSArvind Sankar 			/*
396*6c4bcd8aSArvind Sankar 			 * For hexadecimal, the leading 0x is skipped if the
397*6c4bcd8aSArvind Sankar 			 * output is empty, i.e. both the number and the
398*6c4bcd8aSArvind Sankar 			 * precision are 0.
399*6c4bcd8aSArvind Sankar 			 */
400*6c4bcd8aSArvind Sankar 			if (base == 16 && precision > 0)
401*6c4bcd8aSArvind Sankar 				field_width -= 2;
402*6c4bcd8aSArvind Sankar 			else
403*6c4bcd8aSArvind Sankar 				flags &= ~SPECIAL;
404*6c4bcd8aSArvind Sankar 		}
405*6c4bcd8aSArvind Sankar 		/*
406*6c4bcd8aSArvind Sankar 		 * For zero padding, increase the precision to fill the field
407*6c4bcd8aSArvind Sankar 		 * width.
408*6c4bcd8aSArvind Sankar 		 */
409*6c4bcd8aSArvind Sankar 		if ((flags & ZEROPAD) && field_width > precision)
410*6c4bcd8aSArvind Sankar 			precision = field_width;
411*6c4bcd8aSArvind Sankar 
412*6c4bcd8aSArvind Sankar output:
413*6c4bcd8aSArvind Sankar 		/* Calculate the padding necessary */
414*6c4bcd8aSArvind Sankar 		field_width -= precision;
415*6c4bcd8aSArvind Sankar 		/* Leading padding with ' ' */
416*6c4bcd8aSArvind Sankar 		if (!(flags & LEFT))
417*6c4bcd8aSArvind Sankar 			while (field_width-- > 0)
418*6c4bcd8aSArvind Sankar 				*str++ = ' ';
419*6c4bcd8aSArvind Sankar 		/* sign */
420*6c4bcd8aSArvind Sankar 		if (sign)
421*6c4bcd8aSArvind Sankar 			*str++ = sign;
422*6c4bcd8aSArvind Sankar 		/* 0x/0X for hexadecimal */
423*6c4bcd8aSArvind Sankar 		if (flags & SPECIAL) {
424*6c4bcd8aSArvind Sankar 			*str++ = '0';
425*6c4bcd8aSArvind Sankar 			*str++ = 'X' | (flags & SMALL);
426*6c4bcd8aSArvind Sankar 		}
427*6c4bcd8aSArvind Sankar 		/* Zero padding and excess precision */
428*6c4bcd8aSArvind Sankar 		while (precision-- > len)
429*6c4bcd8aSArvind Sankar 			*str++ = '0';
430*6c4bcd8aSArvind Sankar 		/* Actual output */
431*6c4bcd8aSArvind Sankar 		while (len-- > 0)
432*6c4bcd8aSArvind Sankar 			*str++ = *s++;
433*6c4bcd8aSArvind Sankar 		/* Trailing padding with ' ' */
434*6c4bcd8aSArvind Sankar 		while (field_width-- > 0)
435*6c4bcd8aSArvind Sankar 			*str++ = ' ';
4362c7d1e30SArvind Sankar 	}
4372c7d1e30SArvind Sankar 	*str = '\0';
4383fbcf75bSArvind Sankar 
4393fbcf75bSArvind Sankar 	va_end(args);
4403fbcf75bSArvind Sankar 
4412c7d1e30SArvind Sankar 	return str - buf;
4422c7d1e30SArvind Sankar }
4432c7d1e30SArvind Sankar 
4442c7d1e30SArvind Sankar int sprintf(char *buf, const char *fmt, ...)
4452c7d1e30SArvind Sankar {
4462c7d1e30SArvind Sankar 	va_list args;
4472c7d1e30SArvind Sankar 	int i;
4482c7d1e30SArvind Sankar 
4492c7d1e30SArvind Sankar 	va_start(args, fmt);
4502c7d1e30SArvind Sankar 	i = vsprintf(buf, fmt, args);
4512c7d1e30SArvind Sankar 	va_end(args);
4522c7d1e30SArvind Sankar 	return i;
4532c7d1e30SArvind Sankar }
454