summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cut.c5
-rw-r--r--src/expand.c3
-rw-r--r--src/fold.c3
-rw-r--r--src/head.c2
-rw-r--r--src/join.c1
-rw-r--r--src/nl.c2
-rw-r--r--src/od.c31
-rw-r--r--src/paste.c2
-rw-r--r--src/sort.c3
-rw-r--r--src/tac.c2
-rw-r--r--src/tail.c235
-rw-r--r--src/tr.c3
-rw-r--r--src/unexpand.c3
-rw-r--r--src/uniq.c1
14 files changed, 245 insertions, 51 deletions
diff --git a/src/cut.c b/src/cut.c
index d0f3b0b68..5ce3f85dd 100644
--- 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);
diff --git a/src/expand.c b/src/expand.c
index c45f2fc60..4c46e3f41 100644
--- a/src/expand.c
+++ b/src/expand.c
@@ -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
diff --git a/src/fold.c b/src/fold.c
index a2fb42a0c..4cd0a2c6b 100644
--- a/src/fold.c
+++ b/src/fold.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 David MacKenzie. */
+/* Written by David MacKenzie, djm@gnu.ai.mit.edu. */
+/* Get isblank from GNU libc. */
#define _GNU_SOURCE
#include <ctype.h>
#ifndef isblank
diff --git a/src/head.c b/src/head.c
index 29995698e..475894fff 100644
--- a/src/head.c
+++ b/src/head.c
@@ -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>
diff --git a/src/join.c b/src/join.c
index 9e3537c03..6e593b628 100644
--- a/src/join.c
+++ b/src/join.c
@@ -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
diff --git a/src/nl.c b/src/nl.c
index 51cb5c1f9..09ff8d2b9 100644
--- a/src/nl.c
+++ b/src/nl.c
@@ -16,7 +16,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* 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>
diff --git a/src/od.c b/src/od.c
index ad59ed17c..fe56b5836 100644
--- 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");
diff --git a/src/paste.c b/src/paste.c
index fc120b49f..3b2b1de65 100644
--- a/src/paste.c
+++ b/src/paste.c
@@ -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
diff --git a/src/sort.c b/src/sort.c
index b4522e34a..c2f15ec8b 100644
--- a/src/sort.c
+++ b/src/sort.c
@@ -16,9 +16,10 @@
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
diff --git a/src/tac.c b/src/tac.c
index 837280101..f7a2479e1 100644
--- 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
diff --git a/src/tail.c b/src/tail.c
index cddab26b8..e3aa464fe 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -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.
@@ -43,12 +42,14 @@
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
@@ -67,9 +68,15 @@
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;
diff --git a/src/tr.c b/src/tr.c
index a1376381d..f30fa9cb6 100644
--- 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
diff --git a/src/unexpand.c b/src/unexpand.c
index 8bdb773e6..e595f434b 100644
--- a/src/unexpand.c
+++ b/src/unexpand.c
@@ -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
diff --git a/src/uniq.c b/src/uniq.c
index f30c6afe9..339b2aead 100644
--- a/src/uniq.c
+++ b/src/uniq.c
@@ -17,6 +17,7 @@
/* Written by Richard Stallman and David MacKenzie. */
+/* Get isblank from GNU libc. */
#define _GNU_SOURCE
#include <ctype.h>
#ifndef isblank