subr_scanf.c revision 52843
1/*- 2 * Copyright (c) 1990, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Chris Torek. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $FreeBSD: head/sys/kern/subr_scanf.c 52843 1999-11-03 17:54:26Z phk $ 37 * From: Id: vfscanf.c,v 1.13 1998/09/25 12:20:27 obrien Exp 38 * From: static char sccsid[] = "@(#)strtol.c 8.1 (Berkeley) 6/4/93"; 39 * From: static char sccsid[] = "@(#)strtoul.c 8.1 (Berkeley) 6/4/93"; 40 */ 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/ctype.h> 45#include <machine/limits.h> 46 47/* 48 * Note that stdarg.h and the ANSI style va_start macro is used for both 49 * ANSI and traditional C compilers. 50 */ 51#include <machine/stdarg.h> 52 53#define BUF 32 /* Maximum length of numeric string. */ 54 55/* 56 * Flags used during conversion. 57 */ 58#define LONG 0x01 /* l: long or double */ 59#define SHORT 0x04 /* h: short */ 60#define SUPPRESS 0x08 /* suppress assignment */ 61#define POINTER 0x10 /* weird %p pointer (`fake hex') */ 62#define NOSKIP 0x20 /* do not skip blanks */ 63#define QUAD 0x400 64 65/* 66 * The following are used in numeric conversions only: 67 * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; 68 * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. 69 */ 70#define SIGNOK 0x40 /* +/- is (still) legal */ 71#define NDIGITS 0x80 /* no digits detected */ 72 73#define DPTOK 0x100 /* (float) decimal point is still legal */ 74#define EXPOK 0x200 /* (float) exponent (e+3, etc) still legal */ 75 76#define PFXOK 0x100 /* 0x prefix is (still) legal */ 77#define NZDIGITS 0x200 /* no zero digits detected */ 78 79/* 80 * Conversion types. 81 */ 82#define CT_CHAR 0 /* %c conversion */ 83#define CT_CCL 1 /* %[...] conversion */ 84#define CT_STRING 2 /* %s conversion */ 85#define CT_INT 3 /* integer, i.e., strtoq or strtouq */ 86typedef u_quad_t (*ccfntype)(const char *, const char **, int); 87 88static const u_char *__sccl(char *, const u_char *); 89 90int 91sscanf(const char *ibuf, const char *fmt, ...) 92{ 93 va_list ap; 94 int ret; 95 96 va_start(ap, fmt); 97 ret = vsscanf(ibuf, fmt, ap); 98 va_end(ap); 99 return(ret); 100} 101 102int 103vsscanf(const char *inp, char const *fmt0, va_list ap) 104{ 105 int inr; 106 const u_char *fmt = (const u_char *)fmt0; 107 int c; /* character from format, or conversion */ 108 size_t width; /* field width, or 0 */ 109 char *p; /* points into all kinds of strings */ 110 int n; /* handy integer */ 111 int flags; /* flags as defined above */ 112 char *p0; /* saves original value of p when necessary */ 113 int nassigned; /* number of fields assigned */ 114 int nconversions; /* number of conversions */ 115 int nread; /* number of characters consumed from fp */ 116 int base; /* base argument to strtoq/strtouq */ 117 ccfntype ccfn; /* conversion function (strtoq/strtouq) */ 118 char ccltab[256]; /* character class table for %[...] */ 119 char buf[BUF]; /* buffer for numeric conversions */ 120 121 /* `basefix' is used to avoid `if' tests in the integer scanner */ 122 static short basefix[17] = 123 { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; 124 125 inr = strlen(inp); 126 127 nassigned = 0; 128 nconversions = 0; 129 nread = 0; 130 base = 0; /* XXX just to keep gcc happy */ 131 ccfn = NULL; /* XXX just to keep gcc happy */ 132 for (;;) { 133 c = *fmt++; 134 if (c == 0) 135 return (nassigned); 136 if (isspace(c)) { 137 while (inr > 0 && isspace(*inp)) 138 nread++, inr--, inp++; 139 continue; 140 } 141 if (c != '%') 142 goto literal; 143 width = 0; 144 flags = 0; 145 /* 146 * switch on the format. continue if done; 147 * break once format type is derived. 148 */ 149again: c = *fmt++; 150 switch (c) { 151 case '%': 152literal: 153 if (inr <= 0) 154 goto input_failure; 155 if (*inp != c) 156 goto match_failure; 157 inr--, inp++; 158 nread++; 159 continue; 160 161 case '*': 162 flags |= SUPPRESS; 163 goto again; 164 case 'l': 165 flags |= LONG; 166 goto again; 167 case 'q': 168 flags |= QUAD; 169 goto again; 170 case 'h': 171 flags |= SHORT; 172 goto again; 173 174 case '0': case '1': case '2': case '3': case '4': 175 case '5': case '6': case '7': case '8': case '9': 176 width = width * 10 + c - '0'; 177 goto again; 178 179 /* 180 * Conversions. 181 * 182 */ 183 case 'd': 184 c = CT_INT; 185 ccfn = (ccfntype)strtoq; 186 base = 10; 187 break; 188 189 case 'i': 190 c = CT_INT; 191 ccfn = (ccfntype)strtoq; 192 base = 0; 193 break; 194 195 case 'o': 196 c = CT_INT; 197 ccfn = strtouq; 198 base = 8; 199 break; 200 201 case 'u': 202 c = CT_INT; 203 ccfn = strtouq; 204 base = 10; 205 break; 206 207 case 'x': 208 flags |= PFXOK; /* enable 0x prefixing */ 209 c = CT_INT; 210 ccfn = strtouq; 211 base = 16; 212 break; 213 214 case 's': 215 c = CT_STRING; 216 break; 217 218 case '[': 219 fmt = __sccl(ccltab, fmt); 220 flags |= NOSKIP; 221 c = CT_CCL; 222 break; 223 224 case 'c': 225 flags |= NOSKIP; 226 c = CT_CHAR; 227 break; 228 229 case 'p': /* pointer format is like hex */ 230 flags |= POINTER | PFXOK; 231 c = CT_INT; 232 ccfn = strtouq; 233 base = 16; 234 break; 235 236 case 'n': 237 nconversions++; 238 if (flags & SUPPRESS) /* ??? */ 239 continue; 240 if (flags & SHORT) 241 *va_arg(ap, short *) = nread; 242 else if (flags & LONG) 243 *va_arg(ap, long *) = nread; 244 else if (flags & QUAD) 245 *va_arg(ap, quad_t *) = nread; 246 else 247 *va_arg(ap, int *) = nread; 248 continue; 249 } 250 251 /* 252 * We have a conversion that requires input. 253 */ 254 if (inr <= 0) 255 goto input_failure; 256 257 /* 258 * Consume leading white space, except for formats 259 * that suppress this. 260 */ 261 if ((flags & NOSKIP) == 0) { 262 while (isspace(*inp)) { 263 nread++; 264 if (--inr > 0) 265 inp++; 266 else 267 goto input_failure; 268 } 269 /* 270 * Note that there is at least one character in 271 * the buffer, so conversions that do not set NOSKIP 272 * can no longer result in an input failure. 273 */ 274 } 275 276 /* 277 * Do the conversion. 278 */ 279 switch (c) { 280 281 case CT_CHAR: 282 /* scan arbitrary characters (sets NOSKIP) */ 283 if (width == 0) 284 width = 1; 285 if (flags & SUPPRESS) { 286 size_t sum = 0; 287 for (;;) { 288 if ((n = inr) < width) { 289 sum += n; 290 width -= n; 291 inp += n; 292 if (sum == 0) 293 goto input_failure; 294 break; 295 } else { 296 sum += width; 297 inr -= width; 298 inp += width; 299 break; 300 } 301 } 302 nread += sum; 303 } else { 304 bcopy(inp, va_arg(ap, char *), width); 305 inr -= width; 306 inp += width; 307 nread += width; 308 nassigned++; 309 } 310 nconversions++; 311 break; 312 313 case CT_CCL: 314 /* scan a (nonempty) character class (sets NOSKIP) */ 315 if (width == 0) 316 width = (size_t)~0; /* `infinity' */ 317 /* take only those things in the class */ 318 if (flags & SUPPRESS) { 319 n = 0; 320 while (ccltab[(unsigned char)*inp]) { 321 n++, inr--, inp++; 322 if (--width == 0) 323 break; 324 if (inr <= 0) { 325 if (n == 0) 326 goto input_failure; 327 break; 328 } 329 } 330 if (n == 0) 331 goto match_failure; 332 } else { 333 p0 = p = va_arg(ap, char *); 334 while (ccltab[(unsigned char)*inp]) { 335 inr--; 336 *p++ = *inp++; 337 if (--width == 0) 338 break; 339 if (inr <= 0) { 340 if (p == p0) 341 goto input_failure; 342 break; 343 } 344 } 345 n = p - p0; 346 if (n == 0) 347 goto match_failure; 348 *p = 0; 349 nassigned++; 350 } 351 nread += n; 352 nconversions++; 353 break; 354 355 case CT_STRING: 356 /* like CCL, but zero-length string OK, & no NOSKIP */ 357 if (width == 0) 358 width = (size_t)~0; 359 if (flags & SUPPRESS) { 360 n = 0; 361 while (!isspace(*inp)) { 362 n++, inr--, inp++; 363 if (--width == 0) 364 break; 365 if (inr <= 0) 366 break; 367 } 368 nread += n; 369 } else { 370 p0 = p = va_arg(ap, char *); 371 while (!isspace(*inp)) { 372 inr--; 373 *p++ = *inp++; 374 if (--width == 0) 375 break; 376 if (inr <= 0) 377 break; 378 } 379 *p = 0; 380 nread += p - p0; 381 nassigned++; 382 } 383 nconversions++; 384 continue; 385 386 case CT_INT: 387 /* scan an integer as if by strtoq/strtouq */ 388#ifdef hardway 389 if (width == 0 || width > sizeof(buf) - 1) 390 width = sizeof(buf) - 1; 391#else 392 /* size_t is unsigned, hence this optimisation */ 393 if (--width > sizeof(buf) - 2) 394 width = sizeof(buf) - 2; 395 width++; 396#endif 397 flags |= SIGNOK | NDIGITS | NZDIGITS; 398 for (p = buf; width; width--) { 399 c = *inp; 400 /* 401 * Switch on the character; `goto ok' 402 * if we accept it as a part of number. 403 */ 404 switch (c) { 405 406 /* 407 * The digit 0 is always legal, but is 408 * special. For %i conversions, if no 409 * digits (zero or nonzero) have been 410 * scanned (only signs), we will have 411 * base==0. In that case, we should set 412 * it to 8 and enable 0x prefixing. 413 * Also, if we have not scanned zero digits 414 * before this, do not turn off prefixing 415 * (someone else will turn it off if we 416 * have scanned any nonzero digits). 417 */ 418 case '0': 419 if (base == 0) { 420 base = 8; 421 flags |= PFXOK; 422 } 423 if (flags & NZDIGITS) 424 flags &= ~(SIGNOK|NZDIGITS|NDIGITS); 425 else 426 flags &= ~(SIGNOK|PFXOK|NDIGITS); 427 goto ok; 428 429 /* 1 through 7 always legal */ 430 case '1': case '2': case '3': 431 case '4': case '5': case '6': case '7': 432 base = basefix[base]; 433 flags &= ~(SIGNOK | PFXOK | NDIGITS); 434 goto ok; 435 436 /* digits 8 and 9 ok iff decimal or hex */ 437 case '8': case '9': 438 base = basefix[base]; 439 if (base <= 8) 440 break; /* not legal here */ 441 flags &= ~(SIGNOK | PFXOK | NDIGITS); 442 goto ok; 443 444 /* letters ok iff hex */ 445 case 'A': case 'B': case 'C': 446 case 'D': case 'E': case 'F': 447 case 'a': case 'b': case 'c': 448 case 'd': case 'e': case 'f': 449 /* no need to fix base here */ 450 if (base <= 10) 451 break; /* not legal here */ 452 flags &= ~(SIGNOK | PFXOK | NDIGITS); 453 goto ok; 454 455 /* sign ok only as first character */ 456 case '+': case '-': 457 if (flags & SIGNOK) { 458 flags &= ~SIGNOK; 459 goto ok; 460 } 461 break; 462 463 /* x ok iff flag still set & 2nd char */ 464 case 'x': case 'X': 465 if (flags & PFXOK && p == buf + 1) { 466 base = 16; /* if %i */ 467 flags &= ~PFXOK; 468 goto ok; 469 } 470 break; 471 } 472 473 /* 474 * If we got here, c is not a legal character 475 * for a number. Stop accumulating digits. 476 */ 477 break; 478 ok: 479 /* 480 * c is legal: store it and look at the next. 481 */ 482 *p++ = c; 483 if (--inr > 0) 484 inp++; 485 else 486 break; /* end of input */ 487 } 488 /* 489 * If we had only a sign, it is no good; push 490 * back the sign. If the number ends in `x', 491 * it was [sign] '0' 'x', so push back the x 492 * and treat it as [sign] '0'. 493 */ 494 if (flags & NDIGITS) { 495 if (p > buf) { 496 inp--; 497 inr++; 498 } 499 goto match_failure; 500 } 501 c = ((u_char *)p)[-1]; 502 if (c == 'x' || c == 'X') { 503 --p; 504 inp--; 505 inr++; 506 } 507 if ((flags & SUPPRESS) == 0) { 508 u_quad_t res; 509 510 *p = 0; 511 res = (*ccfn)(buf, (const char **)NULL, base); 512 if (flags & POINTER) 513 *va_arg(ap, void **) = 514 (void *)(uintptr_t)res; 515 else if (flags & SHORT) 516 *va_arg(ap, short *) = res; 517 else if (flags & LONG) 518 *va_arg(ap, long *) = res; 519 else if (flags & QUAD) 520 *va_arg(ap, quad_t *) = res; 521 else 522 *va_arg(ap, int *) = res; 523 nassigned++; 524 } 525 nread += p - buf; 526 nconversions++; 527 break; 528 529 } 530 } 531input_failure: 532 return (nconversions != 0 ? nassigned : -1); 533match_failure: 534 return (nassigned); 535} 536 537/* 538 * Fill in the given table from the scanset at the given format 539 * (just after `['). Return a pointer to the character past the 540 * closing `]'. The table has a 1 wherever characters should be 541 * considered part of the scanset. 542 */ 543static const u_char * 544__sccl(char *tab, const u_char *fmt) 545{ 546 int c, n, v; 547 548 /* first `clear' the whole table */ 549 c = *fmt++; /* first char hat => negated scanset */ 550 if (c == '^') { 551 v = 1; /* default => accept */ 552 c = *fmt++; /* get new first char */ 553 } else 554 v = 0; /* default => reject */ 555 556 /* XXX: Will not work if sizeof(tab*) > sizeof(char) */ 557 for (n = 0; n < 256; n++) 558 tab[n] = v; /* memset(tab, v, 256) */ 559 560 if (c == 0) 561 return (fmt - 1);/* format ended before closing ] */ 562 563 /* 564 * Now set the entries corresponding to the actual scanset 565 * to the opposite of the above. 566 * 567 * The first character may be ']' (or '-') without being special; 568 * the last character may be '-'. 569 */ 570 v = 1 - v; 571 for (;;) { 572 tab[c] = v; /* take character c */ 573doswitch: 574 n = *fmt++; /* and examine the next */ 575 switch (n) { 576 577 case 0: /* format ended too soon */ 578 return (fmt - 1); 579 580 case '-': 581 /* 582 * A scanset of the form 583 * [01+-] 584 * is defined as `the digit 0, the digit 1, 585 * the character +, the character -', but 586 * the effect of a scanset such as 587 * [a-zA-Z0-9] 588 * is implementation defined. The V7 Unix 589 * scanf treats `a-z' as `the letters a through 590 * z', but treats `a-a' as `the letter a, the 591 * character -, and the letter a'. 592 * 593 * For compatibility, the `-' is not considerd 594 * to define a range if the character following 595 * it is either a close bracket (required by ANSI) 596 * or is not numerically greater than the character 597 * we just stored in the table (c). 598 */ 599 n = *fmt; 600 if (n == ']' || n < c) { 601 c = '-'; 602 break; /* resume the for(;;) */ 603 } 604 fmt++; 605 /* fill in the range */ 606 do { 607 tab[++c] = v; 608 } while (c < n); 609 c = n; 610 /* 611 * Alas, the V7 Unix scanf also treats formats 612 * such as [a-c-e] as `the letters a through e'. 613 * This too is permitted by the standard.... 614 */ 615 goto doswitch; 616 break; 617 618 case ']': /* end of scanset */ 619 return (fmt); 620 621 default: /* just another character */ 622 c = n; 623 break; 624 } 625 } 626 /* NOTREACHED */ 627} 628 629/* 630 * Convert a string to an unsigned quad integer. 631 * 632 * Ignores `locale' stuff. Assumes that the upper and lower case 633 * alphabets and digits are each contiguous. 634 */ 635u_quad_t 636strtouq(const char *nptr, const char **endptr, int base) 637{ 638 const char *s = nptr; 639 u_quad_t acc; 640 unsigned char c; 641 u_quad_t qbase, cutoff; 642 int neg, any, cutlim; 643 644 /* 645 * See strtoq for comments as to the logic used. 646 */ 647 s = nptr; 648 do { 649 c = *s++; 650 } while (isspace(c)); 651 if (c == '-') { 652 neg = 1; 653 c = *s++; 654 } else { 655 neg = 0; 656 if (c == '+') 657 c = *s++; 658 } 659 if ((base == 0 || base == 16) && 660 c == '0' && (*s == 'x' || *s == 'X')) { 661 c = s[1]; 662 s += 2; 663 base = 16; 664 } 665 if (base == 0) 666 base = c == '0' ? 8 : 10; 667 qbase = (unsigned)base; 668 cutoff = (u_quad_t)UQUAD_MAX / qbase; 669 cutlim = (u_quad_t)UQUAD_MAX % qbase; 670 for (acc = 0, any = 0;; c = *s++) { 671 if (!isascii(c)) 672 break; 673 if (isdigit(c)) 674 c -= '0'; 675 else if (isalpha(c)) 676 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 677 else 678 break; 679 if (c >= base) 680 break; 681 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 682 any = -1; 683 else { 684 any = 1; 685 acc *= qbase; 686 acc += c; 687 } 688 } 689 if (any < 0) { 690 acc = UQUAD_MAX; 691 } else if (neg) 692 acc = -acc; 693 if (endptr != 0) 694 *endptr = (const char *)(any ? s - 1 : nptr); 695 return (acc); 696} 697 698/* 699 * Convert a string to a quad integer. 700 * 701 * Ignores `locale' stuff. Assumes that the upper and lower case 702 * alphabets and digits are each contiguous. 703 */ 704quad_t 705strtoq(const char *nptr, const char **endptr, int base) 706{ 707 const char *s; 708 u_quad_t acc; 709 unsigned char c; 710 u_quad_t qbase, cutoff; 711 int neg, any, cutlim; 712 713 /* 714 * Skip white space and pick up leading +/- sign if any. 715 * If base is 0, allow 0x for hex and 0 for octal, else 716 * assume decimal; if base is already 16, allow 0x. 717 */ 718 s = nptr; 719 do { 720 c = *s++; 721 } while (isspace(c)); 722 if (c == '-') { 723 neg = 1; 724 c = *s++; 725 } else { 726 neg = 0; 727 if (c == '+') 728 c = *s++; 729 } 730 if ((base == 0 || base == 16) && 731 c == '0' && (*s == 'x' || *s == 'X')) { 732 c = s[1]; 733 s += 2; 734 base = 16; 735 } 736 if (base == 0) 737 base = c == '0' ? 8 : 10; 738 739 /* 740 * Compute the cutoff value between legal numbers and illegal 741 * numbers. That is the largest legal value, divided by the 742 * base. An input number that is greater than this value, if 743 * followed by a legal input character, is too big. One that 744 * is equal to this value may be valid or not; the limit 745 * between valid and invalid numbers is then based on the last 746 * digit. For instance, if the range for quads is 747 * [-9223372036854775808..9223372036854775807] and the input base 748 * is 10, cutoff will be set to 922337203685477580 and cutlim to 749 * either 7 (neg==0) or 8 (neg==1), meaning that if we have 750 * accumulated a value > 922337203685477580, or equal but the 751 * next digit is > 7 (or 8), the number is too big, and we will 752 * return a range error. 753 * 754 * Set any if any `digits' consumed; make it negative to indicate 755 * overflow. 756 */ 757 qbase = (unsigned)base; 758 cutoff = neg ? (u_quad_t)-(QUAD_MIN + QUAD_MAX) + QUAD_MAX : QUAD_MAX; 759 cutlim = cutoff % qbase; 760 cutoff /= qbase; 761 for (acc = 0, any = 0;; c = *s++) { 762 if (!isascii(c)) 763 break; 764 if (isdigit(c)) 765 c -= '0'; 766 else if (isalpha(c)) 767 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 768 else 769 break; 770 if (c >= base) 771 break; 772 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 773 any = -1; 774 else { 775 any = 1; 776 acc *= qbase; 777 acc += c; 778 } 779 } 780 if (any < 0) { 781 acc = neg ? QUAD_MIN : QUAD_MAX; 782 } else if (neg) 783 acc = -acc; 784 if (endptr != 0) 785 *endptr = (const char *)(any ? s - 1 : nptr); 786 return (acc); 787} 788 789/* 790 * Convert a string to a long integer. 791 * 792 * Ignores `locale' stuff. Assumes that the upper and lower case 793 * alphabets and digits are each contiguous. 794 */ 795long 796strtol(nptr, endptr, base) 797 const char *nptr; 798 const char **endptr; 799 int base; 800{ 801 const char *s = nptr; 802 unsigned long acc; 803 unsigned char c; 804 unsigned long cutoff; 805 int neg = 0, any, cutlim; 806 807 /* 808 * Skip white space and pick up leading +/- sign if any. 809 * If base is 0, allow 0x for hex and 0 for octal, else 810 * assume decimal; if base is already 16, allow 0x. 811 */ 812 do { 813 c = *s++; 814 } while (isspace(c)); 815 if (c == '-') { 816 neg = 1; 817 c = *s++; 818 } else if (c == '+') 819 c = *s++; 820 if ((base == 0 || base == 16) && 821 c == '0' && (*s == 'x' || *s == 'X')) { 822 c = s[1]; 823 s += 2; 824 base = 16; 825 } 826 if (base == 0) 827 base = c == '0' ? 8 : 10; 828 829 /* 830 * Compute the cutoff value between legal numbers and illegal 831 * numbers. That is the largest legal value, divided by the 832 * base. An input number that is greater than this value, if 833 * followed by a legal input character, is too big. One that 834 * is equal to this value may be valid or not; the limit 835 * between valid and invalid numbers is then based on the last 836 * digit. For instance, if the range for longs is 837 * [-2147483648..2147483647] and the input base is 10, 838 * cutoff will be set to 214748364 and cutlim to either 839 * 7 (neg==0) or 8 (neg==1), meaning that if we have accumulated 840 * a value > 214748364, or equal but the next digit is > 7 (or 8), 841 * the number is too big, and we will return a range error. 842 * 843 * Set any if any `digits' consumed; make it negative to indicate 844 * overflow. 845 */ 846 cutoff = neg ? -(unsigned long)LONG_MIN : LONG_MAX; 847 cutlim = cutoff % (unsigned long)base; 848 cutoff /= (unsigned long)base; 849 for (acc = 0, any = 0;; c = *s++) { 850 if (!isascii(c)) 851 break; 852 if (isdigit(c)) 853 c -= '0'; 854 else if (isalpha(c)) 855 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 856 else 857 break; 858 if (c >= base) 859 break; 860 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 861 any = -1; 862 else { 863 any = 1; 864 acc *= base; 865 acc += c; 866 } 867 } 868 if (any < 0) { 869 acc = neg ? LONG_MIN : LONG_MAX; 870 } else if (neg) 871 acc = -acc; 872 if (endptr != 0) 873 *endptr = (const char *)(any ? s - 1 : nptr); 874 return (acc); 875} 876 877/* 878 * Convert a string to an unsigned long integer. 879 * 880 * Ignores `locale' stuff. Assumes that the upper and lower case 881 * alphabets and digits are each contiguous. 882 */ 883unsigned long 884strtoul(nptr, endptr, base) 885 const char *nptr; 886 const char **endptr; 887 int base; 888{ 889 const char *s = nptr; 890 unsigned long acc; 891 unsigned char c; 892 unsigned long cutoff; 893 int neg = 0, any, cutlim; 894 895 /* 896 * See strtol for comments as to the logic used. 897 */ 898 do { 899 c = *s++; 900 } while (isspace(c)); 901 if (c == '-') { 902 neg = 1; 903 c = *s++; 904 } else if (c == '+') 905 c = *s++; 906 if ((base == 0 || base == 16) && 907 c == '0' && (*s == 'x' || *s == 'X')) { 908 c = s[1]; 909 s += 2; 910 base = 16; 911 } 912 if (base == 0) 913 base = c == '0' ? 8 : 10; 914 cutoff = (unsigned long)ULONG_MAX / (unsigned long)base; 915 cutlim = (unsigned long)ULONG_MAX % (unsigned long)base; 916 for (acc = 0, any = 0;; c = *s++) { 917 if (!isascii(c)) 918 break; 919 if (isdigit(c)) 920 c -= '0'; 921 else if (isalpha(c)) 922 c -= isupper(c) ? 'A' - 10 : 'a' - 10; 923 else 924 break; 925 if (c >= base) 926 break; 927 if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) 928 any = -1; 929 else { 930 any = 1; 931 acc *= base; 932 acc += c; 933 } 934 } 935 if (any < 0) { 936 acc = ULONG_MAX; 937 } else if (neg) 938 acc = -acc; 939 if (endptr != 0) 940 *endptr = (const char *)(any ? s - 1 : nptr); 941 return (acc); 942} 943