Annotation of src/lib/libc/stdio/vfwscanf.c, Revision 1.1
1.1 ! christos 1: /* $NetBSD$ */
! 2:
! 3: /*-
! 4: * Copyright (c) 1990, 1993
! 5: * The Regents of the University of California. All rights reserved.
! 6: *
! 7: * This code is derived from software contributed to Berkeley by
! 8: * Chris Torek.
! 9: *
! 10: * Redistribution and use in source and binary forms, with or without
! 11: * modification, are permitted provided that the following conditions
! 12: * are met:
! 13: * 1. Redistributions of source code must retain the above copyright
! 14: * notice, this list of conditions and the following disclaimer.
! 15: * 2. Redistributions in binary form must reproduce the above copyright
! 16: * notice, this list of conditions and the following disclaimer in the
! 17: * documentation and/or other materials provided with the distribution.
! 18: * 3. All advertising materials mentioning features or use of this software
! 19: * must display the following acknowledgement:
! 20: * This product includes software developed by the University of
! 21: * California, Berkeley and its contributors.
! 22: * 4. Neither the name of the University nor the names of its contributors
! 23: * may be used to endorse or promote products derived from this software
! 24: * without specific prior written permission.
! 25: *
! 26: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 27: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 28: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 29: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 30: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 31: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 32: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 33: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 34: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 35: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 36: * SUCH DAMAGE.
! 37: */
! 38:
! 39: #include <sys/cdefs.h>
! 40: #if defined(LIBC_SCCS) && !defined(lint)
! 41: #if 0
! 42: static char sccsid[] = "@(#)ftell.c 8.2 (Berkeley) 5/4/95";
! 43: __FBSDID("$FreeBSD: src/lib/libc/stdio/vfwscanf.c,v 1.12 2004/05/02 20:13:29 obrien Exp $");
! 44: #else
! 45: __RCSID("$NetBSD: ftell.c,v 1.15 2003/08/07 16:43:25 agc Exp $");
! 46: #endif
! 47: #endif /* LIBC_SCCS and not lint */
! 48:
! 49: #include "namespace.h"
! 50: #include <ctype.h>
! 51: #include <inttypes.h>
! 52: #include <stdio.h>
! 53: #include <stdlib.h>
! 54: #include <stddef.h>
! 55: #include <stdarg.h>
! 56: #include <string.h>
! 57: #include <limits.h>
! 58: #include <wchar.h>
! 59: #include <wctype.h>
! 60:
! 61: #include "reentrant.h"
! 62: #include "local.h"
! 63:
! 64: #ifndef NO_FLOATING_POINT
! 65: #include <locale.h>
! 66: #endif
! 67:
! 68: #define BUF 513 /* Maximum length of numeric string. */
! 69:
! 70: /*
! 71: * Flags used during conversion.
! 72: */
! 73: #define LONG 0x01 /* l: long or double */
! 74: #define LONGDBL 0x02 /* L: long double */
! 75: #define SHORT 0x04 /* h: short */
! 76: #define SUPPRESS 0x08 /* *: suppress assignment */
! 77: #define POINTER 0x10 /* p: void * (as hex) */
! 78: #define NOSKIP 0x20 /* [ or c: do not skip blanks */
! 79: #define LONGLONG 0x400 /* ll: quad_t (+ deprecated q: quad) */
! 80: #define INTMAXT 0x800 /* j: intmax_t */
! 81: #define PTRDIFFT 0x1000 /* t: ptrdiff_t */
! 82: #define SIZET 0x2000 /* z: size_t */
! 83: #define SHORTSHORT 0x4000 /* hh: char */
! 84: #define UNSIGNED 0x8000 /* %[oupxX] conversions */
! 85:
! 86: /*
! 87: * The following are used in integral conversions only:
! 88: * SIGNOK, NDIGITS, PFXOK, and NZDIGITS
! 89: */
! 90: #define SIGNOK 0x40 /* +/- is (still) legal */
! 91: #define NDIGITS 0x80 /* no digits detected */
! 92: #define PFXOK 0x100 /* 0x prefix is (still) legal */
! 93: #define NZDIGITS 0x200 /* no zero digits detected */
! 94: #define HAVESIGN 0x10000 /* sign detected */
! 95:
! 96: /*
! 97: * Conversion types.
! 98: */
! 99: #define CT_CHAR 0 /* %c conversion */
! 100: #define CT_CCL 1 /* %[...] conversion */
! 101: #define CT_STRING 2 /* %s conversion */
! 102: #define CT_INT 3 /* %[dioupxX] conversion */
! 103: #define CT_FLOAT 4 /* %[efgEFG] conversion */
! 104:
! 105: static int parsefloat(FILE *, wchar_t *, wchar_t *);
! 106:
! 107: #define INCCL(_c) \
! 108: (cclcompl ? (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) == NULL) : \
! 109: (wmemchr(ccls, (_c), (size_t)(ccle - ccls)) != NULL))
! 110:
! 111: /*
! 112: * MT-safe version.
! 113: */
! 114: int
! 115: vfwscanf(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
! 116: {
! 117: int ret;
! 118:
! 119: FLOCKFILE(fp);
! 120: _SET_ORIENTATION(fp, 1);
! 121: ret = __vfwscanf_unlocked(fp, fmt, ap);
! 122: FUNLOCKFILE(fp);
! 123: return (ret);
! 124: }
! 125:
! 126: /*
! 127: * Non-MT-safe version.
! 128: */
! 129: int
! 130: __vfwscanf_unlocked(FILE * __restrict fp, const wchar_t * __restrict fmt, va_list ap)
! 131: {
! 132: wint_t c; /* character from format, or conversion */
! 133: size_t width; /* field width, or 0 */
! 134: wchar_t *p; /* points into all kinds of strings */
! 135: int n; /* handy integer */
! 136: int flags; /* flags as defined above */
! 137: wchar_t *p0; /* saves original value of p when necessary */
! 138: int nassigned; /* number of fields assigned */
! 139: int nconversions; /* number of conversions */
! 140: int nread; /* number of characters consumed from fp */
! 141: int base; /* base argument to conversion function */
! 142: wchar_t buf[BUF]; /* buffer for numeric conversions */
! 143: const wchar_t *ccls; /* character class start */
! 144: const wchar_t *ccle; /* character class end */
! 145: int cclcompl; /* ccl is complemented? */
! 146: wint_t wi; /* handy wint_t */
! 147: char *mbp; /* multibyte string pointer for %c %s %[ */
! 148: size_t nconv; /* number of bytes in mb. conversion */
! 149: char mbbuf[MB_LEN_MAX]; /* temporary mb. character buffer */
! 150: static const mbstate_t initial;
! 151: mbstate_t mbs;
! 152:
! 153: /* `basefix' is used to avoid `if' tests in the integer scanner */
! 154: static short basefix[17] =
! 155: { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 };
! 156:
! 157: nassigned = 0;
! 158: nconversions = 0;
! 159: nread = 0;
! 160: ccls = ccle = NULL;
! 161: for (;;) {
! 162: c = *fmt++;
! 163: if (c == 0)
! 164: return (nassigned);
! 165: if (iswspace(c)) {
! 166: while ((c = __fgetwc_unlock(fp)) != WEOF &&
! 167: iswspace(c))
! 168: ;
! 169: if (c != WEOF)
! 170: ungetwc(c, fp);
! 171: continue;
! 172: }
! 173: if (c != '%')
! 174: goto literal;
! 175: width = 0;
! 176: flags = 0;
! 177: /*
! 178: * switch on the format. continue if done;
! 179: * break once format type is derived.
! 180: */
! 181: again: c = *fmt++;
! 182: switch (c) {
! 183: case '%':
! 184: literal:
! 185: if ((wi = __fgetwc_unlock(fp)) == WEOF)
! 186: goto input_failure;
! 187: if (wi != c) {
! 188: ungetwc(wi, fp);
! 189: goto input_failure;
! 190: }
! 191: nread++;
! 192: continue;
! 193:
! 194: case '*':
! 195: flags |= SUPPRESS;
! 196: goto again;
! 197: case 'j':
! 198: flags |= INTMAXT;
! 199: goto again;
! 200: case 'l':
! 201: if (flags & LONG) {
! 202: flags &= ~LONG;
! 203: flags |= LONGLONG;
! 204: } else
! 205: flags |= LONG;
! 206: goto again;
! 207: case 'q':
! 208: flags |= LONGLONG; /* not quite */
! 209: goto again;
! 210: case 't':
! 211: flags |= PTRDIFFT;
! 212: goto again;
! 213: case 'z':
! 214: flags |= SIZET;
! 215: goto again;
! 216: case 'L':
! 217: flags |= LONGDBL;
! 218: goto again;
! 219: case 'h':
! 220: if (flags & SHORT) {
! 221: flags &= ~SHORT;
! 222: flags |= SHORTSHORT;
! 223: } else
! 224: flags |= SHORT;
! 225: goto again;
! 226:
! 227: case '0': case '1': case '2': case '3': case '4':
! 228: case '5': case '6': case '7': case '8': case '9':
! 229: width = width * 10 + c - '0';
! 230: goto again;
! 231:
! 232: /*
! 233: * Conversions.
! 234: */
! 235: case 'd':
! 236: c = CT_INT;
! 237: base = 10;
! 238: break;
! 239:
! 240: case 'i':
! 241: c = CT_INT;
! 242: base = 0;
! 243: break;
! 244:
! 245: case 'o':
! 246: c = CT_INT;
! 247: flags |= UNSIGNED;
! 248: base = 8;
! 249: break;
! 250:
! 251: case 'u':
! 252: c = CT_INT;
! 253: flags |= UNSIGNED;
! 254: base = 10;
! 255: break;
! 256:
! 257: case 'X':
! 258: case 'x':
! 259: flags |= PFXOK; /* enable 0x prefixing */
! 260: c = CT_INT;
! 261: flags |= UNSIGNED;
! 262: base = 16;
! 263: break;
! 264:
! 265: #ifndef NO_FLOATING_POINT
! 266: case 'A': case 'E': case 'F': case 'G':
! 267: case 'a': case 'e': case 'f': case 'g':
! 268: c = CT_FLOAT;
! 269: break;
! 270: #endif
! 271:
! 272: case 'S':
! 273: flags |= LONG;
! 274: /* FALLTHROUGH */
! 275: case 's':
! 276: c = CT_STRING;
! 277: break;
! 278:
! 279: case '[':
! 280: ccls = fmt;
! 281: if (*fmt == '^') {
! 282: cclcompl = 1;
! 283: fmt++;
! 284: } else
! 285: cclcompl = 0;
! 286: if (*fmt == ']')
! 287: fmt++;
! 288: while (*fmt != '\0' && *fmt != ']')
! 289: fmt++;
! 290: ccle = fmt;
! 291: fmt++;
! 292: flags |= NOSKIP;
! 293: c = CT_CCL;
! 294: break;
! 295:
! 296: case 'C':
! 297: flags |= LONG;
! 298: /* FALLTHROUGH */
! 299: case 'c':
! 300: flags |= NOSKIP;
! 301: c = CT_CHAR;
! 302: break;
! 303:
! 304: case 'p': /* pointer format is like hex */
! 305: flags |= POINTER | PFXOK;
! 306: c = CT_INT; /* assumes sizeof(uintmax_t) */
! 307: flags |= UNSIGNED; /* >= sizeof(uintptr_t) */
! 308: base = 16;
! 309: break;
! 310:
! 311: case 'n':
! 312: nconversions++;
! 313: if (flags & SUPPRESS) /* ??? */
! 314: continue;
! 315: if (flags & SHORTSHORT)
! 316: *va_arg(ap, char *) = nread;
! 317: else if (flags & SHORT)
! 318: *va_arg(ap, short *) = nread;
! 319: else if (flags & LONG)
! 320: *va_arg(ap, long *) = nread;
! 321: else if (flags & LONGLONG)
! 322: *va_arg(ap, quad_t *) = nread;
! 323: else if (flags & INTMAXT)
! 324: *va_arg(ap, intmax_t *) = nread;
! 325: else if (flags & SIZET)
! 326: *va_arg(ap, size_t *) = nread;
! 327: else if (flags & PTRDIFFT)
! 328: *va_arg(ap, ptrdiff_t *) = nread;
! 329: else
! 330: *va_arg(ap, int *) = nread;
! 331: continue;
! 332:
! 333: default:
! 334: goto match_failure;
! 335:
! 336: /*
! 337: * Disgusting backwards compatibility hack. XXX
! 338: */
! 339: case '\0': /* compat */
! 340: return (EOF);
! 341: }
! 342:
! 343: /*
! 344: * Consume leading white space, except for formats
! 345: * that suppress this.
! 346: */
! 347: if ((flags & NOSKIP) == 0) {
! 348: while ((wi = __fgetwc_unlock(fp)) != WEOF && iswspace(wi))
! 349: nread++;
! 350: if (wi == WEOF)
! 351: goto input_failure;
! 352: ungetwc(wi, fp);
! 353: }
! 354:
! 355: /*
! 356: * Do the conversion.
! 357: */
! 358: switch (c) {
! 359:
! 360: case CT_CHAR:
! 361: /* scan arbitrary characters (sets NOSKIP) */
! 362: if (width == 0)
! 363: width = 1;
! 364: if (flags & LONG) {
! 365: if (!(flags & SUPPRESS))
! 366: p = va_arg(ap, wchar_t *);
! 367: n = 0;
! 368: while (width-- != 0 &&
! 369: (wi = __fgetwc_unlock(fp)) != WEOF) {
! 370: if (!(flags & SUPPRESS))
! 371: *p++ = (wchar_t)wi;
! 372: n++;
! 373: }
! 374: if (n == 0)
! 375: goto input_failure;
! 376: nread += n;
! 377: if (!(flags & SUPPRESS))
! 378: nassigned++;
! 379: } else {
! 380: if (!(flags & SUPPRESS))
! 381: mbp = va_arg(ap, char *);
! 382: n = 0;
! 383: mbs = initial;
! 384: while (width != 0 &&
! 385: (wi = __fgetwc_unlock(fp)) != WEOF) {
! 386: if (width >= MB_CUR_MAX &&
! 387: !(flags & SUPPRESS)) {
! 388: nconv = wcrtomb(mbp, wi, &mbs);
! 389: if (nconv == (size_t)-1)
! 390: goto input_failure;
! 391: } else {
! 392: nconv = wcrtomb(mbbuf, wi,
! 393: &mbs);
! 394: if (nconv == (size_t)-1)
! 395: goto input_failure;
! 396: if (nconv > width) {
! 397: ungetwc(wi, fp);
! 398: break;
! 399: }
! 400: if (!(flags & SUPPRESS))
! 401: memcpy(mbp, mbbuf,
! 402: nconv);
! 403: }
! 404: if (!(flags & SUPPRESS))
! 405: mbp += nconv;
! 406: width -= nconv;
! 407: n++;
! 408: }
! 409: if (n == 0)
! 410: goto input_failure;
! 411: nread += n;
! 412: if (!(flags & SUPPRESS))
! 413: nassigned++;
! 414: }
! 415: nconversions++;
! 416: break;
! 417:
! 418: case CT_CCL:
! 419: /* scan a (nonempty) character class (sets NOSKIP) */
! 420: if (width == 0)
! 421: width = (size_t)~0; /* `infinity' */
! 422: /* take only those things in the class */
! 423: if ((flags & SUPPRESS) && (flags & LONG)) {
! 424: n = 0;
! 425: while ((wi = __fgetwc_unlock(fp)) != WEOF &&
! 426: width-- != 0 && INCCL(wi))
! 427: n++;
! 428: if (wi != WEOF)
! 429: ungetwc(wi, fp);
! 430: if (n == 0)
! 431: goto match_failure;
! 432: } else if (flags & LONG) {
! 433: p0 = p = va_arg(ap, wchar_t *);
! 434: while ((wi = __fgetwc_unlock(fp)) != WEOF &&
! 435: width-- != 0 && INCCL(wi))
! 436: *p++ = (wchar_t)wi;
! 437: if (wi != WEOF)
! 438: ungetwc(wi, fp);
! 439: n = p - p0;
! 440: if (n == 0)
! 441: goto match_failure;
! 442: *p = 0;
! 443: nassigned++;
! 444: } else {
! 445: if (!(flags & SUPPRESS))
! 446: mbp = va_arg(ap, char *);
! 447: n = 0;
! 448: mbs = initial;
! 449: while ((wi = __fgetwc_unlock(fp)) != WEOF &&
! 450: width != 0 && INCCL(wi)) {
! 451: if (width >= MB_CUR_MAX &&
! 452: !(flags & SUPPRESS)) {
! 453: nconv = wcrtomb(mbp, wi, &mbs);
! 454: if (nconv == (size_t)-1)
! 455: goto input_failure;
! 456: } else {
! 457: nconv = wcrtomb(mbbuf, wi,
! 458: &mbs);
! 459: if (nconv == (size_t)-1)
! 460: goto input_failure;
! 461: if (nconv > width)
! 462: break;
! 463: if (!(flags & SUPPRESS))
! 464: memcpy(mbp, mbbuf,
! 465: nconv);
! 466: }
! 467: if (!(flags & SUPPRESS))
! 468: mbp += nconv;
! 469: width -= nconv;
! 470: n++;
! 471: }
! 472: if (wi != WEOF)
! 473: ungetwc(wi, fp);
! 474: if (!(flags & SUPPRESS)) {
! 475: *mbp = 0;
! 476: nassigned++;
! 477: }
! 478: }
! 479: nread += n;
! 480: nconversions++;
! 481: break;
! 482:
! 483: case CT_STRING:
! 484: /* like CCL, but zero-length string OK, & no NOSKIP */
! 485: if (width == 0)
! 486: width = (size_t)~0;
! 487: if ((flags & SUPPRESS) && (flags & LONG)) {
! 488: while ((wi = __fgetwc_unlock(fp)) != WEOF &&
! 489: width-- != 0 &&
! 490: !iswspace(wi))
! 491: nread++;
! 492: if (wi != WEOF)
! 493: ungetwc(wi, fp);
! 494: } else if (flags & LONG) {
! 495: p0 = p = va_arg(ap, wchar_t *);
! 496: while ((wi = __fgetwc_unlock(fp)) != WEOF &&
! 497: width-- != 0 &&
! 498: !iswspace(wi)) {
! 499: *p++ = (wchar_t)wi;
! 500: nread++;
! 501: }
! 502: if (wi != WEOF)
! 503: ungetwc(wi, fp);
! 504: *p = '\0';
! 505: nassigned++;
! 506: } else {
! 507: if (!(flags & SUPPRESS))
! 508: mbp = va_arg(ap, char *);
! 509: mbs = initial;
! 510: while ((wi = __fgetwc_unlock(fp)) != WEOF &&
! 511: width != 0 &&
! 512: !iswspace(wi)) {
! 513: if (width >= MB_CUR_MAX &&
! 514: !(flags & SUPPRESS)) {
! 515: nconv = wcrtomb(mbp, wi, &mbs);
! 516: if (nconv == (size_t)-1)
! 517: goto input_failure;
! 518: } else {
! 519: nconv = wcrtomb(mbbuf, wi,
! 520: &mbs);
! 521: if (nconv == (size_t)-1)
! 522: goto input_failure;
! 523: if (nconv > width)
! 524: break;
! 525: if (!(flags & SUPPRESS))
! 526: memcpy(mbp, mbbuf,
! 527: nconv);
! 528: }
! 529: if (!(flags & SUPPRESS))
! 530: mbp += nconv;
! 531: width -= nconv;
! 532: nread++;
! 533: }
! 534: if (wi != WEOF)
! 535: ungetwc(wi, fp);
! 536: if (!(flags & SUPPRESS)) {
! 537: *mbp = 0;
! 538: nassigned++;
! 539: }
! 540: }
! 541: nconversions++;
! 542: continue;
! 543:
! 544: case CT_INT:
! 545: /* scan an integer as if by the conversion function */
! 546: if (width == 0 || width > sizeof(buf) /
! 547: sizeof(*buf) - 1)
! 548: width = sizeof(buf) / sizeof(*buf) - 1;
! 549: flags |= SIGNOK | NDIGITS | NZDIGITS;
! 550: for (p = buf; width; width--) {
! 551: c = __fgetwc_unlock(fp);
! 552: /*
! 553: * Switch on the character; `goto ok'
! 554: * if we accept it as a part of number.
! 555: */
! 556: switch (c) {
! 557:
! 558: /*
! 559: * The digit 0 is always legal, but is
! 560: * special. For %i conversions, if no
! 561: * digits (zero or nonzero) have been
! 562: * scanned (only signs), we will have
! 563: * base==0. In that case, we should set
! 564: * it to 8 and enable 0x prefixing.
! 565: * Also, if we have not scanned zero digits
! 566: * before this, do not turn off prefixing
! 567: * (someone else will turn it off if we
! 568: * have scanned any nonzero digits).
! 569: */
! 570: case '0':
! 571: if (base == 0) {
! 572: base = 8;
! 573: flags |= PFXOK;
! 574: }
! 575: if (flags & NZDIGITS)
! 576: flags &= ~(SIGNOK|NZDIGITS|NDIGITS);
! 577: else
! 578: flags &= ~(SIGNOK|PFXOK|NDIGITS);
! 579: goto ok;
! 580:
! 581: /* 1 through 7 always legal */
! 582: case '1': case '2': case '3':
! 583: case '4': case '5': case '6': case '7':
! 584: base = basefix[base];
! 585: flags &= ~(SIGNOK | PFXOK | NDIGITS);
! 586: goto ok;
! 587:
! 588: /* digits 8 and 9 ok iff decimal or hex */
! 589: case '8': case '9':
! 590: base = basefix[base];
! 591: if (base <= 8)
! 592: break; /* not legal here */
! 593: flags &= ~(SIGNOK | PFXOK | NDIGITS);
! 594: goto ok;
! 595:
! 596: /* letters ok iff hex */
! 597: case 'A': case 'B': case 'C':
! 598: case 'D': case 'E': case 'F':
! 599: case 'a': case 'b': case 'c':
! 600: case 'd': case 'e': case 'f':
! 601: /* no need to fix base here */
! 602: if (base <= 10)
! 603: break; /* not legal here */
! 604: flags &= ~(SIGNOK | PFXOK | NDIGITS);
! 605: goto ok;
! 606:
! 607: /* sign ok only as first character */
! 608: case '+': case '-':
! 609: if (flags & SIGNOK) {
! 610: flags &= ~SIGNOK;
! 611: flags |= HAVESIGN;
! 612: goto ok;
! 613: }
! 614: break;
! 615:
! 616: /*
! 617: * x ok iff flag still set & 2nd char (or
! 618: * 3rd char if we have a sign).
! 619: */
! 620: case 'x': case 'X':
! 621: if (flags & PFXOK && p ==
! 622: buf + 1 + !!(flags & HAVESIGN)) {
! 623: base = 16; /* if %i */
! 624: flags &= ~PFXOK;
! 625: goto ok;
! 626: }
! 627: break;
! 628: }
! 629:
! 630: /*
! 631: * If we got here, c is not a legal character
! 632: * for a number. Stop accumulating digits.
! 633: */
! 634: if (c != WEOF)
! 635: ungetwc(c, fp);
! 636: break;
! 637: ok:
! 638: /*
! 639: * c is legal: store it and look at the next.
! 640: */
! 641: *p++ = (wchar_t)c;
! 642: }
! 643: /*
! 644: * If we had only a sign, it is no good; push
! 645: * back the sign. If the number ends in `x',
! 646: * it was [sign] '0' 'x', so push back the x
! 647: * and treat it as [sign] '0'.
! 648: */
! 649: if (flags & NDIGITS) {
! 650: if (p > buf)
! 651: ungetwc(*--p, fp);
! 652: goto match_failure;
! 653: }
! 654: c = p[-1];
! 655: if (c == 'x' || c == 'X') {
! 656: --p;
! 657: ungetwc(c, fp);
! 658: }
! 659: if ((flags & SUPPRESS) == 0) {
! 660: uintmax_t res;
! 661:
! 662: *p = 0;
! 663: if ((flags & UNSIGNED) == 0)
! 664: res = wcstoimax(buf, NULL, base);
! 665: else
! 666: res = wcstoumax(buf, NULL, base);
! 667: if (flags & POINTER)
! 668: *va_arg(ap, void **) =
! 669: (void *)(uintptr_t)res;
! 670: else if (flags & SHORTSHORT)
! 671: *va_arg(ap, char *) = (char)res;
! 672: else if (flags & SHORT)
! 673: *va_arg(ap, short *) = (short)res;
! 674: else if (flags & LONG)
! 675: *va_arg(ap, long *) = (long)res;
! 676: else if (flags & LONGLONG)
! 677: *va_arg(ap, quad_t *) = res;
! 678: else if (flags & INTMAXT)
! 679: *va_arg(ap, intmax_t *) = res;
! 680: else if (flags & PTRDIFFT)
! 681: *va_arg(ap, ptrdiff_t *) = (ptrdiff_t)res;
! 682: else if (flags & SIZET)
! 683: *va_arg(ap, size_t *) = (size_t)res;
! 684: else
! 685: *va_arg(ap, int *) = (int)res;
! 686: nassigned++;
! 687: }
! 688: nread += p - buf;
! 689: nconversions++;
! 690: break;
! 691:
! 692: #ifndef NO_FLOATING_POINT
! 693: case CT_FLOAT:
! 694: /* scan a floating point number as if by strtod */
! 695: if (width == 0 || width > sizeof(buf) /
! 696: sizeof(*buf) - 1)
! 697: width = sizeof(buf) / sizeof(*buf) - 1;
! 698: if ((width = parsefloat(fp, buf, buf + width)) == 0)
! 699: goto match_failure;
! 700: if ((flags & SUPPRESS) == 0) {
! 701: #ifdef notyet
! 702: if (flags & LONGDBL) {
! 703: long double res = wcstold(buf, &p);
! 704: *va_arg(ap, long double *) = res;
! 705: } else
! 706: #endif
! 707: if (flags & LONG) {
! 708: double res = wcstod(buf, &p);
! 709: *va_arg(ap, double *) = res;
! 710: #ifdef notyet
! 711: } else {
! 712: float res = wcstof(buf, &p);
! 713: *va_arg(ap, float *) = res;
! 714: #endif
! 715: }
! 716: #ifdef DEBUG
! 717: if (p - buf != width)
! 718: abort();
! 719: #endif
! 720: nassigned++;
! 721: }
! 722: nread += width;
! 723: nconversions++;
! 724: break;
! 725: #endif /* !NO_FLOATING_POINT */
! 726: }
! 727: }
! 728: input_failure:
! 729: return (nconversions != 0 ? nassigned : EOF);
! 730: match_failure:
! 731: return (nassigned);
! 732: }
! 733:
! 734: #ifndef NO_FLOATING_POINT
! 735: static int
! 736: parsefloat(FILE *fp, wchar_t *buf, wchar_t *end)
! 737: {
! 738: wchar_t *commit, *p;
! 739: int infnanpos = 0;
! 740: enum {
! 741: S_START, S_GOTSIGN, S_INF, S_NAN, S_MAYBEHEX,
! 742: S_DIGITS, S_FRAC, S_EXP, S_EXPDIGITS
! 743: } state = S_START;
! 744: wchar_t c;
! 745: wchar_t decpt = (wchar_t)(unsigned char)*localeconv()->decimal_point;
! 746: int gotmantdig = 0, ishex = 0;
! 747:
! 748: /*
! 749: * We set commit = p whenever the string we have read so far
! 750: * constitutes a valid representation of a floating point
! 751: * number by itself. At some point, the parse will complete
! 752: * or fail, and we will ungetc() back to the last commit point.
! 753: * To ensure that the file offset gets updated properly, it is
! 754: * always necessary to read at least one character that doesn't
! 755: * match; thus, we can't short-circuit "infinity" or "nan(...)".
! 756: */
! 757: commit = buf - 1;
! 758: c = WEOF;
! 759: for (p = buf; p < end; ) {
! 760: if ((c = __fgetwc_unlock(fp)) == WEOF)
! 761: break;
! 762: reswitch:
! 763: switch (state) {
! 764: case S_START:
! 765: state = S_GOTSIGN;
! 766: if (c == '-' || c == '+')
! 767: break;
! 768: else
! 769: goto reswitch;
! 770: case S_GOTSIGN:
! 771: switch (c) {
! 772: case '0':
! 773: state = S_MAYBEHEX;
! 774: commit = p;
! 775: break;
! 776: case 'I':
! 777: case 'i':
! 778: state = S_INF;
! 779: break;
! 780: case 'N':
! 781: case 'n':
! 782: state = S_NAN;
! 783: break;
! 784: default:
! 785: state = S_DIGITS;
! 786: goto reswitch;
! 787: }
! 788: break;
! 789: case S_INF:
! 790: if (infnanpos > 6 ||
! 791: (c != "nfinity"[infnanpos] &&
! 792: c != "NFINITY"[infnanpos]))
! 793: goto parsedone;
! 794: if (infnanpos == 1 || infnanpos == 6)
! 795: commit = p; /* inf or infinity */
! 796: infnanpos++;
! 797: break;
! 798: case S_NAN:
! 799: switch (infnanpos) {
! 800: case -1: /* XXX kludge to deal with nan(...) */
! 801: goto parsedone;
! 802: case 0:
! 803: if (c != 'A' && c != 'a')
! 804: goto parsedone;
! 805: break;
! 806: case 1:
! 807: if (c != 'N' && c != 'n')
! 808: goto parsedone;
! 809: else
! 810: commit = p;
! 811: break;
! 812: case 2:
! 813: if (c != '(')
! 814: goto parsedone;
! 815: break;
! 816: default:
! 817: if (c == ')') {
! 818: commit = p;
! 819: infnanpos = -2;
! 820: } else if (!iswalnum(c) && c != '_')
! 821: goto parsedone;
! 822: break;
! 823: }
! 824: infnanpos++;
! 825: break;
! 826: case S_MAYBEHEX:
! 827: state = S_DIGITS;
! 828: if (c == 'X' || c == 'x') {
! 829: ishex = 1;
! 830: break;
! 831: } else { /* we saw a '0', but no 'x' */
! 832: gotmantdig = 1;
! 833: goto reswitch;
! 834: }
! 835: case S_DIGITS:
! 836: if ((ishex && iswxdigit(c)) || iswdigit(c))
! 837: gotmantdig = 1;
! 838: else {
! 839: state = S_FRAC;
! 840: if (c != decpt)
! 841: goto reswitch;
! 842: }
! 843: if (gotmantdig)
! 844: commit = p;
! 845: break;
! 846: case S_FRAC:
! 847: if (((c == 'E' || c == 'e') && !ishex) ||
! 848: ((c == 'P' || c == 'p') && ishex)) {
! 849: if (!gotmantdig)
! 850: goto parsedone;
! 851: else
! 852: state = S_EXP;
! 853: } else if ((ishex && iswxdigit(c)) || iswdigit(c)) {
! 854: commit = p;
! 855: gotmantdig = 1;
! 856: } else
! 857: goto parsedone;
! 858: break;
! 859: case S_EXP:
! 860: state = S_EXPDIGITS;
! 861: if (c == '-' || c == '+')
! 862: break;
! 863: else
! 864: goto reswitch;
! 865: case S_EXPDIGITS:
! 866: if (iswdigit(c))
! 867: commit = p;
! 868: else
! 869: goto parsedone;
! 870: break;
! 871: default:
! 872: abort();
! 873: }
! 874: *p++ = c;
! 875: c = WEOF;
! 876: }
! 877:
! 878: parsedone:
! 879: if (c != WEOF)
! 880: ungetwc(c, fp);
! 881: while (commit < --p)
! 882: ungetwc(*p, fp);
! 883: *++commit = '\0';
! 884: return (commit - buf);
! 885: }
! 886: #endif
CVSweb <webmaster@jp.NetBSD.org>