2 * *****************************************************************************
4 * SPDX-License-Identifier: BSD-2-Clause
6 * Copyright (c) 2018-2023 Gavin D. Howard and contributors.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice, this
12 * list of conditions and the following disclaimer.
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.
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.
30 * *****************************************************************************
32 * Adapted from the following:
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.
37 * You can find the original source code at:
38 * http://github.com/antirez/linenoise
40 * You can find the fork that this code is based on at:
41 * https://github.com/rain-1/linenoise-mob
43 * ------------------------------------------------------------------------
45 * This code is also under the following license:
47 * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
48 * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
50 * Redistribution and use in source and binary forms, with or without
51 * modification, are permitted provided that the following conditions are
54 * * Redistributions of source code must retain the above copyright
55 * notice, this list of conditions and the following disclaimer.
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.
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.
73 * ------------------------------------------------------------------------
75 * Does a number of crazy assumptions that happen to be true in 99.9999% of
76 * the 2010 UNIX computers around.
79 * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
80 * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
83 * - Filter bogus Ctrl+<char> combinations.
87 * - History search like Ctrl+r in readline?
89 * List of escape sequences used by this program, we do everything just
90 * with three sequences. In order to be so cheap we may have some
91 * flickering effect with some slow terminal, but the lesser sequences
92 * the more compatible.
96 * Effect: if n is 0 or missing, clear from cursor to end of line
97 * Effect: if n is 1, clear from beginning of line to cursor
98 * Effect: if n is 2, clear entire line
100 * CUF (CUrsor Forward)
101 * Sequence: ESC [ n C
102 * Effect: moves cursor forward n chars
104 * CUB (CUrsor Backward)
105 * Sequence: ESC [ n D
106 * Effect: moves cursor backward n chars
108 * The following is used to get the terminal width if getting
109 * the width with the TIOCGWINSZ ioctl fails
111 * DSR (Device Status Report)
112 * Sequence: ESC [ 6 n
113 * Effect: reports the current cusor position as ESC [ n ; m R
114 * where n is the row and m is the column
116 * When multi line mode is enabled, we also use two additional escape
117 * sequences. However multi line editing is disabled by default.
120 * Sequence: ESC [ n A
121 * Effect: moves cursor up of n chars.
124 * Sequence: ESC [ n B
125 * Effect: moves cursor down of n chars.
127 * When bc_history_clearScreen() is called, two additional escape sequences
128 * are used in order to clear the screen and position the cursor at home
131 * CUP (CUrsor Position)
133 * Effect: moves the cursor to upper left corner
136 * Sequence: ESC [ 2 J
137 * Effect: clear the whole screen
139 * *****************************************************************************
141 * Code for line history.
145 #if BC_ENABLE_HISTORY
147 #if BC_ENABLE_EDITLINE
156 sigjmp_buf bc_history_jmpbuf;
157 volatile sig_atomic_t bc_history_inlinelib;
159 static char* bc_history_prompt;
160 static char bc_history_no_prompt[] = "";
161 static HistEvent bc_history_event;
162 static bool bc_history_use_prompt;
165 bc_history_promptFunc(EditLine* el)
168 return BC_PROMPT && bc_history_use_prompt ? bc_history_prompt :
169 bc_history_no_prompt;
173 bc_history_init(BcHistory* h)
178 home = getenv("HOME");
180 // This will hold the true path to the editrc.
181 bc_vec_init(&v, 1, BC_DTOR_NONE);
183 // Initialize the path to the editrc. This is done manually because the
184 // libedit I used to test was failing with a NULL argument for the path,
185 // which was supposed to automatically do $HOME/.editrc. But it was failing,
186 // so I set it manually.
189 bc_vec_string(&v, bc_history_editrc_len - 1, bc_history_editrc + 1);
193 bc_vec_string(&v, strlen(home), home);
194 bc_vec_concat(&v, bc_history_editrc);
197 h->hist = history_init();
198 if (BC_ERR(h->hist == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
200 h->el = el_init(vm->name, stdin, stdout, stderr);
201 if (BC_ERR(h->el == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
203 // I want history and a prompt.
204 history(h->hist, &bc_history_event, H_SETSIZE, 100);
205 history(h->hist, &bc_history_event, H_SETUNIQUE, 1);
206 el_set(h->el, EL_EDITOR, "emacs");
207 el_set(h->el, EL_HIST, history, h->hist);
208 el_set(h->el, EL_PROMPT, bc_history_promptFunc);
210 // I also want to get the user's .editrc.
211 el_source(h->el, v.v);
216 bc_history_prompt = NULL;
220 bc_history_free(BcHistory* h)
222 if (BC_PROMPT && bc_history_prompt != NULL) free(bc_history_prompt);
224 history_end(h->hist);
228 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
230 BcStatus s = BC_STATUS_SUCCESS;
236 // If the jump happens here, then a SIGINT occurred.
237 if (sigsetjmp(bc_history_jmpbuf, 0))
239 bc_vec_string(vec, 1, "\n");
243 // This is so the signal handler can handle line libraries properly.
244 bc_history_inlinelib = 1;
248 // Make sure to set the prompt.
249 if (bc_history_prompt != NULL)
251 if (strcmp(bc_history_prompt, prompt))
253 free(bc_history_prompt);
254 bc_history_prompt = bc_vm_strdup(prompt);
257 else bc_history_prompt = bc_vm_strdup(prompt);
260 bc_history_use_prompt = true;
267 while (line == NULL && len == -1 && errno == EINTR)
269 line = el_gets(h->el, &len);
270 bc_history_use_prompt = false;
273 // If there is no line...
274 if (BC_ERR(line == NULL))
276 // If this is true, there was an error. Otherwise, it's just EOF.
279 if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
280 bc_err(BC_ERR_FATAL_IO_ERR);
284 bc_file_printf(&vm->fout, "\n");
288 // If there is a line...
291 bc_vec_string(vec, strlen(line), line);
293 if (strcmp(line, "") && strcmp(line, "\n"))
295 history(h->hist, &bc_history_event, H_ENTER, line);
298 s = BC_STATUS_SUCCESS;
303 bc_history_inlinelib = 0;
310 #else // BC_ENABLE_EDITLINE
312 #if BC_ENABLE_READLINE
321 sigjmp_buf bc_history_jmpbuf;
322 volatile sig_atomic_t bc_history_inlinelib;
325 bc_history_init(BcHistory* h)
330 // I want no tab completion.
331 rl_bind_key('\t', rl_insert);
335 bc_history_free(BcHistory* h)
337 if (h->line != NULL) free(h->line);
341 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
343 BcStatus s = BC_STATUS_SUCCESS;
348 // If the jump happens here, then a SIGINT occurred.
349 if (sigsetjmp(bc_history_jmpbuf, 0))
351 bc_vec_string(vec, 1, "\n");
355 // This is so the signal handler can handle line libraries properly.
356 bc_history_inlinelib = 1;
358 // Get rid of the last line.
366 h->line = readline(BC_PROMPT ? prompt : "");
368 // If there was a line, add it to the history. Otherwise, just return an
369 // empty line. Oh, and NULL actually means EOF.
370 if (h->line != NULL && h->line[0])
372 add_history(h->line);
374 len = strlen(h->line);
376 bc_vec_expand(vec, len + 2);
378 bc_vec_string(vec, len, h->line);
379 bc_vec_concat(vec, "\n");
381 else if (h->line == NULL)
383 bc_file_printf(&vm->fout, "%s\n", "^D");
386 else bc_vec_string(vec, 1, "\n");
390 bc_history_inlinelib = 0;
397 #else // BC_ENABLE_READLINE
406 #include <sys/stat.h>
407 #include <sys/types.h>
413 #include <sys/ioctl.h>
414 #include <sys/select.h>
426 /// A file for outputting to when debugging.
427 BcFile bc_history_debug_fp;
429 /// A buffer for the above file.
430 char* bc_history_debug_buf;
432 #endif // BC_DEBUG_CODE
435 * Checks if the code is a wide character.
436 * @param cp The codepoint to check.
437 * @return True if @a cp is a wide character, false otherwise.
440 bc_history_wchar(uint32_t cp)
444 for (i = 0; i < bc_history_wchars_len; ++i)
446 // Ranges are listed in ascending order. Therefore, once the
447 // whole range is higher than the codepoint we're testing, the
448 // codepoint won't be found in any remaining range => bail early.
449 if (bc_history_wchars[i][0] > cp) return false;
452 if (bc_history_wchars[i][0] <= cp && cp <= bc_history_wchars[i][1])
462 * Checks if the code is a combining character.
463 * @param cp The codepoint to check.
464 * @return True if @a cp is a combining character, false otherwise.
467 bc_history_comboChar(uint32_t cp)
471 for (i = 0; i < bc_history_combo_chars_len; ++i)
473 // Combining chars are listed in ascending order, so once we pass
474 // the codepoint of interest, we know it's not a combining char.
475 if (bc_history_combo_chars[i] > cp) return false;
476 if (bc_history_combo_chars[i] == cp) return true;
483 * Gets the length of previous UTF8 character.
484 * @param buf The buffer of characters.
485 * @param pos The index into the buffer.
488 bc_history_prevCharLen(const char* buf, size_t pos)
491 for (pos -= 1; pos < end && (buf[pos] & 0xC0) == 0x80; --pos)
495 return end - (pos >= end ? 0 : pos);
499 * Converts UTF-8 to a Unicode code point.
500 * @param s The string.
501 * @param len The length of the string.
502 * @param cp An out parameter for the codepoint.
503 * @return The number of bytes eaten by the codepoint.
506 bc_history_codePoint(const char* s, size_t len, uint32_t* cp)
510 uchar byte = (uchar) s[0];
512 // This is literally the UTF-8 decoding algorithm. Look that up if you
513 // don't understand this.
515 if ((byte & 0x80) == 0)
520 else if ((byte & 0xE0) == 0xC0)
524 *cp = (((uint32_t) (s[0] & 0x1F)) << 6) |
525 ((uint32_t) (s[1] & 0x3F));
529 else if ((byte & 0xF0) == 0xE0)
533 *cp = (((uint32_t) (s[0] & 0x0F)) << 12) |
534 (((uint32_t) (s[1] & 0x3F)) << 6) |
535 ((uint32_t) (s[2] & 0x3F));
539 else if ((byte & 0xF8) == 0xF0)
543 *cp = (((uint32_t) (s[0] & 0x07)) << 18) |
544 (((uint32_t) (s[1] & 0x3F)) << 12) |
545 (((uint32_t) (s[2] & 0x3F)) << 6) |
546 ((uint32_t) (s[3] & 0x3F));
563 * Gets the length of next grapheme.
564 * @param buf The buffer.
565 * @param buf_len The length of the buffer.
566 * @param pos The index into the buffer.
567 * @param col_len An out parameter for the length of the grapheme on screen.
568 * @return The number of bytes in the grapheme.
571 bc_history_nextLen(const char* buf, size_t buf_len, size_t pos, size_t* col_len)
575 size_t len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
577 if (bc_history_comboChar(cp))
582 if (col_len != NULL) *col_len = 0;
588 // Store the width of the character on screen.
589 if (col_len != NULL) *col_len = bc_history_wchar(cp) ? 2 : 1;
593 // Find the first non-combining character.
594 while (pos < buf_len)
596 len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
598 if (!bc_history_comboChar(cp)) return pos - beg;
607 * Gets the length of previous grapheme.
608 * @param buf The buffer.
609 * @param pos The index into the buffer.
610 * @return The number of bytes in the grapheme.
613 bc_history_prevLen(const char* buf, size_t pos)
617 // Find the first non-combining character.
621 size_t len = bc_history_prevCharLen(buf, pos);
624 bc_history_codePoint(buf + pos, len, &cp);
626 // The original linenoise-mob had an extra parameter col_len, like
627 // bc_history_nextLen(), which, if not NULL, was set in this if
628 // statement. However, we always passed NULL, so just skip that.
629 if (!bc_history_comboChar(cp)) return end - pos;
640 * Reads @a n characters from stdin.
641 * @param buf The buffer to read into. The caller is responsible for making
642 * sure this is big enough for @a n.
643 * @param n The number of characters to read.
644 * @return The number of characters read or less than 0 on error.
647 bc_history_read(char* buf, size_t n)
651 BC_SIG_ASSERT_LOCKED;
657 // We don't care about being interrupted.
658 ret = read(STDIN_FILENO, buf, n);
660 while (ret == EINTR);
666 HANDLE hn = GetStdHandle(STD_INPUT_HANDLE);
668 good = ReadConsole(hn, buf, (DWORD) n, &read, NULL);
670 ret = (read != n || !good) ? -1 : 1;
678 * Reads a Unicode code point into a buffer.
679 * @param buf The buffer to read into.
680 * @param buf_len The length of the buffer.
681 * @param cp An out parameter for the codepoint.
682 * @param nread An out parameter for the number of bytes read.
683 * @return BC_STATUS_EOF or BC_STATUS_SUCCESS.
686 bc_history_readCode(char* buf, size_t buf_len, uint32_t* cp, size_t* nread)
691 assert(buf_len >= 1);
696 n = bc_history_read(buf, 1);
700 if (BC_ERR(n <= 0)) goto err;
703 byte = ((uchar*) buf)[0];
705 // Once again, this is the UTF-8 decoding algorithm, but it has reads
706 // instead of actual decoding.
707 if ((byte & 0x80) != 0)
709 if ((byte & 0xE0) == 0xC0)
711 assert(buf_len >= 2);
715 n = bc_history_read(buf + 1, 1);
719 if (BC_ERR(n <= 0)) goto err;
721 else if ((byte & 0xF0) == 0xE0)
723 assert(buf_len >= 3);
727 n = bc_history_read(buf + 1, 2);
731 if (BC_ERR(n <= 0)) goto err;
733 else if ((byte & 0xF8) == 0xF0)
735 assert(buf_len >= 3);
739 n = bc_history_read(buf + 1, 3);
743 if (BC_ERR(n <= 0)) goto err;
752 // Convert to the codepoint.
753 *nread = bc_history_codePoint(buf, buf_len, cp);
755 return BC_STATUS_SUCCESS;
758 // If we get here, we either had a fatal error of EOF.
759 if (BC_ERR(n < 0)) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
760 else *nread = (size_t) n;
761 return BC_STATUS_EOF;
765 * Gets the column length from beginning of buffer to current byte position.
766 * @param buf The buffer.
767 * @param buf_len The length of the buffer.
768 * @param pos The index into the buffer.
769 * @return The number of columns between the beginning of @a buffer to
773 bc_history_colPos(const char* buf, size_t buf_len, size_t pos)
775 size_t ret = 0, off = 0;
777 // While we haven't reached the offset, get the length of the next grapheme.
778 while (off < pos && off < buf_len)
782 len = bc_history_nextLen(buf, buf_len, off, &col_len);
792 * Returns true if the terminal name is in the list of terminals we know are
793 * not able to understand basic escape sequences.
794 * @return True if the terminal is a bad terminal.
797 bc_history_isBadTerm(void)
801 char* term = bc_vm_getenv("TERM");
803 if (term == NULL) return false;
805 for (i = 0; !ret && bc_history_bad_terms[i]; ++i)
807 ret = (!strcasecmp(term, bc_history_bad_terms[i]));
810 bc_vm_getenvFree(term);
816 * Enables raw mode (1960's black magic).
817 * @param h The history data.
820 bc_history_enableRaw(BcHistory* h)
822 // I don't do anything for Windows because in Windows, you set their
823 // equivalent of raw mode and leave it, so I do it in bc_history_init().
831 if (h->rawMode) return;
835 if (BC_ERR(tcgetattr(STDIN_FILENO, &h->orig_termios) == -1))
837 bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
842 // Modify the original mode.
843 raw = h->orig_termios;
845 // Input modes: no break, no CR to NL, no parity check, no strip char,
846 // no start/stop output control.
847 raw.c_iflag &= (unsigned int) (~(BRKINT | ICRNL | INPCK | ISTRIP | IXON));
849 // Control modes: set 8 bit chars.
850 raw.c_cflag |= (CS8);
852 // Local modes - choing off, canonical off, no extended functions,
853 // no signal chars (^Z,^C).
854 raw.c_lflag &= (unsigned int) (~(ECHO | ICANON | IEXTEN | ISIG));
856 // Control chars - set return condition: min number of bytes and timer.
857 // We want read to give every single byte, w/o timeout (1 byte, no timer).
863 // Put terminal in raw mode after flushing.
866 err = tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
868 while (BC_ERR(err < 0) && errno == EINTR);
872 if (BC_ERR(err < 0)) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
880 * @param h The history data.
883 bc_history_disableRaw(BcHistory* h)
887 if (!h->rawMode) return;
889 BC_SIG_TRYLOCK(lock);
892 if (BC_ERR(tcsetattr(STDIN_FILENO, TCSAFLUSH, &h->orig_termios) != -1))
898 BC_SIG_TRYUNLOCK(lock);
902 * Uses the ESC [6n escape sequence to query the horizontal cursor position
903 * and return it. On error -1 is returned, on success the position of the
905 * @return The horizontal cursor position.
908 bc_history_cursorPos(void)
910 char buf[BC_HIST_SEQ_SIZE];
913 size_t cols, rows, i;
915 BC_SIG_ASSERT_LOCKED;
917 // Report cursor location.
918 bc_file_write(&vm->fout, bc_flush_none, "\x1b[6n", 4);
919 bc_file_flush(&vm->fout, bc_flush_none);
921 // Read the response: ESC [ rows ; cols R.
922 for (i = 0; i < sizeof(buf) - 1; ++i)
924 if (bc_history_read(buf + i, 1) != 1 || buf[i] == 'R') break;
929 // This is basically an error; we didn't get what we were expecting.
930 if (BC_ERR(buf[0] != BC_ACTION_ESC || buf[1] != '[')) return SIZE_MAX;
934 rows = strtoul(ptr, &ptr2, 10);
936 // Here we also didn't get what we were expecting.
937 if (BC_ERR(!rows || ptr2[0] != ';')) return SIZE_MAX;
939 // Parse the columns.
941 cols = strtoul(ptr, NULL, 10);
943 if (BC_ERR(!cols)) return SIZE_MAX;
945 return cols <= UINT16_MAX ? cols : 0;
949 * Tries to get the number of columns in the current terminal, or assume 80
951 * @return The number of columns in the terminal.
954 bc_history_columns(void)
962 ret = ioctl(vm->fout.fd, TIOCGWINSZ, &ws);
964 if (BC_ERR(ret == -1 || !ws.ws_col))
966 // Calling ioctl() failed. Try to query the terminal itself.
969 // Get the initial position so we can restore it later.
970 start = bc_history_cursorPos();
971 if (BC_ERR(start == SIZE_MAX)) return BC_HIST_DEF_COLS;
973 // Go to right margin and get position.
974 bc_file_write(&vm->fout, bc_flush_none, "\x1b[999C", 6);
975 bc_file_flush(&vm->fout, bc_flush_none);
976 cols = bc_history_cursorPos();
977 if (BC_ERR(cols == SIZE_MAX)) return BC_HIST_DEF_COLS;
982 bc_file_printf(&vm->fout, "\x1b[%zuD", cols - start);
983 bc_file_flush(&vm->fout, bc_flush_none);
993 CONSOLE_SCREEN_BUFFER_INFO csbi;
995 if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
1000 return ((size_t) (csbi.srWindow.Right)) - csbi.srWindow.Left + 1;
1006 * Gets the column length of prompt text. This is probably unnecessary because
1007 * the prompts that I use are ASCII, but I kept it just in case.
1008 * @param prompt The prompt.
1009 * @param plen The length of the prompt.
1010 * @return The column length of the prompt.
1013 bc_history_promptColLen(const char* prompt, size_t plen)
1015 char buf[BC_HIST_MAX_LINE + 1];
1016 size_t buf_len = 0, off = 0;
1018 // The original linenoise-mob checked for ANSI escapes here on the prompt. I
1019 // know the prompts do not have ANSI escapes. I deleted the code.
1022 buf[buf_len++] = prompt[off++];
1025 return bc_history_colPos(buf, buf_len, buf_len);
1029 * Rewrites the currently edited line accordingly to the buffer content,
1030 * cursor position, and number of columns of the terminal.
1031 * @param h The history data.
1034 bc_history_refresh(BcHistory* h)
1036 char* buf = h->buf.v;
1037 size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0;
1039 BC_SIG_ASSERT_LOCKED;
1041 bc_file_flush(&vm->fout, bc_flush_none);
1043 // Get to the prompt column position from the left.
1044 while (h->pcol + bc_history_colPos(buf, len, pos) >= h->cols)
1046 size_t chlen = bc_history_nextLen(buf, len, 0, NULL);
1053 // Get to the prompt column position from the right.
1054 while (h->pcol + bc_history_colPos(buf, len, len) > h->cols)
1056 len -= bc_history_prevLen(buf, len);
1059 // Cursor to left edge.
1060 bc_file_write(&vm->fout, bc_flush_none, "\r", 1);
1062 // Take the extra stuff into account. This is where history makes sure to
1063 // preserve stuff that was printed without a newline.
1064 if (h->extras.len > 1)
1066 extras_len = h->extras.len - 1;
1068 bc_vec_grow(&h->buf, extras_len);
1073 bc_file_write(&vm->fout, bc_flush_none, h->extras.v, extras_len);
1076 // Write the prompt, if desired.
1077 if (BC_PROMPT) bc_file_write(&vm->fout, bc_flush_none, h->prompt, h->plen);
1079 bc_file_write(&vm->fout, bc_flush_none, h->buf.v, len - extras_len);
1082 bc_file_write(&vm->fout, bc_flush_none, "\x1b[0K", 4);
1084 // We need to be sure to grow this.
1085 if (pos >= h->buf.len - extras_len) bc_vec_grow(&h->buf, pos + extras_len);
1087 // Move cursor to original position. Do NOT move the putchar of '\r' to the
1088 // printf with colpos. That causes a bug where the cursor will go to the end
1089 // of the line when there is no prompt.
1090 bc_file_putchar(&vm->fout, bc_flush_none, '\r');
1091 colpos = bc_history_colPos(h->buf.v, len - extras_len, pos) + h->pcol;
1093 // Set the cursor position again.
1094 if (colpos) bc_file_printf(&vm->fout, "\x1b[%zuC", colpos);
1096 bc_file_flush(&vm->fout, bc_flush_none);
1100 * Inserts the character(s) 'c' at cursor current position.
1101 * @param h The history data.
1102 * @param cbuf The character buffer to copy from.
1103 * @param clen The number of characters to copy.
1106 bc_history_edit_insert(BcHistory* h, const char* cbuf, size_t clen)
1108 BC_SIG_ASSERT_LOCKED;
1110 bc_vec_grow(&h->buf, clen);
1112 // If we are at the end of the line...
1113 if (h->pos == BC_HIST_BUF_LEN(h))
1115 size_t colpos = 0, len;
1117 // Copy into the buffer.
1118 memcpy(bc_vec_item(&h->buf, h->pos), cbuf, clen);
1120 // Adjust the buffer.
1122 h->buf.len += clen - 1;
1123 bc_vec_pushByte(&h->buf, '\0');
1125 // Set the length and column position.
1126 len = BC_HIST_BUF_LEN(h) + h->extras.len - 1;
1127 colpos = bc_history_promptColLen(h->prompt, h->plen);
1128 colpos += bc_history_colPos(h->buf.v, len, len);
1130 // Do we have the trivial case?
1131 if (colpos < h->cols)
1133 // Avoid a full update of the line in the trivial case.
1134 bc_file_write(&vm->fout, bc_flush_none, cbuf, clen);
1135 bc_file_flush(&vm->fout, bc_flush_none);
1137 else bc_history_refresh(h);
1141 // Amount that we need to move.
1142 size_t amt = BC_HIST_BUF_LEN(h) - h->pos;
1145 memmove(h->buf.v + h->pos + clen, h->buf.v + h->pos, amt);
1146 memcpy(h->buf.v + h->pos, cbuf, clen);
1148 // Adjust the buffer.
1151 h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1153 bc_history_refresh(h);
1158 * Moves the cursor to the left.
1159 * @param h The history data.
1162 bc_history_edit_left(BcHistory* h)
1164 BC_SIG_ASSERT_LOCKED;
1166 // Stop at the left end.
1167 if (h->pos <= 0) return;
1169 h->pos -= bc_history_prevLen(h->buf.v, h->pos);
1171 bc_history_refresh(h);
1175 * Moves the cursor to the right.
1176 * @param h The history data.
1179 bc_history_edit_right(BcHistory* h)
1181 BC_SIG_ASSERT_LOCKED;
1183 // Stop at the right end.
1184 if (h->pos == BC_HIST_BUF_LEN(h)) return;
1186 h->pos += bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1188 bc_history_refresh(h);
1192 * Moves the cursor to the end of the current word.
1193 * @param h The history data.
1196 bc_history_edit_wordEnd(BcHistory* h)
1198 size_t len = BC_HIST_BUF_LEN(h);
1200 BC_SIG_ASSERT_LOCKED;
1203 if (!len || h->pos >= len) return;
1205 // Find the word, then find the end of it.
1206 while (h->pos < len && isspace(h->buf.v[h->pos]))
1210 while (h->pos < len && !isspace(h->buf.v[h->pos]))
1215 bc_history_refresh(h);
1219 * Moves the cursor to the start of the current word.
1220 * @param h The history data.
1223 bc_history_edit_wordStart(BcHistory* h)
1225 size_t len = BC_HIST_BUF_LEN(h);
1227 BC_SIG_ASSERT_LOCKED;
1229 // Stop with no data.
1232 // Find the word, the find the beginning of the word.
1233 while (h->pos > 0 && isspace(h->buf.v[h->pos - 1]))
1237 while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1]))
1242 bc_history_refresh(h);
1246 * Moves the cursor to the start of the line.
1247 * @param h The history data.
1250 bc_history_edit_home(BcHistory* h)
1252 BC_SIG_ASSERT_LOCKED;
1254 // Stop at the beginning.
1255 if (!h->pos) return;
1259 bc_history_refresh(h);
1263 * Moves the cursor to the end of the line.
1264 * @param h The history data.
1267 bc_history_edit_end(BcHistory* h)
1269 BC_SIG_ASSERT_LOCKED;
1271 // Stop at the end of the line.
1272 if (h->pos == BC_HIST_BUF_LEN(h)) return;
1274 h->pos = BC_HIST_BUF_LEN(h);
1276 bc_history_refresh(h);
1280 * Substitutes the currently edited line with the next or previous history
1281 * entry as specified by 'dir' (direction).
1282 * @param h The history data.
1283 * @param dir The direction to substitute; true means previous, false next.
1286 bc_history_edit_next(BcHistory* h, bool dir)
1291 BC_SIG_ASSERT_LOCKED;
1293 // Stop if there is no history.
1294 if (h->history.len <= 1) return;
1296 // Duplicate the buffer.
1297 if (h->buf.v[0]) dup = bc_vm_strdup(h->buf.v);
1300 // Update the current history entry before overwriting it with the next one.
1301 bc_vec_replaceAt(&h->history, h->history.len - 1 - h->idx, &dup);
1303 // Show the new entry.
1304 h->idx += (dir == BC_HIST_PREV ? 1 : SIZE_MAX);
1306 // Se the index appropriately at the ends.
1307 if (h->idx == SIZE_MAX)
1312 else if (h->idx >= h->history.len)
1314 h->idx = h->history.len - 1;
1319 str = *((char**) bc_vec_item(&h->history, h->history.len - 1 - h->idx));
1320 bc_vec_string(&h->buf, strlen(str), str);
1322 assert(h->buf.len > 0);
1324 // Set the position at the end.
1325 h->pos = BC_HIST_BUF_LEN(h);
1327 bc_history_refresh(h);
1331 * Deletes the character at the right of the cursor without altering the cursor
1332 * position. Basically, this is what happens with the "Delete" keyboard key.
1333 * @param h The history data.
1336 bc_history_edit_delete(BcHistory* h)
1338 size_t chlen, len = BC_HIST_BUF_LEN(h);
1340 BC_SIG_ASSERT_LOCKED;
1342 // If there is no character, skip.
1343 if (!len || h->pos >= len) return;
1345 // Get the length of the character.
1346 chlen = bc_history_nextLen(h->buf.v, len, h->pos, NULL);
1348 // Move characters after it into its place.
1349 memmove(h->buf.v + h->pos, h->buf.v + h->pos + chlen, len - h->pos - chlen);
1351 // Make the buffer valid again.
1352 h->buf.len -= chlen;
1353 h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1355 bc_history_refresh(h);
1359 * Deletes the character to the left of the cursor and moves the cursor back one
1360 * space. Basically, this is what happens with the "Backspace" keyboard key.
1361 * @param h The history data.
1364 bc_history_edit_backspace(BcHistory* h)
1366 size_t chlen, len = BC_HIST_BUF_LEN(h);
1368 BC_SIG_ASSERT_LOCKED;
1370 // If there are no characters, skip.
1371 if (!h->pos || !len) return;
1373 // Get the length of the previous character.
1374 chlen = bc_history_prevLen(h->buf.v, h->pos);
1376 // Move everything back one.
1377 memmove(h->buf.v + h->pos - chlen, h->buf.v + h->pos, len - h->pos);
1379 // Make the buffer valid again.
1381 h->buf.len -= chlen;
1382 h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1384 bc_history_refresh(h);
1388 * Deletes the previous word, maintaining the cursor at the start of the
1390 * @param h The history data.
1393 bc_history_edit_deletePrevWord(BcHistory* h)
1395 size_t diff, old_pos = h->pos;
1397 BC_SIG_ASSERT_LOCKED;
1399 // If at the beginning of the line, skip.
1400 if (!old_pos) return;
1402 // Find the word, then the beginning of the word.
1403 while (h->pos > 0 && isspace(h->buf.v[h->pos - 1]))
1407 while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1]))
1412 // Get the difference in position.
1413 diff = old_pos - h->pos;
1415 // Move the data back.
1416 memmove(h->buf.v + h->pos, h->buf.v + old_pos,
1417 BC_HIST_BUF_LEN(h) - old_pos + 1);
1419 // Make the buffer valid again.
1422 bc_history_refresh(h);
1426 * Deletes the next word, maintaining the cursor at the same position.
1427 * @param h The history data.
1430 bc_history_edit_deleteNextWord(BcHistory* h)
1432 size_t next_end = h->pos, len = BC_HIST_BUF_LEN(h);
1434 BC_SIG_ASSERT_LOCKED;
1436 // If at the end of the line, skip.
1437 if (next_end == len) return;
1439 // Find the word, then the end of the word.
1440 while (next_end < len && isspace(h->buf.v[next_end]))
1444 while (next_end < len && !isspace(h->buf.v[next_end]))
1449 // Move the stuff into position.
1450 memmove(h->buf.v + h->pos, h->buf.v + next_end, len - next_end);
1452 // Make the buffer valid again.
1453 h->buf.len -= next_end - h->pos;
1455 bc_history_refresh(h);
1459 * Swaps two characters, the one under the cursor and the one to the left.
1460 * @param h The history data.
1463 bc_history_swap(BcHistory* h)
1468 BC_SIG_ASSERT_LOCKED;
1470 // If there are no characters, skip.
1471 if (!h->pos) return;
1473 // Get the length of the previous and next characters.
1474 pcl = bc_history_prevLen(h->buf.v, h->pos);
1475 ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1477 // To perform a swap we need:
1478 // * Nonzero char length to the left.
1479 // * To not be at the end of the line.
1480 if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5)
1483 memcpy(auxb, h->buf.v + h->pos - pcl, pcl);
1484 memcpy(h->buf.v + h->pos - pcl, h->buf.v + h->pos, ncl);
1485 memcpy(h->buf.v + h->pos - pcl + ncl, auxb, pcl);
1487 // Reset the position.
1488 h->pos += ((~pcl) + 1) + ncl;
1490 bc_history_refresh(h);
1495 * Raises the specified signal. This is a convenience function.
1496 * @param h The history data.
1497 * @param sig The signal to raise.
1500 bc_history_raise(BcHistory* h, int sig)
1502 // We really don't want to be in raw mode when longjmp()'s are flying.
1503 bc_history_disableRaw(h);
1508 * Handles escape sequences. This function will make sense if you know VT100
1509 * escape codes; otherwise, it will be confusing.
1510 * @param h The history data.
1513 bc_history_escape(BcHistory* h)
1517 BC_SIG_ASSERT_LOCKED;
1519 // Read a character into seq.
1520 if (BC_ERR(BC_HIST_READ(seq, 1))) return;
1525 if (c != '[' && c != 'O')
1527 if (c == 'f') bc_history_edit_wordEnd(h);
1528 else if (c == 'b') bc_history_edit_wordStart(h);
1529 else if (c == 'd') bc_history_edit_deleteNextWord(h);
1533 // Read a character into seq.
1534 if (BC_ERR(BC_HIST_READ(seq + 1, 1)))
1536 bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1544 if (c >= '0' && c <= '9')
1546 // Extended escape, read additional byte.
1547 if (BC_ERR(BC_HIST_READ(seq + 2, 1)))
1549 bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1558 bc_history_edit_home(h);
1564 bc_history_edit_delete(h);
1570 bc_history_edit_end(h);
1580 else if (seq[2] == ';')
1582 // Read two characters into seq.
1583 if (BC_ERR(BC_HIST_READ(seq, 2)))
1585 bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1588 if (seq[0] != '5') return;
1589 else if (seq[1] == 'C') bc_history_edit_wordEnd(h);
1590 else if (seq[1] == 'D') bc_history_edit_wordStart(h);
1600 bc_history_edit_next(h, BC_HIST_PREV);
1607 bc_history_edit_next(h, BC_HIST_NEXT);
1614 bc_history_edit_right(h);
1621 bc_history_edit_left(h);
1629 bc_history_edit_home(h);
1637 bc_history_edit_end(h);
1643 bc_history_edit_deleteNextWord(h);
1656 bc_history_edit_next(h, BC_HIST_PREV);
1662 bc_history_edit_next(h, BC_HIST_NEXT);
1668 bc_history_edit_right(h);
1674 bc_history_edit_left(h);
1680 bc_history_edit_end(h);
1686 bc_history_edit_home(h);
1695 * Adds a line to the history.
1696 * @param h The history data.
1697 * @param line The line to add.
1700 bc_history_add(BcHistory* h, char* line)
1702 BC_SIG_ASSERT_LOCKED;
1704 // If there is something already there...
1707 // Get the previous.
1708 char* s = *((char**) bc_vec_item_rev(&h->history, 0));
1710 // Check for, and discard, duplicates.
1711 if (!strcmp(s, line))
1718 bc_vec_push(&h->history, &line);
1722 * Adds an empty line to the history. This is separate from bc_history_add()
1723 * because we don't want it allocating.
1724 * @param h The history data.
1727 bc_history_add_empty(BcHistory* h)
1729 const char* line = "";
1731 BC_SIG_ASSERT_LOCKED;
1733 // If there is something already there...
1736 // Get the previous.
1737 char* s = *((char**) bc_vec_item_rev(&h->history, 0));
1739 // Check for, and discard, duplicates.
1743 bc_vec_push(&h->history, &line);
1747 * Resets the history state to nothing.
1748 * @param h The history data.
1751 bc_history_reset(BcHistory* h)
1753 BC_SIG_ASSERT_LOCKED;
1755 h->oldcolpos = h->pos = h->idx = 0;
1756 h->cols = bc_history_columns();
1758 // The latest history entry is always our current buffer, that
1759 // initially is just an empty string.
1760 bc_history_add_empty(h);
1762 // Buffer starts empty.
1763 bc_vec_empty(&h->buf);
1767 * Prints a control character.
1768 * @param h The history data.
1769 * @param c The control character to print.
1772 bc_history_printCtrl(BcHistory* h, unsigned int c)
1774 char str[3] = { '^', 'A', '\0' };
1775 const char newline[2] = { '\n', '\0' };
1777 BC_SIG_ASSERT_LOCKED;
1779 // Set the correct character.
1780 str[1] = (char) (c + 'A' - BC_ACTION_CTRL_A);
1782 // Concatenate the string.
1783 bc_vec_concat(&h->buf, str);
1785 h->pos = BC_HIST_BUF_LEN(h);
1786 bc_history_refresh(h);
1789 bc_vec_npop(&h->buf, sizeof(str));
1790 bc_vec_pushByte(&h->buf, '\0');
1793 if (c != BC_ACTION_CTRL_C && c != BC_ACTION_CTRL_D)
1795 // We sometimes want to print a newline; for the times we don't; it's
1796 // because newlines are taken care of elsewhere.
1797 bc_file_write(&vm->fout, bc_flush_none, newline, sizeof(newline) - 1);
1798 bc_history_refresh(h);
1803 * Edits a line of history. This function is the core of the line editing
1804 * capability of bc history. It expects 'fd' to be already in "raw mode" so that
1805 * every key pressed will be returned ASAP to read().
1806 * @param h The history data.
1807 * @param prompt The prompt.
1808 * @return BC_STATUS_SUCCESS or BC_STATUS_EOF.
1811 bc_history_edit(BcHistory* h, const char* prompt)
1815 bc_history_reset(h);
1817 // Don't write the saved output the first time. This is because it has
1818 // already been written to output. In other words, don't uncomment the
1819 // line below or add anything like it.
1820 // bc_file_write(&vm->fout, bc_flush_none, h->extras.v, h->extras.len - 1);
1822 // Write the prompt if desired.
1826 h->plen = strlen(prompt);
1827 h->pcol = bc_history_promptColLen(prompt, h->plen);
1829 bc_file_write(&vm->fout, bc_flush_none, prompt, h->plen);
1830 bc_file_flush(&vm->fout, bc_flush_none);
1833 // This is the input loop.
1844 s = bc_history_readCode(cbuf, sizeof(cbuf), &c, &nread);
1845 if (BC_ERR(s)) return s;
1851 case BC_ACTION_LINE_FEED:
1852 case BC_ACTION_ENTER:
1855 bc_vec_pop(&h->history);
1862 // My tab handling is dumb; it just prints 8 spaces every time.
1863 memcpy(cbuf, bc_history_tab, bc_history_tab_len + 1);
1864 bc_history_edit_insert(h, cbuf, bc_history_tab_len);
1868 case BC_ACTION_CTRL_C:
1870 bc_history_printCtrl(h, c);
1872 // Quit if the user wants it.
1875 vm->status = BC_STATUS_QUIT;
1880 // Print the ready message.
1881 bc_file_write(&vm->fout, bc_flush_none, vm->sigmsg, vm->siglen);
1882 bc_file_write(&vm->fout, bc_flush_none, bc_program_ready_msg,
1883 bc_program_ready_msg_len);
1884 bc_history_reset(h);
1885 bc_history_refresh(h);
1890 case BC_ACTION_BACKSPACE:
1891 case BC_ACTION_CTRL_H:
1893 bc_history_edit_backspace(h);
1897 // Act as end-of-file or delete-forward-char.
1898 case BC_ACTION_CTRL_D:
1900 // Act as EOF if there's no chacters, otherwise emulate Emacs
1901 // delete next character to match historical gnu bc behavior.
1902 if (BC_HIST_BUF_LEN(h) == 0)
1904 bc_history_printCtrl(h, c);
1906 return BC_STATUS_EOF;
1909 bc_history_edit_delete(h);
1914 // Swaps current character with previous.
1915 case BC_ACTION_CTRL_T:
1921 case BC_ACTION_CTRL_B:
1923 bc_history_edit_left(h);
1927 case BC_ACTION_CTRL_F:
1929 bc_history_edit_right(h);
1933 case BC_ACTION_CTRL_P:
1935 bc_history_edit_next(h, BC_HIST_PREV);
1939 case BC_ACTION_CTRL_N:
1941 bc_history_edit_next(h, BC_HIST_NEXT);
1947 bc_history_escape(h);
1951 // Delete the whole line.
1952 case BC_ACTION_CTRL_U:
1954 bc_vec_string(&h->buf, 0, "");
1957 bc_history_refresh(h);
1962 // Delete from current to end of line.
1963 case BC_ACTION_CTRL_K:
1965 bc_vec_npop(&h->buf, h->buf.len - h->pos);
1966 bc_vec_pushByte(&h->buf, '\0');
1967 bc_history_refresh(h);
1971 // Go to the start of the line.
1972 case BC_ACTION_CTRL_A:
1974 bc_history_edit_home(h);
1978 // Go to the end of the line.
1979 case BC_ACTION_CTRL_E:
1981 bc_history_edit_end(h);
1986 case BC_ACTION_CTRL_L:
1988 bc_file_write(&vm->fout, bc_flush_none, "\x1b[H\x1b[2J", 7);
1989 bc_history_refresh(h);
1993 // Delete previous word.
1994 case BC_ACTION_CTRL_W:
1996 bc_history_edit_deletePrevWord(h);
2002 // If we have a control character, print it and raise signals as
2004 if ((c >= BC_ACTION_CTRL_A && c <= BC_ACTION_CTRL_Z) ||
2005 c == BC_ACTION_CTRL_BSLASH)
2007 bc_history_printCtrl(h, c);
2009 if (c == BC_ACTION_CTRL_Z) bc_history_raise(h, SIGTSTP);
2010 if (c == BC_ACTION_CTRL_S) bc_history_raise(h, SIGSTOP);
2011 if (c == BC_ACTION_CTRL_BSLASH)
2013 bc_history_raise(h, SIGQUIT);
2016 vm->status = BC_STATUS_QUIT;
2021 // Otherwise, just insert.
2022 else bc_history_edit_insert(h, cbuf, nread);
2030 return BC_STATUS_SUCCESS;
2034 * Returns true if stdin has more data. This is for multi-line pasting, and it
2035 * does not work on Windows.
2036 * @param h The history data.
2039 bc_history_stdinHasData(BcHistory* h)
2043 return pselect(1, &h->rdset, NULL, NULL, &h->ts, &h->sigmask) > 0 ||
2044 (ioctl(STDIN_FILENO, FIONREAD, &n) >= 0 && n > 0);
2051 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
2056 assert(vm->fout.len == 0);
2058 bc_history_enableRaw(h);
2063 s = bc_history_edit(h, prompt);
2065 // Print a newline and flush.
2066 bc_file_write(&vm->fout, bc_flush_none, "\n", 1);
2067 bc_file_flush(&vm->fout, bc_flush_none);
2071 // If we actually have data...
2075 line = bc_vm_strdup(h->buf.v);
2078 bc_history_add(h, line);
2080 // Add an empty string.
2081 else bc_history_add_empty(h);
2085 // Concatenate the line to the return vector.
2086 bc_vec_concat(vec, h->buf.v);
2087 bc_vec_concat(vec, "\n");
2089 while (!s && bc_history_stdinHasData(h));
2091 assert(!s || s == BC_STATUS_EOF);
2093 bc_history_disableRaw(h);
2099 bc_history_string_free(void* str)
2101 char* s = *((char**) str);
2102 BC_SIG_ASSERT_LOCKED;
2107 bc_history_init(BcHistory* h)
2114 BC_SIG_ASSERT_LOCKED;
2117 h->badTerm = bc_history_isBadTerm();
2119 // Just don't initialize with a bad terminal.
2120 if (h->badTerm) return;
2127 in = GetStdHandle(STD_INPUT_HANDLE);
2128 out = GetStdHandle(STD_OUTPUT_HANDLE);
2130 // Set the code pages.
2131 SetConsoleCP(CP_UTF8);
2132 SetConsoleOutputCP(CP_UTF8);
2134 // Get the original modes.
2135 if (!GetConsoleMode(in, &h->orig_in) || !GetConsoleMode(out, &h->orig_out))
2137 // Just mark it as a bad terminal on error.
2143 // Set the new modes.
2144 DWORD reqOut = h->orig_out | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
2145 DWORD reqIn = h->orig_in | ENABLE_VIRTUAL_TERMINAL_INPUT;
2147 // The input handle requires turning *off* some modes. That's why
2148 // history didn't work before; I didn't read the documentation
2149 // closely enough to see that most modes were automaticall enabled,
2150 // and they need to be turned off.
2151 reqOut |= DISABLE_NEWLINE_AUTO_RETURN | ENABLE_PROCESSED_OUTPUT;
2152 reqIn &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
2153 reqIn &= ~(ENABLE_PROCESSED_INPUT);
2155 // Set the modes; if there was an error, assume a bad terminal and
2157 if (!SetConsoleMode(in, reqIn) || !SetConsoleMode(out, reqOut))
2165 bc_vec_init(&h->buf, sizeof(char), BC_DTOR_NONE);
2166 bc_vec_init(&h->history, sizeof(char*), BC_DTOR_HISTORY_STRING);
2167 bc_vec_init(&h->extras, sizeof(char), BC_DTOR_NONE);
2171 FD_SET(STDIN_FILENO, &h->rdset);
2175 sigemptyset(&h->sigmask);
2176 sigaddset(&h->sigmask, SIGINT);
2181 bc_history_free(BcHistory* h)
2183 BC_SIG_ASSERT_LOCKED;
2185 bc_history_disableRaw(h);
2187 SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), h->orig_in);
2188 SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), h->orig_out);
2191 bc_vec_free(&h->buf);
2192 bc_vec_free(&h->history);
2193 bc_vec_free(&h->extras);
2200 * Prints scan codes. This special mode is used by bc history in order to print
2201 * scan codes on screen for debugging / development purposes.
2202 * @param h The history data.
2205 bc_history_printKeyCodes(BcHistory* h)
2209 bc_vm_printf("Linenoise key codes debugging mode.\n"
2210 "Press keys to see scan codes. "
2211 "Type 'quit' at any time to exit.\n");
2213 bc_history_enableRaw(h);
2214 memset(quit, ' ', 4);
2221 nread = bc_history_read(&c, 1);
2222 if (nread <= 0) continue;
2224 // Shift string to left.
2225 memmove(quit, quit + 1, sizeof(quit) - 1);
2227 // Insert current char on the right.
2228 quit[sizeof(quit) - 1] = c;
2229 if (!memcmp(quit, "quit", sizeof(quit))) break;
2231 bc_vm_printf("'%c' %lu (type quit to exit)\n", isprint(c) ? c : '?',
2234 // Go left edge manually, we are in raw mode.
2235 bc_vm_putchar('\r', bc_flush_none);
2236 bc_file_flush(&vm->fout, bc_flush_none);
2239 bc_history_disableRaw(h);
2241 #endif // BC_DEBUG_CODE
2243 #endif // BC_ENABLE_HISTORY
2245 #endif // BC_ENABLE_READLINE
2247 #endif // BC_ENABLE_EDITLINE