1 /*
2  * computil.c - completion utilities
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 "computil.mdh"
31 #include "computil.pro"
32 
33 
34 /* Help for `_describe'. */
35 
36 typedef struct cdset *Cdset;
37 typedef struct cdstr *Cdstr;
38 typedef struct cdrun *Cdrun;
39 
40 struct cdstate {
41     int showd;			/* != 0 if descriptions should be shown */
42     char *sep;			/* the separator string */
43     int slen;			/* its metafied length */
44     int swidth;			/* its screen width */
45     int maxmlen;                /* maximum length to allow for the matches */
46     Cdset sets;			/* the sets of matches */
47     int pre;                    /* longest prefix length (before description) */
48     int premaxw;		/* ... and its screen width */
49     int suf;                    /* longest suffix (description) */
50     int maxg;                   /* size of largest group */
51     int maxglen;                /* columns for matches of largest group */
52     int groups;                 /* number of groups */
53     int descs;                  /* number of non-group matches with desc */
54     int gprew;                   /* prefix screen width for group display */
55     Cdrun runs;                 /* runs to report to shell code */
56 };
57 
58 struct cdstr {
59     Cdstr next;                 /* the next one in this set */
60     char *str;                  /* the string to display */
61     char *desc;                 /* the description or NULL */
62     char *match;                /* the match to add */
63     char *sortstr;		/* unmetafied string used to sort matches */
64     int len;                    /* length of str or match */
65     int width;			/* ... and its screen width */
66     Cdstr other;                /* next string with the same description */
67     int kind;                   /* 0: not in a group, 1: the first, 2: other */
68     Cdset set;                  /* the set this string is in */
69     Cdstr run;                  /* next in this run */
70 };
71 
72 struct cdrun {
73     Cdrun next;                 /* ... */
74     int type;                   /* see CRT_* below */
75     Cdstr strs;                 /* strings in this run */
76     int count;                  /* number of strings in this run */
77 };
78 
79 #define CRT_SIMPLE 0
80 #define CRT_DESC   1
81 #define CRT_SPEC   2
82 #define CRT_DUMMY  3
83 #define CRT_EXPL   4
84 
85 struct cdset {
86     Cdset next;			/* guess what */
87     char **opts;		/* the compadd-options */
88     Cdstr strs;                 /* the strings/matches */
89     int count;                  /* number of matches in this set */
90     int desc;                   /* number of matches with description */
91 };
92 
93 static struct cdstate cd_state;
94 static int cd_parsed = 0;
95 
96 static void
freecdsets(Cdset p)97 freecdsets(Cdset p)
98 {
99     Cdset n;
100     Cdstr s, sn;
101     Cdrun r, rn;
102 
103     for (; p; p = n) {
104 	n = p->next;
105 	if (p->opts)
106 	    freearray(p->opts);
107         for (s = p->strs; s; s = sn) {
108             sn = s->next;
109 	    zfree(s->sortstr, strlen(s->str) + 1);
110             zsfree(s->str);
111             zsfree(s->desc);
112             if (s->match != s->str)
113                 zsfree(s->match);
114             zfree(s, sizeof(*s));
115         }
116         for (r = cd_state.runs; r; r = rn) {
117             rn = r->next;
118             zfree(r, sizeof(*r));
119         }
120 	zfree(p, sizeof(*p));
121     }
122 }
123 
124 /* Find matches with same descriptions and group them. */
125 
126 static void
cd_group(int maxg)127 cd_group(int maxg)
128 {
129     Cdset set1, set2;
130     Cdstr str1, str2, *strp;
131     int num, width;
132 
133     cd_state.groups = cd_state.descs = cd_state.maxglen = 0;
134     cd_state.maxg = 0;
135 
136     for (set1 = cd_state.sets; set1; set1 = set1->next)
137         for (str1 = set1->strs; str1; str1 = str1->next) {
138             str1->kind = 0;
139             str1->other = NULL;
140         }
141 
142     for (set1 = cd_state.sets; set1; set1 = set1->next) {
143         for (str1 = set1->strs; str1; str1 = str1->next) {
144             if (!str1->desc || str1->kind != 0)
145                 continue;
146 
147             num = 1;
148             width = str1->width + cd_state.swidth;
149             if (width > cd_state.maxglen)
150                 cd_state.maxglen = width;
151             strp = &(str1->other);
152 
153             for (set2 = set1; set2; set2 = set2->next) {
154                 for (str2 = (set2 == set1 ? str1->next : set2->strs);
155                      str2; str2 = str2->next)
156                     if (str2->desc && !strcmp(str1->desc, str2->desc)) {
157                         width += CM_SPACE + str2->width;
158                         if (width > cd_state.maxmlen || num == maxg)
159                             break;
160                         if (width > cd_state.maxglen)
161                             cd_state.maxglen = width;
162                         str1->kind = 1;
163                         str2->kind = 2;
164                         num++;
165                         *strp = str2;
166                         strp = &(str2->other);
167                     }
168                 if (str2)
169                     break;
170             }
171             *strp = NULL;
172 
173             if (num > 1)
174                 cd_state.groups++;
175             else
176                 cd_state.descs++;
177 
178             if (num > cd_state.maxg)
179                 cd_state.maxg = num;
180         }
181     }
182 }
183 
184 /* Calculate longest prefix and suffix and count the strings with
185  * descriptions. */
186 
187 static void
cd_calc(void)188 cd_calc(void)
189 {
190     Cdset set;
191     Cdstr str;
192     int l;
193 
194     cd_state.pre = cd_state.suf = 0;
195 
196     for (set = cd_state.sets; set; set = set->next) {
197         set->count = set->desc = 0;
198         for (str = set->strs; str; str = str->next) {
199             set->count++;
200             if ((l = strlen(str->str)) > cd_state.pre)
201                 cd_state.pre = l;
202             if ((l = ZMB_nicewidth(str->str)) > cd_state.premaxw)
203                 cd_state.premaxw = l;
204             if (str->desc) {
205                 set->desc++;
206                 if ((l = strlen(str->desc)) > cd_state.suf) /* ### strlen() assumes no \n */
207                     cd_state.suf = l;
208             }
209         }
210     }
211 }
212 
213 /* Return 1 if cd_state specifies unsorted groups, 0 otherwise. */
214 static int
cd_groups_want_sorting(void)215 cd_groups_want_sorting(void)
216 {
217     Cdset set;
218     char *const *i;
219 
220     for (set = cd_state.sets; set; set = set->next)
221         for (i = set->opts; *i; i++) {
222             if (!strncmp(*i, "-V", 2))
223                 return 0;
224             else if (!strncmp(*i, "-J", 2))
225                 return 1;
226         }
227 
228     /* Sorted by default */
229     return 1;
230 }
231 
232 static int
cd_sort(const void * a,const void * b)233 cd_sort(const void *a, const void *b)
234 {
235     return zstrcmp((*((Cdstr *) a))->sortstr, (*((Cdstr *) b))->sortstr, 0);
236 }
237 
238 static int
cd_prep(void)239 cd_prep(void)
240 {
241     Cdrun run, *runp;
242     Cdset set;
243     Cdstr str, *strp;
244 
245     runp = &(cd_state.runs);
246 
247     if (cd_state.groups) {
248         int preplines = cd_state.groups + cd_state.descs;
249         VARARR(Cdstr, grps, preplines);
250         VARARR(int, wids, cd_state.maxg);
251         Cdstr gs, gp, gn, *gpp;
252         int i, j, d;
253         Cdrun expl;
254         Cdstr *strp2;
255 
256         memset(wids, 0, cd_state.maxg * sizeof(int));
257         strp = grps;
258 
259         for (set = cd_state.sets; set; set = set->next)
260             for (str = set->strs; str; str = str->next) {
261                 if (str->kind != 1) {
262                     if (!str->kind && str->desc) {
263                         if (str->width > wids[0])
264                             wids[0] = str->width;
265                         str->other = NULL;
266                         *strp++ = str;
267                     }
268                     continue;
269                 }
270                 gs = str;
271                 gs->kind = 2;
272                 gp = str->other;
273                 gs->other = NULL;
274                 for (; gp; gp = gn) {
275                     gn = gp->other;
276                     gp->other = NULL;
277                     for (gpp = &gs; *gpp && (*gpp)->width > gp->width;
278                          gpp = &((*gpp)->other));
279                     gp->other = *gpp;
280                     *gpp = gp;
281                 }
282                 for (gp = gs, i = 0; gp; gp = gp->other, i++)
283                     if (gp->width > wids[i])
284                         wids[i] = gp->width;
285 
286                 *strp++ = gs;
287             }
288 
289         cd_state.gprew = 0;
290         for (i = 0; i < cd_state.maxg; i++) {
291             cd_state.gprew += wids[i] + CM_SPACE;
292 	}
293 
294         if (cd_state.gprew > cd_state.maxmlen && cd_state.maxglen > 1)
295             return 1;
296 
297 	for (i = 0; i < preplines; i++) {
298 	    Cdstr s = grps[i];
299 	    int dummy;
300 
301 	    s->sortstr = ztrdup(s->str);
302 	    unmetafy(s->sortstr, &dummy);
303 	}
304 
305         if (cd_groups_want_sorting())
306             qsort(grps, preplines, sizeof(Cdstr), cd_sort);
307 
308         for (i = preplines, strp = grps; i > 1; i--, strp++) {
309             strp2 = strp + 1;
310             if (!strcmp((*strp)->desc, (*strp2)->desc))
311                 continue;
312             for (j = i - 2, strp2++; j > 0; j--, strp2++)
313                 if (!strcmp((*strp)->desc, (*strp2)->desc)) {
314                     Cdstr tmp = *strp2;
315 
316                     memmove(strp + 2, strp + 1,
317                             (strp2 - strp - 1) * sizeof(Cdstr));
318 
319                     *++strp = tmp;
320                     i--;
321                 }
322         }
323         expl =  (Cdrun) zalloc(sizeof(*run));
324         expl->type = CRT_EXPL;
325         expl->strs = grps[0];
326         expl->count = preplines;
327 
328         for (i = preplines, strp = grps, strp2 = NULL; i; i--, strp++) {
329             str = *strp;
330             *strp = str->other;
331             if (strp2)
332                 *strp2 = str;
333             strp2 = &(str->run);
334 
335             *runp = run = (Cdrun) zalloc(sizeof(*run));
336             runp = &(run->next);
337             run->type = CRT_SPEC;
338             run->strs = str;
339             run->count = 1;
340         }
341         *strp2 = NULL;
342 
343         for (i = cd_state.maxg - 1; i; i--) {
344             for (d = 0, j = preplines, strp = grps; j; j--, strp++) {
345                 if ((str = *strp)) {
346                     if (d) {
347                         *runp = run = (Cdrun) zalloc(sizeof(*run));
348                         runp = &(run->next);
349                         run->type = CRT_DUMMY;
350                         run->strs = expl->strs;
351                         run->count = d;
352                         d = 0;
353                     }
354                     *runp = run = (Cdrun) zalloc(sizeof(*run));
355                     runp = &(run->next);
356                     run->type = CRT_SPEC;
357                     run->strs = str;
358                     run->strs->run = NULL;
359                     run->count = 1;
360 
361                     *strp = str->other;
362                 } else
363                     d++;
364             }
365             if (d) {
366                 *runp = run = (Cdrun) zalloc(sizeof(*run));
367                 runp = &(run->next);
368                 run->type = CRT_DUMMY;
369                 run->strs = expl->strs;
370                 run->count = d;
371             }
372         }
373         *runp = expl;
374         runp = &(expl->next);
375 
376         for (set = cd_state.sets; set; set = set->next) {
377             for (i = 0, gs = NULL, gpp = &gs, str = set->strs;
378                  str; str = str->next) {
379                 if (str->kind || str->desc)
380                     continue;
381 
382                 i++;
383                 *gpp = str;
384                 gpp = &(str->run);
385             }
386             *gpp = NULL;
387             if (i) {
388                 *runp = run = (Cdrun) zalloc(sizeof(*run));
389                 runp = &(run->next);
390                 run->type = CRT_SIMPLE;
391                 run->strs = gs;
392                 run->count = i;
393             }
394         }
395     } else if (cd_state.showd) {
396         for (set = cd_state.sets; set; set = set->next) {
397             if (set->desc) {
398                 *runp = run = (Cdrun) zalloc(sizeof(*run));
399                 runp = &(run->next);
400                 run->type = CRT_DESC;
401                 strp = &(run->strs);
402                 for (str = set->strs; str; str = str->next)
403                     if (str->desc) {
404                         *strp = str;
405                         strp = &(str->run);
406                     }
407                 *strp = NULL;
408                 run->count = set->desc;
409             }
410             if (set->desc != set->count) {
411                 *runp = run = (Cdrun) zalloc(sizeof(*run));
412                 runp = &(run->next);
413                 run->type = CRT_SIMPLE;
414                 strp = &(run->strs);
415                 for (str = set->strs; str; str = str->next)
416                     if (!str->desc) {
417                         *strp = str;
418                         strp = &(str->run);
419                     }
420                 *strp = NULL;
421                 run->count = set->count - set->desc;
422             }
423         }
424     } else {
425         for (set = cd_state.sets; set; set = set->next)
426             if (set->count) {
427                 *runp = run = (Cdrun) zalloc(sizeof(*run));
428                 runp = &(run->next);
429                 run->type = CRT_SIMPLE;
430                 run->strs = set->strs;
431                 for (str = set->strs; str; str = str->next)
432                     str->run = str->next;
433                 run->count = set->count;
434             }
435     }
436     *runp = NULL;
437 
438     return 0;
439 }
440 
441 /* Duplicate and concatenate two arrays.  Return the result. */
442 
443 static char **
cd_arrcat(char ** a,char ** b)444 cd_arrcat(char **a, char **b)
445 {
446     if (!b)
447         return zarrdup(a);
448     else {
449         char **r = (char **) zalloc((arrlen(a) + arrlen(b) + 1) *
450                                     sizeof(char *));
451         char **p = r;
452 
453         for (; *a; a++)
454             *p++ = ztrdup(*a);
455         for (; *b; b++)
456             *p++ = ztrdup(*b);
457 
458         *p = NULL;
459 
460         return r;
461     }
462 }
463 
464 /* Initialisation. Store and calculate the string and matches and so on.
465  *
466  * nam: argv[0] of the builtin
467  * hide: ???
468  * mlen: see max-matches-width style
469  * sep: see list-seperator style
470  * opts: options to (eventually) pass to compadd.
471  *       Returned via 2nd return parameter of 'compdescribe -g'.
472  * args: ??? (the positional arguments to 'compdescribe')
473  * disp: 1 if descriptions should be shown, 0 otherwise
474  */
475 
476 static int
cd_init(char * nam,char * hide,char * mlen,char * sep,char ** opts,char ** args,int disp)477 cd_init(char *nam, char *hide, char *mlen, char *sep,
478         char **opts, char **args, int disp)
479 {
480     Cdset *setp, set;
481     Cdstr *strp, str;
482     char **ap, *tmp;
483     int grp = 0, itmp;
484 
485     if (cd_parsed) {
486 	zsfree(cd_state.sep);
487 	freecdsets(cd_state.sets);
488 	cd_parsed = 0;
489     }
490     setp = &(cd_state.sets);
491     cd_state.sep = ztrdup(sep);
492     cd_state.slen = strlen(sep);
493     cd_state.swidth = ZMB_nicewidth(sep);
494     cd_state.sets = NULL;
495     cd_state.showd = disp;
496     cd_state.maxg = cd_state.groups = cd_state.descs = 0;
497     cd_state.maxmlen = atoi(mlen);
498     cd_state.premaxw = 0;
499     itmp = zterm_columns - cd_state.swidth - 4;
500     if (cd_state.maxmlen > itmp)
501         cd_state.maxmlen = itmp;
502     if (cd_state.maxmlen < 4)
503         cd_state.maxmlen = 4;
504     if (*args && !strcmp(*args, "-g")) {
505         args++;
506         grp = 1;
507     }
508     while (*args) {
509 	*setp = set = (Cdset) zshcalloc(sizeof(*set));
510 	setp = &(set->next);
511         *setp = NULL;
512         set->opts = NULL;
513         set->strs = NULL;
514 
515 	if (!(ap = get_user_var(*args))) {
516 	    zwarnnam(nam, "invalid argument: %s", *args);
517             zsfree(cd_state.sep);
518             freecdsets(cd_state.sets);
519 	    return 1;
520 	}
521         for (str = NULL, strp = &(set->strs); *ap; ap++) {
522             *strp = str = (Cdstr) zalloc(sizeof(*str));
523             strp = &(str->next);
524 
525             str->kind = 0;
526             str->other = NULL;
527             str->set = set;
528 
529 	    /* Advance tmp to the first unescaped colon. */
530 	    for (tmp = *ap; *tmp && *tmp != ':'; tmp++)
531                 if (*tmp == '\\' && tmp[1])
532                     tmp++;
533 
534             if (*tmp)
535                 str->desc = ztrdup(rembslash(tmp + 1));
536             else
537                 str->desc = NULL;
538             *tmp = '\0';
539             str->str = str->match = ztrdup(rembslash(*ap));
540             str->len = strlen(str->str);
541             str->width = ZMB_nicewidth(str->str);
542 	    str->sortstr = NULL;
543         }
544         if (str)
545             str->next = NULL;
546 
547 	if (*++args && **args != '-') {
548 	    if (!(ap = get_user_var(*args))) {
549 		zwarnnam(nam, "invalid argument: %s", *args);
550                 zsfree(cd_state.sep);
551                 freecdsets(cd_state.sets);
552 		return 1;
553 	    }
554             for (str = set->strs; str && *ap; str = str->next, ap++)
555                 str->match = ztrdup(*ap);
556 
557 	    args++;
558 	}
559         if (hide && *hide) {
560             for (str = set->strs; str; str = str->next) {
561                 if (str->str == str->match)
562                     str->str = ztrdup(str->str);
563                 if (hide[1] && str->str[0] == '-' && str->str[1] == '-')
564                     memmove(str->str, str->str + 2, strlen(str->str) - 1);
565                 else if (str->str[0] == '-' || str->str[0] == '+')
566                     memmove(str->str, str->str + 1, strlen(str->str));
567             }
568         }
569 	for (ap = args; *args &&
570 		 (args[0][0] != '-' || args[0][1] != '-' || args[0][2]);
571 	     args++);
572 
573 	tmp = *args;
574 	*args = NULL;
575 	set->opts = cd_arrcat(ap, opts);
576 	if ((*args = tmp))
577 	    args++;
578     }
579     if (disp && grp) {
580         int mg = zterm_columns;
581 
582         do {
583             cd_group(mg);
584             mg = cd_state.maxg - 1;
585             cd_calc();
586         } while (cd_prep());
587 
588     } else {
589         cd_calc();
590         cd_prep();
591     }
592     cd_parsed = 1;
593     return 0;
594 }
595 
596 /* Copy an array with one element in reserve (at the beginning). */
597 
598 static char **
cd_arrdup(char ** a)599 cd_arrdup(char **a)
600 {
601     char **r = (char **) zalloc((arrlen(a) + 2) * sizeof(char *));
602     char **p = r + 1;
603 
604     while (*a)
605         *p++ = ztrdup(*a++);
606     *p = NULL;
607 
608     return r;
609 }
610 
611 /* Get the next set. */
612 
613 static int
cd_get(char ** params)614 cd_get(char **params)
615 {
616     Cdrun run;
617 
618     if ((run = cd_state.runs)) {
619         Cdstr str;
620         char **mats, **mp, **dpys, **dp, **opts, *csl = "";
621 
622         cd_state.runs = run->next;
623 
624         switch (run->type) {
625         case CRT_SIMPLE:
626             mats = mp = (char **) zalloc((run->count + 1) * sizeof(char *));
627             dpys = dp = (char **) zalloc((run->count + 1) * sizeof(char *));
628 
629             for (str = run->strs; str; str = str->run) {
630                 *mp++ = ztrdup(str->match);
631                 *dp++ = ztrdup(str->str ? str->str : str->match);
632             }
633             *mp = *dp = NULL;
634             opts = zarrdup(run->strs->set->opts);
635             if (cd_state.groups) {
636                 /* We are building a columnised list with dummy matches
637                  * but there are also matches without descriptions.
638                  * Those end up in a different group, so make sure that
639                  * group doesn't have an explanation. */
640 
641                 for (mp = dp = opts; *mp; mp++) {
642                     if (dp[0][0] == '-' && dp[0][1] == 'X') {
643                         if (!dp[0][2] && dp[1])
644                             mp++;
645                     } else
646                         *dp++ = *mp;
647                 }
648                 *dp = NULL;
649             }
650             break;
651 
652         case CRT_DESC:
653             {
654 		/*
655 		 * The buffer size:
656 		 *     max prefix length (cd_state.pre) +
657 		 *     max padding (cd_state.premaxw generously :) +
658 		 *     separator length (cd_state.slen) +
659 		 *     inter matches gap (CM_SPACE) +
660 		 *     max description length (cd_state.suf) +
661 		 *     trailing \0
662 		 */
663                 VARARR(char, buf,
664                        cd_state.pre + cd_state.suf +
665 		       cd_state.premaxw + cd_state.slen + 3);
666                 mats = mp = (char **) zalloc((run->count + 1) * sizeof(char *));
667                 dpys = dp = (char **) zalloc((run->count + 1) * sizeof(char *));
668 
669                 for (str = run->strs; str; str = str->run) {
670 		    char *p = buf, *pp, *d;
671 		    int l, remw, w;
672 
673                     *mp++ = ztrdup(str->match);
674 		    strcpy(p, str->str);
675 		    p += str->len;
676                     memset(p, ' ', (l = (cd_state.premaxw - str->width + CM_SPACE)));
677 		    p += l;
678 
679 		    remw = zterm_columns - cd_state.premaxw -
680 			cd_state.swidth - 3;
681 		    while (remw < 0 && zterm_columns) {
682 			/* line wrapped, use remainder of the extra line */
683 			remw += zterm_columns;
684 		    }
685 		    if (cd_state.slen < remw) {
686 			strcpy(p, cd_state.sep);
687 			p += cd_state.slen;
688 			remw -= cd_state.slen;
689 
690 			/*
691 			 * copy a character at once until no more screen
692 			 * width is available. Leave 1 character at the
693 			 * end of screen as safety margin
694 			 */
695 			d = str->desc;
696 			w = ZMB_nicewidth(d);
697 			if (w <= remw)
698 			    strcpy(p, d);
699 			else {
700 			    pp = p;
701 			    while (remw > 0 && *d) {
702 				l = MB_METACHARLEN(d);
703 				memcpy(pp, d, l);
704 				pp[l] = '\0';
705 				w = ZMB_nicewidth(pp);
706 				if (w > remw) {
707 				    *pp = '\0';
708 				    break;
709 				}
710 
711 				pp += l;
712 				d += l;
713 				remw -= w;
714 			    }
715 			}
716 		    }
717 
718                     *dp++ = ztrdup(buf);
719                 }
720                 *mp = *dp = NULL;
721                 opts = cd_arrdup(run->strs->set->opts);
722                 opts[0] = ztrdup("-l");
723                 break;
724             }
725 
726         case CRT_SPEC:
727             mats = (char **) zalloc(2 * sizeof(char *));
728             dpys = (char **) zalloc(2 * sizeof(char *));
729             mats[0] = ztrdup(run->strs->match);
730             dpys[0] = ztrdup(run->strs->str);
731             mats[1] = dpys[1] = NULL;
732             opts = cd_arrdup(run->strs->set->opts);
733 
734             /* Set -2V, possibly reusing the group name from an existing -J/-V
735              * flag. */
736             for (dp = opts + 1; *dp; dp++)
737                 if ((dp[0][0] == '-' && dp[0][1] == 'J') ||
738 		    (dp[0][0] == '-' && dp[0][1] == 'V'))
739                     break;
740             if (*dp) {
741                 char *s = tricat("-2V", "", dp[0] + 2);
742 
743                 zsfree(*dp);
744                 *dp = s;
745 
746                 memmove(opts, opts + 1,
747                         (arrlen(opts + 1) + 1) * sizeof(char *));
748 
749             } else
750                 opts[0] = ztrdup("-2V-default-");
751             csl = "packed";
752             break;
753 
754         case CRT_DUMMY:
755             {
756                 char buf[20];
757 
758                 sprintf(buf, "-E%d", run->count);
759 
760                 mats = (char **) zalloc(sizeof(char *));
761                 dpys = (char **) zalloc(sizeof(char *));
762                 mats[0] = dpys[0] = NULL;
763 
764                 opts = cd_arrdup(run->strs->set->opts);
765                 opts[0] = ztrdup(buf);
766 
767                 csl = "packed";
768             }
769             break;
770 
771 	default: /* This silences the "might be used uninitialized" warnings */
772         case CRT_EXPL:
773             {
774 		/* add columns as safety margin */
775                 VARARR(char, dbuf, cd_state.suf + cd_state.slen +
776 		       zterm_columns);
777                 char buf[20], *p, *pp, *d;
778                 int i = run->count, remw, w, l;
779 
780                 sprintf(buf, "-E%d", i);
781 
782                 mats = (char **) zalloc(sizeof(char *));
783                 dpys = (char **) zalloc((i + 1) * sizeof(char *));
784 
785                 for (dp = dpys, str = run->strs; str; str = str->run) {
786                     if (str->run && !strcmp(str->desc, str->run->desc)) {
787                         *dp++ = ztrdup("");
788                         continue;
789                     }
790 
791                     strcpy(dbuf, cd_state.sep);
792 		    remw = zterm_columns - cd_state.gprew -
793 			cd_state.swidth - CM_SPACE;
794 		    p = pp = dbuf + cd_state.slen;
795 		    d = str->desc;
796 		    w = ZMB_nicewidth(d);
797 		    if (w <= remw) {
798 			strcpy(p, d);
799 			remw -= w;
800 			pp += strlen(d);
801 		    } else
802 			while (remw > 0 && *d) {
803 			    l = MB_METACHARLEN(d);
804 			    memcpy(pp, d, l);
805 			    pp[l] = '\0';
806 			    w = ZMB_nicewidth(pp);
807 			    if (w > remw) {
808 				*pp = '\0';
809 				break;
810 			    }
811 
812 			    pp += l;
813 			    d += l;
814 			    remw -= w;
815 			}
816 
817 		    while (remw-- > 0)
818 			*pp++ = ' ';
819 		    *pp = '\0';
820 
821                     *dp++ = ztrdup(dbuf);
822                 }
823                 mats[0] = *dp = NULL;
824 
825                 opts = cd_arrdup(run->strs->set->opts);
826                 opts[0] = ztrdup(buf);
827 
828                 csl = "packed";
829             }
830             break;
831         }
832         setsparam(params[0], ztrdup(csl));
833         setaparam(params[1], opts);
834         setaparam(params[2], mats);
835         setaparam(params[3], dpys);
836 
837         zfree(run, sizeof(*run));
838 
839         return 0;
840     }
841     return 1;
842 }
843 
844 /**/
845 static int
bin_compdescribe(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))846 bin_compdescribe(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
847 {
848     int n = arrlen(args);
849 
850     if (incompfunc != 1) {
851 	zwarnnam(nam, "can only be called from completion function");
852 	return 1;
853     }
854     if (!args[0][0] || !args[0][1] || args[0][2]) {
855 	zwarnnam(nam, "invalid argument: %s", args[0]);
856 	return 1;
857     }
858     switch (args[0][1]) {
859     case 'i':
860         if (n < 3) {
861             zwarnnam(nam, "not enough arguments");
862 
863             return 1;
864         }
865 	return cd_init(nam, args[1], args[2], "", NULL, args + 3, 0);
866     case 'I':
867         if (n < 6) {
868             zwarnnam(nam, "not enough arguments");
869 
870             return 1;
871         } else {
872             char **opts;
873 
874             if (!(opts = getaparam(args[4]))) {
875 		zwarnnam(nam, "unknown parameter: %s", args[4]);
876 		return 1;
877             }
878             return cd_init(nam, args[1], args[2], args[3], opts, args + 5, 1);
879         }
880     case 'g':
881 	if (cd_parsed) {
882 	    if (n != 5) {
883 		zwarnnam(nam, (n < 5 ? "not enough arguments" :
884 			      "too many arguments"));
885 		return 1;
886 	    }
887 	    return cd_get(args + 1);
888 	} else {
889 	    zwarnnam(nam, "no parsed state");
890 	    return 1;
891 	}
892     }
893     zwarnnam(nam, "invalid option: %s", args[0]);
894     return 1;
895 }
896 
897 /* Help for `_arguments'. */
898 
899 typedef struct cadef *Cadef;
900 typedef struct caopt *Caopt;
901 typedef struct caarg *Caarg;
902 
903 /* Cache for a set of _arguments-definitions. */
904 
905 struct cadef {
906     Cadef next;			/* next in cache */
907     Cadef snext;		/* next set */
908     Caopt opts;			/* the options */
909     int nopts, ndopts, nodopts;	/* number of options/direct/optional direct */
910     Caarg args;			/* the normal arguments */
911     Caarg rest;			/* the rest-argument */
912     char **defs;		/* the original strings */
913     int ndefs;			/* number of ... */
914     int lastt;			/* last time this was used */
915     Caopt *single;		/* array of single-letter options */
916     char *match;		/* -M spec to use */
917     int argsactive;		/* if normal arguments are still allowed */
918 				/* used while parsing a command line */
919     char *set;			/* set name prefix (<name>-), shared */
920     int flags;			/* see CDF_* below */
921     char *nonarg;		/* pattern for non-args (-A argument) */
922 };
923 
924 #define CDF_SEP 1		/* -S was specified: -- terminates options */
925 
926 /* Description for an option. */
927 
928 struct caopt {
929     Caopt next;
930     char *name;			/* option name */
931     char *descr;		/* the description */
932     char **xor;			/* if this, then not ... */
933     int type;			/* type, CAO_* */
934     Caarg args;			/* option arguments */
935     int active;			/* still allowed on command line */
936     int num;			/* it's the num'th option */
937     char *gsname;		/* group or set name, shared */
938     int not;			/* don't complete this option (`!...') */
939 };
940 
941 #define CAO_NEXT    1		/* argument follows in next argument (`-opt:...') */
942 #define CAO_DIRECT  2		/* argument follows option directly (`-opt-:...') */
943 #define CAO_ODIRECT 3		/* argument may follow option directly (`-opt+:...') */
944 #define CAO_EQUAL   4		/* argument follows mandatory equals (`-opt=-:...') */
945 #define CAO_OEQUAL  5		/* argument follows optional equals (`-opt=:...') */
946 
947 /* Description for an argument */
948 
949 struct caarg {
950     Caarg next;
951     char *descr;		/* description */
952     char **xor;			/* if this, then not ... */
953     char *action;		/* what to do for it */
954     int type;			/* CAA_* below */
955     char *end;			/* end-pattern for ::<pat>:... */
956     char *opt;			/* option name if for an option */
957     int num;			/* it's the num'th argument */
958     int min;			/* earliest possible arg pos, given optional args */
959     int direct;			/* true if argument number was given explicitly */
960     int active;			/* still allowed on command line */
961     char *gsname;		/* group or set name, shared */
962 };
963 
964 #define CAA_NORMAL 1
965 #define CAA_OPT    2
966 #define CAA_REST   3
967 #define CAA_RARGS  4
968 #define CAA_RREST  5
969 
970 /* The cache of parsed descriptions. */
971 
972 #define MAX_CACACHE 8
973 static Cadef cadef_cache[MAX_CACACHE];
974 
975 /* Compare two arrays of strings for equality. */
976 
977 static int
arrcmp(char ** a,char ** b)978 arrcmp(char **a, char **b)
979 {
980     if (!a && !b)
981 	return 1;
982     else if (!a || !b)
983 	return 0;
984     else {
985 	while (*a && *b)
986 	    if (strcmp(*a++, *b++))
987 		return 0;
988 
989 	return (!*a && !*b);
990     }
991 }
992 
993 /* Memory stuff. Obviously. */
994 
995 static void
freecaargs(Caarg a)996 freecaargs(Caarg a)
997 {
998     Caarg n;
999 
1000     for (; a; a = n) {
1001 	n = a->next;
1002 	zsfree(a->descr);
1003 	if (a->xor)
1004 	    freearray(a->xor);
1005 	zsfree(a->action);
1006 	zsfree(a->end);
1007 	zsfree(a->opt);
1008 	zfree(a, sizeof(*a));
1009     }
1010 }
1011 
1012 static void
freecadef(Cadef d)1013 freecadef(Cadef d)
1014 {
1015     Cadef s;
1016     Caopt p, n;
1017 
1018     while (d) {
1019 	s = d->snext;
1020 	zsfree(d->match);
1021 	zsfree(d->set);
1022 	if (d->defs)
1023 	    freearray(d->defs);
1024 
1025 	for (p = d->opts; p; p = n) {
1026 	    n = p->next;
1027 	    zsfree(p->name);
1028 	    zsfree(p->descr);
1029 	    if (p->xor)
1030 		freearray(p->xor);
1031 	    freecaargs(p->args);
1032 	    zfree(p, sizeof(*p));
1033 	}
1034 	freecaargs(d->args);
1035 	freecaargs(d->rest);
1036 	zsfree(d->nonarg);
1037 	if (d->single)
1038 	    zfree(d->single, 256 * sizeof(Caopt));
1039 	zfree(d, sizeof(*d));
1040 	d = s;
1041     }
1042 }
1043 
1044 /* Remove backslashes before colons. */
1045 
1046 static char *
rembslashcolon(char * s)1047 rembslashcolon(char *s)
1048 {
1049     char *p, *r;
1050 
1051     r = p = s = dupstring(s);
1052 
1053     while (*s) {
1054 	if (s[0] != '\\' || s[1] != ':')
1055 	    *p++ = *s;
1056 	s++;
1057     }
1058     *p = '\0';
1059 
1060     return r;
1061 }
1062 
1063 /* Add backslashes before colons. */
1064 
1065 static char *
bslashcolon(char * s)1066 bslashcolon(char *s)
1067 {
1068     char *p, *r;
1069 
1070     r = p = zhalloc((2 * strlen(s)) + 1);
1071 
1072     while (*s) {
1073 	if (*s == ':')
1074 	    *p++ = '\\';
1075 	*p++ = *s++;
1076     }
1077     *p = '\0';
1078 
1079     return r;
1080 }
1081 
1082 /* Parse an argument definition. */
1083 
1084 static Caarg
parse_caarg(int mult,int type,int num,int opt,char * oname,char ** def,char * set)1085 parse_caarg(int mult, int type, int num, int opt, char *oname, char **def,
1086 	    char *set)
1087 {
1088     Caarg ret = (Caarg) zalloc(sizeof(*ret));
1089     char *p = *def, *d, sav;
1090 
1091     ret->next = NULL;
1092     ret->descr = ret->action = ret->end = NULL;
1093     ret->xor = NULL;
1094     ret->num = num;
1095     ret->min = num - opt;
1096     ret->type = type;
1097     ret->opt = ztrdup(oname);
1098     ret->direct = 0;
1099     ret->gsname = set;
1100 
1101     /* Get the description. */
1102 
1103     for (d = p; *p && *p != ':'; p++)
1104 	if (*p == '\\' && p[1])
1105 	    p++;
1106     sav = *p;
1107     *p = '\0';
1108     ret->descr = ztrdup(rembslashcolon(d));
1109 
1110     /* Get the action if there is one. */
1111 
1112     if (sav) {
1113 	if (mult) {
1114 	    for (d = ++p; *p && *p != ':'; p++)
1115 		if (*p == '\\' && p[1])
1116 		    p++;
1117 	    sav = *p;
1118 	    *p = '\0';
1119 	    ret->action = ztrdup(rembslashcolon(d));
1120 	    if (sav)
1121 		*p = ':';
1122 	} else
1123 	    ret->action = ztrdup(rembslashcolon(p + 1));
1124     } else
1125 	ret->action = ztrdup("");
1126     *def = p;
1127 
1128     return ret;
1129 }
1130 
1131 static Cadef
alloc_cadef(char ** args,int single,char * match,char * nonarg,int flags)1132 alloc_cadef(char **args, int single, char *match, char *nonarg, int flags)
1133 {
1134     Cadef ret;
1135 
1136     ret = (Cadef) zalloc(sizeof(*ret));
1137     ret->next = ret->snext = NULL;
1138     ret->opts = NULL;
1139     ret->args = ret->rest = NULL;
1140     ret->nonarg = ztrdup(nonarg);
1141     if (args) {
1142 	ret->defs = zarrdup(args);
1143 	ret->ndefs = arrlen(args);
1144     } else {
1145 	ret->defs = NULL;
1146 	ret->ndefs = 0;
1147     }
1148     ret->nopts = 0;
1149     ret->ndopts = 0;
1150     ret->nodopts = 0;
1151     ret->lastt = time(0);
1152     ret->set = NULL;
1153     if (single) {
1154 	ret->single = (Caopt *) zalloc(256 * sizeof(Caopt));
1155 	memset(ret->single, 0, 256 * sizeof(Caopt));
1156     } else
1157 	ret->single = NULL;
1158     ret->match = ztrdup(match);
1159     ret->flags = flags;
1160 
1161     return ret;
1162 }
1163 
1164 static void
set_cadef_opts(Cadef def)1165 set_cadef_opts(Cadef def)
1166 {
1167     Caarg argp;
1168     int xnum;
1169 
1170     for (argp = def->args, xnum = 0; argp; argp = argp->next) {
1171 	if (!argp->direct)
1172 	    argp->min = argp->num - xnum;
1173 	if (argp->type == CAA_OPT)
1174 	    xnum++;
1175     }
1176 }
1177 
1178 /* Parse an array of definitions. */
1179 
1180 static Cadef
parse_cadef(char * nam,char ** args)1181 parse_cadef(char *nam, char **args)
1182 {
1183     Cadef all, ret;
1184     Caopt *optp;
1185     char **orig_args = args, *p, *q, *match = "r:|[_-]=* r:|=*", **xor, **sargs;
1186     char *adpre, *adsuf, *axor = NULL, *doset = NULL, **pendset = NULL, **curset = NULL;
1187     char *nonarg = NULL;
1188     int single = 0, anum = 1, xnum, flags = 0;
1189     int foreignset = 0, not = 0;
1190 
1191     /* First string is the auto-description definition. */
1192 
1193     for (p = args[0]; *p && (p[0] != '%' || p[1] != 'd'); p++);
1194 
1195     if (*p) {
1196 	*p = '\0';
1197 	adpre = dupstring(args[0]);
1198 	*p = '%';
1199 	adsuf = dupstring(p + 2);
1200     } else
1201 	adpre = adsuf = NULL;
1202 
1203     /* Now get the -s, -A, -S and -M options. */
1204 
1205     args++;
1206     while ((p = *args) && *p == '-' && p[1]) {
1207 	for (q = ++p; *q; q++)
1208 	    if (*q == 'M' || *q == 'A') {
1209 		q = "";
1210 		break;
1211 	    } else if (*q != 's' && *q != 'S')
1212 		break;
1213 
1214 	if (*q)
1215 	    break;
1216 
1217 	for (; *p; p++) {
1218 	    if (*p == 's')
1219 		single = 1;
1220 	    else if (*p == 'S')
1221 		flags |= CDF_SEP;
1222 	    else if (*p == 'A') {
1223 		if (p[1]) {
1224 		    nonarg = p + 1;
1225 		    p += strlen(p+1);
1226 		} else if (args[1])
1227 		    nonarg = *++args;
1228 		else
1229 		    break;
1230 	    } else if (*p == 'M') {
1231 		if (p[1]) {
1232 		    match = p + 1;
1233 		    p += strlen(p+1);
1234 		} else if (args[1])
1235 		    match = *++args;
1236 		else
1237 		    break;
1238 	    }
1239 	}
1240 	if (*p)
1241 	    break;
1242 
1243 	args++;
1244     }
1245     if (*args && !strcmp(*args, ":"))
1246         args++;
1247     if (!*args)
1248 	return NULL;
1249 
1250     if (nonarg)
1251 	tokenize(nonarg = dupstring(nonarg));
1252     /* Looks good. Optimistically allocate the cadef structure. */
1253 
1254     all = ret = alloc_cadef(orig_args, single, match, nonarg, flags);
1255     optp = &(ret->opts);
1256     sargs = args;
1257 
1258     /* Get the definitions. */
1259 
1260     for (; *args || pendset; args++) {
1261 	if (!*args) {
1262 	    /* start new set */
1263 	    args = sargs; /* go back and repeat parse of common options */
1264 	    doset = NULL;
1265 	    set_cadef_opts(ret);
1266 	    ret = ret->snext = alloc_cadef(NULL, single, match, nonarg, flags);
1267 	    optp = &(ret->opts);
1268 	    anum = 1;
1269 	    foreignset = 0;
1270 	    curset = pendset;
1271 	    pendset = 0;
1272         }
1273         if (args[0][0] == '-' && !args[0][1] && args[1]) {
1274 	    if ((foreignset = curset && args != curset)) {
1275 		if (!pendset && args > curset)
1276 		    pendset = args; /* mark pointer to next pending set */
1277 		++args;
1278 	    } else {
1279 		/* Carrying on: this is the current set */
1280 		char *p = *++args;
1281 		int l = strlen(p) - 1;
1282 
1283 		if (*p == '(' && p[l] == ')') {
1284 		    axor = p = dupstring(p + 1);
1285 		    p[l - 1] = '\0';
1286 		} else
1287 		    axor = NULL;
1288 		if (!*p) {
1289 		    freecadef(all);
1290 		    zwarnnam(nam, "empty set name");
1291 		    return NULL;
1292 		}
1293 		ret->set = doset = tricat(p, "-", "");
1294 		curset = args; /* needed for the first set */
1295 	    }
1296 	    continue;
1297 	} else if (args[0][0] == '+' && !args[0][1] && args[1]) {
1298 	    char *p;
1299 	    int l;
1300 
1301 	    foreignset = 0; /* group not in any set, don't want to skip it */
1302 	    p = *++args;
1303 	    l = strlen(p) - 1;
1304 	    if (*p == '(' && p[l] == ')') {
1305 		axor = p = dupstring(p + 1);
1306 		p[l - 1] = '\0';
1307 	    } else
1308 		axor = NULL;
1309 	    if (!*p) {
1310 		freecadef(all);
1311 		zwarnnam(nam, "empty group name");
1312 		return NULL;
1313 	    }
1314 	    doset = tricat(p, "-", "");
1315 	    continue;
1316 	} else if (foreignset) /* skipping over a different set */
1317 	    continue;
1318 	p = dupstring(*args);
1319 	xnum = 0;
1320 	if ((not = (*p == '!')))
1321 	    p++;
1322 	if (*p == '(') {
1323 	    /* There is a xor list, get it. */
1324 
1325 	    LinkList list = newlinklist();
1326 	    LinkNode node;
1327 	    char **xp, sav;
1328 
1329 	    while (*p && *p != ')') {
1330 		for (p++; inblank(*p); p++);
1331 
1332 		if (*p == ')')
1333 		    break;
1334 		for (q = p++; *p && *p != ')' && !inblank(*p); p++);
1335 
1336 		if (!*p)
1337 		    break;
1338 
1339 		sav = *p;
1340 		*p = '\0';
1341 		addlinknode(list, dupstring(q));
1342 		xnum++;
1343 		*p = sav;
1344 	    }
1345 	    /* Oops, end-of-string. */
1346 	    if (*p != ')') {
1347 		freecadef(all);
1348 		zwarnnam(nam, "invalid argument: %s", *args);
1349 		return NULL;
1350 	    }
1351 	    if (doset && axor)
1352 		xnum++;
1353 	    xor = (char **) zalloc((xnum + 2) * sizeof(char *));
1354 	    for (node = firstnode(list), xp = xor; node; incnode(node), xp++)
1355 		*xp = ztrdup((char *) getdata(node));
1356 	    if (doset && axor)
1357 		*xp++ = ztrdup(axor);
1358 	    xp[0] = xp[1] = NULL;
1359 
1360 	    p++;
1361 	} else if (doset && axor) {
1362 	    xnum = 1;
1363 	    xor = (char **) zalloc(3 * sizeof(char *));
1364 	    xor[0] = ztrdup(axor);
1365 	    xor[1] = xor[2] = NULL;
1366 	} else
1367 	    xor = NULL;
1368 
1369 	if (*p == '-' || *p == '+' ||
1370 	    (*p == '*' && (p[1] == '-' || p[1] == '+'))) {
1371 	    /* It's an option. */
1372 	    Caopt opt;
1373 	    Caarg oargs = NULL;
1374 	    int multi, otype = CAO_NEXT, again = 0;
1375 	    char *name, *descr, c, *againp = NULL;
1376 
1377 	    rec:
1378 
1379 	    /* Allowed more than once? */
1380 	    if ((multi = (*p == '*')))
1381 		p++;
1382 
1383 	    if (((p[0] == '-' && p[1] == '+') ||
1384 		 (p[0] == '+' && p[1] == '-')) &&
1385 		p[2] && p[2] != ':' && p[2] != '[' &&
1386 		p[2] != '=' && p[2] != '-' && p[2] != '+') {
1387 		/* It's a -+ or +- definition. We just execute the whole
1388 		 * stuff twice for such things. */
1389 		againp = dupstring(p);
1390 		name = ++p;
1391 		*p = (again ? '-' : '+');
1392 		again++;
1393 	    } else {
1394 		name = p;
1395 		/* If it's a long option skip over the first `-'. */
1396 		if (p[0] == '-' && p[1] == '-')
1397 		    p++;
1398 	    }
1399 	    if (!p[1]) {
1400 		freecadef(all);
1401 		zwarnnam(nam, "invalid argument: %s", *args);
1402 		return NULL;
1403 	    }
1404 
1405 	    /* Skip over the name. */
1406 	    for (p++; *p && *p != ':' && *p != '[' &&
1407 		     ((*p != '-' && *p != '+') ||
1408 		      (p[1] != ':' && p[1] != '[')) &&
1409 		     (*p != '=' ||
1410 		      (p[1] != ':' && p[1] != '[' && p[1] != '-')); p++)
1411 		if (*p == '\\' && p[1])
1412 		    p++;
1413 
1414 	    /* The character after the option name specifies the type. */
1415 	    c = *p;
1416 	    *p = '\0';
1417 	    if (c == '-') {
1418 		otype = CAO_DIRECT;
1419 		c = *++p;
1420 	    } else if (c == '+') {
1421 		otype = CAO_ODIRECT;
1422 		c = *++p;
1423 	    } else if (c == '=') {
1424 		otype = CAO_OEQUAL;
1425 		if ((c = *++p) == '-') {
1426 		    otype = CAO_EQUAL;
1427 		    c = *++p;
1428 		}
1429 	    }
1430 	    /* Get the optional description, if any. */
1431 	    if (c == '[') {
1432 		for (descr = ++p; *p && *p != ']'; p++)
1433 		    if (*p == '\\' && p[1])
1434 			p++;
1435 
1436 		if (!*p) {
1437 		    freecadef(all);
1438 		    zwarnnam(nam, "invalid option definition: %s", *args);
1439 		    return NULL;
1440 		}
1441 		*p++ = '\0';
1442 		c = *p;
1443 	    } else
1444 		descr = NULL;
1445 
1446 	    if (c && c != ':') {
1447 		freecadef(all);
1448 		zwarnnam(nam, "invalid option definition: %s", *args);
1449 		return NULL;
1450 	    }
1451 	    /* Add the option name to the xor list if not `*-...'. */
1452 	    if (!multi) {
1453 		if (!xor) {
1454 		    xor = (char **) zalloc(2 * sizeof(char *));
1455 		    xor[0] = xor[1] = NULL;
1456 		}
1457                 zsfree(xor[xnum]);
1458 		xor[xnum] = ztrdup(rembslashcolon(name));
1459 	    }
1460 	    if (c == ':') {
1461 		/* There's at least one argument. */
1462 
1463 		Caarg *oargp = &oargs;
1464 		int atype, rest, oanum = 1, onum = 0;
1465 		char *end;
1466 
1467 		/* Loop over the arguments. */
1468 
1469 		while (c == ':') {
1470 		    rest = 0;
1471 		    end = NULL;
1472 
1473 		    /* Get the argument type. */
1474 		    if (*++p == ':') {
1475 			atype = CAA_OPT;
1476 			p++;
1477 		    } else if (*p == '*') {
1478 			if (*++p != ':') {
1479 			    char sav;
1480 
1481 			    for (end = p++; *p && *p != ':'; p++)
1482 				if (*p == '\\' && p[1])
1483 				    p++;
1484 			    sav = *p;
1485 			    *p = '\0';
1486 			    end = dupstring(end);
1487 			    tokenize(end);
1488 			    *p = sav;
1489 			}
1490 			if (*p != ':') {
1491 			    freecadef(all);
1492 			    freecaargs(oargs);
1493 			    zwarnnam(nam, "invalid option definition: %s",
1494 				    *args);
1495 			    return NULL;
1496 			}
1497 			if (*++p == ':') {
1498 			    if (*++p == ':') {
1499 				atype = CAA_RREST;
1500 				p++;
1501 			    } else
1502 				atype = CAA_RARGS;
1503 			} else
1504 			    atype = CAA_REST;
1505 			rest = 1;
1506 		    } else
1507 			atype = CAA_NORMAL;
1508 
1509 		    /* And the definition. */
1510 
1511 		    *oargp = parse_caarg(!rest, atype, oanum++, onum,
1512 					 name, &p, doset);
1513 		    if (atype == CAA_OPT)
1514 			onum++;
1515 		    if (end)
1516 			(*oargp)->end = ztrdup(end);
1517 		    oargp = &((*oargp)->next);
1518 		    if (rest)
1519 			break;
1520 		    c = *p;
1521 		}
1522 	    }
1523 	    /* Store the option definition. */
1524 
1525 	    *optp = opt = (Caopt) zalloc(sizeof(*opt));
1526 	    optp = &((*optp)->next);
1527 
1528 	    opt->next = NULL;
1529 	    opt->gsname = doset;
1530 	    opt->name = ztrdup(rembslashcolon(name));
1531 	    if (descr)
1532 		opt->descr = ztrdup(descr);
1533 	    else if (adpre && oargs && !oargs->next) {
1534 		char *d;
1535 
1536 		for (d = oargs->descr; *d; d++)
1537 		    if (!iblank(*d))
1538 			break;
1539 
1540 		if (*d)
1541 		    opt->descr = tricat(adpre, oargs->descr, adsuf);
1542 		else
1543 		    opt->descr = NULL;
1544 	    } else
1545 		opt->descr = NULL;
1546 	    opt->xor = (again == 1 && xor ? zarrdup(xor) : xor);
1547 	    opt->type = otype;
1548 	    opt->args = oargs;
1549 	    opt->num = ret->nopts++;
1550 	    opt->not = not;
1551 
1552 	    if (otype == CAO_DIRECT || otype == CAO_EQUAL)
1553 		ret->ndopts++;
1554 	    else if (otype == CAO_ODIRECT || otype == CAO_OEQUAL)
1555 		ret->nodopts++;
1556 
1557 	    /* If this is for single-letter option we also store a
1558 	     * pointer for the definition in the array for fast lookup.
1559 	     * But don't treat '--' as a single option called '-' */
1560 
1561 
1562 	    if (single && name[1] && !name[2] && name[1] != '-')
1563 		ret->single[STOUC(name[1])] = opt;
1564 
1565 	    if (again == 1) {
1566 		/* Do it all again for `*-...'. */
1567 		p = againp;
1568 		goto rec;
1569 	    }
1570 	} else if (*p == '*') {
1571 	    /* It's a rest-argument definition. */
1572 
1573 	    int type = CAA_REST;
1574 
1575 	    if (not)
1576 		continue;
1577 
1578 	    if (*++p != ':') {
1579 		freecadef(all);
1580 		zwarnnam(nam, "invalid rest argument definition: %s", *args);
1581 		return NULL;
1582 	    }
1583 	    if (ret->rest) {
1584 		freecadef(all);
1585 		zwarnnam(nam, "doubled rest argument definition: %s", *args);
1586 		return NULL;
1587 	    }
1588 	    if (*++p == ':') {
1589 		if (*++p == ':') {
1590 		    type = CAA_RREST;
1591 		    p++;
1592 		} else
1593 		    type = CAA_RARGS;
1594 	    }
1595 	    ret->rest = parse_caarg(0, type, -1, 0, NULL, &p, doset);
1596 	    ret->rest->xor = xor;
1597 	} else {
1598 	    /* It's a normal argument definition. */
1599 
1600 	    int type = CAA_NORMAL, direct;
1601 	    Caarg arg, tmp, pre;
1602 
1603 	    if (not)
1604 		continue;
1605 
1606 	    if ((direct = idigit(*p))) {
1607 		/* Argument number is given. */
1608 		int num = 0;
1609 
1610 		while (*p && idigit(*p))
1611 		    num = (num * 10) + (((int) *p++) - '0');
1612 
1613 		anum = num + 1;
1614 	    } else
1615 		/* Default number. */
1616 		anum++;
1617 
1618 	    if (*p != ':') {
1619 		freecadef(all);
1620 		zwarnnam(nam, "invalid argument: %s", *args);
1621 		if (xor)
1622 		    free(xor);
1623 		return NULL;
1624 	    }
1625 	    if (*++p == ':') {
1626 		/* Optional argument. */
1627 		type = CAA_OPT;
1628 		p++;
1629 	    }
1630 	    arg = parse_caarg(0, type, anum - 1, 0, NULL, &p, doset);
1631 	    arg->xor = xor;
1632 	    arg->direct = direct;
1633 
1634 	    /* Sort the new definition into the existing list. */
1635 
1636 	    for (tmp = ret->args, pre = NULL;
1637 		 tmp && tmp->num < anum - 1;
1638 		 pre = tmp, tmp = tmp->next);
1639 
1640 	    if (tmp && tmp->num == anum - 1) {
1641 		freecadef(all);
1642 		freecaargs(arg);
1643 		zwarnnam(nam, "doubled argument definition: %s", *args);
1644 		return NULL;
1645 	    }
1646 	    arg->next = tmp;
1647 	    if (pre)
1648 		pre->next = arg;
1649 	    else
1650 		ret->args = arg;
1651 	}
1652     }
1653     set_cadef_opts(ret);
1654 
1655     return all;
1656 }
1657 
1658 /* Given an array of definitions, return the cadef for it. From the cache
1659  * are newly built. */
1660 
1661 static Cadef
get_cadef(char * nam,char ** args)1662 get_cadef(char *nam, char **args)
1663 {
1664     Cadef *p, *min, new;
1665     int i, na = arrlen(args);
1666 
1667     for (i = MAX_CACACHE, p = cadef_cache, min = NULL; i && *p; p++, i--)
1668 	if (*p && na == (*p)->ndefs && arrcmp(args, (*p)->defs)) {
1669 	    (*p)->lastt = time(0);
1670 
1671 	    return *p;
1672 	} else if (!min || !*p || (*p)->lastt < (*min)->lastt)
1673 	    min = p;
1674     if (i > 0)
1675 	min = p;
1676     if ((new = parse_cadef(nam, args))) {
1677 	freecadef(*min);
1678 	*min = new;
1679     }
1680     return new;
1681 }
1682 
1683 /*
1684  * Get the option used in a word from the line, if any.
1685  *
1686  * "d" is a complete set of argument/option definitions to scan.
1687  * "line" is the word we are scanning.
1688  * "full" indicates that the option must match a full word; otherwise
1689  *   we look for "=" arguments or prefixes.
1690  * *"end" is set to point to the end of the option, in some cases
1691  *   leaving an option argument after it.
1692  */
1693 
1694 static Caopt
ca_get_opt(Cadef d,char * line,int full,char ** end)1695 ca_get_opt(Cadef d, char *line, int full, char **end)
1696 {
1697     Caopt p;
1698 
1699     /* The full string may be an option. */
1700 
1701     for (p = d->opts; p; p = p->next)
1702 	if (p->active && !strcmp(p->name, line)) {
1703 	    if (end)
1704 		*end = line + strlen(line);
1705 
1706 	    return p;
1707 	}
1708 
1709     if (!full) {
1710 	/* The string from the line probably only begins with an option. */
1711 	for (p = d->opts; p; p = p->next)
1712 	    if (p->active && ((!p->args || p->type == CAO_NEXT) ?
1713 			      !strcmp(p->name, line) : strpfx(p->name, line))) {
1714 		int l = strlen(p->name);
1715 		if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
1716 		    line[l] && line[l] != '=')
1717 		    continue;
1718 
1719 		if (end) {
1720 		    /* Return a pointer to the end of the option. */
1721 		    if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
1722 			line[l] == '=')
1723 			l++;
1724 
1725 		    *end = line + l;
1726 		}
1727 		return p;
1728 	    }
1729     }
1730     return NULL;
1731 }
1732 
1733 /* Same as above, only for single-letter-style. */
1734 
1735 static Caopt
ca_get_sopt(Cadef d,char * line,char ** end,LinkList * lp)1736 ca_get_sopt(Cadef d, char *line, char **end, LinkList *lp)
1737 {
1738     Caopt p, pp = NULL;
1739     char pre = *line++;
1740     LinkList l = NULL;
1741 
1742     *lp = NULL;
1743     for (p = NULL; *line; line++) {
1744 	if ((p = d->single[STOUC(*line)]) && p->active &&
1745 	    p->args && p->name[0] == pre) {
1746 	    if (p->type == CAO_NEXT) {
1747 		if (!l)
1748 		    *lp = l = newlinklist();
1749 		addlinknode(l, p);
1750 	    } else {
1751 		if (end) {
1752 		    line++;
1753 		    if ((p->type == CAO_OEQUAL || p->type == CAO_EQUAL) &&
1754 			*line == '=')
1755 			line++;
1756 		    *end = line;
1757 		}
1758 		pp = p;
1759 		break;
1760 	    }
1761 	} else if (!p || (p && !p->active))
1762 	    return NULL;
1763 	pp = (p->name[0] == pre ? p : NULL);
1764 	p = NULL;
1765     }
1766     if (pp && end)
1767 	*end = line;
1768     return pp;
1769 }
1770 
1771 /* Search for an option in all sets except the current one.
1772  * Return true if found */
1773 
1774 static int
ca_foreign_opt(Cadef curset,Cadef all,char * option)1775 ca_foreign_opt(Cadef curset, Cadef all, char *option)
1776 {
1777     Cadef d;
1778     Caopt p;
1779 
1780     for (d = all; d; d = d->snext) {
1781 	if (d == curset)
1782 	    continue;
1783 
1784 	for (p = d->opts; p; p = p->next) {
1785 	    if (!strcmp(p->name, option))
1786 		return 1;
1787 	}
1788     }
1789     return 0;
1790 }
1791 
1792 /* Return the n'th argument definition. */
1793 
1794 static Caarg
ca_get_arg(Cadef d,int n)1795 ca_get_arg(Cadef d, int n)
1796 {
1797     if (d->argsactive) {
1798 	Caarg a = d->args;
1799 
1800 	while (a && (!a->active || n < a->min || n > a->num)) {
1801             if (!a->active)
1802                 n++;
1803 	    a = a->next;
1804         }
1805 	if (a && a->min <= n && a->num >= n && a->active)
1806 	    return a;
1807 
1808 	return (d->rest && d->rest->active ? d->rest : NULL);
1809     }
1810     return NULL;
1811 }
1812 
1813 /* Mark options as inactive.
1814  *   d: option definitions for a set
1815  *   pass either:
1816  *     xor: a list if exclusions
1817  *     opts: if set, all options excluded leaving only nornal/rest arguments */
1818 
1819 static void
ca_inactive(Cadef d,char ** xor,int cur,int opts)1820 ca_inactive(Cadef d, char **xor, int cur, int opts)
1821 {
1822     if ((xor || opts) && cur <= compcurrent) {
1823 	Caopt opt;
1824 	char *x;
1825         /* current word could be a prefix of a longer one so only do
1826 	 * exclusions for single-letter options (for option clumping) */
1827 	int single = !opts && (cur == compcurrent);
1828 
1829 	for (; (x = (opts ? "-" : *xor)); xor++) {
1830 	    int excludeall = 0;
1831 	    char *grp = NULL;
1832 	    size_t grplen;
1833 	    char *next, *sep = x;
1834 
1835 	    while (*sep != '+' && *sep != '-' && *sep != ':' && *sep != '*' && !idigit(*sep)) {
1836 		if (!(next = strchr(sep, '-')) || !*++next) {
1837 		    /* exclusion is just the name of a set or group */
1838 		    excludeall = 1; /* excluding options and args */
1839 		    sep += strlen(sep);
1840 		    /* A trailing '-' is included in the various gsname fields but is not
1841 		     * there for this branch. This is why we add excludeall to grplen
1842 		     * when checking for the null in a few places below */
1843 		    break;
1844 		}
1845 		sep = next;
1846 	    }
1847 	    if (sep > x) { /* exclusion included a set or group name */
1848 		grp = x;
1849 		grplen = sep - grp;
1850 		x = sep;
1851 	    }
1852 
1853 	    if (excludeall || (x[0] == ':' && !x[1])) {
1854 		if (grp) {
1855 		    Caarg a;
1856 
1857 		    for (a = d->args; a; a = a->next)
1858 			if (a->gsname && !strncmp(a->gsname, grp, grplen) &&
1859 				!a->gsname[grplen + excludeall])
1860 			    a->active = 0;
1861 		    if (d->rest && d->rest->gsname &&
1862 			    !strncmp(d->rest->gsname, grp, grplen) &&
1863 			    !d->rest->gsname[grplen + excludeall])
1864 			d->rest->active = 0;
1865 		} else
1866 		    d->argsactive = 0;
1867 	    }
1868 
1869 	    if (excludeall || (x[0] == '-' && !x[1])) {
1870 		Caopt p;
1871 
1872 		for (p = d->opts; p; p = p->next)
1873 		    if ((!grp || (p->gsname && !strncmp(p->gsname, grp, grplen) &&
1874 			    !p->gsname[grplen + excludeall])) &&
1875 			    !(single && *p->name && p->name[1] && p->name[2]))
1876 			p->active = 0;
1877 	    }
1878 
1879 	    if (excludeall || (x[0] == '*' && !x[1])) {
1880 		if (d->rest && (!grp || (d->rest->gsname &&
1881 			!strncmp(d->rest->gsname, grp, grplen) &&
1882 			!d->rest->gsname[grplen + excludeall])))
1883 		    d->rest->active = 0;
1884             }
1885 
1886 	    if (!excludeall) {
1887 		if (idigit(x[0])) {
1888 		    int n = atoi(x);
1889 		    Caarg a = d->args;
1890 
1891 		    while (a && a->num < n)
1892 			a = a->next;
1893 
1894 		    if (a && a->num == n && (!grp || (a->gsname &&
1895 			    !strncmp(a->gsname, grp, grplen))))
1896 			a->active = 0;
1897 		} else if ((opt = ca_get_opt(d, x, 1, NULL)) &&
1898 			(!grp || (opt->gsname && !strncmp(opt->gsname, grp, grplen))) &&
1899 			!(single && *opt->name && opt->name[1] && opt->name[2]))
1900 		    opt->active = 0;
1901 		if (opts)
1902 		    break;
1903 	    }
1904 	}
1905     }
1906 }
1907 
1908 /* State when parsing a command line. */
1909 
1910 typedef struct castate *Castate;
1911 
1912 /* Encapsulates details from parsing the current line against a particular set,
1913  * Covers positions of options and normal arguments. Used as a linked list
1914  * with one state for each set. */
1915 
1916 struct castate {
1917     Castate snext;	/* state for next set */
1918     Cadef d;		/* parsed _arguments specs for the set */
1919     int nopts;		/* number of specified options (size of oargs) */
1920     Caarg def;		/* definition for the current set */
1921     Caarg ddef;
1922     Caopt curopt;	/* option description corresponding to option found on the command-line */
1923     Caopt dopt;
1924     int opt;		/* the length of the option up to a maximum of 2 */
1925     int arg;		/* completing arguments to an option or rest args */
1926     int argbeg;         /* position of first rest argument (+1) */
1927     int optbeg;		/* first word after the last option to the left of the cursor:
1928 			 * in effect the start of any arguments to the current option */
1929     int nargbeg;	/* same as optbeg but used during parse */
1930     int restbeg;	/* same as argbeg but used during parse */
1931     int curpos;		/* current word position */
1932     int argend;         /* total number of words */
1933     int inopt;		/* set to current word pos if word is a recognised option */
1934     int inarg;          /* in a normal argument */
1935     int nth;		/* number of current normal arg */
1936     int singles;	/* argument consists of clumped options */
1937     int oopt;
1938     int actopts;	/* count of active options */
1939     LinkList args;	/* list of non-option args used for populating $line */
1940     LinkList *oargs;	/* list of lists used for populating $opt_args */
1941 };
1942 
1943 static struct castate ca_laststate;
1944 static int ca_parsed = 0, ca_alloced = 0;
1945 static int ca_doff; /* no. of chars of ignored prefix (for clumped options or arg to an option) */
1946 
1947 static void
freecastate(Castate s)1948 freecastate(Castate s)
1949 {
1950     int i;
1951     LinkList *p;
1952 
1953     freelinklist(s->args, freestr);
1954     for (i = s->nopts, p = s->oargs; i--; p++)
1955 	if (*p)
1956 	    freelinklist(*p, freestr);
1957     zfree(s->oargs, s->d->nopts * sizeof(LinkList));
1958 }
1959 
1960 /* Return a copy of an option's argument, ignoring possible quoting
1961  * in the option name. */
1962 
1963 static char *
ca_opt_arg(Caopt opt,char * line)1964 ca_opt_arg(Caopt opt, char *line)
1965 {
1966     char *o = opt->name;
1967 
1968     while (1) {
1969         if (*o == '\\')
1970             o++;
1971         if (*line == '\\' || *line == '\'' || *line == '"')
1972             line++;
1973         if (!*o || *o != *line)
1974             break;
1975         o++;
1976         line++;
1977     }
1978     if (*line && (opt->type == CAO_EQUAL || opt->type == CAO_OEQUAL)) {
1979         if (*line == '\\')
1980             line++;
1981         if (*line == '=')
1982             line++;
1983     }
1984     return ztrdup(line);
1985 }
1986 
1987 /* Parse the command line for a particular argument set (d).
1988  * Returns 1 if the set should be skipped because it doesn't match
1989  * existing options on the line. */
1990 
1991 static int
ca_parse_line(Cadef d,Cadef all,int multi,int first)1992 ca_parse_line(Cadef d, Cadef all, int multi, int first)
1993 {
1994     Caarg adef, ddef;
1995     Caopt ptr, wasopt = NULL, dopt;
1996     struct castate state;
1997     char *line, *oline, *pe, **argxor = NULL;
1998     int cur, doff, argend, arglast;
1999     Patprog endpat = NULL, napat = NULL;
2000     LinkList sopts = NULL;
2001 #if 0
2002     int ne;
2003 #endif
2004 
2005     /* Free old state. */
2006 
2007     if (first && ca_alloced) {
2008 	Castate s = &ca_laststate, ss;
2009 
2010 	while (s) {
2011 	    ss = s->snext;
2012 	    freecastate(s);
2013 	    s = ss;
2014 	}
2015     }
2016     /* Mark everything as active. */
2017 
2018     for (ptr = d->opts; ptr; ptr = ptr->next)
2019 	ptr->active = 1;
2020     d->argsactive = 1;
2021     if (d->rest)
2022 	d->rest->active = 1;
2023     for (adef = d->args; adef; adef = adef->next)
2024 	adef->active = 1;
2025 
2026     /* Default values for the state. */
2027 
2028     state.snext = NULL;
2029     state.d = d;
2030     state.nopts = d->nopts;
2031     state.def = state.ddef = NULL;
2032     state.curopt = state.dopt = NULL;
2033     state.argbeg = state.optbeg = state.nargbeg = state.restbeg = state.actopts =
2034 	state.nth = state.inopt = state.inarg = state.opt = state.arg = 1;
2035     state.argend = argend = arrlen(compwords) - 1;
2036     state.singles = state.oopt = 0;
2037     state.curpos = compcurrent;
2038     state.args = znewlinklist();
2039     state.oargs = (LinkList *) zalloc(d->nopts * sizeof(LinkList));
2040     memset(state.oargs, 0, d->nopts * sizeof(LinkList));
2041 
2042     ca_alloced = 1;
2043 
2044     memcpy(&ca_laststate, &state, sizeof(state));
2045 
2046     if (!compwords[1]) {
2047 	ca_laststate.opt = ca_laststate.arg = 0;
2048 
2049 	goto end;
2050     }
2051     if (d->nonarg) /* argument to -A */
2052 	napat = patcompile(d->nonarg, 0, NULL);
2053 
2054     /* Loop over the words from the line. */
2055 
2056     for (line = compwords[1], cur = 2, state.curopt = NULL, state.def = NULL;
2057 	 line; line = compwords[cur++]) {
2058 	ddef = adef = NULL;
2059 	dopt = NULL;
2060 	state.singles = arglast = 0;
2061 
2062         oline = line;
2063 #if 0
2064         /*
2065 	 * remove quotes.
2066 	 * This is commented out:  it doesn't allow you to discriminate
2067 	 * between command line values that can be expanded and those
2068 	 * that can't, and in some cases this generates inconsistency;
2069 	 * for example, ~/foo\[bar unqotes to ~/foo[bar which doesn't
2070 	 * work either way---it's wrong if the ~ is quoted, and
2071 	 * wrong if the [ isn't quoted..  So it's now up to the caller to
2072 	 * unquote.
2073 	 */
2074         line = dupstring(line);
2075         ne = noerrs;
2076         noerrs = 2;
2077         parse_subst_string(line);
2078         noerrs = ne;
2079 #endif
2080         remnulargs(line);
2081         untokenize(line);
2082 
2083 	ca_inactive(d, argxor, cur - 1, 0);
2084 	if ((d->flags & CDF_SEP) && cur != compcurrent && !strcmp(line, "--")) {
2085 	    ca_inactive(d, NULL, cur, 1);
2086 	    continue;
2087 	}
2088 
2089 	/* We've got a definition for an option/rest argument. For an option,
2090 	 * this means that we're completing arguments to that option. */
2091 	if (state.def) {
2092 	    state.arg = 0;
2093 	    if (state.curopt)
2094 		zaddlinknode(state.oargs[state.curopt->num], ztrdup(oline));
2095 
2096 	    if ((state.opt = (state.def->type == CAA_OPT)) && state.def->opt)
2097 		state.oopt++;
2098 
2099 	    if (state.def->type == CAA_REST || state.def->type == CAA_RARGS ||
2100 		state.def->type == CAA_RREST) {
2101 		if (state.def->end && pattry(endpat, line)) {
2102 		    state.def = NULL;
2103 		    state.curopt = NULL;
2104 		    state.opt = state.arg = 1;
2105 		    state.argend = ca_laststate.argend = cur - 1;
2106 		    goto cont;
2107 		}
2108 	    } else if ((state.def = state.def->next)) {
2109 		state.argbeg = cur;
2110 		state.argend = argend;
2111 	    } else if (sopts && nonempty(sopts)) {
2112 		state.curopt = (Caopt) uremnode(sopts, firstnode(sopts));
2113 		state.def = state.curopt->args;
2114 		state.opt = 0;
2115 		state.argbeg = state.optbeg = state.inopt = cur;
2116 		state.argend = argend;
2117 		doff = 0;
2118 		state.singles = 1;
2119 		if (!state.oargs[state.curopt->num])
2120 		    state.oargs[state.curopt->num] = znewlinklist();
2121 		goto cont;
2122 	    } else {
2123 		state.curopt = NULL;
2124 		state.opt = 1;
2125 	    }
2126 	} else {
2127 	    state.opt = state.arg = 1;
2128 	    state.curopt = NULL;
2129 	}
2130 	if (state.opt)
2131 	    state.opt = (line[0] ? (line[1] ? 2 : 1) : 0);
2132 
2133 	pe = NULL;
2134 
2135 	wasopt = NULL;
2136 
2137 	/* See if it's an option. */
2138 
2139 	if (state.opt == 2 && (state.curopt = ca_get_opt(d, line, 0, &pe)) &&
2140 	    (state.curopt->type == CAO_OEQUAL ?
2141 	     (compwords[cur] || pe[-1] == '=') :
2142 	     (state.curopt->type == CAO_EQUAL ?
2143 	      (pe[-1] == '=' || !pe[0]) : 1))) {
2144 
2145 	    if ((ddef = state.def = ((state.curopt->type != CAO_EQUAL ||
2146 				      pe[-1] == '=') ?
2147 				     state.curopt->args : NULL)))
2148 		dopt = state.curopt;
2149 
2150 	    doff = pe - line;
2151 	    state.optbeg = state.argbeg = state.inopt = cur;
2152 	    state.argend = argend;
2153 	    state.singles = (d->single && (!pe || !*pe) &&
2154 			     state.curopt->name[1] && !state.curopt->name[2] &&
2155 			     /* Don't treat '--' as a single option called '-' */
2156 			     state.curopt->name[1] != '-');
2157 
2158 	    if (!state.oargs[state.curopt->num])
2159 		state.oargs[state.curopt->num] = znewlinklist();
2160 
2161 	    ca_inactive(d, state.curopt->xor, cur, 0);
2162 
2163 	    /* Collect the argument strings. Maybe. */
2164 
2165 	    if (state.def &&
2166 		(state.curopt->type == CAO_DIRECT ||
2167 		 state.curopt->type == CAO_EQUAL ||
2168 		 (state.curopt->type == CAO_ODIRECT && pe[0]) ||
2169 		 (state.curopt->type == CAO_OEQUAL &&
2170 		  (pe[0] || pe[-1] == '=')))) {
2171 		if (state.def->type != CAA_REST &&
2172 		    state.def->type != CAA_RARGS &&
2173 		    state.def->type != CAA_RREST)
2174 		    state.def = state.def->next;
2175 
2176 		zaddlinknode(state.oargs[state.curopt->num],
2177                              ca_opt_arg(state.curopt, oline));
2178 	    }
2179 	    if (state.def)
2180 		state.opt = 0;
2181 	    else {
2182 		if (!d->single || (state.curopt->name[1] && state.curopt->name[2]))
2183 		    wasopt = state.curopt;
2184 		state.curopt = NULL;
2185 	    }
2186 	} else if (state.opt == 2 && d->single &&
2187 		   ((state.curopt = ca_get_sopt(d, line, &pe, &sopts)) ||
2188 		    (cur != compcurrent && sopts && nonempty(sopts)))) {
2189 	    /* Or maybe it's a single-letter option? */
2190 
2191 	    char *p;
2192 	    Caopt tmpopt;
2193 
2194 	    if (cur != compcurrent && sopts && nonempty(sopts))
2195 		state.curopt = (Caopt) uremnode(sopts, firstnode(sopts));
2196 
2197 	    if (!state.oargs[state.curopt->num])
2198 		state.oargs[state.curopt->num] = znewlinklist();
2199 
2200 	    state.def = state.curopt->args;
2201 	    ddef = (state.curopt->type == CAO_NEXT && cur == compcurrent ?
2202 		    NULL : state.def);
2203 	    dopt = state.curopt;
2204 	    doff = pe - line;
2205 	    state.optbeg = state.argbeg = state.inopt = cur;
2206 	    state.argend = argend;
2207 	    state.singles = (!pe || !*pe);
2208 
2209 	    for (p = line + 1; p < pe; p++) {
2210 		if ((tmpopt = d->single[STOUC(*p)])) {
2211 		    if (!state.oargs[tmpopt->num])
2212 			state.oargs[tmpopt->num] = znewlinklist();
2213 
2214 		    ca_inactive(d, tmpopt->xor, cur, 0);
2215 		}
2216 	    }
2217 	    if (state.def &&
2218 		(state.curopt->type == CAO_DIRECT ||
2219 		 state.curopt->type == CAO_EQUAL ||
2220 		 (state.curopt->type == CAO_ODIRECT && pe[0]) ||
2221 		 (state.curopt->type == CAO_OEQUAL &&
2222 		  (pe[0] || pe[-1] == '=')))) {
2223 		if (state.def->type != CAA_REST &&
2224 		    state.def->type != CAA_RARGS &&
2225 		    state.def->type != CAA_RREST)
2226 		    state.def = state.def->next;
2227 
2228 		zaddlinknode(state.oargs[state.curopt->num],
2229                              ca_opt_arg(state.curopt, line));
2230 	    }
2231 	    if (state.def)
2232 		state.opt = 0;
2233 	    else
2234 		state.curopt = NULL;
2235 	} else if (multi && (*line == '-' || *line == '+') && cur != compcurrent
2236 		&& (ca_foreign_opt(d, all, line)))
2237 	    return 1;
2238 	else if (state.arg &&
2239 		 (!napat || cur <= compcurrent || !pattry(napat, line))) {
2240 	    /* Otherwise it's a normal argument. */
2241 	    if (napat && cur <= compcurrent)
2242 		ca_inactive(d, NULL, cur + 1, 1);
2243 
2244 	    arglast = 1;
2245 	    /* if this is the first normal arg after an option, may have been
2246 	     * earlier normal arguments if they're intermixed with options */
2247 	    if (state.inopt) {
2248 		state.inopt = 0;
2249 		state.nargbeg = cur - 1;
2250 		state.argend = argend;
2251 	    }
2252 	    if (!d->args && !d->rest && *line && *line != '-' && *line != '+') {
2253 		if (!multi && cur > compcurrent)
2254 		    break;
2255 		return 1;
2256 	    }
2257 	    if ((adef = state.def = ca_get_arg(d, state.nth)) &&
2258 		(state.def->type == CAA_RREST ||
2259 		 state.def->type == CAA_RARGS)) {
2260 
2261 		/* Bart 2009/11/17:
2262 		 * We've reached the "rest" definition.  If at this point
2263 		 * we already found another definition that describes the
2264 		 * current word, use that instead.  If not, prep for the
2265 		 * "narrowing" of scope to only the remaining words.
2266 		 *
2267 		 * We can't test ca_laststate.def in the loop conditions
2268 		 * at the top because this same loop also handles the
2269 		 * ':*PATTERN:MESSAGE:ACTION' form for multiple arguments
2270 		 * after an option, which may need to continue scanning.
2271 		 * There might be an earlier point at which this test can
2272 		 * be made but tracking it down is not worth the effort.
2273 		 */
2274 		if (ca_laststate.def)
2275 		    break;
2276 
2277 		state.opt = (cur == state.nargbeg + 1 &&
2278 			     (!multi || !*line ||
2279 			      *line == '-' || *line == '+'));
2280 		state.optbeg = state.nargbeg;
2281 		state.argbeg = cur - 1;
2282 		state.argend = argend;
2283 
2284 		for (; line; line = compwords[cur++])
2285 		    zaddlinknode(state.args, ztrdup(line));
2286 
2287 		memcpy(&ca_laststate, &state, sizeof(state));
2288 		ca_laststate.ddef = NULL;
2289 		ca_laststate.dopt = NULL;
2290 		break;
2291 	    }
2292 	    zaddlinknode(state.args, ztrdup(line));
2293             if (adef)
2294                 state.oopt = adef->num - state.nth;
2295 
2296 	    if (state.def)
2297 		argxor = state.def->xor;
2298 
2299 	    if (state.def && state.def->type != CAA_NORMAL &&
2300 		state.def->type != CAA_OPT && state.inarg) {
2301 		state.restbeg = cur;
2302 		state.inarg = 0;
2303 	    } else if (!state.def || state.def->type == CAA_NORMAL ||
2304 		       state.def->type == CAA_OPT)
2305 		state.inarg = 1;
2306 	    state.nth++;
2307 	    state.def = NULL;
2308 	}
2309 	/* Do the end-pattern test if needed. */
2310 
2311 	if (state.def && state.curopt &&
2312 	    (state.def->type == CAA_RREST || state.def->type == CAA_RARGS)) {
2313 	    if (state.def->end)
2314 		endpat = patcompile(state.def->end, 0, NULL);
2315 	    else {
2316 		LinkList l = state.oargs[state.curopt->num];
2317 
2318 		if (cur < compcurrent)
2319 		    memcpy(&ca_laststate, &state, sizeof(state));
2320 
2321 		for (; line; line = compwords[cur++])
2322 		    zaddlinknode(l, ztrdup(line));
2323 
2324 		ca_laststate.ddef = NULL;
2325 		ca_laststate.dopt = NULL;
2326 		break;
2327 	    }
2328 	} else if (state.def && state.def->end)
2329 	    endpat = patcompile(state.def->end, 0, NULL);
2330 
2331 	/* Copy the state into the global one. */
2332 
2333     cont:
2334 
2335 	if (cur + 1 == compcurrent) {
2336 	    memcpy(&ca_laststate, &state, sizeof(state));
2337 	    ca_laststate.ddef = NULL;
2338 	    ca_laststate.dopt = NULL;
2339 	} else if (cur == compcurrent && !ca_laststate.def) {
2340 	    if ((ca_laststate.def = ddef)) {
2341 		ca_laststate.singles = state.singles;
2342 		if (state.curopt && state.curopt->type == CAO_NEXT) {
2343 		    ca_laststate.ddef = ddef;
2344 		    ca_laststate.dopt = dopt;
2345 		    ca_laststate.def = NULL;
2346 		    ca_laststate.opt = 1;
2347 		    state.curopt->active = 1;
2348 		} else {
2349 		    ca_doff = doff;
2350 		    ca_laststate.opt = 0;
2351 		}
2352 	    } else {
2353 		ca_laststate.def = adef;
2354 		ca_laststate.opt = (!arglast || !multi || !*line ||
2355 				    *line == '-' || *line == '+');
2356 		ca_laststate.ddef = NULL;
2357 		ca_laststate.dopt = NULL;
2358 		ca_laststate.optbeg = state.nargbeg;
2359 		ca_laststate.argbeg = state.restbeg;
2360 		ca_laststate.argend = state.argend;
2361 		ca_laststate.singles = state.singles;
2362 		ca_laststate.oopt = state.oopt;
2363 		if (wasopt)
2364 		    wasopt->active = 1;
2365 	    }
2366 	}
2367     }
2368  end:
2369 
2370     ca_laststate.actopts = 0;
2371     for (ptr = d->opts; ptr; ptr = ptr->next)
2372 	if (ptr->active)
2373 	    ca_laststate.actopts++;
2374 
2375     return 0;
2376 }
2377 
2378 /* Build a colon-list from a list.
2379  *
2380  * This is only used to populate values of $opt_args.
2381  */
2382 
2383 static char *
ca_colonlist(LinkList l)2384 ca_colonlist(LinkList l)
2385 {
2386     if (l) {
2387 	LinkNode n;
2388 	int len = 0;
2389 	char *p, *ret, *q;
2390 
2391 	/* Compute the length to be allocated. */
2392 	for (n = firstnode(l); n; incnode(n)) {
2393 	    len++;
2394 	    for (p = (char *) getdata(n); *p; p++)
2395 		len += (*p == ':' || *p == '\\') ? 2 : 1;
2396 	}
2397 	ret = q = (char *) zalloc(len);
2398 
2399 	/* Join L into RET, joining with colons and escaping colons and
2400 	 * backslashes. */
2401 	for (n = firstnode(l); n;) {
2402 	    for (p = (char *) getdata(n); *p; p++) {
2403 		if (*p == ':' || *p == '\\')
2404 		    *q++ = '\\';
2405 		*q++ = *p;
2406 	    }
2407 	    incnode(n);
2408 	    if (n)
2409 		*q++ = ':';
2410 	}
2411 	*q = '\0';
2412 
2413 	return ret;
2414     } else
2415 	return ztrdup("");
2416 }
2417 
2418 /*
2419  * This function adds the current set of descriptions, actions,
2420  * and subcontext descriptions to the given linked list for passing
2421  * up in comparguments -D and comparguments -L.  opt is the
2422  * option string (may be NULL if this isn't an option argument) and arg the
2423  * argument structure (either an option argument or a normal argument
2424  * as determined by arg->type).
2425  */
2426 
2427 static void
ca_set_data(LinkList descr,LinkList act,LinkList subc,char * opt,Caarg arg,Caopt optdef,int single)2428 ca_set_data(LinkList descr, LinkList act, LinkList subc,
2429 	    char *opt, Caarg arg, Caopt optdef, int single)
2430 {
2431     LinkNode dnode, anode;
2432     char nbuf[40], *buf;
2433     int restr = 0, onum, miss = 0, rest, oopt = 1, lopt = 0, addopt;
2434 
2435  rec:
2436 
2437     addopt = (opt ? 0 : ca_laststate.oopt);
2438 
2439     for (; arg && (opt || (arg->num < 0 ||
2440 			   (arg->min <= ca_laststate.nth + addopt &&
2441 			    arg->num >= ca_laststate.nth)));) {
2442 	lopt = (arg->type == CAA_OPT);
2443 	if (!opt && !lopt && oopt > 0)
2444 	    oopt = 0;
2445 
2446 	for (dnode = firstnode(descr), anode = firstnode(act);
2447 	     dnode; incnode(dnode), incnode(anode))
2448 	    if (!strcmp((char *) getdata(dnode), arg->descr) &&
2449 		!strcmp((char *) getdata(anode), arg->action))
2450 		break;
2451 
2452 	/* with an ignored prefix, we're not completing any normal arguments */
2453 	if (single && !arg->opt)
2454 	    return;
2455 
2456 	if (!dnode) {
2457 	    addlinknode(descr, arg->descr);
2458 	    addlinknode(act, arg->action);
2459 
2460 	    if (!restr) {
2461 
2462 		if ((restr = (arg->type == CAA_RARGS)))
2463 		    restrict_range(ca_laststate.optbeg, ca_laststate.argend);
2464 		else if ((restr = (arg->type == CAA_RREST)))
2465 		    restrict_range(ca_laststate.argbeg, ca_laststate.argend);
2466 	    }
2467 	    if (arg->opt) {
2468 		buf = (char *) zhalloc((arg->gsname ? strlen(arg->gsname) : 0) +
2469 				       strlen(arg->opt) + 40);
2470 		if (arg->num > 0 && arg->type < CAA_REST)
2471 		    sprintf(buf, "%soption%s-%d",
2472 			    (arg->gsname ? arg->gsname : ""), arg->opt, arg->num);
2473 		else
2474 		    sprintf(buf, "%soption%s-rest",
2475 			    (arg->gsname ? arg->gsname : ""), arg->opt);
2476 	    } else if (arg->num > 0) {
2477 		sprintf(nbuf, "argument-%d", arg->num);
2478 		buf = (arg->gsname ? dyncat(arg->gsname, nbuf) : dupstring(nbuf));
2479 	    } else
2480 		buf = (arg->gsname ? dyncat(arg->gsname, "argument-rest") :
2481 		       dupstring("argument-rest"));
2482 
2483 	    addlinknode(subc, buf);
2484 	}
2485 	/*
2486 	 * If this is an argument to an option, and the option definition says
2487 	 * the argument to the option is required and in the following
2488 	 * (i.e. this) word, then it must match what we've just told it to
2489 	 * match---don't try to match normal arguments.
2490 	 *
2491 	 * This test may be too stringent for what we need, or it
2492 	 * may be too loose; I've simply tweaked it until it gets
2493 	 * the case above right.
2494 	 */
2495 	if (arg->type == CAA_NORMAL &&
2496 	    opt && optdef &&
2497 	    (optdef->type == CAO_NEXT || optdef->type == CAO_ODIRECT ||
2498 	     optdef->type == CAO_OEQUAL))
2499 	    return;
2500 
2501 	if (single)
2502 	    break;
2503 
2504 	if (!opt) {
2505 	    if (arg->num >= 0 && !arg->next && miss)
2506 		arg = (ca_laststate.d->rest && ca_laststate.d->rest->active ?
2507 		       ca_laststate.d->rest : NULL);
2508 	    else {
2509 		onum = arg->num;
2510 		rest = (onum != arg->min && onum == ca_laststate.nth);
2511 		if ((arg = arg->next)) {
2512 		    if (arg->num != onum + 1)
2513 			miss = 1;
2514 		} else if (rest || (oopt > 0 && !opt)) {
2515 		    arg = (ca_laststate.d->rest && ca_laststate.d->rest->active ?
2516 			   ca_laststate.d->rest : NULL);
2517 		    oopt = -1;
2518 		}
2519 	    }
2520 	} else {
2521 	    if (!lopt)
2522 		break;
2523 	    arg = arg->next;
2524 	}
2525     }
2526     if (!single && opt && (lopt || ca_laststate.oopt)) {
2527 	opt = NULL;
2528 	arg = ca_get_arg(ca_laststate.d, ca_laststate.nth);
2529 	goto rec;
2530     }
2531     if (!opt && oopt > 0) {
2532 	oopt = -1;
2533 	arg = (ca_laststate.d->rest && ca_laststate.d->rest->active ?
2534 	       ca_laststate.d->rest : NULL);
2535 
2536 	goto rec;
2537     }
2538 }
2539 
2540 static int
bin_comparguments(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))2541 bin_comparguments(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
2542 {
2543     int min, max, n;
2544     Castate lstate = &ca_laststate;
2545 
2546     if (incompfunc != 1) {
2547 	zwarnnam(nam, "can only be called from completion function");
2548 	return 1;
2549     }
2550     if (args[0][0] != '-' || !args[0][1] || args[0][2]) {
2551 	zwarnnam(nam, "invalid argument: %s", args[0]);
2552 	return 1;
2553     }
2554     if (args[0][1] != 'i' && args[0][1] != 'I' && !ca_parsed) {
2555 	zwarnnam(nam, "no parsed state");
2556 	return 1;
2557     }
2558     switch (args[0][1]) {
2559     case 'i': min = 2; max = -1; break;
2560     case 'D': min = 3; max =  3; break;
2561     case 'O': min = 4; max =  4; break;
2562     case 'L': min = 3; max =  4; break;
2563     case 's': min = 1; max =  1; break;
2564     case 'M': min = 1; max =  1; break;
2565     case 'a': min = 0; max =  0; break;
2566     case 'W': min = 2; max =  2; break;
2567     case 'n': min = 1; max =  1; break;
2568     default:
2569 	zwarnnam(nam, "invalid option: %s", args[0]);
2570 	return 1;
2571     }
2572     n = arrlen(args) - 1;
2573     if (n < min) {
2574 	zwarnnam(nam, "not enough arguments");
2575 	return 1;
2576     } else if (max >= 0 && n > max) {
2577 	zwarnnam(nam, "too many arguments");
2578 	return 1;
2579     }
2580     switch (args[0][1]) {
2581     case 'i':
2582         /* This initialises the internal data structures. Arguments are the
2583          * auto-description string, the optional -s, -S, -A and -M options
2584          * given to _arguments and the specs. */
2585 	if (compcurrent > 1 && compwords[0]) {
2586 	    Cadef def, all;
2587 	    int cap = ca_parsed, multi, first = 1, use, ret = 0;
2588 	    Castate states = NULL, sp;
2589 
2590 	    ca_parsed = 0;
2591 
2592 	    if (!(def = all = get_cadef(nam, args + 1)))
2593 		return 1;
2594 
2595 	    multi = !!def->snext; /* if we have sets */
2596 	    ca_parsed = cap;
2597 	    ca_doff = 0;
2598 
2599 	    while (def) { /* for each set */
2600 		use = !ca_parse_line(def, all, multi, first);
2601 		def = def->snext;
2602 		if (use && def) {
2603 		    /* entry needed so save it into list */
2604 		    sp = (Castate) zalloc(sizeof(*sp));
2605 		    memcpy(sp, &ca_laststate, sizeof(*sp));
2606 		    sp->snext = states;
2607 		    states = sp;
2608 		} else if (!use && !def) {
2609 		    /* final entry not needed */
2610 		    if (states) {
2611 			freecastate(&ca_laststate);
2612 			memcpy(&ca_laststate, states, sizeof(*sp));
2613 			sp = states->snext;
2614 			zfree(states, sizeof(*states));
2615 			states = sp;
2616 		    } else
2617 			ret = 1;
2618 		}
2619 		first = 0;
2620 	    }
2621 	    ca_parsed = 1;
2622 	    ca_laststate.snext = states;
2623 
2624 	    return ret;
2625 	}
2626 	return 1;
2627 
2628     case 'D':
2629         /* This returns the descriptions, actions and sub-contexts for the
2630          * things _arguments has to execute at this place on the line (the
2631          * sub-contexts are used as tags).
2632          * The return value is particularly important here, it says if
2633          * there are arguments to complete at all. */
2634 	{
2635 	    LinkList descr, act, subc;
2636 	    Caarg arg;
2637 	    int ret = 1;
2638 
2639 	    descr = newlinklist();
2640 	    act = newlinklist();
2641 	    subc = newlinklist();
2642 
2643 	    ignore_prefix(ca_doff);
2644 	    while (lstate) {
2645 		arg = lstate->def;
2646 
2647 		if (arg) {
2648 		    ret = 0;
2649 		    ca_set_data(descr, act, subc, arg->opt, arg,
2650 				lstate->curopt, (ca_doff > 0));
2651 		}
2652 		lstate = lstate->snext;
2653 	    }
2654 	    if (!ret) {
2655 		set_list_array(args[1], descr);
2656 		set_list_array(args[2], act);
2657 		set_list_array(args[3], subc);
2658 	    }
2659 	    return ret;
2660 	}
2661     case 'O':
2662         /* This returns the descriptions for the options in the arrays whose
2663          * names are given as arguments.  The descriptions are strings in a
2664          * form usable by _describe.  The return value says if there are any
2665          * options to be completed. */
2666 	{
2667 	    LinkList next = newlinklist();
2668 	    LinkList direct = newlinklist();
2669 	    LinkList odirect = newlinklist();
2670 	    LinkList equal = newlinklist(), l;
2671             LinkNode node;
2672 	    Caopt p;
2673 	    char *str;
2674 	    int ret = 1;
2675 
2676 	    for (; lstate; lstate = lstate->snext) {
2677 		if (lstate->actopts &&
2678 		    (lstate->opt || (ca_doff && lstate->def) ||
2679 		     (lstate->def && lstate->def->opt &&
2680 		      (lstate->def->type == CAA_OPT ||
2681 		       (lstate->def->type >= CAA_RARGS &&
2682 			lstate->def->num < 0)))) &&
2683 		    (!lstate->def || lstate->def->type < CAA_RARGS ||
2684 		     (lstate->def->type == CAA_RARGS ?
2685 		      (lstate->curpos == lstate->argbeg + 1) :
2686 		      (compcurrent == 1)))) {
2687 		    ret = 0;
2688 		    for (p = lstate->d->opts; p; p = p->next) {
2689 			if (p->active && !p->not) {
2690 			    switch (p->type) {
2691 			    case CAO_NEXT:    l = next;    break;
2692 			    case CAO_DIRECT:  l = direct;  break;
2693 			    case CAO_ODIRECT: l = odirect; break;
2694 			    default:          l = equal;   break;
2695 			    }
2696 			    if (p->descr) {
2697 				char *n = bslashcolon(p->name);
2698 				int len = strlen(n) + strlen(p->descr) + 2;
2699 
2700 				str = (char *) zhalloc(len);
2701 				strcpy(str, n);
2702 				strcat(str, ":");
2703 				strcat(str, p->descr);
2704 			    } else
2705 				str = bslashcolon(p->name);
2706 
2707                             for (node = firstnode(l); node; incnode(node))
2708                                 if (!strcmp(str, (char *) getdata(node)))
2709                                     break;
2710 
2711                             if (!node)
2712                                 addlinknode(l, str);
2713 			}
2714 		    }
2715 		}
2716 	    }
2717 	    if (!ret) {
2718 		set_list_array(args[1], next);
2719 		set_list_array(args[2], direct);
2720 		set_list_array(args[3], odirect);
2721 		set_list_array(args[4], equal);
2722 
2723 		return 0;
2724 	    }
2725 	    return (ca_laststate.singles ? 2 : 1);
2726 	}
2727     case 'L':
2728         /* This tests if the beginning of the current word matches an option.
2729          * It is for cases like `./configure --pre=/<TAB>' which should
2730          * complete to `--prefix=/...'.  The options name isn't fully typed
2731          * and _arguments finds out that there is no option `--pre' and that
2732          * it should complete some argument to an option.  It then uses -L
2733          * to find the option the argument is for. */
2734 	{
2735 	    LinkList descr, act, subc;
2736 	    Caopt opt;
2737 	    int ret = 1;
2738 
2739 	    descr = newlinklist();
2740 	    act = newlinklist();
2741 	    subc = newlinklist();
2742 
2743 	    while (lstate) {
2744 		opt = ca_get_opt(lstate->d, args[1], 1, NULL);
2745 
2746 		if (opt && opt->args) {
2747 		    ret = 0;
2748 		    ca_set_data(descr, act, subc, opt->name, opt->args, opt, 1);
2749 		}
2750 		lstate = lstate->snext;
2751 	    }
2752 	    if (!ret) {
2753 		set_list_array(args[2], descr);
2754 		set_list_array(args[3], act);
2755 		set_list_array(args[4], subc);
2756 	    }
2757 	    return ret;
2758 	}
2759     case 's':
2760         /* This returns zero if we are completing single letter options.
2761          * It also uses its argument as the name of a parameter and sets
2762          * that to a string describing the argument behaviour of the last
2763          * option in the current word so that we can get the auto-suffix
2764          * right. */
2765 	for (; lstate; lstate = lstate->snext)
2766 	    if (lstate->d->single && lstate->singles &&
2767 		lstate->actopts
2768 #if 0
2769                 /* let's try without, for the -W option of _arguments */
2770                 && lstate->opt
2771 #endif
2772                 ) {
2773 		setsparam(args[1],
2774 			  ztrdup((lstate->ddef && lstate->dopt) ?
2775 				 (lstate->dopt->type == CAO_DIRECT ?
2776 				  "direct" :
2777 				  ((lstate->dopt->type == CAO_OEQUAL ||
2778 				    lstate->dopt->type == CAO_EQUAL) ?
2779 				   "equal" : "next")) : ""));
2780 		return 0;
2781 	    }
2782 	return 1;
2783     case 'M':
2784         /* This returns the match specs defined for the set of specs we are
2785          * using.  Returned, as usual in a parameter whose name is given as
2786          * the argument. */
2787 	setsparam(args[1], ztrdup(ca_laststate.d->match));
2788 	return 0;
2789     case 'a':
2790         /* This just sets the return value.  To zero if there would be or
2791          * were any normal arguments to be completed.  Used to decide if
2792          * _arguments should say `no arguments' or `no more arguments'. */
2793 	for (; lstate; lstate = lstate->snext)
2794 	    if (lstate->d->args || lstate->d->rest)
2795 		return 0;
2796 	return 1;
2797     case 'W':
2798         /* This gets two parameter names as arguments.  The first is set to
2799          * the current word sans any option prefixes handled by comparguments.
2800          * The second parameter is set to an array containing the options on
2801          * the line and their arguments.  I.e. the stuff _arguments returns
2802          * to its caller in the `line' and `opt_args' parameters. */
2803 	{
2804 	    Castate s;
2805 	    char **ret, **p;
2806 	    LinkNode n;
2807 	    LinkList *a;
2808 	    Caopt o;
2809 	    int num;
2810 
2811 	    for (num = 0, s = lstate; s; s = s->snext)
2812 		num += countlinknodes(s->args);
2813 
2814 	    ret = p = zalloc((num + 1) * sizeof(char *));
2815 
2816 	    for (s = lstate; s; s = s->snext)
2817 		for (n = firstnode(s->args); n; incnode(n))
2818 		    *p++ = ztrdup((char *) getdata(n));
2819 	    *p = NULL;
2820 
2821 	    setaparam(args[1], ret);
2822 
2823 	    for (num = 0, s = lstate; s; s = s->snext)
2824 		for (o = s->d->opts, a = s->oargs; o; o = o->next, a++)
2825 		    if (*a)
2826 			num += 2;
2827 
2828 	    ret = p = zalloc((num + 1) * sizeof(char *));
2829 
2830 	    for (s = lstate; s; s = s->snext)
2831 		for (o = s->d->opts, a = s->oargs; o; o = o->next, a++)
2832 		    if (*a) {
2833 			*p++ = (o->gsname ? tricat(o->gsname, o->name, "") :
2834 				ztrdup(o->name));
2835 			*p++ = ca_colonlist(*a);
2836 		    }
2837 	    *p = NULL;
2838 
2839 	    sethparam(args[2], ret);
2840 	}
2841 	return 0;
2842     case 'n':
2843 	/*
2844 	 * This returns the array index of the word where normal
2845 	 * arguments began.  It uses optbeg rather than nargbeg
2846 	 * (the value used when parsing) because nargbeg is assigned
2847 	 * to optbeg in the returned value and nargbeg isn't
2848 	 * used.
2849 	 *
2850 	 * -->PLEASE DON'T ASK<--
2851 	 *
2852 	 * Thank you.
2853 	 */
2854 	setiparam(args[1], (zlong)ca_laststate.optbeg + !isset(KSHARRAYS));
2855 	return 0;
2856     }
2857     return 1;
2858 }
2859 
2860 /* Help for `_values'. */
2861 
2862 typedef struct cvdef *Cvdef;
2863 typedef struct cvval *Cvval;
2864 
2865 /* Definitions for _values. */
2866 
2867 struct cvdef {
2868     char *descr;		/* global description */
2869     int hassep;			/* multiple values allowed */
2870     char sep;			/* separator character */
2871     char argsep;                /* argument separator */
2872     Cvdef next;			/* next in cache */
2873     Cvval vals;			/* value definitions */
2874     char **defs;		/* original strings */
2875     int ndefs;			/* number of ... */
2876     int lastt;			/* last time used */
2877     int words;                  /* if to look at other words */
2878 };
2879 
2880 /* One value definition. */
2881 
2882 struct cvval {
2883     Cvval next;
2884     char *name;			/* value name */
2885     char *descr;		/* description */
2886     char **xor;			/* xor-list */
2887     int type;			/* CVV_* below */
2888     Caarg arg;			/* argument definition */
2889     int active;			/* still allowed */
2890 };
2891 
2892 #define CVV_NOARG 0
2893 #define CVV_ARG   1
2894 #define CVV_OPT   2
2895 
2896 /* Cache. */
2897 
2898 #define MAX_CVCACHE 8
2899 static Cvdef cvdef_cache[MAX_CVCACHE];
2900 
2901 /* Memory stuff. */
2902 
2903 static void
freecvdef(Cvdef d)2904 freecvdef(Cvdef d)
2905 {
2906     if (d) {
2907 	Cvval p, n;
2908 
2909 	zsfree(d->descr);
2910 	if (d->defs)
2911 	    freearray(d->defs);
2912 
2913 	for (p = d->vals; p; p = n) {
2914 	    n = p->next;
2915 	    zsfree(p->name);
2916 	    zsfree(p->descr);
2917 	    if (p->xor)
2918 		freearray(p->xor);
2919 	    freecaargs(p->arg);
2920 	    zfree(p, sizeof(*p));
2921 	}
2922 	zfree(d, sizeof(*d));
2923     }
2924 }
2925 
2926 /* Parse option definitions. */
2927 
2928 static Cvdef
parse_cvdef(char * nam,char ** args)2929 parse_cvdef(char *nam, char **args)
2930 {
2931     Cvdef ret;
2932     Cvval val, *valp;
2933     Caarg arg;
2934     char **oargs = args, sep = '\0', asep = '=', *name, *descr, *p, *q, **xor, c;
2935     int xnum, multi, vtype, hassep = 0, words = 0;
2936 
2937     while (args && args[0] && args[1] &&
2938            args[0][0] == '-' &&
2939            (args[0][1] == 's' || args[0][1] == 'S' || args[0][1] == 'w') &&
2940            !args[0][2]) {
2941 
2942         if (args[0][1] == 's') {
2943             hassep = 1;
2944             sep = args[1][0];
2945             args += 2;
2946         } else if (args[0][1] == 'S') {
2947             asep = args[1][0];
2948             args += 2;
2949         } else {
2950             words = 1;
2951             args++;
2952         }
2953     }
2954     if (!args[0] || !args[1]) {
2955 	zwarnnam(nam, "not enough arguments");
2956 	return NULL;
2957     }
2958     descr = *args++;
2959 
2960     ret = (Cvdef) zalloc(sizeof(*ret));
2961     ret->descr = ztrdup(descr);
2962     ret->hassep = hassep;
2963     ret->sep = sep;
2964     ret->argsep = asep;
2965     ret->next = NULL;
2966     ret->vals = NULL;
2967     ret->defs = zarrdup(oargs);
2968     ret->ndefs = arrlen(oargs);
2969     ret->lastt = time(0);
2970     ret->words = words;
2971 
2972     for (valp = &(ret->vals); *args; args++) {
2973 	int bs = 0;
2974 	p = dupstring(*args);
2975 	xnum = 0;
2976 
2977 	/* xor list? */
2978 	if (*p == '(') {
2979 	    LinkList list = newlinklist();
2980 	    LinkNode node;
2981 	    char **xp, sav;
2982 
2983 	    while (*p && *p != ')') {
2984 		for (p++; inblank(*p); p++);
2985 
2986 		if (*p == ')')
2987 		    break;
2988 		for (q = p++; *p && *p != ')' && !inblank(*p); p++);
2989 
2990 		if (!*p)
2991 		    break;
2992 
2993 		sav = *p;
2994 		*p = '\0';
2995 		addlinknode(list, dupstring(q));
2996 		xnum++;
2997 		*p = sav;
2998 	    }
2999 	    if (*p != ')') {
3000 		freecvdef(ret);
3001 		zwarnnam(nam, "invalid argument: %s", *args);
3002 		return NULL;
3003 	    }
3004 	    xor = (char **) zalloc((xnum + 2) * sizeof(char *));
3005 	    for (node = firstnode(list), xp = xor; node; incnode(node), xp++)
3006 		*xp = ztrdup((char *) getdata(node));
3007 	    xp[0] = xp[1] = NULL;
3008 
3009 	    p++;
3010 	} else
3011 	    xor = NULL;
3012 
3013 	/* More than once allowed? */
3014 	if ((multi = (*p == '*')))
3015 	    p++;
3016 
3017 	/* Skip option name. */
3018 
3019 	for (name = p; *p && *p != ':' && *p != '['; p++)
3020 	    if (*p == '\\' && p[1])
3021 		p++, bs = 1;
3022 
3023 	if (hassep && !sep && name + bs + 1 < p) {
3024 	    freecvdef(ret);
3025 	    if (xor) freearray(xor);
3026 	    zwarnnam(nam, "no multi-letter values with empty separator allowed");
3027 	    return NULL;
3028 	}
3029 	/* Optional description? */
3030 
3031 	if ((c = *p) == '[') {
3032 	    *p = '\0';
3033 	    for (descr = ++p; *p && *p != ']'; p++)
3034 		if (*p == '\\' && p[1])
3035 		    p++;
3036 
3037 	    if (!*p) {
3038 		freecvdef(ret);
3039 		if (xor) freearray(xor);
3040 		zwarnnam(nam, "invalid value definition: %s", *args);
3041 		return NULL;
3042 	    }
3043 	    *p++ = '\0';
3044 	    c = *p;
3045 	} else {
3046 	    *p = '\0';
3047 	    descr = NULL;
3048 	}
3049 	if (c && c != ':') {
3050 	    freecvdef(ret);
3051 	    if (xor) freearray(xor);
3052 	    zwarnnam(nam, "invalid value definition: %s", *args);
3053 	    return NULL;
3054 	}
3055 	/* Get argument? */
3056 
3057 	if (c == ':') {
3058 	    if (hassep && !sep) {
3059 		freecvdef(ret);
3060 		if (xor) freearray(xor);
3061 		zwarnnam(nam, "no value with argument with empty separator allowed");
3062 		return NULL;
3063 	    }
3064 	    if (*++p == ':') {
3065 		p++;
3066 		vtype = CVV_OPT;
3067 	    } else
3068 		vtype = CVV_ARG;
3069 	    arg = parse_caarg(0, 0, 0, 0, name, &p, NULL);
3070 	} else {
3071 	    vtype = CVV_NOARG;
3072 	    arg = NULL;
3073 	}
3074 	if (!multi) {
3075 	    if (!xor) {
3076 		xor = (char **) zalloc(2 * sizeof(char *));
3077 		xor[1] = NULL;
3078 	    }
3079 	    xor[xnum] = ztrdup(name);
3080 	}
3081 	*valp = val = (Cvval) zalloc(sizeof(*val));
3082 	valp = &((*valp)->next);
3083 
3084 	val->next = NULL;
3085 	val->name = ztrdup(name);
3086 	val->descr = ztrdup(descr);
3087 	val->xor = xor;
3088 	val->type = vtype;
3089 	val->arg = arg;
3090     }
3091     return ret;
3092 }
3093 
3094 /* Get the definition from the cache or newly built. */
3095 
3096 static Cvdef
get_cvdef(char * nam,char ** args)3097 get_cvdef(char *nam, char **args)
3098 {
3099     Cvdef *p, *min, new;
3100     int i, na = arrlen(args);
3101 
3102     for (i = MAX_CVCACHE, p = cvdef_cache, min = NULL; *p && i--; p++)
3103 	if (*p && na == (*p)->ndefs && arrcmp(args, (*p)->defs)) {
3104 	    (*p)->lastt = time(0);
3105 
3106 	    return *p;
3107 	} else if (!min || !*p || (*p)->lastt < (*min)->lastt)
3108 	    min = p;
3109     if (i > 0)
3110 	min = p;
3111     if ((new = parse_cvdef(nam, args))) {
3112 	freecvdef(*min);
3113 	*min = new;
3114     }
3115     return new;
3116 }
3117 
3118 /* Get the definition for a value. */
3119 
3120 static Cvval
cv_get_val(Cvdef d,char * name)3121 cv_get_val(Cvdef d, char *name)
3122 {
3123     Cvval p;
3124 
3125     for (p = d->vals; p; p = p->next)
3126 	if (!strcmp(name, p->name))
3127 	    return p;
3128 
3129     return NULL;
3130 }
3131 
3132 static Cvval
cv_quote_get_val(Cvdef d,char * name)3133 cv_quote_get_val(Cvdef d, char *name)
3134 {
3135     int ne;
3136 
3137     /* remove quotes */
3138     name = dupstring(name);
3139     ne = noerrs;
3140     noerrs = 2;
3141     parse_subst_string(name);
3142     noerrs = ne;
3143     remnulargs(name);
3144     untokenize(name);
3145 
3146     return cv_get_val(d, name);
3147 }
3148 
3149 /* Handle a xor list. */
3150 
3151 static void
cv_inactive(Cvdef d,char ** xor)3152 cv_inactive(Cvdef d, char **xor)
3153 {
3154     if (xor) {
3155 	Cvval val;
3156 
3157 	for (; *xor; xor++)
3158 	    if ((val = cv_get_val(d, *xor)))
3159 		val->active = 0;
3160     }
3161 }
3162 
3163 /* Parse state. */
3164 
3165 struct cvstate {
3166     Cvdef d;
3167     Caarg def;
3168     Cvval val;
3169     LinkList vals;
3170 };
3171 
3172 static struct cvstate cv_laststate;
3173 static int cv_parsed = 0, cv_alloced = 0;
3174 
3175 /* Get the next value in the string.  Return it's definition and update the
3176  * sp pointer to point to the end of the value (plus argument, if any).
3177  * If there is no next value, the string pointer is set to null.  In any
3178  * case ap will point to the beginning of the argument or will be a null
3179  * pointer if there is no argument.
3180  */
3181 
3182 static Cvval
cv_next(Cvdef d,char ** sp,char ** ap)3183 cv_next(Cvdef d, char **sp, char **ap)
3184 {
3185     Cvval r = NULL;
3186     char *s = *sp;
3187 
3188     if (!*s) {
3189         *sp = *ap = NULL;
3190 
3191         return NULL;
3192     }
3193     if ((d->hassep && !d->sep) || !d->argsep) {
3194         char sav, ec, *v = s, *os;
3195 
3196         ec = ((d->hassep && d->sep) ? d->sep : d->argsep);
3197 
3198         do {
3199             sav = *++s;
3200             *s = '\0';
3201             if ((r = cv_quote_get_val(d, v))) {
3202                 *s = sav;
3203 
3204                 break;
3205             }
3206             *s = sav;
3207         } while (*s && *s != ec);
3208 
3209         os = s;
3210 
3211         if (d->hassep && d->sep) {
3212             if ((s = strchr(s, d->sep)))
3213                 *sp = s + 1;
3214             else
3215                 *sp = NULL;
3216         } else
3217             *sp = s;
3218         if (d->argsep && *os == d->argsep) {
3219             *ap = os + 1;
3220             *sp = NULL;
3221         } else if (r && r->type != CVV_NOARG)
3222             *ap = os;
3223         else
3224             *ap = NULL;
3225 
3226         return r;
3227 
3228     } else if (d->hassep) {
3229         char *ns = strchr(s, d->sep), *as = 0, *sap, sav = 0;
3230         int skip = 0;
3231 
3232         if (d->argsep && (as = strchr(s, d->argsep)) && (!ns || as <= ns)) {
3233             *ap = as + 1;
3234             ns = strchr(as + 1, d->sep);
3235             skip = 1;
3236             sap = as;
3237         } else {
3238             *ap = NULL;
3239             sap = ns;
3240         }
3241         if (sap) {
3242             sav = *sap;
3243             *sap = '\0';
3244         }
3245         if ((!(r = cv_quote_get_val(d, s)) || r->type == CVV_NOARG) && skip)
3246             ns = as;
3247 
3248         if (sap)
3249             *sap = sav;
3250 
3251         *sp = ((!ns || (ns == as && r && r->type != CVV_NOARG)) ? NULL : ns + 1);
3252 
3253         return r;
3254     } else {
3255         char *as = strchr(s, d->argsep), *sap, sav = 0;
3256 
3257         *sp = NULL;
3258 
3259         if (as) {
3260             *ap = as + 1;
3261             sap = as;
3262             sav = *as;
3263             *sap = '\0';
3264         } else
3265             *ap = sap = NULL;
3266 
3267         r = cv_quote_get_val(d, s);
3268 
3269         if (sap)
3270             *sap = sav;
3271 
3272         return r;
3273     }
3274 }
3275 
3276 /* Parse the current word. */
3277 
3278 static void
cv_parse_word(Cvdef d)3279 cv_parse_word(Cvdef d)
3280 {
3281     Cvval val;
3282     struct cvstate state;
3283     char *str, *arg = NULL, *pign = compprefix;
3284     int nosfx = 0;
3285 
3286     if (cv_alloced)
3287 	freelinklist(cv_laststate.vals, freestr);
3288 
3289     for (val = d->vals; val; val = val->next)
3290 	val->active = 1;
3291 
3292     state.d = d;
3293     state.def = NULL;
3294     state.val = NULL;
3295     state.vals = (LinkList) znewlinklist();
3296 
3297     cv_alloced = 1;
3298 
3299     if (d->words && compwords[0]) {
3300         int i;
3301 
3302         for (i = 1; compwords[i]; i++)
3303             if (i != compcurrent - 1)
3304                 for (str = compwords[i]; str && *str; ) {
3305                     if ((val = cv_next(d, &str, &arg))) {
3306                         zaddlinknode(state.vals, ztrdup(val->name));
3307                         if (arg) {
3308                             char sav = '\0';
3309 
3310                             if (str) {
3311                                 sav = str[-1];
3312                                 str[-1] = '\0';
3313                             }
3314                             zaddlinknode(state.vals, ztrdup(arg));
3315                             if (str)
3316                                 str[-1] = sav;
3317                         } else
3318                             zaddlinknode(state.vals, ztrdup(""));
3319 
3320                         if (i + 1 < compcurrent)
3321                             cv_inactive(d, val->xor);
3322                     }
3323                 }
3324 
3325         val = NULL;
3326         arg = NULL;
3327     }
3328     for (str = compprefix; str && *str; ) {
3329         if ((val = cv_next(d, &str, &arg))) {
3330             zaddlinknode(state.vals, ztrdup(val->name));
3331             if (arg) {
3332                 if (str) {
3333                     char sav = str[-1];
3334 
3335                     str[-1] = '\0';
3336                     zaddlinknode(state.vals, ztrdup(arg));
3337                     str[-1] = sav;
3338                 } else {
3339                     zaddlinknode(state.vals, tricat(arg, compsuffix, ""));
3340                     nosfx = 1;
3341                 }
3342             } else
3343                 zaddlinknode(state.vals, ztrdup(""));
3344 
3345             cv_inactive(d, val->xor);
3346 
3347             if (str)
3348                 pign = str;
3349             else
3350                 val->active = 1;
3351         }
3352     }
3353     state.val = val;
3354     if (val && arg && !str)
3355         state.def = val->arg;
3356 
3357     if (!nosfx && d->hassep) {
3358         int ign = 0;
3359         char *more = NULL;
3360 
3361         ignore_prefix(pign - compprefix);
3362 
3363         if (!d->sep && (!val || val->type == CVV_NOARG)) {
3364             ign = strlen(compsuffix);
3365             more = compsuffix;
3366         } else {
3367             if (d->sep) {
3368                 char *ns = strchr(compsuffix, d->sep), *as;
3369 
3370                 if (d->argsep && (as = strchr(compsuffix, d->argsep)) &&
3371                     (!ns || as <= ns)) {
3372                     ign = strlen(as);
3373                 } else
3374                     ign = (ns ? strlen(ns) : 0);
3375 
3376                 more = (ns ? ns + 1 : NULL);
3377             } else if (d->argsep) {
3378                 char *as;
3379 
3380                 if ((as = strchr(compsuffix, d->argsep)))
3381                     ign = strlen(as);
3382             }
3383         }
3384         more = dupstring(more);
3385 
3386         if (ign)
3387             ignore_suffix(ign);
3388 
3389         while (more && *more) {
3390             if ((val = cv_next(d, &more, &arg))) {
3391                 zaddlinknode(state.vals, ztrdup(val->name));
3392                 if (arg) {
3393                     if (more) {
3394                         char sav = more[-1];
3395 
3396                         more[-1] = '\0';
3397                         zaddlinknode(state.vals, ztrdup(arg));
3398                         more[-1] = sav;
3399                     } else {
3400                         zaddlinknode(state.vals, tricat(arg, compsuffix, ""));
3401                         nosfx = 1;
3402                     }
3403                 } else
3404                     zaddlinknode(state.vals, ztrdup(""));
3405 
3406                 cv_inactive(d, val->xor);
3407             }
3408         }
3409     } else if (arg)
3410         ignore_prefix(arg - compprefix);
3411     else
3412         ignore_prefix(pign - compprefix);
3413 
3414     memcpy(&cv_laststate, &state, sizeof(state));
3415 }
3416 
3417 static int
bin_compvalues(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))3418 bin_compvalues(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
3419 {
3420     int min, max, n;
3421 
3422     if (incompfunc != 1) {
3423 	zwarnnam(nam, "can only be called from completion function");
3424 	return 1;
3425     }
3426     if (args[0][0] != '-' || !args[0][1] || args[0][2]) {
3427 	zwarnnam(nam, "invalid argument: %s", args[0]);
3428 	return 1;
3429     }
3430     if (args[0][1] != 'i' && !cv_parsed) {
3431 	zwarnnam(nam, "no parsed state");
3432 	return 1;
3433     }
3434     switch (args[0][1]) {
3435     case 'i': min = 2; max = -1; break;
3436     case 'D': min = 2; max =  2; break;
3437     case 'C': min = 1; max =  1; break;
3438     case 'V': min = 3; max =  3; break;
3439     case 's': min = 1; max =  1; break;
3440     case 'S': min = 1; max =  1; break;
3441     case 'd': min = 1; max =  1; break;
3442     case 'L': min = 3; max =  4; break;
3443     case 'v': min = 1; max =  1; break;
3444     default:
3445 	zwarnnam(nam, "invalid option: %s", args[0]);
3446 	return 1;
3447     }
3448     n = arrlen(args) - 1;
3449     if (n < min) {
3450 	zwarnnam(nam, "not enough arguments");
3451 	return 1;
3452     } else if (max >= 0 && n > max) {
3453 	zwarnnam(nam, "too many arguments");
3454 	return 1;
3455     }
3456     switch (args[0][1]) {
3457     case 'i':
3458         /* This initialises the internal data structures.  The arguments are
3459          * just the arguments that were given to _values itself. */
3460 	{
3461 	    Cvdef def = get_cvdef(nam, args + 1);
3462 	    int cvp = cv_parsed;
3463 
3464 	    cv_parsed = 0;
3465 
3466 	    if (!def)
3467 		return 1;
3468 
3469 	    cv_parsed = cvp;
3470 	    cv_parse_word(def);
3471 	    cv_parsed = 1;
3472 
3473 	    return 0;
3474 	}
3475 
3476     case 'D':
3477         /* This returns the description and action to use if we are at
3478          * a place where some action has to be used at all.  In that case
3479          * zero is returned and non-zero otherwise. */
3480 	{
3481 	    Caarg arg = cv_laststate.def;
3482 
3483 	    if (arg) {
3484 		setsparam(args[1], ztrdup(arg->descr));
3485 		setsparam(args[2], ztrdup(arg->action));
3486 
3487 		return 0;
3488 	    }
3489 	    return 1;
3490 	}
3491     case 'C':
3492         /* This returns the sub-context (i.e.: the tag) to use when executing
3493          * an action. */
3494 	{
3495 	    Caarg arg = cv_laststate.def;
3496 
3497 	    if (arg) {
3498 		setsparam(args[1], ztrdup(arg->opt));
3499 
3500 		return 0;
3501 	    }
3502 	    return 1;
3503 	}
3504     case 'V':
3505         /* This is what -O is for comparguments: it returns (in three arrays)
3506          * the values for values without arguments, with arguments and with
3507          * optional arguments (so that we can get the auto-suffixes right).
3508          * As for comparguments, the strings returned are usable for _describe. */
3509 	{
3510 	    LinkList noarg = newlinklist();
3511 	    LinkList arg = newlinklist();
3512 	    LinkList opt = newlinklist(), l;
3513 	    Cvval p;
3514 	    char *str;
3515 
3516 	    for (p = cv_laststate.d->vals; p; p = p->next) {
3517 		if (p->active) {
3518 		    switch (p->type) {
3519 		    case CVV_NOARG: l = noarg; break;
3520 		    case CVV_ARG:   l = arg;   break;
3521 		    default:        l = opt;   break;
3522 		    }
3523 		    if (p->descr) {
3524 			int len = strlen(p->name) + strlen(p->descr) + 2;
3525 
3526 			str = (char *) zhalloc(len);
3527 			strcpy(str, p->name);
3528 			strcat(str, ":");
3529 			strcat(str, p->descr);
3530 		    } else
3531 			str = p->name;
3532 		    addlinknode(l, str);
3533 		}
3534 	    }
3535 	    set_list_array(args[1], noarg);
3536 	    set_list_array(args[2], arg);
3537 	    set_list_array(args[3], opt);
3538 
3539 	    return 0;
3540 	}
3541     case 's':
3542         /* This returns the value separator, if any, and sets the return
3543          * value to say if there is such a separator. */
3544 	if (cv_laststate.d->hassep) {
3545 	    char tmp[2];
3546 
3547 	    tmp[0] = cv_laststate.d->sep;
3548 	    tmp[1] = '\0';
3549 	    setsparam(args[1], ztrdup(tmp));
3550 
3551 	    return 0;
3552 	}
3553 	return 1;
3554     case 'S':
3555         /* Like -s, but for the separator between values and their arguments. */
3556 	{
3557 	    char tmp[2];
3558 
3559 	    tmp[0] = cv_laststate.d->argsep;
3560 	    tmp[1] = '\0';
3561 	    setsparam(args[1], ztrdup(tmp));
3562 	}
3563 	return 0;
3564     case 'd':
3565         /* This returns the description string (first argument to _values)
3566          * which is passed down to _describe. */
3567 	setsparam(args[1], ztrdup(cv_laststate.d->descr));
3568 	return 0;
3569     case 'L':
3570         /* Almost the same as for comparguments.  This gets a value name
3571          * and returns the description and action of its first argument, if
3572          * any.  The rest (prefix matching) is in _values.  Return non-zero
3573          * if there is no such option. */
3574 	{
3575 	    Cvval val = cv_get_val(cv_laststate.d, args[1]);
3576 
3577 	    if (val && val->arg) {
3578 		setsparam(args[2], ztrdup(val->arg->descr));
3579 		setsparam(args[3], ztrdup(val->arg->action));
3580 
3581 		if (args[4])
3582 		    setsparam(args[4], ztrdup(val->name));
3583 
3584 		return 0;
3585 	    }
3586 	    return 1;
3587 	}
3588     case 'v':
3589         /* Again, as for comparguments.  This returns the values and their
3590          * arguments as an array which will be stored in val_args in _values. */
3591 	if (cv_laststate.vals) {
3592 	    char **ret;
3593 
3594 	    ret = zlinklist2array(cv_laststate.vals);
3595 	    sethparam(args[1], ret);
3596 
3597 	    return 0;
3598 	}
3599 	return 1;
3600     }
3601     return 1;
3602 }
3603 
3604 static char *
comp_quote(char * str,int prefix)3605 comp_quote(char *str, int prefix)
3606 {
3607     int x;
3608     char *ret;
3609 
3610     if ((x = (prefix && *str == '=')))
3611 	*str = 'x';
3612 
3613     ret = quotestring(str, *compqstack);
3614 
3615     if (x)
3616 	*str = *ret = '=';
3617 
3618     return ret;
3619 }
3620 
3621 static int
bin_compquote(char * nam,char ** args,Options ops,UNUSED (int func))3622 bin_compquote(char *nam, char **args, Options ops, UNUSED(int func))
3623 {
3624     char *name;
3625     struct value vbuf;
3626     Value v;
3627 
3628     if (incompfunc != 1) {
3629 	zwarnnam(nam, "can only be called from completion function");
3630 	return 1;
3631     }
3632     /* Anything to do? */
3633 
3634     if (!compqstack || !*compqstack)
3635 	return 0;
3636 
3637     /* For all parameters given... */
3638 
3639     while ((name = *args++)) {
3640 	name = dupstring(name);
3641 	queue_signals();
3642 	if ((v = getvalue(&vbuf, &name, 0))) {
3643 	    switch (PM_TYPE(v->pm->node.flags)) {
3644 	    case PM_SCALAR:
3645 		setstrvalue(v, ztrdup(comp_quote(getstrvalue(v),
3646 						 OPT_ISSET(ops,'p'))));
3647 		break;
3648 	    case PM_ARRAY:
3649 		{
3650 		    char **val = v->pm->gsu.a->getfn(v->pm);
3651 		    char **new = (char **) zalloc((arrlen(val) + 1) *
3652 						  sizeof(char *));
3653 		    char **p = new;
3654 
3655 		    for (; *val; val++, p++)
3656 			*p = ztrdup(comp_quote(*val, OPT_ISSET(ops,'p')));
3657 		    *p = NULL;
3658 
3659 		    setarrvalue(v, new);
3660 		}
3661 		break;
3662 	    default:
3663 		zwarnnam(nam, "invalid parameter type: %s", args[-1]);
3664 	    }
3665 	} else
3666 	    zwarnnam(nam, "unknown parameter: %s", args[-1]);
3667 	unqueue_signals();
3668     }
3669     return 0;
3670 }
3671 
3672 /* Tags stuff. */
3673 
3674 typedef struct ctags *Ctags;
3675 typedef struct ctset *Ctset;
3676 
3677 /* A bunch of tag sets. */
3678 
3679 struct ctags {
3680     char **all;			/* all tags offered */
3681     char *context;		/* the current context */
3682     int init;			/* not yet used */
3683     Ctset sets;			/* the tag sets */
3684 };
3685 
3686 /* A tag set. */
3687 
3688 struct ctset {
3689     Ctset next;
3690     char **tags;		/* the tags */
3691     char *tag;			/* last tag checked for -A */
3692     char **ptr;			/* ptr into tags for -A */
3693 };
3694 
3695 /* Array of tag-set infos. Index is the locallevel. */
3696 
3697 #define MAX_TAGS 256
3698 static Ctags comptags[MAX_TAGS];
3699 
3700 /* locallevel at last comptags -i */
3701 
3702 static int lasttaglevel;
3703 
3704 static void
freectset(Ctset s)3705 freectset(Ctset s)
3706 {
3707     Ctset n;
3708 
3709     while (s) {
3710 	n = s->next;
3711 
3712 	if (s->tags)
3713 	    freearray(s->tags);
3714 	zsfree(s->tag);
3715 	zfree(s, sizeof(*s));
3716 
3717 	s = n;
3718     }
3719 }
3720 
3721 static void
freectags(Ctags t)3722 freectags(Ctags t)
3723 {
3724     if (t) {
3725 	if (t->all)
3726 	    freearray(t->all);
3727 	zsfree(t->context);
3728 	freectset(t->sets);
3729 	zfree(t, sizeof(*t));
3730     }
3731 }
3732 
3733 /* Set the tags for the current local level. */
3734 
3735 static void
settags(int level,char ** tags)3736 settags(int level, char **tags)
3737 {
3738     Ctags t;
3739 
3740     if (comptags[level])
3741 	freectags(comptags[level]);
3742 
3743     comptags[level] = t = (Ctags) zalloc(sizeof(*t));
3744 
3745     t->all = zarrdup(tags + 1);
3746     t->context = ztrdup(*tags);
3747     t->sets = NULL;
3748     t->init = 1;
3749 }
3750 
3751 /* Check if an array contains a string. */
3752 
3753 /**/
3754 static int
arrcontains(char ** a,char * s,int colon)3755 arrcontains(char **a, char *s, int colon)
3756 {
3757     char *p, *q;
3758 
3759     while (*a) {
3760 	if (colon) {
3761 	    for (p = s, q = *a++; *p && *q && *p != ':' && *q != ':'; p++, q++)
3762 		if (*p != *q)
3763 		    break;
3764 	    if ((!*p || *p == ':') && (!*q || *q == ':'))
3765 		return 1;
3766 	} else if (!strcmp(*a++, s))
3767 	    return 1;
3768     }
3769     return 0;
3770 }
3771 
3772 static int
bin_comptags(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))3773 bin_comptags(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
3774 {
3775     int min, max, n, level;
3776 
3777     if (incompfunc != 1) {
3778 	zwarnnam(nam, "can only be called from completion function");
3779 	return 1;
3780     }
3781     if (args[0][0] != '-' || !args[0][1] ||
3782 	(args[0][2] && (args[0][2] != '-' || args[0][3]))) {
3783 	zwarnnam(nam, "invalid argument: %s", args[0]);
3784 	return 1;
3785     }
3786     level = locallevel - (args[0][2] ? 1 : 0);
3787     if (level >= MAX_TAGS) {
3788 	zwarnnam(nam, "nesting level too deep");
3789 	return 1;
3790     }
3791     if (args[0][1] != 'i' && args[0][1] != 'I' && !comptags[level]) {
3792 	zwarnnam(nam, "no tags registered");
3793 	return 1;
3794     }
3795     switch (args[0][1]) {
3796     case 'i': min = 2; max = -1; break;
3797     case 'C': min = 1; max =  1; break;
3798     case 'T': min = 0; max =  0; break;
3799     case 'N': min = 0; max =  0; break;
3800     case 'R': min = 1; max =  1; break;
3801     case 'S': min = 1; max =  1; break;
3802     case 'A': min = 2; max =  3; break;
3803     default:
3804 	zwarnnam(nam, "invalid option: %s", args[0]);
3805 	return 1;
3806     }
3807     n = arrlen(args) - 1;
3808     if (n < min) {
3809 	zwarnnam(nam, "not enough arguments");
3810 	return 1;
3811     } else if (max >= 0 && n > max) {
3812 	zwarnnam(nam, "too many arguments");
3813 	return 1;
3814     }
3815     switch (args[0][1]) {
3816     case 'i':
3817 	settags(level, args + 1);
3818 	lasttaglevel = level;
3819 	break;
3820     case 'C':
3821 	setsparam(args[1], ztrdup(comptags[level]->context));
3822 	break;
3823     case 'T':
3824 	return !comptags[level]->sets;
3825     case 'N':
3826 	{
3827 	    Ctset s;
3828 
3829 	    if (comptags[level]->init)
3830 		comptags[level]->init = 0;
3831 	    else if ((s = comptags[level]->sets)) {
3832 		comptags[level]->sets = s->next;
3833 		s->next = NULL;
3834 		freectset(s);
3835 	    }
3836 	    return !comptags[level]->sets;
3837 	}
3838     case 'R':
3839 	{
3840 	    Ctset s;
3841 
3842 	    return !((s = comptags[level]->sets) &&
3843 		     arrcontains(s->tags, args[1], 1));
3844 	}
3845     case 'A':
3846 	{
3847 	    Ctset s;
3848 
3849 	    if (comptags[level] && (s = comptags[level]->sets)) {
3850 		char **q, *v = NULL;
3851 		int l = strlen(args[1]);
3852 
3853 		if (!s->tag || strcmp(s->tag, args[1])) {
3854 		    zsfree(s->tag);
3855 		    s->tag = ztrdup(args[1]);
3856 		    s->ptr = s->tags;
3857 		}
3858 		for (q = s->ptr; *q; q++) {
3859 		    if (strpfx(args[1], *q)) {
3860 			if (!(*q)[l]) {
3861 			    v = *q;
3862 			    break;
3863 			} else if ((*q)[l] == ':') {
3864 			    v = (*q) + l + 1;
3865 			    break;
3866 			}
3867 		    }
3868 		}
3869 		if (!v) {
3870 		    zsfree(s->tag);
3871 		    s->tag = NULL;
3872 		    return 1;
3873 		}
3874 		s->ptr = q + 1;
3875 		setsparam(args[2], ztrdup(*v == '-' ? dyncat(args[1], v) : v));
3876 		if (args[3]) {
3877 		    char *r = dupstring(*q), *p;
3878 
3879 		    for (p = r + (v - *q); *p && *p != ':'; p++);
3880 		    *p = '\0';
3881 
3882 		    setsparam(args[3], ztrdup(r));
3883 		}
3884 		return 0;
3885 	    }
3886 	    return 1;
3887 	}
3888     case 'S':
3889 	if (comptags[level]->sets) {
3890 	    char **ret;
3891 
3892 	    ret = zarrdup(comptags[level]->sets->tags);
3893 	    setaparam(args[1], ret);
3894 	} else
3895 	    return 1;
3896 
3897 	break;
3898     }
3899     return 0;
3900 }
3901 
3902 static int
bin_comptry(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))3903 bin_comptry(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
3904 {
3905     if (incompfunc != 1) {
3906 	zwarnnam(nam, "can only be called from completion function");
3907 	return 1;
3908     }
3909     if (!lasttaglevel || !comptags[lasttaglevel]) {
3910 	zwarnnam(nam, "no tags registered");
3911 	return 1;
3912     }
3913     if (*args) {
3914 	if (!strcmp(*args, "-m")) {
3915 	    char *s, *p, *q, *c, **all = comptags[lasttaglevel]->all;
3916 	    LinkList list = newlinklist();
3917 	    int num = 0;
3918 	    Ctset set;
3919 
3920 	    while ((s = *++args)) {
3921 		while (*s) {
3922 		    while (*s && iblank(*s))
3923 			s++;
3924 		    for (p = q = s, c = NULL; *s && !inblank(*s); s++) {
3925 			if (!c && *s == ':')
3926 			    c = p;
3927 			if (*s == '\\' && s[1])
3928 			    s++;
3929 			*p++ = *s;
3930 		    }
3931 		    if (*s)
3932 			s++;
3933 		    *p = '\0';
3934 		    if (*q) {
3935 			char *qq, *qqq;
3936 
3937 			queue_signals();
3938 
3939 			if (c)
3940 			    *c = '\0';
3941 
3942 			qqq = qq = dupstring(q);
3943 			while (*qqq) {
3944 			    if (*qqq == '\\' && qqq[1])
3945 				qqq++;
3946 			    else if (*qqq == '{')
3947 				*qqq = Inbrace;
3948 			    else if (*qqq == '}')
3949 				*qqq = Outbrace;
3950 			    else if (*qqq == ',')
3951 				*qqq = Comma;
3952 			    qqq++;
3953 			}
3954 			tokenize(qq);
3955 			if (haswilds(qq) || hasbraces(qq)) {
3956 			    Patprog prog;
3957 			    LinkNode bnode, node;
3958 			    LinkList blist = newlinklist();
3959 
3960 			    addlinknode(blist, qq);
3961 			    for (bnode = firstnode(blist); bnode; incnode(bnode))
3962 				while (hasbraces(getdata(bnode)))
3963 				    xpandbraces(blist, &bnode);
3964 
3965 			    for (bnode = firstnode(blist); bnode; incnode(bnode)) {
3966 				qq = (char *) getdata(bnode);
3967 				if ((prog = patcompile(qq, PAT_STATIC, NULL))) {
3968 				    char **a, *n;
3969 				    int l = (c ? strlen(c + 1) + 2 : 1), al;
3970 
3971 				    for (a = all; *a; a++) {
3972 					for (node = firstnode(list); node;
3973 					     incnode(node)) {
3974 					    char *as, *ls;
3975 
3976 					    for (as = *a, ls = (char *) getdata(node);
3977 						 *as && *ls && *ls != ':'; as++, ls++)
3978 						if (*as != *ls)
3979 						    break;
3980 					    if (!*as && (!*ls || *ls == ':'))
3981 						break;
3982 					}
3983 					if (node)
3984 					    continue;
3985 					if (pattry(prog, *a)) {
3986 					    n = (char *) zhalloc((al = strlen(*a)) + l);
3987 					    strcpy(n, *a);
3988 					    if (c) {
3989 						n[al] = ':';
3990 						strcpy(n + al + 1, c + 1);
3991 					    }
3992 					    addlinknode(list, n);
3993 					    num++;
3994 					}
3995 				    }
3996 				}
3997 			    }
3998 			} else if (arrcontains(all, q, 0)) {
3999 			    for (set = comptags[lasttaglevel]->sets; set;
4000 				 set = set->next)
4001 				if (arrcontains(set->tags, q, 0))
4002 				    break;
4003 			    if (!set) {
4004 				addlinknode(list, q);
4005 				num++;
4006 			    }
4007 			}
4008 			if (c)
4009 			    *c = ':';
4010 
4011 			unqueue_signals();
4012 		    }
4013 		}
4014 		if (num) {
4015 		    Ctset l;
4016 
4017 		    set = (Ctset) zalloc(sizeof(*set));
4018 
4019 		    set->tags = zlinklist2array(list);
4020 		    set->next = NULL;
4021 		    set->ptr = NULL;
4022 		    set->tag = NULL;
4023 
4024 		    if ((l = comptags[lasttaglevel]->sets)) {
4025 			while (l->next)
4026 			    l = l->next;
4027 
4028 			l->next = set;
4029 		    } else
4030 			comptags[lasttaglevel]->sets = set;
4031 		}
4032 	    }
4033 	} else {
4034 	    char **p, **q, **all;
4035 	    int sep = 0;
4036 
4037 	    if ((sep = !strcmp(*args, "-s")))
4038 		args++;
4039 
4040 	    for (p = q = args, all = comptags[lasttaglevel]->all; *p; p++)
4041 		if (arrcontains(all, *p, 1)) {
4042 		    Ctset s;
4043 
4044 		    for (s = comptags[lasttaglevel]->sets; s; s = s->next)
4045 			if (arrcontains(s->tags, *p, 0))
4046 			    break;
4047 
4048 		    if (!s)
4049 			*q++ = *p;
4050 		}
4051 	    *q = NULL;
4052 
4053 	    if (*args) {
4054 		char *dummy[2];
4055 
4056 		do {
4057 		    Ctset s = (Ctset) zalloc(sizeof(*s)), l;
4058 
4059 		    if (sep) {
4060 			dummy[0] = *args++;
4061 			dummy[1] = NULL;
4062 			s->tags = zarrdup(dummy);
4063 		    } else
4064 			s->tags = zarrdup(args);
4065 		    s->next = NULL;
4066 		    s->ptr = NULL;
4067 		    s->tag = NULL;
4068 
4069 		    if ((l = comptags[lasttaglevel]->sets)) {
4070 			while (l->next)
4071 			    l = l->next;
4072 
4073 			l->next = s;
4074 		    } else
4075 			comptags[lasttaglevel]->sets = s;
4076 		} while (sep && *args);
4077 	    }
4078 	}
4079     }
4080     return 0;
4081 }
4082 
4083 #define PATH_MAX2 (PATH_MAX * 2)
4084 
4085 /*
4086  * Return a list of files we should accept exactly, without
4087  * trying pattern matching.
4088  *
4089  * This is based on the accept-exact style, which may be
4090  * an array so is passed in via "accept".  The trial files
4091  * are input in "names".  "skipped" is passed down straight
4092  * from the file completion function:  it's got something to
4093  * do with other components in the path but it's hard to work out
4094  * quite what.
4095  *
4096  * There is one extra trick here for Cygwin.  Regardless of the style,
4097  * if the file ends in a colon it has to be a drive or a special device
4098  * file and we always accept it exactly because treating it as a pattern
4099  * won't work.
4100  */
4101 static LinkList
cfp_test_exact(LinkList names,char ** accept,char * skipped)4102 cfp_test_exact(LinkList names, char **accept, char *skipped)
4103 {
4104     char buf[PATH_MAX2 + 1], *suf, *p;
4105     int l, sl, found = 0;
4106     struct stat st;
4107     LinkNode node;
4108     LinkList ret = newlinklist(), alist = NULL;
4109 #ifdef __CYGWIN__
4110     int accept_off = 0;
4111 #endif
4112 
4113     /*
4114      * Don't do this unless completion has provided either a
4115      * prefix or suffix from the command line.
4116      */
4117     if (!(compprefix && *compprefix) && !(compsuffix && *compsuffix))
4118 	return NULL;
4119 
4120     /*
4121      * See if accept-exact is off, implicitly or explicitly.
4122      */
4123     if (!accept || !*accept ||
4124 	((!strcmp(*accept, "false") || !strcmp(*accept, "no") ||
4125 	  !strcmp(*accept, "off") || !strcmp(*accept, "0")) && !accept[1])) {
4126 #ifdef __CYGWIN__
4127 	accept_off = 1;
4128 #else
4129 	/* If not Cygwin, nothing to do here. */
4130 	return NULL;
4131 #endif
4132     }
4133 
4134     /*
4135      * See if the style is something other than just a boolean.
4136      */
4137     if (
4138 #ifdef __CYGWIN__
4139 	!accept_off &&
4140 #endif
4141 	(accept[1] ||
4142 	 (strcmp(*accept, "true") && strcmp(*accept, "yes") &&
4143 	  strcmp(*accept, "on") && strcmp(*accept, "1")))) {
4144 	Patprog prog;
4145 
4146 	alist = newlinklist();
4147 
4148 	for (; (p = *accept); accept++) {
4149 	    if (*p == '*' && !p[1]) {
4150 		alist = NULL;
4151 		break;
4152 	    }
4153 	    tokenize(p = dupstring(p));
4154 	    if ((prog = patcompile(p, 0, NULL)))
4155 		addlinknode(alist, prog);
4156 	}
4157     }
4158     /*
4159      * Assemble the bits other than the set of file names:
4160      * the other components, and the prefix and suffix.
4161      */
4162     sl = strlen(skipped) + (compprefix ? strlen(compprefix) : 0) +
4163 	(compsuffix ? strlen(compsuffix) : 0);
4164 
4165     if (sl > PATH_MAX2)
4166 	return NULL;
4167 
4168     suf = dyncat(skipped, rembslash(dyncat(compprefix ? compprefix : "",
4169 		                           compsuffix ? compsuffix : "")));
4170 
4171     for (node = firstnode(names); node; incnode(node)) {
4172 	l = strlen(p = (char *) getdata(node));
4173 	if (l + sl < PATH_MAX2) {
4174 #ifdef __CYGWIN__
4175 	    char *testbuf;
4176 #define TESTBUF testbuf
4177 #else
4178 #define TESTBUF buf
4179 #endif
4180 	    strcpy(buf, p);
4181 	    strcpy(buf + l, suf);
4182 #ifdef __CYGWIN__
4183 	    if (accept_off) {
4184 		int sl = strlen(buf);
4185 		/*
4186 		 * If accept-exact is not set, accept this only if
4187 		 * it looks like a special file such as a drive.
4188 		 * We still test if it exists.
4189 		 */
4190 		if (!sl || strchr(buf, '/') || buf[sl-1] != ':')
4191 		    continue;
4192 		if (sl == 2) {
4193 		    /*
4194 		     * Recent versions of Cygwin only recognise "c:/",
4195 		     * but not "c:", as special directories.  So
4196 		     * we have to append the slash for the purpose of
4197 		     * the test.
4198 		     */
4199 		    testbuf = zhalloc(sl + 2);
4200 		    strcpy(testbuf, buf);
4201 		    testbuf[sl] = '/';
4202 		    testbuf[sl+1] = '\0';
4203 		} else {
4204 		    /* Don't do this with stuff like PRN: */
4205 		    testbuf = buf;
4206 		}
4207 	    } else {
4208 		testbuf = buf;
4209 	    }
4210 #endif
4211 	    if (!ztat(TESTBUF, &st, 0)) {
4212 		/*
4213 		 * File exists; if accept-exact contained non-boolean
4214 		 * values it must match those, too.
4215 		 */
4216 		if (alist) {
4217 		    LinkNode anode;
4218 
4219 		    for (anode = firstnode(alist); anode; incnode(anode))
4220 			if (pattry((Patprog) getdata(anode), buf))
4221 			    break;
4222 
4223 		    if (!anode)
4224 			continue;
4225 		}
4226 		found = 1;
4227 		addlinknode(ret, dupstring(buf));
4228 	    }
4229 	}
4230     }
4231     return (found ? ret : NULL);
4232 }
4233 
4234 
4235 /*
4236  * This code constructs (from heap) and returns a string that
4237  * corresponds to a series of matches; when compiled as a pattern, at
4238  * each position it matches either the character from the string "add"
4239  * or the corresponding single-character match from the set of matchers.
4240  * To take a simple case, if add is "a" and the single matcher for the
4241  * character position matches "[0-9]", the pattern returned is "[0-9a]".
4242  * We take account of equivalences between the word and line, too.
4243  *
4244  * As there are virtually no comments in this file, I don't really
4245  * know why we're doing this, but it's to do with a matcher which
4246  * is passed as an argument to the utility compfiles -p/-P.
4247  */
4248 static char *
cfp_matcher_range(Cmatcher * ms,char * add)4249 cfp_matcher_range(Cmatcher *ms, char *add)
4250 {
4251     Cmatcher *mp, m;
4252     int len = 0, mt;
4253     char *ret = NULL, *p = NULL, *adds = add;
4254 
4255     /*
4256      * Do this twice:  once to work out the length of the
4257      * string in len, the second time to build it in ret.
4258      * This is probably worthwhile because otherwise memory
4259      * management is difficult.
4260      */
4261     for (;;) {
4262 	MB_METACHARINIT();
4263 	for (mp = ms; *add; ) {
4264 	    convchar_t addc;
4265 	    int addlen;
4266 
4267 	    addlen = MB_METACHARLENCONV(add, &addc);
4268 #ifdef MULTIBYTE_SUPPORT
4269 	    if (addc == WEOF)
4270 		addc = (wchar_t)(*add == Meta ? add[1] ^ 32 : *add);
4271 #endif
4272 
4273 	    if (!(m = *mp)) {
4274 		/*
4275 		 * No matcher, so just match the character
4276 		 * itself.
4277 		 *
4278 		 * TODO: surely this needs quoting if it's a
4279 		 * metacharacter?
4280 		 */
4281 		if (ret) {
4282 		    memcpy(p, add, addlen);
4283 		    p += addlen;
4284 		} else
4285 		    len += addlen;
4286 	    } else if (m->flags & CMF_RIGHT) {
4287 		/*
4288 		 * Right-anchored:  match anything followed
4289 		 * by the character itself.
4290 		 */
4291 		if (ret) {
4292 		    *p++ = '*';
4293 		    /* TODO: quote again? */
4294 		    memcpy(p, add, addlen);
4295 		    p += addlen;
4296 		} else
4297 		    len += addlen + 1;
4298 	    } else {
4299 		/* The usual set of matcher possibilities. */
4300 		convchar_t ind;
4301 		if (m->line->tp == CPAT_EQUIV &&
4302 		    m->word->tp == CPAT_EQUIV) {
4303 		    /*
4304 		     * Genuine equivalence.  Add the character to match
4305 		     * and the equivalent character from the word
4306 		     * pattern.
4307 		     *
4308 		     * TODO: we could be more careful here with special
4309 		     * cases as we are in the basic character class
4310 		     * code below.
4311 		     */
4312 		    if (ret) {
4313 			*p++ = '[';
4314 			memcpy(p, add, addlen);
4315 			p += addlen;
4316 		    } else
4317 			len += addlen + 1;
4318 		    if (PATMATCHRANGE(m->line->u.str, addc, &ind, &mt)) {
4319 			/*
4320 			 * Find the equivalent match for ind in the
4321 			 * word pattern.
4322 			 */
4323 			if ((ind = pattern_match_equivalence
4324 			     (m->word, ind, mt, addc)) != CHR_INVALID) {
4325 			    if (ret) {
4326 				if (imeta(ind)) {
4327 				    *p++ = Meta;
4328 				    *p++ = ind ^ 32;
4329 				} else
4330 				    *p++ = ind;
4331 			    } else
4332 				len += imeta(ind) ? 2 : 1;
4333 			}
4334 		    }
4335 		    if (ret)
4336 			*p++ = ']';
4337 		    else
4338 			len++;
4339 		} else {
4340 		    int newlen, addadd;
4341 
4342 		    switch (m->word->tp) {
4343 		    case CPAT_NCLASS:
4344 			/*
4345 			 * TODO: the old logic implies that we need to
4346 			 * match *add, i.e. it should be deleted from
4347 			 * the set of character's we're not allowed to
4348 			 * match.  That's too much like hard work for
4349 			 * now.  Indeed, in general it's impossible
4350 			 * without trickery.  Consider *add == 'A',
4351 			 * range == "[^[:upper:]]": we would have to
4352 			 * resort to something like "(A|[^[:upper:]])";
4353 			 * and in an expression like that *add may or
4354 			 * may not need backslashing.  So we're deep
4355 			 * into see-if-we-can-get-away-without
4356 			 * territory.
4357 			 */
4358 			if (ret) {
4359 			    *p++ = '[';
4360 			    *p++ = '^';
4361 			} else
4362 			    len += 2;
4363 			/*
4364 			 * Convert the compiled range string back
4365 			 * to an ordinary string.
4366 			 */
4367 			newlen =
4368 			    pattern_range_to_string(m->word->u.str, p);
4369 			DPUTS(!newlen, "empty character range");
4370 			if (ret) {
4371 			    p += newlen;
4372 			    *p++ = ']';
4373 			} else
4374 			    len += newlen + 1;
4375 			break;
4376 
4377 		    case CPAT_CCLASS:
4378 			/*
4379 			 * If there is an equivalence only on one
4380 			 * side it's not equivalent to anything.
4381 			 * Treat it as an ordinary character class.
4382 			 */
4383 		    case CPAT_EQUIV:
4384 		    case CPAT_CHAR:
4385 			if (ret)
4386 			    *p++ = '[';
4387 			else
4388 			    len++;
4389 			/*
4390 			 * We needed to add *add specially only if
4391 			 * it is not covered by the range.  This
4392 			 * is necessary for correct syntax---consider
4393 			 * if *add is ] and ] is also the first
4394 			 * character in the range.
4395 			 */
4396 			addadd = !pattern_match1(m->word, addc, &mt);
4397 			if (addadd && *add == ']') {
4398 			    if (ret)
4399 				*p++ = *add;
4400 			    else
4401 				len++;
4402 			}
4403 			if (m->word->tp == CPAT_CHAR) {
4404 			    /*
4405 			     * The matcher just matches a single
4406 			     * character, but we need to be able
4407 			     * to match *add, too, hence we do
4408 			     * this as a [...].
4409 			     */
4410 			    if (ret) {
4411 				if (imeta(m->word->u.chr)) {
4412 				    *p++ = Meta;
4413 				    *p++ = m->word->u.chr ^ 32;
4414 				} else
4415 				    *p++ = m->word->u.chr;
4416 			    } else
4417 				len += imeta(m->word->u.chr) ? 2 : 1;
4418 			} else {
4419 			    /*
4420 			     * Convert the compiled range string back
4421 			     * to an ordinary string.
4422 			     */
4423 			    newlen =
4424 				pattern_range_to_string(m->word->u.str, p);
4425 			    DPUTS(!newlen, "empty character range");
4426 			    if (ret)
4427 				p += newlen;
4428 			    else
4429 				len += newlen;
4430 			}
4431 			if (addadd && *add != ']') {
4432 			    if (ret) {
4433 				memcpy(p, add, addlen);
4434 				p += addlen;
4435 			    } else
4436 				len += addlen;
4437 			}
4438 			if (ret)
4439 			    *p++ = ']';
4440 			else
4441 			    len++;
4442 			break;
4443 
4444 		    case CPAT_ANY:
4445 			if (ret)
4446 			    *p++ = '?';
4447 			else
4448 			    len++;
4449 			break;
4450 		    }
4451 		}
4452 	    }
4453 	    add += addlen;
4454 	    mp++;
4455 	}
4456 	if (ret) {
4457 	    *p = '\0';
4458 	    return ret;
4459 	}
4460 	p = ret = zhalloc(len + 1);
4461 	add = adds;
4462     }
4463 }
4464 
4465 
4466 static char *
cfp_matcher_pats(char * matcher,char * add)4467 cfp_matcher_pats(char *matcher, char *add)
4468 {
4469     Cmatcher m = parse_cmatcher(NULL, matcher);
4470 
4471     if (m && m != pcm_err) {
4472 	char *tmp;
4473 	int al = strlen(add), zl = ztrlen(add), tl, cl;
4474 	VARARR(Cmatcher, ms, zl);	/* One Cmatcher per character */
4475 	Cmatcher *mp;
4476 	Cpattern stopp;
4477 	int stopl = 0;
4478 
4479 	/* zl >= (number of wide characters) is guaranteed */
4480 	memset(ms, 0, zl * sizeof(Cmatcher));
4481 
4482 	for (; m && *add; m = m->next) {
4483 	    stopp = NULL;
4484 	    if (!(m->flags & (CMF_LEFT|CMF_RIGHT))) {
4485 		if (m->llen == 1 && m->wlen == 1) {
4486 		    /*
4487 		     * In this loop and similar loops below we step
4488 		     * through tmp one (possibly wide) character at a
4489 		     * time.  pattern_match() compares only the first
4490 		     * character using unmeta_one() so keep in step.
4491 		     */
4492 		    for (tmp = add, tl = al, mp = ms; tl; ) {
4493 			if (pattern_match(m->line, tmp, NULL, NULL)) {
4494 			    if (*mp) {
4495 				*tmp = '\0';
4496 				al = tmp - add;
4497 				break;
4498 			    } else
4499 				*mp = m;
4500 			}
4501 			(void) unmeta_one(tmp, &cl);
4502 			tl -= cl;
4503 			tmp += cl;
4504 			mp++;
4505 		    }
4506 		} else {
4507 		    stopp = m->line;
4508 		    stopl = m->llen;
4509 		}
4510 	    } else if (m->flags & CMF_RIGHT) {
4511 		if (m->wlen < 0 && !m->llen && m->ralen == 1) {
4512 		    for (tmp = add, tl = al, mp = ms; tl; ) {
4513 			if (pattern_match(m->right, tmp, NULL, NULL)) {
4514 			    if (*mp || (tmp == add && *tmp == '.')) {
4515 				*tmp = '\0';
4516 				al = tmp - add;
4517 				break;
4518 			    } else
4519 				*mp = m;
4520 			}
4521 			(void) unmeta_one(tmp, &cl);
4522 			tl -= cl;
4523 			tmp += cl;
4524 			mp++;
4525 		    }
4526 		} else if (m->llen) {
4527 		    stopp = m->line;
4528 		    stopl = m->llen;
4529 		} else {
4530 		    stopp = m->right;
4531 		    stopl = m->ralen;
4532 		}
4533 	    } else {
4534 		if (!m->lalen)
4535 		    return "";
4536 
4537 		stopp = m->left;
4538 		stopl = m->lalen;
4539 	    }
4540 	    if (stopp)
4541 		for (tmp = add, tl = al; tl >= stopl; ) {
4542 		    if (pattern_match(stopp, tmp, NULL, NULL)) {
4543 			*tmp = '\0';
4544 			al = tmp - add;
4545 			break;
4546 		    }
4547 		    (void) unmeta_one(tmp, &cl);
4548 		    tl -= cl;
4549 		    tmp += cl;
4550 		}
4551 	}
4552 	if (*add)
4553 	    return cfp_matcher_range(ms, add);
4554     }
4555     return add;
4556 }
4557 
4558 /*
4559  * ### This function call is skipped by _approximate, so "opt" probably means "optimize".
4560  */
4561 
4562 static void
cfp_opt_pats(char ** pats,char * matcher)4563 cfp_opt_pats(char **pats, char *matcher)
4564 {
4565     char *add, **p, *q, *t, *s;
4566 
4567     if (!compprefix || !*compprefix)
4568 	return;
4569 
4570     if (comppatmatch && *comppatmatch) {
4571 	tokenize(t = rembslash(dyncat(compprefix, compsuffix)));
4572 	remnulargs(t);
4573 	if (haswilds(t))
4574 	    return;
4575     }
4576     add = (char *) zhalloc(strlen(compprefix) * 2 + 1);
4577     for (s = compprefix, t = add; *s; s++) {
4578 	if (*s != '\\' || !s[1] || s[1] == '*' || s[1] == '?' ||
4579 	    s[1] == '<' || s[1] == '>' || s[1] == '(' || s[1] == ')' ||
4580 	    s[1] == '[' || s[1] == ']' || s[1] == '|' || s[1] == '#' ||
4581 	    s[1] == '^' || s[1] == '~' || s[1] == '=') {
4582 	    if ((s == compprefix || s[-1] != '\\') &&
4583 		(*s == '*' || *s == '?' || *s == '<' || *s == '>' ||
4584 		 *s == '(' || *s == ')' || *s == '[' || *s == ']' ||
4585 		 *s == '|' || *s == '#' || *s == '^' || *s == '~' ||
4586 		 *s == '='))
4587 		*t++ = '\\';
4588 	    *t++ = *s;
4589 	}
4590     }
4591     *t = '\0';
4592     for (p = pats; *add && (q = *p); p++) {
4593 	if (*q) {
4594 	    q = dupstring(q);
4595 	    t = q + strlen(q) - 1;
4596 	    if (*t == ')') {
4597 		for (s = t--; t > q; t--)
4598 		    if (*t == ')' || *t == '|' || *t == '~' || *t == '(')
4599 			break;
4600 		if (t != q && *t == '(')
4601 		    *t = '\0';
4602 	    }
4603 	    for (; *q && *add; q++) {
4604 		if (*q == '\\' && q[1]) {
4605 		    for (s = add, q++; *s && *s != *q; s++);
4606 		    *s = '\0';
4607 		} else if (*q == '<') {
4608 		    for (s = add; *s && !idigit(*s); s++);
4609 		    *s = '\0';
4610 		} else if (*q == '[') {
4611 		    int not;
4612 		    char *x = ++q;
4613 
4614 		    if ((not = (*x == '!' || *x == '^')))
4615 			x++;
4616 		    for (; *x; x++) {
4617 			if (x[1] == '-' && x[2]) {
4618 			    char c1 = *x, c2 = x[2];
4619 
4620 			    for (s = add; *s && (*x < c1 || *x > c2); s++);
4621 			    *s = '\0';
4622 			} else {
4623 			    for (s = add; *s && *s != *x; s++);
4624 			    *s = '\0';
4625 			}
4626 		    }
4627 		} else if (*q != '?' && *q != '*' && *q != '(' && *q != ')' &&
4628 			   *q != '|' && *q != '~' && *q != '#') {
4629 		    for (s = add; *s && *s != *q; s++);
4630 		    *s = '\0';
4631 		}
4632 	    }
4633 	}
4634     }
4635     if (*add) {
4636 	if (*matcher && !(add = cfp_matcher_pats(matcher, add)))
4637 	    return;
4638 
4639 	for (p = pats; *p; p++)
4640 	    if (**p == '*')
4641 		*p = dyncat(add, *p);
4642     }
4643 }
4644 
4645 static LinkList
cfp_bld_pats(UNUSED (int dirs),LinkList names,char * skipped,char ** pats)4646 cfp_bld_pats(UNUSED(int dirs), LinkList names, char *skipped, char **pats)
4647 {
4648     LinkList ret = newlinklist();
4649     LinkNode node;
4650     int ol, sl = strlen(skipped), pl, dot;
4651     char **p, *o, *str;
4652 
4653     dot = (unset(GLOBDOTS) && compprefix && *compprefix == '.');
4654     for (node = firstnode(names); node; incnode(node)) {
4655 	ol = strlen(o = (char *) getdata(node));
4656 	for (p = pats; *p; p++) {
4657 	    pl = strlen(*p);
4658 	    str = (char *) zhalloc(ol + sl + pl + 1);
4659 	    strcpy(str, o);
4660 	    strcpy(str + ol, skipped);
4661 	    strcpy(str + ol + sl, *p);
4662 	    addlinknode(ret, str);
4663 	    if (dot && **p != '.') {
4664 		str = (char *) zhalloc(ol + sl + pl + 2);
4665 		strcpy(str, o);
4666 		strcpy(str + ol, skipped);
4667 		str[ol + sl] = '.';
4668 		strcpy(str + ol + sl + 1, *p);
4669 		addlinknode(ret, str);
4670 	    }
4671 	}
4672     }
4673     return ret;
4674 }
4675 
4676 static LinkList
cfp_add_sdirs(LinkList final,LinkList orig,char * skipped,char * sdirs,char ** fake)4677 cfp_add_sdirs(LinkList final, LinkList orig, char *skipped,
4678 	      char *sdirs, char **fake)
4679 {
4680     int add = 0;
4681 
4682     if (*sdirs && (isset(GLOBDOTS) || (compprefix && *compprefix == '.'))) {
4683 	if (!strcmp(sdirs, "yes") || !strcmp(sdirs, "true") ||
4684 	    !strcmp(sdirs, "on") || !strcmp(sdirs, "1"))
4685 	    add = 2;
4686 	else if (!strcmp(sdirs, ".."))
4687 	    add = 1;
4688     }
4689     if (add) {
4690 	LinkNode node;
4691 	char *s1 = dyncat(skipped, "..");
4692 	char *s2 = (add == 2 ? dyncat(skipped, ".") : NULL), *m;
4693 
4694 	for (node = firstnode(orig); node; incnode(node)) {
4695 	    if ((m = (char *) getdata(node))) {
4696 		addlinknode(final, dyncat(m, s1));
4697 		if (s2)
4698 		    addlinknode(final, dyncat(m, s2));
4699 	    }
4700 	}
4701     }
4702     if (fake && *fake) {
4703 	LinkNode node;
4704 	char *m, *f, *p, *t, *a, c;
4705 	int sl = strlen(skipped) + 1;
4706 	struct stat st1, st2;
4707 	Patprog pprog;
4708 
4709 	for (; (f = *fake); fake++) {
4710 	    f = dupstring(f);
4711 	    for (p = t = f; *p; p++) {
4712 		if (*p == ':')
4713 		    break;
4714 		else if (*p == '\\' && p[1] == ':') {
4715 		    /*
4716 		     * strip quoted colons here; rely
4717 		     * on tokenization to strip other backslashes
4718 		     */
4719 		    p++;
4720 		}
4721 		*t++ = *p;
4722 	    }
4723 	    if (*p) {
4724 		*t = *p++ = '\0';
4725 		if (!*p)
4726 		    continue;
4727 
4728 		queue_signals();	/* Protect PAT_STATIC */
4729 
4730 		tokenize(f);
4731 		pprog = patcompile(f, PAT_STATIC, NULL);
4732 		untokenize(f);
4733 		for (node = firstnode(orig); node; incnode(node)) {
4734 		    if ((m = (char *) getdata(node)) &&
4735 			((pprog ? pattry(pprog, m) : !strcmp(f, m)) ||
4736 			 (!stat(f, &st1) && !stat((*m ? m : "."), &st2) &&
4737 			  st1.st_dev == st2.st_dev &&
4738 			  st1.st_ino == st2.st_ino))) {
4739 			while (*p) {
4740 			    while (*p && inblank(*p))
4741 				p++;
4742 			    if (!*p)
4743 				break;
4744 			    for (f = t = p; *p; p++) {
4745 				if (inblank(*p))
4746 				    break;
4747 				else if (*p == '\\' && p[1])
4748 				    p++;
4749 				*t++ = *p;
4750 			    }
4751 			    c = *t;
4752 			    *t = '\0';
4753 			    a = (char *) zhalloc(strlen(m) + sl + strlen(f));
4754 			    strcpy(a, m);
4755 			    strcat(a, skipped);
4756 			    strcat(a, f);
4757 			    addlinknode(final, a);
4758 			    *t = c;
4759 			}
4760 		    }
4761 		}
4762 
4763 		unqueue_signals();
4764 	    }
4765 	}
4766     }
4767     return final;
4768 }
4769 
4770 static LinkList
cf_pats(int dirs,int noopt,LinkList names,char ** accept,char * skipped,char * matcher,char * sdirs,char ** fake,char ** pats)4771 cf_pats(int dirs, int noopt, LinkList names, char **accept, char *skipped,
4772 	char *matcher, char *sdirs, char **fake, char **pats)
4773 {
4774     LinkList ret;
4775     char *dpats[2];
4776 
4777     if ((ret = cfp_test_exact(names, accept, skipped)))
4778 	return cfp_add_sdirs(ret, names, skipped, sdirs, fake);
4779 
4780     if (dirs) {
4781 	dpats[0] = "*(-/)";
4782 	dpats[1] = NULL;
4783 	pats = dpats;
4784     }
4785     if (!noopt)
4786 	cfp_opt_pats(pats, matcher);
4787 
4788     return cfp_add_sdirs(cfp_bld_pats(dirs, names, skipped, pats),
4789 			 names, skipped, sdirs, fake);
4790 }
4791 
4792 /*
4793  * This function looks at device/inode pairs to determine if
4794  * a file is one we should ignore because of its relationship
4795  * to the current or parent directory.
4796  *
4797  * We don't follow symbolic links here, because typically
4798  * a user will not want an explicit link to the current or parent
4799  * directory ignored.
4800  */
4801 static void
cf_ignore(char ** names,LinkList ign,char * style,char * path)4802 cf_ignore(char **names, LinkList ign, char *style, char *path)
4803 {
4804     int pl = strlen(path), tpar, tpwd, found;
4805     struct stat nst, est, st;
4806     char *n, *c, *e;
4807 
4808     tpar = !!strstr(style, "parent");
4809     if ((tpwd = !!strstr(style, "pwd")) && lstat(pwd, &est))
4810 	tpwd = 0;
4811 
4812     if (!tpar && !tpwd)
4813 	return;
4814 
4815     for (; (n = *names); names++) {
4816 	if (!ztat(n, &nst, 1) && S_ISDIR(nst.st_mode)) {
4817 	    if (tpwd && nst.st_dev == est.st_dev && nst.st_ino == est.st_ino) {
4818 		addlinknode(ign, quotestring(n, QT_BACKSLASH));
4819 		continue;
4820 	    }
4821 	    if (tpar && !strncmp((c = dupstring(n)), path, pl)) {
4822 		found = 0;
4823 		while ((e = strrchr(c, '/')) && e > c + pl) {
4824 		    *e = '\0';
4825 		    if (!ztat(c, &st, 0) &&
4826 			st.st_dev == nst.st_dev && st.st_ino == nst.st_ino) {
4827 			found = 1;
4828 			break;
4829 		    }
4830 		}
4831 		if (found || ((e = strrchr(c, '/')) && e > c + pl &&
4832 			      !ztat(c, &st, 1) && st.st_dev == nst.st_dev &&
4833 			      st.st_ino == nst.st_ino))
4834 		    addlinknode(ign, quotestring(n, QT_BACKSLASH));
4835 	    }
4836 	}
4837     }
4838 }
4839 
4840 static LinkList
cf_remove_other(char ** names,char * pre,int * amb)4841 cf_remove_other(char **names, char *pre, int *amb)
4842 {
4843     char *p;
4844 
4845     if ((p = strchr(pre, '/'))) {
4846 	char **n;
4847 
4848 	*p = '\0';
4849 	pre = dyncat(pre, "/");
4850 	*p = '/';
4851 
4852 	for (n = names; *n; n++)
4853 	    if (strpfx(pre, *n))
4854 		break;
4855 
4856 	if (*n) {
4857 	    LinkList ret = newlinklist();
4858 
4859 	    for (; *names; names++)
4860 		if (strpfx(pre, *names))
4861 		    addlinknode(ret, dupstring(*names));
4862 
4863 	    *amb = 0;
4864 
4865 	    return ret;
4866 	} else {
4867 	    if (!(p = *names++))
4868 		*amb = 0;
4869 	    else {
4870 		char *q;
4871 
4872 		if ((q = strchr((p = dupstring(p)), '/')))
4873 		    *q = '\0';
4874 
4875                 p = dyncat(p, "/");
4876 
4877 		for (; *names; names++)
4878 		    if (!strpfx(p, *names)) {
4879 			*amb = 1;
4880 			return NULL;
4881 		    }
4882 	    }
4883 	}
4884     } else {
4885 	if (!(p = *names++))
4886 	    *amb = 0;
4887 	else
4888 	    for (; *names; names++)
4889 		if (strcmp(p, *names)) {
4890 		    *amb = 1;
4891 		    return NULL;
4892 		}
4893     }
4894     return NULL;
4895 }
4896 
4897 /*
4898  * SYNOPSIS:
4899  *     1. compfiles -p  parnam1 parnam2 skipped matcher sdirs parnam3 varargs [..varargs]
4900  *     2. compfiles -p- parnam1 parnam2 skipped matcher sdirs parnam3 varargs [..varargs]
4901  *     3. compfiles -P  parnam1 parnam2 skipped matcher sdirs parnam3
4902  *
4903  *     1. Set parnam1 to an array of patterns....
4904  *        ${(P)parnam1} is an in/out parameter.
4905  *     2. Like #1 but without calling cfp_opt_pats().  (This is only used by _approximate.)
4906  *     3. Like #1 but varargs is implicitly set to  char *varargs[2] = { "*(-/)", NULL };.
4907  *
4908  *     parnam2 has to do with the accept-exact style (see cfp_test_exact()).
4909  */
4910 
4911 static int
bin_compfiles(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))4912 bin_compfiles(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
4913 {
4914     if (incompfunc != 1) {
4915 	zwarnnam(nam, "can only be called from completion function");
4916 	return 1;
4917     }
4918     if (**args != '-') {
4919 	zwarnnam(nam, "missing option: %s", *args);
4920 	return 1;
4921     }
4922     switch (args[0][1]) {
4923     case 'p':
4924     case 'P':
4925 	if (args[0][2] && (args[0][2] != '-' || args[0][3])) {
4926 	    zwarnnam(nam, "invalid option: %s", *args);
4927 	    return 1;
4928 	} else {
4929 	    char **tmp;
4930 	    LinkList l;
4931 
4932 	    if (!args[1] || !args[2] || !args[3] || !args[4] || !args[5] ||
4933 		!args[6] || (args[0][1] == 'p' && !args[7])) {
4934 		zwarnnam(nam, "too few arguments");
4935 		return 1;
4936 	    }
4937 	    queue_signals();
4938 	    if (!(tmp = getaparam(args[1]))) {
4939 		unqueue_signals();
4940 		zwarnnam(nam, "unknown parameter: %s", args[1]);
4941 		return 0;
4942 	    }
4943 	    for (l = newlinklist(); *tmp; tmp++)
4944 		addlinknode(l, quotestring(*tmp, QT_BACKSLASH_PATTERN));
4945 	    set_list_array(args[1], cf_pats((args[0][1] == 'P'), !!args[0][2],
4946 					    l, getaparam(args[2]), args[3],
4947 					    args[4], args[5],
4948 					    getaparam(args[6]), args + 7));
4949 	    unqueue_signals();
4950 	    return 0;
4951 	}
4952     case 'i':
4953 	if (args[0][2]) {
4954 	    zwarnnam(nam, "invalid option: %s", *args);
4955 	    return 1;
4956 	} else {
4957 	    char **tmp;
4958 	    LinkList l;
4959 
4960 	    if (!args[1] || !args[2] || !args[3] || !args[4]) {
4961 		zwarnnam(nam, "too few arguments");
4962 		return 1;
4963 	    }
4964 	    if (args[5]) {
4965 		zwarnnam(nam, "too many arguments");
4966 		return 1;
4967 	    }
4968 	    queue_signals();
4969 	    tmp = getaparam(args[2]);
4970 	    l = newlinklist();
4971 	    if (tmp)
4972 		for (; *tmp; tmp++)
4973 		    addlinknode(l, *tmp);
4974 	    if (!(tmp = getaparam(args[1]))) {
4975 		unqueue_signals();
4976 		zwarnnam(nam, "unknown parameter: %s", args[1]);
4977 		return 0;
4978 	    }
4979 	    cf_ignore(tmp, l, args[3], args[4]);
4980 	    unqueue_signals();
4981 	    set_list_array(args[2], l);
4982 	    return 0;
4983 	}
4984     case 'r':
4985 	{
4986 	    char **tmp;
4987 	    LinkList l;
4988 	    int ret = 0;
4989 
4990 	    if (!args[1] || !args[2]) {
4991 		zwarnnam(nam, "too few arguments");
4992 		return 1;
4993 	    }
4994 	    if (args[3]) {
4995 		zwarnnam(nam, "too many arguments");
4996 		return 1;
4997 	    }
4998 	    queue_signals();
4999 	    if (!(tmp = getaparam(args[1]))) {
5000 		unqueue_signals();
5001 		zwarnnam(nam, "unknown parameter: %s", args[1]);
5002 		return 0;
5003 	    }
5004 	    if ((l = cf_remove_other(tmp, args[2], &ret)))
5005 		set_list_array(args[1], l);
5006 	    unqueue_signals();
5007 	    return ret;
5008 	}
5009     }
5010     zwarnnam(nam, "invalid option: %s", *args);
5011     return 1;
5012 }
5013 
5014 static int
bin_compgroups(char * nam,char ** args,UNUSED (Options ops),UNUSED (int func))5015 bin_compgroups(char *nam, char **args, UNUSED(Options ops), UNUSED(int func))
5016 {
5017     Heap oldheap;
5018     char *n;
5019 
5020     if (incompfunc != 1) {
5021 	zwarnnam(nam, "can only be called from completion function");
5022 	return 1;
5023     }
5024     SWITCHHEAPS(oldheap, compheap) {
5025 	while ((n = *args++)) {
5026 	    endcmgroup(NULL);
5027 	    begcmgroup(n, CGF_NOSORT|CGF_UNIQCON);
5028 	    endcmgroup(NULL);
5029 	    begcmgroup(n, CGF_UNIQALL);
5030 	    endcmgroup(NULL);
5031 	    begcmgroup(n, CGF_NOSORT|CGF_UNIQCON);
5032 	    endcmgroup(NULL);
5033 	    begcmgroup(n, CGF_UNIQALL);
5034 	    endcmgroup(NULL);
5035 	    begcmgroup(n, CGF_NOSORT);
5036 	    endcmgroup(NULL);
5037 	    begcmgroup(n, 0);
5038 	}
5039     } SWITCHBACKHEAPS(oldheap);
5040 
5041     return 0;
5042 }
5043 
5044 static struct builtin bintab[] = {
5045     BUILTIN("comparguments", 0, bin_comparguments, 1, -1, 0, NULL, NULL),
5046     BUILTIN("compdescribe", 0, bin_compdescribe, 3, -1, 0, NULL, NULL),
5047     BUILTIN("compfiles", 0, bin_compfiles, 1, -1, 0, NULL, NULL),
5048     BUILTIN("compgroups", 0, bin_compgroups, 1, -1, 0, NULL, NULL),
5049     BUILTIN("compquote", 0, bin_compquote, 1, -1, 0, "p", NULL),
5050     BUILTIN("comptags", 0, bin_comptags, 1, -1, 0, NULL, NULL),
5051     BUILTIN("comptry", 0, bin_comptry, 0, -1, 0, NULL, NULL),
5052     BUILTIN("compvalues", 0, bin_compvalues, 1, -1, 0, NULL, NULL)
5053 };
5054 
5055 static struct features module_features = {
5056     bintab, sizeof(bintab)/sizeof(*bintab),
5057     NULL, 0,
5058     NULL, 0,
5059     NULL, 0,
5060     0
5061 };
5062 
5063 
5064 /**/
5065 int
setup_(UNUSED (Module m))5066 setup_(UNUSED(Module m))
5067 {
5068     memset(cadef_cache, 0, sizeof(cadef_cache));
5069     memset(cvdef_cache, 0, sizeof(cvdef_cache));
5070 
5071     memset(comptags, 0, sizeof(comptags));
5072 
5073     lasttaglevel = 0;
5074 
5075     return 0;
5076 }
5077 
5078 /**/
5079 int
features_(Module m,char *** features)5080 features_(Module m, char ***features)
5081 {
5082     *features = featuresarray(m, &module_features);
5083     return 0;
5084 }
5085 
5086 /**/
5087 int
enables_(Module m,int ** enables)5088 enables_(Module m, int **enables)
5089 {
5090     return handlefeatures(m, &module_features, enables);
5091 }
5092 
5093 /**/
5094 int
boot_(UNUSED (Module m))5095 boot_(UNUSED(Module m))
5096 {
5097     return 0;
5098 }
5099 
5100 /**/
5101 int
cleanup_(Module m)5102 cleanup_(Module m)
5103 {
5104     return setfeatureenables(m, &module_features, NULL);
5105 }
5106 
5107 /**/
5108 int
finish_(UNUSED (Module m))5109 finish_(UNUSED(Module m))
5110 {
5111     int i;
5112 
5113     for (i = 0; i < MAX_CACACHE; i++)
5114 	freecadef(cadef_cache[i]);
5115     for (i = 0; i < MAX_CVCACHE; i++)
5116 	freecvdef(cvdef_cache[i]);
5117 
5118     for (i = 0; i < MAX_TAGS; i++)
5119 	freectags(comptags[i]);
5120 
5121     return 0;
5122 }
5123