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