📄 vfscanf.c
字号:
} break; case L_('c'): /* Match characters. */ if ((flags & LONG) == 0) { if (!(flags & SUPPRESS)) { str = ARG (char *); if (str == NULL) conv_error (); } c = inchar (); if (c == EOF) input_error (); if (width == -1) width = 1;#ifdef COMPILE_WSCANF /* We have to convert the wide character(s) into multibyte characters and store the result. */ memset (&state, '\0', sizeof (state)); do { size_t n; n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state); if (n == (size_t) -1) /* No valid wide character. */ input_error (); /* Increment the output pointer. Even if we don't write anything. */ str += n; } while (--width > 0 && inchar () != EOF);#else if (!(flags & SUPPRESS)) { do *str++ = c; while (--width > 0 && inchar () != EOF); } else while (--width > 0 && inchar () != EOF);#endif if (!(flags & SUPPRESS)) ++done; break; } /* FALLTHROUGH */ case L_('C'): if (!(flags & SUPPRESS)) { wstr = ARG (wchar_t *); if (wstr == NULL) conv_error (); } c = inchar (); if (c == EOF) input_error ();#ifdef COMPILE_WSCANF /* Just store the incoming wide characters. */ if (!(flags & SUPPRESS)) { do *wstr++ = c; while (--width > 0 && inchar () != EOF); } else while (--width > 0 && inchar () != EOF);#else { /* We have to convert the multibyte input sequence to wide characters. */ char buf[1]; mbstate_t cstate; memset (&cstate, '\0', sizeof (cstate)); do { /* This is what we present the mbrtowc function first. */ buf[0] = c; while (1) { size_t n; n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL, buf, 1, &cstate); if (n == (size_t) -2) { /* Possibly correct character, just not enough input. */ if (inchar () == EOF) encode_error (); buf[0] = c; continue; } if (n != 1) encode_error (); /* We have a match. */ break; } /* Advance the result pointer. */ ++wstr; } while (--width > 0 && inchar () != EOF); }#endif if (!(flags & SUPPRESS)) ++done; break; case L_('s'): /* Read a string. */ if (!(flags & LONG)) {#define STRING_ARG(Str, Type) \ do if (!(flags & SUPPRESS)) \ { \ if (flags & MALLOC) \ { \ /* The string is to be stored in a malloc'd buffer. */ \ strptr = ARG (char **); \ if (strptr == NULL) \ conv_error (); \ /* Allocate an initial buffer. */ \ strsize = 100; \ *strptr = (char *) malloc (strsize * sizeof (Type)); \ Str = (Type *) *strptr; \ } \ else \ Str = ARG (Type *); \ if (Str == NULL) \ conv_error (); \ } while (0) STRING_ARG (str, char); c = inchar (); if (c == EOF) input_error ();#ifdef COMPILE_WSCANF memset (&state, '\0', sizeof (state));#endif do { if (ISSPACE (c)) { ungetc_not_eof (c, s); break; }#ifdef COMPILE_WSCANF /* This is quite complicated. We have to convert the wide characters into multibyte characters and then store them. */ { size_t n; if (!(flags & SUPPRESS) && (flags & MALLOC) && str + MB_CUR_MAX >= *strptr + strsize) { /* We have to enlarge the buffer if the `a' flag was given. */ size_t strleng = str - *strptr; char *newstr; newstr = (char *) realloc (*strptr, strsize * 2); if (newstr == NULL) { /* Can't allocate that much. Last-ditch effort. */ newstr = (char *) realloc (*strptr, strleng + MB_CUR_MAX); if (newstr == NULL) { /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strleng] = '\0'; ++done; conv_error (); } else { *strptr = newstr; str = newstr + strleng; strsize = strleng + MB_CUR_MAX; } } else { *strptr = newstr; str = newstr + strleng; strsize *= 2; } } n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state); if (n == (size_t) -1) encode_error (); assert (n <= MB_CUR_MAX); str += n; }#else /* This is easy. */ if (!(flags & SUPPRESS)) { *str++ = c; if ((flags & MALLOC) && (char *) str == *strptr + strsize) { /* Enlarge the buffer. */ str = (char *) realloc (*strptr, 2 * strsize); if (str == NULL) { /* Can't allocate that much. Last-ditch effort. */ str = (char *) realloc (*strptr, strsize + 1); if (str == NULL) { /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strsize - 1] = '\0'; ++done; conv_error (); } else { *strptr = (char *) str; str += strsize; ++strsize; } } else { *strptr = (char *) str; str += strsize; strsize *= 2; } } }#endif } while ((width <= 0 || --width > 0) && inchar () != EOF); if (!(flags & SUPPRESS)) {#ifdef COMPILE_WSCANF /* We have to emit the code to get into the initial state. */ char buf[MB_LEN_MAX]; size_t n = __wcrtomb (buf, L'\0', &state); if (n > 0 && (flags & MALLOC) && str + n >= *strptr + strsize) { /* Enlarge the buffer. */ size_t strleng = str - *strptr; char *newstr; newstr = (char *) realloc (*strptr, strleng + n + 1); if (newstr == NULL) { /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((char *) (*strptr))[strleng] = '\0'; ++done; conv_error (); } else { *strptr = newstr; str = newstr + strleng; strsize = strleng + n + 1; } } str = __mempcpy (str, buf, n);#endif *str++ = '\0'; if ((flags & MALLOC) && str - *strptr != strsize) { char *cp = (char *) realloc (*strptr, str - *strptr); if (cp != NULL) *strptr = cp; } ++done; } break; } /* FALLTHROUGH */ case L_('S'): {#ifndef COMPILE_WSCANF mbstate_t cstate;#endif /* Wide character string. */ STRING_ARG (wstr, wchar_t); c = inchar (); if (c == EOF) input_error ();#ifndef COMPILE_WSCANF memset (&cstate, '\0', sizeof (cstate));#endif do { if (ISSPACE (c)) { ungetc_not_eof (c, s); break; }#ifdef COMPILE_WSCANF /* This is easy. */ if (!(flags & SUPPRESS)) { *wstr++ = c; if ((flags & MALLOC) && wstr == (wchar_t *) *strptr + strsize) { /* Enlarge the buffer. */ wstr = (wchar_t *) realloc (*strptr, (2 * strsize) * sizeof (wchar_t)); if (wstr == NULL) { /* Can't allocate that much. Last-ditch effort. */ wstr = (wchar_t *) realloc (*strptr, (strsize + 1) * sizeof (wchar_t)); if (wstr == NULL) { /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((wchar_t *) (*strptr))[strsize - 1] = L'\0'; ++done; conv_error (); } else { *strptr = (char *) wstr; wstr += strsize; ++strsize; } } else { *strptr = (char *) wstr; wstr += strsize; strsize *= 2; } } }#else { char buf[1]; buf[0] = c; while (1) { size_t n; n = __mbrtowc (!(flags & SUPPRESS) ? wstr : NULL, buf, 1, &cstate); if (n == (size_t) -2) { /* Possibly correct character, just not enough input. */ if (inchar () == EOF) encode_error (); buf[0] = c; continue; } if (n != 1) encode_error (); /* We have a match. */ ++wstr; break; } if (!(flags & SUPPRESS) && (flags & MALLOC) && wstr == (wchar_t *) *strptr + strsize) { /* Enlarge the buffer. */ wstr = (wchar_t *) realloc (*strptr, (2 * strsize * sizeof (wchar_t))); if (wstr == NULL) { /* Can't allocate that much. Last-ditch effort. */ wstr = (wchar_t *) realloc (*strptr, ((strsize + 1) * sizeof (wchar_t))); if (wstr == NULL) { /* We lose. Oh well. Terminate the string and stop converting, so at least we don't skip any input. */ ((wchar_t *) (*strptr))[strsize - 1] = L'\0'; ++done; conv_error (); } else { *strptr = (char *) wstr; wstr += strsize; ++strsize; } } else { *strptr = (char *) wstr; wstr += strsize; strsize *= 2; } } }#endif } while ((width <= 0 || --width > 0) && inchar () != EOF); if (!(flags & SUPPRESS)) { *wstr++ = L'\0'; if ((flags & MALLOC) && wstr - (wchar_t *) *strptr != strsize) { wchar_t *cp = (wchar_t *) realloc (*strptr, ((wstr - (wchar_t *) *strptr) * sizeof(wchar_t))); if (cp != NULL) *strptr = (char *) cp; } ++done; } } break; case L_('x'): /* Hexadecimal integer. */ case L_('X'): /* Ditto. */ base = 16; number_signed = 0; goto number; case L_('o'): /* Octal integer. */ base = 8; number_signed = 0; goto number; case L_('u'): /* Unsigned decimal integer. */ base = 10; number_signed = 0; goto number; case L_('d'): /* Signed decimal integer. */ base = 10; number_signed = 1; goto number; case L_('i'): /* Generic number. */ base = 0; number_signed = 1; number: c = inchar (); if (c == EOF) input_error (); /* Check for a sign. */ if (c == L_('-') || c == L_('+')) { ADDW (c); if (width > 0) --width; c = inchar (); } /* Look for a leading indication of base. */ if (width != 0 && c == L_('0')) { if (width > 0) --width; ADDW (c); c = inchar (); if (width != 0 && TOLOWER (c) == L_('x')) { if (base == 0) base = 16; if (base == 16) { if (width > 0) --width; c = inchar (); } } else if (base == 0) base = 8; } if (base == 0) base = 10; if (base == 10 && (flags & I18N) != 0) { int from_level; int to_level; int level;#ifdef COMPILE_WSCANF const wchar_t *wcdigits[10]; const wchar_t *wcdigits_extended[10];#else const char *mbdigits[10]; const char *mbdigits_extended[10];#endif /* "to_inpunct" is a map from ASCII digits to their equivalent in locale. This is defined for locales which use an extra digits set. */ wctrans_t map = __wctrans ("to_inpunct"); int n; from_level = 0;#ifdef COMPILE_WSCANF to_level = _NL_CURRENT_WORD (LC_CTYPE, _NL_CTYPE_INDIGITS_WC_LEN) - 1;#else to_level = (uint32_t) curctype->values[_NL_ITEM_INDEX (_NL_CTYPE_INDIGITS_MB_LEN)].word - 1;#endif /* Get the alternative digit forms if there are any. */ if (__builtin_expect (map != NULL, 0)) { /* Adding new level for extra digits set in locale file. */ ++to_level; for (n = 0; n < 10; ++n) {#ifdef COMPILE_WSCANF wcdigits[n] = (const wchar_t *) _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n); wchar_t *wc_extended = (wchar_t *) alloca ((to_level + 2) * sizeof (wchar_t)); __wmemcpy (wc_extended, wcdigits[n], to_level); wc_extended[to_level] = __towctrans (L'0' + n, map); wc_extended[to_level + 1] = '\0'; wcdigits_extended[n] = wc_extended;#else mbdigits[n] = curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string; /* Get the equivalent wide char in map. */ wint_t extra_wcdigit = __towctrans (L'0' + n, map); /* Convert it to multibyte representation. */ mbstate_t state; memset (&state, '\0', sizeof (state)); char extra_mbdigit[MB_LEN_MAX]; size_t mblen = __wcrtomb (extra_mbdigit, extra_wcdigit, &state); if (mblen == (size_t) -1) { /* Ignore this new level. */ map = NULL; break; } /* Calculate the length of mbdigits[n]. */ const char *last_char = mbdigits[n]; for (level = 0; level < to_level; ++level) last_char = strchr (last_char, '\0') + 1; size_t mbdigits_len = last_char - mbdigits[n]; /* Allocate memory for extended multibyte digit. */ char *mb_extended; mb_extended = (char *) alloca (mbdigits_len + mblen + 1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -