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