_STD_BEGIN int _Getfld(_Sft *px) { /* convert a field */ px->stored = 0; switch (*px->s) { /* switch on conversion specifier */ case 'c': /* convert an array of char */ #if _HAS_FIXED_POINT if (px->qual == 'v') return (_Getcvec(px)); #endif /* _HAS_FIXED_POINT */ return (_Getstr(px, 0)); case 'd': case 'i': case 'o': case 'u': case 'x': case 'X': #if _HAS_FIXED_POINT if (px->qual == 'v') return (_Geticvec(px)); /* v */ else if (px->qual == 'w') return (_Getihvec(px)); /* hv or vh */ else if (px->qual == 'W') return (_Getilvec(px)); /* hl or lh */ #endif /* _HAS_FIXED_POINT */ case 'p': /* convert a pointer */ return (_Getint(px, 0)); /* convert an integer */ case 'e': case 'E': case 'g': case 'G': case 'f': case 'F': case 'a': case 'A': #if _HAS_FIXED_POINT if (px->qual == 'v') return (_Getfvec(px)); #endif /* _HAS_FIXED_POINT */ return (_Getfloat(px, 0)); /* convert a floating */ #if _HAS_FIXED_POINT case 'k': /* convert a fixed signed accumulator */ return (_Fixed_get(px, FX_ACCUM)); case 'K': /* convert a fixed unsigned accumulator */ return (_Fixed_get(px, FX_ACCUM | FX_UNSIGNED)); case 'r': /* convert a fixed signed fraction */ return (_Fixed_get(px, 0)); case 'R': /* convert a fixed unsigned fraction */ return (_Fixed_get(px, FX_UNSIGNED)); #endif /* _HAS_FIXED_POINT */ case 'n': /* return input count */ if (!px->noconv) switch (px->qual) { /* store in specified integer type */ case 'b': *va_arg(px->ap, signed char *) = (signed char)px->nchar; break; case 'q': *va_arg(px->ap, _Longlong *) = px->nchar; break; case 'j': *va_arg(px->ap, intmax_t *) = px->nchar; break; case 't': *va_arg(px->ap, ptrdiff_t *) = px->nchar; break; case 'z': *va_arg(px->ap, size_t *) = px->nchar; break; case 'h': *va_arg(px->ap, short *) = (short)px->nchar; break; case 'l': *va_arg(px->ap, long *) = px->nchar; break; default: *va_arg(px->ap, int *) = px->nchar; } return (1); case 'S': /* convert a wide string -- nonstandard */ px->qual = 'l'; /* fall through */ case 's': /* convert a string */ return (_Getstr(px, 1)); case '%': { /* match a '%' */ int ch; if ((ch = GET(px)) == '%') return (1); UNGETN(px, ch); return (ch == EOF ? EOF : 0); } case '[': /* convert a scan set */ return (_Getstr(px, -1)); default: /* undefined specifier, quit */ return (0); } }
int _Scanf(int (*pfn)(void *, int), void *arg, const char *fmt, va_list ap) { /* read formatted */ int nconv = 0; _Sft x; x.pfn = pfn; x.arg = arg; x.ap = ap; x.nchar = 0; for (x.s = fmt; ; ++x.s) { /* parse format string */ int ch; { /* match any literal or white-space */ int n; wchar_t wc; _Mbsave state = {0}; while (0 < (n = _Mbtowc(&wc, x.s, MB_CUR_MAX, &state))) { /* check type of multibyte char */ x.s += n; if (wc == '%') break; else if (wc <= UCHAR_MAX && isspace(wc)) { /* match any white-space */ while (isspace(*x.s)) ++x.s; while (isspace(ch = GET(&x))) ; UNGETN(&x, ch); } else /* match literal text */ for (x.s -= n; 0 <= --n; ) if ((ch = GET(&x)) != *x.s++) { /* bad match */ UNGETN(&x, ch); return (nconv); } } if (*x.s == '\0') return (nconv); } { /* process a conversion specifier */ int code; x.noconv = *x.s == '*' ? *x.s++ : '\0'; for (x.width = 0; isdigit(*x.s); ++x.s) if (x.width < _WMAX) x.width = x.width * 10 + *x.s - '0'; x.qual = strchr("hlL", *x.s) ? *x.s++ : '\0'; if (!strchr("cn[", *x.s)) { /* match leading white-space */ while (isspace(ch = GET(&x))) ; UNGETN(&x, ch); } if ((code = _Getfld(&x)) <= 0) return (nconv == 0 ? code : nconv); if (x.stored) ++nconv; } } }