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