cmdbuf.c revision 128345
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 20extern int sc_width; 21 22static char cmdbuf[CMDBUF_SIZE]; /* Buffer for holding a multi-char command */ 23static int cmd_col; /* Current column of the cursor */ 24static int prompt_col; /* Column of cursor just after prompt */ 25static char *cp; /* Pointer into cmdbuf */ 26static int cmd_offset; /* Index into cmdbuf of first displayed char */ 27static int literal; /* Next input char should not be interpreted */ 28 29#if TAB_COMPLETE_FILENAME 30static int cmd_complete(); 31/* 32 * These variables are statics used by cmd_complete. 33 */ 34static int in_completion = 0; 35static char *tk_text; 36static char *tk_original; 37static char *tk_ipoint; 38static char *tk_trial; 39static struct textlist tk_tlist; 40#endif 41 42static int cmd_left(); 43static int cmd_right(); 44 45#if SPACES_IN_FILENAMES 46public char openquote = '"'; 47public char closequote = '"'; 48#endif 49 50#if CMD_HISTORY 51/* 52 * A mlist structure represents a command history. 53 */ 54struct 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 */ 65struct mlist mlist_search = 66 { &mlist_search, &mlist_search, &mlist_search, NULL }; 67public void * constant ml_search = (void *) &mlist_search; 68 69struct mlist mlist_examine = 70 { &mlist_examine, &mlist_examine, &mlist_examine, NULL }; 71public void * constant ml_examine = (void *) &mlist_examine; 72 73#if SHELL_ESCAPE || PIPEC 74struct mlist mlist_shell = 75 { &mlist_shell, &mlist_shell, &mlist_shell, NULL }; 76public 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. */ 82public void * constant ml_search = (void *)1; 83public void * constant ml_examine = (void *)2; 84#if SHELL_ESCAPE || PIPEC 85public void * constant ml_shell = (void *)3; 86#endif 87 88#endif /* CMD_HISTORY */ 89 90/* 91 * History for the current command. 92 */ 93static struct mlist *curr_mlist = NULL; 94static int curr_cmdflags; 95 96 97/* 98 * Reset command buffer (to empty). 99 */ 100 public void 101cmd_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 114clear_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 124cmd_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 136len_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 146cmd_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 176cmd_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 191cmd_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 216cmd_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 246cmd_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 272cmd_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 295cmd_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 328cmd_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 367cmd_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 388cmd_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 414cmd_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 440cmd_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 467set_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 480cmd_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 522cmd_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 570cmd_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 591cmd_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 703cmd_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 * 728delimit_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 815init_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 * 874next_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 896cmd_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 977fail: 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 994cmd_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 1034cmd_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 * 1048get_cmdbuf() 1049{ 1050 return (cmdbuf); 1051} 1052