summaryrefslogtreecommitdiffstats
path: root/src/term.c
blob: dda5f65c950ad1415b5abc15797256eac281a240 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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);
}