1 /*
2  * input.c: does the actual input line stuff... keeps the appropriate stuff
3  * on the input line, handles insert/delete of characters/words... the whole
4  * ball o wax.
5  *
6  * Copyright (c) 1990 Michael Sandroff.
7  * Copyright (c) 1991, 1992 Troy Rollo.
8  * Copyright (c) 1992-1996 Matthew Green.
9  * Copyright 1999, 2015 EPIC Software Labs.
10  * All rights reserved.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notices, the above paragraph (the one permitting redistribution),
19  *    this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. The names of the author(s) may not be used to endorse or promote
22  *    products derived from this software without specific prior written
23  *    permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
26  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
27  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28  * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
32  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
33  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 /*
38  * This file has been mostly rewritten and reorganized by now.  One of the
39  * things we can do now is have completely independant input lines on each
40  * screen, and there are really no global variables any more.  A lot of the
41  * original code still lies about, as its still useful, but the macros have
42  * made the original code hard to distinguish.
43  */
44 
45 #define __need_term_flush__
46 #include "irc.h"
47 #include "alias.h"
48 #include "clock.h"
49 #include "commands.h"
50 #include "exec.h"
51 #include "functions.h"
52 #include "hook.h"
53 #include "input.h"
54 #include "ircaux.h"
55 #include "keys.h"
56 #include "screen.h"
57 #include "server.h"
58 #include "status.h"
59 #include "termx.h"
60 #include "vars.h"
61 #include "window.h"
62 #include "output.h"
63 #include <sys/ioctl.h>		/* XXX ugh */
64 
65 /* used with input_move_cursor */
66 #define RIGHT 1
67 #define LEFT 0
68 
69 static int	input_move_cursor (int dir, int refresh);
70 
71 /*
72  * This is how close you have to be to the edge of the screen before the
73  * input line scrolls to the adjacent zone.  A detailed discussion of zones
74  * can be found below.
75  */
76 	const int	WIDTH = 10;
77 
78 /*
79  * input_prompt: This is the global default for the raw, unexpanded
80  * input prompt for all input lines, as determined by /set input_prompt.
81  */
82 	static	char *	input_prompt;
83 
84 /*
85  * These are sanity macros.  The file was completely unreadable before
86  * I put these in here.  I make no apologies for them.
87  *
88  * current_screen	The screen we are working on
89  * INPUT_BUFFER		The input buffer for the screen we are working on.
90  * LOGICAL_CHARS
91  * LOGICAL_COLUMN
92  * START
93  * LOGICAL_CURSOR
94  * LOGICAL_LOCATION
95  * NEXT_LOGICAL_LOCATION
96  * PREV_LOGICAL_LOCATION
97  * CURSOR_SPOT
98  * NEXT_SPOT
99  * PREV_SPOT
100  * PHYSICAL_CURSOR	The column the physical cursor is in
101  * THIS_CHAR
102  * PREV_CHAR
103  * NEXT_CHAR
104  * ADD_TO_INPUT
105  * CURSOR_RIGHT
106  * CURSOR_LEFT
107  * INPUT_PROMPT		The normalized expanded value of 'input_prompt'.
108  * INPUT_PROMPT_LEN	How many columns INPUT_PROMPT takes.
109  * IND_LEFT
110  * IND_LEFT_LEN
111  * IND_RIGHT
112  * IND_RIGHT_LEN
113  * INPUT_LINE		The line on the terminal where the input line is.
114  * CUT_BUFFER		The saved cut buffer (for deletes)
115  */
116 
117 #define current_screen		last_input_screen
118 
119 /*
120  * This is a UTF8 C string containing the input line.
121  * Although ultimately this is the master reference copy of the input line,
122  * any time you change stuff in it, you need to call retokenize_input_line()
123  * to refresh the metadata and update_input() to refresh the screen.
124  */
125 #define INPUT_BUFFER 		current_screen->il->input_buffer
126 
127 /*
128  * A "LOGICAL CHARACTER" is one or more unicode code points that represent
129  * a single glyph to the user.  A glyph might take up 1 or 2 columns.
130  * A glyph might require multiple code points if the system uses continuation
131  * characters (Mac OS X) instead of composed characters (everybody else)
132  *
133  * When the user hits <backspace> they expect the previous glyph to be deleted,
134  * which might be a surprisingly complicated thing to determine.
135  *
136  * Therefore, each glyph is associated with metadata pointing at INPUT_BUFFER
137  *
138  * 	logical_chars[n]	This glyph is stored in UTF8 at
139  *				   input_buffer + logical_chars[n]
140  *	logical_location[n]	This glyph starts at column <X>
141  *				  when you count all logical columns in the
142  *				  input line starting from 0.
143  *	first_display_glyph	The first logical character that is currently
144  *				  visible on the screen.
145  *
146  */
147 #define LOGICAL_CHARS		current_screen->il->logical_chars
148 #define LOGICAL_COLUMN		current_screen->il->logical_columns
149 #define START			current_screen->il->first_display_char
150 #define MAXCOLS			current_screen->il->number_of_logical_chars
151 
152 /*
153  * The "LOGICAL CURSOR" is wherever the input point is.  Most of the
154  * time it is at the end (pointing at the NUL at the end of INPUT_BUFFER)
155  * but it can point at any glyph.  We always keep the physical cursor on
156  * top of the logical cursor.
157  */
158 #define LOGICAL_CURSOR          current_screen->il->logical_cursor
159 
160 /* This is the offset into INPUT_BUFFER where the logical cursor starts */
161 #define LOGICAL_LOCATION	LOGICAL_CHARS[LOGICAL_CURSOR]
162 
163 /*
164  * This is the offset into INPUT_BUFFER where the character after the
165  * logical cursor starts.  Note that continuation characters mean that
166  * this spot may be several code points away!  That's why we tokenize
167  * the input and keep these in arrays.
168  */
169 #define NEXT_LOGICAL_LOCATION	LOGICAL_CHARS[LOGICAL_CURSOR + 1]
170 #define PREV_LOGICAL_LOCATION	LOGICAL_CHARS[LOGICAL_CURSOR - 1]
171 
172 /*
173  * These are (char *) pointers to where the input cursor currently lives.
174  * (and the next glyph, and the previous glyph)
175  * IN THEORY you could operate on the input buffer by doing string things
176  * on this pointer.  BE VERY CAREFUL YOU DON'T SCREW IT UP!
177  *
178  * IF YOU CHANGE THE INPUT BUFFER YOU _MUST_ CALL retokenize_input()
179  * AND YOU _MUST_ CALL update_input()!
180  */
181 #define CURSOR_SPOT		(INPUT_BUFFER + LOGICAL_LOCATION)
182 #define NEXT_SPOT		(INPUT_BUFFER + NEXT_LOGICAL_LOCATION)
183 #define PREV_SPOT		(INPUT_BUFFER + PREV_LOGICAL_LOCATION)
184 
185 /*
186  * The physical cursor is the distance of the logical cursor from whatever
187  * glyph is "first", plus the input prompt plus the left indicator.
188  */
189 #define PHYSICAL_CURSOR         LOGICAL_COLUMN[LOGICAL_CURSOR] - LOGICAL_COLUMN[START] + INPUT_PROMPT_LEN + (START != 0 ? IND_LEFT_LEN : 0)
190 
191 /*
192  * This returns the FIRST CODE POINT of the character under the cursor.
193  * This is suitable for checking if it's a space or an alphanumeric or
194  * to see how many columns this glyph takes up, that kind of stuff...
195  * But it isn't suitable for actually copying stuff around!
196  * This is an rvalue on purpose to keep you from assigning to it.
197  */
198 #define THIS_CHAR 		grab_codepoint(CURSOR_SPOT)
199 #define PREV_CHAR 		grab_codepoint(PREV_SPOT)
200 #define NEXT_CHAR		grab_codepoint(NEXT_SPOT)
201 
202 
203 /*
204  * Add a byte to the end of the input line.
205  * You should have done *CURSOR_SPOT = 0, if you're modifying
206  * the middle of the input buffer.
207  * You should have done something "CURSOR_SPOT" -- ie, move it to the
208  * cut buffer or saved it to a local string, so you can add it back.
209  *
210  * AFTER YOU CALL ADD_TO_INPUT() YOU _MUST_ CALL retokenize_input().
211  * AND YOU _MUST_ CALL update_input()!
212  */
213 #define ADD_TO_INPUT(x) 	strlcat(INPUT_BUFFER, (x), sizeof INPUT_BUFFER);
214 
215 /*
216  * Moving the cursor is as easy as changing the logical cursor.
217  * HOWEVER IF YOU DO THIS YOU _MUST_ CALL update_input()!
218  * Update_input() is what updates the cursor on the user's screen.
219  */
220 #define CURSOR_RIGHT            LOGICAL_CURSOR++
221 #define CURSOR_LEFT             LOGICAL_CURSOR--
222 
223 
224 #define INPUT_PROMPT 		current_screen->il->input_prompt
225 #define INPUT_PROMPT_LEN 	current_screen->il->input_prompt_len
226 
227 #define IND_LEFT                current_screen->il->ind_left
228 #define IND_LEFT_LEN            current_screen->il->ind_left_len
229 
230 #define IND_RIGHT               current_screen->il->ind_right
231 #define IND_RIGHT_LEN           current_screen->il->ind_right_len
232 
233 /*
234  * This is the physical line on the screen where the input line is.
235  * IE, if the terminal is 46 lines tall, then this is 46.
236  */
237 #define INPUT_LINE 		current_screen->il->input_line
238 #define CUT_BUFFER		cut_buffer
239 
240 
BUILT_IN_KEYBINDING(debug_input_line)241 BUILT_IN_KEYBINDING(debug_input_line)
242 {
243 	int	i;
244 	char	*s;
245 	int	offset, column;
246 	int	codepoint;
247 	char	buffer[2048];
248 	char	byte[8];
249 
250 	*buffer = 0;
251 	for (i = 0; i < INPUT_BUFFER_SIZE; i++)
252 	{
253 		snprintf(byte, sizeof(byte), "%X", INPUT_BUFFER[i]);
254 		strlcat(buffer, " ", sizeof(buffer));
255 		strlcat(buffer, byte, sizeof(buffer));
256 		if (INPUT_BUFFER[i] == 0)
257 			break;
258 	}
259 
260 	yell("INPUT LINE is: %s [%s]", INPUT_BUFFER, buffer);
261 
262 	for (i = 0; i < INPUT_BUFFER_SIZE; i++)
263 	{
264 		offset = LOGICAL_CHARS[i];
265 		column = LOGICAL_COLUMN[i];
266 		codepoint = grab_codepoint(INPUT_BUFFER + offset);
267 
268 		if (i == START)
269 			yell("LC %02d: START OF DISPLAY HERE", i);
270 		yell("LC %02d: Offset %d, Columns %d, Codepoint %x",
271 			i, offset, column, codepoint);
272 		if (i == LOGICAL_CURSOR)
273 			yell("LC %02d: CURSOR HERE", i);
274 		if (codepoint == 0)
275 		{
276 			yell("LC %02d: END HERE", i);
277 			break;
278 		}
279 	}
280 
281 	yell("PHYSICAL CURSOR AT %d %d", PHYSICAL_CURSOR, INPUT_LINE);
282 }
283 
cursor_position(void * vp)284 int	cursor_position (void *vp)
285 {
286 	Screen *s = (Screen *)vp;
287 	if (!s)
288 		return -1;
289 
290 	/*
291 	 * This used to return a byte offset into the input line,
292 	 * because of $mid() and stuff.  But now that those funcs
293 	 * are all utf8 aware, we want to actually return the logical
294 	 * character itself.
295 	 */
296 	/*return s->il->logical_chars[s->il->logical_cursor]; */
297 	return s->il->logical_cursor;
298 }
299 
300 #define LOGICAL_LOCATION	LOGICAL_CHARS[LOGICAL_CURSOR]
301 
302 /* XXXX Only used here anyhow XXXX */
303 /*
304  * safe_puts -- output only 'numcols' columns of bytes from 'str'.
305  *
306  * Arguments:
307  *	str	- A string to output
308  *	numcols	- The maximum number of columns to output
309  */
safe_puts(const unsigned char * str,int numcols)310 static int 	safe_puts (const unsigned char *str, int numcols)
311 {
312 	int 	i = 0;
313 	const unsigned char *s, *x;
314 	unsigned char	utf8str[8];
315 	int	code_point;
316 	int	cols;
317 	int	allow_c1_chars = -1;
318 
319 	s = str;
320 	while ((code_point = next_code_point(&s, 1)))
321 	{
322 		/* C1 chars have to be checked */
323 		if (code_point >= 0x80 && code_point <= 0x9F)
324 		{
325 			if (allow_c1_chars == -1)
326 			    allow_c1_chars = get_int_var(ALLOW_C1_CHARS_VAR);
327 
328 			/* We don't output C1 chars */
329 			if (!allow_c1_chars)
330 				continue;
331 		}
332 
333 		if ((cols = codepoint_numcolumns(code_point)) == -1)
334 			cols = 1;
335 
336 		if (i + cols > numcols)
337 			break;
338 
339 		/* Convert code_point from utf8 to users encoding */
340 		ucs_to_console(code_point, utf8str, sizeof(utf8str));
341 
342 		for (x = utf8str; *x; x++)
343 			term_inputline_putchar(*x);
344 
345 		i += cols;
346 	}
347 
348 	return i;
349 }
350 
351 /* cursor_to_input: move the cursor to the input line, if not there already */
cursor_to_input(void)352 void 	cursor_to_input (void)
353 {
354 	Screen *oldscreen = last_input_screen;
355 	Screen *screen;
356 static	int	recursive = 0;
357 
358 	if (recursive)
359 		return;
360 
361 	if (!foreground)
362 		return;		/* Dont bother */
363 
364 	recursive = 1;
365 	for (screen = screen_list; screen; screen = screen->next)
366 	{
367 		if (screen->alive)
368 		{
369 			output_screen = screen;
370 			last_input_screen = screen;
371 /*yell("moving cursor to %d %d", PHYSICAL_CURSOR, INPUT_LINE); */
372 			term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
373 			term_flush();
374 		}
375 	}
376 	output_screen = last_input_screen = oldscreen;
377 	recursive = 0;
378 }
379 
380 /*
381  * This function populates the "logical_chars" and "logical_columns"
382  * arrays starting from the 'start'th logical char.  If you want to
383  * redo the whole thing, then start should be 0.
384  *
385  * XXX For now, we ignore 'start' and always redo the whole thing.
386  */
retokenize_input(int start)387 static int	retokenize_input (int start)
388 {
389 	const unsigned char *s, *old_s;
390 	int	cols;
391 	int	codepoint;
392 	int	current_column;
393 
394 	start = 0;
395 	current_column = 0;
396 	old_s = s = INPUT_BUFFER;
397 
398 	while (s && *s)
399 	{
400 		codepoint = next_code_point(&s, 1);
401 		cols = codepoint_numcolumns(codepoint);
402 		/* Invalid chars are probably highlights */
403 		if (cols == -1)
404 			cols = 1;
405 
406 		if (cols == 0)
407 			/* skip over continuation chars */;
408 		else
409 		{
410 			LOGICAL_CHARS[start] = old_s - INPUT_BUFFER;
411 			LOGICAL_COLUMN[start] = current_column;
412 
413 			current_column += cols;
414 			start++;
415 			LOGICAL_CHARS[start] = 9999;
416 		}
417 		old_s = s;
418 	}
419 
420 	/* Set down the null */
421 	LOGICAL_CHARS[start] = s - INPUT_BUFFER;
422 	LOGICAL_COLUMN[start] = current_column;
423 	MAXCOLS = start;
424 
425 	while (++start < INPUT_BUFFER_SIZE)
426 	{
427 		LOGICAL_CHARS[start] = 9999;
428 		LOGICAL_COLUMN[start] = 0;
429 		start++;
430 	}
431 
432 	return 0;
433 }
434 
435 
436 /*
437  * update_input: Refresh the input line so what is on screen agrees with
438  *		 what is in memory.
439  *
440  * The input line is operated on 'asynchronously' meaning you can perform
441  * many operations in a batch, and then call update_input() when you're
442  * done and it will sort out what the screen needs to look like.
443  *
444  * There are three broad types of changes you can make:
445  *	1. UPDATE_JUST_CURSOR - I moved the cursor, but didn't change anything
446  *	2. UPDATE_FROM_CURSOR - I changed something at or after the cursor
447  *	3. UPDATE_ALL - I changed something before the cursor, OR
448  *			An external event happened that I think affects
449  *			the input line (such as joining a channel)
450  *
451  * The results of these three are:
452  *	UPDATE_ALL	- The input line is re-compiled and unconditionally
453  *			  redrawn.  This causes flicker, so we try to avoid
454  *			  doing this unnecessarily.
455  *	UPDATE_FROM_CURSOR - The input line is re-compiled starting from
456  *			     the cursor and redrawn fromthe cursor
457  *	UPDATE_JUST_CURSOR - The cursor is moved; nothing else is changed.
458  *
459  * In addition to all of the above, we always perform these checks:
460  *	1. Has the prompt changed?
461  *	2. Has the left indicator changed?
462  *	3. Has the right indicator changed?
463  *	4. Has the size of the screen changed?
464  *	5. Is the cursor too close to the left edge?
465  *	6. Is the cursor too close to the right edge?
466  * If any of these apply, a corrective measure is taken, and then the
467  * refresh is upgraded to UPDATE_ALL.
468  *
469  * Clear as mud?
470  */
update_input(void * which_screen,int update)471 void	update_input (void *which_screen, int update)
472 {
473 	char	*ptr, *ptr_free;
474 	int	max;
475 const char *	prompt;
476 	int	do_echo, old_do_echo;
477 	Screen	*os, *ns;
478 	Window 	*saved_current_window;
479 	int	cols_used;
480 	int	original_update;
481 	Screen	*oos;
482 
483 	/*
484 	 * No input line in dumb or bg mode.
485 	 */
486 	if (dumb_mode || !foreground)
487 		return;
488 
489 	/* Save the state of things */
490 	os = last_input_screen;
491 	saved_current_window = current_window;
492 	original_update = update;
493 	oos = output_screen;
494 
495         for (ns = screen_list; ns; ns = ns->next)
496 	{
497 
498 	/* <<<< INDENTED BACK ONE TAB FOR MY SANITY <<<<< */
499 	/* XXX This is an ugly way to do this. */
500 	if (which_screen && (Screen *)which_screen != ns)
501 		continue;	/* Only update this screen */
502 
503 	/* Ignore inactive screens. */
504 	if (!ns->alive)
505 		continue;
506 
507 	/* XXX The (mis)use of last_input_screen is lamentable */
508 	last_input_screen = ns;
509 	output_screen = ns;
510 	current_window = ns->current_window;
511 	update = original_update;
512 	do_echo = last_input_screen->il->echo;
513 
514 	/*
515 	 * FIRST OFF -- Recalculate the metadata
516 	 *	1. Has the raw prompt changed?
517 	 *	2. Has the resulting expanded prompt changed?
518 	 *	3. Has the resulting expanded left indicator changed?
519 	 *	4. Has the resulting expanded right indicator changed?
520 	 *	5. Has the size of the screen changed?
521 	 *
522 	 * If any of these four are true, we must regenerate zones
523 	 * We know which logical cursor the cursor sits on, we just
524 	 * have to figure out where that lives
525 	 *
526 	 *
527 	 * THE CHEATERS GUIDE TO ZONES
528 	 *  I thought it would be easy to just calculate the 'zone' that
529 	 *  every logical character would be in, but there are three
530 	 *  complications:
531 	 *	1. Changing between zones doesn't happen very much
532 	 *	2. The size of zones can change frequently (prompt/indicators)
533 	 *	3. The condition required to switch zones is easily described
534 	 *
535 	 * WHEN TO SWITCH ZONES:
536 	 *	Let X be the first logical character being displayed (saved)
537 	 *	Let Y be the width of the scrollable zone (saved/calculated)
538 	 *		Y = WIDTH OF SCREEN
539 	 *		Y -= WIDTH OF PROMPT
540 	 *		IF X > 0
541 	 *			Y -= WIDTH OF LEFT INDICATOR
542 	 *		END IF
543 	 *		IF character under (X + Y)
544 	 *			Y -= WIDTH OF RIGHT INDICATOR
545 	 *		END IF
546 	 *
547 	 *	The cursor is allowed to be within (X + 10) and (Y - 10),
548 	 *	with the exception of X = 0, then (X) and (Y - 10).
549 	 *	This means the typable area is either (Y - 10) the first zone
550 	 *	or (Y - 20) other zones).
551 	 *
552 	 *	Therefore, given a logical cursor position, we can calculate
553 	 *	a new X.
554 	 *
555 	 *	# CALCULATE NEW X
556 	 *	IF logical_column(CURRENT) < Y - 10
557 	 *		LET new X = 0
558 	 *	ELSE IF X > 0 AND distance(lc(X), lc(CURRENT)) < 10)
559 	 *		# SHIFT LEFT
560 	 *		LET new X = Z : distance(lc(X), lc(Z)) = Y
561 	 *		IF new X < 0
562 	 *			new X = 0
563 	 *		END
564 	 *	ELSE IF distance(CURRENT, Y) < 10
565 	 *		# SHIFT RIGHT
566 	 *		IF X = 0
567 	 *			LET new X = Y - 20
568 	 *		ELSE
569 	 *			LET new X = X + Y
570 	 *		END
571 	 *	END
572 	 *
573 	 *
574 	 * Thus, after moving the cursor, we must recalculate all of the
575 	 * above things.  Moving the cursor could be a cursor press, but
576 	 * also typing.
577 	 *
578 	 * After the new X is calculated, if it is different from the old X,
579 	 * then the input line must be completely redrawn.
580 	 *
581 	 * Redrawing the input line involves
582 	 *	1. Determining where the first byte lives
583 	 *	2. Determining which column the first byte lives
584 	 *	3. Determining how many bytes must be output
585 	 *	4. Determining which column the cursor goes into
586 	 */
587 
588 
589 	/*
590 	 * Now we need to retokenize the input.
591 	 * UPDATE will tell us where to start from (from the cursor or all)
592 	 * Walk the input buffer, and make a note of the byte offset where
593 	 * each column begins
594 	 */
595 
596 	/*
597 	 * The input line is a utf8 C string
598 	 * Decomposed into a sequence of LOGICAL CHARACTERS
599 	 * Which are composed of ONE OR MORE UNICODE CODE POINTS
600 	 * Which take up ZERO OR MORE COLUMNS
601 	 *
602 	 * char *input_line[]		The UTF8 C string
603 	 * int logical_chars[]		Logical chars -> input_line[x]
604 	 * int logical_column[]		Logical chars -> Logical column
605 	 * int logical_zone[]		Logical chars -> zone
606 	 *
607 	 * A "zone" is a segment of the input line that is displayed
608 	 * at once.  When you move the cursor to an adjacent "zone" then
609 	 * the input line is completely redrawn.  Zones are numbered from 0.
610 	 * Zone 0 contains the start of the input line.  the final zone
611 	 * is whatever zone contains the terminal nul.
612 	 *
613 	 * WHAT IS DISPLAYED:
614 	 * [prompt] [left indicator^] [spill-over from zone N-1]
615 	 *		[zone N]
616 	 *		[spill-over from zone-N] [right indicator^^]
617 	 *    ^ [Left Indicator] is not shown for segment 0, which means
618 	 *	 zone 0 is longer than other zones.
619 	 *    ^^ [Right Indicator] is not shown for the final zone.
620 	 */
621 
622 	/*
623 	 * No matter what happens, we check the input prompt, the left
624 	 * and right indicators.  XXX Sigh!  This is too expensive!
625 	 * If anything changes, we upgrade to "UPDATE_ALL".
626 	 */
627 
628 	/*
629 	 * If the current window is query'ing an exec'd process,
630 	 * then we just get the current prompt for that process.
631 	 * This hardly ever happens, so we malloc() this to make
632 	 * the code below much simpler.
633 	 */
634 	if (last_input_screen->il->input_prompt_raw)
635 		prompt = last_input_screen->il->input_prompt_raw;
636 	else if (is_valid_process(get_target_by_refnum(0)))
637 		prompt = get_prompt_by_refnum(0);
638 	else
639 		prompt = input_prompt;
640 
641 	ptr_free = expand_alias(prompt, empty_string);
642 	ptr = new_normalize_string(ptr_free, 0, display_line_mangler);
643 	new_free(&ptr_free);
644 
645 	/*
646 	 * If the prompt has changed, update the screen, and count
647 	 * the number of columns the new prompt takes up.  If the
648 	 * prompt changes, we have to redraw the entire input line
649 	 * from scratch (since stuff probably has moved)
650 	 */
651 	if (strcmp(ptr, INPUT_PROMPT))
652 	{
653 		malloc_strcpy((char **)&INPUT_PROMPT, ptr);
654 		INPUT_PROMPT_LEN = output_with_count(INPUT_PROMPT, 0, 0);
655 		update = UPDATE_ALL;
656 	}
657 
658 	new_free(&ptr);
659 
660 	ptr_free = expand_alias(get_string_var(INPUT_INDICATOR_LEFT_VAR),
661 					empty_string);
662 	ptr = new_normalize_string(ptr_free, 0, display_line_mangler);
663 	new_free(&ptr_free);
664 
665 	if (strcmp(ptr, IND_LEFT))
666 	{
667 		malloc_strcpy((char **)&IND_LEFT, ptr);
668 		IND_LEFT_LEN = output_with_count(IND_LEFT, 0, 0);
669 		update = UPDATE_ALL;
670 	}
671 
672 	new_free(&ptr);
673 
674 	ptr_free = expand_alias(get_string_var(INPUT_INDICATOR_RIGHT_VAR),
675 					empty_string);
676 	ptr = new_normalize_string(ptr_free, 0, display_line_mangler);
677 	new_free(&ptr_free);
678 
679 	if (strcmp(ptr, IND_RIGHT))
680 	{
681 		malloc_strcpy((char **)&IND_RIGHT, ptr);
682 		IND_RIGHT_LEN = output_with_count(IND_RIGHT, 0, 0);
683 		update = UPDATE_ALL;
684 	}
685 
686 	new_free(&ptr);
687 
688 
689 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
690 	/*
691 	 *
692 	 * HAS THE SCREEN CHANGED SIZE SINCE THE LAST TIME?
693 	 *
694 	 */
695 
696 	/*
697 	 * If the screen has resized, then we need to re-compute the
698 	 * side-to-side scrolling effect.
699 	 */
700 	if ((last_input_screen->li != last_input_screen->old_li) ||
701 	    (last_input_screen->co != last_input_screen->old_co) ||
702 	    (INPUT_LINE != last_input_screen->li))
703 	{
704 		/*
705 		 * The input line is always the bottom line
706 		 */
707 		INPUT_LINE = last_input_screen->li - 1;
708 
709 		last_input_screen->old_co = last_input_screen->co;
710 		last_input_screen->old_li = last_input_screen->li;
711 	}
712 
713 
714 	/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
715 	/*
716 	 * IS THE CURSOR TOO NEAR THE LEFT OR RIGHT EDGE OF SCREEN?
717 	 *
718 	 * XXX This should not be done unconditionally.
719 	 */
720 	if (1)
721 	{
722 		int	targetcol;
723 		int	x;
724 		int	totalcols;
725 		int	zone0_overflow = 0;
726 		int	OLD_START = START;
727 
728 		/*
729 		 * Calculate the "zone" that the cursor is in.
730 		 *
731 		 * The challenge here is the physical screen is
732 		 * divided into three parts
733 		 *
734 		 * LEFT PART: 	Input Prompt
735 		 *		Left Indicator (maybe)
736 		 * RIGHT PART:	Right Indicator (maybe)
737 		 *
738 		 * The space for the input line is the width of the screen
739 		 * minus the size of those two parts.  The "maybe" parts
740 		 * throw a monkey wrench since the space for the input line
741 		 * very much depends on where we are, and where we decide
742 		 * to put the START!
743 		 *
744 		 * As a nod to history, we try to make the zones symmetrical
745 		 * (ie, if you cursor right off the end of zone 0, you will
746 		 * be put in zone 1 in a place where if you do a cursor left
747 		 * you will go back to the end of zone 0); and that the zone
748 		 * you're in does not depend on where the cursor is.
749 		 *
750 		 *	Width Zone 0 is columns - prompt - (right indicator)?
751 		 *	Width Zone 1+ is columns - prompt - left indicator -
752 		 *					(right indicator)?
753 		 *
754 		 * So the only question for Zone 0 is, is the width of the
755 		 * entire input line wider than columns - prompt?
756 		 *
757 		 */
758 		totalcols = input_column_count(INPUT_BUFFER);
759 		if (totalcols > last_input_screen->co - INPUT_PROMPT_LEN)
760 			zone0_overflow = 1;
761 
762 		/*
763 		 * Is the cursor in zone 0?
764 		 */
765 		if (LOGICAL_COLUMN[LOGICAL_CURSOR] <
766 			last_input_screen->co -
767 				INPUT_PROMPT_LEN -
768 				WIDTH -
769 				zone0_overflow * IND_RIGHT_LEN)
770 		{
771 			targetcol = 0;
772 		}
773 
774 		/*
775 		 * Is the cursor in zone 1?
776 		 */
777 		else
778 		{
779 			int	zone0_length;
780 			int	net_columns;
781 			int	zone_length;
782 			int	zone;
783 
784 			/* We know how big zone 0 is */
785 			zone0_length = last_input_screen->co -
786 					INPUT_PROMPT_LEN -
787 					WIDTH -
788 					IND_RIGHT_LEN;
789 
790 			/*
791 			 * After we subtract zone0 (which is wider
792 			 * than the other columns, how many cols do
793 			 * we still have to account for?
794 			 */
795 			net_columns = LOGICAL_COLUMN[LOGICAL_CURSOR] -
796 					zone0_length;
797 
798 			/*
799 			 * Zones 1-N are the same width.  Yes, I know
800 			 * that adding IND_RIGHT_LEN is cheating, but
801 			 * that's a very small thing.  I think?
802 			 */
803 			zone_length = last_input_screen->co -
804 					INPUT_PROMPT_LEN -
805 					WIDTH -
806 					IND_LEFT_LEN -
807 					IND_RIGHT_LEN;
808 
809 			/*
810 			 * Our new ZONE is rounded down from however
811 			 * many columns we have left by how many we can
812 			 * cram into every zone.
813 			 */
814 			zone = net_columns / zone_length;
815 
816 			/*
817 			 * The new START is WIDTH chars before the
818 			 * start of the ZONE we are in (because you
819 			 * aren't permitted to cursor left to the
820 			 * WIDTH chars -- that takes you to the previous
821 			 * zone, got it?
822 			 */
823 			targetcol = (zone0_length + zone * zone_length) - WIDTH;
824 		}
825 
826 		for (x = 0; x <= LOGICAL_CURSOR; x++)
827 		{
828 			if (LOGICAL_COLUMN[x] >= targetcol)
829 			{
830 				START = x;
831 				if (START != OLD_START)
832 					update = UPDATE_ALL;
833 				break;
834 			}
835 		}
836 	}
837 
838 	/*
839 	 * OK.  Now let's update the screen!
840 	 */
841 	if (update == UPDATE_ALL)
842 	{
843 		/*
844 		 * Move the cursor to the start of the input line
845 		 */
846 		term_move_cursor(0, INPUT_LINE);
847 
848 		/* Forcibly output the prompt */
849 		old_do_echo = term_echo(1);
850 
851 		/*
852 		 * Figure out how many cols we will give to the
853 		 * prompt.  If the prompt is too long, we will
854 		 * clobber it below.  If the prompt won't fit, then
855 		 * we will clobber the whole thing.
856 		 */
857 		if (START!=0)
858 			cols_used = INPUT_PROMPT_LEN + IND_LEFT_LEN;
859 		else
860 			cols_used = INPUT_PROMPT_LEN;
861 
862 		if (cols_used > (last_input_screen->co - WIDTH))
863 		{
864 			cols_used = last_input_screen->co - WIDTH;
865 			if (cols_used < 0)
866 				cols_used = 0;
867 		}
868 
869 		/* Only output the prompt if there's room for it. */
870 		if (cols_used > 0)
871 			output_with_count(INPUT_PROMPT, 0, 1);
872 
873 		if (START!=0)
874 			output_with_count(IND_LEFT, 0, 1);
875 
876 		term_echo(old_do_echo);
877 
878 		/*
879 		 * Turn the echo back to what it was before,
880 		 * and output the rest of the input buffer.
881 		 */
882 		term_echo(do_echo);
883 
884 		if (input_column_count(INPUT_BUFFER + LOGICAL_CHARS[START]) >
885 				last_input_screen->co - cols_used)
886 		{
887 			cols_used += IND_RIGHT_LEN;
888 			safe_puts(INPUT_BUFFER + LOGICAL_CHARS[START],
889 				  last_input_screen->co - cols_used);
890 			output_with_count(IND_RIGHT, 0, 1);
891 		}
892 		else
893 			safe_puts(INPUT_BUFFER + LOGICAL_CHARS[START],
894 				  last_input_screen->co - cols_used);
895 
896 		term_echo(old_do_echo);
897 
898 		/*
899 		 * Clear the rest of the input line and reset the cursor
900 		 * to the current input position.
901 		 */
902 		term_clear_to_eol();
903 		term_flush();
904 		term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
905 		term_flush();
906 	}
907 
908 	/*
909 	 * If we're just supposed to refresh whats to the right of the
910 	 * current logical position...
911 	 */
912 	if (update == UPDATE_FROM_CURSOR)
913 	{
914 		/*
915 		 * Move the cursor to where its supposed to be,
916 		 * Figure out how much we can output from here,
917 		 * and then output it.
918 		 */
919 		term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
920 		term_flush();
921 		/* XXX 1 Col per byte assumption */
922 
923 		/* don't ask me why these needed to be split up */
924 		max = last_input_screen->co;
925 		max -= PHYSICAL_CURSOR;
926 
927 		old_do_echo = term_echo(do_echo);
928 
929 		if (input_column_count(INPUT_BUFFER + LOGICAL_LOCATION) > max)
930 		{
931 			max -= IND_RIGHT_LEN;
932 			safe_puts(CURSOR_SPOT, max);
933 			output_with_count(IND_RIGHT, 0, 1);
934 		}
935 		else
936 		{
937 			safe_puts(CURSOR_SPOT, max);
938 		}
939 
940 		term_echo(old_do_echo);
941 		term_clear_to_eol();
942 		term_flush();
943 	}
944 
945 	if (update == UPDATE_JUST_CURSOR)
946 	{
947 		term_move_cursor(PHYSICAL_CURSOR, INPUT_LINE);
948 		term_flush();
949 	}
950 
951 	/*
952 	 * Turn the terminal echo back on, and flush all of the output
953 	 * we may have done here.
954 	 */
955 	term_echo(1);
956 	term_flush();
957 
958 	/* <<<<< END INDENT ONE TAB BACK FOR MY SANITY <<<<<< */
959 	}
960 
961 	output_screen = oos;
962         last_input_screen = os;
963 	current_window = saved_current_window;
964 }
965 
966 
967 /*
968  * input_move_cursor -- Move the cursor LEFT or RIGHT.
969  *
970  * Arguments:
971  *	dir	- Must either be LEFT (-1) or RIGHT (1)
972  *	refresh	- 0 if you don't want me to call update_input.
973  *		     This might happen if you intend to call me multiple times.
974  *		     YOU ARE RESPONSIBLE FOR CALLING UPDATE_INPUT() AFTER YOU
975  *		     ARE DONE!
976  *		  1 if I should call update_input
977  *
978  * Return value:
979  *	1 if I moved the logical cursor
980  *	0 if I didn't move the logical cursor (because i'm at the end already)
981  */
input_move_cursor(int direction,int refresh)982 static int	input_move_cursor (int direction, int refresh)
983 {
984 	int	moved = 1;
985 
986 	if (direction == RIGHT)
987 	{
988 		/* Stop if we hit the end of the input line */
989 		if (!THIS_CHAR)
990 			return 0;
991 
992 		CURSOR_RIGHT;
993 	}
994 	else if (direction == LEFT)
995 	{
996 		/* Stop if we hit the start of the input line */
997 		if (LOGICAL_CURSOR == 0)
998 			return 0;
999 
1000 		CURSOR_LEFT;
1001 	}
1002 	else
1003 	   panic(1, "update_input_cursor not called with RIGHT or LEFT (%d)", direction);
1004 
1005 	if (refresh)
1006 		update_input(last_input_screen, UPDATE_JUST_CURSOR);
1007 	return moved;
1008 }
1009 
1010 /*
1011  * set_input: sets the input buffer to the given string, discarding whatever
1012  * was in the input buffer before
1013  */
set_input(const char * str)1014 static void	set_input (const char *str)
1015 {
1016 	size_t len;
1017 
1018 	strlcpy(INPUT_BUFFER, str, INPUT_BUFFER_SIZE);
1019 	START = 0;
1020 	LOGICAL_CURSOR = 0;
1021 
1022 	retokenize_input(LOGICAL_CURSOR);
1023 	while ((input_move_cursor(RIGHT, 0)))
1024 		;
1025 	update_input(last_input_screen, UPDATE_ALL);
1026 
1027 }
1028 
1029 /*
1030  * get_input: returns a pointer to the input buffer.  Changing this will
1031  * actually change the input buffer.  This is a bad way to change the input
1032  * buffer tho, cause no bounds checking won't be done
1033  */
get_input(void)1034 char *	get_input (void)
1035 {
1036 	return INPUT_BUFFER;
1037 }
1038 
1039 /* init_input: initialized the input buffer by clearing it out */
init_input(void)1040 void	init_input (void)
1041 {
1042 	*INPUT_BUFFER = 0;
1043         START = 0;
1044         LOGICAL_CURSOR = 0;
1045         memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1046 	retokenize_input(LOGICAL_CURSOR);
1047 }
1048 
1049 /*
1050  * set_input_prompt: sets a prompt that will be displayed in the input
1051  * buffer.  This prompt cannot be backspaced over, etc.  It's a prompt.
1052  * Setting the prompt to null uses no prompt
1053  */
set_input_prompt(void * stuff)1054 void	set_input_prompt (void *stuff)
1055 {
1056 	VARIABLE *v;
1057 	const char *prompt;
1058 
1059 	v = (VARIABLE *)stuff;
1060 	prompt = v->string;
1061 
1062 	if (prompt)
1063 		malloc_strcpy(&input_prompt, prompt);
1064 	else if (input_prompt)
1065 		malloc_strcpy(&input_prompt, empty_string);
1066 	else
1067 		return;
1068 
1069 	update_input(NULL, UPDATE_ALL);
1070 }
1071 
1072 
1073 /* Please define 'spaces' as get_string_var(WORD_BREAK_VAR). */
1074 #define WHITESPACE(x)  ((x < 127) && strchr(spaces, (x & 0x7F)) != NULL)
1075 
1076 /*
1077  * Why did i put these in this file?  I dunno.  But i do know that the ones
1078  * in edit.c didnt have to be here, and i knew the ones that were here DID
1079  * have to be here, so i just moved them all to here, so that they would all
1080  * be in the same place.  Easy enough. (jfn, june 1995)
1081  */
1082 
1083 /*
1084  * input_forward_word: move the input cursor forward one word in the input
1085  * line
1086  */
1087 
BUILT_IN_KEYBINDING(input_forward_word)1088 BUILT_IN_KEYBINDING(input_forward_word)
1089 {
1090 	const char *spaces;
1091 
1092         if (!(spaces = get_string_var(WORD_BREAK_VAR)))
1093                 spaces = " \t";
1094 
1095 	cursor_to_input();
1096 
1097 	/* Move to the end of the current word to the whitespace */
1098 	while (THIS_CHAR && !WHITESPACE(THIS_CHAR))
1099 		input_move_cursor(RIGHT, 1);
1100 
1101 	/* Move past the whitespace to the start of the next word */
1102 	while (THIS_CHAR && WHITESPACE(THIS_CHAR))
1103 		input_move_cursor(RIGHT, 1);
1104 }
1105 
1106 /* input_backward_word: move the cursor left on word in the input line */
BUILT_IN_KEYBINDING(input_backward_word)1107 BUILT_IN_KEYBINDING(input_backward_word)
1108 {
1109 	const char *spaces;
1110 
1111         if (!(spaces = get_string_var(WORD_BREAK_VAR)))
1112                 spaces = " \t";
1113 
1114 	cursor_to_input();
1115 
1116 	/* If already at the start of a word, move back a position */
1117 	if (LOGICAL_CURSOR > 0 && !WHITESPACE(THIS_CHAR) && WHITESPACE(PREV_CHAR))
1118 		input_move_cursor(LEFT, 1);
1119 
1120 	/* Move to the start of the current whitespace */
1121 	while (LOGICAL_CURSOR > 0 && WHITESPACE(THIS_CHAR))
1122 		input_move_cursor(LEFT, 1);
1123 
1124 	/* Move to the start of the current word */
1125 	while (LOGICAL_CURSOR > 0 && !WHITESPACE(THIS_CHAR))
1126 		input_move_cursor(LEFT, 1);
1127 
1128 	/* If we overshot our goal, then move forward */
1129 	/* But NOT if at start of input line! (July 6th, 1999) */
1130 	if (LOGICAL_CURSOR > 0 && (THIS_CHAR) && WHITESPACE(THIS_CHAR))
1131 		input_move_cursor(RIGHT, 1);
1132 }
1133 
1134 /*
1135  * input_delete_character -- Deletes the character currently under the
1136  * 			     input cursor.
1137  */
BUILT_IN_KEYBINDING(input_delete_character)1138 BUILT_IN_KEYBINDING(input_delete_character)
1139 {
1140 	/* Delete key does nothing at end of input */
1141 	if (!THIS_CHAR)
1142 		return;
1143 
1144 	/* Whack the character under cursor and redraw input line */
1145 	ov_strcpy(CURSOR_SPOT, NEXT_SPOT);
1146 	retokenize_input(LOGICAL_CURSOR);
1147 	update_input(last_input_screen, UPDATE_FROM_CURSOR);
1148 }
1149 
1150 
1151 /*
1152  * input_backspace -- Basically a combination of backward_character and
1153  *		      delete_character.  No, this is not significantly
1154  *		      more expensive than the old way.
1155  */
BUILT_IN_KEYBINDING(input_backspace)1156 BUILT_IN_KEYBINDING(input_backspace)
1157 {
1158 	/* Backspace key does nothing at start of input */
1159 	if (LOGICAL_CURSOR == 0)
1160 		return;
1161 
1162 	/* Do a cursor-left, followed by a delete. */
1163 	backward_character(0, NULL);
1164 	input_delete_character(0, NULL);
1165 }
1166 
1167 /*
1168  * input_beginning_of_line: moves the input cursor to the first character in
1169  * the input buffer
1170  */
BUILT_IN_KEYBINDING(input_beginning_of_line)1171 BUILT_IN_KEYBINDING(input_beginning_of_line)
1172 {
1173 	START = 0;
1174         LOGICAL_CURSOR=0;
1175 
1176 	update_input(last_input_screen, UPDATE_ALL);
1177 }
1178 
1179 /*
1180  * input_end_of_line: moves the input cursor to the last character in the
1181  * input buffer
1182  */
BUILT_IN_KEYBINDING(input_end_of_line)1183 BUILT_IN_KEYBINDING(input_end_of_line)
1184 {
1185 	while ((input_move_cursor(RIGHT, 0)))
1186 		;
1187 
1188 	update_input(last_input_screen, UPDATE_ALL);
1189 }
1190 
1191 /*
1192  * This removes every code ponit between 'start' and 'end' (inclusive)
1193  * The cursor is moved to 'start' because that is where the cut was
1194  * made as far as the user sees.
1195  */
cut_input(int start,int end)1196 static void	cut_input (int start, int end)
1197 {
1198 	char *	buffer;
1199 	size_t	size;
1200 	int	x;
1201 	int	startpos;
1202 	int	endpos;
1203 
1204 	startpos = LOGICAL_CHARS[start];
1205 	/* We need to sanity check 'end' here. */
1206 	if (end > MAXCOLS)
1207 		end = MAXCOLS;
1208 	endpos = LOGICAL_CHARS[end + 1];
1209 	strext2(&CUT_BUFFER, INPUT_BUFFER, startpos, endpos);
1210 
1211 	LOGICAL_CURSOR = start;
1212 	retokenize_input(start);
1213 	update_input(last_input_screen, UPDATE_ALL);
1214 }
1215 
1216 /*
1217  * To visualize:
1218  *
1219  *		This is the input buffer
1220  *			  ^			(the input cursor)
1221  * orig_pos points to the 'e'.
1222  * c is an 'e'.
1223  * LOGICAL_CURSOR is moved to the space between the 's' and the 't'.
1224  * The input buffer is changed to:
1225  *
1226  *		This is e input buffer
1227  *			^			(the input cursor)
1228  */
BUILT_IN_KEYBINDING(input_delete_to_previous_space)1229 BUILT_IN_KEYBINDING(input_delete_to_previous_space)
1230 {
1231 	int	anchor;
1232 
1233 	cursor_to_input();
1234 
1235 	if (LOGICAL_CURSOR <= 0)
1236 		return;
1237 
1238 	anchor = LOGICAL_CURSOR;
1239 	while (LOGICAL_CURSOR > 0 && !isspace(PREV_CHAR))
1240 		input_move_cursor(LEFT, 0);
1241 	cut_input(LOGICAL_CURSOR, anchor);
1242 }
1243 
1244 /*
1245  * input_delete_previous_word: deletes from the cursor backwards to the next
1246  * space character.  This is probably going to be the same effect as
1247  * delete_to_previous_space, but hey -- you know.
1248  */
BUILT_IN_KEYBINDING(input_delete_previous_word)1249 BUILT_IN_KEYBINDING(input_delete_previous_word)
1250 {
1251 	int	anchor;
1252 
1253 	cursor_to_input();
1254 
1255         if (LOGICAL_CURSOR <= 0)
1256 		return;
1257 
1258 	anchor = LOGICAL_CURSOR;
1259 	input_backward_word(0, NULL);
1260 	cut_input(LOGICAL_CURSOR, anchor);
1261 }
1262 
1263 /*
1264  * input_delete_next_word: deletes from the cursor to the end of the next
1265  * word
1266  */
BUILT_IN_KEYBINDING(input_delete_next_word)1267 BUILT_IN_KEYBINDING(input_delete_next_word)
1268 {
1269 	int	anchor;
1270 
1271 	cursor_to_input();
1272 
1273 	if (!THIS_CHAR)
1274 		return;
1275 
1276 	anchor = LOGICAL_CURSOR;
1277 	input_forward_word(0, NULL);
1278 	cut_input(anchor, LOGICAL_CURSOR - 1);
1279 }
1280 
1281 /*
1282  * input_add_character: adds the codepoint to the input buffer, repecting
1283  * the current overwrite/insert mode status, etc
1284  *
1285  * Arguments
1286  *	key	- A code poing to be added at the cursor point
1287  *	string	- unused
1288  */
BUILT_IN_KEYBINDING(input_add_character)1289 BUILT_IN_KEYBINDING(input_add_character)
1290 {
1291 	int	numcols;
1292 	int	numbytes;
1293 	unsigned char utf8str[8];
1294 	int	utf8strlen;
1295 
1296 #if 0
1297 	/* This test isn't used, but should it be? */
1298 	if ((numcols = codepoint_numcolumns(key)) == -1)
1299 		numcols = 1;
1300 #endif
1301 
1302 	utf8strlen = ucs_to_utf8(key, utf8str, sizeof(utf8str));
1303 
1304 	/* Don't permit the input buffer to get too big. */
1305 	if (strlen(INPUT_BUFFER) + utf8strlen  >= INPUT_BUFFER_SIZE)
1306 		return;
1307 
1308 	/*
1309 	 * If we are NOT at the end of the line, and we're inserting
1310 	 * then insert the char (expensive!)
1311 	 */
1312 	if (THIS_CHAR && get_int_var(INSERT_MODE_VAR))
1313 	{
1314 		char *ptr = LOCAL_COPY(CURSOR_SPOT);
1315 		*CURSOR_SPOT = 0;
1316 		ADD_TO_INPUT(utf8str);
1317 		ADD_TO_INPUT(ptr);
1318 	}
1319 
1320 	/*
1321 	 * Otherwise, we're either at the end of the input buffer,
1322 	 * or we're in overstrike mode.
1323 	 */
1324 	else if (THIS_CHAR == 0)
1325 	{
1326 		ADD_TO_INPUT(utf8str);
1327 	}
1328 	else
1329 	{
1330 		char *ptr = LOCAL_COPY(NEXT_SPOT);
1331 		*CURSOR_SPOT = 0;
1332 		ADD_TO_INPUT(utf8str);
1333 		ADD_TO_INPUT(ptr);
1334 	}
1335 
1336 	retokenize_input(LOGICAL_CURSOR);
1337 	update_input(last_input_screen, UPDATE_FROM_CURSOR);
1338 	input_move_cursor(RIGHT, 1);
1339 }
1340 
1341 /* input_clear_to_eol: erases from the cursor to the end of the input buffer */
BUILT_IN_KEYBINDING(input_clear_to_eol)1342 BUILT_IN_KEYBINDING(input_clear_to_eol)
1343 {
1344 	/* This doesnt really speak to the implementation, but it works.  */
1345 	/* Definitely not right? */
1346 	cut_input(LOGICAL_CURSOR, 9999);
1347 }
1348 
1349 /*
1350  * input_clear_to_bol: clears from the cursor to the beginning of the input
1351  * buffer
1352  */
BUILT_IN_KEYBINDING(input_clear_to_bol)1353 BUILT_IN_KEYBINDING(input_clear_to_bol)
1354 {
1355 	char	c;
1356 	char	*copy;
1357 
1358 	/* XXX Definitely not right */
1359 	cut_input(0, LOGICAL_CURSOR  - 1);
1360 
1361 	LOGICAL_CURSOR = 0;
1362 	update_input(last_input_screen, UPDATE_ALL);
1363 }
1364 
1365 /*
1366  * input_clear_line: clears entire input line
1367  */
BUILT_IN_KEYBINDING(input_clear_line)1368 BUILT_IN_KEYBINDING(input_clear_line)
1369 {
1370 	/* Only copy if there is input. -wd */
1371 	if (*INPUT_BUFFER)
1372 		cut_input(0, 999);
1373 
1374         memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1375 	LOGICAL_CURSOR = 0;
1376         update_input(last_input_screen, UPDATE_ALL);
1377 }
1378 
1379 /*
1380  * input_reset_line: clears entire input line, suitable for use in tabscripts
1381  * This does not mangle the cutbuffer, so you can use it to replace the input
1382  * line w/o any deleterious effects!
1383  */
BUILT_IN_KEYBINDING(input_reset_line)1384 BUILT_IN_KEYBINDING(input_reset_line)
1385 {
1386 	/* XXX This code is used in many places */
1387 	*INPUT_BUFFER = 0;
1388 	START = 0;
1389         LOGICAL_CURSOR=0;
1390         memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1391         update_input(last_input_screen, UPDATE_FROM_CURSOR);
1392 
1393         if (!string)
1394 		set_input(empty_string);
1395 	else
1396 		set_input(string);	/* This calls update_input() */
1397 }
1398 
1399 
1400 #if 0
1401 /*
1402  * input_transpose_characters: move the character before the cursor to
1403  * the position after the cursor.
1404  */
1405 BUILT_IN_KEYBINDING(input_transpose_characters)
1406 {
1407 	/*
1408 	 * This is tricky because the cursor never moves and there are three cases:
1409 	 *
1410 	 * 1. Cursor is at char 0: swap 0 and 1
1411 	 *	A_ B C		->	B_ A C
1412 	 * 2. Cursor is over a char: swap char under cursor and char before cursor
1413 	 *	A B_ C		->	B A_ C
1414 	 * 3. Cursor is at end (not on char): swap char before cursor and char before that
1415 	 *	A B C _		->	A C B _
1416 	 */
1417 
1418 	/* Case 1 -- swap char 0 and 1 */
1419 	if (LOGICAL_CURSOR == 0 && THIS_CHAR && NEXT_CHAR)
1420 	{
1421 		int	tc, nc;
1422 
1423 		tc = THIS_CHAR;
1424 		nc = NEXT_CHAR;
1425 		*THIS_SPOT = nc;
1426 		*NEXT_SPOT = tc;
1427 	}
1428 
1429 	/* Case 2 -- cursor over char, but not the first char */
1430 	else if (LOGICAL_CURSOR > 0 && THIS_CHAR && PREV_CHAR)
1431 	{
1432 		int	tc, pc;
1433 
1434 		tc = THIS_CHAR;
1435 		pc = PREV_CHAR;
1436 		*THIS_SPOT = pc;
1437 		*PREV_SPOT = tc;
1438 	}
1439 
1440 	/* Case 3 -- cursor at end */
1441 	else if (LOGICAL_CURSOR > 1 && !THIS_CHAR && PREV_CHAR && PREV_PREV_CHAR)
1442 	{
1443 		int	pc, ppc;
1444 
1445 		pc = PREV_CHAR;
1446 		ppc = PREV_PREV_CHAR;
1447 		*THIS_SPOT = ppc;
1448 		*PREV_PREV_SPOT = pc;
1449 	}
1450 
1451 	/* In all other cases, this is a no-op. */
1452 	update_input(last_input_screen, UPDATE_ALL);
1453 }
1454 #endif
1455 
1456 
BUILT_IN_KEYBINDING(refresh_inputline)1457 BUILT_IN_KEYBINDING(refresh_inputline)
1458 {
1459 	update_input(NULL, UPDATE_ALL);
1460 }
1461 
1462 /*
1463  * input_yank_cut_buffer: takes the contents of the cut buffer and inserts it
1464  * into the input line
1465  */
BUILT_IN_KEYBINDING(input_yank_cut_buffer)1466 BUILT_IN_KEYBINDING(input_yank_cut_buffer)
1467 {
1468 	char	*ptr = NULL;
1469 	int	x;
1470 
1471 	if (!CUT_BUFFER)
1472 		return;
1473 
1474 	ptr = LOCAL_COPY(CURSOR_SPOT);
1475 	*CURSOR_SPOT = 0;
1476 	ADD_TO_INPUT(CUT_BUFFER);
1477 	ADD_TO_INPUT(ptr);
1478 	retokenize_input(LOGICAL_CURSOR);
1479 
1480 	/* XXX strlen(cut_buffer) is wrong */
1481 	for (x = input_column_count(CUT_BUFFER); x > 0; x--)
1482 		input_move_cursor(RIGHT, 0);
1483 
1484 	update_input(last_input_screen, UPDATE_ALL);
1485 }
1486 
1487 
1488 
1489 /* BIND functions: */
BUILT_IN_KEYBINDING(forward_character)1490 BUILT_IN_KEYBINDING(forward_character)
1491 {
1492 	input_move_cursor(RIGHT, 1);
1493 }
1494 
BUILT_IN_KEYBINDING(backward_character)1495 BUILT_IN_KEYBINDING(backward_character)
1496 {
1497 	input_move_cursor(LEFT, 1);
1498 }
1499 
BUILT_IN_KEYBINDING(send_line)1500 BUILT_IN_KEYBINDING(send_line)
1501 {
1502 	int	server = from_server;
1503 	char *	line;
1504 	int	holding_already;
1505 	int	do_unscroll;
1506 
1507 	/* XXX No No No No No No XXX */
1508 	from_server = get_window_server(0);
1509 	line = LOCAL_COPY(INPUT_BUFFER);
1510 
1511 	/* Clear the input line before dispatching the command */
1512 	*INPUT_BUFFER = 0;
1513         START = 0;
1514         LOGICAL_CURSOR = 0;
1515         memset(INPUT_BUFFER, 0, sizeof(INPUT_BUFFER));
1516 
1517 	update_input(last_input_screen, UPDATE_ALL);
1518 
1519 	holding_already = window_is_holding(last_input_screen->current_window);
1520 	do_unscroll = window_is_scrolled_back(last_input_screen->current_window);
1521 
1522 	/*
1523 	 * Hold_mode is weird.  Hold_mode gets even weirder when you're in
1524 	 * scrollback mode.  Hold_mode users would expect that if they hit
1525 	 * <enter> when in scrollback mode, that they would scroll down, but
1526 	 * they would NOT unhold stuff.  But then you get into the problem of
1527 	 * whether to do the scrolldown before or after you run the command.
1528 	 */
1529 	if (holding_already == 0)
1530 		unhold_a_window(last_input_screen->current_window);
1531 
1532 	/* XXX This should be rolled together with fire_wait_prompt */
1533 	if (last_input_screen->promptlist &&
1534 		last_input_screen->promptlist->type == WAIT_PROMPT_LINE)
1535 	{
1536 		fire_normal_prompt(line);
1537 	}
1538 	else
1539 	{
1540 		int old = system_exception;
1541 
1542 		if (do_hook(INPUT_LIST, "%s", line))
1543 			parse_statement(line, 1, NULL);
1544 
1545 		system_exception = old;
1546 	}
1547 
1548 	if (holding_already == 1)
1549 		unhold_a_window(last_input_screen->current_window);
1550 
1551 	if (last_input_screen->current_window->holding_top_of_display &&
1552 			do_unscroll == 1)
1553 		scrollback_forwards(0, NULL);	/* XXX - Keybinding */
1554 
1555 	from_server = server;
1556 }
1557 
1558 /****************************************************************************/
1559 /*
1560  * None of the following keybindings have anything to do with the input line.
1561  * But they live here, because all of the keybindings are in this file.
1562  * Maybe some day I'll farm out the keybindings to the four corners.
1563  * Maybe I'll convince^H^H^H^H^H black into scripting them.
1564  */
1565 
1566 /* This keybinding should be scripted.  */
BUILT_IN_KEYBINDING(toggle_insert_mode)1567 BUILT_IN_KEYBINDING(toggle_insert_mode)
1568 {
1569 	char *	toggle;
1570 
1571 	toggle = alloca(7);
1572 	strlcpy(toggle, "TOGGLE", 7);
1573 	set_var_value(INSERT_MODE_VAR, toggle, 1);
1574 }
1575 
1576 /* This keybinding should be scripted. */
BUILT_IN_KEYBINDING(my_clear_screen)1577 BUILT_IN_KEYBINDING(my_clear_screen)
1578 {
1579 	clear_window_by_refnum(0, 1);
1580 }
1581 
1582 /* This keybinding should be scripted. */
BUILT_IN_KEYBINDING(input_unclear_screen)1583 BUILT_IN_KEYBINDING(input_unclear_screen)
1584 {
1585 	unclear_window_by_refnum(0, 1);
1586 }
1587 
1588 
1589 /* This keybinding should be in screen.c */
BUILT_IN_KEYBINDING(quote_char)1590 BUILT_IN_KEYBINDING(quote_char)
1591 {
1592 	last_input_screen->quote_hit = 1;
1593 }
1594 
1595 /*
1596  * These six functions are boomerang functions, which allow the highlight
1597  * characters to be bound by simply having these functions put in the
1598  * appropriate characters when you press any key to which you have bound
1599  * that highlight character. >;-)
1600  */
BUILT_IN_KEYBINDING(insert_bold)1601 BUILT_IN_KEYBINDING(insert_bold)
1602 {
1603 	input_add_character(BOLD_TOG, string);
1604 }
1605 
BUILT_IN_KEYBINDING(insert_reverse)1606 BUILT_IN_KEYBINDING(insert_reverse)
1607 {
1608 	input_add_character(REV_TOG, string);
1609 }
1610 
BUILT_IN_KEYBINDING(insert_underline)1611 BUILT_IN_KEYBINDING(insert_underline)
1612 {
1613 	input_add_character(UND_TOG, string);
1614 }
1615 
BUILT_IN_KEYBINDING(highlight_off)1616 BUILT_IN_KEYBINDING(highlight_off)
1617 {
1618 	input_add_character(ALL_OFF, string);
1619 }
1620 
BUILT_IN_KEYBINDING(insert_blink)1621 BUILT_IN_KEYBINDING(insert_blink)
1622 {
1623 	input_add_character(BLINK_TOG, string);
1624 }
1625 
BUILT_IN_KEYBINDING(insert_altcharset)1626 BUILT_IN_KEYBINDING(insert_altcharset)
1627 {
1628 	input_add_character(ALT_TOG, string);
1629 }
1630 
BUILT_IN_KEYBINDING(insert_italic)1631 BUILT_IN_KEYBINDING(insert_italic)
1632 {
1633 	input_add_character(ITALIC_TOG, string);
1634 }
1635 
1636 /* type_text: the BIND function TYPE_TEXT */
BUILT_IN_KEYBINDING(type_text)1637 BUILT_IN_KEYBINDING(type_text)
1638 {
1639 	char *	ptr;
1640 	int	x, totalcols;
1641 
1642 	ptr = LOCAL_COPY(CURSOR_SPOT);
1643 	*CURSOR_SPOT = 0;
1644 	ADD_TO_INPUT(string);
1645 	ADD_TO_INPUT(ptr);
1646 	retokenize_input(LOGICAL_CURSOR);
1647 
1648 	/* Now skip over what we just typed. */
1649 	totalcols = input_column_count(string);
1650 	for (x = totalcols; x > 0; x--)
1651 		input_move_cursor(RIGHT, 0);
1652 
1653 	update_input(last_input_screen, UPDATE_ALL);
1654 }
1655 
1656 /* parse_text: the bindable function that executes its string */
BUILT_IN_KEYBINDING(parse_text)1657 BUILT_IN_KEYBINDING(parse_text)
1658 {
1659 	int	old = system_exception;
1660 
1661 	if (string)
1662 		runcmds(string, empty_string);
1663 	system_exception = old;
1664 }
1665 
BUILT_IN_FUNCTION(function_inputctl,input)1666 BUILT_IN_FUNCTION(function_inputctl, input)
1667 {
1668 	char 	*verb, *domain;
1669 	int	verblen, domainlen;
1670         char    *ret = NULL;
1671         int     old_status_update;
1672 
1673         GET_FUNC_ARG(verb, input);
1674         verblen = strlen(verb);
1675         if (!my_strnicmp(verb, "GET", verblen)) {
1676 	    GET_FUNC_ARG(domain, input)
1677 	    domainlen = strlen(domain);
1678 
1679 	    if (!my_strnicmp(domain, "CUTBUFFER", domainlen)) {
1680 		RETURN_STR((const char *)CUT_BUFFER);
1681 	    }
1682 	}
1683         else if (!my_strnicmp(verb, "SET", verblen)) {
1684 	    GET_FUNC_ARG(domain, input)
1685 	    domainlen = strlen(domain);
1686 
1687 	    if (!my_strnicmp(domain, "CUTBUFFER", domainlen)) {
1688 		malloc_strcpy((char **)&CUT_BUFFER, input);
1689 		RETURN_STR((const char *)CUT_BUFFER);
1690 	    }
1691 	}
1692 
1693 	RETURN_EMPTY;
1694 }
1695 
1696