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