lchat: exclude filter from input tail pipe - lchat - A line oriented chat front end for ii.
 (HTM) git clone git://git.suckless.org/lchat
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit e5371dc7ca278ac80852f30b699ae3f0ae8627bf
 (DIR) parent 5d78aec7398254c86ce90cb53d750af437f12a75
 (HTM) Author: Jan Klemkow <j.klemkow@wemelug.de>
       Date:   Wed, 22 Feb 2017 21:08:33 +0100
       
       lchat: exclude filter from input tail pipe
       
       This avoids a conflict between .bellmatch and .filter.
       Both programs get the same raw input from tail now.
       
       Diffstat:
         M lchat.c                             |      83 ++++++++++++++++++++++++++++---
       
       1 file changed, 77 insertions(+), 6 deletions(-)
       ---
 (DIR) diff --git a/lchat.c b/lchat.c
       @@ -119,6 +119,45 @@ line_output(struct slackline *sl, char *file)
        }
        
        static void
       +fork_filter(int *read, int *write)
       +{
       +        int fds_read[2];        /* .filter -> lchat */
       +        int fds_write[2];        /* lchat -> .filter */
       +
       +        if (pipe(fds_read) == -1)
       +                err(EXIT_FAILURE, "pipe");
       +        if (pipe(fds_write) == -1)
       +                err(EXIT_FAILURE, "pipe");
       +
       +        switch (fork()) {
       +        case -1:
       +                err(EXIT_FAILURE, "fork of .filter");
       +        case 0:        /* child */
       +                if (dup2(fds_read[1], STDOUT_FILENO) == -1)
       +                        err(EXIT_FAILURE, "dup2");
       +                if (dup2(fds_write[0], STDIN_FILENO) == -1)
       +                        err(EXIT_FAILURE, "dup2");
       +
       +                if (close(fds_read[0]) == -1)
       +                        err(EXIT_FAILURE, "close");
       +                if (close(fds_write[1]) == -1)
       +                        err(EXIT_FAILURE, "close");
       +
       +                execl("./.filter", "./.filter", NULL);
       +                err(EXIT_FAILURE, "exec of .filter");
       +        }
       +
       +        /* parent */
       +        if (close(fds_read[1]) == -1)
       +                err(EXIT_FAILURE, "close");
       +        if (close(fds_write[0]) == -1)
       +                err(EXIT_FAILURE, "close");
       +
       +        *read = fds_read[0];
       +        *write = fds_write[1];
       +}
       +
       +static void
        usage(void)
        {
                fprintf(stderr, "lchat [-aeh] [-n lines] [-p prompt] [-t title] [-i in]"
       @@ -129,11 +168,13 @@ usage(void)
        int
        main(int argc, char *argv[])
        {
       -        struct pollfd pfd[2];
       +        struct pollfd pfd[3];
                struct termios term;
                struct slackline *sl = sl_init();
                int fd = STDIN_FILENO;
                int read_fd = 6;
       +        int read_filter = -1;
       +        int backend_sink = STDOUT_FILENO;
                char c;
                int ch;
                bool empty_line = false;
       @@ -260,27 +301,35 @@ main(int argc, char *argv[])
                        snprintf(tail_cmd, sizeof tail_cmd, "exec tail -n %zd -f %s",
                            history_len, out_file);
        
       -                if (access(".filter", X_OK) == 0)
       -                        strlcat(tail_cmd, " | ./.filter", sizeof tail_cmd);
       -
                        if ((fh = popen(tail_cmd, "r")) == NULL)
                                err(EXIT_FAILURE, "unable to open pipe to tail");
        
                        read_fd = fileno(fh);
                }
        
       +        int nfds = 2;
       +
                pfd[0].fd = fd;
                pfd[0].events = POLLIN;
        
                pfd[1].fd = read_fd;
                pfd[1].events = POLLIN;
        
       +        if (access(".filter", X_OK) == 0) {
       +                fork_filter(&read_filter, &backend_sink);
       +
       +                pfd[2].fd = read_filter;
       +                pfd[2].events = POLLIN;
       +
       +                nfds = 3;
       +        }
       +
                /* print initial prompt */
                fputs(prompt, stdout);
        
                for (;;) {
                        errno = 0;
       -                if (poll(pfd, 2, INFTIM) == -1 && errno != EINTR)
       +                if (poll(pfd, nfds, INFTIM) == -1 && errno != EINTR)
                                err(EXIT_FAILURE, "poll");
        
                        /* moves cursor back after linewrap */
       @@ -338,7 +387,7 @@ main(int argc, char *argv[])
                                        errx(EXIT_FAILURE, "backend exited");
                                if (n == -1)
                                        err(EXIT_FAILURE, "read");
       -                        if (write(STDOUT_FILENO, buf, n) == -1)
       +                        if (write(backend_sink, buf, n) == -1)
                                        err(EXIT_FAILURE, "write");
        
                                /* terminate the input buffer with NUL */
       @@ -348,6 +397,28 @@ main(int argc, char *argv[])
                                if (bell_flag && bell_match(buf, bell_file))
                                        putchar('\a');
                        }
       +
       +                /* handel optional .filter i/o */
       +                if (nfds > 2) {
       +                        /* handle .filter error and its broken pipe */
       +                        if (pfd[2].revents & POLLHUP)
       +                                break;
       +                        if (pfd[2].revents & POLLERR ||
       +                            pfd[2].revents & POLLNVAL)
       +                                errx(EXIT_FAILURE, ".filter error");
       +
       +                        /* handle .filter output */
       +                        if (pfd[2].revents & POLLIN) {
       +                                char buf[BUFSIZ];
       +                                ssize_t n = read(pfd[2].fd, buf, sizeof buf);
       +                                if (n == 0)
       +                                        errx(EXIT_FAILURE, ".filter exited");
       +                                if (n == -1)
       +                                        err(EXIT_FAILURE, "read");
       +                                if (write(STDOUT_FILENO, buf, n) == -1)
       +                                        err(EXIT_FAILURE, "write");
       +                        }
       +                }
         out:
                        /* show current input line */
                        fputs(prompt, stdout);