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