mirror of
				https://git.proxmox.com/git/grub2
				synced 2025-10-31 20:49:57 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			639 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			639 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* Formatted output to strings.
 | |
|    Copyright (C) 1999-2000, 2002-2003, 2006-2013 Free Software Foundation, Inc.
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    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, see <http://www.gnu.org/licenses/>.  */
 | |
| 
 | |
| /* 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 PRINTF_PARSE printf_parse
 | |
| # define CHAR_T char
 | |
| # define DIRECTIVE char_directive
 | |
| # define DIRECTIVES char_directives
 | |
| #endif
 | |
| 
 | |
| /* Get size_t, NULL.  */
 | |
| #include <stddef.h>
 | |
| 
 | |
| /* Get intmax_t.  */
 | |
| #if defined IN_LIBINTL || defined IN_LIBASPRINTF
 | |
| # if HAVE_STDINT_H_WITH_UINTMAX
 | |
| #  include <stdint.h>
 | |
| # endif
 | |
| # if HAVE_INTTYPES_H_WITH_UINTMAX
 | |
| #  include <inttypes.h>
 | |
| # endif
 | |
| #else
 | |
| # include <stdint.h>
 | |
| #endif
 | |
| 
 | |
| /* malloc(), realloc(), free().  */
 | |
| #include <stdlib.h>
 | |
| 
 | |
| /* memcpy().  */
 | |
| #include <string.h>
 | |
| 
 | |
| /* errno.  */
 | |
| #include <errno.h>
 | |
| 
 | |
| /* Checked size_t computations.  */
 | |
| #include "xsize.h"
 | |
| 
 | |
| #if CHAR_T_ONLY_ASCII
 | |
| /* c_isascii().  */
 | |
| # include "c-ctype.h"
 | |
| #endif
 | |
| 
 | |
| #ifdef STATIC
 | |
| STATIC
 | |
| #endif
 | |
| int
 | |
| PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
 | |
| {
 | |
|   const CHAR_T *cp = format;    /* pointer into format */
 | |
|   size_t arg_posn = 0;          /* number of regular arguments consumed */
 | |
|   size_t d_allocated;           /* allocated elements of d->dir */
 | |
|   size_t a_allocated;           /* allocated elements of a->arg */
 | |
|   size_t max_width_length = 0;
 | |
|   size_t max_precision_length = 0;
 | |
| 
 | |
|   d->count = 0;
 | |
|   d_allocated = N_DIRECT_ALLOC_DIRECTIVES;
 | |
|   d->dir = d->direct_alloc_dir;
 | |
| 
 | |
|   a->count = 0;
 | |
|   a_allocated = N_DIRECT_ALLOC_ARGUMENTS;
 | |
|   a->arg = a->direct_alloc_arg;
 | |
| 
 | |
| #define REGISTER_ARG(_index_,_type_) \
 | |
|   {                                                                     \
 | |
|     size_t n = (_index_);                                               \
 | |
|     if (n >= a_allocated)                                               \
 | |
|       {                                                                 \
 | |
|         size_t memory_size;                                             \
 | |
|         argument *memory;                                               \
 | |
|                                                                         \
 | |
|         a_allocated = xtimes (a_allocated, 2);                          \
 | |
|         if (a_allocated <= n)                                           \
 | |
|           a_allocated = xsum (n, 1);                                    \
 | |
|         memory_size = xtimes (a_allocated, sizeof (argument));          \
 | |
|         if (size_overflow_p (memory_size))                              \
 | |
|           /* Overflow, would lead to out of memory.  */                 \
 | |
|           goto out_of_memory;                                           \
 | |
|         memory = (argument *) (a->arg != a->direct_alloc_arg            \
 | |
|                                ? realloc (a->arg, memory_size)          \
 | |
|                                : malloc (memory_size));                 \
 | |
|         if (memory == NULL)                                             \
 | |
|           /* Out of memory.  */                                         \
 | |
|           goto out_of_memory;                                           \
 | |
|         if (a->arg == a->direct_alloc_arg)                              \
 | |
|           memcpy (memory, a->arg, a->count * sizeof (argument));        \
 | |
|         a->arg = memory;                                                \
 | |
|       }                                                                 \
 | |
|     while (a->count <= n)                                               \
 | |
|       a->arg[a->count++].type = TYPE_NONE;                              \
 | |
|     if (a->arg[n].type == TYPE_NONE)                                    \
 | |
|       a->arg[n].type = (_type_);                                        \
 | |
|     else if (a->arg[n].type != (_type_))                                \
 | |
|       /* Ambiguous type for positional argument.  */                    \
 | |
|       goto error;                                                       \
 | |
|   }
 | |
| 
 | |
|   while (*cp != '\0')
 | |
|     {
 | |
|       CHAR_T c = *cp++;
 | |
|       if (c == '%')
 | |
|         {
 | |
|           size_t arg_index = ARG_NONE;
 | |
|           DIRECTIVE *dp = &d->dir[d->count]; /* pointer to next directive */
 | |
| 
 | |
|           /* Initialize the next directive.  */
 | |
|           dp->dir_start = cp - 1;
 | |
|           dp->flags = 0;
 | |
|           dp->width_start = NULL;
 | |
|           dp->width_end = NULL;
 | |
|           dp->width_arg_index = ARG_NONE;
 | |
|           dp->precision_start = NULL;
 | |
|           dp->precision_end = NULL;
 | |
|           dp->precision_arg_index = ARG_NONE;
 | |
|           dp->arg_index = ARG_NONE;
 | |
| 
 | |
|           /* Test for positional argument.  */
 | |
|           if (*cp >= '0' && *cp <= '9')
 | |
|             {
 | |
|               const CHAR_T *np;
 | |
| 
 | |
|               for (np = cp; *np >= '0' && *np <= '9'; np++)
 | |
|                 ;
 | |
|               if (*np == '$')
 | |
|                 {
 | |
|                   size_t n = 0;
 | |
| 
 | |
|                   for (np = cp; *np >= '0' && *np <= '9'; np++)
 | |
|                     n = xsum (xtimes (n, 10), *np - '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;
 | |
|                   cp = np + 1;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|           /* Read the flags.  */
 | |
|           for (;;)
 | |
|             {
 | |
|               if (*cp == '\'')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_GROUP;
 | |
|                   cp++;
 | |
|                 }
 | |
|               else if (*cp == '-')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_LEFT;
 | |
|                   cp++;
 | |
|                 }
 | |
|               else if (*cp == '+')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_SHOWSIGN;
 | |
|                   cp++;
 | |
|                 }
 | |
|               else if (*cp == ' ')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_SPACE;
 | |
|                   cp++;
 | |
|                 }
 | |
|               else if (*cp == '#')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_ALT;
 | |
|                   cp++;
 | |
|                 }
 | |
|               else if (*cp == '0')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_ZERO;
 | |
|                   cp++;
 | |
|                 }
 | |
| #if __GLIBC__ >= 2 && !defined __UCLIBC__
 | |
|               else if (*cp == 'I')
 | |
|                 {
 | |
|                   dp->flags |= FLAG_LOCALIZED;
 | |
|                   cp++;
 | |
|                 }
 | |
| #endif
 | |
|               else
 | |
|                 break;
 | |
|             }
 | |
| 
 | |
|           /* Parse the field width.  */
 | |
|           if (*cp == '*')
 | |
|             {
 | |
|               dp->width_start = cp;
 | |
|               cp++;
 | |
|               dp->width_end = cp;
 | |
|               if (max_width_length < 1)
 | |
|                 max_width_length = 1;
 | |
| 
 | |
|               /* Test for positional argument.  */
 | |
|               if (*cp >= '0' && *cp <= '9')
 | |
|                 {
 | |
|                   const CHAR_T *np;
 | |
| 
 | |
|                   for (np = cp; *np >= '0' && *np <= '9'; np++)
 | |
|                     ;
 | |
|                   if (*np == '$')
 | |
|                     {
 | |
|                       size_t n = 0;
 | |
| 
 | |
|                       for (np = cp; *np >= '0' && *np <= '9'; np++)
 | |
|                         n = xsum (xtimes (n, 10), *np - '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;
 | |
|                       dp->width_arg_index = n - 1;
 | |
|                       cp = np + 1;
 | |
|                     }
 | |
|                 }
 | |
|               if (dp->width_arg_index == ARG_NONE)
 | |
|                 {
 | |
|                   dp->width_arg_index = arg_posn++;
 | |
|                   if (dp->width_arg_index == ARG_NONE)
 | |
|                     /* arg_posn wrapped around.  */
 | |
|                     goto error;
 | |
|                 }
 | |
|               REGISTER_ARG (dp->width_arg_index, TYPE_INT);
 | |
|             }
 | |
|           else if (*cp >= '0' && *cp <= '9')
 | |
|             {
 | |
|               size_t width_length;
 | |
| 
 | |
|               dp->width_start = cp;
 | |
|               for (; *cp >= '0' && *cp <= '9'; cp++)
 | |
|                 ;
 | |
|               dp->width_end = cp;
 | |
|               width_length = dp->width_end - dp->width_start;
 | |
|               if (max_width_length < width_length)
 | |
|                 max_width_length = width_length;
 | |
|             }
 | |
| 
 | |
|           /* Parse the precision.  */
 | |
|           if (*cp == '.')
 | |
|             {
 | |
|               cp++;
 | |
|               if (*cp == '*')
 | |
|                 {
 | |
|                   dp->precision_start = cp - 1;
 | |
|                   cp++;
 | |
|                   dp->precision_end = cp;
 | |
|                   if (max_precision_length < 2)
 | |
|                     max_precision_length = 2;
 | |
| 
 | |
|                   /* Test for positional argument.  */
 | |
|                   if (*cp >= '0' && *cp <= '9')
 | |
|                     {
 | |
|                       const CHAR_T *np;
 | |
| 
 | |
|                       for (np = cp; *np >= '0' && *np <= '9'; np++)
 | |
|                         ;
 | |
|                       if (*np == '$')
 | |
|                         {
 | |
|                           size_t n = 0;
 | |
| 
 | |
|                           for (np = cp; *np >= '0' && *np <= '9'; np++)
 | |
|                             n = xsum (xtimes (n, 10), *np - '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;
 | |
|                           dp->precision_arg_index = n - 1;
 | |
|                           cp = np + 1;
 | |
|                         }
 | |
|                     }
 | |
|                   if (dp->precision_arg_index == ARG_NONE)
 | |
|                     {
 | |
|                       dp->precision_arg_index = arg_posn++;
 | |
|                       if (dp->precision_arg_index == ARG_NONE)
 | |
|                         /* arg_posn wrapped around.  */
 | |
|                         goto error;
 | |
|                     }
 | |
|                   REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
 | |
|                 }
 | |
|               else
 | |
|                 {
 | |
|                   size_t precision_length;
 | |
| 
 | |
|                   dp->precision_start = cp - 1;
 | |
|                   for (; *cp >= '0' && *cp <= '9'; cp++)
 | |
|                     ;
 | |
|                   dp->precision_end = cp;
 | |
|                   precision_length = dp->precision_end - dp->precision_start;
 | |
|                   if (max_precision_length < precision_length)
 | |
|                     max_precision_length = precision_length;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|           {
 | |
|             arg_type type;
 | |
| 
 | |
|             /* Parse argument type/size specifiers.  */
 | |
|             {
 | |
|               int flags = 0;
 | |
| 
 | |
|               for (;;)
 | |
|                 {
 | |
|                   if (*cp == 'h')
 | |
|                     {
 | |
|                       flags |= (1 << (flags & 1));
 | |
|                       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++;
 | |
|                     }
 | |
|                   else if (*cp == 'z' || *cp == 'Z')
 | |
|                     {
 | |
|                       /* '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++;
 | |
|                     }
 | |
| #if defined __APPLE__ && defined __MACH__
 | |
|                   /* On Mac OS 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
 | |
| #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 | |
|                   /* On native Windows, PRIdMAX is defined as "I64d".
 | |
|                      We cannot change it to "lld" because PRIdMAX must also
 | |
|                      be understood by the system's printf routines.  */
 | |
|                   else if (*cp == 'I' && cp[1] == '6' && cp[2] == '4')
 | |
|                     {
 | |
|                       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 HAVE_LONG_LONG_INT
 | |
|                   /* If 'long long' exists and is larger than 'long':  */
 | |
|                   if (flags >= 16 || (flags & 4))
 | |
|                     type = TYPE_LONGLONGINT;
 | |
|                   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
 | |
|                     type = TYPE_INT;
 | |
|                   break;
 | |
|                 case 'o': case 'u': case 'x': case 'X':
 | |
| #if HAVE_LONG_LONG_INT
 | |
|                   /* If 'long long' exists and is larger than 'long':  */
 | |
|                   if (flags >= 16 || (flags & 4))
 | |
|                     type = TYPE_ULONGLONGINT;
 | |
|                   else
 | |
| #endif
 | |
|                   /* If 'unsigned long long' exists and is the same as
 | |
|                      'unsigned long', we parse "llu" into TYPE_ULONGINT.  */
 | |
|                   if (flags >= 8)
 | |
|                     type = TYPE_ULONGINT;
 | |
|                   else if (flags & 2)
 | |
|                     type = TYPE_UCHAR;
 | |
|                   else if (flags & 1)
 | |
|                     type = TYPE_USHORT;
 | |
|                   else
 | |
|                     type = TYPE_UINT;
 | |
|                   break;
 | |
|                 case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
 | |
|                 case 'a': case 'A':
 | |
|                   if (flags >= 16 || (flags & 4))
 | |
|                     type = TYPE_LONGDOUBLE;
 | |
|                   else
 | |
|                     type = TYPE_DOUBLE;
 | |
|                   break;
 | |
|                 case 'c':
 | |
|                   if (flags >= 8)
 | |
| #if HAVE_WINT_T
 | |
|                     type = TYPE_WIDE_CHAR;
 | |
| #else
 | |
|                     goto error;
 | |
| #endif
 | |
|                   else
 | |
|                     type = TYPE_CHAR;
 | |
|                   break;
 | |
| #if HAVE_WINT_T
 | |
|                 case 'C':
 | |
|                   type = TYPE_WIDE_CHAR;
 | |
|                   c = 'c';
 | |
|                   break;
 | |
| #endif
 | |
|                 case 's':
 | |
|                   if (flags >= 8)
 | |
| #if HAVE_WCHAR_T
 | |
|                     type = TYPE_WIDE_STRING;
 | |
| #else
 | |
|                     goto error;
 | |
| #endif
 | |
|                   else
 | |
|                     type = TYPE_STRING;
 | |
|                   break;
 | |
| #if HAVE_WCHAR_T
 | |
|                 case 'S':
 | |
|                   type = TYPE_WIDE_STRING;
 | |
|                   c = 's';
 | |
|                   break;
 | |
| #endif
 | |
|                 case 'p':
 | |
|                   type = TYPE_POINTER;
 | |
|                   break;
 | |
|                 case 'n':
 | |
| #if HAVE_LONG_LONG_INT
 | |
|                   /* If 'long long' exists and is larger than 'long':  */
 | |
|                   if (flags >= 16 || (flags & 4))
 | |
|                     type = TYPE_COUNT_LONGLONGINT_POINTER;
 | |
|                   else
 | |
| #endif
 | |
|                   /* If 'long long' exists and is the same as 'long', we parse
 | |
|                      "lln" into TYPE_COUNT_LONGINT_POINTER.  */
 | |
|                   if (flags >= 8)
 | |
|                     type = TYPE_COUNT_LONGINT_POINTER;
 | |
|                   else if (flags & 2)
 | |
|                     type = TYPE_COUNT_SCHAR_POINTER;
 | |
|                   else if (flags & 1)
 | |
|                     type = TYPE_COUNT_SHORT_POINTER;
 | |
|                   else
 | |
|                     type = TYPE_COUNT_INT_POINTER;
 | |
|                   break;
 | |
| #if ENABLE_UNISTDIO
 | |
|                 /* The unistdio extensions.  */
 | |
|                 case 'U':
 | |
|                   if (flags >= 16)
 | |
|                     type = TYPE_U32_STRING;
 | |
|                   else if (flags >= 8)
 | |
|                     type = TYPE_U16_STRING;
 | |
|                   else
 | |
|                     type = TYPE_U8_STRING;
 | |
|                   break;
 | |
| #endif
 | |
|                 case '%':
 | |
|                   type = TYPE_NONE;
 | |
|                   break;
 | |
|                 default:
 | |
|                   /* Unknown conversion character.  */
 | |
|                   goto error;
 | |
|                 }
 | |
|             }
 | |
| 
 | |
|             if (type != TYPE_NONE)
 | |
|               {
 | |
|                 dp->arg_index = arg_index;
 | |
|                 if (dp->arg_index == ARG_NONE)
 | |
|                   {
 | |
|                     dp->arg_index = arg_posn++;
 | |
|                     if (dp->arg_index == ARG_NONE)
 | |
|                       /* arg_posn wrapped around.  */
 | |
|                       goto error;
 | |
|                   }
 | |
|                 REGISTER_ARG (dp->arg_index, type);
 | |
|               }
 | |
|             dp->conversion = c;
 | |
|             dp->dir_end = cp;
 | |
|           }
 | |
| 
 | |
|           d->count++;
 | |
|           if (d->count >= d_allocated)
 | |
|             {
 | |
|               size_t memory_size;
 | |
|               DIRECTIVE *memory;
 | |
| 
 | |
|               d_allocated = xtimes (d_allocated, 2);
 | |
|               memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
 | |
|               if (size_overflow_p (memory_size))
 | |
|                 /* Overflow, would lead to out of memory.  */
 | |
|                 goto out_of_memory;
 | |
|               memory = (DIRECTIVE *) (d->dir != d->direct_alloc_dir
 | |
|                                       ? realloc (d->dir, memory_size)
 | |
|                                       : malloc (memory_size));
 | |
|               if (memory == NULL)
 | |
|                 /* Out of memory.  */
 | |
|                 goto out_of_memory;
 | |
|               if (d->dir == d->direct_alloc_dir)
 | |
|                 memcpy (memory, d->dir, d->count * sizeof (DIRECTIVE));
 | |
|               d->dir = memory;
 | |
|             }
 | |
|         }
 | |
| #if CHAR_T_ONLY_ASCII
 | |
|       else if (!c_isascii (c))
 | |
|         {
 | |
|           /* Non-ASCII character.  Not supported.  */
 | |
|           goto error;
 | |
|         }
 | |
| #endif
 | |
|     }
 | |
|   d->dir[d->count].dir_start = cp;
 | |
| 
 | |
|   d->max_width_length = max_width_length;
 | |
|   d->max_precision_length = max_precision_length;
 | |
|   return 0;
 | |
| 
 | |
| error:
 | |
|   if (a->arg != a->direct_alloc_arg)
 | |
|     free (a->arg);
 | |
|   if (d->dir != d->direct_alloc_dir)
 | |
|     free (d->dir);
 | |
|   errno = EINVAL;
 | |
|   return -1;
 | |
| 
 | |
| out_of_memory:
 | |
|   if (a->arg != a->direct_alloc_arg)
 | |
|     free (a->arg);
 | |
|   if (d->dir != d->direct_alloc_dir)
 | |
|     free (d->dir);
 | |
|   errno = ENOMEM;
 | |
|   return -1;
 | |
| }
 | |
| 
 | |
| #undef PRINTF_PARSE
 | |
| #undef DIRECTIVES
 | |
| #undef DIRECTIVE
 | |
| #undef CHAR_T_ONLY_ASCII
 | |
| #undef CHAR_T
 | 
