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