1 /* 2 * linux/lib/vsprintf.c 3 * 4 * Copyright (C) 1991, 1992 Linus Torvalds 5 */ 6 7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ 8 /* 9 * Wirzenius wrote this portably, Torvalds fucked it up :-) 10 * 11 * from hush: simple_itoa() was lifted from boa-0.93.15 12 */ 13 14 #include <stdarg.h> 15 #include <linux/types.h> 16 #include <linux/string.h> 17 #include <linux/ctype.h> 18 #include <errno.h> 19 20 #include <common.h> 21 #if !defined(CONFIG_PANIC_HANG) 22 #include <command.h> 23 #endif 24 25 #include <div64.h> 26 #define noinline __attribute__((noinline)) 27 28 /* some reluctance to put this into a new limits.h, so it is here */ 29 #define INT_MAX ((int)(~0U>>1)) 30 31 static const char hex_asc[] = "0123456789abcdef"; 32 #define hex_asc_lo(x) hex_asc[((x) & 0x0f)] 33 #define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] 34 35 static inline char *pack_hex_byte(char *buf, u8 byte) 36 { 37 *buf++ = hex_asc_hi(byte); 38 *buf++ = hex_asc_lo(byte); 39 return buf; 40 } 41 42 unsigned long simple_strtoul(const char *cp, char **endp, 43 unsigned int base) 44 { 45 unsigned long result = 0; 46 unsigned long value; 47 48 if (*cp == '0') { 49 cp++; 50 if ((*cp == 'x') && isxdigit(cp[1])) { 51 base = 16; 52 cp++; 53 } 54 55 if (!base) 56 base = 8; 57 } 58 59 if (!base) 60 base = 10; 61 62 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) 63 ? toupper(*cp) : *cp)-'A'+10) < base) { 64 result = result*base + value; 65 cp++; 66 } 67 68 if (endp) 69 *endp = (char *)cp; 70 71 return result; 72 } 73 74 int strict_strtoul(const char *cp, unsigned int base, unsigned long *res) 75 { 76 char *tail; 77 unsigned long val; 78 size_t len; 79 80 *res = 0; 81 len = strlen(cp); 82 if (len == 0) 83 return -EINVAL; 84 85 val = simple_strtoul(cp, &tail, base); 86 if (tail == cp) 87 return -EINVAL; 88 89 if ((*tail == '\0') || 90 ((len == (size_t)(tail - cp) + 1) && (*tail == '\n'))) { 91 *res = val; 92 return 0; 93 } 94 95 return -EINVAL; 96 } 97 98 long simple_strtol(const char *cp, char **endp, unsigned int base) 99 { 100 if (*cp == '-') 101 return -simple_strtoul(cp + 1, endp, base); 102 103 return simple_strtoul(cp, endp, base); 104 } 105 106 unsigned long ustrtoul(const char *cp, char **endp, unsigned int base) 107 { 108 unsigned long result = simple_strtoul(cp, endp, base); 109 switch (**endp) { 110 case 'G': 111 result *= 1024; 112 /* fall through */ 113 case 'M': 114 result *= 1024; 115 /* fall through */ 116 case 'K': 117 case 'k': 118 result *= 1024; 119 if ((*endp)[1] == 'i') { 120 if ((*endp)[2] == 'B') 121 (*endp) += 3; 122 else 123 (*endp) += 2; 124 } 125 } 126 return result; 127 } 128 129 unsigned long long simple_strtoull(const char *cp, char **endp, 130 unsigned int base) 131 { 132 unsigned long long result = 0, value; 133 134 if (*cp == '0') { 135 cp++; 136 if ((*cp == 'x') && isxdigit(cp[1])) { 137 base = 16; 138 cp++; 139 } 140 141 if (!base) 142 base = 8; 143 } 144 145 if (!base) 146 base = 10; 147 148 while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp - '0' 149 : (islower(*cp) ? toupper(*cp) : *cp) - 'A' + 10) < base) { 150 result = result * base + value; 151 cp++; 152 } 153 154 if (endp) 155 *endp = (char *) cp; 156 157 return result; 158 } 159 160 /* we use this so that we can do without the ctype library */ 161 #define is_digit(c) ((c) >= '0' && (c) <= '9') 162 163 static int skip_atoi(const char **s) 164 { 165 int i = 0; 166 167 while (is_digit(**s)) 168 i = i * 10 + *((*s)++) - '0'; 169 170 return i; 171 } 172 173 /* Decimal conversion is by far the most typical, and is used 174 * for /proc and /sys data. This directly impacts e.g. top performance 175 * with many processes running. We optimize it for speed 176 * using code from 177 * http://www.cs.uiowa.edu/~jones/bcd/decimal.html 178 * (with permission from the author, Douglas W. Jones). */ 179 180 /* Formats correctly any integer in [0,99999]. 181 * Outputs from one to five digits depending on input. 182 * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ 183 static char *put_dec_trunc(char *buf, unsigned q) 184 { 185 unsigned d3, d2, d1, d0; 186 d1 = (q>>4) & 0xf; 187 d2 = (q>>8) & 0xf; 188 d3 = (q>>12); 189 190 d0 = 6*(d3 + d2 + d1) + (q & 0xf); 191 q = (d0 * 0xcd) >> 11; 192 d0 = d0 - 10*q; 193 *buf++ = d0 + '0'; /* least significant digit */ 194 d1 = q + 9*d3 + 5*d2 + d1; 195 if (d1 != 0) { 196 q = (d1 * 0xcd) >> 11; 197 d1 = d1 - 10*q; 198 *buf++ = d1 + '0'; /* next digit */ 199 200 d2 = q + 2*d2; 201 if ((d2 != 0) || (d3 != 0)) { 202 q = (d2 * 0xd) >> 7; 203 d2 = d2 - 10*q; 204 *buf++ = d2 + '0'; /* next digit */ 205 206 d3 = q + 4*d3; 207 if (d3 != 0) { 208 q = (d3 * 0xcd) >> 11; 209 d3 = d3 - 10*q; 210 *buf++ = d3 + '0'; /* next digit */ 211 if (q != 0) 212 *buf++ = q + '0'; /* most sign. digit */ 213 } 214 } 215 } 216 return buf; 217 } 218 /* Same with if's removed. Always emits five digits */ 219 static char *put_dec_full(char *buf, unsigned q) 220 { 221 /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ 222 /* but anyway, gcc produces better code with full-sized ints */ 223 unsigned d3, d2, d1, d0; 224 d1 = (q>>4) & 0xf; 225 d2 = (q>>8) & 0xf; 226 d3 = (q>>12); 227 228 /* 229 * Possible ways to approx. divide by 10 230 * gcc -O2 replaces multiply with shifts and adds 231 * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) 232 * (x * 0x67) >> 10: 1100111 233 * (x * 0x34) >> 9: 110100 - same 234 * (x * 0x1a) >> 8: 11010 - same 235 * (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) 236 */ 237 238 d0 = 6*(d3 + d2 + d1) + (q & 0xf); 239 q = (d0 * 0xcd) >> 11; 240 d0 = d0 - 10*q; 241 *buf++ = d0 + '0'; 242 d1 = q + 9*d3 + 5*d2 + d1; 243 q = (d1 * 0xcd) >> 11; 244 d1 = d1 - 10*q; 245 *buf++ = d1 + '0'; 246 247 d2 = q + 2*d2; 248 q = (d2 * 0xd) >> 7; 249 d2 = d2 - 10*q; 250 *buf++ = d2 + '0'; 251 252 d3 = q + 4*d3; 253 q = (d3 * 0xcd) >> 11; /* - shorter code */ 254 /* q = (d3 * 0x67) >> 10; - would also work */ 255 d3 = d3 - 10*q; 256 *buf++ = d3 + '0'; 257 *buf++ = q + '0'; 258 return buf; 259 } 260 /* No inlining helps gcc to use registers better */ 261 static noinline char *put_dec(char *buf, u64 num) 262 { 263 while (1) { 264 unsigned rem; 265 if (num < 100000) 266 return put_dec_trunc(buf, num); 267 rem = do_div(num, 100000); 268 buf = put_dec_full(buf, rem); 269 } 270 } 271 272 #define ZEROPAD 1 /* pad with zero */ 273 #define SIGN 2 /* unsigned/signed long */ 274 #define PLUS 4 /* show plus */ 275 #define SPACE 8 /* space if plus */ 276 #define LEFT 16 /* left justified */ 277 #define SMALL 32 /* Must be 32 == 0x20 */ 278 #define SPECIAL 64 /* 0x */ 279 280 #ifdef CONFIG_SYS_VSNPRINTF 281 /* 282 * Macro to add a new character to our output string, but only if it will 283 * fit. The macro moves to the next character position in the output string. 284 */ 285 #define ADDCH(str, ch) do { \ 286 if ((str) < end) \ 287 *(str) = (ch); \ 288 ++str; \ 289 } while (0) 290 #else 291 #define ADDCH(str, ch) (*(str)++ = (ch)) 292 #endif 293 294 static char *number(char *buf, char *end, u64 num, 295 int base, int size, int precision, int type) 296 { 297 /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ 298 static const char digits[16] = "0123456789ABCDEF"; 299 300 char tmp[66]; 301 char sign; 302 char locase; 303 int need_pfx = ((type & SPECIAL) && base != 10); 304 int i; 305 306 /* locase = 0 or 0x20. ORing digits or letters with 'locase' 307 * produces same digits or (maybe lowercased) letters */ 308 locase = (type & SMALL); 309 if (type & LEFT) 310 type &= ~ZEROPAD; 311 sign = 0; 312 if (type & SIGN) { 313 if ((s64) num < 0) { 314 sign = '-'; 315 num = -(s64) num; 316 size--; 317 } else if (type & PLUS) { 318 sign = '+'; 319 size--; 320 } else if (type & SPACE) { 321 sign = ' '; 322 size--; 323 } 324 } 325 if (need_pfx) { 326 size--; 327 if (base == 16) 328 size--; 329 } 330 331 /* generate full string in tmp[], in reverse order */ 332 i = 0; 333 if (num == 0) 334 tmp[i++] = '0'; 335 /* Generic code, for any base: 336 else do { 337 tmp[i++] = (digits[do_div(num,base)] | locase); 338 } while (num != 0); 339 */ 340 else if (base != 10) { /* 8 or 16 */ 341 int mask = base - 1; 342 int shift = 3; 343 344 if (base == 16) 345 shift = 4; 346 347 do { 348 tmp[i++] = (digits[((unsigned char)num) & mask] 349 | locase); 350 num >>= shift; 351 } while (num); 352 } else { /* base 10 */ 353 i = put_dec(tmp, num) - tmp; 354 } 355 356 /* printing 100 using %2d gives "100", not "00" */ 357 if (i > precision) 358 precision = i; 359 /* leading space padding */ 360 size -= precision; 361 if (!(type & (ZEROPAD + LEFT))) { 362 while (--size >= 0) 363 ADDCH(buf, ' '); 364 } 365 /* sign */ 366 if (sign) 367 ADDCH(buf, sign); 368 /* "0x" / "0" prefix */ 369 if (need_pfx) { 370 ADDCH(buf, '0'); 371 if (base == 16) 372 ADDCH(buf, 'X' | locase); 373 } 374 /* zero or space padding */ 375 if (!(type & LEFT)) { 376 char c = (type & ZEROPAD) ? '0' : ' '; 377 378 while (--size >= 0) 379 ADDCH(buf, c); 380 } 381 /* hmm even more zero padding? */ 382 while (i <= --precision) 383 ADDCH(buf, '0'); 384 /* actual digits of result */ 385 while (--i >= 0) 386 ADDCH(buf, tmp[i]); 387 /* trailing space padding */ 388 while (--size >= 0) 389 ADDCH(buf, ' '); 390 return buf; 391 } 392 393 static char *string(char *buf, char *end, char *s, int field_width, 394 int precision, int flags) 395 { 396 int len, i; 397 398 if (s == NULL) 399 s = "<NULL>"; 400 401 len = strnlen(s, precision); 402 403 if (!(flags & LEFT)) 404 while (len < field_width--) 405 ADDCH(buf, ' '); 406 for (i = 0; i < len; ++i) 407 ADDCH(buf, *s++); 408 while (len < field_width--) 409 ADDCH(buf, ' '); 410 return buf; 411 } 412 413 #ifdef CONFIG_CMD_NET 414 static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width, 415 int precision, int flags) 416 { 417 /* (6 * 2 hex digits), 5 colons and trailing zero */ 418 char mac_addr[6 * 3]; 419 char *p = mac_addr; 420 int i; 421 422 for (i = 0; i < 6; i++) { 423 p = pack_hex_byte(p, addr[i]); 424 if (!(flags & SPECIAL) && i != 5) 425 *p++ = ':'; 426 } 427 *p = '\0'; 428 429 return string(buf, end, mac_addr, field_width, precision, 430 flags & ~SPECIAL); 431 } 432 433 static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width, 434 int precision, int flags) 435 { 436 /* (8 * 4 hex digits), 7 colons and trailing zero */ 437 char ip6_addr[8 * 5]; 438 char *p = ip6_addr; 439 int i; 440 441 for (i = 0; i < 8; i++) { 442 p = pack_hex_byte(p, addr[2 * i]); 443 p = pack_hex_byte(p, addr[2 * i + 1]); 444 if (!(flags & SPECIAL) && i != 7) 445 *p++ = ':'; 446 } 447 *p = '\0'; 448 449 return string(buf, end, ip6_addr, field_width, precision, 450 flags & ~SPECIAL); 451 } 452 453 static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width, 454 int precision, int flags) 455 { 456 /* (4 * 3 decimal digits), 3 dots and trailing zero */ 457 char ip4_addr[4 * 4]; 458 char temp[3]; /* hold each IP quad in reverse order */ 459 char *p = ip4_addr; 460 int i, digits; 461 462 for (i = 0; i < 4; i++) { 463 digits = put_dec_trunc(temp, addr[i]) - temp; 464 /* reverse the digits in the quad */ 465 while (digits--) 466 *p++ = temp[digits]; 467 if (i != 3) 468 *p++ = '.'; 469 } 470 *p = '\0'; 471 472 return string(buf, end, ip4_addr, field_width, precision, 473 flags & ~SPECIAL); 474 } 475 #endif 476 477 /* 478 * Show a '%p' thing. A kernel extension is that the '%p' is followed 479 * by an extra set of alphanumeric characters that are extended format 480 * specifiers. 481 * 482 * Right now we handle: 483 * 484 * - 'M' For a 6-byte MAC address, it prints the address in the 485 * usual colon-separated hex notation 486 * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated 487 * decimal for v4 and colon separated network-order 16 bit hex for v6) 488 * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is 489 * currently the same 490 * 491 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 492 * function pointers are really function descriptors, which contain a 493 * pointer to the real address. 494 */ 495 static char *pointer(const char *fmt, char *buf, char *end, void *ptr, 496 int field_width, int precision, int flags) 497 { 498 /* 499 * Being a boot loader, we explicitly allow pointers to 500 * (physical) address null. 501 */ 502 #if 0 503 if (!ptr) 504 return string(buf, end, "(null)", field_width, precision, 505 flags); 506 #endif 507 508 #ifdef CONFIG_CMD_NET 509 switch (*fmt) { 510 case 'm': 511 flags |= SPECIAL; 512 /* Fallthrough */ 513 case 'M': 514 return mac_address_string(buf, end, ptr, field_width, 515 precision, flags); 516 case 'i': 517 flags |= SPECIAL; 518 /* Fallthrough */ 519 case 'I': 520 if (fmt[1] == '6') 521 return ip6_addr_string(buf, end, ptr, field_width, 522 precision, flags); 523 if (fmt[1] == '4') 524 return ip4_addr_string(buf, end, ptr, field_width, 525 precision, flags); 526 flags &= ~SPECIAL; 527 break; 528 } 529 #endif 530 flags |= SMALL; 531 if (field_width == -1) { 532 field_width = 2*sizeof(void *); 533 flags |= ZEROPAD; 534 } 535 return number(buf, end, (unsigned long)ptr, 16, field_width, 536 precision, flags); 537 } 538 539 static int vsnprintf_internal(char *buf, size_t size, const char *fmt, 540 va_list args) 541 { 542 u64 num; 543 int base; 544 char *str; 545 546 int flags; /* flags to number() */ 547 548 int field_width; /* width of output field */ 549 int precision; /* min. # of digits for integers; max 550 number of chars for from string */ 551 int qualifier; /* 'h', 'l', or 'L' for integer fields */ 552 /* 'z' support added 23/7/1999 S.H. */ 553 /* 'z' changed to 'Z' --davidm 1/25/99 */ 554 /* 't' added for ptrdiff_t */ 555 char *end = buf + size; 556 557 #ifdef CONFIG_SYS_VSNPRINTF 558 /* Make sure end is always >= buf - do we want this in U-Boot? */ 559 if (end < buf) { 560 end = ((void *)-1); 561 size = end - buf; 562 } 563 #endif 564 str = buf; 565 566 for (; *fmt ; ++fmt) { 567 if (*fmt != '%') { 568 ADDCH(str, *fmt); 569 continue; 570 } 571 572 /* process flags */ 573 flags = 0; 574 repeat: 575 ++fmt; /* this also skips first '%' */ 576 switch (*fmt) { 577 case '-': 578 flags |= LEFT; 579 goto repeat; 580 case '+': 581 flags |= PLUS; 582 goto repeat; 583 case ' ': 584 flags |= SPACE; 585 goto repeat; 586 case '#': 587 flags |= SPECIAL; 588 goto repeat; 589 case '0': 590 flags |= ZEROPAD; 591 goto repeat; 592 } 593 594 /* get field width */ 595 field_width = -1; 596 if (is_digit(*fmt)) 597 field_width = skip_atoi(&fmt); 598 else if (*fmt == '*') { 599 ++fmt; 600 /* it's the next argument */ 601 field_width = va_arg(args, int); 602 if (field_width < 0) { 603 field_width = -field_width; 604 flags |= LEFT; 605 } 606 } 607 608 /* get the precision */ 609 precision = -1; 610 if (*fmt == '.') { 611 ++fmt; 612 if (is_digit(*fmt)) 613 precision = skip_atoi(&fmt); 614 else if (*fmt == '*') { 615 ++fmt; 616 /* it's the next argument */ 617 precision = va_arg(args, int); 618 } 619 if (precision < 0) 620 precision = 0; 621 } 622 623 /* get the conversion qualifier */ 624 qualifier = -1; 625 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || 626 *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { 627 qualifier = *fmt; 628 ++fmt; 629 if (qualifier == 'l' && *fmt == 'l') { 630 qualifier = 'L'; 631 ++fmt; 632 } 633 } 634 635 /* default base */ 636 base = 10; 637 638 switch (*fmt) { 639 case 'c': 640 if (!(flags & LEFT)) { 641 while (--field_width > 0) 642 ADDCH(str, ' '); 643 } 644 ADDCH(str, (unsigned char) va_arg(args, int)); 645 while (--field_width > 0) 646 ADDCH(str, ' '); 647 continue; 648 649 case 's': 650 str = string(str, end, va_arg(args, char *), 651 field_width, precision, flags); 652 continue; 653 654 case 'p': 655 str = pointer(fmt + 1, str, end, 656 va_arg(args, void *), 657 field_width, precision, flags); 658 /* Skip all alphanumeric pointer suffixes */ 659 while (isalnum(fmt[1])) 660 fmt++; 661 continue; 662 663 case 'n': 664 if (qualifier == 'l') { 665 long *ip = va_arg(args, long *); 666 *ip = (str - buf); 667 } else { 668 int *ip = va_arg(args, int *); 669 *ip = (str - buf); 670 } 671 continue; 672 673 case '%': 674 ADDCH(str, '%'); 675 continue; 676 677 /* integer number formats - set up the flags and "break" */ 678 case 'o': 679 base = 8; 680 break; 681 682 case 'x': 683 flags |= SMALL; 684 case 'X': 685 base = 16; 686 break; 687 688 case 'd': 689 case 'i': 690 flags |= SIGN; 691 case 'u': 692 break; 693 694 default: 695 ADDCH(str, '%'); 696 if (*fmt) 697 ADDCH(str, *fmt); 698 else 699 --fmt; 700 continue; 701 } 702 if (qualifier == 'L') /* "quad" for 64 bit variables */ 703 num = va_arg(args, unsigned long long); 704 else if (qualifier == 'l') { 705 num = va_arg(args, unsigned long); 706 if (flags & SIGN) 707 num = (signed long) num; 708 } else if (qualifier == 'Z' || qualifier == 'z') { 709 num = va_arg(args, size_t); 710 } else if (qualifier == 't') { 711 num = va_arg(args, ptrdiff_t); 712 } else if (qualifier == 'h') { 713 num = (unsigned short) va_arg(args, int); 714 if (flags & SIGN) 715 num = (signed short) num; 716 } else { 717 num = va_arg(args, unsigned int); 718 if (flags & SIGN) 719 num = (signed int) num; 720 } 721 str = number(str, end, num, base, field_width, precision, 722 flags); 723 } 724 725 #ifdef CONFIG_SYS_VSNPRINTF 726 if (size > 0) { 727 ADDCH(str, '\0'); 728 if (str > end) 729 end[-1] = '\0'; 730 } 731 #else 732 *str = '\0'; 733 #endif 734 /* the trailing null byte doesn't count towards the total */ 735 return str - buf; 736 } 737 738 #ifdef CONFIG_SYS_VSNPRINTF 739 int vsnprintf(char *buf, size_t size, const char *fmt, 740 va_list args) 741 { 742 return vsnprintf_internal(buf, size, fmt, args); 743 } 744 745 int vscnprintf(char *buf, size_t size, const char *fmt, va_list args) 746 { 747 int i; 748 749 i = vsnprintf(buf, size, fmt, args); 750 751 if (likely(i < size)) 752 return i; 753 if (size != 0) 754 return size - 1; 755 return 0; 756 } 757 758 int snprintf(char *buf, size_t size, const char *fmt, ...) 759 { 760 va_list args; 761 int i; 762 763 va_start(args, fmt); 764 i = vsnprintf(buf, size, fmt, args); 765 va_end(args); 766 767 return i; 768 } 769 770 int scnprintf(char *buf, size_t size, const char *fmt, ...) 771 { 772 va_list args; 773 int i; 774 775 va_start(args, fmt); 776 i = vscnprintf(buf, size, fmt, args); 777 va_end(args); 778 779 return i; 780 } 781 #endif /* CONFIG_SYS_VSNPRINT */ 782 783 /** 784 * Format a string and place it in a buffer (va_list version) 785 * 786 * @param buf The buffer to place the result into 787 * @param fmt The format string to use 788 * @param args Arguments for the format string 789 * 790 * The function returns the number of characters written 791 * into @buf. Use vsnprintf() or vscnprintf() in order to avoid 792 * buffer overflows. 793 * 794 * If you're not already dealing with a va_list consider using sprintf(). 795 */ 796 int vsprintf(char *buf, const char *fmt, va_list args) 797 { 798 return vsnprintf_internal(buf, INT_MAX, fmt, args); 799 } 800 801 int sprintf(char *buf, const char *fmt, ...) 802 { 803 va_list args; 804 int i; 805 806 va_start(args, fmt); 807 i = vsprintf(buf, fmt, args); 808 va_end(args); 809 return i; 810 } 811 812 void panic(const char *fmt, ...) 813 { 814 va_list args; 815 va_start(args, fmt); 816 vprintf(fmt, args); 817 putc('\n'); 818 va_end(args); 819 #if defined(CONFIG_PANIC_HANG) 820 hang(); 821 #else 822 udelay(100000); /* allow messages to go out */ 823 do_reset(NULL, 0, 0, NULL); 824 #endif 825 while (1) 826 ; 827 } 828 829 void __assert_fail(const char *assertion, const char *file, unsigned line, 830 const char *function) 831 { 832 /* This will not return */ 833 panic("%s:%u: %s: Assertion `%s' failed.", file, line, function, 834 assertion); 835 } 836 837 char *simple_itoa(ulong i) 838 { 839 /* 21 digits plus null terminator, good for 64-bit or smaller ints */ 840 static char local[22]; 841 char *p = &local[21]; 842 843 *p-- = '\0'; 844 do { 845 *p-- = '0' + i % 10; 846 i /= 10; 847 } while (i > 0); 848 return p + 1; 849 } 850