diff options
-rw-r--r-- | pw.c | 141 |
1 files changed, 85 insertions, 56 deletions
@@ -11,6 +11,8 @@ #include <termios.h> #include <sys/ioctl.h> #include <sys/time.h> +#include <fcntl.h> +#include <errno.h> #include <regex.h> enum status_flags { @@ -120,6 +122,21 @@ static char *addch(char *line, int ch) abort(); } +static char *addchesc(char *line, int ch) +{ + if (ch == 127) { + line = addch(line, '^'); + line = addch(line, '?'); + } else if (ch < 32) { + line = addch(line, '^'); + line = addch(line, ch + 64); + } else { + line = addch(line, ch); + } + + return line; +} + static char *getln(FILE *stream) { char *line = 0; @@ -136,15 +153,7 @@ static char *getln(FILE *stream) return addch(line, 0); } - if (ch == 127) { - line = addch(line, '^'); - line = addch(line, '?'); - } else if (ch < 32) { - line = addch(line, '^'); - line = addch(line, ch + 64); - } else { - line = addch(line, ch); - } + line = addchesc(line, ch); } } @@ -294,7 +303,7 @@ static void execute(char *cmd) int main(int argc, char **argv) { - char *line; + char *line = 0; FILE *tty = fopen("/dev/tty", "r+"); int maxlines = 15, nlines = 0; int poll_interval = 1000; @@ -383,12 +392,14 @@ int main(int argc, char **argv) panic("unable to set TTY parameters"); setvbuf(tty, NULL, _IONBF, 0); - setvbuf(stdin, NULL, _IONBF, 0); + + if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) + panic("unable to set stdin nonblocking"); for (unsigned stat = stat_dirty, hpos = 0, kbd_state = kbd_cmd, lasttime = ~0U; kbd_state != kbd_exit ;) { - int force = 0; + int force = 0, nfds = 2, pollms = poll_interval; struct pollfd pe[2] = { { .fd = ttyfd, .events = POLLIN | POLLHUP | POLLERR }, { .fd = fd, .events = POLLIN | POLLHUP | POLLERR }, @@ -412,59 +423,77 @@ int main(int argc, char **argv) } } - if (force) { - redraw(circbuf, nlines, hpos, columns, stat, curcmd); - stat &= ~(stat_dirty | stat_trgrd); - } - - if (poll(pe, ((stat & stat_eof)) ? 1 : 2, poll_interval) <= 0) { - if ((stat & stat_dirty) && nlines == maxlines) { - redraw(circbuf, nlines, hpos, columns, stat, curcmd); - stat &= ~stat_dirty; - } - if (kbd_state == kbd_esc || kbd_state == kbd_result) { - kbd_state = kbd_cmd; - curcmd = 0; - clrline(); - drawstatus(stat, curcmd); - } - } else { - if ((stat & stat_eof) == 0 && pe[1].revents) { - if ((line = getln(stdin))) { - if ((stat & stat_htmode)) - if (regexec(&trigex, line, 0, NULL, 0) == 0) - stat |= stat_trgrd; - if (nlines == maxlines) { - dsdrop(circbuf[0]); - memmove(circbuf, circbuf + 1, (nlines - 1) * sizeof *circbuf); - circbuf[nlines - 1] = line; - stat |= stat_dirty; - if ((stat & stat_ttmode)) - if (regexec(&trigex, circbuf[0], 0, NULL, 0) == 0) - stat |= stat_trgrd; - } else { - circbuf[nlines++] = line; - if ((stat & stat_susp) == 0) { - snapshot[snaplines++] = dsref(line); - clrline(); - drawline(line, hpos, columns); - drawstatus(stat, curcmd); - } - } - } else { - if (auto_quit) - kbd_state = kbd_exit; - else + if ((stat & stat_eof) == 0) { + int ch; + while ((ch = getc(stdin)) != EOF && ch != '\n') + line = addchesc(line, ch); + if (ch == EOF) { + if (feof(stdin) || (errno != EAGAIN && errno != EWOULDBLOCK)) { + nfds = 1; + if (!auto_quit) stat |= stat_eof; redraw(circbuf, nlines, hpos, columns, stat, curcmd); stat |= stat_eof; stat &= ~stat_dirty; if (!ferror(stdin)) exit_status = 0; - continue; + if (auto_quit) + break; + } + clearerr(stdin); + } else { + nfds = 1; + line = addch(line, 0); + if ((stat & stat_htmode)) + if (regexec(&trigex, line, 0, NULL, 0) == 0) + stat |= stat_trgrd; + if (nlines == maxlines) { + dsdrop(circbuf[0]); + memmove(circbuf, circbuf + 1, (nlines - 1) * sizeof *circbuf); + circbuf[nlines - 1] = line; + stat |= stat_dirty; + if ((stat & stat_ttmode)) + if (regexec(&trigex, circbuf[0], 0, NULL, 0) == 0) + stat |= stat_trgrd; + } else { + circbuf[nlines++] = line; + if ((stat & stat_susp) == 0) { + snapshot[snaplines++] = dsref(line); + clrline(); + drawline(line, hpos, columns); + drawstatus(stat, curcmd); + } } + line = 0; } + } else { + nfds = 1; + } + + if (force) { + redraw(circbuf, nlines, hpos, columns, stat, curcmd); + stat &= ~(stat_dirty | stat_trgrd); + } + + if ((stat & stat_eof)) + pollms = -1; + else if (nfds < 2) + pollms = 0; + if (poll(pe, nfds, pollms) <= 0) { + if (pollms) { + if ((stat & stat_dirty) && nlines == maxlines) { + redraw(circbuf, nlines, hpos, columns, stat, curcmd); + stat &= ~stat_dirty; + } + if (kbd_state == kbd_esc || kbd_state == kbd_result) { + kbd_state = kbd_cmd; + curcmd = 0; + clrline(); + drawstatus(stat, curcmd); + } + } + } else { if ((pe[0].revents)) { int ch = getc(tty); |