1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * Adapted from the following: 33 * 34 * linenoise.c -- guerrilla line editing library against the idea that a 35 * line editing lib needs to be 20,000 lines of C code. 36 * 37 * You can find the original source code at: 38 * http://github.com/antirez/linenoise 39 * 40 * You can find the fork that this code is based on at: 41 * https://github.com/rain-1/linenoise-mob 42 * 43 * ------------------------------------------------------------------------ 44 * 45 * This code is also under the following license: 46 * 47 * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> 48 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> 49 * 50 * Redistribution and use in source and binary forms, with or without 51 * modification, are permitted provided that the following conditions are 52 * met: 53 * 54 * * Redistributions of source code must retain the above copyright 55 * notice, this list of conditions and the following disclaimer. 56 * 57 * * Redistributions in binary form must reproduce the above copyright 58 * notice, this list of conditions and the following disclaimer in the 59 * documentation and/or other materials provided with the distribution. 60 * 61 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 62 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 63 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 64 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 65 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 66 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 67 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 68 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 69 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 70 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 71 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 72 * 73 * ***************************************************************************** 74 * 75 * Definitions for line history. 76 * 77 */ 78 79 #ifndef BC_HISTORY_H 80 #define BC_HISTORY_H 81 82 #ifndef BC_ENABLE_HISTORY 83 #define BC_ENABLE_HISTORY (1) 84 #endif // BC_ENABLE_HISTORY 85 86 #if BC_ENABLE_HISTORY 87 88 #include <stdbool.h> 89 #include <stddef.h> 90 91 #include <signal.h> 92 93 #ifndef _WIN32 94 #include <termios.h> 95 #include <time.h> 96 #include <unistd.h> 97 #include <sys/select.h> 98 #else // _WIN32 99 100 #ifndef WIN32_LEAN_AND_MEAN 101 #define WIN32_LEAN_AND_MEAN 102 #endif // WIN32_LEAN_AND_MEAN 103 104 #include <Windows.h> 105 #include <io.h> 106 #include <conio.h> 107 108 #define strncasecmp _strnicmp 109 #define strcasecmp _stricmp 110 111 #endif // _WIN32 112 113 #include <status.h> 114 #include <vector.h> 115 #include <read.h> 116 117 #if BC_DEBUG_CODE 118 #include <file.h> 119 #endif // BC_DEBUG_CODE 120 121 /// Default columns. 122 #define BC_HIST_DEF_COLS (80) 123 124 /// Max number of history entries. 125 #define BC_HIST_MAX_LEN (128) 126 127 /// Max length of a line. 128 #define BC_HIST_MAX_LINE (4095) 129 130 /// Max size for cursor position buffer. 131 #define BC_HIST_SEQ_SIZE (64) 132 133 /** 134 * The number of entries in the history. 135 * @param h The history data. 136 */ 137 #define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) 138 139 /** 140 * Read n characters into s and check the error. 141 * @param s The buffer to read into. 142 * @param n The number of bytes to read. 143 * @return True if there was an error, false otherwise. 144 */ 145 #define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1) 146 147 /// Markers for direction when using arrow keys. 148 #define BC_HIST_NEXT (false) 149 #define BC_HIST_PREV (true) 150 151 #if BC_DEBUG_CODE 152 153 // These are just for debugging. 154 155 #define BC_HISTORY_DEBUG_BUF_SIZE (1024) 156 157 #define lndebug(...) \ 158 do { \ 159 if (bc_history_debug_fp.fd == 0) { \ 160 bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \ 161 bc_file_init(&bc_history_debug_fp, \ 162 open("/tmp/lndebug.txt", O_APPEND), \ 163 BC_HISTORY_DEBUG_BUF_SIZE); \ 164 bc_file_printf(&bc_history_debug_fp, \ 165 "[%zu %zu %zu] p: %d, rows: %d, " \ 166 "rpos: %d, max: %zu, oldmax: %d\n", \ 167 l->len, l->pos, l->oldcolpos, plen, rows, rpos, \ 168 l->maxrows, old_rows); \ 169 } \ 170 bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \ 171 bc_file_flush(&bc_history_debug_fp); \ 172 } while (0) 173 #else // BC_DEBUG_CODE 174 #define lndebug(fmt, ...) 175 #endif // BC_DEBUG_CODE 176 177 /// An enum of useful actions. To understand what these mean, check terminal 178 /// emulators for their shortcuts or the VT100 codes. 179 typedef enum BcHistoryAction { 180 181 BC_ACTION_NULL = 0, 182 BC_ACTION_CTRL_A = 1, 183 BC_ACTION_CTRL_B = 2, 184 BC_ACTION_CTRL_C = 3, 185 BC_ACTION_CTRL_D = 4, 186 BC_ACTION_CTRL_E = 5, 187 BC_ACTION_CTRL_F = 6, 188 BC_ACTION_CTRL_H = 8, 189 BC_ACTION_TAB = 9, 190 BC_ACTION_LINE_FEED = 10, 191 BC_ACTION_CTRL_K = 11, 192 BC_ACTION_CTRL_L = 12, 193 BC_ACTION_ENTER = 13, 194 BC_ACTION_CTRL_N = 14, 195 BC_ACTION_CTRL_P = 16, 196 BC_ACTION_CTRL_S = 19, 197 BC_ACTION_CTRL_T = 20, 198 BC_ACTION_CTRL_U = 21, 199 BC_ACTION_CTRL_W = 23, 200 BC_ACTION_CTRL_Z = 26, 201 BC_ACTION_ESC = 27, 202 BC_ACTION_CTRL_BSLASH = 28, 203 BC_ACTION_BACKSPACE = 127 204 205 } BcHistoryAction; 206 207 /** 208 * This represents the state during line editing. We pass this state 209 * to functions implementing specific editing functionalities. 210 */ 211 typedef struct BcHistory { 212 213 /// Edited line buffer. 214 BcVec buf; 215 216 /// The history. 217 BcVec history; 218 219 /// Any material printed without a trailing newline. 220 BcVec extras; 221 222 /// Prompt to display. 223 const char *prompt; 224 225 /// Prompt length. 226 size_t plen; 227 228 /// Prompt column length. 229 size_t pcol; 230 231 /// Current cursor position. 232 size_t pos; 233 234 /// Previous refresh cursor column position. 235 size_t oldcolpos; 236 237 /// Number of columns in terminal. 238 size_t cols; 239 240 /// The history index we are currently editing. 241 size_t idx; 242 243 #ifndef _WIN32 244 /// The original terminal state. 245 struct termios orig_termios; 246 #else // _WIN32 247 DWORD orig_console_mode; 248 #endif // _WIN32 249 250 /// These next two are here because pahole found a 4 byte hole here. 251 252 /// Whether we are in rawmode. 253 bool rawMode; 254 255 /// Whether the terminal is bad. 256 bool badTerm; 257 258 #ifndef _WIN32 259 /// This is to check if stdin has more data. 260 fd_set rdset; 261 262 /// This is to check if stdin has more data. 263 struct timespec ts; 264 265 /// This is to check if stdin has more data. 266 sigset_t sigmask; 267 #endif // _WIN32 268 269 } BcHistory; 270 271 /** 272 * Get a line from stdin using history. This returns a status because I don't 273 * want to throw errors while the terminal is in raw mode. 274 * @param h The history data. 275 * @param vec A vector to put the line into. 276 * @param prompt The prompt to display, if desired. 277 * @return A status indicating an error, if any. Returning a status here 278 * is better because if we throw an error out of history, we 279 * leave the terminal in raw mode or in some other half-baked 280 * state. 281 */ 282 BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt); 283 284 /** 285 * Initialize history data. 286 * @param h The struct to initialize. 287 */ 288 void bc_history_init(BcHistory *h); 289 290 /** 291 * Free history data (and recook the terminal). 292 * @param h The struct to free. 293 */ 294 void bc_history_free(BcHistory *h); 295 296 /** 297 * Frees strings used by history. 298 * @param str The string to free. 299 */ 300 void bc_history_string_free(void *str); 301 302 // A list of terminals that don't work. 303 extern const char *bc_history_bad_terms[]; 304 305 // A tab in history and its length. 306 extern const char bc_history_tab[]; 307 extern const size_t bc_history_tab_len; 308 309 // A ctrl+c string. 310 extern const char bc_history_ctrlc[]; 311 312 // UTF-8 data arrays. 313 extern const uint32_t bc_history_wchars[][2]; 314 extern const size_t bc_history_wchars_len; 315 extern const uint32_t bc_history_combo_chars[]; 316 extern const size_t bc_history_combo_chars_len; 317 318 #if BC_DEBUG_CODE 319 320 // Debug data. 321 extern BcFile bc_history_debug_fp; 322 extern char *bc_history_debug_buf; 323 324 /** 325 * A function to print keycodes for debugging. 326 * @param h The history data. 327 */ 328 void bc_history_printKeyCodes(BcHistory* h); 329 330 #endif // BC_DEBUG_CODE 331 332 #endif // BC_ENABLE_HISTORY 333 334 #endif // BC_HISTORY_H 335