⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 vfscanf.c

📁 绝对正真的stdio.h的实现
💻 C
📖 第 1 页 / 共 4 页
字号:
/* Copyright (C) 1991-2002, 2003, 2004 Free Software Foundation, Inc.   This file is part of the GNU C Library.   The GNU C Library is free software; you can redistribute it and/or   modify it under the terms of the GNU Lesser General Public   License as published by the Free Software Foundation; either   version 2.1 of the License, or (at your option) any later version.   The GNU C 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   Lesser General Public License for more details.   You should have received a copy of the GNU Lesser General Public   License along with the GNU C Library; if not, write to the Free   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA   02111-1307 USA.  */#include <assert.h>#include <errno.h>#include <limits.h>#include <ctype.h>#include <stdarg.h>#include <stdio.h>#include <stdint.h>#include <stdlib.h>#include <string.h>#include <wchar.h>#include <wctype.h>#include <bits/libc-lock.h>#include <locale/localeinfo.h>#ifdef	__GNUC__# define HAVE_LONGLONG# define LONGLONG	long long#else# define LONGLONG	long#endif/* Determine whether we have to handle `long long' at all.  */#if LONG_MAX == LONG_LONG_MAX# define need_longlong	0#else# define need_longlong	1#endif/* Determine whether we have to handle `long'.  */#if INT_MAX == LONG_MAX# define need_long	0#else# define need_long 	1#endif/* Those are flags in the conversion format. */#define LONG		0x001	/* l: long or double */#define LONGDBL		0x002	/* L: long long or long double */#define SHORT		0x004	/* h: short */#define SUPPRESS	0x008	/* *: suppress assignment */#define POINTER		0x010	/* weird %p pointer (`fake hex') */#define NOSKIP		0x020	/* do not skip blanks */#define WIDTH		0x040	/* width was given */#define GROUP		0x080	/* ': group numbers */#define MALLOC		0x100	/* a: malloc strings */#define CHAR		0x200	/* hh: char */#define I18N		0x400	/* I: use locale's digits */#include <locale/localeinfo.h>#include <libioP.h>#include <libio.h>#undef va_list#define va_list	_IO_va_list#ifdef COMPILE_WSCANF# define ungetc(c, s)	((void) (c == WEOF				      \				 || (--read_in,				      \				     INTUSE(_IO_sputbackwc) (s, c))))# define ungetc_not_eof(c, s)	((void) (--read_in,			      \					 INTUSE(_IO_sputbackwc) (s, c)))# define inchar()	(c == WEOF ? ((errno = inchar_errno), WEOF)	      \			 : ((c = _IO_getwc_unlocked (s)),		      \			    (void) (c != WEOF				      \				    ? ++read_in				      \				    : (size_t) (inchar_errno = errno)), c))# define MEMCPY(d, s, n) __wmemcpy (d, s, n)# define ISSPACE(Ch)	  iswspace (Ch)# define ISDIGIT(Ch)	  iswdigit (Ch)# define ISXDIGIT(Ch)	  iswxdigit (Ch)# define TOLOWER(Ch)	  towlower (Ch)# define ORIENT	  if (_IO_fwide (s, 1) != 1) return WEOF# define __strtoll_internal	__wcstoll_internal# define __strtoull_internal	__wcstoull_internal# define __strtol_internal	__wcstol_internal# define __strtoul_internal	__wcstoul_internal# define __strtold_internal	__wcstold_internal# define __strtod_internal	__wcstod_internal# define __strtof_internal	__wcstof_internal# define L_(Str)	L##Str# define CHAR_T	  	wchar_t# define UCHAR_T	unsigned int# define WINT_T	  	wint_t# undef EOF# define EOF		WEOF#else# define ungetc(c, s)	((void) ((int) c == EOF				      \				 || (--read_in,				      \				     INTUSE(_IO_sputbackc) (s, (unsigned char) c))))# define ungetc_not_eof(c, s)	((void) (--read_in,			      \					 INTUSE(_IO_sputbackc) (s, (unsigned char) c)))# define inchar()	(c == EOF ? ((errno = inchar_errno), EOF)	      \			 : ((c = _IO_getc_unlocked (s)),		      \			    (void) (c != EOF				      \				    ? ++read_in				      \				    : (size_t) (inchar_errno = errno)), c))# define MEMCPY(d, s, n) memcpy (d, s, n)# define ISSPACE(Ch)	  __isspace_l (Ch, loc)# define ISDIGIT(Ch)	  __isdigit_l (Ch, loc)# define ISXDIGIT(Ch)	  __isxdigit_l (Ch, loc)# define TOLOWER(Ch)	  __tolower_l ((unsigned char) (Ch), loc)# define ORIENT	  if (_IO_vtable_offset (s) == 0			      \			      && _IO_fwide (s, -1) != -1)		      \			    return EOF# define L_(Str)	Str# define CHAR_T	  	char# define UCHAR_T	unsigned char# define WINT_T		int#endif#define encode_error() do {						      \			  errval = 4;					      \			  __set_errno (EILSEQ);				      \			  goto errout;					      \			} while (0)#define conv_error()	do {						      \			  errval = 2;					      \			  goto errout;					      \			} while (0)#define input_error()	do {						      \			  errval = 1;					      \			  if (done == 0) done = EOF;			      \			  goto errout;					      \			} while (0)#define memory_error() do {						      \			  __set_errno (ENOMEM);				      \			  done = EOF;					      \			  goto errout;					      \			} while (0)#define ARGCHECK(s, format)						      \  do									      \    {									      \      /* Check file argument for consistence.  */			      \      CHECK_FILE (s, EOF);						      \      if (s->_flags & _IO_NO_READS)					      \	{								      \	  __set_errno (EBADF);						      \	  return EOF;							      \	}								      \      else if (format == NULL)						      \	{								      \	  MAYBE_SET_EINVAL;						      \	  return EOF;							      \	}								      \    } while (0)#define LOCK_STREAM(S)							      \  __libc_cleanup_region_start (1, (void (*) (void *)) &_IO_funlockfile, (S)); \  _IO_flockfile (S)#define UNLOCK_STREAM(S)						      \  _IO_funlockfile (S);							      \  __libc_cleanup_region_end (0)/* Read formatted input from S according to the format string   FORMAT, using the argument list in ARG.   Return the number of assignments made, or -1 for an input error.  */#ifdef COMPILE_WSCANFint_IO_vfwscanf (s, format, argptr, errp)     _IO_FILE *s;     const wchar_t *format;     _IO_va_list argptr;     int *errp;#elseint_IO_vfscanf (s, format, argptr, errp)     _IO_FILE *s;     const char *format;     _IO_va_list argptr;     int *errp;#endif{  va_list arg;  register const CHAR_T *f = format;  register UCHAR_T fc;	/* Current character of the format.  */  register WINT_T done = 0;	/* Assignments done.  */  register size_t read_in = 0;	/* Chars read in.  */  register WINT_T c = 0;	/* Last char read.  */  register int width;		/* Maximum field width.  */  register int flags;		/* Modifiers for current format element.  */  int errval = 0;#ifndef COMPILE_WSCANF  __locale_t loc = _NL_CURRENT_LOCALE;  struct locale_data *const curctype = loc->__locales[LC_CTYPE];#endif  /* Errno of last failed inchar call.  */  int inchar_errno = 0;  /* Status for reading F-P nums.  */  char got_dot, got_e, negative;  /* If a [...] is a [^...].  */  CHAR_T not_in;#define exp_char not_in  /* Base for integral numbers.  */  int base;  /* Signedness for integral numbers.  */  int number_signed;#define is_hexa number_signed  /* Decimal point character.  */#ifdef COMPILE_WSCANF  wint_t decimal;#else  const char *decimal;#endif  /* The thousands character of the current locale.  */#ifdef COMPILE_WSCANF  wint_t thousands;#else  const char *thousands;#endif  /* State for the conversions.  */  mbstate_t state;  /* Integral holding variables.  */  union    {      long long int q;      unsigned long long int uq;      long int l;      unsigned long int ul;    } num;  /* Character-buffer pointer.  */  char *str = NULL;  wchar_t *wstr = NULL;  char **strptr = NULL;  ssize_t strsize = 0;  /* We must not react on white spaces immediately because they can     possibly be matched even if in the input stream no character is     available anymore.  */  int skip_space = 0;  /* Nonzero if we are reading a pointer.  */  int read_pointer;  /* Workspace.  */  CHAR_T *tw;			/* Temporary pointer.  */  CHAR_T *wp = NULL;		/* Workspace.  */  size_t wpmax = 0;		/* Maximal size of workspace.  */  size_t wpsize;		/* Currently used bytes in workspace.  */#define ADDW(Ch)							    \  do									    \    {									    \      if (wpsize == wpmax)						    \	{								    \	  CHAR_T *old = wp;						    \	  wpmax = (UCHAR_MAX + 1 > 2 * wpmax ? UCHAR_MAX + 1 : 2 * wpmax);  \	  wp = (CHAR_T *) alloca (wpmax * sizeof (wchar_t));		    \	  if (old != NULL)						    \	    MEMCPY (wp, old, wpsize);					    \	}								    \      wp[wpsize++] = (Ch);						    \    }									    \  while (0)#ifdef __va_copy  __va_copy (arg, argptr);#else  arg = (va_list) argptr;#endif#ifdef ORIENT  ORIENT;#endif  ARGCHECK (s, format); {#ifndef COMPILE_WSCANF   struct locale_data *const curnumeric = loc->__locales[LC_NUMERIC];#endif   /* Figure out the decimal point character.  */#ifdef COMPILE_WSCANF   decimal = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_DECIMAL_POINT_WC);#else   decimal = curnumeric->values[_NL_ITEM_INDEX (DECIMAL_POINT)].string;#endif   /* Figure out the thousands separator character.  */#ifdef COMPILE_WSCANF   thousands = _NL_CURRENT_WORD (LC_NUMERIC, _NL_NUMERIC_THOUSANDS_SEP_WC);#else   thousands = curnumeric->values[_NL_ITEM_INDEX (THOUSANDS_SEP)].string;   if (*thousands == '\0')     thousands = NULL;#endif }  /* Lock the stream.  */  LOCK_STREAM (s);#ifndef COMPILE_WSCANF  /* From now on we use `state' to convert the format string.  */  memset (&state, '\0', sizeof (state));#endif  /* Run through the format string.  */  while (*f != '\0')    {      unsigned int argpos;      /* Extract the next argument, which is of type TYPE.	 For a %N$... spec, this is the Nth argument from the beginning;	 otherwise it is the next argument after the state now in ARG.  */#ifdef __va_copy# define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \			 ({ unsigned int pos = argpos;			      \			    va_list arg;				      \			    __va_copy (arg, argptr);			      \			    while (--pos > 0)				      \			      (void) va_arg (arg, void *);		      \			    va_arg (arg, type);				      \			  }))#else# if 0      /* XXX Possible optimization.  */#  define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \			 ({ va_list arg = (va_list) argptr;		      \			    arg = (va_list) ((char *) arg		      \					     + (argpos - 1)		      \					     * __va_rounded_size (void *));   \			    va_arg (arg, type);				      \			 }))# else#  define ARG(type)	(argpos == 0 ? va_arg (arg, type) :		      \			 ({ unsigned int pos = argpos;			      \			    va_list arg = (va_list) argptr;		      \			    while (--pos > 0)				      \			      (void) va_arg (arg, void *);		      \			    va_arg (arg, type);				      \			  }))# endif#endif#ifndef COMPILE_WSCANF      if (!isascii ((unsigned char) *f))	{	  /* Non-ASCII, may be a multibyte.  */	  int len = __mbrlen (f, strlen (f), &state);	  if (len > 0)	    {	      do		{		  c = inchar ();		  if (c == EOF)		    input_error ();		  else if (c != (unsigned char) *f++)		    {		      ungetc_not_eof (c, s);		      conv_error ();		    }		}	      while (--len > 0);	      continue;	    }	}#endif      fc = *f++;      if (fc != '%')	{	  /* Remember to skip spaces.  */	  if (ISSPACE (fc))	    {	      skip_space = 1;	      continue;	    }	  /* Read a character.  */	  c = inchar ();	  /* Characters other than format specs must just match.  */	  if (c == EOF)	    input_error ();	  /* We saw white space char as the last character in the format	     string.  Now it's time to skip all leading white space.  */	  if (skip_space)	    {	      while (ISSPACE (c))		if (inchar () == EOF)		  input_error ();	      skip_space = 0;	    }	  if (c != fc)	    {	      ungetc (c, s);	      conv_error ();	    }	  continue;	}      /* This is the start of the conversion string. */      flags = 0;      /* Not yet decided whether we read a pointer or not.  */      read_pointer = 0;      /* Initialize state of modifiers.  */      argpos = 0;      /* Prepare temporary buffer.  */      wpsize = 0;      /* Check for a positional parameter specification.  */      if (ISDIGIT ((UCHAR_T) *f))	{	  argpos = (UCHAR_T) *f++ - L_('0');	  while (ISDIGIT ((UCHAR_T) *f))	    argpos = argpos * 10 + ((UCHAR_T) *f++ - L_('0'));	  if (*f == L_('$'))	    ++f;	  else	    {	      /* Oops; that was actually the field width.  */	      width = argpos;	      flags |= WIDTH;	      argpos = 0;	      goto got_width;	    }	}      /* Check for the assignment-suppressing, the number grouping flag,	 and the signal to use the locale's digit representation.  */      while (*f == L_('*') || *f == L_('\'') || *f == L_('I'))	switch (*f++)	  {	  case L_('*'):	    flags |= SUPPRESS;	    break;	  case L_('\''):	    flags |= GROUP;	    break;	  case L_('I'):	    flags |= I18N;	    break;	  }      /* We have seen width. */      if (ISDIGIT ((UCHAR_T) *f))	flags |= WIDTH;      /* Find the maximum field width.  */      width = 0;      while (ISDIGIT ((UCHAR_T) *f))	{	  width *= 10;	  width += (UCHAR_T) *f++ - L_('0');	}    got_width:      if (width == 0)	width = -1;      /* Check for type modifiers.  */      switch (*f++)	{	case L_('h'):	  /* ints are short ints or chars.  */	  if (*f == L_('h'))	    {	      ++f;	      flags |= CHAR;	    }	  else	    flags |= SHORT;	  break;	case L_('l'):	  if (*f == L_('l'))	    {	      /* A double `l' is equivalent to an `L'.  */	      ++f;	      flags |= LONGDBL | LONG;	    }	  else	    /* ints are long ints.  */	    flags |= LONG;	  break;	case L_('q'):	case L_('L'):	  /* doubles are long doubles, and ints are long long ints.  */	  flags |= LONGDBL | LONG;	  break;	case L_('a'):	  /* The `a' is used as a flag only if followed by `s', `S' or	     `['.  */	  if (*f != L_('s') && *f != L_('S') && *f != L_('['))	    {	      --f;	      break;	    }	  /* String conversions (%s, %[) take a `char **'	     arg and fill it in with a malloc'd pointer.  */	  flags |= MALLOC;	  break;	case L_('z'):	  if (need_longlong && sizeof (size_t) > sizeof (unsigned long int))	    flags |= LONGDBL;	  else if (sizeof (size_t) > sizeof (unsigned int))	    flags |= LONG;	  break;	case L_('j'):	  if (need_longlong && sizeof (uintmax_t) > sizeof (unsigned long int))	    flags |= LONGDBL;	  else if (sizeof (uintmax_t) > sizeof (unsigned int))	    flags |= LONG;	  break;	case L_('t'):	  if (need_longlong && sizeof (ptrdiff_t) > sizeof (long int))	    flags |= LONGDBL;	  else if (sizeof (ptrdiff_t) > sizeof (int))	    flags |= LONG;	  break;	default:	  /* Not a recognized modifier.  Backup.  */	  --f;	  break;	}      /* End of the format string?  */      if (*f == L_('\0'))	conv_error ();      /* Find the conversion specifier.  */      fc = *f++;      if (skip_space || (fc != L_('[') && fc != L_('c')			 && fc != L_('C') && fc != L_('n')))	{	  /* Eat whitespace.  */	  int save_errno = errno;	  errno = 0;	  do	    if (inchar () == EOF && errno == EINTR)	      input_error ();	  while (ISSPACE (c));	  errno = save_errno;	  ungetc (c, s);	  skip_space = 0;	}      switch (fc)	{	case L_('%'):	/* Must match a literal '%'.  */	  c = inchar ();	  if (c == EOF)	    input_error ();	  if (c != fc)	    {	      ungetc_not_eof (c, s);	      conv_error ();	    }	  break;	case L_('n'):	/* Answer number of assignments done.  */	  /* Corrigendum 1 to ISO C 1990 describes the allowed flags	     with the 'n' conversion specifier.  */	  if (!(flags & SUPPRESS))	    {	      /* Don't count the read-ahead.  */	      if (need_longlong && (flags & LONGDBL))		*ARG (long long int *) = read_in;	      else if (need_long && (flags & LONG))		*ARG (long int *) = read_in;	      else if (flags & SHORT)		*ARG (short int *) = read_in;	      else if (!(flags & CHAR))		*ARG (int *) = read_in;	      else		*ARG (char *) = read_in;#ifdef NO_BUG_IN_ISO_C_CORRIGENDUM_1	      /* We have a severe problem here.  The ISO C standard		 contradicts itself in explaining the effect of the %n		 format in `scanf'.  While in ISO C:1990 and the ISO C		 Amendement 1:1995 the result is described as		   Execution of a %n directive does not effect the		   assignment count returned at the completion of		   execution of the f(w)scanf function.		 in ISO C Corrigendum 1:1994 the following was added:		   Subclause 7.9.6.2		   Add the following fourth example:		     In:		       #include <stdio.h>		       int d1, d2, n1, n2, i;		       i = sscanf("123", "%d%n%n%d", &d1, &n1, &n2, &d2);		     the value 123 is assigned to d1 and the value3 to n1.		     Because %n can never get an input failure the value		     of 3 is also assigned to n2.  The value of d2 is not		     affected.  The value 3 is assigned to i.		 We go for now with the historically correct code from ISO C,		 i.e., we don't count the %n assignments.  When it ever		 should proof to be wrong just remove the #ifdef above.  */	      ++done;#endif

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -