xref: /freebsd/contrib/less/cmdbuf.c (revision 2546665afcaf0d53dc2c7058fee96354b3680f5a)
1 /*
2  * Copyright (C) 1984-2002  Mark Nudelman
3  *
4  * You may distribute under the terms of either the GNU General Public
5  * License or the Less License, as specified in the README file.
6  *
7  * For more information about less, or for information on how to
8  * contact the author, see the README file.
9  */
10 
11 
12 /*
13  * Functions which manipulate the command buffer.
14  * Used only by command() and related functions.
15  */
16 
17 #include "less.h"
18 #include "cmd.h"
19 
20 extern int sc_width;
21 
22 static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */
23 static int cmd_col;		/* Current column of the cursor */
24 static int prompt_col;		/* Column of cursor just after prompt */
25 static char *cp;		/* Pointer into cmdbuf */
26 static int cmd_offset;		/* Index into cmdbuf of first displayed char */
27 static int literal;		/* Next input char should not be interpreted */
28 
29 #if TAB_COMPLETE_FILENAME
30 static int cmd_complete();
31 /*
32  * These variables are statics used by cmd_complete.
33  */
34 static int in_completion = 0;
35 static char *tk_text;
36 static char *tk_original;
37 static char *tk_ipoint;
38 static char *tk_trial;
39 static struct textlist tk_tlist;
40 #endif
41 
42 static int cmd_left();
43 static int cmd_right();
44 
45 #if SPACES_IN_FILENAMES
46 public char openquote = '"';
47 public char closequote = '"';
48 #endif
49 
50 #if CMD_HISTORY
51 /*
52  * A mlist structure represents a command history.
53  */
54 struct mlist
55 {
56 	struct mlist *next;
57 	struct mlist *prev;
58 	struct mlist *curr_mp;
59 	char *string;
60 };
61 
62 /*
63  * These are the various command histories that exist.
64  */
65 struct mlist mlist_search =
66 	{ &mlist_search,  &mlist_search,  &mlist_search,  NULL };
67 public void * constant ml_search = (void *) &mlist_search;
68 
69 struct mlist mlist_examine =
70 	{ &mlist_examine, &mlist_examine, &mlist_examine, NULL };
71 public void * constant ml_examine = (void *) &mlist_examine;
72 
73 #if SHELL_ESCAPE || PIPEC
74 struct mlist mlist_shell =
75 	{ &mlist_shell,   &mlist_shell,   &mlist_shell,   NULL };
76 public void * constant ml_shell = (void *) &mlist_shell;
77 #endif
78 
79 #else /* CMD_HISTORY */
80 
81 /* If CMD_HISTORY is off, these are just flags. */
82 public void * constant ml_search = (void *)1;
83 public void * constant ml_examine = (void *)2;
84 #if SHELL_ESCAPE || PIPEC
85 public void * constant ml_shell = (void *)3;
86 #endif
87 
88 #endif /* CMD_HISTORY */
89 
90 /*
91  * History for the current command.
92  */
93 static struct mlist *curr_mlist = NULL;
94 static int curr_cmdflags;
95 
96 
97 /*
98  * Reset command buffer (to empty).
99  */
100 	public void
101 cmd_reset()
102 {
103 	cp = cmdbuf;
104 	*cp = '\0';
105 	cmd_col = 0;
106 	cmd_offset = 0;
107 	literal = 0;
108 }
109 
110 /*
111  * Clear command line on display.
112  */
113 	public void
114 clear_cmd()
115 {
116 	clear_bot();
117 	cmd_col = prompt_col = 0;
118 }
119 
120 /*
121  * Display a string, usually as a prompt for input into the command buffer.
122  */
123 	public void
124 cmd_putstr(s)
125 	char *s;
126 {
127 	putstr(s);
128 	cmd_col += strlen(s);
129 	prompt_col += strlen(s);
130 }
131 
132 /*
133  * How many characters are in the command buffer?
134  */
135 	public int
136 len_cmdbuf()
137 {
138 	return (strlen(cmdbuf));
139 }
140 
141 /*
142  * Repaint the line from cp onwards.
143  * Then position the cursor just after the char old_cp (a pointer into cmdbuf).
144  */
145 	static void
146 cmd_repaint(old_cp)
147 	char *old_cp;
148 {
149 	char *p;
150 
151 	/*
152 	 * Repaint the line from the current position.
153 	 */
154 	clear_eol();
155 	for ( ;  *cp != '\0';  cp++)
156 	{
157 		p = prchar(*cp);
158 		if (cmd_col + (int)strlen(p) >= sc_width)
159 			break;
160 		putstr(p);
161 		cmd_col += strlen(p);
162 	}
163 
164 	/*
165 	 * Back up the cursor to the correct position.
166 	 */
167 	while (cp > old_cp)
168 		cmd_left();
169 }
170 
171 /*
172  * Put the cursor at "home" (just after the prompt),
173  * and set cp to the corresponding char in cmdbuf.
174  */
175 	static void
176 cmd_home()
177 {
178 	while (cmd_col > prompt_col)
179 	{
180 		putbs();
181 		cmd_col--;
182 	}
183 
184 	cp = &cmdbuf[cmd_offset];
185 }
186 
187 /*
188  * Shift the cmdbuf display left a half-screen.
189  */
190 	static void
191 cmd_lshift()
192 {
193 	char *s;
194 	char *save_cp;
195 	int cols;
196 
197 	/*
198 	 * Start at the first displayed char, count how far to the
199 	 * right we'd have to move to reach the center of the screen.
200 	 */
201 	s = cmdbuf + cmd_offset;
202 	cols = 0;
203 	while (cols < (sc_width - prompt_col) / 2 && *s != '\0')
204 		cols += strlen(prchar(*s++));
205 
206 	cmd_offset = s - cmdbuf;
207 	save_cp = cp;
208 	cmd_home();
209 	cmd_repaint(save_cp);
210 }
211 
212 /*
213  * Shift the cmdbuf display right a half-screen.
214  */
215 	static void
216 cmd_rshift()
217 {
218 	char *s;
219 	char *p;
220 	char *save_cp;
221 	int cols;
222 
223 	/*
224 	 * Start at the first displayed char, count how far to the
225 	 * left we'd have to move to traverse a half-screen width
226 	 * of displayed characters.
227 	 */
228 	s = cmdbuf + cmd_offset;
229 	cols = 0;
230 	while (cols < (sc_width - prompt_col) / 2 && s > cmdbuf)
231 	{
232 		p = prchar(*--s);
233 		cols += strlen(p);
234 	}
235 
236 	cmd_offset = s - cmdbuf;
237 	save_cp = cp;
238 	cmd_home();
239 	cmd_repaint(save_cp);
240 }
241 
242 /*
243  * Move cursor right one character.
244  */
245 	static int
246 cmd_right()
247 {
248 	char *p;
249 
250 	if (*cp == '\0')
251 	{
252 		/*
253 		 * Already at the end of the line.
254 		 */
255 		return (CC_OK);
256 	}
257 	p = prchar(*cp);
258 	if (cmd_col + (int)strlen(p) >= sc_width)
259 		cmd_lshift();
260 	else if (cmd_col + (int)strlen(p) == sc_width - 1 && cp[1] != '\0')
261 		cmd_lshift();
262 	cp++;
263 	putstr(p);
264 	cmd_col += strlen(p);
265 	return (CC_OK);
266 }
267 
268 /*
269  * Move cursor left one character.
270  */
271 	static int
272 cmd_left()
273 {
274 	char *p;
275 
276 	if (cp <= cmdbuf)
277 	{
278 		/* Already at the beginning of the line */
279 		return (CC_OK);
280 	}
281 	p = prchar(cp[-1]);
282 	if (cmd_col < prompt_col + (int)strlen(p))
283 		cmd_rshift();
284 	cp--;
285 	cmd_col -= strlen(p);
286 	while (*p++ != '\0')
287 		putbs();
288 	return (CC_OK);
289 }
290 
291 /*
292  * Insert a char into the command buffer, at the current position.
293  */
294 	static int
295 cmd_ichar(c)
296 	int c;
297 {
298 	char *s;
299 
300 	if (strlen(cmdbuf) >= sizeof(cmdbuf)-2)
301 	{
302 		/*
303 		 * No room in the command buffer for another char.
304 		 */
305 		bell();
306 		return (CC_ERROR);
307 	}
308 
309 	/*
310 	 * Insert the character into the buffer.
311 	 */
312 	for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
313 		s[1] = s[0];
314 	*cp = c;
315 	/*
316 	 * Reprint the tail of the line from the inserted char.
317 	 */
318 	cmd_repaint(cp);
319 	cmd_right();
320 	return (CC_OK);
321 }
322 
323 /*
324  * Backspace in the command buffer.
325  * Delete the char to the left of the cursor.
326  */
327 	static int
328 cmd_erase()
329 {
330 	register char *s;
331 
332 	if (cp == cmdbuf)
333 	{
334 		/*
335 		 * Backspace past beginning of the buffer:
336 		 * this usually means abort the command.
337 		 */
338 		return (CC_QUIT);
339 	}
340 	/*
341 	 * Move cursor left (to the char being erased).
342 	 */
343 	cmd_left();
344 	/*
345 	 * Remove the char from the buffer (shift the buffer left).
346 	 */
347 	for (s = cp;  *s != '\0';  s++)
348 		s[0] = s[1];
349 	/*
350 	 * Repaint the buffer after the erased char.
351 	 */
352 	cmd_repaint(cp);
353 
354 	/*
355 	 * We say that erasing the entire command string causes us
356 	 * to abort the current command, if CF_QUIT_ON_ERASE is set.
357 	 */
358 	if ((curr_cmdflags & CF_QUIT_ON_ERASE) && cp == cmdbuf && *cp == '\0')
359 		return (CC_QUIT);
360 	return (CC_OK);
361 }
362 
363 /*
364  * Delete the char under the cursor.
365  */
366 	static int
367 cmd_delete()
368 {
369 	if (*cp == '\0')
370 	{
371 		/*
372 		 * At end of string; there is no char under the cursor.
373 		 */
374 		return (CC_OK);
375 	}
376 	/*
377 	 * Move right, then use cmd_erase.
378 	 */
379 	cmd_right();
380 	cmd_erase();
381 	return (CC_OK);
382 }
383 
384 /*
385  * Delete the "word" to the left of the cursor.
386  */
387 	static int
388 cmd_werase()
389 {
390 	if (cp > cmdbuf && cp[-1] == ' ')
391 	{
392 		/*
393 		 * If the char left of cursor is a space,
394 		 * erase all the spaces left of cursor (to the first non-space).
395 		 */
396 		while (cp > cmdbuf && cp[-1] == ' ')
397 			(void) cmd_erase();
398 	} else
399 	{
400 		/*
401 		 * If the char left of cursor is not a space,
402 		 * erase all the nonspaces left of cursor (the whole "word").
403 		 */
404 		while (cp > cmdbuf && cp[-1] != ' ')
405 			(void) cmd_erase();
406 	}
407 	return (CC_OK);
408 }
409 
410 /*
411  * Delete the "word" under the cursor.
412  */
413 	static int
414 cmd_wdelete()
415 {
416 	if (*cp == ' ')
417 	{
418 		/*
419 		 * If the char under the cursor is a space,
420 		 * delete it and all the spaces right of cursor.
421 		 */
422 		while (*cp == ' ')
423 			(void) cmd_delete();
424 	} else
425 	{
426 		/*
427 		 * If the char under the cursor is not a space,
428 		 * delete it and all nonspaces right of cursor (the whole word).
429 		 */
430 		while (*cp != ' ' && *cp != '\0')
431 			(void) cmd_delete();
432 	}
433 	return (CC_OK);
434 }
435 
436 /*
437  * Delete all chars in the command buffer.
438  */
439 	static int
440 cmd_kill()
441 {
442 	if (cmdbuf[0] == '\0')
443 	{
444 		/*
445 		 * Buffer is already empty; abort the current command.
446 		 */
447 		return (CC_QUIT);
448 	}
449 	cmd_offset = 0;
450 	cmd_home();
451 	*cp = '\0';
452 	cmd_repaint(cp);
453 
454 	/*
455 	 * We say that erasing the entire command string causes us
456 	 * to abort the current command, if CF_QUIT_ON_ERASE is set.
457 	 */
458 	if (curr_cmdflags & CF_QUIT_ON_ERASE)
459 		return (CC_QUIT);
460 	return (CC_OK);
461 }
462 
463 /*
464  * Select an mlist structure to be the current command history.
465  */
466 	public void
467 set_mlist(mlist, cmdflags)
468 	void *mlist;
469 	int cmdflags;
470 {
471 	curr_mlist = (struct mlist *) mlist;
472 	curr_cmdflags = cmdflags;
473 }
474 
475 #if CMD_HISTORY
476 /*
477  * Move up or down in the currently selected command history list.
478  */
479 	static int
480 cmd_updown(action)
481 	int action;
482 {
483 	char *s;
484 
485 	if (curr_mlist == NULL)
486 	{
487 		/*
488 		 * The current command has no history list.
489 		 */
490 		bell();
491 		return (CC_OK);
492 	}
493 	cmd_home();
494 	clear_eol();
495 	/*
496 	 * Move curr_mp to the next/prev entry.
497 	 */
498 	if (action == EC_UP)
499 		curr_mlist->curr_mp = curr_mlist->curr_mp->prev;
500 	else
501 		curr_mlist->curr_mp = curr_mlist->curr_mp->next;
502 	/*
503 	 * Copy the entry into cmdbuf and echo it on the screen.
504 	 */
505 	s = curr_mlist->curr_mp->string;
506 	if (s == NULL)
507 		s = "";
508 	for (cp = cmdbuf;  *s != '\0';  s++)
509 	{
510 		*cp = *s;
511 		cmd_right();
512 	}
513 	*cp = '\0';
514 	return (CC_OK);
515 }
516 #endif
517 
518 /*
519  * Add a string to a history list.
520  */
521 	public void
522 cmd_addhist(mlist, cmd)
523 	struct mlist *mlist;
524 	char *cmd;
525 {
526 #if CMD_HISTORY
527 	struct mlist *ml;
528 
529 	/*
530 	 * Don't save a trivial command.
531 	 */
532 	if (strlen(cmd) == 0)
533 		return;
534 	/*
535 	 * Don't save if a duplicate of a command which is already
536 	 * in the history.
537 	 * But select the one already in the history to be current.
538 	 */
539 	for (ml = mlist->next;  ml != mlist;  ml = ml->next)
540 	{
541 		if (strcmp(ml->string, cmd) == 0)
542 			break;
543 	}
544 	if (ml == mlist)
545 	{
546 		/*
547 		 * Did not find command in history.
548 		 * Save the command and put it at the end of the history list.
549 		 */
550 		ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
551 		ml->string = save(cmd);
552 		ml->next = mlist;
553 		ml->prev = mlist->prev;
554 		mlist->prev->next = ml;
555 		mlist->prev = ml;
556 	}
557 	/*
558 	 * Point to the cmd just after the just-accepted command.
559 	 * Thus, an UPARROW will always retrieve the previous command.
560 	 */
561 	mlist->curr_mp = ml->next;
562 #endif
563 }
564 
565 /*
566  * Accept the command in the command buffer.
567  * Add it to the currently selected history list.
568  */
569 	public void
570 cmd_accept()
571 {
572 #if CMD_HISTORY
573 	/*
574 	 * Nothing to do if there is no currently selected history list.
575 	 */
576 	if (curr_mlist == NULL)
577 		return;
578 	cmd_addhist(curr_mlist, cmdbuf);
579 #endif
580 }
581 
582 /*
583  * Try to perform a line-edit function on the command buffer,
584  * using a specified char as a line-editing command.
585  * Returns:
586  *	CC_PASS	The char does not invoke a line edit function.
587  *	CC_OK	Line edit function done.
588  *	CC_QUIT	The char requests the current command to be aborted.
589  */
590 	static int
591 cmd_edit(c)
592 	int c;
593 {
594 	int action;
595 	int flags;
596 
597 #if TAB_COMPLETE_FILENAME
598 #define	not_in_completion()	in_completion = 0
599 #else
600 #define	not_in_completion()
601 #endif
602 
603 	/*
604 	 * See if the char is indeed a line-editing command.
605 	 */
606 	flags = 0;
607 #if CMD_HISTORY
608 	if (curr_mlist == NULL)
609 		/*
610 		 * No current history; don't accept history manipulation cmds.
611 		 */
612 		flags |= EC_NOHISTORY;
613 #endif
614 #if TAB_COMPLETE_FILENAME
615 	if (curr_mlist == ml_search)
616 		/*
617 		 * In a search command; don't accept file-completion cmds.
618 		 */
619 		flags |= EC_NOCOMPLETE;
620 #endif
621 
622 	action = editchar(c, flags);
623 
624 	switch (action)
625 	{
626 	case EC_RIGHT:
627 		not_in_completion();
628 		return (cmd_right());
629 	case EC_LEFT:
630 		not_in_completion();
631 		return (cmd_left());
632 	case EC_W_RIGHT:
633 		not_in_completion();
634 		while (*cp != '\0' && *cp != ' ')
635 			cmd_right();
636 		while (*cp == ' ')
637 			cmd_right();
638 		return (CC_OK);
639 	case EC_W_LEFT:
640 		not_in_completion();
641 		while (cp > cmdbuf && cp[-1] == ' ')
642 			cmd_left();
643 		while (cp > cmdbuf && cp[-1] != ' ')
644 			cmd_left();
645 		return (CC_OK);
646 	case EC_HOME:
647 		not_in_completion();
648 		cmd_offset = 0;
649 		cmd_home();
650 		cmd_repaint(cp);
651 		return (CC_OK);
652 	case EC_END:
653 		not_in_completion();
654 		while (*cp != '\0')
655 			cmd_right();
656 		return (CC_OK);
657 	case EC_INSERT:
658 		not_in_completion();
659 		return (CC_OK);
660 	case EC_BACKSPACE:
661 		not_in_completion();
662 		return (cmd_erase());
663 	case EC_LINEKILL:
664 		not_in_completion();
665 		return (cmd_kill());
666 	case EC_W_BACKSPACE:
667 		not_in_completion();
668 		return (cmd_werase());
669 	case EC_DELETE:
670 		not_in_completion();
671 		return (cmd_delete());
672 	case EC_W_DELETE:
673 		not_in_completion();
674 		return (cmd_wdelete());
675 	case EC_LITERAL:
676 		literal = 1;
677 		return (CC_OK);
678 #if CMD_HISTORY
679 	case EC_UP:
680 	case EC_DOWN:
681 		not_in_completion();
682 		return (cmd_updown(action));
683 #endif
684 #if TAB_COMPLETE_FILENAME
685 	case EC_F_COMPLETE:
686 	case EC_B_COMPLETE:
687 	case EC_EXPAND:
688 		return (cmd_complete(action));
689 #endif
690 	case EC_NOACTION:
691 		return (CC_OK);
692 	default:
693 		not_in_completion();
694 		return (CC_PASS);
695 	}
696 }
697 
698 #if TAB_COMPLETE_FILENAME
699 /*
700  * Insert a string into the command buffer, at the current position.
701  */
702 	static int
703 cmd_istr(str)
704 	char *str;
705 {
706 	char *s;
707 	int action;
708 
709 	for (s = str;  *s != '\0';  s++)
710 	{
711 		action = cmd_ichar(*s);
712 		if (action != CC_OK)
713 		{
714 			bell();
715 			return (action);
716 		}
717 	}
718 	return (CC_OK);
719 }
720 
721 /*
722  * Find the beginning and end of the "current" word.
723  * This is the word which the cursor (cp) is inside or at the end of.
724  * Return pointer to the beginning of the word and put the
725  * cursor at the end of the word.
726  */
727 	static char *
728 delimit_word()
729 {
730 	char *word;
731 #if SPACES_IN_FILENAMES
732 	char *p;
733 	int delim_quoted = 0;
734 	int meta_quoted = 0;
735 	char *esc = get_meta_escape();
736 	int esclen = strlen(esc);
737 #endif
738 
739 	/*
740 	 * Move cursor to end of word.
741 	 */
742 	if (*cp != ' ' && *cp != '\0')
743 	{
744 		/*
745 		 * Cursor is on a nonspace.
746 		 * Move cursor right to the next space.
747 		 */
748 		while (*cp != ' ' && *cp != '\0')
749 			cmd_right();
750 	} else if (cp > cmdbuf && cp[-1] != ' ')
751 	{
752 		/*
753 		 * Cursor is on a space, and char to the left is a nonspace.
754 		 * We're already at the end of the word.
755 		 */
756 		;
757 #if 0
758 	} else
759 	{
760 		/*
761 		 * Cursor is on a space and char to the left is a space.
762 		 * Huh? There's no word here.
763 		 */
764 		return (NULL);
765 #endif
766 	}
767 	/*
768 	 * Find the beginning of the word which the cursor is in.
769 	 */
770 	if (cp == cmdbuf)
771 		return (NULL);
772 #if SPACES_IN_FILENAMES
773 	/*
774 	 * If we have an unbalanced quote (that is, an open quote
775 	 * without a corresponding close quote), we return everything
776 	 * from the open quote, including spaces.
777 	 */
778 	for (word = cmdbuf;  word < cp;  word++)
779 		if (*word != ' ')
780 			break;
781 	if (word >= cp)
782 		return (cp);
783 	for (p = cmdbuf;  p < cp;  p++)
784 	{
785 		if (meta_quoted)
786 		{
787 			meta_quoted = 0;
788 		} else if (esclen > 0 && p + esclen < cp &&
789 		           strncmp(p, esc, esclen) == 0)
790 		{
791 			meta_quoted = 1;
792 			p += esclen - 1;
793 		} else if (delim_quoted)
794 		{
795 			if (*p == closequote)
796 				delim_quoted = 0;
797 		} else /* (!delim_quoted) */
798 		{
799 			if (*p == openquote)
800 				delim_quoted = 1;
801 			else if (*p == ' ')
802 				word = p+1;
803 		}
804 	}
805 #endif
806 	return (word);
807 }
808 
809 /*
810  * Set things up to enter completion mode.
811  * Expand the word under the cursor into a list of filenames
812  * which start with that word, and set tk_text to that list.
813  */
814 	static void
815 init_compl()
816 {
817 	char *word;
818 	char c;
819 
820 	/*
821 	 * Get rid of any previous tk_text.
822 	 */
823 	if (tk_text != NULL)
824 	{
825 		free(tk_text);
826 		tk_text = NULL;
827 	}
828 	/*
829 	 * Find the original (uncompleted) word in the command buffer.
830 	 */
831 	word = delimit_word();
832 	if (word == NULL)
833 		return;
834 	/*
835 	 * Set the insertion point to the point in the command buffer
836 	 * where the original (uncompleted) word now sits.
837 	 */
838 	tk_ipoint = word;
839 	/*
840 	 * Save the original (uncompleted) word
841 	 */
842 	if (tk_original != NULL)
843 		free(tk_original);
844 	tk_original = (char *) ecalloc(cp-word+1, sizeof(char));
845 	strncpy(tk_original, word, cp-word);
846 	/*
847 	 * Get the expanded filename.
848 	 * This may result in a single filename, or
849 	 * a blank-separated list of filenames.
850 	 */
851 	c = *cp;
852 	*cp = '\0';
853 	if (*word != openquote)
854 	{
855 		tk_text = fcomplete(word);
856 	} else
857 	{
858 		char *qword = shell_quote(word+1);
859 		if (qword == NULL)
860 			tk_text = fcomplete(word+1);
861 		else
862 		{
863 			tk_text = fcomplete(qword);
864 			free(qword);
865 		}
866 	}
867 	*cp = c;
868 }
869 
870 /*
871  * Return the next word in the current completion list.
872  */
873 	static char *
874 next_compl(action, prev)
875 	int action;
876 	char *prev;
877 {
878 	switch (action)
879 	{
880 	case EC_F_COMPLETE:
881 		return (forw_textlist(&tk_tlist, prev));
882 	case EC_B_COMPLETE:
883 		return (back_textlist(&tk_tlist, prev));
884 	}
885 	/* Cannot happen */
886 	return ("?");
887 }
888 
889 /*
890  * Complete the filename before (or under) the cursor.
891  * cmd_complete may be called multiple times.  The global in_completion
892  * remembers whether this call is the first time (create the list),
893  * or a subsequent time (step thru the list).
894  */
895 	static int
896 cmd_complete(action)
897 	int action;
898 {
899 	char *s;
900 
901 	if (!in_completion || action == EC_EXPAND)
902 	{
903 		/*
904 		 * Expand the word under the cursor and
905 		 * use the first word in the expansion
906 		 * (or the entire expansion if we're doing EC_EXPAND).
907 		 */
908 		init_compl();
909 		if (tk_text == NULL)
910 		{
911 			bell();
912 			return (CC_OK);
913 		}
914 		if (action == EC_EXPAND)
915 		{
916 			/*
917 			 * Use the whole list.
918 			 */
919 			tk_trial = tk_text;
920 		} else
921 		{
922 			/*
923 			 * Use the first filename in the list.
924 			 */
925 			in_completion = 1;
926 			init_textlist(&tk_tlist, tk_text);
927 			tk_trial = next_compl(action, (char*)NULL);
928 		}
929 	} else
930 	{
931 		/*
932 		 * We already have a completion list.
933 		 * Use the next/previous filename from the list.
934 		 */
935 		tk_trial = next_compl(action, tk_trial);
936 	}
937 
938   	/*
939   	 * Remove the original word, or the previous trial completion.
940   	 */
941 	while (cp > tk_ipoint)
942 		(void) cmd_erase();
943 
944 	if (tk_trial == NULL)
945 	{
946 		/*
947 		 * There are no more trial completions.
948 		 * Insert the original (uncompleted) filename.
949 		 */
950 		in_completion = 0;
951 		if (cmd_istr(tk_original) != CC_OK)
952 			goto fail;
953 	} else
954 	{
955 		/*
956 		 * Insert trial completion.
957 		 */
958 		if (cmd_istr(tk_trial) != CC_OK)
959 			goto fail;
960 		/*
961 		 * If it is a directory, append a slash.
962 		 */
963 		if (is_dir(tk_trial))
964 		{
965 			if (cp > cmdbuf && cp[-1] == closequote)
966 				(void) cmd_erase();
967 			s = lgetenv("LESSSEPARATOR");
968 			if (s == NULL)
969 				s = PATHNAME_SEP;
970 			if (cmd_istr(s) != CC_OK)
971 				goto fail;
972 		}
973 	}
974 
975 	return (CC_OK);
976 
977 fail:
978 	in_completion = 0;
979 	bell();
980 	return (CC_OK);
981 }
982 
983 #endif /* TAB_COMPLETE_FILENAME */
984 
985 /*
986  * Process a single character of a multi-character command, such as
987  * a number, or the pattern of a search command.
988  * Returns:
989  *	CC_OK		The char was accepted.
990  *	CC_QUIT		The char requests the command to be aborted.
991  *	CC_ERROR	The char could not be accepted due to an error.
992  */
993 	public int
994 cmd_char(c)
995 	int c;
996 {
997 	int action;
998 
999 	if (literal)
1000 	{
1001 		/*
1002 		 * Insert the char, even if it is a line-editing char.
1003 		 */
1004 		literal = 0;
1005 		return (cmd_ichar(c));
1006 	}
1007 
1008 	/*
1009 	 * See if it is a special line-editing character.
1010 	 */
1011 	if (in_mca())
1012 	{
1013 		action = cmd_edit(c);
1014 		switch (action)
1015 		{
1016 		case CC_OK:
1017 		case CC_QUIT:
1018 			return (action);
1019 		case CC_PASS:
1020 			break;
1021 		}
1022 	}
1023 
1024 	/*
1025 	 * Insert the char into the command buffer.
1026 	 */
1027 	return (cmd_ichar(c));
1028 }
1029 
1030 /*
1031  * Return the number currently in the command buffer.
1032  */
1033 	public LINENUM
1034 cmd_int()
1035 {
1036 	register char *p;
1037 	LINENUM n = 0;
1038 
1039 	for (p = cmdbuf;  *p != '\0';  p++)
1040 		n = (10 * n) + (*p - '0');
1041 	return (n);
1042 }
1043 
1044 /*
1045  * Return a pointer to the command buffer.
1046  */
1047 	public char *
1048 get_cmdbuf()
1049 {
1050 	return (cmdbuf);
1051 }
1052