.::
   %.::
   %*:::
   %*.:::
   %.*:::
   %*.*::::
   Return 0 on success, -1 on failure.  */
static int
do_printf (char *fmt, size_t idx,
	   const struct wp *w, bool point, const struct wp *p,
	   const char *l, char c, type_t val)
{
  int wpval[2] = { 0 };
  size_t nint = 0;
  int result;
  size_t i;
  if (w != NULL)
    {
      if (w->s == NULL)
	{
	  fmt[idx++] = '*';
	  wpval[nint++] = w->i;
	}
      else
	for (i = 0; w->s[i] != '\0'; i++)
	  fmt[idx++] = w->s[i];
    }
  if (point)
    fmt[idx++] = '.';
  if (p != NULL)
    {
      if (p->s == NULL)
	{
	  fmt[idx++] = '*';
	  wpval[nint++] = p->i;
	}
      else
	for (i = 0; p->s[i] != '\0'; i++)
	  fmt[idx++] = p->s[i];
    }
  for (i = 0; length[i] != '\0'; i++)
    fmt[idx++] = length[i];
  fmt[idx++] = c;
  fmt[idx] = ':';
  fmt[idx + 1] = '\0';
  if (fputs (fmt, stdout) == EOF)
    {
      perror ("fputs");
      return -1;
    }
  fmt[idx++] = '\0';
  if (nint > 0)
    {
      result = printf ("%i:", wpval[0]);
      if (result < 0)
	{
	  perror ("printf");
	  return -1;
	}
      if (nint > 1)
	{
	  result = printf ("%i:", wpval[1]);
	  if (result < 0)
	    {
	      perror ("printf");
	      return -1;
	    }
	}
    }
  switch (nint)
    {
    case 0:
      result = printf_under_test (fmt, val);
      break;
    case 1:
      result = printf_under_test (fmt, wpval[0], val);
      break;
    case 2:
      result = printf_under_test (fmt, wpval[0], wpval[1], val);
      break;
    default:
      fputs ("Broken test, nint > 2\n", stderr);
      return -1;
    }
  if (result < 0)
    return -1;
  if (fputs (":\n", stdout) == EOF)
    {
      perror ("fputs");
      return -1;
    }
  return 0;
}
/* Produce a list of records according to '%' and zero or more output
   format flags already provided in FMT at indices 0..IDX-1, iterating
   over widths and precisions defined in global WP array, any length
   modifiers L, conversion C, and value VAL.  Inline '0' is omitted for
   the width, as it is a flag already handled among the flags supplied.
   Precision is omitted where the conversion does not allow it.
   Return 0 on success, -1 on failure.  */
static int
do_printf_flags (char *fmt, size_t idx, const char *l, char c, type_t val)
{
  bool do_prec = strchr (PREC_FORMATS, c) != NULL;
  size_t i;
  if (do_printf (fmt, idx, NULL, false, NULL, l, c, val) < 0)
    return -1;
  if (do_prec && do_printf (fmt, idx, NULL, true, NULL, l, c, val) < 0)
    return -1;
  for (i = 0; i < array_length (wp); i++)
    {
      size_t j;
      if (do_prec && do_printf (fmt, idx, NULL, true, wp + i, l, c, val) < 0)
	return -1;
      /* Inline '0' is a flag rather than width and is handled elsewhere.  */
      if (wp[i].s != NULL && wp[i].s[0] == '0' && wp[i].s[1] == '\0')
	continue;
      if (do_printf (fmt, idx, wp + i, false, NULL, l, c, val) < 0)
	return -1;
      if (do_prec)
	{
	  if (do_printf (fmt, idx, wp + i, true, NULL, l, c, val) < 0)
	    return -1;
	  for (j = 0; j < array_length (wp); j++)
	    if (do_printf (fmt, idx, wp + i, true, wp + j, l, c, val) < 0)
	      return -1;
	}
    }
  return 0;
}
/* Produce a list of records using the formatted output specifier
   supplied in ARGV[1] preceded by any length modifier supplied in
   the global LENGTH variable, iterating over format flags defined
   in the global FLAGS array, and values supplied in the global VALS
   array.  Note that the output specifier supplied is not verified
   against TYPE_T, so undefined behavior will result if this is used
   incorrectly.
   If PREC is nonzero, then this record:
   prec:
   is produced at the beginning.  Then for each VAL from VALS a block
   of records is produced starting with:
   val:
   where VAL is formatted according to REF_FMT output format.  The
   block continues with records as shown with DO_PRINTF above using
   flags iterated over according to TST_PRINTF_DUPS.
   See the top of this file for the definitions that have to be
   provided by the source including this skeleton.  */
static int
do_test (int argc, char *argv[])
{
  char fmt[100] = {'%'};
  size_t j;
  size_t v;
  char c;
  if (argc < 2 || *argv[1] == '\0')
    {
      fprintf (stderr, "Usage: %s \n", basename (argv[0]));
      return EXIT_FAILURE;
    }
  mtrace ();
  if (PREC && printf ("prec:%i\n", PREC) < 0)
    {
      perror ("printf");
      return EXIT_FAILURE;
    }
  c = *argv[1];
  for (v = 0; v < array_length (vals); v++)
    {
      if (printf ("val:%" REF_FMT "\n", REF_VAL (vals[v])) < 0)
	{
	  perror ("printf");
	  return EXIT_FAILURE;
	}
      if (do_printf_flags (fmt, 1, length, c, vals[v]) < 0)
	return EXIT_FAILURE;
      for (j = 0; j < array_length (flags); j++)
	{
	  bool done = false;
	  size_t i[j + 1];
	  size_t k;
	  memset (i, 0, sizeof (i));
	  while (!done)
	    {
	      bool skip = false;
	      size_t idx = 1;
	      char f;
	      for (k = 0; k <= j; k++)
		{
		  const char *s = flags[i[k]].s;
		  if (s && strchr (s, c) == NULL)
		    skip = true;
		  if (!TST_PRINTF_DUPS && j > 1 && k > 0 && i[k] >= i[k - 1])
		    skip = true;
		  if (skip)
		    break;
		  f = flags[i[k]].f;
		  fmt[idx++] = f;
		}
	      if (!skip && do_printf_flags (fmt, idx, length, c, vals[v]) < 0)
		return EXIT_FAILURE;
	      for (k = 0; k <= j; k++)
		{
		  i[k]++;
		  if (i[k] < array_length (flags))
		    break;
		  else if (k == j)
		    done = true;
		  else
		    i[k] = 0;
		}
	    }
	}
    }
  return EXIT_SUCCESS;
}
/* Interpose 'dladdr' with a stub to speed up malloc tracing.  */
int
dladdr (const void *addr, Dl_info *info)
{
  return 0;
}
#define TEST_FUNCTION_ARGV do_test
#include