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