ptty.c - scroll - scrollbackbuffer program for st | |
git clone git://git.suckless.org/scroll | |
Log | |
Files | |
Refs | |
README | |
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)) ==… | |
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 } |