Blame view

lib/vsprintf.c 19.2 KB
153d511e3   wdenk   Initial revision
1
2
3
4
  /*
   *  linux/lib/vsprintf.c
   *
   *  Copyright (C) 1991, 1992  Linus Torvalds
2189d5f1e   Simon Glass   Move strtomhz() t...
5
6
   * (C) Copyright 2000-2009
   * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
153d511e3   wdenk   Initial revision
7
8
9
10
11
   */
  
  /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
  /*
   * Wirzenius wrote this portably, Torvalds fucked it up :-)
3cce8a549   Simon Glass   Move simple_itoa ...
12
13
   *
   * from hush: simple_itoa() was lifted from boa-0.93.15
153d511e3   wdenk   Initial revision
14
   */
153d511e3   wdenk   Initial revision
15
  #include <common.h>
274325c50   Rob Clark   vsprintf.c: add U...
16
  #include <charset.h>
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
17
18
  #include <efi_loader.h>
  #include <div64.h>
f8c987f8f   Alexey Brodkin   lib: Add hexdump
19
  #include <hexdump.h>
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
20
  #include <stdarg.h>
2189d5f1e   Simon Glass   Move strtomhz() t...
21
  #include <vsprintf.h>
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
22
23
24
25
  #include <linux/ctype.h>
  #include <linux/err.h>
  #include <linux/types.h>
  #include <linux/string.h>
153d511e3   wdenk   Initial revision
26

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

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

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

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

0eb257683   Kim Phillips   lib/vsprintf.c: s...
255
  	if (s == NULL)
6c6166f52   Mike Frysinger   vsprintf: pull up...
256
257
258
259
260
261
  		s = "<NULL>";
  
  	len = strnlen(s, precision);
  
  	if (!(flags & LEFT))
  		while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
262
  			ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
263
  	for (i = 0; i < len; ++i)
046a37bd5   Sonny Rao   Add safe vsnprint...
264
  		ADDCH(buf, *s++);
6c6166f52   Mike Frysinger   vsprintf: pull up...
265
  	while (len < field_width--)
046a37bd5   Sonny Rao   Add safe vsnprint...
266
  		ADDCH(buf, ' ');
6c6166f52   Mike Frysinger   vsprintf: pull up...
267
268
  	return buf;
  }
fbb3ea806   Heinrich Schuchardt   lib: build charse...
269
270
  /* 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...
271
272
273
  static char *string16(char *buf, char *end, u16 *s, int field_width,
  		int precision, int flags)
  {
0e66c10a7   Heinrich Schuchardt   lib: vsprintf: av...
274
275
  	const u16 *str = s ? s : L"<NULL>";
  	ssize_t i, len = utf16_strnlen(str, precision);
274325c50   Rob Clark   vsprintf.c: add U...
276
277
  
  	if (!(flags & LEFT))
31bd711cd   Heinrich Schuchardt   lib: vsprintf: co...
278
  		for (; len < field_width; --field_width)
274325c50   Rob Clark   vsprintf.c: add U...
279
  			ADDCH(buf, ' ');
0e66c10a7   Heinrich Schuchardt   lib: vsprintf: av...
280
281
  	for (i = 0; i < len && buf + utf16_utf8_strnlen(str, 1) <= end; ++i) {
  		s32 s = utf16_get(&str);
60c4454dd   Heinrich Schuchardt   lib/vsprintf: pri...
282
283
  		if (s < 0)
  			s = '?';
0e66c10a7   Heinrich Schuchardt   lib: vsprintf: av...
284
285
  		utf8_put(s, &buf);
  	}
31bd711cd   Heinrich Schuchardt   lib: vsprintf: co...
286
  	for (; len < field_width; --field_width)
274325c50   Rob Clark   vsprintf.c: add U...
287
288
289
  		ADDCH(buf, ' ');
  	return buf;
  }
64b5ba4d2   Heinrich Schuchardt   efi_loader: make ...
290
  #if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT)
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
291
292
293
294
  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...
295
  	/* If dp == NULL output the string '<NULL>' */
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
296
  	if (!dp)
5f1ce1d4c   Heinrich Schuchardt   vsprintf.c: corre...
297
  		return string16(buf, end, dp, field_width, precision, flags);
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
298
299
300
301
302
303
304
305
306
307
  
  	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
64b5ba4d2   Heinrich Schuchardt   efi_loader: make ...
308
  #endif
256060e42   Heinrich Schuchardt   vsprintf.c: add E...
309

046a37bd5   Sonny Rao   Add safe vsnprint...
310
  static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
311
  				int precision, int flags)
153d511e3   wdenk   Initial revision
312
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
313
314
  	/* (6 * 2 hex digits), 5 colons and trailing zero */
  	char mac_addr[6 * 3];
