.::
%.::
%*:::
%*.:::
%.*:::
%*.*::::
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