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