a3265a81adca50fc4fd4d98c2da3f60bb6d725e5
[linux-2.6-microblaze.git] / drivers / firmware / efi / libstub / vsprintf.c
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 }