tcmd: execute shell commands - neatvi - [fork] simple vi-type editor with UTF-8 support
 (HTM) git clone git://src.adamsgaard.dk/neatvi
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
       ---
 (DIR) commit 58191346a45866137a12738b1b82b31f40a673aa
 (DIR) parent 6e9f030b017fe128151501d6c0bad0c6e72a8c73
 (HTM) Author: Ali Gholami Rudi <ali@rudi.ir>
       Date:   Fri, 15 May 2015 14:20:23 +0430
       
       cmd: execute shell commands
       
       Diffstat:
         M Makefile                            |       2 +-
         A cmd.c                               |      91 +++++++++++++++++++++++++++++++
         M vi.c                                |      42 +++++++++++++++++++++++++------
         M vi.h                                |       3 +++
       
       4 files changed, 129 insertions(+), 9 deletions(-)
       ---
 (DIR) diff --git a/Makefile b/Makefile
       t@@ -2,7 +2,7 @@ CC = cc
        CFLAGS = -Wall -O2
        LDFLAGS =
        
       -OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o reg.o led.o uc.o term.o rset.o
       +OBJS = vi.o ex.o lbuf.o sbuf.o ren.o dir.o reg.o led.o uc.o term.o rset.o cmd.o
        
        all: vi
        %.o: %.c
 (DIR) diff --git a/cmd.c b/cmd.c
       t@@ -0,0 +1,91 @@
       +#include <poll.h>
       +#include <stdio.h>
       +#include <stdlib.h>
       +#include <string.h>
       +#include <unistd.h>
       +#include <sys/wait.h>
       +#include "vi.h"
       +
       +static int cmd_make(char **argv, int *ifd, int *ofd)
       +{
       +        int pid;
       +        int pipefds0[2];
       +        int pipefds1[2];
       +        if (ifd)
       +                pipe(pipefds0);
       +        if (ofd)
       +                pipe(pipefds1);
       +        if (!(pid = fork())) {
       +                if (ifd) {                /* setting up stdin */
       +                        close(0);
       +                        dup(pipefds0[0]);
       +                        close(pipefds0[1]);
       +                        close(pipefds0[0]);
       +                }
       +                if (ofd) {                /* setting up stdout */
       +                        close(1);
       +                        dup(pipefds1[1]);
       +                        close(pipefds1[0]);
       +                        close(pipefds1[1]);
       +                }
       +                execvp(argv[0], argv);
       +                exit(1);
       +        }
       +        if (ifd)
       +                close(pipefds0[0]);
       +        if (ofd)
       +                close(pipefds1[1]);
       +        if (pid < 0) {
       +                if (ifd)
       +                        close(pipefds0[1]);
       +                if (ofd)
       +                        close(pipefds1[0]);
       +                return -1;
       +        }
       +        if (ifd)
       +                *ifd = pipefds0[1];
       +        if (ofd)
       +                *ofd = pipefds1[0];
       +        return pid;
       +}
       +
       +char *cmd_pipe(char *cmd, char *s)
       +{
       +        char *argv[] = {"/bin/sh", "-c", cmd, NULL};
       +        struct pollfd fds[2];
       +        struct sbuf *sb;
       +        char buf[512];
       +        int ifd = 0, ofd = 0;
       +        int slen = strlen(s);
       +        int nw = 0;
       +        int pid = cmd_make(argv, &ifd, &ofd);
       +        if (pid <= 0)
       +                return NULL;
       +        sb = sbuf_make();
       +        fds[0].fd = ofd;
       +        fds[0].events = POLLIN;
       +        fds[1].fd = ifd;
       +        fds[1].events = POLLOUT;
       +        while ((fds[0].fd >= 0 || fds[1].fd >= 0) && poll(fds, 3, 200) >= 0) {
       +                if (fds[0].revents & POLLIN) {
       +                        int ret = read(fds[0].fd, buf, sizeof(buf));
       +                        if (ret > 0)
       +                                sbuf_mem(sb, buf, ret);
       +                        if (ret < 0)
       +                                close(fds[0].fd);
       +                } else if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
       +                        fds[0].fd = -1;
       +                }
       +                if (fds[1].revents & POLLOUT) {
       +                        int ret = write(fds[1].fd, s + nw, slen - nw);
       +                        if (ret > 0)
       +                                nw += ret;
       +                        if (ret <= 0 || nw == slen)
       +                                close(fds[1].fd);
       +                } else if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
       +                        fds[1].fd = -1;
       +                }
       +        }
       +        waitpid(pid, NULL, 0);
       +        return sbuf_done(sb);
       +}
 (DIR) diff --git a/vi.c b/vi.c
       t@@ -62,6 +62,13 @@ static char *vi_char(void)
                return TK_INT(key) ? NULL : led_keymap(key);
        }
        
       +static char *vi_prompt(char *msg)
       +{
       +        term_pos(xrows, led_pos(msg, 0));
       +        term_kill();
       +        return led_prompt(msg, "");
       +}
       +
        static int vi_yankbuf(void)
        {
                int c = vi_read();
       t@@ -189,10 +196,8 @@ static int vi_search(int cmd, int cnt, int *row, int *col)
                char *off = "";
                if (cmd == '/' || cmd == '?') {
                        char sign[4] = {cmd};
       -                char *kw;
       -                term_pos(xrows, led_pos(sign, 0));
       -                term_kill();
       -                if (!(kw = led_prompt(sign, "")))
       +                char *kw = vi_prompt(sign);
       +                if (!kw)
                                return 1;
                        vi_finddir = cmd == '/' ? +1 : -1;
                        if (kw[0])
       t@@ -332,7 +337,7 @@ static int vi_motionln(int *row, int cmd)
                        break;
                default:
                        if (c == cmd) {
       -                        *row = MIN(*row + cnt - 1, lbuf_len(xb) - 1);
       +                        *row = MAX(0, MIN(*row + cnt - 1, lbuf_len(xb) - 1));
                                break;
                        }
                        vi_back(c);
       t@@ -667,6 +672,26 @@ static void vi_change(int r1, int c1, int r2, int c2, int lnmode, int closed)
                free(post);
        }
        
       +static void vi_pipe(int r1, int c1, int r2, int c2, int lnmode, int closed)
       +{
       +        char *text;
       +        char *rep;
       +        char *cmd = vi_prompt("!");
       +        if (!cmd)
       +                return;
       +        if (r2 < r1)
       +                swap(&r1, &r2);
       +        text = lbuf_cp(xb, r1, r2 + 1);
       +        rep = cmd_pipe(cmd, text);
       +        if (rep) {
       +                lbuf_rm(xb, r1, r2 + 1);
       +                lbuf_put(xb, r1, rep);
       +        }
       +        free(cmd);
       +        free(text);
       +        free(rep);
       +}
       +
        static int vc_motion(int cmd)
        {
                int r1 = xrow, r2 = xrow;        /* region rows */
       t@@ -698,6 +723,8 @@ static int vc_motion(int cmd)
                        vi_delete(r1, c1, r2, c2, lnmode, closed);
                if (cmd == 'c')
                        vi_change(r1, c1, r2, c2, lnmode, closed);
       +        if (cmd == '!')
       +                vi_pipe(r1, c1, r2, c2, lnmode, closed);
                return 0;
        }
        
       t@@ -950,9 +977,7 @@ static void vi(void)
                                        redraw = 1;
                                        break;
                                case ':':
       -                                term_pos(xrows, led_pos(":", 0));
       -                                term_kill();
       -                                ln = led_prompt(":", "");
       +                                ln = vi_prompt(":");
                                        if (ln && ln[0]) {
                                                ex_command(ln);
                                                redraw = 1;
       t@@ -964,6 +989,7 @@ static void vi(void)
                                case 'c':
                                case 'd':
                                case 'y':
       +                        case '!':
                                        if (!vc_motion(c))
                                                redraw = 1;
                                        break;
 (DIR) diff --git a/vi.h b/vi.h
       t@@ -119,6 +119,9 @@ int led_pos(char *s, int pos);
        void ex(void);
        void ex_command(char *cmd);
        
       +/* process management */
       +char *cmd_pipe(char *cmd, char *s);
       +
        /* global variables */
        extern int xvis;
        extern struct lbuf *xb;