|
| 1 | +#!/bin/bash |
| 2 | +set -euo pipefail |
| 3 | + |
| 4 | +main() { |
| 5 | + init_files "$@" |
| 6 | + alter_headers |
| 7 | + alter_structs |
| 8 | + alter_errors |
| 9 | + alter_functions |
| 10 | +} |
| 11 | + |
| 12 | +init_files() { |
| 13 | + in=${1:-termbox2.h} |
| 14 | + out=${1:-termbox2_win.h} |
| 15 | + cp -vf "$in" "$out" |
| 16 | + tmp=$(mktemp) |
| 17 | +} |
| 18 | + |
| 19 | +alter_headers() { |
| 20 | + my_sed '/__posix_header_start/,/__posix_header_end/c\#include <windows.h>\n#include <synchapi.h>\n' |
| 21 | +} |
| 22 | + |
| 23 | +alter_structs() { |
| 24 | + my_sed 's/^(\s+)int (rfd|wfd|ttyfd);/\1HANDLE \2;/g' |
| 25 | + my_sed 's/^(\s+)struct termios orig_tios;/\1DWORD orig_tios[2];/g' |
| 26 | +} |
| 27 | + |
| 28 | +alter_errors() { |
| 29 | + local err_line |
| 30 | + local err_line_num |
| 31 | + local err_val |
| 32 | + err_line=$(grep -E -n '^#define TB_ERR_.+[0-9]+$' "$out" | tail -n1) |
| 33 | + err_line_num=$(cut -d: -f1 <<<"$err_line") |
| 34 | + err_val=$(awk '{print $NF}' <<<"$err_line") |
| 35 | + my_sed "${err_line_num}a #define TB_ERR_WIN_UNSUPPORTED $((err_val - 5))" |
| 36 | + my_sed "${err_line_num}a #define TB_ERR_WIN_NO_STDIO $((err_val - 4))" |
| 37 | + my_sed "${err_line_num}a #define TB_ERR_WIN_SET_CONMODE $((err_val - 3))" |
| 38 | + my_sed "${err_line_num}a #define TB_ERR_WIN_GET_CONMODE $((err_val - 2))" |
| 39 | + my_sed "${err_line_num}a #define TB_ERR_WIN_RESIZE $((err_val - 1))" |
| 40 | + my_sed '/case TB_ERR:/i \ case TB_ERR_WIN_UNSUPPORTED: return "Unsupporrted (Windows)";' |
| 41 | + my_sed '/case TB_ERR:/i \ case TB_ERR_WIN_NO_STDIO: return "Stdio not available (Windows)";' |
| 42 | + my_sed '/case TB_ERR:/i \ case TB_ERR_WIN_SET_CONMODE: return "Failed to set console mode (Windows)";' |
| 43 | + my_sed '/case TB_ERR:/i \ case TB_ERR_WIN_GET_CONMODE: return "Failed to get console mode (Windows)";' |
| 44 | + my_sed '/case TB_ERR:/i \ case TB_ERR_WIN_RESIZE: return "Failed to resize console (Windows)";' |
| 45 | +} |
| 46 | + |
| 47 | +alter_functions() { |
| 48 | + replace_function 'int tb_get_fds' <<<' return TB_ERR_WIN_UNSUPPORTED;' |
| 49 | + replace_function 'static int update_term_size_via_esc' <<<' return TB_ERR;' |
| 50 | + replace_function 'static int load_terminfo' <<<' return TB_ERR;' |
| 51 | + replace_function 'static void handle_resize' <<<' (void)sig;'; |
| 52 | + replace_function 'static int init_resize_handler' <<<' return TB_OK;' |
| 53 | + |
| 54 | + my_sed 's/getenv\("TERM"\)/"xterm-256color"/' |
| 55 | + |
| 56 | + alter_function 'const char \*tb_strerror' <<'EOD' |
| 57 | + snprintf(global.errbuf, sizeof(global.errbuf), "Unknown error (Windows)"); |
| 58 | +EOD |
| 59 | + |
| 60 | + replace_function 'int tb_init_file' <<'EOD' |
| 61 | + if (global.initialized) return TB_ERR_INIT_ALREADY; |
| 62 | + if (strcmp(path, "/dev/tty")) return TB_ERR_WIN_UNSUPPORTED; |
| 63 | + return tb_init_fd(-1); |
| 64 | +EOD |
| 65 | + |
| 66 | + my_sed 's/^(\s+)global\.(rfd|wfd|ttyfd) = -1;$/\1global.\2 = NULL;/' |
| 67 | + alter_function 'int tb_init_rwfd' <<'EOD' |
| 68 | + if (rfd != -1 || wfd != -1) return TB_ERR_WIN_UNSUPPORTED; |
| 69 | + global.rfd = GetStdHandle(STD_INPUT_HANDLE); |
| 70 | + global.wfd = GetStdHandle(STD_OUTPUT_HANDLE); |
| 71 | + if (!global.rfd || global.rfd == INVALID_HANDLE_VALUE) return TB_ERR_WIN_NO_STDIO; |
| 72 | + if (!global.wfd || global.wfd == INVALID_HANDLE_VALUE) return TB_ERR_WIN_NO_STDIO; |
| 73 | + global.ttyfd = global.wfd; |
| 74 | + global.ttyfd_open = 1; |
| 75 | +EOD |
| 76 | + |
| 77 | + alter_function 'static int tb_deinit' <<'EOD' |
| 78 | + if (global.has_orig_tios) { |
| 79 | + SetConsoleMode(global.rfd, global.orig_tios[0]); |
| 80 | + SetConsoleMode(global.wfd, global.orig_tios[1]); |
| 81 | + } |
| 82 | +EOD |
| 83 | + |
| 84 | + my_sed 's/int bytebuf_flush\(struct bytebuf \*b, int fd\)/int bytebuf_flush(struct bytebuf *b, HANDLE fd)/' |
| 85 | + alter_function 'static int bytebuf_flush' <<'EOD' |
| 86 | + DWORD nw; |
| 87 | + if (!WriteConsoleA(fd, b->buf, (DWORD)b->len, &nw, NULL) || nw != b->len) { |
| 88 | + return TB_ERR; // TODO: GetLastError |
| 89 | + } |
| 90 | +EOD |
| 91 | + |
| 92 | + replace_function 'static int init_term_attrs' <<'EOD' |
| 93 | + if ( !SetConsoleCP(CP_UTF8) |
| 94 | + || !SetConsoleOutputCP(CP_UTF8)) { |
| 95 | + return TB_ERR_WIN_SET_CONMODE; |
| 96 | + } else if (!GetConsoleMode(global.rfd, &global.orig_tios[0]) |
| 97 | + || !GetConsoleMode(global.wfd, &global.orig_tios[1]) |
| 98 | + || !(global.has_orig_tios = 1)) { |
| 99 | + return TB_ERR_WIN_GET_CONMODE; |
| 100 | + } else if (!SetConsoleMode(global.rfd, ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT | ENABLE_VIRTUAL_TERMINAL_INPUT) |
| 101 | + || !SetConsoleMode(global.wfd, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN)) { |
| 102 | + return TB_ERR_WIN_SET_CONMODE; |
| 103 | + } |
| 104 | + return TB_OK; |
| 105 | +EOD |
| 106 | + |
| 107 | + |
| 108 | + replace_function 'static int update_term_size' <<'EOD' |
| 109 | + CONSOLE_SCREEN_BUFFER_INFO info; |
| 110 | + if (!GetConsoleScreenBufferInfo(global.wfd, &info)) { |
| 111 | + return TB_ERR_WIN_RESIZE; |
| 112 | + } |
| 113 | + global.width = info.dwSize.X; |
| 114 | + global.height = info.dwSize.Y; |
| 115 | + return TB_OK; |
| 116 | +EOD |
| 117 | + |
| 118 | + replace_function 'static int init_term_caps' <<'EOD' |
| 119 | + (void)load_terminfo; |
| 120 | + (void)parse_terminfo_caps; |
| 121 | + return load_builtin_caps(); |
| 122 | +EOD |
| 123 | + |
| 124 | + replace_function 'static int wait_event' <<'EOD' |
| 125 | + int rv; |
| 126 | + INPUT_RECORD buf[TB_OPT_READ_BUF]; |
| 127 | +
|
| 128 | + memset(event, 0, sizeof(*event)); |
| 129 | + if_ok_return(rv, extract_event(event)); |
| 130 | +
|
| 131 | + do { |
| 132 | + DWORD wait_rv = WaitForSingleObject(global.rfd, (DWORD)timeout); |
| 133 | + if (wait_rv == WAIT_TIMEOUT) { |
| 134 | + return TB_ERR_NO_EVENT; |
| 135 | + } else if (wait_rv != WAIT_OBJECT_0) { |
| 136 | + return TB_ERR_POLL; |
| 137 | + } |
| 138 | +
|
| 139 | + DWORD nevent = 0; |
| 140 | + if (!ReadConsoleInputA(global.rfd, buf, TB_OPT_READ_BUF, &nevent)) { |
| 141 | + return TB_ERR_READ; |
| 142 | + } |
| 143 | +
|
| 144 | + DWORD i; |
| 145 | + for (i = 0; i < nevent; i++) { |
| 146 | + if (buf[i].EventType == KEY_EVENT) { |
| 147 | + if (buf[i].Event.KeyEvent.bKeyDown && |
| 148 | + buf[i].Event.KeyEvent.uChar.AsciiChar != 0) |
| 149 | + { |
| 150 | + bytebuf_nputs(&global.in, |
| 151 | + &(buf[i].Event.KeyEvent.uChar.AsciiChar), 1); |
| 152 | + } |
| 153 | + } |
| 154 | + } |
| 155 | +
|
| 156 | + for (i = 0; i < nevent; i++) { |
| 157 | + if (buf[i].EventType == WINDOW_BUFFER_SIZE_EVENT) { |
| 158 | + if_err_return(rv, update_term_size()); |
| 159 | + if_err_return(rv, resize_cellbufs()); |
| 160 | + event->type = TB_EVENT_RESIZE; |
| 161 | + event->w = global.width; |
| 162 | + event->h = global.height; |
| 163 | + return TB_OK; |
| 164 | + } |
| 165 | + } |
| 166 | +
|
| 167 | + memset(event, 0, sizeof(*event)); |
| 168 | + if_ok_return(rv, extract_event(event)); |
| 169 | + } while (timeout == -1); |
| 170 | +
|
| 171 | + return rv; |
| 172 | +EOD |
| 173 | +} |
| 174 | + |
| 175 | +alter_function() { |
| 176 | + local fsig=$1 |
| 177 | + local fcode=$(cat) |
| 178 | + awk -va=0 -vb=0 -vfcode="$fcode" \ |
| 179 | + "/^${fsig}\(.* {$/ { a=1; print; next } |
| 180 | + a==1 && /__posix_start/ { b=1 } |
| 181 | + b==0 { print } |
| 182 | + b==1 && /__posix_end/ { print fcode; b=0; a=0 }" \ |
| 183 | + "$out" >"$tmp" |
| 184 | + mv -f "$tmp" "$out" |
| 185 | + echo "alter_function $fsig" |
| 186 | +} |
| 187 | + |
| 188 | +replace_function() { |
| 189 | + local fsig=$1 |
| 190 | + local fbody=$(cat) |
| 191 | + awk -va=0 -vfbody="$fbody" \ |
| 192 | + "/^${fsig}\(.* {$/ { a=1; print; next } |
| 193 | + a==0 { print } |
| 194 | + a==1 && /^}$/ { print fbody; print; a=0 }" \ |
| 195 | + "$out" >"$tmp" |
| 196 | + mv -f "$tmp" "$out" |
| 197 | + echo "replace_function $fsig" |
| 198 | +} |
| 199 | + |
| 200 | +my_sed() { |
| 201 | + sed -i -E "$@" "$out" |
| 202 | + echo "sed ${1:-}" |
| 203 | +} |
| 204 | + |
| 205 | +main "$@" |
0 commit comments