Example #1
0
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 = 1;
  d->dir = malloc (d_allocated * sizeof (DIRECTIVE));
  if (d->dir == NULL)
    /* Out of memory.  */
    return -1;

  a->count = 0;
  a_allocated = 0;
  a->arg = NULL;

#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 error;							\
	memory = (a->arg						\
		  ? realloc (a->arg, memory_size)			\
		  : malloc (memory_size));				\
	if (memory == NULL)						\
	  /* Out of memory.  */						\
	  goto error;							\
	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++;
		}
	      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++;
		    }
#ifdef HAVE_INTMAX_T
		  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++;
		    }
#endif
		  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++;
		    }
		  else
		    break;
		}

	      /* Read the conversion character.  */
	      c = *cp++;
	      switch (c)
		{
		case 'd': case 'i':
#ifdef HAVE_LONG_LONG
		  if (flags >= 16 || (flags & 4))
		    type = TYPE_LONGLONGINT;
		  else
#endif
		  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':
#ifdef HAVE_LONG_LONG
		  if (flags >= 16 || (flags & 4))
		    type = TYPE_ULONGLONGINT;
		  else
#endif
		  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':
#ifdef HAVE_LONG_DOUBLE
		  if (flags >= 16 || (flags & 4))
		    type = TYPE_LONGDOUBLE;
		  else
#endif
		  type = TYPE_DOUBLE;
		  break;
		case 'c':
		  if (flags >= 8)
#ifdef HAVE_WINT_T
		    type = TYPE_WIDE_CHAR;
#else
		    goto error;
#endif
		  else
		    type = TYPE_CHAR;
		  break;
#ifdef HAVE_WINT_T
		case 'C':
		  type = TYPE_WIDE_CHAR;
		  c = 'c';
		  break;
#endif
		case 's':
		  if (flags >= 8)
#ifdef HAVE_WCHAR_T
		    type = TYPE_WIDE_STRING;
#else
		    goto error;
#endif
		  else
		    type = TYPE_STRING;
		  break;
#ifdef HAVE_WCHAR_T
		case 'S':
		  type = TYPE_WIDE_STRING;
		  c = 's';
		  break;
#endif
		case 'p':
		  type = TYPE_POINTER;
		  break;
		case 'n':
#ifdef HAVE_LONG_LONG
		  if (flags >= 16 || (flags & 4))
		    type = TYPE_COUNT_LONGLONGINT_POINTER;
		  else
#endif
		  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;
		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;
	  }
Example #2
0
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
                  /* 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
                  /* 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
                  /* 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;
          }
Example #3
0
STATIC
#endif
    int
printf_parse (const char *format, char_directives * d, arguments * a)
{
  const char *cp = format;      /* pointer into format */
  int arg_posn = 0;             /* number of regular arguments consumed */
  unsigned int d_allocated;     /* allocated elements of d->dir */
  unsigned int a_allocated;     /* allocated elements of a->arg */
  unsigned int max_width_length = 0;
  unsigned int max_precision_length = 0;

  d->count = 0;
  d_allocated = 1;
  d->dir = malloc (d_allocated * sizeof (char_directive));
  if (d->dir == NULL)
    /* Out of memory.  */
    return -1;

  a->count = 0;
  a_allocated = 0;
  a->arg = NULL;

#define REGISTER_ARG(_index_,_type_) \
  {									\
    unsigned int n = (_index_);						\
    if (n >= a_allocated)						\
      {									\
	argument *memory;						\
	a_allocated = 2 * a_allocated;					\
	if (a_allocated <= n)						\
	  a_allocated = n + 1;						\
	memory = (a->arg						\
		  ? realloc (a->arg, a_allocated * sizeof (argument))	\
		  : malloc (a_allocated * sizeof (argument)));		\
	if (memory == NULL)						\
	  /* Out of memory.  */						\
	  goto error;							\
	a->arg = memory;						\
      }									\
    while (a->count <= n) {                             \
      a->arg[a->count].type = TYPE_NONE;                \
      a->arg[a->count].ext_string = (char *) 0;         \
      ++a->count;                                       \
    }                                                   \
    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 c = *cp++;
    if (c == '%') {
      int arg_index = -1;
      char_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 = -1;
      dp->precision_start = NULL;
      dp->precision_end = NULL;
      dp->precision_arg_index = -1;
      dp->arg_index = -1;

      /* Test for positional argument.  */
      if (*cp >= '0' && *cp <= '9') {
        const char *np;

        for (np = cp; *np >= '0' && *np <= '9'; np++);
        if (*np == '$') {
          unsigned int n = 0;

          for (np = cp; *np >= '0' && *np <= '9'; np++)
            n = 10 * n + (*np - '0');
          if (n == 0)
            /* Positional argument 0.  */
            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++;
        } 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 *np;

          for (np = cp; *np >= '0' && *np <= '9'; np++);
          if (*np == '$') {
            unsigned int n = 0;

            for (np = cp; *np >= '0' && *np <= '9'; np++)
              n = 10 * n + (*np - '0');
            if (n == 0)
              /* Positional argument 0.  */
              goto error;
            dp->width_arg_index = n - 1;
            cp = np + 1;
          }
        }
        if (dp->width_arg_index < 0)
          dp->width_arg_index = arg_posn++;
        REGISTER_ARG (dp->width_arg_index, TYPE_INT);
      } else if (*cp >= '0' && *cp <= '9') {
        unsigned int 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 *np;

            for (np = cp; *np >= '0' && *np <= '9'; np++);
            if (*np == '$') {
              unsigned int n = 0;

              for (np = cp; *np >= '0' && *np <= '9'; np++)
                n = 10 * n + (*np - '0');
              if (n == 0)
                /* Positional argument 0.  */
                goto error;
              dp->precision_arg_index = n - 1;
              cp = np + 1;
            }
          }
          if (dp->precision_arg_index < 0)
            dp->precision_arg_index = arg_posn++;
          REGISTER_ARG (dp->precision_arg_index, TYPE_INT);
        } else {
          unsigned int 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++;
            }
