1 /******************************************************************************
2 *   This file is part of TinTin++                                             *
3 *                                                                             *
4 *   Copyright 2004-2020 Igor van den Hoven                                    *
5 *                                                                             *
6 *   TinTin++ is free software; you can redistribute it and/or modify          *
7 *   it under the terms of the GNU General Public License as published by      *
8 *   the Free Software Foundation; either version 3 of the License, or         *
9 *   (at your option) any later version.                                       *
10 *                                                                             *
11 *   This program is distributed in the hope that it will be useful,           *
12 *   but WITHOUT ANY WARRANTY; without even the implied warranty of            *
13 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the             *
14 *   GNU General Public License for more details.                              *
15 *                                                                             *
16 *   You should have received a copy of the GNU General Public License         *
17 *   along with TinTin++.  If not, see https://www.gnu.org/licenses.           *
18 ******************************************************************************/
19 
20 /******************************************************************************
21 *                               T I N T I N + +                               *
22 *                                                                             *
23 *                      coded by Igor van den Hoven 2006                       *
24 ******************************************************************************/
25 
26 #include "tintin.h"
27 
DO_COMMAND(do_cursor)28 DO_COMMAND(do_cursor)
29 {
30 	int cnt;
31 
32 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
33 
34 	if (*arg1 == 0)
35 	{
36 		tintin_header(ses, 80, " CURSOR OPTIONS ");
37 
38 		for (cnt = 0 ; cursor_table[cnt].fun ; cnt++)
39 		{
40 			if (*cursor_table[cnt].desc)
41 			{
42 				convert_meta(cursor_table[cnt].code, arg2, FALSE);
43 
44 				tintin_printf2(ses, "  [%-18s] [%-8s] %s", cursor_table[cnt].name, arg2, cursor_table[cnt].desc);
45 			}
46 		}
47 		tintin_header(ses, 80, "");
48 	}
49 	else
50 	{
51 		for (cnt = 0 ; *cursor_table[cnt].name ; cnt++)
52 		{
53 			if (is_abbrev(arg1, cursor_table[cnt].name))
54 			{
55 				cursor_table[cnt].fun(ses, arg);
56 
57 				return ses;
58 			}
59 		}
60 		show_error(ses, LIST_COMMAND, "#ERROR: #CURSOR {%s} IS NOT A VALID OPTION.", arg1);
61 	}
62 	return ses;
63 }
64 
65 // strlen with offset.
66 
inputline_str_str_len(int start,int end)67 int inputline_str_str_len(int start, int end)
68 {
69 	int raw_cnt, str_cnt, ret_cnt, width;
70 
71 	raw_cnt = str_cnt = ret_cnt = 0;
72 
73 	while (raw_cnt < gtd->ses->input->raw_len)
74 	{
75 		if (str_cnt >= end)
76 		{
77 			break;
78 		}
79 
80 		raw_cnt += get_vt102_width(gtd->ses, &gtd->ses->input->buf[raw_cnt], &width);
81 
82 		if (str_cnt >= start)
83 		{
84 			ret_cnt += width;
85 		}
86 		str_cnt += width;
87 	}
88 	return ret_cnt;
89 }
90 
91 // raw range
92 
inputline_raw_str_len(int raw_start,int raw_end)93 int inputline_raw_str_len(int raw_start, int raw_end)
94 {
95 	int raw_cnt, str_len, size, width;
96 
97 	raw_cnt = raw_start;
98 	str_len = 0;
99 
100 	while (raw_cnt < gtd->ses->input->raw_len)
101 	{
102 		if (raw_end >= 0 && raw_cnt >= raw_end)
103 		{
104 			break;
105 		}
106 
107 		size = get_vt102_width(gtd->ses, &gtd->ses->input->buf[raw_cnt], &width);
108 
109 		raw_cnt += size;
110 		str_len += width;
111 	}
112 	return str_len;
113 }
114 
115 // display range
116 
inputline_str_raw_len(int str_start,int str_end)117 int inputline_str_raw_len(int str_start, int str_end)
118 {
119 	int raw_cnt, str_cnt, ret_cnt, size, width;
120 
121 	raw_cnt = str_cnt = ret_cnt = 0;
122 
123 	while (raw_cnt < gtd->ses->input->raw_len)
124 	{
125 		if (str_end >= 0 && str_cnt >= str_end)
126 		{
127 			break;
128 		}
129 
130 		size = get_vt102_width(gtd->ses, &gtd->ses->input->buf[raw_cnt], &width);
131 
132 		if (str_cnt >= str_start)
133 		{
134 			ret_cnt += size;
135 		}
136 		raw_cnt += size;
137 		str_cnt += width;
138 	}
139 	return ret_cnt;
140 }
141 
inputline_raw_raw_len(int start,int end)142 int inputline_raw_raw_len(int start, int end)
143 {
144 	if (start > end)
145 	{
146 		return 0;
147 	}
148 	return end - start;
149 }
150 
inputline_cur_off(void)151 int inputline_cur_off(void)
152 {
153 	int off;
154 
155 	off = gtd->ses->input->str_off;
156 
157 	off += gtd->ses->input->top_col - 1;
158 
159 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
160 	{
161 		off += 10;
162 	}
163 
164 	return off;
165 }
166 
inputline_rows(struct session * ses)167 int inputline_rows(struct session *ses)
168 {
169 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
170 	{
171 		return 1;
172 	}
173 	return 1 + ses->input->bot_row - ses->input->top_row;
174 }
175 
176 // Get string length of the input area
177 
inputline_max_str_len(void)178 int inputline_max_str_len(void)
179 {
180 	int result = 1 + gtd->ses->input->bot_col - gtd->ses->input->top_col;
181 
182 	result -= gtd->ses->input->str_off - 1;
183 
184 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
185 	{
186 		result -= 20;
187 	}
188 
189 	return UMAX(1, result);
190 }
191 
inputline_cur_str_len(void)192 int inputline_cur_str_len(void)
193 {
194 	return inputline_str_str_len(gtd->ses->input->str_hid, gtd->ses->input->str_hid + inputline_max_str_len());
195 }
196 
inputline_editor(void)197 int inputline_editor(void)
198 {
199 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
200 	{
201 		return FALSE;
202 	}
203 
204 	if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT))
205 	{
206 		return FALSE;
207 	}
208 	return TRUE;
209 }
210 
inputline_multiline(void)211 int inputline_multiline(void)
212 {
213 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
214 	{
215 		return FALSE;
216 	}
217 
218 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT))
219 	{
220 		return FALSE;
221 	}
222 
223 	if (gtd->ses->input->top_row == gtd->ses->input->bot_row)
224 	{
225 		return FALSE;
226 	}
227 
228 	return TRUE;
229 }
230 
inputline_tab_valid(void)231 int inputline_tab_valid(void)
232 {
233 	if (gtd->ses->input->raw_len == 0)
234 	{
235 		return FALSE;
236 	}
237 
238 	if (gtd->ses->input->buf[gtd->ses->input->raw_len - 1] == ' ')
239 	{
240 		return FALSE;
241 	}
242 	return TRUE;
243 }
244 
inputline_set_row(int row)245 void inputline_set_row(int row)
246 {
247 	struct edit_data *edit = gtd->ses->input->edit;
248 
249 	if (row == gtd->ses->input->cur_row)
250 	{
251 		return;
252 	}
253 
254 	if (inputline_editor())
255 	{
256 		str_cpy(&edit->line[edit->update]->str, gtd->ses->input->buf);
257 
258 		edit->update = URANGE(0, edit->update + (row - gtd->ses->input->cur_row), edit->used - 1);
259 
260 		inputline_set(edit->line[edit->update]->str, gtd->ses->input->str_pos);
261 	}
262 	gtd->ses->input->cur_row = row;
263 }
264 
inputline_position(int col)265 void inputline_position(int col)
266 {
267 	int size, width;
268 
269 	if (col == -1)
270 	{
271 		gtd->ses->input->raw_pos = gtd->ses->input->raw_len;
272 		gtd->ses->input->str_pos = gtd->ses->input->str_len;
273 
274 		return;
275 	}
276 
277 	gtd->ses->input->raw_pos = 0;
278 	gtd->ses->input->str_pos = 0;
279 
280 	while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len)
281 	{
282 		size = get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
283 
284 		if (gtd->ses->input->str_pos + width > col)
285 		{
286 			break;
287 		}
288 		gtd->ses->input->raw_pos += size;
289 		gtd->ses->input->str_pos += width;
290 	}
291 
292 	if (inputline_editor() && gtd->ses->input->str_len < col)
293 	{
294 		gtd->ses->input->str_pos = col;
295 	}
296 }
297 
inputline_insert(char * arg,int str_pos)298 void inputline_insert(char *arg, int str_pos)
299 {
300 	int raw_len, str_len;
301 
302 	if (HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
303 	{
304 		if (gtd->ses->input->raw_len > INPUT_SIZE)
305 		{
306 			tintin_printf2(gtd->ses, "#CONFIG CHILD LOCK: YOU ARE CONFINED TO %d BYTES OF INPUT.", INPUT_SIZE);
307 
308 			str_cpy(&gtd->ses->input->cut, "");
309 
310 			inputline_set("", -1);
311 
312 			return;
313 		}
314 	}
315 
316 	raw_len = strip_vt102_width(gtd->ses, arg, &str_len);
317 
318 	if (str_len && HAS_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT) && gtd->ses->input->raw_len != gtd->ses->input->raw_pos)
319 	{
320 		int cnt, loop;
321 
322 		cnt = UMAX(gtd->ses->input->str_pos, gtd->ses->input->str_len - str_len);
323 
324 		while (gtd->ses->input->str_len > cnt)
325 		{
326 			loop = gtd->ses->input->raw_len;
327 
328 			cursor_delete(gtd->ses, NULL);
329 
330 			if (loop == gtd->ses->input->raw_len)
331 			{
332 				tintin_printf2(gtd->ses, "inputline_insert: infinite loop detected.");
333 				break;
334 			}
335 		}
336 	}
337 	str_ins(&gtd->ses->input->buf, gtd->ses->input->raw_pos, arg);
338 
339 	gtd->ses->input->raw_len += raw_len;
340 	gtd->ses->input->str_len += str_len;
341 
342 	if (str_pos == -1)
343 	{
344 		gtd->ses->input->raw_pos += raw_len;
345 		gtd->ses->input->str_pos += str_len;
346 	}
347 }
348 
inputline_set(char * arg,int str_pos)349 void inputline_set(char *arg, int str_pos)
350 {
351 	int raw_len, str_len;
352 
353 	str_cpy(&gtd->ses->input->buf, arg);
354 
355 	raw_len = strip_vt102_width(gtd->ses, arg, &str_len);
356 
357 	gtd->ses->input->raw_len = raw_len;
358 	gtd->ses->input->str_len = str_len;
359 
360 	gtd->ses->input->raw_pos = raw_len;
361 	gtd->ses->input->str_pos = str_len;
362 
363 	inputline_position(str_pos);
364 }
365 
inputline_cap(char * arg)366 void inputline_cap(char *arg)
367 {
368 	int raw_len, str_len;
369 
370 	gtd->ses->input->raw_len = gtd->ses->input->raw_pos;
371 	gtd->ses->input->str_len = gtd->ses->input->str_pos;
372 
373 	str_cap(&gtd->ses->input->buf, gtd->ses->input->raw_pos, arg);
374 
375 	raw_len = strip_vt102_width(gtd->ses, arg, &str_len);
376 
377 	gtd->ses->input->raw_len += raw_len;
378 	gtd->ses->input->str_len += str_len;
379 
380 	gtd->ses->input->raw_pos += raw_len;
381 	gtd->ses->input->str_pos += str_len;
382 }
383 
384 
385 // Get the position of the cursor
386 
inputline_cur_row(void)387 int inputline_cur_row(void)
388 {
389 	return gtd->ses->input->cur_row;
390 }
391 
inputline_cur_col(void)392 int inputline_cur_col(void)
393 {
394 	if (inputline_editor())
395 	{
396 		return inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
397 	}
398 
399 	if (gtd->ses->input->top_row == gtd->ses->input->bot_row)
400 	{
401 		return inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
402 	}
403 	else
404 	{
405 		return inputline_cur_off() + gtd->ses->input->str_pos % inputline_max_str_len();
406 	}
407 }
408 
inputline_erase(void)409 void inputline_erase(void)
410 {
411 	input_printf("\e[%dG\e[%dX", inputline_cur_off(), inputline_max_str_len());
412 }
413 
414 // Get the maximum number of rows of the input region
415 
inputline_max_row(void)416 int inputline_max_row(void)
417 {
418 	return 1 + gtd->ses->input->bot_row - gtd->ses->input->top_row;
419 }
420 
421 // Check for invalid characters.
422 
inputline_str_chk(int offset,int totlen)423 int inputline_str_chk(int offset, int totlen)
424 {
425 	int size;
426 
427 	while (offset < totlen)
428 	{
429 		if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_EUC))
430 		{
431 			if (is_euc_head(gtd->ses, &gtd->ses->input->buf[offset]))
432 			{
433 				size = get_euc_size(gtd->ses, &gtd->ses->input->buf[offset]);
434 
435 				if (size == 1 || offset + size > totlen)
436 				{
437 					return FALSE;
438 				}
439 				offset += size;
440 			}
441 			else
442 			{
443 				offset += 1;
444 			}
445 		}
446 		else if (HAS_BIT(gtd->ses->charset, CHARSET_FLAG_UTF8))
447 		{
448 			if (is_utf8_head(&gtd->ses->input->buf[offset]))
449 			{
450 				size = get_utf8_size(&gtd->ses->input->buf[offset]);
451 
452 				if (size == 1 || offset + size > totlen)
453 				{
454 					return FALSE;
455 				}
456 				offset += size;
457 			}
458 			else
459 			{
460 				offset += 1;
461 			}
462 		}
463 		else
464 		{
465 			return TRUE;
466 		}
467 	}
468 	return TRUE;
469 }
470 
DO_CURSOR(cursor_backspace)471 DO_CURSOR(cursor_backspace)
472 {
473 	if (gtd->ses->input->raw_pos == 0)
474 	{
475 		if (inputline_editor())
476 		{
477 			if (gtd->ses->input->edit->update > 0)
478 			{
479 				cursor_move_up(ses, NULL);
480 				cursor_end(ses, NULL);
481 				cursor_delete(ses, NULL);
482 
483 				cursor_redraw_edit(ses, arg);
484 			}
485 		}
486 		return;
487 	}
488 
489 	cursor_move_left(ses, NULL);
490 	cursor_delete(ses, arg);
491 
492 	modified_input();
493 }
494 
DO_CURSOR(cursor_brace)495 DO_CURSOR(cursor_brace)
496 {
497 	char arg1[BUFFER_SIZE];
498 
499 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
500 
501 	if (is_abbrev(arg1, "OPEN"))
502 	{
503 		inputline_insert("{", -1);
504 	}
505 	else if (is_abbrev(arg1, "CLOSE"))
506 	{
507 		inputline_insert("}", -1);
508 	}
509 	else
510 	{
511 		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR {BRACE} {OPEN|CLOSE}");
512 	}
513 	cursor_redraw_line(ses, arg);
514 
515 	modified_input();
516 }
517 
DO_CURSOR(cursor_buffer_down)518 DO_CURSOR(cursor_buffer_down)
519 {
520 	if (inputline_editor())
521 	{
522 		int update = gtd->ses->input->edit->update;
523 
524 		if (update + 1 >= gtd->ses->input->edit->used)
525 		{
526 			return;
527 		}
528 
529 		str_cpy(&gtd->ses->input->edit->line[update]->str, gtd->ses->input->buf);
530 
531 		update = UMIN(gtd->ses->input->edit->used - 1, update + UMAX(1, inputline_rows(gtd->ses) / 2));
532 
533 		inputline_set(gtd->ses->input->edit->line[update]->str, gtd->ses->input->str_pos);
534 
535 		gtd->ses->input->edit->update = update;
536 
537 		cursor_redraw_edit(ses, arg);
538 
539 		return;
540 	}
541 
542 	command(ses, do_buffer, "down %s", arg);
543 }
544 
DO_CURSOR(cursor_buffer_end)545 DO_CURSOR(cursor_buffer_end)
546 {
547 	int update;
548 
549 	if (inputline_editor())
550 	{
551 		update = gtd->ses->input->edit->update;
552 
553 		if (update + 1 >= gtd->ses->input->edit->used && gtd->ses->input->cur_row == gtd->ses->input->bot_row)
554 		{
555 			return;
556 		}
557 
558 		str_cpy(&gtd->ses->input->edit->line[update]->str, gtd->ses->input->buf);
559 
560 		update = gtd->ses->input->edit->used - 1;
561 
562 		inputline_set(gtd->ses->input->edit->line[update]->str, gtd->ses->input->str_pos);
563 
564 		gtd->ses->input->edit->update = update;
565 
566 		gtd->ses->input->cur_row = gtd->ses->input->bot_row;
567 
568 		cursor_redraw_edit(ses, arg);
569 
570 		return;
571 	}
572 	buffer_end(ses, "", "", "");
573 }
574 
DO_CURSOR(cursor_buffer_home)575 DO_CURSOR(cursor_buffer_home)
576 {
577 	if (inputline_editor())
578 	{
579 		int update = gtd->ses->input->edit->update;
580 
581 		if (update <= 0 && gtd->ses->input->cur_row == gtd->ses->input->top_row)
582 		{
583 			return;
584 		}
585 
586 		str_cpy(&gtd->ses->input->edit->line[update]->str, gtd->ses->input->buf);
587 
588 		inputline_set(gtd->ses->input->edit->line[0]->str, gtd->ses->input->str_pos);
589 
590 		gtd->ses->input->edit->update = 0;
591 
592 		gtd->ses->input->cur_row = gtd->ses->input->top_row;
593 
594 		cursor_redraw_edit(ses, arg);
595 
596 		return;
597 	}
598 
599 	buffer_home(ses, "", "", "");
600 }
601 
DO_CURSOR(cursor_buffer_lock)602 DO_CURSOR(cursor_buffer_lock)
603 {
604 	command(ses, do_buffer, "lock %s", arg);
605 }
606 
DO_CURSOR(cursor_buffer_up)607 DO_CURSOR(cursor_buffer_up)
608 {
609 	if (inputline_editor())
610 	{
611 		int update = gtd->ses->input->edit->update;
612 
613 		if (update <= 0)
614 		{
615 			return;
616 		}
617 
618 		str_cpy(&gtd->ses->input->edit->line[update]->str, gtd->ses->input->buf);
619 
620 		update = UMAX(0, update - UMAX(1, inputline_rows(gtd->ses) / 2));
621 
622 		inputline_set(gtd->ses->input->edit->line[update]->str, gtd->ses->input->str_pos);
623 
624 		gtd->ses->input->edit->update = update;
625 
626 		cursor_redraw_edit(ses, arg);
627 
628 		return;
629 	}
630 
631 	command(ses, do_buffer, "up %s", arg);
632 }
633 
DO_CURSOR(cursor_page)634 DO_CURSOR(cursor_page)
635 {
636 	char arg1[BUFFER_SIZE];
637 
638 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
639 
640 	if (is_abbrev(arg1, "DOWN"))
641 	{
642 		return cursor_buffer_down(ses, arg);
643 	}
644 	if (is_abbrev(arg1, "END"))
645 	{
646 		return cursor_buffer_end(ses, arg);
647 	}
648 	if (is_abbrev(arg1, "LOCK"))
649 	{
650 		return cursor_buffer_lock(ses, arg);
651 	}
652 	if (is_abbrev(arg1, "HOME"))
653 	{
654 		return cursor_buffer_home(ses, arg);
655 	}
656 	if (is_abbrev(arg1, "UP"))
657 	{
658 		return cursor_buffer_up(ses, arg);
659 	}
660 	show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR PAGE {DOWN|END|LOCK|HOME|UP}");
661 }
662 
DO_CURSOR(cursor_check_line)663 DO_CURSOR(cursor_check_line)
664 {
665 	if (arg == NULL)
666 	{
667 		return;
668 	}
669 
670 	int str_max = inputline_max_str_len();
671 
672 	if (inputline_multiline())
673 	{
674 		if (gtd->ses->input->cur_row != gtd->ses->input->top_row + (gtd->ses->input->str_pos - gtd->ses->input->str_hid) / str_max)
675 		{
676 			return cursor_redraw_line(ses, "");
677 		}
678 
679 		if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 1)
680 		{
681 			return cursor_redraw_line(ses, "");
682 		}
683 	}
684 	else
685 	{
686 		if (gtd->ses->input->str_pos - gtd->ses->input->str_hid > str_max - 3)
687 		{
688 			return cursor_redraw_line(ses, "");
689 		}
690 
691 		if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
692 		{
693 			return cursor_redraw_line(ses, "");
694 		}
695 	}
696 	gtd->ses->cur_col = inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
697 }
698 
DO_CURSOR(cursor_check_line_modified)699 DO_CURSOR(cursor_check_line_modified)
700 {
701 	int max, width;
702 
703 	if (gtd->ses->input->raw_len != str_len(gtd->ses->input->buf))
704 	{
705 		tintin_printf2(ses, "\e[1;31merror: cursor_check_line_modified1: raw: %d vs %d", gtd->ses->input->raw_len, str_len(gtd->ses->input->buf));
706 	}
707 
708 	strip_vt102_width(gtd->ses, gtd->ses->input->buf, &width);
709 
710 	if (gtd->ses->input->str_len != width)
711 	{
712 		tintin_printf2(ses, "\e[1;31merror: cursor_check_line_modified2: str: %d vs %d", gtd->ses->input->str_len, width);
713 	}
714 
715 	if (gtd->ses->input->str_pos > gtd->ses->input->str_len)
716 	{
717 		return cursor_end(ses, "");
718 	}
719 
720 	max = inputline_max_str_len();
721 
722 	if (inputline_multiline())
723 	{
724 		if (gtd->ses->input->str_len / max != gtd->ses->input->str_pos / max)
725 		{
726 			return cursor_redraw_line(ses, "");
727 		}
728 
729 		if (gtd->ses->input->str_pos % max == 0)
730 		{
731 			return cursor_redraw_line(ses, "");
732 		}
733 	}
734 	return cursor_check_line(ses, "");
735 }
736 
DO_CURSOR(cursor_clear_left)737 DO_CURSOR(cursor_clear_left)
738 {
739 	if (gtd->ses->input->raw_pos == 0)
740 	{
741 		if (inputline_editor())
742 		{
743 			cursor_backspace(ses, arg);
744 		}
745 		return;
746 	}
747 
748 	str_cpy_printf(&gtd->ses->input->cut, "%.*s", gtd->ses->input->raw_pos, gtd->ses->input->buf);
749 
750 	str_mov(&gtd->ses->input->buf, 0, gtd->ses->input->raw_pos);
751 
752 	gtd->ses->input->raw_len -= gtd->ses->input->raw_pos;
753 	gtd->ses->input->str_len -= gtd->ses->input->str_pos;
754 
755 	gtd->ses->input->raw_pos  = 0;
756 	gtd->ses->input->str_pos  = 0;
757 
758 	cursor_redraw_line(ses, "");
759 
760 	modified_input();
761 }
762 
DO_CURSOR(cursor_remove_line)763 DO_CURSOR(cursor_remove_line)
764 {
765 	str_cpy(&gtd->ses->input->cut, gtd->ses->input->buf);
766 
767 	inputline_set("", -1);
768 
769 	cursor_delete(ses, arg);
770 }
771 
DO_CURSOR(cursor_clear_line)772 DO_CURSOR(cursor_clear_line)
773 {
774 	if (inputline_editor())
775 	{
776 		return cursor_remove_line(ses, arg);
777 	}
778 
779 	if (gtd->ses->input->raw_len == 0)
780 	{
781 		return;
782 	}
783 
784 	str_cpy(&gtd->ses->input->cut, gtd->ses->input->buf);
785 
786 	inputline_set("", -1);
787 
788 	gtd->ses->input->str_hid = 0;
789 
790 	cursor_redraw_line(ses, "");
791 
792 	modified_input();
793 }
794 
DO_CURSOR(cursor_clear_right)795 DO_CURSOR(cursor_clear_right)
796 {
797 	if (gtd->ses->input->raw_pos == gtd->ses->input->raw_len)
798 	{
799 		if (inputline_editor())
800 		{
801 			cursor_delete(ses, arg);
802 		}
803 		return;
804 	}
805 
806 	str_cpy(&gtd->ses->input->cut, &gtd->ses->input->buf[gtd->ses->input->raw_pos]);
807 
808 	str_cap(&gtd->ses->input->buf, gtd->ses->input->raw_pos, "");
809 
810 	gtd->ses->input->raw_len = gtd->ses->input->raw_pos;
811 	gtd->ses->input->str_len = gtd->ses->input->str_pos;
812 
813 //	input_printf("\e[%dX", inputline_max_str_len() - inputline_str_str_len(gtd->ses->input->str_hid, gtd->ses->input->str_pos));
814 
815 	cursor_redraw_line(ses, "");
816 
817 	modified_input();
818 }
819 
DO_CURSOR(cursor_convert_meta)820 DO_CURSOR(cursor_convert_meta)
821 {
822 	SET_BIT(gtd->ses->input->flags, INPUT_FLAG_CONVERTMETACHAR);
823 }
824 
DO_CURSOR(cursor_delete_or_exit)825 DO_CURSOR(cursor_delete_or_exit)
826 {
827 	if (gtd->ses->input->raw_len == 0)
828 	{
829 		if (ses == gts)
830 		{
831 			command(ses, do_end, "");
832 		}
833 		else
834 		{
835 			command(ses, do_zap, "");
836 		}
837 	}
838 	else
839 	{
840 		cursor_delete(ses, arg);
841 	}
842 }
843 
DO_CURSOR(cursor_delete)844 DO_CURSOR(cursor_delete)
845 {
846 	int size, width;
847 
848 	if (gtd->ses->input->raw_len == 0)
849 	{
850 		if (inputline_editor())
851 		{
852 			if (gtd->ses->input->edit->update + 1 < gtd->ses->input->edit->used)
853 			{
854 				remove_line(gtd->ses->input->edit, gtd->ses->input->edit->update);
855 
856 				inputline_set(gtd->ses->input->edit->line[gtd->ses->input->edit->update]->str, 0);
857 
858 				cursor_redraw_edit(ses, arg);
859 
860 				modified_input();
861 			}
862 		}
863 		return;
864 	}
865 
866 	if (gtd->ses->input->raw_len == gtd->ses->input->raw_pos)
867 	{
868 		if (inputline_editor())
869 		{
870 			if (gtd->ses->input->edit->update + 1 < gtd->ses->input->edit->used)
871 			{
872 				inputline_insert(gtd->ses->input->edit->line[gtd->ses->input->edit->update + 1]->str, 0);
873 
874 				remove_line(gtd->ses->input->edit, gtd->ses->input->edit->update + 1);
875 
876 				cursor_redraw_edit(ses, arg);
877 
878 				modified_input();
879 			}
880 		}
881 		return;
882 	}
883 
884 	size = get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
885 
886 	gtd->ses->input->raw_len -= size;
887 	gtd->ses->input->str_len -= width;
888 
889 	str_mov(&gtd->ses->input->buf, gtd->ses->input->raw_pos, gtd->ses->input->raw_pos + size);
890 
891 	if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
892 	{
893 		while (gtd->ses->input->raw_len > gtd->ses->input->raw_pos)
894 		{
895 			if (!is_utf8_head(&gtd->ses->input->buf[gtd->ses->input->raw_pos]))
896 			{
897 				break;
898 			}
899 			size = get_utf8_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width, NULL);
900 
901 			if (width)
902 			{
903 				break;
904 			}
905 			gtd->ses->input->raw_len -= size;
906 
907 			str_mov(&gtd->ses->input->buf, gtd->ses->input->raw_pos, gtd->ses->input->raw_pos + size);
908 		}
909 	}
910 
911 	if (gtd->ses->input->raw_len == gtd->ses->input->raw_pos)
912 	{
913 		input_printf("\e[1X");
914 		cursor_check_line(ses, arg);
915 	}
916 	else
917 	{
918 		cursor_redraw_line(ses, "");
919 	}
920 	modified_input();
921 }
922 
DO_CURSOR(cursor_delete_word_left)923 DO_CURSOR(cursor_delete_word_left)
924 {
925 	int index_raw, index_str, span_raw, width;
926 
927 	if (gtd->ses->input->raw_pos == 0)
928 	{
929 		if (inputline_editor())
930 		{
931 			return cursor_backspace(ses, arg);
932 		}
933 		return;
934 	}
935 
936 	index_raw = gtd->ses->input->raw_pos;
937 	index_str = gtd->ses->input->str_pos;
938 
939 	while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] == ' ')
940 	{
941 		gtd->ses->input->raw_pos--;
942 	}
943 
944 	while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] != ' ')
945 	{
946 		gtd->ses->input->raw_pos--;
947 	}
948 
949 	span_raw = gtd->ses->input->raw_pos;
950 
951 	while (span_raw < index_raw)
952 	{
953 		span_raw += get_vt102_width(gtd->ses, &gtd->ses->input->buf[span_raw], &width);
954 
955 		gtd->ses->input->str_pos -= width;
956 	}
957 
958 	str_cpy_printf(&gtd->ses->input->cut, "%.*s", index_raw - gtd->ses->input->raw_pos, &gtd->ses->input->buf[gtd->ses->input->raw_pos]);
959 
960 	str_mov(&gtd->ses->input->buf, gtd->ses->input->raw_pos, index_raw);
961 
962 	gtd->ses->input->raw_len -= index_raw - gtd->ses->input->raw_pos;
963 	gtd->ses->input->str_len -= index_str - gtd->ses->input->str_pos;
964 
965 	cursor_redraw_line(ses, "");
966 
967 	modified_input();
968 }
969 
970 
DO_CURSOR(cursor_delete_word_right)971 DO_CURSOR(cursor_delete_word_right)
972 {
973 	int index_raw, index_str, size, width;
974 
975 	if (gtd->ses->input->raw_pos == gtd->ses->input->raw_len)
976 	{
977 		if (inputline_editor())
978 		{
979 			return cursor_delete(ses, arg);
980 		}
981 		return;
982 	}
983 
984 	index_raw = gtd->ses->input->raw_pos;
985 	index_str = gtd->ses->input->str_pos;
986 
987 	while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] == ' ')
988 	{
989 		gtd->ses->input->raw_pos++;
990 		gtd->ses->input->str_pos++;
991 	}
992 
993 	while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] != ' ')
994 	{
995 		size = get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
996 
997 		gtd->ses->input->raw_pos += size;
998 		gtd->ses->input->str_pos += width;
999 	}
1000 
1001 	str_cpy_printf(&gtd->ses->input->cut, "%.*s", gtd->ses->input->raw_pos - index_raw, &gtd->ses->input->buf[gtd->ses->input->raw_pos]);
1002 
1003 	str_mov(&gtd->ses->input->buf, index_raw, gtd->ses->input->raw_pos);
1004 
1005 	gtd->ses->input->raw_len -= gtd->ses->input->raw_pos - index_raw;
1006 	gtd->ses->input->str_len -= gtd->ses->input->str_pos - index_str;
1007 
1008 	gtd->ses->input->raw_pos = index_raw;
1009 	gtd->ses->input->str_pos = index_str;
1010 
1011 	cursor_redraw_line(ses, "");
1012 
1013 	modified_input();
1014 }
1015 
DO_CURSOR(cursor_echo)1016 DO_CURSOR(cursor_echo)
1017 {
1018 	char arg1[BUFFER_SIZE];
1019 
1020 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
1021 
1022 	if (*arg1 == 0)
1023 	{
1024 		TOG_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1025 	}
1026 	else if (!strcasecmp(arg1, "ON"))
1027 	{
1028 		SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1029 	}
1030 	else if (!strcasecmp(arg1, "OFF"))
1031 	{
1032 		DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1033 	}
1034 	else
1035 	{
1036 		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {ECHO} {ON|OFF}.");
1037 	}
1038 }
1039 
DO_CURSOR(cursor_end)1040 DO_CURSOR(cursor_end)
1041 {
1042 	gtd->ses->input->raw_pos = gtd->ses->input->raw_len;
1043 	gtd->ses->input->str_pos = inputline_raw_str_len(0, -1);
1044 
1045 	cursor_redraw_line(ses, arg);
1046 }
1047 
DO_CURSOR(cursor_enter)1048 DO_CURSOR(cursor_enter)
1049 {
1050 	int filesize;
1051 
1052 	push_call("cursor_enter(%p,%p)",ses,arg);
1053 
1054 	gtd->ses->input->str_hid = 0;
1055 
1056 	gtd->ses->input->raw_pos = 0;
1057 	gtd->ses->input->str_pos = 0;
1058 
1059 	if (inputline_editor())
1060 	{
1061 		char *str1 = str_alloc_stack(0);
1062 
1063 		DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
1064 
1065 		str_cpy(&gtd->ses->input->edit->line[gtd->ses->input->edit->update]->str, gtd->ses->input->buf);
1066 
1067 		filesize = str_save_editor(gtd->ses->input->edit, &str1);
1068 
1069 		check_all_events(gtd->ses, EVENT_FLAG_INPUT, 0, 4, "EDIT FINISHED", gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), str1);
1070 
1071 		if (*gtd->ses->input->edit_name)
1072 		{
1073 			check_all_events(gtd->ses, EVENT_FLAG_INPUT, 1, 4, "EDIT FINISHED %s", gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), gtd->ses->input->edit_name, str1);
1074 
1075 			if (check_all_events(gtd->ses, EVENT_FLAG_CATCH, 1, 4, "CATCH EDIT FINISHED %s", gtd->ses->input->edit_name, gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), str1))
1076 			{
1077 				cursor_enter_finish(ses, "");
1078 
1079 				pop_call();
1080 				return;
1081 			}
1082 		}
1083 
1084 		if (check_all_events(gtd->ses, EVENT_FLAG_CATCH, 0, 4, "CATCH EDIT FINISHED", gtd->ses->input->edit_name, ntos(gtd->ses->input->edit->used), ntos(filesize), str1))
1085 		{
1086 			cursor_enter_finish(ses, "");
1087 
1088 			pop_call();
1089 			return;
1090 		}
1091 	}
1092 
1093 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1094 	{
1095 		struct listroot *root = ses->list[LIST_HISTORY];
1096 
1097 		if (root->update >= 0 && root->update < root->used)
1098 		{
1099 			inputline_set(root->list[root->update]->arg1, -1);
1100 		}
1101 
1102 		DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1103 
1104 		gtd->ses->input->str_hid = 0;
1105 
1106 		gtd->ses->input->raw_pos = 0;
1107 		gtd->ses->input->str_pos = 0;
1108 	}
1109 	else if (*gtd->ses->input->buf == 0)
1110 	{
1111 		struct listroot *root = ses->list[LIST_HISTORY];
1112 
1113 		if (root->used && HAS_BIT(ses->config_flags, CONFIG_FLAG_REPEATENTER))
1114 		{
1115 			inputline_set(root->list[root->used - 1]->arg1, -1);
1116 		}
1117 		gtd->ses->input->str_hid = 0;
1118 
1119 		gtd->ses->input->raw_pos = 0;
1120 		gtd->ses->input->str_pos = 0;
1121 	}
1122 
1123 	if (HAS_BIT(gtd->ses->flags, SES_FLAG_SPLIT))
1124 	{
1125 		inputline_erase();
1126 	}
1127 	else
1128 	{
1129 		input_printf("\n");
1130 	}
1131 
1132 	SET_BIT(gtd->flags, TINTIN_FLAG_PROCESSINPUT);
1133 
1134 	modified_input();
1135 
1136 	pop_call();
1137 	return;
1138 }
1139 
DO_CURSOR(cursor_soft_enter)1140 DO_CURSOR(cursor_soft_enter)
1141 {
1142 	if (!inputline_editor())
1143 	{
1144 //		show_error(ses, LIST_COMMAND, "#ERROR: #CURSOR SOFT ENTER: YOU ARE NOT CURRENTLY EDITING.");
1145 
1146 		return cursor_enter(ses, arg);
1147 	}
1148 
1149 	insert_line(gtd->ses->input->edit, gtd->ses->input->edit->update + 1, &gtd->ses->input->buf[gtd->ses->input->raw_pos]);
1150 
1151 	str_cap(&gtd->ses->input->buf, gtd->ses->input->raw_pos, "");
1152 
1153 	if (gtd->ses->input->raw_pos != gtd->ses->input->raw_len)
1154 	{
1155 		cursor_clear_right(ses, NULL);
1156 	}
1157 
1158 	gtd->ses->input->str_hid = 0;
1159 
1160 	gtd->ses->input->raw_pos = 0;
1161 	gtd->ses->input->str_pos = 0;
1162 
1163 	cursor_move_down(ses, "");
1164 }
1165 
DO_CURSOR(cursor_enter_finish)1166 DO_CURSOR(cursor_enter_finish)
1167 {
1168 	if (inputline_editor())
1169 	{
1170 		cursor_redraw_line(gtd->ses, "");
1171 
1172 		return;
1173 	}
1174 
1175 	str_cpy(&ses->input->tmp, "");
1176 	str_cpy(&ses->input->buf, "");
1177 
1178 	ses->input->raw_len = 0;
1179 	ses->input->str_len = 0;
1180 	ses->input->raw_pos = 0;
1181 	ses->input->str_pos = 0;
1182 
1183 	ses->input->str_off = 1;
1184 	ses->input->str_hid = 0;
1185 
1186 	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_EDIT);
1187 
1188 	if (ses == gtd->ses && gtd->ses->scroll->line != -1)
1189 	{
1190 		cursor_check_line(gtd->ses, "");
1191 
1192 		buffer_end(gtd->ses, "", "", "");
1193 	}
1194 
1195 	if (ses == gtd->ses && HAS_BIT(gtd->ses->flags, SES_FLAG_SPLIT))
1196 	{
1197 		cursor_redraw_line(gtd->ses, "");
1198 	}
1199 }
1200 
DO_CURSOR(cursor_flag)1201 DO_CURSOR(cursor_flag)
1202 {
1203 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
1204 
1205 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
1206 	arg = sub_arg_in_braces(ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
1207 
1208 	if (is_abbrev(arg1, "EOL"))
1209 	{
1210 		if (*arg2 == 0)
1211 		{
1212 			TOG_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF);
1213 		}
1214 		else if (!strcasecmp(arg2, "CR"))
1215 		{
1216 			SET_BIT(ses->telopts, TELOPT_FLAG_CR);
1217 			DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
1218 			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1219 		}
1220 		else if (!strcasecmp(arg2, "LF"))
1221 		{
1222 			DEL_BIT(ses->telopts, TELOPT_FLAG_CR);
1223 			SET_BIT(ses->telopts, TELOPT_FLAG_LF);
1224 			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1225 		}
1226 		else if (!strcasecmp(arg2, "CRLF") || !strcasecmp(arg2, "ON"))
1227 		{
1228 			SET_BIT(ses->telopts, TELOPT_FLAG_CR);
1229 			SET_BIT(ses->telopts, TELOPT_FLAG_LF);
1230 			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1231 		}
1232 		else if (!strcasecmp(arg2, "CRNUL"))
1233 		{
1234 			SET_BIT(ses->telopts, TELOPT_FLAG_CR);
1235 			DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
1236 			SET_BIT(ses->telopts, TELOPT_FLAG_NUL);
1237 		}
1238 		else if (!strcasecmp(arg2, "OFF"))
1239 		{
1240 			DEL_BIT(ses->telopts, TELOPT_FLAG_CR);
1241 			DEL_BIT(ses->telopts, TELOPT_FLAG_LF);
1242 			DEL_BIT(ses->telopts, TELOPT_FLAG_NUL);
1243 		}
1244 		else
1245 		{
1246 			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {EOL} {CR|LF|CRLF|CRNUL|OFF}.");
1247 			return;
1248 		}
1249 
1250 		show_message(gtd->ses, LIST_COMMAND, "#CURSOR FLAG EOL HAS BEEN SET TO: %s",
1251 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == 0 ? "OFF" :
1252 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_NUL) == (TELOPT_FLAG_CR|TELOPT_FLAG_NUL) ? "CRNUL" :
1253 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_CR ? "CR" :
1254 			HAS_BIT(ses->telopts, TELOPT_FLAG_CR|TELOPT_FLAG_LF) == TELOPT_FLAG_LF ? "LF" : "CRLF");
1255 
1256 		return;
1257 	}
1258 
1259 	if (is_abbrev(arg1, "ECHO"))
1260 	{
1261 		if (*arg2 == 0)
1262 		{
1263 			TOG_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1264 		}
1265 		else if (!strcasecmp(arg2, "ON"))
1266 		{
1267 			SET_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1268 		}
1269 		else if (!strcasecmp(arg2, "OFF"))
1270 		{
1271 			DEL_BIT(ses->telopts, TELOPT_FLAG_ECHO);
1272 		}
1273 		else
1274 		{
1275 			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO} {ON|OFF}.");
1276 		}
1277 		return;
1278 	}
1279 
1280 	if (is_abbrev(arg1, "INSERT") || is_abbrev(arg1, "OVERTYPE"))
1281 	{
1282 		if (*arg2 == 0)
1283 		{
1284 			TOG_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1285 		}
1286 		else if (!strcasecmp(arg2, "ON"))
1287 		{
1288 			SET_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1289 		}
1290 		else if (!strcasecmp(arg2, "OFF"))
1291 		{
1292 			DEL_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1293 		}
1294 		else
1295 		{
1296 			show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {INSERT} {ON|OFF}.");
1297 		}
1298 		return;
1299 	}
1300 
1301 	show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {FLAG} {ECHO|EOL|INSERT} {ON|OFF}.");
1302 }
1303 
DO_CURSOR(cursor_get)1304 DO_CURSOR(cursor_get)
1305 {
1306 	char arg1[BUFFER_SIZE];
1307 
1308 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
1309 
1310 	if (*arg1 == 0)
1311 	{
1312 		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR GET {variable}");
1313 	}
1314 	else
1315 	{
1316 		set_nest_node_ses(ses, arg1, "%s", gtd->ses->input->buf);
1317 	}
1318 }
1319 
DO_CURSOR(cursor_history_next)1320 DO_CURSOR(cursor_history_next)
1321 {
1322 	struct listroot *root = ses->list[LIST_HISTORY];
1323 
1324 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1325 	{
1326 		if (root->update == root->used)
1327 		{
1328 			return;
1329 		}
1330 
1331 		for (root->update++ ; root->update < root->used ; root->update++)
1332 		{
1333 			if (*gtd->ses->input->buf && find(ses, root->list[root->update]->arg1, gtd->ses->input->buf, SUB_NONE, REGEX_FLAG_NONE))
1334 			{
1335 				break;
1336 			}
1337 		}
1338 
1339 		if (root->update < root->used)
1340 		{
1341 			input_printf("\e[%dG\e[%dX ]  %.*s",
1342 				inputline_cur_off() + inputline_cur_str_len(),
1343 				inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len(),
1344 				UMAX(0, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() - 4),
1345 				root->list[root->update]->arg1);
1346 
1347 			goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
1348 		}
1349 		return;
1350 	}
1351 
1352 	if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE))
1353 	{
1354 		return;
1355 	}
1356 
1357 	if (root->update < root->used)
1358 	{
1359 		for (root->update++ ; root->update < root->used ; root->update++)
1360 		{
1361 			if (!strncmp(gtd->ses->input->tmp, root->list[root->update]->arg1, str_len(gtd->ses->input->tmp)))
1362 			{
1363 				break;
1364 			}
1365 		}
1366 	}
1367 
1368 	if (root->update >= root->used)
1369 	{
1370 		DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
1371 
1372 		if (!strcmp(gtd->ses->input->buf, gtd->ses->input->tmp))
1373 		{
1374 			return;
1375 		}
1376 		inputline_set(gtd->ses->input->tmp, -1);
1377 	}
1378 	else
1379 	{
1380 		inputline_set(root->list[root->update]->arg1, -1);
1381 		SET_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
1382 	}
1383 	cursor_end(ses, "");
1384 }
1385 
DO_CURSOR(cursor_history_prev)1386 DO_CURSOR(cursor_history_prev)
1387 {
1388 	struct listroot *root = ses->list[LIST_HISTORY];
1389 
1390 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1391 	{
1392 		if (root->update <= 0)
1393 		{
1394 			return;
1395 		}
1396 
1397 		if (root->update > root->used)
1398 		{
1399 			tintin_printf2(ses, "debug: cursor_history_prev %d > %d", root->update, root->used);
1400 			return;
1401 		}
1402 
1403 		for (root->update-- ; root->update >= 0 ; root->update--)
1404 		{
1405 			if (*gtd->ses->input->buf && find(ses, root->list[root->update]->arg1, gtd->ses->input->buf, SUB_NONE, REGEX_FLAG_NONE))
1406 			{
1407 				break;
1408 			}
1409 		}
1410 
1411 		if (root->update >= 0)
1412 		{
1413 			input_printf("\e[%dG\e[%dX ]  %.*s",
1414 				inputline_cur_off() + inputline_cur_str_len(),
1415 				inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len(),
1416 				UMAX(0, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() - 4),
1417 				root->list[root->update]->arg1);
1418 
1419 			goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
1420 		}
1421 		return;
1422 	}
1423 
1424 	if (root->update >= root->used || !HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE))
1425 	{
1426 		SET_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYBROWSE);
1427 
1428 		str_cpy(&gtd->ses->input->tmp, gtd->ses->input->buf);
1429 
1430 		root->update = root->used - 1;
1431 	}
1432 	else if (root->update >= 0)
1433 	{
1434 		root->update--;
1435 	}
1436 
1437 	while (root->update >= 0)
1438 	{
1439 		if (!strncmp(gtd->ses->input->tmp, root->list[root->update]->arg1, str_len(gtd->ses->input->tmp)))
1440 		{
1441 			break;
1442 		}
1443 		root->update--;
1444 	}
1445 
1446 	if (root->update < 0)
1447 	{
1448 		if (!strcmp(gtd->ses->input->buf, gtd->ses->input->tmp))
1449 		{
1450 			return;
1451 		}
1452 		str_cpy(&gtd->ses->input->buf, gtd->ses->input->tmp);
1453 	}
1454 	else
1455 	{
1456 		str_cpy(&gtd->ses->input->buf, root->list[root->update]->arg1);
1457 	}
1458 
1459 	gtd->ses->input->raw_len = strip_vt102_width(ses, gtd->ses->input->buf, &gtd->ses->input->str_len);
1460 
1461 	cursor_end(ses, "");
1462 }
1463 
DO_CURSOR(cursor_history_search)1464 DO_CURSOR(cursor_history_search)
1465 {
1466 	struct listroot *root = ses->list[LIST_HISTORY];
1467 
1468 	if (!HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
1469 	{
1470 		str_cpy(&gtd->ses->input->tmp, gtd->ses->input->buf);
1471 
1472 		inputline_set("", -1);
1473 
1474 		inputline_erase();
1475 
1476 		SET_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1477 
1478 		root->update = -1;
1479 
1480 		input_printf("(search) [ ] \e[3D");
1481 	}
1482 	else
1483 	{
1484 		if (root->update >= 0 && root->update < root->used)
1485 		{
1486 			inputline_set(root->list[root->update]->arg1, -1);
1487 		}
1488 		else
1489 		{
1490 			inputline_set(gtd->ses->input->tmp, -1);
1491 		}
1492 
1493 		DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1494 
1495 		cursor_redraw_line(ses, "");
1496 	}
1497 }
1498 
DO_CURSOR(cursor_history_find)1499 DO_CURSOR(cursor_history_find)
1500 {
1501 	struct listroot *root = ses->list[LIST_HISTORY];
1502 
1503 	push_call("cursor_history_find(%s)", gtd->ses->input->buf);
1504 
1505 	if (inputline_str_chk(0, gtd->ses->input->raw_len) == FALSE)
1506 	{
1507 		pop_call();
1508 		return;
1509 	}
1510 
1511 	if (*gtd->ses->input->buf == 0)
1512 	{
1513 		root->update = -1;
1514 	}
1515 	else
1516 	{
1517 		gtd->level->quiet++;
1518 
1519 		for (root->update = root->used - 1 ; root->update >= 0 ; root->update--)
1520 		{
1521 			if (find(ses, root->list[root->update]->arg1, gtd->ses->input->buf, SUB_NONE, REGEX_FLAG_NONE))
1522 			{
1523 				break;
1524 			}
1525 		}
1526 		gtd->level->quiet--;
1527 	}
1528 
1529 	if (root->update >= 0)
1530 	{
1531 		if (0 && gtd->ses->input->str_hid)
1532 		{
1533 			input_printf("\e[%dG\e[%dX ] %.*s",
1534 				inputline_cur_off() + inputline_max_str_len(),
1535 				7,
1536 				7,
1537 				root->list[root->update]->arg1);
1538 		}
1539 		else
1540 		{
1541 			input_printf("\e[%dG\e[%dX ] %.*s",
1542 				inputline_cur_off() + inputline_cur_str_len(),
1543 				inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() + 20,
1544 				UMAX(7, inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() + 7),
1545 				root->list[root->update]->arg1);
1546 		}
1547 	}
1548 	else
1549 	{
1550 		input_printf("\e[%dG\e[%dX ]",
1551 			inputline_cur_off() + inputline_cur_str_len(),
1552 			inputline_max_str_len() - inputline_cur_off() - inputline_cur_str_len() + 20);
1553 	}
1554 	goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
1555 
1556 	pop_call();
1557 	return;
1558 }
1559 
DO_CURSOR(cursor_home)1560 DO_CURSOR(cursor_home)
1561 {
1562 	if (gtd->ses->input->raw_pos == 0)
1563 	{
1564 		if (gtd->ses->input->str_pos)
1565 		{
1566 			gtd->ses->input->str_pos = 0;
1567 
1568 			return cursor_redraw_line(ses, arg);
1569 		}
1570 		return;
1571 	}
1572 
1573 	input_printf("\e[%dD", gtd->ses->input->str_pos - gtd->ses->input->str_hid);
1574 
1575 	gtd->ses->input->raw_pos = 0;
1576 	gtd->ses->input->str_pos = 0;
1577 
1578 	cursor_check_line(ses, arg);
1579 }
1580 
DO_CURSOR(cursor_insert)1581 DO_CURSOR(cursor_insert)
1582 {
1583 	char arg1[BUFFER_SIZE];
1584 
1585 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
1586 
1587 	if (*arg1 == 0)
1588 	{
1589 		TOG_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1590 	}
1591 	else if (!strcasecmp(arg1, "ON"))
1592 	{
1593 		SET_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1594 	}
1595 	else if (!strcasecmp(arg1, "OFF"))
1596 	{
1597 		DEL_BIT(gtd->flags, TINTIN_FLAG_INSERTINPUT);
1598 	}
1599 	else
1600 	{
1601 		show_error(gtd->ses, LIST_COMMAND, "#SYNTAX: #CURSOR {INSERT} {ON|OFF}.");
1602 	}
1603 }
1604 
DO_CURSOR(cursor_move_page_up)1605 DO_CURSOR(cursor_move_page_up)
1606 {
1607 	int rows = UMAX(1, inputline_rows(gtd->ses) / 2);
1608 
1609 	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1610 
1611 	cursor_move_up(ses, ntos(rows));
1612 }
1613 
DO_CURSOR(cursor_move_up)1614 DO_CURSOR(cursor_move_up)
1615 {
1616 	int str_max, moves, update;
1617 
1618 	if (inputline_editor())
1619 	{
1620 		update = gtd->ses->input->edit->update;
1621 
1622 		if (update <= 0)
1623 		{
1624 			return;
1625 		}
1626 
1627 		moves = arg ? URANGE(1, atoi(arg), update) : 1;
1628 
1629 		str_cpy(&gtd->ses->input->edit->line[update]->str, gtd->ses->input->buf);
1630 
1631 		inputline_set(gtd->ses->input->edit->line[update - moves]->str, gtd->ses->input->str_pos);
1632 
1633 		gtd->ses->input->edit->update -= moves;
1634 
1635 		gtd->ses->input->cur_row = UMAX(gtd->ses->input->top_row, gtd->ses->input->cur_row - moves);
1636 
1637 		cursor_redraw_edit(ses, arg);
1638 
1639 		return;
1640 	}
1641 
1642 	if (!inputline_multiline())
1643 	{
1644 		return cursor_history_prev(ses, "");
1645 	}
1646 
1647 	if (gtd->ses->input->str_pos == 0)
1648 	{
1649 		return cursor_history_prev(ses, "");
1650 	}
1651 
1652 	moves = arg ? UMAX(1, atoi(arg)) : 1;
1653 
1654 	str_max = inputline_max_str_len();
1655 
1656 	while (moves--)
1657 	{
1658 		gtd->ses->input->str_pos = UMAX(0, gtd->ses->input->str_pos - str_max);
1659 	}
1660 
1661 	gtd->ses->input->raw_pos = inputline_str_raw_len(0, gtd->ses->input->str_pos);
1662 
1663 	cursor_redraw_line(ses, arg);
1664 }
1665 
DO_CURSOR(cursor_move_page_down)1666 DO_CURSOR(cursor_move_page_down)
1667 {
1668 	int rows = UMAX(1, inputline_rows(gtd->ses) / 2);
1669 
1670 	DEL_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH);
1671 
1672 	cursor_move_down(ses, ntos(rows));
1673 }
1674 
DO_CURSOR(cursor_move_down)1675 DO_CURSOR(cursor_move_down)
1676 {
1677 	int str_max, moves, update;
1678 
1679 	if (inputline_editor())
1680 	{
1681 		update = gtd->ses->input->edit->update;
1682 
1683 		if (update + 1 >= gtd->ses->input->edit->used)
1684 		{
1685 			return;
1686 		}
1687 
1688 		moves = arg ? URANGE(1, atoi(arg), gtd->ses->input->edit->used - update - 1) : 1;
1689 
1690 		str_cpy(&gtd->ses->input->edit->line[update]->str, gtd->ses->input->buf);
1691 
1692 		inputline_set(gtd->ses->input->edit->line[update + moves]->str, gtd->ses->input->str_pos);
1693 
1694 		gtd->ses->input->edit->update += moves;
1695 
1696 		gtd->ses->input->cur_row = UMIN(gtd->ses->input->bot_row, gtd->ses->input->cur_row + moves);
1697 
1698 		cursor_redraw_edit(ses, arg);
1699 
1700 		return;
1701 	}
1702 
1703 	if (!inputline_multiline())
1704 	{
1705 		return cursor_history_next(ses, "");
1706 	}
1707 
1708 	if (gtd->ses->input->str_pos == gtd->ses->input->str_len)
1709 	{
1710 		return cursor_history_next(ses, "");
1711 	}
1712 
1713 	str_max = inputline_max_str_len();
1714 
1715 	moves = arg ? UMAX(1, atoi(arg)) : 1;
1716 
1717 	while (moves--)
1718 	{
1719 		gtd->ses->input->str_pos = UMIN(gtd->ses->input->str_pos + str_max, gtd->ses->input->str_len);
1720 	}
1721 	gtd->ses->input->raw_pos = inputline_str_raw_len(0, gtd->ses->input->str_pos);
1722 
1723 	cursor_redraw_line(ses, arg);
1724 }
1725 
DO_CURSOR(cursor_move_left)1726 DO_CURSOR(cursor_move_left)
1727 {
1728 	int width;
1729 
1730 	if (gtd->ses->input->raw_pos > 0)
1731 	{
1732 		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
1733 		{
1734 			gtd->ses->input->raw_pos--;
1735 			gtd->ses->input->str_pos--;
1736 			input_printf("\e[1D");
1737 
1738 			if (inputline_str_chk(0, gtd->ses->input->raw_pos) == FALSE)
1739 			{
1740 				gtd->ses->input->raw_pos--;
1741 				gtd->ses->input->str_pos--;
1742 				input_printf("\e[1D");
1743 			}
1744 		}
1745 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
1746 		{
1747 			gtd->ses->input->raw_pos--;
1748 
1749 			if (gtd->ses->input->raw_pos > 0 && is_utf8_tail(&gtd->ses->input->buf[gtd->ses->input->raw_pos]))
1750 			{
1751 				do
1752 				{
1753 					gtd->ses->input->raw_pos--;
1754 				}
1755 				while (gtd->ses->input->raw_pos > 0 && is_utf8_tail(&gtd->ses->input->buf[gtd->ses->input->raw_pos]));
1756 
1757 				get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1758 
1759 				if (width == 0)
1760 				{
1761 					return cursor_move_left(ses, "");
1762 				}
1763 				input_printf("\e[%dD", width);
1764 				gtd->ses->input->str_pos -= width;
1765 			}
1766 			else
1767 			{
1768 				get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1769 
1770 				gtd->ses->input->str_pos -= width;
1771 
1772 				input_printf("\e[%dD", width);
1773 			}
1774 		}
1775 		else
1776 		{
1777 			do
1778 			{
1779 				gtd->ses->input->raw_pos--;
1780 
1781 				get_ascii_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1782 
1783 				if (width)
1784 				{
1785 					gtd->ses->input->str_pos -= width;
1786 					input_printf("\e[%dD", width);
1787 					break;
1788 				}
1789 			}
1790 			while (gtd->ses->input->raw_pos > 0);
1791 		}
1792 
1793 		if (gtd->ses->input->raw_pos != gtd->ses->input->str_pos)
1794 		{
1795 			gtd->ses->input->raw_pos = inputline_str_raw_len(0, gtd->ses->input->str_pos);
1796 		}
1797 
1798 		cursor_check_line(ses, "");
1799 	}
1800 }
1801 
DO_CURSOR(cursor_move_left_word)1802 DO_CURSOR(cursor_move_left_word)
1803 {
1804 	int index_raw, span_raw, width;
1805 
1806 	if (gtd->ses->input->raw_pos == 0)
1807 	{
1808 		return;
1809 	}
1810 
1811 	index_raw = gtd->ses->input->raw_pos;
1812 
1813 	while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] == ' ')
1814 	{
1815 		gtd->ses->input->raw_pos--;
1816 	}
1817 
1818 	while (gtd->ses->input->raw_pos > 0 && gtd->ses->input->buf[gtd->ses->input->raw_pos - 1] != ' ')
1819 	{
1820 		gtd->ses->input->raw_pos--;
1821 	}
1822 
1823 	span_raw = gtd->ses->input->raw_pos;
1824 
1825 	while (span_raw < index_raw)
1826 	{
1827 		span_raw += get_vt102_width(gtd->ses, &gtd->ses->input->buf[span_raw], &width);
1828 
1829 		gtd->ses->input->str_pos -= width;
1830 	}
1831 
1832 	cursor_redraw_line(ses, "");
1833 }
1834 
DO_CURSOR(cursor_move_right)1835 DO_CURSOR(cursor_move_right)
1836 {
1837 	int size, width;
1838 
1839 	if (gtd->ses->input->raw_pos < gtd->ses->input->raw_len)
1840 	{
1841 		if (HAS_BIT(ses->charset, CHARSET_FLAG_EUC))
1842 		{
1843 			gtd->ses->input->raw_pos += get_euc_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1844 
1845 			input_printf("\e[%dC", width);
1846 
1847 			gtd->ses->input->str_pos += width;
1848 		}
1849 		else if (HAS_BIT(ses->charset, CHARSET_FLAG_UTF8))
1850 		{
1851 			gtd->ses->input->raw_pos += get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1852 
1853 			if (width == 0)
1854 			{
1855 				return cursor_move_right(ses, arg);
1856 			}
1857 			input_printf("\e[%dC", width);
1858 
1859 			gtd->ses->input->str_pos += width;
1860 
1861 			while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len)
1862 			{
1863 				if (!is_utf8_head(&gtd->ses->input->buf[gtd->ses->input->raw_pos]))
1864 				{
1865 					break;
1866 				}
1867 				size = get_utf8_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width, NULL);
1868 
1869 				if (width)
1870 				{
1871 					break;
1872 				}
1873 				gtd->ses->input->raw_pos += size;
1874 			}
1875 		}
1876 		else
1877 		{
1878 			gtd->ses->input->raw_pos += get_ascii_width(&gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1879 
1880 			input_printf("\e[1C");
1881 
1882 			gtd->ses->input->str_pos++;
1883 		}
1884 	}
1885 
1886 	cursor_check_line(ses, "");
1887 }
1888 
DO_CURSOR(cursor_move_right_word)1889 DO_CURSOR(cursor_move_right_word)
1890 {
1891 	int size, width;
1892 
1893 	if (gtd->ses->input->raw_pos == gtd->ses->input->raw_len)
1894 	{
1895 		return;
1896 	}
1897 
1898 	while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] == ' ')
1899 	{
1900 		gtd->ses->input->raw_pos++;
1901 		gtd->ses->input->str_pos++;
1902 	}
1903 
1904 	while (gtd->ses->input->raw_pos < gtd->ses->input->raw_len && gtd->ses->input->buf[gtd->ses->input->raw_pos] != ' ')
1905 	{
1906 		size = get_vt102_width(gtd->ses, &gtd->ses->input->buf[gtd->ses->input->raw_pos], &width);
1907 
1908 		gtd->ses->input->raw_pos += size;
1909 		gtd->ses->input->str_pos += width;
1910 	}
1911 
1912 	cursor_redraw_line(ses, "");
1913 }
1914 
DO_CURSOR(cursor_paste_buffer)1915 DO_CURSOR(cursor_paste_buffer)
1916 {
1917 	if (*gtd->ses->input->cut)
1918 	{
1919 		inputline_insert(gtd->ses->input->cut, -1);
1920 
1921 		cursor_redraw_line(ses, "");
1922 
1923 		modified_input();
1924 	}
1925 }
1926 
DO_CURSOR(cursor_position)1927 DO_CURSOR(cursor_position)
1928 {
1929 	char arg1[BUFFER_SIZE], arg2[BUFFER_SIZE];
1930 	int row, col;
1931 
1932 	arg = sub_arg_in_braces(gtd->ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
1933 	arg = sub_arg_in_braces(gtd->ses, arg, arg2, GET_ALL, SUB_VAR|SUB_FUN);
1934 
1935 	if (*arg2 == 0)
1936 	{
1937 		col = gtd->ses->input->str_hid + get_col_index_arg(gtd->ses, arg1) - 1;
1938 
1939 		inputline_position(col);
1940 
1941 		return cursor_redraw_line(ses, arg);
1942 	}
1943 
1944 	row = get_row_index_arg(gtd->ses, arg1);
1945 	col = gtd->ses->input->str_hid + get_col_index_arg(gtd->ses, arg2) - 1;
1946 
1947 	if (row >= gtd->ses->input->top_row && row <= gtd->ses->input->bot_row)
1948 	{
1949 		if (inputline_rows(gtd->ses) > 1)
1950 		{
1951 			if (inputline_editor())
1952 			{
1953 				inputline_set_row(row);
1954 				inputline_position(col);
1955 
1956 				return cursor_redraw_edit(ses, arg);
1957 			}
1958 
1959 			gtd->ses->input->cur_row = gtd->ses->input->top_row;
1960 
1961 			while (gtd->ses->input->cur_row < row)
1962 			{
1963 				gtd->ses->input->cur_row++;
1964 
1965 				col += inputline_max_str_len();
1966 			}
1967 		}
1968 	}
1969 	inputline_position(col);
1970 
1971 	return cursor_redraw_line(ses, arg);
1972 }
1973 
DO_CURSOR(cursor_macro)1974 DO_CURSOR(cursor_macro)
1975 {
1976 	char arg1[BUFFER_SIZE];
1977 
1978 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
1979 
1980 	if (is_abbrev(arg1, "PRESERVE"))
1981 	{
1982 		SET_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO);
1983 
1984 		return;
1985 	}
1986 
1987 	if (is_abbrev(arg1, "RESET"))
1988 	{
1989 		gtd->macro_buf[0] = 0;
1990 
1991 		return;
1992 	}
1993 
1994 	show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR {MACRO} {PRESERVE|RESET}");
1995 }
1996 
DO_CURSOR(cursor_preserve_macro)1997 DO_CURSOR(cursor_preserve_macro)
1998 {
1999 	SET_BIT(gtd->flags, TINTIN_FLAG_PRESERVEMACRO);
2000 }
2001 
DO_CURSOR(cursor_reset_macro)2002 DO_CURSOR(cursor_reset_macro)
2003 {
2004 	gtd->macro_buf[0] = 0;
2005 }
2006 
DO_CURSOR(cursor_redraw_input)2007 DO_CURSOR(cursor_redraw_input)
2008 {
2009 	cursor_redraw_line(ses, "");
2010 
2011 	fflush(stdout);
2012 }
2013 
DO_CURSOR(cursor_redraw_line)2014 DO_CURSOR(cursor_redraw_line)
2015 {
2016 	push_call("cursor_redraw_line(%p,%p)",ses,arg);
2017 
2018 	if (arg == NULL) // avoid unnecessary redraws
2019 	{
2020 		pop_call();
2021 		return;
2022 	}
2023 
2024 	if (inputline_str_chk(0, gtd->ses->input->raw_len) == FALSE)
2025 	{
2026 		tintin_printf2(gtd->ses, "debug: cursor_redraw_line: corrupted utf-8 detected");
2027 		pop_call();
2028 		return;
2029 	}
2030 
2031 	if (inputline_editor())
2032 	{
2033 		cursor_redraw_singleline(ses, "");
2034 
2035 		pop_call();
2036 		return;
2037 	}
2038 
2039 	if (inputline_multiline())
2040 	{
2041 		cursor_redraw_multiline(ses, "");
2042 
2043 		pop_call();
2044 		return;
2045 	}
2046 
2047 	cursor_redraw_singleline(ses, "");
2048 
2049 	pop_call();
2050 	return;
2051 }
2052 
DO_CURSOR(cursor_redraw_singleline)2053 DO_CURSOR(cursor_redraw_singleline)
2054 {
2055 	int raw_len, raw_off, str_pos, str_max, str_len;
2056 
2057 	str_max = inputline_max_str_len();
2058 
2059 	// Center long lines of input
2060 
2061 	if (gtd->ses->input->str_pos > str_max - 3)
2062 	{
2063 		if (inputline_editor())
2064 		{
2065 			return cursor_redraw_edit(ses, arg);
2066 		}
2067 
2068 		while (gtd->ses->input->str_pos - gtd->ses->input->str_hid > str_max - 3)
2069 		{
2070 			gtd->ses->input->str_hid += URANGE(1, 8, str_max);
2071 		}
2072 
2073 		while (gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2074 		{
2075 			gtd->ses->input->str_hid -= URANGE(1, str_max - 8, gtd->ses->input->str_hid);
2076 		}
2077 	}
2078 	else
2079 	{
2080 		if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2081 		{
2082 			if (inputline_editor())
2083 			{
2084 				return cursor_redraw_edit(ses, arg);
2085 			}
2086 
2087 			gtd->ses->input->str_hid = 0;
2088 		}
2089 	}
2090 
2091 	inputline_erase();
2092 
2093 	// Print the entire thing
2094 
2095 	raw_len = inputline_str_raw_len(gtd->ses->input->str_hid, gtd->ses->input->str_hid + str_max - 1);
2096 //	str_len = inputline_raw_str_len(0, -1);
2097 	str_len = gtd->ses->input->str_len;
2098 	raw_off = inputline_str_raw_len(0, gtd->ses->input->str_hid);
2099 	str_pos = inputline_cur_off() + gtd->ses->input->str_pos - gtd->ses->input->str_hid;
2100 
2101 	if (inputline_editor() || str_max <= 4)
2102 	{
2103 		input_printf("%.*s", raw_len, &gtd->ses->input->buf[raw_off]);
2104 	}
2105 	else if (gtd->ses->input->str_hid)
2106 	{
2107 		if (gtd->ses->input->str_hid + str_max >= str_len)
2108 		{
2109 			input_printf("%.*s\e[%dG<", raw_len, &gtd->ses->input->buf[raw_off], inputline_cur_off());
2110 		}
2111 		else
2112 		{
2113 			input_printf("%.*s\e[%dG<\e[%dG>", raw_len, &gtd->ses->input->buf[raw_off], inputline_cur_off(), inputline_cur_off() - 1 + str_max);
2114 		}
2115 	}
2116 	else
2117 	{
2118 		if (str_max >= inputline_raw_str_len(0, -1))
2119 		{
2120 			input_printf("%.*s",   raw_len, &gtd->ses->input->buf[raw_off]);
2121 		}
2122 		else
2123 		{
2124 			input_printf("%.*s\e[%dG>",  raw_len, &gtd->ses->input->buf[raw_off], inputline_cur_off() - 1 + str_max);
2125 		}
2126 	}
2127 
2128 	goto_pos(gtd->ses, inputline_cur_row(), str_pos);
2129 
2130 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
2131 	{
2132 		cursor_history_find(gtd->ses, "");
2133 	}
2134 }
2135 
DO_CURSOR(cursor_redraw_edit)2136 DO_CURSOR(cursor_redraw_edit)
2137 {
2138 	int row, start, end, offset, raw_off, raw_width, str_max;
2139 
2140 	push_call("cursor_redraw_edit(%p,%p)",ses,arg);
2141 
2142 	if (arg == NULL)
2143 	{
2144 		pop_call();
2145 		return;
2146 	}
2147 
2148 	str_max = inputline_max_str_len();
2149 
2150 	// Center long lines of input
2151 
2152 	// Probably needs proper tab handling
2153 
2154 	if (gtd->ses->input->str_pos > str_max - 3)
2155 	{
2156 		while (gtd->ses->input->str_pos - gtd->ses->input->str_hid > str_max - 3)
2157 		{
2158 			gtd->ses->input->str_hid += URANGE(1, 8, str_max);
2159 		}
2160 
2161 		while (gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2162 		{
2163 			gtd->ses->input->str_hid -= URANGE(1, str_max - 8, gtd->ses->input->str_hid);
2164 		}
2165 	}
2166 	else
2167 	{
2168 		if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 3)
2169 		{
2170 			gtd->ses->input->str_hid = 0;
2171 		}
2172 	}
2173 
2174 	end   = gtd->ses->input->bot_row - gtd->ses->input->cur_row;
2175 
2176 	while (end >= gtd->ses->input->edit->used - gtd->ses->input->edit->update)
2177 	{
2178 		gtd->ses->input->cur_row++;
2179 
2180 		end--;
2181 	}
2182 
2183 	offset = gtd->ses->input->cur_row - gtd->ses->input->top_row;
2184 
2185 	start = gtd->ses->input->edit->update - offset;
2186 
2187 	while (start < 0)
2188 	{
2189 		gtd->ses->input->cur_row--;
2190 
2191 		start++;
2192 	}
2193 
2194 
2195 	for (row = gtd->ses->input->top_row ; row <= gtd->ses->input->bot_row ; row++)
2196 	{
2197 		goto_pos(gtd->ses, row, gtd->ses->input->top_col);
2198 
2199 		inputline_erase();
2200 
2201 		if (start >= gtd->ses->input->edit->used)
2202 		{
2203 			continue;
2204 		}
2205 
2206 
2207 		if (row == gtd->ses->input->cur_row)
2208 		{
2209 			raw_off = get_raw_off_str_range_raw_width(gtd->ses, gtd->ses->input->buf, gtd->ses->input->str_hid, gtd->ses->input->str_hid + str_max - 1, &raw_width);
2210 
2211 			input_printf("%.*s", raw_width, &gtd->ses->input->buf[raw_off]);
2212 		}
2213 		else
2214 		{
2215 			raw_off = get_raw_off_str_range_raw_width(gtd->ses, gtd->ses->input->edit->line[start]->str, gtd->ses->input->str_hid, gtd->ses->input->str_hid + str_max - 1, &raw_width);
2216 
2217 			input_printf("%.*s", raw_width, &gtd->ses->input->edit->line[start]->str[raw_off]);
2218 		}
2219 		start++;
2220 	}
2221 /*
2222 	goto_pos(gtd->ses, 1, 1);
2223 
2224 	printf("\e[1;31mcur_row %2d, cur_off %2d, str_hid %3d, str_pos %3d, str_max %3d, str_len %3d\e[0m",
2225 		gtd->ses->input->cur_row,
2226 		inputline_cur_off(),
2227 		gtd->ses->input->str_hid,
2228 		gtd->ses->input->str_pos,
2229 		str_max,
2230 		gtd->ses->input->str_len);
2231 */
2232 	goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_col());
2233 
2234 	pop_call();
2235 	return;
2236 }
2237 
DO_CURSOR(cursor_redraw_multiline)2238 DO_CURSOR(cursor_redraw_multiline)
2239 {
2240 	int row, rows, str_max, hid, str_off, raw_off, raw_len;
2241 
2242 	str_max  = inputline_max_str_len();
2243 	rows     = inputline_rows(gtd->ses);
2244 
2245 	if (gtd->ses->input->str_pos - gtd->ses->input->str_hid > rows * str_max - 1)
2246 	{
2247 		while (gtd->ses->input->str_pos - gtd->ses->input->str_hid > rows * str_max - 1)
2248 		{
2249 			gtd->ses->input->str_hid += rows * str_max;
2250 		}
2251 	}
2252 	else if (gtd->ses->input->str_hid && gtd->ses->input->str_pos - gtd->ses->input->str_hid < 0)
2253 	{
2254 		while (gtd->ses->input->str_pos - gtd->ses->input->str_hid < 0)
2255 		{
2256 			gtd->ses->input->str_hid -= URANGE(1, rows * str_max, gtd->ses->input->str_hid);
2257 		}
2258 	}
2259 
2260 	hid = gtd->ses->input->str_hid;
2261 
2262 	if (hid)
2263 	{
2264 		str_off = gtd->ses->input->str_hid;
2265 		raw_off = inputline_str_raw_len(0, str_off);
2266 	}
2267 	else
2268 	{
2269 		str_off = 0;
2270 		raw_off = 0;
2271 	}
2272 
2273 	for (row = gtd->ses->input->top_row ; row <= gtd->ses->input->bot_row ; row++)
2274 	{
2275 		goto_pos(gtd->ses, row, gtd->ses->input->top_col);
2276 
2277 		inputline_erase();
2278 
2279 		if (gtd->ses->input->str_len < str_off)
2280 		{
2281 			raw_len = 0;
2282 		}
2283 		else
2284 		{
2285 			raw_len = inputline_str_raw_len(str_off, str_off + str_max);
2286 
2287 			input_printf("%.*s", raw_len, &gtd->ses->input->buf[raw_off]);
2288 		}
2289 		str_off += str_max;
2290 		raw_off += raw_len;
2291 	}
2292 
2293 	gtd->ses->input->cur_row = gtd->ses->input->top_row + (gtd->ses->input->str_pos - gtd->ses->input->str_hid) / str_max;
2294 
2295 /*
2296 	goto_pos(gtd->ses, 1, 1);
2297 
2298 	printf("\e[1;31mcur_row %2d, top_row %2d, str_pos %3d, str_hid %3d, str_max %3d, str_len %3d\e[0m",  gtd->ses->input->cur_row, gtd->ses->input->top_row, gtd->ses->input->str_pos, gtd->ses->input->str_hid, str_max, gtd->ses->input->str_len);
2299 */
2300 	goto_pos(gtd->ses, inputline_cur_row(), inputline_cur_off() + gtd->ses->input->str_pos % str_max);
2301 
2302 	if (HAS_BIT(gtd->ses->input->flags, INPUT_FLAG_HISTORYSEARCH))
2303 	{
2304 		cursor_history_find(gtd->ses, "");
2305 	}
2306 }
2307 
2308 
2309 // like set, but sub escapes, unused
2310 
DO_CURSOR(cursor_insert_line)2311 DO_CURSOR(cursor_insert_line)
2312 {
2313 	char arg1[BUFFER_SIZE];
2314 
2315 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN|SUB_ESC);
2316 
2317 	if (*arg1 == 0)
2318 	{
2319 		return;
2320 	}
2321 
2322 	inputline_insert(arg1, -1);
2323 
2324 	cursor_redraw_line(ses, "");
2325 
2326 	modified_input();
2327 }
2328 
DO_CURSOR(cursor_set)2329 DO_CURSOR(cursor_set)
2330 {
2331 	char arg1[BUFFER_SIZE];
2332 
2333 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ALL, SUB_VAR|SUB_FUN);
2334 
2335 	if (*arg1 == 0)
2336 	{
2337 		return;
2338 	}
2339 
2340 	inputline_insert(arg1, -1);
2341 
2342 	cursor_redraw_line(ses, "");
2343 
2344 	modified_input();
2345 }
2346 
DO_CURSOR(cursor_suspend)2347 DO_CURSOR(cursor_suspend)
2348 {
2349 	if (!HAS_BIT(gtd->flags, TINTIN_FLAG_CHILDLOCK))
2350 	{
2351 		do_suspend(ses, arg, NULL, NULL, NULL, NULL);
2352 	}
2353 }
2354 
DO_CURSOR(cursor_info)2355 DO_CURSOR(cursor_info)
2356 {
2357 	tintin_printf2(ses, "inputline_max_str_len():        %10d", inputline_max_str_len());
2358 	tintin_printf2(ses, "inputline_cur_off():            %10d", inputline_cur_off());
2359 	tintin_printf2(ses, "inputline_cur_str_len():        %10d", inputline_cur_str_len());
2360 	tintin_printf2(ses, "inputline_rows():               %10d", inputline_rows(gtd->ses));
2361 
2362 	tintin_printf2(ses, "");
2363 
2364 	tintin_printf2(ses, "inputline_max_row():            %10d", inputline_max_row());
2365 	tintin_printf2(ses, "inputline_cur_row():            %10d", inputline_cur_row());
2366 	tintin_printf2(ses, "inputline_cur_col():            %10d", inputline_cur_col());
2367 	tintin_printf2(ses, "inputline_cur_hid():            %10d", gtd->ses->input->str_hid);
2368 
2369 	tintin_printf2(ses, "");
2370 
2371 	tintin_printf2(ses, "input->raw_len:                 %10d", gtd->ses->input->raw_len);
2372 	tintin_printf2(ses, "input->str_len:                 %10d", gtd->ses->input->str_len);
2373 	tintin_printf2(ses, "input->raw_pos:                 %10d", gtd->ses->input->raw_pos);
2374 	tintin_printf2(ses, "input->str_pos:                 %10d", gtd->ses->input->str_pos);
2375 
2376 	tintin_printf2(ses, "");
2377 
2378 	tintin_printf2(ses, "input->line_name:               %s", gtd->ses->input->line_name);
2379 	tintin_printf2(ses, "");
2380 
2381 	tintin_printf2(ses, "input->sav_top_row:             %10d", gtd->ses->input->sav_top_row);
2382 	tintin_printf2(ses, "input->sav_top_col:             %10d", gtd->ses->input->sav_top_col);
2383 	tintin_printf2(ses, "input->sav_bot_row:             %10d", gtd->ses->input->sav_bot_row);
2384 	tintin_printf2(ses, "input->sav_bot_col:             %10d", gtd->ses->input->sav_bot_col);
2385 
2386 	tintin_printf2(ses, "");
2387 
2388 	tintin_printf2(ses, "input->top_row:                 %10d", gtd->ses->input->top_row);
2389 	tintin_printf2(ses, "input->top_col:                 %10d", gtd->ses->input->top_col);
2390 	tintin_printf2(ses, "input->bot_row:                 %10d", gtd->ses->input->bot_row);
2391 	tintin_printf2(ses, "input->bot_col:                 %10d", gtd->ses->input->bot_col);
2392 }
2393 
2394 /*
2395 	original tab cycling by Ben Love
2396 */
2397 
cursor_tab_add(int flag)2398 int cursor_tab_add(int flag)
2399 {
2400 	struct listroot *tab_root = gtd->ses->list[LIST_TAB];
2401 	struct listroot *cmd_root = gtd->ses->list[LIST_COMMAND];
2402 	struct listnode *node;
2403 	char *tail;
2404 	int tail_len;
2405 
2406 	if (!HAS_BIT(tab_root->flags, LIST_FLAG_IGNORE))
2407 	{
2408 		tail     = cmd_root->list[0]->arg1;
2409 		tail_len = str_len(tail);
2410 
2411 		for (tab_root->update = 0 ; tab_root->update < tab_root->used ; tab_root->update++)
2412 		{
2413 			node = tab_root->list[tab_root->update];
2414 
2415 			if (HAS_BIT(flag, TAB_FLAG_CASELESS))
2416 			{
2417 				if (strncasecmp(node->arg1, tail, tail_len) != 0)
2418 				{
2419 					continue;
2420 				}
2421 			}
2422 			else
2423 			{
2424 				if (*node->arg1 != *tail || strncmp(node->arg1, tail, tail_len) != 0)
2425 				{
2426 					continue;
2427 				}
2428 			}
2429 
2430 			if (search_node_list(cmd_root, node->arg1))
2431 			{
2432 				continue;
2433 			}
2434 			create_node_list(cmd_root, node->arg1, "", "", "");
2435 
2436 			if (node->shots && --node->shots == 0)
2437 			{
2438 				delete_node_list(gtd->ses, LIST_TAB, node);
2439 			}
2440 
2441 			if (HAS_BIT(flag, TAB_FLAG_FORWARD))
2442 			{
2443 				return TRUE;
2444 			}
2445 		}
2446 	}
2447 	return FALSE;
2448 }
2449 
cursor_scrollback_tab_add(int flag)2450 int cursor_scrollback_tab_add(int flag)
2451 {
2452 	char tab[BUFFER_SIZE], buf[BUFFER_SIZE];
2453 	struct listroot *root = gtd->ses->list[LIST_COMMAND];
2454 	struct listnode *node;
2455 	int scroll_cnt, tab_len, tail_len;
2456 	char *ptb, *ptt, *tail;
2457 
2458 	tail     = root->list[0]->arg1;
2459 	tail_len = str_len(tail);
2460 
2461 	if (root->list[root->used - 1]->val32[0])
2462 	{
2463 		scroll_cnt = UMIN(root->list[root->used - 1]->val32[0], gtd->ses->scroll->used - 1);
2464 	}
2465 	else
2466 	{
2467 		scroll_cnt = gtd->ses->scroll->used - 1;
2468 	}
2469 
2470 	for ( ; scroll_cnt > 0 ; scroll_cnt--)
2471 	{
2472 		if (HAS_BIT(gtd->ses->scroll->buffer[scroll_cnt]->flags, BUFFER_FLAG_GREP))
2473 		{
2474 			continue;
2475 		}
2476 
2477 		strip_vt102_codes(gtd->ses->scroll->buffer[scroll_cnt]->str, buf);
2478 
2479 		ptb = buf;
2480 
2481 		while (*ptb)
2482 		{
2483 			while (*ptb && is_space(*ptb))
2484 			{
2485 				ptb++;
2486 			}
2487 
2488 			if (HAS_BIT(flag, TAB_FLAG_CASELESS))
2489 			{
2490 				if (strncasecmp(ptb, tail, tail_len) != 0)
2491 				{
2492 					goto end;
2493 				}
2494 			}
2495 			else
2496 			{
2497 				if (*ptb != *tail || strncmp(ptb, tail, tail_len) != 0)
2498 				{
2499 					goto end;
2500 				}
2501 			}
2502 			ptt = tab;
2503 
2504 			for (tab_len = 0 ; tab_len < tail_len ; tab_len++)
2505 			{
2506 				*ptt++ = *ptb++;
2507 			}
2508 
2509 			while (*ptb && *ptb != ' ')
2510 			{
2511 				switch (*ptb)
2512 				{
2513 					case ';':
2514 					case '.':
2515 					case ',':
2516 					case '!':
2517 					case '?':
2518 					case ':':
2519 					case '"':
2520 						*ptt++ = 0;
2521 						ptb++;
2522 						break;
2523 
2524 					default:
2525 						*ptt++ = *ptb++;
2526 						break;
2527 				}
2528 			}
2529 			*ptt = 0;
2530 
2531 			if (search_node_list(gtd->ses->list[LIST_COMMAND], tab))
2532 			{
2533 				goto end;
2534 			}
2535 
2536 			node = create_node_list(gtd->ses->list[LIST_COMMAND], tab, "", "", "");
2537 
2538 			node->val32[0] = scroll_cnt;
2539 
2540 			if (HAS_BIT(flag, TAB_FLAG_FORWARD))
2541 			{
2542 				return TRUE;
2543 			}
2544 
2545 			if (root->used > 100)
2546 			{
2547 				return FALSE;
2548 			}
2549 
2550 			end:
2551 
2552 			while (*ptb && !is_space(*ptb))
2553 			{
2554 				ptb++;
2555 			}
2556 		}
2557 	}
2558 	return FALSE;
2559 }
2560 
cursor_tab_forward(struct session * ses,int flag)2561 void cursor_tab_forward(struct session *ses, int flag)
2562 {
2563 	struct listroot *root = gtd->ses->list[LIST_COMMAND];
2564 	int tab_found;
2565 
2566 	if (inputline_tab_valid() == FALSE)
2567 	{
2568 		return;
2569 	}
2570 
2571 	cursor_move_left_word(gtd->ses, "");
2572 
2573 	if (root->used == 0)
2574 	{
2575 		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->raw_pos], "", "", "");
2576 	}
2577 
2578 	inputline_cap("");
2579 
2580 	tab_found = 0;
2581 
2582 	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_LIST))
2583 	{
2584 		tab_found = cursor_tab_add(flag);
2585 	}
2586 
2587 	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_SCROLLBACK))
2588 	{
2589 		tab_found = cursor_scrollback_tab_add(flag);
2590 	}
2591 
2592 	if (tab_found == 0 && HAS_BIT(flag, TAB_FLAG_DICTIONARY))
2593 	{
2594 		tab_found = cursor_dictionary_tab_add(flag);
2595 	}
2596 
2597 	if (tab_found == 0)
2598 	{
2599 		inputline_insert(root->list[0]->arg1, -1);
2600 
2601 		kill_list(root);
2602 	}
2603 	else
2604 	{
2605 		inputline_insert(root->list[root->used - 1]->arg1, -1);
2606 	}
2607 	cursor_end(ses, "");
2608 }
2609 
cursor_tab_backward(struct session * ses,int flag)2610 void cursor_tab_backward(struct session *ses, int flag)
2611 {
2612 	struct listroot *root = ses->list[LIST_COMMAND];
2613 
2614 	if (inputline_tab_valid() == FALSE)
2615 	{
2616 		return;
2617 	}
2618 
2619 	if (root->used)
2620 	{
2621 		delete_index_list(root, root->used - 1);
2622 	}
2623 
2624 	cursor_move_left_word(gtd->ses, "");
2625 
2626 	if (root->used == 0)
2627 	{
2628 		create_node_list(root, &gtd->ses->input->buf[gtd->ses->input->raw_pos], "", "", "");
2629 
2630 		inputline_cap("");
2631 
2632 		if (HAS_BIT(flag, TAB_FLAG_LIST))
2633 		{
2634 			cursor_tab_add(flag);
2635 		}
2636 
2637 		if (HAS_BIT(flag, TAB_FLAG_SCROLLBACK))
2638 		{
2639 			cursor_scrollback_tab_add(flag);
2640 		}
2641 
2642 		if (HAS_BIT(flag, TAB_FLAG_DICTIONARY))
2643 		{
2644 			cursor_dictionary_tab_add(flag);
2645 		}
2646 	}
2647 	else
2648 	{
2649 		inputline_cap("");
2650 	}
2651 
2652 	inputline_insert(root->list[root->used - 1]->arg1, -1);
2653 
2654 	cursor_end(ses, "");
2655 }
2656 
DO_CURSOR(cursor_tab)2657 DO_CURSOR(cursor_tab)
2658 {
2659 	char arg1[BUFFER_SIZE];
2660 	int flag = 0;
2661 
2662 	arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
2663 
2664 	while (*arg)
2665 	{
2666 		if (is_abbrev(arg1, "CASELESS"))
2667 		{
2668 			SET_BIT(flag, TAB_FLAG_CASELESS);
2669 		}
2670 		else if (is_abbrev(arg1, "COMPLETE"))
2671 		{
2672 			SET_BIT(flag, TAB_FLAG_COMPLETE);
2673 		}
2674 		else if (is_abbrev(arg1, "DICTIONARY"))
2675 		{
2676 			SET_BIT(flag, TAB_FLAG_DICTIONARY);
2677 		}
2678 		else if (is_abbrev(arg1, "LIST"))
2679 		{
2680 			SET_BIT(flag, TAB_FLAG_LIST);
2681 		}
2682 		else if (is_abbrev(arg1, "SCROLLBACK"))
2683 		{
2684 			SET_BIT(flag, TAB_FLAG_SCROLLBACK);
2685 		}
2686 
2687 		arg = sub_arg_in_braces(ses, arg, arg1, GET_ONE, SUB_VAR|SUB_FUN);
2688 
2689 		if (*arg == COMMAND_SEPARATOR)
2690 		{
2691 			arg++;
2692 		}
2693 	}
2694 
2695 	if (is_abbrev(arg1, "FORWARD"))
2696 	{
2697 		SET_BIT(flag, TAB_FLAG_FORWARD);
2698 
2699 		if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
2700 		{
2701 			sprintf(arg1, "%*s", gtd->ses->tab_width, "");
2702 
2703 			inputline_insert(arg1, -1);
2704 
2705 			return cursor_redraw_line(ses, arg);
2706 		}
2707 
2708 		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
2709 		{
2710 			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY|LIST|SCROLLBACK} FORWARD");
2711 		}
2712 		else
2713 		{
2714 			cursor_tab_forward(ses, flag);
2715 		}
2716 	}
2717 	else if (is_abbrev(arg1, "BACKWARD"))
2718 	{
2719 		SET_BIT(flag, TAB_FLAG_BACKWARD);
2720 
2721 		if (!HAS_BIT(flag, TAB_FLAG_COMPLETE) && inputline_editor())
2722 		{
2723 			sprintf(arg1, "%*s", gtd->ses->tab_width, "");
2724 
2725 			inputline_insert(arg1, 0);
2726 
2727 			return cursor_redraw_line(ses, arg);
2728 		}
2729 
2730 		if (!HAS_BIT(flag, TAB_FLAG_DICTIONARY|TAB_FLAG_LIST|TAB_FLAG_SCROLLBACK))
2731 		{
2732 			show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY|LIST|SCROLLBACK} BACKWARD");
2733 		}
2734 		else
2735 		{
2736 			cursor_tab_backward(ses, flag);
2737 		}
2738 	}
2739 	else
2740 	{
2741 		show_error(ses, LIST_COMMAND, "#SYNTAX: #CURSOR TAB {DICTIONARY;LIST;SCROLLBACK} <BACKWARD|FORWARD>");
2742 	}
2743 }
2744