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