105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Formatted output to strings.
205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   Copyright (C) 1999-2000, 2002-2003, 2006-2012 Free Software Foundation, Inc.
305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is free software; you can redistribute it and/or modify
505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   it under the terms of the GNU General Public License as published by
605436638acc7c010349a69c3395f1a57c642dc62Ying Wang   the Free Software Foundation; either version 3, or (at your option)
705436638acc7c010349a69c3395f1a57c642dc62Ying Wang   any later version.
805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
905436638acc7c010349a69c3395f1a57c642dc62Ying Wang   This program is distributed in the hope that it will be useful,
1005436638acc7c010349a69c3395f1a57c642dc62Ying Wang   but WITHOUT ANY WARRANTY; without even the implied warranty of
1105436638acc7c010349a69c3395f1a57c642dc62Ying Wang   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1205436638acc7c010349a69c3395f1a57c642dc62Ying Wang   GNU General Public License for more details.
1305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1405436638acc7c010349a69c3395f1a57c642dc62Ying Wang   You should have received a copy of the GNU General Public License along
1505436638acc7c010349a69c3395f1a57c642dc62Ying Wang   with this program; if not, see <http://www.gnu.org/licenses/>.  */
1605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
1705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* This file can be parametrized with the following macros:
1805436638acc7c010349a69c3395f1a57c642dc62Ying Wang     CHAR_T             The element type of the format string.
1905436638acc7c010349a69c3395f1a57c642dc62Ying Wang     CHAR_T_ONLY_ASCII  Set to 1 to enable verification that all characters
2005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        in the format string are ASCII.
2105436638acc7c010349a69c3395f1a57c642dc62Ying Wang     DIRECTIVE          Structure denoting a format directive.
2205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        Depends on CHAR_T.
2305436638acc7c010349a69c3395f1a57c642dc62Ying Wang     DIRECTIVES         Structure denoting the set of format directives of a
2405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        format string.  Depends on CHAR_T.
2505436638acc7c010349a69c3395f1a57c642dc62Ying Wang     PRINTF_PARSE       Function that parses a format string.
2605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        Depends on CHAR_T.
2705436638acc7c010349a69c3395f1a57c642dc62Ying Wang     STATIC             Set to 'static' to declare the function static.
2805436638acc7c010349a69c3395f1a57c642dc62Ying Wang     ENABLE_UNISTDIO    Set to 1 to enable the unistdio extensions.  */
2905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef PRINTF_PARSE
3105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <config.h>
3205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3405436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Specification.  */
3505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef PRINTF_PARSE
3605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "printf-parse.h"
3705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
3805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
3905436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Default parameters.  */
4005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifndef PRINTF_PARSE
4105436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define PRINTF_PARSE printf_parse
4205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define CHAR_T char
4305436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DIRECTIVE char_directive
4405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# define DIRECTIVES char_directives
4505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
4605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
4705436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get size_t, NULL.  */
4805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stddef.h>
4905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
5005436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Get intmax_t.  */
5105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined IN_LIBINTL || defined IN_LIBASPRINTF
5205436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if HAVE_STDINT_H_WITH_UINTMAX
5305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  include <stdint.h>
5405436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
5505436638acc7c010349a69c3395f1a57c642dc62Ying Wang# if HAVE_INTTYPES_H_WITH_UINTMAX
5605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#  include <inttypes.h>
5705436638acc7c010349a69c3395f1a57c642dc62Ying Wang# endif
5805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
5905436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include <stdint.h>
6005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
6105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6205436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* malloc(), realloc(), free().  */
6305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <stdlib.h>
6405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* memcpy().  */
6605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <string.h>
6705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
6805436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* errno.  */
6905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include <errno.h>
7005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7105436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* Checked size_t computations.  */
7205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#include "xsize.h"
7305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if CHAR_T_ONLY_ASCII
7505436638acc7c010349a69c3395f1a57c642dc62Ying Wang/* c_isascii().  */
7605436638acc7c010349a69c3395f1a57c642dc62Ying Wang# include "c-ctype.h"
7705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
7805436638acc7c010349a69c3395f1a57c642dc62Ying Wang
7905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#ifdef STATIC
8005436638acc7c010349a69c3395f1a57c642dc62Ying WangSTATIC
8105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
8205436638acc7c010349a69c3395f1a57c642dc62Ying Wangint
8305436638acc7c010349a69c3395f1a57c642dc62Ying WangPRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
8405436638acc7c010349a69c3395f1a57c642dc62Ying Wang{
8505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  const CHAR_T *cp = format;    /* pointer into format */
8605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t arg_posn = 0;          /* number of regular arguments consumed */
8705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t d_allocated;           /* allocated elements of d->dir */
8805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t a_allocated;           /* allocated elements of a->arg */
8905436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t max_width_length = 0;
9005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  size_t max_precision_length = 0;
9105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  d->count = 0;
9305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
9405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  d->dir = d->direct_alloc_dir;
9505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
9605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  a->count = 0;
9705436638acc7c010349a69c3395f1a57c642dc62Ying Wang  a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
9805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  a->arg = a->direct_alloc_arg;
9905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
10005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#define REGISTER_ARG(_index_,_type_) \
10105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  {                                                                     \
10205436638acc7c010349a69c3395f1a57c642dc62Ying Wang    size_t n = (_index_);                                               \
10305436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (n >= a_allocated)                                               \
10405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      {                                                                 \
10505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        size_t memory_size;                                             \
10605436638acc7c010349a69c3395f1a57c642dc62Ying Wang        argument *memory;                                               \
10705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                                                        \
10805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        a_allocated = xtimes (a_allocated, 2);                          \
10905436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (a_allocated <= n)                                           \
11005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          a_allocated = xsum (n, 1);                                    \
11105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        memory_size = xtimes (a_allocated, sizeof (argument));          \
11205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (size_overflow_p (memory_size))                              \
11305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Overflow, would lead to out of memory.  */                 \
11405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          goto out_of_memory;                                           \
11505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        memory = (argument *) (a->arg != a->direct_alloc_arg            \
11605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                               ? realloc (a->arg, memory_size)          \
11705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                               : malloc (memory_size));                 \
11805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (memory == NULL)                                             \
11905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Out of memory.  */                                         \
12005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          goto out_of_memory;                                           \
12105436638acc7c010349a69c3395f1a57c642dc62Ying Wang        if (a->arg == a->direct_alloc_arg)                              \
12205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          memcpy (memory, a->arg, a->count * sizeof (argument));        \
12305436638acc7c010349a69c3395f1a57c642dc62Ying Wang        a->arg = memory;                                                \
12405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      }                                                                 \
12505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    while (a->count <= n)                                               \
12605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      a->arg[a->count++].type = TYPE_NONE;                              \
12705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    if (a->arg[n].type == TYPE_NONE)                                    \
12805436638acc7c010349a69c3395f1a57c642dc62Ying Wang      a->arg[n].type = (_type_);                                        \
12905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    else if (a->arg[n].type != (_type_))                                \
13005436638acc7c010349a69c3395f1a57c642dc62Ying Wang      /* Ambiguous type for positional argument.  */                    \
13105436638acc7c010349a69c3395f1a57c642dc62Ying Wang      goto error;                                                       \
13205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  }
13305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
13405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  while (*cp != '\0')
13505436638acc7c010349a69c3395f1a57c642dc62Ying Wang    {
13605436638acc7c010349a69c3395f1a57c642dc62Ying Wang      CHAR_T c = *cp++;
13705436638acc7c010349a69c3395f1a57c642dc62Ying Wang      if (c == '%')
13805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
13905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          size_t arg_index = ARG_NONE;
14005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
14105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
14205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Initialize the next directive.  */
14305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->dir_start = cp - 1;
14405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->flags = 0;
14505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->width_start = NULL;
14605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->width_end = NULL;
14705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->width_arg_index = ARG_NONE;
14805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->precision_start = NULL;
14905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->precision_end = NULL;
15005436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->precision_arg_index = ARG_NONE;
15105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          dp->arg_index = ARG_NONE;
15205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15305436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Test for positional argument.  */
15405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (*cp >= '0' && *cp <= '9')
15505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
15605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              const CHAR_T *np;
15705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
15805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              for (np = cp; *np >= '0' && *np <= '9'; np++)
15905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                ;
16005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (*np == '$')
16105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
16205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  size_t n = 0;
16305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
16405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  for (np = cp; *np >= '0' && *np <= '9'; np++)
16505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    n = xsum (xtimes (n, 10), *np - '0');
16605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (n == 0)
16705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    /* Positional argument 0.  */
16805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    goto error;
16905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (size_overflow_p (n))
17005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    /* n too large, would lead to out of memory later.  */
17105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    goto error;
17205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  arg_index = n - 1;
17305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp = np + 1;
17405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
17505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
17605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
17705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Read the flags.  */
17805436638acc7c010349a69c3395f1a57c642dc62Ying Wang          for (;;)
17905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
18005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (*cp == '\'')
18105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
18205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_GROUP;
18305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
18405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
18505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else if (*cp == '-')
18605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
18705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_LEFT;
18805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
18905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
19005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else if (*cp == '+')
19105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
19205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_SHOWSIGN;
19305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
19405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
19505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else if (*cp == ' ')
19605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
19705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_SPACE;
19805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
19905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
20005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else if (*cp == '#')
20105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
20205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_ALT;
20305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
20405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
20505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else if (*cp == '0')
20605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
20705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_ZERO;
20805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
20905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
21005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if __GLIBC__ >= 2 && !defined __UCLIBC__
21105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else if (*cp == 'I')
21205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
21305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->flags |= FLAG_LOCALIZED;
21405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
21505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
21605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
21705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else
21805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                break;
21905436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
22005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
22105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Parse the field width.  */
22205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (*cp == '*')
22305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
22405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              dp->width_start = cp;
22505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              cp++;
22605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              dp->width_end = cp;
22705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (max_width_length < 1)
22805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                max_width_length = 1;
22905436638acc7c010349a69c3395f1a57c642dc62Ying Wang
23005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Test for positional argument.  */
23105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (*cp >= '0' && *cp <= '9')
23205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
23305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  const CHAR_T *np;
23405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
23505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  for (np = cp; *np >= '0' && *np <= '9'; np++)
23605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    ;
23705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (*np == '$')
23805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
23905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      size_t n = 0;
24005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
24105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      for (np = cp; *np >= '0' && *np <= '9'; np++)
24205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        n = xsum (xtimes (n, 10), *np - '0');
24305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (n == 0)
24405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        /* Positional argument 0.  */
24505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        goto error;
24605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (size_overflow_p (n))
24705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        /* n too large, would lead to out of memory later.  */
24805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        goto error;
24905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      dp->width_arg_index = n - 1;
25005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp = np + 1;
25105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
25205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
25305436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (dp->width_arg_index == ARG_NONE)
25405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
25505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->width_arg_index = arg_posn++;
25605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (dp->width_arg_index == ARG_NONE)
25705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    /* arg_posn wrapped around.  */
25805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    goto error;
25905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
26005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              REGISTER_ARG (dp->width_arg_index, TYPE_INT);
26105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
26205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          else if (*cp >= '0' && *cp <= '9')
26305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
26405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              size_t width_length;
26505436638acc7c010349a69c3395f1a57c642dc62Ying Wang
26605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              dp->width_start = cp;
26705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              for (; *cp >= '0' && *cp <= '9'; cp++)
26805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                ;
26905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              dp->width_end = cp;
27005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              width_length = dp->width_end - dp->width_start;
27105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (max_width_length < width_length)
27205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                max_width_length = width_length;
27305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
27405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
27505436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Parse the precision.  */
27605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (*cp == '.')
27705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
27805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              cp++;
27905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (*cp == '*')
28005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
28105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->precision_start = cp - 1;
28205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  cp++;
28305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->precision_end = cp;
28405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (max_precision_length < 2)
28505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    max_precision_length = 2;
28605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
28705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* Test for positional argument.  */
28805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (*cp >= '0' && *cp <= '9')
28905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
29005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      const CHAR_T *np;
29105436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      for (np = cp; *np >= '0' && *np <= '9'; np++)
29305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        ;
29405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (*np == '$')
29505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
29605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          size_t n = 0;
29705436638acc7c010349a69c3395f1a57c642dc62Ying Wang
29805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          for (np = cp; *np >= '0' && *np <= '9'; np++)
29905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            n = xsum (xtimes (n, 10), *np - '0');
30005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          if (n == 0)
30105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            /* Positional argument 0.  */
30205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            goto error;
30305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          if (size_overflow_p (n))
30405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            /* n too large, would lead to out of memory
30505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                               later.  */
30605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                            goto error;
30705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          dp->precision_arg_index = n - 1;
30805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          cp = np + 1;
30905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
31005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
31105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (dp->precision_arg_index == ARG_NONE)
31205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
31305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      dp->precision_arg_index = arg_posn++;
31405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (dp->precision_arg_index == ARG_NONE)
31505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        /* arg_posn wrapped around.  */
31605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        goto error;
31705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
31805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
31905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
32005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              else
32105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
32205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  size_t precision_length;
32305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
32405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->precision_start = cp - 1;
32505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  for (; *cp >= '0' && *cp <= '9'; cp++)
32605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    ;
32705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  dp->precision_end = cp;
32805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  precision_length = dp->precision_end - dp->precision_start;
32905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (max_precision_length < precision_length)
33005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    max_precision_length = precision_length;
33105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
33205436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
33305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
33405436638acc7c010349a69c3395f1a57c642dc62Ying Wang          {
33505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            arg_type type;
33605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
33705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            /* Parse argument type/size specifiers.  */
33805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
33905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              int flags = 0;
34005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
34105436638acc7c010349a69c3395f1a57c642dc62Ying Wang              for (;;)
34205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
34305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (*cp == 'h')
34405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
34505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      flags |= (1 << (flags & 1));
34605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
34705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
34805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 'L')
34905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
35005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      flags |= 4;
35105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
35205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
35305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 'l')
35405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
35505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      flags += 8;
35605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
35705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
35805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 'j')
35905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
36005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (sizeof (intmax_t) > sizeof (long))
36105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
36205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* intmax_t = long long */
36305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 16;
36405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
36505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else if (sizeof (intmax_t) > sizeof (int))
36605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
36705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* intmax_t = long */
36805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 8;
36905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
37005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
37105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
37205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 'z' || *cp == 'Z')
37305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
37405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
37505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                         because the warning facility in gcc-2.95.2 understands
37605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                         only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
37705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (sizeof (size_t) > sizeof (long))
37805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
37905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* size_t = long long */
38005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 16;
38105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
38205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else if (sizeof (size_t) > sizeof (int))
38305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
38405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* size_t = long */
38505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 8;
38605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
38705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
38805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
38905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 't')
39005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
39105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (sizeof (ptrdiff_t) > sizeof (long))
39205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
39305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* ptrdiff_t = long long */
39405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 16;
39505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
39605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else if (sizeof (ptrdiff_t) > sizeof (int))
39705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
39805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* ptrdiff_t = long */
39905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 8;
40005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
40105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
40205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
40305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if defined __APPLE__ && defined __MACH__
40405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* On Mac OS X 10.3, PRIdMAX is defined as "qd".
40505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     We cannot change it to "lld" because PRIdMAX must also
40605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     be understood by the system's printf routines.  */
40705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 'q')
40805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
40905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (64 / 8 > sizeof (long))
41005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
41105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* int64_t = long long */
41205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 16;
41305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
41405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else
41505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
41605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* int64_t = long */
41705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 8;
41805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
41905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp++;
42005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
42105436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
42205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
42305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* On native Windows, PRIdMAX is defined as "I64d".
42405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     We cannot change it to "lld" because PRIdMAX must also
42505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     be understood by the system's printf routines.  */
42605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
42705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    {
42805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      if (64 / 8 > sizeof (long))
42905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
43005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* __int64 = long long */
43105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 16;
43205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
43305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      else
43405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        {
43505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          /* __int64 = long */
43605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                          flags += 8;
43705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                        }
43805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      cp += 3;
43905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    }
44005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
44105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
44205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    break;
44305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
44405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
44505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              /* Read the conversion character.  */
44605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              c = *cp++;
44705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              switch (c)
44805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                {
44905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'd': case 'i':
45005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_LONG_LONG_INT
45105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* If 'long long' exists and is larger than 'long':  */
45205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 16 || (flags & 4))
45305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_LONGLONGINT;
45405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
45505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
45605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* If 'long long' exists and is the same as 'long', we parse
45705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     "lld" into TYPE_LONGINT.  */
45805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 8)
45905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_LONGINT;
46005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags & 2)
46105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_SCHAR;
46205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags & 1)
46305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_SHORT;
46405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
46505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_INT;
46605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
46705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'o': case 'u': case 'x': case 'X':
46805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_LONG_LONG_INT
46905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* If 'long long' exists and is larger than 'long':  */
47005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 16 || (flags & 4))
47105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_ULONGLONGINT;
47205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
47305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
47405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* If 'unsigned long long' exists and is the same as
47505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
47605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 8)
47705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_ULONGINT;
47805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags & 2)
47905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_UCHAR;
48005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags & 1)
48105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_USHORT;
48205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
48305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_UINT;
48405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
48505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
48605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'a': case 'A':
48705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 16 || (flags & 4))
48805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_LONGDOUBLE;
48905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
49005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_DOUBLE;
49105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
49205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'c':
49305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 8)
49405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_WINT_T
49505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_WIDE_CHAR;
49605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
49705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    goto error;
49805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
49905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
50005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_CHAR;
50105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
50205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_WINT_T
50305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'C':
50405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  type = TYPE_WIDE_CHAR;
50505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  c = 'c';
50605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
50705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
50805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 's':
50905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 8)
51005436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_WCHAR_T
51105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_WIDE_STRING;
51205436638acc7c010349a69c3395f1a57c642dc62Ying Wang#else
51305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    goto error;
51405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
51505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
51605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_STRING;
51705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
51805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_WCHAR_T
51905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'S':
52005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  type = TYPE_WIDE_STRING;
52105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  c = 's';
52205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
52305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
52405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'p':
52505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  type = TYPE_POINTER;
52605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
52705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'n':
52805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if HAVE_LONG_LONG_INT
52905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* If 'long long' exists and is larger than 'long':  */
53005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 16 || (flags & 4))
53105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_COUNT_LONGLONGINT_POINTER;
53205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
53305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
53405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* If 'long long' exists and is the same as 'long', we parse
53505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                     "lln" into TYPE_COUNT_LONGINT_POINTER.  */
53605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 8)
53705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_COUNT_LONGINT_POINTER;
53805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags & 2)
53905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_COUNT_SCHAR_POINTER;
54005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags & 1)
54105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_COUNT_SHORT_POINTER;
54205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
54305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_COUNT_INT_POINTER;
54405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
54505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if ENABLE_UNISTDIO
54605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                /* The unistdio extensions.  */
54705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case 'U':
54805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  if (flags >= 16)
54905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_U32_STRING;
55005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else if (flags >= 8)
55105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_U16_STRING;
55205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  else
55305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    type = TYPE_U8_STRING;
55405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
55505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
55605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                case '%':
55705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  type = TYPE_NONE;
55805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  break;
55905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                default:
56005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  /* Unknown conversion character.  */
56105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  goto error;
56205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                }
56305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
56405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
56505436638acc7c010349a69c3395f1a57c642dc62Ying Wang            if (type != TYPE_NONE)
56605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              {
56705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                dp->arg_index = arg_index;
56805436638acc7c010349a69c3395f1a57c642dc62Ying Wang                if (dp->arg_index == ARG_NONE)
56905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  {
57005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    dp->arg_index = arg_posn++;
57105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                    if (dp->arg_index == ARG_NONE)
57205436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      /* arg_posn wrapped around.  */
57305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                      goto error;
57405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                  }
57505436638acc7c010349a69c3395f1a57c642dc62Ying Wang                REGISTER_ARG (dp->arg_index, type);
57605436638acc7c010349a69c3395f1a57c642dc62Ying Wang              }
57705436638acc7c010349a69c3395f1a57c642dc62Ying Wang            dp->conversion = c;
57805436638acc7c010349a69c3395f1a57c642dc62Ying Wang            dp->dir_end = cp;
57905436638acc7c010349a69c3395f1a57c642dc62Ying Wang          }
58005436638acc7c010349a69c3395f1a57c642dc62Ying Wang
58105436638acc7c010349a69c3395f1a57c642dc62Ying Wang          d->count++;
58205436638acc7c010349a69c3395f1a57c642dc62Ying Wang          if (d->count >= d_allocated)
58305436638acc7c010349a69c3395f1a57c642dc62Ying Wang            {
58405436638acc7c010349a69c3395f1a57c642dc62Ying Wang              size_t memory_size;
58505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              DIRECTIVE *memory;
58605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
58705436638acc7c010349a69c3395f1a57c642dc62Ying Wang              d_allocated = xtimes (d_allocated, 2);
58805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
58905436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (size_overflow_p (memory_size))
59005436638acc7c010349a69c3395f1a57c642dc62Ying Wang                /* Overflow, would lead to out of memory.  */
59105436638acc7c010349a69c3395f1a57c642dc62Ying Wang                goto out_of_memory;
59205436638acc7c010349a69c3395f1a57c642dc62Ying Wang              memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
59305436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                      ? realloc (d->dir, memory_size)
59405436638acc7c010349a69c3395f1a57c642dc62Ying Wang                                      : malloc (memory_size));
59505436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (memory == NULL)
59605436638acc7c010349a69c3395f1a57c642dc62Ying Wang                /* Out of memory.  */
59705436638acc7c010349a69c3395f1a57c642dc62Ying Wang                goto out_of_memory;
59805436638acc7c010349a69c3395f1a57c642dc62Ying Wang              if (d->dir == d->direct_alloc_dir)
59905436638acc7c010349a69c3395f1a57c642dc62Ying Wang                memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
60005436638acc7c010349a69c3395f1a57c642dc62Ying Wang              d->dir = memory;
60105436638acc7c010349a69c3395f1a57c642dc62Ying Wang            }
60205436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
60305436638acc7c010349a69c3395f1a57c642dc62Ying Wang#if CHAR_T_ONLY_ASCII
60405436638acc7c010349a69c3395f1a57c642dc62Ying Wang      else if (!c_isascii (c))
60505436638acc7c010349a69c3395f1a57c642dc62Ying Wang        {
60605436638acc7c010349a69c3395f1a57c642dc62Ying Wang          /* Non-ASCII character.  Not supported.  */
60705436638acc7c010349a69c3395f1a57c642dc62Ying Wang          goto error;
60805436638acc7c010349a69c3395f1a57c642dc62Ying Wang        }
60905436638acc7c010349a69c3395f1a57c642dc62Ying Wang#endif
61005436638acc7c010349a69c3395f1a57c642dc62Ying Wang    }
61105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  d->dir[d->count].dir_start = cp;
61205436638acc7c010349a69c3395f1a57c642dc62Ying Wang
61305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  d->max_width_length = max_width_length;
61405436638acc7c010349a69c3395f1a57c642dc62Ying Wang  d->max_precision_length = max_precision_length;
61505436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return 0;
61605436638acc7c010349a69c3395f1a57c642dc62Ying Wang
61705436638acc7c010349a69c3395f1a57c642dc62Ying Wangerror:
61805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (a->arg != a->direct_alloc_arg)
61905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (a->arg);
62005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (d->dir != d->direct_alloc_dir)
62105436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (d->dir);
62205436638acc7c010349a69c3395f1a57c642dc62Ying Wang  errno = EINVAL;
62305436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return -1;
62405436638acc7c010349a69c3395f1a57c642dc62Ying Wang
62505436638acc7c010349a69c3395f1a57c642dc62Ying Wangout_of_memory:
62605436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (a->arg != a->direct_alloc_arg)
62705436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (a->arg);
62805436638acc7c010349a69c3395f1a57c642dc62Ying Wang  if (d->dir != d->direct_alloc_dir)
62905436638acc7c010349a69c3395f1a57c642dc62Ying Wang    free (d->dir);
63005436638acc7c010349a69c3395f1a57c642dc62Ying Wang  errno = ENOMEM;
63105436638acc7c010349a69c3395f1a57c642dc62Ying Wang  return -1;
63205436638acc7c010349a69c3395f1a57c642dc62Ying Wang}
63305436638acc7c010349a69c3395f1a57c642dc62Ying Wang
63405436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef PRINTF_PARSE
63505436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef DIRECTIVES
63605436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef DIRECTIVE
63705436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef CHAR_T_ONLY_ASCII
63805436638acc7c010349a69c3395f1a57c642dc62Ying Wang#undef CHAR_T
639