]> git.ipfire.org Git - thirdparty/coreutils.git/commitdiff
Merged in changes for 1.3.5.
authorJim Meyering <jim@meyering.net>
Thu, 19 Nov 1992 21:03:49 +0000 (21:03 +0000)
committerJim Meyering <jim@meyering.net>
Thu, 19 Nov 1992 21:03:49 +0000 (21:03 +0000)
14 files changed:
src/cut.c
src/expand.c
src/fold.c
src/head.c
src/join.c
src/nl.c
src/od.c
src/paste.c
src/sort.c
src/tac.c
src/tail.c
src/tr.c
src/unexpand.c
src/uniq.c

index d0f3b0b68fa57de2b0f4974834d52dbf4992fa43..5ce3f85dda2c6c12adc9add06b9f640cc192875f 100644 (file)
--- a/src/cut.c
+++ b/src/cut.c
@@ -20,7 +20,7 @@
    possible.  -David Ihnat (312) 784-4544 ignatz@homebru.chi.il.us
 
    POSIX changes, bug fixes, long-named options, and cleanup
-   by David MacKenzie <djm@ai.mit.edu>.
+   by David MacKenzie <djm@gnu.ai.mit.edu>.
 
    Options:
    --bytes=byte-list
@@ -57,6 +57,7 @@
 
    A FILE of `-' means standard input. */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
@@ -527,7 +528,7 @@ cut_fields (stream)
       if (fieldfound)
        {
          /* Something was found. Print it. */
-         if (outbufptr[-1] == delim)
+         if ((unsigned char) outbufptr[-1] == delim)
            --outbufptr;        /* Suppress trailing delimiter. */
 
          fwrite (outbuf, sizeof (char), outbufptr - outbuf, stdout);
index c45f2fc60441efb4c604c2072622ba00762695b3..4c46e3f41a9505090b69cade60bd8f5433afc9c8 100644 (file)
@@ -31,8 +31,9 @@
    --initial
    -i                  Only convert initial tabs on each line to spaces.
 
-   David MacKenzie <djm@ai.mit.edu> */
+   David MacKenzie <djm@gnu.ai.mit.edu> */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
index a2fb42a0c26464d4b4c9c85d25635375d67ecb1d..4cd0a2c6b0b75a258a67cd050977b5b046b8d225 100644 (file)
@@ -15,8 +15,9 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-/* Written by David MacKenzie. */
+/* Written by David MacKenzie, djm@gnu.ai.mit.edu. */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
index 29995698e73425d6ba86c227964565e9418c48d2..475894fff5e945ad30219877b731d4f12f1d2c2f 100644 (file)
@@ -31,7 +31,7 @@
    is given.
    By default, prints the first 10 lines (head -n 10).
 
-   David MacKenzie <djm@ai.mit.edu> */
+   David MacKenzie <djm@gnu.ai.mit.edu> */
 
 #include <stdio.h>
 #include <getopt.h>
index 9e3537c034f715ca6623f6cafc74db64148bc5ed..6e593b628f98dfb46b7a2ff632c4baaba521a11d 100644 (file)
@@ -17,6 +17,7 @@
 
    Written by Mike Haertel, mike@gnu.ai.mit.edu. */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
index 51cb5c1f9c5b4db5895724602c083b76473cea9e..09ff8d2b9f023ef0d2034c7f0a7ef41bbe3d788c 100644 (file)
--- a/src/nl.c
+++ b/src/nl.c
@@ -16,7 +16,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 \f
 /* Written by Scott Bartram (nancy!scott@uunet.uu.net)
-   Revised by David MacKenzie (djm@ai.mit.edu) */
+   Revised by David MacKenzie (djm@gnu.ai.mit.edu) */
 
 #include <stdio.h>
 #include <sys/types.h>
index ad59ed17c2610fb4f63207d5d67c94759eb50868..fe56b583686c6c5af9ca8ebfbdb51276b3f667ba 100644 (file)
--- a/src/od.c
+++ b/src/od.c
@@ -43,7 +43,7 @@ char *alloca ();
 #include <float.h>
 #endif
 
-#ifdef __GNUC__
+#ifdef __STDC__
 typedef long double LONG_DOUBLE;
 #else
 typedef double LONG_DOUBLE;
@@ -541,7 +541,7 @@ print_double (n_bytes, block, fmt_string)
     error (2, errno, "standard output");
 }
 
-#ifdef __GNUC__
+#ifdef __STDC__
 static void
 print_long_double (n_bytes, block, fmt_string)
      long unsigned int n_bytes;
@@ -861,9 +861,10 @@ decode_one_format (s, next, tspec)
 
       switch (size_spec)
        {
+         /* Don't use %#e; not all systems support it.  */
        case FP_SINGLE:
          print_function = print_float;
-         pre_fmt_string = "%%%d.%d#e%%c";
+         pre_fmt_string = "%%%d.%de%%c";
          fmt_string = xmalloc (strlen (pre_fmt_string));
          sprintf (fmt_string, pre_fmt_string,
                   FLT_DIG + 8, FLT_DIG);
@@ -871,16 +872,16 @@ decode_one_format (s, next, tspec)
 
        case FP_DOUBLE:
          print_function = print_double;
-         pre_fmt_string = "%%%d.%d#e%%c";
+         pre_fmt_string = "%%%d.%de%%c";
          fmt_string = xmalloc (strlen (pre_fmt_string));
          sprintf (fmt_string, pre_fmt_string,
                   DBL_DIG + 8, DBL_DIG);
          break;
 
-#ifdef __GNUC__
+#ifdef __STDC__
        case FP_LONG_DOUBLE:
          print_function = print_long_double;
-         pre_fmt_string = "%%%d.%d#le%%c";
+         pre_fmt_string = "%%%d.%dle%%c";
          fmt_string = xmalloc (strlen (pre_fmt_string));
          sprintf (fmt_string, pre_fmt_string,
                   LDBL_DIG + 8, LDBL_DIG);
@@ -1569,25 +1570,11 @@ main (argc, argv)
          /* The next several cases map the old, pre-POSIX format
             specification options to the corresponding POSIX format
             specs.  GNU od accepts any combination of old- and
-            new-style options.  If only POSIX format specs are used
-            and more than one is used, they are accumulated.  If only
-            old-style options are used, all but the last are ignored.
-            If both types of specs are used in the same command, the
-            last old-style option and any POSIX specs following it
-            are accumulated.  To illustrate, `od -c -t a' is the same
-            as `od -t ca', but `od -t a -c' is the same as `od -c'.  */
+            new-style options.  Format specification options accumulate.  */
 
 #define CASE_OLD_ARG(old_char,new_string)                              \
        case old_char:                                                  \
-         {                                                             \
-           const char *next;                                           \
-           int tmp;                                                    \
-           assert (n_specs_allocated >= 1);                            \
-           tmp = decode_one_format (new_string, &next, &(spec[0]));    \
-           n_specs = 1;                                                \
-           assert (tmp == 0);                                          \
-           assert (*next == '\0');                                     \
-         }                                                             \
+         assert (decode_format_string (new_string) == 0);              \
          break
 
          CASE_OLD_ARG ('a', "a");
index fc120b49fe6c5fe7adfa59b943c96496772e013b..3b2b1de65d5906a67fc3dd5d697f5ab964661371 100644 (file)
@@ -24,7 +24,7 @@
    version, to include \b, \f, \r, and \v.
  
    POSIX changes, bug fixes, long-named options, and cleanup
-   by David MacKenzie <djm@ai.mit.edu>.
+   by David MacKenzie <djm@gnu.ai.mit.edu>.
  
    Options:
    --serial
index b4522e34a01f0b2e50dd2a35a2254bf4c9fbe610..c2f15ec8bb755d927e8132e07013b5310466c1f0 100644 (file)
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
    Written December 1988 by Mike Haertel.
-   The author may be reached (Email) at the address mike@ai.mit.edu,
+   The author may be reached (Email) at the address mike@gnu.ai.mit.edu,
    or (US mail) as Mike Haertel c/o Free Software Foundation. */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
