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