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 static
235 int get_int(const char **fmt, va_list *ap)
236 {
237 	if (isdigit(**fmt))
238 		return skip_atoi(fmt);
239 	if (**fmt == '*') {
240 		++(*fmt);
241 		/* it's the next argument */
242 		return va_arg(*ap, int);
243 	}
244 	return 0;
245 }
246 
247 static
248 unsigned long long get_number(int sign, int qualifier, va_list *ap)
249 {
250 	if (sign) {
251 		switch (qualifier) {
252 		case 'L':
253 			return va_arg(*ap, long long);
254 		case 'l':
255 			return va_arg(*ap, long);
256 		case 'h':
257 			return (short)va_arg(*ap, int);
258 		case 'H':
259 			return (signed char)va_arg(*ap, int);
260 		default:
261 			return va_arg(*ap, int);
262 		};
263 	} else {
264 		switch (qualifier) {
265 		case 'L':
266 			return va_arg(*ap, unsigned long long);
267 		case 'l':
268 			return va_arg(*ap, unsigned long);
269 		case 'h':
270 			return (unsigned short)va_arg(*ap, int);
271 		case 'H':
272 			return (unsigned char)va_arg(*ap, int);
273 		default:
274 			return va_arg(*ap, unsigned int);
275 		}
276 	}
277 }
278 
279 int vsprintf(char *buf, const char *fmt, va_list ap)
280 {
281 	int len;
282 	unsigned long long num;
283 	int i, base;
284 	char *str;
285 	const char *s;
286 
287 	int flags;		/* flags to number() */
288 
289 	int field_width;	/* width of output field */
290 	int precision;		/* min. # of digits for integers; max
291 				   number of chars for from string */
292 	int qualifier;		/* 'h', 'hh', 'l' or 'll' for integer fields */
293 
294 	va_list args;
295 
296 	/*
297 	 * We want to pass our input va_list to helper functions by reference,
298 	 * but there's an annoying edge case. If va_list was originally passed
299 	 * to us by value, we could just pass &ap down to the helpers. This is
300 	 * the case on, for example, X86_32.
301 	 * However, on X86_64 (and possibly others), va_list is actually a
302 	 * size-1 array containing a structure. Our function parameter ap has
303 	 * decayed from T[1] to T*, and &ap has type T** rather than T(*)[1],
304 	 * which is what will be expected by a function taking a va_list *
305 	 * parameter.
306 	 * One standard way to solve this mess is by creating a copy in a local
307 	 * variable of type va_list and then passing a pointer to that local
308 	 * copy instead, which is what we do here.
309 	 */
310 	va_copy(args, ap);
311 
312 	for (str = buf; *fmt; ++fmt) {
313 		if (*fmt != '%' || *++fmt == '%') {
314 			*str++ = *fmt;
315 			continue;
316 		}
317 
318 		/* process flags */
319 		flags = get_flags(&fmt);
320 
321 		/* get field width */
322 		field_width = get_int(&fmt, &args);
323 		if (field_width < 0) {
324 			field_width = -field_width;
325 			flags |= LEFT;
326 		}
327 
328 		/* get the precision */
329 		precision = -1;
330 		if (*fmt == '.') {
331 			++fmt;
332 			precision = get_int(&fmt, &args);
333 			if (precision >= 0)
334 				flags &= ~ZEROPAD;
335 		}
336 
337 		/* get the conversion qualifier */
338 		qualifier = -1;
339 		if (*fmt == 'h' || *fmt == 'l') {
340 			qualifier = *fmt;
341 			++fmt;
342 			if (qualifier == *fmt) {
343 				qualifier -= 'a'-'A';
344 				++fmt;
345 			}
346 		}
347 
348 		switch (*fmt) {
349 		case 'c':
350 			if (!(flags & LEFT))
351 				while (--field_width > 0)
352 					*str++ = ' ';
353 			*str++ = (unsigned char)va_arg(args, int);
354 			while (--field_width > 0)
355 				*str++ = ' ';
356 			continue;
357 
358 		case 's':
359 			s = va_arg(args, char *);
360 			len = strnlen(s, precision);
361 
362 			if (!(flags & LEFT))
363 				while (len < field_width--)
364 					*str++ = ' ';
365 			for (i = 0; i < len; ++i)
366 				*str++ = *s++;
367 			while (len < field_width--)
368 				*str++ = ' ';
369 			continue;
370 
371 			/* integer number formats - set up the flags and "break" */
372 		case 'o':
373 			base = 8;
374 			break;
375 
376 		case 'p':
377 			if (precision < 0)
378 				precision = 2 * sizeof(void *);
379 			fallthrough;
380 		case 'x':
381 			flags |= SMALL;
382 			fallthrough;
383 		case 'X':
384 			base = 16;
385 			break;
386 
387 		case 'd':
388 		case 'i':
389 			flags |= SIGN;
390 			fallthrough;
391 		case 'u':
392 			base = 10;
393 			break;
394 
395 		default:
396 			*str++ = '%';
397 			if (*fmt)
398 				*str++ = *fmt;
399 			else
400 				--fmt;
401 			continue;
402 		}
403 		if (*fmt == 'p') {
404 			num = (unsigned long)va_arg(args, void *);
405 		} else {
406 			num = get_number(flags & SIGN, qualifier, &args);
407 		}
408 		str = number(str, num, base, field_width, precision, flags);
409 	}
410 	*str = '\0';
411 
412 	va_end(args);
413 
414 	return str - buf;
415 }
416 
417 int sprintf(char *buf, const char *fmt, ...)
418 {
419 	va_list args;
420 	int i;
421 
422 	va_start(args, fmt);
423 	i = vsprintf(buf, fmt, args);
424 	va_end(args);
425 	return i;
426 }
427