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