summaryrefslogtreecommitdiffstats
path: root/src/term.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/term.c')
-rw-r--r--src/term.c120
1 files changed, 120 insertions, 0 deletions
diff --git a/src/term.c b/src/term.c
new file mode 100644
index 0000000..dda5f65
--- /dev/null
+++ b/src/term.c
@@ -0,0 +1,120 @@
+#include <errno.h>
+#include <poll.h>
+#include <signal.h>
+#include <stddef.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <termios.h>
+#include <time.h>
+#include <unistd.h>
+
+static struct termios saved;
+static int active = 0;
+static volatile sig_atomic_t stopped = 0;
+
+static void on_signal(int sig)
+{
+ (void)sig;
+ stopped = 1;
+}
+
+int zm_enter(void)
+{
+ struct termios t;
+ if (tcgetattr(STDIN_FILENO, &saved) != 0)
+ return -1;
+ t = saved;
+ t.c_lflag &= ~(tcflag_t)(ISIG | ICANON | ECHO);
+ t.c_cc[VMIN] = 0;
+ t.c_cc[VTIME] = 0;
+ if (tcsetattr(STDIN_FILENO, TCSANOW, &t) != 0)
+ return -1;
+ active = 1;
+ return 0;
+}
+
+void zm_leave(void)
+{
+ if (active) {
+ tcsetattr(STDIN_FILENO, TCSAFLUSH, &saved);
+ active = 0;
+ }
+}
+
+void zm_install(int lock)
+{
+ struct sigaction handle;
+ struct sigaction ignore;
+ memset(&handle, 0, sizeof handle);
+ memset(&ignore, 0, sizeof ignore);
+ handle.sa_handler = on_signal;
+ ignore.sa_handler = SIG_IGN;
+ sigemptyset(&handle.sa_mask);
+ sigemptyset(&ignore.sa_mask);
+ sigaction(SIGTERM, &handle, NULL);
+ sigaction(SIGHUP, &handle, NULL);
+ sigaction(SIGINT, lock ? &ignore : &handle, NULL);
+}
+
+int zm_stopped(void)
+{
+ return stopped ? 1 : 0;
+}
+
+int zm_size(int *rows, int *cols)
+{
+ struct winsize ws;
+ memset(&ws, 0, sizeof ws);
+ if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != 0 || ws.ws_row == 0 || ws.ws_col == 0) {
+ memset(&ws, 0, sizeof ws);
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != 0 || ws.ws_row == 0 || ws.ws_col == 0)
+ return -1;
+ }
+ *rows = (int)ws.ws_row;
+ *cols = (int)ws.ws_col;
+ return 0;
+}
+
+int zm_wait(int ms)
+{
+ struct pollfd p;
+ int r;
+ p.fd = STDIN_FILENO;
+ p.events = POLLIN;
+ p.revents = 0;
+ r = poll(&p, 1, ms);
+ return (r > 0 && (p.revents & POLLIN)) ? 1 : 0;
+}
+
+ssize_t zm_read(unsigned char *buf, size_t n)
+{
+ return read(STDIN_FILENO, buf, n);
+}
+
+void zm_write(int fd, const unsigned char *buf, size_t n)
+{
+ size_t off = 0;
+ while (off < n) {
+ ssize_t r = write(fd, buf + off, n - off);
+ if (r < 0) {
+ if (errno == EINTR || errno == EAGAIN)
+ continue;
+ return;
+ }
+ off += (size_t)r;
+ }
+}
+
+unsigned long long zm_seed(void)
+{
+ struct timespec ts;
+ unsigned long long a;
+ unsigned long long b;
+ unsigned long long p;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ a = (unsigned long long)ts.tv_sec;
+ b = (unsigned long long)ts.tv_nsec;
+ p = (unsigned long long)getpid();
+ return (a * 1000000007ULL) ^ b ^ (p << 32);
+}