index 837280101249170692efad57ef3867770ee029a6..f7a2479e1198424e5df5e9232653abada1973bfa 100644 (file)
--- a/src/tac.c
+++ b/src/tac.c
@@ -16,7 +16,7 @@
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
 /* Written by Jay Lepreau (lepreau@cs.utah.edu).
-   GNU enhancements by David MacKenzie (djm@ai.mit.edu). */
+   GNU enhancements by David MacKenzie (djm@gnu.ai.mit.edu). */
 
 /* Copy each FILE, or the standard input if none are given or when a
    FILE name of "-" is encountered, to the standard output with the
index cddab26b812c97aefcdf2438e2b6b2efd0b17942..e3aa464fe6cfeaac0a72a33dc9714bca3cdd8718 100644 (file)
@@ -1,4 +1,4 @@
-/* tail -- output last part of file(s)
+/* tail -- output the last part of file(s)
    Copyright (C) 1989, 1990, 1991 Free Software Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -26,7 +26,6 @@
    -f, --follow                Loop forever trying to read more characters at the
                        end of the file, on the assumption that the file
                        is growing.  Ignored if reading from a pipe.
-                       Cannot be used if more than one file is given.
    -k                  Tail by N kilobytes.
    -N, -l, -n, --lines=N       Tail by N lines.
    -m                  Tail by N megabytes.
    By default, prints the last 10 lines (tail -n 10).
 
    Original version by Paul Rubin <phr@ocf.berkeley.edu>.
-   Extensions by David MacKenzie <djm@ai.mit.edu>. */
+   Extensions by David MacKenzie <djm@gnu.ai.mit.edu>.
+   tail -f for multiple files by Ian Lance Taylor <ian@cygnus.com>.  */
 
 #include <stdio.h>
 #include <getopt.h>
 #include <ctype.h>
 #include <sys/types.h>
+#include <signal.h>
 #include "system.h"
 
 #ifdef isascii
    If 0, tail in lines. */
 static int unit_size;
 
-/* If nonzero, read from end of file until killed. */
+/* If nonzero, read from the end of one file until killed. */
 static int forever;
 
+/* If nonzero, read from the end of multiple files until killed.  */
+static int forever_multiple;
+
+/* Array of file descriptors if forever_multiple is 1.  */
+static int *file_descs;
+
 /* If nonzero, count from start of file instead of end. */
 static int from_start;
 
@@ -97,6 +104,7 @@ static int tail_file ();
 static int tail_lines ();
 static long atou();
 static void dump_remainder ();
+static void tail_forever ();
 static void parse_unit ();
 static void usage ();
 static void write_header ();
@@ -130,11 +138,12 @@ main (argc, argv)
      means the value has not been set. */
   long number = -1;
   int c;                       /* Option character. */
+  int fileind;                 /* Index in ARGV of first file name.  */
 
   program_name = argv[0];
   have_read_stdin = 0;
   unit_size = 0;
