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