xref: /freebsd/contrib/bc/src/history.c (revision 924226fba12cc9a228c73b956e1b7fa24c60b055)
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 #if BC_ENABLE_EDITLINE
148 
149 #include <string.h>
150 #include <errno.h>
151 #include <setjmp.h>
152 
153 #include <history.h>
154 #include <vm.h>
155 
156 sigjmp_buf bc_history_jmpbuf;
157 volatile sig_atomic_t bc_history_inlinelib;
158 
159 static char* bc_history_prompt;
160 static char bc_history_no_prompt[] = "";
161 static HistEvent bc_history_event;
162 
163 static char*
164 bc_history_promptFunc(EditLine* el)
165 {
166 	BC_UNUSED(el);
167 	return BC_PROMPT ? bc_history_prompt : bc_history_no_prompt;
168 }
169 
170 void
171 bc_history_init(BcHistory* h)
172 {
173 	BcVec v;
174 	char* home;
175 
176 	home = getenv("HOME");
177 
178 	// This will hold the true path to the editrc.
179 	bc_vec_init(&v, 1, BC_DTOR_NONE);
180 
181 	// Initialize the path to the editrc. This is done manually because the
182 	// libedit I used to test was failing with a NULL argument for the path,
183 	// which was supposed to automatically do $HOME/.editrc. But it was failing,
184 	// so I set it manually.
185 	if (home == NULL)
186 	{
187 		bc_vec_string(&v, bc_history_editrc_len - 1, bc_history_editrc + 1);
188 	}
189 	else
190 	{
191 		bc_vec_string(&v, strlen(home), home);
192 		bc_vec_concat(&v, bc_history_editrc);
193 	}
194 
195 	h->hist = history_init();
196 	if (BC_ERR(h->hist == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
197 
198 	h->el = el_init(vm.name, stdin, stdout, stderr);
199 	if (BC_ERR(h->el == NULL)) bc_vm_fatalError(BC_ERR_FATAL_ALLOC_ERR);
200 
201 	// I want history and a prompt.
202 	history(h->hist, &bc_history_event, H_SETSIZE, 100);
203 	history(h->hist, &bc_history_event, H_SETUNIQUE, 1);
204 	el_set(h->el, EL_EDITOR, "emacs");
205 	el_set(h->el, EL_HIST, history, h->hist);
206 	el_set(h->el, EL_PROMPT, bc_history_promptFunc);
207 
208 	// I also want to get the user's .editrc.
209 	el_source(h->el, v.v);
210 
211 	bc_vec_free(&v);
212 
213 	h->badTerm = false;
214 	bc_history_prompt = NULL;
215 }
216 
217 void
218 bc_history_free(BcHistory* h)
219 {
220 	if (BC_PROMPT && bc_history_prompt != NULL) free(bc_history_prompt);
221 	el_end(h->el);
222 	history_end(h->hist);
223 }
224 
225 BcStatus
226 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
227 {
228 	BcStatus s = BC_STATUS_SUCCESS;
229 	const char* line;
230 	int len;
231 
232 	BC_SIG_LOCK;
233 
234 	// If the jump happens here, then a SIGINT occurred.
235 	if (sigsetjmp(bc_history_jmpbuf, 0))
236 	{
237 		bc_vec_string(vec, 1, "\n");
238 		goto end;
239 	}
240 
241 	// This is so the signal handler can handle line libraries properly.
242 	bc_history_inlinelib = 1;
243 
244 	if (BC_PROMPT)
245 	{
246 		// Make sure to set the prompt.
247 		if (bc_history_prompt != NULL)
248 		{
249 			if (strcmp(bc_history_prompt, prompt))
250 			{
251 				free(bc_history_prompt);
252 				bc_history_prompt = bc_vm_strdup(prompt);
253 			}
254 		}
255 		else bc_history_prompt = bc_vm_strdup(prompt);
256 	}
257 
258 	// Get the line.
259 	line = el_gets(h->el, &len);
260 
261 	// If there is no line...
262 	if (BC_ERR(line == NULL))
263 	{
264 		// If this is true, there was an error. Otherwise, it's just EOF.
265 		if (len == -1)
266 		{
267 			if (errno == ENOMEM) bc_err(BC_ERR_FATAL_ALLOC_ERR);
268 			bc_err(BC_ERR_FATAL_IO_ERR);
269 		}
270 		else
271 		{
272 			bc_file_printf(&vm.fout, "\n");
273 			s = BC_STATUS_EOF;
274 		}
275 	}
276 	// If there is a line...
277 	else
278 	{
279 		bc_vec_string(vec, strlen(line), line);
280 
281 		if (strcmp(line, "") && strcmp(line, "\n"))
282 		{
283 			history(h->hist, &bc_history_event, H_ENTER, line);
284 		}
285 
286 		s = BC_STATUS_SUCCESS;
287 	}
288 
289 end:
290 
291 	bc_history_inlinelib = 0;
292 
293 	BC_SIG_UNLOCK;
294 
295 	return s;
296 }
297 
298 #else // BC_ENABLE_EDITLINE
299 
300 #if BC_ENABLE_READLINE
301 
302 #include <assert.h>
303 #include <setjmp.h>
304 #include <string.h>
305 
306 #include <history.h>
307 #include <vm.h>
308 
309 sigjmp_buf bc_history_jmpbuf;
310 volatile sig_atomic_t bc_history_inlinelib;
311 
312 void
313 bc_history_init(BcHistory* h)
314 {
315 	h->line = NULL;
316 	h->badTerm = false;
317 
318 	// I want no tab completion.
319 	rl_bind_key('\t', rl_insert);
320 }
321 
322 void
323 bc_history_free(BcHistory* h)
324 {
325 	if (h->line != NULL) free(h->line);
326 }
327 
328 BcStatus
329 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
330 {
331 	BcStatus s = BC_STATUS_SUCCESS;
332 	size_t len;
333 
334 	BC_SIG_LOCK;
335 
336 	// If the jump happens here, then a SIGINT occurred.
337 	if (sigsetjmp(bc_history_jmpbuf, 0))
338 	{
339 		bc_vec_string(vec, 1, "\n");
340 		goto end;
341 	}
342 
343 	// This is so the signal handler can handle line libraries properly.
344 	bc_history_inlinelib = 1;
345 
346 	// Get rid of the last line.
347 	if (h->line != NULL)
348 	{
349 		free(h->line);
350 		h->line = NULL;
351 	}
352 
353 	// Get the line.
354 	h->line = readline(BC_PROMPT ? prompt : "");
355 
356 	// If there was a line, add it to the history. Otherwise, just return an
357 	// empty line. Oh, and NULL actually means EOF.
358 	if (h->line != NULL && h->line[0])
359 	{
360 		add_history(h->line);
361 
362 		len = strlen(h->line);
363 
364 		bc_vec_expand(vec, len + 2);
365 
366 		bc_vec_string(vec, len, h->line);
367 		bc_vec_concat(vec, "\n");
368 	}
369 	else if (h->line == NULL)
370 	{
371 		bc_file_printf(&vm.fout, "%s\n", "^D");
372 		s = BC_STATUS_EOF;
373 	}
374 	else bc_vec_string(vec, 1, "\n");
375 
376 end:
377 
378 	bc_history_inlinelib = 0;
379 
380 	BC_SIG_UNLOCK;
381 
382 	return s;
383 }
384 
385 #else // BC_ENABLE_READLINE
386 
387 #include <assert.h>
388 #include <stdlib.h>
389 #include <errno.h>
390 #include <string.h>
391 #include <ctype.h>
392 
393 #include <signal.h>
394 #include <sys/stat.h>
395 #include <sys/types.h>
396 
397 #ifndef _WIN32
398 #include <strings.h>
399 #include <termios.h>
400 #include <unistd.h>
401 #include <sys/ioctl.h>
402 #include <sys/select.h>
403 #endif // _WIN32
404 
405 #include <status.h>
406 #include <vector.h>
407 #include <history.h>
408 #include <read.h>
409 #include <file.h>
410 #include <vm.h>
411 
412 #if BC_DEBUG_CODE
413 
414 /// A file for outputting to when debugging.
415 BcFile bc_history_debug_fp;
416 
417 /// A buffer for the above file.
418 char* bc_history_debug_buf;
419 
420 #endif // BC_DEBUG_CODE
421 
422 /**
423  * Checks if the code is a wide character.
424  * @param cp  The codepoint to check.
425  * @return    True if @a cp is a wide character, false otherwise.
426  */
427 static bool
428 bc_history_wchar(uint32_t cp)
429 {
430 	size_t i;
431 
432 	for (i = 0; i < bc_history_wchars_len; ++i)
433 	{
434 		// Ranges are listed in ascending order.  Therefore, once the
435 		// whole range is higher than the codepoint we're testing, the
436 		// codepoint won't be found in any remaining range => bail early.
437 		if (bc_history_wchars[i][0] > cp) return false;
438 
439 		// Test this range.
440 		if (bc_history_wchars[i][0] <= cp && cp <= bc_history_wchars[i][1])
441 		{
442 			return true;
443 		}
444 	}
445 
446 	return false;
447 }
448 
449 /**
450  * Checks if the code is a combining character.
451  * @param cp  The codepoint to check.
452  * @return    True if @a cp is a combining character, false otherwise.
453  */
454 static bool
455 bc_history_comboChar(uint32_t cp)
456 {
457 	size_t i;
458 
459 	for (i = 0; i < bc_history_combo_chars_len; ++i)
460 	{
461 		// Combining chars are listed in ascending order, so once we pass
462 		// the codepoint of interest, we know it's not a combining char.
463 		if (bc_history_combo_chars[i] > cp) return false;
464 		if (bc_history_combo_chars[i] == cp) return true;
465 	}
466 
467 	return false;
468 }
469 
470 /**
471  * Gets the length of previous UTF8 character.
472  * @param buf  The buffer of characters.
473  * @param pos  The index into the buffer.
474  */
475 static size_t
476 bc_history_prevCharLen(const char* buf, size_t pos)
477 {
478 	size_t end = pos;
479 	for (pos -= 1; pos < end && (buf[pos] & 0xC0) == 0x80; --pos)
480 	{
481 		continue;
482 	}
483 	return end - (pos >= end ? 0 : pos);
484 }
485 
486 /**
487  * Converts UTF-8 to a Unicode code point.
488  * @param s    The string.
489  * @param len  The length of the string.
490  * @param cp   An out parameter for the codepoint.
491  * @return     The number of bytes eaten by the codepoint.
492  */
493 static size_t
494 bc_history_codePoint(const char* s, size_t len, uint32_t* cp)
495 {
496 	if (len)
497 	{
498 		uchar byte = (uchar) s[0];
499 
500 		// This is literally the UTF-8 decoding algorithm. Look that up if you
501 		// don't understand this.
502 
503 		if ((byte & 0x80) == 0)
504 		{
505 			*cp = byte;
506 			return 1;
507 		}
508 		else if ((byte & 0xE0) == 0xC0)
509 		{
510 			if (len >= 2)
511 			{
512 				*cp = (((uint32_t) (s[0] & 0x1F)) << 6) |
513 				      ((uint32_t) (s[1] & 0x3F));
514 				return 2;
515 			}
516 		}
517 		else if ((byte & 0xF0) == 0xE0)
518 		{
519 			if (len >= 3)
520 			{
521 				*cp = (((uint32_t) (s[0] & 0x0F)) << 12) |
522 				      (((uint32_t) (s[1] & 0x3F)) << 6) |
523 				      ((uint32_t) (s[2] & 0x3F));
524 				return 3;
525 			}
526 		}
527 		else if ((byte & 0xF8) == 0xF0)
528 		{
529 			if (len >= 4)
530 			{
531 				*cp = (((uint32_t) (s[0] & 0x07)) << 18) |
532 				      (((uint32_t) (s[1] & 0x3F)) << 12) |
533 				      (((uint32_t) (s[2] & 0x3F)) << 6) |
534 				      ((uint32_t) (s[3] & 0x3F));
535 				return 4;
536 			}
537 		}
538 		else
539 		{
540 			*cp = 0xFFFD;
541 			return 1;
542 		}
543 	}
544 
545 	*cp = 0;
546 
547 	return 1;
548 }
549 
550 /**
551  * Gets the length of next grapheme.
552  * @param buf      The buffer.
553  * @param buf_len  The length of the buffer.
554  * @param pos      The index into the buffer.
555  * @param col_len  An out parameter for the length of the grapheme on screen.
556  * @return         The number of bytes in the grapheme.
557  */
558 static size_t
559 bc_history_nextLen(const char* buf, size_t buf_len, size_t pos, size_t* col_len)
560 {
561 	uint32_t cp;
562 	size_t beg = pos;
563 	size_t len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
564 
565 	if (bc_history_comboChar(cp))
566 	{
567 		BC_UNREACHABLE
568 
569 		if (col_len != NULL) *col_len = 0;
570 
571 		return 0;
572 	}
573 
574 	// Store the width of the character on screen.
575 	if (col_len != NULL) *col_len = bc_history_wchar(cp) ? 2 : 1;
576 
577 	pos += len;
578 
579 	// Find the first non-combining character.
580 	while (pos < buf_len)
581 	{
582 		len = bc_history_codePoint(buf + pos, buf_len - pos, &cp);
583 
584 		if (!bc_history_comboChar(cp)) return pos - beg;
585 
586 		pos += len;
587 	}
588 
589 	return pos - beg;
590 }
591 
592 /**
593  * Gets the length of previous grapheme.
594  * @param buf  The buffer.
595  * @param pos  The index into the buffer.
596  * @return     The number of bytes in the grapheme.
597  */
598 static size_t
599 bc_history_prevLen(const char* buf, size_t pos)
600 {
601 	size_t end = pos;
602 
603 	// Find the first non-combining character.
604 	while (pos > 0)
605 	{
606 		uint32_t cp;
607 		size_t len = bc_history_prevCharLen(buf, pos);
608 
609 		pos -= len;
610 		bc_history_codePoint(buf + pos, len, &cp);
611 
612 		// The original linenoise-mob had an extra parameter col_len, like
613 		// bc_history_nextLen(), which, if not NULL, was set in this if
614 		// statement. However, we always passed NULL, so just skip that.
615 		if (!bc_history_comboChar(cp)) return end - pos;
616 	}
617 
618 	BC_UNREACHABLE
619 
620 	return 0;
621 }
622 
623 /**
624  * Reads @a n characters from stdin.
625  * @param buf  The buffer to read into. The caller is responsible for making
626  *             sure this is big enough for @a n.
627  * @param n    The number of characters to read.
628  * @return     The number of characters read or less than 0 on error.
629  */
630 static ssize_t
631 bc_history_read(char* buf, size_t n)
632 {
633 	ssize_t ret;
634 
635 	BC_SIG_ASSERT_LOCKED;
636 
637 #ifndef _WIN32
638 
639 	do
640 	{
641 		// We don't care about being interrupted.
642 		ret = read(STDIN_FILENO, buf, n);
643 	}
644 	while (ret == EINTR);
645 
646 #else // _WIN32
647 
648 	bool good;
649 	DWORD read;
650 	HANDLE hn = GetStdHandle(STD_INPUT_HANDLE);
651 
652 	good = ReadConsole(hn, buf, (DWORD) n, &read, NULL);
653 
654 	ret = (read != n || !good) ? -1 : 1;
655 
656 #endif // _WIN32
657 
658 	return ret;
659 }
660 
661 /**
662  * Reads a Unicode code point into a buffer.
663  * @param buf      The buffer to read into.
664  * @param buf_len  The length of the buffer.
665  * @param cp       An out parameter for the codepoint.
666  * @param nread    An out parameter for the number of bytes read.
667  * @return         BC_STATUS_EOF or BC_STATUS_SUCCESS.
668  */
669 static BcStatus
670 bc_history_readCode(char* buf, size_t buf_len, uint32_t* cp, size_t* nread)
671 {
672 	ssize_t n;
673 
674 	assert(buf_len >= 1);
675 
676 	BC_SIG_LOCK;
677 
678 	// Read a byte.
679 	n = bc_history_read(buf, 1);
680 
681 	BC_SIG_UNLOCK;
682 
683 	if (BC_ERR(n <= 0)) goto err;
684 
685 	// Get the byte.
686 	uchar byte = ((uchar*) buf)[0];
687 
688 	// Once again, this is the UTF-8 decoding algorithm, but it has reads
689 	// instead of actual decoding.
690 	if ((byte & 0x80) != 0)
691 	{
692 		if ((byte & 0xE0) == 0xC0)
693 		{
694 			assert(buf_len >= 2);
695 
696 			BC_SIG_LOCK;
697 
698 			n = bc_history_read(buf + 1, 1);
699 
700 			BC_SIG_UNLOCK;
701 
702 			if (BC_ERR(n <= 0)) goto err;
703 		}
704 		else if ((byte & 0xF0) == 0xE0)
705 		{
706 			assert(buf_len >= 3);
707 
708 			BC_SIG_LOCK;
709 
710 			n = bc_history_read(buf + 1, 2);
711 
712 			BC_SIG_UNLOCK;
713 
714 			if (BC_ERR(n <= 0)) goto err;
715 		}
716 		else if ((byte & 0xF8) == 0xF0)
717 		{
718 			assert(buf_len >= 3);
719 
720 			BC_SIG_LOCK;
721 
722 			n = bc_history_read(buf + 1, 3);
723 
724 			BC_SIG_UNLOCK;
725 
726 			if (BC_ERR(n <= 0)) goto err;
727 		}
728 		else
729 		{
730 			n = -1;
731 			goto err;
732 		}
733 	}
734 
735 	// Convert to the codepoint.
736 	*nread = bc_history_codePoint(buf, buf_len, cp);
737 
738 	return BC_STATUS_SUCCESS;
739 
740 err:
741 	// If we get here, we either had a fatal error of EOF.
742 	if (BC_ERR(n < 0)) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
743 	else *nread = (size_t) n;
744 	return BC_STATUS_EOF;
745 }
746 
747 /**
748  * Gets the column length from beginning of buffer to current byte position.
749  * @param buf      The buffer.
750  * @param buf_len  The length of the buffer.
751  * @param pos      The index into the buffer.
752  * @return         The number of columns between the beginning of @a buffer to
753  *                 @a pos.
754  */
755 static size_t
756 bc_history_colPos(const char* buf, size_t buf_len, size_t pos)
757 {
758 	size_t ret = 0, off = 0;
759 
760 	// While we haven't reached the offset, get the length of the next grapheme.
761 	while (off < pos && off < buf_len)
762 	{
763 		size_t col_len, len;
764 
765 		len = bc_history_nextLen(buf, buf_len, off, &col_len);
766 
767 		off += len;
768 		ret += col_len;
769 	}
770 
771 	return ret;
772 }
773 
774 /**
775  * Returns true if the terminal name is in the list of terminals we know are
776  * not able to understand basic escape sequences.
777  * @return  True if the terminal is a bad terminal.
778  */
779 static inline bool
780 bc_history_isBadTerm(void)
781 {
782 	size_t i;
783 	bool ret = false;
784 	char* term = bc_vm_getenv("TERM");
785 
786 	if (term == NULL) return false;
787 
788 	for (i = 0; !ret && bc_history_bad_terms[i]; ++i)
789 	{
790 		ret = (!strcasecmp(term, bc_history_bad_terms[i]));
791 	}
792 
793 	bc_vm_getenvFree(term);
794 
795 	return ret;
796 }
797 
798 /**
799  * Enables raw mode (1960's black magic).
800  * @param h  The history data.
801  */
802 static void
803 bc_history_enableRaw(BcHistory* h)
804 {
805 	// I don't do anything for Windows because in Windows, you set their
806 	// equivalent of raw mode and leave it, so I do it in bc_history_init().
807 
808 #ifndef _WIN32
809 	struct termios raw;
810 	int err;
811 
812 	assert(BC_TTYIN);
813 
814 	if (h->rawMode) return;
815 
816 	BC_SIG_LOCK;
817 
818 	if (BC_ERR(tcgetattr(STDIN_FILENO, &h->orig_termios) == -1))
819 	{
820 		bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
821 	}
822 
823 	BC_SIG_UNLOCK;
824 
825 	// Modify the original mode.
826 	raw = h->orig_termios;
827 
828 	// Input modes: no break, no CR to NL, no parity check, no strip char,
829 	// no start/stop output control.
830 	raw.c_iflag &= (unsigned int) (~(BRKINT | ICRNL | INPCK | ISTRIP | IXON));
831 
832 	// Control modes: set 8 bit chars.
833 	raw.c_cflag |= (CS8);
834 
835 	// Local modes - choing off, canonical off, no extended functions,
836 	// no signal chars (^Z,^C).
837 	raw.c_lflag &= (unsigned int) (~(ECHO | ICANON | IEXTEN | ISIG));
838 
839 	// Control chars - set return condition: min number of bytes and timer.
840 	// We want read to give every single byte, w/o timeout (1 byte, no timer).
841 	raw.c_cc[VMIN] = 1;
842 	raw.c_cc[VTIME] = 0;
843 
844 	BC_SIG_LOCK;
845 
846 	// Put terminal in raw mode after flushing.
847 	do
848 	{
849 		err = tcsetattr(STDIN_FILENO, TCSAFLUSH, &raw);
850 	}
851 	while (BC_ERR(err < 0) && errno == EINTR);
852 
853 	BC_SIG_UNLOCK;
854 
855 	if (BC_ERR(err < 0)) bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
856 #endif // _WIN32
857 
858 	h->rawMode = true;
859 }
860 
861 /**
862  * Disables raw mode.
863  * @param h  The history data.
864  */
865 static void
866 bc_history_disableRaw(BcHistory* h)
867 {
868 	sig_atomic_t lock;
869 
870 	if (!h->rawMode) return;
871 
872 	BC_SIG_TRYLOCK(lock);
873 
874 #ifndef _WIN32
875 	if (BC_ERR(tcsetattr(STDIN_FILENO, TCSAFLUSH, &h->orig_termios) != -1))
876 	{
877 		h->rawMode = false;
878 	}
879 #endif // _WIN32
880 
881 	BC_SIG_TRYUNLOCK(lock);
882 }
883 
884 /**
885  * Uses the ESC [6n escape sequence to query the horizontal cursor position
886  * and return it. On error -1 is returned, on success the position of the
887  * cursor.
888  * @return  The horizontal cursor position.
889  */
890 static size_t
891 bc_history_cursorPos(void)
892 {
893 	char buf[BC_HIST_SEQ_SIZE];
894 	char* ptr;
895 	char* ptr2;
896 	size_t cols, rows, i;
897 
898 	BC_SIG_ASSERT_LOCKED;
899 
900 	// Report cursor location.
901 	bc_file_write(&vm.fout, bc_flush_none, "\x1b[6n", 4);
902 	bc_file_flush(&vm.fout, bc_flush_none);
903 
904 	// Read the response: ESC [ rows ; cols R.
905 	for (i = 0; i < sizeof(buf) - 1; ++i)
906 	{
907 		if (bc_history_read(buf + i, 1) != 1 || buf[i] == 'R') break;
908 	}
909 
910 	buf[i] = '\0';
911 
912 	// This is basically an error; we didn't get what we were expecting.
913 	if (BC_ERR(buf[0] != BC_ACTION_ESC || buf[1] != '[')) return SIZE_MAX;
914 
915 	// Parse the rows.
916 	ptr = buf + 2;
917 	rows = strtoul(ptr, &ptr2, 10);
918 
919 	// Here we also didn't get what we were expecting.
920 	if (BC_ERR(!rows || ptr2[0] != ';')) return SIZE_MAX;
921 
922 	// Parse the columns.
923 	ptr = ptr2 + 1;
924 	cols = strtoul(ptr, NULL, 10);
925 
926 	if (BC_ERR(!cols)) return SIZE_MAX;
927 
928 	return cols <= UINT16_MAX ? cols : 0;
929 }
930 
931 /**
932  * Tries to get the number of columns in the current terminal, or assume 80
933  * if it fails.
934  * @return  The number of columns in the terminal.
935  */
936 static size_t
937 bc_history_columns(void)
938 {
939 
940 #ifndef _WIN32
941 
942 	struct winsize ws;
943 	int ret;
944 
945 	ret = ioctl(vm.fout.fd, TIOCGWINSZ, &ws);
946 
947 	if (BC_ERR(ret == -1 || !ws.ws_col))
948 	{
949 		// Calling ioctl() failed. Try to query the terminal itself.
950 		size_t start, cols;
951 
952 		// Get the initial position so we can restore it later.
953 		start = bc_history_cursorPos();
954 		if (BC_ERR(start == SIZE_MAX)) return BC_HIST_DEF_COLS;
955 
956 		// Go to right margin and get position.
957 		bc_file_write(&vm.fout, bc_flush_none, "\x1b[999C", 6);
958 		bc_file_flush(&vm.fout, bc_flush_none);
959 		cols = bc_history_cursorPos();
960 		if (BC_ERR(cols == SIZE_MAX)) return BC_HIST_DEF_COLS;
961 
962 		// Restore position.
963 		if (cols > start)
964 		{
965 			bc_file_printf(&vm.fout, "\x1b[%zuD", cols - start);
966 			bc_file_flush(&vm.fout, bc_flush_none);
967 		}
968 
969 		return cols;
970 	}
971 
972 	return ws.ws_col;
973 
974 #else // _WIN32
975 
976 	CONSOLE_SCREEN_BUFFER_INFO csbi;
977 
978 	if (!GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi))
979 	{
980 		return 80;
981 	}
982 
983 	return ((size_t) (csbi.srWindow.Right)) - csbi.srWindow.Left + 1;
984 
985 #endif // _WIN32
986 }
987 
988 /**
989  * Gets the column length of prompt text. This is probably unnecessary because
990  * the prompts that I use are ASCII, but I kept it just in case.
991  * @param prompt  The prompt.
992  * @param plen    The length of the prompt.
993  * @return        The column length of the prompt.
994  */
995 static size_t
996 bc_history_promptColLen(const char* prompt, size_t plen)
997 {
998 	char buf[BC_HIST_MAX_LINE + 1];
999 	size_t buf_len = 0, off = 0;
1000 
1001 	// The original linenoise-mob checked for ANSI escapes here on the prompt. I
1002 	// know the prompts do not have ANSI escapes. I deleted the code.
1003 	while (off < plen)
1004 	{
1005 		buf[buf_len++] = prompt[off++];
1006 	}
1007 
1008 	return bc_history_colPos(buf, buf_len, buf_len);
1009 }
1010 
1011 /**
1012  * Rewrites the currently edited line accordingly to the buffer content,
1013  * cursor position, and number of columns of the terminal.
1014  * @param h  The history data.
1015  */
1016 static void
1017 bc_history_refresh(BcHistory* h)
1018 {
1019 	char* buf = h->buf.v;
1020 	size_t colpos, len = BC_HIST_BUF_LEN(h), pos = h->pos, extras_len = 0;
1021 
1022 	BC_SIG_ASSERT_LOCKED;
1023 
1024 	bc_file_flush(&vm.fout, bc_flush_none);
1025 
1026 	// Get to the prompt column position from the left.
1027 	while (h->pcol + bc_history_colPos(buf, len, pos) >= h->cols)
1028 	{
1029 		size_t chlen = bc_history_nextLen(buf, len, 0, NULL);
1030 
1031 		buf += chlen;
1032 		len -= chlen;
1033 		pos -= chlen;
1034 	}
1035 
1036 	// Get to the prompt column position from the right.
1037 	while (h->pcol + bc_history_colPos(buf, len, len) > h->cols)
1038 	{
1039 		len -= bc_history_prevLen(buf, len);
1040 	}
1041 
1042 	// Cursor to left edge.
1043 	bc_file_write(&vm.fout, bc_flush_none, "\r", 1);
1044 
1045 	// Take the extra stuff into account. This is where history makes sure to
1046 	// preserve stuff that was printed without a newline.
1047 	if (h->extras.len > 1)
1048 	{
1049 		extras_len = h->extras.len - 1;
1050 
1051 		bc_vec_grow(&h->buf, extras_len);
1052 
1053 		len += extras_len;
1054 		pos += extras_len;
1055 
1056 		bc_file_write(&vm.fout, bc_flush_none, h->extras.v, extras_len);
1057 	}
1058 
1059 	// Write the prompt, if desired.
1060 	if (BC_PROMPT) bc_file_write(&vm.fout, bc_flush_none, h->prompt, h->plen);
1061 
1062 	bc_file_write(&vm.fout, bc_flush_none, h->buf.v, len - extras_len);
1063 
1064 	// Erase to right.
1065 	bc_file_write(&vm.fout, bc_flush_none, "\x1b[0K", 4);
1066 
1067 	// We need to be sure to grow this.
1068 	if (pos >= h->buf.len - extras_len) bc_vec_grow(&h->buf, pos + extras_len);
1069 
1070 	// Move cursor to original position. Do NOT move the putchar of '\r' to the
1071 	// printf with colpos. That causes a bug where the cursor will go to the end
1072 	// of the line when there is no prompt.
1073 	bc_file_putchar(&vm.fout, bc_flush_none, '\r');
1074 	colpos = bc_history_colPos(h->buf.v, len - extras_len, pos) + h->pcol;
1075 
1076 	// Set the cursor position again.
1077 	if (colpos) bc_file_printf(&vm.fout, "\x1b[%zuC", colpos);
1078 
1079 	bc_file_flush(&vm.fout, bc_flush_none);
1080 }
1081 
1082 /**
1083  * Inserts the character(s) 'c' at cursor current position.
1084  * @param h     The history data.
1085  * @param cbuf  The character buffer to copy from.
1086  * @param clen  The number of characters to copy.
1087  */
1088 static void
1089 bc_history_edit_insert(BcHistory* h, const char* cbuf, size_t clen)
1090 {
1091 	BC_SIG_ASSERT_LOCKED;
1092 
1093 	bc_vec_grow(&h->buf, clen);
1094 
1095 	// If we are at the end of the line...
1096 	if (h->pos == BC_HIST_BUF_LEN(h))
1097 	{
1098 		size_t colpos = 0, len;
1099 
1100 		// Copy into the buffer.
1101 		memcpy(bc_vec_item(&h->buf, h->pos), cbuf, clen);
1102 
1103 		// Adjust the buffer.
1104 		h->pos += clen;
1105 		h->buf.len += clen - 1;
1106 		bc_vec_pushByte(&h->buf, '\0');
1107 
1108 		// Set the length and column position.
1109 		len = BC_HIST_BUF_LEN(h) + h->extras.len - 1;
1110 		colpos = bc_history_promptColLen(h->prompt, h->plen);
1111 		colpos += bc_history_colPos(h->buf.v, len, len);
1112 
1113 		// Do we have the trivial case?
1114 		if (colpos < h->cols)
1115 		{
1116 			// Avoid a full update of the line in the trivial case.
1117 			bc_file_write(&vm.fout, bc_flush_none, cbuf, clen);
1118 			bc_file_flush(&vm.fout, bc_flush_none);
1119 		}
1120 		else bc_history_refresh(h);
1121 	}
1122 	else
1123 	{
1124 		// Amount that we need to move.
1125 		size_t amt = BC_HIST_BUF_LEN(h) - h->pos;
1126 
1127 		// Move the stuff.
1128 		memmove(h->buf.v + h->pos + clen, h->buf.v + h->pos, amt);
1129 		memcpy(h->buf.v + h->pos, cbuf, clen);
1130 
1131 		// Adjust the buffer.
1132 		h->pos += clen;
1133 		h->buf.len += clen;
1134 		h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1135 
1136 		bc_history_refresh(h);
1137 	}
1138 }
1139 
1140 /**
1141  * Moves the cursor to the left.
1142  * @param h  The history data.
1143  */
1144 static void
1145 bc_history_edit_left(BcHistory* h)
1146 {
1147 	BC_SIG_ASSERT_LOCKED;
1148 
1149 	// Stop at the left end.
1150 	if (h->pos <= 0) return;
1151 
1152 	h->pos -= bc_history_prevLen(h->buf.v, h->pos);
1153 
1154 	bc_history_refresh(h);
1155 }
1156 
1157 /**
1158  * Moves the cursor to the right.
1159  * @param h  The history data.
1160  */
1161 static void
1162 bc_history_edit_right(BcHistory* h)
1163 {
1164 	BC_SIG_ASSERT_LOCKED;
1165 
1166 	// Stop at the right end.
1167 	if (h->pos == BC_HIST_BUF_LEN(h)) return;
1168 
1169 	h->pos += bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1170 
1171 	bc_history_refresh(h);
1172 }
1173 
1174 /**
1175  * Moves the cursor to the end of the current word.
1176  * @param h  The history data.
1177  */
1178 static void
1179 bc_history_edit_wordEnd(BcHistory* h)
1180 {
1181 	size_t len = BC_HIST_BUF_LEN(h);
1182 
1183 	BC_SIG_ASSERT_LOCKED;
1184 
1185 	// Don't overflow.
1186 	if (!len || h->pos >= len) return;
1187 
1188 	// Find the word, then find the end of it.
1189 	while (h->pos < len && isspace(h->buf.v[h->pos]))
1190 	{
1191 		h->pos += 1;
1192 	}
1193 	while (h->pos < len && !isspace(h->buf.v[h->pos]))
1194 	{
1195 		h->pos += 1;
1196 	}
1197 
1198 	bc_history_refresh(h);
1199 }
1200 
1201 /**
1202  * Moves the cursor to the start of the current word.
1203  * @param h  The history data.
1204  */
1205 static void
1206 bc_history_edit_wordStart(BcHistory* h)
1207 {
1208 	size_t len = BC_HIST_BUF_LEN(h);
1209 
1210 	BC_SIG_ASSERT_LOCKED;
1211 
1212 	// Stop with no data.
1213 	if (!len) return;
1214 
1215 	// Find the word, the find the beginning of the word.
1216 	while (h->pos > 0 && isspace(h->buf.v[h->pos - 1]))
1217 	{
1218 		h->pos -= 1;
1219 	}
1220 	while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1]))
1221 	{
1222 		h->pos -= 1;
1223 	}
1224 
1225 	bc_history_refresh(h);
1226 }
1227 
1228 /**
1229  * Moves the cursor to the start of the line.
1230  * @param h  The history data.
1231  */
1232 static void
1233 bc_history_edit_home(BcHistory* h)
1234 {
1235 	BC_SIG_ASSERT_LOCKED;
1236 
1237 	// Stop at the beginning.
1238 	if (!h->pos) return;
1239 
1240 	h->pos = 0;
1241 
1242 	bc_history_refresh(h);
1243 }
1244 
1245 /**
1246  * Moves the cursor to the end of the line.
1247  * @param h  The history data.
1248  */
1249 static void
1250 bc_history_edit_end(BcHistory* h)
1251 {
1252 	BC_SIG_ASSERT_LOCKED;
1253 
1254 	// Stop at the end of the line.
1255 	if (h->pos == BC_HIST_BUF_LEN(h)) return;
1256 
1257 	h->pos = BC_HIST_BUF_LEN(h);
1258 
1259 	bc_history_refresh(h);
1260 }
1261 
1262 /**
1263  * Substitutes the currently edited line with the next or previous history
1264  * entry as specified by 'dir' (direction).
1265  * @param h    The history data.
1266  * @param dir  The direction to substitute; true means previous, false next.
1267  */
1268 static void
1269 bc_history_edit_next(BcHistory* h, bool dir)
1270 {
1271 	const char* dup;
1272 	const char* str;
1273 
1274 	BC_SIG_ASSERT_LOCKED;
1275 
1276 	// Stop if there is no history.
1277 	if (h->history.len <= 1) return;
1278 
1279 	// Duplicate the buffer.
1280 	if (h->buf.v[0]) dup = bc_vm_strdup(h->buf.v);
1281 	else dup = "";
1282 
1283 	// Update the current history entry before overwriting it with the next one.
1284 	bc_vec_replaceAt(&h->history, h->history.len - 1 - h->idx, &dup);
1285 
1286 	// Show the new entry.
1287 	h->idx += (dir == BC_HIST_PREV ? 1 : SIZE_MAX);
1288 
1289 	// Se the index appropriately at the ends.
1290 	if (h->idx == SIZE_MAX)
1291 	{
1292 		h->idx = 0;
1293 		return;
1294 	}
1295 	else if (h->idx >= h->history.len)
1296 	{
1297 		h->idx = h->history.len - 1;
1298 		return;
1299 	}
1300 
1301 	// Get the string.
1302 	str = *((char**) bc_vec_item(&h->history, h->history.len - 1 - h->idx));
1303 	bc_vec_string(&h->buf, strlen(str), str);
1304 
1305 	assert(h->buf.len > 0);
1306 
1307 	// Set the position at the end.
1308 	h->pos = BC_HIST_BUF_LEN(h);
1309 
1310 	bc_history_refresh(h);
1311 }
1312 
1313 /**
1314  * Deletes the character at the right of the cursor without altering the cursor
1315  * position. Basically, this is what happens with the "Delete" keyboard key.
1316  * @param h  The history data.
1317  */
1318 static void
1319 bc_history_edit_delete(BcHistory* h)
1320 {
1321 	size_t chlen, len = BC_HIST_BUF_LEN(h);
1322 
1323 	BC_SIG_ASSERT_LOCKED;
1324 
1325 	// If there is no character, skip.
1326 	if (!len || h->pos >= len) return;
1327 
1328 	// Get the length of the character.
1329 	chlen = bc_history_nextLen(h->buf.v, len, h->pos, NULL);
1330 
1331 	// Move characters after it into its place.
1332 	memmove(h->buf.v + h->pos, h->buf.v + h->pos + chlen, len - h->pos - chlen);
1333 
1334 	// Make the buffer valid again.
1335 	h->buf.len -= chlen;
1336 	h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1337 
1338 	bc_history_refresh(h);
1339 }
1340 
1341 /**
1342  * Deletes the character to the left of the cursor and moves the cursor back one
1343  * space. Basically, this is what happens with the "Backspace" keyboard key.
1344  * @param h  The history data.
1345  */
1346 static void
1347 bc_history_edit_backspace(BcHistory* h)
1348 {
1349 	size_t chlen, len = BC_HIST_BUF_LEN(h);
1350 
1351 	BC_SIG_ASSERT_LOCKED;
1352 
1353 	// If there are no characters, skip.
1354 	if (!h->pos || !len) return;
1355 
1356 	// Get the length of the previous character.
1357 	chlen = bc_history_prevLen(h->buf.v, h->pos);
1358 
1359 	// Move everything back one.
1360 	memmove(h->buf.v + h->pos - chlen, h->buf.v + h->pos, len - h->pos);
1361 
1362 	// Make the buffer valid again.
1363 	h->pos -= chlen;
1364 	h->buf.len -= chlen;
1365 	h->buf.v[BC_HIST_BUF_LEN(h)] = '\0';
1366 
1367 	bc_history_refresh(h);
1368 }
1369 
1370 /**
1371  * Deletes the previous word, maintaining the cursor at the start of the
1372  * current word.
1373  * @param h  The history data.
1374  */
1375 static void
1376 bc_history_edit_deletePrevWord(BcHistory* h)
1377 {
1378 	size_t diff, old_pos = h->pos;
1379 
1380 	BC_SIG_ASSERT_LOCKED;
1381 
1382 	// If at the beginning of the line, skip.
1383 	if (!old_pos) return;
1384 
1385 	// Find the word, then the beginning of the word.
1386 	while (h->pos > 0 && isspace(h->buf.v[h->pos - 1]))
1387 	{
1388 		h->pos -= 1;
1389 	}
1390 	while (h->pos > 0 && !isspace(h->buf.v[h->pos - 1]))
1391 	{
1392 		h->pos -= 1;
1393 	}
1394 
1395 	// Get the difference in position.
1396 	diff = old_pos - h->pos;
1397 
1398 	// Move the data back.
1399 	memmove(h->buf.v + h->pos, h->buf.v + old_pos,
1400 	        BC_HIST_BUF_LEN(h) - old_pos + 1);
1401 
1402 	// Make the buffer valid again.
1403 	h->buf.len -= diff;
1404 
1405 	bc_history_refresh(h);
1406 }
1407 
1408 /**
1409  * Deletes the next word, maintaining the cursor at the same position.
1410  * @param h  The history data.
1411  */
1412 static void
1413 bc_history_edit_deleteNextWord(BcHistory* h)
1414 {
1415 	size_t next_end = h->pos, len = BC_HIST_BUF_LEN(h);
1416 
1417 	BC_SIG_ASSERT_LOCKED;
1418 
1419 	// If at the end of the line, skip.
1420 	if (next_end == len) return;
1421 
1422 	// Find the word, then the end of the word.
1423 	while (next_end < len && isspace(h->buf.v[next_end]))
1424 	{
1425 		next_end += 1;
1426 	}
1427 	while (next_end < len && !isspace(h->buf.v[next_end]))
1428 	{
1429 		next_end += 1;
1430 	}
1431 
1432 	// Move the stuff into position.
1433 	memmove(h->buf.v + h->pos, h->buf.v + next_end, len - next_end);
1434 
1435 	// Make the buffer valid again.
1436 	h->buf.len -= next_end - h->pos;
1437 
1438 	bc_history_refresh(h);
1439 }
1440 
1441 /**
1442  * Swaps two characters, the one under the cursor and the one to the left.
1443  * @param h  The history data.
1444  */
1445 static void
1446 bc_history_swap(BcHistory* h)
1447 {
1448 	size_t pcl, ncl;
1449 	char auxb[5];
1450 
1451 	BC_SIG_ASSERT_LOCKED;
1452 
1453 	// Get the length of the previous and next characters.
1454 	pcl = bc_history_prevLen(h->buf.v, h->pos);
1455 	ncl = bc_history_nextLen(h->buf.v, BC_HIST_BUF_LEN(h), h->pos, NULL);
1456 
1457 	// To perform a swap we need:
1458 	// * Nonzero char length to the left.
1459 	// * To not be at the end of the line.
1460 	if (pcl && h->pos != BC_HIST_BUF_LEN(h) && pcl < 5 && ncl < 5)
1461 	{
1462 		// Swap.
1463 		memcpy(auxb, h->buf.v + h->pos - pcl, pcl);
1464 		memcpy(h->buf.v + h->pos - pcl, h->buf.v + h->pos, ncl);
1465 		memcpy(h->buf.v + h->pos - pcl + ncl, auxb, pcl);
1466 
1467 		// Reset the position.
1468 		h->pos += ((~pcl) + 1) + ncl;
1469 
1470 		bc_history_refresh(h);
1471 	}
1472 }
1473 
1474 /**
1475  * Raises the specified signal. This is a convenience function.
1476  * @param h    The history data.
1477  * @param sig  The signal to raise.
1478  */
1479 static void
1480 bc_history_raise(BcHistory* h, int sig)
1481 {
1482 	// We really don't want to be in raw mode when longjmp()'s are flying.
1483 	bc_history_disableRaw(h);
1484 	raise(sig);
1485 }
1486 
1487 /**
1488  * Handles escape sequences. This function will make sense if you know VT100
1489  * escape codes; otherwise, it will be confusing.
1490  * @param h  The history data.
1491  */
1492 static void
1493 bc_history_escape(BcHistory* h)
1494 {
1495 	char c, seq[3];
1496 
1497 	BC_SIG_ASSERT_LOCKED;
1498 
1499 	// Read a character into seq.
1500 	if (BC_ERR(BC_HIST_READ(seq, 1))) return;
1501 
1502 	c = seq[0];
1503 
1504 	// ESC ? sequences.
1505 	if (c != '[' && c != 'O')
1506 	{
1507 		if (c == 'f') bc_history_edit_wordEnd(h);
1508 		else if (c == 'b') bc_history_edit_wordStart(h);
1509 		else if (c == 'd') bc_history_edit_deleteNextWord(h);
1510 	}
1511 	else
1512 	{
1513 		// Read a character into seq.
1514 		if (BC_ERR(BC_HIST_READ(seq + 1, 1)))
1515 		{
1516 			bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1517 		}
1518 
1519 		// ESC [ sequences.
1520 		if (c == '[')
1521 		{
1522 			c = seq[1];
1523 
1524 			if (c >= '0' && c <= '9')
1525 			{
1526 				// Extended escape, read additional byte.
1527 				if (BC_ERR(BC_HIST_READ(seq + 2, 1)))
1528 				{
1529 					bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1530 				}
1531 
1532 				if (seq[2] == '~')
1533 				{
1534 					switch (c)
1535 					{
1536 						case '1':
1537 						{
1538 							bc_history_edit_home(h);
1539 							break;
1540 						}
1541 
1542 						case '3':
1543 						{
1544 							bc_history_edit_delete(h);
1545 							break;
1546 						}
1547 
1548 						case '4':
1549 						{
1550 							bc_history_edit_end(h);
1551 							break;
1552 						}
1553 
1554 						default:
1555 						{
1556 							break;
1557 						}
1558 					}
1559 				}
1560 				else if (seq[2] == ';')
1561 				{
1562 					// Read two characters into seq.
1563 					if (BC_ERR(BC_HIST_READ(seq, 2)))
1564 					{
1565 						bc_vm_fatalError(BC_ERR_FATAL_IO_ERR);
1566 					}
1567 
1568 					if (seq[0] != '5') return;
1569 					else if (seq[1] == 'C') bc_history_edit_wordEnd(h);
1570 					else if (seq[1] == 'D') bc_history_edit_wordStart(h);
1571 				}
1572 			}
1573 			else
1574 			{
1575 				switch (c)
1576 				{
1577 					// Up.
1578 					case 'A':
1579 					{
1580 						bc_history_edit_next(h, BC_HIST_PREV);
1581 						break;
1582 					}
1583 
1584 					// Down.
1585 					case 'B':
1586 					{
1587 						bc_history_edit_next(h, BC_HIST_NEXT);
1588 						break;
1589 					}
1590 
1591 					// Right.
1592 					case 'C':
1593 					{
1594 						bc_history_edit_right(h);
1595 						break;
1596 					}
1597 
1598 					// Left.
1599 					case 'D':
1600 					{
1601 						bc_history_edit_left(h);
1602 						break;
1603 					}
1604 
1605 					// Home.
1606 					case 'H':
1607 					case '1':
1608 					{
1609 						bc_history_edit_home(h);
1610 						break;
1611 					}
1612 
1613 					// End.
1614 					case 'F':
1615 					case '4':
1616 					{
1617 						bc_history_edit_end(h);
1618 						break;
1619 					}
1620 
1621 					case 'd':
1622 					{
1623 						bc_history_edit_deleteNextWord(h);
1624 						break;
1625 					}
1626 				}
1627 			}
1628 		}
1629 		// ESC O sequences.
1630 		else
1631 		{
1632 			switch (seq[1])
1633 			{
1634 				case 'A':
1635 				{
1636 					bc_history_edit_next(h, BC_HIST_PREV);
1637 					break;
1638 				}
1639 
1640 				case 'B':
1641 				{
1642 					bc_history_edit_next(h, BC_HIST_NEXT);
1643 					break;
1644 				}
1645 
1646 				case 'C':
1647 				{
1648 					bc_history_edit_right(h);
1649 					break;
1650 				}
1651 
1652 				case 'D':
1653 				{
1654 					bc_history_edit_left(h);
1655 					break;
1656 				}
1657 
1658 				case 'F':
1659 				{
1660 					bc_history_edit_end(h);
1661 					break;
1662 				}
1663 
1664 				case 'H':
1665 				{
1666 					bc_history_edit_home(h);
1667 					break;
1668 				}
1669 			}
1670 		}
1671 	}
1672 }
1673 
1674 /**
1675  * Adds a line to the history.
1676  * @param h     The history data.
1677  * @param line  The line to add.
1678  */
1679 static void
1680 bc_history_add(BcHistory* h, char* line)
1681 {
1682 	BC_SIG_ASSERT_LOCKED;
1683 
1684 	// If there is something already there...
1685 	if (h->history.len)
1686 	{
1687 		// Get the previous.
1688 		char* s = *((char**) bc_vec_item_rev(&h->history, 0));
1689 
1690 		// Check for, and discard, duplicates.
1691 		if (!strcmp(s, line))
1692 		{
1693 			free(line);
1694 			return;
1695 		}
1696 	}
1697 
1698 	bc_vec_push(&h->history, &line);
1699 }
1700 
1701 /**
1702  * Adds an empty line to the history. This is separate from bc_history_add()
1703  * because we don't want it allocating.
1704  * @param h  The history data.
1705  */
1706 static void
1707 bc_history_add_empty(BcHistory* h)
1708 {
1709 	BC_SIG_ASSERT_LOCKED;
1710 
1711 	const char* line = "";
1712 
1713 	// If there is something already there...
1714 	if (h->history.len)
1715 	{
1716 		// Get the previous.
1717 		char* s = *((char**) bc_vec_item_rev(&h->history, 0));
1718 
1719 		// Check for, and discard, duplicates.
1720 		if (!s[0]) return;
1721 	}
1722 
1723 	bc_vec_push(&h->history, &line);
1724 }
1725 
1726 /**
1727  * Resets the history state to nothing.
1728  * @param h  The history data.
1729  */
1730 static void
1731 bc_history_reset(BcHistory* h)
1732 {
1733 	BC_SIG_ASSERT_LOCKED;
1734 
1735 	h->oldcolpos = h->pos = h->idx = 0;
1736 	h->cols = bc_history_columns();
1737 
1738 	// The latest history entry is always our current buffer, that
1739 	// initially is just an empty string.
1740 	bc_history_add_empty(h);
1741 
1742 	// Buffer starts empty.
1743 	bc_vec_empty(&h->buf);
1744 }
1745 
1746 /**
1747  * Prints a control character.
1748  * @param h  The history data.
1749  * @param c  The control character to print.
1750  */
1751 static void
1752 bc_history_printCtrl(BcHistory* h, unsigned int c)
1753 {
1754 	char str[3] = { '^', 'A', '\0' };
1755 	const char newline[2] = { '\n', '\0' };
1756 
1757 	BC_SIG_ASSERT_LOCKED;
1758 
1759 	// Set the correct character.
1760 	str[1] = (char) (c + 'A' - BC_ACTION_CTRL_A);
1761 
1762 	// Concatenate the string.
1763 	bc_vec_concat(&h->buf, str);
1764 
1765 	h->pos = BC_HIST_BUF_LEN(h);
1766 	bc_history_refresh(h);
1767 
1768 	// Pop the string.
1769 	bc_vec_npop(&h->buf, sizeof(str));
1770 	bc_vec_pushByte(&h->buf, '\0');
1771 
1772 	if (c != BC_ACTION_CTRL_C && c != BC_ACTION_CTRL_D)
1773 	{
1774 		// We sometimes want to print a newline; for the times we don't; it's
1775 		// because newlines are taken care of elsewhere.
1776 		bc_file_write(&vm.fout, bc_flush_none, newline, sizeof(newline) - 1);
1777 		bc_history_refresh(h);
1778 	}
1779 }
1780 
1781 /**
1782  * Edits a line of history. This function is the core of the line editing
1783  * capability of bc history. It expects 'fd' to be already in "raw mode" so that
1784  * every key pressed will be returned ASAP to read().
1785  * @param h       The history data.
1786  * @param prompt  The prompt.
1787  * @return        BC_STATUS_SUCCESS or BC_STATUS_EOF.
1788  */
1789 static BcStatus
1790 bc_history_edit(BcHistory* h, const char* prompt)
1791 {
1792 	BC_SIG_LOCK;
1793 
1794 	bc_history_reset(h);
1795 
1796 	// Don't write the saved output the first time. This is because it has
1797 	// already been written to output. In other words, don't uncomment the
1798 	// line below or add anything like it.
1799 	// bc_file_write(&vm.fout, bc_flush_none, h->extras.v, h->extras.len - 1);
1800 
1801 	// Write the prompt if desired.
1802 	if (BC_PROMPT)
1803 	{
1804 		h->prompt = prompt;
1805 		h->plen = strlen(prompt);
1806 		h->pcol = bc_history_promptColLen(prompt, h->plen);
1807 
1808 		bc_file_write(&vm.fout, bc_flush_none, prompt, h->plen);
1809 		bc_file_flush(&vm.fout, bc_flush_none);
1810 	}
1811 
1812 	// This is the input loop.
1813 	for (;;)
1814 	{
1815 		BcStatus s;
1816 		char cbuf[32];
1817 		unsigned int c = 0;
1818 		size_t nread = 0;
1819 
1820 		BC_SIG_UNLOCK;
1821 
1822 		// Read a code.
1823 		s = bc_history_readCode(cbuf, sizeof(cbuf), &c, &nread);
1824 		if (BC_ERR(s)) return s;
1825 
1826 		BC_SIG_LOCK;
1827 
1828 		switch (c)
1829 		{
1830 			case BC_ACTION_LINE_FEED:
1831 			case BC_ACTION_ENTER:
1832 			{
1833 				// Return the line.
1834 				bc_vec_pop(&h->history);
1835 				BC_SIG_UNLOCK;
1836 				return s;
1837 			}
1838 
1839 			case BC_ACTION_TAB:
1840 			{
1841 				// My tab handling is dumb; it just prints 8 spaces every time.
1842 				memcpy(cbuf, bc_history_tab, bc_history_tab_len + 1);
1843 				bc_history_edit_insert(h, cbuf, bc_history_tab_len);
1844 				break;
1845 			}
1846 
1847 			case BC_ACTION_CTRL_C:
1848 			{
1849 				bc_history_printCtrl(h, c);
1850 
1851 				// Quit if the user wants it.
1852 				if (!BC_SIGINT)
1853 				{
1854 					vm.status = BC_STATUS_QUIT;
1855 					BC_SIG_UNLOCK;
1856 					BC_JMP;
1857 				}
1858 
1859 				// Print the ready message.
1860 				bc_file_write(&vm.fout, bc_flush_none, vm.sigmsg, vm.siglen);
1861 				bc_file_write(&vm.fout, bc_flush_none, bc_program_ready_msg,
1862 				              bc_program_ready_msg_len);
1863 				bc_history_reset(h);
1864 				bc_history_refresh(h);
1865 
1866 				break;
1867 			}
1868 
1869 			case BC_ACTION_BACKSPACE:
1870 			case BC_ACTION_CTRL_H:
1871 			{
1872 				bc_history_edit_backspace(h);
1873 				break;
1874 			}
1875 
1876 			// Act as end-of-file or delete-forward-char.
1877 			case BC_ACTION_CTRL_D:
1878 			{
1879 				// Act as EOF if there's no chacters, otherwise emulate Emacs
1880 				// delete next character to match historical gnu bc behavior.
1881 				if (BC_HIST_BUF_LEN(h) == 0)
1882 				{
1883 					bc_history_printCtrl(h, c);
1884 					BC_SIG_UNLOCK;
1885 					return BC_STATUS_EOF;
1886 				}
1887 
1888 				bc_history_edit_delete(h);
1889 
1890 				break;
1891 			}
1892 
1893 			// Swaps current character with previous.
1894 			case BC_ACTION_CTRL_T:
1895 			{
1896 				bc_history_swap(h);
1897 				break;
1898 			}
1899 
1900 			case BC_ACTION_CTRL_B:
1901 			{
1902 				bc_history_edit_left(h);
1903 				break;
1904 			}
1905 
1906 			case BC_ACTION_CTRL_F:
1907 			{
1908 				bc_history_edit_right(h);
1909 				break;
1910 			}
1911 
1912 			case BC_ACTION_CTRL_P:
1913 			{
1914 				bc_history_edit_next(h, BC_HIST_PREV);
1915 				break;
1916 			}
1917 
1918 			case BC_ACTION_CTRL_N:
1919 			{
1920 				bc_history_edit_next(h, BC_HIST_NEXT);
1921 				break;
1922 			}
1923 
1924 			case BC_ACTION_ESC:
1925 			{
1926 				bc_history_escape(h);
1927 				break;
1928 			}
1929 
1930 			// Delete the whole line.
1931 			case BC_ACTION_CTRL_U:
1932 			{
1933 				bc_vec_string(&h->buf, 0, "");
1934 				h->pos = 0;
1935 
1936 				bc_history_refresh(h);
1937 
1938 				break;
1939 			}
1940 
1941 			// Delete from current to end of line.
1942 			case BC_ACTION_CTRL_K:
1943 			{
1944 				bc_vec_npop(&h->buf, h->buf.len - h->pos);
1945 				bc_vec_pushByte(&h->buf, '\0');
1946 				bc_history_refresh(h);
1947 				break;
1948 			}
1949 
1950 			// Go to the start of the line.
1951 			case BC_ACTION_CTRL_A:
1952 			{
1953 				bc_history_edit_home(h);
1954 				break;
1955 			}
1956 
1957 			// Go to the end of the line.
1958 			case BC_ACTION_CTRL_E:
1959 			{
1960 				bc_history_edit_end(h);
1961 				break;
1962 			}
1963 
1964 			// Clear screen.
1965 			case BC_ACTION_CTRL_L:
1966 			{
1967 				bc_file_write(&vm.fout, bc_flush_none, "\x1b[H\x1b[2J", 7);
1968 				bc_history_refresh(h);
1969 				break;
1970 			}
1971 
1972 			// Delete previous word.
1973 			case BC_ACTION_CTRL_W:
1974 			{
1975 				bc_history_edit_deletePrevWord(h);
1976 				break;
1977 			}
1978 
1979 			default:
1980 			{
1981 				// If we have a control character, print it and raise signals as
1982 				// needed.
1983 				if ((c >= BC_ACTION_CTRL_A && c <= BC_ACTION_CTRL_Z) ||
1984 				    c == BC_ACTION_CTRL_BSLASH)
1985 				{
1986 					bc_history_printCtrl(h, c);
1987 #ifndef _WIN32
1988 					if (c == BC_ACTION_CTRL_Z) bc_history_raise(h, SIGTSTP);
1989 					if (c == BC_ACTION_CTRL_S) bc_history_raise(h, SIGSTOP);
1990 					if (c == BC_ACTION_CTRL_BSLASH)
1991 					{
1992 						bc_history_raise(h, SIGQUIT);
1993 					}
1994 #else // _WIN32
1995 					vm.status = BC_STATUS_QUIT;
1996 					BC_SIG_UNLOCK;
1997 					BC_JMP;
1998 #endif // _WIN32
1999 				}
2000 				// Otherwise, just insert.
2001 				else bc_history_edit_insert(h, cbuf, nread);
2002 				break;
2003 			}
2004 		}
2005 	}
2006 
2007 	BC_SIG_UNLOCK;
2008 
2009 	return BC_STATUS_SUCCESS;
2010 }
2011 
2012 /**
2013  * Returns true if stdin has more data. This is for multi-line pasting, and it
2014  * does not work on Windows.
2015  * @param h  The history data.
2016  */
2017 static inline bool
2018 bc_history_stdinHasData(BcHistory* h)
2019 {
2020 #ifndef _WIN32
2021 	int n;
2022 	return pselect(1, &h->rdset, NULL, NULL, &h->ts, &h->sigmask) > 0 ||
2023 	       (ioctl(STDIN_FILENO, FIONREAD, &n) >= 0 && n > 0);
2024 #else // _WIN32
2025 	return false;
2026 #endif // _WIN32
2027 }
2028 
2029 BcStatus
2030 bc_history_line(BcHistory* h, BcVec* vec, const char* prompt)
2031 {
2032 	BcStatus s;
2033 	char* line;
2034 
2035 	assert(vm.fout.len == 0);
2036 
2037 	bc_history_enableRaw(h);
2038 
2039 	do
2040 	{
2041 		// Do the edit.
2042 		s = bc_history_edit(h, prompt);
2043 
2044 		// Print a newline and flush.
2045 		bc_file_write(&vm.fout, bc_flush_none, "\n", 1);
2046 		bc_file_flush(&vm.fout, bc_flush_none);
2047 
2048 		BC_SIG_LOCK;
2049 
2050 		// If we actually have data...
2051 		if (h->buf.v[0])
2052 		{
2053 			// Duplicate it.
2054 			line = bc_vm_strdup(h->buf.v);
2055 
2056 			// Store it.
2057 			bc_history_add(h, line);
2058 		}
2059 		// Add an empty string.
2060 		else bc_history_add_empty(h);
2061 
2062 		BC_SIG_UNLOCK;
2063 
2064 		// Concatenate the line to the return vector.
2065 		bc_vec_concat(vec, h->buf.v);
2066 		bc_vec_concat(vec, "\n");
2067 	}
2068 	while (!s && bc_history_stdinHasData(h));
2069 
2070 	assert(!s || s == BC_STATUS_EOF);
2071 
2072 	bc_history_disableRaw(h);
2073 
2074 	return s;
2075 }
2076 
2077 void
2078 bc_history_string_free(void* str)
2079 {
2080 	char* s = *((char**) str);
2081 	BC_SIG_ASSERT_LOCKED;
2082 	if (s[0]) free(s);
2083 }
2084 
2085 void
2086 bc_history_init(BcHistory* h)
2087 {
2088 
2089 #ifdef _WIN32
2090 	HANDLE out, in;
2091 #endif // _WIN32
2092 
2093 	BC_SIG_ASSERT_LOCKED;
2094 
2095 	h->rawMode = false;
2096 	h->badTerm = bc_history_isBadTerm();
2097 
2098 	// Just don't initialize with a bad terminal.
2099 	if (h->badTerm) return;
2100 
2101 #ifdef _WIN32
2102 
2103 	h->orig_in = 0;
2104 	h->orig_out = 0;
2105 
2106 	in = GetStdHandle(STD_INPUT_HANDLE);
2107 	out = GetStdHandle(STD_OUTPUT_HANDLE);
2108 
2109 	// Set the code pages.
2110 	SetConsoleCP(CP_UTF8);
2111 	SetConsoleOutputCP(CP_UTF8);
2112 
2113 	// Get the original modes.
2114 	if (!GetConsoleMode(in, &h->orig_in) || !GetConsoleMode(out, &h->orig_out))
2115 	{
2116 		// Just mark it as a bad terminal on error.
2117 		h->badTerm = true;
2118 		return;
2119 	}
2120 	else
2121 	{
2122 		// Set the new modes.
2123 		DWORD reqOut = h->orig_out | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
2124 		DWORD reqIn = h->orig_in | ENABLE_VIRTUAL_TERMINAL_INPUT;
2125 
2126 		// The input handle requires turning *off* some modes. That's why
2127 		// history didn't work before; I didn't read the documentation
2128 		// closely enough to see that most modes were automaticall enabled,
2129 		// and they need to be turned off.
2130 		reqOut |= DISABLE_NEWLINE_AUTO_RETURN | ENABLE_PROCESSED_OUTPUT;
2131 		reqIn &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT);
2132 		reqIn &= ~(ENABLE_PROCESSED_INPUT);
2133 
2134 		// Set the modes; if there was an error, assume a bad terminal and
2135 		// quit.
2136 		if (!SetConsoleMode(in, reqIn) || !SetConsoleMode(out, reqOut))
2137 		{
2138 			h->badTerm = true;
2139 			return;
2140 		}
2141 	}
2142 #endif // _WIN32
2143 
2144 	bc_vec_init(&h->buf, sizeof(char), BC_DTOR_NONE);
2145 	bc_vec_init(&h->history, sizeof(char*), BC_DTOR_HISTORY_STRING);
2146 	bc_vec_init(&h->extras, sizeof(char), BC_DTOR_NONE);
2147 
2148 #ifndef _WIN32
2149 	FD_ZERO(&h->rdset);
2150 	FD_SET(STDIN_FILENO, &h->rdset);
2151 	h->ts.tv_sec = 0;
2152 	h->ts.tv_nsec = 0;
2153 
2154 	sigemptyset(&h->sigmask);
2155 	sigaddset(&h->sigmask, SIGINT);
2156 #endif // _WIN32
2157 }
2158 
2159 void
2160 bc_history_free(BcHistory* h)
2161 {
2162 	BC_SIG_ASSERT_LOCKED;
2163 #ifndef _WIN32
2164 	bc_history_disableRaw(h);
2165 #else // _WIN32
2166 	SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), h->orig_in);
2167 	SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), h->orig_out);
2168 #endif // _WIN32
2169 #ifndef NDEBUG
2170 	bc_vec_free(&h->buf);
2171 	bc_vec_free(&h->history);
2172 	bc_vec_free(&h->extras);
2173 #endif // NDEBUG
2174 }
2175 
2176 #if BC_DEBUG_CODE
2177 
2178 /**
2179  * Prints scan codes. This special mode is used by bc history in order to print
2180  * scan codes on screen for debugging / development purposes.
2181  * @param h  The history data.
2182  */
2183 void
2184 bc_history_printKeyCodes(BcHistory* h)
2185 {
2186 	char quit[4];
2187 
2188 	bc_vm_printf("Linenoise key codes debugging mode.\n"
2189 	             "Press keys to see scan codes. "
2190 	             "Type 'quit' at any time to exit.\n");
2191 
2192 	bc_history_enableRaw(h);
2193 	memset(quit, ' ', 4);
2194 
2195 	while (true)
2196 	{
2197 		char c;
2198 		ssize_t nread;
2199 
2200 		nread = bc_history_read(&c, 1);
2201 		if (nread <= 0) continue;
2202 
2203 		// Shift string to left.
2204 		memmove(quit, quit + 1, sizeof(quit) - 1);
2205 
2206 		// Insert current char on the right.
2207 		quit[sizeof(quit) - 1] = c;
2208 		if (!memcmp(quit, "quit", sizeof(quit))) break;
2209 
2210 		bc_vm_printf("'%c' %lu (type quit to exit)\n", isprint(c) ? c : '?',
2211 		             (unsigned long) c);
2212 
2213 		// Go left edge manually, we are in raw mode.
2214 		bc_vm_putchar('\r', bc_flush_none);
2215 		bc_file_flush(&vm.fout, bc_flush_none);
2216 	}
2217 
2218 	bc_history_disableRaw(h);
2219 }
2220 #endif // BC_DEBUG_CODE
2221 
2222 #endif // BC_ENABLE_HISTORY
2223 
2224 #endif // BC_ENABLE_READLINE
2225 
2226 #endif // BC_ENABLE_EDITLINE
2227