diff options
author | Jim Meyering <jim@meyering.net> | 1992-11-19 21:03:49 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1992-11-19 21:03:49 +0000 |
commit | 750bb6aa692485b3ffc567aabead9de97d4eb5ca (patch) | |
tree | d6d98478ae1f81ade5be9ae0368e89775921530a | |
parent | ceda697482339c94618ad1cbd3ab79259f1991d9 (diff) | |
download | coreutils-750bb6aa692485b3ffc567aabead9de97d4eb5ca.tar.xz |
Merged in changes for 1.3.5.
-rw-r--r-- | src/cut.c | 5 | ||||
-rw-r--r-- | src/expand.c | 3 | ||||
-rw-r--r-- | src/fold.c | 3 | ||||
-rw-r--r-- | src/head.c | 2 | ||||
-rw-r--r-- | src/join.c | 1 | ||||
-rw-r--r-- | src/nl.c | 2 | ||||
-rw-r--r-- | src/od.c | 31 | ||||
-rw-r--r-- | src/paste.c | 2 | ||||
-rw-r--r-- | src/sort.c | 3 | ||||
-rw-r--r-- | src/tac.c | 2 | ||||
-rw-r--r-- | src/tail.c | 235 | ||||
-rw-r--r-- | src/tr.c | 3 | ||||
-rw-r--r-- | src/unexpand.c | 3 | ||||
-rw-r--r-- | src/uniq.c | 1 |
14 files changed, 245 insertions, 51 deletions
@@ -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 @@ -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> @@ -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 @@ -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; @@ -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 |