Blame view

lib/vsprintf.c 18.9 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>
f8c987f8f   Alexey Brodkin   lib: Add hexdump
17
  #include <hexdump.h>
22ada0c8e   Rob Clark   vsprintf.c: add G...
18
  #include <uuid.h>
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
19
20
21
22
23
  #include <stdarg.h>
  #include <linux/ctype.h>
  #include <linux/err.h>
  #include <linux/types.h>
  #include <linux/string.h>
153d511e3   wdenk   Initial revision
24

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

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

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

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

0eb257683   Kim Phillips   lib/vsprintf.c: s...
253
  	if (s == NULL)
6c6166f52   Mike Frysinger   vsprintf: pull up...
254
255
256
257
258
259
  		s = "<NULL>";
  
  	len = strnlen(s, precision);
  
  	if (!(flags & LEFT))
  		while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
260
  			ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
261
  	for (i = 0; i < len; ++i)
046a37bd5   Sonny Rao   Add safe vsnprint...
262
  		ADDCH(buf, *s++);
6c6166f52   Mike Frysinger   vsprintf: pull up...
263
  	while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
264
  		ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
265
266
  	return buf;
  }
fbb3ea806   Heinrich Schuchardt   lib: build charse...
267
268
  /* U-Boot uses UTF-16 strings in the EFI context only. */
  #if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
274325c50   Rob Clark   vsprintf.c: add U...
269
270
271
  static char *string16(char *buf, char *end, u16 *s, int field_width,
  		int precision, int flags)
  {
0e66c10a7   Heinrich Schuchardt   lib: vsprintf: av...
272
273
  	const u16 *str = s ? s : L"<NULL>";
  	ssize_t i, len = utf16_strnlen(str, precision);
274325c50   Rob Clark   vsprintf.c: add U...
274
275
  
  	if (!(flags & LEFT))
31bd711cd   Heinrich Schuchardt   lib: vsprintf: co...
276
  		for (; len < field_width; --field_width)
274325c50   Rob Clark   vsprintf.c: add U...
277
  			ADDCH(buf, ' ');
0e66c10a7   Heinrich Schuchardt   lib: vsprintf: av...
278
279
  	for (i = 0; i < len && buf + utf16_utf8_strnlen(str, 1) <= end; ++i) {
  		s32 s = utf16_get(&str);
60c4454dd   Heinrich Schuchardt   lib/vsprintf: pri...
280
281
  		if (s < 0)
  			s = '?';
0e66c10a7   Heinrich Schuchardt   lib: vsprintf: av...
282
283
  		utf8_put(s, &buf);
  	}
31bd711cd   Heinrich Schuchardt   lib: vsprintf: co...
284
  	for (; len < field_width; --field_width)
274325c50   Rob Clark   vsprintf.c: add U...
285
286
287
  		ADDCH(buf, ' ');
  	return buf;
  }
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
288
289
290
291
  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...
292
  	/* If dp == NULL output the string '<NULL>' */
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
293
  	if (!dp)
5f1ce1d4c   Heinrich Schuchardt   vsprintf.c: corre...
294
  		return string16(buf, end, dp, field_width, precision, flags);
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
295
296
297
298
299
300
301
302
303
304
  
  	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...
305
  #ifdef CONFIG_CMD_NET
046a37bd5   Sonny Rao   Add safe vsnprint...
306
  static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
307
  				int precision, int flags)
153d511e3   wdenk   Initial revision
308
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
309
310
  	/* (6 * 2 hex digits), 5 colons and trailing zero */
  	char mac_addr[6 * 3];
6c6166f52   Mike Frysinger   vsprintf: pull up...
311
312
313
314
  	char *p = mac_addr;
  	int i;
  
  	for (i = 0; i < 6; i++) {
f8c987f8f   Alexey Brodkin   lib: Add hexdump
315
  		p = hex_byte_pack(p, addr[i]);
6c6166f52   Mike Frysinger   vsprintf: pull up...
316
317
318
319
  		if (!(flags & SPECIAL) && i != 5)
  			*p++ = ':';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
320
321
  	return string(buf, end, mac_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
322
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
323
  static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
324
325
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
326
327
  	/* (8 * 4 hex digits), 7 colons and trailing zero */
  	char ip6_addr[8 * 5];
6c6166f52   Mike Frysinger   vsprintf: pull up...
328
329
330
331
  	char *p = ip6_addr;
  	int i;
  
  	for (i = 0; i < 8; i++) {
f8c987f8f   Alexey Brodkin   lib: Add hexdump
332
333
  		p = hex_byte_pack(p, addr[2 * i]);
  		p = hex_byte_pack(p, addr[2 * i + 1]);
6c6166f52   Mike Frysinger   vsprintf: pull up...
334
335
336
337
  		if (!(flags & SPECIAL) && i != 7)
  			*p++ = ':';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
338
339
  	return string(buf, end, ip6_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
340
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
341
  static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
342
343
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
344
345
  	/* (4 * 3 decimal digits), 3 dots and trailing zero */
  	char ip4_addr[4 * 4];
6c6166f52   Mike Frysinger   vsprintf: pull up...
346
347
348
349
350
351
352
353
354
355
356
357
358
  	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...
359
360
  	return string(buf, end, ip4_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
361
  }
c40b29568   wdenk   * Patch by Rune T...
362
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
363

22ada0c8e   Rob Clark   vsprintf.c: add G...
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
  #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;
  	}
d7ae1609a   Simon Glass   vsprintf: Handle ...
391
392
393
394
  	if (addr)
  		uuid_bin_to_str(addr, uuid, str_format);
  	else
  		strcpy(uuid, "<NULL>");
22ada0c8e   Rob Clark   vsprintf.c: add G...
395
396
397
398
  
  	return string(buf, end, uuid, field_width, precision, flags);
  }
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
  /*
   * 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...
417
418
  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...
419
  {
1eebd14b7   Thierry Reding   vsprintf: Add mod...
420
  	u64 num = (uintptr_t)ptr;
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
421
422
423
424
425
  	/*
  	 * Being a boot loader, we explicitly allow pointers to
  	 * (physical) address null.
  	 */
  #if 0
6c6166f52   Mike Frysinger   vsprintf: pull up...
426
  	if (!ptr)
046a37bd5   Sonny Rao   Add safe vsnprint...
427
428
  		return string(buf, end, "(null)", field_width, precision,
  			      flags);
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
429
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
430

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

046a37bd5   Sonny Rao   Add safe vsnprint...
502
503
504
505
506
  	/* 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...
507
  	str = buf;
153d511e3   wdenk   Initial revision
508

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

3cce8a549   Simon Glass   Move simple_itoa ...
794
795
796
797
798
799
800
801
802
803
804
805
806
  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...
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
  
  /* 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...
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
  
  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';
  }