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