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 static
206 int get_flags(const char **fmt)
207 {
208 	int flags = 0;
209 
210 	do {
211 		switch (**fmt) {
212 		case '-':
213 			flags |= LEFT;
214 			break;
215 		case '+':
216 			flags |= PLUS;
217 			break;
218 		case ' ':
219 			flags |= SPACE;
220 			break;
221 		case '#':
222 			flags |= SPECIAL;
223 			break;
224 		case '0':
225 			flags |= ZEROPAD;
226 			break;
227 		default:
228 			return flags;
229 		}
230 		++(*fmt);
231 	} while (1);
232 }
233 
234 int vsprintf(char *buf, const char *fmt, va_list args)
235 {
236 	int len;
237 	unsigned long long num;
238 	int i, base;
239 	char *str;
240 	const char *s;
241 
242 	int flags;		/* flags to number() */
243 
244 	int field_width;	/* width of output field */
245 	int precision;		/* min. # of digits for integers; max
246 				   number of chars for from string */
247 	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
248 
249 	for (str = buf; *fmt; ++fmt) {
250 		if (*fmt != '%' || *++fmt == '%') {
251 			*str++ = *fmt;
252 			continue;
253 		}
254 
255 		/* process flags */
256 		flags = get_flags(&fmt);
257 
258 		/* get field width */
259 		field_width = -1;
260 		if (isdigit(*fmt)) {
261 			field_width = skip_atoi(&fmt);
262 		} else if (*fmt == '*') {
263 			++fmt;
264 			/* it's the next argument */
265 			field_width = va_arg(args, int);
266 			if (field_width < 0) {
267 				field_width = -field_width;
268 				flags |= LEFT;
269 			}
270 		}
271 
272 		/* get the precision */
273 		precision = -1;
274 		if (*fmt == '.') {
275 			++fmt;
276 			if (isdigit(*fmt)) {
277 				precision = skip_atoi(&fmt);
278 			} else if (*fmt == '*') {
279 				++fmt;
280 				/* it's the next argument */
281 				precision = va_arg(args, int);
282 			} else {
283 				precision = 0;
284 			}
285 			if (precision >= 0)
286 				flags &= ~ZEROPAD;
287 		}
288 
289 		/* get the conversion qualifier */
290 		qualifier = -1;
291 		if (*fmt == 'h' || *fmt == 'l') {
292 			qualifier = *fmt;
293 			++fmt;
294 			if (qualifier == *fmt) {
295 				qualifier -= 'a'-'A';
296 				++fmt;
297 			}
298 		}
299 
300 		/* default base */
301 		base = 10;
302 
303 		switch (*fmt) {
304 		case 'c':
305 			if (!(flags & LEFT))
306 				while (--field_width > 0)
307 					*str++ = ' ';
308 			*str++ = (unsigned char)va_arg(args, int);
309 			while (--field_width > 0)
310 				*str++ = ' ';
311 			continue;
312 
313 		case 's':
314 			s = va_arg(args, char *);
315 			len = strnlen(s, precision);
316 
317 			if (!(flags & LEFT))
318 				while (len < field_width--)
319 					*str++ = ' ';
320 			for (i = 0; i < len; ++i)
321 				*str++ = *s++;
322 			while (len < field_width--)
323 				*str++ = ' ';
324 			continue;
325 
326 		case 'p':
327 			if (field_width == -1) {
328 				field_width = 2 * sizeof(void *);
329 				flags |= ZEROPAD;
330 			}
331 			str = number(str,
332 				     (unsigned long)va_arg(args, void *), 16,
333 				     field_width, precision, flags);
334 			continue;
335 
336 			/* integer number formats - set up the flags and "break" */
337 		case 'o':
338 			base = 8;
339 			break;
340 
341 		case 'x':
342 			flags |= SMALL;
343 			fallthrough;
344 		case 'X':
345 			base = 16;
346 			break;
347 
348 		case 'd':
349 		case 'i':
350 			flags |= SIGN;
351 			fallthrough;
352 		case 'u':
353 			break;
354 
355 		default:
356 			*str++ = '%';
357 			if (*fmt)
358 				*str++ = *fmt;
359 			else
360 				--fmt;
361 			continue;
362 		}
363 		if (flags & SIGN) {
364 			switch (qualifier) {
365 			case 'L':
366 				num = va_arg(args, long long);
367 				break;
368 			case 'l':
369 				num = va_arg(args, long);
370 				break;
371 			case 'h':
372 				num = (short)va_arg(args, int);
373 				break;
374 			case 'H':
375 				num = (signed char)va_arg(args, int);
376 				break;
377 			default:
378 				num = va_arg(args, int);
379 			}
380 		} else {
381 			switch (qualifier) {
382 			case 'L':
383 				num = va_arg(args, unsigned long long);
384 				break;
385 			case 'l':
386 				num = va_arg(args, unsigned long);
387 				break;
388 			case 'h':
389 				num = (unsigned short)va_arg(args, int);
390 				break;
391 			case 'H':
392 				num = (unsigned char)va_arg(args, int);
393 				break;
394 			default:
395 				num = va_arg(args, unsigned int);
396 			}
397 		}
398 		str = number(str, num, base, field_width, precision, flags);
399 	}
400 	*str = '\0';
401 	return str - buf;
402 }
403 
404 int sprintf(char *buf, const char *fmt, ...)
405 {
406 	va_list args;
407 	int i;
408 
409 	va_start(args, fmt);
410 	i = vsprintf(buf, fmt, args);
411 	va_end(args);
412 	return i;
413 }
414