| /* |
| * ***************************************************************************** |
| * |
| * Copyright (c) 2018-2020 Gavin D. Howard and contributors. |
| * |
| * All rights reserved. |
| * |
| * 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> |
| * |
| * All rights reserved. |
| * |
| * 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 |
| |
| #ifdef _WIN32 |
| #error History is not supported on Windows. |
| #endif |
| |
| #include <stdbool.h> |
| #include <stddef.h> |
| #include <stdio.h> |
| |
| #include <signal.h> |
| |
| #include <termios.h> |
| #include <time.h> |
| #include <unistd.h> |
| #include <sys/select.h> |
| |
| #include <status.h> |
| #include <vector.h> |
| #include <read.h> |
| |
| #define BC_HIST_DEF_COLS (80) |
| #define BC_HIST_MAX_LEN (128) |
| #define BC_HIST_MAX_LINE (4095) |
| #define BC_HIST_SEQ_SIZE (64) |
| |
| #define BC_HIST_BUF_LEN(h) ((h)->buf.len - 1) |
| #define BC_HIST_WRITE(s, n) (write(STDERR_FILENO, (s), (n)) != (ssize_t) (n)) |
| #define BC_HIST_READ(s, n) (read(STDIN_FILENO, (s), (n)) == -1) |
| |
| #define BC_HIST_NEXT (false) |
| #define BC_HIST_PREV (true) |
| |
| #if BC_DEBUG_CODE |
| #define lndebug(...) \ |
| do { \ |
| if (bc_history_debug_fp == NULL) { \ |
| bc_history_debug_fp = fopen("/tmp/lndebug.txt","a"); \ |
| fprintf(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); \ |
| } \ |
| fprintf(bc_history_debug_fp, ", " __VA_ARGS__); \ |
| fflush(bc_history_debug_fp); \ |
| } while (0) |
| #else // BC_DEBUG_CODE |
| #define lndebug(fmt, ...) |
| #endif // BC_DEBUG_CODE |
| |
| #if !BC_ENABLE_PROMPT |
| #define bc_history_line(h, vec, prompt) bc_history_line(h, vec) |
| #define bc_history_raw(h, prompt) bc_history_raw(h) |
| #define bc_history_edit(h, prompt) bc_history_edit(h) |
| #endif // BC_ENABLE_PROMPT |
| |
| 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_T = 20, |
| BC_ACTION_CTRL_U = 21, |
| BC_ACTION_CTRL_W = 23, |
| BC_ACTION_CTRL_Z = 26, |
| BC_ACTION_ESC = 27, |
| 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; |
| |
| /// A temporary buffer for refresh. Using this |
| /// prevents an allocation on every refresh. |
| BcVec tmp; |
| |
| #if BC_ENABLE_PROMPT |
| /// Prompt to display. |
| const char *prompt; |
| |
| /// Prompt length. |
| size_t plen; |
| #endif // BC_ENABLE_PROMPT |
| |
| /// 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; |
| |
| /// The original terminal state. |
| struct termios orig_termios; |
| |
| /// 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; |
| |
| /// This is to signal that there is more, so we don't process yet. |
| bool stdin_has_data; |
| |
| /// Whether we are in rawmode. |
| bool rawMode; |
| |
| /// Whether the terminal is bad. |
| bool badTerm; |
| |
| } BcHistory; |
| |
| BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt); |
| void bc_history_add(BcHistory *h, char *line); |
| |
| void bc_history_init(BcHistory *h); |
| void bc_history_free(BcHistory *h); |
| |
| extern const char *bc_history_bad_terms[]; |
| extern const char bc_history_tab[]; |
| extern const size_t bc_history_tab_len; |
| extern const char bc_history_ctrlc[]; |
| 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 |
| extern FILE *bc_history_debug_fp; |
| BcStatus bc_history_printKeyCodes(BcHistory* l); |
| #endif // BC_DEBUG_CODE |
| |
| #endif // BC_ENABLE_HISTORY |
| |
| #endif // BC_HISTORY_H |