1/* 2 * zle_misc.c - miscellaneous editor routines 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1992-1997 Paul Falstad 7 * All rights reserved. 8 * 9 * Permission is hereby granted, without written agreement and without 10 * license or royalty fees, to use, copy, modify, and distribute this 11 * software and to distribute modified versions of this software for any 12 * purpose, provided that the above copyright notice and the following 13 * two paragraphs appear in all copies of this software. 14 * 15 * In no event shall Paul Falstad or the Zsh Development Group be liable 16 * to any party for direct, indirect, special, incidental, or consequential 17 * damages arising out of the use of this software and its documentation, 18 * even if Paul Falstad and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Paul Falstad and the Zsh Development Group specifically disclaim any 22 * warranties, including, but not limited to, the implied warranties of 23 * merchantability and fitness for a particular purpose. The software 24 * provided hereunder is on an "as is" basis, and Paul Falstad and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "zle.mdh" 31#include "zle_misc.pro" 32 33/* insert a zle string, with repetition and suffix removal */ 34 35/**/ 36void 37doinsert(ZLE_STRING_T zstr, int len) 38{ 39 ZLE_STRING_T s; 40 ZLE_CHAR_T c1 = *zstr; /* first character */ 41 int neg = zmult < 0; /* insert *after* the cursor? */ 42 int m = neg ? -zmult : zmult; /* number of copies to insert */ 43 int count; 44 45 UNMETACHECK(); 46 47 iremovesuffix(c1, 0); 48 invalidatelist(); 49 50 if (insmode) 51 spaceinline(m * len); 52 else 53#ifdef MULTIBYTE_SUPPORT 54 { 55 int pos = zlecs, diff, i; 56 57 /* 58 * Calculate the number of character positions we are 59 * going to be using. The algorithm is that 60 * anything that shows up as a logical single character 61 * (i.e. even if control, or double width, or with combining 62 * characters) is treated as 1 for the purpose of replacing 63 * what's there already. 64 * 65 * This can cause inserting of a combining character in 66 * places where it should overwrite, such as the start 67 * of a line. However, combining characters aren't 68 * useful there anyway and this doesn't cause any 69 * particular harm. 70 */ 71 for (i = 0, count = 0; i < len; i++) { 72 if (!IS_COMBINING(zstr[i])) 73 count++; 74 } 75 /* 76 * Ensure we replace a complete combining character 77 * for each character we overwrite. 78 */ 79 for (i = count; pos < zlell && i--; ) { 80 INCPOS(pos); 81 } 82 /* 83 * Calculate how many raw line places we need. 84 * pos - zlecs is the raw line distance we're replacing, 85 * m * len the number we're inserting. 86 */ 87 diff = pos - zlecs - m * len; 88 if (diff < 0) { 89 spaceinline(-diff); 90 } else if (diff > 0) { 91 /* 92 * We use shiftchars() here because we don't 93 * want combining char alignment fixed up: we 94 * are going to write over any that remain. 95 */ 96 shiftchars(zlecs, diff); 97 } 98 } 99#else 100 if (zlecs + m * len > zlell) 101 spaceinline(zlecs + m * len - zlell); 102#endif 103 while (m--) 104 for (s = zstr, count = len; count; s++, count--) 105 zleline[zlecs++] = *s; 106 if (neg) 107 zlecs += zmult * len; 108 /* if we ended up on a combining character, skip over it */ 109 CCRIGHT(); 110} 111 112/**/ 113mod_export int 114selfinsert(UNUSED(char **args)) 115{ 116 ZLE_CHAR_T tmp; 117 118#ifdef MULTIBYTE_SUPPORT 119 if (!lastchar_wide_valid) 120 if (getrestchar(lastchar) == WEOF) 121 return 1; 122#endif 123 tmp = LASTFULLCHAR; 124 doinsert(&tmp, 1); 125 return 0; 126} 127 128/**/ 129mod_export void 130fixunmeta(void) 131{ 132 lastchar &= 0x7f; 133 if (lastchar == '\r') 134 lastchar = '\n'; 135#ifdef MULTIBYTE_SUPPORT 136 /* 137 * TODO: can we do this better? 138 * We need a wide character to insert. 139 * selfinsertunmeta is intrinsically problematic 140 * with multibyte input. 141 */ 142 lastchar_wide = (ZLE_INT_T)lastchar; 143 lastchar_wide_valid = 1; 144#endif 145} 146 147/**/ 148mod_export int 149selfinsertunmeta(char **args) 150{ 151 fixunmeta(); 152 return selfinsert(args); 153} 154 155/**/ 156int 157deletechar(char **args) 158{ 159 int n; 160 if (zmult < 0) { 161 int ret; 162 zmult = -zmult; 163 ret = backwarddeletechar(args); 164 zmult = -zmult; 165 return ret; 166 } 167 168 n = zmult; 169 while (n--) { 170 if (zlecs == zlell) 171 return 1; 172 INCCS(); 173 } 174 backdel(zmult, 0); 175 return 0; 176} 177 178/**/ 179int 180backwarddeletechar(char **args) 181{ 182 if (zmult < 0) { 183 int ret; 184 zmult = -zmult; 185 ret = deletechar(args); 186 zmult = -zmult; 187 return ret; 188 } 189 backdel(zmult > zlecs ? zlecs : zmult, 0); 190 return 0; 191} 192 193/**/ 194int 195killwholeline(UNUSED(char **args)) 196{ 197 int i, fg, n = zmult; 198 199 if (n < 0) 200 return 1; 201 while (n--) { 202 if ((fg = (zlecs && zlecs == zlell))) 203 zlecs--; 204 while (zlecs && zleline[zlecs - 1] != '\n') 205 zlecs--; 206 for (i = zlecs; i != zlell && zleline[i] != '\n'; i++); 207 forekill(i - zlecs + (i != zlell), fg ? (CUT_FRONT|CUT_RAW) : CUT_RAW); 208 } 209 clearlist = 1; 210 return 0; 211} 212 213/**/ 214int 215killbuffer(UNUSED(char **args)) 216{ 217 zlecs = 0; 218 forekill(zlell, CUT_RAW); 219 clearlist = 1; 220 return 0; 221} 222 223/**/ 224int 225backwardkillline(char **args) 226{ 227 int i = 0, n = zmult; 228 229 if (n < 0) { 230 int ret; 231 zmult = -n; 232 ret = killline(args); 233 zmult = n; 234 return ret; 235 } 236 while (n--) { 237 if (zlecs && zleline[zlecs - 1] == '\n') 238 zlecs--, i++; 239 else 240 while (zlecs && zleline[zlecs - 1] != '\n') 241 zlecs--, i++; 242 } 243 forekill(i, CUT_FRONT|CUT_RAW); 244 clearlist = 1; 245 return 0; 246} 247 248#ifdef MULTIBYTE_SUPPORT 249/* 250 * Transpose the chunk of the line from start to middle with 251 * that from middle to end. 252 */ 253 254static void 255transpose_swap(int start, int middle, int end) 256{ 257 int len1, len2; 258 ZLE_STRING_T first; 259 260 len1 = middle - start; 261 len2 = end - middle; 262 263 first = (ZLE_STRING_T)zalloc(len1 * ZLE_CHAR_SIZE); 264 ZS_memcpy(first, zleline + start, len1); 265 /* Move may be overlapping... */ 266 ZS_memmove(zleline + start, zleline + middle, len2); 267 ZS_memcpy(zleline + start + len2, first, len1); 268 zfree(first, len1 * ZLE_CHAR_SIZE); 269} 270#endif 271 272/**/ 273int 274gosmacstransposechars(UNUSED(char **args)) 275{ 276 if (zlecs < 2 || zleline[zlecs - 1] == '\n' || zleline[zlecs - 2] == '\n') { 277 int twice = (zlecs == 0 || zleline[zlecs - 1] == '\n'); 278 279 if (zlecs == zlell || zleline[zlecs] == '\n') 280 return 1; 281 282 INCCS(); 283 if (twice) { 284 if (zlecs == zlell || zleline[zlecs] == '\n') 285 return 1; 286 INCCS(); 287 } 288 } 289#ifdef MULTIBYTE_SUPPORT 290 { 291 int start, middle; 292 293 middle = zlecs; 294 DECPOS(middle); 295 296 start = middle; 297 DECPOS(start); 298 299 transpose_swap(start, middle, zlecs); 300 } 301#else 302 { 303 ZLE_CHAR_T cc = zleline[zlecs - 2]; 304 zleline[zlecs - 2] = zleline[zlecs - 1]; 305 zleline[zlecs - 1] = cc; 306 } 307#endif 308 return 0; 309} 310 311/**/ 312int 313transposechars(UNUSED(char **args)) 314{ 315 int ct; 316 int n = zmult; 317 int neg = n < 0; 318 319 if (neg) 320 n = -n; 321 while (n--) { 322 if (!(ct = zlecs) || zleline[zlecs - 1] == '\n') { 323 if (zlell == zlecs || zleline[zlecs] == '\n') 324 return 1; 325 if (!neg) 326 INCCS(); 327 INCPOS(ct); 328 } 329 if (neg) { 330 if (zlecs && zleline[zlecs - 1] != '\n') { 331 DECCS(); 332 if (ct > 1 && zleline[ct - 2] != '\n') { 333 DECPOS(ct); 334 } 335 } 336 } else { 337 if (zlecs != zlell && zleline[zlecs] != '\n') 338 INCCS(); 339 } 340 if (ct == zlell || zleline[ct] == '\n') { 341 DECPOS(ct); 342 } 343 if (ct < 1 || zleline[ct - 1] == '\n') 344 return 1; 345#ifdef MULTIBYTE_SUPPORT 346 { 347 /* 348 * We should keep any accents etc. on their original characters. 349 */ 350 int start = ct, end = ct; 351 DECPOS(start); 352 INCPOS(end); 353 354 transpose_swap(start, ct, end); 355 } 356#else 357 { 358 ZLE_CHAR_T cc = zleline[ct - 1]; 359 zleline[ct - 1] = zleline[ct]; 360 zleline[ct] = cc; 361 } 362#endif 363 } 364 return 0; 365} 366 367/**/ 368int 369poundinsert(UNUSED(char **args)) 370{ 371 zlecs = 0; 372 vifirstnonblank(zlenoargs); 373 if (zleline[zlecs] != '#') { 374 spaceinline(1); 375 zleline[zlecs] = '#'; 376 zlecs = findeol(); 377 while(zlecs != zlell) { 378 zlecs++; 379 vifirstnonblank(zlenoargs); 380 spaceinline(1); 381 zleline[zlecs] = '#'; 382 zlecs = findeol(); 383 } 384 } else { 385 foredel(1, 0); 386 zlecs = findeol(); 387 while(zlecs != zlell) { 388 zlecs++; 389 vifirstnonblank(zlenoargs); 390 if(zleline[zlecs] == '#') 391 foredel(1, 0); 392 zlecs = findeol(); 393 } 394 } 395 done = 1; 396 return 0; 397} 398 399/**/ 400int 401acceptline(UNUSED(char **args)) 402{ 403 done = 1; 404 return 0; 405} 406 407/**/ 408int 409acceptandhold(UNUSED(char **args)) 410{ 411 zpushnode(bufstack, zlelineasstring(zleline, zlell, 0, NULL, NULL, 0)); 412 stackcs = zlecs; 413 done = 1; 414 return 0; 415} 416 417/**/ 418int 419killline(char **args) 420{ 421 int i = 0, n = zmult; 422 423 if (n < 0) { 424 int ret; 425 zmult = -n; 426 ret = backwardkillline(args); 427 zmult = n; 428 return ret; 429 } 430 while (n--) { 431 if (zleline[zlecs] == ZWC('\n')) 432 zlecs++, i++; 433 else 434 while (zlecs != zlell && zleline[zlecs] != ZWC('\n')) 435 zlecs++, i++; 436 } 437 backkill(i, CUT_RAW); 438 clearlist = 1; 439 return 0; 440} 441 442/**/ 443int 444killregion(UNUSED(char **args)) 445{ 446 if (mark > zlell) 447 mark = zlell; 448 if (mark > zlecs) 449 forekill(mark - zlecs, CUT_RAW); 450 else 451 backkill(zlecs - mark, CUT_FRONT|CUT_RAW); 452 return 0; 453} 454 455/**/ 456int 457copyregionaskill(char **args) 458{ 459 if (*args) { 460 int len; 461 ZLE_STRING_T line = stringaszleline(*args, 0, &len, NULL, NULL); 462 cuttext(line, len, CUT_REPLACE); 463 free(line); 464 } else { 465 if (mark > zlell) 466 mark = zlell; 467 if (mark > zlecs) 468 cut(zlecs, mark - zlecs, 0); 469 else 470 cut(mark, zlecs - mark, CUT_FRONT); 471 } 472 return 0; 473} 474 475/* 476 * kct: index into kill ring, or -1 for original cutbuffer of yank. 477 * yankb, yanke: mark the start and end of last yank in editing buffer. 478 */ 479static int kct, yankb, yanke; 480/* The original cutbuffer, either cutbuf or one of the vi buffers. */ 481static Cutbuffer kctbuf; 482 483/**/ 484int 485yank(UNUSED(char **args)) 486{ 487 int n = zmult; 488 489 if (n < 0) 490 return 1; 491 if (zmod.flags & MOD_VIBUF) 492 kctbuf = &vibuf[zmod.vibuf]; 493 else 494 kctbuf = &cutbuf; 495 if (!kctbuf->buf) 496 return 1; 497 mark = zlecs; 498 yankb = zlecs; 499 while (n--) { 500 kct = -1; 501 spaceinline(kctbuf->len); 502 ZS_memcpy(zleline + zlecs, kctbuf->buf, kctbuf->len); 503 zlecs += kctbuf->len; 504 yanke = zlecs; 505 } 506 return 0; 507} 508 509/**/ 510int 511yankpop(UNUSED(char **args)) 512{ 513 int cc, kctstart = kct; 514 Cutbuffer buf; 515 516 if (!(lastcmd & ZLE_YANK) || !kring || !kctbuf) { 517 kctbuf = NULL; 518 return 1; 519 } 520 do { 521 /* 522 * This is supposed to make the yankpop loop 523 * original buffer -> kill ring in order -> original buffer -> ... 524 * where the original buffer is -1 and the remainder are 525 * indices into the kill ring, remember that we need to start 526 * that at kringnum rather than zero. 527 */ 528 if (kct == -1) 529 kct = kringnum; 530 else { 531 int kctnew = (kct + kringsize - 1) % kringsize; 532 if (kctnew == kringnum) 533 kct = -1; 534 else 535 kct = kctnew; 536 } 537 if (kct == -1) 538 buf = kctbuf; /* Use original cutbuffer */ 539 else 540 buf = kring+kct; /* Use somewhere in the kill ring */ 541 /* Careful to prevent infinite looping */ 542 if (kct == kctstart) 543 return 1; 544 /* 545 * Skip unset buffers instead of stopping as we used to do. 546 * Also skip zero-length buffers. 547 * There are two reasons for this: 548 * 1. We now map the array $killring directly into the 549 * killring, instead of via some extra size-checking logic. 550 * When $killring has been set, a buffer will always have 551 * at least a zero-length string in it. 552 * 2. The old logic was inconsistent; when the kill ring 553 * was full, we could loop round and round it, otherwise 554 * we just stopped when we hit the first empty buffer. 555 */ 556 } while (!buf->buf || *buf->buf == ZWC('\0')); 557 558 zlecs = yankb; 559 foredel(yanke - yankb, CUT_RAW); 560 cc = buf->len; 561 spaceinline(cc); 562 ZS_memcpy(zleline + zlecs, buf->buf, cc); 563 zlecs += cc; 564 yanke = zlecs; 565 return 0; 566} 567 568/**/ 569int 570overwritemode(UNUSED(char **args)) 571{ 572 insmode ^= 1; 573 return 0; 574} 575 576/**/ 577int 578whatcursorposition(UNUSED(char **args)) 579{ 580 char msg[100]; 581 char *s = msg, *mbstr; 582 int bol = findbol(), len; 583 ZLE_CHAR_T c = zleline[zlecs]; 584 585 if (zlecs == zlell) 586 strucpy(&s, "EOF"); 587 else { 588 strucpy(&s, "Char: "); 589 switch (c) { 590 case ZWC(' '): 591 strucpy(&s, "SPC"); 592 break; 593 case ZWC('\t'): 594 strucpy(&s, "TAB"); 595 break; 596 case ZWC('\n'): 597 strucpy(&s, "LFD"); 598 break; 599 default: 600 /* 601 * convert a single character, remembering it may 602 * turn into a multibyte string or be metafied. 603 */ 604 mbstr = zlelineasstring(zleline+zlecs, 1, 0, &len, NULL, 1); 605 strcpy(s, mbstr); 606 s += len; 607 } 608 sprintf(s, " (0%o, %u, 0x%x)", (unsigned int)c, 609 (unsigned int)c, (unsigned int)c); 610 s += strlen(s); 611 } 612 sprintf(s, " point %d of %d(%d%%) column %d", zlecs+1, zlell+1, 613 zlell ? 100 * zlecs / zlell : 0, zlecs - bol); 614 showmsg(msg); 615 return 0; 616} 617 618/**/ 619int 620undefinedkey(UNUSED(char **args)) 621{ 622 return 1; 623} 624 625/**/ 626int 627quotedinsert(char **args) 628{ 629#ifndef HAS_TIO 630 struct sgttyb sob; 631 632 sob = shttyinfo.sgttyb; 633 sob.sg_flags = (sob.sg_flags | RAW) & ~ECHO; 634 ioctl(SHTTY, TIOCSETN, &sob); 635#endif 636 getfullchar(0); 637#ifndef HAS_TIO 638 zsetterm(); 639#endif 640 if (LASTFULLCHAR == ZLEEOF) 641 return 1; 642 else 643 return selfinsert(args); 644} 645 646static int 647parsedigit(int inkey) 648{ 649#ifdef MULTIBYTE_SUPPORT 650 /* 651 * It's too dangerous to allow metafied input. See 652 * universalargument for comments on (possibly suboptimal) handling 653 * of digits. We are assuming ASCII is a subset of the multibyte 654 * encoding. 655 */ 656#else 657 /* allow metafied as well as ordinary digits */ 658 inkey &= 0x7f; 659#endif 660 661 /* remember inkey is not a wide character */ 662 if (zmod.base > 10) { 663 if (inkey >= 'a' && inkey < 'a' + zmod.base - 10) 664 return inkey - 'a' + 10; 665 if (inkey >= 'A' && inkey < 'A' + zmod.base - 10) 666 return inkey - 'A' + 10; 667 if (idigit(inkey)) 668 return inkey - '0'; 669 return -1; 670 } 671 if (inkey >= '0' && inkey < '0' + zmod.base) 672 return inkey - '0'; 673 return -1; 674} 675 676/**/ 677int 678digitargument(UNUSED(char **args)) 679{ 680 int sign = (zmult < 0) ? -1 : 1; 681 int newdigit = parsedigit(lastchar); 682 683 if (newdigit < 0) 684 return 1; 685 686 if (!(zmod.flags & MOD_TMULT)) 687 zmod.tmult = 0; 688 if (zmod.flags & MOD_NEG) { 689 /* If we just had a negative argument, this is the digit, * 690 * rather than the -1 assumed by negargument() */ 691 zmod.tmult = sign * newdigit; 692 zmod.flags &= ~MOD_NEG; 693 } else 694 zmod.tmult = zmod.tmult * zmod.base + sign * newdigit; 695 zmod.flags |= MOD_TMULT; 696 prefixflag = 1; 697 return 0; 698} 699 700/**/ 701int 702negargument(UNUSED(char **args)) 703{ 704 if (zmod.flags & MOD_TMULT) 705 return 1; 706 zmod.tmult = -1; 707 zmod.flags |= MOD_TMULT|MOD_NEG; 708 prefixflag = 1; 709 return 0; 710} 711 712/**/ 713int 714universalargument(char **args) 715{ 716 int digcnt = 0, pref = 0, minus = 1, gotk; 717 if (*args) { 718 zmod.mult = atoi(*args); 719 zmod.flags |= MOD_MULT; 720 return 0; 721 } 722 /* 723 * TODO: this is quite tricky to do when trying to maintain 724 * compatibility between the old input system and Unicode. 725 * We don't know what follows the digits, so if we try to 726 * read wide characters we may fail (e.g. we may come across an old 727 * \M-style binding). 728 * 729 * If we assume individual bytes are either explicitly ASCII or 730 * not (a la UTF-8), we get away with it; we can back up individual 731 * bytes and everything will work. We may want to relax this 732 * assumption later. ("Much later" - (C) Steven Singer, 733 * CSR BlueCore firmware, ca. 2000.) 734 * 735 * Hence for now this remains byte-by-byte. 736 */ 737 while ((gotk = getbyte(0L, NULL)) != EOF) { 738 if (gotk == '-' && !digcnt) { 739 minus = -1; 740 digcnt++; 741 } else { 742 int newdigit = parsedigit(gotk); 743 744 if (newdigit >= 0) { 745 pref = pref * zmod.base + newdigit; 746 digcnt++; 747 } else { 748 ungetbyte(gotk); 749 break; 750 } 751 } 752 } 753 if (digcnt) 754 zmod.tmult = minus * (pref ? pref : 1); 755 else 756 zmod.tmult *= 4; 757 zmod.flags |= MOD_TMULT; 758 prefixflag = 1; 759 return 0; 760} 761 762/* Set the base for a digit argument. */ 763 764/**/ 765int 766argumentbase(char **args) 767{ 768 int multbase; 769 770 if (*args) 771 multbase = (int)zstrtol(*args, NULL, 0); 772 else 773 multbase = zmod.mult; 774 775 if (multbase < 2 || multbase > ('9' - '0' + 1) + ('z' - 'a' + 1)) 776 return 1; 777 778 zmod.base = multbase; 779 780 /* reset modifier, apart from base... */ 781 zmod.flags = 0; 782 zmod.mult = 1; 783 zmod.tmult = 1; 784 zmod.vibuf = 0; 785 786 /* ...but indicate we are still operating on a prefix argument. */ 787 prefixflag = 1; 788 789 return 0; 790} 791 792/**/ 793int 794copyprevword(UNUSED(char **args)) 795{ 796 int len, t0 = zlecs, t1; 797 798 if (zmult > 0) { 799 int count = zmult; 800 801 for (;;) { 802 t1 = t0; 803 804 while (t0) { 805 int prev = t0; 806 DECPOS(prev); 807 if (ZC_iword(zleline[prev])) 808 break; 809 t0 = prev; 810 } 811 while (t0) { 812 int prev = t0; 813 DECPOS(prev); 814 if (!ZC_iword(zleline[prev])) 815 break; 816 t0 = prev; 817 } 818 819 if (!--count) 820 break; 821 if (t0 == 0) 822 return 1; 823 } 824 } 825 else 826 return 1; 827 len = t1 - t0; 828 spaceinline(len); 829 ZS_memcpy(zleline + zlecs, zleline + t0, len); 830 zlecs += len; 831 return 0; 832} 833 834/**/ 835int 836copyprevshellword(UNUSED(char **args)) 837{ 838 LinkList l; 839 LinkNode n; 840 int i; 841 char *p = NULL; 842 843 if (zmult <= 0) 844 return 1; 845 846 if ((l = bufferwords(NULL, NULL, &i, 0))) { 847 i -= (zmult-1); 848 if (i < 0) 849 return 1; 850 for (n = firstnode(l); n; incnode(n)) 851 if (!i--) { 852 p = getdata(n); 853 break; 854 } 855 } 856 857 if (p) { 858 int len; 859 ZLE_STRING_T lineadd = stringaszleline(p, 0, &len, NULL, NULL); 860 861 spaceinline(len); 862 ZS_memcpy(zleline + zlecs, lineadd, len); 863 zlecs += len; 864 865 free(lineadd); 866 } 867 return 0; 868} 869 870/**/ 871int 872sendbreak(UNUSED(char **args)) 873{ 874 errflag = 1; 875 return 1; 876} 877 878/**/ 879int 880quoteregion(UNUSED(char **args)) 881{ 882 ZLE_STRING_T str; 883 size_t len; 884 885 if (mark > zlell) 886 mark = zlell; 887 if (mark < zlecs) { 888 int tmp = mark; 889 mark = zlecs; 890 zlecs = tmp; 891 } 892 str = (ZLE_STRING_T)hcalloc((len = mark - zlecs) * ZLE_CHAR_SIZE); 893 ZS_memcpy(str, zleline + zlecs, len); 894 foredel(len, CUT_RAW); 895 str = makequote(str, &len); 896 spaceinline(len); 897 ZS_memcpy(zleline + zlecs, str, len); 898 mark = zlecs; 899 zlecs += len; 900 return 0; 901} 902 903/**/ 904int 905quoteline(UNUSED(char **args)) 906{ 907 ZLE_STRING_T str; 908 size_t len = zlell; 909 910 str = makequote(zleline, &len); 911 sizeline(len); 912 ZS_memcpy(zleline, str, len); 913 zlecs = zlell = len; 914 return 0; 915} 916 917/**/ 918static ZLE_STRING_T 919makequote(ZLE_STRING_T str, size_t *len) 920{ 921 int qtct = 0; 922 ZLE_STRING_T l, ol; 923 ZLE_STRING_T end = str + *len; 924 925 for (l = str; l < end; l++) 926 if (*l == ZWC('\'')) 927 qtct++; 928 *len += 2 + qtct*3; 929 l = ol = (ZLE_STRING_T)zhalloc(*len * ZLE_CHAR_SIZE); 930 *l++ = ZWC('\''); 931 for (; str < end; str++) 932 if (*str == ZWC('\'')) { 933 *l++ = ZWC('\''); 934 *l++ = ZWC('\\'); 935 *l++ = ZWC('\''); 936 *l++ = ZWC('\''); 937 } else 938 *l++ = *str; 939 *l++ = ZWC('\''); 940 return ol; 941} 942 943/* 944 * cmdstr is the buffer used for execute-named-command converted 945 * to a metafied multibyte string. 946 */ 947static char *namedcmdstr; 948static LinkList namedcmdll; 949static int namedcmdambig; 950 951/**/ 952static void 953scancompcmd(HashNode hn, UNUSED(int flags)) 954{ 955 int l; 956 Thingy t = (Thingy) hn; 957 958 if(strpfx(namedcmdstr, t->nam)) { 959 addlinknode(namedcmdll, t->nam); 960 l = pfxlen(peekfirst(namedcmdll), t->nam); 961 if (l < namedcmdambig) 962 namedcmdambig = l; 963 } 964 965} 966 967#define NAMLEN 60 968 969/* 970 * Local keymap used when reading a command name for the 971 * execute-named-command and where-is widgets. 972 */ 973 974/**/ 975Keymap command_keymap; 976 977/**/ 978Thingy 979executenamedcommand(char *prmt) 980{ 981 Thingy cmd, retval = NULL; 982 int l, len, feep = 0, listed = 0, curlist = 0; 983 int ols = (listshown && validlist), olll = lastlistlen; 984 char *cmdbuf, *ptr; 985 char *okeymap = ztrdup(curkeymapname); 986 987 clearlist = 1; 988 /* prmt may be constant */ 989 prmt = ztrdup(prmt); 990 l = strlen(prmt); 991 cmdbuf = (char *)zhalloc(l + NAMLEN + 2 992#ifdef MULTIBYTE_SUPPORT 993 + 2 * MB_CUR_MAX 994#endif 995 ); 996 strcpy(cmdbuf, prmt); 997 zsfree(prmt); 998 statusline = cmdbuf; 999 selectlocalmap(command_keymap); 1000 selectkeymap("main", 1); 1001 ptr = cmdbuf += l; 1002 len = 0; 1003 for (;;) { 1004 *ptr = '_'; 1005 ptr[1] = '\0'; 1006 zrefresh(); 1007 if (!(cmd = getkeycmd()) || cmd == Th(z_sendbreak)) { 1008 statusline = NULL; 1009 selectkeymap(okeymap, 1); 1010 zsfree(okeymap); 1011 if ((listshown = ols)) { 1012 showinglist = -2; 1013 lastlistlen = olll; 1014 } else if (listed) 1015 clearlist = listshown = 1; 1016 1017 retval = NULL; 1018 goto done; 1019 } 1020 if(cmd == Th(z_clearscreen)) { 1021 clearscreen(zlenoargs); 1022 if (curlist) { 1023 int zmultsav = zmult; 1024 1025 zmult = 1; 1026 listlist(namedcmdll); 1027 showinglist = 0; 1028 zmult = zmultsav; 1029 } 1030 } else if(cmd == Th(z_redisplay)) { 1031 redisplay(zlenoargs); 1032 if (curlist) { 1033 int zmultsav = zmult; 1034 1035 zmult = 1; 1036 listlist(namedcmdll); 1037 showinglist = 0; 1038 zmult = zmultsav; 1039 } 1040 } else if(cmd == Th(z_viquotedinsert)) { 1041 *ptr = '^'; 1042 zrefresh(); 1043 getfullchar(0); 1044 if(LASTFULLCHAR == ZLEEOF || !LASTFULLCHAR || len >= NAMLEN) 1045 feep = 1; 1046 else { 1047 int ret = zlecharasstring(LASTFULLCHAR, ptr); 1048 len += ret; 1049 ptr += ret; 1050 curlist = 0; 1051 } 1052 } else if(cmd == Th(z_quotedinsert)) { 1053 if(getfullchar(0) == ZLEEOF || 1054 !LASTFULLCHAR || len == NAMLEN) 1055 feep = 1; 1056 else { 1057 int ret = zlecharasstring(LASTFULLCHAR, ptr); 1058 len += ret; 1059 ptr += ret; 1060 curlist = 0; 1061 } 1062 } else if(cmd == Th(z_backwarddeletechar) || 1063 cmd == Th(z_vibackwarddeletechar)) { 1064 if (len) { 1065 ptr = backwardmetafiedchar(cmdbuf, ptr, NULL); 1066 len = ptr - cmdbuf; 1067 curlist = 0; 1068 } 1069 } else if(cmd == Th(z_killregion) || cmd == Th(z_backwardkillword) || 1070 cmd == Th(z_vibackwardkillword)) { 1071 if (len) 1072 curlist = 0; 1073 while (len) { 1074 convchar_t cc; 1075 ptr = backwardmetafiedchar(cmdbuf, ptr, &cc); 1076 len = ptr - cmdbuf; 1077 if (cc == ZWC('-')) 1078 break; 1079 } 1080 } else if(cmd == Th(z_killwholeline) || cmd == Th(z_vikillline) || 1081 cmd == Th(z_backwardkillline)) { 1082 len = 0; 1083 ptr = cmdbuf; 1084 if (listed) 1085 clearlist = listshown = 1; 1086 curlist = 0; 1087 } else { 1088 if(cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) { 1089 Thingy r; 1090 unambiguous: 1091 *ptr = 0; 1092 r = rthingy(cmdbuf); 1093 if (!(r->flags & DISABLED)) { 1094 unrefthingy(r); 1095 statusline = NULL; 1096 selectkeymap(okeymap, 1); 1097 zsfree(okeymap); 1098 if ((listshown = ols)) { 1099 showinglist = -2; 1100 lastlistlen = olll; 1101 } else if (listed) 1102 clearlist = listshown = 1; 1103 1104 retval = r; 1105 goto done; 1106 } 1107 unrefthingy(r); 1108 } 1109 if(cmd == Th(z_selfinsertunmeta)) { 1110 fixunmeta(); 1111 cmd = Th(z_selfinsert); 1112 } 1113 if (cmd == Th(z_listchoices) || cmd == Th(z_deletecharorlist) || 1114 cmd == Th(z_expandorcomplete) || cmd == Th(z_completeword) || 1115 cmd == Th(z_expandorcompleteprefix) || cmd == Th(z_vicmdmode) || 1116 cmd == Th(z_acceptline) || lastchar == ' ' || lastchar == '\t') { 1117 namedcmdambig = 100; 1118 1119 namedcmdll = newlinklist(); 1120 1121 *ptr = '\0'; 1122 namedcmdstr = cmdbuf; 1123 scanhashtable(thingytab, 1, 0, DISABLED, scancompcmd, 0); 1124 namedcmdstr = NULL; 1125 1126 if (empty(namedcmdll)) { 1127 feep = 1; 1128 if (listed) 1129 clearlist = listshown = 1; 1130 curlist = 0; 1131 } else if (cmd == Th(z_listchoices) || 1132 cmd == Th(z_deletecharorlist)) { 1133 int zmultsav = zmult; 1134 *ptr = '_'; 1135 ptr[1] = '\0'; 1136 zmult = 1; 1137 listlist(namedcmdll); 1138 listed = curlist = 1; 1139 showinglist = 0; 1140 zmult = zmultsav; 1141 } else if (!nextnode(firstnode(namedcmdll))) { 1142 strcpy(ptr = cmdbuf, peekfirst(namedcmdll)); 1143 len = strlen(ptr); 1144 ptr += len; 1145 if (cmd == Th(z_acceptline) || cmd == Th(z_vicmdmode)) 1146 goto unambiguous; 1147 } else { 1148 strcpy(cmdbuf, peekfirst(namedcmdll)); 1149 ptr = cmdbuf + namedcmdambig; 1150 *ptr = '_'; 1151 ptr[1] = '\0'; 1152 if (isset(AUTOLIST) && 1153 !(isset(LISTAMBIGUOUS) && namedcmdambig > len)) { 1154 int zmultsav = zmult; 1155 if (isset(LISTBEEP)) 1156 feep = 1; 1157 zmult = 1; 1158 listlist(namedcmdll); 1159 listed = curlist = 1; 1160 showinglist = 0; 1161 zmult = zmultsav; 1162 } 1163 len = namedcmdambig; 1164 } 1165 } else { 1166 if (len == NAMLEN || cmd != Th(z_selfinsert)) 1167 feep = 1; 1168 else { 1169#ifdef MULTIBYTE_SUPPORT 1170 if (!lastchar_wide_valid) 1171 getrestchar(lastchar); 1172 if (lastchar_wide == WEOF) 1173 feep = 1; 1174 else 1175#endif 1176 if (ZC_icntrl(LASTFULLCHAR)) 1177 feep = 1; 1178 else { 1179 int ret = zlecharasstring(LASTFULLCHAR, ptr); 1180 len += ret; 1181 ptr += ret; 1182 if (listed) { 1183 clearlist = listshown = 1; 1184 listed = 0; 1185 } else 1186 curlist = 0; 1187 } 1188 } 1189 } 1190 } 1191 if (feep) 1192 handlefeep(zlenoargs); 1193 feep = 0; 1194 } 1195 1196 done: 1197 selectlocalmap(NULL); 1198 return retval; 1199} 1200 1201/*****************/ 1202/* Suffix system */ 1203/*****************/ 1204 1205/* 1206 * The completion system sometimes tentatively adds a suffix to a word, 1207 * which can be removed depending on what is inserted next. These 1208 * functions provide the capability to handle a removable suffix. 1209 * 1210 * Any removable suffix consists of characters immediately before the 1211 * cursor. Whether it is removed depends on the next editing action. 1212 * There can be more than one suffix simultaneously present, with 1213 * different actions deleting different numbers of characters. 1214 * 1215 * If the next editing action changes the buffer other than by inserting 1216 * characters, normally the suffix should be removed so as to leave a 1217 * meaningful complete word. The behaviour should be the same if the 1218 * next character inserted is a word separator. If the next character 1219 * reasonably belongs where it is typed, or if the next editing action 1220 * is a deletion, the suffix should not be removed. Other reasons for 1221 * suffix removal may have other behaviour. 1222 * 1223 * In order to maintain a consistent state, after a suffix has been added 1224 * the table *must* be zeroed, one way or another, before the buffer is 1225 * changed. If the suffix is not being removed, call fixsuffix() to 1226 * indicate that it is being permanently fixed. 1227 */ 1228 1229struct suffixset; 1230 1231/* An element of a suffix specification */ 1232struct suffixset { 1233 struct suffixset *next; /* Next in the list */ 1234 int tp; /* The SUFTYP_* from enum suffixtype */ 1235 int flags; /* Some of SUFFLAGS_* */ 1236 ZLE_STRING_T chars; /* Set of characters to match (or not) */ 1237 int lenstr; /* Length of chars */ 1238 int lensuf; /* Length of suffix */ 1239}; 1240 1241/* The list of suffix structures */ 1242struct suffixset *suffixlist; 1243 1244/* Shell function to call to remove the suffix. */ 1245 1246/**/ 1247static char *suffixfunc; 1248 1249/* Length associated with the suffix function */ 1250static int suffixfunclen; 1251 1252/* Length associated with uninsertable characters */ 1253/**/ 1254mod_export int 1255suffixnoinslen; 1256 1257/**/ 1258mod_export void 1259addsuffix(int tp, int flags, ZLE_STRING_T chars, int lenstr, int lensuf) 1260{ 1261 struct suffixset *newsuf = zalloc(sizeof(struct suffixset)); 1262 newsuf->next = suffixlist; 1263 suffixlist = newsuf; 1264 1265 newsuf->tp = tp; 1266 newsuf->flags = flags; 1267 if (lenstr) { 1268 newsuf->chars = zalloc(lenstr*sizeof(ZLE_CHAR_T)); 1269 ZS_memcpy(newsuf->chars, chars, lenstr); 1270 } else 1271 newsuf->chars = NULL; 1272 newsuf->lenstr = lenstr; 1273 newsuf->lensuf = lensuf; 1274} 1275 1276 1277/* Same as addsuffix, but from metafied string */ 1278 1279/**/ 1280mod_export void 1281addsuffixstring(int tp, int flags, char *chars, int lensuf) 1282{ 1283 int slen, alloclen; 1284 ZLE_STRING_T suffixstr; 1285 1286 /* string needs to be writable... I've been regretting this for years.. */ 1287 chars = ztrdup(chars); 1288 suffixstr = stringaszleline(chars, 0, &slen, &alloclen, NULL); 1289 addsuffix(tp, flags, suffixstr, slen, lensuf); 1290 zfree(suffixstr, alloclen); 1291 zsfree(chars); 1292} 1293 1294/* Set up suffix: the last n characters are a suffix that should be * 1295 * removed in the usual word end conditions. */ 1296 1297/**/ 1298mod_export void 1299makesuffix(int n) 1300{ 1301 char *suffixchars; 1302 1303 if (!(suffixchars = getsparam("ZLE_REMOVE_SUFFIX_CHARS"))) 1304 suffixchars = " \t\n;&|"; 1305 1306 addsuffixstring(SUFTYP_POSSTR, 0, suffixchars, n); 1307 1308 /* Do this second so it takes precedence */ 1309 if ((suffixchars = getsparam("ZLE_SPACE_SUFFIX_CHARS")) && *suffixchars) 1310 addsuffixstring(SUFTYP_POSSTR, SUFFLAGS_SPACE, suffixchars, n); 1311 1312 suffixnoinslen = n; 1313} 1314 1315/* Set up suffix for parameter names: the last n characters are a suffix * 1316 * that should be removed if the next character is one of the ones that * 1317 * needs to go immediately after the parameter name. br indicates that * 1318 * the name is in braces (${PATH} instead of $PATH), so the extra * 1319 * characters that can only be used in braces are included. */ 1320 1321/**/ 1322mod_export void 1323makeparamsuffix(int br, int n) 1324{ 1325 ZLE_STRING_T charstr = ZWS(":[#%?-+="); 1326 int lenstr = 0; 1327 1328 if (br || unset(KSHARRAYS)) { 1329 lenstr = 2; 1330 if (br) 1331 lenstr += 6; 1332 } 1333 if (lenstr) 1334 addsuffix(SUFTYP_POSSTR, 0, charstr, lenstr, n); 1335} 1336 1337/* Set up suffix given a string containing the characters on which to * 1338 * remove the suffix. */ 1339 1340/**/ 1341mod_export void 1342makesuffixstr(char *f, char *s, int n) 1343{ 1344 if (f) { 1345 zsfree(suffixfunc); 1346 suffixfunc = ztrdup(f); 1347 suffixfunclen = n; 1348 } else if (s) { 1349 int inv, i, z = 0; 1350 ZLE_STRING_T ws, lasts, wptr; 1351 1352 if (*s == '^' || *s == '!') { 1353 inv = 1; 1354 s++; 1355 } else 1356 inv = 0; 1357 s = getkeystring(s, &i, GETKEYS_SUFFIX, &z); 1358 s = metafy(s, i, META_USEHEAP); 1359 ws = stringaszleline(s, 0, &i, NULL, NULL); 1360 1361 if (z) 1362 suffixnoinslen = inv ? 0 : n; 1363 else if (inv) { 1364 /* 1365 * negative match, \- wasn't present, so it *should* 1366 * have this suffix length 1367 */ 1368 suffixnoinslen = n; 1369 } 1370 1371 lasts = wptr = ws; 1372 while (i) { 1373 if (i >= 3 && wptr[1] == ZWC('-')) { 1374 ZLE_CHAR_T str[2]; 1375 1376 if (wptr > lasts) 1377 addsuffix(inv ? SUFTYP_NEGSTR : SUFTYP_POSSTR, 0, 1378 lasts, wptr - lasts, n); 1379 str[0] = *wptr; 1380 str[1] = wptr[2]; 1381 addsuffix(inv ? SUFTYP_NEGRNG : SUFTYP_POSRNG, 0, 1382 str, 2, n); 1383 1384 wptr += 3; 1385 i -= 3; 1386 lasts = wptr; 1387 } else { 1388 wptr++; 1389 i--; 1390 } 1391 } 1392 if (wptr > lasts) 1393 addsuffix(inv ? SUFTYP_NEGSTR : SUFTYP_POSSTR, 0, 1394 lasts, wptr - lasts, n); 1395 free(ws); 1396 } else 1397 makesuffix(n); 1398} 1399 1400/* Remove suffix, if there is one, when inserting character c. */ 1401 1402/**/ 1403mod_export void 1404iremovesuffix(ZLE_INT_T c, int keep) 1405{ 1406 if (suffixfunc) { 1407 Shfunc shfunc = getshfunc(suffixfunc); 1408 1409 if (shfunc) { 1410 LinkList args = newlinklist(); 1411 char buf[20]; 1412 int osc = sfcontext; 1413 int wasmeta = (zlemetaline != 0); 1414 1415 if (wasmeta) { 1416 /* 1417 * The suffix removal function runs as a normal 1418 * ZLE function, not a completion function, so 1419 * the line should be unmetafied if this was 1420 * called from completion. (It may not be since 1421 * we may decide to remove the suffix later.) 1422 */ 1423 unmetafy_line(); 1424 } 1425 1426 sprintf(buf, "%d", suffixfunclen); 1427 addlinknode(args, suffixfunc); 1428 addlinknode(args, buf); 1429 1430 startparamscope(); 1431 makezleparams(0); 1432 sfcontext = SFC_COMPLETE; 1433 doshfunc(shfunc, args, 1); 1434 sfcontext = osc; 1435 endparamscope(); 1436 1437 if (wasmeta) 1438 metafy_line(); 1439 } 1440 zsfree(suffixfunc); 1441 suffixfunc = NULL; 1442 } else { 1443 int sl = 0, flags = 0; 1444 struct suffixset *ss; 1445 1446 if (c == NO_INSERT_CHAR) { 1447 sl = suffixnoinslen; 1448 } else { 1449 ZLE_CHAR_T ch = c; 1450 /* 1451 * Search for a match for ch in the suffix list. 1452 * We stop if we encounter a match in a positive or negative 1453 * list, using the suffix length specified or zero respectively. 1454 * If we reached the end and passed through a negative 1455 * list, we use the suffix length for that, else zero. 1456 * This would break if it were possible to have negative 1457 * sets with different suffix length: that's not supposed 1458 * to happen. 1459 */ 1460 int negsuflen = 0, found = 0; 1461 1462 for (ss = suffixlist; ss; ss = ss->next) { 1463 switch (ss->tp) { 1464 case SUFTYP_POSSTR: 1465 if (ZS_memchr(ss->chars, ch, ss->lenstr)) { 1466 sl = ss->lensuf; 1467 found = 1; 1468 } 1469 break; 1470 1471 case SUFTYP_NEGSTR: 1472 if (ZS_memchr(ss->chars, ch, ss->lenstr)) { 1473 sl = 0; 1474 found = 1; 1475 } else { 1476 negsuflen = ss->lensuf; 1477 } 1478 break; 1479 1480 case SUFTYP_POSRNG: 1481 if (ss->chars[0] <= ch && ch <= ss->chars[1]) { 1482 sl = ss->lensuf; 1483 found = 1; 1484 } 1485 break; 1486 1487 case SUFTYP_NEGRNG: 1488 if (ss->chars[0] <= ch && ch <= ss->chars[1]) { 1489 sl = 0; 1490 found = 1; 1491 } else { 1492 negsuflen = ss->lensuf; 1493 } 1494 break; 1495 } 1496 if (found) { 1497 flags = ss->flags; 1498 break; 1499 } 1500 } 1501 1502 if (!found) 1503 sl = negsuflen; 1504 } 1505 if (sl) { 1506 /* must be shifting wide character lengths */ 1507 backdel(sl, CUT_RAW); 1508 if (flags & SUFFLAGS_SPACE) 1509 { 1510 /* Add a space and advance over it */ 1511 spaceinline(1); 1512 if (zlemetaline) { 1513 zlemetaline[zlemetacs++] = ' '; 1514 } else { 1515 zleline[zlecs++] = ZWC(' '); 1516 } 1517 } 1518 if (!keep) 1519 invalidatelist(); 1520 } 1521 } 1522 fixsuffix(); 1523} 1524 1525/* Fix the suffix in place, if there is one, making it non-removable. */ 1526 1527/**/ 1528mod_export void 1529fixsuffix(void) 1530{ 1531 while (suffixlist) { 1532 struct suffixset *next = suffixlist->next; 1533 1534 if (suffixlist->lenstr) 1535 zfree(suffixlist->chars, suffixlist->lenstr * sizeof(ZLE_CHAR_T)); 1536 zfree(suffixlist, sizeof(struct suffixset)); 1537 1538 suffixlist = next; 1539 } 1540 1541 suffixfunclen = suffixnoinslen = 0; 1542} 1543