1/* 2 * complete.c - the complete module, interface part 3 * 4 * This file is part of zsh, the Z shell. 5 * 6 * Copyright (c) 1999 Sven Wischnowsky 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 Sven Wischnowsky 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 Sven Wischnowsky and the Zsh Development Group have been advised of 19 * the possibility of such damage. 20 * 21 * Sven Wischnowsky 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 Sven Wischnowsky and the 25 * Zsh Development Group have no obligation to provide maintenance, 26 * support, updates, enhancements, or modifications. 27 * 28 */ 29 30#include "complete.mdh" 31#include "complete.pro" 32 33/* global variables for shell parameters in new style completion */ 34 35/**/ 36mod_export 37zlong compcurrent, 38 complistmax; 39/**/ 40zlong complistlines, 41 compignored; 42 43/**/ 44mod_export 45char **compwords, 46 **compredirs, 47 *compprefix, 48 *compsuffix, 49 *complastprefix, 50 *complastsuffix, 51 *compisuffix, 52 *compqiprefix, 53 *compqisuffix, 54 *compquote, 55 *compqstack, 56 *comppatmatch, 57 *complastprompt; 58/**/ 59char *compiprefix, 60 *compcontext, 61 *compparameter, 62 *compredirect, 63 *compquoting, 64 *comprestore, 65 *complist, 66 *compinsert, 67 *compexact, 68 *compexactstr, 69 *comppatinsert, 70 *comptoend, 71 *compoldlist, 72 *compoldins, 73 *compvared; 74 75/**/ 76Param *comprpms, *compkpms; 77 78/**/ 79mod_export void 80freecmlist(Cmlist l) 81{ 82 Cmlist n; 83 84 while (l) { 85 n = l->next; 86 freecmatcher(l->matcher); 87 zsfree(l->str); 88 89 zfree(l, sizeof(struct cmlist)); 90 91 l = n; 92 } 93} 94 95/**/ 96mod_export void 97freecmatcher(Cmatcher m) 98{ 99 Cmatcher n; 100 101 if (!m || --(m->refc)) 102 return; 103 104 while (m) { 105 n = m->next; 106 freecpattern(m->line); 107 freecpattern(m->word); 108 freecpattern(m->left); 109 freecpattern(m->right); 110 111 zfree(m, sizeof(struct cmatcher)); 112 113 m = n; 114 } 115} 116 117/**/ 118void 119freecpattern(Cpattern p) 120{ 121 Cpattern n; 122 123 while (p) { 124 n = p->next; 125 if (p->tp <= CPAT_EQUIV) 126 free(p->u.str); 127 zfree(p, sizeof(struct cpattern)); 128 129 p = n; 130 } 131} 132 133/* Copy a completion matcher list into permanent storage. */ 134 135/**/ 136mod_export Cmatcher 137cpcmatcher(Cmatcher m) 138{ 139 Cmatcher r = NULL, *p = &r, n; 140 141 while (m) { 142 *p = n = (Cmatcher) zalloc(sizeof(struct cmatcher)); 143 144 n->refc = 1; 145 n->next = NULL; 146 n->flags = m->flags; 147 n->line = cpcpattern(m->line); 148 n->llen = m->llen; 149 n->word = cpcpattern(m->word); 150 n->wlen = m->wlen; 151 n->left = cpcpattern(m->left); 152 n->lalen = m->lalen; 153 n->right = cpcpattern(m->right); 154 n->ralen = m->ralen; 155 156 p = &(n->next); 157 m = m->next; 158 } 159 return r; 160} 161 162/* 163 * Copy a single entry in a matcher pattern. 164 * If useheap is 1, it comes from the heap. 165 */ 166 167/**/ 168mod_export Cpattern 169cp_cpattern_element(Cpattern o) 170{ 171 Cpattern n = zalloc(sizeof(struct cpattern)); 172 173 n->next = NULL; 174 175 n->tp = o->tp; 176 switch (o->tp) 177 { 178 case CPAT_CCLASS: 179 case CPAT_NCLASS: 180 case CPAT_EQUIV: 181 n->u.str = ztrdup(o->u.str); 182 break; 183 184 case CPAT_CHAR: 185 n->u.chr = o->u.chr; 186 break; 187 188 default: 189 /* just to keep compiler quiet */ 190 break; 191 } 192 193 return n; 194} 195 196/* Copy a completion matcher pattern. */ 197 198/**/ 199static Cpattern 200cpcpattern(Cpattern o) 201{ 202 Cpattern r = NULL, *p = &r; 203 204 while (o) { 205 *p = cp_cpattern_element(o); 206 p = &((*p)->next); 207 o = o->next; 208 } 209 return r; 210} 211 212/* Parse a string for matcher control, containing multiple matchers. */ 213 214/**/ 215mod_export Cmatcher 216parse_cmatcher(char *name, char *s) 217{ 218 Cmatcher ret = NULL, r = NULL, n; 219 Cpattern line, word, left, right; 220 int fl, fl2, ll, wl, lal, ral, err, both; 221 222 if (!*s) 223 return NULL; 224 225 while (*s) { 226 lal = ral = both = fl2 = 0; 227 left = right = NULL; 228 229 while (*s && inblank(*s)) s++; 230 231 if (!*s) break; 232 233 switch (*s) { 234 case 'b': fl2 = CMF_INTER; 235 case 'l': fl = CMF_LEFT; break; 236 case 'e': fl2 = CMF_INTER; 237 case 'r': fl = CMF_RIGHT; break; 238 case 'm': fl = 0; break; 239 case 'B': fl2 = CMF_INTER; 240 case 'L': fl = CMF_LEFT | CMF_LINE; break; 241 case 'E': fl2 = CMF_INTER; 242 case 'R': fl = CMF_RIGHT | CMF_LINE; break; 243 case 'M': fl = CMF_LINE; break; 244 default: 245 if (name) 246 zwarnnam(name, "unknown match specification character `%c'", 247 *s); 248 return pcm_err; 249 } 250 if (s[1] != ':') { 251 if (name) 252 zwarnnam(name, "missing `:'"); 253 return pcm_err; 254 } 255 s += 2; 256 if (!*s) { 257 if (name) 258 zwarnnam(name, "missing patterns"); 259 return pcm_err; 260 } 261 if ((fl & CMF_LEFT) && !fl2) { 262 left = parse_pattern(name, &s, &lal, '|', &err); 263 if (err) 264 return pcm_err; 265 266 if ((both = (*s && s[1] == '|'))) 267 s++; 268 269 if (!*s || !*++s) { 270 if (name) 271 zwarnnam(name, "missing line pattern"); 272 return pcm_err; 273 } 274 } else 275 left = NULL; 276 277 line = parse_pattern(name, &s, &ll, 278 (((fl & CMF_RIGHT) && !fl2) ? '|' : '='), 279 &err); 280 if (err) 281 return pcm_err; 282 if (both) { 283 right = line; 284 ral = ll; 285 line = NULL; 286 ll = 0; 287 } 288 if ((fl & CMF_RIGHT) && !fl2 && (!*s || !*++s)) { 289 if (name) 290 zwarnnam(name, "missing right anchor"); 291 } else if (!(fl & CMF_RIGHT) || fl2) { 292 if (!*s) { 293 if (name) 294 zwarnnam(name, "missing word pattern"); 295 return pcm_err; 296 } 297 s++; 298 } 299 if ((fl & CMF_RIGHT) && !fl2) { 300 if (*s == '|') { 301 left = line; 302 lal = ll; 303 line = NULL; 304 ll = 0; 305 s++; 306 } 307 right = parse_pattern(name, &s, &ral, '=', &err); 308 if (err) 309 return pcm_err; 310 if (!*s) { 311 if (name) 312 zwarnnam(name, "missing word pattern"); 313 return pcm_err; 314 } 315 s++; 316 } else 317 right = NULL; 318 319 if (*s == '*') { 320 if (!(fl & (CMF_LEFT | CMF_RIGHT))) { 321 if (name) 322 zwarnnam(name, "need anchor for `*'"); 323 return pcm_err; 324 } 325 word = NULL; 326 if (*++s == '*') { 327 s++; 328 wl = -2; 329 } else 330 wl = -1; 331 } else { 332 word = parse_pattern(name, &s, &wl, 0, &err); 333 334 if (!word && !line) { 335 if (name) 336 zwarnnam(name, "need non-empty word or line pattern"); 337 return pcm_err; 338 } 339 } 340 if (err) 341 return pcm_err; 342 343 n = (Cmatcher) hcalloc(sizeof(*ret)); 344 n->next = NULL; 345 n->flags = fl | fl2; 346 n->line = line; 347 n->llen = ll; 348 n->word = word; 349 n->wlen = wl; 350 n->left = left; 351 n->lalen = lal; 352 n->right = right; 353 n->ralen = ral; 354 355 if (ret) 356 r->next = n; 357 else 358 ret = n; 359 360 r = n; 361 } 362 return ret; 363} 364 365/* 366 * Parse a pattern for matcher control. 367 * name is the name of the builtin from which this is called, for errors. 368 * *sp is the input string and will be updated to the end of the parsed 369 * pattern. 370 * *lp will be set to the number of characters (possibly multibyte) 371 * that the pattern will match. This must be deterministic, given 372 * the syntax allowed here. 373 * e, if non-zero, is the ASCII end character to match; if zero, 374 * stop on a blank. 375 * *err is set to 1 to indicate an error, else to 0. 376 */ 377 378/**/ 379static Cpattern 380parse_pattern(char *name, char **sp, int *lp, char e, int *err) 381{ 382 Cpattern ret = NULL, r = NULL, n; 383 char *s = *sp; 384 convchar_t inchar; 385 int l = 0, inlen; 386 387 *err = 0; 388 389 MB_METACHARINIT(); 390 while (*s && (e ? (*s != e) : !inblank(*s))) { 391 n = (Cpattern) hcalloc(sizeof(*n)); 392 n->next = NULL; 393 394 if (*s == '[' || *s == '{') { 395 s = parse_class(n, s); 396 if (!*s) { 397 *err = 1; 398 zwarnnam(name, "unterminated character class"); 399 return NULL; 400 } 401 s++; 402 } else if (*s == '?') { 403 n->tp = CPAT_ANY; 404 s++; 405 } else if (*s == '*' || *s == '(' || *s == ')' || *s == '=') { 406 *err = 1; 407 zwarnnam(name, "invalid pattern character `%c'", *s); 408 return NULL; 409 } else { 410 if (*s == '\\' && s[1]) 411 s++; 412 413 inlen = MB_METACHARLENCONV(s, &inchar); 414#ifdef MULTIBYTE_SUPPORT 415 if (inchar == WEOF) 416 inchar = (convchar_t)(*s == Meta ? s[1] ^ 32 : *s); 417#endif 418 s += inlen; 419 n->tp = CPAT_CHAR; 420 n->u.chr = inchar; 421 } 422 if (ret) 423 r->next = n; 424 else 425 ret = n; 426 427 r = n; 428 429 l++; 430 } 431 *sp = (char *) s; 432 *lp = l; 433 return ret; 434} 435 436/* Parse a character class for matcher control. */ 437 438/**/ 439static char * 440parse_class(Cpattern p, char *iptr) 441{ 442 int endchar, firsttime = 1; 443 char *optr, *nptr; 444 445 if (*iptr++ == '[') { 446 endchar = ']'; 447 /* TODO: surely [^]] is valid? */ 448 if ((*iptr == '!' || *iptr == '^') && iptr[1] != ']') { 449 p->tp = CPAT_NCLASS; 450 iptr++; 451 } else 452 p->tp = CPAT_CCLASS; 453 } else { 454 endchar = '}'; 455 p->tp = CPAT_EQUIV; 456 } 457 458 /* find end of class. End character can appear literally first. */ 459 for (optr = iptr; optr == iptr || *optr != endchar; optr++) 460 if (!*optr) 461 return optr; 462 /* 463 * We can always fit the parsed class within the same length 464 * because of the tokenization (including a null byte). 465 * 466 * As the input string is metafied, but shouldn't contain shell 467 * tokens, we can just add our own tokens willy nilly. 468 */ 469 optr = p->u.str = zhalloc((optr-iptr) + 1); 470 471 while (firsttime || *iptr != endchar) { 472 int ch; 473 474 if (*iptr == '[' && iptr[1] == ':' && 475 (nptr = strchr((char *)iptr + 2, ':')) && nptr[1] == ']') { 476 /* Range type */ 477 iptr += 2; 478 ch = range_type((char *)iptr, nptr-iptr); 479 iptr = nptr + 2; 480 if (ch != PP_UNKWN) 481 *optr++ = STOUC(Meta) + ch; 482 } else { 483 /* characters stay metafied */ 484 char *ptr1 = iptr; 485 if (*iptr == Meta) 486 iptr++; 487 iptr++; 488 if (*iptr == '-' && iptr[1] && iptr[1] != endchar) { 489 /* a run of characters */ 490 iptr++; 491 /* range token */ 492 *optr++ = Meta + PP_RANGE; 493 494 /* start of range character */ 495 if (*ptr1 == Meta) { 496 *optr++ = Meta; 497 *optr++ = ptr1[1] ^ 32; 498 } else 499 *optr++ = *ptr1; 500 501 if (*iptr == Meta) { 502 *optr++ = *iptr++; 503 *optr++ = *iptr++; 504 } else 505 *optr++ = *iptr++; 506 } else { 507 if (*ptr1 == Meta) { 508 *optr++ = Meta; 509 *optr++ = ptr1[1] ^ 32; 510 } else 511 *optr++ = *ptr1; 512 } 513 } 514 firsttime = 0; 515 } 516 517 *optr = '\0'; 518 return iptr; 519} 520 521/**/ 522static int 523bin_compadd(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) 524{ 525 struct cadata dat; 526 char *p, **sp, *e, *m = NULL, *mstr = NULL; 527 int dm; 528 Cmatcher match = NULL; 529 530 if (incompfunc != 1) { 531 zwarnnam(name, "can only be called from completion function"); 532 return 1; 533 } 534 dat.ipre = dat.isuf = dat.ppre = dat.psuf = dat.prpre = dat.mesg = 535 dat.pre = dat.suf = dat.group = dat.rems = dat.remf = dat.disp = 536 dat.ign = dat.exp = dat.apar = dat.opar = dat.dpar = NULL; 537 dat.match = NULL; 538 dat.flags = 0; 539 dat.aflags = CAF_MATCH; 540 dat.dummies = 0; 541 542 for (; *argv && **argv == '-'; argv++) { 543 if (!(*argv)[1]) { 544 argv++; 545 break; 546 } 547 for (p = *argv + 1; *p; p++) { 548 sp = NULL; 549 e = NULL; 550 dm = 0; 551 switch (*p) { 552 case 'q': 553 dat.flags |= CMF_REMOVE; 554 break; 555 case 'Q': 556 dat.aflags |= CAF_QUOTE; 557 break; 558 case 'C': 559 dat.aflags |= CAF_ALL; 560 break; 561 case 'f': 562 dat.flags |= CMF_FILE; 563 break; 564 case 'e': 565 dat.flags |= CMF_ISPAR; 566 break; 567 case 'a': 568 dat.aflags |= CAF_ARRAYS; 569 break; 570 case 'k': 571 dat.aflags |= CAF_ARRAYS|CAF_KEYS; 572 break; 573 case 'F': 574 sp = &(dat.ign); 575 e = "string expected after -%c"; 576 break; 577 case 'n': 578 dat.flags |= CMF_NOLIST; 579 break; 580 case 'U': 581 dat.aflags &= ~CAF_MATCH; 582 break; 583 case 'P': 584 sp = &(dat.pre); 585 e = "string expected after -%c"; 586 break; 587 case 'S': 588 sp = &(dat.suf); 589 e = "string expected after -%c"; 590 break; 591 case 'J': 592 sp = &(dat.group); 593 e = "group name expected after -%c"; 594 break; 595 case 'V': 596 if (!dat.group) 597 dat.aflags |= CAF_NOSORT; 598 sp = &(dat.group); 599 e = "group name expected after -%c"; 600 break; 601 case '1': 602 if (!(dat.aflags & CAF_UNIQCON)) 603 dat.aflags |= CAF_UNIQALL; 604 break; 605 case '2': 606 if (!(dat.aflags & CAF_UNIQALL)) 607 dat.aflags |= CAF_UNIQCON; 608 break; 609 case 'i': 610 sp = &(dat.ipre); 611 e = "string expected after -%c"; 612 break; 613 case 'I': 614 sp = &(dat.isuf); 615 e = "string expected after -%c"; 616 break; 617 case 'p': 618 sp = &(dat.ppre); 619 e = "string expected after -%c"; 620 break; 621 case 's': 622 sp = &(dat.psuf); 623 e = "string expected after -%c"; 624 break; 625 case 'W': 626 sp = &(dat.prpre); 627 e = "string expected after -%c"; 628 break; 629 case 'M': 630 sp = &m; 631 e = "matching specification expected after -%c"; 632 dm = 1; 633 break; 634 case 'X': 635 sp = &(dat.exp); 636 e = "string expected after -%c"; 637 break; 638 case 'x': 639 sp = &(dat.mesg); 640 e = "string expected after -%c"; 641 break; 642 case 'r': 643 dat.flags |= CMF_REMOVE; 644 sp = &(dat.rems); 645 e = "string expected after -%c"; 646 break; 647 case 'R': 648 dat.flags |= CMF_REMOVE; 649 sp = &(dat.remf); 650 e = "function name expected after -%c"; 651 break; 652 case 'A': 653 sp = &(dat.apar); 654 e = "parameter name expected after -%c"; 655 break; 656 case 'O': 657 sp = &(dat.opar); 658 e = "parameter name expected after -%c"; 659 break; 660 case 'D': 661 sp = &(dat.dpar); 662 e = "parameter name expected after -%c"; 663 break; 664 case 'd': 665 sp = &(dat.disp); 666 e = "parameter name expected after -%c"; 667 break; 668 case 'l': 669 dat.flags |= CMF_DISPLINE; 670 break; 671 case 'o': 672 dat.flags |= CMF_MORDER; 673 break; 674 case 'E': 675 if (p[1]) { 676 dat.dummies = atoi(p + 1); 677 p = "" - 1; 678 } else if (argv[1]) { 679 argv++; 680 dat.dummies = atoi(*argv); 681 p = "" - 1; 682 } else { 683 zwarnnam(name, "number expected after -%c", *p); 684 zsfree(mstr); 685 return 1; 686 } 687 if (dat.dummies < 0) { 688 zwarnnam(name, "invalid number: %d", dat.dummies); 689 zsfree(mstr); 690 return 1; 691 } 692 break; 693 case '-': 694 argv++; 695 goto ca_args; 696 default: 697 zwarnnam(name, "bad option: -%c", *p); 698 zsfree(mstr); 699 return 1; 700 } 701 if (sp) { 702 if (p[1]) { 703 if (!*sp) 704 *sp = p + 1; 705 p = "" - 1; 706 } else if (argv[1]) { 707 argv++; 708 if (!*sp) 709 *sp = *argv; 710 p = "" - 1; 711 } else { 712 zwarnnam(name, e, *p); 713 zsfree(mstr); 714 return 1; 715 } 716 if (dm) { 717 if (mstr) { 718 char *tmp = tricat(mstr, " ", m); 719 zsfree(mstr); 720 mstr = tmp; 721 } else 722 mstr = ztrdup(m); 723 m = NULL; 724 } 725 } 726 } 727 } 728 729 ca_args: 730 731 if (mstr && (match = parse_cmatcher(name, mstr)) == pcm_err) { 732 zsfree(mstr); 733 return 1; 734 } 735 zsfree(mstr); 736 737 if (!*argv && !dat.group && !dat.mesg && 738 !(dat.aflags & (CAF_NOSORT|CAF_UNIQALL|CAF_UNIQCON|CAF_ALL))) 739 return 1; 740 741 dat.match = match = cpcmatcher(match); 742 dm = addmatches(&dat, argv); 743 freecmatcher(match); 744 745 return dm; 746} 747 748#define CVT_RANGENUM 0 749#define CVT_RANGEPAT 1 750#define CVT_PRENUM 2 751#define CVT_PREPAT 3 752#define CVT_SUFNUM 4 753#define CVT_SUFPAT 5 754 755/**/ 756mod_export void 757ignore_prefix(int l) 758{ 759 if (l) { 760 char *tmp, sav; 761 int pl = strlen(compprefix); 762 763 if (l > pl) 764 l = pl; 765 766 sav = compprefix[l]; 767 768 compprefix[l] = '\0'; 769 tmp = tricat(compiprefix, compprefix, ""); 770 zsfree(compiprefix); 771 compiprefix = tmp; 772 compprefix[l] = sav; 773 tmp = ztrdup(compprefix + l); 774 zsfree(compprefix); 775 compprefix = tmp; 776 } 777} 778 779/**/ 780mod_export void 781ignore_suffix(int l) 782{ 783 if (l) { 784 char *tmp, sav; 785 int sl = strlen(compsuffix); 786 787 if ((l = sl - l) < 0) 788 l = 0; 789 790 tmp = tricat(compsuffix + l, compisuffix, ""); 791 zsfree(compisuffix); 792 compisuffix = tmp; 793 sav = compsuffix[l]; 794 compsuffix[l] = '\0'; 795 tmp = ztrdup(compsuffix); 796 compsuffix[l] = sav; 797 zsfree(compsuffix); 798 compsuffix = tmp; 799 } 800} 801 802/**/ 803mod_export void 804restrict_range(int b, int e) 805{ 806 int wl = arrlen(compwords) - 1; 807 808 if (wl && b >= 0 && e >= 0 && (b > 0 || e < wl)) { 809 int i; 810 char **p, **q, **pp; 811 812 if (e > wl) 813 e = wl; 814 815 i = e - b + 1; 816 p = (char **) zshcalloc((i + 1) * sizeof(char *)); 817 818 for (q = p, pp = compwords + b; i; i--, q++, pp++) 819 *q = ztrdup(*pp); 820 freearray(compwords); 821 compwords = p; 822 compcurrent -= b; 823 } 824} 825 826/**/ 827static int 828do_comp_vars(int test, int na, char *sa, int nb, char *sb, int mod) 829{ 830 switch (test) { 831 case CVT_RANGENUM: 832 { 833 int l = arrlen(compwords); 834 835 if (na < 0) 836 na += l; 837 else 838 na--; 839 if (nb < 0) 840 nb += l; 841 else 842 nb--; 843 844 if (compcurrent - 1 < na || compcurrent - 1 > nb) 845 return 0; 846 if (mod) 847 restrict_range(na, nb); 848 return 1; 849 } 850 case CVT_RANGEPAT: 851 { 852 char **p; 853 int i, l = arrlen(compwords), t = 0, b = 0, e = l - 1; 854 Patprog pp; 855 856 i = compcurrent - 1; 857 if (i < 0 || i >= l) 858 return 0; 859 860 singsub(&sa); 861 pp = patcompile(sa, PAT_STATIC, NULL); 862 863 for (i--, p = compwords + i; i >= 0; p--, i--) { 864 if (pattry(pp, *p)) { 865 b = i + 1; 866 t = 1; 867 break; 868 } 869 } 870 if (t && sb) { 871 int tt = 0; 872 873 singsub(&sb); 874 pp = patcompile(sb, PAT_STATIC, NULL); 875 876 for (i++, p = compwords + i; i < l; p++, i++) { 877 if (pattry(pp, *p)) { 878 e = i - 1; 879 tt = 1; 880 break; 881 } 882 } 883 if (tt && i < compcurrent) 884 t = 0; 885 } 886 if (e < b) 887 t = 0; 888 if (t && mod) 889 restrict_range(b, e); 890 return t; 891 } 892 case CVT_PRENUM: 893 case CVT_SUFNUM: 894 if (!na) 895 return 1; 896 if (na > 0 && 897 (int)strlen(test == CVT_PRENUM ? compprefix : compsuffix) >= na) { 898 if (mod) { 899 if (test == CVT_PRENUM) 900 ignore_prefix(na); 901 else 902 ignore_suffix(na); 903 return 1; 904 } 905 return 0; 906 } 907 case CVT_PREPAT: 908 case CVT_SUFPAT: 909 { 910 Patprog pp; 911 912 if (!na) 913 return 0; 914 915 if (!(pp = patcompile(sa, PAT_STATIC, 0))) 916 return 0; 917 918 if (test == CVT_PREPAT) { 919 int l, add; 920 char *p, sav; 921 922 if (!(l = strlen(compprefix))) 923 return ((na == 1 || na == -1) && pattry(pp, compprefix)); 924 if (na < 0) { 925 p = compprefix + l; 926 na = -na; 927 add = -1; 928 } else { 929 p = compprefix + 1 + (*compprefix == Meta); 930 if (p > compprefix + l) 931 p = compprefix + l; 932 add = 1; 933 } 934 for (;;) { 935 sav = *p; 936 *p = '\0'; 937 test = pattry(pp, compprefix); 938 *p = sav; 939 if (test && !--na) 940 break; 941 if (add > 0) { 942 if (p == compprefix + l) 943 return 0; 944 p = p + 1 + (*p == Meta); 945 if (p > compprefix + l) 946 p = compprefix + l; 947 } else { 948 if (p == compprefix) 949 return 0; 950 p--; 951 if (p > compprefix && p[-1] == Meta) 952 p--; 953 } 954 } 955 if (mod) 956 ignore_prefix(p - compprefix); 957 } else { 958 int l, ol, add; 959 char *p; 960 961 if (!(ol = l = strlen(compsuffix))) 962 return ((na == 1 || na == -1) && pattry(pp, compsuffix)); 963 if (na < 0) { 964 p = compsuffix; 965 na = -na; 966 add = 1; 967 } else { 968 p = compsuffix + l - 1; 969 if (p > compsuffix && p[-1] == Meta) 970 p--; 971 add = -1; 972 } 973 for (;;) { 974 if (pattry(pp, p) && !--na) 975 break; 976 977 if (add > 0) { 978 if (p == compsuffix + l) 979 return 0; 980 if (*p == Meta) 981 p += 2; 982 else 983 p++; 984 } else { 985 if (p == compsuffix) 986 return 0; 987 p--; 988 if (p > compsuffix && p[-1] == Meta) 989 p--; 990 } 991 } 992 993 if (mod) 994 ignore_suffix(ol - (p - compsuffix)); 995 } 996 return 1; 997 } 998 } 999 return 0; 1000} 1001 1002/**/ 1003static int 1004bin_compset(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) 1005{ 1006 int test = 0, na = 0, nb = 0; 1007 char *sa = NULL, *sb = NULL; 1008 1009 if (incompfunc != 1) { 1010 zwarnnam(name, "can only be called from completion function"); 1011 return 1; 1012 } 1013 if (argv[0][0] != '-') { 1014 zwarnnam(name, "missing option"); 1015 return 1; 1016 } 1017 switch (argv[0][1]) { 1018 case 'n': test = CVT_RANGENUM; break; 1019 case 'N': test = CVT_RANGEPAT; break; 1020 case 'p': test = CVT_PRENUM; break; 1021 case 'P': test = CVT_PREPAT; break; 1022 case 's': test = CVT_SUFNUM; break; 1023 case 'S': test = CVT_SUFPAT; break; 1024 case 'q': return set_comp_sep(); 1025 default: 1026 zwarnnam(name, "bad option -%c", argv[0][1]); 1027 return 1; 1028 } 1029 if (argv[0][2]) { 1030 sa = argv[0] + 2; 1031 sb = argv[1]; 1032 na = 2; 1033 } else { 1034 if (!(sa = argv[1])) { 1035 zwarnnam(name, "missing string for option -%c", argv[0][1]); 1036 return 1; 1037 } 1038 sb = argv[2]; 1039 na = 3; 1040 } 1041 if (((test == CVT_PRENUM || test == CVT_SUFNUM) ? !!sb : 1042 (sb && argv[na]))) { 1043 zwarnnam(name, "too many arguments"); 1044 return 1; 1045 } 1046 switch (test) { 1047 case CVT_RANGENUM: 1048 na = atoi(sa); 1049 nb = (sb ? atoi(sb) : -1); 1050 break; 1051 case CVT_RANGEPAT: 1052 tokenize(sa); 1053 remnulargs(sa); 1054 if (sb) { 1055 tokenize(sb); 1056 remnulargs(sb); 1057 } 1058 break; 1059 case CVT_PRENUM: 1060 case CVT_SUFNUM: 1061 na = atoi(sa); 1062 break; 1063 case CVT_PREPAT: 1064 case CVT_SUFPAT: 1065 if (sb) { 1066 na = atoi(sa); 1067 sa = sb; 1068 } else 1069 na = -1; 1070 tokenize(sa); 1071 remnulargs(sa); 1072 break; 1073 } 1074 return !do_comp_vars(test, na, sa, nb, sb, 1); 1075} 1076 1077/* Definitions for the special parameters. Note that these have to match the 1078 * order of the CP_* bits in comp.h */ 1079 1080#define VAL(X) ((void *) (&(X))) 1081#define GSU(X) ((GsuScalar)(void *) (&(X))) 1082struct compparam { 1083 char *name; 1084 int type; 1085 void *var; 1086 GsuScalar gsu; 1087}; 1088 1089static const struct gsu_scalar compvarscalar_gsu = 1090{ strvargetfn, strvarsetfn, compunsetfn }; 1091static const struct gsu_scalar complist_gsu = 1092{ get_complist, set_complist, compunsetfn }; 1093static const struct gsu_scalar unambig_gsu = 1094{ get_unambig, nullstrsetfn, compunsetfn }; 1095static const struct gsu_scalar unambig_pos_gsu = 1096{ get_unambig_pos, nullstrsetfn, compunsetfn }; 1097static const struct gsu_scalar insert_pos_gsu = 1098{ get_insert_pos, nullstrsetfn, compunsetfn }; 1099static const struct gsu_scalar compqstack_gsu = 1100{ get_compqstack, nullstrsetfn, compunsetfn }; 1101 1102static const struct gsu_integer compvarinteger_gsu = 1103{ intvargetfn, intvarsetfn, compunsetfn }; 1104static const struct gsu_integer nmatches_gsu = 1105{ get_nmatches, NULL, compunsetfn }; 1106static const struct gsu_integer unambig_curs_gsu = 1107{ get_unambig_curs, NULL, compunsetfn }; 1108static const struct gsu_integer listlines_gsu = 1109{ get_listlines, NULL, compunsetfn }; 1110 1111static const struct gsu_array compvararray_gsu = 1112{ arrvargetfn, arrvarsetfn, compunsetfn }; 1113 1114 1115static struct compparam comprparams[] = { 1116 { "words", PM_ARRAY, VAL(compwords), NULL }, 1117 { "redirections", PM_ARRAY, VAL(compredirs), NULL }, 1118 { "CURRENT", PM_INTEGER, VAL(compcurrent), NULL }, 1119 { "PREFIX", PM_SCALAR, VAL(compprefix), NULL }, 1120 { "SUFFIX", PM_SCALAR, VAL(compsuffix), NULL }, 1121 { "IPREFIX", PM_SCALAR, VAL(compiprefix), NULL }, 1122 { "ISUFFIX", PM_SCALAR, VAL(compisuffix), NULL }, 1123 { "QIPREFIX", PM_SCALAR | PM_READONLY, VAL(compqiprefix), NULL }, 1124 { "QISUFFIX", PM_SCALAR | PM_READONLY, VAL(compqisuffix), NULL }, 1125 { NULL, 0, NULL, NULL } 1126}; 1127 1128static struct compparam compkparams[] = { 1129 { "nmatches", PM_INTEGER | PM_READONLY, NULL, GSU(nmatches_gsu) }, 1130 { "context", PM_SCALAR, VAL(compcontext), NULL }, 1131 { "parameter", PM_SCALAR, VAL(compparameter), NULL }, 1132 { "redirect", PM_SCALAR, VAL(compredirect), NULL }, 1133 { "quote", PM_SCALAR | PM_READONLY, VAL(compquote), NULL }, 1134 { "quoting", PM_SCALAR | PM_READONLY, VAL(compquoting), NULL }, 1135 { "restore", PM_SCALAR, VAL(comprestore), NULL }, 1136 { "list", PM_SCALAR, NULL, GSU(complist_gsu) }, 1137 { "insert", PM_SCALAR, VAL(compinsert), NULL }, 1138 { "exact", PM_SCALAR, VAL(compexact), NULL }, 1139 { "exact_string", PM_SCALAR, VAL(compexactstr), NULL }, 1140 { "pattern_match", PM_SCALAR, VAL(comppatmatch), NULL }, 1141 { "pattern_insert", PM_SCALAR, VAL(comppatinsert), NULL }, 1142 { "unambiguous", PM_SCALAR | PM_READONLY, NULL, GSU(unambig_gsu) }, 1143 { "unambiguous_cursor", PM_INTEGER | PM_READONLY, NULL, 1144 GSU(unambig_curs_gsu) }, 1145 { "unambiguous_positions", PM_SCALAR | PM_READONLY, NULL, 1146 GSU(unambig_pos_gsu) }, 1147 { "insert_positions", PM_SCALAR | PM_READONLY, NULL, 1148 GSU(insert_pos_gsu) }, 1149 { "list_max", PM_INTEGER, VAL(complistmax), NULL }, 1150 { "last_prompt", PM_SCALAR, VAL(complastprompt), NULL }, 1151 { "to_end", PM_SCALAR, VAL(comptoend), NULL }, 1152 { "old_list", PM_SCALAR, VAL(compoldlist), NULL }, 1153 { "old_insert", PM_SCALAR, VAL(compoldins), NULL }, 1154 { "vared", PM_SCALAR, VAL(compvared), NULL }, 1155 { "list_lines", PM_INTEGER | PM_READONLY, NULL, GSU(listlines_gsu) }, 1156 { "all_quotes", PM_SCALAR | PM_READONLY, NULL, GSU(compqstack_gsu) }, 1157 { "ignored", PM_INTEGER | PM_READONLY, VAL(compignored), NULL }, 1158 { NULL, 0, NULL, NULL } 1159}; 1160 1161#define COMPSTATENAME "compstate" 1162 1163static void 1164addcompparams(struct compparam *cp, Param *pp) 1165{ 1166 for (; cp->name; cp++, pp++) { 1167 Param pm = createparam(cp->name, 1168 cp->type |PM_SPECIAL|PM_REMOVABLE|PM_LOCAL); 1169 if (!pm) 1170 pm = (Param) paramtab->getnode(paramtab, cp->name); 1171 DPUTS(!pm, "param not set in addcompparams"); 1172 1173 *pp = pm; 1174 pm->level = locallevel + 1; 1175 if ((pm->u.data = cp->var)) { 1176 switch(PM_TYPE(cp->type)) { 1177 case PM_SCALAR: 1178 pm->gsu.s = &compvarscalar_gsu; 1179 break; 1180 case PM_INTEGER: 1181 pm->gsu.i = &compvarinteger_gsu; 1182 pm->base = 10; 1183 break; 1184 case PM_ARRAY: 1185 pm->gsu.a = &compvararray_gsu; 1186 break; 1187 } 1188 } else { 1189 pm->gsu.s = cp->gsu; 1190 } 1191 } 1192} 1193 1194static const struct gsu_hash compstate_gsu = 1195{ get_compstate, set_compstate, compunsetfn }; 1196 1197/**/ 1198void 1199makecompparams(void) 1200{ 1201 Param cpm; 1202 HashTable tht; 1203 1204 addcompparams(comprparams, comprpms); 1205 1206 if (!(cpm = createparam(COMPSTATENAME, 1207 PM_SPECIAL|PM_REMOVABLE|PM_LOCAL|PM_HASHED))) 1208 cpm = (Param) paramtab->getnode(paramtab, COMPSTATENAME); 1209 DPUTS(!cpm, "param not set in makecompparams"); 1210 1211 comprpms[CPN_COMPSTATE] = cpm; 1212 tht = paramtab; 1213 cpm->level = locallevel + 1; 1214 cpm->gsu.h = &compstate_gsu; 1215 cpm->u.hash = paramtab = newparamtable(31, COMPSTATENAME); 1216 addcompparams(compkparams, compkpms); 1217 paramtab = tht; 1218} 1219 1220/**/ 1221static HashTable 1222get_compstate(Param pm) 1223{ 1224 return pm->u.hash; 1225} 1226 1227/**/ 1228static void 1229set_compstate(UNUSED(Param pm), HashTable ht) 1230{ 1231 struct compparam *cp; 1232 Param *pp; 1233 HashNode hn; 1234 int i; 1235 struct value v; 1236 char *str; 1237 1238 if (!ht) 1239 return; 1240 1241 for (i = 0; i < ht->hsize; i++) 1242 for (hn = ht->nodes[i]; hn; hn = hn->next) 1243 for (cp = compkparams, 1244 pp = compkpms; cp->name; cp++, pp++) 1245 if (!strcmp(hn->nam, cp->name)) { 1246 v.isarr = v.flags = v.start = 0; 1247 v.end = -1; 1248 v.arr = NULL; 1249 v.pm = (Param) hn; 1250 if (cp->type == PM_INTEGER) 1251 *((zlong *) cp->var) = getintvalue(&v); 1252 else if ((str = getstrvalue(&v))) { 1253 zsfree(*((char **) cp->var)); 1254 *((char **) cp->var) = ztrdup(str); 1255 } 1256 (*pp)->node.flags &= ~PM_UNSET; 1257 1258 break; 1259 } 1260 deleteparamtable(ht); 1261} 1262 1263/**/ 1264static zlong 1265get_nmatches(UNUSED(Param pm)) 1266{ 1267 return (permmatches(0) ? 0 : nmatches); 1268} 1269 1270/**/ 1271static zlong 1272get_listlines(UNUSED(Param pm)) 1273{ 1274 return list_lines(); 1275} 1276 1277/**/ 1278static void 1279set_complist(UNUSED(Param pm), char *v) 1280{ 1281 comp_list(v); 1282} 1283 1284/**/ 1285static char * 1286get_complist(UNUSED(Param pm)) 1287{ 1288 return complist; 1289} 1290 1291/**/ 1292static char * 1293get_unambig(UNUSED(Param pm)) 1294{ 1295 return unambig_data(NULL, NULL, NULL); 1296} 1297 1298/**/ 1299static zlong 1300get_unambig_curs(UNUSED(Param pm)) 1301{ 1302 int c; 1303 1304 unambig_data(&c, NULL, NULL); 1305 1306 return c; 1307} 1308 1309/**/ 1310static char * 1311get_unambig_pos(UNUSED(Param pm)) 1312{ 1313 char *p; 1314 1315 unambig_data(NULL, &p, NULL); 1316 1317 return p; 1318} 1319 1320/**/ 1321static char * 1322get_insert_pos(UNUSED(Param pm)) 1323{ 1324 char *p; 1325 1326 unambig_data(NULL, NULL, &p); 1327 1328 return p; 1329} 1330 1331/**/ 1332static char * 1333get_compqstack(UNUSED(Param pm)) 1334{ 1335 char *p, *ptr, *cqp; 1336 1337 if (!compqstack) /* TODO: don't think this can happen... */ 1338 return ""; 1339 1340 ptr = p = zhalloc(2*strlen(compqstack)+1); 1341 1342 for (cqp = compqstack; *cqp; cqp++) { 1343 char *str = comp_quoting_string(*cqp); 1344 *ptr++ = *str; 1345 } 1346 *ptr = '\0'; 1347 1348 return p; 1349} 1350 1351/**/ 1352static void 1353compunsetfn(Param pm, int exp) 1354{ 1355 if (exp) { 1356 if (pm->u.data) { 1357 if (PM_TYPE(pm->node.flags) == PM_SCALAR) { 1358 zsfree(*((char **) pm->u.data)); 1359 *((char **) pm->u.data) = ztrdup(""); 1360 } else if (PM_TYPE(pm->node.flags) == PM_ARRAY) { 1361 freearray(*((char ***) pm->u.data)); 1362 *((char ***) pm->u.data) = zshcalloc(sizeof(char *)); 1363 } else if (PM_TYPE(pm->node.flags) == PM_HASHED) { 1364 deleteparamtable(pm->u.hash); 1365 pm->u.hash = NULL; 1366 } 1367 } 1368 } else if (PM_TYPE(pm->node.flags) == PM_HASHED) { 1369 Param *p; 1370 int i; 1371 1372 deletehashtable(pm->u.hash); 1373 pm->u.hash = NULL; 1374 1375 for (p = compkpms, i = CP_KEYPARAMS; i--; p++) 1376 *p = NULL; 1377 } 1378 if (!exp) { 1379 Param *p; 1380 int i; 1381 1382 for (p = comprpms, i = CP_REALPARAMS; i; p++, i--) 1383 if (*p == pm) { 1384 *p = NULL; 1385 break; 1386 } 1387 } 1388} 1389 1390/**/ 1391void 1392comp_setunset(int rset, int runset, int kset, int kunset) 1393{ 1394 Param *p; 1395 1396 if (comprpms && (rset >= 0 || runset >= 0)) { 1397 for (p = comprpms; rset || runset; rset >>= 1, runset >>= 1, p++) { 1398 if (*p) { 1399 if (rset & 1) 1400 (*p)->node.flags &= ~PM_UNSET; 1401 if (runset & 1) 1402 (*p)->node.flags |= PM_UNSET; 1403 } 1404 } 1405 } 1406 if (compkpms && (kset >= 0 || kunset >= 0)) { 1407 for (p = compkpms; kset || kunset; kset >>= 1, kunset >>= 1, p++) { 1408 if (*p) { 1409 if (kset & 1) 1410 (*p)->node.flags &= ~PM_UNSET; 1411 if (kunset & 1) 1412 (*p)->node.flags |= PM_UNSET; 1413 } 1414 } 1415 } 1416} 1417 1418/**/ 1419static int 1420comp_wrapper(Eprog prog, FuncWrap w, char *name) 1421{ 1422 if (incompfunc != 1) 1423 return 1; 1424 else { 1425 char *orest, *opre, *osuf, *oipre, *oisuf, **owords, **oredirs; 1426 char *oqipre, *oqisuf, *oq, *oqi, *oqs, *oaq; 1427 zlong ocur; 1428 unsigned int runset = 0, kunset = 0, m, sm; 1429 Param *pp; 1430 1431 m = CP_WORDS | CP_REDIRS | CP_CURRENT | CP_PREFIX | CP_SUFFIX | 1432 CP_IPREFIX | CP_ISUFFIX | CP_QIPREFIX | CP_QISUFFIX; 1433 for (pp = comprpms, sm = 1; m; pp++, m >>= 1, sm <<= 1) { 1434 if ((m & 1) && ((*pp)->node.flags & PM_UNSET)) 1435 runset |= sm; 1436 } 1437 if (compkpms[CPN_RESTORE]->node.flags & PM_UNSET) 1438 kunset = CP_RESTORE; 1439 orest = comprestore; 1440 comprestore = ztrdup("auto"); 1441 ocur = compcurrent; 1442 opre = ztrdup(compprefix); 1443 osuf = ztrdup(compsuffix); 1444 oipre = ztrdup(compiprefix); 1445 oisuf = ztrdup(compisuffix); 1446 oqipre = ztrdup(compqiprefix); 1447 oqisuf = ztrdup(compqisuffix); 1448 oq = ztrdup(compquote); 1449 oqi = ztrdup(compquoting); 1450 oqs = ztrdup(compqstack); 1451 oaq = ztrdup(autoq); 1452 owords = zarrdup(compwords); 1453 oredirs = zarrdup(compredirs); 1454 1455 runshfunc(prog, w, name); 1456 1457 if (comprestore && !strcmp(comprestore, "auto")) { 1458 compcurrent = ocur; 1459 zsfree(compprefix); 1460 compprefix = opre; 1461 zsfree(compsuffix); 1462 compsuffix = osuf; 1463 zsfree(compiprefix); 1464 compiprefix = oipre; 1465 zsfree(compisuffix); 1466 compisuffix = oisuf; 1467 zsfree(compqiprefix); 1468 compqiprefix = oqipre; 1469 zsfree(compqisuffix); 1470 compqisuffix = oqisuf; 1471 zsfree(compquote); 1472 compquote = oq; 1473 zsfree(compquoting); 1474 compquoting = oqi; 1475 zsfree(compqstack); 1476 compqstack = oqs; 1477 zsfree(autoq); 1478 autoq = oaq; 1479 freearray(compwords); 1480 freearray(compredirs); 1481 compwords = owords; 1482 compredirs = oredirs; 1483 comp_setunset(CP_COMPSTATE | 1484 (~runset & (CP_WORDS | CP_REDIRS | 1485 CP_CURRENT | CP_PREFIX | 1486 CP_SUFFIX | CP_IPREFIX | CP_ISUFFIX | 1487 CP_QIPREFIX | CP_QISUFFIX)), 1488 (runset & CP_ALLREALS), 1489 (~kunset & CP_RESTORE), (kunset & CP_ALLKEYS)); 1490 } else { 1491 comp_setunset(CP_COMPSTATE, 0, (~kunset & CP_RESTORE), 1492 (kunset & CP_RESTORE)); 1493 zsfree(opre); 1494 zsfree(osuf); 1495 zsfree(oipre); 1496 zsfree(oisuf); 1497 zsfree(oqipre); 1498 zsfree(oqisuf); 1499 zsfree(oq); 1500 zsfree(oqi); 1501 zsfree(oqs); 1502 zsfree(oaq); 1503 freearray(owords); 1504 freearray(oredirs); 1505 } 1506 zsfree(comprestore); 1507 comprestore = orest; 1508 1509 return 0; 1510 } 1511} 1512 1513/**/ 1514static int 1515comp_check(void) 1516{ 1517 if (incompfunc != 1) { 1518 zerr("condition can only be used in completion function"); 1519 return 0; 1520 } 1521 return 1; 1522} 1523 1524/**/ 1525static int 1526cond_psfix(char **a, int id) 1527{ 1528 if (comp_check()) { 1529 if (a[1]) 1530 return do_comp_vars(id, cond_val(a, 0), cond_str(a, 1, 1), 1531 0, NULL, 0); 1532 else 1533 return do_comp_vars(id, -1, cond_str(a, 0, 1), 0, NULL, 0); 1534 } 1535 return 0; 1536} 1537 1538/**/ 1539static int 1540cond_range(char **a, int id) 1541{ 1542 return do_comp_vars(CVT_RANGEPAT, 0, cond_str(a, 0, 1), 0, 1543 (id ? cond_str(a, 1, 1) : NULL), 0); 1544} 1545 1546static struct builtin bintab[] = { 1547 BUILTIN("compadd", BINF_HANDLES_OPTS, bin_compadd, 0, -1, 0, NULL, NULL), 1548 BUILTIN("compset", 0, bin_compset, 1, 3, 0, NULL, NULL), 1549}; 1550 1551static struct conddef cotab[] = { 1552 CONDDEF("after", 0, cond_range, 1, 1, 0), 1553 CONDDEF("between", 0, cond_range, 2, 2, 1), 1554 CONDDEF("prefix", 0, cond_psfix, 1, 2, CVT_PREPAT), 1555 CONDDEF("suffix", 0, cond_psfix, 1, 2, CVT_SUFPAT), 1556}; 1557 1558static struct funcwrap wrapper[] = { 1559 WRAPDEF(comp_wrapper), 1560}; 1561 1562/* The order of the entries in this table has to match the *HOOK 1563 * macros in comp.h */ 1564 1565/**/ 1566struct hookdef comphooks[] = { 1567 HOOKDEF("insert_match", NULL, HOOKF_ALL), 1568 HOOKDEF("menu_start", NULL, HOOKF_ALL), 1569 HOOKDEF("compctl_make", NULL, 0), 1570 HOOKDEF("compctl_cleanup", NULL, 0), 1571 HOOKDEF("comp_list_matches", ilistmatches, 0), 1572}; 1573 1574static struct features module_features = { 1575 bintab, sizeof(bintab)/sizeof(*bintab), 1576 cotab, sizeof(cotab)/sizeof(*cotab), 1577 NULL, 0, 1578 NULL, 0, 1579 0 1580}; 1581 1582/**/ 1583int 1584setup_(UNUSED(Module m)) 1585{ 1586 hasperm = 0; 1587 1588 comprpms = compkpms = NULL; 1589 compwords = compredirs = NULL; 1590 compprefix = compsuffix = compiprefix = compisuffix = 1591 compqiprefix = compqisuffix = 1592 compcontext = compparameter = compredirect = compquote = 1593 compquoting = comprestore = complist = compinsert = 1594 compexact = compexactstr = comppatmatch = comppatinsert = 1595 complastprompt = comptoend = compoldlist = compoldins = 1596 compvared = compqstack = NULL; 1597 complastprefix = ztrdup(""); 1598 complastsuffix = ztrdup(""); 1599 complistmax = 0; 1600 hascompmod = 1; 1601 1602 return 0; 1603} 1604 1605/**/ 1606int 1607features_(Module m, char ***features) 1608{ 1609 *features = featuresarray(m, &module_features); 1610 return 0; 1611} 1612 1613/**/ 1614int 1615enables_(Module m, int **enables) 1616{ 1617 return handlefeatures(m, &module_features, enables); 1618} 1619 1620/**/ 1621int 1622boot_(Module m) 1623{ 1624 addhookfunc("complete", (Hookfn) do_completion); 1625 addhookfunc("before_complete", (Hookfn) before_complete); 1626 addhookfunc("after_complete", (Hookfn) after_complete); 1627 addhookfunc("accept_completion", (Hookfn) accept_last); 1628 addhookfunc("reverse_menu", (Hookfn) reverse_menu); 1629 addhookfunc("list_matches", (Hookfn) list_matches); 1630 addhookfunc("invalidate_list", (Hookfn) invalidate_list); 1631 (void)addhookdefs(m, comphooks, sizeof(comphooks)/sizeof(*comphooks)); 1632 return addwrapper(m, wrapper); 1633} 1634 1635/**/ 1636int 1637cleanup_(Module m) 1638{ 1639 deletehookfunc("complete", (Hookfn) do_completion); 1640 deletehookfunc("before_complete", (Hookfn) before_complete); 1641 deletehookfunc("after_complete", (Hookfn) after_complete); 1642 deletehookfunc("accept_completion", (Hookfn) accept_last); 1643 deletehookfunc("reverse_menu", (Hookfn) reverse_menu); 1644 deletehookfunc("list_matches", (Hookfn) list_matches); 1645 deletehookfunc("invalidate_list", (Hookfn) invalidate_list); 1646 (void)deletehookdefs(m, comphooks, 1647 sizeof(comphooks)/sizeof(*comphooks)); 1648 deletewrapper(m, wrapper); 1649 return setfeatureenables(m, &module_features, NULL); 1650} 1651 1652/**/ 1653int 1654finish_(UNUSED(Module m)) 1655{ 1656 if (compwords) 1657 freearray(compwords); 1658 if (compredirs) 1659 freearray(compredirs); 1660 zsfree(compprefix); 1661 zsfree(compsuffix); 1662 zsfree(complastprefix); 1663 zsfree(complastsuffix); 1664 zsfree(compiprefix); 1665 zsfree(compisuffix); 1666 zsfree(compqiprefix); 1667 zsfree(compqisuffix); 1668 zsfree(compcontext); 1669 zsfree(compparameter); 1670 zsfree(compredirect); 1671 zsfree(compquote); 1672 zsfree(compqstack); 1673 zsfree(compquoting); 1674 zsfree(comprestore); 1675 zsfree(complist); 1676 zsfree(compinsert); 1677 zsfree(compexact); 1678 zsfree(compexactstr); 1679 zsfree(comppatmatch); 1680 zsfree(comppatinsert); 1681 zsfree(complastprompt); 1682 zsfree(comptoend); 1683 zsfree(compoldlist); 1684 zsfree(compoldins); 1685 zsfree(compvared); 1686 1687 hascompmod = 0; 1688 1689 return 0; 1690} 1691