aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2022-05-02 21:05:12 -0700
committerKaz Kylheku <kaz@kylheku.com>2022-05-02 21:05:12 -0700
commitb06d9454f395f007a7ef6081fb43c4298b66b09b (patch)
tree420cee03f2089bb0741d65c33e57ad7004942cc4
parente153fa3d6207b5139db352e58cd775c7e42ad202 (diff)
downloadpw-b06d9454f395f007a7ef6081fb43c4298b66b09b.tar.gz
pw-b06d9454f395f007a7ef6081fb43c4298b66b09b.tar.bz2
pw-b06d9454f395f007a7ef6081fb43c4298b66b09b.zip
Remove non-interactive mode.
-rw-r--r--pw.1103
-rw-r--r--pw.c63
2 files changed, 92 insertions, 74 deletions
diff --git a/pw.1 b/pw.1
index 167ec0d..00e106b 100644
--- a/pw.1
+++ b/pw.1
@@ -34,34 +34,15 @@ command | pw [-i interval] [-l interval] [-n number-of-lines] [-dEB]
.SH DESCRIPTION
.I pw
-stands for Pipe Watch. This is a utility which continuously reads textual input
-from a pipe or pipe-like source, and maintains a dynamic display of the
-most recently read
-.I N
-lines.
-
-If
-.I pw
-is invoked such that its standard input is a TTY, it simply reads lines
-and prints them in its characteristic way, with control characters replaced by
-caret codes, until end-of-file is encountered. Long lines aren't clipped,
-and there is no interactive mode.
-
-The intended use of
-.I pw
-is that its standard input is a pipe, such as the output of another command,
-or a pipe-like device such as a socket or whatever.
-In this situation,
-.I pw
-expects to be executed in a TTY session in which a
-.B /dev/tty
-device can be opened, for the purposes of obtaining interactive input.
-The remaining description pertains to this interactive mode.
+stands for Pipe Watch, a utility that continuously reads lines of
+text from a pipe or pipe-like source, passes them through a FIFO buffer, and
+maintains a display based on the occasional sampling the contents of the
+FIFO buffer, with useful features such as triggering and filtering.
-In interactive mode,
+Upon successful startup,
.I pw
-simultaneously monitors its standard input for the arrival of new data,
-as well as the TTY for interactive commands.
+simultaneously monitors its standard input for the
+arrival of new data, as well as the TTY for interactive commands.
Lines from standard input are placed into a FIFO buffer.
While the FIFO buffer is not yet full, lines are displayed immediately.
After the FIFO buffer fills up with the specified number of lines
@@ -69,13 +50,27 @@ After the FIFO buffer fills up with the specified number of lines
.B -n
option) then
.I pw
-transitions into a mode in which, old lines are bumped from the tail of the
-FIFO as new ones are added to the head, and refresh operations are required in
-order to display the current FIFO contents.
+transitions into the free-running mode in which, old lines are removed from the
+tail of the FIFO as new ones are added to the head, and the display is no
+longer refreshed for every new line arriving into the FIFO.
-The display only refreshes with the latest FIFO data when
+In free-running mode, the display is automatically refreshed with the latest
+FIFO data only if:
.IP 1.
-there is some keyboard activity from the terminal; or
+suspended mode is not in effect; and
+.IP 2.
+trigger mode is not in effect; and
+.IP 3.
+.I pw
+isn't executing in the background (see the
+.B Ctrl-Z
+command).
+.PP
+
+When the above conditions do not hold, and thus the display is being
+automatically refreshed, it is refreshed at these times:
+.IP 1.
+when there is some keyboard activity from the terminal; or
.IP 2.
when the interval period has expired
without new input having been seen; or else
@@ -83,12 +78,22 @@ without new input having been seen; or else
whenever the long period elapses.
.PP
-In other words, while the pipe is spewing, and there is
-no keyboard input, the display is updated infrequently, only according to the
-long interval.
+In other words, while the input is rapidly producing data, and there is no
+keyboard input, the display is updated infrequently, only according to the long
+interval.
+
+If
+.I pw
+is executing in the foreground, and if display updates aren't suspended, and if
+trigger mode is effect, then the display updates automatically only when a
+trigger is activated by a pattern match on the FIFO contents. Trigger mode is
+activated using the
+.B >
+and
+.B ?
+commands below.
-The display is also updated when standard input indicates end-of-data.
-In this situation,
+When standard input indicates end-of-data.
.I pw
terminates, unless the
.B -d
@@ -128,10 +133,9 @@ portion appears delimited by
.SH COMMANDS
-When
+While reading data from standard input,
.I pw
-enters closed loop operation, the following single-key commands are
-available.
+monitors the TTY for input, providing the following commands.
The commands may be prefixed by a numeric argument, which is ignored by
commands to which it is not applicable. The numeric argument is specified by
@@ -581,6 +585,27 @@ that is the default, this option has no effect unless it appears after a
.B -E
option.
+.SH ENVIRONMENT
+
+.I pw
+ignores the
+.B TERM
+environment variable, requiring an ANSI terminal.
+
+.I pw
+requires the following conditions to hold in regard to its execution environment,
+otherwise it terminates with an error diagnostic:
+.IP 1.
+Standard output must be a TTY device.
+.IP 2.
+Standard input is either not a TTY device, or else not the same TTY device
+as standard output.
+.IP 3.
+It must be possible to open the
+.B /dev/tty
+device, which is the same TTY as standard output.
+.PP
+
.SH TERMINATION STATUS
If
diff --git a/pw.c b/pw.c
index 379bc8a..b8f3fa3 100644
--- a/pw.c
+++ b/pw.c
@@ -233,26 +233,6 @@ static char *addchesc(char *line, int ch)
return line;
}
-static char *getln(FILE *stream)
-{
- char *line = 0;
-
- for (;;) {
- int ch = getc(stream);
-
- if (ch == EOF)
- return line;
-
- if (ch == '\n') {
- if (line)
- return line;
- return addch(line, 0);
- }
-
- line = addchesc(line, ch);
- }
-}
-
static void usage(const char *name)
{
fprintf(stderr,
@@ -702,7 +682,8 @@ int main(int argc, char **argv)
FILE *tty = fopen("/dev/tty", "r+");
int maxlines = 15, nlines = 0, maxed = 0;
int opt;
- int fd = fileno(stdin);
+ int ifd = fileno(stdin);
+ int ofd = fileno(stdout);
int ttyfd = tty ? fileno(tty) : -1;
char **circbuf;
struct termios tty_saved, tty_new;
@@ -719,11 +700,32 @@ int main(int argc, char **argv)
static struct sigaction sa;
#endif
- if (fd < 0)
- panic("unable to obtain input file descriptor");
+ if (ifd < 0)
+ panic("unable to obtain input file descriptor\n");
+
+ if (ofd < 0)
+ panic("unable to obtain input file descriptor\n");
+
+ if (!isatty(ofd))
+ error("standard output must be a TTY\n");
if (ttyfd < 0)
- panic("unable to open /dev/tty");
+ panic("unable to open /dev/tty\n");
+
+ {
+ pid_t ogrp = tcgetpgrp(ofd);
+ pid_t igrp = tcgetpgrp(ifd);
+ pid_t tgrp = tcgetpgrp(ttyfd);
+
+ if (ogrp < 0)
+ error("standard output isn't a job control TTY\n");
+
+ if (ogrp != tgrp)
+ error("/dev/tty isn't the same as the standard output TTY\n");
+
+ if (igrp == ogrp)
+ error("standard input and standard output are the same TTY\n");
+ }
while ((opt = getopt(argc, argv, "n:i:l:dEB")) != -1) {
switch (opt) {
@@ -774,15 +776,6 @@ int main(int argc, char **argv)
if ((snapshot[0] = calloc(sizeof *snapshot[0], maxlines)) == 0)
panic("out of memory");
- if (isatty(fd)) {
- while ((line = getln(stdin))) {
- puts(line);
- dsdrop(line);
- }
-
- return 0;
- }
-
if (ioctl(ttyfd, TIOCGWINSZ, &ws) == 0 && ws.ws_row != 0) {
if (maxlines >= ws.ws_row) {
maxlines = ws.ws_row - 1;
@@ -804,7 +797,7 @@ int main(int argc, char **argv)
setvbuf(tty, NULL, _IONBF, 0);
- if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
+ if (fcntl(ifd, F_SETFL, O_NONBLOCK) < 0)
panic("unable to set stdin nonblocking");
if (!isbkgnd(stdout))
@@ -826,7 +819,7 @@ int main(int argc, char **argv)
int force = 0, nfds = 2, pollms = poll_interval;
struct pollfd pe[2] = {
{ .fd = ttyfd, .events = POLLIN | POLLHUP | POLLERR },
- { .fd = fd, .events = POLLIN | POLLHUP | POLLERR },
+ { .fd = ifd, .events = POLLIN | POLLHUP | POLLERR },
};
if ((stat & stat_eof) == 0) {