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
cmd_reset()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
clear_cmd()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
cmd_putstr(s)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
len_cmdbuf()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
cmd_repaint(old_cp)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
cmd_home()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
cmd_lshift()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
cmd_rshift()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
cmd_right()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
cmd_left()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
cmd_ichar(c)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
cmd_erase()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
cmd_delete()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
cmd_werase()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
cmd_wdelete()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
cmd_kill()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
set_mlist(mlist,cmdflags)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
cmd_updown(action)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
cmd_addhist(mlist,cmd)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
cmd_accept()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
cmd_edit(c)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
cmd_istr(str)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 *
delimit_word()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
init_compl()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 *
next_compl(action,prev)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
cmd_complete(action)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
cmd_char(c)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
cmd_int()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 *
get_cmdbuf()1048 get_cmdbuf()
1049 {
1050 return (cmdbuf);
1051 }
1052