📄 vfscanf.c
字号:
case 'B': case 'C': case 'D': case 'E': case 'F': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': /* no need to fix base here */ if (base <= 10) break; /* not legal here */ flags &= ~(SIGNOK | PFXOK | NDIGITS | NNZDIGITS); goto ok; /* sign ok only as first character */ case '+': case '-': if (flags & SIGNOK) { flags &= ~SIGNOK; goto ok; } break; /* x ok iff flag still set & single 0 seen */ case 'x': case 'X': if ((flags & (PFXOK | NZDIGITS)) == PFXOK) { base = 16;/* if %i */ flags &= ~PFXOK; /* We must reset the NZDIGITS and NDIGITS flags that would have been unset by seeing the zero that preceded the X or x. */ flags |= NZDIGITS | NDIGITS; goto ok; } break; } /* * If we got here, c is not a legal character * for a number. Stop accumulating digits. */ break; ok: /* * c is legal: store it and look at the next. */ *p++ = c; skip: if (--fp->_r > 0) fp->_p++; else if (__srefill_r (rptr, fp)) break; /* EOF */ } /* * If we had only a sign, it is no good; push back the sign. * If the number ends in `x', it was [sign] '0' 'x', so push back * the x and treat it as [sign] '0'. * Use of ungetc here and below assumes ASCII encoding; we are only * pushing back 7-bit characters, so casting to unsigned char is * not necessary. */ if (flags & NDIGITS) { if (p > buf) _ungetc_r (rptr, *--p, fp); /* [-+xX] */ if (p == buf) goto match_failure; } if ((flags & SUPPRESS) == 0) { u_long res; *p = 0; res = (*ccfn) (rptr, buf, (char **) NULL, base); if (flags & POINTER) { void **vp = GET_ARG (N, ap, void **);#ifndef _NO_LONGLONG if (sizeof (uintptr_t) > sizeof (u_long)) { u_long_long resll; resll = _strtoull_r (rptr, buf, (char **) NULL, base); *vp = (void *) (uintptr_t) resll; } else#endif /* !_NO_LONGLONG */ *vp = (void *) (uintptr_t) res; }#ifdef _WANT_IO_C99_FORMATS else if (flags & CHAR) { cp = GET_ARG (N, ap, char *); *cp = res; }#endif else if (flags & SHORT) { sp = GET_ARG (N, ap, short *); *sp = res; } else if (flags & LONG) { lp = GET_ARG (N, ap, long *); *lp = res; }#ifndef _NO_LONGLONG else if (flags & LONGDBL) { u_long_long resll; if (ccfn == _strtoul_r) resll = _strtoull_r (rptr, buf, (char **) NULL, base); else resll = _strtoll_r (rptr, buf, (char **) NULL, base); llp = GET_ARG (N, ap, long long*); *llp = resll; }#endif else { ip = GET_ARG (N, ap, int *); *ip = res; } nassigned++; } nread += p - buf + skips; break; }#ifdef FLOATING_POINT case CT_FLOAT: { /* scan a floating point number as if by strtod */ /* This code used to assume that the number of digits is reasonable. However, ANSI / ISO C makes no such stipulation; we have to get exact results even when there is an unreasonable amount of leading zeroes. */ long leading_zeroes = 0; long zeroes, exp_adjust; char *exp_start = NULL; unsigned width_left = 0; char nancount = 0; char infcount = 0;#ifdef hardway if (width == 0 || width > sizeof (buf) - 1)#else /* size_t is unsigned, hence this optimisation */ if (width - 1 > sizeof (buf) - 2)#endif { width_left = width - (sizeof (buf) - 1); width = sizeof (buf) - 1; } flags |= SIGNOK | NDIGITS | DPTOK | EXPOK; zeroes = 0; exp_adjust = 0; for (p = buf; width; ) { c = *fp->_p; /* * This code mimicks the integer conversion * code, but is much simpler. */ switch (c) { case '0': if (flags & NDIGITS) { flags &= ~SIGNOK; zeroes++; if (width_left) { width_left--; width++; } goto fskip; } /* Fall through. */ case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (nancount + infcount == 0) { flags &= ~(SIGNOK | NDIGITS); goto fok; } break; case '+': case '-': if (flags & SIGNOK) { flags &= ~SIGNOK; goto fok; } break; case 'n': case 'N': if (nancount == 0 && (flags & (NDIGITS | DPTOK | EXPOK)) == (NDIGITS | DPTOK | EXPOK)) { flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS); nancount = 1; goto fok; } if (nancount == 2) { nancount = 3; goto fok; } if (infcount == 1 || infcount == 4) { infcount++; goto fok; } break; case 'a': case 'A': if (nancount == 1) { nancount = 2; goto fok; } break; case 'i': case 'I': if (infcount == 0 && (flags & (NDIGITS | DPTOK | EXPOK)) == (NDIGITS | DPTOK | EXPOK)) { flags &= ~(SIGNOK | DPTOK | EXPOK | NDIGITS); infcount = 1; goto fok; } if (infcount == 3 || infcount == 5) { infcount++; goto fok; } break; case 'f': case 'F': if (infcount == 2) { infcount = 3; goto fok; } break; case 't': case 'T': if (infcount == 6) { infcount = 7; goto fok; } break; case 'y': case 'Y': if (infcount == 7) { infcount = 8; goto fok; } break; case '.': if (flags & DPTOK) { flags &= ~(SIGNOK | DPTOK); leading_zeroes = zeroes; goto fok; } break; case 'e': case 'E': /* no exponent without some digits */ if ((flags & (NDIGITS | EXPOK)) == EXPOK || ((flags & EXPOK) && zeroes)) { if (! (flags & DPTOK)) { exp_adjust = zeroes - leading_zeroes; exp_start = p; } flags = (flags & ~(EXPOK | DPTOK)) | SIGNOK | NDIGITS; zeroes = 0; goto fok; } break; } break; fok: *p++ = c; fskip: width--; ++nread; if (--fp->_r > 0) fp->_p++; else if (__srefill_r (rptr, fp)) break; /* EOF */ } if (zeroes) flags &= ~NDIGITS; /* We may have a 'N' or possibly even [sign] 'N' 'a' as the start of 'NaN', only to run out of chars before it was complete (or having encountered a non-matching char). So check here if we have an outstanding nancount, and if so put back the chars we did swallow and treat as a failed match. FIXME - we still don't handle NAN([0xdigits]). */ if (nancount - 1U < 2U) /* nancount && nancount < 3 */ { /* Newlib's ungetc works even if we called __srefill in the middle of a partial parse, but POSIX does not guarantee that in all implementations of ungetc. */ while (p > buf) { _ungetc_r (rptr, *--p, fp); /* [-+nNaA] */ --nread; } goto match_failure; } /* Likewise for 'inf' and 'infinity'. But be careful that 'infinite' consumes only 3 characters, leaving the stream at the second 'i'. */ if (infcount - 1U < 7U) /* infcount && infcount < 8 */ { if (infcount >= 3) /* valid 'inf', but short of 'infinity' */ while (infcount-- > 3) { _ungetc_r (rptr, *--p, fp); /* [iInNtT] */ --nread; } else { while (p > buf) { _ungetc_r (rptr, *--p, fp); /* [-+iInN] */ --nread; } goto match_failure; } } /* * If no digits, might be missing exponent digits * (just give back the exponent) or might be missing * regular digits, but had sign and/or decimal point. */ if (flags & NDIGITS) { if (flags & EXPOK) { /* no digits at all */ while (p > buf) { _ungetc_r (rptr, *--p, fp); /* [-+.] */ --nread; } goto match_failure; } /* just a bad exponent (e and maybe sign) */ c = *--p; --nread; if (c != 'e' && c != 'E') { _ungetc_r (rptr, c, fp); /* [-+] */ c = *--p; --nread; } _ungetc_r (rptr, c, fp); /* [eE] */ } if ((flags & SUPPRESS) == 0) { double res = 0;#ifdef _NO_LONGDBL#define QUAD_RES res;#else /* !_NO_LONG_DBL */ long double qres = 0;#define QUAD_RES qres;#endif /* !_NO_LONG_DBL */ long new_exp = 0; *p = 0; if ((flags & (DPTOK | EXPOK)) == EXPOK) { exp_adjust = zeroes - leading_zeroes; new_exp = -exp_adjust; exp_start = p; } else if (exp_adjust) new_exp = _strtol_r (rptr, (exp_start + 1), NULL, 10) - exp_adjust; if (exp_adjust) { /* If there might not be enough space for the new exponent, truncate some trailing digits to make room. */ if (exp_start >= buf + sizeof (buf) - MAX_LONG_LEN) exp_start = buf + sizeof (buf) - MAX_LONG_LEN - 1; sprintf (exp_start, "e%ld", new_exp); } /* Current _strtold routine is markedly slower than _strtod_r. Only use it if we have a long double result. */#ifndef _NO_LONGDBL /* !_NO_LONGDBL */ if (flags & LONGDBL) qres = _strtold (buf, NULL); else#endif res = _strtod_r (rptr, buf, NULL); if (flags & LONG) { dp = GET_ARG (N, ap, double *); *dp = res; } else if (flags & LONGDBL) { ldp = GET_ARG (N, ap, _LONG_DOUBLE *); *ldp = QUAD_RES; } else { flp = GET_ARG (N, ap, float *); if (isnan (res)) *flp = nanf (NULL); else *flp = res; } nassigned++; } break; }#endif /* FLOATING_POINT */ } }input_failure: /* On read failure, return EOF failure regardless of matches; errno should have been set prior to here. On EOF failure (including invalid format string), return EOF if no matches yet, else number of matches made prior to failure. */ _funlockfile (fp); return nassigned && !(fp->_flags & __SERR) ? nassigned : EOF;match_failure:all_done: /* Return number of matches, which can be 0 on match failure. */ _funlockfile (fp); return nassigned;}#ifndef _NO_POS_ARGS/* Process all intermediate arguments. Fortunately, with scanf, all intermediate arguments are sizeof(void*), so we don't need to scan ahead in the format string. */static void *get_arg (int n, va_list *ap, int *numargs_p, void **args){ int numargs = *numargs_p; while (n >= numargs) args[numargs++] = va_arg (*ap, void *); *numargs_p = numargs; return args[n];}#endif /* !_NO_POS_ARGS */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -