bug-coreutils
[Top][All Lists]
Advanced

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

Patch for head: --show-truncated


From: Ed Avis
Subject: Patch for head: --show-truncated
Date: Sun, 6 Jul 2003 13:13:53 +0100 (BST)

Sometimes it would be useful for head to print a notice or reminder
that it hasn't printed the whole content of a file.  For example, if
you use head to shorten the output of a command:

% diff -u old new | head -1000
% lint foo.c 2>&1 | head

then you might want to see whether there was more output, or whether
head printed everything that came from the command.  There's no easy
way to tell that at present.

This patch adds a new flag --show-truncation or -V which prints a
banner after the file contents:

==> truncated $filename <==

in cases where there is more output which head has discarded.  If head
managed to print the whole file contents, there is no banner.

I originally wrote a separate program to do this but I think it makes
more sense as part of head.  I hope you can apply the patch or
implement a similar feature.


diff -ru coreutils-5.0/doc/coreutils.info coreutils-5.0-new/doc/coreutils.info
--- coreutils-5.0/doc/coreutils.info    2003-04-02 22:08:19.000000000 +0100
+++ coreutils-5.0-new/doc/coreutils.info        2003-07-06 12:41:46.000000000 
+0100
@@ -1738,6 +1738,11 @@
 `--verbose'
      Always print file name headers.
 
+`-V'
+`--show-truncation'
+     When the output printed by head is less than the whole content of
+     a file, print a one-line footer noting this.
+
 
    On older systems, `head' supports an obsolete option
 `-COUNTOPTIONS', which is recognized only if it is specified first.
diff -ru coreutils-5.0/man/head.1 coreutils-5.0-new/man/head.1
--- coreutils-5.0/man/head.1    2003-03-30 13:13:37.000000000 +0100
+++ coreutils-5.0-new/man/head.1        2003-07-06 12:38:48.000000000 +0100
@@ -26,6 +26,9 @@
 \fB\-v\fR, \fB\-\-verbose\fR
 always print headers giving file names
 .TP
+\fB\-V\fR, \fB\-\-show\-truncation\fR
+print footer noting truncation of file
+.TP
 \fB\-\-help\fR
 display this help and exit
 .TP
diff -ru coreutils-5.0/src/head.c coreutils-5.0-new/src/head.c
--- coreutils-5.0/src/head.c    2002-10-01 09:47:44.000000000 +0100
+++ coreutils-5.0-new/src/head.c        2003-07-06 12:45:35.000000000 +0100
@@ -56,6 +56,15 @@
   multiple_files, always, never
 };
 
+/* If nonzero, print 'truncated' banners. */
+int show_truncation;
+
+/* A 'three-state Boolean' - used later for EOF information. */
+enum tristate
+{ 
+  maybe, no, yes 
+};
+
 /* Options corresponding to header_mode values.  */
 static char const header_mode_option[][4] = { "", " -v", " -q" };
 
@@ -72,6 +81,7 @@
   {"quiet", no_argument, NULL, 'q'},
   {"silent", no_argument, NULL, 'q'},
   {"verbose", no_argument, NULL, 'v'},
+  {"show-truncation", no_argument, NULL, 'V'},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -105,6 +115,7 @@
       fputs (_("\
   -q, --quiet, --silent    never print headers giving file names\n\
   -v, --verbose            always print headers giving file names\n\
+  -V, --show-truncation    print footer noting truncation of file\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -126,6 +137,78 @@
   first_file = 0;
 }
 
+/* Try to read one more character to test for EOF.  Use only if you
+   don't care about losing that character!
+   Unlike feof(), this can fail.  The return status is zero for
+   success or nonzero for failure (like the other functions in this
+   file), and the EOF flag is placed in *result. */
+static int
+eof (const char *filename, int fd, int *result)
+{
+  char c;
+  size_t bytes_read = safe_read (fd, &c, 1);
+  if (bytes_read == SAFE_READ_ERROR)
+    {
+      error (0, errno, "%s", filename);
+      return 1;
+    }
+  else if (bytes_read == 0)
+    {
+      *result = 1;
+      return 0;
+    }
+  else if (bytes_read == 1)
+    {
+      *result = 0;
+      return 0;
+    }
+  else
+    {
+      /* Shouldn't happen. */
+      error (0, 0, _("bad return from safe_read(): %d"), bytes_read);
+      return 1;
+    }
+}
+
+/* Print a banner saying that the file was truncated, unless we got to
+   EOF on the file descriptor.
+   The eof_knowledge parameter says what you know about the EOF state,
+   to save doing an extra read() if it is not necessary.
+   Returns zero for success, nonzero on failure.
+*/
+static int
+maybe_show_truncation (const char *filename, int fd,
+                      enum tristate eof_knowledge, int newline)
+{
+  /* Work out for certain whether we got to EOF. */
+  int eof_bool;
+  if (eof_knowledge == no)
+    eof_bool = 0;
+  else if (eof_knowledge == yes)
+    eof_bool = 1;
+  else if (eof_knowledge == maybe)
+    {
+      if (eof (filename, fd, &eof_bool))
+       {
+         error (0, 0, _("could not determine end-of-file for %s"),
+                filename);
+         return 1;
+       }
+    }
+  else
+    /* Shouldn't happen. */
+    return 1;
+
+  if (! eof_bool)
+    {
+      if (newline)
+       putc('\n', stdout);
+      printf (_("==> truncated %s <==\n"), filename);
+    }
+
+  return 0;
+}
+
 static int
 head_bytes (const char *filename, int fd, uintmax_t bytes_to_write)
 {
@@ -135,6 +218,7 @@
   /* Need BINARY I/O for the byte counts to be accurate.  */
   SET_BINARY2 (fd, fileno (stdout));
 
+  enum tristate eof_knowledge = maybe;
   while (bytes_to_write)
     {
       size_t bytes_read;
@@ -147,11 +231,20 @@
          return 1;
        }
       if (bytes_read == 0)
-       break;
+       {
+         eof_knowledge = yes;
+         break;
+       }
       if (fwrite (buffer, 1, bytes_read, stdout) == 0)
        error (EXIT_FAILURE, errno, _("write error"));
       bytes_to_write -= bytes_read;
     }
+  if (show_truncation)
+    if (maybe_show_truncation (filename, fd, eof_knowledge, 1))
+      {
+       error (0, 0, _("don't know if %s was truncated or not"), filename);
+       return 1;
+      }
   return 0;
 }
 
@@ -163,6 +256,7 @@
   /* Need BINARY I/O for the byte counts to be accurate.  */
   SET_BINARY2 (fd, fileno (stdout));
 
+  enum tristate eof_knowledge = maybe;
   while (lines_to_write)
     {
       size_t bytes_read = safe_read (fd, buffer, BUFSIZE);
@@ -174,7 +268,10 @@
          return 1;
        }
       if (bytes_read == 0)
-       break;
+       {
+         eof_knowledge = yes;
+         break;
+       }
       while (bytes_to_write < bytes_read)
        if (buffer[bytes_to_write++] == '\n' && --lines_to_write == 0)
          {
@@ -194,7 +291,15 @@
          }
       if (fwrite (buffer, 1, bytes_to_write, stdout) == 0)
        error (EXIT_FAILURE, errno, _("write error"));
+      if (bytes_to_write < bytes_read)
+       eof_knowledge = no;
     }
+  if (show_truncation)
+    if (maybe_show_truncation (filename, fd, eof_knowledge, 0))
+      {
+       error (0, 0, _("don't know if %s was truncated or not"), filename);
+       return 1;
+      }
   return 0;
 }
 
@@ -292,6 +397,7 @@
   have_read_stdin = 0;
 
   print_headers = 0;
+  show_truncation = 0;
 
   if (1 < argc && argv[1][0] == '-' && ISDIGIT (argv[1][1]))
     {
@@ -370,7 +476,7 @@
 
     }
 
-  while ((c = getopt_long (argc, argv, "c:n:qv", long_options, NULL)) != -1)
+  while ((c = getopt_long (argc, argv, "c:n:qvV", long_options, NULL)) != -1)
     {
       switch (c)
        {
@@ -395,6 +501,10 @@
          header_mode = always;
          break;
 
+       case 'V':
+         show_truncation = 1;
+         break;
+
        case_GETOPT_HELP_CHAR;
 
        case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
diff -ru coreutils-5.0/tests/head/Test.pm coreutils-5.0-new/tests/head/Test.pm
--- coreutils-5.0/tests/head/Test.pm    2002-02-17 22:39:47.000000000 +0000
+++ coreutils-5.0-new/tests/head/Test.pm        2003-07-06 12:37:42.000000000 
+0100
@@ -50,6 +50,22 @@
 ['no-oct-2', '-010', "\n"x12, "\n"x10, 0],
 ['no-oct-3', '-n 08', "\n"x12, "\n"x8, 0],
 ['no-oct-4', '-c 08', "\n"x12, "\n"x8, 0],
+
+# Test -V option - head should notice whether it got to EOF.
+['eof-1', '-V', "1\n2\n3\n4\n5\n6\n7\n8\n9", "1\n2\n3\n4\n5\n6\n7\n8\n9", 0],
+['eof-2', '-V', "1\n2\n3\n4\n5\n6\n7\n8\n9\n", "1\n2\n3\n4\n5\n6\n7\n8\n9\n", 
0],
+['eof-3', '-V', "1\n2\n3\n4\n5\n6\n7\n8\n9\n0", 
"1\n2\n3\n4\n5\n6\n7\n8\n9\n0", 0],
+['eof-4', '-V', "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n", 
"1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n", 0],
+# This requires the right locale - hope that's okay.
+['eof-5', '-V', "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n1",
+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n==> truncated ./eof-5.I <==\n", 0],
+['eof-6', '-V', "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n1\n",
+ "1\n2\n3\n4\n5\n6\n7\n8\n9\n0\n==> truncated ./eof-6.I <==\n", 0],
+# Test -V with --bytes.
+['eof-7', '-V --bytes 3', "12", "12", 0],
+['eof-8', '-V --bytes 3', "123", "123", 0],
+['eof-9', '-V --bytes 3', "1234", "123\n==> truncated ./eof-9.I <==\n", 0],
+['eof-10', '-V --bytes 3', "12345", "123\n==> truncated ./eof-10.I <==\n", 0],
 );
 
 sub test_vector


-- 
Ed Avis <address@hidden>






reply via email to

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