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/string.h>
18 
19 static int skip_atoi(const char **s)
20 {
21 	int i = 0;
22 
23 	while (isdigit(**s))
24 		i = i * 10 + *((*s)++) - '0';
25 	return i;
26 }
27 
28 /*
29  * put_dec_full4 handles numbers in the range 0 <= r < 10000.
30  * The multiplier 0xccd is round(2^15/10), and the approximation
31  * r/10 == (r * 0xccd) >> 15 is exact for all r < 16389.
32  */
33 static
34 void put_dec_full4(char *buf, unsigned int r)
35 {
36 	int i;
37 
38 	for (i = 0; i < 3; i++) {
39 		unsigned int q = (r * 0xccd) >> 15;
40 		*buf++ = '0' + (r - q * 10);
41 		r = q;
42 	}
43 	*buf++ = '0' + r;
44 }
45 
46 /* put_dec is copied from lib/vsprintf.c with small modifications */
47 
48 /*
49  * Call put_dec_full4 on x % 10000, return x / 10000.
50  * The approximation x/10000 == (x * 0x346DC5D7) >> 43
51  * holds for all x < 1,128,869,999.  The largest value this
52  * helper will ever be asked to convert is 1,125,520,955.
53  * (second call in the put_dec code, assuming n is all-ones).
54  */
55 static
56 unsigned int put_dec_helper4(char *buf, unsigned int x)
57 {
58 	unsigned int q = (x * 0x346DC5D7ULL) >> 43;
59 
60 	put_dec_full4(buf, x - q * 10000);
61 	return q;
62 }
63 
64 /* Based on code by Douglas W. Jones found at
65  * <http://www.cs.uiowa.edu/~jones/bcd/decimal.html#sixtyfour>
66  * (with permission from the author).
67  * Performs no 64-bit division and hence should be fast on 32-bit machines.
68  */
69 static
70 int put_dec(char *buf, unsigned long long n)
71 {
72 	unsigned int d3, d2, d1, q, h;
73 	char *p = buf;
74 
75 	d1  = ((unsigned int)n >> 16); /* implicit "& 0xffff" */
76 	h   = (n >> 32);
77 	d2  = (h      ) & 0xffff;
78 	d3  = (h >> 16); /* implicit "& 0xffff" */
79 
80 	/* n = 2^48 d3 + 2^32 d2 + 2^16 d1 + d0
81 	     = 281_4749_7671_0656 d3 + 42_9496_7296 d2 + 6_5536 d1 + d0 */
82 	q = 656 * d3 + 7296 * d2 + 5536 * d1 + ((unsigned int)n & 0xffff);
83 	q = put_dec_helper4(p, q);
84 	p += 4;
85 
86 	q += 7671 * d3 + 9496 * d2 + 6 * d1;
87 	q = put_dec_helper4(p, q);
88 	p += 4;
89 
90 	q += 4749 * d3 + 42 * d2;
91 	q = put_dec_helper4(p, q);
92 	p += 4;
93 
94 	q += 281 * d3;
95 	q = put_dec_helper4(p, q);
96 	p += 4;
97 
98 	put_dec_full4(p, q);
99 	p += 4;
100 
101 	/* strip off the extra 0's we printed */
102 	while (p > buf && p[-1] == '0')
103 		--p;
104 
105 	return p - buf;
106 }
107 
108 #define ZEROPAD	1		/* pad with zero */
109 #define SIGN	2		/* unsigned/signed long */
110 #define PLUS	4		/* show plus */
111 #define SPACE	8		/* space if plus */
112 #define LEFT	16		/* left justified */
113 #define SMALL	32		/* Must be 32 == 0x20 */
114 #define SPECIAL	64		/* 0x */
115 
116 static char *number(char *str, long long num, int base, int size, int precision,
117 		    int type)
118 {
119 	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
120 	static const char digits[16] = "0123456789ABCDEF"; /* "GHIJKLMNOPQRSTUVWXYZ"; */
121 
122 	char tmp[66];
123 	char c, sign, locase;
124 	int i;
125 
126 	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
127 	 * produces same digits or (maybe lowercased) letters */
128 	locase = (type & SMALL);
129 	if (type & LEFT)
130 		type &= ~ZEROPAD;
131 	c = (type & ZEROPAD) ? '0' : ' ';
132 	sign = 0;
133 	if (type & SIGN) {
134 		if (num < 0) {
135 			sign = '-';
136 			num = -num;
137 			size--;
138 		} else if (type & PLUS) {
139 			sign = '+';
140 			size--;
141 		} else if (type & SPACE) {
142 			sign = ' ';
143 			size--;
144 		}
145 	}
146 	if (type & SPECIAL) {
147 		if (base == 16)
148 			size -= 2;
149 		else if (base == 8)
150 			size--;
151 	}
152 	i = 0;
153 	if (num == 0)
154 		tmp[i++] = '0';
155 	else {
156 		switch (base) {
157 		case 10:
158 			i += put_dec(&tmp[i], num);
159 			break;
160 		case 8:
161 			while (num != 0) {
162 				tmp[i++] = '0' + (num & 07);
163 				num = (unsigned long long)num >> 3;
164 			}
165 			break;
166 		case 16:
167 			while (num != 0) {
168 				tmp[i++] = digits[num & 0xf] | locase;
169 				num = (unsigned long long)num >> 4;
170 			}
171 			break;
172 		default:
173 			unreachable();
174 		}
175 	}
176 
177 	if (i > precision)
178 		precision = i;
179 	size -= precision;
180 	if (!(type & (ZEROPAD + LEFT)))
181 		while (size-- > 0)
182 			*str++ = ' ';
183 	if (sign)
184 		*str++ = sign;
185 	if (type & SPECIAL) {
186 		if (base == 8) {
187 			*str++ = '0';
188 		} else if (base == 16) {
189 			*str++ = '0';
190 			*str++ = ('X' | locase);
191 		}
192 	}
193 	if (!(type & LEFT))
194 		while (size-- > 0)
195 			*str++ = c;
196 	while (i < precision--)
197 		*str++ = '0';
198 	while (i-- > 0)
199 		*str++ = tmp[i];
200 	while (size-- > 0)
201 		*str++ = ' ';
202 	return str;
203 }
204 
205 int vsprintf(char *buf, const char *fmt, va_list args)
206 {
207 	int len;
208 	unsigned long long num;
209 	int i, base;
210 	char *str;
211 	const char *s;
212 
213 	int flags;		/* flags to number() */
214 
215 	int field_width;	/* width of output field */
216 	int precision;		/* min. # of digits for integers; max
217 				   number of chars for from string */
218 	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
219 
220 	for (str = buf; *fmt; ++fmt) {
221 		if (*fmt != '%') {
222 			*str++ = *fmt;
223 			continue;
224 		}
225 
226 		/* process flags */
227 		flags = 0;
228 	      repeat:
229 		++fmt;		/* this also skips first '%' */
230 		switch (*fmt) {
231 		case '-':
232 			flags |= LEFT;
233 			goto repeat;
234 		case '+':
235 			flags |= PLUS;
236 			goto repeat;
237 		case ' ':
238 			flags |= SPACE;
239 			goto repeat;
240 		case '#':
241 			flags |= SPECIAL;
242 			goto repeat;
243 		case '0':
244 			flags |= ZEROPAD;
245 			goto repeat;
246 		}
247 
248 		/* get field width */
249 		field_width = -1;
250 		if (isdigit(*fmt)) {
251 			field_width = skip_atoi(&fmt);
252 		} else if (*fmt == '*') {
253 			++fmt;
254 			/* it's the next argument */
255 			field_width = va_arg(args, int);
256 			if (field_width < 0) {
257 				field_width = -field_width;
258 				flags |= LEFT;
259 			}
260 		}
261 
262 		/* get the precision */
263 		precision = -1;
264 		if (*fmt == '.') {
265 			++fmt;
266 			if (isdigit(*fmt)) {
267 				precision = skip_atoi(&fmt);
268 			} else if (*fmt == '*') {
269 				++fmt;
270 				/* it's the next argument */
271 				precision = va_arg(args, int);
272 			}
273 			if (precision < 0)
274 				precision = 0;
275 		}
276 
277 		/* get the conversion qualifier */
278 		qualifier = -1;
279 		if (*fmt == 'h' || *fmt == 'l') {
280 			qualifier = *fmt;
281 			++fmt;
282 			if (qualifier == *fmt) {
283 				qualifier -= 'a'-'A';
284 				++fmt;
285 			}
286 		}
287 
288 		/* default base */
289 		base = 10;
290 
291 		switch (*fmt) {
292 		case 'c':
293 			if (!(flags & LEFT))
294 				while (--field_width > 0)
295 					*str++ = ' ';
296 			*str++ = (unsigned char)va_arg(args, int);
297 			while (--field_width > 0)
298 				*str++ = ' ';
299 			continue;
300 
301 		case 's':
302 			s = va_arg(args, char *);
303 			len = strnlen(s, precision);
304 
305 			if (!(flags & LEFT))
306 				while (len < field_width--)
307 					*str++ = ' ';
308 			for (i = 0; i < len; ++i)
309 				*str++ = *s++;
310 			while (len < field_width--)
311 				*str++ = ' ';
312 			continue;
313 
314 		case 'p':
315 			if (field_width == -1) {
316 				field_width = 2 * sizeof(void *);
317 				flags |= ZEROPAD;
318 			}
319 			str = number(str,
320 				     (unsigned long)va_arg(args, void *), 16,
321 				     field_width, precision, flags);
322 			continue;
323 
324 		case '%':
325 			*str++ = '%';
326 			continue;
327 
328 			/* integer number formats - set up the flags and "break" */
329 		case 'o':
330 			base = 8;
331 			break;
332 
333 		case 'x':
334 			flags |= SMALL;
335 			fallthrough;
336 		case 'X':
337 			base = 16;
338 			break;
339 
340 		case 'd':
341 		case 'i':
342 			flags |= SIGN;
343 			fallthrough;
344 		case 'u':
345 			break;
346 
347 		default:
348 			*str++ = '%';
349 			if (*fmt)
350 				*str++ = *fmt;
351 			else
352 				--fmt;
353 			continue;
354 		}
355 		if (flags & SIGN) {
356 			switch (qualifier) {
357 			case 'L':
358 				num = va_arg(args, long long);
359 				break;
360 			case 'l':
361 				num = va_arg(args, long);
362 				break;
363 			case 'h':
364 				num = (short)va_arg(args, int);
365 				break;
366 			case 'H':
367 				num = (signed char)va_arg(args, int);
368 				break;
369 			default:
370 				num = va_arg(args, int);
371 			}
372 		} else {
373 			switch (qualifier) {
374 			case 'L':
375 				num = va_arg(args, unsigned long long);
376 				break;
377 			case 'l':
378 				num = va_arg(args, unsigned long);
379 				break;
380 			case 'h':
381 				num = (unsigned short)va_arg(args, int);
382 				break;
383 			case 'H':
384 				num = (unsigned char)va_arg(args, int);
385 				break;
386 			default:
387 				num = va_arg(args, unsigned int);
388 			}
389 		}
390 		str = number(str, num, base, field_width, precision, flags);
391 	}
392 	*str = '\0';
393 	return str - buf;
394 }
395 
396 int sprintf(char *buf, const char *fmt, ...)
397 {
398 	va_list args;
399 	int i;
400 
401 	va_start(args, fmt);
402 	i = vsprintf(buf, fmt, args);
403 	va_end(args);
404 	return i;
405 }
406