-  forever = from_start = print_headers = 0;
+  forever = forever_multiple = from_start = print_headers = 0;
 
   if (argc > 1
       && ((argv[1][0] == '-' && ISDIGIT (argv[1][1]))
@@ -254,18 +263,27 @@ main (argc, argv)
   if (unit_size > 1)
     number *= unit_size;
 
+  fileind = optind;
+
   if (optind < argc - 1 && forever)
-    error (1, 0, "cannot follow the ends of multiple files");
+    {
+      forever_multiple = 1;
+      forever = 0;
+      file_descs = (int *) xmalloc ((argc - optind) * sizeof (int));
+    }
 
   if (header_mode == always
       || (header_mode == multiple_files && optind < argc - 1))
     print_headers = 1;
 
   if (optind == argc)
-    exit_status |= tail_file ("-", number);
+    exit_status |= tail_file ("-", number, 0);
 
   for (; optind < argc; ++optind)
-    exit_status |= tail_file (argv[optind], number);
+    exit_status |= tail_file (argv[optind], number, optind - fileind);
+
+  if (forever_multiple)
+    tail_forever (argv + fileind, argc - fileind);
 
   if (have_read_stdin && close (0) < 0)
     error (1, errno, "-");
@@ -276,14 +294,16 @@ main (argc, argv)
 
 /* Display the last NUMBER units of file FILENAME.
    "-" for FILENAME means the standard input.
+   FILENUM is this file's index in the list of files the user gave.
    Return 0 if successful, 1 if an error occurred. */
 
 static int
-tail_file (filename, number)
+tail_file (filename, number, filenum)
      char *filename;
      long number;
+     int filenum;
 {
-  int fd;
+  int fd, errors;
 
   if (!strcmp (filename, "-"))
     {
@@ -291,24 +311,48 @@ tail_file (filename, number)
       filename = "standard input";
       if (print_headers)
        write_header (filename);
-      return tail (filename, 0, number);
+      errors = tail (filename, 0, number);
+      if (forever_multiple)
+       file_descs[filenum] = errors ? -1 : 0;
     }
   else
     {
+      /* Not standard input.  */
       fd = open (filename, O_RDONLY);
-      if (fd >= 0)
+      if (fd == -1)
+       {
+         if (forever_multiple)
+           file_descs[filenum] = -1;
+         error (0, errno, "%s", filename);
+         errors = 1;
+       }
+      else
        {
-         int errors;
-
          if (print_headers)
            write_header (filename);
          errors = tail (filename, fd, number);
-         if (close (fd) == 0)
-           return errors;
+         if (forever_multiple)
+           {
+             if (errors)
+               {
+                 close (fd);
+                 file_descs[filenum] = -1;
+               }
+             else
+               file_descs[filenum] = fd;
+           }
+         else
+           {
+             if (close (fd))
+               {
+                 error (0, errno, "%s", filename);
+                 errors = 1;
+               }
+           }
        }
-      error (0, errno, "%s", filename);
-      return 1;
     }
+
+  return errors;
 }
 
 static void
@@ -808,6 +852,161 @@ output:
     }
 }
 
