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 <vsprintf.h>
  23#include <linux/ctype.h>
  24#include <linux/err.h>
  25#include <linux/types.h>
  26#include <linux/string.h>
  27
  28#define noinline __attribute__((noinline))
  29
  30/* we use this so that we can do without the ctype library */
  31#define is_digit(c)     ((c) >= '0' && (c) <= '9')
  32
  33static int skip_atoi(const char **s)
  34{
  35        int i = 0;
  36
  37        while (is_digit(**s))
  38                i = i * 10 + *((*s)++) - '0';
  39
  40        return i;
  41}
  42
  43/* Decimal conversion is by far the most typical, and is used
  44 * for /proc and /sys data. This directly impacts e.g. top performance
  45 * with many processes running. We optimize it for speed
  46 * using code from
  47 * http://www.cs.uiowa.edu/~jones/bcd/decimal.html
  48 * (with permission from the author, Douglas W. Jones). */
  49
  50/* Formats correctly any integer in [0,99999].
  51 * Outputs from one to five digits depending on input.
  52 * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */
  53static char *put_dec_trunc(char *buf, unsigned q)
  54{
  55        unsigned d3, d2, d1, d0;
  56        d1 = (q>>4) & 0xf;
  57        d2 = (q>>8) & 0xf;
  58        d3 = (q>>12);
  59
  60        d0 = 6*(d3 + d2 + d1) + (q & 0xf);
  61        q = (d0 * 0xcd) >> 11;
  62        d0 = d0 - 10*q;
  63        *buf++ = d0 + '0'; /* least significant digit */
  64        d1 = q + 9*d3 + 5*d2 + d1;
  65        if (d1 != 0) {
  66                q = (d1 * 0xcd) >> 11;
  67                d1 = d1 - 10*q;
  68                *buf++ = d1 + '0'; /* next digit */
  69
  70                d2 = q + 2*d2;
  71                if ((d2 != 0) || (d3 != 0)) {
  72                        q = (d2 * 0xd) >> 7;
  73                        d2 = d2 - 10*q;
  74                        *buf++ = d2 + '0'; /* next digit */
  75
  76                        d3 = q + 4*d3;
  77                        if (d3 != 0) {
  78                                q = (d3 * 0xcd) >> 11;
  79                                d3 = d3 - 10*q;
  80                                *buf++ = d3 + '0';  /* next digit */
  81                                if (q != 0)
  82                                        *buf++ = q + '0'; /* most sign. digit */
  83                        }
  84                }
  85        }
  86        return buf;
  87}
  88/* Same with if's removed. Always emits five digits */
  89static char *put_dec_full(char *buf, unsigned q)
  90{
  91        /* BTW, if q is in [0,9999], 8-bit ints will be enough, */
  92        /* but anyway, gcc produces better code with full-sized ints */
  93        unsigned d3, d2, d1, d0;
  94        d1 = (q>>4) & 0xf;
  95        d2 = (q>>8) & 0xf;
  96        d3 = (q>>12);
  97
  98        /*
  99         * Possible ways to approx. divide by 10
 100         * gcc -O2 replaces multiply with shifts and adds
 101         * (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386)
 102         * (x * 0x67) >> 10:  1100111
 103         * (x * 0x34) >> 9:    110100 - same
 104         * (x * 0x1a) >> 8:     11010 - same
 105         * (x * 0x0d) >> 7:      1101 - same, shortest code (on i386)
 106         */
 107
 108        d0 = 6*(d3 + d2 + d1) + (q & 0xf);
 109        q = (d0 * 0xcd) >> 11;
 110        d0 = d0 - 10*q;
 111        *buf++ = d0 + '0';
 112        d1 = q + 9*d3 + 5*d2 + d1;
 113                q = (d1 * 0xcd) >> 11;
 114                d1 = d1 - 10*q;
 115                *buf++ = d1 + '0';
 116
 117                d2 = q + 2*d2;
 118                        q = (d2 * 0xd) >> 7;
 119                        d2 = d2 - 10*q;
 120                        *buf++ = d2 + '0';
 121
 122                        d3 = q + 4*d3;
 123                                q = (d3 * 0xcd) >> 11; /* - shorter code */
 124                                /* q = (d3 * 0x67) >> 10; - would also work */
 125                                d3 = d3 - 10*q;
 126                                *buf++ = d3 + '0';
 127                                        *buf++ = q + '0';
 128        return buf;
 129}
 130/* No inlining helps gcc to use registers better */
 131static noinline char *put_dec(char *buf, uint64_t num)
 132{
 133        while (1) {
 134                unsigned rem;
 135                if (num < 100000)
 136                        return put_dec_trunc(buf, num);
 137                rem = do_div(num, 100000);
 138                buf = put_dec_full(buf, rem);
 139        }
 140}
 141
 142#define ZEROPAD 1               /* pad with zero */
 143#define SIGN    2               /* unsigned/signed long */
 144#define PLUS    4               /* show plus */
 145#define SPACE   8               /* space if plus */
 146#define LEFT    16              /* left justified */
 147#define SMALL   32              /* Must be 32 == 0x20 */
 148#define SPECIAL 64              /* 0x */
 149
 150/*
 151 * Macro to add a new character to our output string, but only if it will
 152 * fit. The macro moves to the next character position in the output string.
 153 */
 154#define ADDCH(str, ch) do { \
 155        if ((str) < end) \
 156                *(str) = (ch); \
 157        ++str; \
 158        } while (0)
 159
 160static char *number(char *buf, char *end, u64 num,
 161                int base, int size, int precision, int type)
 162{
 163        /* we are called with base 8, 10 or 16, only, thus don't need "G..."  */
 164        static const char digits[16] = "0123456789ABCDEF";
 165
 166        char tmp[66];
 167        char sign;
 168        char locase;
 169        int need_pfx = ((type & SPECIAL) && base != 10);
 170        int i;
 171
 172        /* locase = 0 or 0x20. ORing digits or letters with 'locase'
 173         * produces same digits or (maybe lowercased) letters */
 174        locase = (type & SMALL);
 175        if (type & LEFT)
 176                type &= ~ZEROPAD;
 177        sign = 0;
 178        if (type & SIGN) {
 179                if ((s64) num < 0) {
 180                        sign = '-';
 181                        num = -(s64) num;
 182                        size--;
 183                } else if (type & PLUS) {
 184                        sign = '+';
 185                        size--;
 186                } else if (type & SPACE) {
 187                        sign = ' ';
 188                        size--;
 189                }
 190        }
 191        if (need_pfx) {
 192                size--;
 193                if (base == 16)
 194                        size--;
 195        }
 196
 197        /* generate full string in tmp[], in reverse order */
 198        i = 0;
 199        if (num == 0)
 200                tmp[i++] = '0';
 201        /* Generic code, for any base:
 202        else do {
 203                tmp[i++] = (digits[do_div(num,base)] | locase);
 204        } while (num != 0);
 205        */
 206        else if (base != 10) { /* 8 or 16 */
 207                int mask = base - 1;
 208                int shift = 3;
 209
 210                if (base == 16)
 211                        shift = 4;
 212
 213                do {
 214                        tmp[i++] = (digits[((unsigned char)num) & mask]
 215                                        | locase);
 216                        num >>= shift;
 217                } while (num);
 218        } else { /* base 10 */
 219                i = put_dec(tmp, num) - tmp;
 220        }
 221
 222        /* printing 100 using %2d gives "100", not "00" */
 223        if (i > precision)
 224                precision = i;
 225        /* leading space padding */
 226        size -= precision;
 227        if (!(type & (ZEROPAD + LEFT))) {
 228                while (--size >= 0)
 229                        ADDCH(buf, ' ');
 230        }
 231        /* sign */
 232        if (sign)
 233                ADDCH(buf, sign);
 234        /* "0x" / "0" prefix */
 235        if (need_pfx) {
 236                ADDCH(buf, '0');
 237                if (base == 16)
 238                        ADDCH(buf, 'X' | locase);
 239        }
 240        /* zero or space padding */
 241        if (!(type & LEFT)) {
 242                char c = (type & ZEROPAD) ? '0' : ' ';
 243
 244                while (--size >= 0)
 245                        ADDCH(buf, c);
 246        }
 247        /* hmm even more zero padding? */
 248        while (i <= --precision)
 249                ADDCH(buf, '0');
 250        /* actual digits of result */
 251        while (--i >= 0)
 252                ADDCH(buf, tmp[i]);
 253        /* trailing space padding */
 254        while (--size >= 0)
 255                ADDCH(buf, ' ');
 256        return buf;
 257}
 258
 259static char *string(char *buf, char *end, char *s, int field_width,
 260                int precision, int flags)
 261{
 262        int len, i;
 263
 264        if (s == NULL)
 265                s = "<NULL>";
 266
 267        len = strnlen(s, precision);
 268
 269        if (!(flags & LEFT))
 270                while (len < field_width--)
 271                        ADDCH(buf, ' ');
 272        for (i = 0; i < len; ++i)
 273                ADDCH(buf, *s++);
 274        while (len < field_width--)
 275                ADDCH(buf, ' ');
 276        return buf;
 277}
 278
 279/* U-Boot uses UTF-16 strings in the EFI context only. */
 280#if CONFIG_IS_ENABLED(EFI_LOADER) && !defined(API_BUILD)
 281static char *string16(char *buf, char *end, u16 *s, int field_width,
 282                int precision, int flags)
 283{
 284        const u16 *str = s ? s : L"<NULL>";
 285        ssize_t i, len = utf16_strnlen(str, precision);
 286
 287        if (!(flags & LEFT))
 288                for (; len < field_width; --field_width)
 289                        ADDCH(buf, ' ');
 290        for (i = 0; i < len && buf + utf16_utf8_strnlen(str, 1) <= end; ++i) {
 291                s32 s = utf16_get(&str);
 292
 293                if (s < 0)
 294                        s = '?';
 295                utf8_put(s, &buf);
 296        }
 297        for (; len < field_width; --field_width)
 298                ADDCH(buf, ' ');
 299        return buf;
 300}
 301
 302#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT)
 303static char *device_path_string(char *buf, char *end, void *dp, int field_width,
 304                                int precision, int flags)
 305{
 306        u16 *str;
 307
 308        /* If dp == NULL output the string '<NULL>' */
 309        if (!dp)
 310                return string16(buf, end, dp, field_width, precision, flags);
 311
 312        str = efi_dp_str((struct efi_device_path *)dp);
 313        if (!str)
 314                return ERR_PTR(-ENOMEM);
 315
 316        buf = string16(buf, end, str, field_width, precision, flags);
 317        efi_free_pool(str);
 318        return buf;
 319}
 320#endif
 321#endif
 322
 323static char *mac_address_string(char *buf, char *end, u8 *addr, int field_width,
 324                                int precision, int flags)
 325{
 326        /* (6 * 2 hex digits), 5 colons and trailing zero */
 327        char mac_addr[6 * 3];
 328        char *p = mac_addr;
 329        int i;
 330
 331        for (i = 0; i < 6; i++) {
 332                p = hex_byte_pack(p, addr[i]);
 333                if (!(flags & SPECIAL) && i != 5)
 334                        *p++ = ':';
 335        }
 336        *p = '\0';
 337
 338        return string(buf, end, mac_addr, field_width, precision,
 339                      flags & ~SPECIAL);
 340}
 341
 342static char *ip6_addr_string(char *buf, char *end, u8 *addr, int field_width,
 343                         int precision, int flags)
 344{
 345        /* (8 * 4 hex digits), 7 colons and trailing zero */
 346        char ip6_addr[8 * 5];
 347        char *p = ip6_addr;
 348        int i;
 349
 350        for (i = 0; i < 8; i++) {
 351                p = hex_byte_pack(p, addr[2 * i]);
 352                p = hex_byte_pack(p, addr[2 * i + 1]);
 353                if (!(flags & SPECIAL) && i != 7)
 354                        *p++ = ':';
 355        }
 356        *p = '\0';
 357
 358        return string(buf, end, ip6_addr, field_width, precision,
 359                      flags & ~SPECIAL);
 360}
 361
 362static char *ip4_addr_string(char *buf, char *end, u8 *addr, int field_width,
 363                         int precision, int flags)
 364{
 365        /* (4 * 3 decimal digits), 3 dots and trailing zero */
 366        char ip4_addr[4 * 4];
 367        char temp[3];   /* hold each IP quad in reverse order */
 368        char *p = ip4_addr;
 369        int i, digits;
 370
 371        for (i = 0; i < 4; i++) {
 372                digits = put_dec_trunc(temp, addr[i]) - temp;
 373                /* reverse the digits in the quad */
 374                while (digits--)
 375                        *p++ = temp[digits];
 376                if (i != 3)
 377                        *p++ = '.';
 378        }
 379        *p = '\0';
 380
 381        return string(buf, end, ip4_addr, field_width, precision,
 382                      flags & ~SPECIAL);
 383}
 384
 385#ifdef CONFIG_LIB_UUID
 386/*
 387 * This works (roughly) the same way as Linux's.
 388 *
 389 *   %pUb:   01020304-0506-0708-090a-0b0c0d0e0f10
 390 *   %pUB:   01020304-0506-0708-090A-0B0C0D0E0F10
 391 *   %pUl:   04030201-0605-0807-090a-0b0c0d0e0f10
 392 *   %pUL:   04030201-0605-0807-090A-0B0C0D0E0F10
 393 */
 394static char *uuid_string(char *buf, char *end, u8 *addr, int field_width,
 395                         int precision, int flags, const char *fmt)
 396{
 397        char uuid[UUID_STR_LEN + 1];
 398        int str_format;
 399
 400        switch (*(++fmt)) {
 401        case 'L':
 402                str_format = UUID_STR_FORMAT_GUID | UUID_STR_UPPER_CASE;
 403                break;
 404        case 'l':
 405                str_format = UUID_STR_FORMAT_GUID;
 406                break;
 407        case 'B':
 408                str_format = UUID_STR_FORMAT_STD | UUID_STR_UPPER_CASE;
 409                break;
 410        default:
 411                str_format = UUID_STR_FORMAT_STD;
 412                break;
 413        }
 414
 415        if (addr)
 416                uuid_bin_to_str(addr, uuid, str_format);
 417        else
 418                strcpy(uuid, "<NULL>");
 419
 420        return string(buf, end, uuid, field_width, precision, flags);
 421}
 422#endif
 423
 424/*
 425 * Show a '%p' thing.  A kernel extension is that the '%p' is followed
 426 * by an extra set of alphanumeric characters that are extended format
 427 * specifiers.
 428 *
 429 * Right now we handle:
 430 *
 431 * - 'M' For a 6-byte MAC address, it prints the address in the
 432 *       usual colon-separated hex notation
 433 * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way (dot-separated
 434 *       decimal for v4 and colon separated network-order 16 bit hex for v6)
 435 * - 'i' [46] for 'raw' IPv4/IPv6 addresses, IPv6 omits the colons, IPv4 is
 436 *       currently the same
 437 *
 438 * Note: The difference between 'S' and 'F' is that on ia64 and ppc64
 439 * function pointers are really function descriptors, which contain a
 440 * pointer to the real address.
 441 */
 442static char *pointer(const char *fmt, char *buf, char *end, void *ptr,
 443                int field_width, int precision, int flags)
 444{
 445        u64 num = (uintptr_t)ptr;
 446
 447        /*
 448         * Being a boot loader, we explicitly allow pointers to
 449         * (physical) address null.
 450         */
 451#if 0
 452        if (!ptr)
 453                return string(buf, end, "(null)", field_width, precision,
 454                              flags);
 455#endif
 456
 457        switch (*fmt) {
 458/* Device paths only exist in the EFI context. */
 459#if CONFIG_IS_ENABLED(EFI_DEVICE_PATH_TO_TEXT) && !defined(API_BUILD)
 460        case 'D':
 461                return device_path_string(buf, end, ptr, field_width,
 462                                          precision, flags);
 463#endif
 464        case 'a':
 465                flags |= SPECIAL | ZEROPAD;
 466
 467                switch (fmt[1]) {
 468                case 'p':
 469                default:
 470                        field_width = sizeof(phys_addr_t) * 2 + 2;
 471                        num = *(phys_addr_t *)ptr;
 472                        break;
 473                }
 474                break;
 475        case 'm':
 476                flags |= SPECIAL;
 477                /* Fallthrough */
 478        case 'M':
 479                return mac_address_string(buf, end, ptr, field_width,
 480                                          precision, flags);
 481        case 'i':
 482                flags |= SPECIAL;
 483                /* Fallthrough */
 484        case 'I':
 485                if (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        char printbuffer[CONFIG_SYS_PBSIZE];
 792
 793        va_start(args, fmt);
 794
 795        /*
 796         * For this to work, printbuffer must be larger than
 797         * anything we ever want to print.
 798         */
 799        i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
 800        va_end(args);
 801
 802        /* Handle error */
 803        if (i <= 0)
 804                return i;
 805        /* Print the string */
 806        puts(printbuffer);
 807        return i;
 808}
 809
 810int vprintf(const char *fmt, va_list args)
 811{
 812        uint i;
 813        char printbuffer[CONFIG_SYS_PBSIZE];
 814
 815        /*
 816         * For this to work, printbuffer must be larger than
 817         * anything we ever want to print.
 818         */
 819        i = vscnprintf(printbuffer, sizeof(printbuffer), fmt, args);
 820
 821        /* Handle error */
 822        if (i <= 0)
 823                return i;
 824        /* Print the string */
 825        puts(printbuffer);
 826        return i;
 827}
 828#endif
 829
 830char *simple_itoa(ulong i)
 831{
 832        /* 21 digits plus null terminator, good for 64-bit or smaller ints */
 833        static char local[22];
 834        char *p = &local[21];
 835
 836        *p-- = '\0';
 837        do {
 838                *p-- = '0' + i % 10;
 839                i /= 10;
 840        } while (i > 0);
 841        return p + 1;
 842}
 843
 844/* We don't seem to have %'d in U-Boot */
 845void print_grouped_ull(unsigned long long int_val, int digits)
 846{
 847        char str[21], *s;
 848        int grab = 3;
 849
 850        digits = (digits + 2) / 3;
 851        sprintf(str, "%*llu", digits * 3, int_val);
 852        for (s = str; *s; s += grab) {
 853                if (s != str)
 854                        putc(s[-1] != ' ' ? ',' : ' ');
 855                printf("%.*s", grab, s);
 856                grab = 3;
 857        }
 858}
 859
 860bool str2off(const char *p, loff_t *num)
 861{
 862        char *endptr;
 863
 864        *num = simple_strtoull(p, &endptr, 16);
 865        return *p != '\0' && *endptr == '\0';
 866}
 867
 868bool str2long(const char *p, ulong *num)
 869{
 870        char *endptr;
 871
 872        *num = simple_strtoul(p, &endptr, 16);
 873        return *p != '\0' && *endptr == '\0';
 874}
 875
 876char *strmhz(char *buf, unsigned long hz)
 877{
 878        long l, n;
 879        long m;
 880
 881        n = DIV_ROUND_CLOSEST(hz, 1000) / 1000L;
 882        l = sprintf(buf, "%ld", n);
 883
 884        hz -= n * 1000000L;
 885        m = DIV_ROUND_CLOSEST(hz, 1000L);
 886        if (m != 0)
 887                sprintf(buf + l, ".%03ld", m);
 888
 889        return buf;
 890}
 891