Blame view
lib/vsprintf.c
18.9 KB
153d511e3 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 Move simple_itoa ... |
10 11 |
* * from hush: simple_itoa() was lifted from boa-0.93.15 |
153d511e3 Initial revision |
12 |
*/ |
153d511e3 Initial revision |
13 |
#include <common.h> |
274325c50 vsprintf.c: add U... |
14 |
#include <charset.h> |
256060e42 vsprintf.c: add E... |
15 16 |
#include <efi_loader.h> #include <div64.h> |
f8c987f8f lib: Add hexdump |
17 |
#include <hexdump.h> |
22ada0c8e vsprintf.c: add G... |
18 |
#include <uuid.h> |
256060e42 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 Initial revision |
24 |
|
479105065 Use do_div from d... |
25 |
#define noinline __attribute__((noinline)) |
153d511e3 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 lib: vsprintf.c: ... |
31 |
int i = 0; |
153d511e3 Initial revision |
32 33 |
while (is_digit(**s)) |
8acdae681 lib: vsprintf.c: ... |
34 |
i = i * 10 + *((*s)++) - '0'; |
153d511e3 Initial revision |
35 36 |
return i; } |
6c6166f52 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 lib: vsprintf.c: ... |
47 |
static char *put_dec_trunc(char *buf, unsigned q) |
6c6166f52 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 lib: vsprintf.c: ... |
76 |
*buf++ = q + '0'; /* most sign. digit */ |
6c6166f52 vsprintf: pull up... |
77 78 79 80 81 82 |
} } } return buf; } /* Same with if's removed. Always emits five digits */ |
8acdae681 lib: vsprintf.c: ... |
83 |
static char *put_dec_full(char *buf, unsigned q) |
6c6166f52 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 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 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 Use uint64_t inst... |
124 |
static noinline char *put_dec(char *buf, uint64_t num) |
6c6166f52 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 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 vsprintf: pull up... |
139 140 |
#define SMALL 32 /* Must be 32 == 0x20 */ #define SPECIAL 64 /* 0x */ |
153d511e3 Initial revision |
141 |
|
046a37bd5 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 Add safe vsnprint... |
151 |
|
7b64f66c5 lib: vsprintf.c: ... |
152 |
static char *number(char *buf, char *end, u64 num, |
046a37bd5 Add safe vsnprint... |
153 |
int base, int size, int precision, int type) |
153d511e3 Initial revision |
154 |
{ |
6c6166f52 vsprintf: pull up... |
155 |
/* we are called with base 8, 10 or 16, only, thus don't need "G..." */ |
8acdae681 lib: vsprintf.c: ... |
156 |
static const char digits[16] = "0123456789ABCDEF"; |
6c6166f52 vsprintf: pull up... |
157 158 159 160 161 |
char tmp[66]; char sign; char locase; int need_pfx = ((type & SPECIAL) && base != 10); |
153d511e3 Initial revision |
162 |
int i; |
6c6166f52 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 Initial revision |
166 167 |
if (type & LEFT) type &= ~ZEROPAD; |
153d511e3 Initial revision |
168 169 |
sign = 0; if (type & SIGN) { |
7b64f66c5 lib: vsprintf.c: ... |
170 |
if ((s64) num < 0) { |
153d511e3 Initial revision |
171 |
sign = '-'; |
7b64f66c5 lib: vsprintf.c: ... |
172 |
num = -(s64) num; |
153d511e3 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 vsprintf: pull up... |
182 183 |
if (need_pfx) { size--; |
153d511e3 Initial revision |
184 |
if (base == 16) |
153d511e3 Initial revision |
185 186 |
size--; } |
6c6166f52 vsprintf: pull up... |
187 188 |
/* generate full string in tmp[], in reverse order */ |
153d511e3 Initial revision |
189 190 |
i = 0; if (num == 0) |
6c6166f52 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 lib: vsprintf.c: ... |
200 201 202 |
if (base == 16) shift = 4; |
6c6166f52 vsprintf: pull up... |
203 |
do { |
8acdae681 lib: vsprintf.c: ... |
204 205 |
tmp[i++] = (digits[((unsigned char)num) & mask] | locase); |
6c6166f52 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 Initial revision |
213 214 |
if (i > precision) precision = i; |
6c6166f52 vsprintf: pull up... |
215 |
/* leading space padding */ |
153d511e3 Initial revision |
216 |
size -= precision; |
046a37bd5 Add safe vsnprint... |
217 218 219 220 |
if (!(type & (ZEROPAD + LEFT))) { while (--size >= 0) ADDCH(buf, ' '); } |
6c6166f52 vsprintf: pull up... |
221 |
/* sign */ |
153d511e3 Initial revision |
222 |
if (sign) |
046a37bd5 Add safe vsnprint... |
223 |
ADDCH(buf, sign); |
6c6166f52 vsprintf: pull up... |
224 225 |
/* "0x" / "0" prefix */ if (need_pfx) { |
046a37bd5 Add safe vsnprint... |
226 |
ADDCH(buf, '0'); |
6c6166f52 vsprintf: pull up... |
227 |
if (base == 16) |
046a37bd5 Add safe vsnprint... |
228 |
ADDCH(buf, 'X' | locase); |
6c6166f52 vsprintf: pull up... |
229 230 231 232 |
} /* zero or space padding */ if (!(type & LEFT)) { char c = (type & ZEROPAD) ? '0' : ' '; |
046a37bd5 Add safe vsnprint... |
233 |
|
6c6166f52 vsprintf: pull up... |
234 |
while (--size >= 0) |
046a37bd5 Add safe vsnprint... |
235 |
ADDCH(buf, c); |
153d511e3 Initial revision |
236 |
} |
6c6166f52 vsprintf: pull up... |
237 238 |
/* hmm even more zero padding? */ while (i <= --precision) |
046a37bd5 Add safe vsnprint... |
239 |
ADDCH(buf, '0'); |
6c6166f52 vsprintf: pull up... |
240 241 |
/* actual digits of result */ while (--i >= 0) |
046a37bd5 Add safe vsnprint... |
242 |
ADDCH(buf, tmp[i]); |
6c6166f52 vsprintf: pull up... |
243 244 |
/* trailing space padding */ while (--size >= 0) |
046a37bd5 Add safe vsnprint... |
245 |
ADDCH(buf, ' '); |
6c6166f52 vsprintf: pull up... |
246 |
return buf; |
153d511e3 Initial revision |
247 |
} |
046a37bd5 Add safe vsnprint... |
248 249 |
static char *string(char *buf, char *end, char *s, int field_width, int precision, int flags) |
6c6166f52 vsprintf: pull up... |
250 251 |
{ int len, i; |
153d511e3 Initial revision |
252 |
|
0eb257683 lib/vsprintf.c: s... |
253 |
if (s == NULL) |
6c6166f52 vsprintf: pull up... |
254 255 256 257 258 259 |
s = "<NULL>"; len = strnlen(s, precision); if (!(flags & LEFT)) while (len < field_width--) |
046a37bd5 Add safe vsnprint... |
260 |
ADDCH(buf, ' '); |
6c6166f52 vsprintf: pull up... |
261 |
for (i = 0; i < len; ++i) |
046a37bd5 Add safe vsnprint... |
262 |
ADDCH(buf, *s++); |
6c6166f52 vsprintf: pull up... |
263 |
while (len < field_width--) |
046a37bd5 Add safe vsnprint... |
264 |
ADDCH(buf, ' '); |
6c6166f52 vsprintf: pull up... |
265 266 |
return buf; } |
fbb3ea806 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 vsprintf.c: add U... |
269 270 271 |
static char *string16(char *buf, char *end, u16 *s, int field_width, int precision, int flags) { |
0e66c10a7 lib: vsprintf: av... |
272 273 |
const u16 *str = s ? s : L"<NULL>"; ssize_t i, len = utf16_strnlen(str, precision); |
274325c50 vsprintf.c: add U... |
274 275 |
if (!(flags & LEFT)) |
31bd711cd lib: vsprintf: co... |
276 |
for (; len < field_width; --field_width) |
274325c50 vsprintf.c: add U... |
277 |
ADDCH(buf, ' '); |
0e66c10a7 lib: vsprintf: av... |
278 279 |
for (i = 0; i < len && buf + utf16_utf8_strnlen(str, 1) <= end; ++i) { s32 s = utf16_get(&str); |
60c4454dd lib/vsprintf: pri... |
280 281 |
if (s < 0) s = '?'; |
0e66c10a7 lib: vsprintf: av... |
282 283 |
utf8_put(s, &buf); } |
31bd711cd lib: vsprintf: co... |
284 |
for (; len < field_width; --field_width) |
274325c50 vsprintf.c: add U... |
285 286 287 |
ADDCH(buf, ' '); return buf; } |
256060e42 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 vsprintf.c: corre... |
292 |
/* If dp == NULL output the string '<NULL>' */ |
256060e42 vsprintf.c: add E... |
293 |
if (!dp) |
5f1ce1d4c vsprintf.c: corre... |
294 |
return string16(buf, end, dp, field_width, precision, flags); |
256060e42 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 vsprintf: pull up... |
305 |
#ifdef CONFIG_CMD_NET |
046a37bd5 Add safe vsnprint... |
306 |
static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, |
6c6166f52 vsprintf: pull up... |
307 |
int precision, int flags) |
153d511e3 Initial revision |
308 |
{ |
8acdae681 lib: vsprintf.c: ... |
309 310 |
/* (6 * 2 hex digits), 5 colons and trailing zero */ char mac_addr[6 * 3]; |
6c6166f52 vsprintf: pull up... |
311 312 313 314 |
char *p = mac_addr; int i; for (i = 0; i < 6; i++) { |
f8c987f8f lib: Add hexdump |
315 |
p = hex_byte_pack(p, addr[i]); |
6c6166f52 vsprintf: pull up... |
316 317 318 319 |
if (!(flags & SPECIAL) && i != 5) *p++ = ':'; } *p = '\0'; |
046a37bd5 Add safe vsnprint... |
320 321 |
return string(buf, end, mac_addr, field_width, precision, flags & ~SPECIAL); |
6c6166f52 vsprintf: pull up... |
322 |
} |
046a37bd5 Add safe vsnprint... |
323 |
static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, |
6c6166f52 vsprintf: pull up... |
324 325 |
int precision, int flags) { |
8acdae681 lib: vsprintf.c: ... |
326 327 |
/* (8 * 4 hex digits), 7 colons and trailing zero */ char ip6_addr[8 * 5]; |
6c6166f52 vsprintf: pull up... |
328 329 330 331 |
char *p = ip6_addr; int i; for (i = 0; i < 8; i++) { |
f8c987f8f lib: Add hexdump |
332 333 |
p = hex_byte_pack(p, addr[2 * i]); p = hex_byte_pack(p, addr[2 * i + 1]); |
6c6166f52 vsprintf: pull up... |
334 335 336 337 |
if (!(flags & SPECIAL) && i != 7) *p++ = ':'; } *p = '\0'; |
046a37bd5 Add safe vsnprint... |
338 339 |
return string(buf, end, ip6_addr, field_width, precision, flags & ~SPECIAL); |
6c6166f52 vsprintf: pull up... |
340 |
} |
046a37bd5 Add safe vsnprint... |
341 |
static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, |
6c6166f52 vsprintf: pull up... |
342 343 |
int precision, int flags) { |
8acdae681 lib: vsprintf.c: ... |
344 345 |
/* (4 * 3 decimal digits), 3 dots and trailing zero */ char ip4_addr[4 * 4]; |
6c6166f52 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 Add safe vsnprint... |
359 360 |
return string(buf, end, ip4_addr, field_width, precision, flags & ~SPECIAL); |
6c6166f52 vsprintf: pull up... |
361 |
} |
c40b29568 * Patch by Rune T... |
362 |
#endif |
6c6166f52 vsprintf: pull up... |
363 |
|
22ada0c8e 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 vsprintf: Handle ... |
391 392 393 394 |
if (addr) uuid_bin_to_str(addr, uuid, str_format); else strcpy(uuid, "<NULL>"); |
22ada0c8e vsprintf.c: add G... |
395 396 397 398 |
return string(buf, end, uuid, field_width, precision, flags); } #endif |
6c6166f52 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 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 vsprintf: pull up... |
419 |
{ |
1eebd14b7 vsprintf: Add mod... |
420 |
u64 num = (uintptr_t)ptr; |
d266f6692 lib/vsprintf.c: d... |
421 422 423 424 425 |
/* * Being a boot loader, we explicitly allow pointers to * (physical) address null. */ #if 0 |
6c6166f52 vsprintf: pull up... |
426 |
if (!ptr) |
046a37bd5 Add safe vsnprint... |
427 428 |
return string(buf, end, "(null)", field_width, precision, flags); |
d266f6692 lib/vsprintf.c: d... |
429 |
#endif |
6c6166f52 vsprintf: pull up... |
430 |
|
6c6166f52 vsprintf: pull up... |
431 |
switch (*fmt) { |
4ddcc4e5d vsprintf.c: use #... |
432 433 |
/* Device paths only exist in the EFI context. */ #if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD) |
256060e42 vsprintf.c: add E... |
434 435 436 437 |
case 'D': return device_path_string(buf, end, ptr, field_width, precision, flags); #endif |
22ada0c8e vsprintf.c: add G... |
438 |
#ifdef CONFIG_CMD_NET |
1eebd14b7 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 vsprintf: pull up... |
450 451 452 453 |
case 'm': flags |= SPECIAL; /* Fallthrough */ case 'M': |
046a37bd5 Add safe vsnprint... |
454 455 |
return mac_address_string(buf, end, ptr, field_width, precision, flags); |
6c6166f52 vsprintf: pull up... |
456 457 458 459 460 |
case 'i': flags |= SPECIAL; /* Fallthrough */ case 'I': if (fmt[1] == '6') |
046a37bd5 Add safe vsnprint... |
461 462 |
return ip6_addr_string(buf, end, ptr, field_width, precision, flags); |
6c6166f52 vsprintf: pull up... |
463 |
if (fmt[1] == '4') |
046a37bd5 Add safe vsnprint... |
464 465 |
return ip4_addr_string(buf, end, ptr, field_width, precision, flags); |
6c6166f52 vsprintf: pull up... |
466 467 |
flags &= ~SPECIAL; break; |
6c6166f52 vsprintf: pull up... |
468 |
#endif |
22ada0c8e 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 vsprintf: pull up... |
477 478 479 480 481 |
flags |= SMALL; if (field_width == -1) { field_width = 2*sizeof(void *); flags |= ZEROPAD; } |
1eebd14b7 vsprintf: Add mod... |
482 |
return number(buf, end, num, 16, field_width, precision, flags); |
6c6166f52 vsprintf: pull up... |
483 |
} |
046a37bd5 Add safe vsnprint... |
484 485 |
static int vsnprintf_internal(char *buf, size_t size, const char *fmt, va_list args) |
6c6166f52 vsprintf: pull up... |
486 |
{ |
7b64f66c5 lib: vsprintf.c: ... |
487 |
u64 num; |
6c6166f52 vsprintf: pull up... |
488 489 |
int base; char *str; |
153d511e3 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 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 Add safe vsnprint... |
500 |
char *end = buf + size; |
6c6166f52 vsprintf: pull up... |
501 |
|
046a37bd5 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 vsprintf: pull up... |
507 |
str = buf; |
153d511e3 Initial revision |
508 |
|
6c6166f52 vsprintf: pull up... |
509 |
for (; *fmt ; ++fmt) { |
153d511e3 Initial revision |
510 |
if (*fmt != '%') { |
046a37bd5 Add safe vsnprint... |
511 |
ADDCH(str, *fmt); |
153d511e3 Initial revision |
512 513 514 515 516 |
continue; } /* process flags */ flags = 0; |
8acdae681 lib: vsprintf.c: ... |
517 |
repeat: |
153d511e3 Initial revision |
518 519 |
++fmt; /* this also skips first '%' */ switch (*fmt) { |
8acdae681 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 vsprintf: pull up... |
535 |
} |
153d511e3 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 vsprintf: add z a... |
568 |
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || |
6c6166f52 vsprintf: pull up... |
569 |
*fmt == 'Z' || *fmt == 'z' || *fmt == 't') { |
153d511e3 Initial revision |
570 |
qualifier = *fmt; |
6c6166f52 vsprintf: pull up... |
571 572 573 |
++fmt; if (qualifier == 'l' && *fmt == 'l') { qualifier = 'L'; |
bf0529397 Fix 64-bit vsprintf. |
574 575 |
++fmt; } |
153d511e3 Initial revision |
576 577 578 579 580 581 582 |
} /* default base */ base = 10; switch (*fmt) { case 'c': |
046a37bd5 Add safe vsnprint... |
583 |
if (!(flags & LEFT)) { |
153d511e3 Initial revision |
584 |
while (--field_width > 0) |
046a37bd5 Add safe vsnprint... |
585 586 587 |
ADDCH(str, ' '); } ADDCH(str, (unsigned char) va_arg(args, int)); |
153d511e3 Initial revision |
588 |
while (--field_width > 0) |
046a37bd5 Add safe vsnprint... |
589 |
ADDCH(str, ' '); |
153d511e3 Initial revision |
590 591 592 |
continue; case 's': |
fbb3ea806 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 vsprintf.c: add U... |
596 597 |
str = string16(str, end, va_arg(args, u16 *), field_width, precision, flags); |
fbb3ea806 lib: build charse... |
598 599 600 |
} else #endif { |
274325c50 vsprintf.c: add U... |
601 602 603 |
str = string(str, end, va_arg(args, char *), field_width, precision, flags); } |
153d511e3 Initial revision |
604 605 606 |
continue; case 'p': |
8acdae681 lib: vsprintf.c: ... |
607 |
str = pointer(fmt + 1, str, end, |
6c6166f52 vsprintf: pull up... |
608 609 |
va_arg(args, void *), field_width, precision, flags); |
256060e42 vsprintf.c: add E... |
610 611 |
if (IS_ERR(str)) return PTR_ERR(str); |
6c6166f52 vsprintf: pull up... |
612 613 614 |
/* Skip all alphanumeric pointer suffixes */ while (isalnum(fmt[1])) fmt++; |
153d511e3 Initial revision |
615 |
continue; |
153d511e3 Initial revision |
616 617 |
case 'n': if (qualifier == 'l') { |
8acdae681 lib: vsprintf.c: ... |
618 |
long *ip = va_arg(args, long *); |
153d511e3 Initial revision |
619 620 |
*ip = (str - buf); } else { |
8acdae681 lib: vsprintf.c: ... |
621 |
int *ip = va_arg(args, int *); |
153d511e3 Initial revision |
622 623 624 625 626 |
*ip = (str - buf); } continue; case '%': |
046a37bd5 Add safe vsnprint... |
627 |
ADDCH(str, '%'); |
153d511e3 Initial revision |
628 629 630 631 632 633 |
continue; /* integer number formats - set up the flags and "break" */ case 'o': base = 8; break; |
153d511e3 Initial revision |
634 |
case 'x': |
6c6166f52 vsprintf: pull up... |
635 636 |
flags |= SMALL; case 'X': |
153d511e3 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 Add safe vsnprint... |
647 |
ADDCH(str, '%'); |
153d511e3 Initial revision |
648 |
if (*fmt) |
046a37bd5 Add safe vsnprint... |
649 |
ADDCH(str, *fmt); |
153d511e3 Initial revision |
650 651 652 653 |
else --fmt; continue; } |
6c6166f52 vsprintf: pull up... |
654 |
if (qualifier == 'L') /* "quad" for 64 bit variables */ |
c40b29568 * Patch by Rune T... |
655 |
num = va_arg(args, unsigned long long); |
4b142febf common: delete CO... |
656 |
else if (qualifier == 'l') { |
153d511e3 Initial revision |
657 |
num = va_arg(args, unsigned long); |
6c6166f52 vsprintf: pull up... |
658 659 |
if (flags & SIGN) num = (signed long) num; |
f354b73e1 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 Initial revision |
665 666 |
num = (unsigned short) va_arg(args, int); if (flags & SIGN) |
6c6166f52 vsprintf: pull up... |
667 668 |
num = (signed short) num; } else { |
153d511e3 Initial revision |
669 |
num = va_arg(args, unsigned int); |
6c6166f52 vsprintf: pull up... |
670 671 672 |
if (flags & SIGN) num = (signed int) num; } |
046a37bd5 Add safe vsnprint... |
673 674 675 |
str = number(str, end, num, base, field_width, precision, flags); } |
046a37bd5 Add safe vsnprint... |
676 677 678 679 |
if (size > 0) { ADDCH(str, '\0'); if (str > end) end[-1] = '\0'; |
686f60f51 lib: fix return c... |
680 |
--str; |
153d511e3 Initial revision |
681 |
} |
046a37bd5 Add safe vsnprint... |
682 |
/* the trailing null byte doesn't count towards the total */ |
8acdae681 lib: vsprintf.c: ... |
683 |
return str - buf; |
153d511e3 Initial revision |
684 |
} |
046a37bd5 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 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 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 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 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 lib: vsprintf.c: ... |
742 |
int sprintf(char *buf, const char *fmt, ...) |
153d511e3 Initial revision |
743 744 745 746 747 |
{ va_list args; int i; va_start(args, fmt); |
8acdae681 lib: vsprintf.c: ... |
748 |
i = vsprintf(buf, fmt, args); |
153d511e3 Initial revision |
749 750 751 |
va_end(args); return i; } |
4f1eed752 spl: Disable prin... |
752 |
#if CONFIG_IS_ENABLED(PRINTF) |
7d9cde103 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 vsprintf.c: add E... |
767 768 769 |
/* Handle error */ if (i <= 0) return i; |
7d9cde103 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 vsprintf.c: add E... |
785 786 787 |
/* Handle error */ if (i <= 0) return i; |
7d9cde103 lib/tiny-printf.c... |
788 789 790 791 |
/* Print the string */ puts(printbuffer); return i; } |
4f1eed752 spl: Disable prin... |
792 |
#endif |
66312374d dm: Add a panic_s... |
793 |
|
3cce8a549 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 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 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'; } |