From eb7e2aa9334d80747c6f6c4f093716fd030f3f15 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 22 Jan 2014 17:19:55 +0200 Subject: [PATCH] checkpoint actions: further improvements. * NEWS: Update. * doc/tar.texi: Update. * src/buffer.c (print_stats): Avoid use of additional string buffer. Allow for text to be NULL. Call gettext if it is not. (format_total_stats): Don't use gettext when calling print_stats. * src/checkpoint.c (def_format): Change default format. (format_checkpoint_string): Implement optional arguments for T conversion. (finish_checkpoint_actions): Rename to checkpoint_flush_actions, make extern. All uses changed. * src/common.h (checkpoint_flush_actions): New proto. * src/tar.c (main): Set error_hook --- NEWS | 23 ++++++++++++++--------- doc/tar.texi | 24 ++++++++++++++++-------- src/buffer.c | 33 +++++++++++++++++---------------- src/checkpoint.c | 47 ++++++++++++++++++++++++++++++++++++++--------- src/common.h | 1 + src/tar.c | 2 ++ 6 files changed, 88 insertions(+), 42 deletions(-) diff --git a/NEWS b/NEWS index ceda138..1444143 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU tar NEWS - User visible changes. 2014-01-21 +GNU tar NEWS - User visible changes. 2014-01-22 Please send GNU tar bug reports to @@ -11,14 +11,19 @@ total number of bytes transferred at each checkpoint. * Extended checkpoint format specification. -New conversion specifiers are implemented: - - %d - output number of seconds since tar started - %T - output I/O totals - %{FMT}t - output current local time using FMT as strftime(3) format - If {FMT} is omitted, use %c - %{N}* - pad output with spaces to the Nth column, or to the - current screen width, if {N} is not given. +New conversion specifiers are implemented. Some of them take +optional arguments, supplied in curly braces between the percent +sign and the specifier letter. + + %d - output number of seconds since tar started + %{r,w,d}T - output I/O totals; optional arguments supply prefixes + to be used before number of bytes read, written and + deleted, correspondingly. + %{FMT}t - output current local time using FMT as strftime(3) format + If {FMT} is omitted, use %c + %{N}* - pad output with spaces to the Nth column, or to the + current screen width, if {N} is not given. + %c - a shortcut for "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r" version 1.27.1 - Sergey Poznyakoff, 2013-11-17 diff --git a/doc/tar.texi b/doc/tar.texi index 979e242..424617c 100644 --- a/doc/tar.texi +++ b/doc/tar.texi @@ -3975,7 +3975,10 @@ tar: Hit write checkpoint #20 tar: Hit write checkpoint #30 @end smallexample -The complete list of available format specifiers follows: +The complete list of available format specifiers follows. Some of +them can take optional arguments. These arguments, if given, are +supplied in curly braces between the percent sign and the specifier +letter. @table @samp @item %s @@ -3984,17 +3987,18 @@ Print type of the checkpoint (@samp{write} or @samp{read}). @item %u Print number of the checkpoint. -@item %T +@item %@{r,w,d@}T Print number of bytes transferred so far and approximate transfer -speed. The number is preceded by @samp{W:}, when writing and by -@samp{R:} when reading. If @command{tar} is performing delete -operation (@pxref{delete}), three numbers are printed: number of bytes -read, written and deleted, each of them prefixed by @samp{R:}, -@samp{W:} and @samp{D:} correspondingy. For example: +speed. Optional arguments supply prefixes to be used before number +of bytes read, written and deleted, correspondingly. If absent, +they default to @samp{R}. @samp{W}, @samp{D}. Any or all of them can +be omitted, so, that e.g. @samp{%@{@}T} means to print corresponding +statistics without any prefixes. Any surplus arguments, if present, +are silently ignored. @example $ @kbd{tar --delete -f f.tar --checkpoint-action=echo="#%u: %T" main.c} -tar: #1: R: 0 (0B, ?/s),W: 0 (0B, ?/s),D: 0 +tar: #1: R: 0 (0B, 0B/s),W: 0 (0B, 0B/s),D: 0 tar: #2: R: 10240 (10KiB, 19MiB/s),W: 0 (0B, 0B/s),D: 10240 @end example @@ -4012,6 +4016,10 @@ for the current locale. Pad output with spaces to the @var{n}th column. If the @samp{@{@var{n}@}} part is omitted, the current screen width is assumed. + +@item %@var{c} +This is a shortcut for @samp{%@{%Y-%m-%d %H:%M:%S@}t: %ds, %@{read,wrote@}T%*\r}, +intended mainly for use with @samp{ttyout} action (see below). @end table Aside from format expansion, the message string is subject to diff --git a/src/buffer.c b/src/buffer.c index 648b6ba..4cfcb0e 100644 --- a/src/buffer.c +++ b/src/buffer.c @@ -492,20 +492,20 @@ open_compressed_archive (void) static int print_stats (FILE *fp, const char *text, tarlong numbytes) { - char bytes[sizeof (tarlong) * CHAR_BIT]; char abbr[LONGEST_HUMAN_READABLE + 1]; char rate[LONGEST_HUMAN_READABLE + 1]; - + int n = 0; + int human_opts = human_autoscale | human_base_1024 | human_SI | human_B; - sprintf (bytes, TARLONG_FORMAT, numbytes); - - return fprintf (fp, "%s: %s (%s, %s/s)", - text, bytes, - human_readable (numbytes, abbr, human_opts, 1, 1), - (0 < duration && numbytes / duration < (uintmax_t) -1 - ? human_readable (numbytes / duration, rate, human_opts, 1, 1) - : "?")); + if (text && text[0]) + n += fprintf (fp, "%s: ", gettext (text)); + return n + fprintf (fp, TARLONG_FORMAT " (%s, %s/s)", + numbytes, + human_readable (numbytes, abbr, human_opts, 1, 1), + (0 < duration && numbytes / duration < (uintmax_t) -1 + ? human_readable (numbytes / duration, rate, human_opts, 1, 1) + : "?")); } /* Format totals to file FP. FORMATS is an array of strings to output @@ -524,27 +524,28 @@ format_total_stats (FILE *fp, const char **formats, int eor, int eol) case CAT_SUBCOMMAND: case UPDATE_SUBCOMMAND: case APPEND_SUBCOMMAND: - n = print_stats (fp, _(formats[TF_WRITE]), + n = print_stats (fp, formats[TF_WRITE], prev_written + bytes_written); break; case DELETE_SUBCOMMAND: { char buf[UINTMAX_STRSIZE_BOUND]; - n = print_stats (fp, _(formats[TF_READ]), + n = print_stats (fp, formats[TF_READ], records_read * record_size); fputc (eor, fp); n++; - n += print_stats (fp, _(formats[TF_WRITE]), + n += print_stats (fp, formats[TF_WRITE], prev_written + bytes_written); fputc (eor, fp); n++; - - n += fprintf (fp, "%s: %s", - _(formats[TF_DELETED]), + + if (formats[TF_DELETED] && formats[TF_DELETED][0]) + n += fprintf (fp, "%s: ", gettext (formats[TF_DELETED])); + n += fprintf (fp, "%s", STRINGIFY_BIGINT ((records_read - records_skipped) * record_size - (prev_written + bytes_written), buf)); diff --git a/src/checkpoint.c b/src/checkpoint.c index 3c3ca78..f19bf3a 100644 --- a/src/checkpoint.c +++ b/src/checkpoint.c @@ -185,7 +185,8 @@ getarg (const char *input, const char ** endp, char **argbuf, size_t *arglen) static int tty_cleanup; -static const char *def_format = "%s: %t: %T%*\r"; +static const char *def_format = + "%{%Y-%m-%d %H:%M:%S}t: %ds, %{read,wrote}T%*\r"; static int format_checkpoint_string (FILE *fp, size_t len, @@ -254,8 +255,33 @@ format_checkpoint_string (FILE *fp, size_t len, break; case 'T': - compute_duration (); - len += format_total_stats (fp, checkpoint_total_format, ',', 0); + { + const char **fmt = checkpoint_total_format, *fmtbuf[3]; + struct wordsplit ws; + compute_duration (); + + if (arg) + { + ws.ws_delim = ","; + if (wordsplit (arg, &ws, WRDSF_NOVAR | WRDSF_NOCMD | + WRDSF_QUOTE | WRDSF_DELIM)) + ERROR ((0, 0, _("cannot split string '%s': %s"), + arg, wordsplit_strerror (&ws))); + else + { + int i; + + for (i = 0; i < ws.ws_wordc; i++) + fmtbuf[i] = ws.ws_wordv[i]; + for (; i < 3; i++) + fmtbuf[i] = NULL; + fmt = fmtbuf; + } + } + len += format_total_stats (fp, fmt, ',', 0); + if (arg) + wordsplit_free (&ws); + } break; case 't': @@ -362,11 +388,11 @@ run_checkpoint_actions (bool do_write) } } -static void -finish_checkpoint_actions (void) +void +checkpoint_flush_actions (void) { struct checkpoint_action *p; - + for (p = checkpoint_action; p; p = p->next) { switch (p->opcode) @@ -378,14 +404,13 @@ finish_checkpoint_actions (void) while (w--) fputc (' ', tty); fputc ('\r', tty); + fflush (tty); } break; default: /* nothing */; } } - if (tty) - fclose (tty); } void @@ -399,5 +424,9 @@ void checkpoint_finish (void) { if (checkpoint_option) - finish_checkpoint_actions (); + { + checkpoint_flush_actions (); + if (tty) + fclose (tty); + } } diff --git a/src/common.h b/src/common.h index 81e21fa..8f8a337 100644 --- a/src/common.h +++ b/src/common.h @@ -862,6 +862,7 @@ void checkpoint_compile_action (const char *str); void checkpoint_finish_compile (void); void checkpoint_run (bool do_write); void checkpoint_finish (void); +void checkpoint_flush_actions (void); /* Module warning.c */ #define WARN_ALONE_ZERO_BLOCK 0x00000001 diff --git a/src/tar.c b/src/tar.c index 59cde36..300a834 100644 --- a/src/tar.c +++ b/src/tar.c @@ -2623,6 +2623,8 @@ main (int argc, char **argv) exit_failure = TAREXIT_FAILURE; exit_status = TAREXIT_SUCCESS; + error_hook = checkpoint_flush_actions; + filename_terminator = '\n'; set_quoting_style (0, DEFAULT_QUOTING_STYLE); -- 2.45.2