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 #ifndef BC_ENABLE_EDITLINE 87 #define BC_ENABLE_EDITLINE (0) 88 #endif // BC_ENABLE_EDITLINE 89 90 #ifndef BC_ENABLE_READLINE 91 #define BC_ENABLE_READLINE (0) 92 #endif // BC_ENABLE_READLINE 93 94 #if BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 95 #error Must enable only one of editline or readline, not both. 96 #endif // BC_ENABLE_EDITLINE && BC_ENABLE_READLINE 97 98 #if BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 99 #define BC_ENABLE_LINE_LIB (1) 100 #else // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 101 #define BC_ENABLE_LINE_LIB (0) 102 #endif // BC_ENABLE_EDITLINE || BC_ENABLE_READLINE 103 104 #if BC_ENABLE_LINE_LIB 105 106 #include <stdbool.h> 107 #include <setjmp.h> 108 #include <signal.h> 109 110 #include <status.h> 111 #include <vector.h> 112 113 extern sigjmp_buf bc_history_jmpbuf; 114 extern volatile sig_atomic_t bc_history_inlinelib; 115 116 #endif // BC_ENABLE_LINE_LIB 117 118 #if BC_ENABLE_EDITLINE 119 120 #include <stdio.h> 121 #include <histedit.h> 122 123 /** 124 * The history struct for editline. 125 */ 126 typedef struct BcHistory 127 { 128 /// A place to store the current line. 129 EditLine* el; 130 131 /// The history. 132 History* hist; 133 134 /// Whether the terminal is bad. This is more or less not used. 135 bool badTerm; 136 137 } BcHistory; 138 139 // The path to the editrc and its length. 140 extern const char bc_history_editrc[]; 141 extern const size_t bc_history_editrc_len; 142 143 #else // BC_ENABLE_EDITLINE 144 145 #if BC_ENABLE_READLINE 146 147 #include <stdio.h> 148 #include <readline/readline.h> 149 #include <readline/history.h> 150 151 /** 152 * The history struct for readline. 153 */ 154 typedef struct BcHistory 155 { 156 /// A place to store the current line. 157 char* line; 158 159 /// Whether the terminal is bad. This is more or less not used. 160 bool badTerm; 161 162 } BcHistory; 163 164 #else // BC_ENABLE_READLINE 165 166 #if BC_ENABLE_HISTORY 167 168 #include <stddef.h> 169 170 #include <signal.h> 171 172 #ifndef _WIN32 173 #include <termios.h> 174 #include <time.h> 175 #include <unistd.h> 176 #include <sys/select.h> 177 #else // _WIN32 178 179 #ifndef WIN32_LEAN_AND_MEAN 180 #define WIN32_LEAN_AND_MEAN 181 #endif // WIN32_LEAN_AND_MEAN 182 183 #include <Windows.h> 184 #include <io.h> 185 #include <conio.h> 186 187 #define strncasecmp _strnicmp 188 #define strcasecmp _stricmp 189 190 #endif // _WIN32 191 192 #include <status.h> 193 #include <vector.h> 194 #include <read.h> 195 196 #if BC_DEBUG_CODE 197 #include <file.h> 198 #endif // BC_DEBUG_CODE 199 200 /// Default columns. 201 #define BC_HIST_DEF_COLS (80) 202 203 /// Max number of history entries. 204 #define BC_HIST_MAX_LEN (128) 205 206 /// Max length of a line. 207 #define BC_HIST_MAX_LINE (4095) 208 209 /// Max size for cursor position buffer. 210 #define BC_HIST_SEQ_SIZE (64) 211 212 /** 213 * The number of entries in the history. 214 * @param h The history data. 215 */ 216 #define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) 217 218 /** 219 * Read n characters into s and check the error. 220 * @param s The buffer to read into. 221 * @param n The number of bytes to read. 222 * @return True if there was an error, false otherwise. 223 */ 224 #define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1) 225 226 /// Markers for direction when using arrow keys. 227 #define BC_HIST_NEXT (false) 228 #define BC_HIST_PREV (true) 229 230 #if BC_DEBUG_CODE 231 232 // These are just for debugging. 233 234 #define BC_HISTORY_DEBUG_BUF_SIZE (1024) 235 236 // clang-format off 237 #define lndebug(...) \ 238 do \ 239 { \ 240 if (bc_history_debug_fp.fd == 0) \ 241 { \ 242 bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \ 243 bc_file_init(&bc_history_debug_fp, \ 244 open("/tmp/lndebug.txt", O_APPEND), \ 245 BC_HISTORY_DEBUG_BUF_SIZE); \ 246 bc_file_printf(&bc_history_debug_fp, \ 247 "[%zu %zu %zu] p: %d, rows: %d, " \ 248 "rpos: %d, max: %zu, oldmax: %d\n", \ 249 l->len, l->pos, l->oldcolpos, plen, rows, rpos, \ 250 l->maxrows, old_rows); \ 251 } \ 252 bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \ 253 bc_file_flush(&bc_history_debug_fp); \ 254 } \ 255 while (0) 256 #else // BC_DEBUG_CODE 257 #define lndebug(fmt, ...) 258 #endif // BC_DEBUG_CODE 259 // clang-format on 260 261 /// An enum of useful actions. To understand what these mean, check terminal 262 /// emulators for their shortcuts or the VT100 codes. 263 typedef enum BcHistoryAction 264 { 265 BC_ACTION_NULL = 0, 266 BC_ACTION_CTRL_A = 1, 267 BC_ACTION_CTRL_B = 2, 268 BC_ACTION_CTRL_C = 3, 269 BC_ACTION_CTRL_D = 4, 270 BC_ACTION_CTRL_E = 5, 271 BC_ACTION_CTRL_F = 6, 272 BC_ACTION_CTRL_H = 8, 273 BC_ACTION_TAB = 9, 274 BC_ACTION_LINE_FEED = 10, 275 BC_ACTION_CTRL_K = 11, 276 BC_ACTION_CTRL_L = 12, 277 BC_ACTION_ENTER = 13, 278 BC_ACTION_CTRL_N = 14, 279 BC_ACTION_CTRL_P = 16, 280 BC_ACTION_CTRL_S = 19, 281 BC_ACTION_CTRL_T = 20, 282 BC_ACTION_CTRL_U = 21, 283 BC_ACTION_CTRL_W = 23, 284 BC_ACTION_CTRL_Z = 26, 285 BC_ACTION_ESC = 27, 286 BC_ACTION_CTRL_BSLASH = 28, 287 BC_ACTION_BACKSPACE = 127 288 289 } BcHistoryAction; 290 291 /** 292 * This represents the state during line editing. We pass this state 293 * to functions implementing specific editing functionalities. 294 */ 295 typedef struct BcHistory 296 { 297 /// Edited line buffer. 298 BcVec buf; 299 300 /// The history. 301 BcVec history; 302 303 /// Any material printed without a trailing newline. 304 BcVec extras; 305 306 /// Prompt to display. 307 const char* prompt; 308 309 /// Prompt length. 310 size_t plen; 311 312 /// Prompt column length. 313 size_t pcol; 314 315 /// Current cursor position. 316 size_t pos; 317 318 /// Previous refresh cursor column position. 319 size_t oldcolpos; 320 321 /// Number of columns in terminal. 322 size_t cols; 323 324 /// The history index we are currently editing. 325 size_t idx; 326 327 #ifndef _WIN32 328 /// The original terminal state. 329 struct termios orig_termios; 330 #else // _WIN32 331 /// The original input console mode. 332 DWORD orig_in; 333 334 /// The original output console mode. 335 DWORD orig_out; 336 #endif // _WIN32 337 338 /// These next two are here because pahole found a 4 byte hole here. 339 340 /// Whether we are in rawmode. 341 bool rawMode; 342 343 /// Whether the terminal is bad. 344 bool badTerm; 345 346 #ifndef _WIN32 347 /// This is to check if stdin has more data. 348 fd_set rdset; 349 350 /// This is to check if stdin has more data. 351 struct timespec ts; 352 353 /// This is to check if stdin has more data. 354 sigset_t sigmask; 355 #endif // _WIN32 356 357 } BcHistory; 358 359 /** 360 * Frees strings used by history. 361 * @param str The string to free. 362 */ 363 void 364 bc_history_string_free(void* str); 365 366 // A list of terminals that don't work. 367 extern const char* bc_history_bad_terms[]; 368 369 // A tab in history and its length. 370 extern const char bc_history_tab[]; 371 extern const size_t bc_history_tab_len; 372 373 // A ctrl+c string. 374 extern const char bc_history_ctrlc[]; 375 376 // UTF-8 data arrays. 377 extern const uint32_t bc_history_wchars[][2]; 378 extern const size_t bc_history_wchars_len; 379 extern const uint32_t bc_history_combo_chars[]; 380 extern const size_t bc_history_combo_chars_len; 381 382 #if BC_DEBUG_CODE 383 384 // Debug data. 385 extern BcFile bc_history_debug_fp; 386 extern char* bc_history_debug_buf; 387 388 /** 389 * A function to print keycodes for debugging. 390 * @param h The history data. 391 */ 392 void 393 bc_history_printKeyCodes(BcHistory* h); 394 395 #endif // BC_DEBUG_CODE 396 397 #endif // BC_ENABLE_HISTORY 398 399 #endif // BC_ENABLE_READLINE 400 401 #endif // BC_ENABLE_EDITLINE 402 403 #if BC_ENABLE_HISTORY 404 405 /** 406 * Get a line from stdin using history. This returns a status because I don't 407 * want to throw errors while the terminal is in raw mode. 408 * @param h The history data. 409 * @param vec A vector to put the line into. 410 * @param prompt The prompt to display, if desired. 411 * @return A status indicating an error, if any. Returning a status here 412 * is better because if we throw an error out of history, we 413 * leave the terminal in raw mode or in some other half-baked 414 * state. 415 */ 416 BcStatus 417 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt); 418 419 /** 420 * Initialize history data. 421 * @param h The struct to initialize. 422 */ 423 void 424 bc_history_init(BcHistory* h); 425 426 /** 427 * Free history data (and recook the terminal). 428 * @param h The struct to free. 429 */ 430 void 431 bc_history_free(BcHistory* h); 432 433 #endif // BC_ENABLE_HISTORY 434 435 #endif // BC_HISTORY_H 436