📄 scanf.c
字号:
} else { sc->fp->__ungot[1] = 0; } sc->fp->__ungot_width[1] = sc->ungot_wchar_width; }#endif}#ifdef L_vfwscanf#ifdef __UCLIBC_HAS_FLOATS__static const char fake_decpt_str[] = ".";#endif#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__static const char fake_thousands_sep_str[] = ",";#endif#endif /* L_vfwscanf */int VFSCANF (FILE *__restrict fp, const Wchar *__restrict format, va_list arg){ const Wuchar *fmt; unsigned char *b;#ifdef L_vfwscanf wchar_t wbuf[1]; wchar_t *wb;#endif /* L_vfwscanf */#ifdef __UCLIBC_HAS_WCHAR__ mbstate_t mbstate;#endif /* __UCLIBC_HAS_WCHAR__ */ struct scan_cookie sc; psfs_t psfs; int i;#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Fix MAX_DIGITS. We do not do binary, so...!#endif#define MAX_DIGITS 65 /* Allow one leading 0. */ unsigned char buf[MAX_DIGITS+2];#ifdef L_vfscanf unsigned char scanset[UCHAR_MAX + 1]; unsigned char invert; /* Careful! Meaning changes. */#endif /* L_vfscanf */ unsigned char fail; unsigned char zero_conversions = 1; __STDIO_AUTO_THREADLOCK_VAR;#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Make checking of the format string in C locale an option.#endif /* To support old programs, don't check mb validity if in C locale. */#if defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf) /* ANSI/ISO C99 requires format string to be a valid multibyte string * beginning and ending in its initial shift state. */ if (((__UCLIBC_CURLOCALE_DATA).encoding) != __ctype_encoding_7_bit) { const char *p = format; mbstate.__mask = 0; /* Initialize the mbstate. */ if (mbsrtowcs(NULL, &p, SIZE_MAX, &mbstate) == ((size_t)(-1))) { __set_errno(EINVAL); /* Format string is invalid. */ return 0; } }#endif /* defined(__UCLIBC_HAS_LOCALE__) && !defined(L_vfwscanf) */#if defined(NL_ARGMAX) && (NL_ARGMAX > 0) psfs.num_pos_args = -1; /* Must start at -1. */ /* Initialize positional arg ptrs to NULL. */ memset(psfs.pos_args, 0, sizeof(psfs.pos_args));#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */ __STDIO_AUTO_THREADLOCK(fp); __STDIO_STREAM_VALIDATE(fp); __init_scan_cookie(&sc,fp);#ifdef __UCLIBC_HAS_WCHAR__ sc.sc_getc = sc_getc; sc.ungot_wchar_width = sc.fp->__ungot_width[1];#ifdef L_vfwscanf#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ if (*sc.grouping) { sc.thousands_sep = fake_thousands_sep_str; sc.tslen = 1; }#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */#ifdef __UCLIBC_HAS_FLOATS__ sc.fake_decpt = fake_decpt_str;#endif /* __UCLIBC_HAS_FLOATS__ */#else /* L_vfwscanf */#ifdef __UCLIBC_HAS_FLOATS__ sc.fake_decpt = sc.decpt;#endif /* __UCLIBC_HAS_FLOATS__ */#endif /* L_vfwscanf */#endif /* __UCLIBC_HAS_WCHAR__ */ psfs.cnt = 0; /* Note: If we ever wanted to support non-nice codesets, we * would really need to do a mb->wc conversion here in the * vfscanf case. Related changes would have to be made in * the code that follows... basicly wherever fmt appears. */ for (fmt = (const Wuchar *) format ; *fmt ; /* ++fmt */) { psfs.store = 1; psfs.flags = 0;#ifndef NDEBUG psfs.cur_ptr = NULL; /* Debugging aid. */#endif /* NDEBUG */ sc.ungot_flag &= 1; /* Clear (possible fake) EOF. */ sc.width = psfs.max_width = INT_MAX; /* Note: According to the standards, vfscanf does use isspace * here. So, if we did a mb->wc conversion, we would have to do * something like * ((((__uwchar_t)wc) < UCHAR_MAX) && isspace(wc)) * because wc might not be in the allowed domain. */ if (ISSPACE(*fmt)) { do { ++fmt; } while (ISSPACE(*fmt)); --fmt; psfs.conv_num = CONV_whitespace; goto DO_WHITESPACE; } if (*fmt == '%') { /* Conversion specification. */ if (*++fmt == '%') { /* Remember, '%' eats whitespace too. */ /* Note: The standard says no conversion occurs. * So do not reset zero_conversions flag. */ psfs.conv_num = CONV_percent; goto DO_CONVERSION; }#ifdef L_vfscanf psfs.fmt = fmt;#else /* L_vfscanf */ { const __uwchar_t *wf = fmt; psfs.fmt = b = buf; while (*wf && __isascii(*wf) && (b < buf + sizeof(buf) - 1)) { *b++ = *wf++; }#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__#error this is wrong... we need to ched in __psfs_parse_spec instead since this checks last char in buffer and conversion my have stopped before it. if ((*b == 'a') && ((*wf == '[') || ((*wf|0x20) == 's'))) { goto DONE; /* Spec was excessively long. */ }#endif /* __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ */ *b = 0; if (b == buf) { /* Bad conversion specifier! */ goto DONE; } }#endif /* L_vfscanf */ if ((i = __psfs_parse_spec(&psfs)) < 0) { /* Bad conversion specifier! */ goto DONE; } fmt += i; if (psfs.store) {#if defined(NL_ARGMAX) && (NL_ARGMAX > 0) if (psfs.num_pos_args == -2) { psfs.cur_ptr = va_arg(arg, void *); } else { while (psfs.cur_pos_arg > psfs.num_pos_args) { psfs.pos_args[++psfs.num_pos_args] = va_arg(arg, void *); } psfs.cur_ptr = psfs.pos_args[psfs.cur_pos_arg]; }#else /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */ psfs.cur_ptr = va_arg(arg, void *);#endif /* defined(NL_ARGMAX) && (NL_ARGMAX > 0) */ } DO_CONVERSION: /* First, consume white-space if not n, c, [, C, or l[. */ if ((((1L << CONV_n)|(1L << CONV_C)|(1L << CONV_c) |(1L << CONV_LEFTBRACKET)|(1L << CONV_leftbracket)) & (1L << psfs.conv_num)) == 0 ) { DO_WHITESPACE: while ((__scan_getc(&sc) >= 0)#ifdef L_vfscanf && isspace(sc.cc)#else /* L_vfscanf */ && iswspace(sc.wc)#endif /* L_vfscanf */ ) {} __scan_ungetc(&sc); if (psfs.conv_num == CONV_whitespace) { goto NEXT_FMT; } } sc.width = psfs.max_width; /* Now limit the max width. */ if (sc.width == 0) { /* 0 width is forbidden. */ goto DONE; } if (psfs.conv_num == CONV_percent) { goto MATCH_CHAR; } if (psfs.conv_num == CONV_n) {#ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: Should %n count as a conversion as far as EOF return value?#endif/* zero_conversions = 0; */ if (psfs.store) { _store_inttype(psfs.cur_ptr, psfs.dataargtype, (uintmax_t) sc.nread); } goto NEXT_FMT; } if (psfs.conv_num <= CONV_A) { /* pointer, integer, or float spec */ int r = __psfs_do_numeric(&psfs, &sc);#ifndef L_vfscanf if (sc.ungot_wflag == 1) { /* fix up '?', '.', and ',' hacks */ sc.cc = sc.ungot_char = sc.ungot_wchar; }#endif if (r != -1) { /* Either success or a matching failure. */ zero_conversions = 0; } if (r < 0) { goto DONE; } goto NEXT_FMT; } /* Do string conversions here since they are not common code. */#ifdef L_vfscanf if#ifdef __UCLIBC_HAS_WCHAR__ (psfs.conv_num >= CONV_LEFTBRACKET)#else /* __UCLIBC_HAS_WCHAR__ */ (psfs.conv_num >= CONV_c)#endif /* __UCLIBC_HAS_WCHAR__ */ { b = (psfs.store ? ((unsigned char *) psfs.cur_ptr) : buf); fail = 1; if (psfs.conv_num == CONV_c) { if (sc.width == INT_MAX) { sc.width = 1; } while (__scan_getc(&sc) >= 0) { zero_conversions = 0; *b = sc.cc; b += psfs.store; } __scan_ungetc(&sc); if (sc.width > 0) { /* Failed to read all required. */ goto DONE; } psfs.cnt += psfs.store; goto NEXT_FMT; } if (psfs.conv_num == CONV_s) { /* Yes, believe it or not, a %s conversion can store nuls. */ while ((__scan_getc(&sc) >= 0) && !isspace(sc.cc)) { zero_conversions = 0; *b = sc.cc; b += psfs.store; fail = 0; } } else {#ifdef __UCLIBC_HAS_WCHAR__ assert((psfs.conv_num == CONV_LEFTBRACKET) || \ (psfs.conv_num == CONV_leftbracket));#else /* __UCLIBC_HAS_WCHAR__ */ assert((psfs.conv_num == CONV_leftbracket));#endif /* __UCLIBC_HAS_WCHAR__ */ invert = 0; if (*++fmt == '^') { ++fmt; invert = 1; } memset(scanset, invert, sizeof(scanset)); invert = 1-invert; if (*fmt == ']') { scanset[(int)(']')] = invert; ++fmt; } while (*fmt != ']') { if (!*fmt) { /* No closing ']'. */ goto DONE; } if ((*fmt == '-') && (fmt[1] != ']') && (fmt[-1] < fmt[1]) /* sorted? */ ) { /* range */ ++fmt; i = fmt[-2]; /* Note: scanset[i] should already have been done * in the previous iteration. */ do { scanset[++i] = invert; } while (i < *fmt); /* Safe to fall through, and a bit smaller. */ } /* literal char */ scanset[(int) *fmt] = invert; ++fmt; }#ifdef __UCLIBC_HAS_WCHAR__ if (psfs.conv_num == CONV_LEFTBRACKET) { goto DO_LEFTBRACKET; }#endif /* __UCLIBC_HAS_WCHAR__ */ while (__scan_getc(&sc) >= 0) { zero_conversions = 0; if (!scanset[sc.cc]) { break; } *b = sc.cc; b += psfs.store; fail = 0; } } /* Common tail for processing of %s and %[. */ __scan_ungetc(&sc); if (fail) { /* nothing stored! */ goto DONE; } *b = 0; /* Nul-terminate string. */ psfs.cnt += psfs.store; goto NEXT_FMT; }#ifdef __UCLIBC_HAS_WCHAR__ DO_LEFTBRACKET: /* Need to do common wide init. */ if (psfs.conv_num >= CONV_C) { wchar_t wbuf[1]; wchar_t *wb; sc.mbstate.__mask = 0; wb = (psfs.store ? ((wchar_t *) psfs.cur_ptr) : wbuf); fail = 1; if (psfs.conv_num == CONV_C) { if (sc.width == INT_MAX) { sc.width = 1; } while (scan_getwc(&sc) >= 0) { zero_conversions = 0; assert(sc.width >= 0); *wb = sc.wc; wb += psfs.store; } __scan_ungetc(&sc); if (sc.width > 0) { /* Failed to read all required. */ goto DONE; } psfs.cnt += psfs.store; goto NEXT_FMT; } if (psfs.conv_num == CONV_S) { /* Yes, believe it or not, a %s conversion can store nuls. */ while (scan_getwc(&sc) >= 0) { zero_conversions = 0; if ((((__uwchar_t)(sc.wc)) <= UCHAR_MAX) && isspace(sc.wc)) { break; } *wb = sc.wc; wb += psfs.store; fail = 0; } } else { assert(psfs.conv_num == CONV_LEFTBRACKET); while (scan_getwc(&sc) >= 0) { zero_conversions = 0; if (((__uwchar_t) sc.wc) <= UCHAR_MAX) { if (!scanset[sc.wc]) { break; } } else if (invert) { break; } *wb = sc.wc; wb += psfs.store; fail = 0; } } /* Common tail for processing of %ls and %l[. */ __scan_ungetc(&sc); if (fail || sc.mb_fail) { /* Nothing stored or mb error. */ goto DONE; } *wb = 0; /* Nul-terminate string. */ psfs.cnt += psfs.store; goto NEXT_FMT; }#endif /* __UCLIBC_HAS_WCHAR__ */#else /* L_vfscanf */ if (psfs.conv_num >= CONV_C) { b = buf; wb = wbuf; if (psfs.conv_num >= CONV_c) { mbstate.__mask = 0; /* Initialize the mbstate. */ if (psfs.store) { b = (unsigned char *) psfs.cur_ptr; } } else { if (psfs.store) { wb = (wchar_t *) psfs.cur_ptr; } } fail = 1; if ((psfs.conv_num == CONV_C) || (psfs.conv_num == CONV_c)) { if (sc.width == INT_MAX) { sc.width = 1; } while (scan_getwc(&sc) >= 0) { zero_conversions = 0; if (psfs.conv_num == CONV_C) { *wb = sc.wc; wb += psfs.store; } else { i = wcrtomb(b, sc.wc, &mbstate); if (i < 0) { /* Conversion failure. */ goto DONE_DO_UNGET; } if (psfs.store) { b += i; } } } __scan_ungetc(&sc); if (sc.width > 0) { /* Failed to read all required. */ goto DONE; } psfs.cnt += psfs.store; goto NEXT_FMT; } if ((psfs.conv_num == CONV_S) || (psfs.conv_num == CONV_s)) { /* Yes, believe it or not, a %s conversion can store nuls. */ while (scan_getwc(&sc) >= 0) { zero_conversions = 0; if (iswspace(sc.wc)) { break; } if (psfs.conv_num == CONV_S) { *wb = sc.wc; wb += psfs.store; } else { i = wcrtomb(b, sc.wc, &mbstate); if (i < 0) { /* Conversion failure. */ goto DONE_DO_UNGET; } if (psfs.store) { b += i; } } fail = 0; } } else { const wchar_t *sss; const wchar_t *ssp; unsigned char invert = 0; assert((psfs.conv_num == CONV_LEFTBRACKET) || (psfs.conv_num == CONV_leftbracket)); if (*++fmt == '^') { ++fmt; invert = 1; } sss = (const wchar_t *) fmt; if (*fmt == ']') { ++fmt; } while (*fmt != ']') { if (!*fmt) { /* No closing ']'. */ goto DONE; } if ((*fmt == '-') && (fmt[1] != ']') && (fmt[-1] < fmt[1]) /* sorted? */ ) { /* range */ ++fmt; } ++fmt; } /* Ok... a valid scanset spec. */ while (scan_getwc(&sc) >= 0) { zero_conversions = 0; ssp = sss; do { /* We know sss < fmt. */ if (*ssp == '-') { /* possible range... */ /* Note: We accept a-c-e (ordered) as * equivalent to a-e. */ if (ssp > sss) { if ((++ssp < (const wchar_t *) fmt) && (ssp[-2] < *ssp) /* sorted? */ ) { /* yes */ if ((sc.wc >= ssp[-2]) && (sc.wc <= *ssp)) { break; } continue; /* not in range */ } --ssp; /* oops... '-' at end, so back up */ } /* false alarm... a literal '-' */ } if (sc.wc == *ssp) { /* Matched literal char. */ break; } } while (++ssp < (const wchar_t *) fmt); if ((ssp == (const wchar_t *) fmt) ^ invert) { /* no match and not inverting
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -