📄 scanf.c
字号:
/* Copyright (C) 2002-2004 Manuel Novoa III * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *//* Aug 1, 2003 * New *scanf implementation with lots of bug fixes and *wscanf support. * Also now optionally supports hexadecimal float notation, positional * args, and glibc locale-specific digit grouping. Should now be * standards compliant. * * Aug 18, 2003 * Bug fix: scanf %lc,%ls,%l[ would always set mb_fail on eof or error, * even when just starting a new mb char. * Bug fix: wscanf would incorrectly unget in certain situations. * * Sep 5, 2003 * Bug fix: store flag wasn't respected if no positional args. * Implement vs{n}scanf for the non-buffered stdio no-wchar case. * * Sep 13, 2003 * Bug fix: Fix a problem reported by Atsushi Nemoto <anemo@mba.ocn.ne.jp> * for environments where long and long long are the same. * * Sep 21, 2003 * Ugh... EOF handling by scanf was completely broken. :-( Regretably, * I got my mind fixed in one mode and didn't comply with the standards. * Things should be fixed now, but comparision testing is difficult when * glibc's scanf is broken and they stubbornly refuse to even acknowledge * that it is... even when confronted by specific examples from the C99 * standards and from an official C standard defect report. */#define _ISOC99_SOURCE /* for LLONG_MAX primarily... */#define _GNU_SOURCE#define _STDIO_UTILITY#include <features.h>#include "_stdio.h"#include <stdlib.h>#include <unistd.h>#include <ctype.h>#include <string.h>#include <stdarg.h>#include <stdint.h>#include <errno.h>#include <printf.h>#ifdef __UCLIBC_HAS_WCHAR__#include <bits/uClibc_uwchar.h>#include <wchar.h>#include <wctype.h>#endif /* __UCLIBC_HAS_WCHAR__ */#include <langinfo.h>#include <locale.h>#include <assert.h>#include <limits.h>#ifdef __UCLIBC_HAS_THREADS__#include <stdio_ext.h>#include <pthread.h>#endif /* __UCLIBC_HAS_THREADS__ */#ifdef __UCLIBC_HAS_FLOATS__#include <float.h>#include <bits/uClibc_fpmax.h>#endif /* __UCLIBC_HAS_FLOATS__ */#ifdef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__#ifdef L_vfscanf/* only emit this once */#warning Forcing undef of __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__ until implemented!#endif#undef __UCLIBC_HAS_SCANF_GLIBC_A_FLAG__#endif#undef __STDIO_HAS_VSSCANF#if defined(__STDIO_BUFFERS) || !defined(__UCLIBC_HAS_WCHAR__) || defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)#define __STDIO_HAS_VSSCANF 1#if !defined(__STDIO_BUFFERS) && !defined(__UCLIBC_HAS_WCHAR__)typedef struct { FILE f; unsigned char *bufread; /* pointer to 1 past end of buffer */ unsigned char *bufpos;} __FILE_vsscanf;#endif#endifextern void _store_inttype(void *dest, int desttype, uintmax_t val);#if defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX)extern unsigned long long_stdlib_strto_ll(register const char * __restrict str, char ** __restrict endptr, int base, int sflag);#if (ULLONG_MAX == UINTMAX_MAX)#define STRTOUIM(s,e,b,sf) _stdlib_strto_ll(s,e,b,sf)#endif#else /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */extern unsigned long_stdlib_strto_l(register const char * __restrict str, char ** __restrict endptr, int base, int sflag);#if (ULONG_MAX == UINTMAX_MAX)#define STRTOUIM(s,e,b,sf) _stdlib_strto_l(s,e,b,sf)#endif#endif /* defined(ULLONG_MAX) && (LLONG_MAX > LONG_MAX) */#ifndef STRTOUIM#error STRTOUIM conversion function is undefined!#endif/**********************************************************************//* The standards require EOF < 0. */#if EOF >= CHAR_MIN#define __isdigit_char_or_EOF(C) __isdigit_char((C))#else#define __isdigit_char_or_EOF(C) __isdigit_int((C))#endif/**********************************************************************/#ifdef L_fscanfint fscanf(FILE * __restrict stream, const char * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = vfscanf(stream, format, arg); va_end(arg); return rv;}#endif/**********************************************************************/#ifdef L_scanfint scanf(const char * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = vfscanf(stdin, format, arg); va_end(arg); return rv;}#endif/**********************************************************************/#ifdef L_sscanf#ifdef __STDIO_HAS_VSSCANFint sscanf(const char * __restrict str, const char * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = vsscanf(str, format, arg); va_end(arg); return rv;}#else /* __STDIO_HAS_VSSCANF */#warning Skipping sscanf since no vsscanf!#endif /* __STDIO_HAS_VSSCANF */#endif/**********************************************************************/#ifdef L_vscanfint vscanf(const char * __restrict format, va_list arg){ return vfscanf(stdin, format, arg);}#endif/**********************************************************************/#ifdef L_vsscanf#ifdef __UCLIBC_MJN3_ONLY__#warning WISHLIST: Implement vsscanf for non-buf and no custom stream case.#endif /* __UCLIBC_MJN3_ONLY__ */#ifdef __STDIO_BUFFERSint vsscanf(__const char *sp, __const char *fmt, va_list ap){ FILE f;/* __STDIO_STREAM_RESET_GCS(&f); */#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ f.__cookie = &(f.__filedes); f.__gcs.read = NULL; f.__gcs.write = NULL; f.__gcs.seek = NULL; f.__gcs.close = NULL;#endif f.__filedes = __STDIO_STREAM_FAKE_VSSCANF_FILEDES; f.__modeflags = (__FLAG_NARROW|__FLAG_READONLY|__FLAG_READING);#ifdef __UCLIBC_HAS_WCHAR__ f.__ungot_width[0] = 0;#endif#ifdef __STDIO_MBSTATE __INIT_MBSTATE(&(f.__state));#endif#ifdef __UCLIBC_HAS_THREADS__ f.__user_locking = 1; /* Set user locking. */ __stdio_init_mutex(&f.__lock);#endif f.__nextopen = NULL; /* Set these last since __bufgetc initialization depends on * __user_locking and only gets set if user locking is on. */ f.__bufstart = f.__bufpos = (unsigned char *) ((void *) sp); f.__bufread = f.__bufend = f.__bufstart + strlen(sp); __STDIO_STREAM_ENABLE_GETC(&f); __STDIO_STREAM_DISABLE_PUTC(&f); return vfscanf(&f, fmt, ap);}#elif !defined(__UCLIBC_HAS_WCHAR__)int vsscanf(__const char *sp, __const char *fmt, va_list ap){ __FILE_vsscanf f; f.bufpos = (unsigned char *) ((void *) sp); f.bufread = f.bufpos + strlen(sp);/* __STDIO_STREAM_RESET_GCS(&f.f); */#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ f.f.__cookie = &(f.f.__filedes); f.f.__gcs.read = NULL; f.f.__gcs.write = NULL; f.f.__gcs.seek = NULL; f.f.__gcs.close = NULL;#endif f.f.__filedes = __STDIO_STREAM_FAKE_VSSCANF_FILEDES_NB; f.f.__modeflags = (__FLAG_NARROW|__FLAG_READONLY|__FLAG_READING);/* #ifdef __UCLIBC_HAS_WCHAR__ *//* f.f.__ungot_width[0] = 0; *//* #endif */#ifdef __STDIO_MBSTATE#error __STDIO_MBSTATE is defined!/* __INIT_MBSTATE(&(f.f.__state)); */#endif#ifdef __UCLIBC_HAS_THREADS__ f.f.__user_locking = 1; /* Set user locking. */ __stdio_init_mutex(&f.f.__lock);#endif f.f.__nextopen = NULL; return vfscanf(&f.f, fmt, ap);}#elif defined(__UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__)int vsscanf(__const char *sp, __const char *fmt, va_list ap){ FILE *f; int rv = EOF; if ((f = fmemopen((char *)sp, strlen(sp), "r")) != NULL) { rv = vfscanf(f, fmt, ap); fclose(f); } return rv;}#else#warning Skipping vsscanf since no buffering, no custom streams, and wchar enabled!#ifdef __STDIO_HAS_VSSCANF#error WHOA! __STDIO_HAS_VSSCANF is defined!#endif#endif#endif/**********************************************************************/#ifdef L_fwscanfint fwscanf(FILE * __restrict stream, const wchar_t * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = vfwscanf(stream, format, arg); va_end(arg); return rv;}#endif/**********************************************************************/#ifdef L_wscanfint wscanf(const wchar_t * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = vfwscanf(stdin, format, arg); va_end(arg); return rv;}#endif/**********************************************************************/#ifdef L_swscanf#ifdef __STDIO_BUFFERSint swscanf(const wchar_t * __restrict str, const wchar_t * __restrict format, ...){ va_list arg; int rv; va_start(arg, format); rv = vswscanf(str, format, arg); va_end(arg); return rv;}#else /* __STDIO_BUFFERS */#warning Skipping swscanf since no buffering!#endif /* __STDIO_BUFFERS */#endif/**********************************************************************/#ifdef L_vwscanfint vwscanf(const wchar_t * __restrict format, va_list arg){ return vfwscanf(stdin, format, arg);}#endif/**********************************************************************/#ifdef L_vswscanf#ifdef __STDIO_BUFFERSint vswscanf(const wchar_t * __restrict str, const wchar_t * __restrict format, va_list arg){ FILE f; f.__bufstart = f.__bufpos = (char *) str; f.__bufread = f.__bufend = (char *)(str + wcslen(str)); __STDIO_STREAM_DISABLE_GETC(&f); __STDIO_STREAM_DISABLE_PUTC(&f);/* __STDIO_STREAM_RESET_GCS(&f); */#ifdef __UCLIBC_HAS_GLIBC_CUSTOM_STREAMS__ f.__cookie = &(f.__filedes); f.__gcs.read = NULL; f.__gcs.write = NULL; f.__gcs.seek = NULL; f.__gcs.close = NULL;#endif f.__filedes = __STDIO_STREAM_FAKE_VSWSCANF_FILEDES; f.__modeflags = (__FLAG_WIDE|__FLAG_READONLY|__FLAG_READING);#ifdef __UCLIBC_HAS_WCHAR__ f.__ungot_width[0] = 0;#endif /* __UCLIBC_HAS_WCHAR__ */#ifdef __STDIO_MBSTATE __INIT_MBSTATE(&(f.__state));#endif /* __STDIO_MBSTATE */#ifdef __UCLIBC_HAS_THREADS__ f.__user_locking = 1; /* Set user locking. */ __stdio_init_mutex(&f.__lock);#endif f.__nextopen = NULL; return vfwscanf(&f, format, arg);}#else /* __STDIO_BUFFERS */#warning Skipping vswscanf since no buffering!#endif /* __STDIO_BUFFERS */#endif/**********************************************************************//**********************************************************************//* float layout 0123456789012345678901 repeat n for "l[" */#define SPEC_CHARS "npxXoudifFeEgGaACSncs["/* npxXoudif eEgG CS cs[ *//* NOTE: Ordering is important! In particular, CONV_LEFTBRACKET * must immediately precede CONV_c. */enum { CONV_n = 0, CONV_p, CONV_x, CONV_X, CONV_o, CONV_u, CONV_d, CONV_i, CONV_f, CONV_F, CONV_e, CONV_E, CONV_g, CONV_G, CONV_a, CONV_A, CONV_C, CONV_S, CONV_LEFTBRACKET, CONV_c, CONV_s, CONV_leftbracket, CONV_percent, CONV_whitespace /* not in SPEC_* and no flags */};#ifdef __UCLIBC_HAS_FLOATS__#ifdef __UCLIBC_HAS_HEXADECIMAL_FLOATS__/* p x X o u d i f F e E g G a A */#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0 }#else/* p x X o u d i f F e E g G a A */#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0, 10, 10, 10, 10, 10, 10, 10, 10 }#endif#else /* __UCLIBC_HAS_FLOATS__ *//* p x X o u d i f F e E g G a A */#define SPEC_BASE { 16, 16, 16, 8, 10, 10, 0 }#endif /* __UCLIBC_HAS_FLOATS__ */#ifdef __UCLIBC_MJN3_ONLY__#ifdef L_vfscanf/* emit once */#warning CONSIDER: Add a '0' flag to eat 0 padding when grouping?#endif#endif /* __UCLIBC_MJN3_ONLY__ */#define SPEC_FLAGS "*'I"enum { FLAG_SURPRESS = 0x10, /* MUST BE 1ST!! See DO_FLAGS. */ FLAG_THOUSANDS = 0x20, FLAG_I18N = 0x40, /* only works for d, i, u */ FLAG_MALLOC = 0x80, /* only works for s, S, and [ (and l[)*/}; #define SPEC_RANGES { CONV_n, CONV_p, CONV_i, CONV_A, \ CONV_C, CONV_LEFTBRACKET, \ CONV_c, CONV_leftbracket }/* Note: We treat L and ll as synonymous... for ints and floats. */#define SPEC_ALLOWED_FLAGS { \ /* n */ (0x0f|FLAG_SURPRESS), \ /* p */ ( 0|FLAG_SURPRESS), \ /* oxXudi */ (0x0f|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \ /* fFeEgGaA */ (0x0c|FLAG_SURPRESS|FLAG_THOUSANDS|FLAG_I18N), \ /* C */ ( 0|FLAG_SURPRESS), \ /* S and l[ */ ( 0|FLAG_SURPRESS|FLAG_MALLOC), \ /* c */ (0x04|FLAG_SURPRESS), \ /* s and [ */ (0x04|FLAG_SURPRESS|FLAG_MALLOC), \}/**********************************************************************//* * In order to ease translation to what arginfo and _print_info._flags expect, * we map: 0:int 1:char 2:longlong 4:long 8:short * and then _flags |= (((q << 7) + q) & 0x701) and argtype |= (_flags & 0x701) *//* TODO -- Fix the table below to take into account stdint.h. *//* #ifndef LLONG_MAX *//* #error fix QUAL_CHARS for no long long! Affects 'L', 'j', 'q', 'll'. *//* #else *//* #if LLONG_MAX != INTMAX_MAX *//* #error fix QUAL_CHARS intmax_t entry 'j'! *//* #endif *//* #endif */#ifdef PDS#error PDS already defined!#endif#ifdef SS#error SS already defined!#endif#ifdef IMS#error IMS already defined!#endif#if PTRDIFF_MAX == INT_MAX#define PDS 0#elif PTRDIFF_MAX == LONG_MAX#define PDS 4#elif defined(LLONG_MAX) && (PTRDIFF_MAX == LLONG_MAX)#define PDS 8#else#error fix QUAL_CHARS ptrdiff_t entry 't'!#endif#if SIZE_MAX == UINT_MAX#define SS 0#elif SIZE_MAX == ULONG_MAX#define SS 4#elif defined(LLONG_MAX) && (SIZE_MAX == ULLONG_MAX)#define SS 8#else#error fix QUAL_CHARS size_t entries 'z', 'Z'!#endif#if INTMAX_MAX == INT_MAX#define IMS 0#elif INTMAX_MAX == LONG_MAX#define IMS 4#elif defined(LLONG_MAX) && (INTMAX_MAX == LLONG_MAX)#define IMS 8#else#error fix QUAL_CHARS ptrdiff_t entry 't'!#endif#define QUAL_CHARS { \ /* j:(u)intmax_t z:(s)size_t t:ptrdiff_t \0:int q:long_long */ \ 'h', 'l', 'L', 'j', 'z', 't', 'q', 0, \ 2, 4, 8, IMS, SS, PDS, 8, 0, /* TODO -- fix!!! */\ 1, 8 }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -