1252884aeSStefan Eßer /* 2252884aeSStefan Eßer * ***************************************************************************** 3252884aeSStefan Eßer * 43aa99676SStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 5252884aeSStefan Eßer * 610328f8bSStefan Eßer * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7252884aeSStefan Eßer * 8252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 9252884aeSStefan Eßer * modification, are permitted provided that the following conditions are met: 10252884aeSStefan Eßer * 11252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 12252884aeSStefan Eßer * list of conditions and the following disclaimer. 13252884aeSStefan Eßer * 14252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 15252884aeSStefan Eßer * this list of conditions and the following disclaimer in the documentation 16252884aeSStefan Eßer * and/or other materials provided with the distribution. 17252884aeSStefan Eßer * 18252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19252884aeSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20252884aeSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21252884aeSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22252884aeSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23252884aeSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24252884aeSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25252884aeSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26252884aeSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27252884aeSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28252884aeSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 29252884aeSStefan Eßer * 30252884aeSStefan Eßer * ***************************************************************************** 31252884aeSStefan Eßer * 32252884aeSStefan Eßer * Adapted from the following: 33252884aeSStefan Eßer * 34252884aeSStefan Eßer * linenoise.c -- guerrilla line editing library against the idea that a 35252884aeSStefan Eßer * line editing lib needs to be 20,000 lines of C code. 36252884aeSStefan Eßer * 37252884aeSStefan Eßer * You can find the original source code at: 38252884aeSStefan Eßer * http://github.com/antirez/linenoise 39252884aeSStefan Eßer * 40252884aeSStefan Eßer * You can find the fork that this code is based on at: 41252884aeSStefan Eßer * https://github.com/rain-1/linenoise-mob 42252884aeSStefan Eßer * 43252884aeSStefan Eßer * ------------------------------------------------------------------------ 44252884aeSStefan Eßer * 45252884aeSStefan Eßer * This code is also under the following license: 46252884aeSStefan Eßer * 47252884aeSStefan Eßer * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> 48252884aeSStefan Eßer * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> 49252884aeSStefan Eßer * 50252884aeSStefan Eßer * Redistribution and use in source and binary forms, with or without 51252884aeSStefan Eßer * modification, are permitted provided that the following conditions are 52252884aeSStefan Eßer * met: 53252884aeSStefan Eßer * 54252884aeSStefan Eßer * * Redistributions of source code must retain the above copyright 55252884aeSStefan Eßer * notice, this list of conditions and the following disclaimer. 56252884aeSStefan Eßer * 57252884aeSStefan Eßer * * Redistributions in binary form must reproduce the above copyright 58252884aeSStefan Eßer * notice, this list of conditions and the following disclaimer in the 59252884aeSStefan Eßer * documentation and/or other materials provided with the distribution. 60252884aeSStefan Eßer * 61252884aeSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 62252884aeSStefan Eßer * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 63252884aeSStefan Eßer * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 64252884aeSStefan Eßer * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 65252884aeSStefan Eßer * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 66252884aeSStefan Eßer * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 67252884aeSStefan Eßer * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 68252884aeSStefan Eßer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 69252884aeSStefan Eßer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 70252884aeSStefan Eßer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 71252884aeSStefan Eßer * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 72252884aeSStefan Eßer * 73252884aeSStefan Eßer * ***************************************************************************** 74252884aeSStefan Eßer * 75252884aeSStefan Eßer * Definitions for line history. 76252884aeSStefan Eßer * 77252884aeSStefan Eßer */ 78252884aeSStefan Eßer 79252884aeSStefan Eßer #ifndef BC_HISTORY_H 80252884aeSStefan Eßer #define BC_HISTORY_H 81252884aeSStefan Eßer 82252884aeSStefan Eßer #ifndef BC_ENABLE_HISTORY 83252884aeSStefan Eßer #define BC_ENABLE_HISTORY (1) 84252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 85252884aeSStefan Eßer 86252884aeSStefan Eßer #if BC_ENABLE_HISTORY 87252884aeSStefan Eßer 88252884aeSStefan Eßer #ifdef _WIN32 89252884aeSStefan Eßer #error History is not supported on Windows. 90252884aeSStefan Eßer #endif // _WIN32 91252884aeSStefan Eßer 92252884aeSStefan Eßer #include <stdbool.h> 93252884aeSStefan Eßer #include <stddef.h> 94252884aeSStefan Eßer 95252884aeSStefan Eßer #include <signal.h> 96252884aeSStefan Eßer 97252884aeSStefan Eßer #include <termios.h> 98252884aeSStefan Eßer #include <time.h> 99252884aeSStefan Eßer #include <unistd.h> 100252884aeSStefan Eßer #include <sys/select.h> 101252884aeSStefan Eßer 102252884aeSStefan Eßer #include <status.h> 103252884aeSStefan Eßer #include <vector.h> 104252884aeSStefan Eßer #include <read.h> 105252884aeSStefan Eßer 106252884aeSStefan Eßer #if BC_DEBUG_CODE 107252884aeSStefan Eßer #include <file.h> 108252884aeSStefan Eßer #endif // BC_DEBUG_CODE 109252884aeSStefan Eßer 110252884aeSStefan Eßer #define BC_HIST_DEF_COLS (80) 111252884aeSStefan Eßer #define BC_HIST_MAX_LEN (128) 112252884aeSStefan Eßer #define BC_HIST_MAX_LINE (4095) 113252884aeSStefan Eßer #define BC_HIST_SEQ_SIZE (64) 114252884aeSStefan Eßer 115252884aeSStefan Eßer #define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) 116252884aeSStefan Eßer #define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1) 117252884aeSStefan Eßer 118252884aeSStefan Eßer #define BC_HIST_NEXT (false) 119252884aeSStefan Eßer #define BC_HIST_PREV (true) 120252884aeSStefan Eßer 121252884aeSStefan Eßer #if BC_DEBUG_CODE 122252884aeSStefan Eßer 123252884aeSStefan Eßer #define BC_HISTORY_DEBUG_BUF_SIZE (1024) 124252884aeSStefan Eßer 125252884aeSStefan Eßer #define lndebug(...) \ 126252884aeSStefan Eßer do { \ 127252884aeSStefan Eßer if (bc_history_debug_fp.fd == 0) { \ 128252884aeSStefan Eßer bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \ 129252884aeSStefan Eßer bc_file_init(&bc_history_debug_fp, \ 130252884aeSStefan Eßer open("/tmp/lndebug.txt", O_APPEND), \ 131252884aeSStefan Eßer BC_HISTORY_DEBUG_BUF_SIZE); \ 132252884aeSStefan Eßer bc_file_printf(&bc_history_debug_fp, \ 133252884aeSStefan Eßer "[%zu %zu %zu] p: %d, rows: %d, " \ 134252884aeSStefan Eßer "rpos: %d, max: %zu, oldmax: %d\n", \ 135252884aeSStefan Eßer l->len, l->pos, l->oldcolpos, plen, rows, rpos, \ 136252884aeSStefan Eßer l->maxrows, old_rows); \ 137252884aeSStefan Eßer } \ 138252884aeSStefan Eßer bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \ 139252884aeSStefan Eßer bc_file_flush(&bc_history_debug_fp); \ 140252884aeSStefan Eßer } while (0) 141252884aeSStefan Eßer #else // BC_DEBUG_CODE 142252884aeSStefan Eßer #define lndebug(fmt, ...) 143252884aeSStefan Eßer #endif // BC_DEBUG_CODE 144252884aeSStefan Eßer 145252884aeSStefan Eßer #if !BC_ENABLE_PROMPT 146252884aeSStefan Eßer #define bc_history_line(h, vec, prompt) bc_history_line(h, vec) 147252884aeSStefan Eßer #define bc_history_raw(h, prompt) bc_history_raw(h) 148252884aeSStefan Eßer #define bc_history_edit(h, prompt) bc_history_edit(h) 149252884aeSStefan Eßer #endif // BC_ENABLE_PROMPT 150252884aeSStefan Eßer 151252884aeSStefan Eßer typedef enum BcHistoryAction { 152252884aeSStefan Eßer 153252884aeSStefan Eßer BC_ACTION_NULL = 0, 154252884aeSStefan Eßer BC_ACTION_CTRL_A = 1, 155252884aeSStefan Eßer BC_ACTION_CTRL_B = 2, 156252884aeSStefan Eßer BC_ACTION_CTRL_C = 3, 157252884aeSStefan Eßer BC_ACTION_CTRL_D = 4, 158252884aeSStefan Eßer BC_ACTION_CTRL_E = 5, 159252884aeSStefan Eßer BC_ACTION_CTRL_F = 6, 160252884aeSStefan Eßer BC_ACTION_CTRL_H = 8, 161252884aeSStefan Eßer BC_ACTION_TAB = 9, 162252884aeSStefan Eßer BC_ACTION_LINE_FEED = 10, 163252884aeSStefan Eßer BC_ACTION_CTRL_K = 11, 164252884aeSStefan Eßer BC_ACTION_CTRL_L = 12, 165252884aeSStefan Eßer BC_ACTION_ENTER = 13, 166252884aeSStefan Eßer BC_ACTION_CTRL_N = 14, 167252884aeSStefan Eßer BC_ACTION_CTRL_P = 16, 168*8c39e252SStefan Eßer BC_ACTION_CTRL_S = 19, 169252884aeSStefan Eßer BC_ACTION_CTRL_T = 20, 170252884aeSStefan Eßer BC_ACTION_CTRL_U = 21, 171252884aeSStefan Eßer BC_ACTION_CTRL_W = 23, 172252884aeSStefan Eßer BC_ACTION_CTRL_Z = 26, 173252884aeSStefan Eßer BC_ACTION_ESC = 27, 174252884aeSStefan Eßer BC_ACTION_BACKSPACE = 127 175252884aeSStefan Eßer 176252884aeSStefan Eßer } BcHistoryAction; 177252884aeSStefan Eßer 178252884aeSStefan Eßer /** 179252884aeSStefan Eßer * This represents the state during line editing. We pass this state 180252884aeSStefan Eßer * to functions implementing specific editing functionalities. 181252884aeSStefan Eßer */ 182252884aeSStefan Eßer typedef struct BcHistory { 183252884aeSStefan Eßer 184252884aeSStefan Eßer /// Edited line buffer. 185252884aeSStefan Eßer BcVec buf; 186252884aeSStefan Eßer 187252884aeSStefan Eßer /// The history. 188252884aeSStefan Eßer BcVec history; 189252884aeSStefan Eßer 1907e5c51e5SStefan Eßer /// Any material printed without a trailing newline. 1917e5c51e5SStefan Eßer BcVec extras; 1927e5c51e5SStefan Eßer 193252884aeSStefan Eßer #if BC_ENABLE_PROMPT 194252884aeSStefan Eßer /// Prompt to display. 195252884aeSStefan Eßer const char *prompt; 196252884aeSStefan Eßer 197252884aeSStefan Eßer /// Prompt length. 198252884aeSStefan Eßer size_t plen; 199252884aeSStefan Eßer #endif // BC_ENABLE_PROMPT 200252884aeSStefan Eßer 201252884aeSStefan Eßer /// Prompt column length. 202252884aeSStefan Eßer size_t pcol; 203252884aeSStefan Eßer 204252884aeSStefan Eßer /// Current cursor position. 205252884aeSStefan Eßer size_t pos; 206252884aeSStefan Eßer 207252884aeSStefan Eßer /// Previous refresh cursor column position. 208252884aeSStefan Eßer size_t oldcolpos; 209252884aeSStefan Eßer 210252884aeSStefan Eßer /// Number of columns in terminal. 211252884aeSStefan Eßer size_t cols; 212252884aeSStefan Eßer 213252884aeSStefan Eßer /// The history index we are currently editing. 214252884aeSStefan Eßer size_t idx; 215252884aeSStefan Eßer 216252884aeSStefan Eßer /// The original terminal state. 217252884aeSStefan Eßer struct termios orig_termios; 218252884aeSStefan Eßer 219252884aeSStefan Eßer /// These next three are here because pahole found a 4 byte hole here. 220252884aeSStefan Eßer 221252884aeSStefan Eßer /// This is to signal that there is more, so we don't process yet. 222252884aeSStefan Eßer bool stdin_has_data; 223252884aeSStefan Eßer 224252884aeSStefan Eßer /// Whether we are in rawmode. 225252884aeSStefan Eßer bool rawMode; 226252884aeSStefan Eßer 227252884aeSStefan Eßer /// Whether the terminal is bad. 228252884aeSStefan Eßer bool badTerm; 229252884aeSStefan Eßer 230252884aeSStefan Eßer /// This is to check if stdin has more data. 231252884aeSStefan Eßer fd_set rdset; 232252884aeSStefan Eßer 233252884aeSStefan Eßer /// This is to check if stdin has more data. 234252884aeSStefan Eßer struct timespec ts; 235252884aeSStefan Eßer 236252884aeSStefan Eßer /// This is to check if stdin has more data. 237252884aeSStefan Eßer sigset_t sigmask; 238252884aeSStefan Eßer 239252884aeSStefan Eßer } BcHistory; 240252884aeSStefan Eßer 241252884aeSStefan Eßer BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt); 242252884aeSStefan Eßer 243252884aeSStefan Eßer void bc_history_init(BcHistory *h); 244252884aeSStefan Eßer void bc_history_free(BcHistory *h); 245252884aeSStefan Eßer 246252884aeSStefan Eßer extern const char *bc_history_bad_terms[]; 247252884aeSStefan Eßer extern const char bc_history_tab[]; 248252884aeSStefan Eßer extern const size_t bc_history_tab_len; 249252884aeSStefan Eßer extern const char bc_history_ctrlc[]; 250252884aeSStefan Eßer extern const uint32_t bc_history_wchars[][2]; 251252884aeSStefan Eßer extern const size_t bc_history_wchars_len; 252252884aeSStefan Eßer extern const uint32_t bc_history_combo_chars[]; 253252884aeSStefan Eßer extern const size_t bc_history_combo_chars_len; 254252884aeSStefan Eßer #if BC_DEBUG_CODE 255252884aeSStefan Eßer extern BcFile bc_history_debug_fp; 256252884aeSStefan Eßer extern char *bc_history_debug_buf; 257252884aeSStefan Eßer void bc_history_printKeyCodes(BcHistory* l); 258252884aeSStefan Eßer #endif // BC_DEBUG_CODE 259252884aeSStefan Eßer 260252884aeSStefan Eßer #endif // BC_ENABLE_HISTORY 261252884aeSStefan Eßer 262252884aeSStefan Eßer #endif // BC_HISTORY_H 263