diff options
author | Paul Eggert <eggert@cs.ucla.edu> | 2021-08-29 15:22:23 -0700 |
---|---|---|
committer | Paul Eggert <eggert@cs.ucla.edu> | 2021-08-30 10:32:18 -0700 |
commit | 37ff1120ad3512971a0468cb50540ffaa41b6d89 (patch) | |
tree | 51a8837664a75760f69463cfd81fdaa612adf2eb | |
parent | 078321ebeb4d9e83e900278154dbf47ec2758295 (diff) | |
download | diffutils-37ff1120ad3512971a0468cb50540ffaa41b6d89.tar.gz |
diff: use variable arg list for messages
This simplifies the code by using varargs.
* bootstrap.conf (gnulib_modules): Add flexmember.
(XGETTEXT_OPTIONS): Do not flag message5.
* src/util.c: Include flexmember.h, stdarg.h.
(struct msg): New members msgid, argbytes. args is now
FLEXIBLE_ARRAY_MEMBER, and does not contain msgid.
All uses changed.
(message): Now varargs. Detect number of args by counting '%'s.
Use FLEXSIZEOF, to avoid problems on systems with buggy
allocators. Avoid redundant ‘*p = 0’ when *p is already zero
after stpcpy.
(message5): Remove; all callers changed to use ‘message’.
(print_message_queue): Abort if too many args were passed;
this cannot happen with current diffutils.
-rw-r--r-- | bootstrap.conf | 2 | ||||
-rw-r--r-- | src/diff.c | 20 | ||||
-rw-r--r-- | src/diff.h | 4 | ||||
-rw-r--r-- | src/util.c | 104 |
4 files changed, 74 insertions, 56 deletions
diff --git a/bootstrap.conf b/bootstrap.conf index e51b2d8..9234a43 100644 --- a/bootstrap.conf +++ b/bootstrap.conf @@ -36,6 +36,7 @@ error exclude exitfail extensions +flexmember fcntl fdl file-type @@ -103,7 +104,6 @@ XGETTEXT_OPTIONS=$XGETTEXT_OPTIONS'\\\ --flag=asprintf:2:c-format\\\ --from-code=UTF-8\\\ --flag=message:1:c-format\\\ - --flag=message5:1:c-format\\\ --flag=try_help:1:c-format\\\ --flag=vasprintf:2:c-format\\\ --flag=vasnprintf:3:c-format\\\ @@ -1382,11 +1382,11 @@ compare_files (struct comparison const *parent, /* We have two files that are not to be compared. */ /* See POSIX 1003.1-2001 for this format. */ - message5 ("File %s is a %s while file %s is a %s\n", - file_label[0] ? file_label[0] : cmp.file[0].name, - file_type (&cmp.file[0].stat), - file_label[1] ? file_label[1] : cmp.file[1].name, - file_type (&cmp.file[1].stat)); + message ("File %s is a %s while file %s is a %s\n", + file_label[0] ? file_label[0] : cmp.file[0].name, + file_type (&cmp.file[0].stat), + file_label[1] ? file_label[1] : cmp.file[1].name, + file_type (&cmp.file[1].stat)); /* This is a difference. */ status = EXIT_FAILURE; @@ -1432,11 +1432,11 @@ compare_files (struct comparison const *parent, /* We have two files that are not to be compared, because one of them is a symbolic link and the other one is not. */ - message5 ("File %s is a %s while file %s is a %s\n", - file_label[0] ? file_label[0] : cmp.file[0].name, - file_type (&cmp.file[0].stat), - file_label[1] ? file_label[1] : cmp.file[1].name, - file_type (&cmp.file[1].stat)); + message ("File %s is a %s while file %s is a %s\n", + file_label[0] ? file_label[0] : cmp.file[0].name, + file_type (&cmp.file[0].stat), + file_label[1] ? file_label[1] : cmp.file[1].name, + file_type (&cmp.file[1].stat)); /* This is a difference. */ status = EXIT_FAILURE; @@ -392,9 +392,7 @@ extern void cleanup_signal_handlers (void); extern void debug_script (struct change *); extern void fatal (char const *) __attribute__((noreturn)); extern void finish_output (void); -extern void message (char const *, char const *, char const *); -extern void message5 (char const *, char const *, char const *, - char const *, char const *); +extern void message (char const *, ...) _GL_ATTRIBUTE_FORMAT ((printf, 1, 2)); extern void output_1_line (char const *, char const *, char const *, char const *); extern void perror_with_name (char const *); @@ -19,12 +19,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include "diff.h" -#include "argmatch.h" -#include "die.h" + +#include <argmatch.h> +#include <die.h> #include <dirname.h> #include <error.h> +#include <flexmember.h> #include <system-quote.h> #include <xalloc.h> + +#include <stdarg.h> #include <signal.h> /* Use SA_NOCLDSTOP as a proxy for whether the sigaction machinery is @@ -49,7 +53,15 @@ char const pr_program[] = PR_PROGRAM; struct msg { struct msg *next; - char args[1]; /* Format + 4 args, each '\0' terminated, concatenated. */ + + /* Msgid of printf-style format. */ + char const *msgid; + + /* Number of bytes in ARGS. */ + size_t argbytes; + + /* Arg strings, each '\0' terminated, concatenated. */ + char args[FLEXIBLE_ARRAY_MEMBER]; }; /* Head of the chain of queues messages. */ @@ -89,42 +101,43 @@ fatal (char const *msgid) } /* Like printf, except if -l in effect then save the message and print later. + Also, all arguments must be char * or char const *. This is used for things like "Only in ...". */ void -message (char const *format_msgid, char const *arg1, char const *arg2) +message (char const *format_msgid, ...) { - message5 (format_msgid, arg1, arg2, 0, 0); -} + va_list ap; + va_start (ap, format_msgid); -void -message5 (char const *format_msgid, char const *arg1, char const *arg2, - char const *arg3, char const *arg4) -{ if (paginate) { - char *p; - char const *arg[5]; - size_t total_size = offsetof (struct msg, args); - struct msg *new; - - arg[0] = format_msgid; - arg[1] = arg1; - arg[2] = arg2; - arg[3] = arg3 ? arg3 : ""; - arg[4] = arg4 ? arg4 : ""; - - for (int i = 0; i < 5; i++) - total_size += strlen (arg[i]) + 1; - - new = xmalloc (total_size); - - p = new->args; - for (int i = 0; i < 5; i++) - { - p = stpcpy (p, arg[i]); - *p++ = 0; - } + size_t argbytes = 0; + + for (char const *m = format_msgid; *m; m++) + if (*m == '%') + { + if (m[1] == '%') + m++; + else + argbytes += strlen (va_arg (ap, char const *)) + 1; + } + va_end (ap); + + struct msg *new = xmalloc (FLEXSIZEOF (struct msg, args, argbytes)); + new->msgid = format_msgid; + new->argbytes = argbytes; + + va_start (ap, format_msgid); + char *p = new->args; + for (char const *m = format_msgid; *m; m++) + if (*m == '%') + { + if (m[1] == '%') + m++; + else + p = stpcpy (p, va_arg (ap, char const *)) + 1; + } *msg_chain_end = new; new->next = 0; @@ -134,8 +147,10 @@ message5 (char const *format_msgid, char const *arg1, char const *arg2, { if (sdiff_merge_assist) putchar (' '); - printf (_(format_msgid), arg1, arg2, arg3, arg4); + vprintf (_(format_msgid), ap); } + + va_end (ap); } /* Output all the messages that were saved up by calls to 'message'. */ @@ -143,17 +158,22 @@ message5 (char const *format_msgid, char const *arg1, char const *arg2, void print_message_queue (void) { - char const *arg[5]; - int i; - struct msg *m = msg_chain; - - while (m) + for (struct msg *m = msg_chain; m; ) { + /* Change this if diff ever has messages with more than 4 args. */ + char const *p = m->args; + char const *plim = p + m->argbytes; + char const *arg[4]; + for (int i = 0; i < 4; i++) + { + arg[i] = p; + if (p < plim) + p += strlen (p) + 1; + } + printf (_(m->msgid), arg[0], arg[1], arg[2], arg[3]); + if (p < plim) + abort (); struct msg *next = m->next; - arg[0] = m->args; - for (i = 0; i < 4; i++) - arg[i + 1] = arg[i] + strlen (arg[i]) + 1; - printf (_(arg[0]), arg[1], arg[2], arg[3], arg[4]); free (m); m = next; } |