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 occurred if spaces were present in a string withing 48 quotation 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 *, 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, low, 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 *low, 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 /* Should it be honored? */ 805 if (inquote || (p > low && p[-1] != (Char)'\\')) { 806 if (inquote == 0) inquote = *p; 807 else if (inquote == *p) inquote = 0; 808 } 809 } 810 /* Break if unquoted non-word char */ 811 if (!inquote && Strchr(delim, *p) && p > low && p[-1] != (Char)'\\') 812 break; 813 p++; 814 } 815 } 816 817 p--; 818 return(p); 819 } 820 821 822 static Char * 823 c_eword(Char *p, Char *high, int n) 824 { 825 p++; 826 827 while (n--) { 828 int c_class; 829 830 if (p >= high) 831 break; 832 833 /* scan until end of current word (may be all whitespace!) */ 834 c_class = c_to_class(*p); 835 while ((p < high) && c_class == c_to_class(*p)) 836 p++; 837 838 /* if this was a non_whitespace word, we're ready */ 839 if (c_class != C_CLASS_WHITE) 840 continue; 841 842 /* otherwise, move to the end of the word just found */ 843 c_class = c_to_class(*p); 844 while ((p < high) && c_class == c_to_class(*p)) 845 p++; 846 } 847 848 p--; 849 return(p); 850 } 851 852 /* Set the max length of the kill ring */ 853 void 854 SetKillRing(int max) 855 { 856 CStr *new; 857 int count, i, j; 858 859 if (max < 1) 860 max = 1; /* no ring, but always one buffer */ 861 if (max == KillRingMax) 862 return; 863 new = xcalloc(max, sizeof(CStr)); 864 if (KillRing != NULL) { 865 if (KillRingLen != 0) { 866 if (max >= KillRingLen) { 867 count = KillRingLen; 868 j = KillPos; 869 } else { 870 count = max; 871 j = (KillPos - count + KillRingLen) % KillRingLen; 872 } 873 for (i = 0; i < KillRingLen; i++) { 874 if (i < count) /* copy latest */ 875 new[i] = KillRing[j]; 876 else /* free the others */ 877 xfree(KillRing[j].buf); 878 j = (j + 1) % KillRingLen; 879 } 880 KillRingLen = count; 881 KillPos = count % max; 882 YankPos = count - 1; 883 } 884 xfree(KillRing); 885 } 886 KillRing = new; 887 KillRingMax = max; 888 } 889 890 /* Push string from start upto (but not including) end onto kill ring */ 891 static void 892 c_push_kill(Char *start, Char *end) 893 { 894 CStr save, *pos; 895 Char *dp, *cp, *kp; 896 int len = end - start, i, j, k; 897 898 /* Check for duplicates? */ 899 if (KillRingLen > 0 && (dp = varval(STRkilldup)) != STRNULL) { 900 YankPos = (KillPos - 1 + KillRingLen) % KillRingLen; 901 if (eq(dp, STRerase)) { /* erase earlier one (actually move up) */ 902 j = YankPos; 903 for (i = 0; i < KillRingLen; i++) { 904 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 && 905 KillRing[j].buf[len] == '\0') { 906 save = KillRing[j]; 907 for ( ; i > 0; i--) { 908 k = j; 909 j = (j + 1) % KillRingLen; 910 KillRing[k] = KillRing[j]; 911 } 912 KillRing[j] = save; 913 return; 914 } 915 j = (j - 1 + KillRingLen) % KillRingLen; 916 } 917 } else if (eq(dp, STRall)) { /* skip if any earlier */ 918 for (i = 0; i < KillRingLen; i++) 919 if (Strncmp(KillRing[i].buf, start, (size_t) len) == 0 && 920 KillRing[i].buf[len] == '\0') 921 return; 922 } else if (eq(dp, STRprev)) { /* skip if immediately previous */ 923 j = YankPos; 924 if (Strncmp(KillRing[j].buf, start, (size_t) len) == 0 && 925 KillRing[j].buf[len] == '\0') 926 return; 927 } 928 } 929 930 /* No duplicate, go ahead and push */ 931 len++; /* need space for '\0' */ 932 YankPos = KillPos; 933 if (KillRingLen < KillRingMax) 934 KillRingLen++; 935 pos = &KillRing[KillPos]; 936 KillPos = (KillPos + 1) % KillRingMax; 937 if (pos->len < len) { 938 pos->buf = xrealloc(pos->buf, len * sizeof(Char)); 939 pos->len = len; 940 } 941 cp = start; 942 kp = pos->buf; 943 while (cp < end) 944 *kp++ = *cp++; 945 *kp = '\0'; 946 } 947 948 /* Save InputBuf etc in SavedBuf etc for restore after cmd exec */ 949 static void 950 c_save_inputbuf(void) 951 { 952 SavedBuf.len = 0; 953 Strbuf_append(&SavedBuf, InputBuf); 954 Strbuf_terminate(&SavedBuf); 955 LastSaved = LastChar - InputBuf; 956 CursSaved = Cursor - InputBuf; 957 HistSaved = Hist_num; 958 RestoreSaved = 1; 959 } 960 961 CCRETVAL 962 GetHistLine(void) 963 { 964 struct Hist *hp; 965 int h; 966 967 if (Hist_num == 0) { /* if really the current line */ 968 if (HistBuf.s != NULL) 969 copyn(InputBuf, HistBuf.s, INBUFSIZE);/*FIXBUF*/ 970 else 971 *InputBuf = '\0'; 972 LastChar = InputBuf + HistBuf.len; 973 974 #ifdef KSHVI 975 if (VImode) 976 Cursor = InputBuf; 977 else 978 #endif /* KSHVI */ 979 Cursor = LastChar; 980 981 return(CC_REFRESH); 982 } 983 984 hp = Histlist.Hnext; 985 if (hp == NULL) 986 return(CC_ERROR); 987 988 for (h = 1; h < Hist_num; h++) { 989 if ((hp->Hnext) == NULL) { 990 Hist_num = h; 991 return(CC_ERROR); 992 } 993 hp = hp->Hnext; 994 } 995 996 if (HistLit && hp->histline) { 997 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/ 998 CurrentHistLit = 1; 999 } 1000 else { 1001 Char *p; 1002 1003 p = sprlex(&hp->Hlex); 1004 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/ 1005 xfree(p); 1006 CurrentHistLit = 0; 1007 } 1008 LastChar = Strend(InputBuf); 1009 1010 if (LastChar > InputBuf) { 1011 if (LastChar[-1] == '\n') 1012 LastChar--; 1013 #if 0 1014 if (LastChar[-1] == ' ') 1015 LastChar--; 1016 #endif 1017 if (LastChar < InputBuf) 1018 LastChar = InputBuf; 1019 } 1020 1021 #ifdef KSHVI 1022 if (VImode) 1023 Cursor = InputBuf; 1024 else 1025 #endif /* KSHVI */ 1026 Cursor = LastChar; 1027 1028 return(CC_REFRESH); 1029 } 1030 1031 static CCRETVAL 1032 c_search_line(Char *pattern, int dir) 1033 { 1034 Char *cp; 1035 size_t len; 1036 1037 len = Strlen(pattern); 1038 1039 if (dir == F_UP_SEARCH_HIST) { 1040 for (cp = Cursor; cp >= InputBuf; cp--) 1041 if (Strncmp(cp, pattern, len) == 0 || 1042 Gmatch(cp, pattern)) { 1043 Cursor = cp; 1044 return(CC_NORM); 1045 } 1046 return(CC_ERROR); 1047 } else { 1048 for (cp = Cursor; *cp != '\0' && cp < InputLim; cp++) 1049 if (Strncmp(cp, pattern, len) == 0 || 1050 Gmatch(cp, pattern)) { 1051 Cursor = cp; 1052 return(CC_NORM); 1053 } 1054 return(CC_ERROR); 1055 } 1056 } 1057 1058 static CCRETVAL 1059 e_inc_search(int dir) 1060 { 1061 static const Char STRfwd[] = { 'f', 'w', 'd', '\0' }, 1062 STRbck[] = { 'b', 'c', 'k', '\0' }; 1063 static Char pchar = ':'; /* ':' = normal, '?' = failed */ 1064 static Char endcmd[2]; 1065 const Char *cp; 1066 Char ch, 1067 *oldCursor = Cursor, 1068 oldpchar = pchar; 1069 CCRETVAL ret = CC_NORM; 1070 int oldHist_num = Hist_num, 1071 oldpatlen = patbuf.len, 1072 newdir = dir, 1073 done, redo; 1074 1075 if (LastChar + sizeof(STRfwd)/sizeof(Char) + 2 + patbuf.len >= InputLim) 1076 return(CC_ERROR); 1077 1078 for (;;) { 1079 1080 if (patbuf.len == 0) { /* first round */ 1081 pchar = ':'; 1082 Strbuf_append1(&patbuf, '*'); 1083 } 1084 done = redo = 0; 1085 *LastChar++ = '\n'; 1086 for (cp = newdir == F_UP_SEARCH_HIST ? STRbck : STRfwd; 1087 *cp; *LastChar++ = *cp++) 1088 continue; 1089 *LastChar++ = pchar; 1090 for (cp = &patbuf.s[1]; cp < &patbuf.s[patbuf.len]; 1091 *LastChar++ = *cp++) 1092 continue; 1093 *LastChar = '\0'; 1094 if (adrof(STRhighlight) && pchar == ':') { 1095 /* if the no-glob-search patch is applied, remove the - 1 below */ 1096 IncMatchLen = patbuf.len - 1; 1097 ClearLines(); 1098 ClearDisp(); 1099 } 1100 Refresh(); 1101 1102 if (GetNextChar(&ch) != 1) 1103 return(e_send_eof(0)); 1104 1105 switch (GetCmdChar(ch)) { 1106 case F_INSERT: 1107 case F_DIGIT: 1108 case F_MAGIC_SPACE: 1109 if (LastChar + 1 >= InputLim) /*FIXBUF*/ 1110 SoundBeep(); 1111 else { 1112 Strbuf_append1(&patbuf, ch); 1113 *LastChar++ = ch; 1114 *LastChar = '\0'; 1115 Refresh(); 1116 } 1117 break; 1118 1119 case F_INC_FWD: 1120 newdir = F_DOWN_SEARCH_HIST; 1121 redo++; 1122 break; 1123 1124 case F_INC_BACK: 1125 newdir = F_UP_SEARCH_HIST; 1126 redo++; 1127 break; 1128 1129 case F_DELPREV: 1130 if (patbuf.len > 1) 1131 done++; 1132 else 1133 SoundBeep(); 1134 break; 1135 1136 default: 1137 switch (ASC(ch)) { 1138 case 0007: /* ^G: Abort */ 1139 ret = CC_ERROR; 1140 done++; 1141 break; 1142 1143 case 0027: /* ^W: Append word */ 1144 /* No can do if globbing characters in pattern */ 1145 for (cp = &patbuf.s[1]; ; cp++) 1146 if (cp >= &patbuf.s[patbuf.len]) { 1147 Cursor += patbuf.len - 1; 1148 cp = c_next_word(Cursor, LastChar, 1); 1149 while (Cursor < cp && *Cursor != '\n') { 1150 if (LastChar + 1 >= InputLim) {/*FIXBUF*/ 1151 SoundBeep(); 1152 break; 1153 } 1154 Strbuf_append1(&patbuf, *Cursor); 1155 *LastChar++ = *Cursor++; 1156 } 1157 Cursor = oldCursor; 1158 *LastChar = '\0'; 1159 Refresh(); 1160 break; 1161 } else if (isglob(*cp)) { 1162 SoundBeep(); 1163 break; 1164 } 1165 break; 1166 1167 default: /* Terminate and execute cmd */ 1168 endcmd[0] = ch; 1169 PushMacro(endcmd); 1170 /*FALLTHROUGH*/ 1171 1172 case 0033: /* ESC: Terminate */ 1173 ret = CC_REFRESH; 1174 done++; 1175 break; 1176 } 1177 break; 1178 } 1179 1180 while (LastChar > InputBuf && *LastChar != '\n') 1181 *LastChar-- = '\0'; 1182 *LastChar = '\0'; 1183 1184 if (!done) { 1185 1186 /* Can't search if unmatched '[' */ 1187 for (cp = &patbuf.s[patbuf.len - 1], ch = ']'; cp > patbuf.s; cp--) 1188 if (*cp == '[' || *cp == ']') { 1189 ch = *cp; 1190 break; 1191 } 1192 1193 if (patbuf.len > 1 && ch != '[') { 1194 if (redo && newdir == dir) { 1195 if (pchar == '?') { /* wrap around */ 1196 Hist_num = newdir == F_UP_SEARCH_HIST ? 0 : INT_MAX; 1197 if (GetHistLine() == CC_ERROR) 1198 /* Hist_num was fixed by first call */ 1199 (void) GetHistLine(); 1200 Cursor = newdir == F_UP_SEARCH_HIST ? 1201 LastChar : InputBuf; 1202 } else 1203 Cursor += newdir == F_UP_SEARCH_HIST ? -1 : 1; 1204 } 1205 Strbuf_append1(&patbuf, '*'); 1206 Strbuf_terminate(&patbuf); 1207 if (Cursor < InputBuf || Cursor > LastChar || 1208 (ret = c_search_line(&patbuf.s[1], newdir)) == CC_ERROR) { 1209 LastCmd = (KEYCMD) newdir; /* avoid c_hsetpat */ 1210 ret = newdir == F_UP_SEARCH_HIST ? 1211 e_up_search_hist(0) : e_down_search_hist(0); 1212 if (ret != CC_ERROR) { 1213 Cursor = newdir == F_UP_SEARCH_HIST ? 1214 LastChar : InputBuf; 1215 (void) c_search_line(&patbuf.s[1], newdir); 1216 } 1217 } 1218 patbuf.s[--patbuf.len] = '\0'; 1219 if (ret == CC_ERROR) { 1220 SoundBeep(); 1221 if (Hist_num != oldHist_num) { 1222 Hist_num = oldHist_num; 1223 if (GetHistLine() == CC_ERROR) 1224 return(CC_ERROR); 1225 } 1226 Cursor = oldCursor; 1227 pchar = '?'; 1228 } else { 1229 pchar = ':'; 1230 } 1231 } 1232 1233 ret = e_inc_search(newdir); 1234 1235 if (ret == CC_ERROR && pchar == '?' && oldpchar == ':') { 1236 /* break abort of failed search at last non-failed */ 1237 ret = CC_NORM; 1238 } 1239 1240 } 1241 1242 if (ret == CC_NORM || (ret == CC_ERROR && oldpatlen == 0)) { 1243 /* restore on normal return or error exit */ 1244 pchar = oldpchar; 1245 patbuf.len = oldpatlen; 1246 if (Hist_num != oldHist_num) { 1247 Hist_num = oldHist_num; 1248 if (GetHistLine() == CC_ERROR) 1249 return(CC_ERROR); 1250 } 1251 Cursor = oldCursor; 1252 if (ret == CC_ERROR) 1253 Refresh(); 1254 } 1255 if (done || ret != CC_NORM) 1256 return(ret); 1257 1258 } 1259 1260 } 1261 1262 static CCRETVAL 1263 v_search(int dir) 1264 { 1265 struct Strbuf tmpbuf = Strbuf_INIT; 1266 Char ch; 1267 Char *oldbuf; 1268 Char *oldlc, *oldc; 1269 1270 cleanup_push(&tmpbuf, Strbuf_cleanup); 1271 oldbuf = Strsave(InputBuf); 1272 cleanup_push(oldbuf, xfree); 1273 oldlc = LastChar; 1274 oldc = Cursor; 1275 Strbuf_append1(&tmpbuf, '*'); 1276 1277 InputBuf[0] = '\0'; 1278 LastChar = InputBuf; 1279 Cursor = InputBuf; 1280 searchdir = dir; 1281 1282 c_insert(2); /* prompt + '\n' */ 1283 *Cursor++ = '\n'; 1284 *Cursor++ = dir == F_UP_SEARCH_HIST ? '?' : '/'; 1285 Refresh(); 1286 for (ch = 0;ch == 0;) { 1287 if (GetNextChar(&ch) != 1) { 1288 cleanup_until(&tmpbuf); 1289 return(e_send_eof(0)); 1290 } 1291 switch (ASC(ch)) { 1292 case 0010: /* Delete and backspace */ 1293 case 0177: 1294 if (tmpbuf.len > 1) { 1295 *Cursor-- = '\0'; 1296 LastChar = Cursor; 1297 tmpbuf.len--; 1298 } 1299 else { 1300 copyn(InputBuf, oldbuf, INBUFSIZE);/*FIXBUF*/ 1301 LastChar = oldlc; 1302 Cursor = oldc; 1303 cleanup_until(&tmpbuf); 1304 return(CC_REFRESH); 1305 } 1306 Refresh(); 1307 ch = 0; 1308 break; 1309 1310 case 0033: /* ESC */ 1311 #ifdef IS_ASCII 1312 case '\r': /* Newline */ 1313 case '\n': 1314 #else 1315 case '\012': /* ASCII Line feed */ 1316 case '\015': /* ASCII (or EBCDIC) Return */ 1317 #endif 1318 break; 1319 1320 default: 1321 Strbuf_append1(&tmpbuf, ch); 1322 *Cursor++ = ch; 1323 LastChar = Cursor; 1324 Refresh(); 1325 ch = 0; 1326 break; 1327 } 1328 } 1329 cleanup_until(oldbuf); 1330 1331 if (tmpbuf.len == 1) { 1332 /* 1333 * Use the old pattern, but wild-card it. 1334 */ 1335 if (patbuf.len == 0) { 1336 InputBuf[0] = '\0'; 1337 LastChar = InputBuf; 1338 Cursor = InputBuf; 1339 Refresh(); 1340 cleanup_until(&tmpbuf); 1341 return(CC_ERROR); 1342 } 1343 if (patbuf.s[0] != '*') { 1344 oldbuf = Strsave(patbuf.s); 1345 patbuf.len = 0; 1346 Strbuf_append1(&patbuf, '*'); 1347 Strbuf_append(&patbuf, oldbuf); 1348 xfree(oldbuf); 1349 Strbuf_append1(&patbuf, '*'); 1350 Strbuf_terminate(&patbuf); 1351 } 1352 } 1353 else { 1354 Strbuf_append1(&tmpbuf, '*'); 1355 Strbuf_terminate(&tmpbuf); 1356 patbuf.len = 0; 1357 Strbuf_append(&patbuf, tmpbuf.s); 1358 Strbuf_terminate(&patbuf); 1359 } 1360 cleanup_until(&tmpbuf); 1361 LastCmd = (KEYCMD) dir; /* avoid c_hsetpat */ 1362 Cursor = LastChar = InputBuf; 1363 if ((dir == F_UP_SEARCH_HIST ? e_up_search_hist(0) : 1364 e_down_search_hist(0)) == CC_ERROR) { 1365 Refresh(); 1366 return(CC_ERROR); 1367 } 1368 else { 1369 if (ASC(ch) == 0033) { 1370 Refresh(); 1371 *LastChar++ = '\n'; 1372 *LastChar = '\0'; 1373 PastBottom(); 1374 return(CC_NEWLINE); 1375 } 1376 else 1377 return(CC_REFRESH); 1378 } 1379 } 1380 1381 /* 1382 * semi-PUBLIC routines. Any routine that is of type CCRETVAL is an 1383 * entry point, called from the CcKeyMap indirected into the 1384 * CcFuncTbl array. 1385 */ 1386 1387 /*ARGSUSED*/ 1388 CCRETVAL 1389 v_cmd_mode(Char c) 1390 { 1391 USE(c); 1392 InsertPos = 0; 1393 ActionFlag = TCSHOP_NOP; /* [Esc] cancels pending action */ 1394 ActionPos = 0; 1395 DoingArg = 0; 1396 if (UndoPtr > Cursor) 1397 UndoSize = (int)(UndoPtr - Cursor); 1398 else 1399 UndoSize = (int)(Cursor - UndoPtr); 1400 1401 inputmode = MODE_INSERT; 1402 c_alternativ_key_map(1); 1403 #ifdef notdef 1404 /* 1405 * We don't want to move the cursor, because all the editing 1406 * commands don't include the character under the cursor. 1407 */ 1408 if (Cursor > InputBuf) 1409 Cursor--; 1410 #endif 1411 RefCursor(); 1412 return(CC_NORM); 1413 } 1414 1415 /*ARGSUSED*/ 1416 CCRETVAL 1417 e_unassigned(Char c) 1418 { /* bound to keys that arn't really assigned */ 1419 USE(c); 1420 SoundBeep(); 1421 flush(); 1422 return(CC_NORM); 1423 } 1424 1425 #ifdef notyet 1426 static CCRETVAL 1427 e_insert_str(Char *c) 1428 { 1429 int i, n; 1430 1431 n = Strlen(c); 1432 if (LastChar + Argument * n >= InputLim) 1433 return(CC_ERROR); /* end of buffer space */ 1434 if (inputmode != MODE_INSERT) { 1435 c_delafter(Argument * Strlen(c)); 1436 } 1437 c_insert(Argument * n); 1438 while (Argument--) { 1439 for (i = 0; i < n; i++) 1440 *Cursor++ = c[i]; 1441 } 1442 Refresh(); 1443 return(CC_NORM); 1444 } 1445 #endif 1446 1447 CCRETVAL 1448 e_insert(Char c) 1449 { 1450 #ifndef SHORT_STRINGS 1451 c &= ASCII; /* no meta chars ever */ 1452 #endif 1453 1454 if (!c) 1455 return(CC_ERROR); /* no NULs in the input ever!! */ 1456 1457 if (LastChar + Argument >= InputLim) 1458 return(CC_ERROR); /* end of buffer space */ 1459 1460 if (Argument == 1) { /* How was this optimized ???? */ 1461 1462 if (inputmode != MODE_INSERT) { 1463 UndoBuf[UndoSize++] = *Cursor; 1464 UndoBuf[UndoSize] = '\0'; 1465 c_delafter(1); /* Do NOT use the saving ONE */ 1466 } 1467 1468 c_insert(1); 1469 *Cursor++ = (Char) c; 1470 DoingArg = 0; /* just in case */ 1471 RefPlusOne(1); /* fast refresh for one char. */ 1472 } 1473 else { 1474 if (inputmode != MODE_INSERT) { 1475 int i; 1476 for (i = 0; i < Argument; i++) 1477 UndoBuf[UndoSize++] = Cursor[i]; 1478 1479 UndoBuf[UndoSize] = '\0'; 1480 c_delafter(Argument); /* Do NOT use the saving ONE */ 1481 } 1482 1483 c_insert(Argument); 1484 1485 while (Argument--) 1486 *Cursor++ = (Char) c; 1487 Refresh(); 1488 } 1489 1490 if (inputmode == MODE_REPLACE_1) 1491 (void) v_cmd_mode(0); 1492 1493 return(CC_NORM); 1494 } 1495 1496 int 1497 InsertStr(Char *s) /* insert ASCIZ s at cursor (for complete) */ 1498 { 1499 int len; 1500 1501 if ((len = (int) Strlen(s)) <= 0) 1502 return -1; 1503 if (LastChar + len >= InputLim) 1504 return -1; /* end of buffer space */ 1505 1506 c_insert(len); 1507 while (len--) 1508 *Cursor++ = *s++; 1509 return 0; 1510 } 1511 1512 void 1513 DeleteBack(int n) /* delete the n characters before . */ 1514 { 1515 if (n <= 0) 1516 return; 1517 if (Cursor >= &InputBuf[n]) { 1518 c_delbefore(n); /* delete before dot */ 1519 } 1520 } 1521 1522 CCRETVAL 1523 e_digit(Char c) /* gray magic here */ 1524 { 1525 if (!Isdigit(c)) 1526 return(CC_ERROR); /* no NULs in the input ever!! */ 1527 1528 if (DoingArg) { /* if doing an arg, add this in... */ 1529 if (LastCmd == F_ARGFOUR) /* if last command was ^U */ 1530 Argument = c - '0'; 1531 else { 1532 if (Argument > 1000000) 1533 return CC_ERROR; 1534 Argument = (Argument * 10) + (c - '0'); 1535 } 1536 return(CC_ARGHACK); 1537 } 1538 else { 1539 if (LastChar + 1 >= InputLim) 1540 return CC_ERROR; /* end of buffer space */ 1541 1542 if (inputmode != MODE_INSERT) { 1543 UndoBuf[UndoSize++] = *Cursor; 1544 UndoBuf[UndoSize] = '\0'; 1545 c_delafter(1); /* Do NOT use the saving ONE */ 1546 } 1547 c_insert(1); 1548 *Cursor++ = (Char) c; 1549 DoingArg = 0; /* just in case */ 1550 RefPlusOne(1); /* fast refresh for one char. */ 1551 } 1552 return(CC_NORM); 1553 } 1554 1555 CCRETVAL 1556 e_argdigit(Char c) /* for ESC-n */ 1557 { 1558 #ifdef IS_ASCII 1559 c &= ASCII; 1560 #else 1561 c = CTL_ESC(ASC(c) & ASCII); /* stripping for EBCDIC done the ASCII way */ 1562 #endif 1563 1564 if (!Isdigit(c)) 1565 return(CC_ERROR); /* no NULs in the input ever!! */ 1566 1567 if (DoingArg) { /* if doing an arg, add this in... */ 1568 if (Argument > 1000000) 1569 return CC_ERROR; 1570 Argument = (Argument * 10) + (c - '0'); 1571 } 1572 else { /* else starting an argument */ 1573 Argument = c - '0'; 1574 DoingArg = 1; 1575 } 1576 return(CC_ARGHACK); 1577 } 1578 1579 CCRETVAL 1580 v_zero(Char c) /* command mode 0 for vi */ 1581 { 1582 if (DoingArg) { /* if doing an arg, add this in... */ 1583 if (Argument > 1000000) 1584 return CC_ERROR; 1585 Argument = (Argument * 10) + (c - '0'); 1586 return(CC_ARGHACK); 1587 } 1588 else { /* else starting an argument */ 1589 Cursor = InputBuf; 1590 if (ActionFlag & TCSHOP_DELETE) { 1591 c_delfini(); 1592 return(CC_REFRESH); 1593 } 1594 RefCursor(); /* move the cursor */ 1595 return(CC_NORM); 1596 } 1597 } 1598 1599 /*ARGSUSED*/ 1600 CCRETVAL 1601 e_newline(Char c) 1602 { /* always ignore argument */ 1603 USE(c); 1604 if (adrof(STRhighlight) && MarkIsSet) { 1605 MarkIsSet = 0; 1606 ClearLines(); 1607 ClearDisp(); 1608 Refresh(); 1609 } 1610 MarkIsSet = 0; 1611 1612 /* PastBottom(); NOW done in ed.inputl.c */ 1613 *LastChar++ = '\n'; /* for the benefit of CSH */ 1614 *LastChar = '\0'; /* just in case */ 1615 if (VImode) 1616 InsertPos = InputBuf; /* Reset editing position */ 1617 return(CC_NEWLINE); 1618 } 1619 1620 /*ARGSUSED*/ 1621 CCRETVAL 1622 e_newline_hold(Char c) 1623 { 1624 USE(c); 1625 c_save_inputbuf(); 1626 HistSaved = 0; 1627 *LastChar++ = '\n'; /* for the benefit of CSH */ 1628 *LastChar = '\0'; /* just in case */ 1629 return(CC_NEWLINE); 1630 } 1631 1632 /*ARGSUSED*/ 1633 CCRETVAL 1634 e_newline_down_hist(Char c) 1635 { 1636 USE(c); 1637 if (Hist_num > 1) { 1638 HistSaved = Hist_num; 1639 } 1640 *LastChar++ = '\n'; /* for the benefit of CSH */ 1641 *LastChar = '\0'; /* just in case */ 1642 return(CC_NEWLINE); 1643 } 1644 1645 /*ARGSUSED*/ 1646 CCRETVAL 1647 e_send_eof(Char c) 1648 { /* for when ^D is ONLY send-eof */ 1649 USE(c); 1650 PastBottom(); 1651 *LastChar = '\0'; /* just in case */ 1652 return(CC_EOF); 1653 } 1654 1655 /*ARGSUSED*/ 1656 CCRETVAL 1657 e_complete(Char c) 1658 { 1659 USE(c); 1660 *LastChar = '\0'; /* just in case */ 1661 return(CC_COMPLETE); 1662 } 1663 1664 /*ARGSUSED*/ 1665 CCRETVAL 1666 e_complete_back(Char c) 1667 { 1668 USE(c); 1669 *LastChar = '\0'; /* just in case */ 1670 return(CC_COMPLETE_BACK); 1671 } 1672 1673 /*ARGSUSED*/ 1674 CCRETVAL 1675 e_complete_fwd(Char c) 1676 { 1677 USE(c); 1678 *LastChar = '\0'; /* just in case */ 1679 return(CC_COMPLETE_FWD); 1680 } 1681 1682 /*ARGSUSED*/ 1683 CCRETVAL 1684 e_complete_all(Char c) 1685 { 1686 USE(c); 1687 *LastChar = '\0'; /* just in case */ 1688 return(CC_COMPLETE_ALL); 1689 } 1690 1691 /*ARGSUSED*/ 1692 CCRETVAL 1693 v_cm_complete(Char c) 1694 { 1695 USE(c); 1696 if (Cursor < LastChar) 1697 Cursor++; 1698 *LastChar = '\0'; /* just in case */ 1699 return(CC_COMPLETE); 1700 } 1701 1702 /*ARGSUSED*/ 1703 CCRETVAL 1704 e_toggle_hist(Char c) 1705 { 1706 struct Hist *hp; 1707 int h; 1708 1709 USE(c); 1710 *LastChar = '\0'; /* just in case */ 1711 1712 if (Hist_num <= 0) { 1713 return CC_ERROR; 1714 } 1715 1716 hp = Histlist.Hnext; 1717 if (hp == NULL) { /* this is only if no history */ 1718 return(CC_ERROR); 1719 } 1720 1721 for (h = 1; h < Hist_num; h++) 1722 hp = hp->Hnext; 1723 1724 if (!CurrentHistLit) { 1725 if (hp->histline) { 1726 copyn(InputBuf, hp->histline, INBUFSIZE);/*FIXBUF*/ 1727 CurrentHistLit = 1; 1728 } 1729 else { 1730 return CC_ERROR; 1731 } 1732 } 1733 else { 1734 Char *p; 1735 1736 p = sprlex(&hp->Hlex); 1737 copyn(InputBuf, p, sizeof(InputBuf) / sizeof(Char));/*FIXBUF*/ 1738 xfree(p); 1739 CurrentHistLit = 0; 1740 } 1741 1742 LastChar = Strend(InputBuf); 1743 if (LastChar > InputBuf) { 1744 if (LastChar[-1] == '\n') 1745 LastChar--; 1746 if (LastChar[-1] == ' ') 1747 LastChar--; 1748 if (LastChar < InputBuf) 1749 LastChar = InputBuf; 1750 } 1751 1752 #ifdef KSHVI 1753 if (VImode) 1754 Cursor = InputBuf; 1755 else 1756 #endif /* KSHVI */ 1757 Cursor = LastChar; 1758 1759 return(CC_REFRESH); 1760 } 1761 1762 /*ARGSUSED*/ 1763 CCRETVAL 1764 e_up_hist(Char c) 1765 { 1766 Char beep = 0; 1767 1768 USE(c); 1769 UndoAction = TCSHOP_NOP; 1770 *LastChar = '\0'; /* just in case */ 1771 1772 if (Hist_num == 0) { /* save the current buffer away */ 1773 HistBuf.len = 0; 1774 Strbuf_append(&HistBuf, InputBuf); 1775 Strbuf_terminate(&HistBuf); 1776 } 1777 1778 Hist_num += Argument; 1779 1780 if (GetHistLine() == CC_ERROR) { 1781 beep = 1; 1782 (void) GetHistLine(); /* Hist_num was fixed by first call */ 1783 } 1784 1785 Refresh(); 1786 if (beep) 1787 return(CC_ERROR); 1788 else 1789 return(CC_NORM); /* was CC_UP_HIST */ 1790 } 1791 1792 /*ARGSUSED*/ 1793 CCRETVAL 1794 e_down_hist(Char c) 1795 { 1796 USE(c); 1797 UndoAction = TCSHOP_NOP; 1798 *LastChar = '\0'; /* just in case */ 1799 1800 Hist_num -= Argument; 1801 1802 if (Hist_num < 0) { 1803 Hist_num = 0; 1804 return(CC_ERROR); /* make it beep */ 1805 } 1806 1807 return(GetHistLine()); 1808 } 1809 1810 1811 1812 /* 1813 * c_hmatch() return True if the pattern matches the prefix 1814 */ 1815 static int 1816 c_hmatch(Char *str) 1817 { 1818 if (Strncmp(patbuf.s, str, patbuf.len) == 0) 1819 return 1; 1820 return Gmatch(str, patbuf.s); 1821 } 1822 1823 /* 1824 * c_hsetpat(): Set the history seatch pattern 1825 */ 1826 static void 1827 c_hsetpat(void) 1828 { 1829 if (LastCmd != F_UP_SEARCH_HIST && LastCmd != F_DOWN_SEARCH_HIST) { 1830 patbuf.len = 0; 1831 Strbuf_appendn(&patbuf, InputBuf, Cursor - InputBuf); 1832 Strbuf_terminate(&patbuf); 1833 } 1834 #ifdef SDEBUG 1835 xprintf("\nHist_num = %d\n", Hist_num); 1836 xprintf("patlen = %d\n", (int)patbuf.len); 1837 xprintf("patbuf = \"%S\"\n", patbuf.s); 1838 xprintf("Cursor %d LastChar %d\n", Cursor - InputBuf, LastChar - InputBuf); 1839 #endif 1840 } 1841 1842 /*ARGSUSED*/ 1843 CCRETVAL 1844 e_up_search_hist(Char c) 1845 { 1846 struct Hist *hp; 1847 int h; 1848 int found = 0; 1849 1850 USE(c); 1851 ActionFlag = TCSHOP_NOP; 1852 UndoAction = TCSHOP_NOP; 1853 *LastChar = '\0'; /* just in case */ 1854 if (Hist_num < 0) { 1855 #ifdef DEBUG_EDIT 1856 xprintf("%s: e_up_search_hist(): Hist_num < 0; resetting.\n", progname); 1857 #endif 1858 Hist_num = 0; 1859 return(CC_ERROR); 1860 } 1861 1862 if (Hist_num == 0) { 1863 HistBuf.len = 0; 1864 Strbuf_append(&HistBuf, InputBuf); 1865 Strbuf_terminate(&HistBuf); 1866 } 1867 1868 1869 hp = Histlist.Hnext; 1870 if (hp == NULL) 1871 return(CC_ERROR); 1872 1873 c_hsetpat(); /* Set search pattern !! */ 1874 1875 for (h = 1; h <= Hist_num; h++) 1876 hp = hp->Hnext; 1877 1878 while (hp != NULL) { 1879 Char *hl; 1880 int matched; 1881 1882 if (hp->histline == NULL) 1883 hp->histline = sprlex(&hp->Hlex); 1884 if (HistLit) 1885 hl = hp->histline; 1886 else { 1887 hl = sprlex(&hp->Hlex); 1888 cleanup_push(hl, xfree); 1889 } 1890 #ifdef SDEBUG 1891 xprintf("Comparing with \"%S\"\n", hl); 1892 #endif 1893 matched = (Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || 1894 hl[LastChar-InputBuf]) && c_hmatch(hl); 1895 if (!HistLit) 1896 cleanup_until(hl); 1897 if (matched) { 1898 found++; 1899 break; 1900 } 1901 h++; 1902 hp = hp->Hnext; 1903 } 1904 1905 if (!found) { 1906 #ifdef SDEBUG 1907 xprintf("not found\n"); 1908 #endif 1909 return(CC_ERROR); 1910 } 1911 1912 Hist_num = h; 1913 1914 return(GetHistLine()); 1915 } 1916 1917 /*ARGSUSED*/ 1918 CCRETVAL 1919 e_down_search_hist(Char c) 1920 { 1921 struct Hist *hp; 1922 int h; 1923 int found = 0; 1924 1925 USE(c); 1926 ActionFlag = TCSHOP_NOP; 1927 UndoAction = TCSHOP_NOP; 1928 *LastChar = '\0'; /* just in case */ 1929 1930 if (Hist_num == 0) 1931 return(CC_ERROR); 1932 1933 hp = Histlist.Hnext; 1934 if (hp == 0) 1935 return(CC_ERROR); 1936 1937 c_hsetpat(); /* Set search pattern !! */ 1938 1939 for (h = 1; h < Hist_num && hp; h++) { 1940 Char *hl; 1941 if (hp->histline == NULL) 1942 hp->histline = sprlex(&hp->Hlex); 1943 if (HistLit) 1944 hl = hp->histline; 1945 else { 1946 hl = sprlex(&hp->Hlex); 1947 cleanup_push(hl, xfree); 1948 } 1949 #ifdef SDEBUG 1950 xprintf("Comparing with \"%S\"\n", hl); 1951 #endif 1952 if ((Strncmp(hl, InputBuf, (size_t) (LastChar - InputBuf)) || 1953 hl[LastChar-InputBuf]) && c_hmatch(hl)) 1954 found = h; 1955 if (!HistLit) 1956 cleanup_until(hl); 1957 hp = hp->Hnext; 1958 } 1959 1960 if (!found) { /* is it the current history number? */ 1961 if (!c_hmatch(HistBuf.s)) { 1962 #ifdef SDEBUG 1963 xprintf("not found\n"); 1964 #endif 1965 return(CC_ERROR); 1966 } 1967 } 1968 1969 Hist_num = found; 1970 1971 return(GetHistLine()); 1972 } 1973 1974 /*ARGSUSED*/ 1975 CCRETVAL 1976 e_helpme(Char c) 1977 { 1978 USE(c); 1979 PastBottom(); 1980 *LastChar = '\0'; /* just in case */ 1981 return(CC_HELPME); 1982 } 1983 1984 /*ARGSUSED*/ 1985 CCRETVAL 1986 e_correct(Char c) 1987 { 1988 USE(c); 1989 *LastChar = '\0'; /* just in case */ 1990 return(CC_CORRECT); 1991 } 1992 1993 /*ARGSUSED*/ 1994 CCRETVAL 1995 e_correctl(Char c) 1996 { 1997 USE(c); 1998 *LastChar = '\0'; /* just in case */ 1999 return(CC_CORRECT_L); 2000 } 2001 2002 /*ARGSUSED*/ 2003 CCRETVAL 2004 e_run_fg_editor(Char c) 2005 { 2006 struct process *pp; 2007 2008 USE(c); 2009 if ((pp = find_stop_ed()) != NULL) { 2010 /* save our editor state so we can restore it */ 2011 c_save_inputbuf(); 2012 Hist_num = 0; /* for the history commands */ 2013 2014 /* put the tty in a sane mode */ 2015 PastBottom(); 2016 (void) Cookedmode(); /* make sure the tty is set up correctly */ 2017 2018 /* do it! */ 2019 fg_proc_entry(pp); 2020 2021 (void) Rawmode(); /* go on */ 2022 Refresh(); 2023 RestoreSaved = 0; 2024 HistSaved = 0; 2025 } 2026 return(CC_NORM); 2027 } 2028 2029 /*ARGSUSED*/ 2030 CCRETVAL 2031 e_list_choices(Char c) 2032 { 2033 USE(c); 2034 PastBottom(); 2035 *LastChar = '\0'; /* just in case */ 2036 return(CC_LIST_CHOICES); 2037 } 2038 2039 /*ARGSUSED*/ 2040 CCRETVAL 2041 e_list_all(Char c) 2042 { 2043 USE(c); 2044 PastBottom(); 2045 *LastChar = '\0'; /* just in case */ 2046 return(CC_LIST_ALL); 2047 } 2048 2049 /*ARGSUSED*/ 2050 CCRETVAL 2051 e_list_glob(Char c) 2052 { 2053 USE(c); 2054 PastBottom(); 2055 *LastChar = '\0'; /* just in case */ 2056 return(CC_LIST_GLOB); 2057 } 2058 2059 /*ARGSUSED*/ 2060 CCRETVAL 2061 e_expand_glob(Char c) 2062 { 2063 USE(c); 2064 *LastChar = '\0'; /* just in case */ 2065 return(CC_EXPAND_GLOB); 2066 } 2067 2068 /*ARGSUSED*/ 2069 CCRETVAL 2070 e_normalize_path(Char c) 2071 { 2072 USE(c); 2073 *LastChar = '\0'; /* just in case */ 2074 return(CC_NORMALIZE_PATH); 2075 } 2076 2077 /*ARGSUSED*/ 2078 CCRETVAL 2079 e_normalize_command(Char c) 2080 { 2081 USE(c); 2082 *LastChar = '\0'; /* just in case */ 2083 return(CC_NORMALIZE_COMMAND); 2084 } 2085 2086 /*ARGSUSED*/ 2087 CCRETVAL 2088 e_expand_vars(Char c) 2089 { 2090 USE(c); 2091 *LastChar = '\0'; /* just in case */ 2092 return(CC_EXPAND_VARS); 2093 } 2094 2095 /*ARGSUSED*/ 2096 CCRETVAL 2097 e_which(Char c) 2098 { /* do a fast command line which(1) */ 2099 USE(c); 2100 c_save_inputbuf(); 2101 Hist_num = 0; /* for the history commands */ 2102 PastBottom(); 2103 *LastChar = '\0'; /* just in case */ 2104 return(CC_WHICH); 2105 } 2106 2107 /*ARGSUSED*/ 2108 CCRETVAL 2109 e_last_item(Char c) 2110 { /* insert the last element of the prev. cmd */ 2111 struct Hist *hp; 2112 struct wordent *wp, *firstp; 2113 int i; 2114 Char *expanded; 2115 2116 USE(c); 2117 if (Argument <= 0) 2118 return(CC_ERROR); 2119 2120 hp = Histlist.Hnext; 2121 if (hp == NULL) { /* this is only if no history */ 2122 return(CC_ERROR); 2123 } 2124 2125 wp = (hp->Hlex).prev; 2126 2127 if (wp->prev == (struct wordent *) NULL) 2128 return(CC_ERROR); /* an empty history entry */ 2129 2130 firstp = (hp->Hlex).next; 2131 2132 /* back up arg words in lex */ 2133 for (i = 0; i < Argument && wp != firstp; i++) { 2134 wp = wp->prev; 2135 } 2136 2137 expanded = expand_lex(wp->prev, 0, i - 1); 2138 if (InsertStr(expanded)) { 2139 xfree(expanded); 2140 return(CC_ERROR); 2141 } 2142 2143 xfree(expanded); 2144 return(CC_REFRESH); 2145 } 2146 2147 /*ARGSUSED*/ 2148 CCRETVAL 2149 e_dabbrev_expand(Char c) 2150 { /* expand to preceding word matching prefix */ 2151 Char *cp, *ncp, *bp; 2152 struct Hist *hp; 2153 int arg = 0, i; 2154 size_t len = 0; 2155 int found = 0; 2156 Char *hbuf; 2157 static int oldevent, hist, word; 2158 static Char *start, *oldcursor; 2159 2160 USE(c); 2161 if (Argument <= 0) 2162 return(CC_ERROR); 2163 2164 cp = c_preword(Cursor, InputBuf, 1, STRshwordsep); 2165 if (cp == Cursor || Isspace(*cp)) 2166 return(CC_ERROR); 2167 2168 hbuf = NULL; 2169 hp = Histlist.Hnext; 2170 bp = InputBuf; 2171 if (Argument == 1 && eventno == oldevent && cp == start && 2172 Cursor == oldcursor && patbuf.len > 0 2173 && Strncmp(patbuf.s, cp, patbuf.len) == 0){ 2174 /* continue previous search - go to last match (hist/word) */ 2175 if (hist != 0) { /* need to move up history */ 2176 for (i = 1; i < hist && hp != NULL; i++) 2177 hp = hp->Hnext; 2178 if (hp == NULL) /* "can't happen" */ 2179 goto err_hbuf; 2180 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX); 2181 cp = Strend(hbuf); 2182 bp = hbuf; 2183 hp = hp->Hnext; 2184 } 2185 cp = c_preword(cp, bp, word, STRshwordsep); 2186 } else { /* starting new search */ 2187 oldevent = eventno; 2188 start = cp; 2189 patbuf.len = 0; 2190 Strbuf_appendn(&patbuf, cp, Cursor - cp); 2191 hist = 0; 2192 word = 0; 2193 } 2194 2195 while (!found) { 2196 ncp = c_preword(cp, bp, 1, STRshwordsep); 2197 if (ncp == cp || Isspace(*ncp)) { /* beginning of line */ 2198 hist++; 2199 word = 0; 2200 if (hp == NULL) 2201 goto err_hbuf; 2202 hbuf = expand_lex(&hp->Hlex, 0, INT_MAX); 2203 cp = Strend(hbuf); 2204 bp = hbuf; 2205 hp = hp->Hnext; 2206 continue; 2207 } else { 2208 word++; 2209 len = c_endword(ncp-1, InputBuf, cp, 1, STRshwordsep) - ncp + 1; 2210 cp = ncp; 2211 } 2212 if (len > patbuf.len && Strncmp(cp, patbuf.s, patbuf.len) == 0) { 2213 /* We don't fully check distinct matches as Gnuemacs does: */ 2214 if (Argument > 1) { /* just count matches */ 2215 if (++arg >= Argument) 2216 found++; 2217 } else { /* match if distinct from previous */ 2218 if (len != (size_t)(Cursor - start) 2219 || Strncmp(cp, start, len) != 0) 2220 found++; 2221 } 2222 } 2223 } 2224 2225 if (LastChar + len - (Cursor - start) >= InputLim) 2226 goto err_hbuf; /* no room */ 2227 DeleteBack(Cursor - start); 2228 c_insert(len); 2229 while (len--) 2230 *Cursor++ = *cp++; 2231 oldcursor = Cursor; 2232 xfree(hbuf); 2233 return(CC_REFRESH); 2234 2235 err_hbuf: 2236 xfree(hbuf); 2237 return CC_ERROR; 2238 } 2239 2240 /*ARGSUSED*/ 2241 CCRETVAL 2242 e_yank_kill(Char c) 2243 { /* almost like GnuEmacs */ 2244 int len; 2245 Char *kp, *cp; 2246 2247 USE(c); 2248 if (KillRingLen == 0) /* nothing killed */ 2249 return(CC_ERROR); 2250 len = Strlen(KillRing[YankPos].buf); 2251 if (LastChar + len >= InputLim) 2252 return(CC_ERROR); /* end of buffer space */ 2253 2254 /* else */ 2255 cp = Cursor; /* for speed */ 2256 2257 c_insert(len); /* open the space, */ 2258 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */ 2259 *cp++ = *kp; 2260 2261 if (Argument == 1) { /* if no arg */ 2262 Mark = Cursor; /* mark at beginning, cursor at end */ 2263 Cursor = cp; 2264 } else { 2265 Mark = cp; /* else cursor at beginning, mark at end */ 2266 } 2267 2268 if (adrof(STRhighlight) && MarkIsSet) { 2269 ClearLines(); 2270 ClearDisp(); 2271 } 2272 MarkIsSet = 0; 2273 return(CC_REFRESH); 2274 } 2275 2276 /*ARGSUSED*/ 2277 CCRETVAL 2278 e_yank_pop(Char c) 2279 { /* almost like GnuEmacs */ 2280 int m_bef_c, del_len, ins_len; 2281 Char *kp, *cp; 2282 2283 USE(c); 2284 2285 #if 0 2286 /* XXX This "should" be here, but doesn't work, since LastCmd 2287 gets set on CC_ERROR and CC_ARGHACK, which it shouldn't(?). 2288 (But what about F_ARGFOUR?) I.e. if you hit M-y twice the 2289 second one will "succeed" even if the first one wasn't preceded 2290 by a yank, and giving an argument is impossible. Now we "succeed" 2291 regardless of previous command, which is wrong too of course. */ 2292 if (LastCmd != F_YANK_KILL && LastCmd != F_YANK_POP) 2293 return(CC_ERROR); 2294 #endif 2295 2296 if (KillRingLen == 0) /* nothing killed */ 2297 return(CC_ERROR); 2298 YankPos -= Argument; 2299 while (YankPos < 0) 2300 YankPos += KillRingLen; 2301 YankPos %= KillRingLen; 2302 2303 if (Cursor > Mark) { 2304 del_len = Cursor - Mark; 2305 m_bef_c = 1; 2306 } else { 2307 del_len = Mark - Cursor; 2308 m_bef_c = 0; 2309 } 2310 ins_len = Strlen(KillRing[YankPos].buf); 2311 if (LastChar + ins_len - del_len >= InputLim) 2312 return(CC_ERROR); /* end of buffer space */ 2313 2314 if (m_bef_c) { 2315 c_delbefore(del_len); 2316 } else { 2317 c_delafter(del_len); 2318 } 2319 cp = Cursor; /* for speed */ 2320 2321 c_insert(ins_len); /* open the space, */ 2322 for (kp = KillRing[YankPos].buf; *kp; kp++) /* copy the chars */ 2323 *cp++ = *kp; 2324 2325 if (m_bef_c) { 2326 Mark = Cursor; /* mark at beginning, cursor at end */ 2327 Cursor = cp; 2328 } else { 2329 Mark = cp; /* else cursor at beginning, mark at end */ 2330 } 2331 2332 if (adrof(STRhighlight) && MarkIsSet) { 2333 ClearLines(); 2334 ClearDisp(); 2335 } 2336 MarkIsSet = 0; 2337 return(CC_REFRESH); 2338 } 2339 2340 /*ARGSUSED*/ 2341 CCRETVAL 2342 v_delprev(Char c) /* Backspace key in insert mode */ 2343 { 2344 int rc; 2345 2346 USE(c); 2347 rc = CC_ERROR; 2348 2349 if (InsertPos != 0) { 2350 if (Argument <= Cursor - InsertPos) { 2351 c_delbefore(Argument); /* delete before */ 2352 rc = CC_REFRESH; 2353 } 2354 } 2355 return(rc); 2356 } /* v_delprev */ 2357 2358 /*ARGSUSED*/ 2359 CCRETVAL 2360 e_delprev(Char c) 2361 { 2362 USE(c); 2363 if (Cursor > InputBuf) { 2364 c_delbefore(Argument); /* delete before dot */ 2365 return(CC_REFRESH); 2366 } 2367 else { 2368 return(CC_ERROR); 2369 } 2370 } 2371 2372 /*ARGSUSED*/ 2373 CCRETVAL 2374 e_delwordprev(Char c) 2375 { 2376 Char *cp; 2377 2378 USE(c); 2379 if (Cursor == InputBuf) 2380 return(CC_ERROR); 2381 /* else */ 2382 2383 cp = c_prev_word(Cursor, InputBuf, Argument); 2384 2385 c_push_kill(cp, Cursor); /* save the text */ 2386 2387 c_delbefore((int)(Cursor - cp)); /* delete before dot */ 2388 return(CC_REFRESH); 2389 } 2390 2391 /* DCS <dcs@neutron.chem.yale.edu>, 9 Oct 93 2392 * 2393 * Changed the names of some of the ^D family of editor functions to 2394 * correspond to what they actually do and created new e_delnext_list 2395 * for completeness. 2396 * 2397 * Old names: New names: 2398 * 2399 * delete-char delete-char-or-eof 2400 * F_DELNEXT F_DELNEXT_EOF 2401 * e_delnext e_delnext_eof 2402 * edelnxt edelnxteof 2403 * delete-char-or-eof delete-char 2404 * F_DELNEXT_EOF F_DELNEXT 2405 * e_delnext_eof e_delnext 2406 * edelnxteof edelnxt 2407 * delete-char-or-list delete-char-or-list-or-eof 2408 * F_LIST_DELNEXT F_DELNEXT_LIST_EOF 2409 * e_list_delnext e_delnext_list_eof 2410 * edellsteof 2411 * (no old equivalent) delete-char-or-list 2412 * F_DELNEXT_LIST 2413 * e_delnext_list 2414 * e_delnxtlst 2415 */ 2416 2417 /* added by mtk@ari.ncl.omron.co.jp (920818) */ 2418 /* rename e_delnext() -> e_delnext_eof() */ 2419 /*ARGSUSED*/ 2420 CCRETVAL 2421 e_delnext(Char c) 2422 { 2423 USE(c); 2424 if (Cursor == LastChar) {/* if I'm at the end */ 2425 if (!VImode) { 2426 return(CC_ERROR); 2427 } 2428 else { 2429 if (Cursor != InputBuf) 2430 Cursor--; 2431 else 2432 return(CC_ERROR); 2433 } 2434 } 2435 c_delafter(Argument); /* delete after dot */ 2436 if (Cursor > LastChar) 2437 Cursor = LastChar; /* bounds check */ 2438 return(CC_REFRESH); 2439 } 2440 2441 2442 /*ARGSUSED*/ 2443 CCRETVAL 2444 e_delnext_eof(Char c) 2445 { 2446 USE(c); 2447 if (Cursor == LastChar) {/* if I'm at the end */ 2448 if (!VImode) { 2449 if (Cursor == InputBuf) { 2450 /* if I'm also at the beginning */ 2451 so_write(STReof, 4);/* then do a EOF */ 2452 flush(); 2453 return(CC_EOF); 2454 } 2455 else 2456 return(CC_ERROR); 2457 } 2458 else { 2459 if (Cursor != InputBuf) 2460 Cursor--; 2461 else 2462 return(CC_ERROR); 2463 } 2464 } 2465 c_delafter(Argument); /* delete after dot */ 2466 if (Cursor > LastChar) 2467 Cursor = LastChar; /* bounds check */ 2468 return(CC_REFRESH); 2469 } 2470 2471 /*ARGSUSED*/ 2472 CCRETVAL 2473 e_delnext_list(Char c) 2474 { 2475 USE(c); 2476 if (Cursor == LastChar) { /* if I'm at the end */ 2477 PastBottom(); 2478 *LastChar = '\0'; /* just in case */ 2479 return(CC_LIST_CHOICES); 2480 } 2481 else { 2482 c_delafter(Argument); /* delete after dot */ 2483 if (Cursor > LastChar) 2484 Cursor = LastChar; /* bounds check */ 2485 return(CC_REFRESH); 2486 } 2487 } 2488 2489 /*ARGSUSED*/ 2490 CCRETVAL 2491 e_delnext_list_eof(Char c) 2492 { 2493 USE(c); 2494 if (Cursor == LastChar) { /* if I'm at the end */ 2495 if (Cursor == InputBuf) { /* if I'm also at the beginning */ 2496 so_write(STReof, 4);/* then do a EOF */ 2497 flush(); 2498 return(CC_EOF); 2499 } 2500 else { 2501 PastBottom(); 2502 *LastChar = '\0'; /* just in case */ 2503 return(CC_LIST_CHOICES); 2504 } 2505 } 2506 else { 2507 c_delafter(Argument); /* delete after dot */ 2508 if (Cursor > LastChar) 2509 Cursor = LastChar; /* bounds check */ 2510 return(CC_REFRESH); 2511 } 2512 } 2513 2514 /*ARGSUSED*/ 2515 CCRETVAL 2516 e_list_eof(Char c) 2517 { 2518 CCRETVAL rv; 2519 2520 USE(c); 2521 if (Cursor == LastChar && Cursor == InputBuf) { 2522 so_write(STReof, 4); /* then do a EOF */ 2523 flush(); 2524 rv = CC_EOF; 2525 } 2526 else { 2527 PastBottom(); 2528 *LastChar = '\0'; /* just in case */ 2529 rv = CC_LIST_CHOICES; 2530 } 2531 return rv; 2532 } 2533 2534 /*ARGSUSED*/ 2535 CCRETVAL 2536 e_delwordnext(Char c) 2537 { 2538 Char *cp; 2539 2540 USE(c); 2541 if (Cursor == LastChar) 2542 return(CC_ERROR); 2543 /* else */ 2544 2545 cp = c_next_word(Cursor, LastChar, Argument); 2546 2547 c_push_kill(Cursor, cp); /* save the text */ 2548 2549 c_delafter((int)(cp - Cursor)); /* delete after dot */ 2550 if (Cursor > LastChar) 2551 Cursor = LastChar; /* bounds check */ 2552 return(CC_REFRESH); 2553 } 2554 2555 /*ARGSUSED*/ 2556 CCRETVAL 2557 e_toend(Char c) 2558 { 2559 USE(c); 2560 Cursor = LastChar; 2561 if (VImode) 2562 if (ActionFlag & TCSHOP_DELETE) { 2563 c_delfini(); 2564 return(CC_REFRESH); 2565 } 2566 RefCursor(); /* move the cursor */ 2567 return(CC_NORM); 2568 } 2569 2570 /*ARGSUSED*/ 2571 CCRETVAL 2572 e_tobeg(Char c) 2573 { 2574 USE(c); 2575 Cursor = InputBuf; 2576 2577 if (VImode) { 2578 while (Isspace(*Cursor)) /* We want FIRST non space character */ 2579 Cursor++; 2580 if (ActionFlag & TCSHOP_DELETE) { 2581 c_delfini(); 2582 return(CC_REFRESH); 2583 } 2584 } 2585 2586 RefCursor(); /* move the cursor */ 2587 return(CC_NORM); 2588 } 2589 2590 /*ARGSUSED*/ 2591 CCRETVAL 2592 e_killend(Char c) 2593 { 2594 USE(c); 2595 c_push_kill(Cursor, LastChar); /* copy it */ 2596 LastChar = Cursor; /* zap! -- delete to end */ 2597 if (Mark > Cursor) 2598 Mark = Cursor; 2599 MarkIsSet = 0; 2600 return(CC_REFRESH); 2601 } 2602 2603 2604 /*ARGSUSED*/ 2605 CCRETVAL 2606 e_killbeg(Char c) 2607 { 2608 USE(c); 2609 c_push_kill(InputBuf, Cursor); /* copy it */ 2610 c_delbefore((int)(Cursor - InputBuf)); 2611 if (Mark && Mark > Cursor) 2612 Mark -= Cursor-InputBuf; 2613 return(CC_REFRESH); 2614 } 2615 2616 /*ARGSUSED*/ 2617 CCRETVAL 2618 e_killall(Char c) 2619 { 2620 USE(c); 2621 c_push_kill(InputBuf, LastChar); /* copy it */ 2622 Cursor = Mark = LastChar = InputBuf; /* zap! -- delete all of it */ 2623 MarkIsSet = 0; 2624 return(CC_REFRESH); 2625 } 2626 2627 /*ARGSUSED*/ 2628 CCRETVAL 2629 e_killregion(Char c) 2630 { 2631 USE(c); 2632 if (!Mark) 2633 return(CC_ERROR); 2634 2635 if (Mark > Cursor) { 2636 c_push_kill(Cursor, Mark); /* copy it */ 2637 c_delafter((int)(Mark - Cursor)); /* delete it - UNUSED BY VI mode */ 2638 Mark = Cursor; 2639 } 2640 else { /* mark is before cursor */ 2641 c_push_kill(Mark, Cursor); /* copy it */ 2642 c_delbefore((int)(Cursor - Mark)); 2643 } 2644 if (adrof(STRhighlight) && MarkIsSet) { 2645 ClearLines(); 2646 ClearDisp(); 2647 } 2648 MarkIsSet = 0; 2649 return(CC_REFRESH); 2650 } 2651 2652 /*ARGSUSED*/ 2653 CCRETVAL 2654 e_copyregion(Char c) 2655 { 2656 USE(c); 2657 if (!Mark) 2658 return(CC_ERROR); 2659 2660 if (Mark > Cursor) { 2661 c_push_kill(Cursor, Mark); /* copy it */ 2662 } 2663 else { /* mark is before cursor */ 2664 c_push_kill(Mark, Cursor); /* copy it */ 2665 } 2666 return(CC_NORM); /* don't even need to Refresh() */ 2667 } 2668 2669 /*ARGSUSED*/ 2670 CCRETVAL 2671 e_charswitch(Char cc) 2672 { 2673 Char c; 2674 2675 USE(cc); 2676 2677 /* do nothing if we are at beginning of line or have only one char */ 2678 if (Cursor == &InputBuf[0] || LastChar == &InputBuf[1]) { 2679 return(CC_ERROR); 2680 } 2681 2682 if (Cursor < LastChar) { 2683 Cursor++; 2684 } 2685 c = Cursor[-2]; 2686 Cursor[-2] = Cursor[-1]; 2687 Cursor[-1] = c; 2688 return(CC_REFRESH); 2689 } 2690 2691 /*ARGSUSED*/ 2692 CCRETVAL 2693 e_gcharswitch(Char cc) 2694 { /* gosmacs style ^T */ 2695 Char c; 2696 2697 USE(cc); 2698 if (Cursor > &InputBuf[1]) {/* must have at least two chars entered */ 2699 c = Cursor[-2]; 2700 Cursor[-2] = Cursor[-1]; 2701 Cursor[-1] = c; 2702 return(CC_REFRESH); 2703 } 2704 else { 2705 return(CC_ERROR); 2706 } 2707 } 2708 2709 /*ARGSUSED*/ 2710 CCRETVAL 2711 e_charback(Char c) 2712 { 2713 USE(c); 2714 if (Cursor > InputBuf) { 2715 if (Argument > Cursor - InputBuf) 2716 Cursor = InputBuf; 2717 else 2718 Cursor -= Argument; 2719 2720 if (VImode) 2721 if (ActionFlag & TCSHOP_DELETE) { 2722 c_delfini(); 2723 return(CC_REFRESH); 2724 } 2725 2726 RefCursor(); 2727 return(CC_NORM); 2728 } 2729 else { 2730 return(CC_ERROR); 2731 } 2732 } 2733 2734 /*ARGSUSED*/ 2735 CCRETVAL 2736 v_wordback(Char c) 2737 { 2738 USE(c); 2739 if (Cursor == InputBuf) 2740 return(CC_ERROR); 2741 /* else */ 2742 2743 Cursor = c_preword(Cursor, InputBuf, Argument, STRshwspace); /* bounds check */ 2744 2745 if (ActionFlag & TCSHOP_DELETE) { 2746 c_delfini(); 2747 return(CC_REFRESH); 2748 } 2749 2750 RefCursor(); 2751 return(CC_NORM); 2752 } 2753 2754 /*ARGSUSED*/ 2755 CCRETVAL 2756 e_wordback(Char c) 2757 { 2758 USE(c); 2759 if (Cursor == InputBuf) 2760 return(CC_ERROR); 2761 /* else */ 2762 2763 Cursor = c_prev_word(Cursor, InputBuf, Argument); /* bounds check */ 2764 2765 if (VImode) 2766 if (ActionFlag & TCSHOP_DELETE) { 2767 c_delfini(); 2768 return(CC_REFRESH); 2769 } 2770 2771 RefCursor(); 2772 return(CC_NORM); 2773 } 2774 2775 /*ARGSUSED*/ 2776 CCRETVAL 2777 e_charfwd(Char c) 2778 { 2779 USE(c); 2780 if (Cursor < LastChar) { 2781 Cursor += Argument; 2782 if (Cursor > LastChar) 2783 Cursor = LastChar; 2784 2785 if (VImode) 2786 if (ActionFlag & TCSHOP_DELETE) { 2787 c_delfini(); 2788 return(CC_REFRESH); 2789 } 2790 2791 RefCursor(); 2792 return(CC_NORM); 2793 } 2794 else { 2795 return(CC_ERROR); 2796 } 2797 } 2798 2799 /*ARGSUSED*/ 2800 CCRETVAL 2801 e_wordfwd(Char c) 2802 { 2803 USE(c); 2804 if (Cursor == LastChar) 2805 return(CC_ERROR); 2806 /* else */ 2807 2808 Cursor = c_next_word(Cursor, LastChar, Argument); 2809 2810 if (VImode) 2811 if (ActionFlag & TCSHOP_DELETE) { 2812 c_delfini(); 2813 return(CC_REFRESH); 2814 } 2815 2816 RefCursor(); 2817 return(CC_NORM); 2818 } 2819 2820 /*ARGSUSED*/ 2821 CCRETVAL 2822 v_wordfwd(Char c) 2823 { 2824 USE(c); 2825 if (Cursor == LastChar) 2826 return(CC_ERROR); 2827 /* else */ 2828 2829 Cursor = c_nexword(Cursor, LastChar, Argument); 2830 2831 if (VImode) 2832 if (ActionFlag & TCSHOP_DELETE) { 2833 c_delfini(); 2834 return(CC_REFRESH); 2835 } 2836 2837 RefCursor(); 2838 return(CC_NORM); 2839 } 2840 2841 /*ARGSUSED*/ 2842 CCRETVAL 2843 v_wordbegnext(Char c) 2844 { 2845 USE(c); 2846 if (Cursor == LastChar) 2847 return(CC_ERROR); 2848 /* else */ 2849 2850 Cursor = c_next_word(Cursor, LastChar, Argument); 2851 if (Cursor < LastChar) 2852 Cursor++; 2853 2854 if (VImode) 2855 if (ActionFlag & TCSHOP_DELETE) { 2856 c_delfini(); 2857 return(CC_REFRESH); 2858 } 2859 2860 RefCursor(); 2861 return(CC_NORM); 2862 } 2863 2864 /*ARGSUSED*/ 2865 static CCRETVAL 2866 v_repeat_srch(int c) 2867 { 2868 CCRETVAL rv = CC_ERROR; 2869 #ifdef SDEBUG 2870 xprintf("dir %d patlen %d patbuf %S\n", 2871 c, (int)patbuf.len, patbuf.s); 2872 #endif 2873 2874 LastCmd = (KEYCMD) c; /* Hack to stop c_hsetpat */ 2875 LastChar = InputBuf; 2876 switch (c) { 2877 case F_DOWN_SEARCH_HIST: 2878 rv = e_down_search_hist(0); 2879 break; 2880 case F_UP_SEARCH_HIST: 2881 rv = e_up_search_hist(0); 2882 break; 2883 default: 2884 break; 2885 } 2886 return rv; 2887 } 2888 2889 static CCRETVAL 2890 v_csearch_back(Char ch, int count, int tflag) 2891 { 2892 Char *cp; 2893 2894 cp = Cursor; 2895 while (count--) { 2896 if (*cp == ch) 2897 cp--; 2898 while (cp > InputBuf && *cp != ch) 2899 cp--; 2900 } 2901 2902 if (cp < InputBuf || (cp == InputBuf && *cp != ch)) 2903 return(CC_ERROR); 2904 2905 if (*cp == ch && tflag) 2906 cp++; 2907 2908 Cursor = cp; 2909 2910 if (ActionFlag & TCSHOP_DELETE) { 2911 Cursor++; 2912 c_delfini(); 2913 return(CC_REFRESH); 2914 } 2915 2916 RefCursor(); 2917 return(CC_NORM); 2918 } 2919 2920 static CCRETVAL 2921 v_csearch_fwd(Char ch, int count, int tflag) 2922 { 2923 Char *cp; 2924 2925 cp = Cursor; 2926 while (count--) { 2927 if (*cp == ch) 2928 cp++; 2929 while (cp < LastChar && *cp != ch) 2930 cp++; 2931 } 2932 2933 if (cp >= LastChar) 2934 return(CC_ERROR); 2935 2936 if (*cp == ch && tflag) 2937 cp--; 2938 2939 Cursor = cp; 2940 2941 if (ActionFlag & TCSHOP_DELETE) { 2942 Cursor++; 2943 c_delfini(); 2944 return(CC_REFRESH); 2945 } 2946 RefCursor(); 2947 return(CC_NORM); 2948 } 2949 2950 /*ARGSUSED*/ 2951 static CCRETVAL 2952 v_action(int c) 2953 { 2954 Char *cp, *kp; 2955 2956 if (ActionFlag == TCSHOP_DELETE) { 2957 ActionFlag = TCSHOP_NOP; 2958 ActionPos = 0; 2959 2960 UndoSize = 0; 2961 kp = UndoBuf; 2962 for (cp = InputBuf; cp < LastChar; cp++) { 2963 *kp++ = *cp; 2964 UndoSize++; 2965 } 2966 2967 UndoAction = TCSHOP_INSERT; 2968 UndoPtr = InputBuf; 2969 LastChar = InputBuf; 2970 Cursor = InputBuf; 2971 if (c & TCSHOP_INSERT) 2972 c_alternativ_key_map(0); 2973 2974 return(CC_REFRESH); 2975 } 2976 #ifdef notdef 2977 else if (ActionFlag == TCSHOP_NOP) { 2978 #endif 2979 ActionPos = Cursor; 2980 ActionFlag = c; 2981 return(CC_ARGHACK); /* Do NOT clear out argument */ 2982 #ifdef notdef 2983 } 2984 else { 2985 ActionFlag = 0; 2986 ActionPos = 0; 2987 return(CC_ERROR); 2988 } 2989 #endif 2990 } 2991 2992 #ifdef COMMENT 2993 /* by: Brian Allison <uiucdcs!convex!allison@RUTGERS.EDU> */ 2994 static void 2995 c_get_word(Char **begin, Char **end) 2996 { 2997 Char *cp; 2998 2999 cp = &Cursor[0]; 3000 while (Argument--) { 3001 while ((cp <= LastChar) && (isword(*cp))) 3002 cp++; 3003 *end = --cp; 3004 while ((cp >= InputBuf) && (isword(*cp))) 3005 cp--; 3006 *begin = ++cp; 3007 } 3008 } 3009 #endif /* COMMENT */ 3010 3011 /*ARGSUSED*/ 3012 CCRETVAL 3013 e_uppercase(Char c) 3014 { 3015 Char *cp, *end; 3016 3017 USE(c); 3018 end = c_next_word(Cursor, LastChar, Argument); 3019 3020 for (cp = Cursor; cp < end; cp++) /* PWP: was cp=begin */ 3021 if (Islower(*cp)) 3022 *cp = Toupper(*cp); 3023 3024 Cursor = end; 3025 if (Cursor > LastChar) 3026 Cursor = LastChar; 3027 return(CC_REFRESH); 3028 } 3029 3030 3031 /*ARGSUSED*/ 3032 CCRETVAL 3033 e_capitalcase(Char c) 3034 { 3035 Char *cp, *end; 3036 3037 USE(c); 3038 end = c_next_word(Cursor, LastChar, Argument); 3039 3040 cp = Cursor; 3041 for (; cp < end; cp++) { 3042 if (Isalpha(*cp)) { 3043 if (Islower(*cp)) 3044 *cp = Toupper(*cp); 3045 cp++; 3046 break; 3047 } 3048 } 3049 for (; cp < end; cp++) 3050 if (Isupper(*cp)) 3051 *cp = Tolower(*cp); 3052 3053 Cursor = end; 3054 if (Cursor > LastChar) 3055 Cursor = LastChar; 3056 return(CC_REFRESH); 3057 } 3058 3059 /*ARGSUSED*/ 3060 CCRETVAL 3061 e_lowercase(Char c) 3062 { 3063 Char *cp, *end; 3064 3065 USE(c); 3066 end = c_next_word(Cursor, LastChar, Argument); 3067 3068 for (cp = Cursor; cp < end; cp++) 3069 if (Isupper(*cp)) 3070 *cp = Tolower(*cp); 3071 3072 Cursor = end; 3073 if (Cursor > LastChar) 3074 Cursor = LastChar; 3075 return(CC_REFRESH); 3076 } 3077 3078 3079 /*ARGSUSED*/ 3080 CCRETVAL 3081 e_set_mark(Char c) 3082 { 3083 USE(c); 3084 if (adrof(STRhighlight) && MarkIsSet && Mark != Cursor) { 3085 ClearLines(); 3086 ClearDisp(); 3087 Refresh(); 3088 } 3089 Mark = Cursor; 3090 MarkIsSet = 1; 3091 return(CC_NORM); 3092 } 3093 3094 /*ARGSUSED*/ 3095 CCRETVAL 3096 e_exchange_mark(Char c) 3097 { 3098 Char *cp; 3099 3100 USE(c); 3101 cp = Cursor; 3102 Cursor = Mark; 3103 Mark = cp; 3104 RefCursor(); 3105 return(CC_NORM); 3106 } 3107 3108 /*ARGSUSED*/ 3109 CCRETVAL 3110 e_argfour(Char c) 3111 { /* multiply current argument by 4 */ 3112 USE(c); 3113 if (Argument > 1000000) 3114 return CC_ERROR; 3115 DoingArg = 1; 3116 Argument *= 4; 3117 return(CC_ARGHACK); 3118 } 3119 3120 static void 3121 quote_mode_cleanup(void *unused) 3122 { 3123 USE(unused); 3124 QuoteModeOff(); 3125 } 3126 3127 /*ARGSUSED*/ 3128 CCRETVAL 3129 e_quote(Char c) 3130 { 3131 Char ch; 3132 int num; 3133 3134 USE(c); 3135 QuoteModeOn(); 3136 cleanup_push(&c, quote_mode_cleanup); /* Using &c just as a mark */ 3137 num = GetNextChar(&ch); 3138 cleanup_until(&c); 3139 if (num == 1) 3140 return e_insert(ch); 3141 else 3142 return e_send_eof(0); 3143 } 3144 3145 /*ARGSUSED*/ 3146 CCRETVAL 3147 e_metanext(Char c) 3148 { 3149 USE(c); 3150 MetaNext = 1; 3151 return(CC_ARGHACK); /* preserve argument */ 3152 } 3153 3154 #ifdef notdef 3155 /*ARGSUSED*/ 3156 CCRETVAL 3157 e_extendnext(Char c) 3158 { 3159 CurrentKeyMap = CcAltMap; 3160 return(CC_ARGHACK); /* preserve argument */ 3161 } 3162 3163 #endif 3164 3165 /*ARGSUSED*/ 3166 CCRETVAL 3167 v_insbeg(Char c) 3168 { /* move to beginning of line and start vi 3169 * insert mode */ 3170 USE(c); 3171 Cursor = InputBuf; 3172 InsertPos = Cursor; 3173 3174 UndoPtr = Cursor; 3175 UndoAction = TCSHOP_DELETE; 3176 3177 RefCursor(); /* move the cursor */ 3178 c_alternativ_key_map(0); 3179 return(CC_NORM); 3180 } 3181 3182 /*ARGSUSED*/ 3183 CCRETVAL 3184 v_replone(Char c) 3185 { /* vi mode overwrite one character */ 3186 USE(c); 3187 c_alternativ_key_map(0); 3188 inputmode = MODE_REPLACE_1; 3189 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */ 3190 UndoPtr = Cursor; 3191 UndoSize = 0; 3192 return(CC_NORM); 3193 } 3194 3195 /*ARGSUSED*/ 3196 CCRETVAL 3197 v_replmode(Char c) 3198 { /* vi mode start overwriting */ 3199 USE(c); 3200 c_alternativ_key_map(0); 3201 inputmode = MODE_REPLACE; 3202 UndoAction = TCSHOP_CHANGE; /* Set Up for VI undo command */ 3203 UndoPtr = Cursor; 3204 UndoSize = 0; 3205 return(CC_NORM); 3206 } 3207 3208 /*ARGSUSED*/ 3209 CCRETVAL 3210 v_substchar(Char c) 3211 { /* vi mode substitute for one char */ 3212 USE(c); 3213 c_delafter(Argument); 3214 c_alternativ_key_map(0); 3215 return(CC_REFRESH); 3216 } 3217 3218 /*ARGSUSED*/ 3219 CCRETVAL 3220 v_substline(Char c) 3221 { /* vi mode replace whole line */ 3222 USE(c); 3223 (void) e_killall(0); 3224 c_alternativ_key_map(0); 3225 return(CC_REFRESH); 3226 } 3227 3228 /*ARGSUSED*/ 3229 CCRETVAL 3230 v_chgtoend(Char c) 3231 { /* vi mode change to end of line */ 3232 USE(c); 3233 (void) e_killend(0); 3234 c_alternativ_key_map(0); 3235 return(CC_REFRESH); 3236 } 3237 3238 /*ARGSUSED*/ 3239 CCRETVAL 3240 v_insert(Char c) 3241 { /* vi mode start inserting */ 3242 USE(c); 3243 c_alternativ_key_map(0); 3244 3245 InsertPos = Cursor; 3246 UndoPtr = Cursor; 3247 UndoAction = TCSHOP_DELETE; 3248 3249 return(CC_NORM); 3250 } 3251 3252 /*ARGSUSED*/ 3253 CCRETVAL 3254 v_add(Char c) 3255 { /* vi mode start adding */ 3256 USE(c); 3257 c_alternativ_key_map(0); 3258 if (Cursor < LastChar) 3259 { 3260 Cursor++; 3261 if (Cursor > LastChar) 3262 Cursor = LastChar; 3263 RefCursor(); 3264 } 3265 3266 InsertPos = Cursor; 3267 UndoPtr = Cursor; 3268 UndoAction = TCSHOP_DELETE; 3269 3270 return(CC_NORM); 3271 } 3272 3273 /*ARGSUSED*/ 3274 CCRETVAL 3275 v_addend(Char c) 3276 { /* vi mode to add at end of line */ 3277 USE(c); 3278 c_alternativ_key_map(0); 3279 Cursor = LastChar; 3280 3281 InsertPos = LastChar; /* Mark where insertion begins */ 3282 UndoPtr = LastChar; 3283 UndoAction = TCSHOP_DELETE; 3284 3285 RefCursor(); 3286 return(CC_NORM); 3287 } 3288 3289 /*ARGSUSED*/ 3290 CCRETVAL 3291 v_change_case(Char cc) 3292 { 3293 Char c; 3294 3295 USE(cc); 3296 if (Cursor < LastChar) { 3297 #ifndef WINNT_NATIVE 3298 c = *Cursor; 3299 #else 3300 c = CHAR & *Cursor; 3301 #endif /* WINNT_NATIVE */ 3302 if (Isupper(c)) 3303 *Cursor++ = Tolower(c); 3304 else if (Islower(c)) 3305 *Cursor++ = Toupper(c); 3306 else 3307 Cursor++; 3308 RefPlusOne(1); /* fast refresh for one char */ 3309 return(CC_NORM); 3310 } 3311 return(CC_ERROR); 3312 } 3313 3314 /*ARGSUSED*/ 3315 CCRETVAL 3316 e_expand(Char c) 3317 { 3318 Char *p; 3319 3320 USE(c); 3321 for (p = InputBuf; Isspace(*p); p++) 3322 continue; 3323 if (p == LastChar) 3324 return(CC_ERROR); 3325 3326 justpr++; 3327 Expand++; 3328 return(e_newline(0)); 3329 } 3330 3331 /*ARGSUSED*/ 3332 CCRETVAL 3333 e_startover(Char c) 3334 { /* erase all of current line, start again */ 3335 USE(c); 3336 ResetInLine(0); /* reset the input pointers */ 3337 return(CC_REFRESH); 3338 } 3339 3340 /*ARGSUSED*/ 3341 CCRETVAL 3342 e_redisp(Char c) 3343 { 3344 USE(c); 3345 ClearLines(); 3346 ClearDisp(); 3347 return(CC_REFRESH); 3348 } 3349 3350 /*ARGSUSED*/ 3351 CCRETVAL 3352 e_cleardisp(Char c) 3353 { 3354 USE(c); 3355 ClearScreen(); /* clear the whole real screen */ 3356 ClearDisp(); /* reset everything */ 3357 return(CC_REFRESH); 3358 } 3359 3360 /*ARGSUSED*/ 3361 CCRETVAL 3362 e_tty_int(Char c) 3363 { 3364 USE(c); 3365 #if defined(_MINIX) || defined(WINNT_NATIVE) 3366 /* SAK PATCH: erase all of current line, start again */ 3367 ResetInLine(0); /* reset the input pointers */ 3368 xputchar('\n'); 3369 ClearDisp(); 3370 return (CC_REFRESH); 3371 #else /* !_MINIX && !WINNT_NATIVE */ 3372 /* do no editing */ 3373 return (CC_NORM); 3374 #endif /* _MINIX || WINNT_NATIVE */ 3375 } 3376 3377 /* 3378 * From: ghazi@cesl.rutgers.edu (Kaveh R. Ghazi) 3379 * Function to send a character back to the input stream in cooked 3380 * mode. Only works if we have TIOCSTI 3381 */ 3382 /*ARGSUSED*/ 3383 CCRETVAL 3384 e_stuff_char(Char c) 3385 { 3386 #ifdef TIOCSTI 3387 int was_raw = Tty_raw_mode; 3388 char buf[MB_LEN_MAX]; 3389 size_t i, len; 3390 3391 if (was_raw) 3392 (void) Cookedmode(); 3393 3394 (void) xwrite(SHIN, "\n", 1); 3395 len = one_wctomb(buf, c); 3396 for (i = 0; i < len; i++) 3397 (void) ioctl(SHIN, TIOCSTI, (ioctl_t) &buf[i]); 3398 3399 if (was_raw) 3400 (void) Rawmode(); 3401 return(e_redisp(c)); 3402 #else /* !TIOCSTI */ 3403 return(CC_ERROR); 3404 #endif /* !TIOCSTI */ 3405 } 3406 3407 /*ARGSUSED*/ 3408 CCRETVAL 3409 e_insovr(Char c) 3410 { 3411 USE(c); 3412 inputmode = (inputmode == MODE_INSERT ? MODE_REPLACE : MODE_INSERT); 3413 return(CC_NORM); 3414 } 3415 3416 /*ARGSUSED*/ 3417 CCRETVAL 3418 e_tty_dsusp(Char c) 3419 { 3420 USE(c); 3421 /* do no editing */ 3422 return(CC_NORM); 3423 } 3424 3425 /*ARGSUSED*/ 3426 CCRETVAL 3427 e_tty_flusho(Char c) 3428 { 3429 USE(c); 3430 /* do no editing */ 3431 return(CC_NORM); 3432 } 3433 3434 /*ARGSUSED*/ 3435 CCRETVAL 3436 e_tty_quit(Char c) 3437 { 3438 USE(c); 3439 /* do no editing */ 3440 return(CC_NORM); 3441 } 3442 3443 /*ARGSUSED*/ 3444 CCRETVAL 3445 e_tty_tsusp(Char c) 3446 { 3447 USE(c); 3448 /* do no editing */ 3449 return(CC_NORM); 3450 } 3451 3452 /*ARGSUSED*/ 3453 CCRETVAL 3454 e_tty_stopo(Char c) 3455 { 3456 USE(c); 3457 /* do no editing */ 3458 return(CC_NORM); 3459 } 3460 3461 /* returns the number of (attempted) expansions */ 3462 int 3463 ExpandHistory(void) 3464 { 3465 *LastChar = '\0'; /* just in case */ 3466 return c_substitute(); 3467 } 3468 3469 /*ARGSUSED*/ 3470 CCRETVAL 3471 e_expand_history(Char c) 3472 { 3473 USE(c); 3474 (void)ExpandHistory(); 3475 return(CC_NORM); 3476 } 3477 3478 /*ARGSUSED*/ 3479 CCRETVAL 3480 e_magic_space(Char c) 3481 { 3482 USE(c); 3483 *LastChar = '\0'; /* just in case */ 3484 (void)c_substitute(); 3485 return(e_insert(' ')); 3486 } 3487 3488 /*ARGSUSED*/ 3489 CCRETVAL 3490 e_inc_fwd(Char c) 3491 { 3492 CCRETVAL ret; 3493 3494 USE(c); 3495 patbuf.len = 0; 3496 MarkIsSet = 0; 3497 ret = e_inc_search(F_DOWN_SEARCH_HIST); 3498 if (adrof(STRhighlight) && IncMatchLen) { 3499 IncMatchLen = 0; 3500 ClearLines(); 3501 ClearDisp(); 3502 Refresh(); 3503 } 3504 IncMatchLen = 0; 3505 return ret; 3506 } 3507 3508 3509 /*ARGSUSED*/ 3510 CCRETVAL 3511 e_inc_back(Char c) 3512 { 3513 CCRETVAL ret; 3514 3515 USE(c); 3516 patbuf.len = 0; 3517 MarkIsSet = 0; 3518 ret = e_inc_search(F_UP_SEARCH_HIST); 3519 if (adrof(STRhighlight) && IncMatchLen) { 3520 IncMatchLen = 0; 3521 ClearLines(); 3522 ClearDisp(); 3523 Refresh(); 3524 } 3525 IncMatchLen = 0; 3526 return ret; 3527 } 3528 3529 /*ARGSUSED*/ 3530 CCRETVAL 3531 e_copyprev(Char c) 3532 { 3533 Char *cp, *oldc, *dp; 3534 3535 USE(c); 3536 if (Cursor == InputBuf) 3537 return(CC_ERROR); 3538 /* else */ 3539 3540 oldc = Cursor; 3541 /* does a bounds check */ 3542 cp = c_prev_word(Cursor, InputBuf, Argument); 3543 3544 c_insert((int)(oldc - cp)); 3545 for (dp = oldc; cp < oldc && dp < LastChar; cp++) 3546 *dp++ = *cp; 3547 3548 Cursor = dp; /* put cursor at end */ 3549 3550 return(CC_REFRESH); 3551 } 3552 3553 /*ARGSUSED*/ 3554 CCRETVAL 3555 e_tty_starto(Char c) 3556 { 3557 USE(c); 3558 /* do no editing */ 3559 return(CC_NORM); 3560 } 3561 3562 /*ARGSUSED*/ 3563 CCRETVAL 3564 e_load_average(Char c) 3565 { 3566 USE(c); 3567 PastBottom(); 3568 #ifdef TIOCSTAT 3569 /* 3570 * Here we pass &c to the ioctl because some os's (NetBSD) expect it 3571 * there even if they don't use it. (lukem@netbsd.org) 3572 */ 3573 if (ioctl(SHIN, TIOCSTAT, (ioctl_t) &c) < 0) 3574 #endif 3575 xprintf("%s", CGETS(5, 1, "Load average unavailable\n")); 3576 return(CC_REFRESH); 3577 } 3578 3579 /*ARGSUSED*/ 3580 CCRETVAL 3581 v_chgmeta(Char c) 3582 { 3583 USE(c); 3584 /* 3585 * Delete with insert == change: first we delete and then we leave in 3586 * insert mode. 3587 */ 3588 return(v_action(TCSHOP_DELETE|TCSHOP_INSERT)); 3589 } 3590 3591 /*ARGSUSED*/ 3592 CCRETVAL 3593 v_delmeta(Char c) 3594 { 3595 USE(c); 3596 return(v_action(TCSHOP_DELETE)); 3597 } 3598 3599 3600 /*ARGSUSED*/ 3601 CCRETVAL 3602 v_endword(Char c) 3603 { 3604 USE(c); 3605 if (Cursor == LastChar) 3606 return(CC_ERROR); 3607 /* else */ 3608 3609 Cursor = c_endword(Cursor, InputBuf, LastChar, Argument, STRshwspace); 3610 3611 if (ActionFlag & TCSHOP_DELETE) 3612 { 3613 Cursor++; 3614 c_delfini(); 3615 return(CC_REFRESH); 3616 } 3617 3618 RefCursor(); 3619 return(CC_NORM); 3620 } 3621 3622 /*ARGSUSED*/ 3623 CCRETVAL 3624 v_eword(Char c) 3625 { 3626 USE(c); 3627 if (Cursor == LastChar) 3628 return(CC_ERROR); 3629 /* else */ 3630 3631 Cursor = c_eword(Cursor, LastChar, Argument); 3632 3633 if (ActionFlag & TCSHOP_DELETE) { 3634 Cursor++; 3635 c_delfini(); 3636 return(CC_REFRESH); 3637 } 3638 3639 RefCursor(); 3640 return(CC_NORM); 3641 } 3642 3643 /*ARGSUSED*/ 3644 CCRETVAL 3645 v_char_fwd(Char c) 3646 { 3647 Char ch; 3648 3649 USE(c); 3650 if (GetNextChar(&ch) != 1) 3651 return e_send_eof(0); 3652 3653 srch_dir = CHAR_FWD; 3654 srch_char = ch; 3655 3656 return v_csearch_fwd(ch, Argument, 0); 3657 3658 } 3659 3660 /*ARGSUSED*/ 3661 CCRETVAL 3662 v_char_back(Char c) 3663 { 3664 Char ch; 3665 3666 USE(c); 3667 if (GetNextChar(&ch) != 1) 3668 return e_send_eof(0); 3669 3670 srch_dir = CHAR_BACK; 3671 srch_char = ch; 3672 3673 return v_csearch_back(ch, Argument, 0); 3674 } 3675 3676 /*ARGSUSED*/ 3677 CCRETVAL 3678 v_charto_fwd(Char c) 3679 { 3680 Char ch; 3681 3682 USE(c); 3683 if (GetNextChar(&ch) != 1) 3684 return e_send_eof(0); 3685 3686 return v_csearch_fwd(ch, Argument, 1); 3687 3688 } 3689 3690 /*ARGSUSED*/ 3691 CCRETVAL 3692 v_charto_back(Char c) 3693 { 3694 Char ch; 3695 3696 USE(c); 3697 if (GetNextChar(&ch) != 1) 3698 return e_send_eof(0); 3699 3700 return v_csearch_back(ch, Argument, 1); 3701 } 3702 3703 /*ARGSUSED*/ 3704 CCRETVAL 3705 v_rchar_fwd(Char c) 3706 { 3707 USE(c); 3708 if (srch_char == 0) 3709 return CC_ERROR; 3710 3711 return srch_dir == CHAR_FWD ? v_csearch_fwd(srch_char, Argument, 0) : 3712 v_csearch_back(srch_char, Argument, 0); 3713 } 3714 3715 /*ARGSUSED*/ 3716 CCRETVAL 3717 v_rchar_back(Char c) 3718 { 3719 USE(c); 3720 if (srch_char == 0) 3721 return CC_ERROR; 3722 3723 return srch_dir == CHAR_BACK ? v_csearch_fwd(srch_char, Argument, 0) : 3724 v_csearch_back(srch_char, Argument, 0); 3725 } 3726 3727 /*ARGSUSED*/ 3728 CCRETVAL 3729 v_undo(Char c) 3730 { 3731 int loop; 3732 Char *kp, *cp; 3733 Char temp; 3734 int size; 3735 3736 USE(c); 3737 switch (UndoAction) { 3738 case TCSHOP_DELETE|TCSHOP_INSERT: 3739 case TCSHOP_DELETE: 3740 if (UndoSize == 0) return(CC_NORM); 3741 cp = UndoPtr; 3742 kp = UndoBuf; 3743 for (loop=0; loop < UndoSize; loop++) /* copy the chars */ 3744 *kp++ = *cp++; /* into UndoBuf */ 3745 3746 for (cp = UndoPtr; cp <= LastChar; cp++) 3747 *cp = cp[UndoSize]; 3748 3749 LastChar -= UndoSize; 3750 Cursor = UndoPtr; 3751 3752 UndoAction = TCSHOP_INSERT; 3753 break; 3754 3755 case TCSHOP_INSERT: 3756 if (UndoSize == 0) return(CC_NORM); 3757 cp = UndoPtr; 3758 Cursor = UndoPtr; 3759 kp = UndoBuf; 3760 c_insert(UndoSize); /* open the space, */ 3761 for (loop = 0; loop < UndoSize; loop++) /* copy the chars */ 3762 *cp++ = *kp++; 3763 3764 UndoAction = TCSHOP_DELETE; 3765 break; 3766 3767 case TCSHOP_CHANGE: 3768 if (UndoSize == 0) return(CC_NORM); 3769 cp = UndoPtr; 3770 Cursor = UndoPtr; 3771 kp = UndoBuf; 3772 size = (int)(Cursor-LastChar); /* NOT NSL independant */ 3773 if (size < UndoSize) 3774 size = UndoSize; 3775 for (loop = 0; loop < size; loop++) { 3776 temp = *kp; 3777 *kp++ = *cp; 3778 *cp++ = temp; 3779 } 3780 break; 3781 3782 default: 3783 return(CC_ERROR); 3784 } 3785 3786 return(CC_REFRESH); 3787 } 3788 3789 /*ARGSUSED*/ 3790 CCRETVAL 3791 v_ush_meta(Char c) 3792 { 3793 USE(c); 3794 return v_search(F_UP_SEARCH_HIST); 3795 } 3796 3797 /*ARGSUSED*/ 3798 CCRETVAL 3799 v_dsh_meta(Char c) 3800 { 3801 USE(c); 3802 return v_search(F_DOWN_SEARCH_HIST); 3803 } 3804 3805 /*ARGSUSED*/ 3806 CCRETVAL 3807 v_rsrch_fwd(Char c) 3808 { 3809 USE(c); 3810 if (patbuf.len == 0) return(CC_ERROR); 3811 return(v_repeat_srch(searchdir)); 3812 } 3813 3814 /*ARGSUSED*/ 3815 CCRETVAL 3816 v_rsrch_back(Char c) 3817 { 3818 USE(c); 3819 if (patbuf.len == 0) return(CC_ERROR); 3820 return(v_repeat_srch(searchdir == F_UP_SEARCH_HIST ? 3821 F_DOWN_SEARCH_HIST : F_UP_SEARCH_HIST)); 3822 } 3823 3824 #ifndef WINNT_NATIVE 3825 /* Since ed.defns.h is generated from ed.defns.c, these empty 3826 functions will keep the F_NUM_FNS consistent 3827 */ 3828 CCRETVAL 3829 e_copy_to_clipboard(Char c) 3830 { 3831 USE(c); 3832 return CC_ERROR; 3833 } 3834 3835 CCRETVAL 3836 e_paste_from_clipboard(Char c) 3837 { 3838 USE(c); 3839 return (CC_ERROR); 3840 } 3841 3842 CCRETVAL 3843 e_dosify_next(Char c) 3844 { 3845 USE(c); 3846 return (CC_ERROR); 3847 } 3848 CCRETVAL 3849 e_dosify_prev(Char c) 3850 { 3851 USE(c); 3852 return (CC_ERROR); 3853 } 3854 CCRETVAL 3855 e_page_up(Char c) 3856 { 3857 USE(c); 3858 return (CC_ERROR); 3859 } 3860 CCRETVAL 3861 e_page_down(Char c) 3862 { 3863 USE(c); 3864 return (CC_ERROR); 3865 } 3866 #endif /* !WINNT_NATIVE */ 3867 3868 #ifdef notdef 3869 void 3870 MoveCursor(int n) /* move cursor + right - left char */ 3871 { 3872 Cursor = Cursor + n; 3873 if (Cursor < InputBuf) 3874 Cursor = InputBuf; 3875 if (Cursor > LastChar) 3876 Cursor = LastChar; 3877 return; 3878 } 3879 3880 Char * 3881 GetCursor(void) 3882 { 3883 return(Cursor); 3884 } 3885 3886 int 3887 PutCursor(Char *p) 3888 { 3889 if (p < InputBuf || p > LastChar) 3890 return 1; /* Error */ 3891 Cursor = p; 3892 return 0; 3893 } 3894 #endif 3895