diff options
author | Kartik Agaram <vc@akkartik.com> | 2019-12-02 23:59:14 -0800 |
---|---|---|
committer | Kartik Agaram <vc@akkartik.com> | 2019-12-02 23:59:14 -0800 |
commit | db66de4a751a6dc170a28bc235d9900e2459e291 (patch) | |
tree | 757af80db874df73ce97a1cfdbdbdbb053082981 /termbox/termbox.c | |
parent | 41302404c7d2d1d4dbf3858a7bcd5665b43bda82 (diff) | |
download | mu-db66de4a751a6dc170a28bc235d9900e2459e291.tar.gz |
5788
Diffstat (limited to 'termbox/termbox.c')
-rw-r--r-- | termbox/termbox.c | 397 |
1 files changed, 0 insertions, 397 deletions
diff --git a/termbox/termbox.c b/termbox/termbox.c deleted file mode 100644 index c97f03d5..00000000 --- a/termbox/termbox.c +++ /dev/null @@ -1,397 +0,0 @@ -#include <assert.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdio.h> -#include <stdbool.h> -#include <sys/ioctl.h> -#include <sys/time.h> -#include <sys/stat.h> -#include <termios.h> -#include <unistd.h> -#include <wchar.h> -/* hack: we can't define _XOPEN_SOURCE because that causes OpenBSD to not - * include SIGWINCH. But then this prototype is not included on Linux, - * triggering a warning. */ -extern int wcwidth (wchar_t); - -#include "termbox.h" - -#include "bytebuffer.inl" -#include "output.inl" -#include "input.inl" - -#define LAST_COORD_INIT -1 - -static struct termios orig_tios; - -static struct bytebuffer output_buffer; -static struct bytebuffer input_buffer; - -static int termw = -1; -static int termh = -1; - -static int inout; -static int winch_fds[2]; - -static int cursor_x = 0; -static int cursor_y = 0; - -static uint16_t background = TB_BLACK; -static uint16_t foreground = TB_WHITE; - -static void update_size(void); -static void update_term_size(void); -static void send_attr(uint16_t fg, uint16_t bg); -static void send_clear(void); -static void sigwinch_handler(int xxx); -static int wait_fill_event(struct tb_event *event, struct timeval *timeout); - -/* may happen in a different thread */ -static volatile int buffer_size_change_request; - -/* -------------------------------------------------------- */ - -int tb_init(void) -{ - inout = open("/dev/tty", O_RDWR); - if (inout == -1) { - return TB_EFAILED_TO_OPEN_TTY; - } - - if (init_term() < 0) { - close(inout); - return TB_EUNSUPPORTED_TERMINAL; - } - - if (pipe(winch_fds) < 0) { - close(inout); - return TB_EPIPE_TRAP_ERROR; - } - - struct sigaction sa; - memset(&sa, 0, sizeof(sa)); - sa.sa_handler = sigwinch_handler; - sa.sa_flags = 0; - sigaction(SIGWINCH, &sa, 0); - - tcgetattr(inout, &orig_tios); - - struct termios tios; - memcpy(&tios, &orig_tios, sizeof(tios)); - - tios.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP - | INLCR | IGNCR | ICRNL | IXON); - tios.c_oflag &= ~OPOST; - tios.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN); - tios.c_cflag &= ~(CSIZE | PARENB); - tios.c_cflag |= CS8; - tios.c_cc[VMIN] = 0; - tios.c_cc[VTIME] = 0; - tcsetattr(inout, TCSAFLUSH, &tios); - - bytebuffer_init(&input_buffer, 128); - bytebuffer_init(&output_buffer, 32 * 1024); - - bytebuffer_puts(&output_buffer, funcs[T_ENTER_KEYPAD]); - bytebuffer_puts(&output_buffer, funcs[T_ENTER_MOUSE]); - bytebuffer_puts(&output_buffer, funcs[T_ENTER_BRACKETED_PASTE]); - bytebuffer_flush(&output_buffer, inout); - - update_term_size(); - return 0; -} - -void tb_shutdown(void) -{ - if (termw == -1) return; - - bytebuffer_puts(&output_buffer, funcs[T_SGR0]); - bytebuffer_puts(&output_buffer, funcs[T_EXIT_KEYPAD]); - bytebuffer_puts(&output_buffer, funcs[T_EXIT_MOUSE]); - bytebuffer_puts(&output_buffer, funcs[T_EXIT_BRACKETED_PASTE]); - bytebuffer_flush(&output_buffer, inout); - tcsetattr(inout, TCSAFLUSH, &orig_tios); - - shutdown_term(); - close(inout); - close(winch_fds[0]); - close(winch_fds[1]); - - bytebuffer_free(&output_buffer); - bytebuffer_free(&input_buffer); - termw = termh = -1; -} - -int tb_is_active(void) -{ - return termw != -1; -} - -void tb_print(uint32_t ch, uint16_t fg, uint16_t bg) -{ - assert(termw != -1); - send_attr(fg, bg); - if (ch == 0) { - // replace 0 with whitespace - bytebuffer_puts(&output_buffer, " "); - } - else { - char buf[7]; - int bw = tb_utf8_unicode_to_char(buf, ch); - buf[bw] = '\0'; - bytebuffer_puts(&output_buffer, buf); - } - bytebuffer_flush(&output_buffer, inout); -} - -int tb_poll_event(struct tb_event *event) -{ - assert(termw != -1); - return wait_fill_event(event, 0); -} - -int tb_peek_event(struct tb_event *event, int timeout) -{ - struct timeval tv; - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout - (tv.tv_sec * 1000)) * 1000; - assert(termw != -1); - return wait_fill_event(event, &tv); -} - -int tb_width(void) -{ - assert(termw != -1); - return termw; -} - -int tb_height(void) -{ - assert(termw != -1); - return termh; -} - -void tb_clear(void) -{ - assert(termw != -1); - if (buffer_size_change_request) { - update_size(); - buffer_size_change_request = 0; - } - send_clear(); -} - -void tb_set_clear_attributes(uint16_t fg, uint16_t bg) -{ - assert(termw != -1); - foreground = fg; - background = bg; -} - -/* -------------------------------------------------------- */ - -static int convertnum(uint32_t num, char* buf) { - int i, l = 0; - int ch; - do { - buf[l++] = '0' + (num % 10); - num /= 10; - } while (num); - for(i = 0; i < l / 2; i++) { - ch = buf[i]; - buf[i] = buf[l - 1 - i]; - buf[l - 1 - i] = ch; - } - return l; -} - -#define WRITE_LITERAL(X) bytebuffer_append(&output_buffer, (X), sizeof(X)-1) -#define WRITE_INT(X) bytebuffer_append(&output_buffer, buf, convertnum((X), buf)) - -void tb_set_cursor(int x, int y) { - char buf[32]; - WRITE_LITERAL("\033["); - WRITE_INT(y+1); - WRITE_LITERAL(";"); - WRITE_INT(x+1); - WRITE_LITERAL("H"); - bytebuffer_flush(&output_buffer, inout); -} - -static void get_term_size(int *w, int *h) -{ - struct winsize sz; - memset(&sz, 0, sizeof(sz)); - - ioctl(inout, TIOCGWINSZ, &sz); - - if (w) *w = sz.ws_col; - if (h) *h = sz.ws_row; -} - -static void update_term_size(void) -{ - struct winsize sz; - memset(&sz, 0, sizeof(sz)); - - ioctl(inout, TIOCGWINSZ, &sz); - - termw = sz.ws_col; - termh = sz.ws_row; -} - -static void send_attr(uint16_t fg, uint16_t bg) -{ -#define LAST_ATTR_INIT 0xFFFF - static uint16_t lastfg = LAST_ATTR_INIT, lastbg = LAST_ATTR_INIT; - if (fg != lastfg || bg != lastbg) { - bytebuffer_puts(&output_buffer, funcs[T_SGR0]); - - uint16_t fgcol = fg & 0xFF; - uint16_t bgcol = bg & 0xFF; - - if (fg & TB_BOLD) - bytebuffer_puts(&output_buffer, funcs[T_BOLD]); - if (bg & TB_BOLD) - bytebuffer_puts(&output_buffer, funcs[T_BLINK]); - if (fg & TB_UNDERLINE) - bytebuffer_puts(&output_buffer, funcs[T_UNDERLINE]); - if ((fg & TB_REVERSE) || (bg & TB_REVERSE)) - bytebuffer_puts(&output_buffer, funcs[T_REVERSE]); - char buf[32]; - WRITE_LITERAL("\033[38;5;"); - WRITE_INT(fgcol); - WRITE_LITERAL("m"); - WRITE_LITERAL("\033[48;5;"); - WRITE_INT(bgcol); - WRITE_LITERAL("m"); - bytebuffer_flush(&output_buffer, inout); - lastfg = fg; - lastbg = bg; - } -} - -const char* to_unicode(uint32_t c) -{ - static char buf[7]; - int bw = tb_utf8_unicode_to_char(buf, c); - buf[bw] = '\0'; - return buf; -} - -static void send_clear(void) -{ - send_attr(foreground, background); - bytebuffer_puts(&output_buffer, funcs[T_CLEAR_SCREEN]); - tb_set_cursor(cursor_x, cursor_y); - bytebuffer_flush(&output_buffer, inout); -} - -static void sigwinch_handler(int xxx) -{ - (void) xxx; - const int zzz = 1; - int yyy = write(winch_fds[1], &zzz, sizeof(int)); - (void) yyy; -} - -static void update_size(void) -{ - update_term_size(); - send_clear(); -} - -static int read_up_to(int n) { - assert(n > 0); - const int prevlen = input_buffer.len; - bytebuffer_resize(&input_buffer, prevlen + n); - - int read_n = 0; - while (read_n <= n) { - ssize_t r = 0; - if (read_n < n) { - r = read(inout, input_buffer.buf + prevlen + read_n, n - read_n); - } -#ifdef __CYGWIN__ - // While linux man for tty says when VMIN == 0 && VTIME == 0, read - // should return 0 when there is nothing to read, cygwin's read returns - // -1. Not sure why and if it's correct to ignore it, but let's pretend - // it's zero. - if (r < 0) r = 0; -#endif - if (r < 0) { - // EAGAIN / EWOULDBLOCK shouldn't occur here - assert(errno != EAGAIN && errno != EWOULDBLOCK); - return -1; - } else if (r > 0) { - read_n += r; - } else { - bytebuffer_resize(&input_buffer, prevlen + read_n); - return read_n; - } - } - assert(!"unreachable"); - return 0; -} - -int tb_event_ready(void) -{ - return input_buffer.len > 0; -} - -static int wait_fill_event(struct tb_event *event, struct timeval *timeout) -{ - // ;-) -#define ENOUGH_DATA_FOR_PARSING 64 - fd_set events; - memset(event, 0, sizeof(struct tb_event)); - - // try to extract event from input buffer, return on success - event->type = TB_EVENT_KEY; - if (extract_event(event, &input_buffer)) - return event->type; - - // it looks like input buffer is incomplete, let's try the short path, - // but first make sure there is enough space - int n = read_up_to(ENOUGH_DATA_FOR_PARSING); - if (n < 0) - return -1; - if (n > 0 && extract_event(event, &input_buffer)) - return event->type; - - // n == 0, or not enough data, let's go to select - while (1) { - FD_ZERO(&events); - FD_SET(inout, &events); - FD_SET(winch_fds[0], &events); - int maxfd = (winch_fds[0] > inout) ? winch_fds[0] : inout; - int result = select(maxfd+1, &events, 0, 0, timeout); - if (!result) - return 0; - - if (FD_ISSET(inout, &events)) { - event->type = TB_EVENT_KEY; - n = read_up_to(ENOUGH_DATA_FOR_PARSING); - if (n < 0) - return -1; - - if (n == 0) - continue; - - if (extract_event(event, &input_buffer)) - return event->type; - } - if (FD_ISSET(winch_fds[0], &events)) { - event->type = TB_EVENT_RESIZE; - int zzz = 0; - int yyy = read(winch_fds[0], &zzz, sizeof(int)); - (void) yyy; - buffer_size_change_request = 1; - get_term_size(&event->w, &event->h); - return TB_EVENT_RESIZE; - } - } -} |