+#ifndef SIGUSR1
+#define SIGUSR1 SIGSYS
+#endif
+
+/* To support tail_forever we use a signal handler that just quietly
+   exits.  We are going to fork once for each file; we send a SIGUSR1
+   to kill the children if an error occurs.  */
+
+static RETSIGTYPE
+sigusr1 (sig)
+     int sig;
+{
+  exit (0);
+}
+
+/* Print error message MESSAGE for errno ERRNUM;
+   send SIGUSR1 to the KIDS processes in PIDS;
+   exit with status 1.  */
+
+static void
+kill_kids (errnum, message, pids, kids)
+     int errnum;
+     char *message;
+     int *pids;
+     int kids;
+{
+  int i;
+
+  error (0, errnum, message);
+  for (i = 0; i < kids; i++)
+    kill (pids[i], SIGUSR1);
+  exit (1);
+}
+
+/* The number of bytes that a pipe can hold (atomic read or write).  */
+#ifndef PIPE_BUF
+#define PIPE_BUF 512
+#endif
+
+/* Tail NFILES (>1) files forever until killed.  The file names are in NAMES.
+   The open file descriptors are in `file_descs'.  Fork a process for each
+   file, let all the processes write to a single pipe, and then read
+   the pipe.  */
+/* Should we reap the zombies with wait?  */
+
+static void
+tail_forever (names, nfiles)
+     char **names;
+     int nfiles;
+{
+  int pipe_descs[2];
+  int *pids;
+  int i;
+  char *buffer = xmalloc (PIPE_BUF); /* malloc assures `int' alignment.  */
+  int bytes_read;
+  int ilast;
+
+  if (pipe (pipe_descs) < 0)
+    error (1, errno, "cannot make pipe");
+
+  pids = (int *) xmalloc (nfiles * sizeof (int));
+
+  /* fork once for each file.  If this is too ugly for you, don't use
+     tail -f on multiple files.  Maybe we could use select as an
+     alternative, though it's less portable.  Is it worth the bother?  */
+
+  signal (SIGUSR1, sigusr1);
+
+  for (i = 0; i < nfiles; i++)
+    {
+      if (file_descs[i] == -1)
+       continue;
+      
+      pids[i] = fork ();
+      if (pids[i] == -1)
+       kill_kids (errno, "cannot fork", pids, i);
+      if (pids[i] == 0)
+       {
+         /* Child.  */
+         int offset;
+
+         close (pipe_descs[0]);
+
+         /* Each child reads continually from a file and writes to
+            the pipe.  Each write to a pipe is the index of the file
+            being read, followed by the number of bytes read from the
+            file, followed by the actual bytes.  Each child is
+            careful to write no more than PIPE_BUF bytes to the pipe,
+            so that the data from the various children does not get
+            intermixed.  */
+
+         /* The file index for this child is always the same.  */
+         *(int *) buffer = i;
+
+         offset = sizeof i + sizeof bytes_read;
+
+         while (1)
+           {
+             while ((bytes_read = read (file_descs[i], buffer + offset,
+                                        PIPE_BUF - offset)) > 0)
+               {
+                 *(int *) (buffer + sizeof i) = bytes_read;
+                 if (write (pipe_descs[1], buffer, offset + bytes_read)
+                     != offset + bytes_read)
+                   _exit (0);  /* Somebody killed our parent?  */
+               }
+             if (bytes_read == -1)
+               {
+                 error (0, errno, "%s", names[i]);
+                 _exit (1);
+               }
+             sleep (1);
+           }
+       }
+    }
+
+  /* Parent.  */
+
+  close (pipe_descs[1]);
+
+  /* Wait for input to come in on the pipe.  Read the file index
+     and the number of bytes.  Then read that many bytes and print
+     them out.  Repeat until all the children have closed the pipe.  */
+
+  ilast = -1;
+
+  while ((bytes_read = read (pipe_descs[0], buffer,
+                            sizeof i + sizeof bytes_read)) > 0)
+    {
+      int igot;                        /* Index of latest process that wrote.  */
+
+      if (bytes_read != sizeof i + sizeof bytes_read)
+       kill_kids (errno, "read error", pids, nfiles); /* Yikes.  */
+
+      /* Extract the file index and the number of bytes.  */
+      igot = *(int *) buffer;
+      bytes_read = *(int *) (buffer + sizeof i);
+
+      if (print_headers && igot != ilast)
+       write_header (names[igot]);
+      ilast = igot;
+
+      errno = 0;
+      if (read (pipe_descs[0], buffer, bytes_read) != bytes_read)
+       kill_kids (errno, "read error", pids, nfiles);
+      if (write (1, buffer, bytes_read) != bytes_read)
+       kill_kids (errno, "write error", pids, nfiles);
+    }
+       
+  for (i = 0; i < nfiles; i++)
+    kill (pids[i], SIGUSR1);
+
+  free (buffer);
+}
+
 static void
 parse_unit (str)
      char *str;
index a1376381dfe213689ded5c08ff382f61e7b6e795..f30fa9cb64b7c7cc2641508026f3a0d59855ea10 100644 (file)
--- a/src/tr.c
+++ b/src/tr.c
@@ -15,8 +15,9 @@
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
 
-/* Written by Jim Meyering. */
+/* Written by Jim Meyering, meyering@cs.utexas.edu. */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
index 8bdb773e68b465d5f4edeaa5b5f60eeb4f403c3a..e595f434bc42b3d6b583402d544c7f34db6ea56c 100644 (file)
@@ -33,8 +33,9 @@
    -a                  Use tabs wherever they would replace 2 or more spaces,
                        not just at the beginnings of lines.
 
-   David MacKenzie <djm@ai.mit.edu> */
+   David MacKenzie <djm@gnu.ai.mit.edu> */
 
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank
index f30c6afe97d938778d2335ea516f267f457db159..339b2aeaddef2753d2e0c817cb7103daa88e9db9 100644 (file)
@@ -17,6 +17,7 @@
 
 /* Written by Richard Stallman and David MacKenzie. */
 \f
+/* Get isblank from GNU libc.  */
 #define _GNU_SOURCE
 #include <ctype.h>
 #ifndef isblank