summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>1993-01-20 04:29:09 +0000
committerJim Meyering <jim@meyering.net>1993-01-20 04:29:09 +0000
commitb53876554779e7778b84f11abc65a5fbcf5e3971 (patch)
treee2e36d9eb8c4cb55c8d5f702c6693445b0ba9ef1
parentadd6b20a4df42e902c2c708ff6d7b9b7ae949d0e (diff)
downloadcoreutils-b53876554779e7778b84f11abc65a5fbcf5e3971.tar.xz
merge with 1.4
-rw-r--r--lib/regex.c57
-rw-r--r--old/textutils/ChangeLog19
-rw-r--r--src/tail.c243
3 files changed, 135 insertions, 184 deletions
diff --git a/lib/regex.c b/lib/regex.c
index a0e4e8950..eda11b535 100644
--- a/lib/regex.c
+++ b/lib/regex.c
@@ -3,7 +3,7 @@
(Implements POSIX draft P10003.2/D11.2, except for
internationalization features.)
- Copyright (C) 1985, 89, 90, 91, 92 Free Software Foundation, Inc.
+ Copyright (C) 1993 Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -29,7 +29,7 @@
/* We need this for `regex.h', and perhaps for the Emacs include files. */
#include <sys/types.h>
-#if defined (HAVE_CONFIG_H) || defined (emacs)
+#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -2197,18 +2197,20 @@ compile_range (p_ptr, pend, translate, syntax, b)
unsigned this_char;
const char *p = *p_ptr;
+ int range_start, range_end;
- /* Even though the pattern is a signed `char *', we need to fetch into
- `unsigned char's. Reason: if the high bit of the pattern character
- is set, the range endpoints will be negative if we fetch into a
- signed `char *'. */
- unsigned char range_end;
- unsigned char range_start = p[-2];
-
if (p == pend)
return REG_ERANGE;
- PATFETCH (range_end);
+ /* Even though the pattern is a signed `char *', we need to fetch
+ with unsigned char *'s; if the high bit of the pattern character
+ is set, the range endpoints will be negative if we fetch using a
+ signed char *.
+
+ We also want to fetch the endpoints without translating them; the
+ appropriate translation is done in the bit-setting loop below. */
+ range_start = ((unsigned char *) p)[-2];
+ range_end = ((unsigned char *) p)[0];
/* Have to increment the pointer into the pattern string, so the
caller isn't still at the ending character. */
@@ -3989,21 +3991,13 @@ re_match_2 (bufp, string1, size1, string2, size2, pos, regs, stop)
/* If we're at the end of the pattern, we can change. */
if (p2 == pend)
- { /* But if we're also at the end of the string, we might
- as well skip changing anything. For example, in `a+'
- against `a', we'll have already matched the `a', and
- I don't see the the point of changing the opcode,
- popping the failure point, finding out it fails, and
- then going into our endgame. */
- if (d == dend)
- {
- p = pend;
- DEBUG_PRINT1 (" End of pattern & string => done.\n");
- continue;
- }
-
+ {
+ /* Consider what happens when matching ":\(.*\)"
+ against ":/". I don't really understand this code
+ yet. */
p[-3] = (unsigned char) pop_failure_jump;
- DEBUG_PRINT1 (" End of pattern => pop_failure_jump.\n");
+ DEBUG_PRINT1
+ (" End of pattern: change to `pop_failure_jump'.\n");
}
else if ((re_opcode_t) *p2 == exactn
@@ -4875,9 +4869,18 @@ regerror (errcode, preg, errbuf, errbuf_size)
char *errbuf;
size_t errbuf_size;
{
- const char *msg
- = re_error_msg[errcode] == NULL ? "Success" : re_error_msg[errcode];
- size_t msg_size = strlen (msg) + 1; /* Includes the null. */
+ const char *msg;
+ size_t msg_size;
+
+ if (errcode < 0
+ || errcode >= (sizeof (re_error_msg) / sizeof (re_error_msg[0])))
+ /* Only error codes returned by the rest of the code should be passed
+ to this routine. If we are given anything else, or if other regex
+ code generates an invalid error code, then the program has a bug.
+ Dump core so we can fix it. */
+ abort ();
+
+ msg_size = strlen (msg) + 1; /* Includes the null. */
if (errbuf_size != 0)
{
diff --git a/old/textutils/ChangeLog b/old/textutils/ChangeLog
index a4fa7d7ba..3d68bba0b 100644
--- a/old/textutils/ChangeLog
+++ b/old/textutils/ChangeLog
@@ -1,3 +1,22 @@
+Tue Jan 19 13:35:24 1993 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * Version 1.4.
+
+ * system.h: Try BBSIZE if BSIZE isn't defined.
+ From Tony Robinson <ajr@eng.cam.ac.uk>.
+
+Sat Dec 12 12:37:00 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * tail.c (tail_forever): Use an array of file descriptors
+ instead of forking processes.
+ (dump_remainder): Return number of bytes read.
+ (tail_file): Fill in the new array.
+ From Ian Lance Taylor.
+
+Fri Dec 11 17:18:16 1992 David J. MacKenzie (djm@kropotkin.gnu.ai.mit.edu)
+
+ * system.h: Only define index, bcmp, etc. if not already defined.
+
Tue Dec 8 10:31:14 1992 Jim Meyering (meyering@idefix.comco.com)
* tr.c (is_char_class_member): Remove unreached return after abort.
diff --git a/src/tail.c b/src/tail.c
index be0978fe4..138c22894 100644
--- a/src/tail.c
+++ b/src/tail.c
@@ -70,6 +70,9 @@ static int forever_multiple;
/* Array of file descriptors if forever_multiple is 1. */
static int *file_descs;
+/* Array of file sizes if forever_multiple is 1. */
+static off_t *file_sizes;
+
/* If nonzero, count from start of file instead of end. */
static int from_start;
@@ -96,7 +99,7 @@ static int tail_bytes ();
static int tail_file ();
static int tail_lines ();
static long atou();
-static void dump_remainder ();
+static long dump_remainder ();
static void tail_forever ();
static void parse_unit ();
static void usage ();
@@ -263,6 +266,7 @@ main (argc, argv)
forever_multiple = 1;
forever = 0;
file_descs = (int *) xmalloc ((argc - optind) * sizeof (int));
+ file_sizes = (off_t *) xmalloc ((argc - optind) * sizeof (off_t));
}
if (header_mode == always
@@ -297,6 +301,7 @@ tail_file (filename, number, filenum)
int filenum;
{
int fd, errors;
+ struct stat stats;
if (!strcmp (filename, "-"))
{
@@ -306,7 +311,26 @@ tail_file (filename, number, filenum)
write_header (filename);
errors = tail (filename, 0, number);
if (forever_multiple)
- file_descs[filenum] = errors ? -1 : 0;
+ {
+ if (fstat (0, &stats) < 0)
+ {
+ error (0, errno, "standard input");
+ errors = 1;
+ }
+ else if (!S_ISREG (stats.st_mode))
+ {
+ error (0, 0,
+ "standard input: cannot follow end of non-regular file");
+ errors = 1;
+ }
+ if (errors)
+ file_descs[filenum] = -1;
+ else
+ {
+ file_descs[filenum] = 0;
+ file_sizes[filenum] = stats.st_size;
+ }
+ }
}
else
{
@@ -326,13 +350,26 @@ tail_file (filename, number, filenum)
errors = tail (filename, fd, number);
if (forever_multiple)
{
+ if (fstat (fd, &stats) < 0)
+ {
+ error (0, errno, "%s", filename);
+ errors = 1;
+ }
+ else if (!S_ISREG (stats.st_mode))
+ {
+ error (0, 0, "%s: cannot follow end of non-regular file");
+ errors = 1;
+ }
if (errors)
{
close (fd);
file_descs[filenum] = -1;
}
else
- file_descs[filenum] = fd;
+ {
+ file_descs[filenum] = fd;
+ file_sizes[filenum] = stats.st_size;
+ }
}
else
{
@@ -821,21 +858,26 @@ start_lines (filename, fd, number)
return 0;
}
-/* Display file FILENAME from the current position in FD
- to the end. If `forever' is nonzero, keep reading from the
- end of the file until killed. */
+/* Display file FILENAME from the current position in FD to the end.
+ If `forever' is nonzero, keep reading from the end of the file
+ until killed. Return the number of bytes read from the file. */
-static void
+static long
dump_remainder (filename, fd)
char *filename;
int fd;
{
char buffer[BUFSIZE];
int bytes_read;
+ long total;
+ total = 0;
output:
while ((bytes_read = read (fd, buffer, BUFSIZE)) > 0)
- xwrite (1, buffer, bytes_read);
+ {
+ xwrite (1, buffer, bytes_read);
+ total += bytes_read;
+ }
if (bytes_read == -1)
error (1, errno, "%s", filename);
if (forever)
@@ -843,174 +885,61 @@ output:
sleep (1);
goto output;
}
+ return total;
}
-#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? */
+/* Tail NFILES (>1) files forever until killed. The file names are in
+ NAMES. The open file descriptors are in `file_descs', and the size
+ at which we stopped tailing them is in `file_sizes'. We loop over
+ each of them, doing an fstat to see if they have changed size. If
+ none of them have changed size in one iteration, we sleep for a
+ second and try again. We do this until the user interrupts us. */
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));
+ int last;
- /* fork once for each file. This approach uses one process and
- one file descriptor for each file we tail.
- More resource-efficient approaches would be:
+ last = -1;
- 1. Keep an off_t array of the last-seen sizes of the files,
- and fstat them each in turn, watching for growth.
- This would be more portable, but still use the same number of
- file descriptors, and would probably use more CPU.
- For pipes, perhaps a separate process would have to be forked to
- read from the pipe and write to a temporary file.
-
- 2. Keep an off_t array, but only keep recently changed files open
- and use stat for the others, opening them only if they change.
- This would save file descriptors, to allow tail -f on a large number
- of files. It's probably not worth the trouble for most uses, though,
- and GNU won't have arbitrary limits on things like file descriptors. */
-
- signal (SIGUSR1, sigusr1);
-
- for (i = 0; i < nfiles; i++)
+ while (1)
{
- 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;
+ int i;
+ int changed;
- close (pipe_descs[0]);
-
- /* Each child reads continually from a file and writes to
- the pipe. Each write to the pipe is the index of the file
- being read, followed by the number of bytes read from the
- file, followed by the actual data. Each child is
- careful to write no more than PIPE_BUF bytes to the pipe,
- so that the data from the various children do not get
- intermixed. */
-
- /* The file index for this child is always the same. */
- *(int *) buffer = i;
+ changed = 0;
+ for (i = 0; i < nfiles; i++)
+ {
+ struct stat stats;
- offset = sizeof i + sizeof bytes_read;
+ if (file_descs[i] < 0)
+ continue;
+ if (fstat (file_descs[i], &stats) < 0)
+ {
+ error (0, errno, "%s", names[i]);
+ file_descs[i] = -1;
+ continue;
+ }
+ if (stats.st_size == file_sizes[i])
+ continue;
- while (1)
+ /* This file has changed size. Print out what we can, and
+ then keep looping. */
+ if (i != last)
{
- 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);
+ write_header (names[i]);
+ last = i;
}
+ changed = 1;
+ file_sizes[i] += dump_remainder (names[i], file_descs[i]);
}
- }
-
- /* 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);
+ /* If none of the files changed size, sleep. */
+ if (! changed)
+ sleep (1);
}
-
- for (i = 0; i < nfiles; i++)
- kill (pids[i], SIGUSR1);
-
- free (buffer);
}
static void