diff options
author | Jim Meyering <jim@meyering.net> | 1993-01-20 04:29:09 +0000 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 1993-01-20 04:29:09 +0000 |
commit | b53876554779e7778b84f11abc65a5fbcf5e3971 (patch) | |
tree | e2e36d9eb8c4cb55c8d5f702c6693445b0ba9ef1 | |
parent | add6b20a4df42e902c2c708ff6d7b9b7ae949d0e (diff) | |
download | coreutils-b53876554779e7778b84f11abc65a5fbcf5e3971.tar.xz |
merge with 1.4
-rw-r--r-- | lib/regex.c | 57 | ||||
-rw-r--r-- | old/textutils/ChangeLog | 19 | ||||
-rw-r--r-- | src/tail.c | 243 |
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 |