]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bc/src/history.c
contrib/bc: merge version 5.1.0 from vendor branch
[FreeBSD/FreeBSD.git] / contrib / bc / src / history.c
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2021 Gavin D. Howard and contributors.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * * Redistributions of source code must retain the above copyright notice, this
12  *   list of conditions and the following disclaimer.
13  *
14  * * Redistributions in binary form must reproduce the above copyright notice,
15  *   this list of conditions and the following disclaimer in the documentation
16  *   and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * *****************************************************************************
31  *
32  * Adapted from the following:
33  *
34  * linenoise.c -- guerrilla line editing library against the idea that a
35  * line editing lib needs to be 20,000 lines of C code.
36  *
37  * You can find the original source code at:
38  *   http://github.com/antirez/linenoise
39  *
40  * You can find the fork that this code is based on at:
41  *   https://github.com/rain-1/linenoise-mob
42  *
43  * ------------------------------------------------------------------------
44  *
45  * This code is also under the following license:
46  *
47  * Copyright (c) 2010-2016, Salvatore Sanfilippo <antirez at gmail dot com>
48  * Copyright (c) 2010-2013, Pieter Noordhuis <pcnoordhuis at gmail dot com>
49  *
50  * Redistribution and use in source and binary forms, with or without
51  * modification, are permitted provided that the following conditions are
52  * met:
53  *
54  *  *  Redistributions of source code must retain the above copyright
55  *     notice, this list of conditions and the following disclaimer.
56  *
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.
60  *
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.
72  *
73  * ------------------------------------------------------------------------
74  *
75  * Does a number of crazy assumptions that happen to be true in 99.9999% of
76  * the 2010 UNIX computers around.
77  *
78  * References:
79  * - http://invisible-island.net/xterm/ctlseqs/ctlseqs.html
80  * - http://www.3waylabs.com/nw/WWW/products/wizcon/vt220.html
81  *
82  * Todo list:
83  * - Filter bogus Ctrl+<char> combinations.
84  * - Win32 support
85  *
86  * Bloat:
87  * - History search like Ctrl+r in readline?
88  *
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.
93  *
94  * EL (Erase Line)
95  *    Sequence: ESC [ n K
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
99  *
100  * CUF (CUrsor Forward)
101  *    Sequence: ESC [ n C
102  *    Effect: moves cursor forward n chars
103  *
104  * CUB (CUrsor Backward)
105  *    Sequence: ESC [ n D
106  *    Effect: moves cursor backward n chars
107  *
108  * The following is used to get the terminal width if getting
109  * the width with the TIOCGWINSZ ioctl fails
110  *
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
115  *
116  * When multi line mode is enabled, we also use two additional escape
117  * sequences. However multi line editing is disabled by default.
118  *
119  * CUU (CUrsor Up)
120  *    Sequence: ESC [ n A
121  *    Effect: moves cursor up of n chars.
122  *
123  * CUD (CUrsor Down)
124  *    Sequence: ESC [ n B
125  *    Effect: moves cursor down of n chars.
126  *
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
129  * position.
130  *
131  * CUP (CUrsor Position)
132  *    Sequence: ESC [ H
133  *    Effect: moves the cursor to upper left corner
134  *
135  * ED (Erase Display)
136  *    Sequence: ESC [ 2 J
137  *    Effect: clear the whole screen
138  *
139  * *****************************************************************************
140  *
141  * Code for line history.
142  *
143  */
144
145 #if BC_ENABLE_HISTORY
146
147 #include <assert.h>
148 #include <stdlib.h>
149 #include <errno.h>
150 #include <string.h>
151 #include <ctype.h>
152
153 #include <signal.h>
154 #include <sys/stat.h>
155 #include <sys/types.h>
156
157 #ifndef _WIN32
158 #include <strings.h>
159 #include <termios.h>
160 #include <unistd.h>
161 #include <sys/ioctl.h>
162 #include <sys/select.h>
163 #endif // _WIN32
164
165 #include <status.h>
166 #include <vector.h>
167 #include <history.h>
168 #include <read.h>
169 #include <file.h>
170 #include <vm.h>
171
172 #if BC_DEBUG_CODE
173
174 /// A file for outputting to when debugging.
175 BcFile bc_history_debug_fp;
176
177 /// A buffer for the above file.
178 char *bc_history_debug_buf;
179
180 #endif // BC_DEBUG_CODE
181
182 /**
183  * Checks if the code is a wide character.
184  * @param cp  The codepoint to check.
185  * @return    True if @a cp is a wide character, false otherwise.
186  */
187 static bool bc_history_wchar(uint32_t cp) {
188
189         size_t i;
190
191         for (i = 0; i < bc_history_wchars_len; ++i) {
192
193                 // Ranges are listed in ascending order.  Therefore, once the
194                 // whole range is higher than the codepoint we're testing, the
195                 // codepoint won't be found in any remaining range => bail early.
196                 if (bc_history_wchars[i][0] > cp) return false;
197
198                 // Test this range.
199                 if (bc_history_wchars[i][0] <= cp && cp <= bc_history_wchars[i][1])
200                         return true;
201         }
202
203         return false;
204 }
205
206 /**
207  * Checks if the code is a combining character.
208  * @param cp  The codepoint to check.
209  * @return    True if @a cp is a combining character, false otherwise.
210  */
211 static bool bc_history_comboChar(uint32_t cp) {
212
213         size_t i;
214
215         for (i = 0; i < bc_history_combo_chars_len; ++i) {
216
217                 // Combining chars are listed in ascending order, so once we pass
218                 // the codepoint of interest, we know it's not a combining char.
219                 if (bc_history_combo_chars[i] > cp) return false;
220                 if (bc_history_combo_chars[i] == cp) return true;
221         }
222
223         return false;
224 }
225
226 /**
227  * Gets the length of previous UTF8 character.
228  * @param buf  The buffer of characters.
229  * @param pos  The index into the buffer.
230  */
231 static size_t bc_history_prevCharLen(const char *buf, size_t pos) {
232         size_t end = pos;
233         for (pos -= 1; pos < end && (buf[pos] & 0xC0) == 0x80; --pos);
234         return end - (pos >= end ? 0 : pos);
235 }
236
237 /**
238  * Converts UTF-8 to a Unicode code point.
239  * @param s    The string.
240  * @param len  The length of the string.
241  * @param cp   An out parameter for the codepoint.
242  * @return     The number of bytes eaten by the codepoint.
243  */
244 static size_t bc_history_codePoint(const char *s, size_t len, uint32_t *cp) {
245
246         if (len) {
247
248                 uchar byte = (uchar) s[0];
249
250                 // This is literally the UTF-8 decoding algorithm. Look that up if you
251                 // don't understand this.
252
253                 if ((byte & 0x80) == 0) {
254                         *cp = byte;
255                         return 1;
256                 }
257                 else if ((byte & 0xE0) == 0xC0) {
258
259                         if (len >= 2) {
260                                 *cp = (((uint32_t) (s[0] & 0x1F)) << 6) |
261                                            ((uint32_t) (s[1] & 0x3F));
262                                 return 2;
263                         }
264                 }
265                 else if ((byte & 0xF0) == 0xE0) {
266
267                         if (len >= 3) {
268                                 *cp = (((uint32_t) (s[0] & 0x0F)) << 12) |
269                                           (((uint32_t) (s[1] & 0x3F)) << 6) |
270                                            ((uint32_t) (s[2] & 0x3F));
271                                 return 3;
272                         }
273                 }
274                 else if ((byte & 0xF8) == 0xF0) {
275
276                         if (len >= 4) {
277                                 *cp = (((uint32_t) (s[0] & 0x07)) << 18) |
278                                           (((uint32_t) (s[1] & 0x3F)) << 12) |
279                                           (((uint32_t) (s[2] & 0x3F)) << 6) |
280                                            ((uint32_t) (s[3] & 0x3F));
281                                 return 4;
282                         }
283                 }
284                 else {
285                         *cp = 0xFFFD;
286                         return 1;
287                 }
288         }
289
290         *cp = 0;
291
292         return 1;
293 }
294
295 /**
296  * Gets the length of next grapheme.
297  * @param buf      The buffer.
298  * @param buf_len  The length of the buffer.
299  * @param pos      The index into the buffer.
300  * @param col_len  An out parameter for the length of the grapheme on screen.
301  * @return         The number of bytes in the grapheme.
302  */
303 static size_t bc_history_nextLen(const char *buf, size_t buf_len,
304                                  size_t pos, size_t *col_len)
305 {
306         uint32_t cp;
307         size_t beg = pos;
308         size_t len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
309
310         if (bc_history_comboChar(cp)) {
311
312                 BC_UNREACHABLE
313
314                 if (col_len != NULL) *col_len = 0;
315
316                 return 0;
317         }
318
319         // Store the width of the character on screen.
320         if (col_len != NULL) *col_len = bc_history_wchar(cp) ? 2 : 1;
321
322         pos += len;
323
324         // Find the first non-combining character.
325         while (pos < buf_len) {
326
327                 len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
328
329                 if (!bc_history_comboChar(cp)) return pos - beg;
330
331                 pos += len;
332         }
333
334         return pos - beg;
335 }
336
337 /**
338  * Gets the length of previous grapheme.
339  * @param buf  The buffer.
340  * @param pos  The index into the buffer.
341  * @return     The number of bytes in the grapheme.
342  */
343 static size_t bc_history_prevLen(const char *buf, size_t pos) {
344
345         size_t end = pos;
346
347         // Find the first non-combining character.
348         while (pos > 0) {
349
350                 uint32_t cp;
351                 size_t len = bc_history_prevCharLen(buf, pos);
352
353                 pos -= len;
354                 bc_history_codePoint(buf + pos, len, &cp);
355
356                 // The original linenoise-mob had an extra parameter col_len, like
357                 // bc_history_nextLen(), which, if not NULL, was set in this if
358                 // statement. However, we always passed NULL, so just skip that.
359                 if (!bc_history_comboChar(cp)) return end - pos;
360         }
361
362         BC_UNREACHABLE
363
364         return 0;
365 }
366
367 /**
368  * Reads @a n characters from stdin.
369  * @param buf  The buffer to read into. The caller is responsible for making
370  *             sure this is big enough for @a n.
371  * @param n    The number of characters to read.
372  * @return     The number of characters read or less than 0 on error.
373  */
374 static ssize_t bc_history_read(char *buf, size_t n) {
375
376         ssize_t ret;
377
378         BC_SIG_LOCK;
379
380 #ifndef _WIN32
381
382         do {
383                 // We don't care about being interrupted.
384                 ret = read(STDIN_FILENO, buf, n);
385         } while (ret == EINTR);
386
387 #else // _WIN32
388
389         bool good;
390         DWORD read;
391         HANDLE hn = GetStdHandle(STD_INPUT_HANDLE);
392
393         good = ReadConsole(hn, buf, (DWORD) n, &read, NULL);
394
395         ret = (read != n) ? -1 : 1;
396
397 #endif // _WIN32
398
399         BC_SIG_UNLOCK;
400
401         return ret;
402 }
403
404 /**
405  * Reads a Unicode code point into a buffer.
406  * @param buf      The buffer to read into.
407  * @param buf_len  The length of the buffer.
408  * @param cp       An out parameter for the codepoint.
409  * @param nread    An out parameter for the number of bytes read.
410  * @return         BC_STATUS_EOF or BC_STATUS_SUCCESS.
411  */
412 static BcStatus bc_history_readCode(char *buf, size_t buf_len,
413                                     uint32_t *cp, size_t *nread)
414 {
415         ssize_t n;
416
417         assert(buf_len >= 1);
418
419         // Read a byte.
420         n = bc_history_read(buf, 1);
421         if (BC_ERR(n <= 0)) goto err;
422
423         // Get the byte.
424         uchar byte = ((uchar*) buf)[0];
425
426         // Once again, this is the UTF-8 decoding algorithm, but it has reads
427         // instead of actual decoding.
428         if ((byte & 0x80) != 0) {
429
430                 if ((byte & 0xE0) == 0xC0) {
431
432                         assert(buf_len >= 2);
433
434                         n = bc_history_read(buf + 1, 1);
435
436                         if (BC_ERR(n <= 0)) goto err;
437                 }
438                 else if ((byte & 0xF0) == 0xE0) {
439
440                         assert(buf_len >= 3);
441
442                         n = bc_history_read(buf + 1, 2);
443
444                         if (BC_ERR(n <= 0)) goto err;
445                 }
446                 else if ((byte & 0xF8) == 0xF0) {
447
448                         assert(buf_len >= 3);
449
450                         n = bc_history_read(buf + 1, 3);
451
452                         if (BC_ERR(n <= 0)) goto err;
453                 }
454                 else {
455                         n = -1;
456                         goto err;
457                 }
458         }
459
460         // Convert to the codepoint.
461         *nread = bc_history_codePoint(buf, buf_len, cp);
462
463         return BC_STATUS_SUCCESS;
464
465 err:
466         // If we get here, we either had a fatal error of EOF.
467         if (BC_ERR(n < 0)) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
468         else *nread = (size_t) n;
469         return BC_STATUS_EOF;
470 }
471
472 /**
473  * Gets the column length from beginning of buffer to current byte position.
474  * @param buf      The buffer.
475  * @param buf_len  The length of the buffer.
476  * @param pos      The index into the buffer.
477  * @return         The number of columns between the beginning of @a buffer to
478  *                 @a pos.
479  */
480 static size_t bc_history_colPos(const char *buf, size_t buf_len, size_t pos) {
481
482         size_t ret = 0, off = 0;
483
484         // While we haven't reached the offset, get the length of the next grapheme.
485         while (off < pos && off < buf_len) {
486
487                 size_t col_len, len;
488
489                 len = bc_history_nextLen(buf, buf_len, off, &col_len);
490
491                 off += len;
492                 ret += col_len;
493         }
494
495         return ret;
496 }
497
498 /**
499  * Returns true if the terminal name is in the list of terminals we know are
500  * not able to understand basic escape sequences.
501  * @return  True if the terminal is a bad terminal.
502  */
503 static inline bool bc_history_isBadTerm(void) {
504
505         size_t i;
506         bool ret = false;
507         char *term = bc_vm_getenv("TERM");
508
509         if (term == NULL) return false;
510
511         for (i = 0; !ret && bc_history_bad_terms[i]; ++i)
512                 ret = (!strcasecmp(term, bc_history_bad_terms[i]));
513
514         bc_vm_getenvFree(term);
515
516         return ret;
517 }
518
519 /**
520  * Enables raw mode (1960's black magic).
521  * @param h  The history data.
522  */
523 static void bc_history_enableRaw(BcHistory *h) {
524
525         // I don't do anything for Windows because in Windows, you set their
526         // equivalent of raw mode and leave it, so I do it in bc_history_init().
527
528 #ifndef _WIN32
529         struct termios raw;
530         int err;
531
532         assert(BC_TTYIN);
533
534         if (h->rawMode) return;
535
536         BC_SIG_LOCK;
537
538         if (BC_ERR(tcgetattr(STDIN_FILENO, &h->orig_termios) == -1))
539                 bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
540
541         BC_SIG_UNLOCK;
542
543         // Modify the original mode.
544         raw = h->orig_termios;
545
546         // Input modes: no break, no CR to NL, no parity check, no strip char,
547         // no start/stop output control.
548         raw.c_iflag &= (unsigned int) (~(BRKINT | ICRNL | INPCK | ISTRIP | IXON));
549
550         // Control modes: set 8 bit chars.
551         raw.c_cflag |= (CS8);
552
553         // Local modes - choing off, canonical off, no extended functions,
554         // no signal chars (^Z,^C).
555         raw.c_lflag &= (unsigned int) (~(ECHO | ICANON | IEXTEN | ISIG));
556
557         // Control chars - set return condition: min number of bytes and timer.
558         // We want read to give every single byte, w/o timeout (1 byte, no timer).
559         raw.c_cc[VMIN] = 1;
560         raw.c_cc[VTIME] = 0;
561
562         BC_SIG_LOCK;
563
564         // Put terminal in raw mode after flushing.
565         do {
566                 err = tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
567         } while (BC_ERR(err < 0) && errno == EINTR);
568
569         BC_SIG_UNLOCK;
570
571         if (BC_ERR(err < 0)) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
572 #endif // _WIN32
573
574         h->rawMode = true;
575 }
576
577 /**
578  * Disables raw mode.
579  * @param h  The history data.
580  */
581 static void bc_history_disableRaw(BcHistory *h) {
582
583         sig_atomic_t lock;
584
585         if (!h->rawMode) return;
586
587         BC_SIG_TRYLOCK(lock);
588
589 #ifndef _WIN32
590         if (BC_ERR(tcsetattr(STDIN_FILENO, TCSAFLUSH, &h->orig_termios) != -1))
591                 h->rawMode = false;
592 #endif // _WIN32
593
594         BC_SIG_TRYUNLOCK(lock);
595 }
596
597 /**
598  * Uses the ESC [6n escape sequence to query the horizontal cursor position
599  * and return it. On error -1 is returned, on success the position of the
600  * cursor.
601  * @return  The horizontal cursor position.
602  */
603 static size_t bc_history_cursorPos(void) {
604
605         char buf[BC_HIST_SEQ_SIZE];
606         char *ptr, *ptr2;
607         size_t cols, rows, i;
608
609         // Report cursor location.
610         bc_file_write(&vm.fout, bc_flush_none, "\x1b[6n", 4);
611         bc_file_flush(&vm.fout, bc_flush_none);
612
613         // Read the response: ESC [ rows ; cols R.
614         for (i = 0; i < sizeof(buf) - 1; ++i) {
615                 if (bc_history_read(buf + i, 1) != 1 || buf[i] == 'R') break;
616         }
617
618         buf[i] = '\0';
619
620         // This is basically an error; we didn't get what we were expecting.
621         if (BC_ERR(buf[0] != BC_ACTION_ESC || buf[1] != '[')) return SIZE_MAX;
622
623         // Parse the rows.
624         ptr = buf + 2;
625         rows = strtoul(ptr, &ptr2, 10);
626
627         // Here we also didn't get what we were expecting.
628         if (BC_ERR(!rows || ptr2[0] != ';')) return SIZE_MAX;
629
630         // Parse the columns.
631         ptr = ptr2 + 1;
632         cols = strtoul(ptr, NULL, 10);
633
634         if (BC_ERR(!cols)) return SIZE_MAX;
635
636         return cols <= UINT16_MAX ? cols : 0;
637 }
638
639 /**
640  * Tries to get the number of columns in the current terminal, or assume 80
641  * if it fails.
642  * @return  The number of columns in the terminal.
643  */
644 static size_t bc_history_columns(void) {
645
646 #ifndef _WIN32
647
648         struct winsize ws;
649         int ret;
650
651         BC_SIG_LOCK;
652
653         ret = ioctl(vm.fout.fd, TIOCGWINSZ, &ws);
654
655         BC_SIG_UNLOCK;
656
657         if (BC_ERR(ret == -1 || !ws.ws_col)) {
658
659                 // Calling ioctl() failed. Try to query the terminal itself.
660                 size_t start, cols;
661
662                 // Get the initial position so we can restore it later.
663                 start = bc_history_cursorPos();
664                 if (BC_ERR(start == SIZE_MAX)) return BC_HIST_DEF_COLS;
665
666                 // Go to right margin and get position.
667                 bc_file_write(&vm.fout, bc_flush_none, "\x1b[999C", 6);
668                 bc_file_flush(&vm.fout, bc_flush_none);
669                 cols = bc_history_cursorPos();
670                 if (BC_ERR(cols == SIZE_MAX)) return BC_HIST_DEF_COLS;
671
672                 // Restore position.
673                 if (cols > start) {
674                         bc_file_printf(&vm.fout, "\x1b[%zuD", cols - start);
675                         bc_file_flush(&vm.fout, bc_flush_none);
676                 }
677
678                 return cols;
679         }
680
681         return ws.ws_col;
682
683 #else // _WIN32
684
685         CONSOLE_SCREEN_BUFFER_INFO csbi;
686
687         if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
688                 return 80;
689
690         return ((size_t) (csbi.srWindow.Right)) - csbi.srWindow.Left + 1;
691
692 #endif // _WIN32
693 }
694
695 /**
696  * Gets the column length of prompt text. This is probably unnecessary because
697  * the prompts that I use are ASCII, but I kept it just in case.
698  * @param prompt  The prompt.
699  * @param plen    The length of the prompt.
700  * @return        The column length of the prompt.
701  */
702 static size_t bc_history_promptColLen(const char *prompt, size_t plen) {
703
704         char buf[BC_HIST_MAX_LINE + 1];
705         size_t buf_len = 0, off = 0;
706
707         // The original linenoise-mob checked for ANSI escapes here on the prompt. I
708         // know the prompts do not have ANSI escapes. I deleted the code.
709         while (off < plen) buf[buf_len++] = prompt[off++];
710
711         return bc_history_colPos(buf, buf_len, buf_len);
712 }
713
714 /**
715  * Rewrites the currently edited line accordingly to the buffer content,
716  * cursor position, and number of columns of the terminal.
717  * @param h  The history data.
718  */
719 static void bc_history_refresh(BcHistory *h) {
720
721         char* buf = h->buf.v;
722         size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0;
723
724         bc_file_flush(&vm.fout, bc_flush_none);
725
726         // Get to the prompt column position from the left.
727         while(h->pcol + bc_history_colPos(buf, len, pos) >= h->cols) {
728
729                 size_t chlen = bc_history_nextLen(buf, len, 0, NULL);
730
731                 buf += chlen;
732                 len -= chlen;
733                 pos -= chlen;
734         }
735
736         // Get to the prompt column position from the right.
737         while (h->pcol + bc_history_colPos(buf, len, len) > h->cols)
738                 len -= bc_history_prevLen(buf, len);
739
740         // Cursor to left edge.
741         bc_file_write(&vm.fout, bc_flush_none, "\r", 1);
742
743         // Take the extra stuff into account. This is where history makes sure to
744         // preserve stuff that was printed without a newline.
745         if (h->extras.len > 1) {
746
747                 extras_len = h->extras.len - 1;
748
749                 bc_vec_grow(&h->buf, extras_len);
750
751                 len += extras_len;
752                 pos += extras_len;
753
754                 bc_file_write(&vm.fout, bc_flush_none, h->extras.v, extras_len);
755         }
756
757         // Write the prompt, if desired.
758         if (BC_PROMPT) bc_file_write(&vm.fout, bc_flush_none, h->prompt, h->plen);
759
760         bc_file_write(&vm.fout, bc_flush_none, h->buf.v, len - extras_len);
761
762         // Erase to right.
763         bc_file_write(&vm.fout, bc_flush_none, "\x1b[0K", 4);
764
765         // We need to be sure to grow this.
766         if (pos >= h->buf.len - extras_len)
767                 bc_vec_grow(&h->buf, pos + extras_len);
768
769         // Move cursor to original position.
770         colpos = bc_history_colPos(h->buf.v, len - extras_len, pos) + h->pcol;
771
772         // Set the cursor position again.
773         if (colpos) bc_file_printf(&vm.fout, "\r\x1b[%zuC", colpos);
774
775         bc_file_flush(&vm.fout, bc_flush_none);
776 }
777
778 /**
779  * Inserts the character(s) 'c' at cursor current position.
780  * @param h     The history data.
781  * @param cbuf  The character buffer to copy from.
782  * @param clen  The number of characters to copy.
783  */
784 static void bc_history_edit_insert(BcHistory *h, const char *cbuf, size_t clen)
785 {
786         bc_vec_grow(&h->buf, clen);
787
788         // If we are at the end of the line...
789         if (h->pos == BC_HIST_BUF_LEN(h)) {
790
791                 size_t colpos = 0, len;
792
793                 // Copy into the buffer.
794                 memcpy(bc_vec_item(&h->buf, h->pos), cbuf, clen);
795
796                 // Adjust the buffer.
797                 h->pos += clen;
798                 h->buf.len += clen - 1;
799                 bc_vec_pushByte(&h->buf, '\0');
800
801                 // Set the length and column position.
802                 len = BC_HIST_BUF_LEN(h) + h->extras.len - 1;
803                 colpos = bc_history_promptColLen(h->prompt, h->plen);
804                 colpos += bc_history_colPos(h->buf.v, len, len);
805
806                 // Do we have the trivial case?
807                 if (colpos < h->cols) {
808
809                         // Avoid a full update of the line in the trivial case.
810                         bc_file_write(&vm.fout, bc_flush_none, cbuf, clen);
811                         bc_file_flush(&vm.fout, bc_flush_none);
812                 }
813                 else bc_history_refresh(h);
814         }
815         else {
816
817                 // Amount that we need to move.
818                 size_t amt = BC_HIST_BUF_LEN(h) - h->pos;
819
820                 // Move the stuff.
821                 memmove(h->buf.v + h->pos + clen, h->buf.v + h->pos, amt);
822                 memcpy(h->buf.v + h->pos, cbuf, clen);
823
824                 // Adjust the buffer.
825                 h->pos += clen;
826                 h->buf.len += clen;
827                 h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
828
829                 bc_history_refresh(h);
830         }
831 }
832
833 /**
834  * Moves the cursor to the left.
835  * @param h  The history data.
836  */
837 static void bc_history_edit_left(BcHistory *h) {
838
839         // Stop at the left end.
840         if (h->pos <= 0) return;
841
842         h->pos -= bc_history_prevLen(h->buf.v, h->pos);
843
844         bc_history_refresh(h);
845 }
846
847 /**
848  * Moves the cursor to the right.
849  * @param h  The history data.
850 */
851 static void bc_history_edit_right(BcHistory *h) {
852
853         // Stop at the right end.
854         if (h->pos == BC_HIST_BUF_LEN(h)) return;
855
856         h->pos += bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
857
858         bc_history_refresh(h);
859 }
860
861 /**
862  * Moves the cursor to the end of the current word.
863  * @param h  The history data.
864  */
865 static void bc_history_edit_wordEnd(BcHistory *h) {
866
867         size_t len = BC_HIST_BUF_LEN(h);
868
869         // Don't overflow.
870         if (!len || h->pos >= len) return;
871
872         // Find the word, then find the end of it.
873         while (h->pos < len && isspace(h->buf.v[h->pos])) h->pos += 1;
874         while (h->pos < len && !isspace(h->buf.v[h->pos])) h->pos += 1;
875
876         bc_history_refresh(h);
877 }
878
879 /**
880  * Moves the cursor to the start of the current word.
881  * @param h  The history data.
882  */
883 static void bc_history_edit_wordStart(BcHistory *h) {
884
885         size_t len = BC_HIST_BUF_LEN(h);
886
887         // Stop with no data.
888         if (!len) return;
889
890         // Find the word, the find the beginning of the word.
891         while (h->pos > 0 && isspace(h->buf.v[h->pos - 1])) h->pos -= 1;
892         while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1])) h->pos -= 1;
893
894         bc_history_refresh(h);
895 }
896
897 /**
898  * Moves the cursor to the start of the line.
899  * @param h  The history data.
900  */
901 static void bc_history_edit_home(BcHistory *h) {
902
903         // Stop at the beginning.
904         if (!h->pos) return;
905
906         h->pos = 0;
907
908         bc_history_refresh(h);
909 }
910
911 /**
912  * Moves the cursor to the end of the line.
913  * @param h  The history data.
914  */
915 static void bc_history_edit_end(BcHistory *h) {
916
917         // Stop at the end of the line.
918         if (h->pos == BC_HIST_BUF_LEN(h)) return;
919
920         h->pos = BC_HIST_BUF_LEN(h);
921
922         bc_history_refresh(h);
923 }
924
925 /**
926  * Substitutes the currently edited line with the next or previous history
927  * entry as specified by 'dir' (direction).
928  * @param h    The history data.
929  * @param dir  The direction to substitute; true means previous, false next.
930  */
931 static void bc_history_edit_next(BcHistory *h, bool dir) {
932
933         const char *dup, *str;
934
935         // Stop if there is no history.
936         if (h->history.len <= 1) return;
937
938         BC_SIG_LOCK;
939
940         // Duplicate the buffer.
941         if (h->buf.v[0]) dup = bc_vm_strdup(h->buf.v);
942         else dup = "";
943
944         // Update the current history entry before overwriting it with the next one.
945         bc_vec_replaceAt(&h->history, h->history.len - 1 - h->idx, &dup);
946
947         BC_SIG_UNLOCK;
948
949         // Show the new entry.
950         h->idx += (dir == BC_HIST_PREV ? 1 : SIZE_MAX);
951
952         // Se the index appropriately at the ends.
953         if (h->idx == SIZE_MAX) {
954                 h->idx = 0;
955                 return;
956         }
957         else if (h->idx >= h->history.len) {
958                 h->idx = h->history.len - 1;
959                 return;
960         }
961
962         // Get the string.
963         str = *((char**) bc_vec_item(&h->history, h->history.len - 1 - h->idx));
964         bc_vec_string(&h->buf, strlen(str), str);
965
966         assert(h->buf.len > 0);
967
968         // Set the position at the end.
969         h->pos = BC_HIST_BUF_LEN(h);
970
971         bc_history_refresh(h);
972 }
973
974 /**
975  * Deletes the character at the right of the cursor without altering the cursor
976  * position. Basically, this is what happens with the "Delete" keyboard key.
977  * @param h  The history data.
978  */
979 static void bc_history_edit_delete(BcHistory *h) {
980
981         size_t chlen, len = BC_HIST_BUF_LEN(h);
982
983         // If there is no character, skip.
984         if (!len || h->pos >= len) return;
985
986         // Get the length of the character.
987         chlen = bc_history_nextLen(h->buf.v, len, h->pos, NULL);
988
989         // Move characters after it into its place.
990         memmove(h->buf.v + h->pos, h->buf.v + h->pos + chlen, len - h->pos - chlen);
991
992         // Make the buffer valid again.
993         h->buf.len -= chlen;
994         h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
995
996         bc_history_refresh(h);
997 }
998
999 /**
1000  * Deletes the character to the left of the cursor and moves the cursor back one
1001  * space. Basically, this is what happens with the "Backspace" keyboard key.
1002  * @param h  The history data.
1003  */
1004 static void bc_history_edit_backspace(BcHistory *h) {
1005
1006         size_t chlen, len = BC_HIST_BUF_LEN(h);
1007
1008         // If there are no characters, skip.
1009         if (!h->pos || !len) return;
1010
1011         // Get the length of the previous character.
1012         chlen = bc_history_prevLen(h->buf.v, h->pos);
1013
1014         // Move everything back one.
1015         memmove(h->buf.v + h->pos - chlen, h->buf.v + h->pos, len - h->pos);
1016
1017         // Make the buffer valid again.
1018         h->pos -= chlen;
1019         h->buf.len -= chlen;
1020         h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1021
1022         bc_history_refresh(h);
1023 }
1024
1025 /**
1026  * Deletes the previous word, maintaining the cursor at the start of the
1027  * current word.
1028  * @param h  The history data.
1029  */
1030 static void bc_history_edit_deletePrevWord(BcHistory *h) {
1031
1032         size_t diff, old_pos = h->pos;
1033
1034         // If at the beginning of the line, skip.
1035         if (!old_pos) return;
1036
1037         // Find the word, then the beginning of the word.
1038         while (h->pos > 0 && isspace(h->buf.v[h->pos - 1])) --h->pos;
1039         while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1])) --h->pos;
1040
1041         // Get the difference in position.
1042         diff = old_pos - h->pos;
1043
1044         // Move the data back.
1045         memmove(h->buf.v + h->pos, h->buf.v + old_pos,
1046                 BC_HIST_BUF_LEN(h) - old_pos + 1);
1047
1048         // Make the buffer valid again.
1049         h->buf.len -= diff;
1050
1051         bc_history_refresh(h);
1052 }
1053
1054 /**
1055  * Deletes the next word, maintaining the cursor at the same position.
1056  * @param h  The history data.
1057  */
1058 static void bc_history_edit_deleteNextWord(BcHistory *h) {
1059
1060         size_t next_end = h->pos, len = BC_HIST_BUF_LEN(h);
1061
1062         // If at the end of the line, skip.
1063         if (next_end == len) return;
1064
1065         // Find the word, then the end of the word.
1066         while (next_end < len && isspace(h->buf.v[next_end])) ++next_end;
1067         while (next_end < len && !isspace(h->buf.v[next_end])) ++next_end;
1068
1069         // Move the stuff into position.
1070         memmove(h->buf.v + h->pos, h->buf.v + next_end, len - next_end);
1071
1072         // Make the buffer valid again.
1073         h->buf.len -= next_end - h->pos;
1074
1075         bc_history_refresh(h);
1076 }
1077
1078 /**
1079  * Swaps two characters, the one under the cursor and the one to the left.
1080  * @param h  The history data.
1081  */
1082 static void bc_history_swap(BcHistory *h) {
1083
1084         size_t pcl, ncl;
1085         char auxb[5];
1086
1087         // Get the length of the previous and next characters.
1088         pcl = bc_history_prevLen(h->buf.v, h->pos);
1089         ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1090
1091         // To perform a swap we need:
1092         // * Nonzero char length to the left.
1093         // * To not be at the end of the line.
1094         if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5) {
1095
1096                 // Swap.
1097                 memcpy(auxb, h->buf.v + h->pos - pcl, pcl);
1098                 memcpy(h->buf.v + h->pos - pcl, h->buf.v + h->pos, ncl);
1099                 memcpy(h->buf.v + h->pos - pcl + ncl, auxb, pcl);
1100
1101                 // Reset the position.
1102                 h->pos += ((~pcl) + 1) + ncl;
1103
1104                 bc_history_refresh(h);
1105         }
1106 }
1107
1108 /**
1109  * Raises the specified signal. This is a convenience function.
1110  * @param h    The history data.
1111  * @param sig  The signal to raise.
1112  */
1113 static void bc_history_raise(BcHistory *h, int sig) {
1114
1115         // We really don't want to be in raw mode when longjmp()'s are flying.
1116         bc_history_disableRaw(h);
1117         raise(sig);
1118 }
1119
1120 /**
1121  * Handles escape sequences. This function will make sense if you know VT100
1122  * escape codes; otherwise, it will be confusing.
1123  * @param h  The history data.
1124  */
1125 static void bc_history_escape(BcHistory *h) {
1126
1127         char c, seq[3];
1128
1129         // Read a character into seq.
1130         if (BC_ERR(BC_HIST_READ(seq, 1))) return;
1131
1132         c = seq[0];
1133
1134         // ESC ? sequences.
1135         if (c != '[' && c != 'O') {
1136                 if (c == 'f') bc_history_edit_wordEnd(h);
1137                 else if (c == 'b') bc_history_edit_wordStart(h);
1138                 else if (c == 'd') bc_history_edit_deleteNextWord(h);
1139         }
1140         else {
1141
1142                 // Read a character into seq.
1143                 if (BC_ERR(BC_HIST_READ(seq + 1, 1)))
1144                         bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1145
1146                 // ESC [ sequences.
1147                 if (c == '[') {
1148
1149                         c = seq[1];
1150
1151                         if (c >= '0' && c <= '9') {
1152
1153                                 // Extended escape, read additional byte.
1154                                 if (BC_ERR(BC_HIST_READ(seq + 2, 1)))
1155                                         bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1156
1157                                 if (seq[2] == '~' && c == '3') bc_history_edit_delete(h);
1158                                 else if(seq[2] == ';') {
1159
1160                                         // Read two characters into seq.
1161                                         if (BC_ERR(BC_HIST_READ(seq, 2)))
1162                                                 bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1163
1164                                         if (seq[0] != '5') return;
1165                                         else if (seq[1] == 'C') bc_history_edit_wordEnd(h);
1166                                         else if (seq[1] == 'D') bc_history_edit_wordStart(h);
1167                                 }
1168                         }
1169                         else {
1170
1171                                 switch(c) {
1172
1173                                         // Up.
1174                                         case 'A':
1175                                         {
1176                                                 bc_history_edit_next(h, BC_HIST_PREV);
1177                                                 break;
1178                                         }
1179
1180                                         // Down.
1181                                         case 'B':
1182                                         {
1183                                                 bc_history_edit_next(h, BC_HIST_NEXT);
1184                                                 break;
1185                                         }
1186
1187                                         // Right.
1188                                         case 'C':
1189                                         {
1190                                                 bc_history_edit_right(h);
1191                                                 break;
1192                                         }
1193
1194                                         // Left.
1195                                         case 'D':
1196                                         {
1197                                                 bc_history_edit_left(h);
1198                                                 break;
1199                                         }
1200
1201                                         // Home.
1202                                         case 'H':
1203                                         case '1':
1204                                         {
1205                                                 bc_history_edit_home(h);
1206                                                 break;
1207                                         }
1208
1209                                         // End.
1210                                         case 'F':
1211                                         case '4':
1212                                         {
1213                                                 bc_history_edit_end(h);
1214                                                 break;
1215                                         }
1216
1217                                         case 'd':
1218                                         {
1219                                                 bc_history_edit_deleteNextWord(h);
1220                                                 break;
1221                                         }
1222                                 }
1223                         }
1224                 }
1225                 // ESC O sequences.
1226                 else {
1227
1228                         switch (seq[1]) {
1229
1230                                 case 'A':
1231                                 {
1232                                         bc_history_edit_next(h, BC_HIST_PREV);
1233                                         break;
1234                                 }
1235
1236                                 case 'B':
1237                                 {
1238                                         bc_history_edit_next(h, BC_HIST_NEXT);
1239                                         break;
1240                                 }
1241
1242                                 case 'C':
1243                                 {
1244                                         bc_history_edit_right(h);
1245                                         break;
1246                                 }
1247
1248                                 case 'D':
1249                                 {
1250                                         bc_history_edit_left(h);
1251                                         break;
1252                                 }
1253
1254                                 case 'F':
1255                                 {
1256                                         bc_history_edit_end(h);
1257                                         break;
1258                                 }
1259
1260                                 case 'H':
1261                                 {
1262                                         bc_history_edit_home(h);
1263                                         break;
1264                                 }
1265                         }
1266                 }
1267         }
1268 }
1269
1270 /**
1271  * Adds a line to the history.
1272  * @param h     The history data.
1273  * @param line  The line to add.
1274  */
1275 static void bc_history_add(BcHistory *h, char *line) {
1276
1277         // If there is something already there...
1278         if (h->history.len) {
1279
1280                 // Get the previous.
1281                 char *s = *((char**) bc_vec_item_rev(&h->history, 0));
1282
1283                 // Check for, and discard, duplicates.
1284                 if (!strcmp(s, line)) {
1285
1286                         BC_SIG_LOCK;
1287
1288                         free(line);
1289
1290                         BC_SIG_UNLOCK;
1291
1292                         return;
1293                 }
1294         }
1295
1296         bc_vec_push(&h->history, &line);
1297 }
1298
1299 /**
1300  * Adds an empty line to the history. This is separate from bc_history_add()
1301  * because we don't want it allocating.
1302  * @param h  The history data.
1303  */
1304 static void bc_history_add_empty(BcHistory *h) {
1305
1306         const char *line = "";
1307
1308         // If there is something already there...
1309         if (h->history.len) {
1310
1311                 // Get the previous.
1312                 char *s = *((char**) bc_vec_item_rev(&h->history, 0));
1313
1314                 // Check for, and discard, duplicates.
1315                 if (!s[0]) return;
1316         }
1317
1318         bc_vec_push(&h->history, &line);
1319 }
1320
1321 /**
1322  * Resets the history state to nothing.
1323  * @param h  The history data.
1324  */
1325 static void bc_history_reset(BcHistory *h) {
1326
1327         h->oldcolpos = h->pos = h->idx = 0;
1328         h->cols = bc_history_columns();
1329
1330         // The latest history entry is always our current buffer, that
1331         // initially is just an empty string.
1332         bc_history_add_empty(h);
1333
1334         // Buffer starts empty.
1335         bc_vec_empty(&h->buf);
1336 }
1337
1338 /**
1339  * Prints a control character.
1340  * @param h  The history data.
1341  * @param c  The control character to print.
1342  */
1343 static void bc_history_printCtrl(BcHistory *h, unsigned int c) {
1344
1345         char str[3] = "^A";
1346         const char newline[2] = "\n";
1347
1348         // Set the correct character.
1349         str[1] = (char) (c + 'A' - BC_ACTION_CTRL_A);
1350
1351         // Concatenate the string.
1352         bc_vec_concat(&h->buf, str);
1353
1354         bc_history_refresh(h);
1355
1356         // Pop the string.
1357         bc_vec_npop(&h->buf, sizeof(str));
1358         bc_vec_pushByte(&h->buf, '\0');
1359
1360 #ifndef _WIN32
1361         if (c != BC_ACTION_CTRL_C && c != BC_ACTION_CTRL_D)
1362 #endif // _WIN32
1363         {
1364                 // We sometimes want to print a newline; for the times we don't; it's
1365                 // because newlines are taken care of elsewhere.
1366                 bc_file_write(&vm.fout, bc_flush_none, newline, sizeof(newline) - 1);
1367                 bc_history_refresh(h);
1368         }
1369 }
1370
1371 /**
1372  * Edits a line of history. This function is the core of the line editing
1373  * capability of bc history. It expects 'fd' to be already in "raw mode" so that
1374  * every key pressed will be returned ASAP to read().
1375  * @param h       The history data.
1376  * @param prompt  The prompt.
1377  * @return        BC_STATUS_SUCCESS or BC_STATUS_EOF.
1378  */
1379 static BcStatus bc_history_edit(BcHistory *h, const char *prompt) {
1380
1381         bc_history_reset(h);
1382
1383         // Don't write the saved output the first time. This is because it has
1384         // already been written to output. In other words, don't uncomment the
1385         // line below or add anything like it.
1386         // bc_file_write(&vm.fout, bc_flush_none, h->extras.v, h->extras.len - 1);
1387
1388         // Write the prompt if desired.
1389         if (BC_PROMPT) {
1390
1391                 h->prompt = prompt;
1392                 h->plen = strlen(prompt);
1393                 h->pcol = bc_history_promptColLen(prompt, h->plen);
1394
1395                 bc_file_write(&vm.fout, bc_flush_none, prompt, h->plen);
1396                 bc_file_flush(&vm.fout, bc_flush_none);
1397         }
1398
1399         // This is the input loop.
1400         for (;;) {
1401
1402                 BcStatus s;
1403                 char cbuf[32];
1404                 unsigned int c = 0;
1405                 size_t nread = 0;
1406
1407                 // Read a code.
1408                 s = bc_history_readCode(cbuf, sizeof(cbuf), &c, &nread);
1409                 if (BC_ERR(s)) return s;
1410
1411                 switch (c) {
1412
1413                         case BC_ACTION_LINE_FEED:
1414                         case BC_ACTION_ENTER:
1415                         {
1416                                 // Return the line.
1417                                 bc_vec_pop(&h->history);
1418                                 return s;
1419                         }
1420
1421                         case BC_ACTION_TAB:
1422                         {
1423                                 // My tab handling is dumb; it just prints 8 spaces every time.
1424                                 memcpy(cbuf, bc_history_tab, bc_history_tab_len + 1);
1425                                 bc_history_edit_insert(h, cbuf, bc_history_tab_len);
1426                                 break;
1427                         }
1428
1429 #ifndef _WIN32
1430                         case BC_ACTION_CTRL_C:
1431                         {
1432                                 bc_history_printCtrl(h, c);
1433
1434                                 // Quit if the user wants it.
1435                                 if (!BC_SIGINT) {
1436                                         vm.status = BC_STATUS_QUIT;
1437                                         BC_JMP;
1438                                 }
1439
1440                                 // Print the ready message.
1441                                 bc_file_write(&vm.fout, bc_flush_none, vm.sigmsg, vm.siglen);
1442                                 bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg,
1443                                               bc_program_ready_msg_len);
1444                                 bc_history_reset(h);
1445                                 bc_history_refresh(h);
1446
1447                                 break;
1448                         }
1449 #endif // _WIN32
1450
1451                         case BC_ACTION_BACKSPACE:
1452                         case BC_ACTION_CTRL_H:
1453                         {
1454                                 bc_history_edit_backspace(h);
1455                                 break;
1456                         }
1457
1458 #ifndef _WIN32
1459                         // Act as end-of-file.
1460                         case BC_ACTION_CTRL_D:
1461                         {
1462                                 bc_history_printCtrl(h, c);
1463                                 return BC_STATUS_EOF;
1464                         }
1465 #endif // _WIN32
1466
1467                         // Swaps current character with previous.
1468                         case BC_ACTION_CTRL_T:
1469                         {
1470                                 bc_history_swap(h);
1471                                 break;
1472                         }
1473
1474                         case BC_ACTION_CTRL_B:
1475                         {
1476                                 bc_history_edit_left(h);
1477                                 break;
1478                         }
1479
1480                         case BC_ACTION_CTRL_F:
1481                         {
1482                                 bc_history_edit_right(h);
1483                                 break;
1484                         }
1485
1486                         case BC_ACTION_CTRL_P:
1487                         {
1488                                 bc_history_edit_next(h, BC_HIST_PREV);
1489                                 break;
1490                         }
1491
1492                         case BC_ACTION_CTRL_N:
1493                         {
1494                                 bc_history_edit_next(h, BC_HIST_NEXT);
1495                                 break;
1496                         }
1497
1498                         case BC_ACTION_ESC:
1499                         {
1500                                 bc_history_escape(h);
1501                                 break;
1502                         }
1503
1504                         // Delete the whole line.
1505                         case BC_ACTION_CTRL_U:
1506                         {
1507                                 bc_vec_string(&h->buf, 0, "");
1508                                 h->pos = 0;
1509
1510                                 bc_history_refresh(h);
1511
1512                                 break;
1513                         }
1514
1515                         // Delete from current to end of line.
1516                         case BC_ACTION_CTRL_K:
1517                         {
1518                                 bc_vec_npop(&h->buf, h->buf.len - h->pos);
1519                                 bc_vec_pushByte(&h->buf, '\0');
1520                                 bc_history_refresh(h);
1521                                 break;
1522                         }
1523
1524                         // Go to the start of the line.
1525                         case BC_ACTION_CTRL_A:
1526                         {
1527                                 bc_history_edit_home(h);
1528                                 break;
1529                         }
1530
1531                         // Go to the end of the line.
1532                         case BC_ACTION_CTRL_E:
1533                         {
1534                                 bc_history_edit_end(h);
1535                                 break;
1536                         }
1537
1538                         // Clear screen.
1539                         case BC_ACTION_CTRL_L:
1540                         {
1541                                 bc_file_write(&vm.fout, bc_flush_none, "\x1b[H\x1b[2J", 7);
1542                                 bc_history_refresh(h);
1543                                 break;
1544                         }
1545
1546                         // Delete previous word.
1547                         case BC_ACTION_CTRL_W:
1548                         {
1549                                 bc_history_edit_deletePrevWord(h);
1550                                 break;
1551                         }
1552
1553                         default:
1554                         {
1555                                 // If we have a control character, print it and raise signals as
1556                                 // needed.
1557                                 if ((c >= BC_ACTION_CTRL_A && c <= BC_ACTION_CTRL_Z) ||
1558                                     c == BC_ACTION_CTRL_BSLASH)
1559                                 {
1560                                         bc_history_printCtrl(h, c);
1561 #ifndef _WIN32
1562                                         if (c == BC_ACTION_CTRL_Z) bc_history_raise(h, SIGTSTP);
1563                                         if (c == BC_ACTION_CTRL_S) bc_history_raise(h, SIGSTOP);
1564                                         if (c == BC_ACTION_CTRL_BSLASH)
1565                                                 bc_history_raise(h, SIGQUIT);
1566 #else // _WIN32
1567                                         vm.status = BC_STATUS_QUIT;
1568                                         BC_JMP;
1569 #endif // _WIN32
1570                                 }
1571                                 // Otherwise, just insert.
1572                                 else bc_history_edit_insert(h, cbuf, nread);
1573                                 break;
1574                         }
1575                 }
1576         }
1577
1578         return BC_STATUS_SUCCESS;
1579 }
1580
1581 /**
1582  * Returns true if stdin has more data. This is for multi-line pasting, and it
1583  * does not work on Windows.
1584  * @param h  The history data.
1585  */
1586 static inline bool bc_history_stdinHasData(BcHistory *h) {
1587 #ifndef _WIN32
1588         int n;
1589         return pselect(1, &h->rdset, NULL, NULL, &h->ts, &h->sigmask) > 0 ||
1590                (ioctl(STDIN_FILENO, FIONREAD, &n) >= 0 && n > 0);
1591 #else // _WIN32
1592         return false;
1593 #endif // _WIN32
1594 }
1595
1596 BcStatus bc_history_line(BcHistory *h, BcVec *vec, const char *prompt) {
1597
1598         BcStatus s;
1599         char* line;
1600
1601         assert(vm.fout.len == 0);
1602
1603         bc_history_enableRaw(h);
1604
1605         do {
1606
1607                 // Do the edit.
1608                 s = bc_history_edit(h, prompt);
1609
1610                 // Print a newline and flush.
1611                 bc_file_write(&vm.fout, bc_flush_none, "\n", 1);
1612                 bc_file_flush(&vm.fout, bc_flush_none);
1613
1614                 // If we actually have data...
1615                 if (h->buf.v[0]) {
1616
1617                         BC_SIG_LOCK;
1618
1619                         // Duplicate it.
1620                         line = bc_vm_strdup(h->buf.v);
1621
1622                         BC_SIG_UNLOCK;
1623
1624                         // Store it.
1625                         bc_history_add(h, line);
1626                 }
1627                 // Add an empty string.
1628                 else bc_history_add_empty(h);
1629
1630                 // Concatenate the line to the return vector.
1631                 bc_vec_concat(vec, h->buf.v);
1632                 bc_vec_concat(vec, "\n");
1633
1634         } while (!s && bc_history_stdinHasData(h));
1635
1636         assert(!s || s == BC_STATUS_EOF);
1637
1638         bc_history_disableRaw(h);
1639
1640         return s;
1641 }
1642
1643 void bc_history_string_free(void *str) {
1644         char *s = *((char**) str);
1645         BC_SIG_ASSERT_LOCKED;
1646         if (s[0]) free(s);
1647 }
1648
1649 void bc_history_init(BcHistory *h) {
1650
1651 #ifdef _WIN32
1652         HANDLE out, in;
1653 #endif // _WIN32
1654
1655         BC_SIG_ASSERT_LOCKED;
1656
1657         h->rawMode = false;
1658         h->badTerm = bc_history_isBadTerm();
1659
1660 #ifdef _WIN32
1661
1662         h->orig_in = 0;
1663         h->orig_out = 0;
1664
1665         in = GetStdHandle(STD_INPUT_HANDLE);
1666         out = GetStdHandle(STD_OUTPUT_HANDLE);
1667
1668         if (!h->badTerm) {
1669                 SetConsoleCP(CP_UTF8);
1670                 SetConsoleOutputCP(CP_UTF8);
1671                 if (!GetConsoleMode(in, &h->orig_in) ||
1672                         !GetConsoleMode(out, &h->orig_out))
1673                 {
1674                         h->badTerm = true;
1675                         return;
1676                 }
1677                 else {
1678                         DWORD reqOut = ENABLE_VIRTUAL_TERMINAL_PROCESSING |
1679                                 DISABLE_NEWLINE_AUTO_RETURN;
1680                         DWORD reqIn = ENABLE_VIRTUAL_TERMINAL_INPUT;
1681                         if (!SetConsoleMode(in, h->orig_in | reqIn) ||
1682                                 !SetConsoleMode(out, h->orig_out | reqOut))
1683                         {
1684                                 h->badTerm = true;
1685                         }
1686                 }
1687         }
1688 #endif // _WIN32
1689
1690         bc_vec_init(&h->buf, sizeof(char), BC_DTOR_NONE);
1691         bc_vec_init(&h->history, sizeof(char*), BC_DTOR_HISTORY_STRING);
1692         bc_vec_init(&h->extras, sizeof(char), BC_DTOR_NONE);
1693
1694 #ifndef _WIN32
1695         FD_ZERO(&h->rdset);
1696         FD_SET(STDIN_FILENO, &h->rdset);
1697         h->ts.tv_sec = 0;
1698         h->ts.tv_nsec = 0;
1699
1700         sigemptyset(&h->sigmask);
1701         sigaddset(&h->sigmask, SIGINT);
1702 #endif // _WIN32
1703 }
1704
1705 void bc_history_free(BcHistory *h) {
1706         BC_SIG_ASSERT_LOCKED;
1707 #ifndef _WIN32
1708         bc_history_disableRaw(h);
1709 #else // _WIN32
1710         SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), h->orig_in);
1711         SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), h->orig_out);
1712 #endif // _WIN32
1713 #ifndef NDEBUG
1714         bc_vec_free(&h->buf);
1715         bc_vec_free(&h->history);
1716         bc_vec_free(&h->extras);
1717 #endif // NDEBUG
1718 }
1719
1720 #if BC_DEBUG_CODE
1721
1722 /**
1723  * Prints scan codes. This special mode is used by bc history in order to print
1724  * scan codes on screen for debugging / development purposes.
1725  * @param h  The history data.
1726  */
1727 void bc_history_printKeyCodes(BcHistory *h) {
1728
1729         char quit[4];
1730
1731         bc_vm_printf("Linenoise key codes debugging mode.\n"
1732                      "Press keys to see scan codes. "
1733                      "Type 'quit' at any time to exit.\n");
1734
1735         bc_history_enableRaw(h);
1736         memset(quit, ' ', 4);
1737
1738         while(true) {
1739
1740                 char c;
1741                 ssize_t nread;
1742
1743                 nread = bc_history_read(&c, 1);
1744                 if (nread <= 0) continue;
1745
1746                 // Shift string to left.
1747                 memmove(quit, quit + 1, sizeof(quit) - 1);
1748
1749                 // Insert current char on the right.
1750                 quit[sizeof(quit) - 1] = c;
1751                 if (!memcmp(quit, "quit", sizeof(quit))) break;
1752
1753                 bc_vm_printf("'%c' %lu (type quit to exit)\n",
1754                              isprint(c) ? c : '?', (unsigned long) c);
1755
1756                 // Go left edge manually, we are in raw mode.
1757                 bc_vm_putchar('\r', bc_flush_none);
1758                 bc_file_flush(&vm.fout, bc_flush_none);
1759         }
1760
1761         bc_history_disableRaw(h);
1762 }
1763 #endif // BC_DEBUG_CODE
1764
1765 #endif // BC_ENABLE_HISTORY