1 /* 2 * ed.chared.c: Character editing functions. 3 */ 4 /*- 5 * Copyright (c) 1980, 1991 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the University nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 /* 33 Bjorn Knutsson @ Thu Jun 24 19:02:17 1999 34 35 e_dabbrev_expand() did not do proper completion if quoted spaces were present 36 in the string being completed. Exemple: 37 38 # echo hello\ world 39 hello world 40 # echo h<press key bound to dabbrev-expande> 41 # echo hello\<cursor> 42 43 Correct behavior is: 44 # echo h<press key bound to dabbrev-expande> 45 # echo hello\ world<cursor> 46 47 The same problem occured if spaces were present in a string withing quotation 48 marks. Example: 49 50 # echo "hello world" 51 hello world 52 # echo "h<press key bound to dabbrev-expande> 53 # echo "hello<cursor> 54 55 The former problem could be solved with minor modifications of c_preword() 56 and c_endword(). The latter, however, required a significant rewrite of 57 c_preword(), since quoted strings must be parsed from start to end to 58 determine if a given character is inside or outside the quotation marks. 59 60 Compare the following two strings: 61 62 # echo \"" 'foo \' bar\" 63 " 'foo \' bar\ 64 # echo '\"" 'foo \' bar\" 65 \"" foo ' bar" 66 67 The only difference between the two echo lines is in the first character 68 after the echo command. The result is either one or three arguments. 69 70 */ 71 72 #include "sh.h" 73 #include "ed.h" 74 #include "tw.h" 75 #include "ed.defns.h" 76 77 /* #define SDEBUG */ 78 79 #define TCSHOP_NOP 0x00 80 #define TCSHOP_DELETE 0x01 81 #define TCSHOP_INSERT 0x02 82 #define TCSHOP_CHANGE 0x04 83 84 #define CHAR_FWD 0 85 #define CHAR_BACK 1 86 87 /* 88 * vi word treatment 89 * from: Gert-Jan Vons <vons@cesar.crbca1.sinet.slb.com> 90 */ 91 #define C_CLASS_WHITE 1 92 #define C_CLASS_WORD 2 93 #define C_CLASS_OTHER 3 94 95 static Char *InsertPos = InputBuf; /* Where insertion starts */ 96 static Char *ActionPos = 0; /* Where action begins */ 97 static int ActionFlag = TCSHOP_NOP; /* What delayed action to take */ 98 /* 99 * Word search state 100 */ 101 static int searchdir = F_UP_SEARCH_HIST; /* Direction of last search */ 102 static struct Strbuf patbuf; /* = Strbuf_INIT; Search target */ 103 /* 104 * Char search state 105 */ 106 static int srch_dir = CHAR_FWD; /* Direction of last search */ 107 static Char srch_char = 0; /* Search target */ 108 109 /* all routines that start with c_ are private to this set of routines */ 110 static void c_alternativ_key_map (int); 111 void c_insert (int); 112 void c_delafter (int); 113 void c_delbefore (int); 114 static int c_to_class (Char); 115 static Char *c_prev_word (Char *, Char *, int); 116 static Char *c_next_word (Char *, Char *, int); 117 static Char *c_number (Char *, int *, int); 118 static Char *c_expand (Char *); 119 static int c_excl (Char *); 120 static int c_substitute (void); 121 static void c_delfini (void); 122 static int c_hmatch (Char *); 123 static void c_hsetpat (void); 124 #ifdef COMMENT 125 static void c_get_word (Char **, Char **); 126 #endif 127 static Char *c_preword (Char *, Char *, int, Char *); 128 static Char *c_nexword (Char *, Char *, int); 129 static Char *c_endword (Char *, Char *, int, Char *); 130 static Char *c_eword (Char *, Char *, int); 131 static void c_push_kill (Char *, Char *); 132 static void c_save_inputbuf (void); 133 static CCRETVAL c_search_line (Char *, int); 134 static CCRETVAL v_repeat_srch (int); 135 static CCRETVAL e_inc_search (int); 136 #ifdef notyet 137 static CCRETVAL e_insert_str (Char *); 138 #endif 139 static CCRETVAL v_search (int); 140 static CCRETVAL v_csearch_fwd (Char, int, int); 141 static CCRETVAL v_action (int); 142 static CCRETVAL v_csearch_back (Char, int, int); 143 144 static void 145 c_alternativ_key_map(int state) 146 { 147 switch (state) { 148 case 0: 149 CurrentKeyMap = CcKeyMap; 150 break; 151 case 1: 152 CurrentKeyMap = CcAltMap; 153 break; 154 default: 155 return; 156 } 157 158 AltKeyMap = (Char) state; 159 } 160 161 void 162 c_insert(int num) 163 { 164 Char *cp; 165 166 if (LastChar + num >= InputLim) 167 return; /* can't go past end of buffer */ 168 169 if (Cursor < LastChar) { /* if I must move chars */ 170 for (cp = LastChar; cp >= Cursor; cp--) 171 cp[num] = *cp; 172 if (Mark && Mark > Cursor) 173 Mark += num; 174 } 175 LastChar += num; 176 } 177 178 void 179 c_delafter(int num) 180 { 181 Char *cp, *kp = NULL; 182 183 if (num > LastChar - Cursor) 184 num = (int) (LastChar - Cursor); /* bounds check */ 185 186 if (num > 0) { /* if I can delete anything */ 187 if (VImode) { 188 kp = UndoBuf; /* Set Up for VI undo command */ 189 UndoAction = TCSHOP_INSERT; 190 UndoSize = num; 191 UndoPtr = Cursor; 192 for (cp = Cursor; cp <= LastChar; cp++) { 193 *kp++ = *cp; /* Save deleted chars into undobuf */ 194 *cp = cp[num]; 195 } 196 } 197 else 198 for (cp = Cursor; cp + num <= LastChar; cp++) 199 *cp = cp[num]; 200 LastChar -= num; 201 /* Mark was within the range of the deleted word? */ 202 if (Mark && Mark > Cursor && Mark <= Cursor+num) 203 Mark = Cursor; 204 /* Mark after the deleted word? */ 205 else if (Mark && Mark > Cursor) 206 Mark -= num; 207 } 208 #ifdef notdef 209 else { 210 /* 211 * XXX: We don't want to do that. In emacs mode overwrite should be 212 * sticky. I am not sure how that affects vi mode 213 */ 214 inputmode = MODE_INSERT; 215 } 216 #endif /* notdef */ 217 } 218 219 void 220 c_delbefore(int num) /* delete before dot, with bounds checking */ 221 { 222 Char *cp, *kp = NULL; 223 224 if (num > Cursor - InputBuf) 225 num = (int) (Cursor - InputBuf); /* bounds check */ 226 227 if (num > 0) { /* if I can delete anything */ 228 if (VImode) { 229 kp = UndoBuf; /* Set Up for VI undo command */ 230 UndoAction = TCSHOP_INSERT; 231 UndoSize = num; 232 UndoPtr = Cursor - num; 233 for (cp = Cursor - num; cp <= LastChar; cp++) { 234 *kp++ = *cp; 235 *cp = cp[num]; 236 } 237 } 238 else 239 for (cp = Cursor - num; cp + num <= LastChar; cp++) 240 *cp = cp[num]; 241 LastChar -= num; 242 Cursor -= num; 243 /* Mark was within the range of the deleted word? */ 244 if (Mark && Mark > Cursor && Mark <= Cursor+num) 245 Mark = Cursor; 246 /* Mark after the deleted word? */ 247 else if (Mark && Mark > Cursor) 248 Mark -= num; 249 } 250 } 251 252 static Char * 253 c_preword(Char *p, Char *low, int n, Char *delim) 254 { 255 while (n--) { 256 Char *prev = low; 257 Char *new; 258 259 while (prev < p) { /* Skip initial non-word chars */ 260 if (!Strchr(delim, *prev) || (prev > low && prev[-1] == (Char)'\\')) 261 break; 262 prev++; 263 } 264 265 new = prev; 266 267 while (new < p) { 268 prev = new; 269 new = c_endword(prev-1, p, 1, delim); /* Skip to next non-word char */ 270 new++; /* Step away from end of word */ 271 while (new <= p) { /* Skip trailing non-word chars */ 272 if (!Strchr(delim, *new) || (new > prev && new[-1] == (Char)'\\')) 273 break; 274 new++; 275 } 276 } 277 278 p = prev; /* Set to previous word start */ 279 280 } 281 if (p < low) 282 p = low; 283 return (p); 284 } 285 286 /* 287 * c_to_class() returns the class of the given character. 288 * 289 * This is used to make the c_prev_word(), c_next_word() and c_eword() functions 290 * work like vi's, which classify characters. A word is a sequence of 291 * characters belonging to the same class, classes being defined as 292 * follows: 293 * 294 * 1/ whitespace 295 * 2/ alphanumeric chars, + underscore 296 * 3/ others 297 */ 298 static int 299 c_to_class(Char ch) 300 { 301 if (Isspace(ch)) 302 return C_CLASS_WHITE; 303 304 if (isword(ch)) 305 return C_CLASS_WORD; 306 307 return C_CLASS_OTHER; 308 } 309 310 static Char * 311 c_prev_word(Char *p, Char *low, int n) 312 { 313 p--; 314 315 if (!VImode) { 316 while (n--) { 317 while ((p >= low) && !isword(*p)) 318 p--; 319 while ((p >= low) && isword(*p)) 320 p--; 321 } 322 323 /* cp now points to one character before the word */ 324 p++; 325 if (p < low) 326 p = low; 327 /* cp now points where we want it */ 328 return(p); 329 } 330 331 while (n--) { 332 int c_class; 333 334 if (p < low) 335 break; 336 337 /* scan until beginning of current word (may be all whitespace!) */ 338 c_class = c_to_class(*p); 339 while ((p >= low) && c_class == c_to_class(*p)) 340 p--; 341 342 /* if this was a non_whitespace word, we're ready */ 343 if (c_class != C_CLASS_WHITE) 344 continue; 345 346 /* otherwise, move back to beginning of the word just found */ 347 c_class = c_to_class(*p); 348 while ((p >= low) && c_class == c_to_class(*p)) 349 p--; 350 } 351 352 p++; /* correct overshoot */ 353 354 return (p); 355 } 356 357 static Char * 358 c_next_word(Char *p, Char *high, int n) 359 { 360 if (!VImode) { 361 while (n--) { 362 while ((p < high) && !isword(*p)) 363 p++; 364 while ((p < high) && isword(*p)) 365 p++; 366 } 367 if (p > high) 368 p = high; 369 /* p now points where we want it */ 370 return(p); 371 } 372 373 while (n--) { 374 int c_class; 375 376 if (p >= high) 377 break; 378 379 /* scan until end of current word (may be all whitespace!) */ 380 c_class = c_to_class(*p); 381 while ((p < high) && c_class == c_to_class(*p)) 382 p++; 383 384 /* if this was all whitespace, we're ready */ 385 if (c_class == C_CLASS_WHITE) 386 continue; 387 388 /* if we've found white-space at the end of the word, skip it */ 389 while ((p < high) && c_to_class(*p) == C_CLASS_WHITE) 390 p++; 391 } 392 393 p--; /* correct overshoot */ 394 395 return (p); 396 } 397 398 static Char * 399 c_nexword(Char *p, Char *high, int n) 400 { 401 while (n--) { 402 while ((p < high) && !Isspace(*p)) 403 p++; 404 while ((p < high) && Isspace(*p)) 405 p++; 406 } 407 408 if (p > high) 409 p = high; 410 /* p now points where we want it */ 411 return(p); 412 } 413 414 /* 415 * Expand-History (originally "Magic-Space") code added by 416 * Ray Moody <ray@gibbs.physics.purdue.edu> 417 * this is a neat, but odd, addition. 418 */ 419 420 /* 421 * c_number: Ignore character p points to, return number appearing after that. 422 * A '$' by itself means a big number; "$-" is for negative; '^' means 1. 423 * Return p pointing to last char used. 424 */ 425 426 /* 427 * dval is the number to subtract from for things like $-3 428 */ 429 430 static Char * 431 c_number(Char *p, int *num, int dval) 432 { 433 int i; 434 int sign = 1; 435 436 if (*++p == '^') { 437 *num = 1; 438 return(p); 439 } 440 if (*p == '$') { 441 if (*++p != '-') { 442 *num = INT_MAX; /* Handle $ */ 443 return(--p); 444 } 445 sign = -1; /* Handle $- */ 446 ++p; 447 } 448 for (i = 0; *p >= '0' && *p <= '9'; i = 10 * i + *p++ - '0') 449 continue; 450 *num = (sign < 0 ? dval - i : i); 451 return(--p); 452 } 453 454 /* 455 * excl_expand: There is an excl to be expanded to p -- do the right thing 456 * with it and return a version of p advanced over the expanded stuff. Also, 457 * update tsh_cur and related things as appropriate... 458 */ 459 460 static Char * 461 c_expand(Char *p) 462 { 463 Char *q; 464 struct Hist *h = Histlist.Hnext; 465 struct wordent *l; 466 int i, from, to, dval; 467 int all_dig; 468 int been_once = 0; 469 Char *op = p; 470 Char *buf; 471 size_t buf_len; 472 Char *modbuf; 473 474 buf = NULL; 475 if (!h) 476 goto excl_err; 477 excl_sw: 478 switch (*(q = p + 1)) { 479 480 case '^': 481 buf = expand_lex(&h->Hlex, 1, 1); 482 break; 483 484 case '$': 485 if ((l = (h->Hlex).prev) != 0) 486 buf = expand_lex(l->prev->prev, 0, 0); 487 break; 488 489 case '*': 490 buf = expand_lex(&h->Hlex, 1, INT_MAX); 491 break; 492 493 default: 494 if (been_once) { /* unknown argument */ 495 /* assume it's a modifier, e.g. !foo:h, and get whole cmd */ 496 buf = expand_lex(&h->Hlex, 0, INT_MAX); 497 q -= 2; 498 break; 499 } 500 been_once = 1; 501 502 if (*q == ':') /* short form: !:arg */ 503 --q; 504 505 if (HIST != '\0' && *q != HIST) { 506 /* 507 * Search for a space, tab, or colon. See if we have a number (as 508 * in !1234:xyz). Remember the number. 509 */ 510 for (i = 0, all_dig = 1; 511 *q != ' ' && *q != '\t' && *q != ':' && q < Cursor; q++) { 512 /* 513 * PWP: !-4 is a valid history argument too, therefore the test 514 * is if not a digit, or not a - as the first character. 515 */ 516 if ((*q < '0' || *q > '9') && (*q != '-' || q != p + 1)) 517 all_dig = 0; 518 else if (*q == '-') 519 all_dig = 2;/* we are sneeky about this */ 520 else 521 i = 10 * i + *q - '0'; 522 } 523 --q; 524 525 /* 526 * If we have a number, search for event i. Otherwise, search for 527 * a named event (as in !foo). (In this case, I is the length of 528 * the named event). 529 */ 530 if (all_dig) { 531 if (all_dig == 2) 532 i = -i; /* make it negitive */ 533 if (i < 0) /* if !-4 (for example) */ 534 i = eventno + 1 + i; /* remember: i is < 0 */ 535 for (; h; h = h->Hnext) { 536 if (h->Hnum == i) 537 break; 538 } 539 } 540 else { 541 for (i = (int) (q - p); h; h = h->Hnext) { 542 if ((l = &h->Hlex) != 0) { 543 if (!Strncmp(p + 1, l->next->word, (size_t) i)) 544 break; 545 } 546 } 547 } 548 } 549 if (!h) 550 goto excl_err; 551 if (q[1] == ':' || q[1] == '-' || q[1] == '*' || 552 q[1] == '$' || q[1] == '^') { /* get some args */ 553 p = q[1] == ':' ? ++q : q; 554 /* 555 * Go handle !foo:* 556 */ 557 if ((q[1] < '0' || q[1] > '9') && 558 q[1] != '-' && q[1] != '$' && q[1] != '^') 559 goto excl_sw; 560 /* 561 * Go handle !foo:$ 562 */ 563 if (q[1] == '$' && (q[2] != '-' || q[3] < '0' || q[3] > '9')) 564 goto excl_sw; 565 /* 566 * Count up the number of words in this event. Store it in dval. 567 * Dval will be fed to number. 568 */ 569 dval = 0; 570 if ((l = h->Hlex.prev) != 0) { 571 for (l = l->prev; l != h->Hlex.next; l = l->prev, dval++) 572 continue; 573 } 574 if (!dval) 575 goto excl_err; 576 if (q[1] == '-') 577 from = 0; 578 else 579 q = c_number(q, &from, dval); 580 if (q[1] == '-') { 581 ++q; 582 if ((q[1] < '0' || q[1] > '9') && q[1] != '$') 583 to = dval - 1; 584 else 585 q = c_number(q, &to, dval); 586 } 587 else if (q[1] == '*') { 588 ++q; 589 to = INT_MAX; 590 } 591 else { 592 to = from; 593 } 594 if (from < 0 || to < from) 595 goto excl_err; 596 buf = expand_lex(&h->Hlex, from, to); 597 } 598 else /* get whole cmd */ 599 buf = expand_lex(&h->Hlex, 0, INT_MAX); 600 break; 601 } 602 if (buf == NULL) 603 buf = SAVE(""); 604 605 /* 606 * Apply modifiers, if any. 607 */ 608 if (q[1] == ':') { 609 modbuf = buf; 610 while (q[1] == ':' && modbuf != NULL) { 611 switch (q[2]) { 612 case 'r': 613 case 'e': 614 case 'h': 615 case 't': 616 case 'q': 617 case 'x': 618 case 'u': 619 case 'l': 620 if ((modbuf = domod(buf, (int) q[2])) != NULL) { 621 xfree(buf); 622 buf = modbuf; 623 } 624 ++q; 625 break; 626 627 case 'a': 628 case 'g': 629 /* Not implemented; this needs to be done before expanding 630 * lex. We don't have the words available to us anymore. 631 */ 632 ++q; 633 break; 634 635 case 'p': 636 /* Ok */ 637 ++q; 638 break; 639 640 case '\0': 641 break; 642 643 default: 644 ++q; 645 break; 646 } 647 if (q[1]) 648 ++q; 649 } 650 } 651 652 buf_len = Strlen(buf); 653 /* 654 * Now replace the text from op to q inclusive with the text from buf. 655 */ 656 q++; 657 658 /* 659 * Now replace text non-inclusively like a real CS major! 660 */ 661 if (LastChar + buf_len - (q - op) >= InputLim) 662 goto excl_err; 663 (void) memmove(op + buf_len, q, (LastChar - q) * sizeof(Char)); 664 LastChar += buf_len - (q - op); 665 Cursor += buf_len - (q - op); 666 (void) memcpy(op, buf, buf_len * sizeof(Char)); 667 *LastChar = '\0'; 668 xfree(buf); 669 return op + buf_len; 670 excl_err: 671 xfree(buf); 672 SoundBeep(); 673 return(op + 1); 674 } 675 676 /* 677 * c_excl: An excl has been found at point p -- back up and find some white 678 * space (or the beginning of the buffer) and properly expand all the excl's 679 * from there up to the current cursor position. We also avoid (trying to) 680 * expanding '>!' 681 * Returns number of expansions attempted (doesn't matter whether they succeeded 682 * or not). 683 */ 684 685 static int 686 c_excl(Char *p) 687 { 688 int i; 689 Char *q; 690 int nr_exp; 691 692 /* 693 * if />[SPC TAB]*![SPC TAB]/, back up p to just after the >. otherwise, 694 * back p up to just before the current word. 695 */ 696 if ((p[1] == ' ' || p[1] == '\t') && 697 (p[-1] == ' ' || p[-1] == '\t' || p[-1] == '>')) { 698 for (q = p - 1; q > InputBuf && (*q == ' ' || *q == '\t'); --q) 699 continue; 700 if (*q == '>') 701 ++p; 702 } 703 else { 704 while (*p != ' ' && *p != '\t' && p > InputBuf) 705 --p; 706 } 707 708 /* 709 * Forever: Look for history char. (Stop looking when we find the cursor.) 710 * Count backslashes. If odd, skip history char. Expand if even number of 711 * backslashes. 712 */ 713 nr_exp = 0; 714 for (;;) { 715 if (HIST != '\0') 716 while (*p != HIST && p < Cursor) 717 ++p; 718 for (i = 1; (p - i) >= InputBuf && p[-i] == '\\'; i++) 719 continue; 720 if (i % 2 == 0) 721 ++p; 722 if (p >= Cursor) /* all done */ 723 return nr_exp; 724 if (i % 2 == 1) { 725 p = c_expand(p); 726 ++nr_exp; 727 } 728 } 729 } 730 731 732 static int 733 c_substitute(void) 734 { 735 Char *p; 736 int nr_exp; 737 738 /* 739 * Start p out one character before the cursor. Move it backwards looking 740 * for white space, the beginning of the line, or a history character. 741 */ 742 for (p = Cursor - 1; 743 p > InputBuf && *p != ' ' && *p != '\t' && *p && *p != HIST; --p) 744 continue; 745 746 /* 747 * If we found a history character, go expand it. 748 */ 749 if (p >= InputBuf && HIST != '\0' && *p == HIST) 750 nr_exp = c_excl(p); 751 else 752 nr_exp = 0; 753 Refresh(); 754 755 return nr_exp; 756 } 757 758 static void 759 c_delfini(void) /* Finish up delete action */ 760 { 761 int Size; 762 763 if (ActionFlag & TCSHOP_INSERT) 764 c_alternativ_key_map(0); 765 766 ActionFlag = TCSHOP_NOP; 767 768 if (ActionPos == 0) 769 return; 770 771 UndoAction = TCSHOP_INSERT; 772 773 if (Cursor > ActionPos) { 774 Size = (int) (Cursor-ActionPos); 775 c_delbefore(Size); 776 RefCursor(); 777 } 778 else if (Cursor < ActionPos) { 779 Size = (int)(ActionPos-Cursor); 780 c_delafter(Size); 781 } 782 else { 783 Size = 1; 784 c_delafter(Size); 785 } 786 UndoPtr = Cursor; 787 UndoSize = Size; 788 } 789 790 static Char * 791 c_endword(Char *p, Char *high, int n, Char *delim) 792 { 793 Char inquote = 0; 794 p++; 795 796 while (n--) { 797 while (p < high) { /* Skip non-word chars */ 798 if (!Strchr(delim, *p) || p[-1] == (Char)'\\') 799 break; 800 p++; 801 } 802 while (p < high) { /* Skip string */ 803 if ((*p == (Char)'\'' || *p == (Char)'"')) { /* Quotation marks? */ 804 if (inquote || p[-1] != (Char)'\\') { /* Should it be honored? */ 805 if (inquote == 0) inquote = *p; 806 else if (inquote == *p) inquote = 0; 807 } 808 } 809 /* Break if unquoted non-word char */ 810 if (!inquote && Strchr(delim, *p) && p[-1] != (Char)'\\') 811 break; 812 p++; 813 } 814 } 815 816 p--; 817 return(p); 818 } 819 820 821 static Char * 822 c_eword(Char *p, Char *high, int n) 823 { 824 p++; 825 826 while (n--) { 827 int c_class; 828 829 if (p >= high) 830 break; 831 832 /* scan until end of current word (may be all whitespace!) */ 833 c_class = c_to_class(*p); 834 while ((p < high) && c_class == c_to_class(*p)) 835 p++; 836 837 /* if this was a non_whitespace word, we're ready */ 838 if (c_class != C_CLASS_WHITE) 839 continue; 840 841 /* otherwise, move to the end of the word just found */ 842 c_class = c_to_class(*p); 843 while ((p < high) && c_class == c_to_class(*p)) 844 p++; 845 } 846 847 p--; 848 return(p); 849 } 850 851 /* Set the max length of the kill ring */ 852 void 853 SetKillRing(int max) 854 { 855 CStr *new; 856 int count, i, j; 857 858 if (max < 1) 859 max = 1; /* no ring, but always one buffer */ 860 if (max == KillRingMax) 861 return; 862 new = xcalloc(max, sizeof(CStr)); 863 if (KillRing != NULL) { 864 if (KillRingLen != 0) { 865 if (max >= KillRingLen) { 866 count = KillRingLen; 867 j = KillPos; 868 } else { 869 count = max; 870 j = (KillPos - count + KillRingLen) % KillRingLen; 871 } 872 for (i = 0; i < KillRingLen; i++) { 873 if (i < count) /* copy latest */ 874 new[i] = KillRing[j]; 875 else /* free the others */ 876 xfree(KillRing[j].buf); 877 j = (j + 1) % KillRingLen; 878 } 879 KillRingLen = count; 880 KillPos = count % max; 881 YankPos = count - 1; 882 } 883 xfree(KillRing); 884 } 885 KillRing = new; 886 KillRingMax = max; 887 } 888 889 /* Push string from start upto (but not including) end onto kill ring */ 890 static void 891 c_push_kill(Char *start, Char *end) 892 { 893 CStr save, *pos; 894 Char *dp, *cp, *kp; 895 int len = end - start, i, j, k; 896 897 /* Check for duplicates? */ 898 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) { 899 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen; 900 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */ 901 j = YankPos; 902 for (i = 0; i < KillRingLen; i++) { 903 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 && 904 KillRing[j].buf[len] == '\0') { 905 save = KillRing[j]; 906 for ( ; i > 0; i--) { 907 k = j; 908 j = (j + 1) % KillRingLen; 909 KillRing[k] = KillRing[j]; 910 } 911 KillRing[j] = save; 912 return; 913 } 914 j = (j - 1 + KillRingLen) % KillRingLen; 915 } 916 } else if (eq(dp, STRall)) { /* skip if any earlier */ 917 for (i = 0; i < KillRingLen; i++) 918 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 && 919 KillRing[i].buf[len] == '\0') 920 return; 921 } else if (eq(dp, STRprev)) { /* skip if immediately previous */ 922 j = YankPos; 923 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 && 924 KillRing[j].buf[len] == '\0') 925 return; 926 } 927 } 928 929 /* No duplicate, go ahead and push */ 930 len++; /* need space for '\0' */ 931 YankPos = KillPos; 932 if (KillRingLen < KillRingMax) 933 KillRingLen++; 934 pos = &KillRing[KillPos]; 935 KillPos = (KillPos + 1) % KillRingMax; 936 if (pos->len < len) { 937 pos->buf = xrealloc(pos->buf, len * sizeof(Char)); 938 pos->len = len; 939 } 940 cp = start; 941 kp = pos->buf; 942 while (cp < end) 943 *kp++ = *cp++; 944 *kp = '\0'; 945 } 946 947 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */ 948 static void 949 c_save_inputbuf(void) 950 { 951 SavedBuf.len = 0; 952 Strbuf_append(&SavedBuf, InputBuf); 953 Strbuf_terminate(&SavedBuf); 954 LastSaved = LastChar - InputBuf; 955 CursSaved = Cursor - InputBuf; 956 HistSaved = Hist_num; 957 RestoreSaved = 1; 958 } 959 960 CCRETVAL 961 GetHistLine(void) 962 { 963 struct Hist *hp; 964 int h; 965 966 if (Hist_num == 0) { /* if really the current line */ 967 if (HistBuf.s != NULL) 968 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/ 969 else 970 *InputBuf = '\0'; 971 LastChar = InputBuf + HistBuf.len; 972 973 #ifdef KSHVI 974 if (VImode) 975 Cursor = InputBuf; 976 else 977 #endif /* KSHVI */ 978 Cursor = LastChar; 979 980 return(CC_REFRESH); 981 } 982 983 hp = Histlist.Hnext; 984 if (hp == NULL) 985 return(CC_ERROR); 986 987 for (h = 1; h < Hist_num; h++) { 988 if ((hp->Hnext) == NULL) { 989 Hist_num = h; 990 return(CC_ERROR); 991 } 992 hp = hp->Hnext; 993 } 994 995 if (HistLit && hp->histline) { 996 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/ 997 CurrentHistLit = 1; 998 } 999 else { 1000 Char *p; 1001 1002 p = sprlex(&hp->Hlex); 1003 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/ 1004 xfree(p); 1005 CurrentHistLit = 0; 1006 } 1007 LastChar = Strend(InputBuf); 1008 1009 if (LastChar > InputBuf) { 1010 if (LastChar[-1] == '\n') 1011 LastChar--; 1012 #if 0 1013 if (LastChar[-1] == ' ') 1014 LastChar--; 1015 #endif 1016 if (LastChar < InputBuf) 1017 LastChar = InputBuf; 1018 } 1019 1020 #ifdef KSHVI 1021 if (VImode) 1022 Cursor = InputBuf; 1023 else 1024 #endif /* KSHVI */ 1025 Cursor = LastChar; 1026 1027 return(CC_REFRESH); 1028 } 1029 1030 static CCRETVAL 1031 c_search_line(Char *pattern, int dir) 1032 { 1033 Char *cp; 1034 size_t len; 1035 1036 len = Strlen(pattern); 1037 1038 if (dir == F_UP_SEARCH_HIST) { 1039 for (cp = Cursor; cp >= InputBuf; cp--) 1040 if (Strncmp(cp, pattern, len) == 0 || 1041 Gmatch(cp, pattern)) { 1042 Cursor = cp; 1043 return(CC_NORM); 1044 } 1045 return(CC_ERROR); 1046 } else { 1047 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++) 1048 if (Strncmp(cp, pattern, len) == 0 || 1049 Gmatch(cp, pattern)) { 1050 Cursor = cp; 1051 return(CC_NORM); 1052 } 1053 return(CC_ERROR); 1054 } 1055 } 1056 1057 static CCRETVAL 1058 e_inc_search(int dir) 1059 { 1060 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' }, 1061 STRbck[] = { 'b', 'c', 'k', '\0' }; 1062 static Char pchar = ':'; /* ':' = normal, '?' = failed */ 1063 static Char endcmd[2]; 1064 const Char *cp; 1065 Char ch, 1066 *oldCursor = Cursor, 1067 oldpchar = pchar; 1068 CCRETVAL ret = CC_NORM; 1069 int oldHist_num = Hist_num, 1070 oldpatlen = patbuf.len, 1071 newdir = dir, 1072 done, redo; 1073 1074 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim) 1075 return(CC_ERROR); 1076 1077 for (;;) { 1078 1079 if (patbuf.len == 0) { /* first round */ 1080 pchar = ':'; 1081 Strbuf_append1(&patbuf, '*'); 1082 } 1083 done = redo = 0; 1084 *LastChar++ = '\n'; 1085 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd; 1086 *cp; *LastChar++ = *cp++) 1087 continue; 1088 *LastChar++ = pchar; 1089 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len]; 1090 *LastChar++ = *cp++) 1091 continue; 1092 *LastChar = '\0'; 1093 if (adrof(STRhighlight) && pchar == ':') { 1094 /* if the no-glob-search patch is applied, remove the - 1 below */ 1095 IncMatchLen = patbuf.len - 1; 1096 ClearLines(); 1097 ClearDisp(); 1098 } 1099 Refresh(); 1100 1101 if (GetNextChar(&ch) != 1) 1102 return(e_send_eof(0)); 1103 1104 switch (GetCmdChar(ch)) { 1105 case F_INSERT: 1106 case F_DIGIT: 1107 case F_MAGIC_SPACE: 1108 if (LastChar + 1 >= InputLim) /*FIXBUF*/ 1109 SoundBeep(); 1110 else { 1111 Strbuf_append1(&patbuf, ch); 1112 *LastChar++ = ch; 1113 *LastChar = '\0'; 1114 Refresh(); 1115 } 1116 break; 1117 1118 case F_INC_FWD: 1119 newdir = F_DOWN_SEARCH_HIST; 1120 redo++; 1121 break; 1122 1123 case F_INC_BACK: 1124 newdir = F_UP_SEARCH_HIST; 1125 redo++; 1126 break; 1127 1128 case F_DELPREV: 1129 if (patbuf.len > 1) 1130 done++; 1131 else 1132 SoundBeep(); 1133 break; 1134 1135 default: 1136 switch (ASC(ch)) { 1137 case 0007: /* ^G: Abort */ 1138 ret = CC_ERROR; 1139 done++; 1140 break; 1141 1142 case 0027: /* ^W: Append word */ 1143 /* No can do if globbing characters in pattern */ 1144 for (cp = &patbuf.s[1]; ; cp++) 1145 if (cp >= &patbuf.s[patbuf.len]) { 1146 Cursor += patbuf.len - 1; 1147 cp = c_next_word(Cursor, LastChar, 1); 1148 while (Cursor < cp && *Cursor != '\n') { 1149 if (LastChar + 1 >= InputLim) {/*FIXBUF*/ 1150 SoundBeep(); 1151 break; 1152 } 1153 Strbuf_append1(&patbuf, *Cursor); 1154 *LastChar++ = *Cursor++; 1155 } 1156 Cursor = oldCursor; 1157 *LastChar = '\0'; 1158 Refresh(); 1159 break; 1160 } else if (isglob(*cp)) { 1161 SoundBeep(); 1162 break; 1163 } 1164 break; 1165 1166 default: /* Terminate and execute cmd */ 1167 endcmd[0] = ch; 1168 PushMacro(endcmd); 1169 /*FALLTHROUGH*/ 1170 1171 case 0033: /* ESC: Terminate */ 1172 ret = CC_REFRESH; 1173 done++; 1174 break; 1175 } 1176 break; 1177 } 1178 1179 while (LastChar > InputBuf && *LastChar != '\n') 1180 *LastChar-- = '\0'; 1181 *LastChar = '\0'; 1182 1183 if (!done) { 1184 1185 /* Can't search if unmatched '[' */ 1186 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--) 1187 if (*cp == '[' || *cp == ']') { 1188 ch = *cp; 1189 break; 1190 } 1191 1192 if (patbuf.len > 1 && ch != '[') { 1193 if (redo && newdir == dir) { 1194 if (pchar == '?') { /* wrap around */ 1195 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX; 1196 if (GetHistLine() == CC_ERROR) 1197 /* Hist_num was fixed by first call */ 1198 (void) GetHistLine(); 1199 Cursor = newdir == F_UP_SEARCH_HIST ? 1200 LastChar : InputBuf; 1201 } else 1202 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1; 1203 } 1204 Strbuf_append1(&patbuf, '*'); 1205 Strbuf_terminate(&patbuf); 1206 if (Cursor < InputBuf || Cursor > LastChar || 1207 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) { 1208 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */ 1209 ret = newdir == F_UP_SEARCH_HIST ? 1210 e_up_search_hist(0) : e_down_search_hist(0); 1211 if (ret != CC_ERROR) { 1212 Cursor = newdir == F_UP_SEARCH_HIST ? 1213 LastChar : InputBuf; 1214 (void) c_search_line(&patbuf.s[1], newdir); 1215 } 1216 } 1217 patbuf.s[--patbuf.len] = '\0'; 1218 if (ret == CC_ERROR) { 1219 SoundBeep(); 1220 if (Hist_num != oldHist_num) { 1221 Hist_num = oldHist_num; 1222 if (GetHistLine() == CC_ERROR) 1223 return(CC_ERROR); 1224 } 1225 Cursor = oldCursor; 1226 pchar = '?'; 1227 } else { 1228 pchar = ':'; 1229 } 1230 } 1231 1232 ret = e_inc_search(newdir); 1233 1234 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') { 1235 /* break abort of failed search at last non-failed */ 1236 ret = CC_NORM; 1237 } 1238 1239 } 1240 1241 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) { 1242 /* restore on normal return or error exit */ 1243 pchar = oldpchar; 1244 patbuf.len = oldpatlen; 1245 if (Hist_num != oldHist_num) { 1246 Hist_num = oldHist_num; 1247 if (GetHistLine() == CC_ERROR) 1248 return(CC_ERROR); 1249 } 1250 Cursor = oldCursor; 1251 if (ret == CC_ERROR) 1252 Refresh(); 1253 } 1254 if (done || ret != CC_NORM) 1255 return(ret); 1256 1257 } 1258 1259 } 1260 1261 static CCRETVAL 1262 v_search(int dir) 1263 { 1264 struct Strbuf tmpbuf = Strbuf_INIT; 1265 Char ch; 1266 Char *oldbuf; 1267 Char *oldlc, *oldc; 1268 1269 cleanup_push(&tmpbuf, Strbuf_cleanup); 1270 oldbuf = Strsave(InputBuf); 1271 cleanup_push(oldbuf, xfree); 1272 oldlc = LastChar; 1273 oldc = Cursor; 1274 Strbuf_append1(&tmpbuf, '*'); 1275 1276 InputBuf[0] = '\0'; 1277 LastChar = InputBuf; 1278 Cursor = InputBuf; 1279 searchdir = dir; 1280 1281 c_insert(2); /* prompt + '\n' */ 1282 *Cursor++ = '\n'; 1283 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/'; 1284 Refresh(); 1285 for (ch = 0;ch == 0;) { 1286 if (GetNextChar(&ch) != 1) { 1287 cleanup_until(&tmpbuf); 1288 return(e_send_eof(0)); 1289 } 1290 switch (ASC(ch)) { 1291 case 0010: /* Delete and backspace */ 1292 case 0177: 1293 if (tmpbuf.len > 1) { 1294 *Cursor-- = '\0'; 1295 LastChar = Cursor; 1296 tmpbuf.len--; 1297 } 1298 else { 1299 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/ 1300 LastChar = oldlc; 1301 Cursor = oldc; 1302 cleanup_until(&tmpbuf); 1303 return(CC_REFRESH); 1304 } 1305 Refresh(); 1306 ch = 0; 1307 break; 1308 1309 case 0033: /* ESC */ 1310 #ifdef IS_ASCII 1311 case '\r': /* Newline */ 1312 case '\n': 1313 #else 1314 case '\012': /* ASCII Line feed */ 1315 case '\015': /* ASCII (or EBCDIC) Return */ 1316 #endif 1317 break; 1318 1319 default: 1320 Strbuf_append1(&tmpbuf, ch); 1321 *Cursor++ = ch; 1322 LastChar = Cursor; 1323 Refresh(); 1324 ch = 0; 1325 break; 1326 } 1327 } 1328 cleanup_until(oldbuf); 1329 1330 if (tmpbuf.len == 1) { 1331 /* 1332 * Use the old pattern, but wild-card it. 1333 */ 1334 if (patbuf.len == 0) { 1335 InputBuf[0] = '\0'; 1336 LastChar = InputBuf; 1337 Cursor = InputBuf; 1338 Refresh(); 1339 cleanup_until(&tmpbuf); 1340 return(CC_ERROR); 1341 } 1342 if (patbuf.s[0] != '*') { 1343 oldbuf = Strsave(patbuf.s); 1344 patbuf.len = 0; 1345 Strbuf_append1(&patbuf, '*'); 1346 Strbuf_append(&patbuf, oldbuf); 1347 xfree(oldbuf); 1348 Strbuf_append1(&patbuf, '*'); 1349 Strbuf_terminate(&patbuf); 1350 } 1351 } 1352 else { 1353 Strbuf_append1(&tmpbuf, '*'); 1354 Strbuf_terminate(&tmpbuf); 1355 patbuf.len = 0; 1356 Strbuf_append(&patbuf, tmpbuf.s); 1357 Strbuf_terminate(&patbuf); 1358 } 1359 cleanup_until(&tmpbuf); 1360 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */ 1361 Cursor = LastChar = InputBuf; 1362 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) : 1363 e_down_search_hist(0)) == CC_ERROR) { 1364 Refresh(); 1365 return(CC_ERROR); 1366 } 1367 else { 1368 if (ASC(ch) == 0033) { 1369 Refresh(); 1370 *LastChar++ = '\n'; 1371 *LastChar = '\0'; 1372 PastBottom(); 1373 return(CC_NEWLINE); 1374 } 1375 else 1376 return(CC_REFRESH); 1377 } 1378 } 1379 1380 /* 1381 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an 1382 * entry point, called from the CcKeyMap indirected into the 1383 * CcFuncTbl array. 1384 */ 1385 1386 /*ARGSUSED*/ 1387 CCRETVAL 1388 v_cmd_mode(Char c) 1389 { 1390 USE(c); 1391 InsertPos = 0; 1392 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */ 1393 ActionPos = 0; 1394 DoingArg = 0; 1395 if (UndoPtr > Cursor) 1396 UndoSize = (int)(UndoPtr - Cursor); 1397 else 1398 UndoSize = (int)(Cursor - UndoPtr); 1399 1400 inputmode = MODE_INSERT; 1401 c_alternativ_key_map(1); 1402 #ifdef notdef 1403 /* 1404 * We don't want to move the cursor, because all the editing 1405 * commands don't include the character under the cursor. 1406 */ 1407 if (Cursor > InputBuf) 1408 Cursor--; 1409 #endif 1410 RefCursor(); 1411 return(CC_NORM); 1412 } 1413 1414 /*ARGSUSED*/ 1415 CCRETVAL 1416 e_unassigned(Char c) 1417 { /* bound to keys that arn't really assigned */ 1418 USE(c); 1419 SoundBeep(); 1420 flush(); 1421 return(CC_NORM); 1422 } 1423 1424 #ifdef notyet 1425 static CCRETVAL 1426 e_insert_str(Char *c) 1427 { 1428 int i, n; 1429 1430 n = Strlen(c); 1431 if (LastChar + Argument * n >= InputLim) 1432 return(CC_ERROR); /* end of buffer space */ 1433 if (inputmode != MODE_INSERT) { 1434 c_delafter(Argument * Strlen(c)); 1435 } 1436 c_insert(Argument * n); 1437 while (Argument--) { 1438 for (i = 0; i < n; i++) 1439 *Cursor++ = c[i]; 1440 } 1441 Refresh(); 1442 return(CC_NORM); 1443 } 1444 #endif 1445 1446 CCRETVAL 1447 e_insert(Char c) 1448 { 1449 #ifndef SHORT_STRINGS 1450 c &= ASCII; /* no meta chars ever */ 1451 #endif 1452 1453 if (!c) 1454 return(CC_ERROR); /* no NULs in the input ever!! */ 1455 1456 if (LastChar + Argument >= InputLim) 1457 return(CC_ERROR); /* end of buffer space */ 1458 1459 if (Argument == 1) { /* How was this optimized ???? */ 1460 1461 if (inputmode != MODE_INSERT) { 1462 UndoBuf[UndoSize++] = *Cursor; 1463 UndoBuf[UndoSize] = '\0'; 1464 c_delafter(1); /* Do NOT use the saving ONE */ 1465 } 1466 1467 c_insert(1); 1468 *Cursor++ = (Char) c; 1469 DoingArg = 0; /* just in case */ 1470 RefPlusOne(1); /* fast refresh for one char. */ 1471 } 1472 else { 1473 if (inputmode != MODE_INSERT) { 1474 int i; 1475 for (i = 0; i < Argument; i++) 1476 UndoBuf[UndoSize++] = Cursor[i]; 1477 1478 UndoBuf[UndoSize] = '\0'; 1479 c_delafter(Argument); /* Do NOT use the saving ONE */ 1480 } 1481 1482 c_insert(Argument); 1483 1484 while (Argument--) 1485 *Cursor++ = (Char) c; 1486 Refresh(); 1487 } 1488 1489 if (inputmode == MODE_REPLACE_1) 1490 (void) v_cmd_mode(0); 1491 1492 return(CC_NORM); 1493 } 1494 1495 int 1496 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */ 1497 { 1498 int len; 1499 1500 if ((len = (int) Strlen(s)) <= 0) 1501 return -1; 1502 if (LastChar + len >= InputLim) 1503 return -1; /* end of buffer space */ 1504 1505 c_insert(len); 1506 while (len--) 1507 *Cursor++ = *s++; 1508 return 0; 1509 } 1510 1511 void 1512 DeleteBack(int n) /* delete the n characters before . */ 1513 { 1514 if (n <= 0) 1515 return; 1516 if (Cursor >= &InputBuf[n]) { 1517 c_delbefore(n); /* delete before dot */ 1518 } 1519 } 1520 1521 CCRETVAL 1522 e_digit(Char c) /* gray magic here */ 1523 { 1524 if (!Isdigit(c)) 1525 return(CC_ERROR); /* no NULs in the input ever!! */ 1526 1527 if (DoingArg) { /* if doing an arg, add this in... */ 1528 if (LastCmd == F_ARGFOUR) /* if last command was ^U */ 1529 Argument = c - '0'; 1530 else { 1531 if (Argument > 1000000) 1532 return CC_ERROR; 1533 Argument = (Argument * 10) + (c - '0'); 1534 } 1535 return(CC_ARGHACK); 1536 } 1537 else { 1538 if (LastChar + 1 >= InputLim) 1539 return CC_ERROR; /* end of buffer space */ 1540 1541 if (inputmode != MODE_INSERT) { 1542 UndoBuf[UndoSize++] = *Cursor; 1543 UndoBuf[UndoSize] = '\0'; 1544 c_delafter(1); /* Do NOT use the saving ONE */ 1545 } 1546 c_insert(1); 1547 *Cursor++ = (Char) c; 1548 DoingArg = 0; /* just in case */ 1549 RefPlusOne(1); /* fast refresh for one char. */ 1550 } 1551 return(CC_NORM); 1552 } 1553 1554 CCRETVAL 1555 e_argdigit(Char c) /* for ESC-n */ 1556 { 1557 #ifdef IS_ASCII 1558 c &= ASCII; 1559 #else 1560 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */ 1561 #endif 1562 1563 if (!Isdigit(c)) 1564 return(CC_ERROR); /* no NULs in the input ever!! */ 1565 1566 if (DoingArg) { /* if doing an arg, add this in... */ 1567 if (Argument > 1000000) 1568 return CC_ERROR; 1569 Argument = (Argument * 10) + (c - '0'); 1570 } 1571 else { /* else starting an argument */ 1572 Argument = c - '0'; 1573 DoingArg = 1; 1574 } 1575 return(CC_ARGHACK); 1576 } 1577 1578 CCRETVAL 1579 v_zero(Char c) /* command mode 0 for vi */ 1580 { 1581 if (DoingArg) { /* if doing an arg, add this in... */ 1582 if (Argument > 1000000) 1583 return CC_ERROR; 1584 Argument = (Argument * 10) + (c - '0'); 1585 return(CC_ARGHACK); 1586 } 1587 else { /* else starting an argument */ 1588 Cursor = InputBuf; 1589 if (ActionFlag & TCSHOP_DELETE) { 1590 c_delfini(); 1591 return(CC_REFRESH); 1592 } 1593 RefCursor(); /* move the cursor */ 1594 return(CC_NORM); 1595 } 1596 } 1597 1598 /*ARGSUSED*/ 1599 CCRETVAL 1600 e_newline(Char c) 1601 { /* always ignore argument */ 1602 USE(c); 1603 if (adrof(STRhighlight) && MarkIsSet) { 1604 MarkIsSet = 0; 1605 ClearLines(); 1606 ClearDisp(); 1607 Refresh(); 1608 } 1609 MarkIsSet = 0; 1610 1611 /* PastBottom(); NOW done in ed.inputl.c */ 1612 *LastChar++ = '\n'; /* for the benefit of CSH */ 1613 *LastChar = '\0'; /* just in case */ 1614 if (VImode) 1615 InsertPos = InputBuf; /* Reset editing position */ 1616 return(CC_NEWLINE); 1617 } 1618 1619 /*ARGSUSED*/ 1620 CCRETVAL 1621 e_newline_hold(Char c) 1622 { 1623 USE(c); 1624 c_save_inputbuf(); 1625 HistSaved = 0; 1626 *LastChar++ = '\n'; /* for the benefit of CSH */ 1627 *LastChar = '\0'; /* just in case */ 1628 return(CC_NEWLINE); 1629 } 1630 1631 /*ARGSUSED*/ 1632 CCRETVAL 1633 e_newline_down_hist(Char c) 1634 { 1635 USE(c); 1636 if (Hist_num > 1) { 1637 HistSaved = Hist_num; 1638 } 1639 *LastChar++ = '\n'; /* for the benefit of CSH */ 1640 *LastChar = '\0'; /* just in case */ 1641 return(CC_NEWLINE); 1642 } 1643 1644 /*ARGSUSED*/ 1645 CCRETVAL 1646 e_send_eof(Char c) 1647 { /* for when ^D is ONLY send-eof */ 1648 USE(c); 1649 PastBottom(); 1650 *LastChar = '\0'; /* just in case */ 1651 return(CC_EOF); 1652 } 1653 1654 /*ARGSUSED*/ 1655 CCRETVAL 1656 e_complete(Char c) 1657 { 1658 USE(c); 1659 *LastChar = '\0'; /* just in case */ 1660 return(CC_COMPLETE); 1661 } 1662 1663 /*ARGSUSED*/ 1664 CCRETVAL 1665 e_complete_back(Char c) 1666 { 1667 USE(c); 1668 *LastChar = '\0'; /* just in case */ 1669 return(CC_COMPLETE_BACK); 1670 } 1671 1672 /*ARGSUSED*/ 1673 CCRETVAL 1674 e_complete_fwd(Char c) 1675 { 1676 USE(c); 1677 *LastChar = '\0'; /* just in case */ 1678 return(CC_COMPLETE_FWD); 1679 } 1680 1681 /*ARGSUSED*/ 1682 CCRETVAL 1683 e_complete_all(Char c) 1684 { 1685 USE(c); 1686 *LastChar = '\0'; /* just in case */ 1687 return(CC_COMPLETE_ALL); 1688 } 1689 1690 /*ARGSUSED*/ 1691 CCRETVAL 1692 v_cm_complete(Char c) 1693 { 1694 USE(c); 1695 if (Cursor < LastChar) 1696 Cursor++; 1697 *LastChar = '\0'; /* just in case */ 1698 return(CC_COMPLETE); 1699 } 1700 1701 /*ARGSUSED*/ 1702 CCRETVAL 1703 e_toggle_hist(Char c) 1704 { 1705 struct Hist *hp; 1706 int h; 1707 1708 USE(c); 1709 *LastChar = '\0'; /* just in case */ 1710 1711 if (Hist_num <= 0) { 1712 return CC_ERROR; 1713 } 1714 1715 hp = Histlist.Hnext; 1716 if (hp == NULL) { /* this is only if no history */ 1717 return(CC_ERROR); 1718 } 1719 1720 for (h = 1; h < Hist_num; h++) 1721 hp = hp->Hnext; 1722 1723 if (!CurrentHistLit) { 1724 if (hp->histline) { 1725 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/ 1726 CurrentHistLit = 1; 1727 } 1728 else { 1729 return CC_ERROR; 1730 } 1731 } 1732 else { 1733 Char *p; 1734 1735 p = sprlex(&hp->Hlex); 1736 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/ 1737 xfree(p); 1738 CurrentHistLit = 0; 1739 } 1740 1741 LastChar = Strend(InputBuf); 1742 if (LastChar > InputBuf) { 1743 if (LastChar[-1] == '\n') 1744 LastChar--; 1745 if (LastChar[-1] == ' ') 1746 LastChar--; 1747 if (LastChar < InputBuf) 1748 LastChar = InputBuf; 1749 } 1750 1751 #ifdef KSHVI 1752 if (VImode) 1753 Cursor = InputBuf; 1754 else 1755 #endif /* KSHVI */ 1756 Cursor = LastChar; 1757 1758 return(CC_REFRESH); 1759 } 1760 1761 /*ARGSUSED*/ 1762 CCRETVAL 1763 e_up_hist(Char c) 1764 { 1765 Char beep = 0; 1766 1767 USE(c); 1768 UndoAction = TCSHOP_NOP; 1769 *LastChar = '\0'; /* just in case */ 1770 1771 if (Hist_num == 0) { /* save the current buffer away */ 1772 HistBuf.len = 0; 1773 Strbuf_append(&HistBuf, InputBuf); 1774 Strbuf_terminate(&HistBuf); 1775 } 1776 1777 Hist_num += Argument; 1778 1779 if (GetHistLine() == CC_ERROR) { 1780 beep = 1; 1781 (void) GetHistLine(); /* Hist_num was fixed by first call */ 1782 } 1783 1784 Refresh(); 1785 if (beep) 1786 return(CC_ERROR); 1787 else 1788 return(CC_NORM); /* was CC_UP_HIST */ 1789 } 1790 1791 /*ARGSUSED*/ 1792 CCRETVAL 1793 e_down_hist(Char c) 1794 { 1795 USE(c); 1796 UndoAction = TCSHOP_NOP; 1797 *LastChar = '\0'; /* just in case */ 1798 1799 Hist_num -= Argument; 1800 1801 if (Hist_num < 0) { 1802 Hist_num = 0; 1803 return(CC_ERROR); /* make it beep */ 1804 } 1805 1806 return(GetHistLine()); 1807 } 1808 1809 1810 1811 /* 1812 * c_hmatch() return True if the pattern matches the prefix 1813 */ 1814 static int 1815 c_hmatch(Char *str) 1816 { 1817 if (Strncmp(patbuf.s, str, patbuf.len) == 0) 1818 return 1; 1819 return Gmatch(str, patbuf.s); 1820 } 1821 1822 /* 1823 * c_hsetpat(): Set the history seatch pattern 1824 */ 1825 static void 1826 c_hsetpat(void) 1827 { 1828 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) { 1829 patbuf.len = 0; 1830 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf); 1831 Strbuf_terminate(&patbuf); 1832 } 1833 #ifdef SDEBUG 1834 xprintf("\nHist_num = %d\n", Hist_num); 1835 xprintf("patlen = %d\n", (int)patbuf.len); 1836 xprintf("patbuf = \"%S\"\n", patbuf.s); 1837 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf); 1838 #endif 1839 } 1840 1841 /*ARGSUSED*/ 1842 CCRETVAL 1843 e_up_search_hist(Char c) 1844 { 1845 struct Hist *hp; 1846 int h; 1847 int found = 0; 1848 1849 USE(c); 1850 ActionFlag = TCSHOP_NOP; 1851 UndoAction = TCSHOP_NOP; 1852 *LastChar = '\0'; /* just in case */ 1853 if (Hist_num < 0) { 1854 #ifdef DEBUG_EDIT 1855 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname); 1856 #endif 1857 Hist_num = 0; 1858 return(CC_ERROR); 1859 } 1860 1861 if (Hist_num == 0) { 1862 HistBuf.len = 0; 1863 Strbuf_append(&HistBuf, InputBuf); 1864 Strbuf_terminate(&HistBuf); 1865 } 1866 1867 1868 hp = Histlist.Hnext; 1869 if (hp == NULL) 1870 return(CC_ERROR); 1871 1872 c_hsetpat(); /* Set search pattern !! */ 1873 1874 for (h = 1; h <= Hist_num; h++) 1875 hp = hp->Hnext; 1876 1877 while (hp != NULL) { 1878 Char *hl; 1879 int matched; 1880 1881 if (hp->histline == NULL) 1882 hp->histline = sprlex(&hp->Hlex); 1883 if (HistLit) 1884 hl = hp->histline; 1885 else { 1886 hl = sprlex(&hp->Hlex); 1887 cleanup_push(hl, xfree); 1888 } 1889 #ifdef SDEBUG 1890 xprintf("Comparing with \"%S\"\n", hl); 1891 #endif 1892 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || 1893 hl[LastChar-InputBuf]) && c_hmatch(hl); 1894 if (!HistLit) 1895 cleanup_until(hl); 1896 if (matched) { 1897 found++; 1898 break; 1899 } 1900 h++; 1901 hp = hp->Hnext; 1902 } 1903 1904 if (!found) { 1905 #ifdef SDEBUG 1906 xprintf("not found\n"); 1907 #endif 1908 return(CC_ERROR); 1909 } 1910 1911 Hist_num = h; 1912 1913 return(GetHistLine()); 1914 } 1915 1916 /*ARGSUSED*/ 1917 CCRETVAL 1918 e_down_search_hist(Char c) 1919 { 1920 struct Hist *hp; 1921 int h; 1922 int found = 0; 1923 1924 USE(c); 1925 ActionFlag = TCSHOP_NOP; 1926 UndoAction = TCSHOP_NOP; 1927 *LastChar = '\0'; /* just in case */ 1928 1929 if (Hist_num == 0) 1930 return(CC_ERROR); 1931 1932 hp = Histlist.Hnext; 1933 if (hp == 0) 1934 return(CC_ERROR); 1935 1936 c_hsetpat(); /* Set search pattern !! */ 1937 1938 for (h = 1; h < Hist_num && hp; h++) { 1939 Char *hl; 1940 if (hp->histline == NULL) 1941 hp->histline = sprlex(&hp->Hlex); 1942 if (HistLit) 1943 hl = hp->histline; 1944 else { 1945 hl = sprlex(&hp->Hlex); 1946 cleanup_push(hl, xfree); 1947 } 1948 #ifdef SDEBUG 1949 xprintf("Comparing with \"%S\"\n", hl); 1950 #endif 1951 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || 1952 hl[LastChar-InputBuf]) && c_hmatch(hl)) 1953 found = h; 1954 if (!HistLit) 1955 cleanup_until(hl); 1956 hp = hp->Hnext; 1957 } 1958 1959 if (!found) { /* is it the current history number? */ 1960 if (!c_hmatch(HistBuf.s)) { 1961 #ifdef SDEBUG 1962 xprintf("not found\n"); 1963 #endif 1964 return(CC_ERROR); 1965 } 1966 } 1967 1968 Hist_num = found; 1969 1970 return(GetHistLine()); 1971 } 1972 1973 /*ARGSUSED*/ 1974 CCRETVAL 1975 e_helpme(Char c) 1976 { 1977 USE(c); 1978 PastBottom(); 1979 *LastChar = '\0'; /* just in case */ 1980 return(CC_HELPME); 1981 } 1982 1983 /*ARGSUSED*/ 1984 CCRETVAL 1985 e_correct(Char c) 1986 { 1987 USE(c); 1988 *LastChar = '\0'; /* just in case */ 1989 return(CC_CORRECT); 1990 } 1991 1992 /*ARGSUSED*/ 1993 CCRETVAL 1994 e_correctl(Char c) 1995 { 1996 USE(c); 1997 *LastChar = '\0'; /* just in case */ 1998 return(CC_CORRECT_L); 1999 } 2000 2001 /*ARGSUSED*/ 2002 CCRETVAL 2003 e_run_fg_editor(Char c) 2004 { 2005 struct process *pp; 2006 2007 USE(c); 2008 if ((pp = find_stop_ed()) != NULL) { 2009 /* save our editor state so we can restore it */ 2010 c_save_inputbuf(); 2011 Hist_num = 0; /* for the history commands */ 2012 2013 /* put the tty in a sane mode */ 2014 PastBottom(); 2015 (void) Cookedmode(); /* make sure the tty is set up correctly */ 2016 2017 /* do it! */ 2018 fg_proc_entry(pp); 2019 2020 (void) Rawmode(); /* go on */ 2021 Refresh(); 2022 RestoreSaved = 0; 2023 HistSaved = 0; 2024 } 2025 return(CC_NORM); 2026 } 2027 2028 /*ARGSUSED*/ 2029 CCRETVAL 2030 e_list_choices(Char c) 2031 { 2032 USE(c); 2033 PastBottom(); 2034 *LastChar = '\0'; /* just in case */ 2035 return(CC_LIST_CHOICES); 2036 } 2037 2038 /*ARGSUSED*/ 2039 CCRETVAL 2040 e_list_all(Char c) 2041 { 2042 USE(c); 2043 PastBottom(); 2044 *LastChar = '\0'; /* just in case */ 2045 return(CC_LIST_ALL); 2046 } 2047 2048 /*ARGSUSED*/ 2049 CCRETVAL 2050 e_list_glob(Char c) 2051 { 2052 USE(c); 2053 PastBottom(); 2054 *LastChar = '\0'; /* just in case */ 2055 return(CC_LIST_GLOB); 2056 } 2057 2058 /*ARGSUSED*/ 2059 CCRETVAL 2060 e_expand_glob(Char c) 2061 { 2062 USE(c); 2063 *LastChar = '\0'; /* just in case */ 2064 return(CC_EXPAND_GLOB); 2065 } 2066 2067 /*ARGSUSED*/ 2068 CCRETVAL 2069 e_normalize_path(Char c) 2070 { 2071 USE(c); 2072 *LastChar = '\0'; /* just in case */ 2073 return(CC_NORMALIZE_PATH); 2074 } 2075 2076 /*ARGSUSED*/ 2077 CCRETVAL 2078 e_normalize_command(Char c) 2079 { 2080 USE(c); 2081 *LastChar = '\0'; /* just in case */ 2082 return(CC_NORMALIZE_COMMAND); 2083 } 2084 2085 /*ARGSUSED*/ 2086 CCRETVAL 2087 e_expand_vars(Char c) 2088 { 2089 USE(c); 2090 *LastChar = '\0'; /* just in case */ 2091 return(CC_EXPAND_VARS); 2092 } 2093 2094 /*ARGSUSED*/ 2095 CCRETVAL 2096 e_which(Char c) 2097 { /* do a fast command line which(1) */ 2098 USE(c); 2099 c_save_inputbuf(); 2100 Hist_num = 0; /* for the history commands */ 2101 PastBottom(); 2102 *LastChar = '\0'; /* just in case */ 2103 return(CC_WHICH); 2104 } 2105 2106 /*ARGSUSED*/ 2107 CCRETVAL 2108 e_last_item(Char c) 2109 { /* insert the last element of the prev. cmd */ 2110 struct Hist *hp; 2111 struct wordent *wp, *firstp; 2112 int i; 2113 Char *expanded; 2114 2115 USE(c); 2116 if (Argument <= 0) 2117 return(CC_ERROR); 2118 2119 hp = Histlist.Hnext; 2120 if (hp == NULL) { /* this is only if no history */ 2121 return(CC_ERROR); 2122 } 2123 2124 wp = (hp->Hlex).prev; 2125 2126 if (wp->prev == (struct wordent *) NULL) 2127 return(CC_ERROR); /* an empty history entry */ 2128 2129 firstp = (hp->Hlex).next; 2130 2131 /* back up arg words in lex */ 2132 for (i = 0; i < Argument && wp != firstp; i++) { 2133 wp = wp->prev; 2134 } 2135 2136 expanded = expand_lex(wp->prev, 0, i - 1); 2137 if (InsertStr(expanded)) { 2138 xfree(expanded); 2139 return(CC_ERROR); 2140 } 2141 2142 xfree(expanded); 2143 return(CC_REFRESH); 2144 } 2145 2146 /*ARGSUSED*/ 2147 CCRETVAL 2148 e_dabbrev_expand(Char c) 2149 { /* expand to preceding word matching prefix */ 2150 Char *cp, *ncp, *bp; 2151 struct Hist *hp; 2152 int arg = 0, i; 2153 size_t len = 0; 2154 int found = 0; 2155 Char *hbuf; 2156 static int oldevent, hist, word; 2157 static Char *start, *oldcursor; 2158 2159 USE(c); 2160 if (Argument <= 0) 2161 return(CC_ERROR); 2162 2163 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep); 2164 if (cp == Cursor || Isspace(*cp)) 2165 return(CC_ERROR); 2166 2167 hbuf = NULL; 2168 hp = Histlist.Hnext; 2169 bp = InputBuf; 2170 if (Argument == 1 && eventno == oldevent && cp == start && 2171 Cursor == oldcursor && patbuf.len > 0 2172 && Strncmp(patbuf.s, cp, patbuf.len) == 0){ 2173 /* continue previous search - go to last match (hist/word) */ 2174 if (hist != 0) { /* need to move up history */ 2175 for (i = 1; i < hist && hp != NULL; i++) 2176 hp = hp->Hnext; 2177 if (hp == NULL) /* "can't happen" */ 2178 goto err_hbuf; 2179 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX); 2180 cp = Strend(hbuf); 2181 bp = hbuf; 2182 hp = hp->Hnext; 2183 } 2184 cp = c_preword(cp, bp, word, STRshwordsep); 2185 } else { /* starting new search */ 2186 oldevent = eventno; 2187 start = cp; 2188 patbuf.len = 0; 2189 Strbuf_appendn(&patbuf, cp, Cursor - cp); 2190 hist = 0; 2191 word = 0; 2192 } 2193 2194 while (!found) { 2195 ncp = c_preword(cp, bp, 1, STRshwordsep); 2196 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */ 2197 hist++; 2198 word = 0; 2199 if (hp == NULL) 2200 goto err_hbuf; 2201 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX); 2202 cp = Strend(hbuf); 2203 bp = hbuf; 2204 hp = hp->Hnext; 2205 continue; 2206 } else { 2207 word++; 2208 len = c_endword(ncp-1, cp, 1, STRshwordsep) - ncp + 1; 2209 cp = ncp; 2210 } 2211 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) { 2212 /* We don't fully check distinct matches as Gnuemacs does: */ 2213 if (Argument > 1) { /* just count matches */ 2214 if (++arg >= Argument) 2215 found++; 2216 } else { /* match if distinct from previous */ 2217 if (len != (size_t)(Cursor - start) 2218 || Strncmp(cp, start, len) != 0) 2219 found++; 2220 } 2221 } 2222 } 2223 2224 if (LastChar + len - (Cursor - start) >= InputLim) 2225 goto err_hbuf; /* no room */ 2226 DeleteBack(Cursor - start); 2227 c_insert(len); 2228 while (len--) 2229 *Cursor++ = *cp++; 2230 oldcursor = Cursor; 2231 xfree(hbuf); 2232 return(CC_REFRESH); 2233 2234 err_hbuf: 2235 xfree(hbuf); 2236 return CC_ERROR; 2237 } 2238 2239 /*ARGSUSED*/ 2240 CCRETVAL 2241 e_yank_kill(Char c) 2242 { /* almost like GnuEmacs */ 2243 int len; 2244 Char *kp, *cp; 2245 2246 USE(c); 2247 if (KillRingLen == 0) /* nothing killed */ 2248 return(CC_ERROR); 2249 len = Strlen(KillRing[YankPos].buf); 2250 if (LastChar + len >= InputLim) 2251 return(CC_ERROR); /* end of buffer space */ 2252 2253 /* else */ 2254 cp = Cursor; /* for speed */ 2255 2256 c_insert(len); /* open the space, */ 2257 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */ 2258 *cp++ = *kp; 2259 2260 if (Argument == 1) { /* if no arg */ 2261 Mark = Cursor; /* mark at beginning, cursor at end */ 2262 Cursor = cp; 2263 } else { 2264 Mark = cp; /* else cursor at beginning, mark at end */ 2265 } 2266 2267 if (adrof(STRhighlight) && MarkIsSet) { 2268 ClearLines(); 2269 ClearDisp(); 2270 } 2271 MarkIsSet = 0; 2272 return(CC_REFRESH); 2273 } 2274 2275 /*ARGSUSED*/ 2276 CCRETVAL 2277 e_yank_pop(Char c) 2278 { /* almost like GnuEmacs */ 2279 int m_bef_c, del_len, ins_len; 2280 Char *kp, *cp; 2281 2282 USE(c); 2283 2284 #if 0 2285 /* XXX This "should" be here, but doesn't work, since LastCmd 2286 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?). 2287 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the 2288 second one will "succeed" even if the first one wasn't preceded 2289 by a yank, and giving an argument is impossible. Now we "succeed" 2290 regardless of previous command, which is wrong too of course. */ 2291 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP) 2292 return(CC_ERROR); 2293 #endif 2294 2295 if (KillRingLen == 0) /* nothing killed */ 2296 return(CC_ERROR); 2297 YankPos -= Argument; 2298 while (YankPos < 0) 2299 YankPos += KillRingLen; 2300 YankPos %= KillRingLen; 2301 2302 if (Cursor > Mark) { 2303 del_len = Cursor - Mark; 2304 m_bef_c = 1; 2305 } else { 2306 del_len = Mark - Cursor; 2307 m_bef_c = 0; 2308 } 2309 ins_len = Strlen(KillRing[YankPos].buf); 2310 if (LastChar + ins_len - del_len >= InputLim) 2311 return(CC_ERROR); /* end of buffer space */ 2312 2313 if (m_bef_c) { 2314 c_delbefore(del_len); 2315 } else { 2316 c_delafter(del_len); 2317 } 2318 cp = Cursor; /* for speed */ 2319 2320 c_insert(ins_len); /* open the space, */ 2321 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */ 2322 *cp++ = *kp; 2323 2324 if (m_bef_c) { 2325 Mark = Cursor; /* mark at beginning, cursor at end */ 2326 Cursor = cp; 2327 } else { 2328 Mark = cp; /* else cursor at beginning, mark at end */ 2329 } 2330 2331 if (adrof(STRhighlight) && MarkIsSet) { 2332 ClearLines(); 2333 ClearDisp(); 2334 } 2335 MarkIsSet = 0; 2336 return(CC_REFRESH); 2337 } 2338 2339 /*ARGSUSED*/ 2340 CCRETVAL 2341 v_delprev(Char c) /* Backspace key in insert mode */ 2342 { 2343 int rc; 2344 2345 USE(c); 2346 rc = CC_ERROR; 2347 2348 if (InsertPos != 0) { 2349 if (Argument <= Cursor - InsertPos) { 2350 c_delbefore(Argument); /* delete before */ 2351 rc = CC_REFRESH; 2352 } 2353 } 2354 return(rc); 2355 } /* v_delprev */ 2356 2357 /*ARGSUSED*/ 2358 CCRETVAL 2359 e_delprev(Char c) 2360 { 2361 USE(c); 2362 if (Cursor > InputBuf) { 2363 c_delbefore(Argument); /* delete before dot */ 2364 return(CC_REFRESH); 2365 } 2366 else { 2367 return(CC_ERROR); 2368 } 2369 } 2370 2371 /*ARGSUSED*/ 2372 CCRETVAL 2373 e_delwordprev(Char c) 2374 { 2375 Char *cp; 2376 2377 USE(c); 2378 if (Cursor == InputBuf) 2379 return(CC_ERROR); 2380 /* else */ 2381 2382 cp = c_prev_word(Cursor, InputBuf, Argument); 2383 2384 c_push_kill(cp, Cursor); /* save the text */ 2385 2386 c_delbefore((int)(Cursor - cp)); /* delete before dot */ 2387 return(CC_REFRESH); 2388 } 2389 2390 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93 2391 * 2392 * Changed the names of some of the ^D family of editor functions to 2393 * correspond to what they actually do and created new e_delnext_list 2394 * for completeness. 2395 * 2396 * Old names: New names: 2397 * 2398 * delete-char delete-char-or-eof 2399 * F_DELNEXT F_DELNEXT_EOF 2400 * e_delnext e_delnext_eof 2401 * edelnxt edelnxteof 2402 * delete-char-or-eof delete-char 2403 * F_DELNEXT_EOF F_DELNEXT 2404 * e_delnext_eof e_delnext 2405 * edelnxteof edelnxt 2406 * delete-char-or-list delete-char-or-list-or-eof 2407 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF 2408 * e_list_delnext e_delnext_list_eof 2409 * edellsteof 2410 * (no old equivalent) delete-char-or-list 2411 * F_DELNEXT_LIST 2412 * e_delnext_list 2413 * e_delnxtlst 2414 */ 2415 2416 /* added by mtk@ari.ncl.omron.co.jp (920818) */ 2417 /* rename e_delnext() -> e_delnext_eof() */ 2418 /*ARGSUSED*/ 2419 CCRETVAL 2420 e_delnext(Char c) 2421 { 2422 USE(c); 2423 if (Cursor == LastChar) {/* if I'm at the end */ 2424 if (!VImode) { 2425 return(CC_ERROR); 2426 } 2427 else { 2428 if (Cursor != InputBuf) 2429 Cursor--; 2430 else 2431 return(CC_ERROR); 2432 } 2433 } 2434 c_delafter(Argument); /* delete after dot */ 2435 if (Cursor > LastChar) 2436 Cursor = LastChar; /* bounds check */ 2437 return(CC_REFRESH); 2438 } 2439 2440 2441 /*ARGSUSED*/ 2442 CCRETVAL 2443 e_delnext_eof(Char c) 2444 { 2445 USE(c); 2446 if (Cursor == LastChar) {/* if I'm at the end */ 2447 if (!VImode) { 2448 if (Cursor == InputBuf) { 2449 /* if I'm also at the beginning */ 2450 so_write(STReof, 4);/* then do a EOF */ 2451 flush(); 2452 return(CC_EOF); 2453 } 2454 else 2455 return(CC_ERROR); 2456 } 2457 else { 2458 if (Cursor != InputBuf) 2459 Cursor--; 2460 else 2461 return(CC_ERROR); 2462 } 2463 } 2464 c_delafter(Argument); /* delete after dot */ 2465 if (Cursor > LastChar) 2466 Cursor = LastChar; /* bounds check */ 2467 return(CC_REFRESH); 2468 } 2469 2470 /*ARGSUSED*/ 2471 CCRETVAL 2472 e_delnext_list(Char c) 2473 { 2474 USE(c); 2475 if (Cursor == LastChar) { /* if I'm at the end */ 2476 PastBottom(); 2477 *LastChar = '\0'; /* just in case */ 2478 return(CC_LIST_CHOICES); 2479 } 2480 else { 2481 c_delafter(Argument); /* delete after dot */ 2482 if (Cursor > LastChar) 2483 Cursor = LastChar; /* bounds check */ 2484 return(CC_REFRESH); 2485 } 2486 } 2487 2488 /*ARGSUSED*/ 2489 CCRETVAL 2490 e_delnext_list_eof(Char c) 2491 { 2492 USE(c); 2493 if (Cursor == LastChar) { /* if I'm at the end */ 2494 if (Cursor == InputBuf) { /* if I'm also at the beginning */ 2495 so_write(STReof, 4);/* then do a EOF */ 2496 flush(); 2497 return(CC_EOF); 2498 } 2499 else { 2500 PastBottom(); 2501 *LastChar = '\0'; /* just in case */ 2502 return(CC_LIST_CHOICES); 2503 } 2504 } 2505 else { 2506 c_delafter(Argument); /* delete after dot */ 2507 if (Cursor > LastChar) 2508 Cursor = LastChar; /* bounds check */ 2509 return(CC_REFRESH); 2510 } 2511 } 2512 2513 /*ARGSUSED*/ 2514 CCRETVAL 2515 e_list_eof(Char c) 2516 { 2517 CCRETVAL rv; 2518 2519 USE(c); 2520 if (Cursor == LastChar && Cursor == InputBuf) { 2521 so_write(STReof, 4); /* then do a EOF */ 2522 flush(); 2523 rv = CC_EOF; 2524 } 2525 else { 2526 PastBottom(); 2527 *LastChar = '\0'; /* just in case */ 2528 rv = CC_LIST_CHOICES; 2529 } 2530 return rv; 2531 } 2532 2533 /*ARGSUSED*/ 2534 CCRETVAL 2535 e_delwordnext(Char c) 2536 { 2537 Char *cp; 2538 2539 USE(c); 2540 if (Cursor == LastChar) 2541 return(CC_ERROR); 2542 /* else */ 2543 2544 cp = c_next_word(Cursor, LastChar, Argument); 2545 2546 c_push_kill(Cursor, cp); /* save the text */ 2547 2548 c_delafter((int)(cp - Cursor)); /* delete after dot */ 2549 if (Cursor > LastChar) 2550 Cursor = LastChar; /* bounds check */ 2551 return(CC_REFRESH); 2552 } 2553 2554 /*ARGSUSED*/ 2555 CCRETVAL 2556 e_toend(Char c) 2557 { 2558 USE(c); 2559 Cursor = LastChar; 2560 if (VImode) 2561 if (ActionFlag & TCSHOP_DELETE) { 2562 c_delfini(); 2563 return(CC_REFRESH); 2564 } 2565 RefCursor(); /* move the cursor */ 2566 return(CC_NORM); 2567 } 2568 2569 /*ARGSUSED*/ 2570 CCRETVAL 2571 e_tobeg(Char c) 2572 { 2573 USE(c); 2574 Cursor = InputBuf; 2575 2576 if (VImode) { 2577 while (Isspace(*Cursor)) /* We want FIRST non space character */ 2578 Cursor++; 2579 if (ActionFlag & TCSHOP_DELETE) { 2580 c_delfini(); 2581 return(CC_REFRESH); 2582 } 2583 } 2584 2585 RefCursor(); /* move the cursor */ 2586 return(CC_NORM); 2587 } 2588 2589 /*ARGSUSED*/ 2590 CCRETVAL 2591 e_killend(Char c) 2592 { 2593 USE(c); 2594 c_push_kill(Cursor, LastChar); /* copy it */ 2595 LastChar = Cursor; /* zap! -- delete to end */ 2596 if (Mark > Cursor) 2597 Mark = Cursor; 2598 MarkIsSet = 0; 2599 return(CC_REFRESH); 2600 } 2601 2602 2603 /*ARGSUSED*/ 2604 CCRETVAL 2605 e_killbeg(Char c) 2606 { 2607 USE(c); 2608 c_push_kill(InputBuf, Cursor); /* copy it */ 2609 c_delbefore((int)(Cursor - InputBuf)); 2610 if (Mark && Mark > Cursor) 2611 Mark -= Cursor-InputBuf; 2612 return(CC_REFRESH); 2613 } 2614 2615 /*ARGSUSED*/ 2616 CCRETVAL 2617 e_killall(Char c) 2618 { 2619 USE(c); 2620 c_push_kill(InputBuf, LastChar); /* copy it */ 2621 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */ 2622 MarkIsSet = 0; 2623 return(CC_REFRESH); 2624 } 2625 2626 /*ARGSUSED*/ 2627 CCRETVAL 2628 e_killregion(Char c) 2629 { 2630 USE(c); 2631 if (!Mark) 2632 return(CC_ERROR); 2633 2634 if (Mark > Cursor) { 2635 c_push_kill(Cursor, Mark); /* copy it */ 2636 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */ 2637 Mark = Cursor; 2638 } 2639 else { /* mark is before cursor */ 2640 c_push_kill(Mark, Cursor); /* copy it */ 2641 c_delbefore((int)(Cursor - Mark)); 2642 } 2643 if (adrof(STRhighlight) && MarkIsSet) { 2644 ClearLines(); 2645 ClearDisp(); 2646 } 2647 MarkIsSet = 0; 2648 return(CC_REFRESH); 2649 } 2650 2651 /*ARGSUSED*/ 2652 CCRETVAL 2653 e_copyregion(Char c) 2654 { 2655 USE(c); 2656 if (!Mark) 2657 return(CC_ERROR); 2658 2659 if (Mark > Cursor) { 2660 c_push_kill(Cursor, Mark); /* copy it */ 2661 } 2662 else { /* mark is before cursor */ 2663 c_push_kill(Mark, Cursor); /* copy it */ 2664 } 2665 return(CC_NORM); /* don't even need to Refresh() */ 2666 } 2667 2668 /*ARGSUSED*/ 2669 CCRETVAL 2670 e_charswitch(Char cc) 2671 { 2672 Char c; 2673 2674 USE(cc); 2675 2676 /* do nothing if we are at beginning of line or have only one char */ 2677 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) { 2678 return(CC_ERROR); 2679 } 2680 2681 if (Cursor < LastChar) { 2682 Cursor++; 2683 } 2684 c = Cursor[-2]; 2685 Cursor[-2] = Cursor[-1]; 2686 Cursor[-1] = c; 2687 return(CC_REFRESH); 2688 } 2689 2690 /*ARGSUSED*/ 2691 CCRETVAL 2692 e_gcharswitch(Char cc) 2693 { /* gosmacs style ^T */ 2694 Char c; 2695 2696 USE(cc); 2697 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */ 2698 c = Cursor[-2]; 2699 Cursor[-2] = Cursor[-1]; 2700 Cursor[-1] = c; 2701 return(CC_REFRESH); 2702 } 2703 else { 2704 return(CC_ERROR); 2705 } 2706 } 2707 2708 /*ARGSUSED*/ 2709 CCRETVAL 2710 e_charback(Char c) 2711 { 2712 USE(c); 2713 if (Cursor > InputBuf) { 2714 if (Argument > Cursor - InputBuf) 2715 Cursor = InputBuf; 2716 else 2717 Cursor -= Argument; 2718 2719 if (VImode) 2720 if (ActionFlag & TCSHOP_DELETE) { 2721 c_delfini(); 2722 return(CC_REFRESH); 2723 } 2724 2725 RefCursor(); 2726 return(CC_NORM); 2727 } 2728 else { 2729 return(CC_ERROR); 2730 } 2731 } 2732 2733 /*ARGSUSED*/ 2734 CCRETVAL 2735 v_wordback(Char c) 2736 { 2737 USE(c); 2738 if (Cursor == InputBuf) 2739 return(CC_ERROR); 2740 /* else */ 2741 2742 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */ 2743 2744 if (ActionFlag & TCSHOP_DELETE) { 2745 c_delfini(); 2746 return(CC_REFRESH); 2747 } 2748 2749 RefCursor(); 2750 return(CC_NORM); 2751 } 2752 2753 /*ARGSUSED*/ 2754 CCRETVAL 2755 e_wordback(Char c) 2756 { 2757 USE(c); 2758 if (Cursor == InputBuf) 2759 return(CC_ERROR); 2760 /* else */ 2761 2762 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */ 2763 2764 if (VImode) 2765 if (ActionFlag & TCSHOP_DELETE) { 2766 c_delfini(); 2767 return(CC_REFRESH); 2768 } 2769 2770 RefCursor(); 2771 return(CC_NORM); 2772 } 2773 2774 /*ARGSUSED*/ 2775 CCRETVAL 2776 e_charfwd(Char c) 2777 { 2778 USE(c); 2779 if (Cursor < LastChar) { 2780 Cursor += Argument; 2781 if (Cursor > LastChar) 2782 Cursor = LastChar; 2783 2784 if (VImode) 2785 if (ActionFlag & TCSHOP_DELETE) { 2786 c_delfini(); 2787 return(CC_REFRESH); 2788 } 2789 2790 RefCursor(); 2791 return(CC_NORM); 2792 } 2793 else { 2794 return(CC_ERROR); 2795 } 2796 } 2797 2798 /*ARGSUSED*/ 2799 CCRETVAL 2800 e_wordfwd(Char c) 2801 { 2802 USE(c); 2803 if (Cursor == LastChar) 2804 return(CC_ERROR); 2805 /* else */ 2806 2807 Cursor = c_next_word(Cursor, LastChar, Argument); 2808 2809 if (VImode) 2810 if (ActionFlag & TCSHOP_DELETE) { 2811 c_delfini(); 2812 return(CC_REFRESH); 2813 } 2814 2815 RefCursor(); 2816 return(CC_NORM); 2817 } 2818 2819 /*ARGSUSED*/ 2820 CCRETVAL 2821 v_wordfwd(Char c) 2822 { 2823 USE(c); 2824 if (Cursor == LastChar) 2825 return(CC_ERROR); 2826 /* else */ 2827 2828 Cursor = c_nexword(Cursor, LastChar, Argument); 2829 2830 if (VImode) 2831 if (ActionFlag & TCSHOP_DELETE) { 2832 c_delfini(); 2833 return(CC_REFRESH); 2834 } 2835 2836 RefCursor(); 2837 return(CC_NORM); 2838 } 2839 2840 /*ARGSUSED*/ 2841 CCRETVAL 2842 v_wordbegnext(Char c) 2843 { 2844 USE(c); 2845 if (Cursor == LastChar) 2846 return(CC_ERROR); 2847 /* else */ 2848 2849 Cursor = c_next_word(Cursor, LastChar, Argument); 2850 if (Cursor < LastChar) 2851 Cursor++; 2852 2853 if (VImode) 2854 if (ActionFlag & TCSHOP_DELETE) { 2855 c_delfini(); 2856 return(CC_REFRESH); 2857 } 2858 2859 RefCursor(); 2860 return(CC_NORM); 2861 } 2862 2863 /*ARGSUSED*/ 2864 static CCRETVAL 2865 v_repeat_srch(int c) 2866 { 2867 CCRETVAL rv = CC_ERROR; 2868 #ifdef SDEBUG 2869 xprintf("dir %d patlen %d patbuf %S\n", 2870 c, (int)patbuf.len, patbuf.s); 2871 #endif 2872 2873 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */ 2874 LastChar = InputBuf; 2875 switch (c) { 2876 case F_DOWN_SEARCH_HIST: 2877 rv = e_down_search_hist(0); 2878 break; 2879 case F_UP_SEARCH_HIST: 2880 rv = e_up_search_hist(0); 2881 break; 2882 default: 2883 break; 2884 } 2885 return rv; 2886 } 2887 2888 static CCRETVAL 2889 v_csearch_back(Char ch, int count, int tflag) 2890 { 2891 Char *cp; 2892 2893 cp = Cursor; 2894 while (count--) { 2895 if (*cp == ch) 2896 cp--; 2897 while (cp > InputBuf && *cp != ch) 2898 cp--; 2899 } 2900 2901 if (cp < InputBuf || (cp == InputBuf && *cp != ch)) 2902 return(CC_ERROR); 2903 2904 if (*cp == ch && tflag) 2905 cp++; 2906 2907 Cursor = cp; 2908 2909 if (ActionFlag & TCSHOP_DELETE) { 2910 Cursor++; 2911 c_delfini(); 2912 return(CC_REFRESH); 2913 } 2914 2915 RefCursor(); 2916 return(CC_NORM); 2917 } 2918 2919 static CCRETVAL 2920 v_csearch_fwd(Char ch, int count, int tflag) 2921 { 2922 Char *cp; 2923 2924 cp = Cursor; 2925 while (count--) { 2926 if (*cp == ch) 2927 cp++; 2928 while (cp < LastChar && *cp != ch) 2929 cp++; 2930 } 2931 2932 if (cp >= LastChar) 2933 return(CC_ERROR); 2934 2935 if (*cp == ch && tflag) 2936 cp--; 2937 2938 Cursor = cp; 2939 2940 if (ActionFlag & TCSHOP_DELETE) { 2941 Cursor++; 2942 c_delfini(); 2943 return(CC_REFRESH); 2944 } 2945 RefCursor(); 2946 return(CC_NORM); 2947 } 2948 2949 /*ARGSUSED*/ 2950 static CCRETVAL 2951 v_action(int c) 2952 { 2953 Char *cp, *kp; 2954 2955 if (ActionFlag == TCSHOP_DELETE) { 2956 ActionFlag = TCSHOP_NOP; 2957 ActionPos = 0; 2958 2959 UndoSize = 0; 2960 kp = UndoBuf; 2961 for (cp = InputBuf; cp < LastChar; cp++) { 2962 *kp++ = *cp; 2963 UndoSize++; 2964 } 2965 2966 UndoAction = TCSHOP_INSERT; 2967 UndoPtr = InputBuf; 2968 LastChar = InputBuf; 2969 Cursor = InputBuf; 2970 if (c & TCSHOP_INSERT) 2971 c_alternativ_key_map(0); 2972 2973 return(CC_REFRESH); 2974 } 2975 #ifdef notdef 2976 else if (ActionFlag == TCSHOP_NOP) { 2977 #endif 2978 ActionPos = Cursor; 2979 ActionFlag = c; 2980 return(CC_ARGHACK); /* Do NOT clear out argument */ 2981 #ifdef notdef 2982 } 2983 else { 2984 ActionFlag = 0; 2985 ActionPos = 0; 2986 return(CC_ERROR); 2987 } 2988 #endif 2989 } 2990 2991 #ifdef COMMENT 2992 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */ 2993 static void 2994 c_get_word(Char **begin, Char **end) 2995 { 2996 Char *cp; 2997 2998 cp = &Cursor[0]; 2999 while (Argument--) { 3000 while ((cp <= LastChar) && (isword(*cp))) 3001 cp++; 3002 *end = --cp; 3003 while ((cp >= InputBuf) && (isword(*cp))) 3004 cp--; 3005 *begin = ++cp; 3006 } 3007 } 3008 #endif /* COMMENT */ 3009 3010 /*ARGSUSED*/ 3011 CCRETVAL 3012 e_uppercase(Char c) 3013 { 3014 Char *cp, *end; 3015 3016 USE(c); 3017 end = c_next_word(Cursor, LastChar, Argument); 3018 3019 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */ 3020 if (Islower(*cp)) 3021 *cp = Toupper(*cp); 3022 3023 Cursor = end; 3024 if (Cursor > LastChar) 3025 Cursor = LastChar; 3026 return(CC_REFRESH); 3027 } 3028 3029 3030 /*ARGSUSED*/ 3031 CCRETVAL 3032 e_capitalcase(Char c) 3033 { 3034 Char *cp, *end; 3035 3036 USE(c); 3037 end = c_next_word(Cursor, LastChar, Argument); 3038 3039 cp = Cursor; 3040 for (; cp < end; cp++) { 3041 if (Isalpha(*cp)) { 3042 if (Islower(*cp)) 3043 *cp = Toupper(*cp); 3044 cp++; 3045 break; 3046 } 3047 } 3048 for (; cp < end; cp++) 3049 if (Isupper(*cp)) 3050 *cp = Tolower(*cp); 3051 3052 Cursor = end; 3053 if (Cursor > LastChar) 3054 Cursor = LastChar; 3055 return(CC_REFRESH); 3056 } 3057 3058 /*ARGSUSED*/ 3059 CCRETVAL 3060 e_lowercase(Char c) 3061 { 3062 Char *cp, *end; 3063 3064 USE(c); 3065 end = c_next_word(Cursor, LastChar, Argument); 3066 3067 for (cp = Cursor; cp < end; cp++) 3068 if (Isupper(*cp)) 3069 *cp = Tolower(*cp); 3070 3071 Cursor = end; 3072 if (Cursor > LastChar) 3073 Cursor = LastChar; 3074 return(CC_REFRESH); 3075 } 3076 3077 3078 /*ARGSUSED*/ 3079 CCRETVAL 3080 e_set_mark(Char c) 3081 { 3082 USE(c); 3083 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) { 3084 ClearLines(); 3085 ClearDisp(); 3086 Refresh(); 3087 } 3088 Mark = Cursor; 3089 MarkIsSet = 1; 3090 return(CC_NORM); 3091 } 3092 3093 /*ARGSUSED*/ 3094 CCRETVAL 3095 e_exchange_mark(Char c) 3096 { 3097 Char *cp; 3098 3099 USE(c); 3100 cp = Cursor; 3101 Cursor = Mark; 3102 Mark = cp; 3103 RefCursor(); 3104 return(CC_NORM); 3105 } 3106 3107 /*ARGSUSED*/ 3108 CCRETVAL 3109 e_argfour(Char c) 3110 { /* multiply current argument by 4 */ 3111 USE(c); 3112 if (Argument > 1000000) 3113 return CC_ERROR; 3114 DoingArg = 1; 3115 Argument *= 4; 3116 return(CC_ARGHACK); 3117 } 3118 3119 static void 3120 quote_mode_cleanup(void *unused) 3121 { 3122 USE(unused); 3123 QuoteModeOff(); 3124 } 3125 3126 /*ARGSUSED*/ 3127 CCRETVAL 3128 e_quote(Char c) 3129 { 3130 Char ch; 3131 int num; 3132 3133 USE(c); 3134 QuoteModeOn(); 3135 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */ 3136 num = GetNextChar(&ch); 3137 cleanup_until(&c); 3138 if (num == 1) 3139 return e_insert(ch); 3140 else 3141 return e_send_eof(0); 3142 } 3143 3144 /*ARGSUSED*/ 3145 CCRETVAL 3146 e_metanext(Char c) 3147 { 3148 USE(c); 3149 MetaNext = 1; 3150 return(CC_ARGHACK); /* preserve argument */ 3151 } 3152 3153 #ifdef notdef 3154 /*ARGSUSED*/ 3155 CCRETVAL 3156 e_extendnext(Char c) 3157 { 3158 CurrentKeyMap = CcAltMap; 3159 return(CC_ARGHACK); /* preserve argument */ 3160 } 3161 3162 #endif 3163 3164 /*ARGSUSED*/ 3165 CCRETVAL 3166 v_insbeg(Char c) 3167 { /* move to beginning of line and start vi 3168 * insert mode */ 3169 USE(c); 3170 Cursor = InputBuf; 3171 InsertPos = Cursor; 3172 3173 UndoPtr = Cursor; 3174 UndoAction = TCSHOP_DELETE; 3175 3176 RefCursor(); /* move the cursor */ 3177 c_alternativ_key_map(0); 3178 return(CC_NORM); 3179 } 3180 3181 /*ARGSUSED*/ 3182 CCRETVAL 3183 v_replone(Char c) 3184 { /* vi mode overwrite one character */ 3185 USE(c); 3186 c_alternativ_key_map(0); 3187 inputmode = MODE_REPLACE_1; 3188 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */ 3189 UndoPtr = Cursor; 3190 UndoSize = 0; 3191 return(CC_NORM); 3192 } 3193 3194 /*ARGSUSED*/ 3195 CCRETVAL 3196 v_replmode(Char c) 3197 { /* vi mode start overwriting */ 3198 USE(c); 3199 c_alternativ_key_map(0); 3200 inputmode = MODE_REPLACE; 3201 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */ 3202 UndoPtr = Cursor; 3203 UndoSize = 0; 3204 return(CC_NORM); 3205 } 3206 3207 /*ARGSUSED*/ 3208 CCRETVAL 3209 v_substchar(Char c) 3210 { /* vi mode substitute for one char */ 3211 USE(c); 3212 c_delafter(Argument); 3213 c_alternativ_key_map(0); 3214 return(CC_REFRESH); 3215 } 3216 3217 /*ARGSUSED*/ 3218 CCRETVAL 3219 v_substline(Char c) 3220 { /* vi mode replace whole line */ 3221 USE(c); 3222 (void) e_killall(0); 3223 c_alternativ_key_map(0); 3224 return(CC_REFRESH); 3225 } 3226 3227 /*ARGSUSED*/ 3228 CCRETVAL 3229 v_chgtoend(Char c) 3230 { /* vi mode change to end of line */ 3231 USE(c); 3232 (void) e_killend(0); 3233 c_alternativ_key_map(0); 3234 return(CC_REFRESH); 3235 } 3236 3237 /*ARGSUSED*/ 3238 CCRETVAL 3239 v_insert(Char c) 3240 { /* vi mode start inserting */ 3241 USE(c); 3242 c_alternativ_key_map(0); 3243 3244 InsertPos = Cursor; 3245 UndoPtr = Cursor; 3246 UndoAction = TCSHOP_DELETE; 3247 3248 return(CC_NORM); 3249 } 3250 3251 /*ARGSUSED*/ 3252 CCRETVAL 3253 v_add(Char c) 3254 { /* vi mode start adding */ 3255 USE(c); 3256 c_alternativ_key_map(0); 3257 if (Cursor < LastChar) 3258 { 3259 Cursor++; 3260 if (Cursor > LastChar) 3261 Cursor = LastChar; 3262 RefCursor(); 3263 } 3264 3265 InsertPos = Cursor; 3266 UndoPtr = Cursor; 3267 UndoAction = TCSHOP_DELETE; 3268 3269 return(CC_NORM); 3270 } 3271 3272 /*ARGSUSED*/ 3273 CCRETVAL 3274 v_addend(Char c) 3275 { /* vi mode to add at end of line */ 3276 USE(c); 3277 c_alternativ_key_map(0); 3278 Cursor = LastChar; 3279 3280 InsertPos = LastChar; /* Mark where insertion begins */ 3281 UndoPtr = LastChar; 3282 UndoAction = TCSHOP_DELETE; 3283 3284 RefCursor(); 3285 return(CC_NORM); 3286 } 3287 3288 /*ARGSUSED*/ 3289 CCRETVAL 3290 v_change_case(Char cc) 3291 { 3292 Char c; 3293 3294 USE(cc); 3295 if (Cursor < LastChar) { 3296 #ifndef WINNT_NATIVE 3297 c = *Cursor; 3298 #else 3299 c = CHAR & *Cursor; 3300 #endif /* WINNT_NATIVE */ 3301 if (Isupper(c)) 3302 *Cursor++ = Tolower(c); 3303 else if (Islower(c)) 3304 *Cursor++ = Toupper(c); 3305 else 3306 Cursor++; 3307 RefPlusOne(1); /* fast refresh for one char */ 3308 return(CC_NORM); 3309 } 3310 return(CC_ERROR); 3311 } 3312 3313 /*ARGSUSED*/ 3314 CCRETVAL 3315 e_expand(Char c) 3316 { 3317 Char *p; 3318 3319 USE(c); 3320 for (p = InputBuf; Isspace(*p); p++) 3321 continue; 3322 if (p == LastChar) 3323 return(CC_ERROR); 3324 3325 justpr++; 3326 Expand++; 3327 return(e_newline(0)); 3328 } 3329 3330 /*ARGSUSED*/ 3331 CCRETVAL 3332 e_startover(Char c) 3333 { /* erase all of current line, start again */ 3334 USE(c); 3335 ResetInLine(0); /* reset the input pointers */ 3336 return(CC_REFRESH); 3337 } 3338 3339 /*ARGSUSED*/ 3340 CCRETVAL 3341 e_redisp(Char c) 3342 { 3343 USE(c); 3344 ClearLines(); 3345 ClearDisp(); 3346 return(CC_REFRESH); 3347 } 3348 3349 /*ARGSUSED*/ 3350 CCRETVAL 3351 e_cleardisp(Char c) 3352 { 3353 USE(c); 3354 ClearScreen(); /* clear the whole real screen */ 3355 ClearDisp(); /* reset everything */ 3356 return(CC_REFRESH); 3357 } 3358 3359 /*ARGSUSED*/ 3360 CCRETVAL 3361 e_tty_int(Char c) 3362 { 3363 USE(c); 3364 #if defined(_MINIX) || defined(WINNT_NATIVE) 3365 /* SAK PATCH: erase all of current line, start again */ 3366 ResetInLine(0); /* reset the input pointers */ 3367 xputchar('\n'); 3368 ClearDisp(); 3369 return (CC_REFRESH); 3370 #else /* !_MINIX && !WINNT_NATIVE */ 3371 /* do no editing */ 3372 return (CC_NORM); 3373 #endif /* _MINIX || WINNT_NATIVE */ 3374 } 3375 3376 /* 3377 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi) 3378 * Function to send a character back to the input stream in cooked 3379 * mode. Only works if we have TIOCSTI 3380 */ 3381 /*ARGSUSED*/ 3382 CCRETVAL 3383 e_stuff_char(Char c) 3384 { 3385 #ifdef TIOCSTI 3386 int was_raw = Tty_raw_mode; 3387 char buf[MB_LEN_MAX]; 3388 size_t i, len; 3389 3390 if (was_raw) 3391 (void) Cookedmode(); 3392 3393 (void) xwrite(SHIN, "\n", 1); 3394 len = one_wctomb(buf, c); 3395 for (i = 0; i < len; i++) 3396 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]); 3397 3398 if (was_raw) 3399 (void) Rawmode(); 3400 return(e_redisp(c)); 3401 #else /* !TIOCSTI */ 3402 return(CC_ERROR); 3403 #endif /* !TIOCSTI */ 3404 } 3405 3406 /*ARGSUSED*/ 3407 CCRETVAL 3408 e_insovr(Char c) 3409 { 3410 USE(c); 3411 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT); 3412 return(CC_NORM); 3413 } 3414 3415 /*ARGSUSED*/ 3416 CCRETVAL 3417 e_tty_dsusp(Char c) 3418 { 3419 USE(c); 3420 /* do no editing */ 3421 return(CC_NORM); 3422 } 3423 3424 /*ARGSUSED*/ 3425 CCRETVAL 3426 e_tty_flusho(Char c) 3427 { 3428 USE(c); 3429 /* do no editing */ 3430 return(CC_NORM); 3431 } 3432 3433 /*ARGSUSED*/ 3434 CCRETVAL 3435 e_tty_quit(Char c) 3436 { 3437 USE(c); 3438 /* do no editing */ 3439 return(CC_NORM); 3440 } 3441 3442 /*ARGSUSED*/ 3443 CCRETVAL 3444 e_tty_tsusp(Char c) 3445 { 3446 USE(c); 3447 /* do no editing */ 3448 return(CC_NORM); 3449 } 3450 3451 /*ARGSUSED*/ 3452 CCRETVAL 3453 e_tty_stopo(Char c) 3454 { 3455 USE(c); 3456 /* do no editing */ 3457 return(CC_NORM); 3458 } 3459 3460 /* returns the number of (attempted) expansions */ 3461 int 3462 ExpandHistory(void) 3463 { 3464 *LastChar = '\0'; /* just in case */ 3465 return c_substitute(); 3466 } 3467 3468 /*ARGSUSED*/ 3469 CCRETVAL 3470 e_expand_history(Char c) 3471 { 3472 USE(c); 3473 (void)ExpandHistory(); 3474 return(CC_NORM); 3475 } 3476 3477 /*ARGSUSED*/ 3478 CCRETVAL 3479 e_magic_space(Char c) 3480 { 3481 USE(c); 3482 *LastChar = '\0'; /* just in case */ 3483 (void)c_substitute(); 3484 return(e_insert(' ')); 3485 } 3486 3487 /*ARGSUSED*/ 3488 CCRETVAL 3489 e_inc_fwd(Char c) 3490 { 3491 CCRETVAL ret; 3492 3493 USE(c); 3494 patbuf.len = 0; 3495 MarkIsSet = 0; 3496 ret = e_inc_search(F_DOWN_SEARCH_HIST); 3497 if (adrof(STRhighlight) && IncMatchLen) { 3498 IncMatchLen = 0; 3499 ClearLines(); 3500 ClearDisp(); 3501 Refresh(); 3502 } 3503 IncMatchLen = 0; 3504 return ret; 3505 } 3506 3507 3508 /*ARGSUSED*/ 3509 CCRETVAL 3510 e_inc_back(Char c) 3511 { 3512 CCRETVAL ret; 3513 3514 USE(c); 3515 patbuf.len = 0; 3516 MarkIsSet = 0; 3517 ret = e_inc_search(F_UP_SEARCH_HIST); 3518 if (adrof(STRhighlight) && IncMatchLen) { 3519 IncMatchLen = 0; 3520 ClearLines(); 3521 ClearDisp(); 3522 Refresh(); 3523 } 3524 IncMatchLen = 0; 3525 return ret; 3526 } 3527 3528 /*ARGSUSED*/ 3529 CCRETVAL 3530 e_copyprev(Char c) 3531 { 3532 Char *cp, *oldc, *dp; 3533 3534 USE(c); 3535 if (Cursor == InputBuf) 3536 return(CC_ERROR); 3537 /* else */ 3538 3539 oldc = Cursor; 3540 /* does a bounds check */ 3541 cp = c_prev_word(Cursor, InputBuf, Argument); 3542 3543 c_insert((int)(oldc - cp)); 3544 for (dp = oldc; cp < oldc && dp < LastChar; cp++) 3545 *dp++ = *cp; 3546 3547 Cursor = dp; /* put cursor at end */ 3548 3549 return(CC_REFRESH); 3550 } 3551 3552 /*ARGSUSED*/ 3553 CCRETVAL 3554 e_tty_starto(Char c) 3555 { 3556 USE(c); 3557 /* do no editing */ 3558 return(CC_NORM); 3559 } 3560 3561 /*ARGSUSED*/ 3562 CCRETVAL 3563 e_load_average(Char c) 3564 { 3565 USE(c); 3566 PastBottom(); 3567 #ifdef TIOCSTAT 3568 /* 3569 * Here we pass &c to the ioctl because some os's (NetBSD) expect it 3570 * there even if they don't use it. (lukem@netbsd.org) 3571 */ 3572 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0) 3573 #endif 3574 xprintf("%s", CGETS(5, 1, "Load average unavailable\n")); 3575 return(CC_REFRESH); 3576 } 3577 3578 /*ARGSUSED*/ 3579 CCRETVAL 3580 v_chgmeta(Char c) 3581 { 3582 USE(c); 3583 /* 3584 * Delete with insert == change: first we delete and then we leave in 3585 * insert mode. 3586 */ 3587 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT)); 3588 } 3589 3590 /*ARGSUSED*/ 3591 CCRETVAL 3592 v_delmeta(Char c) 3593 { 3594 USE(c); 3595 return(v_action(TCSHOP_DELETE)); 3596 } 3597 3598 3599 /*ARGSUSED*/ 3600 CCRETVAL 3601 v_endword(Char c) 3602 { 3603 USE(c); 3604 if (Cursor == LastChar) 3605 return(CC_ERROR); 3606 /* else */ 3607 3608 Cursor = c_endword(Cursor, LastChar, Argument, STRshwspace); 3609 3610 if (ActionFlag & TCSHOP_DELETE) 3611 { 3612 Cursor++; 3613 c_delfini(); 3614 return(CC_REFRESH); 3615 } 3616 3617 RefCursor(); 3618 return(CC_NORM); 3619 } 3620 3621 /*ARGSUSED*/ 3622 CCRETVAL 3623 v_eword(Char c) 3624 { 3625 USE(c); 3626 if (Cursor == LastChar) 3627 return(CC_ERROR); 3628 /* else */ 3629 3630 Cursor = c_eword(Cursor, LastChar, Argument); 3631 3632 if (ActionFlag & TCSHOP_DELETE) { 3633 Cursor++; 3634 c_delfini(); 3635 return(CC_REFRESH); 3636 } 3637 3638 RefCursor(); 3639 return(CC_NORM); 3640 } 3641 3642 /*ARGSUSED*/ 3643 CCRETVAL 3644 v_char_fwd(Char c) 3645 { 3646 Char ch; 3647 3648 USE(c); 3649 if (GetNextChar(&ch) != 1) 3650 return e_send_eof(0); 3651 3652 srch_dir = CHAR_FWD; 3653 srch_char = ch; 3654 3655 return v_csearch_fwd(ch, Argument, 0); 3656 3657 } 3658 3659 /*ARGSUSED*/ 3660 CCRETVAL 3661 v_char_back(Char c) 3662 { 3663 Char ch; 3664 3665 USE(c); 3666 if (GetNextChar(&ch) != 1) 3667 return e_send_eof(0); 3668 3669 srch_dir = CHAR_BACK; 3670 srch_char = ch; 3671 3672 return v_csearch_back(ch, Argument, 0); 3673 } 3674 3675 /*ARGSUSED*/ 3676 CCRETVAL 3677 v_charto_fwd(Char c) 3678 { 3679 Char ch; 3680 3681 USE(c); 3682 if (GetNextChar(&ch) != 1) 3683 return e_send_eof(0); 3684 3685 return v_csearch_fwd(ch, Argument, 1); 3686 3687 } 3688 3689 /*ARGSUSED*/ 3690 CCRETVAL 3691 v_charto_back(Char c) 3692 { 3693 Char ch; 3694 3695 USE(c); 3696 if (GetNextChar(&ch) != 1) 3697 return e_send_eof(0); 3698 3699 return v_csearch_back(ch, Argument, 1); 3700 } 3701 3702 /*ARGSUSED*/ 3703 CCRETVAL 3704 v_rchar_fwd(Char c) 3705 { 3706 USE(c); 3707 if (srch_char == 0) 3708 return CC_ERROR; 3709 3710 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) : 3711 v_csearch_back(srch_char, Argument, 0); 3712 } 3713 3714 /*ARGSUSED*/ 3715 CCRETVAL 3716 v_rchar_back(Char c) 3717 { 3718 USE(c); 3719 if (srch_char == 0) 3720 return CC_ERROR; 3721 3722 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) : 3723 v_csearch_back(srch_char, Argument, 0); 3724 } 3725 3726 /*ARGSUSED*/ 3727 CCRETVAL 3728 v_undo(Char c) 3729 { 3730 int loop; 3731 Char *kp, *cp; 3732 Char temp; 3733 int size; 3734 3735 USE(c); 3736 switch (UndoAction) { 3737 case TCSHOP_DELETE|TCSHOP_INSERT: 3738 case TCSHOP_DELETE: 3739 if (UndoSize == 0) return(CC_NORM); 3740 cp = UndoPtr; 3741 kp = UndoBuf; 3742 for (loop=0; loop < UndoSize; loop++) /* copy the chars */ 3743 *kp++ = *cp++; /* into UndoBuf */ 3744 3745 for (cp = UndoPtr; cp <= LastChar; cp++) 3746 *cp = cp[UndoSize]; 3747 3748 LastChar -= UndoSize; 3749 Cursor = UndoPtr; 3750 3751 UndoAction = TCSHOP_INSERT; 3752 break; 3753 3754 case TCSHOP_INSERT: 3755 if (UndoSize == 0) return(CC_NORM); 3756 cp = UndoPtr; 3757 Cursor = UndoPtr; 3758 kp = UndoBuf; 3759 c_insert(UndoSize); /* open the space, */ 3760 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */ 3761 *cp++ = *kp++; 3762 3763 UndoAction = TCSHOP_DELETE; 3764 break; 3765 3766 case TCSHOP_CHANGE: 3767 if (UndoSize == 0) return(CC_NORM); 3768 cp = UndoPtr; 3769 Cursor = UndoPtr; 3770 kp = UndoBuf; 3771 size = (int)(Cursor-LastChar); /* NOT NSL independant */ 3772 if (size < UndoSize) 3773 size = UndoSize; 3774 for (loop = 0; loop < size; loop++) { 3775 temp = *kp; 3776 *kp++ = *cp; 3777 *cp++ = temp; 3778 } 3779 break; 3780 3781 default: 3782 return(CC_ERROR); 3783 } 3784 3785 return(CC_REFRESH); 3786 } 3787 3788 /*ARGSUSED*/ 3789 CCRETVAL 3790 v_ush_meta(Char c) 3791 { 3792 USE(c); 3793 return v_search(F_UP_SEARCH_HIST); 3794 } 3795 3796 /*ARGSUSED*/ 3797 CCRETVAL 3798 v_dsh_meta(Char c) 3799 { 3800 USE(c); 3801 return v_search(F_DOWN_SEARCH_HIST); 3802 } 3803 3804 /*ARGSUSED*/ 3805 CCRETVAL 3806 v_rsrch_fwd(Char c) 3807 { 3808 USE(c); 3809 if (patbuf.len == 0) return(CC_ERROR); 3810 return(v_repeat_srch(searchdir)); 3811 } 3812 3813 /*ARGSUSED*/ 3814 CCRETVAL 3815 v_rsrch_back(Char c) 3816 { 3817 USE(c); 3818 if (patbuf.len == 0) return(CC_ERROR); 3819 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ? 3820 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST)); 3821 } 3822 3823 #ifndef WINNT_NATIVE 3824 /* Since ed.defns.h is generated from ed.defns.c, these empty 3825 functions will keep the F_NUM_FNS consistent 3826 */ 3827 CCRETVAL 3828 e_copy_to_clipboard(Char c) 3829 { 3830 USE(c); 3831 return CC_ERROR; 3832 } 3833 3834 CCRETVAL 3835 e_paste_from_clipboard(Char c) 3836 { 3837 USE(c); 3838 return (CC_ERROR); 3839 } 3840 3841 CCRETVAL 3842 e_dosify_next(Char c) 3843 { 3844 USE(c); 3845 return (CC_ERROR); 3846 } 3847 CCRETVAL 3848 e_dosify_prev(Char c) 3849 { 3850 USE(c); 3851 return (CC_ERROR); 3852 } 3853 CCRETVAL 3854 e_page_up(Char c) 3855 { 3856 USE(c); 3857 return (CC_ERROR); 3858 } 3859 CCRETVAL 3860 e_page_down(Char c) 3861 { 3862 USE(c); 3863 return (CC_ERROR); 3864 } 3865 #endif /* !WINNT_NATIVE */ 3866 3867 #ifdef notdef 3868 void 3869 MoveCursor(int n) /* move cursor + right - left char */ 3870 { 3871 Cursor = Cursor + n; 3872 if (Cursor < InputBuf) 3873 Cursor = InputBuf; 3874 if (Cursor > LastChar) 3875 Cursor = LastChar; 3876 return; 3877 } 3878 3879 Char * 3880 GetCursor(void) 3881 { 3882 return(Cursor); 3883 } 3884 3885 int 3886 PutCursor(Char *p) 3887 { 3888 if (p < InputBuf || p > LastChar) 3889 return 1; /* Error */ 3890 Cursor = p; 3891 return 0; 3892 } 3893 #endif 3894