xref: /OK3568_Linux_fs/kernel/drivers/firmware/efi/libstub/vsprintf.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /* -*- linux-c -*- ------------------------------------------------------- *
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *   Copyright (C) 1991, 1992 Linus Torvalds
5*4882a593Smuzhiyun  *   Copyright 2007 rPath, Inc. - All Rights Reserved
6*4882a593Smuzhiyun  *
7*4882a593Smuzhiyun  * ----------------------------------------------------------------------- */
8*4882a593Smuzhiyun 
9*4882a593Smuzhiyun /*
10*4882a593Smuzhiyun  * Oh, it's a waste of space, but oh-so-yummy for debugging.
11*4882a593Smuzhiyun  */
12*4882a593Smuzhiyun 
13*4882a593Smuzhiyun #include <stdarg.h>
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun #include <linux/compiler.h>
16*4882a593Smuzhiyun #include <linux/ctype.h>
17*4882a593Smuzhiyun #include <linux/kernel.h>
18*4882a593Smuzhiyun #include <linux/limits.h>
19*4882a593Smuzhiyun #include <linux/string.h>
20*4882a593Smuzhiyun #include <linux/types.h>
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun static
skip_atoi(const char ** s)23*4882a593Smuzhiyun int skip_atoi(const char **s)
24*4882a593Smuzhiyun {
25*4882a593Smuzhiyun 	int i = 0;
26*4882a593Smuzhiyun 
27*4882a593Smuzhiyun 	while (isdigit(**s))
28*4882a593Smuzhiyun 		i = i * 10 + *((*s)++) - '0';
29*4882a593Smuzhiyun 	return i;
30*4882a593Smuzhiyun }
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun /*
33*4882a593Smuzhiyun  * put_dec_full4 handles numbers in the range 0 <= r < 10000.
34*4882a593Smuzhiyun  * The multiplier 0xccd is round(2^15/10), and the approximation
35*4882a593Smuzhiyun  * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
36*4882a593Smuzhiyun  */
37*4882a593Smuzhiyun static
put_dec_full4(char * end,unsigned int r)38*4882a593Smuzhiyun void put_dec_full4(char *end, unsigned int r)
39*4882a593Smuzhiyun {
40*4882a593Smuzhiyun 	int i;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	for (i = 0; i < 3; i++) {
43*4882a593Smuzhiyun 		unsigned int q = (r * 0xccd) >> 15;
44*4882a593Smuzhiyun 		*--end = '0' + (r - q * 10);
45*4882a593Smuzhiyun 		r = q;
46*4882a593Smuzhiyun 	}
47*4882a593Smuzhiyun 	*--end = '0' + r;
48*4882a593Smuzhiyun }
49*4882a593Smuzhiyun 
50*4882a593Smuzhiyun /* put_dec is copied from lib/vsprintf.c with small modifications */
51*4882a593Smuzhiyun 
52*4882a593Smuzhiyun /*
53*4882a593Smuzhiyun  * Call put_dec_full4 on x % 10000, return x / 10000.
54*4882a593Smuzhiyun  * The approximation x/10000 == (x * 0x346DC5D7) >> 43
55*4882a593Smuzhiyun  * holds for all x < 1,128,869,999.  The largest value this
56*4882a593Smuzhiyun  * helper will ever be asked to convert is 1,125,520,955.
57*4882a593Smuzhiyun  * (second call in the put_dec code, assuming n is all-ones).
58*4882a593Smuzhiyun  */
59*4882a593Smuzhiyun static
put_dec_helper4(char * end,unsigned int x)60*4882a593Smuzhiyun unsigned int put_dec_helper4(char *end, unsigned int x)
61*4882a593Smuzhiyun {
62*4882a593Smuzhiyun 	unsigned int q = (x * 0x346DC5D7ULL) >> 43;
63*4882a593Smuzhiyun 
64*4882a593Smuzhiyun 	put_dec_full4(end, x - q * 10000);
65*4882a593Smuzhiyun 	return q;
66*4882a593Smuzhiyun }
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun /* Based on code by Douglas W. Jones found at
69*4882a593Smuzhiyun  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
70*4882a593Smuzhiyun  * (with permission from the author).
71*4882a593Smuzhiyun  * Performs no 64-bit division and hence should be fast on 32-bit machines.
72*4882a593Smuzhiyun  */
73*4882a593Smuzhiyun static
put_dec(char * end,unsigned long long n)74*4882a593Smuzhiyun char *put_dec(char *end, unsigned long long n)
75*4882a593Smuzhiyun {
76*4882a593Smuzhiyun 	unsigned int d3, d2, d1, q, h;
77*4882a593Smuzhiyun 	char *p = end;
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun 	d1  = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
80*4882a593Smuzhiyun 	h   = (n >> 32);
81*4882a593Smuzhiyun 	d2  = (h      ) & 0xffff;
82*4882a593Smuzhiyun 	d3  = (h >> 16); /* implicit "& 0xffff" */
83*4882a593Smuzhiyun 
84*4882a593Smuzhiyun 	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
85*4882a593Smuzhiyun 	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
86*4882a593Smuzhiyun 	q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
87*4882a593Smuzhiyun 	q = put_dec_helper4(p, q);
88*4882a593Smuzhiyun 	p -= 4;
89*4882a593Smuzhiyun 
90*4882a593Smuzhiyun 	q += 7671 * d3 + 9496 * d2 + 6 * d1;
91*4882a593Smuzhiyun 	q = put_dec_helper4(p, q);
92*4882a593Smuzhiyun 	p -= 4;
93*4882a593Smuzhiyun 
94*4882a593Smuzhiyun 	q += 4749 * d3 + 42 * d2;
95*4882a593Smuzhiyun 	q = put_dec_helper4(p, q);
96*4882a593Smuzhiyun 	p -= 4;
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 	q += 281 * d3;
99*4882a593Smuzhiyun 	q = put_dec_helper4(p, q);
100*4882a593Smuzhiyun 	p -= 4;
101*4882a593Smuzhiyun 
102*4882a593Smuzhiyun 	put_dec_full4(p, q);
103*4882a593Smuzhiyun 	p -= 4;
104*4882a593Smuzhiyun 
105*4882a593Smuzhiyun 	/* strip off the extra 0's we printed */
106*4882a593Smuzhiyun 	while (p < end && *p == '0')
107*4882a593Smuzhiyun 		++p;
108*4882a593Smuzhiyun 
109*4882a593Smuzhiyun 	return p;
110*4882a593Smuzhiyun }
111*4882a593Smuzhiyun 
112*4882a593Smuzhiyun static
number(char * end,unsigned long long num,int base,char locase)113*4882a593Smuzhiyun char *number(char *end, unsigned long long num, int base, char locase)
114*4882a593Smuzhiyun {
115*4882a593Smuzhiyun 	/*
116*4882a593Smuzhiyun 	 * locase = 0 or 0x20. ORing digits or letters with 'locase'
117*4882a593Smuzhiyun 	 * produces same digits or (maybe lowercased) letters
118*4882a593Smuzhiyun 	 */
119*4882a593Smuzhiyun 
120*4882a593Smuzhiyun 	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
121*4882a593Smuzhiyun 	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
122*4882a593Smuzhiyun 
123*4882a593Smuzhiyun 	switch (base) {
124*4882a593Smuzhiyun 	case 10:
125*4882a593Smuzhiyun 		if (num != 0)
126*4882a593Smuzhiyun 			end = put_dec(end, num);
127*4882a593Smuzhiyun 		break;
128*4882a593Smuzhiyun 	case 8:
129*4882a593Smuzhiyun 		for (; num != 0; num >>= 3)
130*4882a593Smuzhiyun 			*--end = '0' + (num & 07);
131*4882a593Smuzhiyun 		break;
132*4882a593Smuzhiyun 	case 16:
133*4882a593Smuzhiyun 		for (; num != 0; num >>= 4)
134*4882a593Smuzhiyun 			*--end = digits[num & 0xf] | locase;
135*4882a593Smuzhiyun 		break;
136*4882a593Smuzhiyun 	default:
137*4882a593Smuzhiyun 		unreachable();
138*4882a593Smuzhiyun 	}
139*4882a593Smuzhiyun 
140*4882a593Smuzhiyun 	return end;
141*4882a593Smuzhiyun }
142*4882a593Smuzhiyun 
143*4882a593Smuzhiyun #define ZEROPAD	1		/* pad with zero */
144*4882a593Smuzhiyun #define SIGN	2		/* unsigned/signed long */
145*4882a593Smuzhiyun #define PLUS	4		/* show plus */
146*4882a593Smuzhiyun #define SPACE	8		/* space if plus */
147*4882a593Smuzhiyun #define LEFT	16		/* left justified */
148*4882a593Smuzhiyun #define SMALL	32		/* Must be 32 == 0x20 */
149*4882a593Smuzhiyun #define SPECIAL	64		/* 0x */
150*4882a593Smuzhiyun #define WIDE	128		/* UTF-16 string */
151*4882a593Smuzhiyun 
152*4882a593Smuzhiyun static
get_flags(const char ** fmt)153*4882a593Smuzhiyun int get_flags(const char **fmt)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	int flags = 0;
156*4882a593Smuzhiyun 
157*4882a593Smuzhiyun 	do {
158*4882a593Smuzhiyun 		switch (**fmt) {
159*4882a593Smuzhiyun 		case '-':
160*4882a593Smuzhiyun 			flags |= LEFT;
161*4882a593Smuzhiyun 			break;
162*4882a593Smuzhiyun 		case '+':
163*4882a593Smuzhiyun 			flags |= PLUS;
164*4882a593Smuzhiyun 			break;
165*4882a593Smuzhiyun 		case ' ':
166*4882a593Smuzhiyun 			flags |= SPACE;
167*4882a593Smuzhiyun 			break;
168*4882a593Smuzhiyun 		case '#':
169*4882a593Smuzhiyun 			flags |= SPECIAL;
170*4882a593Smuzhiyun 			break;
171*4882a593Smuzhiyun 		case '0':
172*4882a593Smuzhiyun 			flags |= ZEROPAD;
173*4882a593Smuzhiyun 			break;
174*4882a593Smuzhiyun 		default:
175*4882a593Smuzhiyun 			return flags;
176*4882a593Smuzhiyun 		}
177*4882a593Smuzhiyun 		++(*fmt);
178*4882a593Smuzhiyun 	} while (1);
179*4882a593Smuzhiyun }
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun static
get_int(const char ** fmt,va_list * ap)182*4882a593Smuzhiyun int get_int(const char **fmt, va_list *ap)
183*4882a593Smuzhiyun {
184*4882a593Smuzhiyun 	if (isdigit(**fmt))
185*4882a593Smuzhiyun 		return skip_atoi(fmt);
186*4882a593Smuzhiyun 	if (**fmt == '*') {
187*4882a593Smuzhiyun 		++(*fmt);
188*4882a593Smuzhiyun 		/* it's the next argument */
189*4882a593Smuzhiyun 		return va_arg(*ap, int);
190*4882a593Smuzhiyun 	}
191*4882a593Smuzhiyun 	return 0;
192*4882a593Smuzhiyun }
193*4882a593Smuzhiyun 
194*4882a593Smuzhiyun static
get_number(int sign,int qualifier,va_list * ap)195*4882a593Smuzhiyun unsigned long long get_number(int sign, int qualifier, va_list *ap)
196*4882a593Smuzhiyun {
197*4882a593Smuzhiyun 	if (sign) {
198*4882a593Smuzhiyun 		switch (qualifier) {
199*4882a593Smuzhiyun 		case 'L':
200*4882a593Smuzhiyun 			return va_arg(*ap, long long);
201*4882a593Smuzhiyun 		case 'l':
202*4882a593Smuzhiyun 			return va_arg(*ap, long);
203*4882a593Smuzhiyun 		case 'h':
204*4882a593Smuzhiyun 			return (short)va_arg(*ap, int);
205*4882a593Smuzhiyun 		case 'H':
206*4882a593Smuzhiyun 			return (signed char)va_arg(*ap, int);
207*4882a593Smuzhiyun 		default:
208*4882a593Smuzhiyun 			return va_arg(*ap, int);
209*4882a593Smuzhiyun 		};
210*4882a593Smuzhiyun 	} else {
211*4882a593Smuzhiyun 		switch (qualifier) {
212*4882a593Smuzhiyun 		case 'L':
213*4882a593Smuzhiyun 			return va_arg(*ap, unsigned long long);
214*4882a593Smuzhiyun 		case 'l':
215*4882a593Smuzhiyun 			return va_arg(*ap, unsigned long);
216*4882a593Smuzhiyun 		case 'h':
217*4882a593Smuzhiyun 			return (unsigned short)va_arg(*ap, int);
218*4882a593Smuzhiyun 		case 'H':
219*4882a593Smuzhiyun 			return (unsigned char)va_arg(*ap, int);
220*4882a593Smuzhiyun 		default:
221*4882a593Smuzhiyun 			return va_arg(*ap, unsigned int);
222*4882a593Smuzhiyun 		}
223*4882a593Smuzhiyun 	}
224*4882a593Smuzhiyun }
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun static
get_sign(long long * num,int flags)227*4882a593Smuzhiyun char get_sign(long long *num, int flags)
228*4882a593Smuzhiyun {
229*4882a593Smuzhiyun 	if (!(flags & SIGN))
230*4882a593Smuzhiyun 		return 0;
231*4882a593Smuzhiyun 	if (*num < 0) {
232*4882a593Smuzhiyun 		*num = -(*num);
233*4882a593Smuzhiyun 		return '-';
234*4882a593Smuzhiyun 	}
235*4882a593Smuzhiyun 	if (flags & PLUS)
236*4882a593Smuzhiyun 		return '+';
237*4882a593Smuzhiyun 	if (flags & SPACE)
238*4882a593Smuzhiyun 		return ' ';
239*4882a593Smuzhiyun 	return 0;
240*4882a593Smuzhiyun }
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun static
utf16s_utf8nlen(const u16 * s16,size_t maxlen)243*4882a593Smuzhiyun size_t utf16s_utf8nlen(const u16 *s16, size_t maxlen)
244*4882a593Smuzhiyun {
245*4882a593Smuzhiyun 	size_t len, clen;
246*4882a593Smuzhiyun 
247*4882a593Smuzhiyun 	for (len = 0; len < maxlen && *s16; len += clen) {
248*4882a593Smuzhiyun 		u16 c0 = *s16++;
249*4882a593Smuzhiyun 
250*4882a593Smuzhiyun 		/* First, get the length for a BMP character */
251*4882a593Smuzhiyun 		clen = 1 + (c0 >= 0x80) + (c0 >= 0x800);
252*4882a593Smuzhiyun 		if (len + clen > maxlen)
253*4882a593Smuzhiyun 			break;
254*4882a593Smuzhiyun 		/*
255*4882a593Smuzhiyun 		 * If this is a high surrogate, and we're already at maxlen, we
256*4882a593Smuzhiyun 		 * can't include the character if it's a valid surrogate pair.
257*4882a593Smuzhiyun 		 * Avoid accessing one extra word just to check if it's valid
258*4882a593Smuzhiyun 		 * or not.
259*4882a593Smuzhiyun 		 */
260*4882a593Smuzhiyun 		if ((c0 & 0xfc00) == 0xd800) {
261*4882a593Smuzhiyun 			if (len + clen == maxlen)
262*4882a593Smuzhiyun 				break;
263*4882a593Smuzhiyun 			if ((*s16 & 0xfc00) == 0xdc00) {
264*4882a593Smuzhiyun 				++s16;
265*4882a593Smuzhiyun 				++clen;
266*4882a593Smuzhiyun 			}
267*4882a593Smuzhiyun 		}
268*4882a593Smuzhiyun 	}
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun 	return len;
271*4882a593Smuzhiyun }
272*4882a593Smuzhiyun 
273*4882a593Smuzhiyun static
utf16_to_utf32(const u16 ** s16)274*4882a593Smuzhiyun u32 utf16_to_utf32(const u16 **s16)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	u16 c0, c1;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	c0 = *(*s16)++;
279*4882a593Smuzhiyun 	/* not a surrogate */
280*4882a593Smuzhiyun 	if ((c0 & 0xf800) != 0xd800)
281*4882a593Smuzhiyun 		return c0;
282*4882a593Smuzhiyun 	/* invalid: low surrogate instead of high */
283*4882a593Smuzhiyun 	if (c0 & 0x0400)
284*4882a593Smuzhiyun 		return 0xfffd;
285*4882a593Smuzhiyun 	c1 = **s16;
286*4882a593Smuzhiyun 	/* invalid: missing low surrogate */
287*4882a593Smuzhiyun 	if ((c1 & 0xfc00) != 0xdc00)
288*4882a593Smuzhiyun 		return 0xfffd;
289*4882a593Smuzhiyun 	/* valid surrogate pair */
290*4882a593Smuzhiyun 	++(*s16);
291*4882a593Smuzhiyun 	return (0x10000 - (0xd800 << 10) - 0xdc00) + (c0 << 10) + c1;
292*4882a593Smuzhiyun }
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun #define PUTC(c) \
295*4882a593Smuzhiyun do {				\
296*4882a593Smuzhiyun 	if (pos < size)		\
297*4882a593Smuzhiyun 		buf[pos] = (c);	\
298*4882a593Smuzhiyun 	++pos;			\
299*4882a593Smuzhiyun } while (0);
300*4882a593Smuzhiyun 
vsnprintf(char * buf,size_t size,const char * fmt,va_list ap)301*4882a593Smuzhiyun int vsnprintf(char *buf, size_t size, const char *fmt, va_list ap)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	/* The maximum space required is to print a 64-bit number in octal */
304*4882a593Smuzhiyun 	char tmp[(sizeof(unsigned long long) * 8 + 2) / 3];
305*4882a593Smuzhiyun 	char *tmp_end = &tmp[ARRAY_SIZE(tmp)];
306*4882a593Smuzhiyun 	long long num;
307*4882a593Smuzhiyun 	int base;
308*4882a593Smuzhiyun 	const char *s;
309*4882a593Smuzhiyun 	size_t len, pos;
310*4882a593Smuzhiyun 	char sign;
311*4882a593Smuzhiyun 
312*4882a593Smuzhiyun 	int flags;		/* flags to number() */
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun 	int field_width;	/* width of output field */
315*4882a593Smuzhiyun 	int precision;		/* min. # of digits for integers; max
316*4882a593Smuzhiyun 				   number of chars for from string */
317*4882a593Smuzhiyun 	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
318*4882a593Smuzhiyun 
319*4882a593Smuzhiyun 	va_list args;
320*4882a593Smuzhiyun 
321*4882a593Smuzhiyun 	/*
322*4882a593Smuzhiyun 	 * We want to pass our input va_list to helper functions by reference,
323*4882a593Smuzhiyun 	 * but there's an annoying edge case. If va_list was originally passed
324*4882a593Smuzhiyun 	 * to us by value, we could just pass &ap down to the helpers. This is
325*4882a593Smuzhiyun 	 * the case on, for example, X86_32.
326*4882a593Smuzhiyun 	 * However, on X86_64 (and possibly others), va_list is actually a
327*4882a593Smuzhiyun 	 * size-1 array containing a structure. Our function parameter ap has
328*4882a593Smuzhiyun 	 * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
329*4882a593Smuzhiyun 	 * which is what will be expected by a function taking a va_list *
330*4882a593Smuzhiyun 	 * parameter.
331*4882a593Smuzhiyun 	 * One standard way to solve this mess is by creating a copy in a local
332*4882a593Smuzhiyun 	 * variable of type va_list and then passing a pointer to that local
333*4882a593Smuzhiyun 	 * copy instead, which is what we do here.
334*4882a593Smuzhiyun 	 */
335*4882a593Smuzhiyun 	va_copy(args, ap);
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	for (pos = 0; *fmt; ++fmt) {
338*4882a593Smuzhiyun 		if (*fmt != '%' || *++fmt == '%') {
339*4882a593Smuzhiyun 			PUTC(*fmt);
340*4882a593Smuzhiyun 			continue;
341*4882a593Smuzhiyun 		}
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 		/* process flags */
344*4882a593Smuzhiyun 		flags = get_flags(&fmt);
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 		/* get field width */
347*4882a593Smuzhiyun 		field_width = get_int(&fmt, &args);
348*4882a593Smuzhiyun 		if (field_width < 0) {
349*4882a593Smuzhiyun 			field_width = -field_width;
350*4882a593Smuzhiyun 			flags |= LEFT;
351*4882a593Smuzhiyun 		}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 		if (flags & LEFT)
354*4882a593Smuzhiyun 			flags &= ~ZEROPAD;
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun 		/* get the precision */
357*4882a593Smuzhiyun 		precision = -1;
358*4882a593Smuzhiyun 		if (*fmt == '.') {
359*4882a593Smuzhiyun 			++fmt;
360*4882a593Smuzhiyun 			precision = get_int(&fmt, &args);
361*4882a593Smuzhiyun 			if (precision >= 0)
362*4882a593Smuzhiyun 				flags &= ~ZEROPAD;
363*4882a593Smuzhiyun 		}
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun 		/* get the conversion qualifier */
366*4882a593Smuzhiyun 		qualifier = -1;
367*4882a593Smuzhiyun 		if (*fmt == 'h' || *fmt == 'l') {
368*4882a593Smuzhiyun 			qualifier = *fmt;
369*4882a593Smuzhiyun 			++fmt;
370*4882a593Smuzhiyun 			if (qualifier == *fmt) {
371*4882a593Smuzhiyun 				qualifier -= 'a'-'A';
372*4882a593Smuzhiyun 				++fmt;
373*4882a593Smuzhiyun 			}
374*4882a593Smuzhiyun 		}
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun 		sign = 0;
377*4882a593Smuzhiyun 
378*4882a593Smuzhiyun 		switch (*fmt) {
379*4882a593Smuzhiyun 		case 'c':
380*4882a593Smuzhiyun 			flags &= LEFT;
381*4882a593Smuzhiyun 			s = tmp;
382*4882a593Smuzhiyun 			if (qualifier == 'l') {
383*4882a593Smuzhiyun 				((u16 *)tmp)[0] = (u16)va_arg(args, unsigned int);
384*4882a593Smuzhiyun 				((u16 *)tmp)[1] = L'\0';
385*4882a593Smuzhiyun 				precision = INT_MAX;
386*4882a593Smuzhiyun 				goto wstring;
387*4882a593Smuzhiyun 			} else {
388*4882a593Smuzhiyun 				tmp[0] = (unsigned char)va_arg(args, int);
389*4882a593Smuzhiyun 				precision = len = 1;
390*4882a593Smuzhiyun 			}
391*4882a593Smuzhiyun 			goto output;
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 		case 's':
394*4882a593Smuzhiyun 			flags &= LEFT;
395*4882a593Smuzhiyun 			if (precision < 0)
396*4882a593Smuzhiyun 				precision = INT_MAX;
397*4882a593Smuzhiyun 			s = va_arg(args, void *);
398*4882a593Smuzhiyun 			if (!s)
399*4882a593Smuzhiyun 				s = precision < 6 ? "" : "(null)";
400*4882a593Smuzhiyun 			else if (qualifier == 'l') {
401*4882a593Smuzhiyun 		wstring:
402*4882a593Smuzhiyun 				flags |= WIDE;
403*4882a593Smuzhiyun 				precision = len = utf16s_utf8nlen((const u16 *)s, precision);
404*4882a593Smuzhiyun 				goto output;
405*4882a593Smuzhiyun 			}
406*4882a593Smuzhiyun 			precision = len = strnlen(s, precision);
407*4882a593Smuzhiyun 			goto output;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 			/* integer number formats - set up the flags and "break" */
410*4882a593Smuzhiyun 		case 'o':
411*4882a593Smuzhiyun 			base = 8;
412*4882a593Smuzhiyun 			break;
413*4882a593Smuzhiyun 
414*4882a593Smuzhiyun 		case 'p':
415*4882a593Smuzhiyun 			if (precision < 0)
416*4882a593Smuzhiyun 				precision = 2 * sizeof(void *);
417*4882a593Smuzhiyun 			fallthrough;
418*4882a593Smuzhiyun 		case 'x':
419*4882a593Smuzhiyun 			flags |= SMALL;
420*4882a593Smuzhiyun 			fallthrough;
421*4882a593Smuzhiyun 		case 'X':
422*4882a593Smuzhiyun 			base = 16;
423*4882a593Smuzhiyun 			break;
424*4882a593Smuzhiyun 
425*4882a593Smuzhiyun 		case 'd':
426*4882a593Smuzhiyun 		case 'i':
427*4882a593Smuzhiyun 			flags |= SIGN;
428*4882a593Smuzhiyun 			fallthrough;
429*4882a593Smuzhiyun 		case 'u':
430*4882a593Smuzhiyun 			flags &= ~SPECIAL;
431*4882a593Smuzhiyun 			base = 10;
432*4882a593Smuzhiyun 			break;
433*4882a593Smuzhiyun 
434*4882a593Smuzhiyun 		default:
435*4882a593Smuzhiyun 			/*
436*4882a593Smuzhiyun 			 * Bail out if the conversion specifier is invalid.
437*4882a593Smuzhiyun 			 * There's probably a typo in the format string and the
438*4882a593Smuzhiyun 			 * remaining specifiers are unlikely to match up with
439*4882a593Smuzhiyun 			 * the arguments.
440*4882a593Smuzhiyun 			 */
441*4882a593Smuzhiyun 			goto fail;
442*4882a593Smuzhiyun 		}
443*4882a593Smuzhiyun 		if (*fmt == 'p') {
444*4882a593Smuzhiyun 			num = (unsigned long)va_arg(args, void *);
445*4882a593Smuzhiyun 		} else {
446*4882a593Smuzhiyun 			num = get_number(flags & SIGN, qualifier, &args);
447*4882a593Smuzhiyun 		}
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 		sign = get_sign(&num, flags);
450*4882a593Smuzhiyun 		if (sign)
451*4882a593Smuzhiyun 			--field_width;
452*4882a593Smuzhiyun 
453*4882a593Smuzhiyun 		s = number(tmp_end, num, base, flags & SMALL);
454*4882a593Smuzhiyun 		len = tmp_end - s;
455*4882a593Smuzhiyun 		/* default precision is 1 */
456*4882a593Smuzhiyun 		if (precision < 0)
457*4882a593Smuzhiyun 			precision = 1;
458*4882a593Smuzhiyun 		/* precision is minimum number of digits to print */
459*4882a593Smuzhiyun 		if (precision < len)
460*4882a593Smuzhiyun 			precision = len;
461*4882a593Smuzhiyun 		if (flags & SPECIAL) {
462*4882a593Smuzhiyun 			/*
463*4882a593Smuzhiyun 			 * For octal, a leading 0 is printed only if necessary,
464*4882a593Smuzhiyun 			 * i.e. if it's not already there because of the
465*4882a593Smuzhiyun 			 * precision.
466*4882a593Smuzhiyun 			 */
467*4882a593Smuzhiyun 			if (base == 8 && precision == len)
468*4882a593Smuzhiyun 				++precision;
469*4882a593Smuzhiyun 			/*
470*4882a593Smuzhiyun 			 * For hexadecimal, the leading 0x is skipped if the
471*4882a593Smuzhiyun 			 * output is empty, i.e. both the number and the
472*4882a593Smuzhiyun 			 * precision are 0.
473*4882a593Smuzhiyun 			 */
474*4882a593Smuzhiyun 			if (base == 16 && precision > 0)
475*4882a593Smuzhiyun 				field_width -= 2;
476*4882a593Smuzhiyun 			else
477*4882a593Smuzhiyun 				flags &= ~SPECIAL;
478*4882a593Smuzhiyun 		}
479*4882a593Smuzhiyun 		/*
480*4882a593Smuzhiyun 		 * For zero padding, increase the precision to fill the field
481*4882a593Smuzhiyun 		 * width.
482*4882a593Smuzhiyun 		 */
483*4882a593Smuzhiyun 		if ((flags & ZEROPAD) && field_width > precision)
484*4882a593Smuzhiyun 			precision = field_width;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun output:
487*4882a593Smuzhiyun 		/* Calculate the padding necessary */
488*4882a593Smuzhiyun 		field_width -= precision;
489*4882a593Smuzhiyun 		/* Leading padding with ' ' */
490*4882a593Smuzhiyun 		if (!(flags & LEFT))
491*4882a593Smuzhiyun 			while (field_width-- > 0)
492*4882a593Smuzhiyun 				PUTC(' ');
493*4882a593Smuzhiyun 		/* sign */
494*4882a593Smuzhiyun 		if (sign)
495*4882a593Smuzhiyun 			PUTC(sign);
496*4882a593Smuzhiyun 		/* 0x/0X for hexadecimal */
497*4882a593Smuzhiyun 		if (flags & SPECIAL) {
498*4882a593Smuzhiyun 			PUTC('0');
499*4882a593Smuzhiyun 			PUTC( 'X' | (flags & SMALL));
500*4882a593Smuzhiyun 		}
501*4882a593Smuzhiyun 		/* Zero padding and excess precision */
502*4882a593Smuzhiyun 		while (precision-- > len)
503*4882a593Smuzhiyun 			PUTC('0');
504*4882a593Smuzhiyun 		/* Actual output */
505*4882a593Smuzhiyun 		if (flags & WIDE) {
506*4882a593Smuzhiyun 			const u16 *ws = (const u16 *)s;
507*4882a593Smuzhiyun 
508*4882a593Smuzhiyun 			while (len-- > 0) {
509*4882a593Smuzhiyun 				u32 c32 = utf16_to_utf32(&ws);
510*4882a593Smuzhiyun 				u8 *s8;
511*4882a593Smuzhiyun 				size_t clen;
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun 				if (c32 < 0x80) {
514*4882a593Smuzhiyun 					PUTC(c32);
515*4882a593Smuzhiyun 					continue;
516*4882a593Smuzhiyun 				}
517*4882a593Smuzhiyun 
518*4882a593Smuzhiyun 				/* Number of trailing octets */
519*4882a593Smuzhiyun 				clen = 1 + (c32 >= 0x800) + (c32 >= 0x10000);
520*4882a593Smuzhiyun 
521*4882a593Smuzhiyun 				len -= clen;
522*4882a593Smuzhiyun 				s8 = (u8 *)&buf[pos];
523*4882a593Smuzhiyun 
524*4882a593Smuzhiyun 				/* Avoid writing partial character */
525*4882a593Smuzhiyun 				PUTC('\0');
526*4882a593Smuzhiyun 				pos += clen;
527*4882a593Smuzhiyun 				if (pos >= size)
528*4882a593Smuzhiyun 					continue;
529*4882a593Smuzhiyun 
530*4882a593Smuzhiyun 				/* Set high bits of leading octet */
531*4882a593Smuzhiyun 				*s8 = (0xf00 >> 1) >> clen;
532*4882a593Smuzhiyun 				/* Write trailing octets in reverse order */
533*4882a593Smuzhiyun 				for (s8 += clen; clen; --clen, c32 >>= 6)
534*4882a593Smuzhiyun 					*s8-- = 0x80 | (c32 & 0x3f);
535*4882a593Smuzhiyun 				/* Set low bits of leading octet */
536*4882a593Smuzhiyun 				*s8 |= c32;
537*4882a593Smuzhiyun 			}
538*4882a593Smuzhiyun 		} else {
539*4882a593Smuzhiyun 			while (len-- > 0)
540*4882a593Smuzhiyun 				PUTC(*s++);
541*4882a593Smuzhiyun 		}
542*4882a593Smuzhiyun 		/* Trailing padding with ' ' */
543*4882a593Smuzhiyun 		while (field_width-- > 0)
544*4882a593Smuzhiyun 			PUTC(' ');
545*4882a593Smuzhiyun 	}
546*4882a593Smuzhiyun fail:
547*4882a593Smuzhiyun 	va_end(args);
548*4882a593Smuzhiyun 
549*4882a593Smuzhiyun 	if (size)
550*4882a593Smuzhiyun 		buf[min(pos, size-1)] = '\0';
551*4882a593Smuzhiyun 
552*4882a593Smuzhiyun 	return pos;
553*4882a593Smuzhiyun }
554*4882a593Smuzhiyun 
snprintf(char * buf,size_t size,const char * fmt,...)555*4882a593Smuzhiyun int snprintf(char *buf, size_t size, const char *fmt, ...)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	va_list args;
558*4882a593Smuzhiyun 	int i;
559*4882a593Smuzhiyun 
560*4882a593Smuzhiyun 	va_start(args, fmt);
561*4882a593Smuzhiyun 	i = vsnprintf(buf, size, fmt, args);
562*4882a593Smuzhiyun 	va_end(args);
563*4882a593Smuzhiyun 	return i;
564*4882a593Smuzhiyun }
565