xref: /openbsd-src/usr.bin/less/cmdbuf.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: cmdbuf.c,v 1.3 2001/11/19 19:02:14 mpech Exp $	*/
2 
3 /*
4  * Copyright (c) 1984,1985,1989,1994,1995  Mark Nudelman
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice in the documentation and/or other materials provided with
14  *    the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
22  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 
30 /*
31  * Functions which manipulate the command buffer.
32  * Used only by command() and related functions.
33  */
34 
35 #include "less.h"
36 #include "cmd.h"
37 
38 extern int sc_width;
39 
40 static char cmdbuf[120];	/* Buffer for holding a multi-char command */
41 static int cmd_col;		/* Current column of the multi-char command */
42 static char *cp;		/* Pointer into cmdbuf */
43 static int literal;
44 
45 #if TAB_COMPLETE_FILENAME
46 static int cmd_complete();
47 /*
48  * These variables are statics used by cmd_complete.
49  */
50 static int in_completion = 0;
51 static char *tk_text;
52 static char *tk_original;
53 static char *tk_ipoint;
54 static char *tk_trial;
55 static struct textlist tk_tlist;
56 #endif
57 
58 #if CMD_HISTORY
59 /*
60  * A mlist structure represents a command history.
61  */
62 struct mlist
63 {
64 	struct mlist *next;
65 	struct mlist *prev;
66 	struct mlist *curr_mp;
67 	char *string;
68 };
69 
70 /*
71  * These are the various command histories that exist.
72  */
73 struct mlist mlist_search =
74 	{ &mlist_search,  &mlist_search,  &mlist_search,  NULL };
75 public void *ml_search = (void *) &mlist_search;
76 struct mlist mlist_examine =
77 	{ &mlist_examine, &mlist_examine, &mlist_examine, NULL };
78 public void *ml_examine = (void *) &mlist_examine;
79 #if SHELL_ESCAPE || PIPEC
80 struct mlist mlist_shell =
81 	{ &mlist_shell,   &mlist_shell,   &mlist_shell,   NULL };
82 public void *ml_shell = (void *) &mlist_shell;
83 #endif /* SHELL_ESCAPE || PIPEC */
84 
85 /*
86  * History for the current command.
87  */
88 static struct mlist *curr_mlist = NULL;
89 
90 #endif /* CMD_HISTORY */
91 
92 /*
93  * Reset command buffer (to empty).
94  */
95 	public void
96 cmd_reset()
97 {
98 	cp = cmdbuf;
99 	*cp = '\0';
100 	cmd_col = 0;
101 	literal = 0;
102 }
103 
104 /*
105  * How many characters are in the command buffer?
106  */
107 	public int
108 len_cmdbuf()
109 {
110 	return (strlen(cmdbuf));
111 }
112 
113 /*
114  * Backspace in the command buffer.
115  * Delete the char to the left of the cursor.
116  */
117 	static int
118 cmd_erase()
119 {
120 	char *s;
121 	char *p;
122 	int col;
123 
124 	if (cp == cmdbuf)
125 	{
126 		/*
127 		 * Backspace past beginning of the buffer:
128 		 * this usually means abort the command.
129 		 */
130 		return (CC_QUIT);
131 	}
132 	/*
133 	 * Back up the pointer.
134 	 */
135 	--cp;
136 	/*
137 	 * Remember the current cursor column and
138 	 * set it back the width of the char being erased.
139 	 */
140 	col = cmd_col;
141 	p = prchar(*cp);
142 	cmd_col -= strlen(p);
143 	/*
144 	 * Shift left the buffer after the erased char.
145 	 */
146 	for (s = cp;  *s != '\0';  s++)
147 		s[0] = s[1];
148 	/*
149 	 * Back up the cursor to the position of the erased char,
150 	 * clear the tail of the line,
151 	 * and reprint the line after the erased char.
152 	 */
153 	while (col > cmd_col)
154 	{
155 		putbs();
156 		col--;
157 	}
158 	clear_eol();
159 	for (s = cp;  *s != '\0';  s++)
160 	{
161 		p = prchar(*s);
162 		putstr(p);
163 		col += strlen(p);
164 	}
165 	/*
166 	 * Back up the cursor again.
167 	 */
168 	while (col > cmd_col)
169 	{
170 		putbs();
171 		col--;
172 	}
173 
174 	/*
175 	 * This is rather weird.
176 	 * We say that erasing the entire command string causes us
177 	 * to abort the current command, BUT ONLY IF there is no history
178 	 * for this type of command.  This causes commands like search (/)
179 	 * and edit (:e) to stay active even if we erase the entire string,
180 	 * but commands like <digit> and - go away when we erase the string.
181 	 * (See same thing in cmd_kill.)
182 	 */
183 	if (curr_mlist == NULL && cp == cmdbuf && *cp == '\0')
184 		return (CC_QUIT);
185 	return (CC_OK);
186 }
187 
188 /*
189  * Delete the char under the cursor.
190  */
191 	static int
192 cmd_delete()
193 {
194 	char *p;
195 
196 	if (*cp == '\0')
197 	{
198 		/*
199 		 * At end of string; there is no char under the cursor.
200 		 */
201 		return (CC_OK);
202 	}
203 	/*
204 	 * Move right, then use cmd_erase.
205 	 */
206 	p = prchar(*cp);
207 	cp++;
208 	putstr(p);
209 	cmd_col += strlen(p);
210 	cmd_erase();
211 	return (CC_OK);
212 }
213 
214 /*
215  * Delete the "word" to the left of the cursor.
216  */
217 	static int
218 cmd_werase()
219 {
220 	if (cp > cmdbuf && cp[-1] == ' ')
221 	{
222 		/*
223 		 * If the char left of cursor is a space,
224 		 * erase all the spaces left of cursor (to the first non-space).
225 		 */
226 		while (cp > cmdbuf && cp[-1] == ' ')
227 			(void) cmd_erase();
228 	} else
229 	{
230 		/*
231 		 * If the char left of cursor is not a space,
232 		 * erase all the nonspaces left of cursor (the whole "word").
233 		 */
234 		while (cp > cmdbuf && cp[-1] != ' ')
235 			(void) cmd_erase();
236 	}
237 	return (CC_OK);
238 }
239 
240 /*
241  * Delete the "word" under the cursor.
242  */
243 	static int
244 cmd_wdelete()
245 {
246 	if (*cp == ' ')
247 	{
248 		/*
249 		 * If the char under the cursor is a space,
250 		 * delete it and all the spaces right of cursor.
251 		 */
252 		while (*cp == ' ')
253 			(void) cmd_delete();
254 	} else
255 	{
256 		/*
257 		 * If the char under the cursor is not a space,
258 		 * delete it and all nonspaces right of cursor (the whole word).
259 		 */
260 		while (*cp != ' ' && *cp != '\0')
261 			(void) cmd_delete();
262 	}
263 	return (CC_OK);
264 }
265 
266 /*
267  * Move cursor to start of command buffer.
268  */
269 	static int
270 cmd_home()
271 {
272 	char *p;
273 
274 	/*
275 	 * Back up until we hit start of buffer.
276 	 */
277 	while (cp > cmdbuf)
278 	{
279 		cp--;
280 		p = prchar(*cp);
281 		cmd_col -= strlen(p);
282 		while (*p++ != '\0')
283 			putbs();
284 	}
285 	return (CC_OK);
286 }
287 
288 /*
289  * Delete all chars in the command buffer.
290  */
291 	static int
292 cmd_kill()
293 {
294 	if (cmdbuf[0] == '\0')
295 	{
296 		/*
297 		 * Buffer is already empty; abort the current command.
298 		 */
299 		return (CC_QUIT);
300 	}
301 	(void) cmd_home();
302 	*cp = '\0';
303 	clear_eol();
304 	/*
305 	 * Same weirdness as in cmd_erase.
306 	 * If the current command has no history, abort the current command.
307 	 */
308 	if (curr_mlist == NULL)
309 		return (CC_QUIT);
310 	return (CC_OK);
311 }
312 
313 /*
314  * Move cursor right one character.
315  */
316 	static int
317 cmd_right()
318 {
319 	char *p;
320 
321 	if (*cp == '\0')
322 	{
323 		/*
324 		 * Already at the end of the line.
325 		 */
326 		return (CC_OK);
327 	}
328 	p = prchar(*cp);
329 	cp++;
330 	putstr(p);
331 	cmd_col += strlen(p);
332 	return (CC_OK);
333 }
334 
335 /*
336  * Move cursor left one character.
337  */
338 	static int
339 cmd_left()
340 {
341 	char *p;
342 
343 	if (cp <= cmdbuf)
344 	{
345 		/* Already at the beginning of the line */
346 		return (CC_OK);
347 	}
348 	cp--;
349 	p = prchar(*cp);
350 	cmd_col -= strlen(p);
351 	while (*p++ != '\0')
352 		putbs();
353 	return (CC_OK);
354 }
355 
356 #if CMD_HISTORY
357 /*
358  * Select an mlist structure to be the current command history.
359  */
360 	public void
361 set_mlist(mlist)
362 	void *mlist;
363 {
364 	curr_mlist = (struct mlist *) mlist;
365 }
366 
367 /*
368  * Move up or down in the currently selected command history list.
369  */
370 	static int
371 cmd_updown(action)
372 	int action;
373 {
374 	char *p;
375 	char *s;
376 
377 	if (curr_mlist == NULL)
378 	{
379 		/*
380 		 * The current command has no history list.
381 		 */
382 		bell();
383 		return (CC_OK);
384 	}
385 	cmd_home();
386 	clear_eol();
387 	/*
388 	 * Move curr_mp to the next/prev entry.
389 	 */
390 	if (action == EC_UP)
391 		curr_mlist->curr_mp = curr_mlist->curr_mp->prev;
392 	else
393 		curr_mlist->curr_mp = curr_mlist->curr_mp->next;
394 	/*
395 	 * Copy the entry into cmdbuf and echo it on the screen.
396 	 */
397 	s = curr_mlist->curr_mp->string;
398 	if (s == NULL)
399 		s = "";
400 	for (cp = cmdbuf;  *s != '\0';  s++, cp++)
401 	{
402 		*cp = *s;
403 		p = prchar(*cp);
404 		cmd_col += strlen(p);
405 		putstr(p);
406 	}
407 	*cp = '\0';
408 	return (CC_OK);
409 }
410 
411 /*
412  * Accept the command in the command buffer.
413  * Add it to the currently selected history list.
414  */
415 	public void
416 cmd_accept()
417 {
418 	struct mlist *ml;
419 
420 	/*
421 	 * Nothing to do if there is no currently selected history list.
422 	 */
423 	if (curr_mlist == NULL)
424 		return;
425 	/*
426 	 * Don't save a trivial command.
427 	 */
428 	if (strlen(cmdbuf) == 0)
429 		return;
430 	/*
431 	 * Don't save if a duplicate of a command which is already in the history.
432 	 * But select the one already in the history to be current.
433 	 */
434 	for (ml = curr_mlist->next;  ml != curr_mlist;  ml = ml->next)
435 	{
436 		if (strcmp(ml->string, cmdbuf) == 0)
437 			break;
438 	}
439 	if (ml == curr_mlist)
440 	{
441 		/*
442 		 * Did not find command in history.
443 		 * Save the command and put it at the end of the history list.
444 		 */
445 		ml = (struct mlist *) ecalloc(1, sizeof(struct mlist));
446 		ml->string = save(cmdbuf);
447 		ml->next = curr_mlist;
448 		ml->prev = curr_mlist->prev;
449 		curr_mlist->prev->next = ml;
450 		curr_mlist->prev = ml;
451 	}
452 	/*
453 	 * Point to the cmd just after the just-accepted command.
454 	 * Thus, an UPARROW will always retrieve the previous command.
455 	 */
456 	curr_mlist->curr_mp = ml->next;
457 }
458 #endif
459 
460 /*
461  * Try to perform a line-edit function on the command buffer,
462  * using a specified char as a line-editing command.
463  * Returns:
464  *	CC_PASS	The char does not invoke a line edit function.
465  *	CC_OK	Line edit function done.
466  *	CC_QUIT	The char requests the current command to be aborted.
467  */
468 	static int
469 cmd_edit(c)
470 	int c;
471 {
472 	int action;
473 	int flags;
474 
475 #if TAB_COMPLETE_FILENAME
476 #define	not_in_completion()	in_completion = 0
477 #else
478 #define	not_in_completion()
479 #endif
480 
481 	/*
482 	 * See if the char is indeed a line-editing command.
483 	 */
484 	flags = 0;
485 	if (curr_mlist == NULL)
486 		/*
487 		 * No current history; don't accept history manipulation cmds.
488 		 */
489 		flags |= EC_NOHISTORY;
490 	if (curr_mlist == &mlist_search)
491 		/*
492 		 * In a search command; don't accept file-completion cmds.
493 		 */
494 		flags |= EC_NOCOMPLETE;
495 
496 	action = editchar(c, flags);
497 
498 	switch (action)
499 	{
500 	case EC_RIGHT:
501 		not_in_completion();
502 		return (cmd_right());
503 	case EC_LEFT:
504 		not_in_completion();
505 		return (cmd_left());
506 	case EC_W_RIGHT:
507 		not_in_completion();
508 		while (*cp != '\0' && *cp != ' ')
509 			cmd_right();
510 		while (*cp == ' ')
511 			cmd_right();
512 		return (CC_OK);
513 	case EC_W_LEFT:
514 		not_in_completion();
515 		while (cp > cmdbuf && cp[-1] == ' ')
516 			cmd_left();
517 		while (cp > cmdbuf && cp[-1] != ' ')
518 			cmd_left();
519 		return (CC_OK);
520 	case EC_HOME:
521 		not_in_completion();
522 		return (cmd_home());
523 	case EC_END:
524 		not_in_completion();
525 		while (*cp != '\0')
526 			cmd_right();
527 		return (CC_OK);
528 	case EC_INSERT:
529 		not_in_completion();
530 		return (CC_OK);
531 	case EC_BACKSPACE:
532 		not_in_completion();
533 		return (cmd_erase());
534 	case EC_LINEKILL:
535 		not_in_completion();
536 		return (cmd_kill());
537 	case EC_W_BACKSPACE:
538 		not_in_completion();
539 		return (cmd_werase());
540 	case EC_DELETE:
541 		not_in_completion();
542 		return (cmd_delete());
543 	case EC_W_DELETE:
544 		not_in_completion();
545 		return (cmd_wdelete());
546 	case EC_LITERAL:
547 		literal = 1;
548 		return (CC_OK);
549 #if CMD_HISTORY
550 	case EC_UP:
551 	case EC_DOWN:
552 		not_in_completion();
553 		return (cmd_updown(action));
554 #endif
555 #if TAB_COMPLETE_FILENAME
556 	case EC_F_COMPLETE:
557 	case EC_B_COMPLETE:
558 	case EC_EXPAND:
559 		return (cmd_complete(action));
560 #endif
561 	default:
562 		not_in_completion();
563 		return (CC_PASS);
564 	}
565 }
566 
567 /*
568  * Insert a char into the command buffer, at the current position.
569  */
570 	static int
571 cmd_ichar(c)
572 	int c;
573 {
574 	int col;
575 	char *p;
576 	char *s;
577 
578 	if (strlen(cmdbuf) >= sizeof(cmdbuf)-2)
579 	{
580 		/*
581 		 * No room in the command buffer for another char.
582 		 */
583 		bell();
584 		return (CC_ERROR);
585 	}
586 
587 	/*
588 	 * Remember the current cursor column and
589 	 * move it forward the width of the char being inserted.
590 	 */
591 	col = cmd_col;
592 	p = prchar(c);
593 	cmd_col += strlen(p);
594 	if (cmd_col >= sc_width-1)
595 	{
596 		cmd_col -= strlen(p);
597 		bell();
598 		return (CC_ERROR);
599 	}
600 	/*
601 	 * Insert the character in the string.
602 	 * First, make room for the new char.
603 	 */
604 	for (s = &cmdbuf[strlen(cmdbuf)];  s >= cp;  s--)
605 		s[1] = s[0];
606 	*cp++ = c;
607 	/*
608 	 * Reprint the tail of the line after the inserted char.
609 	 */
610 	clear_eol();
611 	for (s = cp-1;  *s != '\0';  s++)
612 	{
613 		p = prchar(*s);
614 		col += strlen(p);
615 		if (col >= sc_width-1)
616 		{
617 			/*
618 			 * Oops.  There is no room on the screen
619 			 * for the new char.  Back up the cursor to
620 			 * just after the inserted char and erase it.
621 			 */
622 			col -= strlen(p);
623 			while (col > cmd_col)
624 			{
625 				putbs();
626 				col--;
627 			}
628 			(void) cmd_erase();
629 			bell();
630 			return (CC_ERROR);
631 		}
632 		putstr(p);
633 	}
634 	/*
635 	 * Back up the cursor to just after the inserted char.
636 	 */
637 	while (col > cmd_col)
638 	{
639 		putbs();
640 		col--;
641 	}
642 	return (CC_OK);
643 }
644 
645 #if TAB_COMPLETE_FILENAME
646 /*
647  * Insert a string into the command buffer, at the current position.
648  */
649 	static int
650 cmd_istr(str)
651 	char *str;
652 {
653 	char *s;
654 	int action;
655 
656 	for (s = str;  *s != '\0';  s++)
657 	{
658 		action = cmd_ichar(*s);
659 		if (action != CC_OK)
660 		{
661 			bell();
662 			return (action);
663 		}
664 	}
665 	return (CC_OK);
666 }
667 
668 /*
669  * Find the beginning and end of the "current" word.
670  * This is the word which the cursor (cp) is inside or at the end of.
671  * Return pointer to the beginning of the word and put the
672  * cursor at the end of the word.
673  */
674 	static char *
675 delimit_word()
676 {
677 	char *word;
678 
679 	/*
680 	 * Move cursor to end of word.
681 	 */
682 	if (*cp != ' ' && *cp != '\0')
683 	{
684 		/*
685 		 * Cursor is on a nonspace.
686 		 * Move cursor right to the next space.
687 		 */
688 		while (*cp != ' ' && *cp != '\0')
689 			cmd_right();
690 	} else if (cp > cmdbuf && cp[-1] != ' ')
691 	{
692 		/*
693 		 * Cursor is on a space, and char to the left is a nonspace.
694 		 * We're already at the end of the word.
695 		 */
696 		;
697 	} else
698 	{
699 		/*
700 		 * Cursor is on a space and char to the left is a space.
701 		 * Huh? There's no word here.
702 		 */
703 		return (NULL);
704 	}
705 	/*
706 	 * Search backwards for beginning of the word.
707 	 */
708 	if (cp == cmdbuf)
709 		return (NULL);
710 	for (word = cp-1;  word > cmdbuf;  word--)
711 		if (word[-1] == ' ')
712 			break;
713 	return (word);
714 }
715 
716 /*
717  * Set things up to enter completion mode.
718  * Expand the word under the cursor into a list of filenames
719  * which start with that word, and set tk_text to that list.
720  */
721 	static void
722 init_compl()
723 {
724 	char *word;
725 	char c;
726 
727 	/*
728 	 * Get rid of any previous tk_text.
729 	 */
730 	if (tk_text != NULL)
731 	{
732 		free(tk_text);
733 		tk_text = NULL;
734 	}
735 	/*
736 	 * Find the original (uncompleted) word in the command buffer.
737 	 */
738 	word = delimit_word();
739 	if (word == NULL)
740 		return;
741 	/*
742 	 * Set the insertion point to the point in the command buffer
743 	 * where the original (uncompleted) word now sits.
744 	 */
745 	tk_ipoint = word;
746 	/*
747 	 * Save the original (uncompleted) word
748 	 */
749 	if (tk_original != NULL)
750 		free(tk_original);
751 	tk_original = (char *) ecalloc(cp-word+1, sizeof(char));
752 	strncpy(tk_original, word, cp-word);
753 	/*
754 	 * Get the expanded filename.
755 	 * This may result in a single filename, or
756 	 * a blank-separated list of filenames.
757 	 */
758 	c = *cp;
759 	*cp = '\0';
760 	tk_text = fcomplete(word);
761 	*cp = c;
762 }
763 
764 /*
765  * Return the next word in the current completion list.
766  */
767 	static char *
768 next_compl(action, prev)
769      	int action;
770 	char *prev;
771 {
772 	switch (action)
773 	{
774 	case EC_F_COMPLETE:
775 		return (forw_textlist(&tk_tlist, prev));
776 	case EC_B_COMPLETE:
777 		return (back_textlist(&tk_tlist, prev));
778 	default:
779 		/* Cannot happen */
780 		return ("?");
781 	}
782 }
783 
784 /*
785  * Complete the filename before (or under) the cursor.
786  * cmd_complete may be called multiple times.  The global in_completion
787  * remembers whether this call is the first time (create the list),
788  * or a subsequent time (step thru the list).
789  */
790 	static int
791 cmd_complete(action)
792 	int action;
793 {
794 
795 	if (!in_completion || action == EC_EXPAND)
796 	{
797 		/*
798 		 * Expand the word under the cursor and
799 		 * use the first word in the expansion
800 		 * (or the entire expansion if we're doing EC_EXPAND).
801 		 */
802 		init_compl();
803 		if (tk_text == NULL)
804 		{
805 			bell();
806 			return (CC_OK);
807 		}
808 		if (action == EC_EXPAND)
809 		{
810 			/*
811 			 * Use the whole list.
812 			 */
813 			tk_trial = tk_text;
814 		} else
815 		{
816 			/*
817 			 * Use the first filename in the list.
818 			 */
819 			in_completion = 1;
820 			init_textlist(&tk_tlist, tk_text);
821 			tk_trial = next_compl(action, (char*)NULL);
822 		}
823 	} else
824 	{
825 		/*
826 		 * We already have a completion list.
827 		 * Use the next/previous filename from the list.
828 		 */
829 		tk_trial = next_compl(action, tk_trial);
830 	}
831 
832   	/*
833   	 * Remove the original word, or the previous trial completion.
834   	 */
835 	while (cp > tk_ipoint)
836 		(void) cmd_erase();
837 
838 	if (tk_trial == NULL)
839 	{
840 		/*
841 		 * There are no more trial completions.
842 		 * Insert the original (uncompleted) filename.
843 		 */
844 		in_completion = 0;
845 		if (cmd_istr(tk_original) != CC_OK)
846 			goto fail;
847 	} else
848 	{
849 		/*
850 		 * Insert trial completion.
851 		 */
852 		if (cmd_istr(tk_trial) != CC_OK)
853 			goto fail;
854 	}
855 
856 	return (CC_OK);
857 
858 fail:
859 	in_completion = 0;
860 	bell();
861 	return (CC_OK);
862 }
863 
864 #endif /* TAB_COMPLETE_FILENAME */
865 
866 /*
867  * Process a single character of a multi-character command, such as
868  * a number, or the pattern of a search command.
869  * Returns:
870  *	CC_OK		The char was accepted.
871  *	CC_QUIT		The char requests the command to be aborted.
872  *	CC_ERROR	The char could not be accepted due to an error.
873  */
874 	public int
875 cmd_char(c)
876 	int c;
877 {
878 	int action;
879 
880 	if (literal)
881 	{
882 		/*
883 		 * Insert the char, even if it is a line-editing char.
884 		 */
885 		literal = 0;
886 		return (cmd_ichar(c));
887 	}
888 
889 	/*
890 	 * See if it is a special line-editing character.
891 	 */
892 	if (in_mca())
893 	{
894 		action = cmd_edit(c);
895 		switch (action)
896 		{
897 		case CC_OK:
898 		case CC_QUIT:
899 			return (action);
900 		case CC_PASS:
901 			break;
902 		}
903 	}
904 
905 	/*
906 	 * Insert the char into the command buffer.
907 	 */
908 	action = cmd_ichar(c);
909 	if (action != CC_OK)
910 		return (action);
911 	return (CC_OK);
912 }
913 
914 /*
915  * Return the number currently in the command buffer.
916  */
917 	public int
918 cmd_int()
919 {
920 	return (atoi(cmdbuf));
921 }
922 
923 /*
924  * Display a string, usually as a prompt for input into the command buffer.
925  */
926 	public void
927 cmd_putstr(s)
928 	char *s;
929 {
930 	putstr(s);
931 	cmd_col += strlen(s);
932 }
933 
934 /*
935  * Return a pointer to the command buffer.
936  */
937 	public char *
938 get_cmdbuf()
939 {
940 	return (cmdbuf);
941 }
942