1 /* 2 * ***************************************************************************** 3 * 4 * Copyright (c) 2018-2019 Gavin D. Howard and contributors. 5 * 6 * All rights reserved. 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 * All rights reserved. 51 * 52 * Redistribution and use in source and binary forms, with or without 53 * modification, are permitted provided that the following conditions are 54 * met: 55 * 56 * * Redistributions of source code must retain the above copyright 57 * notice, this list of conditions and the following disclaimer. 58 * 59 * * Redistributions in binary form must reproduce the above copyright 60 * notice, this list of conditions and the following disclaimer in the 61 * documentation and/or other materials provided with the distribution. 62 * 63 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 64 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 65 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 66 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 67 * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 68 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 69 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 70 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 71 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 72 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 73 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 74 * 75 * ***************************************************************************** 76 * 77 * Definitions for line history. 78 * 79 */ 80 81 #ifndef BC_HISTORY_H 82 #define BC_HISTORY_H 83 84 #ifndef BC_ENABLE_HISTORY 85 #define BC_ENABLE_HISTORY (1) 86 #endif // BC_ENABLE_HISTORY 87 88 #if BC_ENABLE_HISTORY 89 90 #ifdef _WIN32 91 #error History is not supported on Windows. 92 #endif 93 94 #include <stdbool.h> 95 #include <stddef.h> 96 #include <stdio.h> 97 98 #include <signal.h> 99 100 #include <termios.h> 101 #include <time.h> 102 #include <unistd.h> 103 #include <sys/select.h> 104 105 #include <status.h> 106 #include <vector.h> 107 #include <read.h> 108 109 #define BC_HIST_DEF_COLS (80) 110 #define BC_HIST_MAX_LEN (128) 111 #define BC_HIST_MAX_LINE (4095) 112 #define BC_HIST_SEQ_SIZE (64) 113 114 #define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) 115 #define BC_HIST_WRITE(s, n) (write(STDERR_FILENO, (s), (n)) != (ssize_t) (n)) 116 #define BC_HIST_READ(s, n) (read(STDIN_FILENO, (s), (n)) == -1) 117 118 #define BC_HIST_NEXT (false) 119 #define BC_HIST_PREV (true) 120 121 #if BC_DEBUG_CODE 122 #define lndebug(...) \ 123 do { \ 124 if (bc_history_debug_fp == NULL) { \ 125 bc_history_debug_fp = fopen("/tmp/lndebug.txt","a"); \ 126 fprintf(bc_history_debug_fp, \ 127 "[%zu %zu %zu] p: %d, rows: %d, " \ 128 "rpos: %d, max: %zu, oldmax: %d\n", \ 129 l->len, l->pos, l->oldcolpos, plen, rows, rpos, \ 130 l->maxrows, old_rows); \ 131 } \ 132 fprintf(bc_history_debug_fp, ", " __VA_ARGS__); \ 133 fflush(bc_history_debug_fp); \ 134 } while (0) 135 #else // BC_DEBUG_CODE 136 #define lndebug(fmt, ...) 137 #endif // BC_DEBUG_CODE 138 139 #if !BC_ENABLE_PROMPT 140 #define bc_history_line(h, vec, prompt) bc_history_line(h, vec) 141 #define bc_history_raw(h, prompt) bc_history_raw(h) 142 #define bc_history_edit(h, prompt) bc_history_edit(h) 143 #endif // BC_ENABLE_PROMPT 144 145 typedef enum BcHistoryAction { 146 147 BC_ACTION_NULL = 0, 148 BC_ACTION_CTRL_A = 1, 149 BC_ACTION_CTRL_B = 2, 150 BC_ACTION_CTRL_C = 3, 151 BC_ACTION_CTRL_D = 4, 152 BC_ACTION_CTRL_E = 5, 153 BC_ACTION_CTRL_F = 6, 154 BC_ACTION_CTRL_H = 8, 155 BC_ACTION_TAB = 9, 156 BC_ACTION_LINE_FEED = 10, 157 BC_ACTION_CTRL_K = 11, 158 BC_ACTION_CTRL_L = 12, 159 BC_ACTION_ENTER = 13, 160 BC_ACTION_CTRL_N = 14, 161 BC_ACTION_CTRL_P = 16, 162 BC_ACTION_CTRL_T = 20, 163 BC_ACTION_CTRL_U = 21, 164 BC_ACTION_CTRL_W = 23, 165 BC_ACTION_CTRL_Z = 26, 166 BC_ACTION_ESC = 27, 167 BC_ACTION_BACKSPACE = 127 168 169 } BcHistoryAction; 170 171 /** 172 * This represents the state during line editing. We pass this state 173 * to functions implementing specific editing functionalities. 174 */ 175 typedef struct BcHistory { 176 177 /// Edited line buffer. 178 BcVec buf; 179 180 /// The history. 181 BcVec history; 182 183 /// A temporary buffer for refresh. Using this 184 /// prevents an allocation on every refresh. 185 BcVec tmp; 186 187 #if BC_ENABLE_PROMPT 188 /// Prompt to display. 189 const char *prompt; 190 191 /// Prompt length. 192 size_t plen; 193 #endif // BC_ENABLE_PROMPT 194 195 /// Prompt column length. 196 size_t pcol; 197 198 /// Current cursor position. 199 size_t pos; 200 201 /// Previous refresh cursor column position. 202 size_t oldcolpos; 203 204 /// Number of columns in terminal. 205 size_t cols; 206 207 /// The history index we are currently editing. 208 size_t idx; 209 210 /// The original terminal state. 211 struct termios orig_termios; 212 213 /// This is to check if stdin has more data. 214 fd_set rdset; 215 216 /// This is to check if stdin has more data. 217 struct timespec ts; 218 219 /// This is to check if stdin has more data. 220 sigset_t sigmask; 221 222 /// This is to signal that there is more, so we don't process yet. 223 bool stdin_has_data; 224 225 /// Whether we are in rawmode. 226 bool rawMode; 227 228 /// Whether the terminal is bad. 229 bool badTerm; 230 231 } BcHistory; 232 233 BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt); 234 void bc_history_add(BcHistory *h, char *line); 235 236 void bc_history_init(BcHistory *h); 237 void bc_history_free(BcHistory *h); 238 239 extern const char *bc_history_bad_terms[]; 240 extern const char bc_history_tab[]; 241 extern const size_t bc_history_tab_len; 242 extern const char bc_history_ctrlc[]; 243 extern const uint32_t bc_history_wchars[][2]; 244 extern const size_t bc_history_wchars_len; 245 extern const uint32_t bc_history_combo_chars[]; 246 extern const size_t bc_history_combo_chars_len; 247 #if BC_DEBUG_CODE 248 extern FILE *bc_history_debug_fp; 249 BcStatus bc_history_printKeyCodes(BcHistory* l); 250 #endif // BC_DEBUG_CODE 251 252 #endif // BC_ENABLE_HISTORY 253 254 #endif // BC_HISTORY_H 255