Blame view

lib/vsprintf.c 18.5 KB
153d511e3   wdenk   Initial revision
1
2
3
4
5
6
7
8
9
  /*
   *  linux/lib/vsprintf.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
   */
  
  /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
  /*
   * Wirzenius wrote this portably, Torvalds fucked it up :-)
3cce8a549   Simon Glass   Move simple_itoa ...
10
11
   *
   * from hush: simple_itoa() was lifted from boa-0.93.15
153d511e3   wdenk   Initial revision
12
13
14
15
16
17
   */
  
  #include <stdarg.h>
  #include <linux/types.h>
  #include <linux/string.h>
  #include <linux/ctype.h>
a7fd0d9ff   Heiko Schocher   lib, vsprintf: in...
18
  #include <errno.h>
153d511e3   wdenk   Initial revision
19
20
  
  #include <common.h>
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
21
  #if !defined(CONFIG_PANIC_HANG)
153d511e3   wdenk   Initial revision
22
  #include <command.h>
153d511e3   wdenk   Initial revision
23
  #endif
479105065   Dirk Behme   Use do_div from d...
24
  #include <div64.h>
479105065   Dirk Behme   Use do_div from d...
25
  #define noinline __attribute__((noinline))
046a37bd5   Sonny Rao   Add safe vsnprint...
26
27
  /* some reluctance to put this into a new limits.h, so it is here */
  #define INT_MAX		((int)(~0U>>1))
0eb257683   Kim Phillips   lib/vsprintf.c: s...
28
  static const char hex_asc[] = "0123456789abcdef";
6c6166f52   Mike Frysinger   vsprintf: pull up...
29
30
31
32
33
34
35
36
37
  #define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
  #define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]
  
  static inline char *pack_hex_byte(char *buf, u8 byte)
  {
  	*buf++ = hex_asc_hi(byte);
  	*buf++ = hex_asc_lo(byte);
  	return buf;
  }
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
38
39
  unsigned long simple_strtoul(const char *cp, char **endp,
  				unsigned int base)
153d511e3   wdenk   Initial revision
40
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
41
42
  	unsigned long result = 0;
  	unsigned long value;
153d511e3   wdenk   Initial revision
43
44
45
46
47
48
49
  
  	if (*cp == '0') {
  		cp++;
  		if ((*cp == 'x') && isxdigit(cp[1])) {
  			base = 16;
  			cp++;
  		}
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
50
51
  
  		if (!base)
153d511e3   wdenk   Initial revision
52
  			base = 8;
153d511e3   wdenk   Initial revision
53
  	}
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
54
55
  
  	if (!base)
153d511e3   wdenk   Initial revision
56
  		base = 10;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
57

153d511e3   wdenk   Initial revision
58
59
60
61
62
  	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
  	    ? toupper(*cp) : *cp)-'A'+10) < base) {
  		result = result*base + value;
  		cp++;
  	}
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
63

153d511e3   wdenk   Initial revision
64
65
  	if (endp)
  		*endp = (char *)cp;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
66

153d511e3   wdenk   Initial revision
67
68
  	return result;
  }
a7fd0d9ff   Heiko Schocher   lib, vsprintf: in...
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
  int strict_strtoul(const char *cp, unsigned int base, unsigned long *res)
  {
  	char *tail;
  	unsigned long val;
  	size_t len;
  
  	*res = 0;
  	len = strlen(cp);
  	if (len == 0)
  		return -EINVAL;
  
  	val = simple_strtoul(cp, &tail, base);
  	if (tail == cp)
  		return -EINVAL;
  
  	if ((*tail == '\0') ||
  		((len == (size_t)(tail - cp) + 1) && (*tail == '
  '))) {
  		*res = val;
  		return 0;
  	}
  
  	return -EINVAL;
  }
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
93
  long simple_strtol(const char *cp, char **endp, unsigned int base)
153d511e3   wdenk   Initial revision
94
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
95
96
97
98
  	if (*cp == '-')
  		return -simple_strtoul(cp + 1, endp, base);
  
  	return simple_strtoul(cp, endp, base);
153d511e3   wdenk   Initial revision
99
  }
3ec44111a   Lukasz Majewski   vsprintf:fix: Cha...
100
  unsigned long ustrtoul(const char *cp, char **endp, unsigned int base)
7e6ee7ad2   Kyungmin Park   UBI: Add basic UB...
101
102
103
  {
  	unsigned long result = simple_strtoul(cp, endp, base);
  	switch (**endp) {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
104
  	case 'G':
7e6ee7ad2   Kyungmin Park   UBI: Add basic UB...
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
  		result *= 1024;
  		/* fall through */
  	case 'M':
  		result *= 1024;
  		/* fall through */
  	case 'K':
  	case 'k':
  		result *= 1024;
  		if ((*endp)[1] == 'i') {
  			if ((*endp)[2] == 'B')
  				(*endp) += 3;
  			else
  				(*endp) += 2;
  		}
  	}
  	return result;
  }
7df54d316   Piotr Wilczek   vsprintf: add ust...
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
  unsigned long long ustrtoull(const char *cp, char **endp, unsigned int base)
  {
  	unsigned long long result = simple_strtoull(cp, endp, base);
  	switch (**endp) {
  	case 'G':
  		result *= 1024;
  		/* fall through */
  	case 'M':
  		result *= 1024;
  		/* fall through */
  	case 'K':
  	case 'k':
  		result *= 1024;
  		if ((*endp)[1] == 'i') {
  			if ((*endp)[2] == 'B')
  				(*endp) += 3;
  			else
  				(*endp) += 2;
  		}
  	}
  	return result;
  }
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
144
145
  unsigned long long simple_strtoull(const char *cp, char **endp,
  					unsigned int base)
c40b29568   wdenk   * Patch by Rune T...
146
147
148
149
150
  {
  	unsigned long long result = 0, value;
  
  	if (*cp == '0') {
  		cp++;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
151
  		if ((*cp == 'x') && isxdigit(cp[1])) {
c40b29568   wdenk   * Patch by Rune T...
152
153
154
  			base = 16;
  			cp++;
  		}
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
155
156
  
  		if (!base)
c40b29568   wdenk   * Patch by Rune T...
157
  			base = 8;
c40b29568   wdenk   * Patch by Rune T...
158
  	}
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
159
160
  
  	if (!base)
c40b29568   wdenk   * Patch by Rune T...
161
  		base = 10;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
162
163
164
  
  	while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0'
  		: (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) {
c40b29568   wdenk   * Patch by Rune T...
165
166
167
  		result = result * base + value;
  		cp++;
  	}
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
168

c40b29568   wdenk   * Patch by Rune T...
169
170
  	if (endp)
  		*endp = (char *) cp;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
171

c40b29568   wdenk   * Patch by Rune T...
172
173
  	return result;
  }
c40b29568   wdenk   * Patch by Rune T...
174

153d511e3   wdenk   Initial revision
175
176
177
178
179
  /* we use this so that we can do without the ctype library */
  #define is_digit(c)	((c) >= '0' && (c) <= '9')
  
  static int skip_atoi(const char **s)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
180
  	int i = 0;
153d511e3   wdenk   Initial revision
181
182
  
  	while (is_digit(**s))
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
183
  		i = i * 10 + *((*s)++) - '0';
153d511e3   wdenk   Initial revision
184
185
  	return i;
  }
6c6166f52   Mike Frysinger   vsprintf: pull up...
186
187
188
189
190
191
192
193
194
195
  /* Decimal conversion is by far the most typical, and is used
   * for /proc and /sys data. This directly impacts e.g. top performance
   * with many processes running. We optimize it for speed
   * using code from
   * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
   * (with permission from the author, Douglas W. Jones). */
  
  /* Formats correctly any integer in [0,99999].
   * Outputs from one to five digits depending on input.
   * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
196
  static char *put_dec_trunc(char *buf, unsigned q)
6c6166f52   Mike Frysinger   vsprintf: pull up...
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
  {
  	unsigned d3, d2, d1, d0;
  	d1 = (q>>4) & 0xf;
  	d2 = (q>>8) & 0xf;
  	d3 = (q>>12);
  
  	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  	q = (d0 * 0xcd) >> 11;
  	d0 = d0 - 10*q;
  	*buf++ = d0 + '0'; /* least significant digit */
  	d1 = q + 9*d3 + 5*d2 + d1;
  	if (d1 != 0) {
  		q = (d1 * 0xcd) >> 11;
  		d1 = d1 - 10*q;
  		*buf++ = d1 + '0'; /* next digit */
  
  		d2 = q + 2*d2;
  		if ((d2 != 0) || (d3 != 0)) {
  			q = (d2 * 0xd) >> 7;
  			d2 = d2 - 10*q;
  			*buf++ = d2 + '0'; /* next digit */
  
  			d3 = q + 4*d3;
  			if (d3 != 0) {
  				q = (d3 * 0xcd) >> 11;
  				d3 = d3 - 10*q;
  				*buf++ = d3 + '0';  /* next digit */
  				if (q != 0)
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
225
  					*buf++ = q + '0'; /* most sign. digit */
6c6166f52   Mike Frysinger   vsprintf: pull up...
226
227
228
229
230
231
  			}
  		}
  	}
  	return buf;
  }
  /* Same with if's removed. Always emits five digits */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
232
  static char *put_dec_full(char *buf, unsigned q)
6c6166f52   Mike Frysinger   vsprintf: pull up...
233
234
235
236
237
238
239
  {
  	/* BTW, if q is in [0,9999], 8-bit ints will be enough, */
  	/* but anyway, gcc produces better code with full-sized ints */
  	unsigned d3, d2, d1, d0;
  	d1 = (q>>4) & 0xf;
  	d2 = (q>>8) & 0xf;
  	d3 = (q>>12);
c0a14aedc   Wolfgang Denk   Update CHANGELOG,...
240
241
242
243
244
245
246
247
248
  	/*
  	 * Possible ways to approx. divide by 10
  	 * gcc -O2 replaces multiply with shifts and adds
  	 * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
  	 * (x * 0x67) >> 10:  1100111
  	 * (x * 0x34) >> 9:    110100 - same
  	 * (x * 0x1a) >> 8:     11010 - same
  	 * (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
  	 */
6c6166f52   Mike Frysinger   vsprintf: pull up...
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
  
  	d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  	q = (d0 * 0xcd) >> 11;
  	d0 = d0 - 10*q;
  	*buf++ = d0 + '0';
  	d1 = q + 9*d3 + 5*d2 + d1;
  		q = (d1 * 0xcd) >> 11;
  		d1 = d1 - 10*q;
  		*buf++ = d1 + '0';
  
  		d2 = q + 2*d2;
  			q = (d2 * 0xd) >> 7;
  			d2 = d2 - 10*q;
  			*buf++ = d2 + '0';
  
  			d3 = q + 4*d3;
  				q = (d3 * 0xcd) >> 11; /* - shorter code */
  				/* q = (d3 * 0x67) >> 10; - would also work */
  				d3 = d3 - 10*q;
  				*buf++ = d3 + '0';
  					*buf++ = q + '0';
  	return buf;
  }
  /* No inlining helps gcc to use registers better */
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
273
  static noinline char *put_dec(char *buf, u64 num)
6c6166f52   Mike Frysinger   vsprintf: pull up...
274
275
276
277
278
279
280
281
282
  {
  	while (1) {
  		unsigned rem;
  		if (num < 100000)
  			return put_dec_trunc(buf, num);
  		rem = do_div(num, 100000);
  		buf = put_dec_full(buf, rem);
  	}
  }
153d511e3   wdenk   Initial revision
283
284
285
286
287
  #define ZEROPAD	1		/* pad with zero */
  #define SIGN	2		/* unsigned/signed long */
  #define PLUS	4		/* show plus */
  #define SPACE	8		/* space if plus */
  #define LEFT	16		/* left justified */
6c6166f52   Mike Frysinger   vsprintf: pull up...
288
289
  #define SMALL	32		/* Must be 32 == 0x20 */
  #define SPECIAL	64		/* 0x */
153d511e3   wdenk   Initial revision
290

046a37bd5   Sonny Rao   Add safe vsnprint...
291
292
293
294
295
296
297
298
299
300
301
302
303
  #ifdef CONFIG_SYS_VSNPRINTF
  /*
   * Macro to add a new character to our output string, but only if it will
   * fit. The macro moves to the next character position in the output string.
   */
  #define ADDCH(str, ch) do { \
  	if ((str) < end) \
  		*(str) = (ch); \
  	++str; \
  	} while (0)
  #else
  #define ADDCH(str, ch)	(*(str)++ = (ch))
  #endif
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
304
  static char *number(char *buf, char *end, u64 num,
046a37bd5   Sonny Rao   Add safe vsnprint...
305
  		int base, int size, int precision, int type)
153d511e3   wdenk   Initial revision
306
  {
6c6166f52   Mike Frysinger   vsprintf: pull up...
307
  	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
308
  	static const char digits[16] = "0123456789ABCDEF";
6c6166f52   Mike Frysinger   vsprintf: pull up...
309
310
311
312
313
  
  	char tmp[66];
  	char sign;
  	char locase;
  	int need_pfx = ((type & SPECIAL) && base != 10);
153d511e3   wdenk   Initial revision
314
  	int i;
6c6166f52   Mike Frysinger   vsprintf: pull up...
315
316
317
  	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
  	 * produces same digits or (maybe lowercased) letters */
  	locase = (type & SMALL);
153d511e3   wdenk   Initial revision
318
319
  	if (type & LEFT)
  		type &= ~ZEROPAD;
153d511e3   wdenk   Initial revision
320
321
  	sign = 0;
  	if (type & SIGN) {
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
322
  		if ((s64) num < 0) {
153d511e3   wdenk   Initial revision
323
  			sign = '-';
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
324
  			num = -(s64) num;
153d511e3   wdenk   Initial revision
325
326
327
328
329
330
331
332
333
  			size--;
  		} else if (type & PLUS) {
  			sign = '+';
  			size--;
  		} else if (type & SPACE) {
  			sign = ' ';
  			size--;
  		}
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
334
335
  	if (need_pfx) {
  		size--;
153d511e3   wdenk   Initial revision
336
  		if (base == 16)
153d511e3   wdenk   Initial revision
337
338
  			size--;
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
339
340
  
  	/* generate full string in tmp[], in reverse order */
153d511e3   wdenk   Initial revision
341
342
  	i = 0;
  	if (num == 0)
6c6166f52   Mike Frysinger   vsprintf: pull up...
343
344
345
346
347
348
349
350
351
  		tmp[i++] = '0';
  	/* Generic code, for any base:
  	else do {
  		tmp[i++] = (digits[do_div(num,base)] | locase);
  	} while (num != 0);
  	*/
  	else if (base != 10) { /* 8 or 16 */
  		int mask = base - 1;
  		int shift = 3;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
352
353
354
  
  		if (base == 16)
  			shift = 4;
6c6166f52   Mike Frysinger   vsprintf: pull up...
355
  		do {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
356
357
  			tmp[i++] = (digits[((unsigned char)num) & mask]
  					| locase);
6c6166f52   Mike Frysinger   vsprintf: pull up...
358
359
360
361
362
363
364
  			num >>= shift;
  		} while (num);
  	} else { /* base 10 */
  		i = put_dec(tmp, num) - tmp;
  	}
  
  	/* printing 100 using %2d gives "100", not "00" */
153d511e3   wdenk   Initial revision
365
366
  	if (i > precision)
  		precision = i;
6c6166f52   Mike Frysinger   vsprintf: pull up...
367
  	/* leading space padding */
153d511e3   wdenk   Initial revision
368
  	size -= precision;
046a37bd5   Sonny Rao   Add safe vsnprint...
369
370
371
372
  	if (!(type & (ZEROPAD + LEFT))) {
  		while (--size >= 0)
  			ADDCH(buf, ' ');
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
373
  	/* sign */
153d511e3   wdenk   Initial revision
374
  	if (sign)
046a37bd5   Sonny Rao   Add safe vsnprint...
375
  		ADDCH(buf, sign);
6c6166f52   Mike Frysinger   vsprintf: pull up...
376
377
  	/* "0x" / "0" prefix */
  	if (need_pfx) {
046a37bd5   Sonny Rao   Add safe vsnprint...
378
  		ADDCH(buf, '0');
6c6166f52   Mike Frysinger   vsprintf: pull up...
379
  		if (base == 16)
046a37bd5   Sonny Rao   Add safe vsnprint...
380
  			ADDCH(buf, 'X' | locase);
6c6166f52   Mike Frysinger   vsprintf: pull up...
381
382
383
384
  	}
  	/* zero or space padding */
  	if (!(type & LEFT)) {
  		char c = (type & ZEROPAD) ? '0' : ' ';
046a37bd5   Sonny Rao   Add safe vsnprint...
385

6c6166f52   Mike Frysinger   vsprintf: pull up...
386
  		while (--size >= 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
387
  			ADDCH(buf, c);
153d511e3   wdenk   Initial revision
388
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
389
390
  	/* hmm even more zero padding? */
  	while (i <= --precision)
046a37bd5   Sonny Rao   Add safe vsnprint...
391
  		ADDCH(buf, '0');
6c6166f52   Mike Frysinger   vsprintf: pull up...
392
393
  	/* actual digits of result */
  	while (--i >= 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
394
  		ADDCH(buf, tmp[i]);
6c6166f52   Mike Frysinger   vsprintf: pull up...
395
396
  	/* trailing space padding */
  	while (--size >= 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
397
  		ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
398
  	return buf;
153d511e3   wdenk   Initial revision
399
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
400
401
  static char *string(char *buf, char *end, char *s, int field_width,
  		int precision, int flags)
6c6166f52   Mike Frysinger   vsprintf: pull up...
402
403
  {
  	int len, i;
153d511e3   wdenk   Initial revision
404

0eb257683   Kim Phillips   lib/vsprintf.c: s...
405
  	if (s == NULL)
6c6166f52   Mike Frysinger   vsprintf: pull up...
406
407
408
409
410
411
  		s = "<NULL>";
  
  	len = strnlen(s, precision);
  
  	if (!(flags & LEFT))
  		while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
412
  			ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
413
  	for (i = 0; i < len; ++i)
046a37bd5   Sonny Rao   Add safe vsnprint...
414
  		ADDCH(buf, *s++);
6c6166f52   Mike Frysinger   vsprintf: pull up...
415
  	while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
416
  		ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
417
418
419
420
  	return buf;
  }
  
  #ifdef CONFIG_CMD_NET
046a37bd5   Sonny Rao   Add safe vsnprint...
421
  static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
422
  				int precision, int flags)
153d511e3   wdenk   Initial revision
423
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
424
425
  	/* (6 * 2 hex digits), 5 colons and trailing zero */
  	char mac_addr[6 * 3];
6c6166f52   Mike Frysinger   vsprintf: pull up...
426
427
428
429
430
431
432
433
434
  	char *p = mac_addr;
  	int i;
  
  	for (i = 0; i < 6; i++) {
  		p = pack_hex_byte(p, addr[i]);
  		if (!(flags & SPECIAL) && i != 5)
  			*p++ = ':';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
435
436
  	return string(buf, end, mac_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
437
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
438
  static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
439
440
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
441
442
  	/* (8 * 4 hex digits), 7 colons and trailing zero */
  	char ip6_addr[8 * 5];
6c6166f52   Mike Frysinger   vsprintf: pull up...
443
444
445
446
447
448
449
450
451
452
  	char *p = ip6_addr;
  	int i;
  
  	for (i = 0; i < 8; i++) {
  		p = pack_hex_byte(p, addr[2 * i]);
  		p = pack_hex_byte(p, addr[2 * i + 1]);
  		if (!(flags & SPECIAL) && i != 7)
  			*p++ = ':';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
453
454
  	return string(buf, end, ip6_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
455
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
456
  static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
457
458
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
459
460
  	/* (4 * 3 decimal digits), 3 dots and trailing zero */
  	char ip4_addr[4 * 4];
6c6166f52   Mike Frysinger   vsprintf: pull up...
461
462
463
464
465
466
467
468
469
470
471
472
473
  	char temp[3];	/* hold each IP quad in reverse order */
  	char *p = ip4_addr;
  	int i, digits;
  
  	for (i = 0; i < 4; i++) {
  		digits = put_dec_trunc(temp, addr[i]) - temp;
  		/* reverse the digits in the quad */
  		while (digits--)
  			*p++ = temp[digits];
  		if (i != 3)
  			*p++ = '.';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
474
475
  	return string(buf, end, ip4_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
476
  }
c40b29568   wdenk   * Patch by Rune T...
477
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
  
  /*
   * Show a '%p' thing.  A kernel extension is that the '%p' is followed
   * by an extra set of alphanumeric characters that are extended format
   * specifiers.
   *
   * Right now we handle:
   *
   * - 'M' For a 6-byte MAC address, it prints the address in the
   *       usual colon-separated hex notation
   * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
   *       decimal for v4 and colon separated network-order 16 bit hex for v6)
   * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
   *       currently the same
   *
   * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
   * function pointers are really function descriptors, which contain a
   * pointer to the real address.
   */
046a37bd5   Sonny Rao   Add safe vsnprint...
497
498
  static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
  		int field_width, int precision, int flags)
6c6166f52   Mike Frysinger   vsprintf: pull up...
499
  {
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
500
501
502
503
504
  	/*
  	 * Being a boot loader, we explicitly allow pointers to
  	 * (physical) address null.
  	 */
  #if 0
6c6166f52   Mike Frysinger   vsprintf: pull up...
505
  	if (!ptr)
046a37bd5   Sonny Rao   Add safe vsnprint...
506
507
  		return string(buf, end, "(null)", field_width, precision,
  			      flags);
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
508
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
509
510
511
512
513
514
515
  
  #ifdef CONFIG_CMD_NET
  	switch (*fmt) {
  	case 'm':
  		flags |= SPECIAL;
  		/* Fallthrough */
  	case 'M':
046a37bd5   Sonny Rao   Add safe vsnprint...
516
517
  		return mac_address_string(buf, end, ptr, field_width,
  					  precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
518
519
520
521
522
  	case 'i':
  		flags |= SPECIAL;
  		/* Fallthrough */
  	case 'I':
  		if (fmt[1] == '6')
046a37bd5   Sonny Rao   Add safe vsnprint...
523
524
  			return ip6_addr_string(buf, end, ptr, field_width,
  					       precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
525
  		if (fmt[1] == '4')
046a37bd5   Sonny Rao   Add safe vsnprint...
526
527
  			return ip4_addr_string(buf, end, ptr, field_width,
  					       precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
528
529
530
531
532
533
534
535
536
  		flags &= ~SPECIAL;
  		break;
  	}
  #endif
  	flags |= SMALL;
  	if (field_width == -1) {
  		field_width = 2*sizeof(void *);
  		flags |= ZEROPAD;
  	}
046a37bd5   Sonny Rao   Add safe vsnprint...
537
538
  	return number(buf, end, (unsigned long)ptr, 16, field_width,
  		      precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
539
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
540
541
  static int vsnprintf_internal(char *buf, size_t size, const char *fmt,
  			      va_list args)
6c6166f52   Mike Frysinger   vsprintf: pull up...
542
  {
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
543
  	u64 num;
6c6166f52   Mike Frysinger   vsprintf: pull up...
544
545
  	int base;
  	char *str;
153d511e3   wdenk   Initial revision
546
547
548
549
550
551
  
  	int flags;		/* flags to number() */
  
  	int field_width;	/* width of output field */
  	int precision;		/* min. # of digits for integers; max
  				   number of chars for from string */
6c6166f52   Mike Frysinger   vsprintf: pull up...
552
553
554
555
  	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
  				/* 'z' support added 23/7/1999 S.H.    */
  				/* 'z' changed to 'Z' --davidm 1/25/99 */
  				/* 't' added for ptrdiff_t */
046a37bd5   Sonny Rao   Add safe vsnprint...
556
  	char *end = buf + size;
6c6166f52   Mike Frysinger   vsprintf: pull up...
557

046a37bd5   Sonny Rao   Add safe vsnprint...
558
559
560
561
562
563
564
  #ifdef CONFIG_SYS_VSNPRINTF
  	/* Make sure end is always >= buf - do we want this in U-Boot? */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
  	}
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
565
  	str = buf;
153d511e3   wdenk   Initial revision
566

6c6166f52   Mike Frysinger   vsprintf: pull up...
567
  	for (; *fmt ; ++fmt) {
153d511e3   wdenk   Initial revision
568
  		if (*fmt != '%') {
046a37bd5   Sonny Rao   Add safe vsnprint...
569
  			ADDCH(str, *fmt);
153d511e3   wdenk   Initial revision
570
571
572
573
574
  			continue;
  		}
  
  		/* process flags */
  		flags = 0;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
575
  repeat:
153d511e3   wdenk   Initial revision
576
577
  			++fmt;		/* this also skips first '%' */
  			switch (*fmt) {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  			case '-':
  				flags |= LEFT;
  				goto repeat;
  			case '+':
  				flags |= PLUS;
  				goto repeat;
  			case ' ':
  				flags |= SPACE;
  				goto repeat;
  			case '#':
  				flags |= SPECIAL;
  				goto repeat;
  			case '0':
  				flags |= ZEROPAD;
  				goto repeat;
6c6166f52   Mike Frysinger   vsprintf: pull up...
593
  			}
153d511e3   wdenk   Initial revision
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
  
  		/* get field width */
  		field_width = -1;
  		if (is_digit(*fmt))
  			field_width = skip_atoi(&fmt);
  		else if (*fmt == '*') {
  			++fmt;
  			/* it's the next argument */
  			field_width = va_arg(args, int);
  			if (field_width < 0) {
  				field_width = -field_width;
  				flags |= LEFT;
  			}
  		}
  
  		/* get the precision */
  		precision = -1;
  		if (*fmt == '.') {
  			++fmt;
  			if (is_digit(*fmt))
  				precision = skip_atoi(&fmt);
  			else if (*fmt == '*') {
  				++fmt;
  				/* it's the next argument */
  				precision = va_arg(args, int);
  			}
  			if (precision < 0)
  				precision = 0;
  		}
  
  		/* get the conversion qualifier */
  		qualifier = -1;
f354b73e1   Jean-Christophe PLAGNIOL-VILLARD   vsprintf: add z a...
626
  		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
6c6166f52   Mike Frysinger   vsprintf: pull up...
627
  		    *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
153d511e3   wdenk   Initial revision
628
  			qualifier = *fmt;
6c6166f52   Mike Frysinger   vsprintf: pull up...
629
630
631
  			++fmt;
  			if (qualifier == 'l' && *fmt == 'l') {
  				qualifier = 'L';
bf0529397   James Yang   Fix 64-bit vsprintf.
632
633
  				++fmt;
  			}
153d511e3   wdenk   Initial revision
634
635
636
637
638
639
640
  		}
  
  		/* default base */
  		base = 10;
  
  		switch (*fmt) {
  		case 'c':
046a37bd5   Sonny Rao   Add safe vsnprint...
641
  			if (!(flags & LEFT)) {
153d511e3   wdenk   Initial revision
642
  				while (--field_width > 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
643
644
645
  					ADDCH(str, ' ');
  			}
  			ADDCH(str, (unsigned char) va_arg(args, int));
153d511e3   wdenk   Initial revision
646
  			while (--field_width > 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
647
  				ADDCH(str, ' ');
153d511e3   wdenk   Initial revision
648
649
650
  			continue;
  
  		case 's':
046a37bd5   Sonny Rao   Add safe vsnprint...
651
652
  			str = string(str, end, va_arg(args, char *),
  				     field_width, precision, flags);
153d511e3   wdenk   Initial revision
653
654
655
  			continue;
  
  		case 'p':
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
656
  			str = pointer(fmt + 1, str, end,
6c6166f52   Mike Frysinger   vsprintf: pull up...
657
658
659
660
661
  					va_arg(args, void *),
  					field_width, precision, flags);
  			/* Skip all alphanumeric pointer suffixes */
  			while (isalnum(fmt[1]))
  				fmt++;
153d511e3   wdenk   Initial revision
662
  			continue;
153d511e3   wdenk   Initial revision
663
664
  		case 'n':
  			if (qualifier == 'l') {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
665
  				long *ip = va_arg(args, long *);
153d511e3   wdenk   Initial revision
666
667
  				*ip = (str - buf);
  			} else {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
668
  				int *ip = va_arg(args, int *);
153d511e3   wdenk   Initial revision
669
670
671
672
673
  				*ip = (str - buf);
  			}
  			continue;
  
  		case '%':
046a37bd5   Sonny Rao   Add safe vsnprint...
674
  			ADDCH(str, '%');
153d511e3   wdenk   Initial revision
675
676
677
678
679
680
  			continue;
  
  		/* integer number formats - set up the flags and "break" */
  		case 'o':
  			base = 8;
  			break;
153d511e3   wdenk   Initial revision
681
  		case 'x':
6c6166f52   Mike Frysinger   vsprintf: pull up...
682
683
  			flags |= SMALL;
  		case 'X':
153d511e3   wdenk   Initial revision
684
685
686
687
688
689
690
691
692
693
  			base = 16;
  			break;
  
  		case 'd':
  		case 'i':
  			flags |= SIGN;
  		case 'u':
  			break;
  
  		default:
046a37bd5   Sonny Rao   Add safe vsnprint...
694
  			ADDCH(str, '%');
153d511e3   wdenk   Initial revision
695
  			if (*fmt)
046a37bd5   Sonny Rao   Add safe vsnprint...
696
  				ADDCH(str, *fmt);
153d511e3   wdenk   Initial revision
697
698
699
700
  			else
  				--fmt;
  			continue;
  		}
6c6166f52   Mike Frysinger   vsprintf: pull up...
701
  		if (qualifier == 'L')  /* "quad" for 64 bit variables */
c40b29568   wdenk   * Patch by Rune T...
702
  			num = va_arg(args, unsigned long long);
4b142febf   Heiko Schocher   common: delete CO...
703
  		else if (qualifier == 'l') {
153d511e3   wdenk   Initial revision
704
  			num = va_arg(args, unsigned long);
6c6166f52   Mike Frysinger   vsprintf: pull up...
705
706
  			if (flags & SIGN)
  				num = (signed long) num;
f354b73e1   Jean-Christophe PLAGNIOL-VILLARD   vsprintf: add z a...
707
708
709
710
711
  		} else if (qualifier == 'Z' || qualifier == 'z') {
  			num = va_arg(args, size_t);
  		} else if (qualifier == 't') {
  			num = va_arg(args, ptrdiff_t);
  		} else if (qualifier == 'h') {
153d511e3   wdenk   Initial revision
712
713
  			num = (unsigned short) va_arg(args, int);
  			if (flags & SIGN)
6c6166f52   Mike Frysinger   vsprintf: pull up...
714
715
  				num = (signed short) num;
  		} else {
153d511e3   wdenk   Initial revision
716
  			num = va_arg(args, unsigned int);
6c6166f52   Mike Frysinger   vsprintf: pull up...
717
718
719
  			if (flags & SIGN)
  				num = (signed int) num;
  		}
046a37bd5   Sonny Rao   Add safe vsnprint...
720
721
722
723
724
725
726
727
728
  		str = number(str, end, num, base, field_width, precision,
  			     flags);
  	}
  
  #ifdef CONFIG_SYS_VSNPRINTF
  	if (size > 0) {
  		ADDCH(str, '\0');
  		if (str > end)
  			end[-1] = '\0';
686f60f51   Darwin Rambo   lib: fix return c...
729
  		--str;
153d511e3   wdenk   Initial revision
730
  	}
046a37bd5   Sonny Rao   Add safe vsnprint...
731
  #else
153d511e3   wdenk   Initial revision
732
  	*str = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
733
734
  #endif
  	/* the trailing null byte doesn't count towards the total */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
735
  	return str - buf;
153d511e3   wdenk   Initial revision
736
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
737
738
739
740
741
742
  #ifdef CONFIG_SYS_VSNPRINTF
  int vsnprintf(char *buf, size_t size, const char *fmt,
  			      va_list args)
  {
  	return vsnprintf_internal(buf, size, fmt, args);
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
743
744
745
746
747
748
749
750
751
752
753
754
  int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
  {
  	int i;
  
  	i = vsnprintf(buf, size, fmt, args);
  
  	if (likely(i < size))
  		return i;
  	if (size != 0)
  		return size - 1;
  	return 0;
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
755
756
757
758
759
760
761
762
763
764
765
  int snprintf(char *buf, size_t size, const char *fmt, ...)
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
  	i = vsnprintf(buf, size, fmt, args);
  	va_end(args);
  
  	return i;
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
  int scnprintf(char *buf, size_t size, const char *fmt, ...)
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
  	i = vscnprintf(buf, size, fmt, args);
  	va_end(args);
  
  	return i;
  }
  #endif /* CONFIG_SYS_VSNPRINT */
  
  /**
   * Format a string and place it in a buffer (va_list version)
   *
   * @param buf	The buffer to place the result into
   * @param fmt	The format string to use
   * @param args	Arguments for the format string
   *
   * The function returns the number of characters written
   * into @buf. Use vsnprintf() or vscnprintf() in order to avoid
   * buffer overflows.
   *
   * If you're not already dealing with a va_list consider using sprintf().
   */
  int vsprintf(char *buf, const char *fmt, va_list args)
  {
  	return vsnprintf_internal(buf, INT_MAX, fmt, args);
  }
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
796
  int sprintf(char *buf, const char *fmt, ...)
153d511e3   wdenk   Initial revision
797
798
799
800
801
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
802
  	i = vsprintf(buf, fmt, args);
153d511e3   wdenk   Initial revision
803
804
805
806
807
808
  	va_end(args);
  	return i;
  }
  
  void panic(const char *fmt, ...)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
809
  	va_list args;
153d511e3   wdenk   Initial revision
810
  	va_start(args, fmt);
6dd652fa4   wdenk   Patches by Murray...
811
  	vprintf(fmt, args);
153d511e3   wdenk   Initial revision
812
813
814
  	putc('
  ');
  	va_end(args);
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
815
  #if defined(CONFIG_PANIC_HANG)
153d511e3   wdenk   Initial revision
816
817
  	hang();
  #else
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
818
819
  	udelay(100000);	/* allow messages to go out */
  	do_reset(NULL, 0, 0, NULL);
153d511e3   wdenk   Initial revision
820
  #endif
40e018815   Heiko Schocher   panic: remove war...
821
822
  	while (1)
  		;
153d511e3   wdenk   Initial revision
823
  }
21726a7af   Simon Glass   Add assert() for ...
824
825
826
827
828
829
830
831
  
  void __assert_fail(const char *assertion, const char *file, unsigned line,
  		   const char *function)
  {
  	/* This will not return */
  	panic("%s:%u: %s: Assertion `%s' failed.", file, line, function,
  	      assertion);
  }
3cce8a549   Simon Glass   Move simple_itoa ...
832
833
834
835
836
837
838
839
840
841
842
843
844
845
  
  char *simple_itoa(ulong i)
  {
  	/* 21 digits plus null terminator, good for 64-bit or smaller ints */
  	static char local[22];
  	char *p = &local[21];
  
  	*p-- = '\0';
  	do {
  		*p-- = '0' + i % 10;
  		i /= 10;
  	} while (i > 0);
  	return p + 1;
  }
b8bcaa3ad   Simon Glass   Add function to p...
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
  
  /* We don't seem to have %'d in U-Boot */
  void print_grouped_ull(unsigned long long int_val, int digits)
  {
  	char str[21], *s;
  	int grab = 3;
  
  	digits = (digits + 2) / 3;
  	sprintf(str, "%*llu", digits * 3, int_val);
  	for (s = str; *s; s += grab) {
  		if (s != str)
  			putc(s[-1] != ' ' ? ',' : ' ');
  		printf("%.*s", grab, s);
  		grab = 3;
  	}
  }