| /* |
| * ***************************************************************************** |
| * |
| * SPDX-License-Identifier: BSD-2-Clause |
| * |
| * Copyright (c) 2018-2021 Gavin D. Howard and contributors. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are met: |
| * |
| * * Redistributions of source code must retain the above copyright notice, this |
| * list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| * |
| * ***************************************************************************** |
| * |
| * Adapted from the following: |
| * |
| * linenoise.c -- guerrilla line editing library against the idea that a |
| * line editing lib needs to be 20,000 lines of C code. |
| * |
| * You can find the original source code at: |
| * http://github.com/antirez/linenoise |
| * |
| * You can find the fork that this code is based on at: |
| * https://github.com/rain-1/linenoise-mob |
| * |
| * ------------------------------------------------------------------------ |
| * |
| * This code is also under the following license: |
| * |
| * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com> |
| * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com> |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * |
| * * Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| * |
| * ***************************************************************************** |
| * |
| * Definitions for line history. |
| * |
| */ |
| |
| #ifndef BC_HISTORY_H |
| #define BC_HISTORY_H |
| |
| #ifndef BC_ENABLE_HISTORY |
| #define BC_ENABLE_HISTORY (1) |
| #endif // BC_ENABLE_HISTORY |
| |
| #if BC_ENABLE_HISTORY |
| |
| #include <stdbool.h> |
| #include <stddef.h> |
| |
| #include <signal.h> |
| |
| #ifndef _WIN32 |
| #include <termios.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include <sys/select.h> |
| #else // _WIN32 |
| |
| #ifndef WIN32_LEAN_AND_MEAN |
| #define WIN32_LEAN_AND_MEAN |
| #endif // WIN32_LEAN_AND_MEAN |
| |
| #include <Windows.h> |
| #include <io.h> |
| #include <conio.h> |
| |
| #define strncasecmp _strnicmp |
| #define strcasecmp _stricmp |
| |
| #endif // _WIN32 |
| |
| #include <status.h> |
| #include <vector.h> |
| #include <read.h> |
| |
| #if BC_DEBUG_CODE |
| #include <file.h> |
| #endif // BC_DEBUG_CODE |
| |
| /// Default columns. |
| #define BC_HIST_DEF_COLS (80) |
| |
| /// Max number of history entries. |
| #define BC_HIST_MAX_LEN (128) |
| |
| /// Max length of a line. |
| #define BC_HIST_MAX_LINE (4095) |
| |
| /// Max size for cursor position buffer. |
| #define BC_HIST_SEQ_SIZE (64) |
| |
| /** |
| * The number of entries in the history. |
| * @param h The history data. |
| */ |
| #define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) |
| |
| /** |
| * Read n characters into s and check the error. |
| * @param s The buffer to read into. |
| * @param n The number of bytes to read. |
| * @return True if there was an error, false otherwise. |
| */ |
| #define BC_HIST_READ(s, n) (bc_history_read((s), (n)) == -1) |
| |
| /// Markers for direction when using arrow keys. |
| #define BC_HIST_NEXT (false) |
| #define BC_HIST_PREV (true) |
| |
| #if BC_DEBUG_CODE |
| |
| // These are just for debugging. |
| |
| #define BC_HISTORY_DEBUG_BUF_SIZE (1024) |
| |
| #define lndebug(...) \ |
| do { \ |
| if (bc_history_debug_fp.fd == 0) { \ |
| bc_history_debug_buf = bc_vm_malloc(BC_HISTORY_DEBUG_BUF_SIZE); \ |
| bc_file_init(&bc_history_debug_fp, \ |
| open("/tmp/lndebug.txt", O_APPEND), \ |
| BC_HISTORY_DEBUG_BUF_SIZE); \ |
| bc_file_printf(&bc_history_debug_fp, \ |
| "[%zu %zu %zu] p: %d, rows: %d, " \ |
| "rpos: %d, max: %zu, oldmax: %d\n", \ |
| l->len, l->pos, l->oldcolpos, plen, rows, rpos, \ |
| l->maxrows, old_rows); \ |
| } \ |
| bc_file_printf(&bc_history_debug_fp, ", " __VA_ARGS__); \ |
| bc_file_flush(&bc_history_debug_fp); \ |
| } while (0) |
| #else // BC_DEBUG_CODE |
| #define lndebug(fmt, ...) |
| #endif // BC_DEBUG_CODE |
| |
| /// An enum of useful actions. To understand what these mean, check terminal |
| /// emulators for their shortcuts or the VT100 codes. |
| typedef enum BcHistoryAction { |
| |
| BC_ACTION_NULL = 0, |
| BC_ACTION_CTRL_A = 1, |
| BC_ACTION_CTRL_B = 2, |
| BC_ACTION_CTRL_C = 3, |
| BC_ACTION_CTRL_D = 4, |
| BC_ACTION_CTRL_E = 5, |
| BC_ACTION_CTRL_F = 6, |
| BC_ACTION_CTRL_H = 8, |
| BC_ACTION_TAB = 9, |
| BC_ACTION_LINE_FEED = 10, |
| BC_ACTION_CTRL_K = 11, |
| BC_ACTION_CTRL_L = 12, |
| BC_ACTION_ENTER = 13, |
| BC_ACTION_CTRL_N = 14, |
| BC_ACTION_CTRL_P = 16, |
| BC_ACTION_CTRL_S = 19, |
| BC_ACTION_CTRL_T = 20, |
| BC_ACTION_CTRL_U = 21, |
| BC_ACTION_CTRL_W = 23, |
| BC_ACTION_CTRL_Z = 26, |
| BC_ACTION_ESC = 27, |
| BC_ACTION_CTRL_BSLASH = 28, |
| BC_ACTION_BACKSPACE = 127 |
| |
| } BcHistoryAction; |
| |
| /** |
| * This represents the state during line editing. We pass this state |
| * to functions implementing specific editing functionalities. |
| */ |
| typedef struct BcHistory { |
| |
| /// Edited line buffer. |
| BcVec buf; |
| |
| /// The history. |
| BcVec history; |
| |
| /// Any material printed without a trailing newline. |
| BcVec extras; |
| |
| /// Prompt to display. |
| const char *prompt; |
| |
| /// Prompt length. |
| size_t plen; |
| |
| /// Prompt column length. |
| size_t pcol; |
| |
| /// Current cursor position. |
| size_t pos; |
| |
| /// Previous refresh cursor column position. |
| size_t oldcolpos; |
| |
| /// Number of columns in terminal. |
| size_t cols; |
| |
| /// The history index we are currently editing. |
| size_t idx; |
| |
| #ifndef _WIN32 |
| /// The original terminal state. |
| struct termios orig_termios; |
| #else // _WIN32 |
| DWORD orig_console_mode; |
| #endif // _WIN32 |
| |
| /// These next two are here because pahole found a 4 byte hole here. |
| |
| /// Whether we are in rawmode. |
| bool rawMode; |
| |
| /// Whether the terminal is bad. |
| bool badTerm; |
| |
| #ifndef _WIN32 |
| /// This is to check if stdin has more data. |
| fd_set rdset; |
| |
| /// This is to check if stdin has more data. |
| struct timespec ts; |
| |
| /// This is to check if stdin has more data. |
| sigset_t sigmask; |
| #endif // _WIN32 |
| |
| } BcHistory; |
| |
| /** |
| * Get a line from stdin using history. This returns a status because I don't |
| * want to throw errors while the terminal is in raw mode. |
| * @param h The history data. |
| * @param vec A vector to put the line into. |
| * @param prompt The prompt to display, if desired. |
| * @return A status indicating an error, if any. Returning a status here |
| * is better because if we throw an error out of history, we |
| * leave the terminal in raw mode or in some other half-baked |
| * state. |
| */ |
| BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt); |
| |
| /** |
| * Initialize history data. |
| * @param h The struct to initialize. |
| */ |
| void bc_history_init(BcHistory *h); |
| |
| /** |
| * Free history data (and recook the terminal). |
| * @param h The struct to free. |
| */ |
| void bc_history_free(BcHistory *h); |
| |
| /** |
| * Frees strings used by history. |
| * @param str The string to free. |
| */ |
| void bc_history_string_free(void *str); |
| |
| // A list of terminals that don't work. |
| extern const char *bc_history_bad_terms[]; |
| |
| // A tab in history and its length. |
| extern const char bc_history_tab[]; |
| extern const size_t bc_history_tab_len; |
| |
| // A ctrl+c string. |
| extern const char bc_history_ctrlc[]; |
| |
| // UTF-8 data arrays. |
| extern const uint32_t bc_history_wchars[][2]; |
| extern const size_t bc_history_wchars_len; |
| extern const uint32_t bc_history_combo_chars[]; |
| extern const size_t bc_history_combo_chars_len; |
| |
| #if BC_DEBUG_CODE |
| |
| // Debug data. |
| extern BcFile bc_history_debug_fp; |
| extern char *bc_history_debug_buf; |
| |
| /** |
| * A function to print keycodes for debugging. |
| * @param h The history data. |
| */ |
| void bc_history_printKeyCodes(BcHistory* h); |
| |
| #endif // BC_DEBUG_CODE |
| |
| #endif // BC_ENABLE_HISTORY |
| |
| #endif // BC_HISTORY_H |