vsprintf.c: add GUID printing
[oweals/u-boot.git] / lib / vsprintf.c
1 /*
2  *  linux/lib/vsprintf.c
3  *
4  *  Copyright (C) 1991, 1992  Linus Torvalds
5  */
6
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
8 /*
9  * Wirzenius wrote this portably, Torvalds fucked it up :-)
10  *
11  * from hush: simple_itoa() was lifted from boa-0.93.15
12  */
13
14 #include <stdarg.h>
15 #include <linux/types.h>
16 #include <linux/string.h>
17 #include <linux/ctype.h>
18
19 #include <common.h>
20 #include <charset.h>
21 #include <uuid.h>
22
23 #include <div64.h>
24 #define noinline __attribute__((noinline))
25
26 /* we use this so that we can do without the ctype library */
27 #define is_digit(c)     ((c) >= '0' && (c) <= '9')
28
29 static int skip_atoi(const char **s)
30 {
31         int i = 0;
32
33         while (is_digit(**s))
34                 i = i * 10 + *((*s)++) - '0';
35
36         return i;
37 }
38
39 /* Decimal conversion is by far the most typical, and is used
40  * for /proc and /sys data. This directly impacts e.g. top performance
41  * with many processes running. We optimize it for speed
42  * using code from
43  * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
44  * (with permission from the author, Douglas W. Jones). */
45
46 /* Formats correctly any integer in [0,99999].
47  * Outputs from one to five digits depending on input.
48  * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
49 static char *put_dec_trunc(char *buf, unsigned q)
50 {
51         unsigned d3, d2, d1, d0;
52         d1 = (q>>4) & 0xf;
53         d2 = (q>>8) & 0xf;
54         d3 = (q>>12);
55
56         d0 = 6*(d3 + d2 + d1) + (q & 0xf);
57         q = (d0 * 0xcd) >> 11;
58         d0 = d0 - 10*q;
59         *buf++ = d0 + '0'; /* least significant digit */
60         d1 = q + 9*d3 + 5*d2 + d1;
61         if (d1 != 0) {
62                 q = (d1 * 0xcd) >> 11;
63                 d1 = d1 - 10*q;
64                 *buf++ = d1 + '0'; /* next digit */
65
66                 d2 = q + 2*d2;
67                 if ((d2 != 0) || (d3 != 0)) {
68                         q = (d2 * 0xd) >> 7;
69                         d2 = d2 - 10*q;
70                         *buf++ = d2 + '0'; /* next digit */
71
72                         d3 = q + 4*d3;
73                         if (d3 != 0) {
74                                 q = (d3 * 0xcd) >> 11;
75                                 d3 = d3 - 10*q;
76                                 *buf++ = d3 + '0';  /* next digit */
77                                 if (q != 0)
78                                         *buf++ = q + '0'; /* most sign. digit */
79                         }
80                 }
81         }
82         return buf;
83 }
84 /* Same with if's removed. Always emits five digits */
85 static char *put_dec_full(char *buf, unsigned q)
86 {
87         /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
88         /* but anyway, gcc produces better code with full-sized ints */
89         unsigned d3, d2, d1, d0;
90         d1 = (q>>4) & 0xf;
91         d2 = (q>>8) & 0xf;
92         d3 = (q>>12);
93
94         /*
95          * Possible ways to approx. divide by 10
96          * gcc -O2 replaces multiply with shifts and adds
97          * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
98          * (x * 0x67) >> 10:  1100111
99          * (x * 0x34) >> 9:    110100 - same
100          * (x * 0x1a) >> 8:     11010 - same
101          * (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
102          */
103
104         d0 = 6*(d3 + d2 + d1) + (q & 0xf);
105         q = (d0 * 0xcd) >> 11;
106         d0 = d0 - 10*q;
107         *buf++ = d0 + '0';
108         d1 = q + 9*d3 + 5*d2 + d1;
109                 q = (d1 * 0xcd) >> 11;
110                 d1 = d1 - 10*q;
111                 *buf++ = d1 + '0';
112
113                 d2 = q + 2*d2;
114                         q = (d2 * 0xd) >> 7;
115                         d2 = d2 - 10*q;
116                         *buf++ = d2 + '0';
117
118                         d3 = q + 4*d3;
119                                 q = (d3 * 0xcd) >> 11; /* - shorter code */
120                                 /* q = (d3 * 0x67) >> 10; - would also work */
121                                 d3 = d3 - 10*q;
122                                 *buf++ = d3 + '0';
123                                         *buf++ = q + '0';
124         return buf;
125 }
126 /* No inlining helps gcc to use registers better */
127 static noinline char *put_dec(char *buf, uint64_t num)
128 {
129         while (1) {
130                 unsigned rem;
131                 if (num < 100000)
132                         return put_dec_trunc(buf, num);
133                 rem = do_div(num, 100000);
134                 buf = put_dec_full(buf, rem);
135         }
136 }
137
138 #define ZEROPAD 1               /* pad with zero */
139 #define SIGN    2               /* unsigned/signed long */
140 #define PLUS    4               /* show plus */
141 #define SPACE   8               /* space if plus */
142 #define LEFT    16              /* left justified */
143 #define SMALL   32              /* Must be 32 == 0x20 */
144 #define SPECIAL 64              /* 0x */
145
146 /*
147  * Macro to add a new character to our output string, but only if it will
148  * fit. The macro moves to the next character position in the output string.
149  */
150 #define ADDCH(str, ch) do { \
151         if ((str) < end) \
152                 *(str) = (ch); \
153         ++str; \
154         } while (0)
155
156 static char *number(char *buf, char *end, u64 num,
157                 int base, int size, int precision, int type)
158 {
159         /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
160         static const char digits[16] = "0123456789ABCDEF";
161
162         char tmp[66];
163         char sign;
164         char locase;
165         int need_pfx = ((type & SPECIAL) && base != 10);
166         int i;
167
168         /* locase = 0 or 0x20. ORing digits or letters with 'locase'
169          * produces same digits or (maybe lowercased) letters */
170         locase = (type & SMALL);
171         if (type & LEFT)
172                 type &= ~ZEROPAD;
173         sign = 0;
174         if (type & SIGN) {
175                 if ((s64) num < 0) {
176                         sign = '-';
177                         num = -(s64) num;
178                         size--;
179                 } else if (type & PLUS) {
180                         sign = '+';
181                         size--;
182                 } else if (type & SPACE) {
183                         sign = ' ';
184                         size--;
185                 }
186         }
187         if (need_pfx) {
188                 size--;
189                 if (base == 16)
190                         size--;
191         }
192
193         /* generate full string in tmp[], in reverse order */
194         i = 0;
195         if (num == 0)
196                 tmp[i++] = '0';
197         /* Generic code, for any base:
198         else do {
199                 tmp[i++] = (digits[do_div(num,base)] | locase);
200         } while (num != 0);
201         */
202         else if (base != 10) { /* 8 or 16 */
203                 int mask = base - 1;
204                 int shift = 3;
205
206                 if (base == 16)
207                         shift = 4;
208
209                 do {
210                         tmp[i++] = (digits[((unsigned char)num) & mask]
211                                         | locase);
212                         num >>= shift;
213                 } while (num);
214         } else { /* base 10 */
215                 i = put_dec(tmp, num) - tmp;
216         }
217
218         /* printing 100 using %2d gives "100", not "00" */
219         if (i > precision)
220                 precision = i;
221         /* leading space padding */
222         size -= precision;
223         if (!(type & (ZEROPAD + LEFT))) {
224                 while (--size >= 0)
225                         ADDCH(buf, ' ');
226         }
227         /* sign */
228         if (sign)
229                 ADDCH(buf, sign);
230         /* "0x" / "0" prefix */
231         if (need_pfx) {
232                 ADDCH(buf, '0');
233                 if (base == 16)
234                         ADDCH(buf, 'X' | locase);
235         }
236         /* zero or space padding */
237         if (!(type & LEFT)) {
238                 char c = (type & ZEROPAD) ? '0' : ' ';
239
240                 while (--size >= 0)
241                         ADDCH(buf, c);
242         }
243         /* hmm even more zero padding? */
244         while (i <= --precision)
245                 ADDCH(buf, '0');
246         /* actual digits of result */
247         while (--i >= 0)
248                 ADDCH(buf, tmp[i]);
249         /* trailing space padding */
250         while (--size >= 0)
251                 ADDCH(buf, ' ');
252         return buf;
253 }
254
255 static char *string(char *buf, char *end, char *s, int field_width,
256                 int precision, int flags)
257 {
258         int len, i;
259
260         if (s == NULL)
261                 s = "<NULL>";
262
263         len = strnlen(s, precision);
264
265         if (!(flags & LEFT))
266                 while (len < field_width--)
267                         ADDCH(buf, ' ');
268         for (i = 0; i < len; ++i)
269                 ADDCH(buf, *s++);
270         while (len < field_width--)
271                 ADDCH(buf, ' ');
272         return buf;
273 }
274
275 static char *string16(char *buf, char *end, u16 *s, int field_width,
276                 int precision, int flags)
277 {
278         u16 *str = s ? s : L"<NULL>";
279         int utf16_len = utf16_strnlen(str, precision);
280         u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
281         int utf8_len, i;
282
283         utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
284
285         if (!(flags & LEFT))
286                 while (utf8_len < field_width--)
287                         ADDCH(buf, ' ');
288         for (i = 0; i < utf8_len; ++i)
289                 ADDCH(buf, utf8[i]);
290         while (utf8_len < field_width--)
291                 ADDCH(buf, ' ');
292         return buf;
293 }
294
295 #ifdef CONFIG_CMD_NET
296 static const char hex_asc[] = "0123456789abcdef";
297 #define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
298 #define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]
299
300 static inline char *pack_hex_byte(char *buf, u8 byte)
301 {
302         *buf++ = hex_asc_hi(byte);
303         *buf++ = hex_asc_lo(byte);
304         return buf;
305 }
306
307 static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
308                                 int precision, int flags)
309 {
310         /* (6 * 2 hex digits), 5 colons and trailing zero */
311         char mac_addr[6 * 3];
312         char *p = mac_addr;
313         int i;
314
315         for (i = 0; i < 6; i++) {
316                 p = pack_hex_byte(p, addr[i]);
317                 if (!(flags & SPECIAL) && i != 5)
318                         *p++ = ':';
319         }
320         *p = '\0';
321
322         return string(buf, end, mac_addr, field_width, precision,
323                       flags & ~SPECIAL);
324 }
325
326 static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
327                          int precision, int flags)
328 {
329         /* (8 * 4 hex digits), 7 colons and trailing zero */
330         char ip6_addr[8 * 5];
331         char *p = ip6_addr;
332         int i;
333
334         for (i = 0; i < 8; i++) {
335                 p = pack_hex_byte(p, addr[2 * i]);
336                 p = pack_hex_byte(p, addr[2 * i + 1]);
337                 if (!(flags & SPECIAL) && i != 7)
338                         *p++ = ':';
339         }
340         *p = '\0';
341
342         return string(buf, end, ip6_addr, field_width, precision,
343                       flags & ~SPECIAL);
344 }
345
346 static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
347                          int precision, int flags)
348 {
349         /* (4 * 3 decimal digits), 3 dots and trailing zero */
350         char ip4_addr[4 * 4];
351         char temp[3];   /* hold each IP quad in reverse order */
352         char *p = ip4_addr;
353         int i, digits;
354
355         for (i = 0; i < 4; i++) {
356                 digits = put_dec_trunc(temp, addr[i]) - temp;
357                 /* reverse the digits in the quad */
358                 while (digits--)
359                         *p++ = temp[digits];
360                 if (i != 3)
361                         *p++ = '.';
362         }
363         *p = '\0';
364
365         return string(buf, end, ip4_addr, field_width, precision,
366                       flags & ~SPECIAL);
367 }
368 #endif
369
370 #ifdef CONFIG_LIB_UUID
371 /*
372  * This works (roughly) the same way as linux's, but we currently always
373  * print lower-case (ie. we just keep %pUB and %pUL for compat with linux),
374  * mostly just because that is what uuid_bin_to_str() supports.
375  *
376  *   %pUb:   01020304-0506-0708-090a-0b0c0d0e0f10
377  *   %pUl:   04030201-0605-0807-090a-0b0c0d0e0f10
378  */
379 static char *uuid_string(char *buf, char *end, u8 *addr, int field_width,
380                          int precision, int flags, const char *fmt)
381 {
382         char uuid[UUID_STR_LEN + 1];
383         int str_format = UUID_STR_FORMAT_STD;
384
385         switch (*(++fmt)) {
386         case 'L':
387         case 'l':
388                 str_format = UUID_STR_FORMAT_GUID;
389                 break;
390         case 'B':
391         case 'b':
392                 /* this is the default */
393                 break;
394         default:
395                 break;
396         }
397
398         uuid_bin_to_str(addr, uuid, str_format);
399
400         return string(buf, end, uuid, field_width, precision, flags);
401 }
402 #endif
403
404 /*
405  * Show a '%p' thing.  A kernel extension is that the '%p' is followed
406  * by an extra set of alphanumeric characters that are extended format
407  * specifiers.
408  *
409  * Right now we handle:
410  *
411  * - 'M' For a 6-byte MAC address, it prints the address in the
412  *       usual colon-separated hex notation
413  * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
414  *       decimal for v4 and colon separated network-order 16 bit hex for v6)
415  * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
416  *       currently the same
417  *
418  * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
419  * function pointers are really function descriptors, which contain a
420  * pointer to the real address.
421  */
422 static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
423                 int field_width, int precision, int flags)
424 {
425         u64 num = (uintptr_t)ptr;
426
427         /*
428          * Being a boot loader, we explicitly allow pointers to
429          * (physical) address null.
430          */
431 #if 0
432         if (!ptr)
433                 return string(buf, end, "(null)", field_width, precision,
434                               flags);
435 #endif
436
437         switch (*fmt) {
438 #ifdef CONFIG_CMD_NET
439         case 'a':
440                 flags |= SPECIAL | ZEROPAD;
441
442                 switch (fmt[1]) {
443                 case 'p':
444                 default:
445                         field_width = sizeof(phys_addr_t) * 2 + 2;
446                         num = *(phys_addr_t *)ptr;
447                         break;
448                 }
449                 break;
450         case 'm':
451                 flags |= SPECIAL;
452                 /* Fallthrough */
453         case 'M':
454                 return mac_address_string(buf, end, ptr, field_width,
455                                           precision, flags);
456         case 'i':
457                 flags |= SPECIAL;
458                 /* Fallthrough */
459         case 'I':
460                 if (fmt[1] == '6')
461                         return ip6_addr_string(buf, end, ptr, field_width,
462                                                precision, flags);
463                 if (fmt[1] == '4')
464                         return ip4_addr_string(buf, end, ptr, field_width,
465                                                precision, flags);
466                 flags &= ~SPECIAL;
467                 break;
468 #endif
469 #ifdef CONFIG_LIB_UUID
470         case 'U':
471                 return uuid_string(buf, end, ptr, field_width, precision,
472                                    flags, fmt);
473 #endif
474         default:
475                 break;
476         }
477         flags |= SMALL;
478         if (field_width == -1) {
479                 field_width = 2*sizeof(void *);
480                 flags |= ZEROPAD;
481         }
482         return number(buf, end, num, 16, field_width, precision, flags);
483 }
484
485 static int vsnprintf_internal(char *buf, size_t size, const char *fmt,
486                               va_list args)
487 {
488         u64 num;
489         int base;
490         char *str;
491
492         int flags;              /* flags to number() */
493
494         int field_width;        /* width of output field */
495         int precision;          /* min. # of digits for integers; max
496                                    number of chars for from string */
497         int qualifier;          /* 'h', 'l', or 'L' for integer fields */
498                                 /* 'z' support added 23/7/1999 S.H.    */
499                                 /* 'z' changed to 'Z' --davidm 1/25/99 */
500                                 /* 't' added for ptrdiff_t */
501         char *end = buf + size;
502
503         /* Make sure end is always >= buf - do we want this in U-Boot? */
504         if (end < buf) {
505                 end = ((void *)-1);
506                 size = end - buf;
507         }
508         str = buf;
509
510         for (; *fmt ; ++fmt) {
511                 if (*fmt != '%') {
512                         ADDCH(str, *fmt);
513                         continue;
514                 }
515
516                 /* process flags */
517                 flags = 0;
518 repeat:
519                         ++fmt;          /* this also skips first '%' */
520                         switch (*fmt) {
521                         case '-':
522                                 flags |= LEFT;
523                                 goto repeat;
524                         case '+':
525                                 flags |= PLUS;
526                                 goto repeat;
527                         case ' ':
528                                 flags |= SPACE;
529                                 goto repeat;
530                         case '#':
531                                 flags |= SPECIAL;
532                                 goto repeat;
533                         case '0':
534                                 flags |= ZEROPAD;
535                                 goto repeat;
536                         }
537
538                 /* get field width */
539                 field_width = -1;
540                 if (is_digit(*fmt))
541                         field_width = skip_atoi(&fmt);
542                 else if (*fmt == '*') {
543                         ++fmt;
544                         /* it's the next argument */
545                         field_width = va_arg(args, int);
546                         if (field_width < 0) {
547                                 field_width = -field_width;
548                                 flags |= LEFT;
549                         }
550                 }
551
552                 /* get the precision */
553                 precision = -1;
554                 if (*fmt == '.') {
555                         ++fmt;
556                         if (is_digit(*fmt))
557                                 precision = skip_atoi(&fmt);
558                         else if (*fmt == '*') {
559                                 ++fmt;
560                                 /* it's the next argument */
561                                 precision = va_arg(args, int);
562                         }
563                         if (precision < 0)
564                                 precision = 0;
565                 }
566
567                 /* get the conversion qualifier */
568                 qualifier = -1;
569                 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
570                     *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
571                         qualifier = *fmt;
572                         ++fmt;
573                         if (qualifier == 'l' && *fmt == 'l') {
574                                 qualifier = 'L';
575                                 ++fmt;
576                         }
577                 }
578
579                 /* default base */
580                 base = 10;
581
582                 switch (*fmt) {
583                 case 'c':
584                         if (!(flags & LEFT)) {
585                                 while (--field_width > 0)
586                                         ADDCH(str, ' ');
587                         }
588                         ADDCH(str, (unsigned char) va_arg(args, int));
589                         while (--field_width > 0)
590                                 ADDCH(str, ' ');
591                         continue;
592
593                 case 's':
594                         if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
595                                 str = string16(str, end, va_arg(args, u16 *),
596                                                field_width, precision, flags);
597                         } else {
598                                 str = string(str, end, va_arg(args, char *),
599                                              field_width, precision, flags);
600                         }
601                         continue;
602
603                 case 'p':
604                         str = pointer(fmt + 1, str, end,
605                                         va_arg(args, void *),
606                                         field_width, precision, flags);
607                         /* Skip all alphanumeric pointer suffixes */
608                         while (isalnum(fmt[1]))
609                                 fmt++;
610                         continue;
611
612                 case 'n':
613                         if (qualifier == 'l') {
614                                 long *ip = va_arg(args, long *);
615                                 *ip = (str - buf);
616                         } else {
617                                 int *ip = va_arg(args, int *);
618                                 *ip = (str - buf);
619                         }
620                         continue;
621
622                 case '%':
623                         ADDCH(str, '%');
624                         continue;
625
626                 /* integer number formats - set up the flags and "break" */
627                 case 'o':
628                         base = 8;
629                         break;
630
631                 case 'x':
632                         flags |= SMALL;
633                 case 'X':
634                         base = 16;
635                         break;
636
637                 case 'd':
638                 case 'i':
639                         flags |= SIGN;
640                 case 'u':
641                         break;
642
643                 default:
644                         ADDCH(str, '%');
645                         if (*fmt)
646                                 ADDCH(str, *fmt);
647                         else
648                                 --fmt;
649                         continue;
650                 }
651                 if (qualifier == 'L')  /* "quad" for 64 bit variables */
652                         num = va_arg(args, unsigned long long);
653                 else if (qualifier == 'l') {
654                         num = va_arg(args, unsigned long);
655                         if (flags & SIGN)
656                                 num = (signed long) num;
657                 } else if (qualifier == 'Z' || qualifier == 'z') {
658                         num = va_arg(args, size_t);
659                 } else if (qualifier == 't') {
660                         num = va_arg(args, ptrdiff_t);
661                 } else if (qualifier == 'h') {
662                         num = (unsigned short) va_arg(args, int);
663                         if (flags & SIGN)
664                                 num = (signed short) num;
665                 } else {
666                         num = va_arg(args, unsigned int);
667                         if (flags & SIGN)
668                                 num = (signed int) num;
669                 }
670                 str = number(str, end, num, base, field_width, precision,
671                              flags);
672         }
673
674         if (size > 0) {
675                 ADDCH(str, '\0');
676                 if (str > end)
677                         end[-1] = '\0';
678                 --str;
679         }
680         /* the trailing null byte doesn't count towards the total */
681         return str - buf;
682 }
683
684 int vsnprintf(char *buf, size_t size, const char *fmt,
685                               va_list args)
686 {
687         return vsnprintf_internal(buf, size, fmt, args);
688 }
689
690 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
691 {
692         int i;
693
694         i = vsnprintf(buf, size, fmt, args);
695
696         if (likely(i < size))
697                 return i;
698         if (size != 0)
699                 return size - 1;
700         return 0;
701 }
702
703 int snprintf(char *buf, size_t size, const char *fmt, ...)
704 {
705         va_list args;
706         int i;
707
708         va_start(args, fmt);
709         i = vsnprintf(buf, size, fmt, args);
710         va_end(args);
711
712         return i;
713 }
714
715 int scnprintf(char *buf, size_t size, const char *fmt, ...)
716 {
717         va_list args;
718         int i;
719
720         va_start(args, fmt);
721         i = vscnprintf(buf, size, fmt, args);
722         va_end(args);
723
724         return i;
725 }
726
727 /**
728  * Format a string and place it in a buffer (va_list version)
729  *
730  * @param buf   The buffer to place the result into
731  * @param fmt   The format string to use
732  * @param args  Arguments for the format string
733  *
734  * The function returns the number of characters written
735  * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
736  * buffer overflows.
737  *
738  * If you're not already dealing with a va_list consider using sprintf().
739  */
740 int vsprintf(char *buf, const char *fmt, va_list args)
741 {
742         return vsnprintf_internal(buf, INT_MAX, fmt, args);
743 }
744
745 int sprintf(char *buf, const char *fmt, ...)
746 {
747         va_list args;
748         int i;
749
750         va_start(args, fmt);
751         i = vsprintf(buf, fmt, args);
752         va_end(args);
753         return i;
754 }
755
756 int printf(const char *fmt, ...)
757 {
758         va_list args;
759         uint i;
760         char printbuffer[CONFIG_SYS_PBSIZE];
761
762         va_start(args, fmt);
763
764         /*
765          * For this to work, printbuffer must be larger than
766          * anything we ever want to print.
767          */
768         i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
769         va_end(args);
770
771         /* Print the string */
772         puts(printbuffer);
773         return i;
774 }
775
776 int vprintf(const char *fmt, va_list args)
777 {
778         uint i;
779         char printbuffer[CONFIG_SYS_PBSIZE];
780
781         /*
782          * For this to work, printbuffer must be larger than
783          * anything we ever want to print.
784          */
785         i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
786
787         /* Print the string */
788         puts(printbuffer);
789         return i;
790 }
791
792
793 void __assert_fail(const char *assertion, const char *file, unsigned line,
794                    const char *function)
795 {
796         /* This will not return */
797         panic("%s:%u: %s: Assertion `%s' failed.", file, line, function,
798               assertion);
799 }
800
801 char *simple_itoa(ulong i)
802 {
803         /* 21 digits plus null terminator, good for 64-bit or smaller ints */
804         static char local[22];
805         char *p = &local[21];
806
807         *p-- = '\0';
808         do {
809                 *p-- = '0' + i % 10;
810                 i /= 10;
811         } while (i > 0);
812         return p + 1;
813 }
814
815 /* We don't seem to have %'d in U-Boot */
816 void print_grouped_ull(unsigned long long int_val, int digits)
817 {
818         char str[21], *s;
819         int grab = 3;
820
821         digits = (digits + 2) / 3;
822         sprintf(str, "%*llu", digits * 3, int_val);
823         for (s = str; *s; s += grab) {
824                 if (s != str)
825                         putc(s[-1] != ' ' ? ',' : ' ');
826                 printf("%.*s", grab, s);
827                 grab = 3;
828         }
829 }
830
831 bool str2off(const char *p, loff_t *num)
832 {
833         char *endptr;
834
835         *num = simple_strtoull(p, &endptr, 16);
836         return *p != '\0' && *endptr == '\0';
837 }
838
839 bool str2long(const char *p, ulong *num)
840 {
841         char *endptr;
842
843         *num = simple_strtoul(p, &endptr, 16);
844         return *p != '\0' && *endptr == '\0';
845 }