diff options
Diffstat (limited to 'contrib/bc/src/history.c')
-rw-r--r-- | contrib/bc/src/history.c | 955 |
1 files changed, 692 insertions, 263 deletions
diff --git a/contrib/bc/src/history.c b/contrib/bc/src/history.c index 9f158413efc2..924b62b41c2d 100644 --- a/contrib/bc/src/history.c +++ b/contrib/bc/src/history.c @@ -3,7 +3,7 @@ * * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2018-2021 Gavin D. Howard and contributors. + * Copyright (c) 2018-2023 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: @@ -144,6 +144,258 @@ #if BC_ENABLE_HISTORY +#if BC_ENABLE_EDITLINE + +#include <string.h> +#include <errno.h> +#include <setjmp.h> + +#include <history.h> +#include <vm.h> + +sigjmp_buf bc_history_jmpbuf; +volatile sig_atomic_t bc_history_inlinelib; + +static char* bc_history_prompt; +static char bc_history_no_prompt[] = ""; +static HistEvent bc_history_event; +static bool bc_history_use_prompt; + +static char* +bc_history_promptFunc(EditLine* el) +{ + BC_UNUSED(el); + return BC_PROMPT && bc_history_use_prompt ? bc_history_prompt : + bc_history_no_prompt; +} + +void +bc_history_init(BcHistory* h) +{ + BcVec v; + char* home; + + home = getenv("HOME"); + + // This will hold the true path to the editrc. + bc_vec_init(&v, 1, BC_DTOR_NONE); + + // Initialize the path to the editrc. This is done manually because the + // libedit I used to test was failing with a NULL argument for the path, + // which was supposed to automatically do $HOME/.editrc. But it was failing, + // so I set it manually. + if (home == NULL) + { + bc_vec_string(&v, bc_history_editrc_len - 1, bc_history_editrc + 1); + } + else + { + bc_vec_string(&v, strlen(home), home); + bc_vec_concat(&v, bc_history_editrc); + } + + h->hist = history_init(); + if (BC_ERR(h->hist == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); + + h->el = el_init(vm->name, stdin, stdout, stderr); + if (BC_ERR(h->el == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR); + + // I want history and a prompt. + history(h->hist, &bc_history_event, H_SETSIZE, 100); + history(h->hist, &bc_history_event, H_SETUNIQUE, 1); + el_set(h->el, EL_EDITOR, "emacs"); + el_set(h->el, EL_HIST, history, h->hist); + el_set(h->el, EL_PROMPT, bc_history_promptFunc); + + // I also want to get the user's .editrc. + el_source(h->el, v.v); + + bc_vec_free(&v); + + h->badTerm = false; + bc_history_prompt = NULL; +} + +void +bc_history_free(BcHistory* h) +{ + if (BC_PROMPT && bc_history_prompt != NULL) free(bc_history_prompt); + el_end(h->el); + history_end(h->hist); +} + +BcStatus +bc_history_line(BcHistory* h, BcVec* vec, const char* prompt) +{ + BcStatus s = BC_STATUS_SUCCESS; + const char* line; + int len; + + BC_SIG_LOCK; + + // If the jump happens here, then a SIGINT occurred. + if (sigsetjmp(bc_history_jmpbuf, 0)) + { + bc_vec_string(vec, 1, "\n"); + goto end; + } + + // This is so the signal handler can handle line libraries properly. + bc_history_inlinelib = 1; + + if (BC_PROMPT) + { + // Make sure to set the prompt. + if (bc_history_prompt != NULL) + { + if (strcmp(bc_history_prompt, prompt)) + { + free(bc_history_prompt); + bc_history_prompt = bc_vm_strdup(prompt); + } + } + else bc_history_prompt = bc_vm_strdup(prompt); + } + + bc_history_use_prompt = true; + + line = NULL; + len = -1; + errno = EINTR; + + // Get the line. + while (line == NULL && len == -1 && errno == EINTR) + { + line = el_gets(h->el, &len); + bc_history_use_prompt = false; + } + + // If there is no line... + if (BC_ERR(line == NULL)) + { + // If this is true, there was an error. Otherwise, it's just EOF. + if (len == -1) + { + if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR); + bc_err(BC_ERR_FATAL_IO_ERR); + } + else + { + bc_file_printf(&vm->fout, "\n"); + s = BC_STATUS_EOF; + } + } + // If there is a line... + else + { + bc_vec_string(vec, strlen(line), line); + + if (strcmp(line, "") && strcmp(line, "\n")) + { + history(h->hist, &bc_history_event, H_ENTER, line); + } + + s = BC_STATUS_SUCCESS; + } + +end: + + bc_history_inlinelib = 0; + + BC_SIG_UNLOCK; + + return s; +} + +#else // BC_ENABLE_EDITLINE + +#if BC_ENABLE_READLINE + +#include <assert.h> +#include <setjmp.h> +#include <string.h> + +#include <history.h> +#include <vm.h> + +sigjmp_buf bc_history_jmpbuf; +volatile sig_atomic_t bc_history_inlinelib; + +void +bc_history_init(BcHistory* h) +{ + h->line = NULL; + h->badTerm = false; + + // I want no tab completion. + rl_bind_key('\t', rl_insert); +} + +void +bc_history_free(BcHistory* h) +{ + if (h->line != NULL) free(h->line); +} + +BcStatus +bc_history_line(BcHistory* h, BcVec* vec, const char* prompt) +{ + BcStatus s = BC_STATUS_SUCCESS; + size_t len; + + BC_SIG_LOCK; + + // If the jump happens here, then a SIGINT occurred. + if (sigsetjmp(bc_history_jmpbuf, 0)) + { + bc_vec_string(vec, 1, "\n"); + goto end; + } + + // This is so the signal handler can handle line libraries properly. + bc_history_inlinelib = 1; + + // Get rid of the last line. + if (h->line != NULL) + { + free(h->line); + h->line = NULL; + } + + // Get the line. + h->line = readline(BC_PROMPT ? prompt : ""); + + // If there was a line, add it to the history. Otherwise, just return an + // empty line. Oh, and NULL actually means EOF. + if (h->line != NULL && h->line[0]) + { + add_history(h->line); + + len = strlen(h->line); + + bc_vec_expand(vec, len + 2); + + bc_vec_string(vec, len, h->line); + bc_vec_concat(vec, "\n"); + } + else if (h->line == NULL) + { + bc_file_printf(&vm->fout, "%s\n", "^D"); + s = BC_STATUS_EOF; + } + else bc_vec_string(vec, 1, "\n"); + +end: + + bc_history_inlinelib = 0; + + BC_SIG_UNLOCK; + + return s; +} + +#else // BC_ENABLE_READLINE + #include <assert.h> #include <stdlib.h> #include <errno.h> @@ -175,7 +427,7 @@ BcFile bc_history_debug_fp; /// A buffer for the above file. -char *bc_history_debug_buf; +char* bc_history_debug_buf; #endif // BC_DEBUG_CODE @@ -184,12 +436,13 @@ char *bc_history_debug_buf; * @param cp The codepoint to check. * @return True if @a cp is a wide character, false otherwise. */ -static bool bc_history_wchar(uint32_t cp) { - +static bool +bc_history_wchar(uint32_t cp) +{ size_t i; - for (i = 0; i < bc_history_wchars_len; ++i) { - + for (i = 0; i < bc_history_wchars_len; ++i) + { // Ranges are listed in ascending order. Therefore, once the // whole range is higher than the codepoint we're testing, the // codepoint won't be found in any remaining range => bail early. @@ -197,7 +450,9 @@ static bool bc_history_wchar(uint32_t cp) { // Test this range. if (bc_history_wchars[i][0] <= cp && cp <= bc_history_wchars[i][1]) + { return true; + } } return false; @@ -208,12 +463,13 @@ static bool bc_history_wchar(uint32_t cp) { * @param cp The codepoint to check. * @return True if @a cp is a combining character, false otherwise. */ -static bool bc_history_comboChar(uint32_t cp) { - +static bool +bc_history_comboChar(uint32_t cp) +{ size_t i; - for (i = 0; i < bc_history_combo_chars_len; ++i) { - + for (i = 0; i < bc_history_combo_chars_len; ++i) + { // Combining chars are listed in ascending order, so once we pass // the codepoint of interest, we know it's not a combining char. if (bc_history_combo_chars[i] > cp) return false; @@ -228,9 +484,14 @@ static bool bc_history_comboChar(uint32_t cp) { * @param buf The buffer of characters. * @param pos The index into the buffer. */ -static size_t bc_history_prevCharLen(const char *buf, size_t pos) { +static size_t +bc_history_prevCharLen(const char* buf, size_t pos) +{ size_t end = pos; - for (pos -= 1; pos < end && (buf[pos] & 0xC0) == 0x80; --pos); + for (pos -= 1; pos < end && (buf[pos] & 0xC0) == 0x80; --pos) + { + continue; + } return end - (pos >= end ? 0 : pos); } @@ -241,47 +502,53 @@ static size_t bc_history_prevCharLen(const char *buf, size_t pos) { * @param cp An out parameter for the codepoint. * @return The number of bytes eaten by the codepoint. */ -static size_t bc_history_codePoint(const char *s, size_t len, uint32_t *cp) { - - if (len) { - +static size_t +bc_history_codePoint(const char* s, size_t len, uint32_t* cp) +{ + if (len) + { uchar byte = (uchar) s[0]; // This is literally the UTF-8 decoding algorithm. Look that up if you // don't understand this. - if ((byte & 0x80) == 0) { + if ((byte & 0x80) == 0) + { *cp = byte; return 1; } - else if ((byte & 0xE0) == 0xC0) { - - if (len >= 2) { + else if ((byte & 0xE0) == 0xC0) + { + if (len >= 2) + { *cp = (((uint32_t) (s[0] & 0x1F)) << 6) | - ((uint32_t) (s[1] & 0x3F)); + ((uint32_t) (s[1] & 0x3F)); return 2; } } - else if ((byte & 0xF0) == 0xE0) { - - if (len >= 3) { + else if ((byte & 0xF0) == 0xE0) + { + if (len >= 3) + { *cp = (((uint32_t) (s[0] & 0x0F)) << 12) | - (((uint32_t) (s[1] & 0x3F)) << 6) | - ((uint32_t) (s[2] & 0x3F)); + (((uint32_t) (s[1] & 0x3F)) << 6) | + ((uint32_t) (s[2] & 0x3F)); return 3; } } - else if ((byte & 0xF8) == 0xF0) { - - if (len >= 4) { + else if ((byte & 0xF8) == 0xF0) + { + if (len >= 4) + { *cp = (((uint32_t) (s[0] & 0x07)) << 18) | - (((uint32_t) (s[1] & 0x3F)) << 12) | - (((uint32_t) (s[2] & 0x3F)) << 6) | - ((uint32_t) (s[3] & 0x3F)); + (((uint32_t) (s[1] & 0x3F)) << 12) | + (((uint32_t) (s[2] & 0x3F)) << 6) | + ((uint32_t) (s[3] & 0x3F)); return 4; } } - else { + else + { *cp = 0xFFFD; return 1; } @@ -300,20 +567,22 @@ static size_t bc_history_codePoint(const char *s, size_t len, uint32_t *cp) { * @param col_len An out parameter for the length of the grapheme on screen. * @return The number of bytes in the grapheme. */ -static size_t bc_history_nextLen(const char *buf, size_t buf_len, - size_t pos, size_t *col_len) +static size_t +bc_history_nextLen(const char* buf, size_t buf_len, size_t pos, size_t* col_len) { uint32_t cp; size_t beg = pos; size_t len = bc_history_codePoint(buf + pos, buf_len - pos, &cp); - if (bc_history_comboChar(cp)) { - + if (bc_history_comboChar(cp)) + { BC_UNREACHABLE +#if !BC_CLANG if (col_len != NULL) *col_len = 0; return 0; +#endif // !BC_CLANG } // Store the width of the character on screen. @@ -322,8 +591,8 @@ static size_t bc_history_nextLen(const char *buf, size_t buf_len, pos += len; // Find the first non-combining character. - while (pos < buf_len) { - + while (pos < buf_len) + { len = bc_history_codePoint(buf + pos, buf_len - pos, &cp); if (!bc_history_comboChar(cp)) return pos - beg; @@ -340,13 +609,14 @@ static size_t bc_history_nextLen(const char *buf, size_t buf_len, * @param pos The index into the buffer. * @return The number of bytes in the grapheme. */ -static size_t bc_history_prevLen(const char *buf, size_t pos) { - +static size_t +bc_history_prevLen(const char* buf, size_t pos) +{ size_t end = pos; // Find the first non-combining character. - while (pos > 0) { - + while (pos > 0) + { uint32_t cp; size_t len = bc_history_prevCharLen(buf, pos); @@ -361,7 +631,9 @@ static size_t bc_history_prevLen(const char *buf, size_t pos) { BC_UNREACHABLE +#if !BC_CLANG return 0; +#endif // BC_CLANG } /** @@ -371,18 +643,21 @@ static size_t bc_history_prevLen(const char *buf, size_t pos) { * @param n The number of characters to read. * @return The number of characters read or less than 0 on error. */ -static ssize_t bc_history_read(char *buf, size_t n) { - +static ssize_t +bc_history_read(char* buf, size_t n) +{ ssize_t ret; BC_SIG_ASSERT_LOCKED; #ifndef _WIN32 - do { + do + { // We don't care about being interrupted. ret = read(STDIN_FILENO, buf, n); - } while (ret == EINTR); + } + while (ret == EINTR); #else // _WIN32 @@ -392,7 +667,7 @@ static ssize_t bc_history_read(char *buf, size_t n) { good = ReadConsole(hn, buf, (DWORD) n, &read, NULL); - ret = (read != n) ? -1 : 1; + ret = (read != n || !good) ? -1 : 1; #endif // _WIN32 @@ -407,10 +682,11 @@ static ssize_t bc_history_read(char *buf, size_t n) { * @param nread An out parameter for the number of bytes read. * @return BC_STATUS_EOF or BC_STATUS_SUCCESS. */ -static BcStatus bc_history_readCode(char *buf, size_t buf_len, - uint32_t *cp, size_t *nread) +static BcStatus +bc_history_readCode(char* buf, size_t buf_len, uint32_t* cp, size_t* nread) { ssize_t n; + uchar byte; assert(buf_len >= 1); @@ -424,14 +700,14 @@ static BcStatus bc_history_readCode(char *buf, size_t buf_len, if (BC_ERR(n <= 0)) goto err; // Get the byte. - uchar byte = ((uchar*) buf)[0]; + byte = ((uchar*) buf)[0]; // Once again, this is the UTF-8 decoding algorithm, but it has reads // instead of actual decoding. - if ((byte & 0x80) != 0) { - - if ((byte & 0xE0) == 0xC0) { - + if ((byte & 0x80) != 0) + { + if ((byte & 0xE0) == 0xC0) + { assert(buf_len >= 2); BC_SIG_LOCK; @@ -442,8 +718,8 @@ static BcStatus bc_history_readCode(char *buf, size_t buf_len, if (BC_ERR(n <= 0)) goto err; } - else if ((byte & 0xF0) == 0xE0) { - + else if ((byte & 0xF0) == 0xE0) + { assert(buf_len >= 3); BC_SIG_LOCK; @@ -454,8 +730,8 @@ static BcStatus bc_history_readCode(char *buf, size_t buf_len, if (BC_ERR(n <= 0)) goto err; } - else if ((byte & 0xF8) == 0xF0) { - + else if ((byte & 0xF8) == 0xF0) + { assert(buf_len >= 3); BC_SIG_LOCK; @@ -466,7 +742,8 @@ static BcStatus bc_history_readCode(char *buf, size_t buf_len, if (BC_ERR(n <= 0)) goto err; } - else { + else + { n = -1; goto err; } @@ -492,13 +769,14 @@ err: * @return The number of columns between the beginning of @a buffer to * @a pos. */ -static size_t bc_history_colPos(const char *buf, size_t buf_len, size_t pos) { - +static size_t +bc_history_colPos(const char* buf, size_t buf_len, size_t pos) +{ size_t ret = 0, off = 0; // While we haven't reached the offset, get the length of the next grapheme. - while (off < pos && off < buf_len) { - + while (off < pos && off < buf_len) + { size_t col_len, len; len = bc_history_nextLen(buf, buf_len, off, &col_len); @@ -515,16 +793,19 @@ static size_t bc_history_colPos(const char *buf, size_t buf_len, size_t pos) { * not able to understand basic escape sequences. * @return True if the terminal is a bad terminal. */ -static inline bool bc_history_isBadTerm(void) { - +static inline bool +bc_history_isBadTerm(void) +{ size_t i; bool ret = false; - char *term = bc_vm_getenv("TERM"); + char* term = bc_vm_getenv("TERM"); if (term == NULL) return false; for (i = 0; !ret && bc_history_bad_terms[i]; ++i) + { ret = (!strcasecmp(term, bc_history_bad_terms[i])); + } bc_vm_getenvFree(term); @@ -535,8 +816,9 @@ static inline bool bc_history_isBadTerm(void) { * Enables raw mode (1960's black magic). * @param h The history data. */ -static void bc_history_enableRaw(BcHistory *h) { - +static void +bc_history_enableRaw(BcHistory* h) +{ // I don't do anything for Windows because in Windows, you set their // equivalent of raw mode and leave it, so I do it in bc_history_init(). @@ -551,7 +833,9 @@ static void bc_history_enableRaw(BcHistory *h) { BC_SIG_LOCK; if (BC_ERR(tcgetattr(STDIN_FILENO, &h->orig_termios) == -1)) + { bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } BC_SIG_UNLOCK; @@ -577,9 +861,11 @@ static void bc_history_enableRaw(BcHistory *h) { BC_SIG_LOCK; // Put terminal in raw mode after flushing. - do { + do + { err = tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw); - } while (BC_ERR(err < 0) && errno == EINTR); + } + while (BC_ERR(err < 0) && errno == EINTR); BC_SIG_UNLOCK; @@ -593,8 +879,9 @@ static void bc_history_enableRaw(BcHistory *h) { * Disables raw mode. * @param h The history data. */ -static void bc_history_disableRaw(BcHistory *h) { - +static void +bc_history_disableRaw(BcHistory* h) +{ sig_atomic_t lock; if (!h->rawMode) return; @@ -603,7 +890,9 @@ static void bc_history_disableRaw(BcHistory *h) { #ifndef _WIN32 if (BC_ERR(tcsetattr(STDIN_FILENO, TCSAFLUSH, &h->orig_termios) != -1)) + { h->rawMode = false; + } #endif // _WIN32 BC_SIG_TRYUNLOCK(lock); @@ -615,20 +904,23 @@ static void bc_history_disableRaw(BcHistory *h) { * cursor. * @return The horizontal cursor position. */ -static size_t bc_history_cursorPos(void) { - +static size_t +bc_history_cursorPos(void) +{ char buf[BC_HIST_SEQ_SIZE]; - char *ptr, *ptr2; + char* ptr; + char* ptr2; size_t cols, rows, i; BC_SIG_ASSERT_LOCKED; // Report cursor location. - bc_file_write(&vm.fout, bc_flush_none, "\x1b[6n", 4); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_write(&vm->fout, bc_flush_none, "\x1b[6n", 4); + bc_file_flush(&vm->fout, bc_flush_none); // Read the response: ESC [ rows ; cols R. - for (i = 0; i < sizeof(buf) - 1; ++i) { + for (i = 0; i < sizeof(buf) - 1; ++i) + { if (bc_history_read(buf + i, 1) != 1 || buf[i] == 'R') break; } @@ -658,17 +950,19 @@ static size_t bc_history_cursorPos(void) { * if it fails. * @return The number of columns in the terminal. */ -static size_t bc_history_columns(void) { +static size_t +bc_history_columns(void) +{ #ifndef _WIN32 struct winsize ws; int ret; - ret = ioctl(vm.fout.fd, TIOCGWINSZ, &ws); - - if (BC_ERR(ret == -1 || !ws.ws_col)) { + ret = ioctl(vm->fout.fd, TIOCGWINSZ, &ws); + if (BC_ERR(ret == -1 || !ws.ws_col)) + { // Calling ioctl() failed. Try to query the terminal itself. size_t start, cols; @@ -677,15 +971,16 @@ static size_t bc_history_columns(void) { if (BC_ERR(start == SIZE_MAX)) return BC_HIST_DEF_COLS; // Go to right margin and get position. - bc_file_write(&vm.fout, bc_flush_none, "\x1b[999C", 6); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_write(&vm->fout, bc_flush_none, "\x1b[999C", 6); + bc_file_flush(&vm->fout, bc_flush_none); cols = bc_history_cursorPos(); if (BC_ERR(cols == SIZE_MAX)) return BC_HIST_DEF_COLS; // Restore position. - if (cols > start) { - bc_file_printf(&vm.fout, "\x1b[%zuD", cols - start); - bc_file_flush(&vm.fout, bc_flush_none); + if (cols > start) + { + bc_file_printf(&vm->fout, "\x1b[%zuD", cols - start); + bc_file_flush(&vm->fout, bc_flush_none); } return cols; @@ -698,7 +993,9 @@ static size_t bc_history_columns(void) { CONSOLE_SCREEN_BUFFER_INFO csbi; if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) + { return 80; + } return ((size_t) (csbi.srWindow.Right)) - csbi.srWindow.Left + 1; @@ -712,14 +1009,18 @@ static size_t bc_history_columns(void) { * @param plen The length of the prompt. * @return The column length of the prompt. */ -static size_t bc_history_promptColLen(const char *prompt, size_t plen) { - +static size_t +bc_history_promptColLen(const char* prompt, size_t plen) +{ char buf[BC_HIST_MAX_LINE + 1]; size_t buf_len = 0, off = 0; // The original linenoise-mob checked for ANSI escapes here on the prompt. I // know the prompts do not have ANSI escapes. I deleted the code. - while (off < plen) buf[buf_len++] = prompt[off++]; + while (off < plen) + { + buf[buf_len++] = prompt[off++]; + } return bc_history_colPos(buf, buf_len, buf_len); } @@ -729,18 +1030,19 @@ static size_t bc_history_promptColLen(const char *prompt, size_t plen) { * cursor position, and number of columns of the terminal. * @param h The history data. */ -static void bc_history_refresh(BcHistory *h) { - +static void +bc_history_refresh(BcHistory* h) +{ char* buf = h->buf.v; size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0; BC_SIG_ASSERT_LOCKED; - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_flush(&vm->fout, bc_flush_none); // Get to the prompt column position from the left. - while(h->pcol + bc_history_colPos(buf, len, pos) >= h->cols) { - + while (h->pcol + bc_history_colPos(buf, len, pos) >= h->cols) + { size_t chlen = bc_history_nextLen(buf, len, 0, NULL); buf += chlen; @@ -750,15 +1052,17 @@ static void bc_history_refresh(BcHistory *h) { // Get to the prompt column position from the right. while (h->pcol + bc_history_colPos(buf, len, len) > h->cols) + { len -= bc_history_prevLen(buf, len); + } // Cursor to left edge. - bc_file_write(&vm.fout, bc_flush_none, "\r", 1); + bc_file_write(&vm->fout, bc_flush_none, "\r", 1); // Take the extra stuff into account. This is where history makes sure to // preserve stuff that was printed without a newline. - if (h->extras.len > 1) { - + if (h->extras.len > 1) + { extras_len = h->extras.len - 1; bc_vec_grow(&h->buf, extras_len); @@ -766,28 +1070,30 @@ static void bc_history_refresh(BcHistory *h) { len += extras_len; pos += extras_len; - bc_file_write(&vm.fout, bc_flush_none, h->extras.v, extras_len); + bc_file_write(&vm->fout, bc_flush_none, h->extras.v, extras_len); } // Write the prompt, if desired. - if (BC_PROMPT) bc_file_write(&vm.fout, bc_flush_none, h->prompt, h->plen); + if (BC_PROMPT) bc_file_write(&vm->fout, bc_flush_none, h->prompt, h->plen); - bc_file_write(&vm.fout, bc_flush_none, h->buf.v, len - extras_len); + bc_file_write(&vm->fout, bc_flush_none, h->buf.v, len - extras_len); // Erase to right. - bc_file_write(&vm.fout, bc_flush_none, "\x1b[0K", 4); + bc_file_write(&vm->fout, bc_flush_none, "\x1b[0K", 4); // We need to be sure to grow this. - if (pos >= h->buf.len - extras_len) - bc_vec_grow(&h->buf, pos + extras_len); + if (pos >= h->buf.len - extras_len) bc_vec_grow(&h->buf, pos + extras_len); - // Move cursor to original position. + // Move cursor to original position. Do NOT move the putchar of '\r' to the + // printf with colpos. That causes a bug where the cursor will go to the end + // of the line when there is no prompt. + bc_file_putchar(&vm->fout, bc_flush_none, '\r'); colpos = bc_history_colPos(h->buf.v, len - extras_len, pos) + h->pcol; // Set the cursor position again. - if (colpos) bc_file_printf(&vm.fout, "\r\x1b[%zuC", colpos); + if (colpos) bc_file_printf(&vm->fout, "\x1b[%zuC", colpos); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_flush(&vm->fout, bc_flush_none); } /** @@ -796,15 +1102,16 @@ static void bc_history_refresh(BcHistory *h) { * @param cbuf The character buffer to copy from. * @param clen The number of characters to copy. */ -static void bc_history_edit_insert(BcHistory *h, const char *cbuf, size_t clen) +static void +bc_history_edit_insert(BcHistory* h, const char* cbuf, size_t clen) { BC_SIG_ASSERT_LOCKED; bc_vec_grow(&h->buf, clen); // If we are at the end of the line... - if (h->pos == BC_HIST_BUF_LEN(h)) { - + if (h->pos == BC_HIST_BUF_LEN(h)) + { size_t colpos = 0, len; // Copy into the buffer. @@ -821,16 +1128,16 @@ static void bc_history_edit_insert(BcHistory *h, const char *cbuf, size_t clen) colpos += bc_history_colPos(h->buf.v, len, len); // Do we have the trivial case? - if (colpos < h->cols) { - + if (colpos < h->cols) + { // Avoid a full update of the line in the trivial case. - bc_file_write(&vm.fout, bc_flush_none, cbuf, clen); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_write(&vm->fout, bc_flush_none, cbuf, clen); + bc_file_flush(&vm->fout, bc_flush_none); } else bc_history_refresh(h); } - else { - + else + { // Amount that we need to move. size_t amt = BC_HIST_BUF_LEN(h) - h->pos; @@ -851,8 +1158,9 @@ static void bc_history_edit_insert(BcHistory *h, const char *cbuf, size_t clen) * Moves the cursor to the left. * @param h The history data. */ -static void bc_history_edit_left(BcHistory *h) { - +static void +bc_history_edit_left(BcHistory* h) +{ BC_SIG_ASSERT_LOCKED; // Stop at the left end. @@ -866,9 +1174,10 @@ static void bc_history_edit_left(BcHistory *h) { /** * Moves the cursor to the right. * @param h The history data. -*/ -static void bc_history_edit_right(BcHistory *h) { - + */ +static void +bc_history_edit_right(BcHistory* h) +{ BC_SIG_ASSERT_LOCKED; // Stop at the right end. @@ -883,8 +1192,9 @@ static void bc_history_edit_right(BcHistory *h) { * Moves the cursor to the end of the current word. * @param h The history data. */ -static void bc_history_edit_wordEnd(BcHistory *h) { - +static void +bc_history_edit_wordEnd(BcHistory* h) +{ size_t len = BC_HIST_BUF_LEN(h); BC_SIG_ASSERT_LOCKED; @@ -893,8 +1203,14 @@ static void bc_history_edit_wordEnd(BcHistory *h) { if (!len || h->pos >= len) return; // Find the word, then find the end of it. - while (h->pos < len && isspace(h->buf.v[h->pos])) h->pos += 1; - while (h->pos < len && !isspace(h->buf.v[h->pos])) h->pos += 1; + while (h->pos < len && isspace(h->buf.v[h->pos])) + { + h->pos += 1; + } + while (h->pos < len && !isspace(h->buf.v[h->pos])) + { + h->pos += 1; + } bc_history_refresh(h); } @@ -903,8 +1219,9 @@ static void bc_history_edit_wordEnd(BcHistory *h) { * Moves the cursor to the start of the current word. * @param h The history data. */ -static void bc_history_edit_wordStart(BcHistory *h) { - +static void +bc_history_edit_wordStart(BcHistory* h) +{ size_t len = BC_HIST_BUF_LEN(h); BC_SIG_ASSERT_LOCKED; @@ -913,8 +1230,14 @@ static void bc_history_edit_wordStart(BcHistory *h) { if (!len) return; // Find the word, the find the beginning of the word. - while (h->pos > 0 && isspace(h->buf.v[h->pos - 1])) h->pos -= 1; - while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1])) h->pos -= 1; + while (h->pos > 0 && isspace(h->buf.v[h->pos - 1])) + { + h->pos -= 1; + } + while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1])) + { + h->pos -= 1; + } bc_history_refresh(h); } @@ -923,8 +1246,9 @@ static void bc_history_edit_wordStart(BcHistory *h) { * Moves the cursor to the start of the line. * @param h The history data. */ -static void bc_history_edit_home(BcHistory *h) { - +static void +bc_history_edit_home(BcHistory* h) +{ BC_SIG_ASSERT_LOCKED; // Stop at the beginning. @@ -939,8 +1263,9 @@ static void bc_history_edit_home(BcHistory *h) { * Moves the cursor to the end of the line. * @param h The history data. */ -static void bc_history_edit_end(BcHistory *h) { - +static void +bc_history_edit_end(BcHistory* h) +{ BC_SIG_ASSERT_LOCKED; // Stop at the end of the line. @@ -957,9 +1282,11 @@ static void bc_history_edit_end(BcHistory *h) { * @param h The history data. * @param dir The direction to substitute; true means previous, false next. */ -static void bc_history_edit_next(BcHistory *h, bool dir) { - - const char *dup, *str; +static void +bc_history_edit_next(BcHistory* h, bool dir) +{ + const char* dup; + const char* str; BC_SIG_ASSERT_LOCKED; @@ -977,11 +1304,13 @@ static void bc_history_edit_next(BcHistory *h, bool dir) { h->idx += (dir == BC_HIST_PREV ? 1 : SIZE_MAX); // Se the index appropriately at the ends. - if (h->idx == SIZE_MAX) { + if (h->idx == SIZE_MAX) + { h->idx = 0; return; } - else if (h->idx >= h->history.len) { + else if (h->idx >= h->history.len) + { h->idx = h->history.len - 1; return; } @@ -1003,8 +1332,9 @@ static void bc_history_edit_next(BcHistory *h, bool dir) { * position. Basically, this is what happens with the "Delete" keyboard key. * @param h The history data. */ -static void bc_history_edit_delete(BcHistory *h) { - +static void +bc_history_edit_delete(BcHistory* h) +{ size_t chlen, len = BC_HIST_BUF_LEN(h); BC_SIG_ASSERT_LOCKED; @@ -1030,8 +1360,9 @@ static void bc_history_edit_delete(BcHistory *h) { * space. Basically, this is what happens with the "Backspace" keyboard key. * @param h The history data. */ -static void bc_history_edit_backspace(BcHistory *h) { - +static void +bc_history_edit_backspace(BcHistory* h) +{ size_t chlen, len = BC_HIST_BUF_LEN(h); BC_SIG_ASSERT_LOCKED; @@ -1058,8 +1389,9 @@ static void bc_history_edit_backspace(BcHistory *h) { * current word. * @param h The history data. */ -static void bc_history_edit_deletePrevWord(BcHistory *h) { - +static void +bc_history_edit_deletePrevWord(BcHistory* h) +{ size_t diff, old_pos = h->pos; BC_SIG_ASSERT_LOCKED; @@ -1068,8 +1400,14 @@ static void bc_history_edit_deletePrevWord(BcHistory *h) { if (!old_pos) return; // Find the word, then the beginning of the word. - while (h->pos > 0 && isspace(h->buf.v[h->pos - 1])) --h->pos; - while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1])) --h->pos; + while (h->pos > 0 && isspace(h->buf.v[h->pos - 1])) + { + h->pos -= 1; + } + while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1])) + { + h->pos -= 1; + } // Get the difference in position. diff = old_pos - h->pos; @@ -1088,8 +1426,9 @@ static void bc_history_edit_deletePrevWord(BcHistory *h) { * Deletes the next word, maintaining the cursor at the same position. * @param h The history data. */ -static void bc_history_edit_deleteNextWord(BcHistory *h) { - +static void +bc_history_edit_deleteNextWord(BcHistory* h) +{ size_t next_end = h->pos, len = BC_HIST_BUF_LEN(h); BC_SIG_ASSERT_LOCKED; @@ -1098,8 +1437,14 @@ static void bc_history_edit_deleteNextWord(BcHistory *h) { if (next_end == len) return; // Find the word, then the end of the word. - while (next_end < len && isspace(h->buf.v[next_end])) ++next_end; - while (next_end < len && !isspace(h->buf.v[next_end])) ++next_end; + while (next_end < len && isspace(h->buf.v[next_end])) + { + next_end += 1; + } + while (next_end < len && !isspace(h->buf.v[next_end])) + { + next_end += 1; + } // Move the stuff into position. memmove(h->buf.v + h->pos, h->buf.v + next_end, len - next_end); @@ -1114,13 +1459,17 @@ static void bc_history_edit_deleteNextWord(BcHistory *h) { * Swaps two characters, the one under the cursor and the one to the left. * @param h The history data. */ -static void bc_history_swap(BcHistory *h) { - +static void +bc_history_swap(BcHistory* h) +{ size_t pcl, ncl; char auxb[5]; BC_SIG_ASSERT_LOCKED; + // If there are no characters, skip. + if (!h->pos) return; + // Get the length of the previous and next characters. pcl = bc_history_prevLen(h->buf.v, h->pos); ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL); @@ -1128,8 +1477,8 @@ static void bc_history_swap(BcHistory *h) { // To perform a swap we need: // * Nonzero char length to the left. // * To not be at the end of the line. - if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5) { - + if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5) + { // Swap. memcpy(auxb, h->buf.v + h->pos - pcl, pcl); memcpy(h->buf.v + h->pos - pcl, h->buf.v + h->pos, ncl); @@ -1147,8 +1496,9 @@ static void bc_history_swap(BcHistory *h) { * @param h The history data. * @param sig The signal to raise. */ -static void bc_history_raise(BcHistory *h, int sig) { - +static void +bc_history_raise(BcHistory* h, int sig) +{ // We really don't want to be in raw mode when longjmp()'s are flying. bc_history_disableRaw(h); raise(sig); @@ -1159,8 +1509,9 @@ static void bc_history_raise(BcHistory *h, int sig) { * escape codes; otherwise, it will be confusing. * @param h The history data. */ -static void bc_history_escape(BcHistory *h) { - +static void +bc_history_escape(BcHistory* h) +{ char c, seq[3]; BC_SIG_ASSERT_LOCKED; @@ -1171,44 +1522,78 @@ static void bc_history_escape(BcHistory *h) { c = seq[0]; // ESC ? sequences. - if (c != '[' && c != 'O') { + if (c != '[' && c != 'O') + { if (c == 'f') bc_history_edit_wordEnd(h); else if (c == 'b') bc_history_edit_wordStart(h); else if (c == 'd') bc_history_edit_deleteNextWord(h); } - else { - + else + { // Read a character into seq. if (BC_ERR(BC_HIST_READ(seq + 1, 1))) + { bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } // ESC [ sequences. - if (c == '[') { - + if (c == '[') + { c = seq[1]; - if (c >= '0' && c <= '9') { - + if (c >= '0' && c <= '9') + { // Extended escape, read additional byte. if (BC_ERR(BC_HIST_READ(seq + 2, 1))) + { bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } - if (seq[2] == '~' && c == '3') bc_history_edit_delete(h); - else if(seq[2] == ';') { - + if (seq[2] == '~') + { + switch (c) + { + case '1': + { + bc_history_edit_home(h); + break; + } + + case '3': + { + bc_history_edit_delete(h); + break; + } + + case '4': + { + bc_history_edit_end(h); + break; + } + + default: + { + break; + } + } + } + else if (seq[2] == ';') + { // Read two characters into seq. if (BC_ERR(BC_HIST_READ(seq, 2))) + { bc_vm_fatalError(BC_ERR_FATAL_IO_ERR); + } if (seq[0] != '5') return; else if (seq[1] == 'C') bc_history_edit_wordEnd(h); else if (seq[1] == 'D') bc_history_edit_wordStart(h); } } - else { - - switch(c) { - + else + { + switch (c) + { // Up. case 'A': { @@ -1262,10 +1647,10 @@ static void bc_history_escape(BcHistory *h) { } } // ESC O sequences. - else { - - switch (seq[1]) { - + else + { + switch (seq[1]) + { case 'A': { bc_history_edit_next(h, BC_HIST_PREV); @@ -1311,18 +1696,20 @@ static void bc_history_escape(BcHistory *h) { * @param h The history data. * @param line The line to add. */ -static void bc_history_add(BcHistory *h, char *line) { - +static void +bc_history_add(BcHistory* h, char* line) +{ BC_SIG_ASSERT_LOCKED; // If there is something already there... - if (h->history.len) { - + if (h->history.len) + { // Get the previous. - char *s = *((char**) bc_vec_item_rev(&h->history, 0)); + char* s = *((char**) bc_vec_item_rev(&h->history, 0)); // Check for, and discard, duplicates. - if (!strcmp(s, line)) { + if (!strcmp(s, line)) + { free(line); return; } @@ -1336,17 +1723,18 @@ static void bc_history_add(BcHistory *h, char *line) { * because we don't want it allocating. * @param h The history data. */ -static void bc_history_add_empty(BcHistory *h) { +static void +bc_history_add_empty(BcHistory* h) +{ + const char* line = ""; BC_SIG_ASSERT_LOCKED; - const char *line = ""; - // If there is something already there... - if (h->history.len) { - + if (h->history.len) + { // Get the previous. - char *s = *((char**) bc_vec_item_rev(&h->history, 0)); + char* s = *((char**) bc_vec_item_rev(&h->history, 0)); // Check for, and discard, duplicates. if (!s[0]) return; @@ -1359,8 +1747,9 @@ static void bc_history_add_empty(BcHistory *h) { * Resets the history state to nothing. * @param h The history data. */ -static void bc_history_reset(BcHistory *h) { - +static void +bc_history_reset(BcHistory* h) +{ BC_SIG_ASSERT_LOCKED; h->oldcolpos = h->pos = h->idx = 0; @@ -1379,10 +1768,11 @@ static void bc_history_reset(BcHistory *h) { * @param h The history data. * @param c The control character to print. */ -static void bc_history_printCtrl(BcHistory *h, unsigned int c) { - - char str[3] = "^A"; - const char newline[2] = "\n"; +static void +bc_history_printCtrl(BcHistory* h, unsigned int c) +{ + char str[3] = { '^', 'A', '\0' }; + const char newline[2] = { '\n', '\0' }; BC_SIG_ASSERT_LOCKED; @@ -1392,19 +1782,19 @@ static void bc_history_printCtrl(BcHistory *h, unsigned int c) { // Concatenate the string. bc_vec_concat(&h->buf, str); + h->pos = BC_HIST_BUF_LEN(h); bc_history_refresh(h); // Pop the string. bc_vec_npop(&h->buf, sizeof(str)); bc_vec_pushByte(&h->buf, '\0'); + h->pos = 0; -#ifndef _WIN32 if (c != BC_ACTION_CTRL_C && c != BC_ACTION_CTRL_D) -#endif // _WIN32 { // We sometimes want to print a newline; for the times we don't; it's // because newlines are taken care of elsewhere. - bc_file_write(&vm.fout, bc_flush_none, newline, sizeof(newline) - 1); + bc_file_write(&vm->fout, bc_flush_none, newline, sizeof(newline) - 1); bc_history_refresh(h); } } @@ -1417,8 +1807,9 @@ static void bc_history_printCtrl(BcHistory *h, unsigned int c) { * @param prompt The prompt. * @return BC_STATUS_SUCCESS or BC_STATUS_EOF. */ -static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { - +static BcStatus +bc_history_edit(BcHistory* h, const char* prompt) +{ BC_SIG_LOCK; bc_history_reset(h); @@ -1426,22 +1817,22 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { // Don't write the saved output the first time. This is because it has // already been written to output. In other words, don't uncomment the // line below or add anything like it. - // bc_file_write(&vm.fout, bc_flush_none, h->extras.v, h->extras.len - 1); + // bc_file_write(&vm->fout, bc_flush_none, h->extras.v, h->extras.len - 1); // Write the prompt if desired. - if (BC_PROMPT) { - + if (BC_PROMPT) + { h->prompt = prompt; h->plen = strlen(prompt); h->pcol = bc_history_promptColLen(prompt, h->plen); - bc_file_write(&vm.fout, bc_flush_none, prompt, h->plen); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_write(&vm->fout, bc_flush_none, prompt, h->plen); + bc_file_flush(&vm->fout, bc_flush_none); } // This is the input loop. - for (;;) { - + for (;;) + { BcStatus s; char cbuf[32]; unsigned int c = 0; @@ -1455,8 +1846,8 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { BC_SIG_LOCK; - switch (c) { - + switch (c) + { case BC_ACTION_LINE_FEED: case BC_ACTION_ENTER: { @@ -1474,28 +1865,27 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { break; } -#ifndef _WIN32 case BC_ACTION_CTRL_C: { bc_history_printCtrl(h, c); // Quit if the user wants it. - if (!BC_SIGINT) { - vm.status = BC_STATUS_QUIT; + if (!BC_SIGINT) + { + vm->status = BC_STATUS_QUIT; BC_SIG_UNLOCK; BC_JMP; } // Print the ready message. - bc_file_write(&vm.fout, bc_flush_none, vm.sigmsg, vm.siglen); - bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg, + bc_file_write(&vm->fout, bc_flush_none, vm->sigmsg, vm->siglen); + bc_file_write(&vm->fout, bc_flush_none, bc_program_ready_msg, bc_program_ready_msg_len); bc_history_reset(h); bc_history_refresh(h); break; } -#endif // _WIN32 case BC_ACTION_BACKSPACE: case BC_ACTION_CTRL_H: @@ -1504,15 +1894,22 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { break; } -#ifndef _WIN32 - // Act as end-of-file. + // Act as end-of-file or delete-forward-char. case BC_ACTION_CTRL_D: { - bc_history_printCtrl(h, c); - BC_SIG_UNLOCK; - return BC_STATUS_EOF; + // Act as EOF if there's no chacters, otherwise emulate Emacs + // delete next character to match historical gnu bc behavior. + if (BC_HIST_BUF_LEN(h) == 0) + { + bc_history_printCtrl(h, c); + BC_SIG_UNLOCK; + return BC_STATUS_EOF; + } + + bc_history_edit_delete(h); + + break; } -#endif // _WIN32 // Swaps current character with previous. case BC_ACTION_CTRL_T: @@ -1588,7 +1985,7 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { // Clear screen. case BC_ACTION_CTRL_L: { - bc_file_write(&vm.fout, bc_flush_none, "\x1b[H\x1b[2J", 7); + bc_file_write(&vm->fout, bc_flush_none, "\x1b[H\x1b[2J", 7); bc_history_refresh(h); break; } @@ -1612,9 +2009,11 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { if (c == BC_ACTION_CTRL_Z) bc_history_raise(h, SIGTSTP); if (c == BC_ACTION_CTRL_S) bc_history_raise(h, SIGSTOP); if (c == BC_ACTION_CTRL_BSLASH) + { bc_history_raise(h, SIGQUIT); + } #else // _WIN32 - vm.status = BC_STATUS_QUIT; + vm->status = BC_STATUS_QUIT; BC_SIG_UNLOCK; BC_JMP; #endif // _WIN32 @@ -1636,7 +2035,9 @@ static BcStatus bc_history_edit(BcHistory *h, const char *prompt) { * does not work on Windows. * @param h The history data. */ -static inline bool bc_history_stdinHasData(BcHistory *h) { +static inline bool +bc_history_stdinHasData(BcHistory* h) +{ #ifndef _WIN32 int n; return pselect(1, &h->rdset, NULL, NULL, &h->ts, &h->sigmask) > 0 || @@ -1646,29 +2047,30 @@ static inline bool bc_history_stdinHasData(BcHistory *h) { #endif // _WIN32 } -BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt) { - +BcStatus +bc_history_line(BcHistory* h, BcVec* vec, const char* prompt) +{ BcStatus s; char* line; - assert(vm.fout.len == 0); + assert(vm->fout.len == 0); bc_history_enableRaw(h); - do { - + do + { // Do the edit. s = bc_history_edit(h, prompt); // Print a newline and flush. - bc_file_write(&vm.fout, bc_flush_none, "\n", 1); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_write(&vm->fout, bc_flush_none, "\n", 1); + bc_file_flush(&vm->fout, bc_flush_none); BC_SIG_LOCK; // If we actually have data... - if (h->buf.v[0]) { - + if (h->buf.v[0]) + { // Duplicate it. line = bc_vm_strdup(h->buf.v); @@ -1683,8 +2085,8 @@ BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt) { // Concatenate the line to the return vector. bc_vec_concat(vec, h->buf.v); bc_vec_concat(vec, "\n"); - - } while (!s && bc_history_stdinHasData(h)); + } + while (!s && bc_history_stdinHasData(h)); assert(!s || s == BC_STATUS_EOF); @@ -1693,13 +2095,17 @@ BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt) { return s; } -void bc_history_string_free(void *str) { - char *s = *((char**) str); +void +bc_history_string_free(void* str) +{ + char* s = *((char**) str); BC_SIG_ASSERT_LOCKED; if (s[0]) free(s); } -void bc_history_init(BcHistory *h) { +void +bc_history_init(BcHistory* h) +{ #ifdef _WIN32 HANDLE out, in; @@ -1710,6 +2116,9 @@ void bc_history_init(BcHistory *h) { h->rawMode = false; h->badTerm = bc_history_isBadTerm(); + // Just don't initialize with a bad terminal. + if (h->badTerm) return; + #ifdef _WIN32 h->orig_in = 0; @@ -1718,25 +2127,38 @@ void bc_history_init(BcHistory *h) { in = GetStdHandle(STD_INPUT_HANDLE); out = GetStdHandle(STD_OUTPUT_HANDLE); - if (!h->badTerm) { - SetConsoleCP(CP_UTF8); - SetConsoleOutputCP(CP_UTF8); - if (!GetConsoleMode(in, &h->orig_in) || - !GetConsoleMode(out, &h->orig_out)) + // Set the code pages. + SetConsoleCP(CP_UTF8); + SetConsoleOutputCP(CP_UTF8); + + // Get the original modes. + if (!GetConsoleMode(in, &h->orig_in) || !GetConsoleMode(out, &h->orig_out)) + { + // Just mark it as a bad terminal on error. + h->badTerm = true; + return; + } + else + { + // Set the new modes. + DWORD reqOut = h->orig_out | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + DWORD reqIn = h->orig_in | ENABLE_VIRTUAL_TERMINAL_INPUT; + + // The input handle requires turning *off* some modes. That's why + // history didn't work before; I didn't read the documentation + // closely enough to see that most modes were automaticall enabled, + // and they need to be turned off. + reqOut |= DISABLE_NEWLINE_AUTO_RETURN | ENABLE_PROCESSED_OUTPUT; + reqIn &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT); + reqIn &= ~(ENABLE_PROCESSED_INPUT); + + // Set the modes; if there was an error, assume a bad terminal and + // quit. + if (!SetConsoleMode(in, reqIn) || !SetConsoleMode(out, reqOut)) { h->badTerm = true; return; } - else { - DWORD reqOut = ENABLE_VIRTUAL_TERMINAL_PROCESSING | - DISABLE_NEWLINE_AUTO_RETURN; - DWORD reqIn = ENABLE_VIRTUAL_TERMINAL_INPUT; - if (!SetConsoleMode(in, h->orig_in | reqIn) || - !SetConsoleMode(out, h->orig_out | reqOut)) - { - h->badTerm = true; - } - } } #endif // _WIN32 @@ -1755,7 +2177,9 @@ void bc_history_init(BcHistory *h) { #endif // _WIN32 } -void bc_history_free(BcHistory *h) { +void +bc_history_free(BcHistory* h) +{ BC_SIG_ASSERT_LOCKED; #ifndef _WIN32 bc_history_disableRaw(h); @@ -1763,11 +2187,11 @@ void bc_history_free(BcHistory *h) { SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), h->orig_in); SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), h->orig_out); #endif // _WIN32 -#ifndef NDEBUG +#if BC_DEBUG bc_vec_free(&h->buf); bc_vec_free(&h->history); bc_vec_free(&h->extras); -#endif // NDEBUG +#endif // BC_DEBUG } #if BC_DEBUG_CODE @@ -1777,8 +2201,9 @@ void bc_history_free(BcHistory *h) { * scan codes on screen for debugging / development purposes. * @param h The history data. */ -void bc_history_printKeyCodes(BcHistory *h) { - +void +bc_history_printKeyCodes(BcHistory* h) +{ char quit[4]; bc_vm_printf("Linenoise key codes debugging mode.\n" @@ -1788,8 +2213,8 @@ void bc_history_printKeyCodes(BcHistory *h) { bc_history_enableRaw(h); memset(quit, ' ', 4); - while(true) { - + while (true) + { char c; ssize_t nread; @@ -1803,12 +2228,12 @@ void bc_history_printKeyCodes(BcHistory *h) { quit[sizeof(quit) - 1] = c; if (!memcmp(quit, "quit", sizeof(quit))) break; - bc_vm_printf("'%c' %lu (type quit to exit)\n", - isprint(c) ? c : '?', (unsigned long) c); + bc_vm_printf("'%c' %lu (type quit to exit)\n", isprint(c) ? c : '?', + (unsigned long) c); // Go left edge manually, we are in raw mode. bc_vm_putchar('\r', bc_flush_none); - bc_file_flush(&vm.fout, bc_flush_none); + bc_file_flush(&vm->fout, bc_flush_none); } bc_history_disableRaw(h); @@ -1816,3 +2241,7 @@ void bc_history_printKeyCodes(BcHistory *h) { #endif // BC_DEBUG_CODE #endif // BC_ENABLE_HISTORY + +#endif // BC_ENABLE_READLINE + +#endif // BC_ENABLE_EDITLINE |