len = strlen (str);
len = specs[cnt].info.prec;
static printf_function printf_unknown;extern printf_function **__printf_function_table;static char *group_number __P ((char *, char *, const char *, wchar_t));intvfprintf (s, format, ap)    register FILE *s;    const char *format;    va_list ap;{  /* The character used as thousands separator.  */  wchar_t thousands_sep;  /* The string describing the size of groups of digits.  */  const char *grouping;  /* Array with information about the needed arguments.  This has to be     dynamically extendable.  */  size_t nspecs;  size_t nspecs_max;  struct printf_spec *specs;  /* The number of arguments the format string requests.  This will     determine the size of the array needed to store the argument     attributes.  */  size_t nargs;  int *args_type;  union printf_arg *args_value;  /* Positional parameters refer to arguments directly.  This could also     determine the maximum number of arguments.  Track the maximum number.  */  size_t max_ref_arg;  /* End of leading constant string.  */  const char *lead_str_end;  /* Number of characters written.  */  register size_t done = 0;  /* Running pointer through format string.  */  const char *f;  /* Just a counter.  */  int cnt;  ARGCHECK (s, format);  if (UNBUFFERED_P (s))    /* Use a helper function which will allocate a local temporary buffer       for the stream and then call us again.  */    return buffered_vfprintf (s, format, ap);  /* Reset multibyte characters to their initial state.  */  (void) mblen ((char *) NULL, 0);  /* Figure out the thousands separator character.  */  if (mbtowc (&thousands_sep, _NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP),              strlen (_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP))) <= 0)    thousands_sep = (wchar_t) *_NL_CURRENT (LC_NUMERIC, THOUSANDS_SEP);  grouping = _NL_CURRENT (LC_NUMERIC, GROUPING);  if (*grouping == '\0' || *grouping == CHAR_MAX || thousands_sep == L'\0')    grouping = NULL;  nspecs_max = 32;		/* A more or less arbitrary start value.  */  specs = alloca (nspecs_max * sizeof (struct printf_spec));  nspecs = 0;  nargs = 0;  max_ref_arg = 0;  /* Find the first format specifier.  */  lead_str_end = find_spec (format);  for (f = lead_str_end; *f != '\0'; f = specs[nspecs++].next_fmt)    {      if (nspecs >= nspecs_max)	{	  /* Extend the array of format specifiers.  */	  struct printf_spec *old = specs;	  nspecs_max *= 2;	  specs = alloca (nspecs_max * sizeof (struct printf_spec));	  if (specs == &old[nspecs])	    /* Stack grows up, OLD was the last thing allocated; extend it.  */	    nspecs_max += nspecs_max / 2;	  else	    {	      /* Copy the old array's elements to the new space.  */	      memcpy (specs, old, nspecs * sizeof (struct printf_spec));	      if (old == &specs[nspecs])		/* Stack grows down, OLD was just below the new SPECS.		   We can use that space when the new space runs out.  */		nspecs_max += nspecs_max / 2;	    }	}      /* Parse the format specifier.  */      nargs += parse_one_spec (f, nargs, &specs[nspecs], &max_ref_arg);    }  /* Determine the number of arguments the format string consumes.  */  nargs = MAX (nargs, max_ref_arg);  /* Allocate memory for the argument descriptions.  */  args_type = alloca (nargs * sizeof (int));  args_value = alloca (nargs * sizeof (union printf_arg));  /* XXX Could do sanity check here:     Initialize args_type elts to zero.     If any is still zero after this loop, format is invalid.  */  /* Fill in the types of all the arguments.  */  for (cnt = 0; cnt < nspecs; ++cnt)    {      /* If the width is determined by an argument this is an int.  */       if (specs[cnt].width_arg != -1)	args_type[specs[cnt].width_arg] = PA_INT;      /* If the precision is determined by an argument this is an int.  */       if (specs[cnt].prec_arg != -1)	args_type[specs[cnt].prec_arg] = PA_INT;      switch (specs[cnt].ndata_args)	{	case 0:			/* No arguments.  */	  break;	case 1:			/* One argument; we already have the type.  */	  args_type[specs[cnt].data_arg] = specs[cnt].data_arg_type;	  break;	default:	  /* We have more than one argument for this format spec.  We must	     call the arginfo function again to determine all the types.  */	  (void) (*__printf_arginfo_table[specs[cnt].info.spec])	    (&specs[cnt].info,	     specs[cnt].ndata_args, &args_type[specs[cnt].data_arg]);	  break;	}    }  /* Now we know all the types and the order.  Fill in the argument values.  */  for (cnt = 0; cnt < nargs; ++cnt)    switch (args_type[cnt])      {#define T(tag, mem, type)						      \      case tag:								      \	args_value[cnt].mem = va_arg (ap, type);			      \	break	T (PA_CHAR, pa_char, int); /* Promoted.  */	T (PA_INT|PA_FLAG_SHORT, pa_short_int, int); /* Promoted.  */	T (PA_INT, pa_int, int);	T (PA_INT|PA_FLAG_LONG, pa_long_int, long int);	T (PA_INT|PA_FLAG_LONG_LONG, pa_long_long_int, long long int);	T (PA_FLOAT, pa_float, double);	/* Promoted.  */	T (PA_DOUBLE, pa_double, double);	T (PA_DOUBLE|PA_FLAG_LONG_DOUBLE, pa_long_double, long double);	T (PA_STRING, pa_string, const char *);	T (PA_POINTER, pa_pointer, void *);#undef T      default:	if ((args_type[cnt] & PA_FLAG_PTR) != 0)	  args_value[cnt].pa_pointer = va_arg (ap, void *);	break;      }  /* Write the literal text before the first format.  */  outstring (format, lead_str_end - format);  /* Now walk through all format specifiers and process them.  */  for (cnt = 0; cnt < nspecs; ++cnt)    {      printf_function *function; /* Auxiliary function to do output.  */      int is_neg;		/* Decimal integer is negative.  */      int base;			/* Base of a number to be written.  */      unsigned long long int num; /* Integral number to be written.  */      const char *str;		/* String to be written.  */      char errorbuf[1024];      /* Buffer sometimes used by %m.  */      if (specs[cnt].width_arg != -1)	{	  /* Extract the field width from an argument.  */	  specs[cnt].info.width = args_value[specs[cnt].width_arg].pa_int;	  if (specs[cnt].info.width < 0)	    /* If the width value is negative left justification is selected	       and the value is taken as being positive.  */	    {	      specs[cnt].info.width = -specs[cnt].info.width;	      specs[cnt].info.left = 1;	    }	}      if (specs[cnt].prec_arg != -1)	{	  /* Extract the precision from an argument.  */	  specs[cnt].info.prec = args_value[specs[cnt].prec_arg].pa_int;	  if (specs[cnt].info.prec < 0)	    /* If the precision is negative the precision is omitted.  */	    specs[cnt].info.prec = -1;	}      /* Check for a user-defined handler for this spec.  */      function = (__printf_function_table == NULL ? NULL :                  __printf_function_table[specs[cnt].info.spec]);      if (function != NULL)      use_function:		/* Built-in formats with helpers use this.  */	{	  int function_done;	  unsigned int i;	  const void *ptr[specs[cnt].ndata_args];	  /* Fill in an array of pointers to the argument values.  */	  for (i = 0; i < specs[cnt].ndata_args; ++i)	    ptr[i] = &args_value[specs[cnt].data_arg + i];	  /* Call the function.  */	  function_done = (*function) (s, &specs[cnt].info, ptr);	  /* If an error occured don't do any further work.  */	  if (function_done < 0)	    return -1;	  done += function_done;	}      else	switch (specs[cnt].info.spec)	  {	  case '%':	    /* Write a literal "%".  */	    outchar ('%');	    break;	  case 'i':	  case 'd':	    {	      long long int signed_num;	      /* Decimal integer.  */	      base = 10;	      if (specs[cnt].info.is_longlong)		signed_num = args_value[specs[cnt].data_arg].pa_long_long_int;	      else if (specs[cnt].info.is_long)		signed_num = args_value[specs[cnt].data_arg].pa_long_int;	      else if (!specs[cnt].info.is_short)		signed_num = args_value[specs[cnt].data_arg].pa_int;	      else		signed_num = args_value[specs[cnt].data_arg].pa_short_int;	      is_neg = signed_num < 0;	      num = is_neg ? (- signed_num) : signed_num;	      goto number;	    }	  case 'u':	    /* Decimal unsigned integer.  */            base = 10;            goto unsigned_number;	  case 'o':            /* Octal unsigned integer.  */            base = 8;            goto unsigned_number;          case 'X':            /* Hexadecimal unsigned integer.  */          case 'x':            /* Hex with lower-case digits.  */            base = 16;	  unsigned_number:            /* Unsigned number of base BASE.  */            if (specs[cnt].info.is_longlong)	      num = args_value[specs[cnt].data_arg].pa_u_long_long_int;            else if (specs[cnt].info.is_long)	      num = args_value[specs[cnt].data_arg].pa_u_long_int;            else if (!specs[cnt].info.is_short)	      num = args_value[specs[cnt].data_arg].pa_u_int;            else	      num = args_value[specs[cnt].data_arg].pa_u_short_int;            /* ANSI only specifies the `+' and               ` ' flags for signed conversions.  */            is_neg = 0;	    specs[cnt].info.showsign = 0;	    specs[cnt].info.space = 0;	  number:	    /* Number of base BASE.  */            {              char work[BUFSIZ];              char *const workend = &work[sizeof(work) - 1];              register char *w;              /* Supply a default precision if none was given.  */              if (specs[cnt].info.prec == -1)                specs[cnt].info.prec = 1;              /* Put the number in WORK.  */              w = _itoa (num, workend + 1, base, specs[cnt].info.spec == 'X');	      w -= 1;              if (specs[cnt].info.group && grouping)                w = group_number (w, workend, grouping, thousands_sep);              specs[cnt].info.width -= workend - w;              specs[cnt].info.prec -= workend - w;              if (num != 0 && specs[cnt].info.alt && base == 8		  && specs[cnt].info.prec <= 0)                {		  /* Add octal marker.  */                  *w-- = '0';                  --specs[cnt].info.width;                }              if (specs[cnt].info.prec > 0)                {		  /* Add zeros to the precision.  */                  specs[cnt].info.width -= specs[cnt].info.prec;                  while (specs[cnt].info.prec-- > 0)                    *w-- = '0';                }              if (num != 0 && specs[cnt].info.alt && base == 16)		/* Account for 0X hex marker.  */                specs[cnt].info.width -= 2;              if (is_neg || specs[cnt].info.showsign || specs[cnt].info.space)                --specs[cnt].info.width;              if (!specs[cnt].info.left && specs[cnt].info.pad == ' ')                PAD (' ');              if (is_neg)                outchar ('-');              else if (specs[cnt].info.showsign)                outchar ('+');              else if (specs[cnt].info.space)                outchar (' ');              if (num != 0 && specs[cnt].info.alt && base == 16)                {                  outchar ('0');                  outchar (specs[cnt].info.spec);                }              if (!specs[cnt].info.left && specs[cnt].info.pad == '0')                PAD ('0');              /* Write the number.  */              while (++w <= workend)                outchar (*w);              if (specs[cnt].info.left)                PAD (' ');            }            break;          case 'e':          case 'E':          case 'f':          case 'g':          case 'G':            {              /* Floating-point number.  This is handled by printf_fp.c.  */              extern printf_function __printf_fp;              function = __printf_fp;              goto use_function;            }          case 'c':            /* Character.  */            if (!specs[cnt].info.left)              {                --specs[cnt].info.width;                PAD (' ');              }            outchar ((unsigned char) args_value[specs[cnt].data_arg].pa_char);            if (specs[cnt].info.left)              PAD (' ');            break;          case 's':            {              static const char null[] = "(null)";              size_t len;	      str = args_value[specs[cnt].data_arg].pa_string;	    string:              if (str == NULL)		{		  /* Write "(null)" if there's space.  */		  if (specs[cnt].info.prec == -1		      || specs[cnt].info.prec >= (int) sizeof (null) - 1)		    {		      str = null;		      len = sizeof (null) - 1;		    }		  else		    {		      str = "";		      len = 0;		    }		}              else if (specs[cnt].info.prec != -1)		{		  const char *end = memchr (str, '\0', specs[cnt].info.prec);		  if (end)		    len = end - str;		  else		    len = strlen (str);		}	      else		{		  len = strlen (str);		  if (specs[cnt].info.prec != -1		      && (size_t) specs[cnt].info.prec < len)		    /* Limit the length to the precision.  */		    len = specs[cnt].info.prec;		}              specs[cnt].info.width -= len;              if (!specs[cnt].info.left)                PAD (' ');              outstring (str, len);              if (specs[cnt].info.left)                PAD (' ');            }            break;          case 'p':            /* Generic pointer.  */            {              const void *ptr;              ptr = args_value[specs[cnt].data_arg].pa_pointer;              if (ptr != NULL)                {                  /* If the pointer is not NULL, write it as a %#x spec.  */                  base = 16;                  num = (unsigned long long int) (unsigned long int) ptr;                  is_neg = 0;                  specs[cnt].info.alt = 1;		  specs[cnt].info.spec = 'x';                  specs[cnt].info.group = 0;                  goto number;                }              else                {                  /* Write "(nil)" for a nil pointer.  */                  str = "(nil)";		  /* Make sure the full string "(nil)" is printed.  */		  if (specs[cnt].info.prec < 5)		    specs[cnt].info.prec = 5;                  goto string;                }            }            break;          case 'n':            /* Answer the count of characters written.  */            if (specs[cnt].info.is_longlong)	      *(long long int *) 		args_value[specs[cnt].data_arg].pa_pointer = done;            else if (specs[cnt].info.is_long)	      *(long int *) 		args_value[specs[cnt].data_arg].pa_pointer = done;            else if (!specs[cnt].info.is_short)	      *(int *) 		args_value[specs[cnt].data_arg].pa_pointer = done;            else	      *(short int *) 		args_value[specs[cnt].data_arg].pa_pointer = done;            break;          case 'm':            {              extern char *_strerror_internal __P ((int, char buf[1024]));              str = _strerror_internal (errno, errorbuf);              goto string;            }          default:            /* Unrecognized format specifier.  */            function = printf_unknown;            goto use_function;	  }      /* Write the following constant string.  */      outstring (specs[cnt].end_of_fmt,		 specs[cnt].next_fmt - specs[cnt].end_of_fmt);    }  return done;}/* Handle an unknown format specifier.  This prints out a canonicalized   representation of the format spec itself.  */static intprintf_unknown (s, info, args)  FILE *s;  const struct printf_info *info;  const void **const args;{  int done = 0;  char work[BUFSIZ];  char *const workend = &work[sizeof(work) - 1];  register char *w;  outchar ('%');  if (info->alt)    outchar ('#');  if (info->group)    outchar ('\'');  if (info->showsign)    outchar ('+');  else if (info->space)    outchar (' ');  if (info->left)    outchar ('-');  if (info->pad == '0')    outchar ('0');  if (info->width != 0)    {      w = _itoa (info->width, workend + 1, 10, 0);      while (++w <= workend)	outchar (*w);    }  if (info->prec != -1)    {      outchar ('.');      w = _itoa (info->prec, workend + 1, 10, 0);      while (++w <= workend)	outchar (*w);    }  if (info->spec != '\0')    outchar (info->spec);  return done;}