📄 scanf.c
字号:
* or match and inverting */ break; } if (psfs.conv_num == CONV_LEFTBRACKET) { *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; } } /* Common tail for processing of %s and %[. */ __scan_ungetc(&sc); if (fail) { /* nothing stored! */ goto DONE; } *wb = 0; /* Nul-terminate string. */ *b = 0; psfs.cnt += psfs.store; goto NEXT_FMT; }#endif /* L_vfscanf */ assert(0); goto DONE; } /* conversion specification */ MATCH_CHAR: if (__scan_getc(&sc) != *fmt) {#ifdef L_vfwscanf DONE_DO_UNGET:#endif /* L_vfwscanf */ __scan_ungetc(&sc); goto DONE; } NEXT_FMT: ++fmt; if (__FERROR_UNLOCKED(fp)) { break; } } DONE: if (__FERROR_UNLOCKED(fp) || (*fmt && zero_conversions && __FEOF_UNLOCKED(fp))) { psfs.cnt = EOF; /* Yes, vfwscanf also returns EOF. */ } kill_scan_cookie(&sc); __STDIO_STREAM_VALIDATE(fp); __STDIO_AUTO_THREADUNLOCK(fp); return psfs.cnt;}#endif/**********************************************************************/#ifdef L___psfs_do_numericstatic const unsigned char spec_base[] = SPEC_BASE;static const unsigned char nil_string[] = "(nil)";int __psfs_do_numeric(psfs_t *psfs, struct scan_cookie *sc){ unsigned char *b; const unsigned char *p;#ifdef __UCLIBC_HAS_FLOATS__ int exp_adjust = 0;#endif#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Fix MAX_DIGITS. We do not do binary, so...!#warning TODO: Fix buf!#endif#define MAX_DIGITS 65 /* Allow one leading 0. */ unsigned char buf[MAX_DIGITS+2+ 100]; unsigned char usflag, base; unsigned char nonzero = 0; unsigned char seendigit = 0; #ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: What should be returned for an invalid conversion specifier?#endif#ifndef __UCLIBC_HAS_FLOATS__ if (psfs->conv_num > CONV_i) { /* floating point */ goto DONE; }#endif base = spec_base[psfs->conv_num - CONV_p]; usflag = (psfs->conv_num <= CONV_u); /* (1)0 if (un)signed */ b = buf; if (psfs->conv_num == CONV_p) { /* Pointer */ p = nil_string; do { if ((__scan_getc(sc) < 0) || (*p != sc->cc)) { __scan_ungetc(sc); if (p > nil_string) { /* We matched at least the '(' so even if we * are at eof, we can not match a pointer. */ return -2; /* Matching failure */ } break; } if (!*++p) { /* Matched (nil), so no unget necessary. */ if (psfs->store) { ++psfs->cnt; _store_inttype(psfs->cur_ptr, psfs->dataargtype, (uintmax_t) NULL); } return 0; } } while (1);#ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: Should we require a 0x prefix and disallow +/- for pointer %p?#endif /* __UCLIBC_MJN3_ONLY__ */ } __scan_getc(sc); if (sc->cc < 0) { return -1; /* Input failure (nothing read yet). */ } if ((sc->cc == '+') || (sc->cc == '-')) { /* Handle leading sign.*/ *b++ = sc->cc; __scan_getc(sc); } if ((base & 0xef) == 0) { /* 0xef is ~16, so 16 or 0. */ if (sc->cc == '0') { /* Possibly set base and handle prefix. */ __scan_getc(sc); if ((sc->cc|0x20) == 'x') { /* Assumes ascii.. x or X. */ if (__scan_getc(sc) < 0) { /* Either EOF or error (including wc outside char range). * If EOF or error, this is a matching failure (we read 0x). * If wc outside char range, this is also a matching failure. * Hence, we do an unget (although not really necessary here * and fail. */ goto DONE_DO_UNGET; /* matching failure */ } base = 16; /* Base 16 for sure now. */#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ /* The prefix is required for hexadecimal floats. */ *b++ = '0'; *b++ = 'x';#endif /* __UCLIBC_HAS_HEXADECIMAL_FLOATS__ */ } else { /* oops... back up */ __scan_ungetc(sc); sc->cc = '0'; /* NASTY HACK! */ base = (base >> 1) + 8; /* 0->8, 16->16. no 'if' */#ifdef __UCLIBC_HAS_FLOATS__ if (psfs->conv_num > CONV_i) { /* floating point */ base = 10; }#endif } } else if (!base) { base = 10; } } /***************** digit grouping **********************/#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ if ((psfs->flags & FLAG_THOUSANDS) && (base == 10) && *(p = sc->grouping) ) { int nblk1, nblk2, nbmax, lastblock, pass, i;#ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: Should we initalize the grouping blocks in __init_scan_cookie()?#endif /* __UCLIBC_MJN3_ONLY__ */ nbmax = nblk2 = nblk1 = *p; if (*++p) { nblk2 = *p; if (nbmax < nblk2) { nbmax = nblk2; } assert(!p[1]); } /* Note: for printf, if 0 and \' flags appear then * grouping is done before 0-padding. Should we * strip leading 0's first? Or add a 0 flag? */ /* For vfwscanf, sc_getc translates, so the value of sc->cc is * either EOF or a char. */ if (!__isdigit_char_or_EOF(sc->cc)) { /* No starting digit! */#ifdef __UCLIBC_HAS_FLOATS__ if (psfs->conv_num > CONV_i) { /* floating point */ goto NO_STARTING_DIGIT; }#endif goto DONE_DO_UNGET; } if (sc->cc == '0') { seendigit = 1; *b++ = '0'; /* Store the first 0. */#ifdef __UCLIBC_MJN3_ONLY__#warning CONSIDER: Should leading 0s be skipped before digit grouping? (printf 0 pad)#endif /* __UCLIBC_MJN3_ONLY__ */#if 0 do { /* But ignore all subsequent 0s. */ __scan_getc(sc); } while (sc->cc == '0');#endif } pass = 0; lastblock = 0; do { i = 0; while (__isdigit_char_or_EOF(sc->cc)) { seendigit = 1; if (i == nbmax) { /* too many digits for a block */#ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ if (!pass) { /* treat as nongrouped */ if (nonzero) { goto DO_NO_GROUP; } goto DO_TRIM_LEADING_ZEROS; }#endif if (nbmax > nblk1) { goto DONE_DO_UNGET; /* matching failure */ } goto DONE_GROUPING_DO_UNGET; /* nbmax == nblk1 */ } ++i; if (nonzero || (sc->cc != '0')) { if (b < buf + MAX_DIGITS) { *b++ = sc->cc; nonzero = 1;#ifdef __UCLIBC_HAS_FLOATS__ } else { ++exp_adjust;#endif } } __scan_getc(sc); } if (i) { /* we saw digits digits */ if ((i == nblk2) || ((i < nblk2) && !pass)) { /* (possible) outer grp */ p = sc->thousands_sep; if (*p == sc->cc) { /* first byte matches... */ /* so check if grouping mb char */ /* Since 1st matched, either match or fail now * unless EOF (yuk) */ __scan_getc(sc); MBG_LOOP: if (!*++p) { /* is a grouping mb char */ lastblock = i; ++pass; continue; } if (*p == sc->cc) { __scan_getc(sc); goto MBG_LOOP; } /* bad grouping mb char! */ __scan_ungetc(sc); if ((sc->cc >= 0) || (p > sc->thousands_sep + 1)) {#ifdef __UCLIBC_HAS_FLOATS__ /* We failed to match a thousep mb char, and * we've read too much to recover. But if * this is a floating point conversion and * the initial portion of the decpt mb char * matches, then we may still be able to * recover. */ int k = p - sc->thousands_sep - 1; if ((psfs->conv_num > CONV_i) /* float conversion */ && (!pass || (i == nblk1)) /* possible last */ && !memcmp(sc->thousands_sep, sc->fake_decpt, k) /* and prefix matched, so could be decpt */ ) { __scan_getc(sc); p = sc->fake_decpt + k; do { if (!*++p) { strcpy(b, sc->decpt); b += sc->decpt_len; goto GOT_DECPT; } if (*p != sc->cc) { __scan_ungetc(sc); break; /* failed */ } __scan_getc(sc); } while (1); }#endif /* __UCLIBC_HAS_FLOATS__ */ goto DONE; } /* was EOF and 1st, so recoverable. */ } } if ((i == nblk1) || ((i < nblk1) && !pass)) { /* got an inner group */ goto DONE_GROUPING_DO_UNGET; } goto DONE_DO_UNGET; /* Matching failure. */ } /* i != 0 */ assert(pass); goto DONE_DO_UNGET; } while (1); assert(0); /* Should never get here. */ }#endif /***************** digit grouping **********************/ /* Not grouping so first trim all but one leading 0. */#ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ DO_TRIM_LEADING_ZEROS:#endif /* __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ */ if (sc->cc == '0') { seendigit = 1; *b++ = '0'; /* Store the first 0. */ do { /* But ignore all subsequent 0s. */ __scan_getc(sc); } while (sc->cc == '0'); }#ifdef __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ DO_NO_GROUP:#endif /* __UCLIBC_HAS_SCANF_LENIENT_DIGIT_GROUPING__ */ /* At this point, we're ready to start reading digits. */#define valid_digit(cc,base) (isxdigit(cc) && ((base == 16) || (cc - '0' < base))) while (valid_digit(sc->cc,base)) { /* Now for significant digits.*/ if (b - buf < MAX_DIGITS) { nonzero = seendigit = 1; /* Set nonzero too 0s trimmed above. */ *b++ = sc->cc;#ifdef __UCLIBC_HAS_FLOATS__ } else { ++exp_adjust;#endif } __scan_getc(sc); }#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ DONE_GROUPING_DO_UNGET:#endif /* __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ */ if (psfs->conv_num <= CONV_i) { /* integer conversion */ __scan_ungetc(sc); *b = 0; /* null-terminate */ if (!seendigit) { goto DONE; /* No digits! */ } if (psfs->store) { if (*buf == '-') { usflag = 0; } ++psfs->cnt; _store_inttype(psfs->cur_ptr, psfs->dataargtype, (uintmax_t) STRTOUIM(buf, NULL, base, 1-usflag)); } return 0; }#ifdef __UCLIBC_HAS_FLOATS__ /* At this point, we have everything left of the decimal point or exponent. */#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ NO_STARTING_DIGIT:#endif p = sc->fake_decpt; do { if (!*p) { strcpy(b, sc->decpt); b += sc->decpt_len; break; } if (*p != sc->cc) { if (p > sc->fake_decpt) { goto DONE_DO_UNGET; /* matching failure (read some of decpt) */ } goto DO_DIGIT_CHECK; } ++p; __scan_getc(sc); } while (1);#ifdef __UCLIBC_HAS_GLIBC_DIGIT_GROUPING__ GOT_DECPT:#endif if (!nonzero) { if (sc->cc == '0') { assert(exp_adjust == 0); *b++ = '0'; ++exp_adjust; seendigit = 1; do { --exp_adjust; __scan_getc(sc); } while (sc->cc == '0'); } } while (valid_digit(sc->cc,base)) { /* Process fractional digits.*/ if (b - buf < MAX_DIGITS) { seendigit = 1; *b++ = sc->cc; } __scan_getc(sc); } DO_DIGIT_CHECK: /* Hmm... no decimal point. */ if (!seendigit) { static const unsigned char nan_inf_str[] = "an\0nfinity"; if (base == 16) { /* We had a prefix, but no digits! */ goto DONE_DO_UNGET; /* matching failure */ } /* Avoid tolower problems for INFINITY in the tr_TR locale. (yuk)*/#undef TOLOWER#define TOLOWER(C) ((C)|0x20) switch (TOLOWER(sc->cc)) { case 'i': p = nan_inf_str + 3; break; case 'n': p = nan_inf_str; break; default: /* No digits and not inf or nan. */ goto DONE_DO_UNGET; } *b++ = sc->cc; do { __scan_getc(sc); if (TOLOWER(sc->cc) == *p) { *b++ = sc->cc; ++p; continue; } if (!*p || (p == nan_inf_str + 5)) { /* match nan/infinity or inf */ goto GOT_FLOAT; } /* Unrecoverable. Even if on 1st char, we had no digits. */ goto DONE_DO_UNGET; } while (1); } /* If we get here, we had some digits. */ if (#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__ ((base == 16) && (((sc->cc)|0x20) == 'p')) ||#endif (((sc->cc)|0x20) == 'e') ) { /* Process an exponent. */ *b++ = sc->cc; __scan_getc(sc); if (sc->cc < 0) { goto DONE_DO_UNGET; /* matching failure.. no exponent digits */ } if ((sc->cc == '+') || (sc->cc == '-')) { /* Signed exponent? */ *b++ = sc->cc; __scan_getc(sc); }#ifdef __UCLIBC_MJN3_ONLY__#warning TODO: Fix MAX_EXP_DIGITS!#endif#define MAX_EXP_DIGITS 20 assert(seendigit); seendigit = 0; nonzero = 0; if (sc->cc == '0') { seendigit = 1; *b++ = '0'; do { __scan_getc(sc); } while (sc->cc == '0'); } while (__isdigit_char_or_EOF(sc->cc)) { /* Exponent digits (base 10).*/ if (seendigit < MAX_EXP_DIGITS) { ++seendigit; *b++ = sc->cc; } __scan_getc(sc); } if (!seendigit) { /* No digits. Unrecoverable. */ goto DONE_DO_UNGET; } } GOT_FLOAT: *b = 0; { __fpmax_t x; char *e; x = __strtofpmax(buf, &e, exp_adjust); assert(!*e); if (psfs->store) { if (psfs->dataargtype & PA_FLAG_LONG_LONG) { *((long double *)psfs->cur_ptr) = (long double) x; } else if (psfs->dataargtype & PA_FLAG_LONG) { *((double *)psfs->cur_ptr) = (double) x; } else { *((float *)psfs->cur_ptr) = (float) x; } ++psfs->cnt; } __scan_ungetc(sc); return 0; }#endif /* __UCLIBC_HAS_FLOATS__ */ DONE_DO_UNGET: __scan_ungetc(sc); DONE: return -2; /* Matching failure. */}#endif/**********************************************************************/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -