#include #include #include #include #include #include #include #include #include #include #include int master; void winsize_set(void) { struct winsize win; ioctl(fileno(stdin), TIOCGWINSZ, &win); ioctl(master, TIOCSWINSZ, &win); } void sig_handler(int sig) { switch (sig) { case SIGWINCH: winsize_set(); break; case SIGCHLD: { struct termios tt; tcgetattr(fileno(stdout), &tt); tt.c_oflag |= OPOST; tt.c_lflag |= ECHO|ICANON|ISIG; tt.c_iflag |= IXON; tcsetattr(fileno(stdout), TCSANOW, &tt); } /* printf("Child Terminated.\n"); */ break; } } int write_all(int fd, char *buf, int len) { int cnt = 0; char *p = buf; while (len > cnt) { int ret = write(fd, p+cnt, len-cnt); if (ret < 0) return ret; cnt += ret; } return cnt; } int automate_vim() { int pm, ps; pid_t pid; if (openpty(&pm, &ps, NULL, NULL, NULL) < 0) { perror("openpty()"); exit(-1); } master = pm; /* for signal handler */ { /* Disable echo */ struct termios tt; tcgetattr(ps, &tt); tt.c_lflag &= ~ECHO; tcsetattr(ps, TCSANOW, &tt); } pid = fork(); if (pid<0) { perror("fork()"); close(pm); exit(-1); } if (pid != 0) { /* Parent */ close(ps); { /* Setup STDIN and STDOUT */ struct termios tt; tcgetattr(fileno(stdout), &tt); tt.c_oflag &= ~OPOST; tcsetattr(fileno(stdout), TCSANOW, &tt); tcgetattr(fileno(stdin), &tt); tt.c_lflag &= ~(ECHO|ICANON|ISIG); tt.c_iflag &= ~IXON; tcsetattr(fileno(stdin), TCSANOW, &tt); } signal(SIGWINCH, sig_handler); signal(SIGCHLD, sig_handler); winsize_set(); { /* Send commands to vim */ int i; write(pm, "1G", 2); /* Goto first line */ for (i=0; i<100; i++) { write(pm, "\006\002", 2); /* Scroll up and down */ } write(pm, ":q!\n", 4); /* Quit */ } /* Process Input and Output */ for (;;) { fd_set rdfds; int nfd; int r; FD_ZERO(&rdfds); FD_SET(pm, &rdfds); FD_SET(fileno(stdin), &rdfds); nfd = ((pm > fileno(stdin))? pm : fileno(stdin) ) + 1; r = select(nfd, &rdfds, NULL, NULL, NULL); if (r<0 && errno == EINTR) { /* if ( waitpid(pid, NULL, WNOHANG) == pid) break; */ continue; } if (r<=0) { perror("select()"); close(pm); exit(-1); } if (r) { char buf[BUFSIZ]; int len; if (FD_ISSET(pm, &rdfds)) { len = read(pm, buf, BUFSIZ); if (len<=0) break; if (len > 0) { len = write_all(fileno(stdout), buf, len); if (len<=0) break; } } if (FD_ISSET(fileno(stdin), &rdfds)) { len = read(fileno(stdin), buf, BUFSIZ); if (len<=0) break; len = write_all(pm, buf, len); if (len<=0) break; } } } wait(NULL); close(pm); } else { /* Child */ close(pm); setsid(); ioctl(ps, TIOCSCTTY, 0); dup2(ps, fileno(stdin)); dup2(ps, fileno(stdout)); dup2(ps, fileno(stderr)); close(ps); execl("/usr/bin/vim", "vim", "pty_vim.c", NULL); perror("execl()"); exit(-1); } return 0; } int main() { struct timespec tv0, tv1; clock_gettime(CLOCK_MONOTONIC, &tv0); automate_vim(); clock_gettime(CLOCK_MONOTONIC, &tv1); printf("Total: %f second\n", (tv1.tv_sec - tv0.tv_sec) + (tv1.tv_nsec - tv0.tv_nsec)*1e-9); return 0; }