6c6166f52   Mike Frysinger   vsprintf: pull up...
315
316
317
318
  	char *p = mac_addr;
  	int i;
  
  	for (i = 0; i < 6; i++) {
f8c987f8f   Alexey Brodkin   lib: Add hexdump
319
  		p = hex_byte_pack(p, addr[i]);
6c6166f52   Mike Frysinger   vsprintf: pull up...
320
321
322
323
  		if (!(flags & SPECIAL) && i != 5)
  			*p++ = ':';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
324
325
  	return string(buf, end, mac_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
326
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
327
  static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
328
329
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
330
331
  	/* (8 * 4 hex digits), 7 colons and trailing zero */
  	char ip6_addr[8 * 5];
6c6166f52   Mike Frysinger   vsprintf: pull up...
332
333
334
335
  	char *p = ip6_addr;
  	int i;
  
  	for (i = 0; i < 8; i++) {
f8c987f8f   Alexey Brodkin   lib: Add hexdump
336
337
  		p = hex_byte_pack(p, addr[2 * i]);
  		p = hex_byte_pack(p, addr[2 * i + 1]);
6c6166f52   Mike Frysinger   vsprintf: pull up...
338
339
340
341
  		if (!(flags & SPECIAL) && i != 7)
  			*p++ = ':';
  	}
  	*p = '\0';
046a37bd5   Sonny Rao   Add safe vsnprint...
342
343
  	return string(buf, end, ip6_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
344
  }
046a37bd5   Sonny Rao   Add safe vsnprint...
345
  static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
6c6166f52   Mike Frysinger   vsprintf: pull up...
346
347
  			 int precision, int flags)
  {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
348
349
  	/* (4 * 3 decimal digits), 3 dots and trailing zero */
  	char ip4_addr[4 * 4];
6c6166f52   Mike Frysinger   vsprintf: pull up...
350
351
352
353
354
355
356
357
358
359
360
361
362
  	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...
363
364
  	return string(buf, end, ip4_addr, field_width, precision,
  		      flags & ~SPECIAL);
6c6166f52   Mike Frysinger   vsprintf: pull up...
365
  }
6c6166f52   Mike Frysinger   vsprintf: pull up...
366

22ada0c8e   Rob Clark   vsprintf.c: add G...
367
368
  #ifdef CONFIG_LIB_UUID
  /*
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
369
   * This works (roughly) the same way as Linux's.
22ada0c8e   Rob Clark   vsprintf.c: add G...
370
371
   *
   *   %pUb:   01020304-0506-0708-090a-0b0c0d0e0f10
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
372
   *   %pUB:   01020304-0506-0708-090A-0B0C0D0E0F10
22ada0c8e   Rob Clark   vsprintf.c: add G...
373
   *   %pUl:   04030201-0605-0807-090a-0b0c0d0e0f10
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
374
   *   %pUL:   04030201-0605-0807-090A-0B0C0D0E0F10
22ada0c8e   Rob Clark   vsprintf.c: add G...
375
376
377
378
379
   */
  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];
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
380
  	int str_format;
22ada0c8e   Rob Clark   vsprintf.c: add G...
381
382
383
  
  	switch (*(++fmt)) {
  	case 'L':
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
384
385
  		str_format = UUID_STR_FORMAT_GUID | UUID_STR_UPPER_CASE;
  		break;
22ada0c8e   Rob Clark   vsprintf.c: add G...
386
387
388
389
  	case 'l':
  		str_format = UUID_STR_FORMAT_GUID;
  		break;
  	case 'B':
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
390
  		str_format = UUID_STR_FORMAT_STD | UUID_STR_UPPER_CASE;
22ada0c8e   Rob Clark   vsprintf.c: add G...
391
392
  		break;
  	default:
3bad256f5   Heinrich Schuchardt   lib/vsprintf: all...
393
  		str_format = UUID_STR_FORMAT_STD;
22ada0c8e   Rob Clark   vsprintf.c: add G...
394
395
  		break;
  	}
d7ae1609a   Simon Glass   vsprintf: Handle ...
396
397
398
399
  	if (addr)
  		uuid_bin_to_str(addr, uuid, str_format);
  	else
  		strcpy(uuid, "<NULL>");
22ada0c8e   Rob Clark   vsprintf.c: add G...
400
401
402
403
  
  	return string(buf, end, uuid, field_width, precision, flags);
  }
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
  /*
   * 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...
422
423
  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...
424
  {
1eebd14b7   Thierry Reding   vsprintf: Add mod...
425
  	u64 num = (uintptr_t)ptr;
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
426
427
428
429
430
  	/*
  	 * Being a boot loader, we explicitly allow pointers to
  	 * (physical) address null.
  	 */
  #if 0
