xref: /DragonStub/apps/lib/vsprintf.c (revision 78b790fa8bc8298f8bdfd5bd1945781650dbf361)
1f412fd2aSLoGin 
2f412fd2aSLoGin #include <dragonstub/dragonstub.h>
3f412fd2aSLoGin #include <dragonstub/linux/stdarg.h>
4f412fd2aSLoGin #include <dragonstub/bug.h>
5f412fd2aSLoGin #include <dragonstub/minmax.h>
6f412fd2aSLoGin #include <dragonstub/limits.h>
7f412fd2aSLoGin #include <dragonstub/compiler_types.h>
8f412fd2aSLoGin #include <dragonstub/linux/err.h>
9f412fd2aSLoGin #include <dragonstub/linux/byteorder.h>
10f412fd2aSLoGin #include <dragonstub/linux/div64.h>
11f412fd2aSLoGin 
12f412fd2aSLoGin struct printf_spec {
13f412fd2aSLoGin 	unsigned int type : 8; /* format_type enum */
14f412fd2aSLoGin 	signed int field_width : 24; /* width of output field */
15f412fd2aSLoGin 	unsigned int flags : 8; /* flags to number() */
16f412fd2aSLoGin 	unsigned int base : 8; /* number base, 8, 10 or 16 only */
17f412fd2aSLoGin 	signed int precision : 16; /* # of digits/chars */
18f412fd2aSLoGin } __packed;
19f412fd2aSLoGin 
20f412fd2aSLoGin #define SIGN 1 /* unsigned/signed, must be 1 */
21f412fd2aSLoGin #define LEFT 2 /* left justified */
22f412fd2aSLoGin #define PLUS 4 /* show plus */
23f412fd2aSLoGin #define SPACE 8 /* space if plus */
24f412fd2aSLoGin #define ZEROPAD 16 /* pad with zero, must be 16 == '0' - ' ' */
25f412fd2aSLoGin #define SMALL 32 /* use lowercase in hex (must be 32 == 0x20) */
26f412fd2aSLoGin #define SPECIAL 64 /* prefix hex with "0x", octal with "0" */
27f412fd2aSLoGin 
28f412fd2aSLoGin static_assert(SIGN == 1);
29f412fd2aSLoGin static_assert(ZEROPAD == ('0' - ' '));
30f412fd2aSLoGin static_assert(SMALL == ('a' ^ 'A'));
31f412fd2aSLoGin 
32f412fd2aSLoGin enum format_type {
33f412fd2aSLoGin 	FORMAT_TYPE_NONE, /* Just a string part */
34f412fd2aSLoGin 	FORMAT_TYPE_WIDTH,
35f412fd2aSLoGin 	FORMAT_TYPE_PRECISION,
36f412fd2aSLoGin 	FORMAT_TYPE_CHAR,
37f412fd2aSLoGin 	FORMAT_TYPE_STR,
38f412fd2aSLoGin 	FORMAT_TYPE_PTR,
39f412fd2aSLoGin 	FORMAT_TYPE_PERCENT_CHAR,
40f412fd2aSLoGin 	FORMAT_TYPE_INVALID,
41f412fd2aSLoGin 	FORMAT_TYPE_LONG_LONG,
42f412fd2aSLoGin 	FORMAT_TYPE_ULONG,
43f412fd2aSLoGin 	FORMAT_TYPE_LONG,
44f412fd2aSLoGin 	FORMAT_TYPE_UBYTE,
45f412fd2aSLoGin 	FORMAT_TYPE_BYTE,
46f412fd2aSLoGin 	FORMAT_TYPE_USHORT,
47f412fd2aSLoGin 	FORMAT_TYPE_SHORT,
48f412fd2aSLoGin 	FORMAT_TYPE_UINT,
49f412fd2aSLoGin 	FORMAT_TYPE_INT,
50f412fd2aSLoGin 	FORMAT_TYPE_SIZE_T,
51f412fd2aSLoGin 	FORMAT_TYPE_PTRDIFF
52f412fd2aSLoGin };
53f412fd2aSLoGin 
skip_atoi(const char ** s)54f412fd2aSLoGin static noinline_for_stack int skip_atoi(const char **s)
55f412fd2aSLoGin {
56f412fd2aSLoGin 	int i = 0;
57f412fd2aSLoGin 
58f412fd2aSLoGin 	do {
59f412fd2aSLoGin 		i = i * 10 + *((*s)++) - '0';
60f412fd2aSLoGin 	} while (isdigit(**s));
61f412fd2aSLoGin 
62f412fd2aSLoGin 	return i;
63f412fd2aSLoGin }
64f412fd2aSLoGin 
65f412fd2aSLoGin /*
66f412fd2aSLoGin  * Decimal conversion is by far the most typical, and is used for
67f412fd2aSLoGin  * /proc and /sys data. This directly impacts e.g. top performance
68f412fd2aSLoGin  * with many processes running. We optimize it for speed by emitting
69f412fd2aSLoGin  * two characters at a time, using a 200 byte lookup table. This
70f412fd2aSLoGin  * roughly halves the number of multiplications compared to computing
71f412fd2aSLoGin  * the digits one at a time. Implementation strongly inspired by the
72f412fd2aSLoGin  * previous version, which in turn used ideas described at
73f412fd2aSLoGin  * <http://www.cs.uiowa.edu/~jones/bcd/divide.html> (with permission
74f412fd2aSLoGin  * from the author, Douglas W. Jones).
75f412fd2aSLoGin  *
76f412fd2aSLoGin  * It turns out there is precisely one 26 bit fixed-point
77f412fd2aSLoGin  * approximation a of 64/100 for which x/100 == (x * (u64)a) >> 32
78f412fd2aSLoGin  * holds for all x in [0, 10^8-1], namely a = 0x28f5c29. The actual
79f412fd2aSLoGin  * range happens to be somewhat larger (x <= 1073741898), but that's
80f412fd2aSLoGin  * irrelevant for our purpose.
81f412fd2aSLoGin  *
82f412fd2aSLoGin  * For dividing a number in the range [10^4, 10^6-1] by 100, we still
83f412fd2aSLoGin  * need a 32x32->64 bit multiply, so we simply use the same constant.
84f412fd2aSLoGin  *
85f412fd2aSLoGin  * For dividing a number in the range [100, 10^4-1] by 100, there are
86f412fd2aSLoGin  * several options. The simplest is (x * 0x147b) >> 19, which is valid
87f412fd2aSLoGin  * for all x <= 43698.
88f412fd2aSLoGin  */
89f412fd2aSLoGin 
90f412fd2aSLoGin static const u16 decpair[100] = {
91f412fd2aSLoGin #define _(x) (__force u16) cpu_to_le16(((x % 10) | ((x / 10) << 8)) + 0x3030)
92f412fd2aSLoGin 	_(0),  _(1),  _(2),  _(3),  _(4),  _(5),  _(6),	 _(7),	_(8),  _(9),
93f412fd2aSLoGin 	_(10), _(11), _(12), _(13), _(14), _(15), _(16), _(17), _(18), _(19),
94f412fd2aSLoGin 	_(20), _(21), _(22), _(23), _(24), _(25), _(26), _(27), _(28), _(29),
95f412fd2aSLoGin 	_(30), _(31), _(32), _(33), _(34), _(35), _(36), _(37), _(38), _(39),
96f412fd2aSLoGin 	_(40), _(41), _(42), _(43), _(44), _(45), _(46), _(47), _(48), _(49),
97f412fd2aSLoGin 	_(50), _(51), _(52), _(53), _(54), _(55), _(56), _(57), _(58), _(59),
98f412fd2aSLoGin 	_(60), _(61), _(62), _(63), _(64), _(65), _(66), _(67), _(68), _(69),
99f412fd2aSLoGin 	_(70), _(71), _(72), _(73), _(74), _(75), _(76), _(77), _(78), _(79),
100f412fd2aSLoGin 	_(80), _(81), _(82), _(83), _(84), _(85), _(86), _(87), _(88), _(89),
101f412fd2aSLoGin 	_(90), _(91), _(92), _(93), _(94), _(95), _(96), _(97), _(98), _(99),
102f412fd2aSLoGin #undef _
103f412fd2aSLoGin };
104f412fd2aSLoGin 
105f412fd2aSLoGin /*
106f412fd2aSLoGin  * This will print a single '0' even if r == 0, since we would
107f412fd2aSLoGin  * immediately jump to out_r where two 0s would be written but only
108f412fd2aSLoGin  * one of them accounted for in buf. This is needed by ip4_string
109f412fd2aSLoGin  * below. All other callers pass a non-zero value of r.
110f412fd2aSLoGin */
put_dec_trunc8(char * buf,unsigned r)111f412fd2aSLoGin static noinline_for_stack char *put_dec_trunc8(char *buf, unsigned r)
112f412fd2aSLoGin {
113f412fd2aSLoGin 	unsigned q;
114f412fd2aSLoGin 
115f412fd2aSLoGin 	/* 1 <= r < 10^8 */
116f412fd2aSLoGin 	if (r < 100)
117f412fd2aSLoGin 		goto out_r;
118f412fd2aSLoGin 
119f412fd2aSLoGin 	/* 100 <= r < 10^8 */
120f412fd2aSLoGin 	q = (r * (u64)0x28f5c29) >> 32;
121f412fd2aSLoGin 	*((u16 *)buf) = decpair[r - 100 * q];
122f412fd2aSLoGin 	buf += 2;
123f412fd2aSLoGin 
124f412fd2aSLoGin 	/* 1 <= q < 10^6 */
125f412fd2aSLoGin 	if (q < 100)
126f412fd2aSLoGin 		goto out_q;
127f412fd2aSLoGin 
128f412fd2aSLoGin 	/*  100 <= q < 10^6 */
129f412fd2aSLoGin 	r = (q * (u64)0x28f5c29) >> 32;
130f412fd2aSLoGin 	*((u16 *)buf) = decpair[q - 100 * r];
131f412fd2aSLoGin 	buf += 2;
132f412fd2aSLoGin 
133f412fd2aSLoGin 	/* 1 <= r < 10^4 */
134f412fd2aSLoGin 	if (r < 100)
135f412fd2aSLoGin 		goto out_r;
136f412fd2aSLoGin 
137f412fd2aSLoGin 	/* 100 <= r < 10^4 */
138f412fd2aSLoGin 	q = (r * 0x147b) >> 19;
139f412fd2aSLoGin 	*((u16 *)buf) = decpair[r - 100 * q];
140f412fd2aSLoGin 	buf += 2;
141f412fd2aSLoGin out_q:
142f412fd2aSLoGin 	/* 1 <= q < 100 */
143f412fd2aSLoGin 	r = q;
144f412fd2aSLoGin out_r:
145f412fd2aSLoGin 	/* 1 <= r < 100 */
146f412fd2aSLoGin 	*((u16 *)buf) = decpair[r];
147f412fd2aSLoGin 	buf += r < 10 ? 1 : 2;
148f412fd2aSLoGin 	return buf;
149f412fd2aSLoGin }
150f412fd2aSLoGin 
151f412fd2aSLoGin #if BITS_PER_LONG == 64 && BITS_PER_LONG_LONG == 64
put_dec_full8(char * buf,unsigned r)152f412fd2aSLoGin static noinline_for_stack char *put_dec_full8(char *buf, unsigned r)
153f412fd2aSLoGin {
154f412fd2aSLoGin 	unsigned q;
155f412fd2aSLoGin 
156f412fd2aSLoGin 	/* 0 <= r < 10^8 */
157f412fd2aSLoGin 	q = (r * (u64)0x28f5c29) >> 32;
158f412fd2aSLoGin 	*((u16 *)buf) = decpair[r - 100 * q];
159f412fd2aSLoGin 	buf += 2;
160f412fd2aSLoGin 
161f412fd2aSLoGin 	/* 0 <= q < 10^6 */
162f412fd2aSLoGin 	r = (q * (u64)0x28f5c29) >> 32;
163f412fd2aSLoGin 	*((u16 *)buf) = decpair[q - 100 * r];
164f412fd2aSLoGin 	buf += 2;
165f412fd2aSLoGin 
166f412fd2aSLoGin 	/* 0 <= r < 10^4 */
167f412fd2aSLoGin 	q = (r * 0x147b) >> 19;
168f412fd2aSLoGin 	*((u16 *)buf) = decpair[r - 100 * q];
169f412fd2aSLoGin 	buf += 2;
170f412fd2aSLoGin 
171f412fd2aSLoGin 	/* 0 <= q < 100 */
172f412fd2aSLoGin 	*((u16 *)buf) = decpair[q];
173f412fd2aSLoGin 	buf += 2;
174f412fd2aSLoGin 	return buf;
175f412fd2aSLoGin }
176f412fd2aSLoGin 
put_dec(char * buf,unsigned long long n)177f412fd2aSLoGin static noinline_for_stack char *put_dec(char *buf, unsigned long long n)
178f412fd2aSLoGin {
179f412fd2aSLoGin 	if (n >= 100 * 1000 * 1000)
180f412fd2aSLoGin 		buf = put_dec_full8(buf, do_div(n, 100 * 1000 * 1000));
181f412fd2aSLoGin 	/* 1 <= n <= 1.6e11 */
182f412fd2aSLoGin 	if (n >= 100 * 1000 * 1000)
183f412fd2aSLoGin 		buf = put_dec_full8(buf, do_div(n, 100 * 1000 * 1000));
184f412fd2aSLoGin 	/* 1 <= n < 1e8 */
185f412fd2aSLoGin 	return put_dec_trunc8(buf, n);
186f412fd2aSLoGin }
187f412fd2aSLoGin 
188f412fd2aSLoGin #elif BITS_PER_LONG == 32 && BITS_PER_LONG_LONG == 64
189f412fd2aSLoGin 
put_dec_full4(char * buf,unsigned r)190*78b790faSLoGin static void put_dec_full4(char *buf, unsigned r)
191f412fd2aSLoGin {
192f412fd2aSLoGin 	unsigned q;
193f412fd2aSLoGin 
194f412fd2aSLoGin 	/* 0 <= r < 10^4 */
195f412fd2aSLoGin 	q = (r * 0x147b) >> 19;
196f412fd2aSLoGin 	*((u16 *)buf) = decpair[r - 100 * q];
197f412fd2aSLoGin 	buf += 2;
198f412fd2aSLoGin 	/* 0 <= q < 100 */
199f412fd2aSLoGin 	*((u16 *)buf) = decpair[q];
200f412fd2aSLoGin }
201f412fd2aSLoGin 
202f412fd2aSLoGin /*
203f412fd2aSLoGin  * Call put_dec_full4 on x % 10000, return x / 10000.
204f412fd2aSLoGin  * The approximation x/10000 == (x * 0x346DC5D7) >> 43
205f412fd2aSLoGin  * holds for all x < 1,128,869,999.  The largest value this
206f412fd2aSLoGin  * helper will ever be asked to convert is 1,125,520,955.
207f412fd2aSLoGin  * (second call in the put_dec code, assuming n is all-ones).
208f412fd2aSLoGin  */
put_dec_helper4(char * buf,unsigned x)209*78b790faSLoGin static noinline_for_stack unsigned put_dec_helper4(char *buf, unsigned x)
210f412fd2aSLoGin {
211f412fd2aSLoGin 	uint32_t q = (x * (uint64_t)0x346DC5D7) >> 43;
212f412fd2aSLoGin 
213f412fd2aSLoGin 	put_dec_full4(buf, x - q * 10000);
214f412fd2aSLoGin 	return q;
215f412fd2aSLoGin }
216f412fd2aSLoGin 
217f412fd2aSLoGin /* Based on code by Douglas W. Jones found at
218f412fd2aSLoGin  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
219f412fd2aSLoGin  * (with permission from the author).
220f412fd2aSLoGin  * Performs no 64-bit division and hence should be fast on 32-bit machines.
221f412fd2aSLoGin  */
put_dec(char * buf,unsigned long long n)222*78b790faSLoGin static char *put_dec(char *buf, unsigned long long n)
223f412fd2aSLoGin {
224f412fd2aSLoGin 	uint32_t d3, d2, d1, q, h;
225f412fd2aSLoGin 
226f412fd2aSLoGin 	if (n < 100 * 1000 * 1000)
227f412fd2aSLoGin 		return put_dec_trunc8(buf, n);
228f412fd2aSLoGin 
229f412fd2aSLoGin 	d1 = ((uint32_t)n >> 16); /* implicit "& 0xffff" */
230f412fd2aSLoGin 	h = (n >> 32);
231f412fd2aSLoGin 	d2 = (h)&0xffff;
232f412fd2aSLoGin 	d3 = (h >> 16); /* implicit "& 0xffff" */
233f412fd2aSLoGin 
234f412fd2aSLoGin 	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
235f412fd2aSLoGin 	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
236f412fd2aSLoGin 	q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((uint32_t)n & 0xffff);
237f412fd2aSLoGin 	q = put_dec_helper4(buf, q);
238f412fd2aSLoGin 
239f412fd2aSLoGin 	q += 7671 * d3 + 9496 * d2 + 6 * d1;
240f412fd2aSLoGin 	q = put_dec_helper4(buf + 4, q);
241f412fd2aSLoGin 
242f412fd2aSLoGin 	q += 4749 * d3 + 42 * d2;
243f412fd2aSLoGin 	q = put_dec_helper4(buf + 8, q);
244f412fd2aSLoGin 
245f412fd2aSLoGin 	q += 281 * d3;
246f412fd2aSLoGin 	buf += 12;
247f412fd2aSLoGin 	if (q)
248f412fd2aSLoGin 		buf = put_dec_trunc8(buf, q);
249*78b790faSLoGin 	else
250*78b790faSLoGin 		while (buf[-1] == '0')
251f412fd2aSLoGin 			--buf;
252f412fd2aSLoGin 
253f412fd2aSLoGin 	return buf;
254f412fd2aSLoGin }
255f412fd2aSLoGin 
256f412fd2aSLoGin #endif
257f412fd2aSLoGin 
258f412fd2aSLoGin #define FIELD_WIDTH_MAX ((1 << 23) - 1)
259f412fd2aSLoGin #define PRECISION_MAX ((1 << 15) - 1)
260f412fd2aSLoGin 
set_field_width(struct printf_spec * spec,int width)261f412fd2aSLoGin static void set_field_width(struct printf_spec *spec, int width)
262f412fd2aSLoGin {
263f412fd2aSLoGin 	spec->field_width = width;
264f412fd2aSLoGin 	if (WARN_ONCE(spec->field_width != width, "field width %d too large",
265f412fd2aSLoGin 		      width)) {
266f412fd2aSLoGin 		spec->field_width =
267f412fd2aSLoGin 			clamp(width, -FIELD_WIDTH_MAX, FIELD_WIDTH_MAX);
268f412fd2aSLoGin 	}
269f412fd2aSLoGin }
270f412fd2aSLoGin 
set_precision(struct printf_spec * spec,int prec)271f412fd2aSLoGin static void set_precision(struct printf_spec *spec, int prec)
272f412fd2aSLoGin {
273f412fd2aSLoGin 	spec->precision = prec;
274f412fd2aSLoGin 	if (WARN_ONCE(spec->precision != prec, "precision %d too large",
275f412fd2aSLoGin 		      prec)) {
276f412fd2aSLoGin 		spec->precision = clamp(prec, 0, PRECISION_MAX);
277f412fd2aSLoGin 	}
278f412fd2aSLoGin }
279f412fd2aSLoGin 
280f412fd2aSLoGin static noinline_for_stack char *
number(char * buf,char * end,unsigned long long num,struct printf_spec spec)281f412fd2aSLoGin number(char *buf, char *end, unsigned long long num, struct printf_spec spec)
282f412fd2aSLoGin {
283f412fd2aSLoGin 	/* put_dec requires 2-byte alignment of the buffer. */
284f412fd2aSLoGin 	char tmp[3 * sizeof(num)] __aligned(2);
285f412fd2aSLoGin 	char sign;
286f412fd2aSLoGin 	char locase;
287f412fd2aSLoGin 	int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10);
288f412fd2aSLoGin 	int i;
289f412fd2aSLoGin 	bool is_zero = num == 0LL;
290f412fd2aSLoGin 	int field_width = spec.field_width;
291f412fd2aSLoGin 	int precision = spec.precision;
292f412fd2aSLoGin 
293f412fd2aSLoGin 	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
294f412fd2aSLoGin 	 * produces same digits or (maybe lowercased) letters */
295f412fd2aSLoGin 	locase = (spec.flags & SMALL);
296f412fd2aSLoGin 	if (spec.flags & LEFT)
297f412fd2aSLoGin 		spec.flags &= ~ZEROPAD;
298f412fd2aSLoGin 	sign = 0;
299f412fd2aSLoGin 	if (spec.flags & SIGN) {
300f412fd2aSLoGin 		if ((signed long long)num < 0) {
301f412fd2aSLoGin 			sign = '-';
302f412fd2aSLoGin 			num = -(signed long long)num;
303f412fd2aSLoGin 			field_width--;
304f412fd2aSLoGin 		} else if (spec.flags & PLUS) {
305f412fd2aSLoGin 			sign = '+';
306f412fd2aSLoGin 			field_width--;
307f412fd2aSLoGin 		} else if (spec.flags & SPACE) {
308f412fd2aSLoGin 			sign = ' ';
309f412fd2aSLoGin 			field_width--;
310f412fd2aSLoGin 		}
311f412fd2aSLoGin 	}
312f412fd2aSLoGin 	if (need_pfx) {
313f412fd2aSLoGin 		if (spec.base == 16)
314f412fd2aSLoGin 			field_width -= 2;
315f412fd2aSLoGin 		else if (!is_zero)
316f412fd2aSLoGin 			field_width--;
317f412fd2aSLoGin 	}
318f412fd2aSLoGin 
319f412fd2aSLoGin 	/* generate full string in tmp[], in reverse order */
320f412fd2aSLoGin 	i = 0;
321f412fd2aSLoGin 	if (num < spec.base)
322f412fd2aSLoGin 		tmp[i++] = hex_asc_upper[num] | locase;
323f412fd2aSLoGin 	else if (spec.base != 10) { /* 8 or 16 */
324f412fd2aSLoGin 		int mask = spec.base - 1;
325f412fd2aSLoGin 		int shift = 3;
326f412fd2aSLoGin 
327f412fd2aSLoGin 		if (spec.base == 16)
328f412fd2aSLoGin 			shift = 4;
329f412fd2aSLoGin 		do {
330f412fd2aSLoGin 			tmp[i++] = (hex_asc_upper[((unsigned char)num) & mask] |
331f412fd2aSLoGin 				    locase);
332f412fd2aSLoGin 			num >>= shift;
333f412fd2aSLoGin 		} while (num);
334f412fd2aSLoGin 	} else { /* base 10 */
335f412fd2aSLoGin 		i = put_dec(tmp, num) - tmp;
336f412fd2aSLoGin 	}
337f412fd2aSLoGin 
338f412fd2aSLoGin 	/* printing 100 using %2d gives "100", not "00" */
339f412fd2aSLoGin 	if (i > precision)
340f412fd2aSLoGin 		precision = i;
341f412fd2aSLoGin 	/* leading space padding */
342f412fd2aSLoGin 	field_width -= precision;
343f412fd2aSLoGin 	if (!(spec.flags & (ZEROPAD | LEFT))) {
344f412fd2aSLoGin 		while (--field_width >= 0) {
345f412fd2aSLoGin 			if (buf < end)
346f412fd2aSLoGin 				*buf = ' ';
347f412fd2aSLoGin 			++buf;
348f412fd2aSLoGin 		}
349f412fd2aSLoGin 	}
350f412fd2aSLoGin 	/* sign */
351f412fd2aSLoGin 	if (sign) {
352f412fd2aSLoGin 		if (buf < end)
353f412fd2aSLoGin 			*buf = sign;
354f412fd2aSLoGin 		++buf;
355f412fd2aSLoGin 	}
356f412fd2aSLoGin 	/* "0x" / "0" prefix */
357f412fd2aSLoGin 	if (need_pfx) {
358f412fd2aSLoGin 		if (spec.base == 16 || !is_zero) {
359f412fd2aSLoGin 			if (buf < end)
360f412fd2aSLoGin 				*buf = '0';
361f412fd2aSLoGin 			++buf;
362f412fd2aSLoGin 		}
363f412fd2aSLoGin 		if (spec.base == 16) {
364f412fd2aSLoGin 			if (buf < end)
365f412fd2aSLoGin 				*buf = ('X' | locase);
366f412fd2aSLoGin 			++buf;
367f412fd2aSLoGin 		}
368f412fd2aSLoGin 	}
369f412fd2aSLoGin 	/* zero or space padding */
370f412fd2aSLoGin 	if (!(spec.flags & LEFT)) {
371f412fd2aSLoGin 		char c = ' ' + (spec.flags & ZEROPAD);
372f412fd2aSLoGin 
373f412fd2aSLoGin 		while (--field_width >= 0) {
374f412fd2aSLoGin 			if (buf < end)
375f412fd2aSLoGin 				*buf = c;
376f412fd2aSLoGin 			++buf;
377f412fd2aSLoGin 		}
378f412fd2aSLoGin 	}
379f412fd2aSLoGin 	/* hmm even more zero padding? */
380f412fd2aSLoGin 	while (i <= --precision) {
381f412fd2aSLoGin 		if (buf < end)
382f412fd2aSLoGin 			*buf = '0';
383f412fd2aSLoGin 		++buf;
384f412fd2aSLoGin 	}
385f412fd2aSLoGin 	/* actual digits of result */
386f412fd2aSLoGin 	while (--i >= 0) {
387f412fd2aSLoGin 		if (buf < end)
388f412fd2aSLoGin 			*buf = tmp[i];
389f412fd2aSLoGin 		++buf;
390f412fd2aSLoGin 	}
391f412fd2aSLoGin 	/* trailing space padding */
392f412fd2aSLoGin 	while (--field_width >= 0) {
393f412fd2aSLoGin 		if (buf < end)
394f412fd2aSLoGin 			*buf = ' ';
395f412fd2aSLoGin 		++buf;
396f412fd2aSLoGin 	}
397f412fd2aSLoGin 
398f412fd2aSLoGin 	return buf;
399f412fd2aSLoGin }
400f412fd2aSLoGin 
401f412fd2aSLoGin static noinline_for_stack char *
special_hex_number(char * buf,char * end,unsigned long long num,int size)402f412fd2aSLoGin special_hex_number(char *buf, char *end, unsigned long long num, int size)
403f412fd2aSLoGin {
404f412fd2aSLoGin 	struct printf_spec spec;
405f412fd2aSLoGin 
406f412fd2aSLoGin 	spec.type = FORMAT_TYPE_PTR;
407f412fd2aSLoGin 	spec.field_width = 2 + 2 * size; /* 0x + hex */
408f412fd2aSLoGin 	spec.flags = SPECIAL | SMALL | ZEROPAD;
409f412fd2aSLoGin 	spec.base = 16;
410f412fd2aSLoGin 	spec.precision = -1;
411f412fd2aSLoGin 
412f412fd2aSLoGin 	return number(buf, end, num, spec);
413f412fd2aSLoGin }
414f412fd2aSLoGin 
move_right(char * buf,char * end,unsigned len,unsigned spaces)415f412fd2aSLoGin static void move_right(char *buf, char *end, unsigned len, unsigned spaces)
416f412fd2aSLoGin {
417f412fd2aSLoGin 	size_t size;
418f412fd2aSLoGin 	if (buf >= end) /* nowhere to put anything */
419f412fd2aSLoGin 		return;
420f412fd2aSLoGin 	size = end - buf;
421f412fd2aSLoGin 	if (size <= spaces) {
422f412fd2aSLoGin 		memset(buf, ' ', size);
423f412fd2aSLoGin 		return;
424f412fd2aSLoGin 	}
425f412fd2aSLoGin 	if (len) {
426f412fd2aSLoGin 		if (len > size - spaces)
427f412fd2aSLoGin 			len = size - spaces;
428f412fd2aSLoGin 		memmove(buf + spaces, buf, len);
429f412fd2aSLoGin 	}
430f412fd2aSLoGin 	memset(buf, ' ', spaces);
431f412fd2aSLoGin }
432f412fd2aSLoGin 
433f412fd2aSLoGin /*
434f412fd2aSLoGin  * Handle field width padding for a string.
435f412fd2aSLoGin  * @buf: current buffer position
436f412fd2aSLoGin  * @n: length of string
437f412fd2aSLoGin  * @end: end of output buffer
438f412fd2aSLoGin  * @spec: for field width and flags
439f412fd2aSLoGin  * Returns: new buffer position after padding.
440f412fd2aSLoGin  */
widen_string(char * buf,int n,char * end,struct printf_spec spec)441f412fd2aSLoGin static noinline_for_stack char *widen_string(char *buf, int n, char *end,
442f412fd2aSLoGin 					     struct printf_spec spec)
443f412fd2aSLoGin {
444f412fd2aSLoGin 	unsigned spaces;
445f412fd2aSLoGin 
446f412fd2aSLoGin 	if (likely(n >= spec.field_width))
447f412fd2aSLoGin 		return buf;
448f412fd2aSLoGin 	/* we want to pad the sucker */
449f412fd2aSLoGin 	spaces = spec.field_width - n;
450f412fd2aSLoGin 	if (!(spec.flags & LEFT)) {
451f412fd2aSLoGin 		move_right(buf - n, end, n, spaces);
452f412fd2aSLoGin 		return buf + spaces;
453f412fd2aSLoGin 	}
454f412fd2aSLoGin 	while (spaces--) {
455f412fd2aSLoGin 		if (buf < end)
456f412fd2aSLoGin 			*buf = ' ';
457f412fd2aSLoGin 		++buf;
458f412fd2aSLoGin 	}
459f412fd2aSLoGin 	return buf;
460f412fd2aSLoGin }
461f412fd2aSLoGin 
462f412fd2aSLoGin /* Handle string from a well known address. */
string_nocheck(char * buf,char * end,const char * s,struct printf_spec spec)463f412fd2aSLoGin static char *string_nocheck(char *buf, char *end, const char *s,
464f412fd2aSLoGin 			    struct printf_spec spec)
465f412fd2aSLoGin {
466f412fd2aSLoGin 	int len = 0;
467f412fd2aSLoGin 	int lim = spec.precision;
468f412fd2aSLoGin 
469f412fd2aSLoGin 	while (lim--) {
470f412fd2aSLoGin 		char c = *s++;
471f412fd2aSLoGin 		if (!c)
472f412fd2aSLoGin 			break;
473f412fd2aSLoGin 		if (buf < end)
474f412fd2aSLoGin 			*buf = c;
475f412fd2aSLoGin 		++buf;
476f412fd2aSLoGin 		++len;
477f412fd2aSLoGin 	}
478f412fd2aSLoGin 	return widen_string(buf, len, end, spec);
479f412fd2aSLoGin }
480f412fd2aSLoGin 
481f412fd2aSLoGin /* Be careful: error messages must fit into the given buffer. */
error_string(char * buf,char * end,const char * s,struct printf_spec spec)482f412fd2aSLoGin static char *error_string(char *buf, char *end, const char *s,
483f412fd2aSLoGin 			  struct printf_spec spec)
484f412fd2aSLoGin {
485f412fd2aSLoGin 	/*
486f412fd2aSLoGin 	 * Hard limit to avoid a completely insane messages. It actually
487f412fd2aSLoGin 	 * works pretty well because most error messages are in
488f412fd2aSLoGin 	 * the many pointer format modifiers.
489f412fd2aSLoGin 	 */
490f412fd2aSLoGin 	if (spec.precision == -1)
491f412fd2aSLoGin 		spec.precision = 2 * sizeof(void *);
492f412fd2aSLoGin 
493f412fd2aSLoGin 	return string_nocheck(buf, end, s, spec);
494f412fd2aSLoGin }
495f412fd2aSLoGin 
496f412fd2aSLoGin /*
497f412fd2aSLoGin  * Do not call any complex external code here. Nested printk()/vsprintf()
498f412fd2aSLoGin  * might cause infinite loops. Failures might break printk() and would
499f412fd2aSLoGin  * be hard to debug.
500f412fd2aSLoGin  */
check_pointer_msg(const void * ptr)501f412fd2aSLoGin static const char *check_pointer_msg(const void *ptr)
502f412fd2aSLoGin {
503f412fd2aSLoGin 	if (!ptr)
504f412fd2aSLoGin 		return "(null)";
505f412fd2aSLoGin 
506f412fd2aSLoGin 	if ((unsigned long)ptr < PAGE_SIZE || IS_ERR_VALUE(ptr))
507f412fd2aSLoGin 		return "(efault)";
508f412fd2aSLoGin 
509f412fd2aSLoGin 	return NULL;
510f412fd2aSLoGin }
511f412fd2aSLoGin 
check_pointer(char ** buf,char * end,const void * ptr,struct printf_spec spec)512f412fd2aSLoGin static int check_pointer(char **buf, char *end, const void *ptr,
513f412fd2aSLoGin 			 struct printf_spec spec)
514f412fd2aSLoGin {
515f412fd2aSLoGin 	const char *err_msg;
516f412fd2aSLoGin 
517f412fd2aSLoGin 	err_msg = check_pointer_msg(ptr);
518f412fd2aSLoGin 	if (err_msg) {
519f412fd2aSLoGin 		*buf = error_string(*buf, end, err_msg, spec);
520f412fd2aSLoGin 		return -EFAULT;
521f412fd2aSLoGin 	}
522f412fd2aSLoGin 
523f412fd2aSLoGin 	return 0;
524f412fd2aSLoGin }
525f412fd2aSLoGin 
string(char * buf,char * end,const char * s,struct printf_spec spec)526f412fd2aSLoGin static noinline_for_stack char *string(char *buf, char *end, const char *s,
527f412fd2aSLoGin 				       struct printf_spec spec)
528f412fd2aSLoGin {
529f412fd2aSLoGin 	if (check_pointer(&buf, end, s, spec))
530f412fd2aSLoGin 		return buf;
531f412fd2aSLoGin 
532f412fd2aSLoGin 	return string_nocheck(buf, end, s, spec);
533f412fd2aSLoGin }
534f412fd2aSLoGin 
pointer_string(char * buf,char * end,const void * ptr,struct printf_spec spec)535f412fd2aSLoGin static char *pointer_string(char *buf, char *end, const void *ptr,
536f412fd2aSLoGin 			    struct printf_spec spec)
537f412fd2aSLoGin {
538f412fd2aSLoGin 	spec.base = 16;
539f412fd2aSLoGin 	spec.flags |= SMALL;
540f412fd2aSLoGin 	if (spec.field_width == -1) {
541f412fd2aSLoGin 		spec.field_width = 2 * sizeof(ptr);
542f412fd2aSLoGin 		spec.flags |= ZEROPAD;
543f412fd2aSLoGin 	}
544f412fd2aSLoGin 
545f412fd2aSLoGin 	return number(buf, end, (unsigned long int)ptr, spec);
546f412fd2aSLoGin }
547f412fd2aSLoGin 
hex_string(char * buf,char * end,u8 * addr,struct printf_spec spec,const char * fmt)548*78b790faSLoGin static noinline_for_stack char *hex_string(char *buf, char *end, u8 *addr,
549*78b790faSLoGin 					   struct printf_spec spec,
550f412fd2aSLoGin 					   const char *fmt)
551f412fd2aSLoGin {
552f412fd2aSLoGin 	int i, len = 1; /* if we pass '%ph[CDN]', field width remains
553f412fd2aSLoGin 				   negative value, fallback to the default */
554f412fd2aSLoGin 	char separator;
555f412fd2aSLoGin 
556f412fd2aSLoGin 	if (spec.field_width == 0)
557f412fd2aSLoGin 		/* nothing to print */
558f412fd2aSLoGin 		return buf;
559f412fd2aSLoGin 
560f412fd2aSLoGin 	if (check_pointer(&buf, end, addr, spec))
561f412fd2aSLoGin 		return buf;
562f412fd2aSLoGin 
563f412fd2aSLoGin 	switch (fmt[1]) {
564f412fd2aSLoGin 	case 'C':
565f412fd2aSLoGin 		separator = ':';
566f412fd2aSLoGin 		break;
567f412fd2aSLoGin 	case 'D':
568f412fd2aSLoGin 		separator = '-';
569f412fd2aSLoGin 		break;
570f412fd2aSLoGin 	case 'N':
571f412fd2aSLoGin 		separator = 0;
572f412fd2aSLoGin 		break;
573f412fd2aSLoGin 	default:
574f412fd2aSLoGin 		separator = ' ';
575f412fd2aSLoGin 		break;
576f412fd2aSLoGin 	}
577f412fd2aSLoGin 
578f412fd2aSLoGin 	if (spec.field_width > 0)
579f412fd2aSLoGin 		len = min_t(int, spec.field_width, 64);
580f412fd2aSLoGin 
581f412fd2aSLoGin 	for (i = 0; i < len; ++i) {
582f412fd2aSLoGin 		if (buf < end)
583f412fd2aSLoGin 			*buf = hex_asc_hi(addr[i]);
584f412fd2aSLoGin 		++buf;
585f412fd2aSLoGin 		if (buf < end)
586f412fd2aSLoGin 			*buf = hex_asc_lo(addr[i]);
587f412fd2aSLoGin 		++buf;
588f412fd2aSLoGin 
589f412fd2aSLoGin 		if (separator && i != len - 1) {
590f412fd2aSLoGin 			if (buf < end)
591f412fd2aSLoGin 				*buf = separator;
592f412fd2aSLoGin 			++buf;
593f412fd2aSLoGin 		}
594f412fd2aSLoGin 	}
595f412fd2aSLoGin 
596f412fd2aSLoGin 	return buf;
597f412fd2aSLoGin }
598f412fd2aSLoGin 
mac_address_string(char * buf,char * end,u8 * addr,struct printf_spec spec,const char * fmt)599*78b790faSLoGin static noinline_for_stack char *mac_address_string(char *buf, char *end,
600*78b790faSLoGin 						   u8 *addr,
601*78b790faSLoGin 						   struct printf_spec spec,
602*78b790faSLoGin 						   const char *fmt)
603f412fd2aSLoGin {
604f412fd2aSLoGin 	char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")];
605f412fd2aSLoGin 	char *p = mac_addr;
606f412fd2aSLoGin 	int i;
607f412fd2aSLoGin 	char separator;
608f412fd2aSLoGin 	bool reversed = false;
609f412fd2aSLoGin 
610f412fd2aSLoGin 	if (check_pointer(&buf, end, addr, spec))
611f412fd2aSLoGin 		return buf;
612f412fd2aSLoGin 
613f412fd2aSLoGin 	switch (fmt[1]) {
614f412fd2aSLoGin 	case 'F':
615f412fd2aSLoGin 		separator = '-';
616f412fd2aSLoGin 		break;
617f412fd2aSLoGin 
618f412fd2aSLoGin 	case 'R':
619f412fd2aSLoGin 		reversed = true;
620f412fd2aSLoGin 		fallthrough;
621f412fd2aSLoGin 
622f412fd2aSLoGin 	default:
623f412fd2aSLoGin 		separator = ':';
624f412fd2aSLoGin 		break;
625f412fd2aSLoGin 	}
626f412fd2aSLoGin 
627f412fd2aSLoGin 	for (i = 0; i < 6; i++) {
628f412fd2aSLoGin 		if (reversed)
629f412fd2aSLoGin 			p = hex_byte_pack(p, addr[5 - i]);
630f412fd2aSLoGin 		else
631f412fd2aSLoGin 			p = hex_byte_pack(p, addr[i]);
632f412fd2aSLoGin 
633f412fd2aSLoGin 		if (fmt[0] == 'M' && i != 5)
634f412fd2aSLoGin 			*p++ = separator;
635f412fd2aSLoGin 	}
636f412fd2aSLoGin 	*p = '\0';
637f412fd2aSLoGin 
638f412fd2aSLoGin 	return string_nocheck(buf, end, mac_addr, spec);
639f412fd2aSLoGin }
640f412fd2aSLoGin 
default_pointer(char * buf,char * end,const void * ptr,struct printf_spec spec)641f412fd2aSLoGin static char *default_pointer(char *buf, char *end, const void *ptr,
642f412fd2aSLoGin 			     struct printf_spec spec)
643f412fd2aSLoGin {
644f412fd2aSLoGin 	return pointer_string(buf, end, ptr, spec);
645f412fd2aSLoGin }
646f412fd2aSLoGin 
err_ptr(char * buf,char * end,void * ptr,struct printf_spec spec)647*78b790faSLoGin static char *err_ptr(char *buf, char *end, void *ptr, struct printf_spec spec)
648f412fd2aSLoGin {
649f412fd2aSLoGin 	int err = PTR_ERR(ptr);
650f412fd2aSLoGin 	// const char *sym = errname(err);
651f412fd2aSLoGin 
652f412fd2aSLoGin 	// if (sym)
653f412fd2aSLoGin 	// 	return string_nocheck(buf, end, sym, spec);
654f412fd2aSLoGin 
655f412fd2aSLoGin 	/*
656f412fd2aSLoGin 	 * Somebody passed ERR_PTR(-1234) or some other non-existing
657f412fd2aSLoGin 	 * Efoo - or perhaps CONFIG_SYMBOLIC_ERRNAME=n. Fall back to
658f412fd2aSLoGin 	 * printing it as its decimal representation.
659f412fd2aSLoGin 	 */
660f412fd2aSLoGin 	spec.flags |= SIGN;
661f412fd2aSLoGin 	spec.base = 10;
662f412fd2aSLoGin 	return number(buf, end, err, spec);
663f412fd2aSLoGin }
664f412fd2aSLoGin 
665f412fd2aSLoGin /*
666f412fd2aSLoGin  * Show a '%p' thing.  A kernel extension is that the '%p' is followed
667f412fd2aSLoGin  * by an extra set of alphanumeric characters that are extended format
668f412fd2aSLoGin  * specifiers.
669f412fd2aSLoGin  *
670f412fd2aSLoGin  * Please update scripts/checkpatch.pl when adding/removing conversion
671f412fd2aSLoGin  * characters.  (Search for "check for vsprintf extension").
672f412fd2aSLoGin  *
673f412fd2aSLoGin  * Right now we handle:
674f412fd2aSLoGin  *
675f412fd2aSLoGin  * - 'S' For symbolic direct pointers (or function descriptors) with offset
676f412fd2aSLoGin  * - 's' For symbolic direct pointers (or function descriptors) without offset
677f412fd2aSLoGin  * - '[Ss]R' as above with __builtin_extract_return_addr() translation
678f412fd2aSLoGin  * - 'S[R]b' as above with module build ID (for use in backtraces)
679f412fd2aSLoGin  * - '[Ff]' %pf and %pF were obsoleted and later removed in favor of
680f412fd2aSLoGin  *	    %ps and %pS. Be careful when re-using these specifiers.
681f412fd2aSLoGin  * - 'B' For backtraced symbolic direct pointers with offset
682f412fd2aSLoGin  * - 'Bb' as above with module build ID (for use in backtraces)
683f412fd2aSLoGin  * - 'R' For decoded struct resource, e.g., [mem 0x0-0x1f 64bit pref]
684f412fd2aSLoGin  * - 'r' For raw struct resource, e.g., [mem 0x0-0x1f flags 0x201]
685f412fd2aSLoGin  * - 'b[l]' For a bitmap, the number of bits is determined by the field
686f412fd2aSLoGin  *       width which must be explicitly specified either as part of the
687f412fd2aSLoGin  *       format string '%32b[l]' or through '%*b[l]', [l] selects
688f412fd2aSLoGin  *       range-list format instead of hex format
689f412fd2aSLoGin  * - 'M' For a 6-byte MAC address, it prints the address in the
690f412fd2aSLoGin  *       usual colon-separated hex notation
691f412fd2aSLoGin  * - 'm' For a 6-byte MAC address, it prints the hex address without colons
692f412fd2aSLoGin  * - 'MF' For a 6-byte MAC FDDI address, it prints the address
693f412fd2aSLoGin  *       with a dash-separated hex notation
694f412fd2aSLoGin  * - '[mM]R' For a 6-byte MAC address, Reverse order (Bluetooth)
695f412fd2aSLoGin  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way
696f412fd2aSLoGin  *       IPv4 uses dot-separated decimal without leading 0's (1.2.3.4)
697f412fd2aSLoGin  *       IPv6 uses colon separated network-order 16 bit hex with leading 0's
698f412fd2aSLoGin  *       [S][pfs]
699f412fd2aSLoGin  *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
700f412fd2aSLoGin  *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
701f412fd2aSLoGin  * - 'i' [46] for 'raw' IPv4/IPv6 addresses
702f412fd2aSLoGin  *       IPv6 omits the colons (01020304...0f)
703f412fd2aSLoGin  *       IPv4 uses dot-separated decimal with leading 0's (010.123.045.006)
704f412fd2aSLoGin  *       [S][pfs]
705f412fd2aSLoGin  *       Generic IPv4/IPv6 address (struct sockaddr *) that falls back to
706f412fd2aSLoGin  *       [4] or [6] and is able to print port [p], flowinfo [f], scope [s]
707f412fd2aSLoGin  * - '[Ii][4S][hnbl]' IPv4 addresses in host, network, big or little endian order
708f412fd2aSLoGin  * - 'I[6S]c' for IPv6 addresses printed as specified by
709f412fd2aSLoGin  *       https://tools.ietf.org/html/rfc5952
710f412fd2aSLoGin  * - 'E[achnops]' For an escaped buffer, where rules are defined by combination
711f412fd2aSLoGin  *                of the following flags (see string_escape_mem() for the
712f412fd2aSLoGin  *                details):
713f412fd2aSLoGin  *                  a - ESCAPE_ANY
714f412fd2aSLoGin  *                  c - ESCAPE_SPECIAL
715f412fd2aSLoGin  *                  h - ESCAPE_HEX
716f412fd2aSLoGin  *                  n - ESCAPE_NULL
717f412fd2aSLoGin  *                  o - ESCAPE_OCTAL
718f412fd2aSLoGin  *                  p - ESCAPE_NP
719f412fd2aSLoGin  *                  s - ESCAPE_SPACE
720f412fd2aSLoGin  *                By default ESCAPE_ANY_NP is used.
721f412fd2aSLoGin  * - 'U' For a 16 byte UUID/GUID, it prints the UUID/GUID in the form
722f412fd2aSLoGin  *       "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
723f412fd2aSLoGin  *       Options for %pU are:
724f412fd2aSLoGin  *         b big endian lower case hex (default)
725f412fd2aSLoGin  *         B big endian UPPER case hex
726f412fd2aSLoGin  *         l little endian lower case hex
727f412fd2aSLoGin  *         L little endian UPPER case hex
728f412fd2aSLoGin  *           big endian output byte order is:
729f412fd2aSLoGin  *             [0][1][2][3]-[4][5]-[6][7]-[8][9]-[10][11][12][13][14][15]
730f412fd2aSLoGin  *           little endian output byte order is:
731f412fd2aSLoGin  *             [3][2][1][0]-[5][4]-[7][6]-[8][9]-[10][11][12][13][14][15]
732f412fd2aSLoGin  * - 'V' For a struct va_format which contains a format string * and va_list *,
733f412fd2aSLoGin  *       call vsnprintf(->format, *->va_list).
734f412fd2aSLoGin  *       Implements a "recursive vsnprintf".
735f412fd2aSLoGin  *       Do not use this feature without some mechanism to verify the
736f412fd2aSLoGin  *       correctness of the format string and va_list arguments.
737f412fd2aSLoGin  * - 'K' For a kernel pointer that should be hidden from unprivileged users.
738f412fd2aSLoGin  *       Use only for procfs, sysfs and similar files, not printk(); please
739f412fd2aSLoGin  *       read the documentation (path below) first.
740f412fd2aSLoGin  * - 'NF' For a netdev_features_t
741f412fd2aSLoGin  * - '4cc' V4L2 or DRM FourCC code, with endianness and raw numerical value.
742f412fd2aSLoGin  * - 'h[CDN]' For a variable-length buffer, it prints it as a hex string with
743f412fd2aSLoGin  *            a certain separator (' ' by default):
744f412fd2aSLoGin  *              C colon
745f412fd2aSLoGin  *              D dash
746f412fd2aSLoGin  *              N no separator
747f412fd2aSLoGin  *            The maximum supported length is 64 bytes of the input. Consider
748f412fd2aSLoGin  *            to use print_hex_dump() for the larger input.
749f412fd2aSLoGin  * - 'a[pd]' For address types [p] phys_addr_t, [d] dma_addr_t and derivatives
750f412fd2aSLoGin  *           (default assumed to be phys_addr_t, passed by reference)
751f412fd2aSLoGin  * - 'd[234]' For a dentry name (optionally 2-4 last components)
752f412fd2aSLoGin  * - 'D[234]' Same as 'd' but for a struct file
753f412fd2aSLoGin  * - 'g' For block_device name (gendisk + partition number)
754f412fd2aSLoGin  * - 't[RT][dt][r][s]' For time and date as represented by:
755f412fd2aSLoGin  *      R    struct rtc_time
756f412fd2aSLoGin  *      T    time64_t
757f412fd2aSLoGin  * - 'C' For a clock, it prints the name (Common Clock Framework) or address
758f412fd2aSLoGin  *       (legacy clock framework) of the clock
759f412fd2aSLoGin  * - 'Cn' For a clock, it prints the name (Common Clock Framework) or address
760f412fd2aSLoGin  *        (legacy clock framework) of the clock
761f412fd2aSLoGin  * - 'G' For flags to be printed as a collection of symbolic strings that would
762f412fd2aSLoGin  *       construct the specific value. Supported flags given by option:
763f412fd2aSLoGin  *       p page flags (see struct page) given as pointer to unsigned long
764f412fd2aSLoGin  *       g gfp flags (GFP_* and __GFP_*) given as pointer to gfp_t
765f412fd2aSLoGin  *       v vma flags (VM_*) given as pointer to unsigned long
766f412fd2aSLoGin  * - 'OF[fnpPcCF]'  For a device tree object
767f412fd2aSLoGin  *                  Without any optional arguments prints the full_name
768f412fd2aSLoGin  *                  f device node full_name
769f412fd2aSLoGin  *                  n device node name
770f412fd2aSLoGin  *                  p device node phandle
771f412fd2aSLoGin  *                  P device node path spec (name + @unit)
772f412fd2aSLoGin  *                  F device node flags
773f412fd2aSLoGin  *                  c major compatible string
774f412fd2aSLoGin  *                  C full compatible string
775f412fd2aSLoGin  * - 'fw[fP]'	For a firmware node (struct fwnode_handle) pointer
776f412fd2aSLoGin  *		Without an option prints the full name of the node
777f412fd2aSLoGin  *		f full name
778f412fd2aSLoGin  *		P node name, including a possible unit address
779f412fd2aSLoGin  * - 'x' For printing the address unmodified. Equivalent to "%lx".
780f412fd2aSLoGin  *       Please read the documentation (path below) before using!
781f412fd2aSLoGin  * - '[ku]s' For a BPF/tracing related format specifier, e.g. used out of
782f412fd2aSLoGin  *           bpf_trace_printk() where [ku] prefix specifies either kernel (k)
783f412fd2aSLoGin  *           or user (u) memory to probe, and:
784f412fd2aSLoGin  *              s a string, equivalent to "%s" on direct vsnprintf() use
785f412fd2aSLoGin  *
786f412fd2aSLoGin  * ** When making changes please also update:
787f412fd2aSLoGin  *	Documentation/core-api/printk-formats.rst
788f412fd2aSLoGin  *
789f412fd2aSLoGin  * Note: The default behaviour (unadorned %p) is to hash the address,
790f412fd2aSLoGin  * rendering it useful as a unique identifier.
791f412fd2aSLoGin  *
792f412fd2aSLoGin  * There is also a '%pA' format specifier, but it is only intended to be used
793f412fd2aSLoGin  * from Rust code to format core::fmt::Arguments. Do *not* use it from C.
794f412fd2aSLoGin  * See rust/kernel/print.rs for details.
795f412fd2aSLoGin  */
pointer(const char * fmt,char * buf,char * end,void * ptr,struct printf_spec spec)796f412fd2aSLoGin static noinline_for_stack char *pointer(const char *fmt, char *buf, char *end,
797f412fd2aSLoGin 					void *ptr, struct printf_spec spec)
798f412fd2aSLoGin {
799f412fd2aSLoGin 	switch (*fmt) {
800f412fd2aSLoGin 	// case 'S':
801f412fd2aSLoGin 	// case 's':
802f412fd2aSLoGin 	// 	ptr = dereference_symbol_descriptor(ptr);
803f412fd2aSLoGin 	// 	fallthrough;
804f412fd2aSLoGin 	// case 'B':
805f412fd2aSLoGin 	// 	return symbol_string(buf, end, ptr, spec, fmt);
806f412fd2aSLoGin 	// case 'R':
807f412fd2aSLoGin 	// case 'r':
808f412fd2aSLoGin 	// 	return resource_string(buf, end, ptr, spec, fmt);
809f412fd2aSLoGin 	case 'h':
810f412fd2aSLoGin 		return hex_string(buf, end, ptr, spec, fmt);
811f412fd2aSLoGin 	// case 'b':
812f412fd2aSLoGin 	// 	switch (fmt[1]) {
813f412fd2aSLoGin 	// 	case 'l':
814f412fd2aSLoGin 	// 		return bitmap_list_string(buf, end, ptr, spec, fmt);
815f412fd2aSLoGin 	// 	default:
816f412fd2aSLoGin 	// 		return bitmap_string(buf, end, ptr, spec, fmt);
817f412fd2aSLoGin 	// 	}
818f412fd2aSLoGin 	case 'M': /* Colon separated: 00:01:02:03:04:05 */
819f412fd2aSLoGin 	case 'm': /* Contiguous: 000102030405 */
820f412fd2aSLoGin 		/* [mM]F (FDDI) */
821f412fd2aSLoGin 		/* [mM]R (Reverse order; Bluetooth) */
822f412fd2aSLoGin 		return mac_address_string(buf, end, ptr, spec, fmt);
823f412fd2aSLoGin 		// case 'I': /* Formatted IP supported
824f412fd2aSLoGin 		// 				 * 4:	1.2.3.4
825f412fd2aSLoGin 		// 				 * 6:	0001:0203:...:0708
826f412fd2aSLoGin 		// 				 * 6c:	1::708 or 1::1.2.3.4
827f412fd2aSLoGin 		// 				 */
828f412fd2aSLoGin 		// case 'i': /* Contiguous:
829f412fd2aSLoGin 		// 				 * 4:	001.002.003.004
830f412fd2aSLoGin 		// 				 * 6:   000102...0f
831f412fd2aSLoGin 		// 				 */
832f412fd2aSLoGin 		// 	return ip_addr_string(buf, end, ptr, spec, fmt);
833f412fd2aSLoGin 		// case 'E':
834f412fd2aSLoGin 		// 	return escaped_string(buf, end, ptr, spec, fmt);
835f412fd2aSLoGin 		// case 'U':
836f412fd2aSLoGin 		// 	return uuid_string(buf, end, ptr, spec, fmt);
837f412fd2aSLoGin 		// case 'V':
838f412fd2aSLoGin 		// 	return va_format(buf, end, ptr, spec, fmt);
839f412fd2aSLoGin 		// case 'K':
840f412fd2aSLoGin 		// 	return restricted_pointer(buf, end, ptr, spec);
841f412fd2aSLoGin 		// case 'N':
842f412fd2aSLoGin 		// 	return netdev_bits(buf, end, ptr, spec, fmt);
843f412fd2aSLoGin 		// case '4':
844f412fd2aSLoGin 		// 	return fourcc_string(buf, end, ptr, spec, fmt);
845f412fd2aSLoGin 		// case 'a':
846f412fd2aSLoGin 		// 	return address_val(buf, end, ptr, spec, fmt);
847f412fd2aSLoGin 		// case 'd':
848f412fd2aSLoGin 		// 	return dentry_name(buf, end, ptr, spec, fmt);
849f412fd2aSLoGin 		// case 't':
850f412fd2aSLoGin 		// 	return time_and_date(buf, end, ptr, spec, fmt);
851f412fd2aSLoGin 		// case 'C':
852f412fd2aSLoGin 		// 	return clock(buf, end, ptr, spec, fmt);
853f412fd2aSLoGin 		// case 'D':
854f412fd2aSLoGin 		// 	return file_dentry_name(buf, end, ptr, spec, fmt);
855f412fd2aSLoGin #ifdef CONFIG_BLOCK
856f412fd2aSLoGin 	case 'g':
857f412fd2aSLoGin 		return bdev_name(buf, end, ptr, spec, fmt);
858f412fd2aSLoGin #endif
859f412fd2aSLoGin 
860f412fd2aSLoGin 	// case 'G':
861f412fd2aSLoGin 	// 	return flags_string(buf, end, ptr, spec, fmt);
862f412fd2aSLoGin 	// case 'O':
863f412fd2aSLoGin 	// 	return device_node_string(buf, end, ptr, spec, fmt + 1);
864f412fd2aSLoGin 	// case 'f':
865f412fd2aSLoGin 	// 	return fwnode_string(buf, end, ptr, spec, fmt + 1);
866f412fd2aSLoGin 	// case 'A':
867f412fd2aSLoGin 	// 	if (!IS_ENABLED(CONFIG_RUST)) {
868f412fd2aSLoGin 	// 		WARN_ONCE(1, "Please remove %%pA from non-Rust code\n");
869f412fd2aSLoGin 	// 		return error_string(buf, end, "(%pA?)", spec);
870f412fd2aSLoGin 	// 	}
871f412fd2aSLoGin 	// 	return rust_fmt_argument(buf, end, ptr);
872f412fd2aSLoGin 	case 'x':
873f412fd2aSLoGin 		return pointer_string(buf, end, ptr, spec);
874f412fd2aSLoGin 	case 'e':
875f412fd2aSLoGin 		/* %pe with a non-ERR_PTR gets treated as plain %p */
876f412fd2aSLoGin 		if (!IS_ERR(ptr))
877f412fd2aSLoGin 			return default_pointer(buf, end, ptr, spec);
878f412fd2aSLoGin 		return err_ptr(buf, end, ptr, spec);
879f412fd2aSLoGin 	case 'u':
880f412fd2aSLoGin 	case 'k':
881f412fd2aSLoGin 		switch (fmt[1]) {
882f412fd2aSLoGin 		case 's':
883f412fd2aSLoGin 			return string(buf, end, ptr, spec);
884f412fd2aSLoGin 		default:
885f412fd2aSLoGin 			return error_string(buf, end, "(einval)", spec);
886f412fd2aSLoGin 		}
887f412fd2aSLoGin 	default:
888f412fd2aSLoGin 		return default_pointer(buf, end, ptr, spec);
889f412fd2aSLoGin 	}
890f412fd2aSLoGin }
891f412fd2aSLoGin 
892f412fd2aSLoGin /*
893f412fd2aSLoGin  * Helper function to decode printf style format.
894f412fd2aSLoGin  * Each call decode a token from the format and return the
895f412fd2aSLoGin  * number of characters read (or likely the delta where it wants
896f412fd2aSLoGin  * to go on the next call).
897f412fd2aSLoGin  * The decoded token is returned through the parameters
898f412fd2aSLoGin  *
899f412fd2aSLoGin  * 'h', 'l', or 'L' for integer fields
900f412fd2aSLoGin  * 'z' support added 23/7/1999 S.H.
901f412fd2aSLoGin  * 'z' changed to 'Z' --davidm 1/25/99
902f412fd2aSLoGin  * 'Z' changed to 'z' --adobriyan 2017-01-25
903f412fd2aSLoGin  * 't' added for ptrdiff_t
904f412fd2aSLoGin  *
905f412fd2aSLoGin  * @fmt: the format string
906f412fd2aSLoGin  * @type of the token returned
907f412fd2aSLoGin  * @flags: various flags such as +, -, # tokens..
908f412fd2aSLoGin  * @field_width: overwritten width
909f412fd2aSLoGin  * @base: base of the number (octal, hex, ...)
910f412fd2aSLoGin  * @precision: precision of a number
911f412fd2aSLoGin  * @qualifier: qualifier of a number (long, size_t, ...)
912f412fd2aSLoGin  */
format_decode(const char * fmt,struct printf_spec * spec)913f412fd2aSLoGin static noinline_for_stack int format_decode(const char *fmt,
914f412fd2aSLoGin 					    struct printf_spec *spec)
915f412fd2aSLoGin {
916f412fd2aSLoGin 	const char *start = fmt;
917f412fd2aSLoGin 	char qualifier;
918f412fd2aSLoGin 
919f412fd2aSLoGin 	/* we finished early by reading the field width */
920f412fd2aSLoGin 	if (spec->type == FORMAT_TYPE_WIDTH) {
921f412fd2aSLoGin 		if (spec->field_width < 0) {
922f412fd2aSLoGin 			spec->field_width = -spec->field_width;
923f412fd2aSLoGin 			spec->flags |= LEFT;
924f412fd2aSLoGin 		}
925f412fd2aSLoGin 		spec->type = FORMAT_TYPE_NONE;
926f412fd2aSLoGin 		goto precision;
927f412fd2aSLoGin 	}
928f412fd2aSLoGin 
929f412fd2aSLoGin 	/* we finished early by reading the precision */
930f412fd2aSLoGin 	if (spec->type == FORMAT_TYPE_PRECISION) {
931f412fd2aSLoGin 		if (spec->precision < 0)
932f412fd2aSLoGin 			spec->precision = 0;
933f412fd2aSLoGin 
934f412fd2aSLoGin 		spec->type = FORMAT_TYPE_NONE;
935f412fd2aSLoGin 		goto qualifier;
936f412fd2aSLoGin 	}
937f412fd2aSLoGin 
938f412fd2aSLoGin 	/* By default */
939f412fd2aSLoGin 	spec->type = FORMAT_TYPE_NONE;
940f412fd2aSLoGin 
941f412fd2aSLoGin 	for (; *fmt; ++fmt) {
942f412fd2aSLoGin 		if (*fmt == '%')
943f412fd2aSLoGin 			break;
944f412fd2aSLoGin 	}
945f412fd2aSLoGin 
946f412fd2aSLoGin 	/* Return the current non-format string */
947f412fd2aSLoGin 	if (fmt != start || !*fmt)
948f412fd2aSLoGin 		return fmt - start;
949f412fd2aSLoGin 
950f412fd2aSLoGin 	/* Process flags */
951f412fd2aSLoGin 	spec->flags = 0;
952f412fd2aSLoGin 
953f412fd2aSLoGin 	while (1) { /* this also skips first '%' */
954f412fd2aSLoGin 		bool found = true;
955f412fd2aSLoGin 
956f412fd2aSLoGin 		++fmt;
957f412fd2aSLoGin 
958f412fd2aSLoGin 		switch (*fmt) {
959f412fd2aSLoGin 		case '-':
960f412fd2aSLoGin 			spec->flags |= LEFT;
961f412fd2aSLoGin 			break;
962f412fd2aSLoGin 		case '+':
963f412fd2aSLoGin 			spec->flags |= PLUS;
964f412fd2aSLoGin 			break;
965f412fd2aSLoGin 		case ' ':
966f412fd2aSLoGin 			spec->flags |= SPACE;
967f412fd2aSLoGin 			break;
968f412fd2aSLoGin 		case '#':
969f412fd2aSLoGin 			spec->flags |= SPECIAL;
970f412fd2aSLoGin 			break;
971f412fd2aSLoGin 		case '0':
972f412fd2aSLoGin 			spec->flags |= ZEROPAD;
973f412fd2aSLoGin 			break;
974f412fd2aSLoGin 		default:
975f412fd2aSLoGin 			found = false;
976f412fd2aSLoGin 		}
977f412fd2aSLoGin 
978f412fd2aSLoGin 		if (!found)
979f412fd2aSLoGin 			break;
980f412fd2aSLoGin 	}
981f412fd2aSLoGin 
982f412fd2aSLoGin 	/* get field width */
983f412fd2aSLoGin 	spec->field_width = -1;
984f412fd2aSLoGin 
985f412fd2aSLoGin 	if (isdigit(*fmt))
986f412fd2aSLoGin 		spec->field_width = skip_atoi(&fmt);
987f412fd2aSLoGin 	else if (*fmt == '*') {
988f412fd2aSLoGin 		/* it's the next argument */
989f412fd2aSLoGin 		spec->type = FORMAT_TYPE_WIDTH;
990f412fd2aSLoGin 		return ++fmt - start;
991f412fd2aSLoGin 	}
992f412fd2aSLoGin 
993f412fd2aSLoGin precision:
994f412fd2aSLoGin 	/* get the precision */
995f412fd2aSLoGin 	spec->precision = -1;
996f412fd2aSLoGin 	if (*fmt == '.') {
997f412fd2aSLoGin 		++fmt;
998f412fd2aSLoGin 		if (isdigit(*fmt)) {
999f412fd2aSLoGin 			spec->precision = skip_atoi(&fmt);
1000f412fd2aSLoGin 			if (spec->precision < 0)
1001f412fd2aSLoGin 				spec->precision = 0;
1002f412fd2aSLoGin 		} else if (*fmt == '*') {
1003f412fd2aSLoGin 			/* it's the next argument */
1004f412fd2aSLoGin 			spec->type = FORMAT_TYPE_PRECISION;
1005f412fd2aSLoGin 			return ++fmt - start;
1006f412fd2aSLoGin 		}
1007f412fd2aSLoGin 	}
1008f412fd2aSLoGin 
1009f412fd2aSLoGin qualifier:
1010f412fd2aSLoGin 	/* get the conversion qualifier */
1011f412fd2aSLoGin 	qualifier = 0;
1012f412fd2aSLoGin 	if (*fmt == 'h' || _tolower(*fmt) == 'l' || *fmt == 'z' ||
1013f412fd2aSLoGin 	    *fmt == 't') {
1014f412fd2aSLoGin 		qualifier = *fmt++;
1015f412fd2aSLoGin 		if (unlikely(qualifier == *fmt)) {
1016f412fd2aSLoGin 			if (qualifier == 'l') {
1017f412fd2aSLoGin 				qualifier = 'L';
1018f412fd2aSLoGin 				++fmt;
1019f412fd2aSLoGin 			} else if (qualifier == 'h') {
1020f412fd2aSLoGin 				qualifier = 'H';
1021f412fd2aSLoGin 				++fmt;
1022f412fd2aSLoGin 			}
1023f412fd2aSLoGin 		}
1024f412fd2aSLoGin 	}
1025f412fd2aSLoGin 
1026f412fd2aSLoGin 	/* default base */
1027f412fd2aSLoGin 	spec->base = 10;
1028f412fd2aSLoGin 	switch (*fmt) {
1029f412fd2aSLoGin 	case 'c':
1030f412fd2aSLoGin 		spec->type = FORMAT_TYPE_CHAR;
1031f412fd2aSLoGin 		return ++fmt - start;
1032f412fd2aSLoGin 
1033f412fd2aSLoGin 	case 's':
1034f412fd2aSLoGin 		spec->type = FORMAT_TYPE_STR;
1035f412fd2aSLoGin 		return ++fmt - start;
1036f412fd2aSLoGin 
1037f412fd2aSLoGin 	case 'p':
1038f412fd2aSLoGin 		spec->type = FORMAT_TYPE_PTR;
1039f412fd2aSLoGin 		return ++fmt - start;
1040f412fd2aSLoGin 
1041f412fd2aSLoGin 	case '%':
1042f412fd2aSLoGin 		spec->type = FORMAT_TYPE_PERCENT_CHAR;
1043f412fd2aSLoGin 		return ++fmt - start;
1044f412fd2aSLoGin 
1045f412fd2aSLoGin 	/* integer number formats - set up the flags and "break" */
1046f412fd2aSLoGin 	case 'o':
1047f412fd2aSLoGin 		spec->base = 8;
1048f412fd2aSLoGin 		break;
1049f412fd2aSLoGin 
1050f412fd2aSLoGin 	case 'x':
1051f412fd2aSLoGin 		spec->flags |= SMALL;
1052f412fd2aSLoGin 		fallthrough;
1053f412fd2aSLoGin 
1054f412fd2aSLoGin 	case 'X':
1055f412fd2aSLoGin 		spec->base = 16;
1056f412fd2aSLoGin 		break;
1057f412fd2aSLoGin 
1058f412fd2aSLoGin 	case 'd':
1059f412fd2aSLoGin 	case 'i':
1060f412fd2aSLoGin 		spec->flags |= SIGN;
1061f412fd2aSLoGin 		break;
1062f412fd2aSLoGin 	case 'u':
1063f412fd2aSLoGin 		break;
1064f412fd2aSLoGin 
1065f412fd2aSLoGin 	case 'n':
1066f412fd2aSLoGin 		/*
1067f412fd2aSLoGin 		 * Since %n poses a greater security risk than
1068f412fd2aSLoGin 		 * utility, treat it as any other invalid or
1069f412fd2aSLoGin 		 * unsupported format specifier.
1070f412fd2aSLoGin 		 */
1071f412fd2aSLoGin 		fallthrough;
1072f412fd2aSLoGin 
1073f412fd2aSLoGin 	default:
1074f412fd2aSLoGin 		WARN_ONCE(1,
1075f412fd2aSLoGin 			  "Please remove unsupported %%%c in format string\n",
1076f412fd2aSLoGin 			  *fmt);
1077f412fd2aSLoGin 		spec->type = FORMAT_TYPE_INVALID;
1078f412fd2aSLoGin 		return fmt - start;
1079f412fd2aSLoGin 	}
1080f412fd2aSLoGin 
1081f412fd2aSLoGin 	if (qualifier == 'L')
1082f412fd2aSLoGin 		spec->type = FORMAT_TYPE_LONG_LONG;
1083f412fd2aSLoGin 	else if (qualifier == 'l') {
1084f412fd2aSLoGin 		BUILD_BUG_ON(FORMAT_TYPE_ULONG + SIGN != FORMAT_TYPE_LONG);
1085f412fd2aSLoGin 		spec->type = FORMAT_TYPE_ULONG + (spec->flags & SIGN);
1086f412fd2aSLoGin 	} else if (qualifier == 'z') {
1087f412fd2aSLoGin 		spec->type = FORMAT_TYPE_SIZE_T;
1088f412fd2aSLoGin 	} else if (qualifier == 't') {
1089f412fd2aSLoGin 		spec->type = FORMAT_TYPE_PTRDIFF;
1090f412fd2aSLoGin 	} else if (qualifier == 'H') {
1091f412fd2aSLoGin 		BUILD_BUG_ON(FORMAT_TYPE_UBYTE + SIGN != FORMAT_TYPE_BYTE);
1092f412fd2aSLoGin 		spec->type = FORMAT_TYPE_UBYTE + (spec->flags & SIGN);
1093f412fd2aSLoGin 	} else if (qualifier == 'h') {
1094f412fd2aSLoGin 		BUILD_BUG_ON(FORMAT_TYPE_USHORT + SIGN != FORMAT_TYPE_SHORT);
1095f412fd2aSLoGin 		spec->type = FORMAT_TYPE_USHORT + (spec->flags & SIGN);
1096f412fd2aSLoGin 	} else {
1097f412fd2aSLoGin 		BUILD_BUG_ON(FORMAT_TYPE_UINT + SIGN != FORMAT_TYPE_INT);
1098f412fd2aSLoGin 		spec->type = FORMAT_TYPE_UINT + (spec->flags & SIGN);
1099f412fd2aSLoGin 	}
1100f412fd2aSLoGin 
1101f412fd2aSLoGin 	return ++fmt - start;
1102f412fd2aSLoGin }
1103f412fd2aSLoGin 
1104f412fd2aSLoGin /**
1105f412fd2aSLoGin  * vsnprintf - Format a string and place it in a buffer
1106f412fd2aSLoGin  * @buf: The buffer to place the result into
1107f412fd2aSLoGin  * @size: The size of the buffer, including the trailing null space
1108f412fd2aSLoGin  * @fmt: The format string to use
1109f412fd2aSLoGin  * @args: Arguments for the format string
1110f412fd2aSLoGin  *
1111f412fd2aSLoGin  * This function generally follows C99 vsnprintf, but has some
1112f412fd2aSLoGin  * extensions and a few limitations:
1113f412fd2aSLoGin  *
1114f412fd2aSLoGin  *  - ``%n`` is unsupported
1115f412fd2aSLoGin  *  - ``%p*`` is handled by pointer()
1116f412fd2aSLoGin  *
1117f412fd2aSLoGin  * See pointer() or Documentation/core-api/printk-formats.rst for more
1118f412fd2aSLoGin  * extensive description.
1119f412fd2aSLoGin  *
1120f412fd2aSLoGin  * **Please update the documentation in both places when making changes**
1121f412fd2aSLoGin  *
1122f412fd2aSLoGin  * The return value is the number of characters which would
1123f412fd2aSLoGin  * be generated for the given input, excluding the trailing
1124f412fd2aSLoGin  * '\0', as per ISO C99. If you want to have the exact
1125f412fd2aSLoGin  * number of characters written into @buf as return value
1126f412fd2aSLoGin  * (not including the trailing '\0'), use vscnprintf(). If the
1127f412fd2aSLoGin  * return is greater than or equal to @size, the resulting
1128f412fd2aSLoGin  * string is truncated.
1129f412fd2aSLoGin  *
1130f412fd2aSLoGin  * If you're not already dealing with a va_list consider using snprintf().
1131f412fd2aSLoGin  */
vsnprintf(char * buf,size_t size,const char * fmt,va_list args)1132f412fd2aSLoGin int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
1133f412fd2aSLoGin {
1134f412fd2aSLoGin 	unsigned long long num;
1135f412fd2aSLoGin 	char *str, *end;
1136f412fd2aSLoGin 	struct printf_spec spec = { 0 };
1137f412fd2aSLoGin 
1138f412fd2aSLoGin 	/* Reject out-of-range values early.  Large positive sizes are
1139f412fd2aSLoGin 	   used for unknown buffer sizes. */
1140f412fd2aSLoGin 	if (WARN_ON_ONCE(size > INT_MAX))
1141f412fd2aSLoGin 		return 0;
1142f412fd2aSLoGin 
1143f412fd2aSLoGin 	str = buf;
1144f412fd2aSLoGin 	end = buf + size;
1145f412fd2aSLoGin 
1146f412fd2aSLoGin 	/* Make sure end is always >= buf */
1147f412fd2aSLoGin 	if (end < buf) {
1148f412fd2aSLoGin 		end = ((void *)-1);
1149f412fd2aSLoGin 		size = end - buf;
1150f412fd2aSLoGin 	}
1151f412fd2aSLoGin 
1152f412fd2aSLoGin 	while (*fmt) {
1153f412fd2aSLoGin 		const char *old_fmt = fmt;
1154f412fd2aSLoGin 		int read = format_decode(fmt, &spec);
1155f412fd2aSLoGin 
1156f412fd2aSLoGin 		fmt += read;
1157f412fd2aSLoGin 
1158f412fd2aSLoGin 		switch (spec.type) {
1159f412fd2aSLoGin 		case FORMAT_TYPE_NONE: {
1160f412fd2aSLoGin 			int copy = read;
1161f412fd2aSLoGin 			if (str < end) {
1162f412fd2aSLoGin 				if (copy > end - str)
1163f412fd2aSLoGin 					copy = end - str;
1164f412fd2aSLoGin 				memcpy(str, old_fmt, copy);
1165f412fd2aSLoGin 			}
1166f412fd2aSLoGin 			str += read;
1167f412fd2aSLoGin 			break;
1168f412fd2aSLoGin 		}
1169f412fd2aSLoGin 
1170f412fd2aSLoGin 		case FORMAT_TYPE_WIDTH:
1171f412fd2aSLoGin 			set_field_width(&spec, va_arg(args, int));
1172f412fd2aSLoGin 			break;
1173f412fd2aSLoGin 
1174f412fd2aSLoGin 		case FORMAT_TYPE_PRECISION:
1175f412fd2aSLoGin 			set_precision(&spec, va_arg(args, int));
1176f412fd2aSLoGin 			break;
1177f412fd2aSLoGin 
1178f412fd2aSLoGin 		case FORMAT_TYPE_CHAR: {
1179f412fd2aSLoGin 			char c;
1180f412fd2aSLoGin 
1181f412fd2aSLoGin 			if (!(spec.flags & LEFT)) {
1182f412fd2aSLoGin 				while (--spec.field_width > 0) {
1183f412fd2aSLoGin 					if (str < end)
1184f412fd2aSLoGin 						*str = ' ';
1185f412fd2aSLoGin 					++str;
1186f412fd2aSLoGin 				}
1187f412fd2aSLoGin 			}
1188f412fd2aSLoGin 			c = (unsigned char)va_arg(args, int);
1189f412fd2aSLoGin 			if (str < end)
1190f412fd2aSLoGin 				*str = c;
1191f412fd2aSLoGin 			++str;
1192f412fd2aSLoGin 			while (--spec.field_width > 0) {
1193f412fd2aSLoGin 				if (str < end)
1194f412fd2aSLoGin 					*str = ' ';
1195f412fd2aSLoGin 				++str;
1196f412fd2aSLoGin 			}
1197f412fd2aSLoGin 			break;
1198f412fd2aSLoGin 		}
1199f412fd2aSLoGin 
1200f412fd2aSLoGin 		case FORMAT_TYPE_STR:
1201f412fd2aSLoGin 			str = string(str, end, va_arg(args, char *), spec);
1202f412fd2aSLoGin 			break;
1203f412fd2aSLoGin 
1204f412fd2aSLoGin 		case FORMAT_TYPE_PTR:
1205f412fd2aSLoGin 			str = pointer(fmt, str, end, va_arg(args, void *),
1206f412fd2aSLoGin 				      spec);
1207f412fd2aSLoGin 			while (isalnum(*fmt))
1208f412fd2aSLoGin 				fmt++;
1209f412fd2aSLoGin 			break;
1210f412fd2aSLoGin 
1211f412fd2aSLoGin 		case FORMAT_TYPE_PERCENT_CHAR:
1212f412fd2aSLoGin 			if (str < end)
1213f412fd2aSLoGin 				*str = '%';
1214f412fd2aSLoGin 			++str;
1215f412fd2aSLoGin 			break;
1216f412fd2aSLoGin 
1217f412fd2aSLoGin 		case FORMAT_TYPE_INVALID:
1218f412fd2aSLoGin 			/*
1219f412fd2aSLoGin 			 * Presumably the arguments passed gcc's type
1220f412fd2aSLoGin 			 * checking, but there is no safe or sane way
1221f412fd2aSLoGin 			 * for us to continue parsing the format and
1222f412fd2aSLoGin 			 * fetching from the va_list; the remaining
1223f412fd2aSLoGin 			 * specifiers and arguments would be out of
1224f412fd2aSLoGin 			 * sync.
1225f412fd2aSLoGin 			 */
1226f412fd2aSLoGin 			goto out;
1227f412fd2aSLoGin 
1228f412fd2aSLoGin 		default:
1229f412fd2aSLoGin 			switch (spec.type) {
1230f412fd2aSLoGin 			case FORMAT_TYPE_LONG_LONG:
1231f412fd2aSLoGin 				num = va_arg(args, long long);
1232f412fd2aSLoGin 				break;
1233f412fd2aSLoGin 			case FORMAT_TYPE_ULONG:
1234f412fd2aSLoGin 				num = va_arg(args, unsigned long);
1235f412fd2aSLoGin 				break;
1236f412fd2aSLoGin 			case FORMAT_TYPE_LONG:
1237f412fd2aSLoGin 				num = va_arg(args, long);
1238f412fd2aSLoGin 				break;
1239f412fd2aSLoGin 			case FORMAT_TYPE_SIZE_T:
1240f412fd2aSLoGin 				if (spec.flags & SIGN)
1241f412fd2aSLoGin 					num = va_arg(args, ssize_t);
1242f412fd2aSLoGin 				else
1243f412fd2aSLoGin 					num = va_arg(args, size_t);
1244f412fd2aSLoGin 				break;
1245f412fd2aSLoGin 			case FORMAT_TYPE_PTRDIFF:
1246f412fd2aSLoGin 				num = va_arg(args, ptrdiff_t);
1247f412fd2aSLoGin 				break;
1248f412fd2aSLoGin 			case FORMAT_TYPE_UBYTE:
1249f412fd2aSLoGin 				num = (unsigned char)va_arg(args, int);
1250f412fd2aSLoGin 				break;
1251f412fd2aSLoGin 			case FORMAT_TYPE_BYTE:
1252f412fd2aSLoGin 				num = (signed char)va_arg(args, int);
1253f412fd2aSLoGin 				break;
1254f412fd2aSLoGin 			case FORMAT_TYPE_USHORT:
1255f412fd2aSLoGin 				num = (unsigned short)va_arg(args, int);
1256f412fd2aSLoGin 				break;
1257f412fd2aSLoGin 			case FORMAT_TYPE_SHORT:
1258f412fd2aSLoGin 				num = (short)va_arg(args, int);
1259f412fd2aSLoGin 				break;
1260f412fd2aSLoGin 			case FORMAT_TYPE_INT:
1261f412fd2aSLoGin 				num = (int)va_arg(args, int);
1262f412fd2aSLoGin 				break;
1263f412fd2aSLoGin 			default:
1264f412fd2aSLoGin 				num = va_arg(args, unsigned int);
1265f412fd2aSLoGin 			}
1266f412fd2aSLoGin 
1267f412fd2aSLoGin 			str = number(str, end, num, spec);
1268f412fd2aSLoGin 		}
1269f412fd2aSLoGin 	}
1270f412fd2aSLoGin 
1271f412fd2aSLoGin out:
1272f412fd2aSLoGin 	if (size > 0) {
1273f412fd2aSLoGin 		if (str < end)
1274f412fd2aSLoGin 			*str = '\0';
1275f412fd2aSLoGin 		else
1276f412fd2aSLoGin 			end[-1] = '\0';
1277f412fd2aSLoGin 	}
1278f412fd2aSLoGin 
1279f412fd2aSLoGin 	/* the trailing null byte doesn't count towards the total */
1280f412fd2aSLoGin 	return str - buf;
1281f412fd2aSLoGin }
1282f412fd2aSLoGin 
1283f412fd2aSLoGin /**
1284f412fd2aSLoGin  * snprintf - Format a string and place it in a buffer
1285f412fd2aSLoGin  * @buf: The buffer to place the result into
1286f412fd2aSLoGin  * @size: The size of the buffer, including the trailing null space
1287f412fd2aSLoGin  * @fmt: The format string to use
1288f412fd2aSLoGin  * @...: Arguments for the format string
1289f412fd2aSLoGin  *
1290f412fd2aSLoGin  * The return value is the number of characters which would be
1291f412fd2aSLoGin  * generated for the given input, excluding the trailing null,
1292f412fd2aSLoGin  * as per ISO C99.  If the return is greater than or equal to
1293f412fd2aSLoGin  * @size, the resulting string is truncated.
1294f412fd2aSLoGin  *
1295f412fd2aSLoGin  * See the vsnprintf() documentation for format string extensions over C99.
1296f412fd2aSLoGin  */
snprintf(char * buf,size_t size,const char * fmt,...)1297f412fd2aSLoGin int snprintf(char *buf, size_t size, const char *fmt, ...)
1298f412fd2aSLoGin {
1299f412fd2aSLoGin 	va_list args;
1300f412fd2aSLoGin 	int i;
1301f412fd2aSLoGin 
1302f412fd2aSLoGin 	va_start(args, fmt);
1303f412fd2aSLoGin 	i = vsnprintf(buf, size, fmt, args);
1304f412fd2aSLoGin 	va_end(args);
1305f412fd2aSLoGin 
1306f412fd2aSLoGin 	return i;
1307f412fd2aSLoGin }