ptty.c - scroll - scrollbackbuffer program for st
 (HTM) git clone git://git.suckless.org/scroll
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
       ptty.c (2734B)
       ---
            1 #include <sys/wait.h>
            2 
            3 #include <errno.h>
            4 #include <inttypes.h>
            5 #include <limits.h>
            6 #include <poll.h>
            7 #include <stdarg.h>
            8 #include <stdbool.h>
            9 #include <stdio.h>
           10 #include <stdlib.h>
           11 #include <string.h>
           12 #include <termios.h>
           13 #include <unistd.h>
           14 
           15 #if   defined(__linux)
           16  #include <pty.h>
           17 #elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
           18  #include <util.h>
           19 #elif defined(__FreeBSD__) || defined(__DragonFly__)
           20  #include <libutil.h>
           21 #endif
           22 
           23 void
           24 die(const char *fmt, ...)
           25 {
           26         va_list ap;
           27         va_start(ap, fmt);
           28         vfprintf(stderr, fmt, ap);
           29         va_end(ap);
           30 
           31         if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
           32                 fputc(' ', stderr);
           33                 perror(NULL);
           34         } else {
           35                 fputc('\n', stderr);
           36         }
           37 
           38         exit(EXIT_FAILURE);
           39 }
           40 
           41 void
           42 usage(void)
           43 {
           44         fputs("ptty [-C] [-c cols] [-r rows] cmd\n", stderr);
           45         exit(EXIT_FAILURE);
           46 }
           47 
           48 int
           49 main(int argc, char *argv[])
           50 {
           51         struct winsize ws = {.ws_row = 25, .ws_col = 80, 0, 0};
           52         int ch;
           53         bool closeflag = false;
           54 
           55         while ((ch = getopt(argc, argv, "c:r:Ch")) != -1) {
           56                 switch (ch) {
           57                 case 'c':        /* cols */
           58                         ws.ws_col = strtoimax(optarg, NULL, 10);
           59                         if (errno != 0)
           60                                 die("strtoimax: %s", optarg);
           61                         break;
           62                 case 'r':        /* lines */
           63                         ws.ws_row = strtoimax(optarg, NULL, 10);
           64                         if (errno != 0)
           65                                 die("strtoimax: %s", optarg);
           66                         break;
           67                 case 'C':
           68                         closeflag = true;
           69                         break;
           70                 case 'h':
           71                 default:
           72                         usage();
           73                 }
           74         }
           75         argc -= optind;
           76         argv += optind;
           77 
           78         if (argc < 1)
           79                 usage();
           80 
           81         int mfd;
           82         pid_t child = forkpty(&mfd, NULL, NULL, &ws);
           83         switch (child) {
           84         case -1:
           85                 die("forkpty");
           86         case  0: /* child */
           87                 execvp(argv[0], argv);
           88                 die("exec");
           89         }
           90 
           91         /* parent */
           92 
           93         if (closeflag && close(mfd) == -1)
           94                 die("close:");
           95 
           96         int pfds = 2;
           97         struct pollfd pfd[2] = {
           98                 { STDIN_FILENO, POLLIN, 0},
           99                 { mfd,          POLLIN, 0}
          100         };
          101 
          102         for (;;) {
          103                 char buf[BUFSIZ];
          104                 ssize_t n;
          105                 int r;
          106 
          107                 if ((r = poll(pfd, pfds, -1)) == -1)
          108                         die("poll:");
          109 
          110                 if (pfd[0].revents & POLLIN) {
          111                         if ((n = read(STDIN_FILENO, buf, sizeof buf)) == -1)
          112                                 die("read:");
          113                         if (n == 0) {
          114                                 pfd[0].fd = -1;
          115                                 if (close(mfd) == -1)
          116                                         die("close:");
          117                                 break;
          118                         }
          119                         if (write(mfd, buf, n) == -1)
          120                                 die("write:");
          121                 }
          122 
          123                 if (pfd[1].revents & POLLIN) {
          124                         if ((n = read(mfd, buf, sizeof(buf)-1)) == -1)
          125                                 die("read:");
          126 
          127                         if (n == 0) break;
          128 
          129                         buf[n] = '\0';
          130 
          131                         /* handle cursor position request */
          132                         if (strcmp("\033[6n", buf) == 0) {
          133                                 dprintf(mfd, "\033[25;1R");
          134                                 continue;
          135                         }
          136 
          137                         if (write(STDOUT_FILENO, buf, n) == -1)
          138                                 die("write:");
          139                 }
          140 
          141                 if (pfd[0].revents & POLLHUP) {
          142                         pfd[0].fd = -1;
          143                         if (close(mfd) == -1)
          144                                 die("close:");
          145                         break;
          146                 }
          147                 if (pfd[1].revents & POLLHUP)
          148                         break;
          149         }
          150 
          151         int status;
          152         if (waitpid(child, &status, 0) != child)
          153                 die("waitpid:");
          154 
          155         return WEXITSTATUS(status);
          156 }