📄 scanf.c
字号:
/**********************************************************************/#ifdef L_vfwscanf#if WINT_MIN > EOF#error Unfortunately, we currently need wint_t to be able to store EOF. Sorry.#endif#define W_EOF WEOF#define Wint wint_t#define Wchar wchar_t#define Wuchar __uwchar_t#define ISSPACE(C) iswspace((C))#define VFSCANF vfwscanf#define GETC(SC) (SC)->sc_getc((SC))#elsetypedef unsigned char __uchar_t;#define W_EOF EOF#define Wint int#define Wchar char#define Wuchar __uchar_t#define ISSPACE(C) isspace((C))#define VFSCANF vfscanf#ifdef __UCLIBC_HAS_WCHAR__#define GETC(SC) (SC)->sc_getc((SC))#else /* __UCLIBC_HAS_WCHAR__ */#define GETC(SC) getc_unlocked((SC)->fp)#endif /* __UCLIBC_HAS_WCHAR__ */#endifstruct scan_cookie { Wint cc; Wint ungot_char; FILE *fp; int nread; int width;#ifdef __UCLIBC_HAS_WCHAR__ wchar_t app_ungot; /* Match FILE struct member type. */ unsigned char ungot_wchar_width;#else /* __UCLIBC_HAS_WCHAR__ */ unsigned char app_ungot; /* Match FILE struct member type. */#endif /* __UCLIBC_HAS_WCHAR__ */ char ungot_flag;#ifdef __UCLIBC_HAS_WCHAR__ char ungot_wflag; /* vfwscanf */ char mb_fail; /* vfscanf */ mbstate_t mbstate; /* vfscanf */ wint_t wc; wint_t ungot_wchar; /* to support __scan_getc */ int (*sc_getc)(struct scan_cookie *);#endif /* __UCLIBC_HAS_WCHAR__ */#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ const char *grouping; const unsigned char *thousands_sep; int tslen;#ifdef __UCLIBC_HAS_WCHAR__ wchar_t thousands_sep_wc;#endif /* __UCLIBC_HAS_WCHAR__ */#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */#ifdef __UCLIBC_HAS_FLOATS__ const unsigned char *decpt; int decpt_len;#ifdef __UCLIBC_HAS_WCHAR__ wchar_t decpt_wc;#endif /* __UCLIBC_HAS_WCHAR__ */ const unsigned char *fake_decpt;#endif /* __UCLIBC_HAS_FLOATS__ */};typedef struct {#if defined(NL_ARGMAX) && (NL_ARGMAX > 0)#if NL_ARGMAX > 10#warning NL_ARGMAX > 10, and space is allocated on the stack for positional args.#endif void *pos_args[NL_ARGMAX]; int num_pos_args; /* Must start at -1. */ int cur_pos_arg;#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */ void *cur_ptr; const unsigned char *fmt; int cnt, dataargtype, conv_num, max_width; unsigned char store, flags;} psfs_t; /* parse scanf format state *//**********************************************************************//**********************************************************************/extern void __init_scan_cookie(register struct scan_cookie *sc, register FILE *fp);extern int __scan_getc(register struct scan_cookie *sc);extern void __scan_ungetc(register struct scan_cookie *sc);#ifdef __UCLIBC_HAS_FLOATS__extern int __scan_strtold(long double *ld, struct scan_cookie *sc);#endif /* __UCLIBC_HAS_FLOATS__ */extern int __psfs_parse_spec(psfs_t *psfs);extern int __psfs_do_numeric(psfs_t *psfs, struct scan_cookie *sc);/**********************************************************************/#ifdef L___scan_cookie#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Remove dependence on decpt_str and fake_decpt in stub locale mode.#endif#ifndef __UCLIBC_HAS_LOCALE__static const char decpt_str[] = ".";#endifvoid __init_scan_cookie(register struct scan_cookie *sc, register FILE *fp){ sc->fp = fp; sc->nread = 0; sc->ungot_flag = 0; sc->app_ungot = ((fp->__modeflags & __FLAG_UNGOT) ? fp->__ungot[1] : 0);#ifdef __UCLIBC_HAS_WCHAR__ sc->ungot_wflag = 0; /* vfwscanf */ sc->mb_fail = 0;#endif /* __UCLIBC_HAS_WCHAR__ */#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ if (*(sc->grouping = __UCLIBC_CURLOCALE_DATA.grouping)) { sc->thousands_sep = __UCLIBC_CURLOCALE_DATA.thousands_sep; sc->tslen = __UCLIBC_CURLOCALE_DATA.thousands_sep_len;#ifdef __UCLIBC_HAS_WCHAR__ sc->thousands_sep_wc = __UCLIBC_CURLOCALE_DATA.thousands_sep_wc;#endif /* __UCLIBC_HAS_WCHAR__ */ }#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */#ifdef __UCLIBC_HAS_FLOATS__#ifdef __UCLIBC_HAS_LOCALE__ sc->decpt = __UCLIBC_CURLOCALE_DATA.decimal_point; sc->decpt_len = __UCLIBC_CURLOCALE_DATA.decimal_point_len;#else /* __UCLIBC_HAS_LOCALE__ */ sc->fake_decpt = sc->decpt = decpt_str; sc->decpt_len = 1;#endif /* __UCLIBC_HAS_LOCALE__ */#ifdef __UCLIBC_HAS_WCHAR__#ifdef __UCLIBC_HAS_LOCALE__ sc->decpt_wc = __UCLIBC_CURLOCALE_DATA.decimal_point_wc;#else sc->decpt_wc = '.';#endif#endif /* __UCLIBC_HAS_WCHAR__ */#endif /* __UCLIBC_HAS_FLOATS__ */}int __scan_getc(register struct scan_cookie *sc){ int c;#ifdef __UCLIBC_HAS_WCHAR__ assert(!sc->mb_fail);#endif /* __UCLIBC_HAS_WCHAR__ */ sc->cc = EOF; if (--sc->width < 0) { sc->ungot_flag |= 2; return -1; } if (sc->ungot_flag == 0) {#if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__) if (!__STDIO_STREAM_IS_FAKE_VSSCANF_NB(sc->fp)) { c = GETC(sc); } else { __FILE_vsscanf *fv = (__FILE_vsscanf *)(sc->fp); if (fv->bufpos < fv->bufread) { c = *fv->bufpos++; } else { c = EOF; sc->fp->__modeflags |= __FLAG_EOF; } } if (c == EOF) { sc->ungot_flag |= 2; return -1; }#else if ((c = GETC(sc)) == EOF) { sc->ungot_flag |= 2; return -1; }#endif sc->ungot_char = c; } else { assert(sc->ungot_flag == 1); sc->ungot_flag = 0; } ++sc->nread; return sc->cc = sc->ungot_char;}void __scan_ungetc(register struct scan_cookie *sc){ ++sc->width; if (sc->ungot_flag == 2) { /* last was EOF */ sc->ungot_flag = 0; sc->cc = sc->ungot_char; } else if (sc->ungot_flag == 0) { sc->ungot_flag = 1; --sc->nread; } else { assert(0); }}#endif/**********************************************************************/#ifdef L___psfs_parse_spec#ifdef SPEC_FLAGSstatic const unsigned char spec_flags[] = SPEC_FLAGS;#endif /* SPEC_FLAGS */static const unsigned char spec_chars[] = SPEC_CHARS;static const unsigned char qual_chars[] = QUAL_CHARS;static const unsigned char spec_ranges[] = SPEC_RANGES;static const unsigned short spec_allowed[] = SPEC_ALLOWED_FLAGS;int __psfs_parse_spec(register psfs_t *psfs){ const unsigned char *p; const unsigned char *fmt0 = psfs->fmt; int i;#ifdef SPEC_FLAGS int j;#endif#if defined(NL_ARGMAX) && (NL_ARGMAX > 0) unsigned char fail = 0; i = 0; /* Do this here to avoid a warning. */ if (!__isdigit_char(*psfs->fmt)) { /* Not a positional arg. */ fail = 1; goto DO_FLAGS; } /* parse the positional arg (or width) value */ do { if (i <= ((INT_MAX - 9)/10)) { i = (i * 10) + (*psfs->fmt++ - '0'); } } while (__isdigit_char(*psfs->fmt)); if (*psfs->fmt != '$') { /* This is a max field width. */ if (psfs->num_pos_args >= 0) { /* Already saw a pos arg! */ goto ERROR_EINVAL; } psfs->max_width = i; psfs->num_pos_args = -2; goto DO_QUALIFIER; } ++psfs->fmt; /* Advance past '$'. */#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */#if defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0)) DO_FLAGS:#endif /* defined(SPEC_FLAGS) || (defined(NL_ARGMAX) && (NL_ARGMAX > 0)) */#ifdef SPEC_FLAGS p = spec_flags; j = FLAG_SURPRESS; do { if (*p == *psfs->fmt) { ++psfs->fmt; psfs->flags |= j; goto DO_FLAGS; } j += j; } while (*++p); if (psfs->flags & FLAG_SURPRESS) { /* Suppress assignment. */ psfs->store = 0; goto DO_WIDTH; }#else /* SPEC_FLAGS */ if (*psfs->fmt == '*') { /* Suppress assignment. */ ++psfs->fmt; psfs->store = 0; goto DO_WIDTH; }#endif /* SPEC_FLAGS */#if defined(NL_ARGMAX) && (NL_ARGMAX > 0) if (fail) { /* Must be a non-positional arg */ if (psfs->num_pos_args >= 0) { /* Already saw a pos arg! */ goto ERROR_EINVAL; } psfs->num_pos_args = -2; } else { if ((psfs->num_pos_args == -2) || (((unsigned int)(--i)) >= NL_ARGMAX)) { /* Already saw a non-pos arg or (0-based) num too large. */ goto ERROR_EINVAL; } psfs->cur_pos_arg = i; }#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */ DO_WIDTH: for (i = 0 ; __isdigit_char(*psfs->fmt) ; ) { if (i <= ((INT_MAX - 9)/10)) { i = (i * 10) + (*psfs->fmt++ - '0'); psfs->max_width = i; } }#if defined(NL_ARGMAX) && (NL_ARGMAX > 0) DO_QUALIFIER:#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */ p = qual_chars; do { if (*psfs->fmt == *p) { ++psfs->fmt; break; } } while (*++p); if ((p - qual_chars < 2) && (*psfs->fmt == *p)) { p += ((sizeof(qual_chars)-2) / 2); ++psfs->fmt; } psfs->dataargtype = ((int)(p[(sizeof(qual_chars)-2) / 2])) << 8;#ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: Should we validate that psfs->max_width > 0 in __psfs_parse_spec()? It would avoid whitespace consumption...#warning CONSIDER: Should INT_MAX be a valid width (%c/%C)? See __psfs_parse_spec().#endif /* __UCLIBC_MJN3_ONLY__ */ p = spec_chars; do { if (*psfs->fmt == *p) { int p_m_spec_chars = p - spec_chars;#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__#error implement gnu a flag if ((*p == 'a') && ((psfs->fmt[1] == '[') || ((psfs->fmt[1]|0x20) == 's')) ) { /* Assumes ascii for 's' and 'S' test. */ psfs->flags |= FLAG_MALLOC; ++psfs->fmt; ++p; continue; /* The related conversions follow 'a'. */ }#endif /* __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ */ for (p = spec_ranges; p_m_spec_chars > *p ; ++p) {} if (((psfs->dataargtype >> 8) | psfs->flags) & ~spec_allowed[(int)(p - spec_ranges)] ) { goto ERROR_EINVAL; } if ((p_m_spec_chars >= CONV_c) && (psfs->dataargtype & PA_FLAG_LONG)) { p_m_spec_chars -= 3; /* lc -> C, ls -> S, l[ -> ?? */ } psfs->conv_num = p_m_spec_chars; return psfs->fmt - fmt0; } if (!*++p) { ERROR_EINVAL: __set_errno(EINVAL); return -1; } } while(1); assert(0);}#endif/**********************************************************************/#if defined(L_vfscanf) || defined(L_vfwscanf)#ifdef __UCLIBC_HAS_WCHAR__#ifdef L_vfscanfstatic int sc_getc(register struct scan_cookie *sc){ return (getc_unlocked)(sc->fp); /* Disable the macro. */}static int scan_getwc(register struct scan_cookie *sc){ size_t r; int width; wchar_t wc[1]; char b[1]; if (--sc->width < 0) { sc->ungot_flag |= 2; return -1; } width = sc->width; /* Preserve width. */ sc->width = INT_MAX; /* MB_CUR_MAX can invoke a function. */ assert(!sc->mb_fail); r = (size_t)(-3); while (__scan_getc(sc) >= 0) { *b = sc->cc; r = mbrtowc(wc, b, 1, &sc->mbstate); if (((ssize_t) r) >= 0) { /* Successful completion of a wc. */ sc->wc = *wc; goto SUCCESS; } else if (r == ((size_t) -2)) { /* Potentially valid but incomplete. */ continue; } break; } if (r == ((size_t)(-3))) { /* EOF or ERROR on first read */ sc->wc = WEOF; r = (size_t)(-1); } else { /* If we reach here, either r == ((size_t)-1) and * mbrtowc set errno to EILSEQ, or r == ((size_t)-2) * and stream is in an error state or at EOF with a * partially complete wchar. */ __set_errno(EILSEQ); /* In case of incomplete conversion. */ sc->mb_fail = 1; } SUCCESS: sc->width = width; /* Restore width. */ return (int)((ssize_t) r);}#endif /* L_vfscanf */#ifdef L_vfwscanf/* This gets called by __scan_getc. __scan_getc is called by vfwscanf * when the next wide char is expected to be valid ascii (digits). */static int sc_getc(register struct scan_cookie *sc){ wint_t wc; if (__STDIO_STREAM_IS_FAKE_VSWSCANF(sc->fp)) { if (sc->fp->__bufpos < sc->fp->__bufend) { wc = *((wchar_t *)(sc->fp->__bufpos)); sc->fp->__bufpos += sizeof(wchar_t); } else { sc->fp->__modeflags |= __FLAG_EOF; return EOF; } } else if ((wc = fgetwc_unlocked(sc->fp)) == WEOF) { return EOF; } sc->ungot_wflag = 1; sc->ungot_wchar = wc; sc->ungot_wchar_width = sc->fp->__ungot_width[0];#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ if (wc == sc->thousands_sep_wc) { wc = ','; } else#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */#ifdef __UCLIBC_HAS_FLOATS__ if (wc == sc->decpt_wc) { wc = '.'; } else#endif /* __UCLIBC_HAS_FLOATS__ */ if (!__isascii(wc)) { wc = '?'; } sc->wc = sc->ungot_char = wc; return (int) wc;}static int scan_getwc(register struct scan_cookie *sc){ wint_t wc; sc->wc = WEOF; if (--sc->width < 0) { sc->ungot_flag |= 2; return -1; } if (sc->ungot_flag == 0) { if (__STDIO_STREAM_IS_FAKE_VSWSCANF(sc->fp)) { if (sc->fp->__bufpos < sc->fp->__bufend) { wc = *((wchar_t *)(sc->fp->__bufpos)); sc->fp->__bufpos += sizeof(wchar_t); } else { sc->ungot_flag |= 2; return -1; } } else if ((wc = fgetwc_unlocked(sc->fp)) == WEOF) { sc->ungot_flag |= 2; return -1; } sc->ungot_wflag = 1; sc->ungot_char = wc; sc->ungot_wchar_width = sc->fp->__ungot_width[0]; } else { assert(sc->ungot_flag == 1); sc->ungot_flag = 0; } ++sc->nread; sc->wc = sc->ungot_char; return 0;}#endif /* L_vfwscanf */#endif /* __UCLIBC_HAS_WCHAR__ */static __inline void kill_scan_cookie(register struct scan_cookie *sc){#ifdef L_vfscanf if (sc->ungot_flag & 1) {#if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__) if (!__STDIO_STREAM_IS_FAKE_VSSCANF_NB(sc->fp)) { ungetc(sc->ungot_char, sc->fp); }#else ungetc(sc->ungot_char, sc->fp);#endif /* Deal with distiction between user and scanf ungots. */ if (sc->nread == 0) { /* Only one char was read... app ungot? */ sc->fp->__ungot[1] = sc->app_ungot; /* restore ungot state. */ } else { sc->fp->__ungot[1] = 0; } }#else if ((sc->ungot_flag & 1) && (sc->ungot_wflag & 1) && !__STDIO_STREAM_IS_FAKE_VSWSCANF(sc->fp) && (sc->fp->__state.__mask == 0) ) { ungetwc(sc->ungot_char, sc->fp); /* Deal with distiction between user and scanf ungots. */ if (sc->nread == 0) { /* Only one char was read... app ungot? */ sc->fp->__ungot[1] = sc->app_ungot; /* restore ungot state. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -