bug-coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[RFC] wc: add new option, --progress


From: Bo Borgerson
Subject: [RFC] wc: add new option, --progress
Date: Fri, 31 Oct 2008 18:20:46 -0400
User-agent: Thunderbird 2.0.0.17 (X11/20080925)

Hi,

I've recently found myself wishing for an option in 'wc' that shows
progress during an invocation.  I modified my local copy with the
changes in the attached patch to accept a '--progress' option.

This patch is also available at git://repo.or.cz/coreutils/bo.git

An example of behavior can be observed with the attached 'slowrite' program:

$ ./slowrite 100000 | src/wc --progress
 100000  200000  800000

$ src/wc --progress <(./slowrite 100000 3) <(./slowrite 1000000 4)
 100000  200000  800000 /dev/fd/63
1000000 2000000 8000000 /dev/fd/62
1100000 2200000 8800000 total

Of course these examples don't show any difference from an ordinary wc
invocation once they're complete. ;)

Here's a view when stdout isn't attached to a terminal:

$ ./slowrite 100000 | src/wc --progress > log &
[1] 19880
$ tail -f log
   8704   17408   69632
  16896   33792  135168
  25088   50176  200704
  33792   67584  270336
  41984   83968  335872
  50176  100352  401408
  58368  116736  466944
  67072  134144  536576
  75264  150528  602112
  83456  166912  667648
  92160  184320  737280
 100000  200000  800000

Would this be useful to anyone else?

Thanks,

Bo
>From 80089c8b1d616ec3c3a88b4f58131506a5aa43f3 Mon Sep 17 00:00:00 2001
From: Bo Borgerson <address@hidden>
Date: Wed, 29 Oct 2008 11:00:06 -0400
Subject: [PATCH] wc: add new option, --progress

* src/wc.c (set_do_monitor) ALRM handler sets DO_MONITOR flag that triggers 
output.
(write_counts) Unset DO_MONITOR flag.  New argument, is_final, set to true for 
the
final invocation for each input. If stdout is connected to a terminal, write all
counts for a single input on a single line.
(wc) Check DO_MONITOR flag in read loop and call write_counts if set.
(main) Set up an ALRM sigaction handler to call set_do_monitor.
---
 src/wc.c |   89 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 78 insertions(+), 11 deletions(-)

diff --git a/src/wc.c b/src/wc.c
index 0bb1929..771d6f1 100644
--- a/src/wc.c
+++ b/src/wc.c
@@ -21,6 +21,7 @@
 
 #include <stdio.h>
 #include <getopt.h>
+#include <signal.h>
 #include <sys/types.h>
 #include <wchar.h>
 #include <wctype.h>
@@ -66,6 +67,9 @@ static int number_width;
 /* True if we have ever read the standard input. */
 static bool have_read_stdin;
 
+/* Set by sig ALRM handler, triggers output at convenience.  Unset at output. 
*/
+static bool do_progress = false;
+
 /* The result of calling fstat or stat on a file descriptor or file.  */
 struct fstatus
 {
@@ -81,7 +85,8 @@ struct fstatus
    non-character as a pseudo short option, starting with CHAR_MAX + 1.  */
 enum
 {
-  FILES0_FROM_OPTION = CHAR_MAX + 1
+  FILES0_FROM_OPTION = CHAR_MAX + 1,
+  PROGRESS_OPTION
 };
 
 static struct option const longopts[] =
@@ -92,6 +97,7 @@ static struct option const longopts[] =
   {"words", no_argument, NULL, 'w'},
   {"files0-from", required_argument, NULL, FILES0_FROM_OPTION},
   {"max-line-length", no_argument, NULL, 'L'},
+  {"progress", no_argument, NULL, PROGRESS_OPTION},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -122,6 +128,7 @@ read standard input.\n\
       --files0-from=F    read input from the files specified by\n\
                            NUL-terminated names in file F\n\
   -L, --max-line-length  print the length of the longest line\n\
+      --progress         print counts every second until complete\n\
   -w, --words            print the word counts\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
@@ -131,6 +138,13 @@ read standard input.\n\
   exit (status);
 }
 
+static void
+set_do_progress (int sig)
+{
+  do_progress = true;
+  alarm (1);
+}
+
 /* FILE is the name of the file (or NULL for standard input)
    associated with the specified counters.  */
 static void
@@ -139,39 +153,58 @@ write_counts (uintmax_t lines,
              uintmax_t chars,
              uintmax_t bytes,
              uintmax_t linelength,
-             const char *file)
+             const char *file,
+             bool is_final)
 {
   static char const format_sp_int[] = " %*s";
   char const *format_int = format_sp_int + 1;
   char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+  static size_t plen = 0;
+
+  if (0 < plen && isatty (STDOUT_FILENO))
+    {
+      size_t i;
+      for (i = 0; i < plen; i++)
+        putchar (0x08); /* Backspace. */
+      plen = 0;
+    }
 
   if (print_lines)
     {
-      printf (format_int, number_width, umaxtostr (lines, buf));
+      plen += printf (format_int, number_width, umaxtostr (lines, buf));
       format_int = format_sp_int;
     }
   if (print_words)
     {
-      printf (format_int, number_width, umaxtostr (words, buf));
+      plen += printf (format_int, number_width, umaxtostr (words, buf));
       format_int = format_sp_int;
     }
   if (print_chars)
     {
-      printf (format_int, number_width, umaxtostr (chars, buf));
+      plen += printf (format_int, number_width, umaxtostr (chars, buf));
       format_int = format_sp_int;
     }
   if (print_bytes)
     {
-      printf (format_int, number_width, umaxtostr (bytes, buf));
+      plen += printf (format_int, number_width, umaxtostr (bytes, buf));
       format_int = format_sp_int;
     }
   if (print_linelength)
     {
-      printf (format_int, number_width, umaxtostr (linelength, buf));
+      plen += printf (format_int, number_width, umaxtostr (linelength, buf));
     }
   if (file)
-    printf (" %s", file);
-  putchar ('\n');
+    plen += printf (" %s", file);
+
+  if (is_final || !isatty (STDOUT_FILENO))
+    {
+      putchar ('\n');
+      plen = 0;
+    }
+  if (!is_final)
+    fflush (stdout);
+
+  do_progress = false;
 }
 
 /* Count words.  FILE_X is the name of the file (or NULL for standard
@@ -241,6 +274,10 @@ wc (int fd, char const *file_x, struct fstatus *fstatus)
                  break;
                }
              bytes += bytes_read;
+
+             if (do_progress)
+               write_counts (lines, words, chars, bytes, linelength, file_x,
+                             false);
            }
        }
     }
@@ -265,6 +302,9 @@ wc (int fd, char const *file_x, struct fstatus *fstatus)
              ++lines;
            }
          bytes += bytes_read;
+
+         if (do_progress)
+           write_counts (lines, words, chars, bytes, linelength, file_x, 
false);
        }
     }
 #if HAVE_MBRTOWC && (MB_LEN_MAX > 1)
@@ -401,6 +441,8 @@ wc (int fd, char const *file_x, struct fstatus *fstatus)
            }
          prev = bytes_read;
 # endif
+         if (do_progress)
+           write_counts (lines, words, chars, bytes, linelength, file_x, 
false);
        }
       if (linepos > linelength)
        linelength = linepos;
@@ -459,6 +501,9 @@ wc (int fd, char const *file_x, struct fstatus *fstatus)
                }
            }
          while (--bytes_read);
+
+         if (do_progress)
+           write_counts (lines, words, chars, bytes, linelength, file_x, 
false);
        }
       if (linepos > linelength)
        linelength = linepos;
@@ -468,7 +513,7 @@ wc (int fd, char const *file_x, struct fstatus *fstatus)
   if (count_chars < print_chars)
     chars = bytes;
 
-  write_counts (lines, words, chars, bytes, linelength, file_x);
+  write_counts (lines, words, chars, bytes, linelength, file_x, true);
   total_lines += lines;
   total_words += words;
   total_chars += chars;
@@ -623,6 +668,10 @@ main (int argc, char **argv)
        files_from = optarg;
        break;
 
+      case PROGRESS_OPTION:
+        do_progress = true;
+       break;
+
       case_GETOPT_HELP_CHAR;
 
       case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -679,6 +728,24 @@ main (int argc, char **argv)
   fstatus = get_input_fstatus (nfiles, files);
   number_width = compute_number_width (nfiles, fstatus);
 
+  if (do_progress)
+    {
+      struct sigaction alarm_handler;
+
+      sigemptyset (&alarm_handler.sa_mask);
+
+      alarm_handler.sa_handler = set_do_progress;
+
+      alarm_handler.sa_flags = SA_RESTART;
+
+      sigaction (SIGALRM, &alarm_handler, NULL);
+
+      alarm (1);
+
+      /* This will be set again in one second by SET_DO_PROGRESS. */
+      do_progress = false;
+    }
+
   ok = true;
   for (i = 0; i < nfiles; i++)
     {
@@ -720,7 +787,7 @@ main (int argc, char **argv)
 
   if (1 < nfiles)
     write_counts (total_lines, total_words, total_chars, total_bytes,
-                 max_line_length, _("total"));
+                 max_line_length, _("total"), true);
 
   free (fstatus);
 
-- 
1.5.4.3

#!/usr/bin/perl -w

use strict;

my ($n, $s) = @ARGV;

$n or die "usage: $0 RECORDS [SECONDS]\n";

$s ||= 10;
my $m = $n / 100 / $s; 
$m < 2 and $m = 2;

for (1..$n){
  print "foo bar\n";
  ($_ % $m) == 1 and select (undef, undef, undef, 0.01);
}

reply via email to

[Prev in Thread] Current Thread [Next in Thread]