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