mirror of
git://git.sv.gnu.org/coreutils
synced 2026-06-05 15:22:12 -04:00
Merged in changes for 1.3.5.
This commit is contained in:
@@ -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);
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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>
|
||||
|
||||
@@ -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");
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
+217
-18
@@ -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
|
||||
|
||||
+2
-1
@@ -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
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
/* Written by Richard Stallman and David MacKenzie. */
|
||||
|
||||
/* Get isblank from GNU libc. */
|
||||
#define _GNU_SOURCE
|
||||
#include <ctype.h>
|
||||
#ifndef isblank
|
||||
|
||||
Reference in New Issue
Block a user