mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-02-19 22:02:21 +02:00
printf: refactor macros to function
* src/printf.c (struct arg_cursor): New struct. (get_curr_arg): New function. (print_formatted): Use it instead of ... (GET_CURR_ARG, SET_CURR_ARG): ... these removed macros. This makes the code a bit easier to follow, and any efficiency cost should be minimal.
This commit is contained in:
186
src/printf.c
186
src/printf.c
@@ -440,6 +440,52 @@ print_direc (char const *start, char conversion,
|
||||
free (p);
|
||||
}
|
||||
|
||||
/* Set curr_arg from indexed %i$ or otherwise next in sequence.
|
||||
POS can be 0,1,2,3 corresponding to
|
||||
[%][width][.precision][conversion] respectively. */
|
||||
|
||||
struct arg_cursor
|
||||
{
|
||||
char const *f; /* Pointer into 'format'. */
|
||||
int curr_arg; /* Current offset. */
|
||||
int curr_s_arg; /* Current sequential offset. */
|
||||
int end_arg; /* End arg processed. */
|
||||
int direc_arg; /* Arg for main directive. */
|
||||
};
|
||||
static struct arg_cursor
|
||||
get_curr_arg (int pos, struct arg_cursor ac)
|
||||
{
|
||||
intmax_t arg = 0;
|
||||
size_t argl;
|
||||
/* Check with strspn() first to avoid spaces etc.
|
||||
This also avoids any locale ambiguities,
|
||||
and simplifies strtoimax errno checking. */
|
||||
if (pos < 3 && (argl = strspn (ac.f, "0123456789")) && ac.f[argl] == '$')
|
||||
arg = MIN (strtoimax (ac.f, nullptr, 10), INT_MAX);
|
||||
if (1 <= arg && arg <= INT_MAX)
|
||||
{
|
||||
/* Process indexed %i$ format. */
|
||||
arg--;
|
||||
ac.f += argl + 1;
|
||||
if (pos == 0)
|
||||
ac.direc_arg = arg;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Process sequential arg. */
|
||||
arg = (pos == 0 ? (ac.direc_arg = -1)
|
||||
: pos < 3 || ac.direc_arg < 0 ? ++ac.curr_s_arg
|
||||
: ac.direc_arg);
|
||||
}
|
||||
|
||||
if (0 <= arg)
|
||||
{
|
||||
ac.curr_arg = arg;
|
||||
ac.end_arg = MAX (ac.end_arg, arg);
|
||||
}
|
||||
return ac;
|
||||
}
|
||||
|
||||
/* Print the text in FORMAT, using ARGV (with ARGC elements) for
|
||||
arguments to any '%' directives.
|
||||
Return the number of elements of ARGV used. */
|
||||
@@ -447,52 +493,8 @@ print_direc (char const *start, char conversion,
|
||||
static int
|
||||
print_formatted (char const *format, int argc, char **argv)
|
||||
{
|
||||
|
||||
/* Set curr_arg from indexed %i$ or otherwise next in sequence.
|
||||
POS can be 0,1,2,3 corresponding to
|
||||
[%][width][.precision][conversion] respectively. */
|
||||
|
||||
#define GET_CURR_ARG(POS) \
|
||||
do { \
|
||||
intmax_t arg = 0; \
|
||||
size_t argl; \
|
||||
/* Check with strspn() first to avoid spaces etc. \
|
||||
This also avoids any locale ambiguities, \
|
||||
and simplifies strtoimax errno checking. */ \
|
||||
if (POS != 3 && (argl = strspn (f, "0123456789")) \
|
||||
&& f[argl] == '$') \
|
||||
arg = MIN (strtoimax (f, nullptr, 10), INT_MAX); \
|
||||
if (1 <= arg && arg <= INT_MAX) \
|
||||
/* Process indexed %i$ format. */ \
|
||||
{ \
|
||||
SET_CURR_ARG (arg - 1); \
|
||||
f += argl + 1; \
|
||||
if (POS == 0) \
|
||||
direc_arg = arg - 1; \
|
||||
} \
|
||||
else \
|
||||
/* Sequential arg processing. */ \
|
||||
{ \
|
||||
if (POS == 0) \
|
||||
direc_arg = -1; \
|
||||
else if (POS < 3 || direc_arg == -1) \
|
||||
SET_CURR_ARG (++curr_s_arg); \
|
||||
else \
|
||||
SET_CURR_ARG (direc_arg); \
|
||||
} \
|
||||
} while (0) \
|
||||
|
||||
#define SET_CURR_ARG(ARG) \
|
||||
do { \
|
||||
curr_arg = ARG; \
|
||||
end_arg = MAX (curr_arg, end_arg); \
|
||||
} while (0) \
|
||||
|
||||
int curr_arg = -1; /* Current offset. */
|
||||
int curr_s_arg = -1; /* Current sequential offset. */
|
||||
int end_arg = -1; /* End arg processed. */
|
||||
int direc_arg = -1; /* Arg for main directive. */
|
||||
char const *f; /* Pointer into 'format'. */
|
||||
struct arg_cursor ac;
|
||||
ac.curr_arg = ac.curr_s_arg = ac.end_arg = ac.direc_arg = -1;
|
||||
char const *direc_start; /* Start of % directive. */
|
||||
char *direc; /* Generated % directive. */
|
||||
char *pdirec; /* Pointer to current end of directive. */
|
||||
@@ -504,40 +506,40 @@ do { \
|
||||
|
||||
direc = xmalloc (strlen (format) + 1);
|
||||
|
||||
for (f = format; *f; ++f)
|
||||
for (ac.f = format; *ac.f; ac.f++)
|
||||
{
|
||||
switch (*f)
|
||||
switch (*ac.f)
|
||||
{
|
||||
case '%':
|
||||
direc_start = f;
|
||||
direc_start = ac.f;
|
||||
pdirec = direc;
|
||||
*pdirec++ = *f++;
|
||||
*pdirec++ = *ac.f++;
|
||||
have_field_width = have_precision = false;
|
||||
if (*f == '%')
|
||||
if (*ac.f == '%')
|
||||
{
|
||||
putchar ('%');
|
||||
break;
|
||||
}
|
||||
|
||||
GET_CURR_ARG (0);
|
||||
ac = get_curr_arg (0, ac);
|
||||
|
||||
if (*f == 'b')
|
||||
if (*ac.f == 'b')
|
||||
{
|
||||
/* FIXME: Field width and precision are not supported
|
||||
for %b, even though POSIX requires it. */
|
||||
GET_CURR_ARG (3);
|
||||
if (curr_arg < argc)
|
||||
print_esc_string (argv[curr_arg]);
|
||||
ac = get_curr_arg (3, ac);
|
||||
if (ac.curr_arg < argc)
|
||||
print_esc_string (argv[ac.curr_arg]);
|
||||
break;
|
||||
}
|
||||
|
||||
if (*f == 'q')
|
||||
if (*ac.f == 'q')
|
||||
{
|
||||
GET_CURR_ARG (3);
|
||||
if (curr_arg < argc)
|
||||
ac = get_curr_arg (3, ac);
|
||||
if (ac.curr_arg < argc)
|
||||
{
|
||||
fputs (quotearg_style (shell_escape_quoting_style,
|
||||
argv[curr_arg]), stdout);
|
||||
argv[ac.curr_arg]), stdout);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -547,9 +549,9 @@ do { \
|
||||
ok['f'] = ok['F'] = ok['g'] = ok['G'] = ok['i'] = ok['o'] =
|
||||
ok['s'] = ok['u'] = ok['x'] = ok['X'] = 1;
|
||||
|
||||
for (;; f++)
|
||||
for (;; ac.f++)
|
||||
{
|
||||
switch (*f)
|
||||
switch (*ac.f)
|
||||
{
|
||||
#if (__GLIBC__ == 2 && 2 <= __GLIBC_MINOR__) || 3 <= __GLIBC__
|
||||
case 'I':
|
||||
@@ -569,45 +571,45 @@ do { \
|
||||
default:
|
||||
goto no_more_flag_characters;
|
||||
}
|
||||
*pdirec++ = *f;
|
||||
*pdirec++ = *ac.f;
|
||||
}
|
||||
no_more_flag_characters:
|
||||
|
||||
if (*f == '*')
|
||||
if (*ac.f == '*')
|
||||
{
|
||||
*pdirec++ = *f++;
|
||||
*pdirec++ = *ac.f++;
|
||||
|
||||
GET_CURR_ARG (1);
|
||||
ac = get_curr_arg (1, ac);
|
||||
|
||||
if (curr_arg < argc)
|
||||
if (ac.curr_arg < argc)
|
||||
{
|
||||
intmax_t width = vstrtoimax (argv[curr_arg]);
|
||||
intmax_t width = vstrtoimax (argv[ac.curr_arg]);
|
||||
if (INT_MIN <= width && width <= INT_MAX)
|
||||
field_width = width;
|
||||
else
|
||||
error (EXIT_FAILURE, 0, _("invalid field width: %s"),
|
||||
quote (argv[curr_arg]));
|
||||
quote (argv[ac.curr_arg]));
|
||||
}
|
||||
else
|
||||
field_width = 0;
|
||||
have_field_width = true;
|
||||
}
|
||||
else
|
||||
while (ISDIGIT (*f))
|
||||
*pdirec++ = *f++;
|
||||
if (*f == '.')
|
||||
while (ISDIGIT (*ac.f))
|
||||
*pdirec++ = *ac.f++;
|
||||
if (*ac.f == '.')
|
||||
{
|
||||
*pdirec++ = *f++;
|
||||
*pdirec++ = *ac.f++;
|
||||
ok['c'] = 0;
|
||||
if (*f == '*')
|
||||
if (*ac.f == '*')
|
||||
{
|
||||
*pdirec++ = *f++;
|
||||
*pdirec++ = *ac.f++;
|
||||
|
||||
GET_CURR_ARG (2);
|
||||
ac = get_curr_arg (2, ac);
|
||||
|
||||
if (curr_arg < argc)
|
||||
if (ac.curr_arg < argc)
|
||||
{
|
||||
intmax_t prec = vstrtoimax (argv[curr_arg]);
|
||||
intmax_t prec = vstrtoimax (argv[ac.curr_arg]);
|
||||
if (prec < 0)
|
||||
{
|
||||
/* A negative precision is taken as if the
|
||||
@@ -617,7 +619,7 @@ do { \
|
||||
}
|
||||
else if (INT_MAX < prec)
|
||||
error (EXIT_FAILURE, 0, _("invalid precision: %s"),
|
||||
quote (argv[curr_arg]));
|
||||
quote (argv[ac.curr_arg]));
|
||||
else
|
||||
precision = prec;
|
||||
}
|
||||
@@ -626,45 +628,45 @@ do { \
|
||||
have_precision = true;
|
||||
}
|
||||
else
|
||||
while (ISDIGIT (*f))
|
||||
*pdirec++ = *f++;
|
||||
while (ISDIGIT (*ac.f))
|
||||
*pdirec++ = *ac.f++;
|
||||
}
|
||||
|
||||
*pdirec++ = '\0';
|
||||
|
||||
while (*f == 'l' || *f == 'L' || *f == 'h'
|
||||
|| *f == 'j' || *f == 't' || *f == 'z')
|
||||
++f;
|
||||
while (*ac.f == 'l' || *ac.f == 'L' || *ac.f == 'h'
|
||||
|| *ac.f == 'j' || *ac.f == 't' || *ac.f == 'z')
|
||||
++ac.f;
|
||||
|
||||
{
|
||||
unsigned char conversion = *f;
|
||||
int speclen = MIN (f + 1 - direc_start, INT_MAX);
|
||||
unsigned char conversion = *ac.f;
|
||||
int speclen = MIN (ac.f + 1 - direc_start, INT_MAX);
|
||||
if (! ok[conversion])
|
||||
error (EXIT_FAILURE, 0,
|
||||
_("%.*s: invalid conversion specification"),
|
||||
speclen, direc_start);
|
||||
}
|
||||
|
||||
GET_CURR_ARG (3);
|
||||
ac = get_curr_arg (3, ac);
|
||||
|
||||
print_direc (direc, *f,
|
||||
print_direc (direc, *ac.f,
|
||||
have_field_width, field_width,
|
||||
have_precision, precision,
|
||||
(argc <= curr_arg ? "" : argv[curr_arg]));
|
||||
argc <= ac.curr_arg ? "" : argv[ac.curr_arg]);
|
||||
|
||||
break;
|
||||
|
||||
case '\\':
|
||||
f += print_esc (f, false);
|
||||
ac.f += print_esc (ac.f, false);
|
||||
break;
|
||||
|
||||
default:
|
||||
putchar (*f);
|
||||
putchar (*ac.f);
|
||||
}
|
||||
}
|
||||
|
||||
free (direc);
|
||||
return MIN (argc, end_arg + 1);
|
||||
return MIN (argc, ac.end_arg + 1);
|
||||
}
|
||||
|
||||
int
|
||||
|
||||
Reference in New Issue
Block a user