1/* 2 * compctl.c - the compctl builtin 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 "compctl.mdh" 31#include "compctl.pro" 32 33/* Global matcher. */ 34 35/**/ 36static Cmlist cmatcher; 37 38/* Default completion infos */ 39 40/**/ 41struct compctl cc_compos, cc_default, cc_first, cc_dummy; 42 43/* Hash table for completion info for commands */ 44 45/**/ 46HashTable compctltab; 47 48/* List of pattern compctls */ 49 50/**/ 51Patcomp patcomps; 52 53#define COMP_LIST (1<<0) /* -L */ 54#define COMP_COMMAND (1<<1) /* -C */ 55#define COMP_DEFAULT (1<<2) /* -D */ 56#define COMP_FIRST (1<<3) /* -T */ 57#define COMP_REMOVE (1<<4) 58#define COMP_LISTMATCH (1<<5) /* -L and -M */ 59 60#define COMP_SPECIAL (COMP_COMMAND|COMP_DEFAULT|COMP_FIRST) 61 62/* Flag for listing, command, default, or first completion */ 63static int cclist; 64 65/* Mask for determining what to print */ 66static unsigned long showmask = 0; 67 68/**/ 69static void 70createcompctltable(void) 71{ 72 compctltab = newhashtable(23, "compctltab", NULL); 73 74 compctltab->hash = hasher; 75 compctltab->emptytable = emptyhashtable; 76 compctltab->filltable = NULL; 77 compctltab->cmpnodes = strcmp; 78 compctltab->addnode = addhashnode; 79 compctltab->getnode = gethashnode2; 80 compctltab->getnode2 = gethashnode2; 81 compctltab->removenode = removehashnode; 82 compctltab->disablenode = NULL; 83 compctltab->enablenode = NULL; 84 compctltab->freenode = freecompctlp; 85 compctltab->printnode = printcompctlp; 86 87 patcomps = NULL; 88} 89 90/**/ 91static void 92freecompctlp(HashNode hn) 93{ 94 Compctlp ccp = (Compctlp) hn; 95 96 zsfree(ccp->node.nam); 97 freecompctl(ccp->cc); 98 zfree(ccp, sizeof(struct compctlp)); 99} 100 101/**/ 102void 103freecompctl(Compctl cc) 104{ 105 if (cc == &cc_default || 106 cc == &cc_first || 107 cc == &cc_compos || 108 --cc->refc > 0) 109 return; 110 111 zsfree(cc->keyvar); 112 zsfree(cc->glob); 113 zsfree(cc->str); 114 zsfree(cc->func); 115 zsfree(cc->explain); 116 zsfree(cc->ylist); 117 zsfree(cc->prefix); 118 zsfree(cc->suffix); 119 zsfree(cc->hpat); 120 zsfree(cc->gname); 121 zsfree(cc->subcmd); 122 zsfree(cc->substr); 123 if (cc->cond) 124 freecompcond(cc->cond); 125 if (cc->ext) { 126 Compctl n, m; 127 128 n = cc->ext; 129 do { 130 m = (Compctl) (n->next); 131 freecompctl(n); 132 n = m; 133 } 134 while (n); 135 } 136 if (cc->xor && cc->xor != &cc_default) 137 freecompctl(cc->xor); 138 if (cc->matcher) 139 freecmatcher(cc->matcher); 140 zsfree(cc->mstr); 141 zfree(cc, sizeof(struct compctl)); 142} 143 144/**/ 145void 146freecompcond(void *a) 147{ 148 Compcond cc = (Compcond) a; 149 Compcond and, or, c; 150 int n; 151 152 for (c = cc; c; c = or) { 153 or = c->or; 154 for (; c; c = and) { 155 and = c->and; 156 if (c->type == CCT_POS || 157 c->type == CCT_NUMWORDS) { 158 free(c->u.r.a); 159 free(c->u.r.b); 160 } else if (c->type == CCT_CURSUF || 161 c->type == CCT_CURPRE) { 162 for (n = 0; n < c->n; n++) 163 if (c->u.s.s[n]) 164 zsfree(c->u.s.s[n]); 165 free(c->u.s.s); 166 } else if (c->type == CCT_RANGESTR || 167 c->type == CCT_RANGEPAT) { 168 for (n = 0; n < c->n; n++) 169 if (c->u.l.a[n]) 170 zsfree(c->u.l.a[n]); 171 free(c->u.l.a); 172 for (n = 0; n < c->n; n++) 173 if (c->u.l.b[n]) 174 zsfree(c->u.l.b[n]); 175 free(c->u.l.b); 176 } else { 177 for (n = 0; n < c->n; n++) 178 if (c->u.s.s[n]) 179 zsfree(c->u.s.s[n]); 180 free(c->u.s.p); 181 free(c->u.s.s); 182 } 183 zfree(c, sizeof(struct compcond)); 184 } 185 } 186} 187 188/**/ 189int 190compctlread(char *name, char **args, Options ops, char *reply) 191{ 192 char *buf, *bptr; 193 194 /* only allowed to be called for completion */ 195 if (!incompctlfunc) { 196 zwarnnam(name, "option valid only in functions called for completion"); 197 return 1; 198 } 199 200 METACHECK(); 201 202 if (OPT_ISSET(ops,'l')) { 203 /* 204 * -ln gives the index of the word the cursor is currently on, which 205 * is available in zlemetacs (but remember that Zsh counts from one, 206 * not zero!) 207 */ 208 if (OPT_ISSET(ops,'n')) { 209 char nbuf[14]; 210 211 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) 212 printf("%d\n", zlemetacs + 1); 213 if (!OPT_ISSET(ops,'e')) { 214 sprintf(nbuf, "%d", zlemetacs + 1); 215 setsparam(reply, ztrdup(nbuf)); 216 } 217 return 0; 218 } 219 /* without -n, the current line is assigned to the given parameter as a 220 scalar */ 221 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) { 222 zputs(zlemetaline, stdout); 223 putchar('\n'); 224 } 225 if (!OPT_ISSET(ops,'e')) 226 setsparam(reply, ztrdup(zlemetaline)); 227 } else { 228 int i; 229 230 /* -cn gives the current cursor position within the current word, which 231 is available in clwpos (but remember that Zsh counts from one, not 232 zero!) */ 233 if (OPT_ISSET(ops,'n')) { 234 char nbuf[14]; 235 236 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) 237 printf("%d\n", clwpos + 1); 238 if (!OPT_ISSET(ops,'e')) { 239 sprintf(nbuf, "%d", clwpos + 1); 240 setsparam(reply, ztrdup(nbuf)); 241 } 242 return 0; 243 } 244 /* without -n, the words of the current line are assigned to the given 245 parameters separately */ 246 if (OPT_ISSET(ops,'A') && !OPT_ISSET(ops,'e')) { 247 /* the -A option means that one array is specified, instead of 248 many parameters */ 249 char **p, **b = (char **)zshcalloc((clwnum + 1) * sizeof(char *)); 250 251 for (i = 0, p = b; i < clwnum; p++, i++) 252 *p = ztrdup(clwords[i]); 253 254 setaparam(reply, b); 255 return 0; 256 } 257 if (OPT_ISSET(ops,'e') || OPT_ISSET(ops,'E')) { 258 for (i = 0; i < clwnum; i++) { 259 zputs(clwords[i], stdout); 260 putchar('\n'); 261 } 262 263 if (OPT_ISSET(ops,'e')) 264 return 0; 265 } 266 267 for (i = 0; i < clwnum && *args; reply = *args++, i++) 268 setsparam(reply, ztrdup(clwords[i])); 269 270 if (i < clwnum) { 271 int j, len; 272 273 for (j = i, len = 0; j < clwnum; len += strlen(clwords[j++])); 274 bptr = buf = zalloc(len + j - i); 275 while (i < clwnum) { 276 strucpy(&bptr, clwords[i++]); 277 *bptr++ = ' '; 278 } 279 bptr[-1] = '\0'; 280 } else 281 buf = ztrdup(""); 282 setsparam(reply, buf); 283 } 284 return 0; 285} 286 287/* Copy a list of completion matchers. */ 288 289/**/ 290static Cmlist 291cpcmlist(Cmlist l) 292{ 293 Cmlist r = NULL, *p = &r, n; 294 295 while (l) { 296 *p = n = (Cmlist) zalloc(sizeof(struct cmlist)); 297 n->next = NULL; 298 n->matcher = cpcmatcher(l->matcher); 299 n->str = ztrdup(l->str); 300 301 p = &(n->next); 302 l = l->next; 303 } 304 return r; 305} 306 307/* Set the global match specs. */ 308 309/**/ 310static int 311set_gmatcher(char *name, char **argv) 312{ 313 Cmlist l = NULL, *q = &l, n; 314 Cmatcher m; 315 316 while (*argv) { 317 if ((m = parse_cmatcher(name, *argv)) == pcm_err) 318 return 1; 319 *q = n = (Cmlist) zhalloc(sizeof(struct cmlist)); 320 n->next = NULL; 321 n->matcher = m; 322 n->str = *argv++; 323 324 q = &(n->next); 325 } 326 freecmlist(cmatcher); 327 cmatcher = cpcmlist(l); 328 329 return 1; 330} 331 332/* Try to get the global matcher from the given compctl. */ 333 334/**/ 335static int 336get_gmatcher(char *name, char **argv) 337{ 338 if (!strcmp(*argv, "-M")) { 339 char **p = ++argv; 340 341 while (*p) { 342 if (**p++ == '-') 343 return 0; 344 } 345 if (set_gmatcher(name, argv)) 346 return 2; 347 348 return 1; 349 } 350 return 0; 351} 352 353/* This prints the global matcher definitions. */ 354 355/**/ 356static void 357print_gmatcher(int ac) 358{ 359 Cmlist p; 360 361 if ((p = cmatcher)) { 362 printf((ac ? "compctl -M" : "MATCH")); 363 364 while (p) { 365 printf(" \'%s\'", p->str); 366 367 p = p->next; 368 } 369 putchar('\n'); 370 } 371} 372 373/* Parse the basic flags for `compctl' */ 374 375/**/ 376static int 377get_compctl(char *name, char ***av, Compctl cc, int first, int isdef, int cl) 378{ 379 /* Parse the basic flags for completion: 380 * first is a flag that we are not in extended completion, 381 * while hx indicates or (+) completion (need to know for 382 * default and command completion as the initial compctl is special). 383 * cct is a temporary just to hold flags; it never needs freeing. 384 */ 385 struct compctl cct; 386 char **argv = *av; 387 int ready = 0, hx = 0; 388 389 /* Handle `compctl + foo ...' specially: turn it into 390 * a default compctl by removing it from the hash table. 391 */ 392 if (first && argv[0][0] == '+' && !argv[0][1] && 393 !(argv[1] && argv[1][0] == '-' && argv[1][1])) { 394 argv++; 395 if(argv[0] && argv[0][0] == '-') 396 argv++; 397 *av = argv; 398 if (cl) 399 return 1; 400 else { 401 freecompctl(cc); 402 cclist = COMP_REMOVE; 403 return 0; 404 } 405 } 406 407 memset((void *)&cct, 0, sizeof(cct)); 408 cct.mask2 = CC_CCCONT; 409 410 /* Loop through the flags until we have no more: * 411 * those with arguments are not properly allocated yet, * 412 * we just hang on to the argument that was passed. */ 413 for (; !ready && argv[0] && argv[0][0] == '-' && (argv[0][1] || !first);) { 414 if (!argv[0][1]) 415 *argv = "-+"; 416 while (!ready && *++(*argv)) { 417 if(**argv == Meta) 418 *++*argv ^= 32; 419 switch (**argv) { 420 case 'f': 421 cct.mask |= CC_FILES; 422 break; 423 case 'c': 424 cct.mask |= CC_COMMPATH; 425 break; 426 case 'm': 427 cct.mask |= CC_EXTCMDS; 428 break; 429 case 'w': 430 cct.mask |= CC_RESWDS; 431 break; 432 case 'o': 433 cct.mask |= CC_OPTIONS; 434 break; 435 case 'v': 436 cct.mask |= CC_VARS; 437 break; 438 case 'b': 439 cct.mask |= CC_BINDINGS; 440 break; 441 case 'A': 442 cct.mask |= CC_ARRAYS; 443 break; 444 case 'I': 445 cct.mask |= CC_INTVARS; 446 break; 447 case 'F': 448 cct.mask |= CC_SHFUNCS; 449 break; 450 case 'p': 451 cct.mask |= CC_PARAMS; 452 break; 453 case 'E': 454 cct.mask |= CC_ENVVARS; 455 break; 456 case 'j': 457 cct.mask |= CC_JOBS; 458 break; 459 case 'r': 460 cct.mask |= CC_RUNNING; 461 break; 462 case 'z': 463 cct.mask |= CC_STOPPED; 464 break; 465 case 'B': 466 cct.mask |= CC_BUILTINS; 467 break; 468 case 'a': 469 cct.mask |= CC_ALREG | CC_ALGLOB; 470 break; 471 case 'R': 472 cct.mask |= CC_ALREG; 473 break; 474 case 'G': 475 cct.mask |= CC_ALGLOB; 476 break; 477 case 'u': 478 cct.mask |= CC_USERS; 479 break; 480 case 'd': 481 cct.mask |= CC_DISCMDS; 482 break; 483 case 'e': 484 cct.mask |= CC_EXCMDS; 485 break; 486 case 'N': 487 cct.mask |= CC_SCALARS; 488 break; 489 case 'O': 490 cct.mask |= CC_READONLYS; 491 break; 492 case 'Z': 493 cct.mask |= CC_SPECIALS; 494 break; 495 case 'q': 496 cct.mask |= CC_REMOVE; 497 break; 498 case 'U': 499 cct.mask |= CC_DELETE; 500 break; 501 case 'n': 502 cct.mask |= CC_NAMED; 503 break; 504 case 'Q': 505 cct.mask |= CC_QUOTEFLAG; 506 break; 507 case '/': 508 cct.mask |= CC_DIRS; 509 break; 510 case 't': 511 { 512 char *p; 513 514 if (cl) { 515 zwarnnam(name, "illegal option -%c", **argv); 516 return 1; 517 } 518 if ((*argv)[1]) { 519 p = (*argv) + 1; 520 *argv = "" - 1; 521 } else if (!argv[1]) { 522 zwarnnam(name, "retry specification expected after -%c", 523 **argv); 524 return 1; 525 } else { 526 p = *++argv; 527 *argv = "" - 1; 528 } 529 switch (*p) { 530 case '+': 531 cct.mask2 = CC_XORCONT; 532 break; 533 case 'n': 534 cct.mask2 = 0; 535 break; 536 case '-': 537 cct.mask2 = CC_PATCONT; 538 break; 539 case 'x': 540 cct.mask2 = CC_DEFCONT; 541 break; 542 default: 543 zwarnnam(name, "invalid retry specification character `%c'", 544 *p); 545 return 1; 546 } 547 if (p[1]) { 548 zwarnnam(name, "too many retry specification characters: `%s'", 549 p + 1); 550 return 1; 551 } 552 } 553 break; 554 case 'k': 555 if ((*argv)[1]) { 556 cct.keyvar = (*argv) + 1; 557 *argv = "" - 1; 558 } else if (!argv[1]) { 559 zwarnnam(name, "variable name expected after -%c", **argv); 560 return 1; 561 } else { 562 cct.keyvar = *++argv; 563 *argv = "" - 1; 564 } 565 break; 566 case 'K': 567 if ((*argv)[1]) { 568 cct.func = (*argv) + 1; 569 *argv = "" - 1; 570 } else if (!argv[1]) { 571 zwarnnam(name, "function name expected after -%c", **argv); 572 return 1; 573 } else { 574 cct.func = *++argv; 575 *argv = "" - 1; 576 } 577 break; 578 case 'Y': 579 cct.mask |= CC_EXPANDEXPL; 580 goto expl; 581 case 'X': 582 cct.mask &= ~CC_EXPANDEXPL; 583 expl: 584 if ((*argv)[1]) { 585 cct.explain = (*argv) + 1; 586 *argv = "" - 1; 587 } else if (!argv[1]) { 588 zwarnnam(name, "string expected after -%c", **argv); 589 return 1; 590 } else { 591 cct.explain = *++argv; 592 *argv = "" - 1; 593 } 594 break; 595 case 'y': 596 if ((*argv)[1]) { 597 cct.ylist = (*argv) + 1; 598 *argv = "" - 1; 599 } else if (!argv[1]) { 600 zwarnnam(name, "function/variable expected after -%c", 601 **argv); 602 } else { 603 cct.ylist = *++argv; 604 *argv = "" - 1; 605 } 606 break; 607 case 'P': 608 if ((*argv)[1]) { 609 cct.prefix = (*argv) + 1; 610 *argv = "" - 1; 611 } else if (!argv[1]) { 612 zwarnnam(name, "string expected after -%c", **argv); 613 return 1; 614 } else { 615 cct.prefix = *++argv; 616 *argv = "" - 1; 617 } 618 break; 619 case 'S': 620 if ((*argv)[1]) { 621 cct.suffix = (*argv) + 1; 622 *argv = "" - 1; 623 } else if (!argv[1]) { 624 zwarnnam(name, "string expected after -%c", **argv); 625 return 1; 626 } else { 627 cct.suffix = *++argv; 628 *argv = "" - 1; 629 } 630 break; 631 case 'g': 632 if ((*argv)[1]) { 633 cct.glob = (*argv) + 1; 634 *argv = "" - 1; 635 } else if (!argv[1]) { 636 zwarnnam(name, "glob pattern expected after -%c", **argv); 637 return 1; 638 } else { 639 cct.glob = *++argv; 640 *argv = "" - 1; 641 } 642 break; 643 case 's': 644 if ((*argv)[1]) { 645 cct.str = (*argv) + 1; 646 *argv = "" - 1; 647 } else if (!argv[1]) { 648 zwarnnam(name, "command string expected after -%c", 649 **argv); 650 return 1; 651 } else { 652 cct.str = *++argv; 653 *argv = "" - 1; 654 } 655 break; 656 case 'l': 657 if (cl) { 658 zwarnnam(name, "illegal option -%c", **argv); 659 return 1; 660 } else if ((*argv)[1]) { 661 cct.subcmd = (*argv) + 1; 662 *argv = "" - 1; 663 } else if (!argv[1]) { 664 zwarnnam(name, "command name expected after -%c", **argv); 665 return 1; 666 } else { 667 cct.subcmd = *++argv; 668 *argv = "" - 1; 669 } 670 break; 671 case 'h': 672 if (cl) { 673 zwarnnam(name, "illegal option -%c", **argv); 674 return 1; 675 } else if ((*argv)[1]) { 676 cct.substr = (*argv) + 1; 677 *argv = "" - 1; 678 } else if (!argv[1]) { 679 zwarnnam(name, "command name expected after -%c", **argv); 680 return 1; 681 } else { 682 cct.substr = *++argv; 683 *argv = "" - 1; 684 } 685 break; 686 case 'W': 687 if ((*argv)[1]) { 688 cct.withd = (*argv) + 1; 689 *argv = "" - 1; 690 } else if (!argv[1]) { 691 zwarnnam(name, "path expected after -%c", **argv); 692 return 1; 693 } else { 694 cct.withd = *++argv; 695 *argv = "" - 1; 696 } 697 break; 698 case 'J': 699 if ((*argv)[1]) { 700 cct.gname = (*argv) + 1; 701 *argv = "" - 1; 702 } else if (!argv[1]) { 703 zwarnnam(name, "group name expected after -%c", **argv); 704 return 1; 705 } else { 706 cct.gname = *++argv; 707 *argv = "" - 1; 708 } 709 break; 710 case 'V': 711 if ((*argv)[1]) { 712 cct.gname = (*argv) + 1; 713 *argv = "" - 1; 714 } else if (!argv[1]) { 715 zwarnnam(name, "group name expected after -%c", **argv); 716 return 1; 717 } else { 718 cct.gname = *++argv; 719 *argv = "" - 1; 720 } 721 cct.mask2 |= CC_NOSORT; 722 break; 723 case '1': 724 cct.mask2 |= CC_UNIQALL; 725 cct.mask2 &= ~CC_UNIQCON; 726 break; 727 case '2': 728 cct.mask2 |= CC_UNIQCON; 729 cct.mask2 &= ~CC_UNIQALL; 730 break; 731 case 'M': 732 if (cclist & COMP_LIST) { 733 cclist |= COMP_LISTMATCH; 734 } else if ((*argv)[1]) { 735 if ((cct.matcher = 736 parse_cmatcher(name, (cct.mstr = (*argv) + 1))) == 737 pcm_err) { 738 cct.matcher = NULL; 739 cct.mstr = NULL; 740 return 1; 741 } 742 *argv = "" - 1; 743 } else if (!argv[1]) { 744 zwarnnam(name, "matching specification expected after -%c", 745 **argv); 746 return 1; 747 } else { 748 if ((cct.matcher = 749 parse_cmatcher(name, (cct.mstr = *++argv))) == 750 pcm_err) { 751 cct.matcher = NULL; 752 cct.mstr = NULL; 753 return 1; 754 } 755 *argv = "" - 1; 756 } 757 break; 758 case 'H': 759 if ((*argv)[1]) 760 cct.hnum = atoi((*argv) + 1); 761 else if (argv[1]) 762 cct.hnum = atoi(*++argv); 763 else { 764 zwarnnam(name, "number expected after -%c", **argv); 765 return 1; 766 } 767 if (!argv[1]) { 768 zwarnnam(name, "missing pattern after -%c", **argv); 769 return 1; 770 } 771 cct.hpat = *++argv; 772 if (cct.hnum < 1) 773 cct.hnum = 0; 774 if (*cct.hpat == '*' && !cct.hpat[1]) 775 cct.hpat = ""; 776 *argv = "" - 1; 777 break; 778 case 'C': 779 if (cl) { 780 zwarnnam(name, "illegal option -%c", **argv); 781 return 1; 782 } 783 if (first && !hx) { 784 cclist |= COMP_COMMAND; 785 } else { 786 zwarnnam(name, "misplaced command completion (-C) flag"); 787 return 1; 788 } 789 break; 790 case 'D': 791 if (cl) { 792 zwarnnam(name, "illegal option -%c", **argv); 793 return 1; 794 } 795 if (first && !hx) { 796 isdef = 1; 797 cclist |= COMP_DEFAULT; 798 } else { 799 zwarnnam(name, "misplaced default completion (-D) flag"); 800 return 1; 801 } 802 break; 803 case 'T': 804 if (cl) { 805 zwarnnam(name, "illegal option -%c", **argv); 806 return 1; 807 } 808 if (first && !hx) { 809 cclist |= COMP_FIRST; 810 } else { 811 zwarnnam(name, "misplaced first completion (-T) flag"); 812 return 1; 813 } 814 break; 815 case 'L': 816 if (cl) { 817 zwarnnam(name, "illegal option -%c", **argv); 818 return 1; 819 } 820 if (!first || hx) { 821 zwarnnam(name, "illegal use of -L flag"); 822 return 1; 823 } 824 cclist |= COMP_LIST; 825 break; 826 case 'x': 827 if (cl) { 828 zwarnnam(name, "extended completion not allowed"); 829 return 1; 830 } 831 if (!argv[1]) { 832 zwarnnam(name, "condition expected after -%c", **argv); 833 return 1; 834 } 835 if (first) { 836 argv++; 837 if (get_xcompctl(name, &argv, &cct, isdef)) { 838 if (cct.ext) 839 freecompctl(cct.ext); 840 return 1; 841 } 842 ready = 2; 843 } else { 844 zwarnnam(name, "recursive extended completion not allowed"); 845 return 1; 846 } 847 break; 848 default: 849 if (!first && (**argv == '-' || **argv == '+') && !argv[0][1]) 850 (*argv)--, argv--, ready = 1; 851 else { 852 zwarnnam(name, "bad option: -%c", **argv); 853 return 1; 854 } 855 } 856 } 857 858 if (*++argv && (!ready || ready == 2) && 859 **argv == '+' && !argv[0][1]) { 860 if (cl) { 861 zwarnnam(name, "xor'ed completion illegal"); 862 return 1; 863 } 864 /* There's an alternative (+) completion: assign 865 * what we have so far before moving on to that. 866 */ 867 if (cc_assign(name, &cc, &cct, first && !hx)) 868 return 1; 869 870 hx = 1; 871 ready = 0; 872 873 if (!*++argv || **argv != '-' || 874 (**argv == '-' && (!argv[0][1] || 875 (argv[0][1] == '-' && !argv[0][2])))) { 876 /* No argument to +, which means do default completion */ 877 if (isdef) 878 zwarnnam(name, 879 "recursive xor'd default completions not allowed"); 880 else 881 cc->xor = &cc_default; 882 } else { 883 /* more flags follow: prepare to loop again */ 884 cc->xor = (Compctl) zshcalloc(sizeof(*cc)); 885 cc = cc->xor; 886 memset((void *)&cct, 0, sizeof(cct)); 887 cct.mask2 = CC_CCCONT; 888 } 889 } 890 } 891 if (!ready && *argv && **argv == '-') 892 argv++; 893 894 if (! (cct.mask & (CC_EXCMDS | CC_DISCMDS))) 895 cct.mask |= CC_EXCMDS; 896 897 /* assign the last set of flags we parsed */ 898 if (cc_assign(name, &cc, &cct, first && !hx)) 899 return 1; 900 901 *av = argv; 902 903 return 0; 904} 905 906/* Handle the -x ... -- part of compctl. */ 907 908/**/ 909static int 910get_xcompctl(char *name, char ***av, Compctl cc, int isdef) 911{ 912 char **argv = *av, *t, *tt, sav; 913 int n, l = 0, ready = 0; 914 Compcond m, c, o; 915 Compctl *next = &(cc->ext); 916 917 while (!ready) { 918 /* o keeps track of or's, m remembers the starting condition, 919 * c is the current condition being parsed 920 */ 921 o = m = c = (Compcond) zshcalloc(sizeof(*c)); 922 /* Loop over each condition: something like 's[...][...], p[...]' */ 923 for (t = *argv; *t;) { 924 while (*t == ' ') 925 t++; 926 /* First get the condition code */ 927 switch (*t) { 928 case 'q': 929 c->type = CCT_QUOTE; 930 break; 931 case 's': 932 c->type = CCT_CURSUF; 933 break; 934 case 'S': 935 c->type = CCT_CURPRE; 936 break; 937 case 'p': 938 c->type = CCT_POS; 939 break; 940 case 'c': 941 c->type = CCT_CURSTR; 942 break; 943 case 'C': 944 c->type = CCT_CURPAT; 945 break; 946 case 'w': 947 c->type = CCT_WORDSTR; 948 break; 949 case 'W': 950 c->type = CCT_WORDPAT; 951 break; 952 case 'n': 953 c->type = CCT_CURSUB; 954 break; 955 case 'N': 956 c->type = CCT_CURSUBC; 957 break; 958 case 'm': 959 c->type = CCT_NUMWORDS; 960 break; 961 case 'r': 962 c->type = CCT_RANGESTR; 963 break; 964 case 'R': 965 c->type = CCT_RANGEPAT; 966 break; 967 default: 968 t[1] = '\0'; 969 zwarnnam(name, "unknown condition code: %s", t); 970 zfree(m, sizeof(struct compcond)); 971 972 return 1; 973 } 974 /* Now get the arguments in square brackets */ 975 if (t[1] != '[') { 976 t[1] = '\0'; 977 zwarnnam(name, "expected condition after condition code: %s", t); 978 zfree(m, sizeof(struct compcond)); 979 980 return 1; 981 } 982 t++; 983 /* First count how many or'd arguments there are, 984 * marking the active ]'s and ,'s with unprintable characters. 985 */ 986 for (n = 0, tt = t; *tt == '['; n++) { 987 for (l = 1, tt++; *tt && l; tt++) 988 if (*tt == '\\' && tt[1]) 989 tt++; 990 else if (*tt == '[') 991 l++; 992 else if (*tt == ']') 993 l--; 994 else if (l == 1 && *tt == ',') 995 *tt = '\201'; 996 if (tt[-1] == ']') 997 tt[-1] = '\200'; 998 } 999 1000 if (l) { 1001 t[1] = '\0'; 1002 zwarnnam(name, "error after condition code: %s", t); 1003 zfree(m, sizeof(struct compcond)); 1004 1005 return 1; 1006 } 1007 c->n = n; 1008 1009 /* Allocate space for all the arguments of the conditions */ 1010 if (c->type == CCT_POS || 1011 c->type == CCT_NUMWORDS) { 1012 c->u.r.a = (int *)zshcalloc(n * sizeof(int)); 1013 c->u.r.b = (int *)zshcalloc(n * sizeof(int)); 1014 } else if (c->type == CCT_CURSUF || 1015 c->type == CCT_CURPRE || 1016 c->type == CCT_QUOTE) 1017 c->u.s.s = (char **)zshcalloc(n * sizeof(char *)); 1018 1019 else if (c->type == CCT_RANGESTR || 1020 c->type == CCT_RANGEPAT) { 1021 c->u.l.a = (char **)zshcalloc(n * sizeof(char *)); 1022 c->u.l.b = (char **)zshcalloc(n * sizeof(char *)); 1023 } else { 1024 c->u.s.p = (int *)zshcalloc(n * sizeof(int)); 1025 c->u.s.s = (char **)zshcalloc(n * sizeof(char *)); 1026 } 1027 /* Now loop over the actual arguments */ 1028 for (l = 0; *t == '['; l++, t++) { 1029 for (t++; *t && *t == ' '; t++); 1030 tt = t; 1031 if (c->type == CCT_POS || 1032 c->type == CCT_NUMWORDS) { 1033 /* p[...] or m[...]: one or two numbers expected */ 1034 for (; *t && *t != '\201' && *t != '\200'; t++); 1035 if (!(sav = *t)) { 1036 zwarnnam(name, "error in condition"); 1037 freecompcond(m); 1038 return 1; 1039 } 1040 *t = '\0'; 1041 c->u.r.a[l] = atoi(tt); 1042 /* Second argument is optional: see if it's there */ 1043 if (sav == '\200') 1044 /* no: copy first argument */ 1045 c->u.r.b[l] = c->u.r.a[l]; 1046 else { 1047 tt = ++t; 1048 for (; *t && *t != '\200'; t++); 1049 if (!*t) { 1050 zwarnnam(name, "error in condition"); 1051 freecompcond(m); 1052 return 1; 1053 } 1054 *t = '\0'; 1055 c->u.r.b[l] = atoi(tt); 1056 } 1057 } else if (c->type == CCT_CURSUF || 1058 c->type == CCT_CURPRE || 1059 c->type == CCT_QUOTE) { 1060 /* -s[..] or -S[..]: single string expected */ 1061 for (; *t && *t != '\200'; t++) 1062 if (*t == '\201') 1063 *t = ','; 1064 if (!*t) { 1065 zwarnnam(name, "error in condition"); 1066 freecompcond(m); 1067 return 1; 1068 } 1069 *t = '\0'; 1070 c->u.s.s[l] = ztrdup(tt); 1071 } else if (c->type == CCT_RANGESTR || 1072 c->type == CCT_RANGEPAT) { 1073 int hc; 1074 1075 /* -r[..,..] or -R[..,..]: two strings expected */ 1076 for (; *t && *t != '\201' && *t != '\200'; t++); 1077 if (!*t) { 1078 zwarnnam(name, "error in condition"); 1079 freecompcond(m); 1080 return 1; 1081 } 1082 hc = (*t == '\201'); 1083 *t = '\0'; 1084 c->u.l.a[l] = ztrdup(tt); 1085 if (hc) { 1086 tt = ++t; 1087 /* any more commas are text, not active */ 1088 for (; *t && *t != '\200'; t++) 1089 if (*t == '\201') 1090 *t = ','; 1091 if (!*t) { 1092 zwarnnam(name, "error in condition"); 1093 freecompcond(m); 1094 return 1; 1095 } 1096 *t = '\0'; 1097 c->u.l.b[l] = ztrdup(tt); 1098 } 1099 else 1100 c->u.l.b[l] = NULL; 1101 } else { 1102 /* remaining patterns are number followed by string */ 1103 for (; *t && *t != '\200' && *t != '\201'; t++); 1104 if (!*t || *t == '\200') { 1105 zwarnnam(name, "error in condition"); 1106 freecompcond(m); 1107 return 1; 1108 } 1109 *t = '\0'; 1110 c->u.s.p[l] = atoi(tt); 1111 tt = ++t; 1112 for (; *t && *t != '\200'; t++) 1113 if (*t == '\201') 1114 *t = ','; 1115 if (!*t) { 1116 zwarnnam(name, "error in condition"); 1117 freecompcond(m); 1118 return 1; 1119 } 1120 *t = '\0'; 1121 c->u.s.s[l] = ztrdup(tt); 1122 } 1123 } 1124 while (*t == ' ') 1125 t++; 1126 if (*t == ',') { 1127 /* Another condition to `or' */ 1128 o->or = c = (Compcond) zshcalloc(sizeof(*c)); 1129 o = c; 1130 t++; 1131 } else if (*t) { 1132 /* Another condition to `and' */ 1133 c->and = (Compcond) zshcalloc(sizeof(*c)); 1134 c = c->and; 1135 } 1136 } 1137 /* Assign condition to current compctl */ 1138 *next = (Compctl) zshcalloc(sizeof(*cc)); 1139 (*next)->cond = m; 1140 argv++; 1141 /* End of the condition; get the flags that go with it. */ 1142 if (get_compctl(name, &argv, *next, 0, isdef, 0)) 1143 return 1; 1144 if ((!argv || !*argv) && (cclist & COMP_SPECIAL)) 1145 /* default, first, or command completion finished */ 1146 ready = 1; 1147 else { 1148 /* see if we are looking for more conditions or are 1149 * ready to return (ready = 1) 1150 */ 1151 if (!argv || !*argv || **argv != '-' || 1152 ((!argv[0][1] || argv[0][1] == '+') && !argv[1])) { 1153 zwarnnam(name, "missing command names"); 1154 return 1; 1155 } 1156 if (!strcmp(*argv, "--")) 1157 ready = 1; 1158 else if (!strcmp(*argv, "-+") && argv[1] && 1159 !strcmp(argv[1], "--")) { 1160 ready = 1; 1161 argv++; 1162 } 1163 argv++; 1164 /* prepare to put the next lot of conditions on the end */ 1165 next = &((*next)->next); 1166 } 1167 } 1168 /* save position at end of parsing */ 1169 *av = argv - 1; 1170 return 0; 1171} 1172 1173/**/ 1174static int 1175cc_assign(char *name, Compctl *ccptr, Compctl cct, int reass) 1176{ 1177 /* Copy over the details from the values in cct to those in *ccptr */ 1178 Compctl cc; 1179 1180 /* Handle assignment of new default or command completion */ 1181 if (reass && !(cclist & COMP_LIST)) { 1182 /* if not listing */ 1183 if (cclist == (COMP_COMMAND|COMP_DEFAULT) 1184 || cclist == (COMP_COMMAND|COMP_FIRST) 1185 || cclist == (COMP_DEFAULT|COMP_FIRST) 1186 || cclist == COMP_SPECIAL) { 1187 zwarnnam(name, "can't set -D, -T, and -C simultaneously"); 1188 /* ... because the following code wouldn't work. */ 1189 return 1; 1190 } 1191 if (cclist & COMP_COMMAND) { 1192 /* command */ 1193 *ccptr = &cc_compos; 1194 cc_reassign(*ccptr); 1195 } else if (cclist & COMP_DEFAULT) { 1196 /* default */ 1197 *ccptr = &cc_default; 1198 cc_reassign(*ccptr); 1199 } else if (cclist & COMP_FIRST) { 1200 /* first */ 1201 *ccptr = &cc_first; 1202 cc_reassign(*ccptr); 1203 } 1204 } 1205 1206 /* Free the old compctl */ 1207 cc = *ccptr; 1208 zsfree(cc->keyvar); 1209 zsfree(cc->glob); 1210 zsfree(cc->str); 1211 zsfree(cc->func); 1212 zsfree(cc->explain); 1213 zsfree(cc->ylist); 1214 zsfree(cc->prefix); 1215 zsfree(cc->suffix); 1216 zsfree(cc->subcmd); 1217 zsfree(cc->substr); 1218 zsfree(cc->withd); 1219 zsfree(cc->hpat); 1220 zsfree(cc->gname); 1221 zsfree(cc->mstr); 1222 freecmatcher(cc->matcher); 1223 1224 /* and copy over the new stuff, (permanently) allocating 1225 * space for strings. 1226 */ 1227 cc->mask = cct->mask; 1228 cc->mask2 = cct->mask2; 1229 cc->keyvar = ztrdup(cct->keyvar); 1230 cc->glob = ztrdup(cct->glob); 1231 cc->str = ztrdup(cct->str); 1232 cc->func = ztrdup(cct->func); 1233 cc->explain = ztrdup(cct->explain); 1234 cc->ylist = ztrdup(cct->ylist); 1235 cc->prefix = ztrdup(cct->prefix); 1236 cc->suffix = ztrdup(cct->suffix); 1237 cc->subcmd = ztrdup(cct->subcmd); 1238 cc->substr = ztrdup(cct->substr); 1239 cc->withd = ztrdup(cct->withd); 1240 cc->gname = ztrdup(cct->gname); 1241 cc->hpat = ztrdup(cct->hpat); 1242 cc->hnum = cct->hnum; 1243 cc->matcher = cpcmatcher(cct->matcher); 1244 cc->mstr = ztrdup(cct->mstr); 1245 1246 /* careful with extended completion: it's already allocated */ 1247 cc->ext = cct->ext; 1248 1249 return 0; 1250} 1251 1252/**/ 1253static void 1254cc_reassign(Compctl cc) 1255{ 1256 /* Free up a new default or command completion: 1257 * this is a hack to free up the parts which should be deleted, 1258 * without removing the basic variable which is statically allocated 1259 */ 1260 Compctl c2; 1261 1262 c2 = (Compctl) zshcalloc(sizeof *cc); 1263 c2->xor = cc->xor; 1264 c2->ext = cc->ext; 1265 c2->refc = 1; 1266 1267 freecompctl(c2); 1268 1269 cc->ext = cc->xor = NULL; 1270} 1271 1272/* Check if the given string is a pattern. If so, return one and tokenize * 1273 * it. If not, we just remove the backslashes. */ 1274 1275static int 1276compctl_name_pat(char **p) 1277{ 1278 char *s = *p; 1279 1280 tokenize(s = dupstring(s)); 1281 remnulargs(s); 1282 1283 if (haswilds(s)) { 1284 *p = s; 1285 return 1; 1286 } else 1287 *p = rembslash(*p); 1288 1289 return 0; 1290} 1291 1292/* Delete the pattern compctl with the given name. */ 1293 1294static void 1295delpatcomp(char *n) 1296{ 1297 Patcomp p, q; 1298 1299 for (q = 0, p = patcomps; p; q = p, p = p->next) { 1300 if (!strcmp(n, p->pat)) { 1301 if (q) 1302 q->next = p->next; 1303 else 1304 patcomps = p->next; 1305 zsfree(p->pat); 1306 freecompctl(p->cc); 1307 free(p); 1308 1309 break; 1310 } 1311 } 1312} 1313 1314/**/ 1315static void 1316compctl_process_cc(char **s, Compctl cc) 1317{ 1318 Compctlp ccp; 1319 char *n; 1320 1321 if (cclist & COMP_REMOVE) { 1322 /* Delete entries for the commands listed */ 1323 for (; *s; s++) { 1324 n = *s; 1325 if (compctl_name_pat(&n)) 1326 delpatcomp(n); 1327 else if ((ccp = (Compctlp) compctltab->removenode(compctltab, n))) 1328 compctltab->freenode(&ccp->node); 1329 } 1330 } else { 1331 /* Add the compctl just read to the hash table */ 1332 1333 cc->refc = 0; 1334 for (; *s; s++) { 1335 n = *s; 1336 1337 cc->refc++; 1338 if (compctl_name_pat(&n)) { 1339 Patcomp pc; 1340 1341 delpatcomp(n); 1342 pc = zalloc(sizeof *pc); 1343 pc->pat = ztrdup(n); 1344 pc->cc = cc; 1345 pc->next = patcomps; 1346 patcomps = pc; 1347 } else { 1348 ccp = (Compctlp) zalloc(sizeof *ccp); 1349 ccp->cc = cc; 1350 compctltab->addnode(compctltab, ztrdup(n), ccp); 1351 } 1352 } 1353 } 1354} 1355 1356/* Print a `compctl' */ 1357 1358/**/ 1359static void 1360printcompctl(char *s, Compctl cc, int printflags, int ispat) 1361{ 1362 Compctl cc2; 1363 char *css = "fcqovbAIFpEjrzBRGudeNOZUnQmw/"; 1364 char *mss = " pcCwWsSnNmrRq"; 1365 unsigned long t = 0x7fffffff; 1366 unsigned long flags = cc->mask, flags2 = cc->mask2; 1367 unsigned long oldshowmask; 1368 1369 /* Printflags is used outside the standard compctl commands*/ 1370 if (printflags & PRINT_LIST) 1371 cclist |= COMP_LIST; 1372 else if (printflags & PRINT_TYPE) 1373 cclist &= ~COMP_LIST; 1374 1375 if ((flags & CC_EXCMDS) && !(flags & CC_DISCMDS)) 1376 flags &= ~CC_EXCMDS; 1377 1378 /* If showmask is non-zero, then print only those * 1379 * commands with that flag set. */ 1380 if (showmask && !(flags & showmask)) 1381 return; 1382 1383 /* Temporarily clear showmask in case we make * 1384 * recursive calls to printcompctl. */ 1385 oldshowmask = showmask; 1386 showmask = 0; 1387 1388 /* print either command name or start of compctl command itself */ 1389 if (s) { 1390 if (cclist & COMP_LIST) { 1391 printf("compctl"); 1392 if (cc == &cc_compos) 1393 printf(" -C"); 1394 if (cc == &cc_default) 1395 printf(" -D"); 1396 if (cc == &cc_first) 1397 printf(" -T"); 1398 } else if (ispat) { 1399 char *p = dupstring(s); 1400 1401 untokenize(p); 1402 quotedzputs(p, stdout); 1403 } else 1404 quotedzputs(quotestring(s, NULL, QT_BACKSLASH), stdout); 1405 } 1406 1407 /* loop through flags w/o args that are set, printing them if so */ 1408 if ((flags & t) || (flags2 & (CC_UNIQALL | CC_UNIQCON))) { 1409 printf(" -"); 1410 if ((flags & (CC_ALREG | CC_ALGLOB)) == (CC_ALREG | CC_ALGLOB)) 1411 putchar('a'), flags &= ~(CC_ALREG | CC_ALGLOB); 1412 while (*css) { 1413 if (flags & t & 1) 1414 putchar(*css); 1415 css++; 1416 flags >>= 1; 1417 t >>= 1; 1418 } 1419 if (flags2 & CC_UNIQALL) 1420 putchar('1'); 1421 else if (flags2 & CC_UNIQCON) 1422 putchar('2'); 1423 } 1424 if (flags2 & (CC_XORCONT | CC_PATCONT | CC_DEFCONT)) { 1425 printf(" -t"); 1426 if (flags2 & CC_XORCONT) 1427 putchar('+'); 1428 if (flags2 & CC_PATCONT) 1429 putchar('-'); 1430 if (flags2 & CC_DEFCONT) 1431 putchar('x'); 1432 } else if (!(flags2 & CC_CCCONT)) 1433 printf(" -tn"); 1434 /* now flags with arguments */ 1435 printif(cc->mstr, 'M'); 1436 if (flags2 & CC_NOSORT) 1437 printif(cc->gname, 'V'); 1438 else 1439 printif(cc->gname, 'J'); 1440 printif(cc->keyvar, 'k'); 1441 printif(cc->func, 'K'); 1442 printif(cc->explain, (cc->mask & CC_EXPANDEXPL) ? 'Y' : 'X'); 1443 printif(cc->ylist, 'y'); 1444 printif(cc->prefix, 'P'); 1445 printif(cc->suffix, 'S'); 1446 printif(cc->glob, 'g'); 1447 printif(cc->str, 's'); 1448 printif(cc->subcmd, 'l'); 1449 printif(cc->substr, 'h'); 1450 printif(cc->withd, 'W'); 1451 if (cc->hpat) { 1452 printf(" -H %d ", cc->hnum); 1453 quotedzputs(cc->hpat, stdout); 1454 } 1455 1456 /* now the -x ... -- extended completion part */ 1457 if (cc->ext) { 1458 Compcond c, o; 1459 int i; 1460 1461 cc2 = cc->ext; 1462 printf(" -x"); 1463 1464 while (cc2) { 1465 /* loop over conditions */ 1466 c = cc2->cond; 1467 1468 printf(" '"); 1469 for (c = cc2->cond; c;) { 1470 /* loop over or's */ 1471 o = c->or; 1472 while (c) { 1473 /* loop over and's */ 1474 putchar(mss[c->type]); 1475 1476 for (i = 0; i < c->n; i++) { 1477 /* for all [...]'s of a given condition */ 1478 putchar('['); 1479 switch (c->type) { 1480 case CCT_POS: 1481 case CCT_NUMWORDS: 1482 printf("%d,%d", c->u.r.a[i], c->u.r.b[i]); 1483 break; 1484 case CCT_CURSUF: 1485 case CCT_CURPRE: 1486 case CCT_QUOTE: 1487 printqt(c->u.s.s[i]); 1488 break; 1489 case CCT_RANGESTR: 1490 case CCT_RANGEPAT: 1491 printqt(c->u.l.a[i]); 1492 putchar(','); 1493 printqt(c->u.l.b[i]); 1494 break; 1495 default: 1496 printf("%d,", c->u.s.p[i]); 1497 printqt(c->u.s.s[i]); 1498 } 1499 putchar(']'); 1500 } 1501 if ((c = c->and)) 1502 putchar(' '); 1503 } 1504 if ((c = o)) 1505 printf(" , "); 1506 } 1507 putchar('\''); 1508 c = cc2->cond; 1509 cc2->cond = NULL; 1510 /* now print the flags for the current condition */ 1511 printcompctl(NULL, cc2, 0, 0); 1512 cc2->cond = c; 1513 if ((cc2 = (Compctl) (cc2->next))) 1514 printf(" -"); 1515 } 1516 if (cclist & COMP_LIST) 1517 printf(" --"); 1518 } 1519 if (cc && cc->xor) { 1520 /* print xor'd (+) completions */ 1521 printf(" +"); 1522 if (cc->xor != &cc_default) 1523 printcompctl(NULL, cc->xor, 0, 0); 1524 } 1525 if (s) { 1526 if ((cclist & COMP_LIST) && (cc != &cc_compos) 1527 && (cc != &cc_default) && (cc != &cc_first)) { 1528 if(s[0] == '-' || s[0] == '+') 1529 printf(" -"); 1530 putchar(' '); 1531 if (ispat) { 1532 char *p = dupstring(s); 1533 1534 untokenize(p); 1535 quotedzputs(p, stdout); 1536 } else { 1537 char *p = dupstring(s); 1538 1539 untokenize(p); 1540 quotedzputs(quotestring(p, NULL, QT_BACKSLASH), stdout); 1541 } 1542 } 1543 putchar('\n'); 1544 } 1545 1546 showmask = oldshowmask; 1547} 1548 1549/**/ 1550static void 1551printcompctlp(HashNode hn, int printflags) 1552{ 1553 Compctlp ccp = (Compctlp) hn; 1554 1555 /* Function needed for use by scanhashtable() */ 1556 printcompctl(ccp->node.nam, ccp->cc, printflags, 0); 1557} 1558 1559/* Main entry point for the `compctl' builtin */ 1560 1561/**/ 1562static int 1563bin_compctl(char *name, char **argv, UNUSED(Options ops), UNUSED(int func)) 1564{ 1565 Compctl cc = NULL; 1566 int ret = 0; 1567 1568 /* clear static flags */ 1569 cclist = 0; 1570 showmask = 0; 1571 1572 /* Parse all the arguments */ 1573 if (*argv) { 1574 /* Let's see if this is a global matcher definition. */ 1575 if ((ret = get_gmatcher(name, argv))) 1576 return ret - 1; 1577 1578 cc = (Compctl) zshcalloc(sizeof(*cc)); 1579 if (get_compctl(name, &argv, cc, 1, 0, 0)) { 1580 freecompctl(cc); 1581 return 1; 1582 } 1583 1584 /* remember flags for printing */ 1585 showmask = cc->mask; 1586 if ((showmask & CC_EXCMDS) && !(showmask & CC_DISCMDS)) 1587 showmask &= ~CC_EXCMDS; 1588 1589 /* if no command arguments or just listing, we don't want cc */ 1590 if (!*argv || (cclist & COMP_LIST)) 1591 freecompctl(cc); 1592 } 1593 1594 /* If no commands and no -C, -T, or -D, print all the compctl's * 1595 * If some flags (other than -C, -T, or -D) were given, then * 1596 * only print compctl containing those flags. */ 1597 if (!*argv && !(cclist & (COMP_SPECIAL|COMP_LISTMATCH))) { 1598 Patcomp pc; 1599 1600 for (pc = patcomps; pc; pc = pc->next) 1601 printcompctl(pc->pat, pc->cc, 0, 1); 1602 1603 scanhashtable(compctltab, 1, 0, 0, compctltab->printnode, 0); 1604 printcompctl((cclist & COMP_LIST) ? "" : "COMMAND", &cc_compos, 0, 0); 1605 printcompctl((cclist & COMP_LIST) ? "" : "DEFAULT", &cc_default, 0, 0); 1606 printcompctl((cclist & COMP_LIST) ? "" : "FIRST", &cc_first, 0, 0); 1607 print_gmatcher((cclist & COMP_LIST)); 1608 return ret; 1609 } 1610 1611 /* If we're listing and we've made it to here, then there are arguments * 1612 * or a COMP_SPECIAL flag (-D, -C, -T), so print only those. */ 1613 if (cclist & COMP_LIST) { 1614 HashNode hn; 1615 char **ptr, *n; 1616 1617 showmask = 0; 1618 for (ptr = argv; *ptr; ptr++) { 1619 n = *ptr; 1620 if (compctl_name_pat(&n)) { 1621 Patcomp pc; 1622 1623 for (pc = patcomps; pc; pc = pc->next) 1624 if (!strcmp(n, pc->pat)) { 1625 printcompctl(pc->pat, pc->cc, 0, 1); 1626 n = NULL; 1627 break; 1628 } 1629 } else if ((hn = compctltab->getnode(compctltab, n))) { 1630 compctltab->printnode(hn, 0); 1631 n = NULL; 1632 } 1633 if (n) { 1634 zwarnnam(name, "no compctl defined for %s", n); 1635 ret = 1; 1636 } 1637 } 1638 if (cclist & COMP_COMMAND) 1639 printcompctl("", &cc_compos, 0, 0); 1640 if (cclist & COMP_DEFAULT) 1641 printcompctl("", &cc_default, 0, 0); 1642 if (cclist & COMP_FIRST) 1643 printcompctl("", &cc_first, 0, 0); 1644 if (cclist & COMP_LISTMATCH) 1645 print_gmatcher(COMP_LIST); 1646 return ret; 1647 } 1648 1649 /* Assign the compctl to the commands given */ 1650 if (*argv) { 1651 if(cclist & COMP_SPECIAL) 1652 /* Ideally we'd handle this properly, setting both the * 1653 * special and normal completions. For the moment, * 1654 * this is better than silently failing. */ 1655 zwarnnam(name, "extraneous commands ignored"); 1656 else 1657 compctl_process_cc(argv, cc); 1658 } 1659 1660 return ret; 1661} 1662 1663/* Flags for makecomplist*(). Things not to do. */ 1664 1665#define CFN_FIRST 1 1666#define CFN_DEFAULT 2 1667 1668static int 1669bin_compcall(char *name, UNUSED(char **argv), Options ops, UNUSED(int func)) 1670{ 1671 if (incompfunc != 1) { 1672 zwarnnam(name, "can only be called from completion function"); 1673 return 1; 1674 } 1675 return makecomplistctl((OPT_ISSET(ops,'T') ? 0 : CFN_FIRST) | 1676 (OPT_ISSET(ops,'D') ? 0 : CFN_DEFAULT)); 1677} 1678 1679/* 1680 * Functions to generate matches. 1681 */ 1682 1683/* A pointer to the compctl we are using. */ 1684 1685static Compctl curcc; 1686 1687/* A list of all compctls we have already used. */ 1688 1689static LinkList ccused, lastccused; 1690 1691/* A stack of currently used compctls. */ 1692 1693static LinkList ccstack; 1694 1695/* The beginning and end of a word range to be used by -l. */ 1696 1697static int brange, erange; 1698 1699/* This is used to detect when and what to continue. */ 1700 1701static unsigned long ccont; 1702 1703/* Two patterns used when doing glob-completion. The first one is built * 1704 * from the whole word we are completing and the second one from that * 1705 * part of the word that was identified as a possible filename. */ 1706 1707static Patprog patcomp, filecomp; 1708 1709/* We store the following prefixes/suffixes: * 1710 * lpre/lsuf -- what's on the line * 1711 * rpre/rsuf -- same as lpre/lsuf, but expanded * 1712 * ppre/psuf -- the path prefix/suffix * 1713 * lppre/lpsuf -- the path prefix/suffix, unexpanded * 1714 * fpre/fsuf -- prefix/suffix of the pathname component the cursor is in * 1715 * prpre -- ppre in expanded form usable for opendir * 1716 * qipre, qisuf-- ingnored quoted string * 1717 * * 1718 * The integer variables hold the lengths of lpre, lsuf, rpre, rsuf, * 1719 * fpre, fsuf, lppre, and lpsuf. noreal is non-zero if we have rpre/rsuf. */ 1720 1721static char *lpre, *lsuf; 1722static char *rpre, *rsuf; 1723static char *ppre, *psuf, *lppre, *lpsuf, *prpre; 1724static char *fpre, *fsuf; 1725static char *qfpre, *qfsuf, *qrpre, *qrsuf, *qlpre, *qlsuf; 1726static int lpl, lsl, rpl, rsl, fpl, fsl, lppl, lpsl; 1727static int noreal; 1728 1729/* This is either zero or equal to the special character the word we are * 1730 * trying to complete starts with (e.g. Tilde or Equals). */ 1731 1732static char ic; 1733 1734/* This variable says what we are currently adding to the list of matches. */ 1735 1736static int addwhat; 1737 1738/* 1739 * Convenience macro for calling quotestring (formerly bslashquote() 1740 * (formerly quotename())). 1741 * This uses the instring variable exported from zle_tricky.c. 1742 */ 1743 1744#define quotename(s, e) \ 1745quotestring(s, e, instring == QT_NONE ? QT_BACKSLASH : instring) 1746 1747/* Hook functions */ 1748 1749static int 1750ccmakehookfn(UNUSED(Hookdef dummy), struct ccmakedat *dat) 1751{ 1752 char *s = dat->str; 1753 int incmd = dat->incmd, lst = dat->lst; 1754 struct cmlist ms; 1755 Cmlist m; 1756 char *os = s; 1757 int onm = nmatches, odm = diffmatches, osi = movefd(0); 1758 LinkNode n; 1759 1760 /* We build a copy of the list of matchers to use to make sure that this 1761 * works even if a shell function called from the completion code changes 1762 * the global matchers. */ 1763 1764 if ((m = cmatcher)) { 1765 Cmlist mm, *mp = &mm; 1766 int n; 1767 1768 for (n = 0; m; m = m->next, n++) { 1769 *mp = (Cmlist) zhalloc(sizeof(struct cmlist)); 1770 (*mp)->matcher = m->matcher; 1771 (*mp)->next = NULL; 1772 (*mp)->str = dupstring(m->str); 1773 mp = &((*mp)->next); 1774 addlinknode(matchers, m->matcher); 1775 if (m->matcher) 1776 m->matcher->refc++; 1777 } 1778 m = mm; 1779 } 1780 1781 /* Walk through the global matchers. */ 1782 for (;;) { 1783 bmatchers = NULL; 1784 if (m) { 1785 ms.next = NULL; 1786 ms.matcher = m->matcher; 1787 mstack = &ms; 1788 1789 /* Store the matchers used in the bmatchers list which is used 1790 * when building new parts for the string to insert into the 1791 * line. */ 1792 add_bmatchers(m->matcher); 1793 } else 1794 mstack = NULL; 1795 1796 ainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); 1797 fainfo = (Aminfo) hcalloc(sizeof(struct aminfo)); 1798 1799 freecl = NULL; 1800 1801 if (!validlist) 1802 lastambig = 0; 1803 amatches = NULL; 1804 mnum = 0; 1805 unambig_mnum = -1; 1806 isuf = NULL; 1807 insmnum = 1; 1808#if 0 1809 /* group-numbers in compstate[insert] */ 1810 insgnum = 1; 1811 insgroup = 0; 1812#endif 1813 oldlist = oldins = 0; 1814 begcmgroup("default", 0); 1815 menucmp = menuacc = newmatches = onlyexpl = 0; 1816 1817 ccused = newlinklist(); 1818 ccstack = newlinklist(); 1819 1820 s = dupstring(os); 1821 makecomplistglobal(s, incmd, lst, 0); 1822 endcmgroup(NULL); 1823 1824 if (amatches && !oldlist) { 1825 if (lastccused) 1826 freelinklist(lastccused, (FreeFunc) freecompctl); 1827 1828 lastccused = znewlinklist(); 1829 for (n = firstnode(ccused); n; incnode(n)) 1830 zaddlinknode(lastccused, getdata(n)); 1831 } else if (ccused) 1832 for (n = firstnode(ccused); n; incnode(n)) 1833 if (((Compctl) getdata(n)) != &cc_dummy) 1834 freecompctl((Compctl) getdata(n)); 1835 1836 if (oldlist) { 1837 nmatches = onm; 1838 diffmatches = odm; 1839 validlist = 1; 1840 amatches = lastmatches; 1841#ifdef ZSH_HEAP_DEBUG 1842 if (memory_validate(amatches->heap_id)) { 1843 HEAP_ERROR(amatches->heap_id); 1844 } 1845#endif 1846 lmatches = lastlmatches; 1847 if (pmatches) { 1848 freematches(pmatches, 1); 1849 pmatches = NULL; 1850 hasperm = 0; 1851 } 1852 redup(osi, 0); 1853 1854 dat->lst = 0; 1855 return 0; 1856 } 1857 if (lastmatches) { 1858 freematches(lastmatches, 1); 1859 lastmatches = NULL; 1860 } 1861 permmatches(1); 1862 amatches = pmatches; 1863 lastpermmnum = permmnum; 1864 lastpermgnum = permgnum; 1865 1866 lastmatches = pmatches; 1867 lastlmatches = lmatches; 1868 pmatches = NULL; 1869 hasperm = 0; 1870 hasoldlist = 1; 1871 1872 if (nmatches && !errflag) { 1873 validlist = 1; 1874 1875 redup(osi, 0); 1876 1877 dat->lst = 0; 1878 return 0; 1879 } 1880 if (!m || !(m = m->next)) 1881 break; 1882 1883 errflag = 0; 1884 } 1885 redup(osi, 0); 1886 dat->lst = 1; 1887 return 0; 1888} 1889 1890static int 1891cccleanuphookfn(UNUSED(Hookdef dummy), UNUSED(void *dat)) 1892{ 1893 ccused = ccstack = NULL; 1894 return 0; 1895} 1896 1897/* This adds a match to the list of matches. The string to add is given * 1898 * in s, the type of match is given in the global variable addwhat and * 1899 * the parameter t (if not NULL) is a pointer to a hash node which * 1900 * may be used to give other information to this function. * 1901 * * 1902 * addwhat contains either one of the special values (negative, see below) * 1903 * or the inclusive OR of some of the CC_* flags used for compctls. */ 1904 1905/**/ 1906static void 1907addmatch(char *s, char *t) 1908{ 1909 int isfile = 0, isalt = 0, isexact; 1910 char *ms = NULL, *tt; 1911 HashNode hn; 1912 Param pm; 1913 Cline lc = NULL; 1914 Brinfo bp, bpl = brbeg, bsl = brend, bpt, bst; 1915 1916 for (bp = brbeg; bp; bp = bp->next) 1917 bp->curpos = ((addwhat == CC_QUOTEFLAG) ? bp->qpos : bp->pos); 1918 for (bp = brend; bp; bp = bp->next) 1919 bp->curpos = ((addwhat == CC_QUOTEFLAG) ? bp->qpos : bp->pos); 1920 1921 /* 1922 * addwhat: -5 is for files, 1923 * -6 is for glob expansions, 1924 * -8 is for executable files (e.g. command paths), 1925 * -9 is for parameters 1926 * -7 is for command names (from cmdnamtab) 1927 * -4 is for a cdable parameter 1928 * -3 is for executable command names. 1929 * -2 is for anything unquoted 1930 * -1 is for other file specifications 1931 * (things with `~' or `=' at the beginning, ...). 1932 */ 1933 1934 /* Just to make the code cleaner */ 1935 hn = (HashNode) t; 1936 pm = (Param) t; 1937 1938 if (addwhat == -1 || addwhat == -5 || addwhat == -6 || 1939 addwhat == CC_FILES || addwhat == -7 || addwhat == -8) { 1940 int ppl = (ppre ? strlen(ppre) : 0), psl = (psuf ? strlen(psuf) : 0); 1941 1942 while (bpl && bpl->curpos < ppl) 1943 bpl = bpl->next; 1944 while (bsl && bsl->curpos < psl) 1945 bsl = bsl->next; 1946 1947 if ((addwhat == CC_FILES || 1948 addwhat == -5) && !*psuf) { 1949 /* If this is a filename, do the fignore check. */ 1950 char **pt = fignore; 1951 int filell, sl = strlen(s); 1952 1953 for (isalt = 0; !isalt && *pt; pt++) 1954 if ((filell = strlen(*pt)) < sl && 1955 !strcmp(*pt, s + sl - filell)) 1956 isalt = 1; 1957 } 1958 ms = ((addwhat == CC_FILES || addwhat == -6 || 1959 addwhat == -5 || addwhat == -8) ? 1960 comp_match(tildequote(qfpre, 1), multiquote(qfsuf, 1), 1961 s, filecomp, &lc, (ppre && *ppre ? 1 : 2), 1962 &bpl, ppl ,&bsl, psl, &isexact) : 1963 comp_match(multiquote(fpre, 1), multiquote(fsuf, 1), 1964 s, filecomp, &lc, 0, 1965 &bpl, ppl, &bsl, psl, &isexact)); 1966 if (!ms) 1967 return; 1968 1969 if (addwhat == -7 && !findcmd(s, 0)) 1970 return; 1971 isfile = CMF_FILE; 1972 } else if (addwhat == CC_QUOTEFLAG || addwhat == -2 || 1973 (addwhat == -3 && !(hn->flags & DISABLED)) || 1974 (addwhat == -4 && (PM_TYPE(pm->node.flags) == PM_SCALAR) && 1975 !pm->level && (tt = pm->gsu.s->getfn(pm)) && *tt == '/') || 1976 (addwhat == -9 && !(hn->flags & PM_UNSET) && !pm->level) || 1977 (addwhat > 0 && 1978 ((!(hn->flags & PM_UNSET) && 1979 (((addwhat & CC_ARRAYS) && (hn->flags & PM_ARRAY)) || 1980 ((addwhat & CC_INTVARS) && (hn->flags & PM_INTEGER)) || 1981 ((addwhat & CC_ENVVARS) && (hn->flags & PM_EXPORTED)) || 1982 ((addwhat & CC_SCALARS) && (hn->flags & PM_SCALAR)) || 1983 ((addwhat & CC_READONLYS) && (hn->flags & PM_READONLY)) || 1984 ((addwhat & CC_SPECIALS) && (hn->flags & PM_SPECIAL)) || 1985 ((addwhat & CC_PARAMS) && !(hn->flags & PM_EXPORTED))) && 1986 !pm->level) || 1987 ((( addwhat & CC_SHFUNCS) || 1988 ( addwhat & CC_BUILTINS) || 1989 ( addwhat & CC_EXTCMDS) || 1990 ( addwhat & CC_RESWDS) || 1991 ((addwhat & CC_ALREG) && !(hn->flags & ALIAS_GLOBAL)) || 1992 ((addwhat & CC_ALGLOB) && (hn->flags & ALIAS_GLOBAL))) && 1993 (((addwhat & CC_DISCMDS) && (hn->flags & DISABLED)) || 1994 ((addwhat & CC_EXCMDS) && !(hn->flags & DISABLED)))) || 1995 ((addwhat & CC_BINDINGS) && !(hn->flags & DISABLED))))) { 1996 char *p1, *s1, *p2, *s2; 1997 1998 if (addwhat == CC_QUOTEFLAG) { 1999 p1 = qrpre; s1 = qrsuf; 2000 p2 = rpre; s2 = rsuf; 2001 } else { 2002 p1 = qlpre; s1 = qlsuf; 2003 p2 = lpre; s2 = lsuf; 2004 } 2005 p1 = multiquote(p1, 1); s1 = multiquote(s1, 1); 2006 p2 = multiquote(p2, 1); s2 = multiquote(s2, 1); 2007 bpt = bpl; 2008 bst = bsl; 2009 2010 if (!(ms = comp_match(p1, s1, s, patcomp, &lc, 2011 (addwhat == CC_QUOTEFLAG), 2012 &bpl, strlen(p1), &bsl, strlen(s1), 2013 &isexact))) { 2014 bpl = bpt; 2015 bsl = bst; 2016 if (!(ms = comp_match(p2, s2, s, NULL, &lc, 2017 (addwhat == CC_QUOTEFLAG), 2018 &bpl, strlen(p2), &bsl, strlen(s2), 2019 &isexact))) 2020 return; 2021 } 2022 } 2023 if (!ms) 2024 return; 2025 add_match_data(isalt, ms, s, lc, ipre, ripre, isuf, 2026 (incompfunc ? dupstring(curcc->prefix) : curcc->prefix), 2027 prpre, 2028 (isfile ? lppre : NULL), NULL, 2029 (isfile ? lpsuf : NULL), NULL, 2030 (incompfunc ? dupstring(curcc->suffix) : curcc->suffix), 2031 (mflags | isfile), isexact); 2032} 2033 2034/**/ 2035static void 2036maketildelist(void) 2037{ 2038 /* add all the usernames to the named directory table */ 2039 nameddirtab->filltable(nameddirtab); 2040 2041 scanhashtable(nameddirtab, 0, (addwhat==-1) ? 0 : ND_USERNAME, 0, 2042 addhnmatch, 0); 2043} 2044 2045/* This does the check for compctl -x `n' and `N' patterns. */ 2046 2047/**/ 2048int 2049getcpat(char *str, int cpatindex, char *cpat, int class) 2050{ 2051 char *s, *t, *p; 2052 int d = 0; 2053 2054 if (!str || !*str) 2055 return -1; 2056 2057 cpat = rembslash(cpat); 2058 2059 if (!cpatindex) 2060 cpatindex++, d = 0; 2061 else if ((d = (cpatindex < 0))) 2062 cpatindex = -cpatindex; 2063 2064 for (s = d ? str + strlen(str) - 1 : str; 2065 d ? (s >= str) : *s; 2066 d ? s-- : s++) { 2067 for (t = s, p = cpat; *t && *p; p++) { 2068 if (class) { 2069 if (*p == *s && !--cpatindex) 2070 return (int)(s - str + 1); 2071 } else if (*t++ != *p) 2072 break; 2073 } 2074 if (!class && !*p && !--cpatindex) 2075 return t - str; 2076 } 2077 return -1; 2078} 2079 2080/* Dump a hash table (without sorting). For each element the addmatch * 2081 * function is called and at the beginning the addwhat variable is set. * 2082 * This could be done using scanhashtable(), but this is easy and much * 2083 * more efficient. */ 2084 2085/**/ 2086static void 2087dumphashtable(HashTable ht, int what) 2088{ 2089 HashNode hn; 2090 int i; 2091 2092 addwhat = what; 2093 2094 for (i = 0; i < ht->hsize; i++) 2095 for (hn = ht->nodes[i]; hn; hn = hn->next) 2096 addmatch(dupstring(hn->nam), (char *) hn); 2097} 2098 2099/* ScanFunc used by maketildelist() et al. */ 2100 2101/**/ 2102static void 2103addhnmatch(HashNode hn, UNUSED(int flags)) 2104{ 2105 addmatch(hn->nam, NULL); 2106} 2107 2108/* Perform expansion on the given string and return the result. * 2109 * During this errors are not reported. */ 2110 2111/**/ 2112static char * 2113getreal(char *str) 2114{ 2115 LinkList l = newlinklist(); 2116 int ne = noerrs; 2117 2118 noerrs = 1; 2119 addlinknode(l, dupstring(str)); 2120 prefork(l, 0); 2121 noerrs = ne; 2122 if (!errflag && nonempty(l) && 2123 ((char *) peekfirst(l)) && ((char *) peekfirst(l))[0]) 2124 return dupstring(peekfirst(l)); 2125 errflag = 0; 2126 2127 return dupstring(str); 2128} 2129 2130/* This reads a directory and adds the files to the list of * 2131 * matches. The parameters say which files should be added. */ 2132 2133/**/ 2134static void 2135gen_matches_files(int dirs, int execs, int all) 2136{ 2137 DIR *d; 2138 struct stat buf; 2139 char *n, p[PATH_MAX], *q = NULL, *e, *pathpref; 2140 LinkList l = NULL; 2141 int ns = 0, ng = opts[NULLGLOB], test, aw = addwhat, pathpreflen; 2142 2143 opts[NULLGLOB] = 1; 2144 2145 if (*psuf) { 2146 /* If there is a path suffix, check if it doesn't have a `*' or * 2147 * `)' at the end (this is used to determine if we should use * 2148 * globbing). */ 2149 q = psuf + strlen(psuf) - 1; 2150 ns = !(*q == Star || *q == Outpar); 2151 l = newlinklist(); 2152 /* And generate only directory names. */ 2153 dirs = 1; 2154 all = execs = 0; 2155 } 2156 /* Open directory. */ 2157 if (prpre && *prpre) { 2158 pathpref = dupstring(prpre); 2159 unmetafy(pathpref, &pathpreflen); 2160 /* system needs NULL termination, not provided by unmetafy */ 2161 pathpref[pathpreflen] = '\0'; 2162 } else { 2163 pathpref = NULL; 2164 pathpreflen = 0; 2165 } 2166 if ((d = opendir(pathpref ? pathpref : "."))) { 2167 /* If we search only special files, prepare a path buffer for stat. */ 2168 if (!all && pathpreflen) { 2169 /* include null byte we carefully added */ 2170 memcpy(p, pathpref, pathpreflen+1); 2171 } 2172 q = p + pathpreflen; 2173 /* Fine, now read the directory. */ 2174 while ((n = zreaddir(d, 1)) && !errflag) { 2175 /* Ignore files beginning with `.' unless the thing we found on * 2176 * the command line also starts with a dot or GLOBDOTS is set. */ 2177 if (*n != '.' || *fpre == '.' || isset(GLOBDOTS)) { 2178 addwhat = execs ? -8 : -5; 2179 if (filecomp) 2180 /* If we have a pattern for the filename check, use it. */ 2181 test = pattry(filecomp, n); 2182 else { 2183 /* Otherwise use the prefix and suffix strings directly. */ 2184 e = n + strlen(n) - fsl; 2185 if ((test = !strncmp(n, fpre, fpl))) 2186 test = !strcmp(e, fsuf); 2187 if (!test && mstack) { 2188 test = 1; 2189 addwhat = CC_FILES; 2190 } 2191 } 2192 /* Filename didn't match? */ 2193 if (!test) 2194 continue; 2195 if (!all) { 2196 char *ums; 2197 int umlen; 2198 /* We still have to check the file type, so prepare * 2199 * the path buffer by appending the filename. */ 2200 ums = dupstring(n); 2201 unmetafy(ums, ¨en); 2202 memcpy(q, ums, umlen); 2203 q[umlen] = '\0'; 2204 /* And do the stat. */ 2205 if (stat(p, &buf) < 0) 2206 continue; 2207 } 2208 if (all || 2209 (dirs && S_ISDIR(buf.st_mode)) || 2210 (execs && S_ISREG(buf.st_mode) && (buf.st_mode&S_IXUGO))) { 2211 /* If we want all files or the file has the right type... */ 2212 if (*psuf) { 2213 /* We have to test for a path suffix. */ 2214 int o = strlen(p), tt; 2215 2216 /* Append it to the path buffer. */ 2217 strcpy(p + o, psuf); 2218 2219 /* Do we have to use globbing? */ 2220 if (ispattern || 2221 (ns && comppatmatch && *comppatmatch)) { 2222 /* Yes, so append a `*' if needed. */ 2223 if (ns && comppatmatch && *comppatmatch == '*') { 2224 int tl = strlen(p); 2225 2226 p[tl] = Star; 2227 p[tl + 1] = '\0'; 2228 } 2229 /* Do the globbing... */ 2230 remnulargs(p); 2231 addlinknode(l, p); 2232 globlist(l, 0); 2233 /* And see if that produced a filename. */ 2234 tt = nonempty(l); 2235 while (ugetnode(l)); 2236 } else 2237 /* Otherwise just check, if we have access * 2238 * to the file. */ 2239 tt = !access(p, F_OK); 2240 2241 p[o] = '\0'; 2242 if (tt) 2243 /* Ok, we can add the filename to the * 2244 * list of matches. */ 2245 addmatch(dupstring(n), NULL); 2246 } else 2247 /* We want all files, so just add the name * 2248 * to the matches. */ 2249 addmatch(dupstring(n), NULL); 2250 } 2251 } 2252 } 2253 closedir(d); 2254 } 2255 opts[NULLGLOB] = ng; 2256 addwhat = aw; 2257} 2258 2259/* This returns the node with the given data. */ 2260/* ...should probably be moved to linklist.c. */ 2261 2262static LinkNode 2263findnode(LinkList list, void *dat) 2264{ 2265 LinkNode tmp = firstnode(list); 2266 2267 while (tmp && getdata(tmp) != dat) incnode(tmp); 2268 2269 return tmp; 2270} 2271 2272/* A simple counter to avoid endless recursion between old and new style * 2273 * completion. */ 2274 2275static int cdepth = 0; 2276 2277#define MAX_CDEPTH 16 2278 2279/**/ 2280static int 2281makecomplistctl(int flags) 2282{ 2283 Heap oldheap; 2284 int ret; 2285 2286 if (cdepth == MAX_CDEPTH) 2287 return 0; 2288 2289 cdepth++; 2290 SWITCHHEAPS(oldheap, compheap) { 2291 int ooffs = offs, lip, lp; 2292 char *str = comp_str(&lip, &lp, 0), *t; 2293 char *os = cmdstr, **ow = clwords, **p, **q, qc; 2294 int on = clwnum, op = clwpos, ois = instring, oib = inbackt; 2295 char *oisuf = isuf, *oqp = qipre, *oqs = qisuf, *oaq = autoq; 2296 char buf[3]; 2297 2298 if (compquote && (qc = *compquote)) { 2299 if (qc == '`') { 2300 instring = QT_NONE; 2301 /* 2302 * Yes, inbackt has always been set to zero here. I'm 2303 * sure there's a simple explanation. 2304 */ 2305 inbackt = 0; 2306 autoq = ""; 2307 } else { 2308 switch (qc) { 2309 case '\'': 2310 instring = QT_SINGLE; 2311 break; 2312 2313 case '"': 2314 instring = QT_DOUBLE; 2315 break; 2316 2317 case '$': 2318 instring = QT_DOLLARS; 2319 break; 2320 } 2321 inbackt = 0; 2322 strcpy(buf, *compquote == '$' ? compquote+1 : compquote); 2323 autoq = buf; 2324 } 2325 } else { 2326 instring = QT_NONE; 2327 inbackt = 0; 2328 autoq = ""; 2329 } 2330 qipre = ztrdup(compqiprefix ? compqiprefix : ""); 2331 qisuf = ztrdup(compqisuffix ? compqisuffix : ""); 2332 isuf = dupstring(compisuffix); 2333 ctokenize(isuf); 2334 remnulargs(isuf); 2335 clwnum = arrlen(compwords); 2336 clwpos = compcurrent - 1; 2337 cmdstr = ztrdup(compwords[0]); 2338 clwords = (char **) zalloc((clwnum + 1) * sizeof(char *)); 2339 for (p = compwords, q = clwords; *p; p++, q++) { 2340 t = dupstring(*p); 2341 tokenize(t); 2342 remnulargs(t); 2343 *q = ztrdup(t); 2344 } 2345 *q = NULL; 2346 offs = lip + lp; 2347 incompfunc = 2; 2348 ret = makecomplistglobal(str, !clwpos, COMP_COMPLETE, flags); 2349 incompfunc = 1; 2350 isuf = oisuf; 2351 zsfree(qipre); 2352 zsfree(qisuf); 2353 qipre = oqp; 2354 qisuf = oqs; 2355 instring = ois; 2356 inbackt = oib; 2357 autoq = oaq; 2358 offs = ooffs; 2359 zsfree(cmdstr); 2360 freearray(clwords); 2361 cmdstr = os; 2362 clwords = ow; 2363 clwnum = on; 2364 clwpos = op; 2365 } SWITCHBACKHEAPS(oldheap); 2366 cdepth--; 2367 2368 return ret; 2369} 2370 2371/* This function gets the compctls for the given command line and * 2372 * adds all completions for them. */ 2373 2374/**/ 2375static int 2376makecomplistglobal(char *os, int incmd, UNUSED(int lst), int flags) 2377{ 2378 Compctl cc = NULL; 2379 char *s; 2380 2381 ccont = CC_CCCONT; 2382 cc_dummy.suffix = NULL; 2383 2384 if (linwhat == IN_ENV) { 2385 /* Default completion for parameter values. */ 2386 if (!(flags & CFN_DEFAULT)) { 2387 cc = &cc_default; 2388 keypm = NULL; 2389 } 2390 } else if (linwhat == IN_MATH) { 2391 if (!(flags & CFN_DEFAULT)) { 2392 if (insubscr >= 2) { 2393 /* Inside subscript of assoc array, complete keys. */ 2394 cc_dummy.mask = 0; 2395 cc_dummy.suffix = (insubscr == 2 ? "]" : ""); 2396 } else { 2397 /* Other math environment, complete paramete names. */ 2398 keypm = NULL; 2399 cc_dummy.mask = CC_PARAMS; 2400 } 2401 cc = &cc_dummy; 2402 cc_dummy.refc = 10000; 2403 } 2404 } else if (linwhat == IN_COND) { 2405 /* We try to be clever here: in conditions we complete option * 2406 * names after a `-o', file names after `-nt', `-ot', and `-ef' * 2407 * and file names and parameter names elsewhere. */ 2408 if (!(flags & CFN_DEFAULT)) { 2409 s = clwpos ? clwords[clwpos - 1] : ""; 2410 cc_dummy.mask = !strcmp("-o", s) ? CC_OPTIONS : 2411 ((*s == '-' && s[1] && !s[2]) || 2412 !strcmp("-nt", s) || 2413 !strcmp("-ot", s) || 2414 !strcmp("-ef", s)) ? CC_FILES : 2415 (CC_FILES | CC_PARAMS); 2416 cc = &cc_dummy; 2417 cc_dummy.refc = 10000; 2418 keypm = NULL; 2419 } 2420 } else if (linredir) { 2421 if (!(flags & CFN_DEFAULT)) { 2422 /* In redirections use default completion. */ 2423 cc = &cc_default; 2424 keypm = NULL; 2425 } 2426 } else { 2427 /* Otherwise get the matches for the command. */ 2428 keypm = NULL; 2429 return makecomplistcmd(os, incmd, flags); 2430 } 2431 if (cc) { 2432 /* First, use the -T compctl. */ 2433 if (!(flags & CFN_FIRST)) { 2434 makecomplistcc(&cc_first, os, incmd); 2435 2436 if (!(ccont & CC_CCCONT)) 2437 return 0; 2438 } 2439 makecomplistcc(cc, os, incmd); 2440 return 1; 2441 } 2442 return 0; 2443} 2444 2445/* This produces the matches for a command. */ 2446 2447/**/ 2448static int 2449makecomplistcmd(char *os, int incmd, int flags) 2450{ 2451 Compctl cc; 2452 Compctlp ccp; 2453 char *s; 2454 int ret = 0; 2455 2456 /* First, use the -T compctl. */ 2457 if (!(flags & CFN_FIRST)) { 2458 makecomplistcc(&cc_first, os, incmd); 2459 2460 if (!(ccont & CC_CCCONT)) 2461 return 0; 2462 } 2463 /* Then search the pattern compctls, with the command name and the * 2464 * full pathname of the command. */ 2465 if (cmdstr) { 2466 ret |= makecomplistpc(os, incmd); 2467 if (!(ccont & CC_CCCONT)) 2468 return ret; 2469 } 2470 /* If the command string starts with `=', try the path name of the * 2471 * command. */ 2472 if (cmdstr && cmdstr[0] == Equals) { 2473 char *c = findcmd(cmdstr + 1, 1); 2474 2475 if (c) { 2476 zsfree(cmdstr); 2477 cmdstr = ztrdup(c); 2478 } 2479 } 2480 2481 /* Find the compctl for this command, trying the full name and then * 2482 * the trailing pathname component. If that doesn't yield anything, * 2483 * use default completion. */ 2484 if (incmd) 2485 cc = &cc_compos; 2486 else if (!(cmdstr && 2487 (((ccp = (Compctlp) compctltab->getnode(compctltab, cmdstr)) && 2488 (cc = ccp->cc)) || 2489 ((s = dupstring(cmdstr)) && remlpaths(&s) && 2490 (ccp = (Compctlp) compctltab->getnode(compctltab, s)) && 2491 (cc = ccp->cc))))) { 2492 if (flags & CFN_DEFAULT) 2493 return ret; 2494 cc = &cc_default; 2495 } else 2496 ret|= 1; 2497 makecomplistcc(cc, os, incmd); 2498 return ret; 2499} 2500 2501/* This adds the matches for the pattern compctls. */ 2502 2503/**/ 2504static int 2505makecomplistpc(char *os, int incmd) 2506{ 2507 Patcomp pc; 2508 Patprog pat; 2509 char *s; 2510 int ret = 0; 2511 2512 s = ((shfunctab->getnode(shfunctab, cmdstr) || 2513 builtintab->getnode(builtintab, cmdstr)) ? NULL : findcmd(cmdstr, 1)); 2514 2515 for (pc = patcomps; pc; pc = pc->next) { 2516 if ((pat = patcompile(pc->pat, PAT_STATIC, NULL)) && 2517 (pattry(pat, cmdstr) || 2518 (s && pattry(pat, s)))) { 2519 makecomplistcc(pc->cc, os, incmd); 2520 ret |= 2; 2521 if (!(ccont & CC_CCCONT)) 2522 return ret; 2523 } 2524 } 2525 return ret; 2526} 2527 2528/* This produces the matches for one compctl. */ 2529 2530/**/ 2531static void 2532makecomplistcc(Compctl cc, char *s, int incmd) 2533{ 2534 cc->refc++; 2535 if (!ccused) 2536 ccused = newlinklist(); 2537 addlinknode(ccused, cc); 2538 2539 ccont = 0; 2540 2541 makecomplistor(cc, s, incmd, 0, 0); 2542} 2543 2544/* This adds the completions for one run of [x]or'ed completions. */ 2545 2546/**/ 2547static void 2548makecomplistor(Compctl cc, char *s, int incmd, int compadd, int sub) 2549{ 2550 int mn, ct, um = usemenu; 2551 2552 /* Loop over xors. */ 2553 do { 2554 mn = mnum; 2555 2556 /* Loop over ors. */ 2557 do { 2558 /* Reset the range information if we are not in a sub-list. */ 2559 if (!sub) { 2560 brange = 0; 2561 erange = clwnum - 1; 2562 } 2563 usemenu = 0; 2564 makecomplistlist(cc, s, incmd, compadd); 2565 um |= usemenu; 2566 2567 ct = cc->mask2 & CC_XORCONT; 2568 2569 cc = cc->xor; 2570 } while (cc && ct); 2571 2572 /* Stop if we got some matches. */ 2573 if (mn != mnum) 2574 break; 2575 if (cc) { 2576 ccont &= ~(CC_DEFCONT | CC_PATCONT); 2577 if (!sub) 2578 ccont &= ~CC_CCCONT; 2579 } 2580 } while (cc); 2581 2582 usemenu = um; 2583} 2584 2585/* This dispatches for simple and extended completion. */ 2586 2587/**/ 2588static void 2589makecomplistlist(Compctl cc, char *s, int incmd, int compadd) 2590{ 2591 int oloffs = offs, owe = we, owb = wb, ocs = zlemetacs; 2592 2593 METACHECK(); 2594 2595 if (cc->ext) 2596 /* Handle extended completion. */ 2597 makecomplistext(cc, s, incmd); 2598 else 2599 /* Only normal flags. */ 2600 makecomplistflags(cc, s, incmd, compadd); 2601 2602 /* Reset some information variables for the next try. */ 2603 errflag = 0; 2604 offs = oloffs; 2605 wb = owb; 2606 we = owe; 2607 zlemetacs = ocs; 2608} 2609 2610/* This add matches for extended completion patterns */ 2611 2612/**/ 2613static void 2614makecomplistext(Compctl occ, char *os, int incmd) 2615{ 2616 Compctl compc; 2617 Compcond or, cc; 2618 Patprog pprog; 2619 int compadd, m = 0, d = 0, t, tt, i, j, a, b, ins; 2620 char *sc = NULL, *s, *ss; 2621 2622 ins = (instring != QT_NONE ? instring : (inbackt ? QT_BACKTICK : 0)); 2623 2624 /* This loops over the patterns separated by `-'s. */ 2625 for (compc = occ->ext; compc; compc = compc->next) { 2626 compadd = t = brange = 0; 2627 erange = clwnum - 1; 2628 /* This loops over OR'ed patterns. */ 2629 for (cc = compc->cond; cc && !t; cc = or) { 2630 or = cc->or; 2631 /* This loops over AND'ed patterns. */ 2632 for (t = 1; cc && t; cc = cc->and) { 2633 /* And this loops over [...] pairs. */ 2634 for (t = i = 0; i < cc->n && !t; i++) { 2635 s = NULL; 2636 brange = 0; 2637 erange = clwnum - 1; 2638 switch (cc->type) { 2639 case CCT_QUOTE: 2640 t = ((cc->u.s.s[i][0] == 's' && ins == QT_SINGLE) || 2641 (cc->u.s.s[i][0] == 'd' && ins == QT_DOUBLE) || 2642 (cc->u.s.s[i][0] == 'b' && ins == QT_BACKTICK)); 2643 break; 2644 case CCT_POS: 2645 tt = clwpos; 2646 goto cct_num; 2647 case CCT_NUMWORDS: 2648 tt = clwnum; 2649 cct_num: 2650 if ((a = cc->u.r.a[i]) < 0) 2651 a += clwnum; 2652 if ((b = cc->u.r.b[i]) < 0) 2653 b += clwnum; 2654 if (cc->type == CCT_POS) 2655 brange = a, erange = b; 2656 t = (tt >= a && tt <= b); 2657 break; 2658 case CCT_CURSUF: 2659 case CCT_CURPRE: 2660 s = ztrdup(clwpos < clwnum ? os : ""); 2661 untokenize(s); 2662 if (isset(COMPLETEINWORD)) s[offs] = '\0'; 2663 sc = rembslash(cc->u.s.s[i]); 2664 a = strlen(sc); 2665 if (!strncmp(s, sc, a)) { 2666 compadd = (cc->type == CCT_CURSUF ? a : 0); 2667 t = 1; 2668 } 2669 break; 2670 case CCT_CURSUB: 2671 case CCT_CURSUBC: 2672 if (clwpos < 0 || clwpos >= clwnum) 2673 t = 0; 2674 else { 2675 s = ztrdup(os); 2676 untokenize(s); 2677 if (isset(COMPLETEINWORD)) s[offs] = '\0'; 2678 a = getcpat(s, 2679 cc->u.s.p[i], 2680 cc->u.s.s[i], 2681 cc->type == CCT_CURSUBC); 2682 if (a != -1) 2683 compadd = a, t = 1; 2684 } 2685 break; 2686 2687 case CCT_CURPAT: 2688 case CCT_CURSTR: 2689 tt = clwpos; 2690 goto cct_str; 2691 case CCT_WORDPAT: 2692 case CCT_WORDSTR: 2693 tt = 0; 2694 cct_str: 2695 if ((a = tt + cc->u.s.p[i]) < 0) 2696 a += clwnum; 2697 s = ztrdup((a < 0 || a >= clwnum) ? "" : 2698 clwords[a]); 2699 untokenize(s); 2700 2701 if (cc->type == CCT_CURPAT || 2702 cc->type == CCT_WORDPAT) { 2703 tokenize(ss = dupstring(cc->u.s.s[i])); 2704 t = ((pprog = patcompile(ss, PAT_STATIC, NULL)) && 2705 pattry(pprog, s)); 2706 } else 2707 t = (!strcmp(s, rembslash(cc->u.s.s[i]))); 2708 break; 2709 case CCT_RANGESTR: 2710 case CCT_RANGEPAT: 2711 if (cc->type == CCT_RANGEPAT) 2712 tokenize(sc = dupstring(cc->u.l.a[i])); 2713 for (j = clwpos - 1; j > 0; j--) { 2714 untokenize(s = ztrdup(clwords[j])); 2715 if (cc->type == CCT_RANGESTR) 2716 sc = rembslash(cc->u.l.a[i]); 2717 if (cc->type == CCT_RANGESTR ? 2718 !strncmp(s, sc, strlen(sc)) : 2719 ((pprog = patcompile(sc, PAT_STATIC, 0)) && 2720 pattry(pprog, s))) { 2721 zsfree(s); 2722 brange = j + 1; 2723 t = 1; 2724 break; 2725 } 2726 zsfree(s); 2727 } 2728 if (t && cc->u.l.b[i]) { 2729 if (cc->type == CCT_RANGEPAT) 2730 tokenize(sc = dupstring(cc->u.l.b[i])); 2731 for (j++; j < clwnum; j++) { 2732 untokenize(s = ztrdup(clwords[j])); 2733 if (cc->type == CCT_RANGESTR) 2734 sc = rembslash(cc->u.l.b[i]); 2735 if (cc->type == CCT_RANGESTR ? 2736 !strncmp(s, sc, strlen(sc)) : 2737 ((pprog = patcompile(sc, PAT_STATIC, 0)) && 2738 pattry(pprog, s))) { 2739 zsfree(s); 2740 erange = j - 1; 2741 t = clwpos <= erange; 2742 break; 2743 } 2744 zsfree(s); 2745 } 2746 } 2747 s = NULL; 2748 } 2749 zsfree(s); 2750 } 2751 } 2752 } 2753 if (t) { 2754 /* The patterns matched, use the flags. */ 2755 m = 1; 2756 ccont &= ~(CC_PATCONT | CC_DEFCONT); 2757 makecomplistor(compc, os, incmd, compadd, 1); 2758 if (!d && (ccont & CC_DEFCONT)) { 2759 d = 1; 2760 compadd = 0; 2761 brange = 0; 2762 erange = clwnum - 1; 2763 makecomplistflags(occ, os, incmd, 0); 2764 } 2765 if (!(ccont & CC_PATCONT)) 2766 break; 2767 } 2768 } 2769 /* If no pattern matched, use the standard flags. */ 2770 if (!m) { 2771 compadd = 0; 2772 brange = 0; 2773 erange = clwnum - 1; 2774 makecomplistflags(occ, os, incmd, 0); 2775 } 2776} 2777 2778/**/ 2779static int 2780sep_comp_string(char *ss, char *s, int noffs) 2781{ 2782 LinkList foo = newlinklist(); 2783 LinkNode n; 2784 int owe = we, owb = wb, ocs = zlemetacs, swb, swe, scs, soffs, ne = noerrs; 2785 int sl = strlen(ss), tl, got = 0, i = 0, cur = -1, oll = zlemetall, remq; 2786 int ois = instring, oib = inbackt, ona = noaliases; 2787 char *tmp, *p, *ns, *ol = zlemetaline, sav, *oaq = autoq; 2788 char *qp, *qs, *ts; 2789 2790 swb = swe = soffs = 0; 2791 ns = NULL; 2792 2793 METACHECK(); 2794 2795 /* Put the string in the lexer buffer and call the lexer to * 2796 * get the words we have to expand. */ 2797 addedx = 1; 2798 noerrs = 1; 2799 lexsave(); 2800 lexflags = LEXFLAGS_ZLE; 2801 tmp = (char *) zhalloc(tl = sl + 3 + strlen(s)); 2802 strcpy(tmp, ss); 2803 tmp[sl] = ' '; 2804 memcpy(tmp + sl + 1, s, noffs); 2805 tmp[(scs = zlemetacs = sl + 1 + noffs)] = 'x'; 2806 strcpy(tmp + sl + 2 + noffs, s + noffs); 2807 if ((remq = (*compqstack == QT_BACKSLASH))) 2808 tmp = rembslash(tmp); 2809 inpush(dupstrspace(tmp), 0, NULL); 2810 zlemetaline = tmp; 2811 zlemetall = tl - 1; 2812 strinbeg(0); 2813 noaliases = 1; 2814 do { 2815 ctxtlex(); 2816 if (tok == LEXERR) { 2817 int j; 2818 2819 if (!tokstr) 2820 break; 2821 for (j = 0, p = tokstr; *p; p++) 2822 if (*p == Snull || *p == Dnull) 2823 j++; 2824 if (j & 1) { 2825 tok = STRING; 2826 if (p > tokstr && p[-1] == ' ') 2827 p[-1] = '\0'; 2828 } 2829 } 2830 if (tok == ENDINPUT || tok == LEXERR) 2831 break; 2832 if (tokstr && *tokstr) 2833 addlinknode(foo, (p = ztrdup(tokstr))); 2834 else 2835 p = NULL; 2836 if (!got && !lexflags) { 2837 DPUTS(!p, "no current word in substr"); 2838 got = 1; 2839 cur = i; 2840 swb = wb - 1; 2841 swe = we - 1; 2842 soffs = zlemetacs - swb; 2843 chuck(p + soffs); 2844 ns = dupstring(p); 2845 } 2846 i++; 2847 } while (tok != ENDINPUT && tok != LEXERR); 2848 noaliases = ona; 2849 strinend(); 2850 inpop(); 2851 errflag = 0; 2852 noerrs = ne; 2853 lexrestore(); 2854 wb = owb; 2855 we = owe; 2856 zlemetacs = ocs; 2857 zlemetaline = ol; 2858 zlemetall = oll; 2859 if (cur < 0 || i < 1) 2860 return 1; 2861 owb = offs; 2862 offs = soffs; 2863 if ((p = check_param(ns, 0, 1))) { 2864 for (p = ns; *p; p++) 2865 if (*p == Dnull) 2866 *p = '"'; 2867 else if (*p == Snull) 2868 *p = '\''; 2869 } 2870 offs = owb; 2871 2872 untokenize(ts = dupstring(ns)); 2873 2874 if (*ns == Snull || *ns == Dnull || 2875 ((*ns == String || *ns == Qstring) && ns[1] == Snull)) { 2876 char *tsptr = ts, *nsptr = ns, sav; 2877 switch (*ns) { 2878 case Snull: 2879 instring = QT_SINGLE; 2880 break; 2881 2882 case Dnull: 2883 instring = QT_DOUBLE; 2884 break; 2885 2886 default: 2887 instring = QT_DOLLARS; 2888 nsptr++; 2889 tsptr++; 2890 break; 2891 } 2892 2893 inbackt = 0; 2894 swb++; 2895 if (nsptr[strlen(nsptr) - 1] == *nsptr && nsptr[1]) 2896 swe--; 2897 sav = *++tsptr; 2898 *tsptr = '\0'; 2899 autoq = compqstack[1] ? "" : multiquote(ts, 1); 2900 *(ts = tsptr) = sav; 2901 } else { 2902 instring = QT_NONE; 2903 autoq = ""; 2904 } 2905 for (p = ns, i = swb; *p; p++, i++) { 2906 if (inull(*p)) { 2907 if (i < scs) { 2908 soffs--; 2909 if (remq && *p == Bnull && p[1]) 2910 swb -= 2; 2911 } 2912 if (p[1] || *p != Bnull) { 2913 if (*p == Bnull) { 2914 if (scs == i + 1) 2915 scs++, soffs++; 2916 } else { 2917 if (scs > i--) 2918 scs--; 2919 } 2920 } else { 2921 if (scs == swe) 2922 scs--; 2923 } 2924 chuck(p--); 2925 } 2926 } 2927 ns = ts; 2928 2929 if (instring != QT_NONE && strchr(compqstack, QT_BACKSLASH)) { 2930 int rl = strlen(ns), ql = strlen(multiquote(ns, !!compqstack[1])); 2931 2932 if (ql > rl) 2933 swb -= ql - rl; 2934 } 2935 sav = s[(i = swb - sl - 1)]; 2936 s[i] = '\0'; 2937 qp = tricat(qipre, multiquote(s, 0), ""); 2938 s[i] = sav; 2939 if (swe < swb) 2940 swe = swb; 2941 swe -= sl + 1; 2942 sl = strlen(s); 2943 if (swe > sl) { 2944 swe = sl; 2945 if ((int)strlen(ns) > swe - swb + 1) 2946 ns[swe - swb + 1] = '\0'; 2947 } 2948 qs = tricat(multiquote(s + swe, 0), qisuf, ""); 2949 sl = strlen(ns); 2950 if (soffs > sl) 2951 soffs = sl; 2952 2953 { 2954 char **ow = clwords, *os = cmdstr, *oqp = qipre, *oqs = qisuf; 2955 char *oqst = compqstack, compnewchar[2]; 2956 int olws = clwsize, olwn = clwnum, olwp = clwpos; 2957 int obr = brange, oer = erange, oof = offs; 2958 unsigned long occ = ccont; 2959 2960 compnewchar[0] = (char)(instring != QT_NONE ? (char)instring : 2961 QT_BACKSLASH); 2962 compnewchar[1] = '\0'; 2963 compqstack = tricat(compnewchar, compqstack, ""); 2964 2965 clwsize = clwnum = countlinknodes(foo); 2966 clwords = (char **) zalloc((clwnum + 1) * sizeof(char *)); 2967 for (n = firstnode(foo), i = 0; n; incnode(n), i++) { 2968 p = clwords[i] = (char *) getdata(n); 2969 untokenize(p); 2970 } 2971 clwords[i] = NULL; 2972 clwpos = cur; 2973 cmdstr = ztrdup(clwords[0]); 2974 brange = 0; 2975 erange = clwnum - 1; 2976 qipre = qp; 2977 qisuf = qs; 2978 offs = soffs; 2979 ccont = CC_CCCONT; 2980 makecomplistcmd(ns, !clwpos, CFN_FIRST); 2981 ccont = occ; 2982 offs = oof; 2983 zsfree(cmdstr); 2984 cmdstr = os; 2985 freearray(clwords); 2986 clwords = ow; 2987 clwsize = olws; 2988 clwnum = olwn; 2989 clwpos = olwp; 2990 brange = obr; 2991 erange = oer; 2992 zsfree(qipre); 2993 qipre = oqp; 2994 zsfree(qisuf); 2995 qisuf = oqs; 2996 zsfree(compqstack); 2997 compqstack = oqst; 2998 } 2999 autoq = oaq; 3000 instring = ois; 3001 inbackt = oib; 3002 3003 return 0; 3004} 3005 3006/* This adds the completions for the flags in the given compctl. */ 3007 3008/**/ 3009static void 3010makecomplistflags(Compctl cc, char *s, int incmd, int compadd) 3011{ 3012 int t, sf1, sf2, ooffs, um = usemenu, delit, oaw, gflags; 3013 int mn = mnum, ohp = haspattern; 3014 char *p, *sd = NULL, *tt, *s1, *s2, *os = dupstring(s); 3015 struct cmlist ms; 3016 3017 ccont |= (cc->mask2 & (CC_CCCONT | CC_DEFCONT | CC_PATCONT)); 3018 3019 if (incompfunc != 1 && ccstack && findnode(ccstack, cc)) 3020 return; 3021 3022 if (!ccstack) 3023 ccstack = newlinklist(); 3024 addlinknode(ccstack, cc); 3025 3026 if (incompfunc != 1 && allccs) { 3027 if (findnode(allccs, cc)) { 3028 uremnode(ccstack, firstnode(ccstack)); 3029 return; 3030 } 3031 addlinknode(allccs, cc); 3032 } 3033 /* Go to the end of the word if complete_in_word is not set. */ 3034 if (unset(COMPLETEINWORD) && zlemetacs != we) 3035 zlemetacs = we, offs = strlen(s); 3036 3037 s = dupstring(s); 3038 delit = ispattern = 0; 3039 usemenu = um; 3040 patcomp = filecomp = NULL; 3041 rpre = rsuf = lpre = lsuf = ppre = psuf = lppre = lpsuf = 3042 fpre = fsuf = ipre = ripre = prpre = 3043 qfpre = qfsuf = qrpre = qrsuf = qlpre = qlsuf = NULL; 3044 3045 curcc = cc; 3046 3047 mflags = 0; 3048 gflags = (((cc->mask2 & CC_NOSORT ) ? CGF_NOSORT : 0) | 3049 ((cc->mask2 & CC_UNIQALL) ? CGF_UNIQALL : 0) | 3050 ((cc->mask2 & CC_UNIQCON) ? CGF_UNIQCON : 0)); 3051 if (cc->gname) { 3052 endcmgroup(NULL); 3053 begcmgroup(cc->gname, gflags); 3054 } 3055 if (cc->ylist) { 3056 endcmgroup(NULL); 3057 begcmgroup(NULL, gflags); 3058 } 3059 if (cc->mask & CC_REMOVE) 3060 mflags |= CMF_REMOVE; 3061 if (cc->explain) { 3062 curexpl = (Cexpl) zhalloc(sizeof(struct cexpl)); 3063 curexpl->count = curexpl->fcount = 0; 3064 } else 3065 curexpl = NULL; 3066 /* compadd is the number of characters we have to ignore at the * 3067 * beginning of the word. */ 3068 if (compadd) { 3069 ipre = dupstring(s); 3070 ipre[compadd] = '\0'; 3071 untokenize(ipre); 3072 wb += compadd; 3073 s += compadd; 3074 if ((offs -= compadd) < 0) { 3075 /* It's bigger than our word prefix, so we can't help here... */ 3076 uremnode(ccstack, firstnode(ccstack)); 3077 return; 3078 } 3079 } else 3080 ipre = NULL; 3081 3082 if (cc->matcher) { 3083 ms.next = mstack; 3084 ms.matcher = cc->matcher; 3085 mstack = &ms; 3086 3087 if (!mnum) 3088 add_bmatchers(cc->matcher); 3089 3090 addlinknode(matchers, cc->matcher); 3091 cc->matcher->refc++; 3092 } 3093 if (mnum && (mstack || bmatchers)) 3094 update_bmatchers(); 3095 3096 /* Insert the prefix (compctl -P), if any. */ 3097 if (cc->prefix) { 3098 int pl = 0; 3099 3100 if (*s) { 3101 char *dp = rembslash(cc->prefix); 3102 /* First find out how much of the prefix is already on the line. */ 3103 sd = dupstring(s); 3104 untokenize(sd); 3105 pl = pfxlen(dp, sd); 3106 s += pl; 3107 sd += pl; 3108 offs -= pl; 3109 } 3110 } 3111 /* Does this compctl have a suffix (compctl -S)? */ 3112 if (cc->suffix) { 3113 char *sdup = rembslash(cc->suffix); 3114 int sl = strlen(sdup), suffixll; 3115 3116 /* Ignore trailing spaces. */ 3117 for (p = sdup + sl - 1; p >= sdup && *p == ' '; p--, sl--); 3118 p[1] = '\0'; 3119 3120 if (!sd) { 3121 sd = dupstring(s); 3122 untokenize(sd); 3123 } 3124 /* If the suffix is already there, ignore it (and don't add * 3125 * it again). */ 3126 if (*sd && (suffixll = strlen(sd)) >= sl && 3127 offs <= suffixll - sl && !strcmp(sdup, sd + suffixll - sl)) 3128 s[suffixll - sl] = '\0'; 3129 } 3130 /* Do we have one of the special characters `~' and `=' at the beginning? */ 3131 if (incompfunc || ((ic = *s) != Tilde && ic != Equals)) 3132 ic = 0; 3133 3134 /* Check if we have to complete a parameter name... */ 3135 if (!incompfunc && (p = check_param(s, 1, 0))) { 3136 s = p; 3137 /* And now make sure that we complete parameter names. */ 3138 cc = &cc_dummy; 3139 cc_dummy.refc = 10000; 3140 cc_dummy.mask = CC_PARAMS | CC_ENVVARS; 3141 } 3142 ooffs = offs; 3143 /* If we have to ignore the word, do that. */ 3144 if (cc->mask & CC_DELETE) { 3145 delit = 1; 3146 *s = '\0'; 3147 offs = 0; 3148 if (isset(AUTOMENU)) 3149 usemenu = 1; 3150 } 3151 3152 /* Compute line prefix/suffix. */ 3153 lpl = offs; 3154 lpre = zhalloc(lpl + 1); 3155 memcpy(lpre, s, lpl); 3156 lpre[lpl] = '\0'; 3157 qlpre = quotename(lpre, NULL); 3158 lsuf = dupstring(s + offs); 3159 lsl = strlen(lsuf); 3160 qlsuf = quotename(lsuf, NULL); 3161 3162 /* First check for ~.../... */ 3163 if (ic == Tilde) { 3164 for (p = lpre + lpl; p > lpre; p--) 3165 if (*p == '/') 3166 break; 3167 3168 if (*p == '/') 3169 ic = 0; 3170 } 3171 /* Compute real prefix/suffix. */ 3172 3173 noreal = !delit; 3174 for (p = lpre; *p && *p != String && *p != Tick; p++); 3175 tt = ic && !ispar ? lpre + 1 : lpre; 3176 rpre = (*p || *lpre == Tilde || *lpre == Equals) ? 3177 (noreal = 0, getreal(tt)) : 3178 dupstring(tt); 3179 qrpre = quotename(rpre, NULL); 3180 3181 for (p = lsuf; *p && *p != String && *p != Tick; p++); 3182 rsuf = *p ? (noreal = 0, getreal(lsuf)) : dupstring(lsuf); 3183 qrsuf = quotename(rsuf, NULL); 3184 3185 /* Check if word is a pattern. */ 3186 3187 for (s1 = NULL, sf1 = 0, p = rpre + (rpl = strlen(rpre)) - 1; 3188 p >= rpre && (ispattern != 3 || !sf1); 3189 p--) 3190 if (itok(*p) && (p > rpre || (*p != Equals && *p != Tilde))) 3191 ispattern |= sf1 ? 1 : 2; 3192 else if (*p == '/') { 3193 sf1++; 3194 if (!s1) 3195 s1 = p; 3196 } 3197 rsl = strlen(rsuf); 3198 for (s2 = NULL, sf2 = t = 0, p = rsuf; *p && (!t || !sf2); p++) 3199 if (itok(*p)) 3200 t |= sf2 ? 4 : 2; 3201 else if (*p == '/') { 3202 sf2++; 3203 if (!s2) 3204 s2 = p; 3205 } 3206 ispattern = ispattern | t; 3207 3208 /* But if we were asked not to do glob completion, we never treat the * 3209 * thing as a pattern. */ 3210 if (!comppatmatch || !*comppatmatch) 3211 ispattern = 0; 3212 3213 if (ispattern) { 3214 /* The word should be treated as a pattern, so compute the matcher. */ 3215 p = (char *) zhalloc(rpl + rsl + 2); 3216 strcpy(p, rpre); 3217 if (rpl && p[rpl - 1] != Star && 3218 (!comppatmatch || *comppatmatch == '*')) { 3219 p[rpl] = Star; 3220 strcpy(p + rpl + 1, rsuf); 3221 } else 3222 strcpy(p + rpl, rsuf); 3223 patcomp = patcompile(p, 0, NULL); 3224 haspattern = 1; 3225 } 3226 if (!patcomp) { 3227 untokenize(rpre); 3228 untokenize(rsuf); 3229 3230 rpl = strlen(rpre); 3231 rsl = strlen(rsuf); 3232 } 3233 untokenize(lpre); 3234 untokenize(lsuf); 3235 3236 if (!(cc->mask & CC_DELETE)) 3237 hasmatched = 1; 3238 3239 /* Handle completion of files specially (of course). */ 3240 3241 if ((cc->mask & (CC_FILES | CC_DIRS | CC_COMMPATH)) || cc->glob) { 3242 /* s1 and s2 point to the last/first slash in the prefix/suffix. */ 3243 if (!s1) 3244 s1 = rpre; 3245 if (!s2) 3246 s2 = rsuf + rsl; 3247 3248 /* Compute the path prefix/suffix. */ 3249 if (*s1 != '/') 3250 ppre = ""; 3251 else 3252 ppre = dupstrpfx(rpre, s1 - rpre + 1); 3253 psuf = dupstring(s2); 3254 3255 if (zlemetacs != wb) { 3256 char save = zlemetaline[zlemetacs]; 3257 3258 zlemetaline[zlemetacs] = 0; 3259 lppre = dupstring(zlemetaline + wb + 3260 (qipre && *qipre ? 3261 (strlen(qipre) - 3262 (*qipre == '\'' || *qipre == '\"')) : 0)); 3263 zlemetaline[zlemetacs] = save; 3264 if (brbeg) { 3265 Brinfo bp; 3266 3267 for (bp = brbeg; bp; bp = bp->next) 3268 strcpy(lppre + bp->qpos, 3269 lppre + bp->qpos + strlen(bp->str)); 3270 } 3271 if ((p = strrchr(lppre, '/'))) { 3272 p[1] = '\0'; 3273 lppl = strlen(lppre); 3274 } else if (!sf1) { 3275 lppre = NULL; 3276 lppl = 0; 3277 } else { 3278 lppre = ppre; 3279 lppl = strlen(lppre); 3280 } 3281 } else { 3282 lppre = NULL; 3283 lppl = 0; 3284 } 3285 if (zlemetacs != we) { 3286 int end = we; 3287 char save = zlemetaline[end]; 3288 3289 if (qisuf && *qisuf) { 3290 int ql = strlen(qisuf); 3291 3292 end -= ql - (qisuf[ql-1] == '\'' || qisuf[ql-1] == '"'); 3293 } 3294 zlemetaline[end] = 0; 3295 lpsuf = dupstring(zlemetaline + zlemetacs); 3296 zlemetaline[end] = save; 3297 if (brend) { 3298 Brinfo bp; 3299 char *p; 3300 int bl; 3301 3302 for (bp = brend; bp; bp = bp->next) { 3303 p = lpsuf + (we - zlemetacs) - bp->qpos - 3304 (bl = strlen(bp->str)); 3305 strcpy(p, p + bl); 3306 } 3307 } 3308 if (!(lpsuf = strchr(lpsuf, '/')) && sf2) 3309 lpsuf = psuf; 3310 lpsl = (lpsuf ? strlen(lpsuf) : 0); 3311 } else { 3312 lpsuf = NULL; 3313 lpsl = 0; 3314 } 3315 3316 /* And get the file prefix. */ 3317 fpre = dupstring(((s1 == s || s1 == rpre || ic) && 3318 (*s != '/' || zlemetacs == wb)) ? s1 : s1 + 1); 3319 qfpre = quotename(fpre, NULL); 3320 /* And the suffix. */ 3321 fsuf = dupstrpfx(rsuf, s2 - rsuf); 3322 qfsuf = quotename(fsuf, NULL); 3323 3324 if (comppatmatch && *comppatmatch && (ispattern & 2)) { 3325 int t2; 3326 3327 /* We have to use globbing, so compute the pattern from * 3328 * the file prefix and suffix with a `*' between them. */ 3329 p = (char *) zhalloc((t2 = strlen(fpre)) + strlen(fsuf) + 2); 3330 strcpy(p, fpre); 3331 if ((!t2 || p[t2 - 1] != Star) && *fsuf != Star && 3332 (!comppatmatch || *comppatmatch == '*')) 3333 p[t2++] = Star; 3334 strcpy(p + t2, fsuf); 3335 filecomp = patcompile(p, 0, NULL); 3336 } 3337 if (!filecomp) { 3338 untokenize(fpre); 3339 untokenize(fsuf); 3340 3341 fpl = strlen(fpre); 3342 fsl = strlen(fsuf); 3343 } 3344 addwhat = -1; 3345 3346 /* Completion after `~', maketildelist adds the usernames * 3347 * and named directories. */ 3348 if (ic == Tilde) { 3349 char *oi = ipre; 3350 3351 ipre = (ipre ? dyncat("~", ipre) : "~"); 3352 maketildelist(); 3353 ipre = oi; 3354 } else if (ic == Equals) { 3355 /* Completion after `=', get the command names from * 3356 * the cmdnamtab and aliases from aliastab. */ 3357 char *oi = ipre; 3358 3359 ipre = (ipre ? dyncat("=", ipre) : "="); 3360 if (isset(HASHLISTALL)) 3361 cmdnamtab->filltable(cmdnamtab); 3362 dumphashtable(cmdnamtab, -7); 3363 dumphashtable(aliastab, -2); 3364 ipre = oi; 3365 } else { 3366 /* Normal file completion... */ 3367 if (ispattern & 1) { 3368 /* But with pattern matching. */ 3369 LinkList l = newlinklist(); 3370 LinkNode n; 3371 int ng = opts[NULLGLOB]; 3372 3373 opts[NULLGLOB] = 1; 3374 3375 addwhat = 0; 3376 p = (char *) zhalloc(lpl + lsl + 3); 3377 strcpy(p, lpre); 3378 if (*lsuf != '*' && *lpre && lpre[lpl - 1] != '*') 3379 strcat(p, "*"); 3380 strcat(p, lsuf); 3381 if (*lsuf && lsuf[lsl - 1] != '*' && lsuf[lsl - 1] != ')') 3382 strcat(p, "*"); 3383 3384 /* Do the globbing. */ 3385 tokenize(p); 3386 remnulargs(p); 3387 addlinknode(l, p); 3388 globlist(l, 0); 3389 3390 if (nonempty(l)) { 3391 /* And add the resulting words. */ 3392 mflags |= CMF_FILE; 3393 for (n = firstnode(l); n; incnode(n)) 3394 addmatch(getdata(n), NULL); 3395 mflags &= !CMF_FILE; 3396 } 3397 opts[NULLGLOB] = ng; 3398 } else { 3399 char **dirs = 0, *ta[2]; 3400 3401 /* No pattern matching. */ 3402 addwhat = CC_FILES; 3403 3404 if (cc->withd) { 3405 char **pp, **npp, *tp; 3406 int tl = strlen(ppre) + 2, pl; 3407 3408 if ((pp = get_user_var(cc->withd))) { 3409 dirs = npp = 3410 (char**) zhalloc(sizeof(char *)*(arrlen(pp)+1)); 3411 while (*pp) { 3412 pl = strlen(*pp); 3413 tp = (char *) zhalloc(strlen(*pp) + tl); 3414 strcpy(tp, *pp); 3415 tp[pl] = '/'; 3416 strcpy(tp + pl + 1, ppre); 3417 *npp++ = tp; 3418 pp++; 3419 } 3420 *npp = '\0'; 3421 } 3422 } 3423 if (!dirs) { 3424 dirs = ta; 3425 if (cc->withd) { 3426 char *tp; 3427 int pl = strlen(cc->withd); 3428 3429 ta[0] = tp = (char *) zhalloc(strlen(ppre) + pl + 2); 3430 strcpy(tp, cc->withd); 3431 tp[pl] = '/'; 3432 strcpy(tp + pl + 1, ppre); 3433 } else 3434 ta[0] = ppre; 3435 ta[1] = NULL; 3436 } 3437 while (*dirs) { 3438 prpre = *dirs; 3439 3440 if (sf2) 3441 /* We are in the path, so add only directories. */ 3442 gen_matches_files(1, 0, 0); 3443 else { 3444 if (cc->mask & CC_FILES) 3445 /* Add all files. */ 3446 gen_matches_files(0, 0, 1); 3447 else if (cc->mask & CC_COMMPATH) { 3448 /* Completion of command paths. */ 3449 if (sf1 || cc->withd) 3450 /* There is a path prefix, so add * 3451 * directories and executables. */ 3452 gen_matches_files(1, 1, 0); 3453 else { 3454 /* No path prefix, so add the things * 3455 * reachable via the PATH variable. */ 3456 char **pc = path, *pp = prpre; 3457 3458 for (; *pc; pc++) 3459 if (!**pc || (pc[0][0] == '.' && !pc[0][1])) 3460 break; 3461 if (*pc) { 3462 prpre = "./"; 3463 gen_matches_files(1, 1, 0); 3464 prpre = pp; 3465 } 3466 } 3467 } else if (cc->mask & CC_DIRS) 3468 gen_matches_files(1, 0, 0); 3469 /* The compctl has a glob pattern (compctl -g). */ 3470 if (cc->glob) { 3471 int ns, pl = strlen(prpre), o, paalloc; 3472 char *g = dupstring(cc->glob), *pa; 3473 char *p2, *p3; 3474 int ne = noerrs, md = opts[MARKDIRS]; 3475 3476 /* These are used in the globbing code to make * 3477 * things a bit faster. */ 3478 if (ispattern || mstack) 3479 glob_pre = glob_suf = NULL; 3480 else { 3481 glob_pre = fpre; 3482 glob_suf = fsuf; 3483 } 3484 noerrs = 1; 3485 addwhat = -6; 3486 o = strlen(prpre); 3487 pa = (char *)zalloc(paalloc = o + PATH_MAX); 3488 strcpy(pa, prpre); 3489 opts[MARKDIRS] = 0; 3490 3491 /* The compctl -g string may contain more than * 3492 * one pattern, so we need a loop. */ 3493 while (*g) { 3494 LinkList l = newlinklist(); 3495 int ng; 3496 3497 /* Find the blank terminating the pattern. */ 3498 while (*g && inblank(*g)) 3499 g++; 3500 /* Oops, we already reached the end of the 3501 string. */ 3502 if (!*g) 3503 break; 3504 for (p = g + 1; *p && !inblank(*p); p++) 3505 if (*p == '\\' && p[1]) 3506 p++; 3507 /* Get the pattern string. */ 3508 tokenize(g = dupstrpfx(g, p - g)); 3509 if (*g == '=' && isset(EQUALS)) 3510 *g = Equals; 3511 if (*g == '~') 3512 *g = Tilde; 3513 remnulargs(g); 3514 if ((*g == Equals || *g == Tilde) && !cc->withd) { 3515 /* The pattern has a `~' or `=' at the * 3516 * beginning, so we expand this and use * 3517 * the result. */ 3518 filesub(&g, 0); 3519 addlinknode(l, dupstring(g)); 3520 } else if (*g == '/' && !cc->withd) 3521 /* The pattern is a full path (starting * 3522 * with '/'), so add it unchanged. */ 3523 addlinknode(l, dupstring(g)); 3524 else { 3525 /* It's a simple pattern, so append it to * 3526 * the path we have on the command line. */ 3527 int minlen = o + strlen(g); 3528 if (minlen >= paalloc) 3529 pa = (char *) 3530 zrealloc(pa, paalloc = minlen+1); 3531 strcpy(pa + o, g); 3532 addlinknode(l, dupstring(pa)); 3533 } 3534 /* Do the globbing. */ 3535 ng = opts[NULLGLOB]; 3536 opts[NULLGLOB] = 1; 3537 globlist(l, 0); 3538 opts[NULLGLOB] = ng; 3539 /* Get the results. */ 3540 if (nonempty(l) && peekfirst(l)) { 3541 for (p2 = (char *)peekfirst(l); *p2; p2++) 3542 if (itok(*p2)) 3543 break; 3544 if (!*p2) { 3545 if ((*g == Equals || *g == Tilde || 3546 *g == '/') || cc->withd) { 3547 /* IF the pattern started with `~', * 3548 * `=', or `/', add the result only, * 3549 * if it really matches what we have * 3550 * on the line. * 3551 * Do this if an initial directory * 3552 * was specified, too. */ 3553 while ((p2 = (char *)ugetnode(l))) 3554 if (strpfx(prpre, p2)) 3555 addmatch(p2 + pl, NULL); 3556 } else { 3557 /* Otherwise ignore the path we * 3558 * prepended to the pattern. */ 3559 while ((p2 = p3 = 3560 (char *)ugetnode(l))) { 3561 for (ns = sf1; *p3 && ns; p3++) 3562 if (*p3 == '/') 3563 ns--; 3564 3565 addmatch(p3, NULL); 3566 } 3567 } 3568 } 3569 } 3570 pa[o] = '\0'; 3571 g = p; 3572 } 3573 glob_pre = glob_suf = NULL; 3574 noerrs = ne; 3575 opts[MARKDIRS] = md; 3576 3577 zfree(pa, paalloc); 3578 } 3579 } 3580 dirs++; 3581 } 3582 prpre = NULL; 3583 } 3584 } 3585 lppre = lpsuf = NULL; 3586 lppl = lpsl = 0; 3587 } 3588 if (ic) { 3589 /* Now change the `~' and `=' tokens to the real characters so * 3590 * that things starting with these characters will be added. */ 3591 rpre = dyncat((ic == Tilde) ? "~" : "=", rpre); 3592 rpl++; 3593 qrpre = dyncat((ic == Tilde) ? "~" : "=", qrpre); 3594 } 3595 if (!ic && (cc->mask & CC_COMMPATH) && !*ppre && !*psuf) { 3596 /* If we have to complete commands, add alias names, * 3597 * shell functions and builtins too. */ 3598 dumphashtable(aliastab, -3); 3599 dumphashtable(reswdtab, -3); 3600 dumphashtable(shfunctab, -3); 3601 dumphashtable(builtintab, -3); 3602 if (isset(HASHLISTALL)) 3603 cmdnamtab->filltable(cmdnamtab); 3604 dumphashtable(cmdnamtab, -3); 3605 /* And parameter names if autocd and cdablevars are set. */ 3606 if (isset(AUTOCD) && isset(CDABLEVARS)) 3607 dumphashtable(paramtab, -4); 3608 } 3609 oaw = addwhat = (cc->mask & CC_QUOTEFLAG) ? -2 : CC_QUOTEFLAG; 3610 3611 if (cc->mask & CC_NAMED) 3612 /* Add named directories. */ 3613 dumphashtable(nameddirtab, addwhat); 3614 if (cc->mask & CC_OPTIONS) 3615 /* Add option names. */ 3616 dumphashtable(optiontab, addwhat); 3617 if (cc->mask & CC_VARS) { 3618 /* And parameter names. */ 3619 dumphashtable(paramtab, -9); 3620 addwhat = oaw; 3621 } 3622 if (cc->mask & CC_BINDINGS) { 3623 /* And zle function names... */ 3624 dumphashtable(thingytab, CC_BINDINGS); 3625 addwhat = oaw; 3626 } 3627 if (cc->keyvar) { 3628 /* This adds things given to the compctl -k flag * 3629 * (from a parameter or a list of words). */ 3630 char **usr = get_user_var(cc->keyvar); 3631 3632 if (usr) 3633 while (*usr) 3634 addmatch(*usr++, NULL); 3635 } 3636 if (cc->mask & CC_USERS) { 3637 /* Add user names. */ 3638 maketildelist(); 3639 addwhat = oaw; 3640 } 3641 if (cc->func) { 3642 /* This handles the compctl -K flag. */ 3643 Shfunc shfunc; 3644 char **r; 3645 int lv = lastval; 3646 3647 /* Get the function. */ 3648 if ((shfunc = getshfunc(cc->func))) { 3649 /* We have it, so build a argument list. */ 3650 LinkList args = newlinklist(); 3651 int osc = sfcontext; 3652 3653 addlinknode(args, cc->func); 3654 3655 if (delit) { 3656 p = dupstrpfx(os, ooffs); 3657 untokenize(p); 3658 addlinknode(args, p); 3659 p = dupstring(os + ooffs); 3660 untokenize(p); 3661 addlinknode(args, p); 3662 } else { 3663 addlinknode(args, lpre); 3664 addlinknode(args, lsuf); 3665 } 3666 3667 /* This flag allows us to use read -l and -c. */ 3668 if (incompfunc != 1) 3669 incompctlfunc = 1; 3670 sfcontext = SFC_COMPLETE; 3671 /* Call the function. */ 3672 doshfunc(shfunc, args, 1); 3673 sfcontext = osc; 3674 incompctlfunc = 0; 3675 /* And get the result from the reply parameter. */ 3676 if ((r = get_user_var("reply"))) 3677 while (*r) 3678 addmatch(*r++, NULL); 3679 } 3680 lastval = lv; 3681 } 3682 if (cc->mask & (CC_JOBS | CC_RUNNING | CC_STOPPED)) { 3683 /* Get job names. */ 3684 int i; 3685 char *j; 3686 3687 for (i = 0; i <= maxjob; i++) 3688 if ((jobtab[i].stat & STAT_INUSE) && 3689 jobtab[i].procs && jobtab[i].procs->text) { 3690 int stopped = jobtab[i].stat & STAT_STOPPED; 3691 3692 j = dupstring(jobtab[i].procs->text); 3693 if ((cc->mask & CC_JOBS) || 3694 (stopped && (cc->mask & CC_STOPPED)) || 3695 (!stopped && (cc->mask & CC_RUNNING))) 3696 addmatch(j, NULL); 3697 } 3698 } 3699 if (cc->str) { 3700 /* Get the stuff from a compctl -s. */ 3701 LinkList foo = newlinklist(); 3702 LinkNode n; 3703 int first = 1, ng = opts[NULLGLOB], oowe = we, oowb = wb; 3704 int ona = noaliases; 3705 char *tmpbuf; 3706 3707 opts[NULLGLOB] = 1; 3708 3709 /* Put the string in the lexer buffer and call the lexer to * 3710 * get the words we have to expand. */ 3711 lexsave(); 3712 lexflags = LEXFLAGS_ZLE; 3713 tmpbuf = (char *)zhalloc(strlen(cc->str) + 5); 3714 sprintf(tmpbuf, "foo %s", cc->str); /* KLUDGE! */ 3715 inpush(tmpbuf, 0, NULL); 3716 strinbeg(0); 3717 noaliases = 1; 3718 do { 3719 ctxtlex(); 3720 if (tok == ENDINPUT || tok == LEXERR) 3721 break; 3722 if (!first && tokstr && *tokstr) 3723 addlinknode(foo, ztrdup(tokstr)); 3724 first = 0; 3725 } while (tok != ENDINPUT && tok != LEXERR); 3726 noaliases = ona; 3727 strinend(); 3728 inpop(); 3729 errflag = 0; 3730 lexrestore(); 3731 /* Fine, now do full expansion. */ 3732 prefork(foo, 0); 3733 if (!errflag) { 3734 globlist(foo, 0); 3735 if (!errflag) 3736 /* And add the resulting words as matches. */ 3737 for (n = firstnode(foo); n; incnode(n)) 3738 addmatch(getdata(n), NULL); 3739 } 3740 opts[NULLGLOB] = ng; 3741 we = oowe; 3742 wb = oowb; 3743 } 3744 if (cc->hpat) { 3745 /* We have a pattern to take things from the history. */ 3746 Patprog pprogc = NULL; 3747 char *e, *h, hpatsav; 3748 zlong i = addhistnum(curhist,-1,HIST_FOREIGN), n = cc->hnum; 3749 Histent he = gethistent(i, GETHIST_UPWARD); 3750 3751 /* Parse the pattern, if it isn't the null string. */ 3752 if (*(cc->hpat)) { 3753 char *thpat = dupstring(cc->hpat); 3754 3755 tokenize(thpat); 3756 pprogc = patcompile(thpat, 0, NULL); 3757 } 3758 /* n holds the number of history line we have to search. */ 3759 if (!n) 3760 n = -1; 3761 3762 /* Now search the history. */ 3763 while (n-- && he) { 3764 int iwords; 3765 for (iwords = he->nwords - 1; iwords >= 0; iwords--) { 3766 h = he->node.nam + he->words[iwords*2]; 3767 e = he->node.nam + he->words[iwords*2+1]; 3768 hpatsav = *e; 3769 *e = '\0'; 3770 /* We now have a word from the history, ignore it * 3771 * if it begins with a quote or `$'. */ 3772 if (*h != '\'' && *h != '"' && *h != '`' && *h != '$' && 3773 (!pprogc || pattry(pprogc, h))) 3774 /* Otherwise add it if it was matched. */ 3775 addmatch(dupstring(h), NULL); 3776 if (hpatsav) 3777 *e = hpatsav; 3778 } 3779 he = up_histent(he); 3780 } 3781 freepatprog(pprogc); 3782 } 3783 if ((t = cc->mask & (CC_ARRAYS | CC_INTVARS | CC_ENVVARS | CC_SCALARS | 3784 CC_READONLYS | CC_SPECIALS | CC_PARAMS))) 3785 /* Add various flavours of parameters. */ 3786 dumphashtable(paramtab, t); 3787 if ((t = cc->mask & CC_SHFUNCS)) 3788 /* Add shell functions. */ 3789 dumphashtable(shfunctab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); 3790 if ((t = cc->mask & CC_BUILTINS)) 3791 /* Add builtins. */ 3792 dumphashtable(builtintab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); 3793 if ((t = cc->mask & CC_EXTCMDS)) { 3794 /* Add external commands */ 3795 if (isset(HASHLISTALL)) 3796 cmdnamtab->filltable(cmdnamtab); 3797 dumphashtable(cmdnamtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); 3798 } 3799 if ((t = cc->mask & CC_RESWDS)) 3800 /* Add reserved words */ 3801 dumphashtable(reswdtab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); 3802 if ((t = cc->mask & (CC_ALREG | CC_ALGLOB))) 3803 /* Add the two types of aliases. */ 3804 dumphashtable(aliastab, t | (cc->mask & (CC_DISCMDS|CC_EXCMDS))); 3805 if (keypm && cc == &cc_dummy) { 3806 /* Add the keys of the parameter in keypm. */ 3807 HashTable t = keypm->gsu.h->getfn(keypm); 3808 3809 if (t) 3810 scanhashtable(t, 0, 0, PM_UNSET, addhnmatch, 0); 3811 keypm = NULL; 3812 cc_dummy.suffix = NULL; 3813 } 3814 if (!errflag && cc->ylist) { 3815 /* generate the user-defined display list: if anything fails, * 3816 * we silently allow the normal completion list to be used. */ 3817 char **yaptr = NULL, *uv = NULL; 3818 Shfunc shfunc; 3819 3820 if (cc->ylist[0] == '$' || cc->ylist[0] == '(') { 3821 /* from variable */ 3822 uv = cc->ylist + (cc->ylist[0] == '$'); 3823 } else if ((shfunc = getshfunc(cc->ylist))) { 3824 /* from function: pass completions as arg list */ 3825 LinkList args = newlinklist(); 3826 LinkNode ln; 3827 Cmatch m; 3828 int osc = sfcontext; 3829 3830 addlinknode(args, cc->ylist); 3831 for (ln = firstnode(matches); ln; ln = nextnode(ln)) { 3832 m = (Cmatch) getdata(ln); 3833 if (m->ppre) { 3834 char *s = (m->psuf ? m->psuf : ""); 3835 char *p = (char *) zhalloc(strlen(m->ppre) + strlen(m->str) + 3836 strlen(s) + 1); 3837 3838 sprintf(p, "%s%s%s", m->ppre, m->str, s); 3839 addlinknode(args, dupstring(p)); 3840 } else 3841 addlinknode(args, dupstring(m->str)); 3842 } 3843 3844 /* No harm in allowing read -l and -c here, too */ 3845 if (incompfunc != 1) 3846 incompctlfunc = 1; 3847 sfcontext = SFC_COMPLETE; 3848 doshfunc(shfunc, args, 1); 3849 sfcontext = osc; 3850 incompctlfunc = 0; 3851 uv = "reply"; 3852 } 3853 if (uv) 3854 yaptr = get_user_var(uv); 3855 if ((tt = cc->explain)) { 3856 tt = dupstring(tt); 3857 if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { 3858 singsub(&tt); 3859 untokenize(tt); 3860 } 3861 curexpl->str = tt; 3862 if (cc->gname) { 3863 endcmgroup(yaptr); 3864 begcmgroup(cc->gname, gflags); 3865 addexpl(0); 3866 } else { 3867 addexpl(0); 3868 endcmgroup(yaptr); 3869 begcmgroup("default", 0); 3870 } 3871 } else { 3872 endcmgroup(yaptr); 3873 begcmgroup("default", 0); 3874 } 3875 } else if ((tt = cc->explain)) { 3876 tt = dupstring(tt); 3877 if ((cc->mask & CC_EXPANDEXPL) && !parsestr(tt)) { 3878 singsub(&tt); 3879 untokenize(tt); 3880 } 3881 curexpl->str = tt; 3882 addexpl(0); 3883 } 3884 if (cc->subcmd) { 3885 /* Handle -l sub-completion. */ 3886 char **ow = clwords, *os = cmdstr, *ops = NULL; 3887 int oldn = clwnum, oldp = clwpos, br; 3888 unsigned long occ = ccont; 3889 3890 ccont = CC_CCCONT; 3891 3892 /* So we restrict the words-array. */ 3893 if (brange >= clwnum) 3894 brange = clwnum - 1; 3895 if (brange < 1) 3896 brange = 1; 3897 if (erange >= clwnum) 3898 erange = clwnum - 1; 3899 if (erange < 1) 3900 erange = 1; 3901 clwnum = erange - brange + 1; 3902 clwpos = clwpos - brange; 3903 br = brange; 3904 3905 if (cc->subcmd[0]) { 3906 /* And probably put the command name given to the flag * 3907 * in the array. */ 3908 clwpos++; 3909 clwnum++; 3910 incmd = 0; 3911 ops = clwords[br - 1]; 3912 clwords[br - 1] = ztrdup(cc->subcmd); 3913 cmdstr = ztrdup(cc->subcmd); 3914 clwords += br - 1; 3915 } else { 3916 cmdstr = ztrdup(clwords[br]); 3917 incmd = !clwpos; 3918 clwords += br; 3919 } 3920 /* Produce the matches. */ 3921 makecomplistcmd(s, incmd, CFN_FIRST); 3922 3923 /* And restore the things we changed. */ 3924 clwords = ow; 3925 zsfree(cmdstr); 3926 cmdstr = os; 3927 clwnum = oldn; 3928 clwpos = oldp; 3929 if (ops) { 3930 zsfree(clwords[br - 1]); 3931 clwords[br - 1] = ops; 3932 } 3933 ccont = occ; 3934 } 3935 if (cc->substr) 3936 sep_comp_string(cc->substr, s, offs); 3937 uremnode(ccstack, firstnode(ccstack)); 3938 if (cc->matcher) 3939 mstack = mstack->next; 3940 3941 if (mn == mnum) 3942 haspattern = ohp; 3943} 3944 3945 3946static struct builtin bintab[] = { 3947 BUILTIN("compcall", 0, bin_compcall, 0, 0, 0, "TD", NULL), 3948 BUILTIN("compctl", 0, bin_compctl, 0, -1, 0, NULL, NULL), 3949}; 3950 3951static struct features module_features = { 3952 bintab, sizeof(bintab)/sizeof(*bintab), 3953 NULL, 0, 3954 NULL, 0, 3955 NULL, 0, 3956 0 3957}; 3958 3959/**/ 3960int 3961setup_(UNUSED(Module m)) 3962{ 3963 compctlreadptr = compctlread; 3964 createcompctltable(); 3965 cc_compos.mask = CC_COMMPATH; 3966 cc_compos.mask2 = 0; 3967 cc_default.refc = 10000; 3968 cc_default.mask = CC_FILES; 3969 cc_default.mask2 = 0; 3970 cc_first.refc = 10000; 3971 cc_first.mask = 0; 3972 cc_first.mask2 = CC_CCCONT; 3973 3974 lastccused = NULL; 3975 3976 return 0; 3977} 3978 3979/**/ 3980int 3981features_(Module m, char ***features) 3982{ 3983 *features = featuresarray(m, &module_features); 3984 return 0; 3985} 3986 3987/**/ 3988int 3989enables_(Module m, int **enables) 3990{ 3991 return handlefeatures(m, &module_features, enables); 3992} 3993 3994/**/ 3995int 3996boot_(Module m) 3997{ 3998 addhookfunc("compctl_make", (Hookfn) ccmakehookfn); 3999 addhookfunc("compctl_cleanup", (Hookfn) cccleanuphookfn); 4000 return 0; 4001} 4002 4003/**/ 4004int 4005cleanup_(Module m) 4006{ 4007 deletehookfunc("compctl_make", (Hookfn) ccmakehookfn); 4008 deletehookfunc("compctl_cleanup", (Hookfn) cccleanuphookfn); 4009 return setfeatureenables(m, &module_features, NULL); 4010} 4011 4012/**/ 4013int 4014finish_(UNUSED(Module m)) 4015{ 4016 deletehashtable(compctltab); 4017 4018 if (lastccused) 4019 freelinklist(lastccused, (FreeFunc) freecompctl); 4020 4021 compctlreadptr = fallback_compctlread; 4022 return 0; 4023} 4024