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