uboot/lib/sscanf.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause
   2/*
   3 * Copyright (c) 1990, 1993
   4 * The Regents of the University of California. All rights reserved.
   5 *
   6 * This code is derived from software contributed to Berkeley by
   7 * Chris Torek.
   8 *
   9 * Copyright (c) 2011 The FreeBSD Foundation
  10 * All rights reserved.
  11 * Portions of this software were developed by David Chisnall
  12 * under sponsorship from the FreeBSD Foundation.
  13 *
  14 * Author: Juergen Gross <jgross@suse.com>
  15 * Date: Jun 2016
  16 */
  17
  18#if !defined HAVE_LIBC
  19
  20#include <os.h>
  21#include <linux/kernel.h>
  22#include <linux/ctype.h>
  23#include <vsprintf.h>
  24#include <linux/string.h>
  25#include <malloc.h>
  26#define __DECONST(type, var)    ((type)(uintptr_t)(const void *)(var))
  27
  28/**
  29 * struct str_info - Input string parameters
  30 * @neg: negative number or not
  31 *       0 - not negative
  32 *       1 - negative
  33 * @any: set any if any `digits' consumed; make it negative to indicate
  34 *       overflow
  35 * @acc: accumulated value
  36 */
  37struct str_info {
  38        int neg, any;
  39        u64 acc;
  40};
  41
  42/**
  43 * str_to_int_convert() - Write string data to structure
  44 * @nptr: pointer to string
  45 * @base: number's base
  46 * @unsign: describes what integer is expected
  47 *          0 - not unsigned
  48 *          1 - unsigned
  49 *
  50 * Ignores `locale' stuff.  Assumes that the upper and lower case
  51 * alphabets and digits are each contiguous.
  52 *
  53 * Return: struct str_info *, which contains string data to future process
  54 */
  55static struct str_info *
  56str_to_int_convert(const char **nptr, int base, unsigned int unsign)
  57{
  58        const char *s = *nptr;
  59        u64 acc;
  60        unsigned char c;
  61        u64 cutoff;
  62        int neg, any, cutlim;
  63        u64 qbase;
  64        struct str_info *info;
  65
  66        /*
  67         * Skip white space and pick up leading +/- sign if any.
  68         * If base is 0, allow 0x for hex and 0 for octal, else
  69         * assume decimal; if base is already 16, allow 0x.
  70         */
  71        info = (struct str_info *)malloc(sizeof(struct str_info));
  72        if (!info)
  73                return NULL;
  74
  75        do {
  76                c = *s++;
  77        } while (isspace(c));
  78        if (c == '-') {
  79                neg = 1;
  80                c = *s++;
  81        } else {
  82                neg = 0;
  83                if (c == '+')
  84                        c = *s++;
  85        }
  86        if ((base == 0 || base == 16) &&
  87            c == '0' && (*s == 'x' || *s == 'X')) {
  88                c = s[1];
  89                s += 2;
  90                base = 16;
  91        }
  92        if (base == 0)
  93                base = c == '0' ? 8 : 10;
  94
  95        /*
  96         * Compute the cutoff value between legal numbers and illegal
  97         * numbers.  That is the largest legal value, divided by the
  98         * base.  An input number that is greater than this value, if
  99         * followed by a legal input character, is too big.  One that
 100         * is equal to this value may be valid or not; the limit
 101         * between valid and invalid numbers is then based on the last
 102         * digit.  For instance, if the range for quads is
 103         * [-9223372036854775808..9223372036854775807] and the input base
 104         * is 10, cutoff will be set to 922337203685477580 and cutlim to
 105         * either 7 (neg==0) or 8 (neg==1), meaning that if we have
 106         * accumulated a value > 922337203685477580, or equal but the
 107         * next digit is > 7 (or 8), the number is too big, and we will
 108         * return a range error.
 109         *
 110         * Set any if any `digits' consumed; make it negative to indicate
 111         * overflow.
 112         */
 113        qbase = (unsigned int)base;
 114
 115        if (!unsign) {
 116                cutoff = neg ? (u64)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX : LLONG_MAX;
 117                cutlim = cutoff % qbase;
 118                cutoff /= qbase;
 119        } else {
 120                cutoff = (u64)ULLONG_MAX / qbase;
 121                cutlim = (u64)ULLONG_MAX % qbase;
 122        }
 123
 124        for (acc = 0, any = 0;; c = *s++) {
 125                if (!isascii(c))
 126                        break;
 127                if (isdigit(c))
 128                        c -= '0';
 129                else if (isalpha(c))
 130                        c -= isupper(c) ? 'A' - 10 : 'a' - 10;
 131                else
 132                        break;
 133                if (c >= base)
 134                        break;
 135                if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) {
 136                        any = -1;
 137                } else {
 138                        any = 1;
 139                        acc *= qbase;
 140                        acc += c;
 141                }
 142        }
 143
 144        info->any = any;
 145        info->neg = neg;
 146        info->acc = acc;
 147
 148        *nptr = s;
 149
 150        return info;
 151}
 152
 153/**
 154 * strtoq() - Convert a string to a quad integer
 155 * @nptr: pointer to string
 156 * @endptr: pointer to number's end in the string
 157 * @base: number's base
 158 *
 159 * Return: s64 quad integer number converted from input string
 160 */
 161static s64
 162strtoq(const char *nptr, char **endptr, int base)
 163{
 164        const char *s = nptr;
 165        u64 acc;
 166        int unsign = 0;
 167        struct str_info *info;
 168
 169        info = str_to_int_convert(&s, base, unsign);
 170        if (!info)
 171                return -1;
 172
 173        acc = info->acc;
 174
 175        if (info->any < 0)
 176                acc = info->neg ? LLONG_MIN : LLONG_MAX;
 177        else if (info->neg)
 178                acc = -acc;
 179        if (endptr != 0)
 180                *endptr = __DECONST(char *, info->any ? s - 1 : nptr);
 181
 182        free(info);
 183
 184        return acc;
 185}
 186
 187/**
 188 * strtouq() - Convert a string to an unsigned quad integer
 189 * @nptr: pointer to string
 190 * @endptr: pointer to number's end in the string
 191 * @base: number's base
 192 *
 193 * Return: s64 unsigned quad integer number converted from
 194 *         input string
 195 */
 196u64
 197strtouq(const char *nptr, char **endptr, int base)
 198{
 199                const char *s = nptr;
 200        u64 acc;
 201        int unsign = 1;
 202        struct str_info *info;
 203
 204        info = str_to_int_convert(&s, base, unsign);
 205        if (!info)
 206                return -1;
 207
 208        acc = info->acc;
 209
 210        if (info->any < 0)
 211                acc = ULLONG_MAX;
 212        else if (info->neg)
 213                acc = -acc;
 214        if (endptr != 0)
 215                *endptr = __DECONST(char *, info->any ? s - 1 : nptr);
 216
 217        free(info);
 218
 219        return acc;
 220}
 221
 222/**
 223 * __sccl() - Fill in the given table from the scanset at the given format
 224 * (just after `[')
 225 * @tab: table to fill in
 226 * @fmt: format of buffer
 227 *
 228 * The table has a 1 wherever characters should be considered part of the
 229 * scanset.
 230 *
 231 * Return: pointer to the character past the closing `]'
 232 */
 233static const u_char *
 234__sccl(char *tab, const u_char *fmt)
 235{
 236        int c, n, v;
 237
 238        /* first `clear' the whole table */
 239        c = *fmt++;             /* first char hat => negated scanset */
 240        if (c == '^') {
 241                v = 1;          /* default => accept */
 242                c = *fmt++;     /* get new first char */
 243        } else {
 244                v = 0;          /* default => reject */
 245        }
 246
 247        /* XXX: Will not work if sizeof(tab*) > sizeof(char) */
 248        for (n = 0; n < 256; n++)
 249                tab[n] = v;        /* memset(tab, v, 256) */
 250
 251        if (c == 0)
 252                return (fmt - 1);/* format ended before closing ] */
 253
 254        /*
 255         * Now set the entries corresponding to the actual scanset
 256         * to the opposite of the above.
 257         *
 258         * The first character may be ']' (or '-') without being special;
 259         * the last character may be '-'.
 260         */
 261        v = 1 - v;
 262        for (;;) {
 263                tab[c] = v;             /* take character c */
 264doswitch:
 265                n = *fmt++;             /* and examine the next */
 266                switch (n) {
 267                case 0:                 /* format ended too soon */
 268                        return (fmt - 1);
 269
 270                case '-':
 271                        /*
 272                         * A scanset of the form
 273                         *      [01+-]
 274                         * is defined as `the digit 0, the digit 1,
 275                         * the character +, the character -', but
 276                         * the effect of a scanset such as
 277                         *      [a-zA-Z0-9]
 278                         * is implementation defined.  The V7 Unix
 279                         * scanf treats `a-z' as `the letters a through
 280                         * z', but treats `a-a' as `the letter a, the
 281                         * character -, and the letter a'.
 282                         *
 283                         * For compatibility, the `-' is not considerd
 284                         * to define a range if the character following
 285                         * it is either a close bracket (required by ANSI)
 286                         * or is not numerically greater than the character
 287                         * we just stored in the table (c).
 288                         */
 289                        n = *fmt;
 290                        if (n == ']' || n < c) {
 291                                c = '-';
 292                                break;  /* resume the for(;;) */
 293                        }
 294                        fmt++;
 295                        /* fill in the range */
 296                        do {
 297                                tab[++c] = v;
 298                        } while (c < n);
 299                        c = n;
 300                        /*
 301                         * Alas, the V7 Unix scanf also treats formats
 302                         * such as [a-c-e] as `the letters a through e'.
 303                         * This too is permitted by the standard....
 304                         */
 305                        goto doswitch;
 306                        break;
 307
 308                case ']':               /* end of scanset */
 309                        return (fmt);
 310
 311                default:                /* just another character */
 312                        c = n;
 313                        break;
 314                }
 315        }
 316        /* NOTREACHED */
 317}
 318
 319/**
 320 * vsscanf - Unformat a buffer into a list of arguments
 321 * @buf:        input buffer
 322 * @fmt:        format of buffer
 323 * @args:       arguments
 324 */
 325#define BUF             32      /* Maximum length of numeric string. */
 326
 327/*
 328 * Flags used during conversion.
 329 */
 330#define LONG            0x01    /* l: long or double */
 331#define SHORT           0x04    /* h: short */
 332#define SUPPRESS        0x08    /* suppress assignment */
 333#define POINTER         0x10    /* weird %p pointer (`fake hex') */
 334#define NOSKIP          0x20    /* do not skip blanks */
 335#define QUAD            0x400
 336#define SHORTSHORT      0x4000  /** hh: char */
 337
 338/*
 339 * The following are used in numeric conversions only:
 340 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
 341 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
 342 */
 343#define SIGNOK          0x40    /* +/- is (still) legal */
 344#define NDIGITS         0x80    /* no digits detected */
 345
 346#define DPTOK           0x100   /* (float) decimal point is still legal */
 347#define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
 348
 349#define PFXOK           0x100   /* 0x prefix is (still) legal */
 350#define NZDIGITS        0x200   /* no zero digits detected */
 351
 352/*
 353 * Conversion types.
 354 */
 355#define CT_CHAR         0       /* %c conversion */
 356#define CT_CCL          1       /* %[...] conversion */
 357#define CT_STRING       2       /* %s conversion */
 358#define CT_INT          3       /* integer, i.e., strtoq or strtouq */
 359typedef u64 (*ccfntype)(const char *, char **, int);
 360
 361int
 362vsscanf(const char *inp, char const *fmt0, va_list ap)
 363{
 364        int inr;
 365        const u_char *fmt = (const u_char *)fmt0;
 366        int c;                  /* character from format, or conversion */
 367        size_t width;           /* field width, or 0 */
 368        char *p;                /* points into all kinds of strings */
 369        int n;                  /* handy integer */
 370        int flags;              /* flags as defined above */
 371        char *p0;               /* saves original value of p when necessary */
 372        int nassigned;          /* number of fields assigned */
 373        int nconversions;       /* number of conversions */
 374        int nread;              /* number of characters consumed from fp */
 375        int base;               /* base argument to strtoq/strtouq */
 376        ccfntype ccfn;          /* conversion function (strtoq/strtouq) */
 377        char ccltab[256];       /* character class table for %[...] */
 378        char buf[BUF];          /* buffer for numeric conversions */
 379
 380        /* `basefix' is used to avoid `if' tests in the integer scanner */
 381        static short basefix[17] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
 382                                     12, 13, 14, 15, 16 };
 383
 384        inr = strlen(inp);
 385
 386        nassigned = 0;
 387        nconversions = 0;
 388        nread = 0;
 389        base = 0;               /* XXX just to keep gcc happy */
 390        ccfn = NULL;            /* XXX just to keep gcc happy */
 391        for (;;) {
 392                c = *fmt++;
 393                if (c == 0)
 394                        return (nassigned);
 395                if (isspace(c)) {
 396                        while (inr > 0 && isspace(*inp))
 397                                nread++, inr--, inp++;
 398                        continue;
 399                }
 400                if (c != '%')
 401                        goto literal;
 402                width = 0;
 403                flags = 0;
 404                /*
 405                 * switch on the format.  continue if done;
 406                 * break once format type is derived.
 407                 */
 408again:          c = *fmt++;
 409                switch (c) {
 410                case '%':
 411literal:
 412                        if (inr <= 0)
 413                                goto input_failure;
 414                        if (*inp != c)
 415                                goto match_failure;
 416                        inr--, inp++;
 417                        nread++;
 418                        continue;
 419
 420                case '*':
 421                        flags |= SUPPRESS;
 422                        goto again;
 423                case 'l':
 424                        if (flags & LONG) {
 425                                flags &= ~LONG;
 426                                flags |= QUAD;
 427                        } else {
 428                                flags |= LONG;
 429                        }
 430                        goto again;
 431                case 'q':
 432                        flags |= QUAD;
 433                        goto again;
 434                case 'h':
 435                        if (flags & SHORT) {
 436                                flags &= ~SHORT;
 437                                flags |= SHORTSHORT;
 438                        } else {
 439                                flags |= SHORT;
 440                        }
 441                        goto again;
 442
 443                case '0': case '1': case '2': case '3': case '4':
 444                case '5': case '6': case '7': case '8': case '9':
 445                        width = width * 10 + c - '0';
 446                        goto again;
 447
 448                /*
 449                 * Conversions.
 450                 *
 451                 */
 452                case 'd':
 453                        c = CT_INT;
 454                        ccfn = (ccfntype)strtoq;
 455                        base = 10;
 456                        break;
 457
 458                case 'i':
 459                        c = CT_INT;
 460                        ccfn = (ccfntype)strtoq;
 461                        base = 0;
 462                        break;
 463
 464                case 'o':
 465                        c = CT_INT;
 466                        ccfn = strtouq;
 467                        base = 8;
 468                        break;
 469
 470                case 'u':
 471                        c = CT_INT;
 472                        ccfn = strtouq;
 473                        base = 10;
 474                        break;
 475
 476                case 'x':
 477                        flags |= PFXOK; /* enable 0x prefixing */
 478                        c = CT_INT;
 479                        ccfn = strtouq;
 480                        base = 16;
 481                        break;
 482
 483                case 's':
 484                        c = CT_STRING;
 485                        break;
 486
 487                case '[':
 488                        fmt = __sccl(ccltab, fmt);
 489                        flags |= NOSKIP;
 490                        c = CT_CCL;
 491                        break;
 492
 493                case 'c':
 494                        flags |= NOSKIP;
 495                        c = CT_CHAR;
 496                        break;
 497
 498                case 'p':       /* pointer format is like hex */
 499                        flags |= POINTER | PFXOK;
 500                        c = CT_INT;
 501                        ccfn = strtouq;
 502                        base = 16;
 503                        break;
 504
 505                case 'n':
 506                        nconversions++;
 507                        if (flags & SUPPRESS)   /* ??? */
 508                                continue;
 509                        if (flags & SHORTSHORT)
 510                                *va_arg(ap, char *) = nread;
 511                        else if (flags & SHORT)
 512                                *va_arg(ap, short *) = nread;
 513                        else if (flags & LONG)
 514                                *va_arg(ap, long *) = nread;
 515                        else if (flags & QUAD)
 516                                *va_arg(ap, s64 *) = nread;
 517                        else
 518                                *va_arg(ap, int *) = nread;
 519                        continue;
 520                }
 521
 522                /*
 523                 * We have a conversion that requires input.
 524                 */
 525                if (inr <= 0)
 526                        goto input_failure;
 527
 528                /*
 529                 * Consume leading white space, except for formats
 530                 * that suppress this.
 531                 */
 532                if ((flags & NOSKIP) == 0) {
 533                        while (isspace(*inp)) {
 534                                nread++;
 535                                if (--inr > 0)
 536                                        inp++;
 537                                else
 538                                        goto input_failure;
 539                        }
 540                        /*
 541                         * Note that there is at least one character in
 542                         * the buffer, so conversions that do not set NOSKIP
 543                         * can no longer result in an input failure.
 544                         */
 545                }
 546
 547                /*
 548                 * Do the conversion.
 549                 */
 550                switch (c) {
 551                case CT_CHAR:
 552                        /* scan arbitrary characters (sets NOSKIP) */
 553                        if (width == 0)
 554                                width = 1;
 555                        if (flags & SUPPRESS) {
 556                                size_t sum = 0;
 557
 558                                n = inr;
 559                                if (n < width) {
 560                                        sum += n;
 561                                        width -= n;
 562                                        inp += n;
 563                                        if (sum == 0)
 564                                                goto input_failure;
 565                                } else {
 566                                        sum += width;
 567                                        inr -= width;
 568                                        inp += width;
 569                                }
 570                                nread += sum;
 571                        } else {
 572                                memcpy(va_arg(ap, char *), inp, width);
 573                                inr -= width;
 574                                inp += width;
 575                                nread += width;
 576                                nassigned++;
 577                        }
 578                        nconversions++;
 579                        break;
 580
 581                case CT_CCL:
 582                        /* scan a (nonempty) character class (sets NOSKIP) */
 583                        if (width == 0)
 584                                width = (size_t)~0;     /* `infinity' */
 585                        /* take only those things in the class */
 586                        if (flags & SUPPRESS) {
 587                                n = 0;
 588                                while (ccltab[(unsigned char)*inp]) {
 589                                        n++, inr--, inp++;
 590                                        if (--width == 0)
 591                                                break;
 592                                        if (inr <= 0) {
 593                                                if (n == 0)
 594                                                        goto input_failure;
 595                                                break;
 596                                        }
 597                                }
 598                                if (n == 0)
 599                                        goto match_failure;
 600                        } else {
 601                                p = va_arg(ap, char *);
 602                                p0 = p;
 603                                while (ccltab[(unsigned char)*inp]) {
 604                                        inr--;
 605                                        *p++ = *inp++;
 606                                        if (--width == 0)
 607                                                break;
 608                                        if (inr <= 0) {
 609                                                if (p == p0)
 610                                                        goto input_failure;
 611                                                break;
 612                                        }
 613                                }
 614                                n = p - p0;
 615                                if (n == 0)
 616                                        goto match_failure;
 617                                *p = 0;
 618                                nassigned++;
 619                        }
 620                        nread += n;
 621                        nconversions++;
 622                        break;
 623
 624                case CT_STRING:
 625                        /* like CCL, but zero-length string OK, & no NOSKIP */
 626                        if (width == 0)
 627                                width = (size_t)~0;
 628                        if (flags & SUPPRESS) {
 629                                n = 0;
 630                                while (!isspace(*inp)) {
 631                                        n++, inr--, inp++;
 632                                        if (--width == 0)
 633                                                break;
 634                                        if (inr <= 0)
 635                                                break;
 636                                }
 637                                nread += n;
 638                        } else {
 639                                p = va_arg(ap, char *);
 640                                p0 = p;
 641                                while (!isspace(*inp)) {
 642                                        inr--;
 643                                        *p++ = *inp++;
 644                                        if (--width == 0)
 645                                                break;
 646                                        if (inr <= 0)
 647                                                break;
 648                                }
 649                                *p = 0;
 650                                nread += p - p0;
 651                                nassigned++;
 652                        }
 653                        nconversions++;
 654                        continue;
 655
 656                case CT_INT:
 657                        /* scan an integer as if by strtoq/strtouq */
 658#ifdef hardway
 659                        if (width == 0 || width > sizeof(buf) - 1)
 660                                width = sizeof(buf) - 1;
 661#else
 662                        /* size_t is unsigned, hence this optimisation */
 663                        if (--width > sizeof(buf) - 2)
 664                                width = sizeof(buf) - 2;
 665                        width++;
 666#endif
 667                        flags |= SIGNOK | NDIGITS | NZDIGITS;
 668                        for (p = buf; width; width--) {
 669                                c = *inp;
 670                                /*
 671                                 * Switch on the character; `goto ok'
 672                                 * if we accept it as a part of number.
 673                                 */
 674                                switch (c) {
 675                                /*
 676                                 * The digit 0 is always legal, but is
 677                                 * special.  For %i conversions, if no
 678                                 * digits (zero or nonzero) have been
 679                                 * scanned (only signs), we will have
 680                                 * base==0.  In that case, we should set
 681                                 * it to 8 and enable 0x prefixing.
 682                                 * Also, if we have not scanned zero digits
 683                                 * before this, do not turn off prefixing
 684                                 * (someone else will turn it off if we
 685                                 * have scanned any nonzero digits).
 686                                 */
 687                                case '0':
 688                                        if (base == 0) {
 689                                                base = 8;
 690                                                flags |= PFXOK;
 691                                        }
 692                                        if (flags & NZDIGITS)
 693                                                flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
 694                                        else
 695                                                flags &= ~(SIGNOK | PFXOK | NDIGITS);
 696                                        goto ok;
 697
 698                                /* 1 through 7 always legal */
 699                                case '1': case '2': case '3':
 700                                case '4': case '5': case '6': case '7':
 701                                        base = basefix[base];
 702                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
 703                                        goto ok;
 704
 705                                /* digits 8 and 9 ok iff decimal or hex */
 706                                case '8': case '9':
 707                                        base = basefix[base];
 708                                        if (base <= 8)
 709                                                break;  /* not legal here */
 710                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
 711                                        goto ok;
 712
 713                                /* letters ok iff hex */
 714                                case 'A': case 'B': case 'C':
 715                                case 'D': case 'E': case 'F':
 716                                case 'a': case 'b': case 'c':
 717                                case 'd': case 'e': case 'f':
 718                                        /* no need to fix base here */
 719                                        if (base <= 10)
 720                                                break;  /* not legal here */
 721                                        flags &= ~(SIGNOK | PFXOK | NDIGITS);
 722                                        goto ok;
 723
 724                                /* sign ok only as first character */
 725                                case '+': case '-':
 726                                        if (flags & SIGNOK) {
 727                                                flags &= ~SIGNOK;
 728                                                goto ok;
 729                                                }
 730                                        break;
 731
 732                                /* x ok iff flag still set & 2nd char */
 733                                case 'x': case 'X':
 734                                        if (flags & PFXOK && p == buf + 1) {
 735                                                base = 16;      /* if %i */
 736                                                flags &= ~PFXOK;
 737                                                goto ok;
 738                                        }
 739                                        break;
 740                                }
 741
 742                                /*
 743                                 * If we got here, c is not a legal character
 744                                 * for a number.  Stop accumulating digits.
 745                                 */
 746                                break;
 747ok:
 748                                /*
 749                                 * c is legal: store it and look at the next.
 750                                 */
 751                                *p++ = c;
 752                                if (--inr > 0)
 753                                        inp++;
 754                                else
 755                                        break;          /* end of input */
 756                        }
 757                        /*
 758                         * If we had only a sign, it is no good; push
 759                         * back the sign.  If the number ends in `x',
 760                         * it was [sign] '' 'x', so push back the x
 761                         * and treat it as [sign] ''.
 762                         */
 763                        if (flags & NDIGITS) {
 764                                if (p > buf) {
 765                                        inp--;
 766                                        inr++;
 767                                }
 768                                goto match_failure;
 769                        }
 770                        c = ((u_char *)p)[-1];
 771                        if (c == 'x' || c == 'X') {
 772                                --p;
 773                                inp--;
 774                                inr++;
 775                        }
 776                        if ((flags & SUPPRESS) == 0) {
 777                                u64 res;
 778
 779                                *p = 0;
 780                                res = (*ccfn)(buf, (char **)NULL, base);
 781                                if (flags & POINTER)
 782                                        *va_arg(ap, void **) =
 783                                        (void *)(uintptr_t)res;
 784                                else if (flags & SHORTSHORT)
 785                                        *va_arg(ap, char *) = res;
 786                                else if (flags & SHORT)
 787                                        *va_arg(ap, short *) = res;
 788                                else if (flags & LONG)
 789                                        *va_arg(ap, long *) = res;
 790                                else if (flags & QUAD)
 791                                        *va_arg(ap, s64 *) = res;
 792                                else
 793                                        *va_arg(ap, int *) = res;
 794                                nassigned++;
 795                        }
 796                        nread += p - buf;
 797                        nconversions++;
 798                        break;
 799                }
 800        }
 801input_failure:
 802                return (nconversions != 0 ? nassigned : -1);
 803match_failure:
 804                return (nassigned);
 805}
 806
 807/**
 808 * sscanf - Unformat a buffer into a list of arguments
 809 * @buf:        input buffer
 810 * @fmt:        formatting of buffer
 811 * @...:        resulting arguments
 812 */
 813int sscanf(const char *buf, const char *fmt, ...)
 814{
 815        va_list args;
 816        int i;
 817
 818        va_start(args, fmt);
 819        i = vsscanf(buf, fmt, args);
 820        va_end(args);
 821        return i;
 822}
 823
 824#endif
 825