mirror of
				https://sourceware.org/git/glibc.git
				synced 2025-11-03 20:53:13 +03:00 
			
		
		
		
	This avoids a race condition if the process-global locale is changed while vfscanf is running. MB_LEN_MAX is always larger than MB_CUR_MAX, so we might realloc earlier than necessary (but even MB_CUR_MAX could be larger than the minimum required space). The existing length was a bit questionable because str + MB_LEN_MAX might point past the end of the buffer.
		
			
				
	
	
		
			3074 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			3074 lines
		
	
	
		
			73 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/* Copyright (C) 1991-2016 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, see
 | 
						|
   <http://www.gnu.org/licenses/>.  */
 | 
						|
 | 
						|
#include <assert.h>
 | 
						|
#include <errno.h>
 | 
						|
#include <limits.h>
 | 
						|
#include <ctype.h>
 | 
						|
#include <stdarg.h>
 | 
						|
#include <stdbool.h>
 | 
						|
#include <stdio.h>
 | 
						|
#include <stdint.h>
 | 
						|
#include <stdlib.h>
 | 
						|
#include <string.h>
 | 
						|
#include <wchar.h>
 | 
						|
#include <wctype.h>
 | 
						|
#include <libc-internal.h>
 | 
						|
#include <libc-lock.h>
 | 
						|
#include <locale/localeinfo.h>
 | 
						|
#include <scratch_buffer.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		0x0001	/* l: long or double */
 | 
						|
#define LONGDBL		0x0002	/* L: long long or long double */
 | 
						|
#define SHORT		0x0004	/* h: short */
 | 
						|
#define SUPPRESS	0x0008	/* *: suppress assignment */
 | 
						|
#define POINTER		0x0010	/* weird %p pointer (`fake hex') */
 | 
						|
#define NOSKIP		0x0020	/* do not skip blanks */
 | 
						|
#define NUMBER_SIGNED	0x0040	/* signed integer */
 | 
						|
#define GROUP		0x0080	/* ': group numbers */
 | 
						|
#define GNU_MALLOC	0x0100	/* a: malloc strings */
 | 
						|
#define CHAR		0x0200	/* hh: char */
 | 
						|
#define I18N		0x0400	/* I: use locale's digits */
 | 
						|
#define HEXA_FLOAT	0x0800	/* hexadecimal float */
 | 
						|
#define READ_POINTER	0x1000	/* this is a pointer value */
 | 
						|
#define POSIX_MALLOC	0x2000	/* m: malloc strings */
 | 
						|
#define MALLOC		(GNU_MALLOC | POSIX_MALLOC)
 | 
						|
 | 
						|
#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,				      \
 | 
						|
				     _IO_sputbackwc (s, c))))
 | 
						|
# define ungetc_not_eof(c, s)	((void) (--read_in,			      \
 | 
						|
					 _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 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,				      \
 | 
						|
				     _IO_sputbackc (s, (unsigned char) c))))
 | 
						|
# define ungetc_not_eof(c, s)	((void) (--read_in,			      \
 | 
						|
					 _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 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 add_ptr_to_free(ptr)						      \
 | 
						|
  do									      \
 | 
						|
    {									      \
 | 
						|
      if (ptrs_to_free == NULL						      \
 | 
						|
	  || ptrs_to_free->count == (sizeof (ptrs_to_free->ptrs)	      \
 | 
						|
				     / sizeof (ptrs_to_free->ptrs[0])))	      \
 | 
						|
	{								      \
 | 
						|
	  struct ptrs_to_free *new_ptrs = alloca (sizeof (*ptrs_to_free));    \
 | 
						|
	  new_ptrs->count = 0;						      \
 | 
						|
	  new_ptrs->next = ptrs_to_free;				      \
 | 
						|
	  ptrs_to_free = new_ptrs;					      \
 | 
						|
	}								      \
 | 
						|
      ptrs_to_free->ptrs[ptrs_to_free->count++] = (ptr);		      \
 | 
						|
    }									      \
 | 
						|
  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)
 | 
						|
 | 
						|
struct ptrs_to_free
 | 
						|
{
 | 
						|
  size_t count;
 | 
						|
  struct ptrs_to_free *next;
 | 
						|
  char **ptrs[32];
 | 
						|
};
 | 
						|
 | 
						|
struct char_buffer {
 | 
						|
  CHAR_T *current;
 | 
						|
  CHAR_T *end;
 | 
						|
  struct scratch_buffer scratch;
 | 
						|
};
 | 
						|
 | 
						|
/* Returns a pointer to the first CHAR_T object in the buffer.  Only
 | 
						|
   valid if char_buffer_add (BUFFER, CH) has been called and
 | 
						|
   char_buffer_error (BUFFER) is false.  */
 | 
						|
static inline CHAR_T *
 | 
						|
char_buffer_start (const struct char_buffer *buffer)
 | 
						|
{
 | 
						|
  return (CHAR_T *) buffer->scratch.data;
 | 
						|
}
 | 
						|
 | 
						|
/* Returns the number of CHAR_T objects in the buffer.  Only valid if
 | 
						|
   char_buffer_error (BUFFER) is false.  */
 | 
						|
static inline size_t
 | 
						|
char_buffer_size (const struct char_buffer *buffer)
 | 
						|
{
 | 
						|
  return buffer->current - char_buffer_start (buffer);
 | 
						|
}
 | 
						|
 | 
						|
/* Reinitializes BUFFER->current and BUFFER->end to cover the entire
 | 
						|
   scratch buffer.  */
 | 
						|
static inline void
 | 
						|
char_buffer_rewind (struct char_buffer *buffer)
 | 
						|
{
 | 
						|
  buffer->current = char_buffer_start (buffer);
 | 
						|
  buffer->end = buffer->current + buffer->scratch.length / sizeof (CHAR_T);
 | 
						|
}
 | 
						|
 | 
						|
/* Returns true if a previous call to char_buffer_add (BUFFER, CH)
 | 
						|
   failed.  */
 | 
						|
static inline bool
 | 
						|
char_buffer_error (const struct char_buffer *buffer)
 | 
						|
{
 | 
						|
  return __glibc_unlikely (buffer->current == NULL);
 | 
						|
}
 | 
						|
 | 
						|
/* Slow path for char_buffer_add.  */
 | 
						|
static void
 | 
						|
