Blame view

lib/vsprintf.c 19.1 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
   */
153d511e3   wdenk   Initial revision
13
  #include <common.h>
274325c50   Rob Clark   vsprintf.c: add U...
14
  #include <charset.h>
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
15
16
  #include <efi_loader.h>
  #include <div64.h>
22ada0c8e   Rob Clark   vsprintf.c: add G...
17
  #include <uuid.h>
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
18
19
20
21
22
  #include <stdarg.h>
  #include <linux/ctype.h>
  #include <linux/err.h>
  #include <linux/types.h>
  #include <linux/string.h>
153d511e3   wdenk   Initial revision
23

479105065   Dirk Behme   Use do_div from d...
24
  #define noinline __attribute__((noinline))
153d511e3   wdenk   Initial revision
25
26
27
28
29
  /* 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: ...
30
  	int i = 0;
153d511e3   wdenk   Initial revision
31
32
  
  	while (is_digit(**s))
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
33
  		i = i * 10 + *((*s)++) - '0';
153d511e3   wdenk   Initial revision
34
35
  	return i;
  }
6c6166f52   Mike Frysinger   vsprintf: pull up...
36
37
38
39
40
41
42
43
44
45
  /* 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: ...
46
  static char *put_dec_trunc(char *buf, unsigned q)
6c6166f52   Mike Frysinger   vsprintf: pull up...
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
  {
  	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: ...
75
  					*buf++ = q + '0'; /* most sign. digit */
6c6166f52   Mike Frysinger   vsprintf: pull up...
76
77
78
79
80
81
  			}
  		}
  	}
  	return buf;
  }
  /* Same with if's removed. Always emits five digits */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
82
  static char *put_dec_full(char *buf, unsigned q)
