aboutsummaryrefslogtreecommitdiff
path: root/client/acronc/handler_stdin.c
blob: fb7c87c744da924ec9bb9828ee31a76ebd84d947 (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
/*
 * Created by yuuta on 7/24/22.
 */

#include "handler.h"
#include "log.h"

#include <stdlib.h>
#include <string.h>

static unsigned int id = 0;

static uv_tty_t tty;

static int (*cb_recv)(ac_request_t *req);

static void (*cb_close)(void);

static void on_close(uv_handle_t *handle) {
    cb_close();
}

static void on_alloc(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
    LOGDV("on_alloc(handle = %p): size = %lu",
          handle,
          size);
    void *b = malloc(size);
    if (!b) {
        LOGEV("Cannot allocate memory of %u bytes: %s.",
              size,
              strerror(errno));
        /* Stream is still working now. */
        uv_close(handle, on_close);
        *buf = uv_buf_init(NULL, 0); /* Just in case? */
        return;
    }
    *buf = uv_buf_init(b, size);
}

static void on_stdin(uv_stream_t *t, ssize_t nread, const uv_buf_t *buf) {
    LOGDV("on_stdin(stream = %p): nread = %ld, buf = %p, buf->base = %p, buf->len = %lu",
          t,
          nread,
          buf, buf->base, buf->len);
    if (!nread) {
        if (buf->base) free(buf->base);
        return;
    }
    if (nread == UV_EOF) {
        LOGI("Exit.");
        free(buf->base);

        cb_close();
        return;
    }
    if (nread < 0) {
        LOGEV("Encountered a failure while reading stdin: ", uv_strerror(nread));
        if (buf->base) free(buf->base);
        uv_close((uv_handle_t *) t, on_close);
        return;
    }
#ifdef _WIN32
    buf->base[nread - 2] = '\0'; /* Remove junk and tailing \r\n */
#else
    buf->base[nread - 1] = '\0'; /* Remove junk and tailing \n */
#endif
    if ((++ id) > INT_MAX) {
        id = 0;
    }
    ac_request_cmd_t req = {
            .type = AC_REQUEST_CMD,
            .id = (int) id,
            .cmd = buf->base
    };
    if (cb_recv((ac_request_t *) &req)) {
        uv_close((uv_handle_t *) t, on_close);
    }
    free(buf->base);
}

int stdin_start(void) {
    return uv_read_start((uv_stream_t *) &tty, on_alloc, on_stdin);
}

void stdin_stop(void) {
    uv_read_stop((uv_stream_t *) &tty);
}

int h_stdin(int (*on_input)(ac_request_t *req),
            void (*on_close)(void)) {
    cb_recv = on_input;
    cb_close = on_close;
    int r;
    if ((r = uv_tty_init(loop, &tty, 0, 0))) return r;
    if ((r = stdin_start())) return r;
    return 0;
}