📄 scanf.c
字号:
/* * Modified by Manuel Novoa III Mar 13, 2001 * * The vfscanf routine was completely rewritten to add features and remove * bugs. The function __strtold, based on my strtod code in stdlib, was * added to provide floating point support for the scanf functions. * * So far they pass the test cases from glibc-2.1.3, except in two instances. * In one case, the test appears to be broken. The other case is something * I need to research further. This version of scanf assumes it can only * peek one character ahead. Apparently, glibc looks further. The difference * can be seen when parsing a floating point value in the character * sequence "100ergs". glibc is able to back up before the 'e' and return * a value of 100, whereas this scanf reports a bad match with the stream * pointer at 'r'. A similar situation can also happen when parsing hex * values prefixed by 0x or 0X; a failure would occur for "0xg". In order to * fix this, I need to rework the "ungetc" machinery in stdio.c again. * I do have one reference though, that seems to imply scanf has a single * character of lookahead. * * May 20, 2001 * * Quote from ANSI/ISO C99 standard: * * fscanf pushes back at most one input character onto the input stream. * Therefore, some sequences that are acceptable to strtod, strtol, etc., * are unacceptable to fscanf. * * So uClibc's *scanf functions conform to the standard, and glibc's * implementation doesn't for the "100ergs" case mentioned above. */#include <stdlib.h>#include <unistd.h>#define __USE_ISOC99#include <stdio.h>#include <ctype.h>#include <string.h>#include <stdarg.h>#ifdef L_scanf#ifdef __STDC__int scanf(const char *fmt, ...)#elseint scanf(fmt, va_alist)__const char *fmt;va_dcl#endif{ va_list ptr; int rv; va_start(ptr, fmt); rv = vfscanf(stdin, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_sscanf#ifdef __STDC__int sscanf(const char *sp, const char *fmt, ...)#elseint sscanf(sp, fmt, va_alist)__const char *sp;__const char *fmt;va_dcl#endif{ FILE string[1] = { {0, (unsigned char *) ((unsigned) -1), 0, 0, (char *) ((unsigned) -1), 0, -1, _IOFBF} }; va_list ptr; int rv; string->bufpos = (unsigned char *) ((void *) sp); va_start(ptr, fmt); rv = vfscanf(string, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_fscanf#ifdef __STDC__int fscanf(FILE * fp, const char *fmt, ...)#elseint fscanf(fp, fmt, va_alist)FILE *fp;__const char *fmt;va_dcl#endif{ va_list ptr; int rv; va_start(ptr, fmt); rv = vfscanf(fp, fmt, ptr); va_end(ptr); return rv;}#endif#ifdef L_vscanfint vscanf(fmt, ap)__const char *fmt;va_list ap;{ return vfscanf(stdin, fmt, ap);}#endif#ifdef L_vsscanfint vsscanf(__const char *sp, __const char *fmt, va_list ap){ FILE string[1] = { {0, (unsigned char *) ((unsigned) -1), 0, 0, (char *) ((unsigned) -1), 0, -1, _IOFBF} }; string->bufpos = (unsigned char *) sp; return vfscanf(string, fmt, ap);}#endif#ifdef L_vfscanf#include <assert.h>#include <ctype.h>#include <limits.h>static int valid_digit(char c, char base){ if (base == 16) { return isxdigit(c); } else { return (isdigit(c) && (c < '0' + base)); }}extern unsigned long long_strto_ll(const char *str, char **endptr, int base, int uflag);extern unsigned long_strto_l(const char *str, char **endptr, int base, int uflag);struct scan_cookie { FILE *fp; int nread; int width; int width_flag; int ungot_char; int ungot_flag;};#ifdef __UCLIBC_HAS_LONG_LONG__static const char qual[] = "hl" /* "jtz" */ "Lq";/* char = -2, short = -1, int = 0, long = 1, long long = 2 */static const char qsz[] = { -1, 1, 2, 2 };#elsestatic const char qual[] = "hl" /* "jtz" */;static const char qsz[] = { -1, 1, };#endif#ifdef __UCLIBC_HAS_FLOATS__static int __strtold(long double *ld, struct scan_cookie *sc); /*01234567890123456 */static const char spec[] = "%n[csoupxXidfeEgG";#elsestatic const char spec[] = "%n[csoupxXid";#endif/* radix[i] <-> spec[i+5] o u p x X i d */static const char radix[] = { 8, 10, 16, 16, 16, 0, 10 };static void init_scan_cookie(struct scan_cookie *sc, FILE *fp){ sc->fp = fp; sc->nread = 0; sc->width_flag = 0; sc->ungot_flag = 0;}static int scan_getc_nw(struct scan_cookie *sc){ if (sc->ungot_flag == 0) { sc->ungot_char = getc(sc->fp); } else { sc->ungot_flag = 0; } if (sc->ungot_char > 0) { ++sc->nread; } sc->width_flag = 0; return sc->ungot_char;}static int scan_getc(struct scan_cookie *sc){ if (sc->ungot_flag == 0) { sc->ungot_char = getc(sc->fp); } sc->width_flag = 1; if (--sc->width < 0) { sc->ungot_flag = 1; return 0; } sc->ungot_flag = 0; if (sc->ungot_char > 0) { ++sc->nread; } return sc->ungot_char;}static void scan_ungetc(struct scan_cookie *sc){ if (sc->ungot_flag != 0) { assert(sc->width < 0); return; } if (sc->width_flag) { ++sc->width; } sc->ungot_flag = 1; if (sc->ungot_char > 0) { /* not EOF or EOS */ --sc->nread; }}static void kill_scan_cookie(struct scan_cookie *sc){ if (sc->ungot_flag) { ungetc(sc->ungot_char,sc->fp); }}int vfscanf(fp, format, ap)FILE *fp;const char *format;va_list ap;{#ifdef __UCLIBC_HAS_LONG_LONG__#define STRTO_L_(s,e,b,u) _strto_ll(s,e,b,u)#define MAX_DIGITS 64#define UV_TYPE unsigned long long#define V_TYPE long long#else#define STRTO_L_(s,e,b,u) _strto_l(s,e,b,u)#define MAX_DIGITS 32#define UV_TYPE unsigned long#define V_TYPE long#endif#ifdef __UCLIBC_HAS_FLOATS__ long double ld;#endif UV_TYPE uv; struct scan_cookie sc; unsigned const char *fmt; const char *p; unsigned char *b; void *vp; int cc, i, cnt; signed char lval; unsigned char store, usflag, base, invert, r0, r1; unsigned char buf[MAX_DIGITS+2]; unsigned char scanset[UCHAR_MAX + 1]; init_scan_cookie(&sc,fp); fmt = (unsigned const char *) format; cnt = 0; while (*fmt) { store = 1; lval = 0; sc.width = INT_MAX; if (*fmt == '%') { /* Conversion specification. */ ++fmt; if (*fmt == '*') { /* Suppress assignment. */ store = 0; ++fmt; } for (i = 0 ; isdigit(*fmt) ; sc.width = i) { i = (i * 10) + (*fmt++ - '0'); /* Get specified width. */ } for (i = 0 ; i < sizeof(qual) ; i++) { /* Optional qualifier. */ if (qual[i] == *fmt) { ++fmt; lval += qsz[i]; if ((i < 2) && (qual[i] == *fmt)) { /* Double h or l. */ ++fmt; lval += qsz[i]; } break; } } for (p = spec ; *p ; p++) { /* Process format specifier. */ if (*fmt != *p) continue; if (p-spec < 1) { /* % - match a '%'*/ goto matchchar; } if (p-spec < 2) { /* n - store number of chars read */ *(va_arg(ap, int *)) = sc.nread; scan_getc_nw(&sc); goto nextfmt; } if (p-spec > 3) { /* skip white space if not c or [ */ while (isspace(scan_getc_nw(&sc))) {} scan_ungetc(&sc); } if (p-spec < 5) { /* [,c,s - string conversions */ invert = 0; if (*p == 'c') { invert = 1; if (sc.width == INT_MAX) { sc.width = 1; } } for (i=0 ; i<= UCHAR_MAX ; i++) { scanset[i] = ((*p == 's') ? (isspace(i) == 0) : 0); } if (*p == '[') { /* need to build a scanset */ if (*++fmt == '^') { invert = 1; ++fmt; } if (*fmt == ']') { scanset[(int)']'] = 1; ++fmt; } r0 = 0; while (*fmt && *fmt !=']') { /* build scanset */ if ((*fmt == '-') && r0 && (fmt[1] != ']')) { /* range */ ++fmt; if (*fmt < r0) { r1 = r0; r0 = *fmt; } else { r1 = *fmt; } for (i=r0 ; i<= r1 ; i++) { scanset[i] = 1; } r0 = 0; } else { r0 = *fmt; scanset[r0] = 1; } ++fmt; } if (!*fmt) { /* format string exhausted! */ goto done; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -