Home | History | Annotate | Line # | Download | only in lib
printf-parse.c revision 1.1
      1 /* Formatted output to strings.
      2    Copyright (C) 1999-2000, 2002-2003 Free Software Foundation, Inc.
      3 
      4    This program is free software; you can redistribute it and/or modify
      5    it under the terms of the GNU General Public License as published by
      6    the Free Software Foundation; either version 2, or (at your option)
      7    any later version.
      8 
      9    This program is distributed in the hope that it will be useful,
     10    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     12    GNU General Public License for more details.
     13 
     14    You should have received a copy of the GNU General Public License along
     15    with this program; if not, write to the Free Software Foundation,
     16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
     17 
     18 #ifdef HAVE_CONFIG_H
     19 # include <config.h>
     20 #endif
     21 
     22 /* Specification.  */
     23 #if WIDE_CHAR_VERSION
     24 # include "wprintf-parse.h"
     25 #else
     26 # include "printf-parse.h"
     27 #endif
     28 
     29 /* Get size_t, NULL.  */
     30 #include <stddef.h>
     31 
     32 /* Get intmax_t.  */
     33 #if HAVE_STDINT_H_WITH_UINTMAX
     34 # include <stdint.h>
     35 #endif
     36 #if HAVE_INTTYPES_H_WITH_UINTMAX
     37 # include <inttypes.h>
     38 #endif
     39 
     40 /* malloc(), realloc(), free().  */
     41 #include <stdlib.h>
     42 
     43 /* Checked size_t computations.  */
     44 #include "xsize.h"
     45 
     46 #if WIDE_CHAR_VERSION
     47 # define PRINTF_PARSE wprintf_parse
     48 # define CHAR_T wchar_t
     49 # define DIRECTIVE wchar_t_directive
     50 # define DIRECTIVES wchar_t_directives
     51 #else
     52 # define PRINTF_PARSE printf_parse
     53 # define CHAR_T char
     54 # define DIRECTIVE char_directive
     55 # define DIRECTIVES char_directives
     56 #endif
     57 
     58 #ifdef STATIC
     59 STATIC
     60 #endif
     61 int
     62 PRINTF_PARSE (const CHAR_T *format, DIRECTIVES *d, arguments *a)
     63 {
     64   const CHAR_T *cp = format;		/* pointer into format */
     65   size_t arg_posn = 0;		/* number of regular arguments consumed */
     66   size_t d_allocated;			/* allocated elements of d->dir */
     67   size_t a_allocated;			/* allocated elements of a->arg */
     68   size_t max_width_length = 0;
     69   size_t max_precision_length = 0;
     70 
     71   d->count = 0;
     72   d_allocated = 1;
     73   d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
     74   if (d->dir == NULL)
     75     /* Out of memory.  */
     76     return -1;
     77 
     78   a->count = 0;
     79   a_allocated = 0;
     80   a->arg = NULL;
     81 
     82 #define REGISTER_ARG(_index_,_type_) \
     83   {									\
     84     size_t n = (_index_);						\
     85     if (n >= a_allocated)						\
     86       {									\
     87 	size_t memory_size;						\
     88 	argument *memory;						\
     89 									\
     90 	a_allocated = xtimes (a_allocated, 2);				\
     91 	if (a_allocated <= n)						\
     92 	  a_allocated = xsum (n, 1);					\
     93 	memory_size = xtimes (a_allocated, sizeof (argument));		\
     94 	if (size_overflow_p (memory_size))				\
     95 	  /* Overflow, would lead to out of memory.  */			\
     96 	  goto error;							\
     97 	memory = (a->arg						\
     98 		  ? realloc (a->arg, memory_size)			\
     99 		  : malloc (memory_size));				\
    100 	if (memory == NULL)						\
    101 	  /* Out of memory.  */						\
    102 	  goto error;							\
    103 	a->arg = memory;						\
    104       }									\
    105     while (a->count <= n)						\
    106       a->arg[a->count++].type = TYPE_NONE;				\
    107     if (a->arg[n].type == TYPE_NONE)					\
    108       a->arg[n].type = (_type_);					\
    109     else if (a->arg[n].type != (_type_))				\
    110       /* Ambiguous type for positional argument.  */			\
    111       goto error;							\
    112   }
    113 
    114   while (*cp != '\0')
    115     {
    116       CHAR_T c = *cp++;
    117       if (c == '%')
    118 	{
    119 	  size_t arg_index = ARG_NONE;
    120 	  DIRECTIVE *dp = &d->dir[d->count];/* pointer to next directive */
    121 
    122 	  /* Initialize the next directive.  */
    123 	  dp->dir_start = cp - 1;
    124 	  dp->flags = 0;
    125 	  dp->width_start = NULL;
    126 	  dp->width_end = NULL;
    127 	  dp->width_arg_index = ARG_NONE;
    128 	  dp->precision_start = NULL;
    129 	  dp->precision_end = NULL;
    130 	  dp->precision_arg_index = ARG_NONE;
    131 	  dp->arg_index = ARG_NONE;
    132 
    133 	  /* Test for positional argument.  */
    134 	  if (*cp >= '0' && *cp <= '9')
    135 	    {
    136 	      const CHAR_T *np;
    137 
    138 	      for (np = cp; *np >= '0' && *np <= '9'; np++)
    139 		;
    140 	      if (*np == '$')
    141 		{
    142 		  size_t n = 0;
    143 
    144 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
    145 		    n = xsum (xtimes (n, 10), *np - '0');
    146 		  if (n == 0)
    147 		    /* Positional argument 0.  */
    148 		    goto error;
    149 		  if (size_overflow_p (n))
    150 		    /* n too large, would lead to out of memory later.  */
    151 		    goto error;
    152 		  arg_index = n - 1;
    153 		  cp = np + 1;
    154 		}
    155 	    }
    156 
    157 	  /* Read the flags.  */
    158 	  for (;;)
    159 	    {
    160 	      if (*cp == '\'')
    161 		{
    162 		  dp->flags |= FLAG_GROUP;
    163 		  cp++;
    164 		}
    165 	      else if (*cp == '-')
    166 		{
    167 		  dp->flags |= FLAG_LEFT;
    168 		  cp++;
    169 		}
    170 	      else if (*cp == '+')
    171 		{
    172 		  dp->flags |= FLAG_SHOWSIGN;
    173 		  cp++;
    174 		}
    175 	      else if (*cp == ' ')
    176 		{
    177 		  dp->flags |= FLAG_SPACE;
    178 		  cp++;
    179 		}
    180 	      else if (*cp == '#')
    181 		{
    182 		  dp->flags |= FLAG_ALT;
    183 		  cp++;
    184 		}
    185 	      else if (*cp == '0')
    186 		{
    187 		  dp->flags |= FLAG_ZERO;
    188 		  cp++;
    189 		}
    190 	      else
    191 		break;
    192 	    }
    193 
    194 	  /* Parse the field width.  */
    195 	  if (*cp == '*')
    196 	    {
    197 	      dp->width_start = cp;
    198 	      cp++;
    199 	      dp->width_end = cp;
    200 	      if (max_width_length < 1)
    201 		max_width_length = 1;
    202 
    203 	      /* Test for positional argument.  */
    204 	      if (*cp >= '0' && *cp <= '9')
    205 		{
    206 		  const CHAR_T *np;
    207 
    208 		  for (np = cp; *np >= '0' && *np <= '9'; np++)
    209 		    ;
    210 		  if (*np == '$')
    211 		    {
    212 		      size_t n = 0;
    213 
    214 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
    215 			n = xsum (xtimes (n, 10), *np - '0');
    216 		      if (n == 0)
    217 			/* Positional argument 0.  */
    218 			goto error;
    219 		      if (size_overflow_p (n))
    220 			/* n too large, would lead to out of memory later.  */
    221 			goto error;
    222 		      dp->width_arg_index = n - 1;
    223 		      cp = np + 1;
    224 		    }
    225 		}
    226 	      if (dp->width_arg_index == ARG_NONE)
    227 		{
    228 		  dp->width_arg_index = arg_posn++;
    229 		  if (dp->width_arg_index == ARG_NONE)
    230 		    /* arg_posn wrapped around.  */
    231 		    goto error;
    232 		}
    233 	      REGISTER_ARG (dp->width_arg_index, TYPE_INT);
    234 	    }
    235 	  else if (*cp >= '0' && *cp <= '9')
    236 	    {
    237 	      size_t width_length;
    238 
    239 	      dp->width_start = cp;
    240 	      for (; *cp >= '0' && *cp <= '9'; cp++)
    241 		;
    242 	      dp->width_end = cp;
    243 	      width_length = dp->width_end - dp->width_start;
    244 	      if (max_width_length < width_length)
    245 		max_width_length = width_length;
    246 	    }
    247 
    248 	  /* Parse the precision.  */
    249 	  if (*cp == '.')
    250 	    {
    251 	      cp++;
    252 	      if (*cp == '*')
    253 		{
    254 		  dp->precision_start = cp - 1;
    255 		  cp++;
    256 		  dp->precision_end = cp;
    257 		  if (max_precision_length < 2)
    258 		    max_precision_length = 2;
    259 
    260 		  /* Test for positional argument.  */
    261 		  if (*cp >= '0' && *cp <= '9')
    262 		    {
    263 		      const CHAR_T *np;
    264 
    265 		      for (np = cp; *np >= '0' && *np <= '9'; np++)
    266 			;
    267 		      if (*np == '$')
    268 			{
    269 			  size_t n = 0;
    270 
    271 			  for (np = cp; *np >= '0' && *np <= '9'; np++)
    272 			    n = xsum (xtimes (n, 10), *np - '0');
    273 			  if (n == 0)
    274 			    /* Positional argument 0.  */
    275 			    goto error;
    276 			  if (size_overflow_p (n))
    277 			    /* n too large, would lead to out of memory
    278 			       later.  */
    279 			    goto error;
    280 			  dp->precision_arg_index = n - 1;
    281 			  cp = np + 1;
    282 			}
    283 		    }
    284 		  if (dp->precision_arg_index == ARG_NONE)
    285 		    {
    286 		      dp->precision_arg_index = arg_posn++;
    287 		      if (dp->precision_arg_index == ARG_NONE)
    288 			/* arg_posn wrapped around.  */
    289 			goto error;
    290 		    }
    291 		  REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
    292 		}
    293 	      else
    294 		{
    295 		  size_t precision_length;
    296 
    297 		  dp->precision_start = cp - 1;
    298 		  for (; *cp >= '0' && *cp <= '9'; cp++)
    299 		    ;
    300 		  dp->precision_end = cp;
    301 		  precision_length = dp->precision_end - dp->precision_start;
    302 		  if (max_precision_length < precision_length)
    303 		    max_precision_length = precision_length;
    304 		}
    305 	    }
    306 
    307 	  {
    308 	    arg_type type;
    309 
    310 	    /* Parse argument type/size specifiers.  */
    311 	    {
    312 	      int flags = 0;
    313 
    314 	      for (;;)
    315 		{
    316 		  if (*cp == 'h')
    317 		    {
    318 		      flags |= (1 << (flags & 1));
    319 		      cp++;
    320 		    }
    321 		  else if (*cp == 'L')
    322 		    {
    323 		      flags |= 4;
    324 		      cp++;
    325 		    }
    326 		  else if (*cp == 'l')
    327 		    {
    328 		      flags += 8;
    329 		      cp++;
    330 		    }
    331 #ifdef HAVE_INTMAX_T
    332 		  else if (*cp == 'j')
    333 		    {
    334 		      if (sizeof (intmax_t) > sizeof (long))
    335 			{
    336 			  /* intmax_t = long long */
    337 			  flags += 16;
    338 			}
    339 		      else if (sizeof (intmax_t) > sizeof (int))
    340 			{
    341 			  /* intmax_t = long */
    342 			  flags += 8;
    343 			}
    344 		      cp++;
    345 		    }
    346 #endif
    347 		  else if (*cp == 'z' || *cp == 'Z')
    348 		    {
    349 		      /* 'z' is standardized in ISO C 99, but glibc uses 'Z'
    350 			 because the warning facility in gcc-2.95.2 understands
    351 			 only 'Z' (see gcc-2.95.2/gcc/c-common.c:1784).  */
    352 		      if (sizeof (size_t) > sizeof (long))
    353 			{
    354 			  /* size_t = long long */
    355 			  flags += 16;
    356 			}
    357 		      else if (sizeof (size_t) > sizeof (int))
    358 			{
    359 			  /* size_t = long */
    360 			  flags += 8;
    361 			}
    362 		      cp++;
    363 		    }
    364 		  else if (*cp == 't')
    365 		    {
    366 		      if (sizeof (ptrdiff_t) > sizeof (long))
    367 			{
    368 			  /* ptrdiff_t = long long */
    369 			  flags += 16;
    370 			}
    371 		      else if (sizeof (ptrdiff_t) > sizeof (int))
    372 			{
    373 			  /* ptrdiff_t = long */
    374 			  flags += 8;
    375 			}
    376 		      cp++;
    377 		    }
    378 		  else
    379 		    break;
    380 		}
    381 
    382 	      /* Read the conversion character.  */
    383 	      c = *cp++;
    384 	      switch (c)
    385 		{
    386 		case 'd': case 'i':
    387 #ifdef HAVE_LONG_LONG
    388 		  if (flags >= 16 || (flags & 4))
    389 		    type = TYPE_LONGLONGINT;
    390 		  else
    391 #endif
    392 		  if (flags >= 8)
    393 		    type = TYPE_LONGINT;
    394 		  else if (flags & 2)
    395 		    type = TYPE_SCHAR;
    396 		  else if (flags & 1)
    397 		    type = TYPE_SHORT;
    398 		  else
    399 		    type = TYPE_INT;
    400 		  break;
    401 		case 'o': case 'u': case 'x': case 'X':
    402 #ifdef HAVE_LONG_LONG
    403 		  if (flags >= 16 || (flags & 4))
    404 		    type = TYPE_ULONGLONGINT;
    405 		  else
    406 #endif
    407 		  if (flags >= 8)
    408 		    type = TYPE_ULONGINT;
    409 		  else if (flags & 2)
    410 		    type = TYPE_UCHAR;
    411 		  else if (flags & 1)
    412 		    type = TYPE_USHORT;
    413 		  else
    414 		    type = TYPE_UINT;
    415 		  break;
    416 		case 'f': case 'F': case 'e': case 'E': case 'g': case 'G':
    417 		case 'a': case 'A':
    418 #ifdef HAVE_LONG_DOUBLE
    419 		  if (flags >= 16 || (flags & 4))
    420 		    type = TYPE_LONGDOUBLE;
    421 		  else
    422 #endif
    423 		  type = TYPE_DOUBLE;
    424 		  break;
    425 		case 'c':
    426 		  if (flags >= 8)
    427 #ifdef HAVE_WINT_T
    428 		    type = TYPE_WIDE_CHAR;
    429 #else
    430 		    goto error;
    431 #endif
    432 		  else
    433 		    type = TYPE_CHAR;
    434 		  break;
    435 #ifdef HAVE_WINT_T
    436 		case 'C':
    437 		  type = TYPE_WIDE_CHAR;
    438 		  c = 'c';
    439 		  break;
    440 #endif
    441 		case 's':
    442 		  if (flags >= 8)
    443 #ifdef HAVE_WCHAR_T
    444 		    type = TYPE_WIDE_STRING;
    445 #else
    446 		    goto error;
    447 #endif
    448 		  else
    449 		    type = TYPE_STRING;
    450 		  break;
    451 #ifdef HAVE_WCHAR_T
    452 		case 'S':
    453 		  type = TYPE_WIDE_STRING;
    454 		  c = 's';
    455 		  break;
    456 #endif
    457 		case 'p':
    458 		  type = TYPE_POINTER;
    459 		  break;
    460 		case 'n':
    461 #ifdef HAVE_LONG_LONG
    462 		  if (flags >= 16 || (flags & 4))
    463 		    type = TYPE_COUNT_LONGLONGINT_POINTER;
    464 		  else
    465 #endif
    466 		  if (flags >= 8)
    467 		    type = TYPE_COUNT_LONGINT_POINTER;
    468 		  else if (flags & 2)
    469 		    type = TYPE_COUNT_SCHAR_POINTER;
    470 		  else if (flags & 1)
    471 		    type = TYPE_COUNT_SHORT_POINTER;
    472 		  else
    473 		    type = TYPE_COUNT_INT_POINTER;
    474 		  break;
    475 		case '%':
    476 		  type = TYPE_NONE;
    477 		  break;
    478 		default:
    479 		  /* Unknown conversion character.  */
    480 		  goto error;
    481 		}
    482 	    }
    483 
    484 	    if (type != TYPE_NONE)
    485 	      {
    486 		dp->arg_index = arg_index;
    487 		if (dp->arg_index == ARG_NONE)
    488 		  {
    489 		    dp->arg_index = arg_posn++;
    490 		    if (dp->arg_index == ARG_NONE)
    491 		      /* arg_posn wrapped around.  */
    492 		      goto error;
    493 		  }
    494 		REGISTER_ARG (dp->arg_index, type);
    495 	      }
    496 	    dp->conversion = c;
    497 	    dp->dir_end = cp;
    498 	  }
    499 
    500 	  d->count++;
    501 	  if (d->count >= d_allocated)
    502 	    {
    503 	      size_t memory_size;
    504 	      DIRECTIVE *memory;
    505 
    506 	      d_allocated = xtimes (d_allocated, 2);
    507 	      memory_size = xtimes (d_allocated, sizeof (DIRECTIVE));
    508 	      if (size_overflow_p (memory_size))
    509 		/* Overflow, would lead to out of memory.  */
    510 		goto error;
    511 	      memory = realloc (d->dir, memory_size);
    512 	      if (memory == NULL)
    513 		/* Out of memory.  */
    514 		goto error;
    515 	      d->dir = memory;
    516 	    }
    517 	}
    518     }
    519   d->dir[d->count].dir_start = cp;
    520 
    521   d->max_width_length = max_width_length;
    522   d->max_precision_length = max_precision_length;
    523   return 0;
    524 
    525 error:
    526   if (a->arg)
    527     free (a->arg);
    528   if (d->dir)
    529     free (d->dir);
    530   return -1;
    531 }
    532 
    533 #undef DIRECTIVES
    534 #undef DIRECTIVE
    535 #undef CHAR_T
    536 #undef PRINTF_PARSE
    537