#ifdef HAVE_INT64_AND_I64
            else if (cp[0] == 'I' && cp[1] == '6' && cp[2] == '4') {
              flags = 64;
              cp += 3;
            }
#endif
#ifdef HAVE_INTMAX_T
            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++;
            }
#endif
            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++;
            } else
              break;
          }

          /* Read the conversion character.  */
          c = *cp++;
          switch (c) {
            case 'd':
            case 'i':
#ifdef HAVE_INT64_AND_I64
              if (flags == 64)
                type = TYPE_INT64;
              else
#endif
#ifdef HAVE_LONG_LONG
              if (flags >= 16 || (flags & 4))
                type = TYPE_LONGLONGINT;
              else
#endif
              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':
#ifdef HAVE_INT64_AND_I64
              if (flags == 64)
                type = TYPE_UINT64;
              else
#endif
#ifdef HAVE_LONG_LONG
              if (flags >= 16 || (flags & 4))
                type = TYPE_ULONGLONGINT;
              else
#endif
              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':
#ifdef HAVE_LONG_DOUBLE
              if (flags >= 16 || (flags & 4))
                type = TYPE_LONGDOUBLE;
              else
#endif
                type = TYPE_DOUBLE;
              break;
            case 'c':
              if (flags >= 8)
#ifdef HAVE_WINT_T
                type = TYPE_WIDE_CHAR;
#else
                goto error;
#endif
              else
                type = TYPE_CHAR;
              break;
#ifdef HAVE_WINT_T
            case 'C':
              type = TYPE_WIDE_CHAR;
              c = 'c';
              break;
#endif
            case 's':
              if (flags >= 8)
#ifdef HAVE_WCHAR_T
                type = TYPE_WIDE_STRING;
#else
                goto error;
#endif
              else
                type = TYPE_STRING;
              break;
#ifdef HAVE_WCHAR_T
            case 'S':
              type = TYPE_WIDE_STRING;
              c = 's';
              break;
#endif
              /* Old GST_PTR_FORMAT, handle for binary backwards compatibility */
            case 'P':
              type = TYPE_POINTER_EXT;
              dp->flags |= FLAG_PTR_EXT;
              dp->ptr_ext_char = 'A';
              c = 'p';
              break;
            case 'p':
              /* Note: cp points already to the char after the 'p' now */
              if (cp[0] == POINTER_EXT_SIGNIFIER_CHAR && cp[1] != '\0') {
                type = TYPE_POINTER_EXT;
                dp->flags |= FLAG_PTR_EXT;
                dp->ptr_ext_char = cp[1];
                cp += 2;
                /* we do not use dp->conversion='s' on purpose here, so we
                 * can fall back to printing just the pointer with %p if the
                 * serialisation function returned NULL for some reason */
              } else {
                type = TYPE_POINTER;
              }
              break;
              /* Old GST_SEGMENT_FORMAT, handle for backwards compatibility */
            case 'Q':
              type = TYPE_POINTER_EXT;
              dp->flags |= FLAG_PTR_EXT;
              dp->ptr_ext_char = 'B';
              c = 'p';
              break;
            case 'n':
#ifdef HAVE_LONG_LONG
              if (flags >= 16 || (flags & 4))
                type = TYPE_COUNT_LONGLONGINT_POINTER;
              else
#endif
              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;
            case '%':
              type = TYPE_NONE;
              break;
            default:
              /* Unknown conversion character.  */
              goto error;
          }
        }

        if (type != TYPE_NONE) {
          dp->arg_index = arg_index;
          if (dp->arg_index < 0)
            dp->arg_index = arg_posn++;
          REGISTER_ARG (dp->arg_index, type);
        }
        dp->conversion = c;
        dp->dir_end = cp;
      }