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