|
#include <assert.h> |
|
#include <signal.h> |
|
#include <stdbool.h> |
|
#include <stdio.h> |
|
#include <stdlib.h> |
|
#include <uv.h> |
|
|
|
uv_loop_t *loop; |
|
uv_tty_t tty; |
|
uv_tty_t tty_out; |
|
uv_signal_t sigterm; |
|
uv_write_t write_req; |
|
uv_buf_t write_buf[] = { { .base = NULL, .len = 0 } }; |
|
|
|
char *string_to_hex(char *str, size_t len) { |
|
size_t res_len = (len << 1) + 1; |
|
char *res = malloc(res_len); |
|
|
|
for (size_t i = 0; i < len; i++) { |
|
snprintf(res + (i << 1), res_len - (i << 1), "%02hhx", str[i]); |
|
} |
|
res[len << 1] = '\0'; |
|
|
|
return res; |
|
} |
|
|
|
void alloc_cb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { |
|
buf->base = malloc(suggested_size); |
|
buf->len = suggested_size; |
|
} |
|
|
|
void write_cb(uv_write_t *req, int status) { |
|
assert(status == 0); |
|
free(write_buf[0].base); |
|
write_buf[0].len = 0; |
|
} |
|
|
|
void stop() { |
|
int stop_ret = uv_read_stop((uv_stream_t*)&tty); |
|
assert(stop_ret == 0); |
|
|
|
int sigstop_ret = uv_signal_stop(&sigterm); |
|
assert(sigstop_ret == 0); |
|
} |
|
|
|
void read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) { |
|
bool end = false; |
|
if (nread > 0) { |
|
write_buf[0].base = string_to_hex(buf->base, (size_t)nread); |
|
write_buf[0].len = ((size_t)nread << 1) + 1; |
|
int write_ret = uv_write(&write_req, (uv_stream_t*)&tty_out, write_buf, 1, &write_cb); |
|
assert(write_ret == 0); |
|
|
|
for (ssize_t i = 0; i < nread; i++) { |
|
if (buf->base[i] == (0xf & 'c')) { |
|
end = true; |
|
} |
|
} |
|
} else if (nread < 0) { |
|
// error; stop reading |
|
end = true; |
|
} |
|
|
|
if (buf->base && buf->len > 0) { |
|
free(buf->base); |
|
} |
|
|
|
if (end) { |
|
stop(); |
|
} |
|
} |
|
|
|
void signal_cb(uv_signal_t *sig, int signum) { |
|
stop(); |
|
} |
|
|
|
void walk_and_close_cb(uv_handle_t *handle, void *arg) { |
|
if (!uv_is_closing(handle)) { |
|
uv_close(handle, NULL); |
|
} |
|
} |
|
|
|
int main() { |
|
loop = uv_default_loop(); |
|
|
|
int tty_ret = uv_tty_init(loop, &tty, fileno(stdin), 0); |
|
int tty_out_ret = uv_tty_init(loop, &tty_out, fileno(stdout), 0); |
|
int sig_ret = uv_signal_init(loop, &sigterm); |
|
int mode_ret = uv_tty_set_mode(&tty, UV_TTY_MODE_RAW); |
|
assert(tty_ret == 0); |
|
assert(tty_out_ret == 0); |
|
assert(sig_ret == 0); |
|
assert(mode_ret == 0); |
|
|
|
int read_ret = uv_read_start((uv_stream_t*)&tty, &alloc_cb, &read_cb); |
|
assert(read_ret == 0); |
|
|
|
int sigstart_ret = uv_signal_start(&sigterm, signal_cb, SIGTERM); |
|
assert(sigstart_ret == 0); |
|
|
|
int run_ret = uv_run(loop, UV_RUN_DEFAULT); |
|
assert(run_ret == 0); |
|
|
|
int reset_ret = uv_tty_reset_mode(); |
|
assert(reset_ret == 0); |
|
|
|
uv_walk(loop, &walk_and_close_cb, NULL); |
|
run_ret = uv_run(loop, UV_RUN_DEFAULT); |
|
assert(run_ret == 0); |
|
|
|
int close_ret = uv_loop_close(loop); |
|
assert(close_ret == 0); |
|
} |