/* Formatted output to strings.
Copyright (C) 1999-2000, 2002-2003, 2006-2010 Free Software Foundation, Inc.
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
This program 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 General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
/* This file can be parametrized with the following macros:
CHAR_T The element type of the format string.
CHAR_T_ONLY_ASCII Set to 1 to enable verification that all characters
in the format string are ASCII.
DIRECTIVE Structure denoting a format directive.
Depends on CHAR_T.
DIRECTIVES Structure denoting the set of format directives of a
format string. Depends on CHAR_T.
PRINTF_PARSE Function that parses a format string.
Depends on CHAR_T.
STATIC Set to 'static' to declare the function static.
ENABLE_UNISTDIO Set to 1 to enable the unistdio extensions. */
#ifndef PRINTF_PARSE
# include <config.h>
#endif
/* Specification. */
#ifndef PRINTF_PARSE
# include "printf-parse.h"
#endif
/* Default parameters. */
#ifndef PRINTF_PARSE
# define CHAR_T char
#endif
/* Get size_t, NULL. */
#include <stddef.h>
/* Get intmax_t. */
#if defined IN_LIBINTL || defined IN_LIBASPRINTF
# include <stdint.h>
# endif
# include <inttypes.h>
# endif
#else
# include <stdint.h>
#endif
/* malloc(), realloc(), free(). */
#include <stdlib.h>
/* errno. */
#include <errno.h>
/* Checked size_t computations. */
#include "xsize.h"
/* c_isascii(). */
# include "c-ctype.h"
#endif
#ifdef STATIC
#endif
int
{
d->count = 0;
d_allocated = 1;
/* Out of memory. */
goto out_of_memory_1;
a->count = 0;
a_allocated = 0;
{ \
if (n >= a_allocated) \
{ \
\
if (a_allocated <= n) \
if (size_overflow_p (memory_size)) \
/* Overflow, would lead to out of memory. */ \
goto out_of_memory; \
: malloc (memory_size)); \
/* Out of memory. */ \
goto out_of_memory; \
} \
while (a->count <= n) \
/* Ambiguous type for positional argument. */ \
goto error; \
}
while (*cp != '\0')
{
if (c == '%')
{
/* Initialize the next directive. */
/* Test for positional argument. */
{
;
if (*np == '$')
{
size_t n = 0;
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory later. */
goto error;
arg_index = n - 1;
}
}
/* Read the flags. */
for (;;)
{
if (*cp == '\'')
{
cp++;
}
else if (*cp == '-')
{
cp++;
}
else if (*cp == '+')
{
cp++;
}
else if (*cp == ' ')
{
cp++;
}
else if (*cp == '#')
{
cp++;
}
else if (*cp == '0')
{
cp++;
}
else
break;
}
/* Parse the field width. */
if (*cp == '*')
{
cp++;
if (max_width_length < 1)
max_width_length = 1;
/* Test for positional argument. */
{
;
if (*np == '$')
{
size_t n = 0;
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory later. */
goto error;
}
}
{
/* arg_posn wrapped around. */
goto error;
}
}
{
;
if (max_width_length < width_length)
}
/* Parse the precision. */
if (*cp == '.')
{
cp++;
if (*cp == '*')
{
cp++;
if (max_precision_length < 2)
max_precision_length = 2;
/* Test for positional argument. */
{
;
if (*np == '$')
{
size_t n = 0;
if (n == 0)
/* Positional argument 0. */
goto error;
if (size_overflow_p (n))
/* n too large, would lead to out of memory
later. */
goto error;
}
}
{
/* arg_posn wrapped around. */
goto error;
}
}
else
{
;
}
}
{
{
int flags = 0;
for (;;)
{
if (*cp == 'h')
{
cp++;
}
else if (*cp == 'L')
{
flags |= 4;
cp++;
}
else if (*cp == 'l')
{
flags += 8;
cp++;
}
else if (*cp == 'j')
{
if (sizeof (intmax_t) > sizeof (long))
{
/* intmax_t = long long */
flags += 16;
}
else if (sizeof (intmax_t) > sizeof (int))
{
/* intmax_t = long */
flags += 8;
}
cp++;
}
{
/* 'z' is standardized in ISO C 99, but glibc uses 'Z'
because the warning facility in gcc-2.95.2 understands
only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784). */
if (sizeof (size_t) > sizeof (long))
{
/* size_t = long long */
flags += 16;
}
else if (sizeof (size_t) > sizeof (int))
{
/* size_t = long */
flags += 8;
}
cp++;
}
else if (*cp == 't')
{
if (sizeof (ptrdiff_t) > sizeof (long))
{
/* ptrdiff_t = long long */
flags += 16;
}
else if (sizeof (ptrdiff_t) > sizeof (int))
{
/* ptrdiff_t = long */
flags += 8;
}
cp++;
}
/* On MacOS X 10.3, PRIdMAX is defined as "qd".
We cannot change it to "lld" because PRIdMAX must also
be understood by the system's printf routines. */
else if (*cp == 'q')
{
if (64 / 8 > sizeof (long))
{
/* int64_t = long long */
flags += 16;
}
else
{
/* int64_t = long */
flags += 8;
}
cp++;
}
#endif
/* On native Win32, PRIdMAX is defined as "I64d".
We cannot change it to "lld" because PRIdMAX must also
be understood by the system's printf routines. */
{
if (64 / 8 > sizeof (long))
{
/* __int64 = long long */
flags += 16;
}
else
{
/* __int64 = long */
flags += 8;
}
cp += 3;
}
#endif
else
break;
}
/* Read the conversion character. */
c = *cp++;
switch (c)
{
case 'd': case 'i':
/* If 'long long' exists and is larger than 'long': */
else
#endif
/* If 'long long' exists and is the same as 'long', we parse
"lld" into TYPE_LONGINT. */
if (flags >= 8)
type = TYPE_LONGINT;
else if (flags & 2)
type = TYPE_SCHAR;
else if (flags & 1)
type = TYPE_SHORT;
else
break;
case 'o': case 'u': case 'x': case 'X':
/* If 'long long' exists and is larger than 'long': */
else
#endif
/* If 'unsigned long long' exists and is the same as
'unsigned long', we parse "llu" into TYPE_ULONGINT. */
if (flags >= 8)
else if (flags & 2)
type = TYPE_UCHAR;
else if (flags & 1)
type = TYPE_USHORT;
else
break;
case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
case 'a': case 'A':
else
type = TYPE_DOUBLE;
break;
case 'c':
if (flags >= 8)
#if HAVE_WINT_T
#else
goto error;
#endif
else
break;
#if HAVE_WINT_T
case 'C':
c = 'c';
break;
#endif
case 's':
if (flags >= 8)
#if HAVE_WCHAR_T
#else
goto error;
#endif
else
type = TYPE_STRING;
break;
#if HAVE_WCHAR_T
case 'S':
c = 's';
break;
#endif
case 'p':
type = TYPE_POINTER;
break;
case 'n':
/* If 'long long' exists and is larger than 'long': */
else
#endif
/* If 'long long' exists and is the same as 'long', we parse
"lln" into TYPE_COUNT_LONGINT_POINTER. */
if (flags >= 8)
else if (flags & 2)
else if (flags & 1)
else
break;
#if ENABLE_UNISTDIO
/* The unistdio extensions. */
case 'U':
if (flags >= 16)
else if (flags >= 8)
else
break;
#endif
case '%':
break;
default:
/* Unknown conversion character. */
goto error;
}
}
{
{
/* arg_posn wrapped around. */
goto error;
}
}
dp->conversion = c;
}
d->count++;
if (d->count >= d_allocated)
{
if (size_overflow_p (memory_size))
/* Overflow, would lead to out of memory. */
goto out_of_memory;
/* Out of memory. */
goto out_of_memory;
}
}
else if (!c_isascii (c))
{
/* Non-ASCII character. Not supported. */
goto error;
}
#endif
}
return 0;
if (a->arg)
if (d->dir)
return -1;
if (a->arg)
if (d->dir)
return -1;
}