X-Git-Url: https://git.dogcows.com/gitweb?a=blobdiff_plain;f=src%2Fcheckpoint.c;h=54e7b5967de2bd77233eaa920f1d4f8cacd86738;hb=4423e1743e10c79ce8430c9740923c82281ca579;hp=76374524a1f9d340cdc5fe2f73a907dadb9d43d9;hpb=f0a1f78196f75678424712ac36f0a4a46e3e5658;p=chaz%2Ftar diff --git a/src/checkpoint.c b/src/checkpoint.c index 7637452..54e7b59 100644 --- a/src/checkpoint.c +++ b/src/checkpoint.c @@ -1,6 +1,6 @@ /* Checkpoint management for tar. - Copyright 2007, 2013 Free Software Foundation, Inc. + Copyright 2007, 2013-2014 Free Software Foundation, Inc. This file is part of GNU tar. @@ -21,6 +21,7 @@ #include "common.h" #include "wordsplit.h" #include +#include #include "fprintftime.h" enum checkpoint_opcode @@ -134,27 +135,32 @@ checkpoint_finish_compile (void) checkpoint_option = DEFAULT_CHECKPOINT; } -static char *checkpoint_total_format[] = { +static const char *checkpoint_total_format[] = { "R", "W", "D" }; -static int -getwidth(FILE *fp) +static long +getwidth (FILE *fp) { + char const *columns; + +#ifdef TIOCGWINSZ struct winsize ws; + if (ioctl (fileno (fp), TIOCGWINSZ, &ws) == 0 && 0 < ws.ws_col) + return ws.ws_col; +#endif - ws.ws_col = ws.ws_row = 0; - if ((ioctl (fileno (fp), TIOCGWINSZ, (char *) &ws) < 0) || ws.ws_col == 0) + columns = getenv ("COLUMNS"); + if (columns) { - const char *col = getenv ("COLUMNS"); - if (col) - return strtol (col, NULL, 10); - else - return 80; + long int col = strtol (columns, NULL, 10); + if (0 < col) + return col; } - return ws.ws_col; + + return 80; } static char * @@ -183,21 +189,25 @@ getarg (const char *input, const char ** endp, char **argbuf, size_t *arglen) return NULL; } +static int tty_cleanup; -static void -format_checkpoint_string (FILE *fp, const char *input, bool do_write, +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, + const char *input, bool do_write, unsigned cpn) { const char *opstr = do_write ? gettext ("write") : gettext ("read"); char uintbuf[UINTMAX_STRSIZE_BOUND]; char *cps = STRINGIFY_BIGINT (cpn, uintbuf); const char *ip; - size_t len = 0; static char *argbuf = NULL; static size_t arglen = 0; char *arg = NULL; - + if (!input) { if (do_write) @@ -213,7 +223,7 @@ format_checkpoint_string (FILE *fp, const char *input, bool do_write, *not* "Leyendo un punto de comprobaci@'on" */ input = gettext ("Read checkpoint %u"); } - + for (ip = input; *ip; ip++) { if (*ip == '%') @@ -231,6 +241,11 @@ format_checkpoint_string (FILE *fp, const char *input, bool do_write, } switch (*ip) { + case 'c': + len += format_checkpoint_string (fp, len, def_format, do_write, + cpn); + break; + case 'u': fputs (cps, fp); len += strlen (cps); @@ -244,32 +259,57 @@ format_checkpoint_string (FILE *fp, const char *input, bool do_write, case 'd': len += fprintf (fp, "%.0f", compute_duration ()); 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': { struct timeval tv; struct tm *tm; - char *fmt = arg ? arg : "%c"; + const char *fmt = arg ? arg : "%c"; gettimeofday (&tv, NULL); tm = localtime (&tv.tv_sec); len += fprintftime (fp, fmt, tm, 0, tv.tv_usec * 1000); } break; - + case '*': { - int w = arg ? strtoul (arg, NULL, 10) : getwidth (fp); + long w = arg ? strtol (arg, NULL, 10) : getwidth (fp); for (; w > len; len++) fputc (' ', fp); } break; - + default: fputc ('%', fp); fputc (*ip, fp); @@ -282,19 +322,24 @@ format_checkpoint_string (FILE *fp, const char *input, bool do_write, { fputc (*ip, fp); if (*ip == '\r') - len = 0; + { + len = 0; + tty_cleanup = 1; + } else len++; } } fflush (fp); + return len; } +static FILE *tty = NULL; + static void run_checkpoint_actions (bool do_write) { struct checkpoint_action *p; - FILE *tty = NULL; for (p = checkpoint_action; p; p = p->next) { @@ -316,20 +361,20 @@ run_checkpoint_actions (bool do_write) break; case cop_echo: - fprintf (stderr, "%s: ", program_name); - format_checkpoint_string (stderr, p->v.command, do_write, checkpoint); - fputc ('\n', stderr); + { + int n = fprintf (stderr, "%s: ", program_name); + format_checkpoint_string (stderr, n, p->v.command, do_write, + checkpoint); + fputc ('\n', stderr); + } break; case cop_ttyout: if (!tty) tty = fopen ("/dev/tty", "w"); if (tty) - { - format_checkpoint_string (tty, p->v.command, do_write, - checkpoint); - fflush (tty); - } + format_checkpoint_string (tty, 0, p->v.command, do_write, + checkpoint); break; case cop_sleep: @@ -347,8 +392,31 @@ run_checkpoint_actions (bool do_write) print_total_stats (); } } - if (tty) - fclose (tty); +} + +void +checkpoint_flush_actions (void) +{ + struct checkpoint_action *p; + + for (p = checkpoint_action; p; p = p->next) + { + switch (p->opcode) + { + case cop_ttyout: + if (tty && tty_cleanup) + { + long w = getwidth (tty); + while (w--) + fputc (' ', tty); + fputc ('\r', tty); + fflush (tty); + } + break; + default: + /* nothing */; + } + } } void @@ -357,3 +425,14 @@ checkpoint_run (bool do_write) if (checkpoint_option && !(++checkpoint % checkpoint_option)) run_checkpoint_actions (do_write); } + +void +checkpoint_finish (void) +{ + if (checkpoint_option) + { + checkpoint_flush_actions (); + if (tty) + fclose (tty); + } +}