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