6c6166f52   Mike Frysinger   vsprintf: pull up...
83
84
85
86
87
88
89
  {
  	/* 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,...
90
91
92
93
94
95
96
97
98
  	/*
  	 * 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...
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
  
  	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 */
6bf672596   Simon Glass   Use uint64_t inst...
123
  static noinline char *put_dec(char *buf, uint64_t num)
6c6166f52   Mike Frysinger   vsprintf: pull up...
124
125
126
127
128
129
130
131
132
  {
  	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
133
134
135
136
137
  #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...
138
139
  #define SMALL	32		/* Must be 32 == 0x20 */
  #define SPECIAL	64		/* 0x */
153d511e3   wdenk   Initial revision
140

046a37bd5   Sonny Rao   Add safe vsnprint...
141
142
143
144
145
146
147
148
149
  /*
   * 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)
046a37bd5   Sonny Rao   Add safe vsnprint...
150

7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
151
  static char *number(char *buf, char *end, u64 num,
046a37bd5   Sonny Rao   Add safe vsnprint...
152
  		int base, int size, int precision, int type)
153d511e3   wdenk   Initial revision
153
  {
6c6166f52   Mike Frysinger   vsprintf: pull up...
154
  	/* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
155
  	static const char digits[16] = "0123456789ABCDEF";
6c6166f52   Mike Frysinger   vsprintf: pull up...
156
157
158
159
160
  
  	char tmp[66];
  	char sign;
  	char locase;
  	int need_pfx = ((type & SPECIAL) && base != 10);
153d511e3   wdenk   Initial revision
161
  	int i;
6c6166f52   Mike Frysinger   vsprintf: pull up...
162
163
164
  	/* locase = 0 or 0x20. ORing digits or letters with 'locase'
  	 * produces same digits or (maybe lowercased) letters */
  	locase = (type & SMALL);
153d511e3   wdenk   Initial revision
165
166
  	if (type & LEFT)
  		type &= ~ZEROPAD;
153d511e3   wdenk   Initial revision
167
168
  	sign = 0;
  	if (type & SIGN) {
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
169
  		if ((s64) num < 0) {
153d511e3   wdenk   Initial revision
170
  			sign = '-';
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
171
  			num = -(s64) num;
153d511e3   wdenk   Initial revision
172
173
174
175
176
177
178
179
180
  			size--;
  		} else if (type & PLUS) {
  			sign = '+';
  			size--;
  		} else if (type & SPACE) {
  			sign = ' ';
  			size--;
  		}
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
181
182
  	if (need_pfx) {
  		size--;
153d511e3   wdenk   Initial revision
183
  		if (base == 16)
153d511e3   wdenk   Initial revision
184
185
  			size--;
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
186
187
  
  	/* generate full string in tmp[], in reverse order */
153d511e3   wdenk   Initial revision
188
189
  	i = 0;
  	if (num == 0)
6c6166f52   Mike Frysinger   vsprintf: pull up...
190
191
192
193
194
195
196
197
198
  		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: ...
199
200
201
  
  		if (base == 16)
  			shift = 4;
6c6166f52   Mike Frysinger   vsprintf: pull up...
202
  		do {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
203
204
  			tmp[i++] = (digits[((unsigned char)num) & mask]
  					| locase);
6c6166f52   Mike Frysinger   vsprintf: pull up...
205
206
207
208
209
210
211
  			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
212
213
  	if (i > precision)
  		precision = i;
6c6166f52   Mike Frysinger   vsprintf: pull up...
214
  	/* leading space padding */
153d511e3   wdenk   Initial revision
215
  	size -= precision;
046a37bd5   Sonny Rao   Add safe vsnprint...
216
217
218
219
  	if (!(type & (ZEROPAD + LEFT))) {
  		while (--size >= 0)
  			ADDCH(buf, ' ');
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
220
  	/* sign */
153d511e3   wdenk   Initial revision
221
  	if (sign)
046a37bd5   Sonny Rao   Add safe vsnprint...
222
  		ADDCH(buf, sign);
6c6166f52   Mike Frysinger   vsprintf: pull up...
223
224
  	/* "0x" / "0" prefix */
  	if (need_pfx) {
046a37bd5   Sonny Rao   Add safe vsnprint...
225
  		ADDCH(buf, '0');
6c6166f52   Mike Frysinger   vsprintf: pull up...
226
  		if (base == 16)
046a37bd5   Sonny Rao   Add safe vsnprint...
227
  			ADDCH(buf, 'X' | locase);
6c6166f52   Mike Frysinger   vsprintf: pull up...
228
229
230
231
  	}
  	/* zero or space padding */
  	if (!(type & LEFT)) {
  		char c = (type & ZEROPAD) ? '0' : ' ';
046a37bd5   Sonny Rao   Add safe vsnprint...
232

6c6166f52   Mike Frysinger   vsprintf: pull up...
233
  		while (--size >= 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
234
  			ADDCH(buf, c);
153d511e3   wdenk   Initial revision
235
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
236
237
  	/* hmm even more zero padding? */
  	while (i <= --precision)
046a37bd5   Sonny Rao   Add safe vsnprint...
238
  		ADDCH(buf, '0');
6c6166f52   Mike Frysinger   vsprintf: pull up...
239
240
  	/* actual digits of result */
  	while (--i >= 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
241
  		ADDCH(buf, tmp[i]);
6c6166f52   Mike Frysinger   vsprintf: pull up...
242
243
  	/* trailing space padding */
  	while (--size >= 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
244
  		ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
245
  	return buf;
153d511e3   wdenk   Initial revision
246
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
247
248
  static char *string(char *buf, char *end, char *s, int field_width,
  		int precision, int flags)
6c6166f52   Mike Frysinger   vsprintf: pull up...
249
250
  {
  	int len, i;
153d511e3   wdenk   Initial revision
251

0eb257683   Kim Phillips   lib/vsprintf.c: s...
252
  	if (s == NULL)
6c6166f52   Mike Frysinger   vsprintf: pull up...
253
254
255
256
257
258
  		s = "<NULL>";
  
  	len = strnlen(s, precision);
  
  	if (!(flags & LEFT))
  		while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
259
  			ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
260
  	for (i = 0; i < len; ++i)
046a37bd5   Sonny Rao   Add safe vsnprint...
261
  		ADDCH(buf, *s++);
6c6166f52   Mike Frysinger   vsprintf: pull up...
262
  	while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
263
  		ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
264
265
  	return buf;
  }
274325c50   Rob Clark   vsprintf.c: add U...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
  static char *string16(char *buf, char *end, u16 *s, int field_width,
  		int precision, int flags)
  {
  	u16 *str = s ? s : L"<NULL>";
  	int utf16_len = utf16_strnlen(str, precision);
  	u8 utf8[utf16_len * MAX_UTF8_PER_UTF16];
  	int utf8_len, i;
  
  	utf8_len = utf16_to_utf8(utf8, str, utf16_len) - utf8;
  
  	if (!(flags & LEFT))
  		while (utf8_len < field_width--)
  			ADDCH(buf, ' ');
  	for (i = 0; i < utf8_len; ++i)
  		ADDCH(buf, utf8[i]);
  	while (utf8_len < field_width--)
  		ADDCH(buf, ' ');
  	return buf;
  }
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
285
286
287
288
289
290
  #if defined(CONFIG_EFI_LOADER) && \
  	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
  static char *device_path_string(char *buf, char *end, void *dp, int field_width,
  				int precision, int flags)
  {
  	u16 *str;
5f1ce1d4c   Heinrich Schuchardt   vsprintf.c: corre...
291
  	/* If dp == NULL output the string '<NULL>' */
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
292
  	if (!dp)
5f1ce1d4c   Heinrich Schuchardt   vsprintf.c: corre...
293
  		return string16(buf, end, dp, field_width, precision, flags);
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
294
295
296
297
298
299
300
301
302
303
  
  	str = efi_dp_str((struct efi_device_path *)dp);
  	if (!str)
  		return ERR_PTR(-ENOMEM);
  
  	buf = string16(buf, end, str, field_width, precision, flags);
  	efi_free_pool(str);
  	return buf;
  }
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
304
  #ifdef CONFIG_CMD_NET
d7b2d9df0   Jeroen Hofstee   lib:vsprintf: red...
305
306
307
308
309
310
311
312
313
314
  static const char hex_asc[] = "0123456789abcdef";
  #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;
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
315
  static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
316
  				int precision, int flags)
153d511e3   wdenk   Initial revision
317
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
318
319
  	/* (6 * 2 hex digits), 5 colons and trailing zero */
  	char mac_addr[6 * 3];
6c6166f52   Mike Frysinger   vsprintf: pull up...
320
321
322
323
324
325
326
327
328
  	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...
329
330
  	return string(buf, end, mac_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
331
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
332
  static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
333
334
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
335
336
  	/* (8 * 4 hex digits), 7 colons and trailing zero */
  	char ip6_addr[8 * 5];
6c6166f52   Mike Frysinger   vsprintf: pull up...
337
338
339
340
341
342
343
344
345
346
  	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...
347
348
  	return string(buf, end, ip6_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
349
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
350
  static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
351
352
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
353
354
  	/* (4 * 3 decimal digits), 3 dots and trailing zero */
  	char ip4_addr[4 * 4];
6c6166f52   Mike Frysinger   vsprintf: pull up...
355
356
357
358
359
360
361
362
363
364
365
366
367
  	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...
368
369
  	return string(buf, end, ip4_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
370
  }
c40b29568   wdenk   * Patch by Rune T...
371
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
372

22ada0c8e   Rob Clark   vsprintf.c: add G...
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
  #ifdef CONFIG_LIB_UUID
  /*
   * This works (roughly) the same way as linux's, but we currently always
   * print lower-case (ie. we just keep %pUB and %pUL for compat with linux),
   * mostly just because that is what uuid_bin_to_str() supports.
   *
   *   %pUb:   01020304-0506-0708-090a-0b0c0d0e0f10
   *   %pUl:   04030201-0605-0807-090a-0b0c0d0e0f10
   */
  static char *uuid_string(char *buf, char *end, u8 *addr, int field_width,
  			 int precision, int flags, const char *fmt)
  {
  	char uuid[UUID_STR_LEN + 1];
  	int str_format = UUID_STR_FORMAT_STD;
  
  	switch (*(++fmt)) {
  	case 'L':
  	case 'l':
  		str_format = UUID_STR_FORMAT_GUID;
  		break;
  	case 'B':
  	case 'b':
  		/* this is the default */
  		break;
  	default:
  		break;
  	}
  
  	uuid_bin_to_str(addr, uuid, str_format);
  
  	return string(buf, end, uuid, field_width, precision, flags);
  }
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
  /*
   * 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...
424
425
  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...
426
  {
1eebd14b7   Thierry Reding   vsprintf: Add mod...
427
  	u64 num = (uintptr_t)ptr;
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
428
429
430
431
432
  	/*
  	 * Being a boot loader, we explicitly allow pointers to
  	 * (physical) address null.
  	 */
  #if 0
6c6166f52   Mike Frysinger   vsprintf: pull up...
433
  	if (!ptr)
046a37bd5   Sonny Rao   Add safe vsnprint...
434
435
  		return string(buf, end, "(null)", field_width, precision,
  			      flags);
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
436
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
437

6c6166f52   Mike Frysinger   vsprintf: pull up...
438
  	switch (*fmt) {
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
439
440
441
442
443
444
  #if defined(CONFIG_EFI_LOADER) && \
  	!defined(CONFIG_SPL_BUILD) && !defined(API_BUILD)
  	case 'D':
  		return device_path_string(buf, end, ptr, field_width,
  					  precision, flags);
  #endif
22ada0c8e   Rob Clark   vsprintf.c: add G...
445
  #ifdef CONFIG_CMD_NET
1eebd14b7   Thierry Reding   vsprintf: Add mod...
446
447
448
449
450
451
452
453
454
455
456
  	case 'a':
  		flags |= SPECIAL | ZEROPAD;
  
  		switch (fmt[1]) {
  		case 'p':
  		default:
  			field_width = sizeof(phys_addr_t) * 2 + 2;
  			num = *(phys_addr_t *)ptr;
  			break;
  		}
  		break;
6c6166f52   Mike Frysinger   vsprintf: pull up...
457
458
459
460
  	case 'm':
  		flags |= SPECIAL;
  		/* Fallthrough */
  	case 'M':
046a37bd5   Sonny Rao   Add safe vsnprint...
461
462
  		return mac_address_string(buf, end, ptr, field_width,
  					  precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
463
464
465
466
467
  	case 'i':
  		flags |= SPECIAL;
  		/* Fallthrough */
  	case 'I':
  		if (fmt[1] == '6')
046a37bd5   Sonny Rao   Add safe vsnprint...
468
469
  			return ip6_addr_string(buf, end, ptr, field_width,
  					       precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
470
  		if (fmt[1] == '4')
046a37bd5   Sonny Rao   Add safe vsnprint...
471
472
  			return ip4_addr_string(buf, end, ptr, field_width,
  					       precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
473
474
  		flags &= ~SPECIAL;
  		break;
6c6166f52   Mike Frysinger   vsprintf: pull up...
475
  #endif
22ada0c8e   Rob Clark   vsprintf.c: add G...
476
477
478
479
480
481
482
483
  #ifdef CONFIG_LIB_UUID
  	case 'U':
  		return uuid_string(buf, end, ptr, field_width, precision,
  				   flags, fmt);
  #endif
  	default:
  		break;
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
484
485
486
487
488
  	flags |= SMALL;
  	if (field_width == -1) {
  		field_width = 2*sizeof(void *);
  		flags |= ZEROPAD;
  	}
1eebd14b7   Thierry Reding   vsprintf: Add mod...
489
  	return number(buf, end, num, 16, field_width, precision, flags);
6c6166f52   Mike Frysinger   vsprintf: pull up...
490
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
491
492
  static int vsnprintf_internal(char *buf, size_t size, const char *fmt,
  			      va_list args)
6c6166f52   Mike Frysinger   vsprintf: pull up...
493
  {
7b64f66c5   Daniel Schwierzeck   lib: vsprintf.c: ...
494
  	u64 num;
6c6166f52   Mike Frysinger   vsprintf: pull up...
495
496
  	int base;
  	char *str;
153d511e3   wdenk   Initial revision
497
498
499
500
501
502
  
  	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...
503
504
505
506
  	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...
507
  	char *end = buf + size;
6c6166f52   Mike Frysinger   vsprintf: pull up...
508

046a37bd5   Sonny Rao   Add safe vsnprint...
509
510
511
512
513
  	/* Make sure end is always >= buf - do we want this in U-Boot? */
  	if (end < buf) {
  		end = ((void *)-1);
  		size = end - buf;
  	}
6c6166f52   Mike Frysinger   vsprintf: pull up...
514
  	str = buf;
153d511e3   wdenk   Initial revision
515

6c6166f52   Mike Frysinger   vsprintf: pull up...
516
  	for (; *fmt ; ++fmt) {
153d511e3   wdenk   Initial revision
517
  		if (*fmt != '%') {
046a37bd5   Sonny Rao   Add safe vsnprint...
518
  			ADDCH(str, *fmt);
153d511e3   wdenk   Initial revision
519
520
521
522
523
  			continue;
  		}
  
  		/* process flags */
  		flags = 0;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
524
  repeat:
153d511e3   wdenk   Initial revision
525
526
  			++fmt;		/* this also skips first '%' */
  			switch (*fmt) {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
  			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...
542
  			}
153d511e3   wdenk   Initial revision
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
  
  		/* 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...
575
  		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
6c6166f52   Mike Frysinger   vsprintf: pull up...
576
  		    *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
153d511e3   wdenk   Initial revision
577
  			qualifier = *fmt;
6c6166f52   Mike Frysinger   vsprintf: pull up...
578
579
580
  			++fmt;
  			if (qualifier == 'l' && *fmt == 'l') {
  				qualifier = 'L';
bf0529397   James Yang   Fix 64-bit vsprintf.
581
582
  				++fmt;
  			}
153d511e3   wdenk   Initial revision
583
584
585
586
587
588
589
  		}
  
  		/* default base */
  		base = 10;
  
  		switch (*fmt) {
  		case 'c':
046a37bd5   Sonny Rao   Add safe vsnprint...
590
  			if (!(flags & LEFT)) {
153d511e3   wdenk   Initial revision
591
  				while (--field_width > 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
592
593
594
  					ADDCH(str, ' ');
  			}
  			ADDCH(str, (unsigned char) va_arg(args, int));
153d511e3   wdenk   Initial revision
595
  			while (--field_width > 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
596
  				ADDCH(str, ' ');
153d511e3   wdenk   Initial revision
597
598
599
  			continue;
  
  		case 's':
274325c50   Rob Clark   vsprintf.c: add U...
600
601
602
603
604
605
606
  			if (qualifier == 'l' && !IS_ENABLED(CONFIG_SPL_BUILD)) {
  				str = string16(str, end, va_arg(args, u16 *),
  					       field_width, precision, flags);
  			} else {
  				str = string(str, end, va_arg(args, char *),
  					     field_width, precision, flags);
  			}
153d511e3   wdenk   Initial revision
607
608
609
  			continue;
  
  		case 'p':
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
610
  			str = pointer(fmt + 1, str, end,
6c6166f52   Mike Frysinger   vsprintf: pull up...
611
612
  					va_arg(args, void *),
  					field_width, precision, flags);
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
613
614
  			if (IS_ERR(str))
  				return PTR_ERR(str);
6c6166f52   Mike Frysinger   vsprintf: pull up...
615
616
617
  			/* Skip all alphanumeric pointer suffixes */
  			while (isalnum(fmt[1]))
  				fmt++;
153d511e3   wdenk   Initial revision
618
  			continue;
153d511e3   wdenk   Initial revision
619
620
  		case 'n':
  			if (qualifier == 'l') {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
621
  				long *ip = va_arg(args, long *);
153d511e3   wdenk   Initial revision
622
623
  				*ip = (str - buf);
  			} else {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
624
  				int *ip = va_arg(args, int *);
153d511e3   wdenk   Initial revision
625
626
627
628
629
  				*ip = (str - buf);
  			}
  			continue;
  
  		case '%':
046a37bd5   Sonny Rao   Add safe vsnprint...
630
  			ADDCH(str, '%');
153d511e3   wdenk   Initial revision
631
632
633
634
635
636
  			continue;
  
  		/* integer number formats - set up the flags and "break" */
  		case 'o':
  			base = 8;
  			break;
153d511e3   wdenk   Initial revision
637
  		case 'x':
6c6166f52   Mike Frysinger   vsprintf: pull up...
638
639
  			flags |= SMALL;
  		case 'X':
153d511e3   wdenk   Initial revision
640
641
642
643
644
645
646
647
648
649
  			base = 16;
  			break;
  
  		case 'd':
  		case 'i':
  			flags |= SIGN;
  		case 'u':
  			break;
  
  		default:
046a37bd5   Sonny Rao   Add safe vsnprint...
650
  			ADDCH(str, '%');
153d511e3   wdenk   Initial revision
651
  			if (*fmt)
046a37bd5   Sonny Rao   Add safe vsnprint...
652
  				ADDCH(str, *fmt);
153d511e3   wdenk   Initial revision
653
654
655
656
  			else
  				--fmt;
  			continue;
  		}
6c6166f52   Mike Frysinger   vsprintf: pull up...
657
  		if (qualifier == 'L')  /* "quad" for 64 bit variables */
c40b29568   wdenk   * Patch by Rune T...
658
  			num = va_arg(args, unsigned long long);
4b142febf   Heiko Schocher   common: delete CO...
659
  		else if (qualifier == 'l') {
153d511e3   wdenk   Initial revision
660
  			num = va_arg(args, unsigned long);
6c6166f52   Mike Frysinger   vsprintf: pull up...
661
662
  			if (flags & SIGN)
  				num = (signed long) num;
f354b73e1   Jean-Christophe PLAGNIOL-VILLARD   vsprintf: add z a...
663
664
665
666
667
  		} 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
668
669
  			num = (unsigned short) va_arg(args, int);
  			if (flags & SIGN)
6c6166f52   Mike Frysinger   vsprintf: pull up...
670
671
  				num = (signed short) num;
  		} else {
153d511e3   wdenk   Initial revision
672
  			num = va_arg(args, unsigned int);
6c6166f52   Mike Frysinger   vsprintf: pull up...
673
674
675
  			if (flags & SIGN)
  				num = (signed int) num;
  		}
046a37bd5   Sonny Rao   Add safe vsnprint...
676
677
678
  		str = number(str, end, num, base, field_width, precision,
  			     flags);
  	}
046a37bd5   Sonny Rao   Add safe vsnprint...
679
680
681
682
  	if (size > 0) {
  		ADDCH(str, '\0');
  		if (str > end)
  			end[-1] = '\0';
686f60f51   Darwin Rambo   lib: fix return c...
683
  		--str;
153d511e3   wdenk   Initial revision
684
  	}
046a37bd5   Sonny Rao   Add safe vsnprint...
685
  	/* the trailing null byte doesn't count towards the total */
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
686
  	return str - buf;
153d511e3   wdenk   Initial revision
687
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
688
689
690
691
692
  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...
693
694
695
696
697
698
699
700
701
702
703
704
  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...
705
706
707
708
709
710
711
712
713
714
715
  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...
716
717
718
719
720
721
722
723
724
725
726
  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;
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
  
  /**
   * 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: ...
745
  int sprintf(char *buf, const char *fmt, ...)
153d511e3   wdenk   Initial revision
746
747
748
749
750
  {
  	va_list args;
  	int i;
  
  	va_start(args, fmt);
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
751
  	i = vsprintf(buf, fmt, args);
153d511e3   wdenk   Initial revision
752
753
754
  	va_end(args);
  	return i;
  }
7d9cde103   Stefan Roese   lib/tiny-printf.c...
755
756
757
758
759
760
761
762
763
764
765
766
767
768
  int printf(const char *fmt, ...)
  {
  	va_list args;
  	uint i;
  	char printbuffer[CONFIG_SYS_PBSIZE];
  
  	va_start(args, fmt);
  
  	/*
  	 * For this to work, printbuffer must be larger than
  	 * anything we ever want to print.
  	 */
  	i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
  	va_end(args);
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
769
770
771
  	/* Handle error */
  	if (i <= 0)
  		return i;
7d9cde103   Stefan Roese   lib/tiny-printf.c...
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
  	/* Print the string */
  	puts(printbuffer);
  	return i;
  }
  
  int vprintf(const char *fmt, va_list args)
  {
  	uint i;
  	char printbuffer[CONFIG_SYS_PBSIZE];
  
  	/*
  	 * For this to work, printbuffer must be larger than
  	 * anything we ever want to print.
  	 */
  	i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
787
788
789
  	/* Handle error */
  	if (i <= 0)
  		return i;
7d9cde103   Stefan Roese   lib/tiny-printf.c...
790
791
792
793
  	/* Print the string */
  	puts(printbuffer);
  	return i;
  }
66312374d   Simon Glass   dm: Add a panic_s...
794

21726a7af   Simon Glass   Add assert() for ...
795
796
797
798
799
800
801
  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 ...
802
803
804
805
806
807
808
809
810
811
812
813
814
815
  
  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...
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
  
  /* 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;
  	}
  }
09c328075   Heiko Schocher   mtd, nand: Move c...
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
  
  bool str2off(const char *p, loff_t *num)
  {
  	char *endptr;
  
  	*num = simple_strtoull(p, &endptr, 16);
  	return *p != '\0' && *endptr == '\0';
  }
  
  bool str2long(const char *p, ulong *num)
  {
  	char *endptr;
  
  	*num = simple_strtoul(p, &endptr, 16);
  	return *p != '\0' && *endptr == '\0';
  }