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 }