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#ifdef _WIN32 89#error History is not supported on Windows. 90#endif // _WIN32 91 92#include <stdbool.h> 93#include <stddef.h> 94 95#include <signal.h> 96 97#include <termios.h> 98#include <time.h> 99#include <unistd.h> 100#include <sys/select.h> 101 102#include <status.h> 103#include <vector.h> 104#include <read.h> 105 106#if BC_DEBUG_CODE 107#include <file.h> 108#endif // BC_DEBUG_CODE 109 110#define BC_HIST_DEF_COLS (80) 111#define BC_HIST_MAX_LEN (128) 112#define BC_HIST_MAX_LINE (4095) 113#define BC_HIST_SEQ_SIZE (64) 114 115#define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) 116#define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1) 117 118#define BC_HIST_NEXT (false) 119#define BC_HIST_PREV (true) 120 121#if BC_DEBUG_CODE 122 123#define BC_HISTORY_DEBUG_BUF_SIZE (1024) 124 125#define lndebug(...) \ 126 do { \ 127 if (bc_history_debug_fp.fd == 0) { \ 128 bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \ 129 bc_file_init(&bc_history_debug_fp, \ 130 open("/tmp/lndebug.txt", O_APPEND), \ 131 BC_HISTORY_DEBUG_BUF_SIZE); \ 132 bc_file_printf(&bc_history_debug_fp, \ 133 "[%zu %zu %zu] p: %d, rows: %d, " \ 134 "rpos: %d, max: %zu, oldmax: %d\n", \ 135 l->len, l->pos, l->oldcolpos, plen, rows, rpos, \ 136 l->maxrows, old_rows); \ 137 } \ 138 bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \ 139 bc_file_flush(&bc_history_debug_fp); \ 140 } while (0) 141#else // BC_DEBUG_CODE 142#define lndebug(fmt, ...) 143#endif // BC_DEBUG_CODE 144 145#if !BC_ENABLE_PROMPT 146#define bc_history_line(h, vec, prompt) bc_history_line(h, vec) 147#define bc_history_raw(h, prompt) bc_history_raw(h) 148#define bc_history_edit(h, prompt) bc_history_edit(h) 149#endif // BC_ENABLE_PROMPT 150 151typedef enum BcHistoryAction { 152 153 BC_ACTION_NULL = 0, 154 BC_ACTION_CTRL_A = 1, 155 BC_ACTION_CTRL_B = 2, 156 BC_ACTION_CTRL_C = 3, 157 BC_ACTION_CTRL_D = 4, 158 BC_ACTION_CTRL_E = 5, 159 BC_ACTION_CTRL_F = 6, 160 BC_ACTION_CTRL_H = 8, 161 BC_ACTION_TAB = 9, 162 BC_ACTION_LINE_FEED = 10, 163 BC_ACTION_CTRL_K = 11, 164 BC_ACTION_CTRL_L = 12, 165 BC_ACTION_ENTER = 13, 166 BC_ACTION_CTRL_N = 14, 167 BC_ACTION_CTRL_P = 16, 168 BC_ACTION_CTRL_T = 20, 169 BC_ACTION_CTRL_U = 21, 170 BC_ACTION_CTRL_W = 23, 171 BC_ACTION_CTRL_Z = 26, 172 BC_ACTION_ESC = 27, 173 BC_ACTION_BACKSPACE = 127 174 175} BcHistoryAction; 176 177/** 178 * This represents the state during line editing. We pass this state 179 * to functions implementing specific editing functionalities. 180 */ 181typedef struct BcHistory { 182 183 /// Edited line buffer. 184 BcVec buf; 185 186 /// The history. 187 BcVec history; 188 189 /// Any material printed without a trailing newline. 190 BcVec extras; 191 192#if BC_ENABLE_PROMPT 193 /// Prompt to display. 194 const char *prompt; 195 196 /// Prompt length. 197 size_t plen; 198#endif // BC_ENABLE_PROMPT 199 200 /// Prompt column length. 201 size_t pcol; 202 203 /// Current cursor position. 204 size_t pos; 205 206 /// Previous refresh cursor column position. 207 size_t oldcolpos; 208 209 /// Number of columns in terminal. 210 size_t cols; 211 212 /// The history index we are currently editing. 213 size_t idx; 214 215 /// The original terminal state. 216 struct termios orig_termios; 217 218 /// These next three are here because pahole found a 4 byte hole here. 219 220 /// This is to signal that there is more, so we don't process yet. 221 bool stdin_has_data; 222 223 /// Whether we are in rawmode. 224 bool rawMode; 225 226 /// Whether the terminal is bad. 227 bool badTerm; 228 229 /// This is to check if stdin has more data. 230 fd_set rdset; 231 232 /// This is to check if stdin has more data. 233 struct timespec ts; 234 235 /// This is to check if stdin has more data. 236 sigset_t sigmask; 237 238} BcHistory; 239 240BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt); 241 242void bc_history_init(BcHistory *h); 243void bc_history_free(BcHistory *h); 244 245extern const char *bc_history_bad_terms[]; 246extern const char bc_history_tab[]; 247extern const size_t bc_history_tab_len; 248extern const char bc_history_ctrlc[]; 249extern const uint32_t bc_history_wchars[][2]; 250extern const size_t bc_history_wchars_len; 251extern const uint32_t bc_history_combo_chars[]; 252extern const size_t bc_history_combo_chars_len; 253#if BC_DEBUG_CODE 254extern BcFile bc_history_debug_fp; 255extern char *bc_history_debug_buf; 256void bc_history_printKeyCodes(BcHistory* l); 257#endif // BC_DEBUG_CODE 258 259#endif // BC_ENABLE_HISTORY 260 261#endif // BC_HISTORY_H 262