6c6166f52   Mike Frysinger   vsprintf: pull up...
431
  	if (!ptr)
046a37bd5   Sonny Rao   Add safe vsnprint...
432
433
  		return string(buf, end, "(null)", field_width, precision,
  			      flags);
d266f6692   Wolfgang Denk   lib/vsprintf.c: d...
434
  #endif
6c6166f52   Mike Frysinger   vsprintf: pull up...
435

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

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

6c6166f52   Mike Frysinger   vsprintf: pull up...
512
  	for (; *fmt ; ++fmt) {
153d511e3   wdenk   Initial revision
513
  		if (*fmt != '%') {
046a37bd5   Sonny Rao   Add safe vsnprint...
514
  			ADDCH(str, *fmt);
153d511e3   wdenk   Initial revision
515
516
517
518
519
  			continue;
  		}
  
  		/* process flags */
  		flags = 0;
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
520
  repeat:
153d511e3   wdenk   Initial revision
521
522
  			++fmt;		/* this also skips first '%' */
  			switch (*fmt) {
8acdae681   Daniel Schwierzeck   lib: vsprintf.c: ...
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
  			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...
538
  			}
153d511e3   wdenk   Initial revision
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
568
569
570
  
  		/* 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...
571
  		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
6c6166f52   Mike Frysinger   vsprintf: pull up...
572
  		    *fmt == 'Z' || *fmt == 'z' || *fmt == 't') {
153d511e3   wdenk   Initial revision
573
  			qualifier = *fmt;
6c6166f52   Mike Frysinger   vsprintf: pull up...
574
575
576
  			++fmt;
  			if (qualifier == 'l' && *fmt == 'l') {
  				qualifier = 'L';
bf0529397   James Yang   Fix 64-bit vsprintf.
577
578
  				++fmt;
  			}
153d511e3   wdenk   Initial revision
579
580
581
582
583
584
585
  		}
  
  		/* default base */
  		base = 10;
  
  		switch (*fmt) {
  		case 'c':
046a37bd5   Sonny Rao   Add safe vsnprint...
586
  			if (!(flags & LEFT)) {
153d511e3   wdenk   Initial revision
587
  				while (--field_width > 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
588
589
590
  					ADDCH(str, ' ');
  			}
  			ADDCH(str, (unsigned char) va_arg(args, int));
153d511e3   wdenk   Initial revision
591
  			while (--field_width > 0)
046a37bd5   Sonny Rao   Add safe vsnprint...
592
  				ADDCH(str, ' ');
153d511e3   wdenk   Initial revision
593
594
595
  			continue;
  
  		case 's':
fbb3ea806   Heinrich Schuchardt   lib: build charse...
596
597
598
  /* 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...
599
600
  				str = string16(str, end, va_arg(args, u16 *),
  					       field_width, precision, flags);
fbb3ea806   Heinrich Schuchardt   lib: build charse...
601
602
603
  			} else
  #endif
  			{
274325c50   Rob Clark   vsprintf.c: add U...
604
605
606
  				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;
  }
4f1eed752   Alex Kiernan   spl: Disable prin...
755
  #if CONFIG_IS_ENABLED(PRINTF)
7d9cde103   Stefan Roese   lib/tiny-printf.c...
756
757
758
759
760
761
762
763
764
765
766
767
768
769
  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...
770
771
772
  	/* Handle error */
  	if (i <= 0)
  		return i;
7d9cde103   Stefan Roese   lib/tiny-printf.c...
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
  	/* 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...
788
789
790
  	/* Handle error */
  	if (i <= 0)
  		return i;
7d9cde103   Stefan Roese   lib/tiny-printf.c...
791
792
793
794
  	/* Print the string */
  	puts(printbuffer);
  	return i;
  }
4f1eed752   Alex Kiernan   spl: Disable prin...
795
  #endif
66312374d   Simon Glass   dm: Add a panic_s...
796

3cce8a549   Simon Glass   Move simple_itoa ...
797
798
799
800
801
802
803
804
805
806
807
808
809
  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...
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
  
  /* 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...
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
  
  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';
  }
2189d5f1e   Simon Glass   Move strtomhz() t...
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
  
  char *strmhz(char *buf, unsigned long hz)
  {
  	long l, n;
  	long m;
  
  	n = DIV_ROUND_CLOSEST(hz, 1000) / 1000L;
  	l = sprintf(buf, "%ld", n);
  
  	hz -= n * 1000000L;
  	m = DIV_ROUND_CLOSEST(hz, 1000L);
  	if (m != 0)
  		sprintf(buf + l, ".%03ld", m);
  
  	return buf;
  }