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