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