Archived
0
0
Fork 0
This repository has been archived on 2024-02-06. You can view files and clone it, but cannot push or open issues or pull requests.
dotfiles/suckless/scroll/ptty.c
2021-12-27 21:04:49 -08:00

156 lines
2.7 KiB
C

#include <sys/wait.h>
#include <errno.h>
#include <inttypes.h>
#include <limits.h>
#include <poll.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#if defined(__linux)
#include <pty.h>
#elif defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
#include <util.h>
#elif defined(__FreeBSD__) || defined(__DragonFly__)
#include <libutil.h>
#endif
void
die(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
if (fmt[0] && fmt[strlen(fmt)-1] == ':') {
fputc(' ', stderr);
perror(NULL);
} else {
fputc('\n', stderr);
}
exit(EXIT_FAILURE);
}
void
usage(void)
{
fputs("ptty [-C] [-c cols] [-r rows] cmd\n", stderr);
exit(EXIT_FAILURE);
}
int
main(int argc, char *argv[])
{
struct winsize ws = {.ws_row = 25, .ws_col = 80, 0, 0};
int ch;
bool closeflag = false;
while ((ch = getopt(argc, argv, "c:r:Ch")) != -1) {
switch (ch) {
case 'c': /* cols */
ws.ws_col = strtoimax(optarg, NULL, 10);
if (errno != 0)
die("strtoimax: %s", optarg);
break;
case 'r': /* lines */
ws.ws_row = strtoimax(optarg, NULL, 10);
if (errno != 0)
die("strtoimax: %s", optarg);
break;
case 'C':
closeflag = true;
break;
case 'h':
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc < 1)
usage();
int mfd;
pid_t child = forkpty(&mfd, NULL, NULL, &ws);
switch (child) {
case -1:
die("forkpty");
case 0: /* child */
execvp(argv[0], argv);
die("exec");
}
/* parent */
if (closeflag && close(mfd) == -1)
die("close:");
int pfds = 2;
struct pollfd pfd[2] = {
{ STDIN_FILENO, POLLIN, 0},
{ mfd, POLLIN, 0}
};
for (;;) {
char buf[BUFSIZ];
ssize_t n;
int r;
if ((r = poll(pfd, pfds, -1)) == -1)
die("poll:");
if (pfd[0].revents & POLLIN) {
if ((n = read(STDIN_FILENO, buf, sizeof buf)) == -1)
die("read:");
if (n == 0) {
pfd[0].fd = -1;
if (close(mfd) == -1)
die("close:");
break;
}
if (write(mfd, buf, n) == -1)
die("write:");
}
if (pfd[1].revents & POLLIN) {
if ((n = read(mfd, buf, sizeof(buf)-1)) == -1)
die("read:");
if (n == 0) break;
buf[n] = '\0';
/* handle cursor position request */
if (strcmp("\033[6n", buf) == 0) {
dprintf(mfd, "\033[25;1R");
continue;
}
if (write(STDOUT_FILENO, buf, n) == -1)
die("write:");
}
if (pfd[0].revents & POLLHUP) {
pfd[0].fd = -1;
if (close(mfd) == -1)
die("close:");
break;
}
if (pfd[1].revents & POLLHUP)
break;
}
int status;
if (waitpid(child, &status, 0) != child)
die("waitpid:");
return WEXITSTATUS(status);
}