char_buffer_add_slow (struct char_buffer *buffer, CHAR_T ch)
 | 
						|
{
 | 
						|
  if (char_buffer_error (buffer))
 | 
						|
    return;
 | 
						|
  size_t offset = buffer->end - (CHAR_T *) buffer->scratch.data;
 | 
						|
  if (!scratch_buffer_grow_preserve (&buffer->scratch))
 | 
						|
    {
 | 
						|
      buffer->current = NULL;
 | 
						|
      buffer->end = NULL;
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  char_buffer_rewind (buffer);
 | 
						|
  buffer->current += offset;
 | 
						|
  *buffer->current++ = ch;
 | 
						|
}
 | 
						|
 | 
						|
/* Adds CH to BUFFER.  This function does not report any errors, check
 | 
						|
   for them with char_buffer_error.  */
 | 
						|
static inline void
 | 
						|
char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
 | 
						|
  __attribute__ ((always_inline));
 | 
						|
static inline void
 | 
						|
char_buffer_add (struct char_buffer *buffer, CHAR_T ch)
 | 
						|
{
 | 
						|
  if (__glibc_unlikely (buffer->current == buffer->end))
 | 
						|
    char_buffer_add_slow (buffer, ch);
 | 
						|
  else
 | 
						|
    *buffer->current++ = ch;
 | 
						|
}
 | 
						|
 | 
						|
/* 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_WSCANF
 | 
						|
int
 | 
						|
_IO_vfwscanf (_IO_FILE *s, const wchar_t *format, _IO_va_list argptr,
 | 
						|
	      int *errp)
 | 
						|
#else
 | 
						|
int
 | 
						|
_IO_vfscanf_internal (_IO_FILE *s, const char *format, _IO_va_list argptr,
 | 
						|
		      int *errp)
 | 
						|
#endif
 | 
						|
{
 | 
						|
  va_list arg;
 | 
						|
  const CHAR_T *f = format;
 | 
						|
  UCHAR_T fc;	/* Current character of the format.  */
 | 
						|
  WINT_T done = 0;	/* Assignments done.  */
 | 
						|
  size_t read_in = 0;	/* Chars read in.  */
 | 
						|
  WINT_T c = 0;	/* Last char read.  */
 | 
						|
  int width;		/* Maximum field width.  */
 | 
						|
  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_digit, got_dot, got_e, negative;
 | 
						|
  /* If a [...] is a [^...].  */
 | 
						|
  CHAR_T not_in;
 | 
						|
#define exp_char not_in
 | 
						|
  /* Base for integral numbers.  */
 | 
						|
  int base;
 | 
						|
  /* 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
 | 
						|
  struct ptrs_to_free *ptrs_to_free = NULL;
 | 
						|
  /* 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;
 | 
						|
  /* Workspace.  */
 | 
						|
  CHAR_T *tw;			/* Temporary pointer.  */
 | 
						|
  struct char_buffer charbuf;
 | 
						|
  scratch_buffer_init (&charbuf.scratch);
 | 
						|
 | 
						|
#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 (__glibc_unlikely (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 (__glibc_unlikely (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 (__glibc_unlikely (inchar () == EOF))
 | 
						|
		  input_error ();
 | 
						|
	      skip_space = 0;
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (__glibc_unlikely (c != fc))
 | 
						|
	    {
 | 
						|
	      ungetc (c, s);
 | 
						|
	      conv_error ();
 | 
						|
	    }
 | 
						|
 | 
						|
	  continue;
 | 
						|
	}
 | 
						|
 | 
						|
      /* This is the start of the conversion string. */
 | 
						|
      flags = 0;
 | 
						|
 | 
						|
      /* Initialize state of modifiers.  */
 | 
						|
      argpos = 0;
 | 
						|
 | 
						|
      /* Prepare temporary buffer.  */
 | 
						|
      char_buffer_rewind (&charbuf);
 | 
						|
 | 
						|
      /* 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;
 | 
						|
	      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_('\''):
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
	    if (thousands != L'\0')
 | 
						|
#else
 | 
						|
	    if (thousands != NULL)
 | 
						|
#endif
 | 
						|
	      flags |= GROUP;
 | 
						|
	    break;
 | 
						|
	  case L_('I'):
 | 
						|
	    flags |= I18N;
 | 
						|
	    break;
 | 
						|
	  }
 | 
						|
 | 
						|
      /* 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;
 | 
						|
	    }
 | 
						|
	  /* In __isoc99_*scanf %as, %aS and %a[ extension is not
 | 
						|
	     supported at all.  */
 | 
						|
	  if (s->_flags2 & _IO_FLAGS2_SCANF_STD)
 | 
						|
	    {
 | 
						|
	      --f;
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  /* String conversions (%s, %[) take a `char **'
 | 
						|
	     arg and fill it in with a malloc'd pointer.  */
 | 
						|
	  flags |= GNU_MALLOC;
 | 
						|
	  break;
 | 
						|
	case L_('m'):
 | 
						|
	  flags |= POSIX_MALLOC;
 | 
						|
	  if (*f == L_('l'))
 | 
						|
	    {
 | 
						|
	      ++f;
 | 
						|
	      flags |= LONG;
 | 
						|
	    }
 | 
						|
	  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 (__glibc_unlikely (*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;
 | 
						|
	  __set_errno (0);
 | 
						|
	  do
 | 
						|
	    /* We add the additional test for EOF here since otherwise
 | 
						|
	       inchar will restore the old errno value which might be
 | 
						|
	       EINTR but does not indicate an interrupt since nothing
 | 
						|
	       was read at this time.  */
 | 
						|
	    if (__builtin_expect ((c == EOF || inchar () == EOF)
 | 
						|
				  && errno == EINTR, 0))
 | 
						|
	      input_error ();
 | 
						|
	  while (ISSPACE (c));
 | 
						|
	  __set_errno (save_errno);
 | 
						|
	  ungetc (c, s);
 | 
						|
	  skip_space = 0;
 | 
						|
	}
 | 
						|
 | 
						|
      switch (fc)
 | 
						|
	{
 | 
						|
	case L_('%'):	/* Must match a literal '%'.  */
 | 
						|
	  c = inchar ();
 | 
						|
	  if (__glibc_unlikely (c == EOF))
 | 
						|
	    input_error ();
 | 
						|
	  if (__glibc_unlikely (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
 | 
						|
	    }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case L_('c'):	/* Match characters.  */
 | 
						|
	  if ((flags & LONG) == 0)
 | 
						|
	    {
 | 
						|
	      if (width == -1)
 | 
						|
		width = 1;
 | 
						|
 | 
						|
#define STRING_ARG(Str, Type, Width)					      \
 | 
						|
	      do if (!(flags & SUPPRESS))				      \
 | 
						|
		{							      \
 | 
						|
		  if (flags & MALLOC)					      \
 | 
						|
		    {							      \
 | 
						|
		      /* The string is to be stored in a malloc'd buffer.  */ \
 | 
						|
		      /* For %mS using char ** is actually wrong, but	      \
 | 
						|
			 shouldn't make a difference on any arch glibc	      \
 | 
						|
			 supports and would unnecessarily complicate	      \
 | 
						|
			 things. */					      \
 | 
						|
		      strptr = ARG (char **);				      \
 | 
						|
		      if (strptr == NULL)				      \
 | 
						|
			conv_error ();					      \
 | 
						|
		      /* Allocate an initial buffer.  */		      \
 | 
						|
		      strsize = Width;					      \
 | 
						|
		      *strptr = (char *) malloc (strsize * sizeof (Type));    \
 | 
						|
		      Str = (Type *) *strptr;				      \
 | 
						|
		      if (Str != NULL)					      \
 | 
						|
			add_ptr_to_free (strptr);			      \
 | 
						|
		      else if (flags & POSIX_MALLOC)			      \
 | 
						|
			{						      \
 | 
						|
			  done = EOF;					      \
 | 
						|
			  goto errout;					      \
 | 
						|
			}						      \
 | 
						|
		    }							      \
 | 
						|
		  else							      \
 | 
						|
		    Str = ARG (Type *);					      \
 | 
						|
		  if (Str == NULL)					      \
 | 
						|
		    conv_error ();					      \
 | 
						|
		} while (0)
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
	      STRING_ARG (str, char, 100);
 | 
						|
#else
 | 
						|
	      STRING_ARG (str, char, (width > 1024 ? 1024 : width));
 | 
						|
#endif
 | 
						|
 | 
						|
	      c = inchar ();
 | 
						|
	      if (__glibc_unlikely (c == EOF))
 | 
						|
		input_error ();
 | 
						|
 | 
						|
#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;
 | 
						|
 | 
						|
		  if (!(flags & SUPPRESS) && (flags & POSIX_MALLOC)
 | 
						|
		      && *strptr + strsize - str <= MB_LEN_MAX)
 | 
						|
		    {
 | 
						|
		      /* We have to enlarge the buffer if the `m' 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_LEN_MAX);
 | 
						|
			  if (newstr == NULL)
 | 
						|
			    {
 | 
						|
			      /* c can't have `a' flag, only `m'.  */
 | 
						|
			      done = EOF;
 | 
						|
			      goto errout;
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = newstr;
 | 
						|
			      str = newstr + strleng;
 | 
						|
			      strsize = strleng + MB_LEN_MAX;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			{
 | 
						|
			  *strptr = newstr;
 | 
						|
			  str = newstr + strleng;
 | 
						|
			  strsize *= 2;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
 | 
						|
		  if (__glibc_unlikely (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
 | 
						|
		    {
 | 
						|
		      if ((flags & MALLOC)
 | 
						|
			  && (char *) str == *strptr + strsize)
 | 
						|
			{
 | 
						|
			  /* Enlarge the buffer.  */
 | 
						|
			  size_t newsize
 | 
						|
			    = strsize
 | 
						|
			      + (strsize >= width ? width - 1 : strsize);
 | 
						|
 | 
						|
			  str = (char *) realloc (*strptr, newsize);
 | 
						|
			  if (str == NULL)
 | 
						|
			    {
 | 
						|
			      /* Can't allocate that much.  Last-ditch
 | 
						|
				 effort.  */
 | 
						|
			      str = (char *) realloc (*strptr, strsize + 1);
 | 
						|
			      if (str == NULL)
 | 
						|
				{
 | 
						|
				  /* c can't have `a' flag, only `m'.  */
 | 
						|
				  done = EOF;
 | 
						|
				  goto errout;
 | 
						|
				}
 | 
						|
			      else
 | 
						|
				{
 | 
						|
				  *strptr = (char *) str;
 | 
						|
				  str += strsize;
 | 
						|
				  ++strsize;
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = (char *) str;
 | 
						|
			      str += strsize;
 | 
						|
			      strsize = newsize;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		      *str++ = c;
 | 
						|
		    }
 | 
						|
		  while (--width > 0 && inchar () != EOF);
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		while (--width > 0 && inchar () != EOF);
 | 
						|
#endif
 | 
						|
 | 
						|
	      if (!(flags & SUPPRESS))
 | 
						|
		{
 | 
						|
		  if ((flags & MALLOC) && str - *strptr != strsize)
 | 
						|
		    {
 | 
						|
		      char *cp = (char *) realloc (*strptr, str - *strptr);
 | 
						|
		      if (cp != NULL)
 | 
						|
			*strptr = cp;
 | 
						|
		    }
 | 
						|
		  strptr = NULL;
 | 
						|
		  ++done;
 | 
						|
		}
 | 
						|
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  /* FALLTHROUGH */
 | 
						|
	case L_('C'):
 | 
						|
	  if (width == -1)
 | 
						|
	    width = 1;
 | 
						|
 | 
						|
	  STRING_ARG (wstr, wchar_t, (width > 1024 ? 1024 : width));
 | 
						|
 | 
						|
	  c = inchar ();
 | 
						|
	  if (__glibc_unlikely (c == EOF))
 | 
						|
	    input_error ();
 | 
						|
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
	  /* Just store the incoming wide characters.  */
 | 
						|
	  if (!(flags & SUPPRESS))
 | 
						|
	    {
 | 
						|
	      do
 | 
						|
		{
 | 
						|
		  if ((flags & MALLOC)
 | 
						|
		      && wstr == (wchar_t *) *strptr + strsize)
 | 
						|
		    {
 | 
						|
		      size_t newsize
 | 
						|
			= strsize + (strsize > width ? width - 1 : strsize);
 | 
						|
		      /* Enlarge the buffer.  */
 | 
						|
		      wstr = (wchar_t *) realloc (*strptr,
 | 
						|
						  newsize * 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)
 | 
						|
			    {
 | 
						|
			      /* C or lc can't have `a' flag, only `m'
 | 
						|
				 flag.  */
 | 
						|
			      done = EOF;
 | 
						|
			      goto errout;
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = (char *) wstr;
 | 
						|
			      wstr += strsize;
 | 
						|
			      ++strsize;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			{
 | 
						|
			  *strptr = (char *) wstr;
 | 
						|
			  wstr += strsize;
 | 
						|
			  strsize = newsize;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		  *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;
 | 
						|
 | 
						|
		if (!(flags & SUPPRESS) && (flags & MALLOC)
 | 
						|
		    && wstr == (wchar_t *) *strptr + strsize)
 | 
						|
		  {
 | 
						|
		    size_t newsize
 | 
						|
		      = strsize + (strsize > width ? width - 1 : strsize);
 | 
						|
		    /* Enlarge the buffer.  */
 | 
						|
		    wstr = (wchar_t *) realloc (*strptr,
 | 
						|
						newsize * 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)
 | 
						|
			  {
 | 
						|
			    /* C or lc can't have `a' flag, only `m' flag.  */
 | 
						|
			    done = EOF;
 | 
						|
			    goto errout;
 | 
						|
			  }
 | 
						|
			else
 | 
						|
			  {
 | 
						|
			    *strptr = (char *) wstr;
 | 
						|
			    wstr += strsize;
 | 
						|
			    ++strsize;
 | 
						|
			  }
 | 
						|
		      }
 | 
						|
		    else
 | 
						|
		      {
 | 
						|
			*strptr = (char *) wstr;
 | 
						|
			wstr += strsize;
 | 
						|
			strsize = newsize;
 | 
						|
		      }
 | 
						|
		  }
 | 
						|
 | 
						|
		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 (__glibc_unlikely (inchar () == EOF))
 | 
						|
			  encode_error ();
 | 
						|
 | 
						|
			buf[0] = c;
 | 
						|
			continue;
 | 
						|
		      }
 | 
						|
 | 
						|
		    if (__glibc_unlikely (n != 1))
 | 
						|
		      encode_error ();
 | 
						|
 | 
						|
		    /* We have a match.  */
 | 
						|
		    break;
 | 
						|
		  }
 | 
						|
 | 
						|
		/* Advance the result pointer.  */
 | 
						|
		++wstr;
 | 
						|
	      }
 | 
						|
	    while (--width > 0 && inchar () != EOF);
 | 
						|
	  }
 | 
						|
#endif
 | 
						|
 | 
						|
	  if (!(flags & SUPPRESS))
 | 
						|
	    {
 | 
						|
	      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;
 | 
						|
		}
 | 
						|
	      strptr = NULL;
 | 
						|
 | 
						|
	      ++done;
 | 
						|
	    }
 | 
						|
 | 
						|
	  break;
 | 
						|
 | 
						|
	case L_('s'):		/* Read a string.  */
 | 
						|
	  if (!(flags & LONG))
 | 
						|
	    {
 | 
						|
	      STRING_ARG (str, char, 100);
 | 
						|
 | 
						|
	      c = inchar ();
 | 
						|
	      if (__glibc_unlikely (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)
 | 
						|
			&& *strptr + strsize - str <= MB_LEN_MAX)
 | 
						|
		      {
 | 
						|
			/* We have to enlarge the buffer if the `a' or `m'
 | 
						|
			   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_LEN_MAX);
 | 
						|
			    if (newstr == NULL)
 | 
						|
			      {
 | 
						|
				if (flags & POSIX_MALLOC)
 | 
						|
				  {
 | 
						|
				    done = EOF;
 | 
						|
				    goto errout;
 | 
						|
				  }
 | 
						|
				/* We lose.  Oh well.  Terminate the
 | 
						|
				   string and stop converting,
 | 
						|
				   so at least we don't skip any input.  */
 | 
						|
				((char *) (*strptr))[strleng] = '\0';
 | 
						|
				strptr = NULL;
 | 
						|
				++done;
 | 
						|
				conv_error ();
 | 
						|
			      }
 | 
						|
			    else
 | 
						|
			      {
 | 
						|
				*strptr = newstr;
 | 
						|
				str = newstr + strleng;
 | 
						|
				strsize = strleng + MB_LEN_MAX;
 | 
						|
			      }
 | 
						|
			  }
 | 
						|
			else
 | 
						|
			  {
 | 
						|
			    *strptr = newstr;
 | 
						|
			    str = newstr + strleng;
 | 
						|
			    strsize *= 2;
 | 
						|
			  }
 | 
						|
		      }
 | 
						|
 | 
						|
		    n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c,
 | 
						|
				   &state);
 | 
						|
		    if (__glibc_unlikely (n == (size_t) -1))
 | 
						|
		      encode_error ();
 | 
						|
 | 
						|
		    assert (n <= MB_LEN_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)
 | 
						|
				{
 | 
						|
				  if (flags & POSIX_MALLOC)
 | 
						|
				    {
 | 
						|
				      done = EOF;
 | 
						|
				      goto errout;
 | 
						|
				    }
 | 
						|
				  /* We lose.  Oh well.  Terminate the
 | 
						|
				     string and stop converting,
 | 
						|
				     so at least we don't skip any input.  */
 | 
						|
				  ((char *) (*strptr))[strsize - 1] = '\0';
 | 
						|
				  strptr = NULL;
 | 
						|
				  ++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)
 | 
						|
			{
 | 
						|
			  if (flags & POSIX_MALLOC)
 | 
						|
			    {
 | 
						|
			      done = EOF;
 | 
						|
			      goto errout;
 | 
						|
			    }
 | 
						|
			  /* We lose.  Oh well.  Terminate the string
 | 
						|
			     and stop converting, so at least we don't
 | 
						|
			     skip any input.  */
 | 
						|
			  ((char *) (*strptr))[strleng] = '\0';
 | 
						|
			  strptr = NULL;
 | 
						|
			  ++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;
 | 
						|
		    }
 | 
						|
		  strptr = NULL;
 | 
						|
 | 
						|
		  ++done;
 | 
						|
		}
 | 
						|
	      break;
 | 
						|
	    }
 | 
						|
	  /* FALLTHROUGH */
 | 
						|
 | 
						|
	case L_('S'):
 | 
						|
	  {
 | 
						|
#ifndef COMPILE_WSCANF
 | 
						|
	    mbstate_t cstate;
 | 
						|
#endif
 | 
						|
 | 
						|
	    /* Wide character string.  */
 | 
						|
	    STRING_ARG (wstr, wchar_t, 100);
 | 
						|
 | 
						|
	    c = inchar ();
 | 
						|
	    if (__builtin_expect (c == EOF,  0))
 | 
						|
	      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)
 | 
						|
			      {
 | 
						|
				if (flags & POSIX_MALLOC)
 | 
						|
				  {
 | 
						|
				    done = EOF;
 | 
						|
				    goto errout;
 | 
						|
				  }
 | 
						|
				/* 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';
 | 
						|
				strptr = NULL;
 | 
						|
				++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 (__glibc_unlikely (inchar () == EOF))
 | 
						|
			    encode_error ();
 | 
						|
 | 
						|
			  buf[0] = c;
 | 
						|
			  continue;
 | 
						|
			}
 | 
						|
 | 
						|
		      if (__glibc_unlikely (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)
 | 
						|
			    {
 | 
						|
			      if (flags & POSIX_MALLOC)
 | 
						|
				{
 | 
						|
				  done = EOF;
 | 
						|
				  goto errout;
 | 
						|
				}
 | 
						|
			      /* 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';
 | 
						|
			      strptr = NULL;
 | 
						|
			      ++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;
 | 
						|
		  }
 | 
						|
		strptr = NULL;
 | 
						|
 | 
						|
		++done;
 | 
						|
	      }
 | 
						|
	  }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case L_('x'):	/* Hexadecimal integer.  */
 | 
						|
	case L_('X'):	/* Ditto.  */
 | 
						|
	  base = 16;
 | 
						|
	  goto number;
 | 
						|
 | 
						|
	case L_('o'):	/* Octal integer.  */
 | 
						|
	  base = 8;
 | 
						|
	  goto number;
 | 
						|
 | 
						|
	case L_('u'):	/* Unsigned decimal integer.  */
 | 
						|
	  base = 10;
 | 
						|
	  goto number;
 | 
						|
 | 
						|
	case L_('d'):	/* Signed decimal integer.  */
 | 
						|
	  base = 10;
 | 
						|
	  flags |= NUMBER_SIGNED;
 | 
						|
	  goto number;
 | 
						|
 | 
						|
	case L_('i'):	/* Generic number.  */
 | 
						|
	  base = 0;
 | 
						|
	  flags |= NUMBER_SIGNED;
 | 
						|
 | 
						|
	number:
 | 
						|
	  c = inchar ();
 | 
						|
	  if (__glibc_unlikely (c == EOF))
 | 
						|
	    input_error ();
 | 
						|
 | 
						|
	  /* Check for a sign.  */
 | 
						|
	  if (c == L_('-') || c == L_('+'))
 | 
						|
	    {
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	      c = inchar ();
 | 
						|
	    }
 | 
						|
 | 
						|
	  /* Look for a leading indication of base.  */
 | 
						|
	  if (width != 0 && c == L_('0'))
 | 
						|
	    {
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
 | 
						|
	      char_buffer_add (&charbuf, 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 && __builtin_expect ((flags & I18N) != 0, 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 (__glibc_unlikely (map != NULL))
 | 
						|
		{
 | 
						|
		  /*  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);
 | 
						|
 | 
						|
		      /*  And get the mbdigits + extra_digit string.  */
 | 
						|
		      *(char *) __mempcpy (__mempcpy (mb_extended, mbdigits[n],
 | 
						|
						      mbdigits_len),
 | 
						|
					   extra_mbdigit, mblen) = '\0';
 | 
						|
		      mbdigits_extended[n] = mb_extended;
 | 
						|
#endif
 | 
						|
		    }
 | 
						|
		}
 | 
						|
 | 
						|
	      /* Read the number into workspace.  */
 | 
						|
	      while (c != EOF && width != 0)
 | 
						|
		{
 | 
						|
		  /* In this round we get the pointer to the digit strings
 | 
						|
		     and also perform the first round of comparisons.  */
 | 
						|
		  for (n = 0; n < 10; ++n)
 | 
						|
		    {
 | 
						|
		      /* Get the string for the digits with value N.  */
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
 | 
						|
		      /* wcdigits_extended[] is fully set in the loop
 | 
						|
			 above, but the test for "map != NULL" is done
 | 
						|
			 inside the loop here and outside the loop there.  */
 | 
						|
		      DIAG_PUSH_NEEDS_COMMENT;
 | 
						|
		      DIAG_IGNORE_NEEDS_COMMENT (4.7, "-Wmaybe-uninitialized");
 | 
						|
 | 
						|
		      if (__glibc_unlikely (map != NULL))
 | 
						|
			wcdigits[n] = wcdigits_extended[n];
 | 
						|
		      else
 | 
						|
			wcdigits[n] = (const wchar_t *)
 | 
						|
			  _NL_CURRENT (LC_CTYPE, _NL_CTYPE_INDIGITS0_WC + n);
 | 
						|
		      wcdigits[n] += from_level;
 | 
						|
 | 
						|
		      DIAG_POP_NEEDS_COMMENT;
 | 
						|
 | 
						|
		      if (c == (wint_t) *wcdigits[n])
 | 
						|
			{
 | 
						|
			  to_level = from_level;
 | 
						|
			  break;
 | 
						|
			}
 | 
						|
 | 
						|
		      /* Advance the pointer to the next string.  */
 | 
						|
		      ++wcdigits[n];
 | 
						|
#else
 | 
						|
		      const char *cmpp;
 | 
						|
		      int avail = width > 0 ? width : INT_MAX;
 | 
						|
 | 
						|
		      if (__glibc_unlikely (map != NULL))
 | 
						|
			mbdigits[n] = mbdigits_extended[n];
 | 
						|
		      else
 | 
						|
			mbdigits[n]
 | 
						|
			  = curctype->values[_NL_CTYPE_INDIGITS0_MB + n].string;
 | 
						|
 | 
						|
		      for (level = 0; level < from_level; level++)
 | 
						|
			mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
 | 
						|
 | 
						|
		      cmpp = mbdigits[n];
 | 
						|
		      while ((unsigned char) *cmpp == c && avail >= 0)
 | 
						|
			{
 | 
						|
			  if (*++cmpp == '\0')
 | 
						|
			    break;
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      if (avail == 0 || inchar () == EOF)
 | 
						|
				break;
 | 
						|
			      --avail;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
 | 
						|
		      if (*cmpp == '\0')
 | 
						|
			{
 | 
						|
			  if (width > 0)
 | 
						|
			    width = avail;
 | 
						|
			  to_level = from_level;
 | 
						|
			  break;
 | 
						|
			}
 | 
						|
 | 
						|
		      /* We are pushing all read characters back.  */
 | 
						|
		      if (cmpp > mbdigits[n])
 | 
						|
			{
 | 
						|
			  ungetc (c, s);
 | 
						|
			  while (--cmpp > mbdigits[n])
 | 
						|
			    ungetc_not_eof ((unsigned char) *cmpp, s);
 | 
						|
			  c = (unsigned char) *cmpp;
 | 
						|
			}
 | 
						|
 | 
						|
		      /* Advance the pointer to the next string.  */
 | 
						|
		      mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
 | 
						|
#endif
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (n == 10)
 | 
						|
		    {
 | 
						|
		      /* Have not yet found the digit.  */
 | 
						|
		      for (level = from_level + 1; level <= to_level; ++level)
 | 
						|
			{
 | 
						|
			  /* Search all ten digits of this level.  */
 | 
						|
			  for (n = 0; n < 10; ++n)
 | 
						|
			    {
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
			      if (c == (wint_t) *wcdigits[n])
 | 
						|
				break;
 | 
						|
 | 
						|
			      /* Advance the pointer to the next string.  */
 | 
						|
			      ++wcdigits[n];
 | 
						|
#else
 | 
						|
			      const char *cmpp;
 | 
						|
			      int avail = width > 0 ? width : INT_MAX;
 | 
						|
 | 
						|
			      cmpp = mbdigits[n];
 | 
						|
			      while ((unsigned char) *cmpp == c && avail >= 0)
 | 
						|
				{
 | 
						|
				  if (*++cmpp == '\0')
 | 
						|
				    break;
 | 
						|
				  else
 | 
						|
				    {
 | 
						|
				      if (avail == 0 || inchar () == EOF)
 | 
						|
					break;
 | 
						|
				      --avail;
 | 
						|
				    }
 | 
						|
				}
 | 
						|
 | 
						|
			      if (*cmpp == '\0')
 | 
						|
				{
 | 
						|
				  if (width > 0)
 | 
						|
				    width = avail;
 | 
						|
				  break;
 | 
						|
				}
 | 
						|
 | 
						|
			      /* We are pushing all read characters back.  */
 | 
						|
			      if (cmpp > mbdigits[n])
 | 
						|
				{
 | 
						|
				  ungetc (c, s);
 | 
						|
				  while (--cmpp > mbdigits[n])
 | 
						|
				    ungetc_not_eof ((unsigned char) *cmpp, s);
 | 
						|
				  c = (unsigned char) *cmpp;
 | 
						|
				}
 | 
						|
 | 
						|
			      /* Advance the pointer to the next string.  */
 | 
						|
			      mbdigits[n] = strchr (mbdigits[n], '\0') + 1;
 | 
						|
#endif
 | 
						|
			    }
 | 
						|
 | 
						|
			  if (n < 10)
 | 
						|
			    {
 | 
						|
			      /* Found it.  */
 | 
						|
			      from_level = level;
 | 
						|
			      to_level = level;
 | 
						|
			      break;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (n < 10)
 | 
						|
		    c = L_('0') + n;
 | 
						|
		  else if (flags & GROUP)
 | 
						|
		    {
 | 
						|
		      /* Try matching against the thousands separator.  */
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
		      if (c != thousands)
 | 
						|
			  break;
 | 
						|
#else
 | 
						|
		      const char *cmpp = thousands;
 | 
						|
		      int avail = width > 0 ? width : INT_MAX;
 | 
						|
 | 
						|
		      while ((unsigned char) *cmpp == c && avail >= 0)
 | 
						|
			{
 | 
						|
			  char_buffer_add (&charbuf, c);
 | 
						|
			  if (*++cmpp == '\0')
 | 
						|
			    break;
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      if (avail == 0 || inchar () == EOF)
 | 
						|
				break;
 | 
						|
			      --avail;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
 | 
						|
		      if (char_buffer_error (&charbuf))
 | 
						|
			{
 | 
						|
			  __set_errno (ENOMEM);
 | 
						|
			  done = EOF;
 | 
						|
			  goto errout;
 | 
						|
			}
 | 
						|
 | 
						|
		      if (*cmpp != '\0')
 | 
						|
			{
 | 
						|
			  /* We are pushing all read characters back.  */
 | 
						|
			  if (cmpp > thousands)
 | 
						|
			    {
 | 
						|
			      charbuf.current -= cmpp - thousands;
 | 
						|
			      ungetc (c, s);
 | 
						|
			      while (--cmpp > thousands)
 | 
						|
				ungetc_not_eof ((unsigned char) *cmpp, s);
 | 
						|
			      c = (unsigned char) *cmpp;
 | 
						|
			    }
 | 
						|
			  break;
 | 
						|
			}
 | 
						|
 | 
						|
		      if (width > 0)
 | 
						|
			width = avail;
 | 
						|
 | 
						|
		      /* The last thousands character will be added back by
 | 
						|
			 the char_buffer_add below.  */
 | 
						|
		      --charbuf.current;
 | 
						|
#endif
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    break;
 | 
						|
 | 
						|
		  char_buffer_add (&charbuf, c);
 | 
						|
		  if (width > 0)
 | 
						|
		    --width;
 | 
						|
 | 
						|
		  c = inchar ();
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    /* Read the number into workspace.  */
 | 
						|
	    while (c != EOF && width != 0)
 | 
						|
	      {
 | 
						|
		if (base == 16)
 | 
						|
		  {
 | 
						|
		    if (!ISXDIGIT (c))
 | 
						|
		      break;
 | 
						|
		  }
 | 
						|
		else if (!ISDIGIT (c) || (int) (c - L_('0')) >= base)
 | 
						|
		  {
 | 
						|
		    if (base == 10 && (flags & GROUP))
 | 
						|
		      {
 | 
						|
			/* Try matching against the thousands separator.  */
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
			if (c != thousands)
 | 
						|
			  break;
 | 
						|
#else
 | 
						|
			const char *cmpp = thousands;
 | 
						|
			int avail = width > 0 ? width : INT_MAX;
 | 
						|
 | 
						|
			while ((unsigned char) *cmpp == c && avail >= 0)
 | 
						|
			  {
 | 
						|
			    char_buffer_add (&charbuf, c);
 | 
						|
			    if (*++cmpp == '\0')
 | 
						|
			      break;
 | 
						|
			    else
 | 
						|
			      {
 | 
						|
				if (avail == 0 || inchar () == EOF)
 | 
						|
				  break;
 | 
						|
				--avail;
 | 
						|
			      }
 | 
						|
			  }
 | 
						|
 | 
						|
			if (char_buffer_error (&charbuf))
 | 
						|
			  {
 | 
						|
			    __set_errno (ENOMEM);
 | 
						|
			    done = EOF;
 | 
						|
			    goto errout;
 | 
						|
			  }
 | 
						|
 | 
						|
			if (*cmpp != '\0')
 | 
						|
			  {
 | 
						|
			    /* We are pushing all read characters back.  */
 | 
						|
			    if (cmpp > thousands)
 | 
						|
			      {
 | 
						|
				charbuf.current -= cmpp - thousands;
 | 
						|
				ungetc (c, s);
 | 
						|
				while (--cmpp > thousands)
 | 
						|
				  ungetc_not_eof ((unsigned char) *cmpp, s);
 | 
						|
				c = (unsigned char) *cmpp;
 | 
						|
			      }
 | 
						|
			    break;
 | 
						|
			  }
 | 
						|
 | 
						|
			if (width > 0)
 | 
						|
			  width = avail;
 | 
						|
 | 
						|
			/* The last thousands character will be added back by
 | 
						|
			   the char_buffer_add below.  */
 | 
						|
			--charbuf.current;
 | 
						|
#endif
 | 
						|
		      }
 | 
						|
		    else
 | 
						|
		      break;
 | 
						|
		  }
 | 
						|
		char_buffer_add (&charbuf, c);
 | 
						|
		if (width > 0)
 | 
						|
		  --width;
 | 
						|
 | 
						|
		c = inchar ();
 | 
						|
	      }
 | 
						|
 | 
						|
	  if (char_buffer_error (&charbuf))
 | 
						|
	    {
 | 
						|
	      __set_errno (ENOMEM);
 | 
						|
	      done = EOF;
 | 
						|
	      goto errout;
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (char_buffer_size (&charbuf) == 0
 | 
						|
	      || (char_buffer_size (&charbuf) == 1
 | 
						|
		  && (char_buffer_start (&charbuf)[0] == L_('+')
 | 
						|
		      || char_buffer_start (&charbuf)[0] == L_('-'))))
 | 
						|
	    {
 | 
						|
	      /* There was no number.  If we are supposed to read a pointer
 | 
						|
		 we must recognize "(nil)" as well.  */
 | 
						|
	      if (__builtin_expect (char_buffer_size (&charbuf) == 0
 | 
						|
				    && (flags & READ_POINTER)
 | 
						|
				    && (width < 0 || width >= 5)
 | 
						|
				    && c == '('
 | 
						|
				    && TOLOWER (inchar ()) == L_('n')
 | 
						|
				    && TOLOWER (inchar ()) == L_('i')
 | 
						|
				    && TOLOWER (inchar ()) == L_('l')
 | 
						|
				    && inchar () == L_(')'), 1))
 | 
						|
		/* We must produce the value of a NULL pointer.  A single
 | 
						|
		   '0' digit is enough.  */
 | 
						|
		  char_buffer_add (&charbuf, L_('0'));
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  /* The last read character is not part of the number
 | 
						|
		     anymore.  */
 | 
						|
		  ungetc (c, s);
 | 
						|
 | 
						|
		  conv_error ();
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    /* The just read character is not part of the number anymore.  */
 | 
						|
	    ungetc (c, s);
 | 
						|
 | 
						|
	  /* Convert the number.  */
 | 
						|
	  char_buffer_add (&charbuf, L_('\0'));
 | 
						|
	  if (char_buffer_error (&charbuf))
 | 
						|
	    {
 | 
						|
	      __set_errno (ENOMEM);
 | 
						|
	      done = EOF;
 | 
						|
	      goto errout;
 | 
						|
	    }
 | 
						|
	  if (need_longlong && (flags & LONGDBL))
 | 
						|
	    {
 | 
						|
	      if (flags & NUMBER_SIGNED)
 | 
						|
		num.q = __strtoll_internal
 | 
						|
		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 | 
						|
	      else
 | 
						|
		num.uq = __strtoull_internal
 | 
						|
		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      if (flags & NUMBER_SIGNED)
 | 
						|
		num.l = __strtol_internal
 | 
						|
		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 | 
						|
	      else
 | 
						|
		num.ul = __strtoul_internal
 | 
						|
		  (char_buffer_start (&charbuf), &tw, base, flags & GROUP);
 | 
						|
	    }
 | 
						|
	  if (__glibc_unlikely (char_buffer_start (&charbuf) == tw))
 | 
						|
	    conv_error ();
 | 
						|
 | 
						|
	  if (!(flags & SUPPRESS))
 | 
						|
	    {
 | 
						|
	      if (flags & NUMBER_SIGNED)
 | 
						|
		{
 | 
						|
		  if (need_longlong && (flags & LONGDBL))
 | 
						|
		    *ARG (LONGLONG int *) = num.q;
 | 
						|
		  else if (need_long && (flags & LONG))
 | 
						|
		    *ARG (long int *) = num.l;
 | 
						|
		  else if (flags & SHORT)
 | 
						|
		    *ARG (short int *) = (short int) num.l;
 | 
						|
		  else if (!(flags & CHAR))
 | 
						|
		    *ARG (int *) = (int) num.l;
 | 
						|
		  else
 | 
						|
		    *ARG (signed char *) = (signed char) num.ul;
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  if (need_longlong && (flags & LONGDBL))
 | 
						|
		    *ARG (unsigned LONGLONG int *) = num.uq;
 | 
						|
		  else if (need_long && (flags & LONG))
 | 
						|
		    *ARG (unsigned long int *) = num.ul;
 | 
						|
		  else if (flags & SHORT)
 | 
						|
		    *ARG (unsigned short int *)
 | 
						|
		      = (unsigned short int) num.ul;
 | 
						|
		  else if (!(flags & CHAR))
 | 
						|
		    *ARG (unsigned int *) = (unsigned int) num.ul;
 | 
						|
		  else
 | 
						|
		    *ARG (unsigned char *) = (unsigned char) num.ul;
 | 
						|
		}
 | 
						|
	      ++done;
 | 
						|
	    }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case L_('e'):	/* Floating-point numbers.  */
 | 
						|
	case L_('E'):
 | 
						|
	case L_('f'):
 | 
						|
	case L_('F'):
 | 
						|
	case L_('g'):
 | 
						|
	case L_('G'):
 | 
						|
	case L_('a'):
 | 
						|
	case L_('A'):
 | 
						|
	  c = inchar ();
 | 
						|
	  if (width > 0)
 | 
						|
	    --width;
 | 
						|
	  if (__glibc_unlikely (c == EOF))
 | 
						|
	    input_error ();
 | 
						|
 | 
						|
	  got_digit = got_dot = got_e = 0;
 | 
						|
 | 
						|
	  /* Check for a sign.  */
 | 
						|
	  if (c == L_('-') || c == L_('+'))
 | 
						|
	    {
 | 
						|
	      negative = c == L_('-');
 | 
						|
	      if (__glibc_unlikely (width == 0 || inchar () == EOF))
 | 
						|
		/* EOF is only an input error before we read any chars.  */
 | 
						|
		conv_error ();
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    negative = 0;
 | 
						|
 | 
						|
	  /* Take care for the special arguments "nan" and "inf".  */
 | 
						|
	  if (TOLOWER (c) == L_('n'))
 | 
						|
	    {
 | 
						|
	      /* Maybe "nan".  */
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      if (__builtin_expect (width == 0
 | 
						|
				    || inchar () == EOF
 | 
						|
				    || TOLOWER (c) != L_('a'), 0))
 | 
						|
		conv_error ();
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      if (__builtin_expect (width == 0
 | 
						|
				    || inchar () == EOF
 | 
						|
				    || TOLOWER (c) != L_('n'), 0))
 | 
						|
		conv_error ();
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      /* It is "nan".  */
 | 
						|
	      goto scan_float;
 | 
						|
	    }
 | 
						|
	  else if (TOLOWER (c) == L_('i'))
 | 
						|
	    {
 | 
						|
	      /* Maybe "inf" or "infinity".  */
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      if (__builtin_expect (width == 0
 | 
						|
				    || inchar () == EOF
 | 
						|
				    || TOLOWER (c) != L_('n'), 0))
 | 
						|
		conv_error ();
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      if (__builtin_expect (width == 0
 | 
						|
				    || inchar () == EOF
 | 
						|
				    || TOLOWER (c) != L_('f'), 0))
 | 
						|
		conv_error ();
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      /* It is as least "inf".  */
 | 
						|
	      if (width != 0 && inchar () != EOF)
 | 
						|
		{
 | 
						|
		  if (TOLOWER (c) == L_('i'))
 | 
						|
		    {
 | 
						|
		      if (width > 0)
 | 
						|
			--width;
 | 
						|
		      /* Now we have to read the rest as well.  */
 | 
						|
		      char_buffer_add (&charbuf, c);
 | 
						|
		      if (__builtin_expect (width == 0
 | 
						|
					    || inchar () == EOF
 | 
						|
					    || TOLOWER (c) != L_('n'), 0))
 | 
						|
			conv_error ();
 | 
						|
		      if (width > 0)
 | 
						|
			--width;
 | 
						|
		      char_buffer_add (&charbuf, c);
 | 
						|
		      if (__builtin_expect (width == 0
 | 
						|
					    || inchar () == EOF
 | 
						|
					    || TOLOWER (c) != L_('i'), 0))
 | 
						|
			conv_error ();
 | 
						|
		      if (width > 0)
 | 
						|
			--width;
 | 
						|
		      char_buffer_add (&charbuf, c);
 | 
						|
		      if (__builtin_expect (width == 0
 | 
						|
					    || inchar () == EOF
 | 
						|
					    || TOLOWER (c) != L_('t'), 0))
 | 
						|
			conv_error ();
 | 
						|
		      if (width > 0)
 | 
						|
			--width;
 | 
						|
		      char_buffer_add (&charbuf, c);
 | 
						|
		      if (__builtin_expect (width == 0
 | 
						|
					    || inchar () == EOF
 | 
						|
					    || TOLOWER (c) != L_('y'), 0))
 | 
						|
			conv_error ();
 | 
						|
		      if (width > 0)
 | 
						|
			--width;
 | 
						|
		      char_buffer_add (&charbuf, c);
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    /* Never mind.  */
 | 
						|
		    ungetc (c, s);
 | 
						|
		}
 | 
						|
	      goto scan_float;
 | 
						|
	    }
 | 
						|
 | 
						|
	  exp_char = L_('e');
 | 
						|
	  if (width != 0 && c == L_('0'))
 | 
						|
	    {
 | 
						|
	      char_buffer_add (&charbuf, c);
 | 
						|
	      c = inchar ();
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	      if (width != 0 && TOLOWER (c) == L_('x'))
 | 
						|
		{
 | 
						|
		  /* It is a number in hexadecimal format.  */
 | 
						|
		  char_buffer_add (&charbuf, c);
 | 
						|
 | 
						|
		  flags |= HEXA_FLOAT;
 | 
						|
		  exp_char = L_('p');
 | 
						|
 | 
						|
		  /* Grouping is not allowed.  */
 | 
						|
		  flags &= ~GROUP;
 | 
						|
		  c = inchar ();
 | 
						|
		  if (width > 0)
 | 
						|
		    --width;
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		got_digit = 1;
 | 
						|
	    }
 | 
						|
 | 
						|
	  while (1)
 | 
						|
	    {
 | 
						|
	      if (char_buffer_error (&charbuf))
 | 
						|
		{
 | 
						|
		  __set_errno (ENOMEM);
 | 
						|
		  done = EOF;
 | 
						|
		  goto errout;
 | 
						|
		}
 | 
						|
	      if (ISDIGIT (c))
 | 
						|
		{
 | 
						|
		  char_buffer_add (&charbuf, c);
 | 
						|
		  got_digit = 1;
 | 
						|
		}
 | 
						|
	      else if (!got_e && (flags & HEXA_FLOAT) && ISXDIGIT (c))
 | 
						|
		{
 | 
						|
		  char_buffer_add (&charbuf, c);
 | 
						|
		  got_digit = 1;
 | 
						|
		}
 | 
						|
	      else if (got_e && charbuf.current[-1] == exp_char
 | 
						|
		       && (c == L_('-') || c == L_('+')))
 | 
						|
		char_buffer_add (&charbuf, c);
 | 
						|
	      else if (got_digit && !got_e
 | 
						|
		       && (CHAR_T) TOLOWER (c) == exp_char)
 | 
						|
		{
 | 
						|
		  char_buffer_add (&charbuf, exp_char);
 | 
						|
		  got_e = got_dot = 1;
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
		  if (! got_dot && c == decimal)
 | 
						|
		    {
 | 
						|
		      char_buffer_add (&charbuf, c);
 | 
						|
		      got_dot = 1;
 | 
						|
		    }
 | 
						|
		  else if ((flags & GROUP) != 0 && ! got_dot && c == thousands)
 | 
						|
		    char_buffer_add (&charbuf, c);
 | 
						|
		  else
 | 
						|
		    {
 | 
						|
		      /* The last read character is not part of the number
 | 
						|
			 anymore.  */
 | 
						|
		      ungetc (c, s);
 | 
						|
		      break;
 | 
						|
		    }
 | 
						|
#else
 | 
						|
		  const char *cmpp = decimal;
 | 
						|
		  int avail = width > 0 ? width : INT_MAX;
 | 
						|
 | 
						|
		  if (! got_dot)
 | 
						|
		    {
 | 
						|
		      while ((unsigned char) *cmpp == c && avail >= 0)
 | 
						|
			if (*++cmpp == '\0')
 | 
						|
			  break;
 | 
						|
			else
 | 
						|
			  {
 | 
						|
			    if (avail == 0 || inchar () == EOF)
 | 
						|
			      break;
 | 
						|
			    --avail;
 | 
						|
			  }
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (*cmpp == '\0')
 | 
						|
		    {
 | 
						|
		      /* Add all the characters.  */
 | 
						|
		      for (cmpp = decimal; *cmpp != '\0'; ++cmpp)
 | 
						|
			char_buffer_add (&charbuf, (unsigned char) *cmpp);
 | 
						|
		      if (width > 0)
 | 
						|
			width = avail;
 | 
						|
		      got_dot = 1;
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    {
 | 
						|
		      /* Figure out whether it is a thousands separator.
 | 
						|
			 There is one problem: we possibly read more than
 | 
						|
			 one character.  We cannot push them back but since
 | 
						|
			 we know that parts of the `decimal' string matched,
 | 
						|
			 we can compare against it.  */
 | 
						|
		      const char *cmp2p = thousands;
 | 
						|
 | 
						|
		      if ((flags & GROUP) != 0 && ! got_dot)
 | 
						|
			{
 | 
						|
			  while (cmp2p - thousands < cmpp - decimal
 | 
						|
				 && *cmp2p == decimal[cmp2p - thousands])
 | 
						|
			    ++cmp2p;
 | 
						|
			  if (cmp2p - thousands == cmpp - decimal)
 | 
						|
			    {
 | 
						|
			      while ((unsigned char) *cmp2p == c && avail >= 0)
 | 
						|
				if (*++cmp2p == '\0')
 | 
						|
				  break;
 | 
						|
				else
 | 
						|
				  {
 | 
						|
				    if (avail == 0 || inchar () == EOF)
 | 
						|
				      break;
 | 
						|
				    --avail;
 | 
						|
				  }
 | 
						|
			    }
 | 
						|
			}
 | 
						|
 | 
						|
		      if (cmp2p != NULL && *cmp2p == '\0')
 | 
						|
			{
 | 
						|
			  /* Add all the characters.  */
 | 
						|
			  for (cmpp = thousands; *cmpp != '\0'; ++cmpp)
 | 
						|
			    char_buffer_add (&charbuf, (unsigned char) *cmpp);
 | 
						|
			  if (width > 0)
 | 
						|
			    width = avail;
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			{
 | 
						|
			  /* The last read character is not part of the number
 | 
						|
			     anymore.  */
 | 
						|
			  ungetc (c, s);
 | 
						|
			  break;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
#endif
 | 
						|
		}
 | 
						|
 | 
						|
	      if (width == 0 || inchar () == EOF)
 | 
						|
		break;
 | 
						|
 | 
						|
	      if (width > 0)
 | 
						|
		--width;
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (char_buffer_error (&charbuf))
 | 
						|
	    {
 | 
						|
	      __set_errno (ENOMEM);
 | 
						|
	      done = EOF;
 | 
						|
	      goto errout;
 | 
						|
	    }
 | 
						|
 | 
						|
	  wctrans_t map;
 | 
						|
	  if (__builtin_expect ((flags & I18N) != 0, 0)
 | 
						|
	      /* Hexadecimal floats make no sense, fixing localized
 | 
						|
		 digits with ASCII letters.  */
 | 
						|
	      && !(flags & HEXA_FLOAT)
 | 
						|
	      /* Minimum requirement.  */
 | 
						|
	      && (char_buffer_size (&charbuf) == 0 || got_dot)
 | 
						|
	      && (map = __wctrans ("to_inpunct")) != NULL)
 | 
						|
	    {
 | 
						|
	      /* Reget the first character.  */
 | 
						|
	      inchar ();
 | 
						|
 | 
						|
	      /* Localized digits, decimal points, and thousands
 | 
						|
		 separator.  */
 | 
						|
	      wint_t wcdigits[12];
 | 
						|
 | 
						|
	      /* First get decimal equivalent to check if we read it
 | 
						|
		 or not.  */
 | 
						|
	      wcdigits[11] = __towctrans (L'.', map);
 | 
						|
 | 
						|
	      /* If we have not read any character or have just read
 | 
						|
		 locale decimal point which matches the decimal point
 | 
						|
		 for localized FP numbers, then we may have localized
 | 
						|
		 digits.  Note, we test GOT_DOT above.  */
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
	      if (char_buffer_size (&charbuf) == 0
 | 
						|
		  || (char_buffer_size (&charbuf) == 1
 | 
						|
		      && wcdigits[11] == decimal))
 | 
						|
#else
 | 
						|
	      char mbdigits[12][MB_LEN_MAX + 1];
 | 
						|
 | 
						|
	      mbstate_t state;
 | 
						|
	      memset (&state, '\0', sizeof (state));
 | 
						|
 | 
						|
	      bool match_so_far = char_buffer_size (&charbuf) == 0;
 | 
						|
	      size_t mblen = __wcrtomb (mbdigits[11], wcdigits[11], &state);
 | 
						|
	      if (mblen != (size_t) -1)
 | 
						|
		{
 | 
						|
		  mbdigits[11][mblen] = '\0';
 | 
						|
		  match_so_far |=
 | 
						|
		    (char_buffer_size (&charbuf) == strlen (decimal)
 | 
						|
		     && strcmp (decimal, mbdigits[11]) == 0);
 | 
						|
		}
 | 
						|
	      else
 | 
						|
		{
 | 
						|
		  size_t decimal_len = strlen (decimal);
 | 
						|
		  /* This should always be the case but the data comes
 | 
						|
		     from a file.  */
 | 
						|
		  if (decimal_len <= MB_LEN_MAX)
 | 
						|
		    {
 | 
						|
		      match_so_far |= char_buffer_size (&charbuf) == decimal_len;
 | 
						|
		      memcpy (mbdigits[11], decimal, decimal_len + 1);
 | 
						|
		    }
 | 
						|
		  else
 | 
						|
		    match_so_far = false;
 | 
						|
		}
 | 
						|
 | 
						|
	      if (match_so_far)
 | 
						|
#endif
 | 
						|
		{
 | 
						|
		  bool have_locthousands = (flags & GROUP) != 0;
 | 
						|
 | 
						|
		  /* Now get the digits and the thousands-sep equivalents.  */
 | 
						|
		  for (int n = 0; n < 11; ++n)
 | 
						|
		    {
 | 
						|
		      if (n < 10)
 | 
						|
			wcdigits[n] = __towctrans (L'0' + n, map);
 | 
						|
		      else if (n == 10)
 | 
						|
			{
 | 
						|
			  wcdigits[10] = __towctrans (L',', map);
 | 
						|
			  have_locthousands &= wcdigits[10] != L'\0';
 | 
						|
			}
 | 
						|
 | 
						|
#ifndef COMPILE_WSCANF
 | 
						|
		      memset (&state, '\0', sizeof (state));
 | 
						|
 | 
						|
		      size_t mblen = __wcrtomb (mbdigits[n], wcdigits[n],
 | 
						|
						&state);
 | 
						|
		      if (mblen == (size_t) -1)
 | 
						|
			{
 | 
						|
			  if (n == 10)
 | 
						|
			    {
 | 
						|
			      if (have_locthousands)
 | 
						|
				{
 | 
						|
				  size_t thousands_len = strlen (thousands);
 | 
						|
				  if (thousands_len <= MB_LEN_MAX)
 | 
						|
				    memcpy (mbdigits[10], thousands,
 | 
						|
					    thousands_len + 1);
 | 
						|
				  else
 | 
						|
				    have_locthousands = false;
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    /* Ignore checking against localized digits.  */
 | 
						|
			    goto no_i18nflt;
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			mbdigits[n][mblen] = '\0';
 | 
						|
#endif
 | 
						|
		    }
 | 
						|
 | 
						|
		  /* Start checking against localized digits, if
 | 
						|
		     conversion is done correctly. */
 | 
						|
		  while (1)
 | 
						|
		    {
 | 
						|
		      if (char_buffer_error (&charbuf))
 | 
						|
			{
 | 
						|
			  __set_errno (ENOMEM);
 | 
						|
			  done = EOF;
 | 
						|
			  goto errout;
 | 
						|
			}
 | 
						|
		      if (got_e && charbuf.current[-1] == exp_char
 | 
						|
			  && (c == L_('-') || c == L_('+')))
 | 
						|
			char_buffer_add (&charbuf, c);
 | 
						|
		      else if (char_buffer_size (&charbuf) > 0 && !got_e
 | 
						|
			       && (CHAR_T) TOLOWER (c) == exp_char)
 | 
						|
			{
 | 
						|
			  char_buffer_add (&charbuf, exp_char);
 | 
						|
			  got_e = got_dot = 1;
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			{
 | 
						|
			  /* Check against localized digits, decimal point,
 | 
						|
			     and thousands separator.  */
 | 
						|
			  int n;
 | 
						|
			  for (n = 0; n < 12; ++n)
 | 
						|
			    {
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
			      if (c == wcdigits[n])
 | 
						|
				{
 | 
						|
				  if (n < 10)
 | 
						|
				    char_buffer_add (&charbuf, L_('0') + n);
 | 
						|
				  else if (n == 11 && !got_dot)
 | 
						|
				    {
 | 
						|
				      char_buffer_add (&charbuf, decimal);
 | 
						|
				      got_dot = 1;
 | 
						|
				    }
 | 
						|
				  else if (n == 10 && have_locthousands
 | 
						|
					   && ! got_dot)
 | 
						|
				    char_buffer_add (&charbuf, thousands);
 | 
						|
				  else
 | 
						|
				    /* The last read character is not part
 | 
						|
				       of the number anymore.  */
 | 
						|
				    n = 12;
 | 
						|
 | 
						|
				  break;
 | 
						|
				}
 | 
						|
#else
 | 
						|
			      const char *cmpp = mbdigits[n];
 | 
						|
			      int avail = width > 0 ? width : INT_MAX;
 | 
						|
 | 
						|
			      while ((unsigned char) *cmpp == c && avail >= 0)
 | 
						|
				if (*++cmpp == '\0')
 | 
						|
				  break;
 | 
						|
				else
 | 
						|
				  {
 | 
						|
				    if (avail == 0 || inchar () == EOF)
 | 
						|
				      break;
 | 
						|
				    --avail;
 | 
						|
				  }
 | 
						|
			      if (*cmpp == '\0')
 | 
						|
				{
 | 
						|
				  if (width > 0)
 | 
						|
				    width = avail;
 | 
						|
 | 
						|
				  if (n < 10)
 | 
						|
				    char_buffer_add (&charbuf, L_('0') + n);
 | 
						|
				  else if (n == 11 && !got_dot)
 | 
						|
				    {
 | 
						|
				      /* Add all the characters.  */
 | 
						|
				      for (cmpp = decimal; *cmpp != '\0';
 | 
						|
					   ++cmpp)
 | 
						|
					char_buffer_add (&charbuf,
 | 
						|
							 (unsigned char) *cmpp);
 | 
						|
 | 
						|
				      got_dot = 1;
 | 
						|
				    }
 | 
						|
				  else if (n == 10 && (flags & GROUP) != 0
 | 
						|
					   && ! got_dot)
 | 
						|
				    {
 | 
						|
				      /* Add all the characters.  */
 | 
						|
				      for (cmpp = thousands; *cmpp != '\0';
 | 
						|
					   ++cmpp)
 | 
						|
					char_buffer_add (&charbuf,
 | 
						|
							 (unsigned char) *cmpp);
 | 
						|
				    }
 | 
						|
				  else
 | 
						|
				    /* The last read character is not part
 | 
						|
				       of the number anymore.  */
 | 
						|
				      n = 12;
 | 
						|
 | 
						|
				  break;
 | 
						|
				}
 | 
						|
 | 
						|
			      /* We are pushing all read characters back.  */
 | 
						|
			      if (cmpp > mbdigits[n])
 | 
						|
				{
 | 
						|
				  ungetc (c, s);
 | 
						|
				  while (--cmpp > mbdigits[n])
 | 
						|
				    ungetc_not_eof ((unsigned char) *cmpp, s);
 | 
						|
				  c = (unsigned char) *cmpp;
 | 
						|
				}
 | 
						|
#endif
 | 
						|
			    }
 | 
						|
 | 
						|
			  if (n >= 12)
 | 
						|
			    {
 | 
						|
			      /* The last read character is not part
 | 
						|
				 of the number anymore.  */
 | 
						|
			      ungetc (c, s);
 | 
						|
			      break;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
 | 
						|
		      if (width == 0 || inchar () == EOF)
 | 
						|
			break;
 | 
						|
 | 
						|
		      if (width > 0)
 | 
						|
			--width;
 | 
						|
		    }
 | 
						|
		}
 | 
						|
 | 
						|
#ifndef COMPILE_WSCANF
 | 
						|
	    no_i18nflt:
 | 
						|
	      ;
 | 
						|
#endif
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (char_buffer_error (&charbuf))
 | 
						|
	    {
 | 
						|
	      __set_errno (ENOMEM);
 | 
						|
	      done = EOF;
 | 
						|
	      goto errout;
 | 
						|
	    }
 | 
						|
 | 
						|
	  /* Have we read any character?  If we try to read a number
 | 
						|
	     in hexadecimal notation and we have read only the `0x'
 | 
						|
	     prefix this is an error.  */
 | 
						|
	  if (__glibc_unlikely (char_buffer_size (&charbuf) == 0
 | 
						|
				|| ((flags & HEXA_FLOAT)
 | 
						|
				    && char_buffer_size (&charbuf) == 2)))
 | 
						|
	    conv_error ();
 | 
						|
 | 
						|
	scan_float:
 | 
						|
	  /* Convert the number.  */
 | 
						|
	  char_buffer_add (&charbuf, L_('\0'));
 | 
						|
	  if (char_buffer_error (&charbuf))
 | 
						|
	    {
 | 
						|
	      __set_errno (ENOMEM);
 | 
						|
	      done = EOF;
 | 
						|
	      goto errout;
 | 
						|
	    }
 | 
						|
	  if ((flags & LONGDBL) && !__ldbl_is_dbl)
 | 
						|
	    {
 | 
						|
	      long double d = __strtold_internal
 | 
						|
		(char_buffer_start (&charbuf), &tw, flags & GROUP);
 | 
						|
	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
 | 
						|
		*ARG (long double *) = negative ? -d : d;
 | 
						|
	    }
 | 
						|
	  else if (flags & (LONG | LONGDBL))
 | 
						|
	    {
 | 
						|
	      double d = __strtod_internal
 | 
						|
		(char_buffer_start (&charbuf), &tw, flags & GROUP);
 | 
						|
	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
 | 
						|
		*ARG (double *) = negative ? -d : d;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      float d = __strtof_internal
 | 
						|
		(char_buffer_start (&charbuf), &tw, flags & GROUP);
 | 
						|
	      if (!(flags & SUPPRESS) && tw != char_buffer_start (&charbuf))
 | 
						|
		*ARG (float *) = negative ? -d : d;
 | 
						|
	    }
 | 
						|
 | 
						|
	  if (__glibc_unlikely (tw == char_buffer_start (&charbuf)))
 | 
						|
	    conv_error ();
 | 
						|
 | 
						|
	  if (!(flags & SUPPRESS))
 | 
						|
	    ++done;
 | 
						|
	  break;
 | 
						|
 | 
						|
	case L_('['):	/* Character class.  */
 | 
						|
	  if (flags & LONG)
 | 
						|
	    STRING_ARG (wstr, wchar_t, 100);
 | 
						|
	  else
 | 
						|
	    STRING_ARG (str, char, 100);
 | 
						|
 | 
						|
	  if (*f == L_('^'))
 | 
						|
	    {
 | 
						|
	      ++f;
 | 
						|
	      not_in = 1;
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    not_in = 0;
 | 
						|
 | 
						|
	  if (width < 0)
 | 
						|
	    /* There is no width given so there is also no limit on the
 | 
						|
	       number of characters we read.  Therefore we set width to
 | 
						|
	       a very high value to make the algorithm easier.  */
 | 
						|
	    width = INT_MAX;
 | 
						|
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
	  /* Find the beginning and the end of the scanlist.  We are not
 | 
						|
	     creating a lookup table since it would have to be too large.
 | 
						|
	     Instead we search each time through the string.  This is not
 | 
						|
	     a constant lookup time but who uses this feature deserves to
 | 
						|
	     be punished.  */
 | 
						|
	  tw = (wchar_t *) f;	/* Marks the beginning.  */
 | 
						|
 | 
						|
	  if (*f == L']')
 | 
						|
	    ++f;
 | 
						|
 | 
						|
	  while ((fc = *f++) != L'\0' && fc != L']');
 | 
						|
 | 
						|
	  if (__glibc_unlikely (fc == L'\0'))
 | 
						|
	    conv_error ();
 | 
						|
	  wchar_t *twend = (wchar_t *) f - 1;
 | 
						|
#else
 | 
						|
	  /* Fill WP with byte flags indexed by character.
 | 
						|
	     We will use this flag map for matching input characters.  */
 | 
						|
	  if (!scratch_buffer_set_array_size
 | 
						|
	      (&charbuf.scratch, UCHAR_MAX + 1, 1))
 | 
						|
	    {
 | 
						|
	      done = EOF;
 | 
						|
	      goto errout;
 | 
						|
	    }
 | 
						|
	  memset (charbuf.scratch.data, '\0', UCHAR_MAX + 1);
 | 
						|
 | 
						|
	  fc = *f;
 | 
						|
	  if (fc == ']' || fc == '-')
 | 
						|
	    {
 | 
						|
	      /* If ] or - appears before any char in the set, it is not
 | 
						|
		 the terminator or separator, but the first char in the
 | 
						|
		 set.  */
 | 
						|
	      ((char *)charbuf.scratch.data)[fc] = 1;
 | 
						|
	      ++f;
 | 
						|
	    }
 | 
						|
 | 
						|
	  while ((fc = *f++) != '\0' && fc != ']')
 | 
						|
	    if (fc == '-' && *f != '\0' && *f != ']'
 | 
						|
		&& (unsigned char) f[-2] <= (unsigned char) *f)
 | 
						|
	      {
 | 
						|
		/* Add all characters from the one before the '-'
 | 
						|
		   up to (but not including) the next format char.  */
 | 
						|
		for (fc = (unsigned char) f[-2]; fc < (unsigned char) *f; ++fc)
 | 
						|
		  ((char *)charbuf.scratch.data)[fc] = 1;
 | 
						|
	      }
 | 
						|
	    else
 | 
						|
	      /* Add the character to the flag map.  */
 | 
						|
	      ((char *)charbuf.scratch.data)[fc] = 1;
 | 
						|
 | 
						|
	  if (__glibc_unlikely (fc == '\0'))
 | 
						|
	    conv_error();
 | 
						|
#endif
 | 
						|
 | 
						|
	  if (flags & LONG)
 | 
						|
	    {
 | 
						|
	      size_t now = read_in;
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
	      if (__glibc_unlikely (inchar () == WEOF))
 | 
						|
		input_error ();
 | 
						|
 | 
						|
	      do
 | 
						|
		{
 | 
						|
		  wchar_t *runp;
 | 
						|
 | 
						|
		  /* Test whether it's in the scanlist.  */
 | 
						|
		  runp = tw;
 | 
						|
		  while (runp < twend)
 | 
						|
		    {
 | 
						|
		      if (runp[0] == L'-' && runp[1] != '\0'
 | 
						|
			  && runp + 1 != twend
 | 
						|
			  && runp != tw
 | 
						|
			  && (unsigned int) runp[-1] <= (unsigned int) runp[1])
 | 
						|
			{
 | 
						|
			  /* Match against all characters in between the
 | 
						|
			     first and last character of the sequence.  */
 | 
						|
			  wchar_t wc;
 | 
						|
 | 
						|
			  for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
 | 
						|
			    if ((wint_t) wc == c)
 | 
						|
			      break;
 | 
						|
 | 
						|
			  if (wc <= runp[1] && !not_in)
 | 
						|
			    break;
 | 
						|
			  if (wc <= runp[1] && not_in)
 | 
						|
			    {
 | 
						|
			      /* The current character is not in the
 | 
						|
				 scanset.  */
 | 
						|
			      ungetc (c, s);
 | 
						|
			      goto out;
 | 
						|
			    }
 | 
						|
 | 
						|
			  runp += 2;
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			{
 | 
						|
			  if ((wint_t) *runp == c && !not_in)
 | 
						|
			    break;
 | 
						|
			  if ((wint_t) *runp == c && not_in)
 | 
						|
			    {
 | 
						|
			      ungetc (c, s);
 | 
						|
			      goto out;
 | 
						|
			    }
 | 
						|
 | 
						|
			  ++runp;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (runp == twend && !not_in)
 | 
						|
		    {
 | 
						|
		      ungetc (c, s);
 | 
						|
		      goto out;
 | 
						|
		    }
 | 
						|
 | 
						|
		  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)
 | 
						|
				{
 | 
						|
				  if (flags & POSIX_MALLOC)
 | 
						|
				    {
 | 
						|
				      done = EOF;
 | 
						|
				      goto errout;
 | 
						|
				    }
 | 
						|
				  /* 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';
 | 
						|
				  strptr = NULL;
 | 
						|
				  ++done;
 | 
						|
				  conv_error ();
 | 
						|
				}
 | 
						|
			      else
 | 
						|
				{
 | 
						|
				  *strptr = (char *) wstr;
 | 
						|
				  wstr += strsize;
 | 
						|
				  ++strsize;
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = (char *) wstr;
 | 
						|
			      wstr += strsize;
 | 
						|
			      strsize *= 2;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      while (--width > 0 && inchar () != WEOF);
 | 
						|
	    out:
 | 
						|
#else
 | 
						|
	      char buf[MB_LEN_MAX];
 | 
						|
	      size_t cnt = 0;
 | 
						|
	      mbstate_t cstate;
 | 
						|
 | 
						|
	      if (__glibc_unlikely (inchar () == EOF))
 | 
						|
		input_error ();
 | 
						|
 | 
						|
	      memset (&cstate, '\0', sizeof (cstate));
 | 
						|
 | 
						|
	      do
 | 
						|
		{
 | 
						|
		  if (((char *) charbuf.scratch.data)[c] == not_in)
 | 
						|
		    {
 | 
						|
		      ungetc_not_eof (c, s);
 | 
						|
		      break;
 | 
						|
		    }
 | 
						|
 | 
						|
		  /* This is easy.  */
 | 
						|
		  if (!(flags & SUPPRESS))
 | 
						|
		    {
 | 
						|
		      size_t n;
 | 
						|
 | 
						|
		      /* Convert it into a wide character.  */
 | 
						|
		      buf[0] = c;
 | 
						|
		      n = __mbrtowc (wstr, buf, 1, &cstate);
 | 
						|
 | 
						|
		      if (n == (size_t) -2)
 | 
						|
			{
 | 
						|
			  /* Possibly correct character, just not enough
 | 
						|
			     input.  */
 | 
						|
			  ++cnt;
 | 
						|
			  assert (cnt < MB_LEN_MAX);
 | 
						|
			  continue;
 | 
						|
			}
 | 
						|
		      cnt = 0;
 | 
						|
 | 
						|
		      ++wstr;
 | 
						|
		      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)
 | 
						|
				{
 | 
						|
				  if (flags & POSIX_MALLOC)
 | 
						|
				    {
 | 
						|
				      done = EOF;
 | 
						|
				      goto errout;
 | 
						|
				    }
 | 
						|
				  /* 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';
 | 
						|
				  strptr = NULL;
 | 
						|
				  ++done;
 | 
						|
				  conv_error ();
 | 
						|
				}
 | 
						|
			      else
 | 
						|
				{
 | 
						|
				  *strptr = (char *) wstr;
 | 
						|
				  wstr += strsize;
 | 
						|
				  ++strsize;
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = (char *) wstr;
 | 
						|
			      wstr += strsize;
 | 
						|
			      strsize *= 2;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (--width <= 0)
 | 
						|
		    break;
 | 
						|
		}
 | 
						|
	      while (inchar () != EOF);
 | 
						|
 | 
						|
	      if (__glibc_unlikely (cnt != 0))
 | 
						|
		/* We stopped in the middle of recognizing another
 | 
						|
		   character.  That's a problem.  */
 | 
						|
		encode_error ();
 | 
						|
#endif
 | 
						|
 | 
						|
	      if (__glibc_unlikely (now == read_in))
 | 
						|
		/* We haven't succesfully read any character.  */
 | 
						|
		conv_error ();
 | 
						|
 | 
						|
	      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;
 | 
						|
		    }
 | 
						|
		  strptr = NULL;
 | 
						|
 | 
						|
		  ++done;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  else
 | 
						|
	    {
 | 
						|
	      size_t now = read_in;
 | 
						|
 | 
						|
	      if (__glibc_unlikely (inchar () == EOF))
 | 
						|
		input_error ();
 | 
						|
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
 | 
						|
	      memset (&state, '\0', sizeof (state));
 | 
						|
 | 
						|
	      do
 | 
						|
		{
 | 
						|
		  wchar_t *runp;
 | 
						|
		  size_t n;
 | 
						|
 | 
						|
		  /* Test whether it's in the scanlist.  */
 | 
						|
		  runp = tw;
 | 
						|
		  while (runp < twend)
 | 
						|
		    {
 | 
						|
		      if (runp[0] == L'-' && runp[1] != '\0'
 | 
						|
			  && runp + 1 != twend
 | 
						|
			  && runp != tw
 | 
						|
			  && (unsigned int) runp[-1] <= (unsigned int) runp[1])
 | 
						|
			{
 | 
						|
			  /* Match against all characters in between the
 | 
						|
			     first and last character of the sequence.  */
 | 
						|
			  wchar_t wc;
 | 
						|
 | 
						|
			  for (wc = runp[-1] + 1; wc <= runp[1]; ++wc)
 | 
						|
			    if ((wint_t) wc == c)
 | 
						|
			      break;
 | 
						|
 | 
						|
			  if (wc <= runp[1] && !not_in)
 | 
						|
			    break;
 | 
						|
			  if (wc <= runp[1] && not_in)
 | 
						|
			    {
 | 
						|
			      /* The current character is not in the
 | 
						|
				 scanset.  */
 | 
						|
			      ungetc (c, s);
 | 
						|
			      goto out2;
 | 
						|
			    }
 | 
						|
 | 
						|
			  runp += 2;
 | 
						|
			}
 | 
						|
		      else
 | 
						|
			{
 | 
						|
			  if ((wint_t) *runp == c && !not_in)
 | 
						|
			    break;
 | 
						|
			  if ((wint_t) *runp == c && not_in)
 | 
						|
			    {
 | 
						|
			      ungetc (c, s);
 | 
						|
			      goto out2;
 | 
						|
			    }
 | 
						|
 | 
						|
			  ++runp;
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (runp == twend && !not_in)
 | 
						|
		    {
 | 
						|
		      ungetc (c, s);
 | 
						|
		      goto out2;
 | 
						|
		    }
 | 
						|
 | 
						|
		  if (!(flags & SUPPRESS))
 | 
						|
		    {
 | 
						|
		      if ((flags & MALLOC)
 | 
						|
			  && *strptr + strsize - str <= MB_LEN_MAX)
 | 
						|
			{
 | 
						|
			  /* Enlarge the buffer.  */
 | 
						|
			  size_t strleng = str - *strptr;
 | 
						|
			  char *newstr;
 | 
						|
 | 
						|
			  newstr = (char *) realloc (*strptr, 2 * strsize);
 | 
						|
			  if (newstr == NULL)
 | 
						|
			    {
 | 
						|
			      /* Can't allocate that much.  Last-ditch
 | 
						|
				 effort.  */
 | 
						|
			      newstr = (char *) realloc (*strptr,
 | 
						|
							 strleng + MB_LEN_MAX);
 | 
						|
			      if (newstr == NULL)
 | 
						|
				{
 | 
						|
				  if (flags & POSIX_MALLOC)
 | 
						|
				    {
 | 
						|
				      done = EOF;
 | 
						|
				      goto errout;
 | 
						|
				    }
 | 
						|
				  /* We lose.  Oh well.  Terminate the string
 | 
						|
				     and stop converting, so at least we don't
 | 
						|
				     skip any input.  */
 | 
						|
				  ((char *) (*strptr))[strleng] = '\0';
 | 
						|
				  strptr = NULL;
 | 
						|
				  ++done;
 | 
						|
				  conv_error ();
 | 
						|
				}
 | 
						|
			      else
 | 
						|
				{
 | 
						|
				  *strptr = newstr;
 | 
						|
				  str = newstr + strleng;
 | 
						|
				  strsize = strleng + MB_LEN_MAX;
 | 
						|
				}
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = newstr;
 | 
						|
			      str = newstr + strleng;
 | 
						|
			      strsize *= 2;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		    }
 | 
						|
 | 
						|
		  n = __wcrtomb (!(flags & SUPPRESS) ? str : NULL, c, &state);
 | 
						|
		  if (__glibc_unlikely (n == (size_t) -1))
 | 
						|
		    encode_error ();
 | 
						|
 | 
						|
		  assert (n <= MB_LEN_MAX);
 | 
						|
		  str += n;
 | 
						|
		}
 | 
						|
	      while (--width > 0 && inchar () != WEOF);
 | 
						|
	    out2:
 | 
						|
#else
 | 
						|
	      do
 | 
						|
		{
 | 
						|
		  if (((char *) charbuf.scratch.data)[c] == not_in)
 | 
						|
		    {
 | 
						|
		      ungetc_not_eof (c, s);
 | 
						|
		      break;
 | 
						|
		    }
 | 
						|
 | 
						|
		  /* This is easy.  */
 | 
						|
		  if (!(flags & SUPPRESS))
 | 
						|
		    {
 | 
						|
		      *str++ = c;
 | 
						|
		      if ((flags & MALLOC)
 | 
						|
			  && (char *) str == *strptr + strsize)
 | 
						|
			{
 | 
						|
			  /* Enlarge the buffer.  */
 | 
						|
			  size_t newsize = 2 * strsize;
 | 
						|
 | 
						|
			allocagain:
 | 
						|
			  str = (char *) realloc (*strptr, newsize);
 | 
						|
			  if (str == NULL)
 | 
						|
			    {
 | 
						|
			      /* Can't allocate that much.  Last-ditch
 | 
						|
				 effort.  */
 | 
						|
			      if (newsize > strsize + 1)
 | 
						|
				{
 | 
						|
				  newsize = strsize + 1;
 | 
						|
				  goto allocagain;
 | 
						|
				}
 | 
						|
			      if (flags & POSIX_MALLOC)
 | 
						|
				{
 | 
						|
				  done = EOF;
 | 
						|
				  goto errout;
 | 
						|
				}
 | 
						|
			      /* We lose.  Oh well.  Terminate the
 | 
						|
				 string and stop converting,
 | 
						|
				 so at least we don't skip any input.  */
 | 
						|
			      ((char *) (*strptr))[strsize - 1] = '\0';
 | 
						|
			      strptr = NULL;
 | 
						|
			      ++done;
 | 
						|
			      conv_error ();
 | 
						|
			    }
 | 
						|
			  else
 | 
						|
			    {
 | 
						|
			      *strptr = (char *) str;
 | 
						|
			      str += strsize;
 | 
						|
			      strsize = newsize;
 | 
						|
			    }
 | 
						|
			}
 | 
						|
		    }
 | 
						|
		}
 | 
						|
	      while (--width > 0 && inchar () != EOF);
 | 
						|
#endif
 | 
						|
 | 
						|
	      if (__glibc_unlikely (now == read_in))
 | 
						|
		/* We haven't succesfully read any character.  */
 | 
						|
		conv_error ();
 | 
						|
 | 
						|
	      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)
 | 
						|
			{
 | 
						|
			  if (flags & POSIX_MALLOC)
 | 
						|
			    {
 | 
						|
			      done = EOF;
 | 
						|
			      goto errout;
 | 
						|
			    }
 | 
						|
			  /* We lose.  Oh well.  Terminate the string
 | 
						|
			     and stop converting, so at least we don't
 | 
						|
			     skip any input.  */
 | 
						|
			  ((char *) (*strptr))[strleng] = '\0';
 | 
						|
			  strptr = NULL;
 | 
						|
			  ++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;
 | 
						|
		    }
 | 
						|
		  strptr = NULL;
 | 
						|
 | 
						|
		  ++done;
 | 
						|
		}
 | 
						|
	    }
 | 
						|
	  break;
 | 
						|
 | 
						|
	case L_('p'):	/* Generic pointer.  */
 | 
						|
	  base = 16;
 | 
						|
	  /* A PTR must be the same size as a `long int'.  */
 | 
						|
	  flags &= ~(SHORT|LONGDBL);
 | 
						|
	  if (need_long)
 | 
						|
	    flags |= LONG;
 | 
						|
	  flags |= READ_POINTER;
 | 
						|
	  goto number;
 | 
						|
 | 
						|
	default:
 | 
						|
	  /* If this is an unknown format character punt.  */
 | 
						|
	  conv_error ();
 | 
						|
	}
 | 
						|
    }
 | 
						|
 | 
						|
  /* The last thing we saw int the format string was a white space.
 | 
						|
     Consume the last white spaces.  */
 | 
						|
  if (skip_space)
 | 
						|
    {
 | 
						|
      do
 | 
						|
	c = inchar ();
 | 
						|
      while (ISSPACE (c));
 | 
						|
      ungetc (c, s);
 | 
						|
    }
 | 
						|
 | 
						|
 errout:
 | 
						|
  /* Unlock stream.  */
 | 
						|
  UNLOCK_STREAM (s);
 | 
						|
 | 
						|
  scratch_buffer_free (&charbuf.scratch);
 | 
						|
  if (errp != NULL)
 | 
						|
    *errp |= errval;
 | 
						|
 | 
						|
  if (__glibc_unlikely (done == EOF))
 | 
						|
    {
 | 
						|
      if (__glibc_unlikely (ptrs_to_free != NULL))
 | 
						|
	{
 | 
						|
	  struct ptrs_to_free *p = ptrs_to_free;
 | 
						|
	  while (p != NULL)
 | 
						|
	    {
 | 
						|
	      for (size_t cnt = 0; cnt < p->count; ++cnt)
 | 
						|
		{
 | 
						|
		  free (*p->ptrs[cnt]);
 | 
						|
		  *p->ptrs[cnt] = NULL;
 | 
						|
		}
 | 
						|
	      p = p->next;
 | 
						|
	      ptrs_to_free = p;
 | 
						|
	    }
 | 
						|
	}
 | 
						|
    }
 | 
						|
  else if (__glibc_unlikely (strptr != NULL))
 | 
						|
    {
 | 
						|
      free (*strptr);
 | 
						|
      *strptr = NULL;
 | 
						|
    }
 | 
						|
  return done;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef COMPILE_WSCANF
 | 
						|
int
 | 
						|
__vfwscanf (FILE *s, const wchar_t *format, va_list argptr)
 | 
						|
{
 | 
						|
  return _IO_vfwscanf (s, format, argptr, NULL);
 | 
						|
}
 | 
						|
ldbl_weak_alias (__vfwscanf, vfwscanf)
 | 
						|
#else
 | 
						|
int
 | 
						|
___vfscanf (FILE *s, const char *format, va_list argptr)
 | 
						|
{
 | 
						|
  return _IO_vfscanf_internal (s, format, argptr, NULL);
 | 
						|
}
 | 
						|
ldbl_strong_alias (_IO_vfscanf_internal, _IO_vfscanf)
 | 
						|
ldbl_hidden_def (_IO_vfscanf_internal, _IO_vfscanf)
 | 
						|
ldbl_strong_alias (___vfscanf, __vfscanf)
 | 
						|
ldbl_hidden_def (___vfscanf, __vfscanf)
 | 
						|
ldbl_weak_alias (___vfscanf, vfscanf)
 | 
						|
#endif
 |