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