📄 vfscanf.c
字号:
/*- * Copyright (c) 1990, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Chris Torek. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#define FLOATING_POINT 1#if defined(LIBC_SCCS) && !defined(lint)static char rcsid[] = "$OpenBSD: vfscanf.c,v 1.6 1998/01/20 21:25:39 millert Exp $";#endif /* LIBC_SCCS and not lint */#include <stdio.h>#include <stdlib.h>#include <ctype.h>#ifdef __STDC__#include <stdarg.h>#else#include <varargs.h>#endif#include "local.h"#define FLOATING_POINT 1#ifdef FLOATING_POINT#include "floatio.h"#endif#define BUF 513 /* Maximum length of numeric string. *//* * Flags used during conversion. */#define LONG 0x01 /* l: long or double */#define LONGDBL 0x02 /* L: long double; unimplemented */#define SHORT 0x04 /* h: short */#define QUAD 0x08 /* q: quad */#define SUPPRESS 0x10 /* suppress assignment */#define POINTER 0x20 /* weird %p pointer (`fake hex') */#define NOSKIP 0x40 /* do not skip blanks *//* * The following are used in numeric conversions only: * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point; * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral. */#define SIGNOK 0x080 /* +/- is (still) legal */#define NDIGITS 0x100 /* no digits detected */#define DPTOK 0x200 /* (float) decimal point is still legal */#define EXPOK 0x400 /* (float) exponent (e+3, etc) still legal */#define PFXOK 0x200 /* 0x prefix is (still) legal */#define NZDIGITS 0x400 /* no zero digits detected *//* * Conversion types. */#define CT_CHAR 0 /* %c conversion */#define CT_CCL 1 /* %[...] conversion */#define CT_STRING 2 /* %s conversion */#define CT_INT 3 /* integer, i.e., strtoq or strtouq */#define CT_FLOAT 4 /* floating, i.e., strtod */#define u_char unsigned char#define u_long unsigned longstatic u_char *__sccl();/* * vfscanf */int__svfscanf(fp, fmt0, ap) register FILE *fp; char const *fmt0; _BSD_VA_LIST_ ap;{ register u_char *fmt = (u_char *)fmt0; register int c; /* character from format, or conversion */ register size_t width; /* field width, or 0 */ register char *p; /* points into all kinds of strings */ register int n; /* handy integer */ register int flags; /* flags as defined above */ register char *p0; /* saves original value of p when necessary */ int nassigned; /* number of fields assigned */ int nread; /* number of characters consumed from fp */ int base; /* base argument to strtoq/strtouq */ u_quad_t (*ccfn)(); /* conversion function (strtoq/strtouq) */ char ccltab[256]; /* character class table for %[...] */ char buf[BUF]; /* buffer for numeric conversions */ /* `basefix' is used to avoid `if' tests in the integer scanner */ static short basefix[17] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; nassigned = 0; nread = 0; base = 0; /* XXX just to keep gcc happy */ ccfn = NULL; /* XXX just to keep gcc happy */ for (;;) { c = *fmt++; if (c == 0) return (nassigned); if (isspace(c)) { while ((fp->_r > 0 || __srefill(fp) == 0) && isspace(*fp->_p)) nread++, fp->_r--, fp->_p++; continue; } if (c != '%') goto literal; width = 0; flags = 0; /* * switch on the format. continue if done; * break once format type is derived. */again: c = *fmt++; switch (c) { case '%':literal: if (fp->_r <= 0 && __srefill(fp)) goto input_failure; if (*fp->_p != c) goto match_failure; fp->_r--, fp->_p++; nread++; continue; case '*': flags |= SUPPRESS; goto again; case 'L': flags |= LONGDBL; goto again; case 'h': flags |= SHORT; goto again; case 'l': if (*fmt == 'l') { fmt++; flags |= QUAD; } else { flags |= LONG; } goto again; case 'q': flags |= QUAD; goto again; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': width = width * 10 + c - '0'; goto again; /* * Conversions. * Those marked `compat' are for 4.[123]BSD compatibility. * * (According to ANSI, E and X formats are supposed * to the same as e and x. Sorry about that.) */ case 'D': /* compat */ flags |= LONG; /* FALLTHROUGH */ case 'd': c = CT_INT; ccfn = (u_quad_t (*)())strtoq; base = 10; break; case 'i': c = CT_INT; ccfn = (u_quad_t (*)())strtoq; base = 0; break; case 'O': /* compat */ flags |= LONG; /* FALLTHROUGH */ case 'o': c = CT_INT; ccfn = strtouq; base = 8; break; case 'u': c = CT_INT; ccfn = strtouq; base = 10; break; case 'X': case 'x': flags |= PFXOK; /* enable 0x prefixing */ c = CT_INT; ccfn = strtouq; base = 16; break;#ifdef FLOATING_POINT case 'E': case 'G': case 'e': case 'f': case 'g': c = CT_FLOAT; break;#endif case 's': c = CT_STRING; break; case '[': fmt = __sccl(ccltab, fmt); flags |= NOSKIP; c = CT_CCL; break; case 'c': flags |= NOSKIP; c = CT_CHAR; break; case 'p': /* pointer format is like hex */ flags |= POINTER | PFXOK; c = CT_INT; ccfn = strtouq; base = 16; break; case 'n': if (flags & SUPPRESS) /* ??? */ continue; if (flags & SHORT) *va_arg(ap, short *) = nread; else if (flags & LONG) *va_arg(ap, long *) = nread; else *va_arg(ap, int *) = nread; continue; /* * Disgusting backwards compatibility hacks. XXX */ case '\0': /* compat */ return (EOF); default: /* compat */ if (isupper(c)) flags |= LONG; c = CT_INT; ccfn = (u_quad_t (*)())strtoq; base = 10; break; } /* * We have a conversion that requires input. */ if (fp->_r <= 0 && __srefill(fp)) goto input_failure; /* * Consume leading white space, except for formats * that suppress this. */ if ((flags & NOSKIP) == 0) { while (isspace(*fp->_p)) { nread++; if (--fp->_r > 0) fp->_p++; else if (__srefill(fp)) goto input_failure; } /* * Note that there is at least one character in * the buffer, so conversions that do not set NOSKIP * ca no longer result in an input failure. */ } /* * Do the conversion. */ switch (c) { case CT_CHAR: /* scan arbitrary characters (sets NOSKIP) */ if (width == 0) width = 1; if (flags & SUPPRESS) { size_t sum = 0; for (;;) { if ((n = fp->_r) < width) { sum += n; width -= n; fp->_p += n; if (__srefill(fp)) { if (sum == 0) goto input_failure; break; } } else { sum += width; fp->_r -= width; fp->_p += width; break; } } nread += sum; } else { size_t r = fread((void *)va_arg(ap, char *), 1, width, fp); if (r == 0) goto input_failure; nread += r; nassigned++; } break; case CT_CCL: /* scan a (nonempty) character class (sets NOSKIP) */ if (width == 0) width = (size_t)~0; /* `infinity' */ /* take only those things in the class */ if (flags & SUPPRESS) { n = 0; while (ccltab[*fp->_p]) { n++, fp->_r--, fp->_p++; if (--width == 0) break; if (fp->_r <= 0 && __srefill(fp)) { if (n == 0) goto input_failure; break; } } if (n == 0) goto match_failure; } else { p0 = p = va_arg(ap, char *); while (ccltab[*fp->_p]) { fp->_r--; *p++ = *fp->_p++; if (--width == 0) break; if (fp->_r <= 0 && __srefill(fp)) { if (p == p0)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -