1/*
2 * compresult.c - the complete module, completion result handling
3 *
4 * This file is part of zsh, the Z shell.
5 *
6 * Copyright (c) 1999 Sven Wischnowsky
7 * All rights reserved.
8 *
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
14 *
15 * In no event shall Sven Wischnowsky or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Sven Wischnowsky and the Zsh Development Group have been advised of
19 * the possibility of such damage.
20 *
21 * Sven Wischnowsky and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose.  The software
24 * provided hereunder is on an "as is" basis, and Sven Wischnowsky and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
27 *
28 */
29
30#include "complete.mdh"
31#include "compresult.pro"
32
33/* This counts how often the list of completions was invalidated.
34 * Can be used to detect if we have a new list.  */
35
36/**/
37mod_export int invcount;
38
39#define inststr(X) inststrlen((X),1,-1)
40
41/* This cuts the cline list before the stuff that isn't worth
42 * inserting in the line. */
43
44/**/
45static Cline
46cut_cline(Cline l)
47{
48    Cline q, p, e = NULL, maxp = NULL;
49    int sum = 0, max = 0, tmp, ls = 0, miss = 0;
50
51    /* If no match was added with matching, we don't really know
52     * which parts of the unambiguous string are worth keeping,
53     * so for now we keep everything (in the hope that this
54     * produces a string containing at least everything that was
55     * originally on the line). */
56
57    if (!hasmatched) {
58	cline_setlens(l, 0);
59	return l;
60    }
61    e = l = cp_cline(l, 0);
62
63    /* First, search the last struct for which we have something on
64     * the line. Anything before that is kept. */
65
66    for (q = NULL, p = l; p; p = p->next) {
67	if (p->orig || p->olen || !(p->flags & CLF_NEW))
68	    e = p->next;
69	if (!p->suffix && (p->wlen || p->llen || p->prefix))
70	    q = p;
71    }
72    if (!e && q && !q->orig && !q->olen && (q->flags & CLF_MISS) &&
73	(!(q->flags & CLF_MATCHED) || (!q->prefix && !q->suffix)) &&
74	(q->word ? q->wlen : q->llen) < 3) {
75	q->word = q->line = NULL;
76	q->wlen = q->llen = 0;
77    }
78    /* Then keep all structs without missing characters. */
79
80    while (e && !(e->flags & CLF_MISS))
81	e = e->next;
82
83    if (e) {
84	/* Then we see if there is another struct with missing
85	 * characters. If not, we keep the whole list. */
86
87	for (p = e->next; p && !(p->flags & CLF_MISS); p = p->next);
88
89	if (p) {
90	    for (p = e; p; p = p->next) {
91		if (!(p->flags & CLF_MISS))
92		    sum += p->max;
93		else {
94		    tmp = cline_sublen(p);
95		    if (tmp > 2 && tmp > ((p->max + p->min) >> 1))
96			sum += tmp - (p->max - tmp);
97		    else if (tmp < p->min)
98			sum -= (((p->max + p->min) >> 1) - tmp) << (tmp < 2);
99		}
100		if (sum > max) {
101		    max = sum;
102		    maxp = p;
103		}
104	    }
105	    if (max)
106		e = maxp;
107	    else {
108		int len = 0;
109
110		cline_setlens(l, 0);
111		ls = 1;
112
113		for (p = e; p; p = p->next)
114		    len += p->min;
115
116		if (len > ((minmlen << 1) / 3))
117		    goto end;
118	    }
119	    e->line = e->word = NULL;
120	    e->llen = e->wlen = e->olen = 0;
121	    e->next = NULL;
122	}
123    }
124 end:
125
126    /* Sanity check. If there are no parts with missing characters but
127     * parts with joined substrings, remove those. */
128
129    for (p = l, e = 0, tmp = 0; p; p = p->next) {
130	if (p->flags & (CLF_MISS|CLF_DIFF))
131	    miss = 1;
132	for (q = p->prefix; q; q = q->next)
133	    if (q->flags & CLF_JOIN) {
134		e = p;
135		tmp = 0;
136		break;
137	    }
138	for (q = p->suffix; q; q = q->next)
139	    if (q->flags & CLF_JOIN) {
140		e = p;
141		tmp = 1;
142		break;
143	    }
144    }
145    if (e && (!miss || cline_sublen(e) == e->min)) {
146	for (p = (tmp ? e->suffix : e->prefix);
147	     p && p->next && !(p->next->flags & CLF_JOIN); p = p->next);
148	if (p)
149	    p->next = NULL;
150    }
151    if (!ls)
152	cline_setlens(l, 0);
153
154    return l;
155}
156
157/* This builds the unambiguous string. If ins is one, it is immediately
158 * inserted into the line. Otherwise csp is used to return the relative
159 * cursor position in the string returned and posl contains all
160 * positions with missing or ambiguous characters. If ins is two, csp
161 * and posl contain real command line positions (including braces). */
162
163/**/
164static char *
165cline_str(Cline l, int ins, int *csp, LinkList posl)
166{
167    Cline s;
168    int ocs = zlemetacs, ncs, pcs, scs, opos = -1, npos;
169    int pm, pmax, pmm, pma, sm, smax, smm, sma, d, dm, mid;
170    int i, j, li = 0, cbr, padd = (ins ? wb - ocs : -ocs);
171    Brinfo brp, brs;
172
173    METACHECK();
174
175    l = cut_cline(l);
176
177    pmm = pma = smm = sma = dm = pcs = scs = 0;
178    pm = pmax = sm = smax = d = mid = cbr = -1;
179    brp = brs = NULL;
180
181    /* Get the information about the brace beginning and end we have
182     * to re-insert. */
183    if (ins) {
184	Brinfo bp;
185	int olen = we - wb;
186
187	if ((brp = brbeg)) {
188	    for (bp = brbeg; bp; bp = bp->next) {
189		bp->curpos = (hasunqu ? bp->pos : bp->qpos);
190		olen -= strlen(bp->str);
191	    }
192	}
193	if ((brs = lastbrend)) {
194	    for (bp = brend; bp; bp = bp->next)
195		olen -= strlen(bp->str);
196
197	    for (bp = brend; bp; bp = bp->next)
198		bp->curpos = olen - (hasunqu ? bp->pos : bp->qpos);
199	}
200	while (brp && !brp->curpos) {
201	    inststrlen(brp->str, 1, -1);
202	    brp = brp->next;
203	}
204	while (brs && !brs->curpos) {
205	    if (cbr < 0)
206		cbr = zlemetacs;
207	    inststrlen(brs->str, 1, -1);
208	    brs = brs->prev;
209	}
210    }
211    /* Walk through the top-level cline list. */
212    while (l) {
213	/* Insert the original string if no prefix. */
214	if (l->olen && !(l->flags & CLF_SUF) && !l->prefix) {
215	    pcs = zlemetacs + l->olen;
216	    inststrlen(l->orig, 1, l->olen);
217	} else {
218	    /* Otherwise insert the prefix. */
219	    for (s = l->prefix; s; s = s->next) {
220		pcs = zlemetacs + s->llen;
221		if (s->flags & CLF_LINE)
222		    inststrlen(s->line, 1, s->llen);
223		else
224		    inststrlen(s->word, 1, s->wlen);
225		scs = zlemetacs;
226
227		if ((s->flags & CLF_DIFF) && (!dm || (s->flags & CLF_MATCHED))) {
228		    d = zlemetacs; dm = s->flags & CLF_MATCHED;
229		    if (posl && (npos = zlemetacs + padd) != opos) {
230			opos = npos;
231			addlinknode(posl, (void *) ((long) npos));
232		    }
233		}
234		li += s->llen;
235	    }
236	}
237	if (ins) {
238	    int ocs, bl;
239
240	    while (brp && li >= brp->curpos) {
241		ocs = zlemetacs;
242		bl = strlen(brp->str);
243		zlemetacs = pcs - (li - brp->curpos);
244		inststrlen(brp->str, 1, bl);
245		zlemetacs = ocs + bl;
246		pcs += bl;
247		scs += bl;
248		brp = brp->next;
249	    }
250	}
251	/* Remember the position if this is the first prefix with
252	 * missing characters. */
253	if ((l->flags & CLF_MISS) && !(l->flags & CLF_SUF)) {
254	    if (posl && (npos = zlemetacs + padd) != opos) {
255		opos = npos;
256		addlinknode(posl, (void *) ((long) npos));
257	    }
258	    if (((pmax <= (l->max - l->min) || (pma && l->max != l->min)) &&
259		 (!pmm || (l->flags & CLF_MATCHED))) ||
260		((l->flags & CLF_MATCHED) && !pmm)) {
261		pm = zlemetacs; pmax = l->max - l->min; pmm = l->flags & CLF_MATCHED;
262		pma = ((l->prefix || l->suffix) && l->min == cline_sublen(l));
263	    }
264	}
265	if (ins) {
266	    int ocs, bl;
267
268	    while (brs && li >= brs->curpos) {
269		ocs = zlemetacs;
270		bl = strlen(brs->str);
271		zlemetacs = scs - (li - brs->curpos);
272		if (cbr < 0)
273		    cbr = zlemetacs;
274		inststrlen(brs->str, 1, bl);
275		zlemetacs = ocs + bl;
276		pcs += bl;
277		brs = brs->prev;
278	    }
279	}
280	pcs = zlemetacs;
281	/* Insert the anchor. */
282	if (l->flags & CLF_LINE)
283	    inststrlen(l->line, 1, l->llen);
284	else
285	    inststrlen(l->word, 1, l->wlen);
286	scs = zlemetacs;
287	if (ins) {
288	    int ocs, bl;
289
290	    li += l->llen;
291
292	    while (brp && li >= brp->curpos) {
293		ocs = zlemetacs;
294		bl = strlen(brp->str);
295		zlemetacs = pcs + l->llen - (li - brp->curpos);
296		inststrlen(brp->str, 1, bl);
297		zlemetacs = ocs + bl;
298		pcs += bl;
299		scs += bl;
300		brp = brp->next;
301	    }
302	}
303	/* Remember the cursor position for suffixes and mids. */
304	if (l->flags & CLF_MISS) {
305	    if (l->flags & CLF_MID)
306		mid = zlemetacs;
307	    else if (l->flags & CLF_SUF) {
308		if (posl && (npos = zlemetacs + padd) != opos) {
309		    opos = npos;
310		    addlinknode(posl, (void *) ((long) npos));
311		}
312		if (((smax <= (l->min - l->max) || (sma && l->max != l->min)) &&
313		     (!smm || (l->flags & CLF_MATCHED))) ||
314		    ((l->flags & CLF_MATCHED) && !smm)) {
315		    sm = zlemetacs; smax = l->min - l->max; smm = l->flags & CLF_MATCHED;
316		    sma = ((l->prefix || l->suffix) && l->min == cline_sublen(l));
317		}
318	    }
319	}
320	if (ins) {
321	    int ocs, bl;
322
323	    while (brs && li >= brs->curpos) {
324		ocs = zlemetacs;
325		bl = strlen(brs->str);
326		zlemetacs = scs - (li - brs->curpos);
327		if (cbr < 0)
328		    cbr = zlemetacs;
329		inststrlen(brs->str, 1, bl);
330		zlemetacs = ocs + bl;
331		pcs += bl;
332		brs = brs->prev;
333	    }
334	}
335	/* And now insert the suffix or the original string. */
336	if (l->olen && (l->flags & CLF_SUF) && !l->suffix) {
337	    pcs = zlemetacs;
338	    inststrlen(l->orig, 1, l->olen);
339	    if (ins) {
340		int ocs, bl;
341
342		li += l->olen;
343
344		while (brp && li >= brp->curpos) {
345		    ocs = zlemetacs;
346		    bl = strlen(brp->str);
347		    zlemetacs = pcs + l->olen - (li - brp->curpos);
348		    inststrlen(brp->str, 1, bl);
349		    zlemetacs = ocs + bl;
350		    pcs += bl;
351		    brp = brp->next;
352		}
353		while (brs && li >= brs->curpos) {
354		    ocs = zlemetacs;
355		    bl = strlen(brs->str);
356		    zlemetacs = pcs + l->olen - (li - brs->curpos);
357		    if (cbr < 0)
358			cbr = zlemetacs;
359		    inststrlen(brs->str, 1, bl);
360		    zlemetacs = ocs + bl;
361		    pcs += bl;
362		    brs = brs->prev;
363		}
364	    }
365	} else {
366	    Cline js = NULL;
367
368	    for (j = -1, i = 0, s = l->suffix; s; s = s->next) {
369		if (j < 0 && (s->flags & CLF_DIFF))
370		    j = i, js = s;
371		pcs = zlemetacs;
372		if (s->flags & CLF_LINE) {
373		    inststrlen(s->line, 0, s->llen);
374		    i += s->llen; scs = zlemetacs + s->llen;
375		} else {
376		    inststrlen(s->word, 0, s->wlen);
377		    i += s->wlen; scs = zlemetacs + s->wlen;
378		}
379		if (ins) {
380		    int ocs, bl;
381
382		    li += s->llen;
383
384		    while (brp && li >= brp->curpos) {
385			ocs = zlemetacs;
386			bl = strlen(brp->str);
387			zlemetacs = pcs + (li - brp->curpos);
388			inststrlen(brp->str, 1, bl);
389			zlemetacs = ocs + bl;
390			pcs += bl;
391			scs += bl;
392			brp = brp->next;
393		    }
394		    while (brs && li >= brs->curpos) {
395			ocs = zlemetacs;
396			bl = strlen(brs->str);
397			zlemetacs = scs - (li - brs->curpos);
398			if (cbr < 0)
399			    cbr = zlemetacs;
400			inststrlen(brs->str, 1, bl);
401			zlemetacs = ocs + bl;
402			pcs += bl;
403			brs = brs->prev;
404		    }
405		}
406	    }
407	    zlemetacs += i;
408	    if (j >= 0 && (!dm || (js->flags & CLF_MATCHED))) {
409		d = zlemetacs - j; dm = js->flags & CLF_MATCHED;
410		if (posl && (npos = zlemetacs - j + padd) != opos) {
411		    opos = npos;
412		    addlinknode(posl, (void *) ((long) npos));
413		}
414	    }
415	}
416	l = l->next;
417    }
418    if (posl && (npos = zlemetacs + padd) != opos)
419#if 0
420	/* This could be used to put an extra colon before the end-of-word
421	 * position if there is nothing missing. */
422	addlinknode(posl, (void *) ((long) -npos));
423#endif
424	addlinknode(posl, (void *) ((long) npos));
425
426    if (ins) {
427	int ocs = zlemetacs;
428
429	for (; brp; brp = brp->next)
430	    inststrlen(brp->str, 1, -1);
431	for (; brs; brs = brs->prev) {
432	    if (cbr < 0)
433		cbr = zlemetacs;
434	    inststrlen(brs->str, 1, -1);
435	}
436	if (mid >= ocs)
437	    mid += zlemetacs - ocs;
438	if (pm >= ocs)
439	    pm += zlemetacs - ocs;
440	if (sm >= ocs)
441	    sm += zlemetacs - ocs;
442	if (d >= ocs)
443	    d += zlemetacs - ocs;
444
445	if (posl) {
446	    LinkNode node;
447	    long p;
448
449	    for (node = firstnode(posl); node; incnode(node)) {
450		p = (long) getdata(node);
451		if (p >= ocs)
452		    setdata(node, (void *) (p + zlemetacs - ocs));
453	    }
454	}
455    }
456    /* This calculates the new cursor position. If we had a mid cline
457     * with missing characters, we take this, otherwise if we have a
458     * prefix with missing characters, we take that, the same for a
459     * suffix, and finally a place where the matches differ. */
460    ncs = (mid >= 0 ? mid :
461	   (cbr >= 0 ? cbr :
462	    (pm >= 0 ? pm : (sm >= 0 ? sm : (d >= 0 ? d : zlemetacs)))));
463
464    if (ins != 1) {
465	/* We always inserted the string in the line. If that was not
466	 * requested, we copy it and remove from the line. */
467	char *r = zalloc((i = zlemetacs - ocs) + 1);
468
469	memcpy(r, zlemetaline + ocs, i);
470	r[i] = '\0';
471	zlemetacs = ocs;
472	foredel(i, CUT_RAW);
473
474	if (csp)
475	    *csp = ncs - ocs;
476
477	return r;
478    }
479    lastend = zlemetacs;
480    zlemetacs = ncs;
481
482    return NULL;
483}
484
485/* Small utility function turning a list of positions into a colon
486 * separated string. */
487
488static char *
489build_pos_string(LinkList list)
490{
491    LinkNode node;
492    int l;
493    char buf[40], *s;
494    long p;
495
496    for (node = firstnode(list), l = 0; node; incnode(node)) {
497	p = (long) getdata(node);
498#if 0
499	/* This could be used to put an extra colon before the end-of-word
500	 * position if there is nothing missing. */
501	if (p < 0)
502	    sprintf(buf, ":%ld", -p);
503	else
504#endif
505	    sprintf(buf, "%ld", p);
506	setdata(node, dupstring(buf));
507	l += 1 + strlen(buf);
508    }
509    s = (char *) zalloc(l * sizeof(char));
510    *s = 0;
511    for (node = firstnode(list); node;) {
512	strcat(s, (char *) getdata(node));
513	incnode(node);
514	if (node)
515	    strcat(s, ":");
516    }
517    return s;
518}
519
520/* This is a utility function using the function above to allow access
521 * to the unambiguous string and cursor position via compstate. */
522
523/**/
524char *
525unambig_data(int *cp, char **pp, char **ip)
526{
527    static char *scache = NULL, *pcache = NULL, *icache = NULL;
528    static int ccache;
529
530    if (mnum && ainfo) {
531	if (mnum != unambig_mnum) {
532	    LinkList list = newlinklist();
533
534	    zsfree(scache);
535	    scache = cline_str((ainfo->count ? ainfo->line : fainfo->line),
536			       0, &ccache, list);
537	    zsfree(pcache);
538	    if (empty(list))
539		pcache = ztrdup("");
540	    else
541		pcache = build_pos_string(list);
542
543	    zsfree(icache);
544
545	    list = newlinklist();
546	    zsfree(cline_str((ainfo->count ? ainfo->line : fainfo->line),
547			     2, NULL, list));
548	    if (empty(list))
549		icache = ztrdup("");
550	    else
551		icache = build_pos_string(list);
552	}
553    } else if (mnum != unambig_mnum || !ainfo || !scache) {
554	zsfree(scache);
555	scache = ztrdup("");
556	zsfree(pcache);
557	pcache = ztrdup("");
558	zsfree(icache);
559	icache = ztrdup("");
560	ccache = 0;
561    }
562    unambig_mnum = mnum;
563    if (cp)
564	*cp = ccache + 1;
565    if (pp)
566	*pp = pcache;
567    if (ip)
568	*ip = icache;
569    return scache;
570}
571
572/* Insert the given match. This returns the number of bytes inserted.
573 * scs is used to return the position where a automatically created suffix
574 * has to be inserted. */
575
576/**/
577static int
578instmatch(Cmatch m, int *scs)
579{
580    int l, r = 0, ocs, a = zlemetacs, brb = 0, bradd, *brpos;
581    Brinfo bp;
582
583    METACHECK();
584
585    zsfree(lastprebr);
586    zsfree(lastpostbr);
587    lastprebr = lastpostbr = NULL;
588
589    /* Ignored prefix. */
590    if (m->ipre) {
591	char *p = m->ipre + (menuacc ? m->qipl : 0);
592
593	inststrlen(p, 1, (l = strlen(p)));
594	r += l;
595    }
596    /* -P prefix. */
597    if (m->pre) {
598	inststrlen(m->pre, 1, (l = strlen(m->pre)));
599	r += l;
600    }
601    /* Path prefix. */
602    if (m->ppre) {
603	inststrlen(m->ppre, 1, (l = strlen(m->ppre)));
604	r += l;
605    }
606    /* The string itself. */
607    inststrlen(m->str, 1, (l = strlen(m->str)));
608    r += l;
609    ocs = zlemetacs;
610    /* Re-insert the brace beginnings, if any. */
611    if (brbeg) {
612	int pcs = zlemetacs;
613
614	l = 0;
615	for (bp = brbeg, brpos = m->brpl,
616		 bradd = (m->pre ? strlen(m->pre) : 0);
617	     bp; bp = bp->next, brpos++) {
618	    zlemetacs = a + *brpos + bradd;
619	    pcs = zlemetacs;
620	    l = strlen(bp->str);
621	    bradd += l;
622	    brpcs = zlemetacs;
623	    inststrlen(bp->str, 1, l);
624	    r += l;
625	    ocs += l;
626	}
627	lastprebr = (char *) zalloc(pcs - a + 1);
628	memcpy(lastprebr, zlemetaline + a, pcs - a);
629	lastprebr[pcs - a] = '\0';
630	zlemetacs = ocs;
631    }
632    /* Path suffix. */
633    if (m->psuf) {
634	inststrlen(m->psuf, 1, (l = strlen(m->psuf)));
635	r += l;
636    }
637    /* Re-insert the brace end. */
638    if (brend) {
639	a = zlemetacs;
640	for (bp = brend, brpos = m->brsl, bradd = 0; bp; bp = bp->next, brpos++) {
641	    zlemetacs = a - *brpos;
642	    ocs = brscs = zlemetacs;
643	    l = strlen(bp->str);
644	    bradd += l;
645	    inststrlen(bp->str, 1, l);
646	    brb = zlemetacs;
647	    r += l;
648	}
649	zlemetacs = a + bradd;
650	if (scs)
651	    *scs = ocs;
652    } else {
653	brscs = -1;
654
655	if (scs)
656	    *scs = zlemetacs;
657    }
658    /* -S suffix */
659    if (m->suf) {
660	inststrlen(m->suf, 1, (l = strlen(m->suf)));
661	r += l;
662    }
663    /* ignored suffix */
664    if (m->isuf) {
665	inststrlen(m->isuf, 1, (l = strlen(m->isuf)));
666	r += l;
667    }
668    if (brend) {
669	lastpostbr = (char *) zalloc(zlemetacs - brb + 1);
670	memcpy(lastpostbr, zlemetaline + brb, zlemetacs - brb);
671	lastpostbr[zlemetacs - brb] = '\0';
672    }
673    lastend = zlemetacs;
674    zlemetacs = ocs;
675
676    return r;
677}
678
679/* Check if the match has the given prefix/suffix before/after the
680 * braces. */
681
682/**/
683mod_export int
684hasbrpsfx(Cmatch m, char *pre, char *suf)
685{
686    int was_meta;
687
688    if (m->flags & CMF_ALL)
689	return 1;
690
691    /* May not be metafied if calculating whether to show a list. */
692    if (zlemetaline == NULL) {
693	was_meta = 0;
694	metafy_line();
695    } else
696	was_meta = 1;
697
698    {
699	char *op = lastprebr, *os = lastpostbr;
700	VARARR(char, oline, zlemetall);
701	int oll = zlemetall, newll, ole = lastend;
702	int opcs = brpcs, oscs = brscs, ret;
703
704	zle_save_positions();
705	memcpy(oline, zlemetaline, zlemetall);
706
707	lastprebr = lastpostbr = NULL;
708
709	instmatch(m, NULL);
710
711	zlemetacs = 0;
712	foredel(zlemetall, CUT_RAW);
713	spaceinline(oll);
714	memcpy(zlemetaline, oline, oll);
715	/* we do not want to restore zlemetall */
716	newll = zlemetall;
717	zle_restore_positions();
718	zlemetall = newll;
719	lastend = ole;
720	brpcs = opcs;
721	brscs = oscs;
722
723	ret = (((!pre && !lastprebr) ||
724		(pre && lastprebr && !strcmp(pre, lastprebr))) &&
725	       ((!suf && !lastpostbr) ||
726		(suf && lastpostbr && !strcmp(suf, lastpostbr))));
727
728	zsfree(lastprebr);
729	zsfree(lastpostbr);
730	lastprebr = op;
731	lastpostbr = os;
732
733	if (!was_meta)
734	    unmetafy_line();
735	return ret;
736    }
737}
738
739/* Handle the case were we found more than one match. */
740
741/**/
742int
743do_ambiguous(void)
744{
745    int ret = 0;
746
747    menucmp = menuacc = 0;
748
749    /* If we have to insert the first match, call do_single().  This is *
750     * how REC_EXACT takes effect.  We effectively turn the ambiguous   *
751     * completion into an unambiguous one.                              */
752    if (ainfo && ainfo->exact == 1 && !(fromcomp & FC_LINE)) {
753	minfo.cur = NULL;
754	do_single(ainfo->exactm);
755	invalidatelist();
756	return ret;
757    }
758    /* Setting lastambig here means that the completion is ambiguous and *
759     * AUTO_MENU might want to start a menu completion next time round,  *
760     * but this might be overridden below if we can complete an          *
761     * unambiguous prefix.                                               */
762    lastambig = 1;
763
764    if (iforcemenu != -1 &&
765        (usemenu || (haspattern && comppatinsert &&
766                     !strcmp(comppatinsert, "menu")))) {
767	/* We are in a position to start using menu completion due to one  *
768	 * of the menu completion options, or due to the menu-complete-    *
769	 * word command, or due to using GLOB_COMPLETE which does menu-    *
770	 * style completion regardless of the setting of the normal menu   *
771	 * completion options.                                             */
772	do_ambig_menu();
773    } else if (ainfo) {
774	int atend = (zlemetacs == we), la, eq, tcs;
775	VARARR(char, old, we - wb);
776
777	minfo.cur = NULL;
778	minfo.asked = 0;
779
780	fixsuffix();
781
782	/* First remove the old string from the line. */
783	tcs = zlemetacs;
784	zlemetacs = wb;
785	memcpy(old, zlemetaline + wb, we - wb);
786	foredel(we - wb, CUT_RAW);
787
788	/* Now get the unambiguous string and insert it into the line. */
789	cline_str(ainfo->line, 1, NULL, NULL);
790
791	/* Sometimes the different match specs used may result in a cline
792	 * that gives an empty string. If that happened, we re-insert the
793         * old string. Unless there were matches added with -U, that is. */
794
795	if (lastend < we && !lenchanged && !hasunmatched) {
796	    zlemetacs = wb;
797	    foredel(lastend - wb, CUT_RAW);
798	    inststrlen(old, 0, we - wb);
799	    lastend = we;
800	    zlemetacs = tcs;
801	}
802	if (eparq) {
803	    tcs = zlemetacs;
804	    zlemetacs = lastend;
805	    for (eq = eparq; eq; eq--)
806		inststrlen("\"", 0, 1);
807	    zlemetacs = tcs;
808	}
809	/* la is non-zero if listambiguous may be used. Copying and
810	 * comparing the line looks like BFI but it is the easiest
811	 * solution. Really. */
812	la = (zlemetall != origll || strncmp(origline, zlemetaline, zlemetall));
813
814	/* If REC_EXACT and AUTO_MENU are set and what we inserted is an  *
815	 * exact match, we want menu completion the next time round       *
816	 * so we set fromcomp, to ensure that the word on the line is not *
817	 * taken as an exact match. Also we remember if we just moved the *
818	 * cursor into the word.                                          */
819	fromcomp = ((isset(AUTOMENU) ? FC_LINE : 0) |
820		    ((atend && zlemetacs != lastend) ? FC_INWORD : 0));
821
822	/* Probably move the cursor to the end. */
823	if (movetoend == 3)
824	    zlemetacs = lastend;
825
826	/* If the LIST_AMBIGUOUS option (meaning roughly `show a list only *
827	 * if the completion is completely ambiguous') is set, and some    *
828	 * prefix was inserted, return now, bypassing the list-displaying  *
829	 * code.  On the way, invalidate the list and note that we don't   *
830	 * want to enter an AUTO_MENU imediately.                          */
831	if ((uselist == 3 ||
832	     (!uselist && isset(BASHAUTOLIST) && isset(LISTAMBIGUOUS))) &&
833	    la && iforcemenu != -1) {
834	    int fc = fromcomp;
835
836	    invalidatelist();
837	    fromcomp = fc;
838	    lastambig = 0;
839	    clearlist = 1;
840	    return ret;
841	}
842    } else
843	return ret;
844
845    /* At this point, we might want a completion listing.  Show the listing *
846     * if it is needed.                                                     */
847    if (isset(LISTBEEP) && !oldlist)
848	ret = 1;
849
850    if (uselist && (usemenu != 2 || (!listshown && !oldlist)) &&
851	((!showinglist && (!listshown || !oldlist)) ||
852	 (usemenu == 3 && !oldlist)) &&
853	(smatches >= 2 || forcelist))
854	showinglist = -2;
855
856    return ret;
857}
858
859/* This is a stat that ignores backslashes in the filename.  The `ls' *
860 * parameter says if we have to do lstat() or stat().  I think this   *
861 * should instead be done by use of a general function to expand a    *
862 * filename (stripping backslashes), combined with the actual         *
863 * (l)stat().                                                         *
864 * Make sure input is unmetafied                                      */
865
866/**/
867mod_export int
868ztat(char *nam, struct stat *buf, int ls)
869{
870    int ret;
871
872    nam = unmeta(nam);
873    if (!nam)
874	return -1;
875
876    if ((ret = ls ? lstat(nam, buf) : stat(nam, buf))) {
877	char *p, *q;
878
879	for (p = q = nam; *q; q++)
880	    if (*q == '\\' && q[1])
881		*p++ = *++q;
882	    else
883		*p++ = *q;
884	*p = '\0';
885
886	ret = ls ? lstat(nam, buf) : stat(nam, buf);
887    }
888
889    return ret;
890}
891
892/* Insert all matches in the command line. */
893
894/**/
895void
896do_allmatches(UNUSED(int end))
897{
898    int first = 1, nm = nmatches - 1, omc = menucmp, oma = menuacc, e;
899    Cmatch *mc;
900    struct menuinfo mi;
901    char *p = (brbeg ? ztrdup(lastbrbeg->str) : NULL);
902
903    memcpy(&mi, &minfo, sizeof(struct menuinfo));
904    menucmp = 1;
905    menuacc = 0;
906
907    for (minfo.group = amatches;
908	 minfo.group && !(minfo.group)->mcount;
909	 minfo.group = (minfo.group)->next) {
910#ifdef ZSH_HEAP_DEBUG
911	if (memory_validate(minfo.group->heap_id)) {
912	    HEAP_ERROR(minfo.group->heap_id);
913	}
914#endif
915    }
916
917
918    mc = (minfo.group)->matches;
919
920    while (1) {
921	if (!((*mc)->flags & CMF_ALL)) {
922	    if (!first)
923		accept_last();
924	    first = 0;
925
926	    if (!omc && !--nm)
927		menucmp = 0;
928
929	    do_single(*mc);
930	}
931	minfo.cur = mc;
932
933	if (!*++(minfo.cur)) {
934	    do {
935		if (!(minfo.group = (minfo.group)->next))
936		    break;
937	    } while (!(minfo.group)->mcount);
938	    if (!minfo.group)
939		break;
940	    minfo.cur = minfo.group->matches;
941	}
942	mc = minfo.cur;
943    }
944    menucmp = omc;
945    menuacc = oma;
946
947    e = minfo.end;
948    memcpy(&minfo, &mi, sizeof(struct menuinfo));
949    minfo.end = e;
950    minfo.len = e - minfo.pos;
951
952    if (p) {
953	zsfree(lastbrbeg->str);
954	lastbrbeg->str = p;
955    }
956}
957
958/* Insert a single match in the command line. */
959
960/**/
961mod_export void
962do_single(Cmatch m)
963{
964    int l, sr = 0, scs;
965    int havesuff = 0;
966    int partest = (m->ripre || ((m->flags & CMF_ISPAR) && parpre));
967    char *str = m->orig, *ppre = m->ppre, *psuf = m->psuf, *prpre = m->prpre;
968
969    if (!prpre) prpre = "";
970    if (!ppre) ppre = "";
971    if (!psuf) psuf = "";
972
973    fixsuffix();
974
975    if (!minfo.cur) {
976	/* We are currently not in a menu-completion, *
977	 * so set the position variables.             */
978	minfo.pos = wb;
979	minfo.we = (movetoend >= 2 || (movetoend == 1 && !menucmp) ||
980		    (!movetoend && zlemetacs == we));
981	minfo.end = we;
982    }
983    /* If we are already in a menu-completion or if we have done a *
984     * glob completion, we have to delete some of the stuff on the *
985     * command line.                                               */
986    if (minfo.cur)
987	l = minfo.len + minfo.insc;
988    else
989	l = we - wb;
990
991    minfo.insc = 0;
992    zlemetacs = minfo.pos;
993    foredel(l, CUT_RAW);
994
995    if (m->flags & CMF_ALL) {
996	do_allmatches(0);
997        return;
998    }
999
1000    /* And then we insert the new string. */
1001    minfo.len = instmatch(m, &scs);
1002    minfo.end = zlemetacs;
1003    zlemetacs = minfo.pos + minfo.len;
1004
1005    if (m->suf) {
1006	havesuff = 1;
1007	/*
1008	 * This strlen(0 got converted to a ztrlen(), but I don't
1009	 * think that's correct since it's dealing with raw bytes,
1010	 * right?
1011	 */
1012	minfo.insc = strlen(m->suf);
1013	minfo.len -= minfo.insc;
1014	if (minfo.we) {
1015	    minfo.end += minfo.insc;
1016	    if (m->flags & CMF_REMOVE) {
1017		/*
1018		 * Here we need the number of characters, not
1019		 * bytes in the string.
1020		 */
1021		int len;
1022		ZLE_STRING_T wsuf =
1023		    stringaszleline(m->suf, 0, &len, NULL, NULL);
1024		makesuffixstr(m->remf, m->rems, len);
1025		if (len == 1)
1026		    addsuffix(SUFTYP_POSSTR, 0, wsuf, 1, 1);
1027		free(wsuf);
1028	    }
1029	}
1030    } else {
1031	/* There is no user-specified suffix, *
1032	 * so generate one automagically.     */
1033	zlemetacs = scs;
1034	if (partest && (m->flags & CMF_PARBR)) {
1035	    int pq;
1036
1037	    /*{{*/
1038	    /* Completing a parameter in braces.  Add a removable `}' suffix. */
1039	    zlemetacs += eparq;
1040	    for (pq = parq; pq; pq--)
1041		inststrlen("\"", 1, 1);
1042	    minfo.insc += parq;
1043	    inststrlen("}", 1, 1);
1044	    minfo.insc++;
1045	    if (minfo.we)
1046		minfo.end += minfo.insc;
1047	    if (m->flags & CMF_PARNEST)
1048		havesuff = 1;
1049	}
1050	if (((m->flags & CMF_FILE) || (partest && isset(AUTOPARAMSLASH))) &&
1051	    zlemetacs > 0 && zlemetaline[zlemetacs - 1] != '/') {
1052	    /* If we have a filename or we completed a parameter name      *
1053	     * and AUTO_PARAM_SLASH is set, lets see if it is a directory. *
1054	     * If it is, we append a slash.                                */
1055	    struct stat buf;
1056	    char *p;
1057	    int t = 0;
1058
1059	    if (m->ipre && m->ipre[0] == '~' && !m->ipre[1])
1060		t = 1;
1061	    else {
1062		/* Build the path name. */
1063		if (partest && !*psuf && !(m->flags & CMF_PARNEST)) {
1064		    int ne = noerrs, tryit = 1;
1065
1066		    p = (char *) zhalloc(strlen((m->flags & CMF_ISPAR) ?
1067						parpre : m->ripre) +
1068					 strlen(str) + 2);
1069		    sprintf(p, "%s%s%c",
1070			    ((m->flags & CMF_ISPAR) ? parpre : m->ripre), str,
1071			    ((m->flags & CMF_PARBR) ? '}' : '\0'));
1072		    if (*p == '$') {
1073			char *n;
1074			Param pm;
1075
1076			if (p[1] == '{') {
1077			    char *e;
1078
1079			    n = dupstring(p + 2);
1080			    e = n + strlen(n) - 1;
1081
1082			    if (*e == '}')
1083				*e = '\0';
1084			} else
1085			    n = p + 1;
1086
1087			if ((pm = (Param) paramtab->getnode(paramtab, n)) &&
1088			    PM_TYPE(pm->node.flags) != PM_SCALAR)
1089			    tryit = 0;
1090		    }
1091		    if (tryit) {
1092			noerrs = 1;
1093			parsestr(p);
1094			singsub(&p);
1095			errflag = 0;
1096			noerrs = ne;
1097		    }
1098		} else {
1099		    p = (char *) zhalloc(strlen(prpre) + strlen(str) +
1100				 strlen(psuf) + 3);
1101		    sprintf(p, "%s%s%s", ((prpre && *prpre) ?
1102					  prpre : "./"), str, psuf);
1103		}
1104		/* And do the stat. */
1105		t = (!(sr = ztat(p, &buf, 0)) && S_ISDIR(buf.st_mode));
1106	    }
1107	    if (t) {
1108		/* It is a directory, so add the slash. */
1109		havesuff = 1;
1110		inststrlen("/", 1, 1);
1111		minfo.insc++;
1112		if (minfo.we)
1113		    minfo.end++;
1114		if (!menucmp || minfo.we) {
1115		    if (m->remf || m->rems)
1116			makesuffixstr(m->remf, m->rems, 1);
1117		    else if (isset(AUTOREMOVESLASH)) {
1118			makesuffix(1);
1119			addsuffix(SUFTYP_POSSTR, 0, ZWS("/"), 1, 1);
1120		    }
1121		}
1122	    }
1123	}
1124	if (!minfo.insc)
1125	    zlemetacs = minfo.pos + minfo.len - m->qisl;
1126    }
1127    /* If completing in a brace expansion... */
1128    if (brbeg) {
1129	if (havesuff) {
1130	    /*{{*/
1131	    /* If a suffix was added, and is removable, let *
1132	     * `,' and `}' remove it.                       */
1133	    if (isset(AUTOPARAMKEYS))
1134		addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, suffixnoinslen);
1135	} else if (!menucmp) {
1136	    /*{{*/
1137	    /* Otherwise, add a `,' suffix, and let `}' remove it. */
1138	    zlemetacs = scs;
1139	    havesuff = 1;
1140	    inststrlen(",", 1, 1);
1141	    minfo.insc++;
1142	    makesuffix(1);
1143	    if ((!menucmp || minfo.we) && isset(AUTOPARAMKEYS))
1144		addsuffix(SUFTYP_POSSTR, 0, ZWS(",}"), 2, 1);
1145	}
1146    } else if (!havesuff && (!(m->flags & CMF_FILE) || !sr)) {
1147	/* If we didn't add a suffix, add a space, unless we are *
1148	 * doing menu completion or we are completing files and  *
1149	 * the string doesn't name an existing file.             */
1150	if (m->autoq && (!m->isuf || !strpfx(m->autoq, m->isuf))) {
1151	    int al = strlen(m->autoq);
1152	    inststrlen(m->autoq, 1, al);
1153	    minfo.insc += al;
1154	}
1155	if (!menucmp && !(m->flags & CMF_NOSPACE) &&
1156	    (usemenu != 3 || insspace)) {
1157	    inststrlen(" ", 1, 1);
1158	    minfo.insc++;
1159	    if (minfo.we)
1160		makesuffixstr(m->remf, m->rems, 1);
1161	}
1162    }
1163    if (minfo.we && partest && isset(AUTOPARAMKEYS) && minfo.insc - parq > 0) {
1164	/* the suffix code needs numbers of characters, not octets */
1165	int outlen;
1166	char *tmpstr = dupstrpfx(zlemetaline + parq, minfo.insc - parq);
1167	ZLE_STRING_T subline = stringaszleline(tmpstr, 0, &outlen, NULL, NULL);
1168	makeparamsuffix(((m->flags & CMF_PARBR) ? 1 : 0), outlen);
1169	free(subline);
1170    }
1171
1172    if ((menucmp && !minfo.we) || !movetoend) {
1173	zlemetacs = minfo.end;
1174	if (zlemetacs + m->qisl == lastend)
1175	    zlemetacs += minfo.insc;
1176    }
1177    {
1178	Cmatch *om = minfo.cur;
1179	struct chdata dat;
1180
1181	dat.matches = amatches;
1182#ifdef ZSH_HEAP_DEBUG
1183	if (memory_validate(dat.matches->heap_id)) {
1184	    HEAP_ERROR(dat.matches->heap_id);
1185	}
1186#endif
1187	dat.num = nmatches;
1188	dat.cur = m;
1189
1190	if (menucmp)
1191	    minfo.cur = &m;
1192	runhookdef(INSERTMATCHHOOK, (void *) &dat);
1193	minfo.cur = om;
1194    }
1195}
1196
1197/* Do completion, given that we are in the middle of a menu completion.  We *
1198 * don't need to generate a list of matches, because that's already been    *
1199 * done by previous commands.  We will either list the completions, or      *
1200 * insert the next completion.                                              */
1201
1202/**/
1203mod_export void
1204do_menucmp(int lst)
1205{
1206    int was_meta;
1207
1208    /* Just list the matches if the list was requested. */
1209    if (lst == COMP_LIST_COMPLETE) {
1210	showinglist = -2;
1211	return;
1212    }
1213
1214    /* Already metafied when called from domenuselect already */
1215    if (zlemetaline == NULL) {
1216	was_meta = 0;
1217	metafy_line();
1218    } else
1219	was_meta = 1;
1220
1221    /* Otherwise go to the next match in the array... */
1222    do {
1223	if (!*++(minfo.cur)) {
1224	    do {
1225		if (!(minfo.group = (minfo.group)->next)) {
1226		    minfo.group = amatches;
1227#ifdef ZSH_HEAP_DEBUG
1228		    if (memory_validate(minfo.group->heap_id)) {
1229			HEAP_ERROR(minfo.group->heap_id);
1230		    }
1231#endif
1232		}
1233	    } while (!(minfo.group)->mcount);
1234	    minfo.cur = minfo.group->matches;
1235	}
1236    } while ((menuacc &&
1237	      !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
1238             ((*minfo.cur)->flags & CMF_DUMMY) ||
1239	     (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
1240	      (!(*minfo.cur)->str || !*(*minfo.cur)->str)));
1241    /* ... and insert it into the command line. */
1242    do_single(*minfo.cur);
1243
1244    if (!was_meta)
1245	unmetafy_line();
1246}
1247
1248/**/
1249int
1250reverse_menu(UNUSED(Hookdef dummy), UNUSED(void *dummy2))
1251{
1252    int was_meta;
1253
1254    if (minfo.cur == NULL)
1255	return 1;
1256
1257    do {
1258	if (minfo.cur == (minfo.group)->matches) {
1259	    do {
1260		if (!(minfo.group = (minfo.group)->prev))
1261		    minfo.group = lmatches;
1262	    } while (!(minfo.group)->mcount);
1263	    minfo.cur = (minfo.group)->matches + (minfo.group)->mcount - 1;
1264	} else
1265	    minfo.cur--;
1266    } while ((menuacc &&
1267	      !hasbrpsfx(*(minfo.cur), minfo.prebr, minfo.postbr)) ||
1268	     ((*minfo.cur)->flags & CMF_DUMMY) ||
1269	     (((*minfo.cur)->flags & (CMF_NOLIST | CMF_MULT)) &&
1270	      (!(*minfo.cur)->str || !*(*minfo.cur)->str)));
1271    /* May already be metafied if called from within a selection */
1272    if (zlemetaline == NULL) {
1273	metafy_line();
1274	was_meta = 0;
1275    }
1276    else
1277	was_meta = 1;
1278    do_single(*(minfo.cur));
1279    if (!was_meta)
1280	unmetafy_line();
1281
1282    return 0;
1283}
1284
1285/* Accepts the current completion and starts a new arg, *
1286 * with the next completions. This gives you a way to   *
1287 * accept several selections from the list of matches.  */
1288
1289/**/
1290mod_export int
1291accept_last(void)
1292{
1293    /* give up trying to work out what state it should be in */
1294    int wasmeta;
1295    if (zlemetaline != NULL) {
1296	wasmeta = 1;
1297    } else {
1298	wasmeta = 0;
1299	metafy_line();
1300    }
1301
1302    if (!menuacc) {
1303	zsfree(minfo.prebr);
1304	minfo.prebr = ztrdup(lastprebr);
1305	zsfree(minfo.postbr);
1306	minfo.postbr = ztrdup(lastpostbr);
1307
1308	if (listshown && (lastprebr || lastpostbr)) {
1309	    Cmgroup g;
1310	    Cmatch *m;
1311
1312	    for (g = amatches, m = NULL; g && (!m || !*m); g = g->next) {
1313#ifdef ZSH_HEAP_DEBUG
1314		if (memory_validate(g->heap_id)) {
1315		    HEAP_ERROR(g->heap_id);
1316		}
1317#endif
1318		for (m = g->matches; *m; m++)
1319		    if (!hasbrpsfx(*m, minfo.prebr, minfo.postbr)) {
1320			showinglist = -2;
1321			break;
1322		    }
1323	    }
1324	}
1325    }
1326    menuacc++;
1327
1328    if (brbeg) {
1329	int l;
1330
1331	iremovesuffix(',', 1);
1332
1333	l = (brscs >= 0 ? brscs : zlemetacs) - brpcs;
1334
1335	zsfree(lastbrbeg->str);
1336	lastbrbeg->str = (char *) zalloc(l + 2);
1337	memcpy(lastbrbeg->str, zlemetaline + brpcs, l);
1338	lastbrbeg->str[l] = ',';
1339	lastbrbeg->str[l + 1] = '\0';
1340    } else {
1341	int l;
1342
1343	zlemetacs = minfo.pos + minfo.len + minfo.insc;
1344	iremovesuffix(' ', 1);
1345	l = zlemetacs;
1346	zlemetacs = minfo.pos + minfo.len + minfo.insc - (*(minfo.cur))->qisl;
1347	if (zlemetacs < l)
1348	    foredel(l - zlemetacs, CUT_RAW);
1349	else if (zlemetacs > zlemetall)
1350	    zlemetacs = zlemetall;
1351	inststrlen(" ", 1, 1);
1352	minfo.insc = minfo.len = 0;
1353	minfo.pos = zlemetacs;
1354	minfo.we = 1;
1355    }
1356
1357    if (!wasmeta)
1358	unmetafy_line();
1359    return 0;
1360}
1361
1362/* This maps the value in v into the range [0,m-1], decrementing v
1363 * if it is non-negative and making negative values count backwards. */
1364
1365/**/
1366static int
1367comp_mod(int v, int m)
1368{
1369    if (v >= 0)
1370	v--;
1371    if (v >= 0)
1372	return v % m;
1373    else {
1374	while (v < 0)
1375	    v += m;
1376	return v;
1377    }
1378}
1379
1380/* This handles the beginning of menu-completion. */
1381
1382/**/
1383void
1384do_ambig_menu(void)
1385{
1386    Cmatch *mc;
1387
1388    if (iforcemenu == -1)
1389        do_ambiguous();
1390
1391    if (usemenu != 3) {
1392	menucmp = 1;
1393	menuacc = 0;
1394	minfo.cur = NULL;
1395    } else {
1396	if (oldlist) {
1397	    if (oldins && minfo.cur)
1398		accept_last();
1399	} else
1400	    minfo.cur = NULL;
1401    }
1402#if 0
1403    /* group-numbers in compstate[insert] */
1404    if (insgroup) {
1405	insgnum = comp_mod(insgnum, lastpermgnum);
1406	for (minfo.group = amatches;
1407	     minfo.group && (minfo.group)->num != insgnum + 1;
1408	     minfo.group = (minfo.group)->next) {
1409#ifdef ZSH_HEAP_DEBUG
1410	    if (memory_validate(minfo.group->heap_id)) {
1411		HEAP_ERROR(minfo.group->heap_id);
1412	    }
1413#endif
1414	}
1415	if (!minfo.group || !(minfo.group)->mcount) {
1416	    minfo.cur = NULL;
1417	    minfo.asked = 0;
1418	    return;
1419	}
1420	insmnum = comp_mod(insmnum, (minfo.group)->mcount);
1421    } else {
1422#endif
1423	insmnum = comp_mod(insmnum, lastpermmnum);
1424	for (minfo.group = amatches;
1425	     minfo.group && (minfo.group)->mcount <= insmnum;
1426	     minfo.group = (minfo.group)->next) {
1427	    insmnum -= (minfo.group)->mcount;
1428#ifdef ZSH_HEAP_DEBUG
1429	    if (memory_validate(minfo.group->heap_id)) {
1430		HEAP_ERROR(minfo.group->heap_id);
1431	    }
1432#endif
1433	}
1434	if (!minfo.group) {
1435	    minfo.cur = NULL;
1436	    minfo.asked = 0;
1437	    return;
1438	}
1439#if 0
1440	/* group-numbers in compstate[insert] */
1441    }
1442#endif
1443    mc = (minfo.group)->matches + insmnum;
1444    if (iforcemenu != -1)
1445        do_single(*mc);
1446    minfo.cur = mc;
1447}
1448
1449/* Return the number of screen lines needed for the list. */
1450
1451/**/
1452zlong
1453list_lines(void)
1454{
1455    Cmgroup oam;
1456
1457    permmatches(0);
1458
1459    oam = amatches;
1460    amatches = pmatches;
1461    listdat.valid = 0;
1462    calclist(0);
1463    listdat.valid = 0;
1464    amatches = oam;
1465
1466    return listdat.nlines;
1467}
1468
1469/**/
1470void
1471comp_list(char *v)
1472{
1473    zsfree(complist);
1474    complist = v;
1475
1476    onlyexpl = (v ? ((strstr(v, "expl") ? 1 : 0) |
1477		     (strstr(v, "messages") ? 2 : 0)) : 0);
1478}
1479
1480/* This skips over matches that are not to be listed. */
1481
1482/**/
1483mod_export Cmatch *
1484skipnolist(Cmatch *p, int showall)
1485{
1486    int mask = (showall ? 0 : (CMF_NOLIST | CMF_MULT)) | CMF_HIDE;
1487
1488    while (*p && (((*p)->flags & mask) ||
1489		  ((*p)->disp &&
1490		   ((*p)->flags & (CMF_DISPLINE | CMF_HIDE)))))
1491	p++;
1492
1493    return p;
1494}
1495
1496/**/
1497mod_export int
1498calclist(int showall)
1499{
1500    static int lastinvcount = -1;
1501
1502    Cmgroup g;
1503    Cmatch *p, m;
1504    Cexpl *e;
1505    int hidden = 0, nlist = 0, nlines = 0;
1506    int max = 0, i;
1507    VARARR(int, mlens, nmatches + 1);
1508
1509    if (lastinvcount == invcount &&
1510	listdat.valid && onlyexpl == listdat.onlyexpl &&
1511	menuacc == listdat.menuacc && showall == listdat.showall &&
1512	zterm_lines == listdat.zterm_lines &&
1513	zterm_columns == listdat.zterm_columns)
1514	return 0;
1515    lastinvcount = invcount;
1516
1517    for (g = amatches; g; g = g->next) {
1518	char **pp = g->ylist;
1519	int nl = 0, l, glong = 1, gshort = zterm_columns, ndisp = 0, totl = 0;
1520        int hasf = 0;
1521
1522#ifdef ZSH_HEAP_DEBUG
1523	if (memory_validate(g->heap_id)) {
1524	    HEAP_ERROR(g->heap_id);
1525	}
1526#endif
1527	g->flags |= CGF_PACKED | CGF_ROWS;
1528
1529	if (!onlyexpl && pp) {
1530            if (*pp) {
1531                if (!isset(LISTPACKED))
1532                    g->flags &= ~CGF_PACKED;
1533                if (!isset(LISTROWSFIRST))
1534                    g->flags &= ~CGF_ROWS;
1535            }
1536
1537	    /* We have an ylist, lets see, if it contains newlines. */
1538	    hidden = 1;
1539	    while (!nl && *pp) {
1540                if (MB_METASTRWIDTH(*pp) >= zterm_columns)
1541                    nl = 1;
1542                else
1543                    nl = !!strchr(*pp++, '\n');
1544            }
1545	    pp = g->ylist;
1546	    if (nl || !pp[1]) {
1547		/* Yup, there are newlines, count lines. */
1548		char *nlptr, *sptr;
1549
1550		g->flags |= CGF_LINES;
1551		hidden = 1;
1552		while ((sptr = *pp)) {
1553		    while (*sptr) {
1554			if ((nlptr = strchr(sptr, '\n'))) {
1555			    *nlptr = '\0';
1556			    nlines += 1 + (MB_METASTRWIDTH(sptr)-1) /
1557				zterm_columns;
1558			    *nlptr = '\n';
1559			    sptr = nlptr + 1;
1560			} else {
1561			    nlines += (MB_METASTRWIDTH(sptr)-1) / zterm_columns;
1562			    break;
1563			}
1564		    }
1565		    nlines++;
1566		    pp++;
1567		}
1568		/*** nlines--; */
1569	    } else {
1570		while (*pp) {
1571		    l = MB_METASTRWIDTH(*pp);
1572		    ndisp++;
1573		    if (l > glong)
1574			glong = l;
1575		    if (l < gshort)
1576			gshort = l;
1577		    totl += l;
1578		    nlist++;
1579		    pp++;
1580		}
1581	    }
1582	} else if (!onlyexpl) {
1583	    for (p = g->matches; (m = *p); p++) {
1584                if (m->flags & CMF_FILE)
1585                    hasf = 1;
1586		if (menuacc && !hasbrpsfx(m, minfo.prebr, minfo.postbr)) {
1587		    m->flags |= CMF_HIDE;
1588		    continue;
1589		}
1590		m->flags &= ~CMF_HIDE;
1591
1592                if (showall || !(m->flags & (CMF_NOLIST | CMF_MULT))) {
1593		    if ((m->flags & (CMF_NOLIST | CMF_MULT)) &&
1594			(!m->str || !*m->str)) {
1595			m->flags |= CMF_HIDE;
1596			continue;
1597		    }
1598                    if (m->disp) {
1599                        if (m->flags & CMF_DISPLINE) {
1600                            nlines += 1 + printfmt(m->disp, 0, 0, 0);
1601                            g->flags |= CGF_HASDL;
1602                        } else {
1603                            l = ZMB_nicewidth(m->disp);
1604                            ndisp++;
1605                            if (l > glong)
1606                                glong = l;
1607                            if (l < gshort)
1608                                gshort = l;
1609                            totl += l;
1610                            mlens[m->gnum] = l;
1611                        }
1612                        nlist++;
1613                        if (!(m->flags & CMF_PACKED))
1614                            g->flags &= ~CGF_PACKED;
1615                        if (!(m->flags & CMF_ROWS))
1616                            g->flags &= ~CGF_ROWS;
1617                    } else {
1618                        l = ZMB_nicewidth(m->str) + !!m->modec;
1619                        ndisp++;
1620                        if (l > glong)
1621                            glong = l;
1622                        if (l < gshort)
1623                            gshort = l;
1624                        totl += l;
1625                        mlens[m->gnum] = l;
1626                        nlist++;
1627                        if (!(m->flags & CMF_PACKED))
1628                            g->flags &= ~CGF_PACKED;
1629                        if (!(m->flags & CMF_ROWS))
1630                            g->flags &= ~CGF_ROWS;
1631                    }
1632		} else
1633		    hidden = 1;
1634	    }
1635	}
1636	if ((e = g->expls)) {
1637	    while (*e) {
1638		if (((*e)->count || (*e)->always) &&
1639		    (!onlyexpl ||
1640		     (onlyexpl & ((*e)->always > 0 ? 2 : 1))))
1641		    nlines += 1 + printfmt((*e)->str,
1642                                           ((*e)->always ? -1 : (*e)->count),
1643                                           0, 1);
1644		e++;
1645	    }
1646	}
1647        if (isset(LISTTYPES) && hasf)
1648            g->flags |= CGF_FILES;
1649	g->totl = totl + (ndisp * CM_SPACE);
1650	g->dcount = ndisp;
1651	g->width = glong + CM_SPACE;
1652	g->shortest = gshort + CM_SPACE;
1653	if ((g->cols = zterm_columns / g->width) > g->dcount)
1654	    g->cols = g->dcount;
1655	if (g->cols) {
1656	    i = g->cols * g->width - CM_SPACE;
1657	    if (i > max)
1658		max = i;
1659	}
1660    }
1661    if (!onlyexpl) {
1662	char **pp;
1663	int *ws, tlines, tcols, width, glines;
1664
1665	for (g = amatches; g; g = g->next) {
1666	    glines = 0;
1667
1668#ifdef ZSH_HEAP_DEBUG
1669	    if (memory_validate(g->heap_id)) {
1670		HEAP_ERROR(g->heap_id);
1671	    }
1672#endif
1673	    zfree(g->widths, 0);
1674	    g->widths = NULL;
1675
1676	    if ((pp = g->ylist)) {
1677		if (!(g->flags & CGF_LINES)) {
1678		    if (g->cols) {
1679			glines += (arrlen(pp) + g->cols - 1) / g->cols;
1680			if (g->cols > 1)
1681			    g->width += ((max - (g->width * g->cols -
1682                                                 CM_SPACE)) /
1683                                         g->cols);
1684		    } else {
1685			g->cols = 1;
1686			g->width = 1;
1687
1688			while (*pp)
1689			    glines += 1 + (MB_METASTRWIDTH(*pp++) /
1690					   zterm_columns);
1691		    }
1692		}
1693	    } else {
1694		if (g->cols) {
1695		    glines += (g->dcount + g->cols - 1) / g->cols;
1696		    if (g->cols > 1)
1697			g->width += ((max - (g->width * g->cols - CM_SPACE)) /
1698                                     g->cols);
1699		} else if (!(g->flags & CGF_LINES)) {
1700		    g->cols = 1;
1701		    g->width = 0;
1702
1703		    for (p = g->matches; (m = *p); p++)
1704			if (!(m->flags & CMF_HIDE)) {
1705			    if (m->disp) {
1706				if (!(m->flags & CMF_DISPLINE))
1707				    glines += 1 + ((mlens[m->gnum] - 1) /
1708						   zterm_columns);
1709			    } else if (showall ||
1710				       !(m->flags & (CMF_NOLIST | CMF_MULT)))
1711				glines += 1 + (((mlens[m->gnum]) - 1) /
1712					       zterm_columns);
1713			}
1714		}
1715	    }
1716	    g->lins = glines;
1717	    nlines += glines;
1718	}
1719	for (g = amatches; g; g = g->next) {
1720	    if (!(g->flags & CGF_PACKED))
1721		continue;
1722
1723	    ws = g->widths = (int *) zalloc(zterm_columns * sizeof(int));
1724	    memset(ws, 0, zterm_columns * sizeof(int));
1725	    tlines = g->lins;
1726	    tcols = g->cols;
1727	    width = 0;
1728
1729	    if ((pp = g->ylist)) {
1730		if (!(g->flags & CGF_LINES)) {
1731		    int yl = arrlen(pp), i;
1732		    VARARR(int, ylens, yl);
1733
1734		    for (i = 0; *pp; i++, pp++)
1735			ylens[i] = MB_METASTRWIDTH(*pp) + CM_SPACE;
1736
1737		    if (g->flags & CGF_ROWS) {
1738                        int nth, tcol, len;
1739
1740                        for (tcols = zterm_columns / (g->shortest + CM_SPACE);
1741                             tcols > g->cols;
1742                             tcols--) {
1743
1744                            memset(ws, 0, tcols * sizeof(int));
1745
1746                            for (width = nth = tcol = 0, tlines = 1;
1747                                 width < zterm_columns && nth < g->dcount;
1748                                 nth++, tcol++) {
1749
1750                                m = *p;
1751
1752                                if (tcol == tcols) {
1753                                    tcol = 0;
1754                                    tlines++;
1755                                }
1756                                len = ylens[nth];
1757
1758                                if (len > ws[tcol]) {
1759                                    width += len - ws[tcol];
1760                                    ws[tcol] = len;
1761                                }
1762                            }
1763                            if (width < zterm_columns)
1764                                break;
1765                        }
1766		    } else {
1767                        int nth, tcol, tline, len;
1768
1769                        for (tcols = zterm_columns / (g->shortest + CM_SPACE);
1770                             tcols > g->cols;
1771                             tcols--) {
1772
1773                            if ((tlines = (g->dcount + tcols - 1) / tcols) <= 0)
1774                                tlines = 1;
1775
1776                            memset(ws, 0, tcols * sizeof(int));
1777
1778                            for (width = nth = tcol = tline = 0;
1779                                 width < zterm_columns && nth < g->dcount;
1780                                 nth++, tline++) {
1781
1782                                m = *p;
1783
1784                                if (tline == tlines) {
1785                                    tcol++;
1786                                    tline = 0;
1787                                }
1788                                if (tcol == tcols) {
1789                                    tcol = 0;
1790                                    tlines++;
1791                                }
1792                                len = ylens[nth];
1793
1794                                if (len > ws[tcol]) {
1795                                    width += len - ws[tcol];
1796                                    ws[tcol] = len;
1797                                }
1798                            }
1799                            if (width < zterm_columns)
1800                                break;
1801                        }
1802		    }
1803		}
1804	    } else if (g->width) {
1805		if (g->flags & CGF_ROWS) {
1806                    int nth, tcol, len;
1807
1808                    for (tcols = zterm_columns / (g->shortest + CM_SPACE);
1809                         tcols > g->cols;
1810                         tcols--) {
1811
1812                        memset(ws, 0, tcols * sizeof(int));
1813
1814                        for (width = nth = tcol = 0, tlines = 1,
1815                             p = skipnolist(g->matches, showall);
1816                             *p && width < zterm_columns && nth < g->dcount;
1817                             nth++, p = skipnolist(p + 1, showall), tcol++) {
1818
1819                            m = *p;
1820
1821                            if (tcol == tcols) {
1822                                tcol = 0;
1823                                tlines++;
1824                            }
1825                            len = (mlens[m->gnum] +
1826                                   (tcol == tcols - 1 ? 0 : CM_SPACE));
1827
1828                            if (len > ws[tcol]) {
1829                                width += len - ws[tcol];
1830                                ws[tcol] = len;
1831                            }
1832                        }
1833                        if (width < zterm_columns)
1834                            break;
1835                    }
1836		} else {
1837                    int nth, tcol, tline, len;
1838
1839                    for (tcols = zterm_columns / (g->shortest + CM_SPACE);
1840                         tcols > g->cols;
1841                         tcols--) {
1842
1843                        if ((tlines = (g->dcount + tcols - 1) / tcols) <= 0)
1844                            tlines = 1;
1845
1846                        memset(ws, 0, tcols * sizeof(int));
1847
1848                        for (width = nth = tcol = tline = 0,
1849                             p = skipnolist(g->matches, showall);
1850                             *p && width < zterm_columns && nth < g->dcount;
1851                             nth++, p = skipnolist(p + 1, showall), tline++) {
1852
1853                            m = *p;
1854
1855                            if (tline == tlines) {
1856                                tcol++;
1857                                tline = 0;
1858                            }
1859                            if (tcol == tcols) {
1860                                tcol = 0;
1861                                tlines++;
1862                            }
1863                            len = (mlens[m->gnum] +
1864                                   (tcol == tcols - 1 ? 0 : CM_SPACE));
1865
1866                            if (len > ws[tcol]) {
1867                                width += len - ws[tcol];
1868                                ws[tcol] = len;
1869                            }
1870                        }
1871                        if (width < zterm_columns) {
1872                            if (++tcol < tcols)
1873                                tcols = tcol;
1874                            break;
1875                        }
1876                    }
1877		}
1878	    }
1879            if (tcols <= g->cols)
1880                tlines = g->lins;
1881	    if (tlines == g->lins) {
1882		zfree(ws, zterm_columns * sizeof(int));
1883		g->widths = NULL;
1884	    } else {
1885		nlines += tlines - g->lins;
1886		g->lins = tlines;
1887		g->cols = tcols;
1888		g->totl = width;
1889		width -= CM_SPACE;
1890		if (width > max)
1891		    max = width;
1892	    }
1893	}
1894	for (g = amatches; g; g = g->next) {
1895	    if (g->widths) {
1896		int *p, a = (max - g->totl + CM_SPACE) / g->cols;
1897
1898		for (i = g->cols, p = g->widths; i; i--, p++)
1899		    *p += a;
1900	    } else if (g->width && g->cols > 1)
1901		g->width += (max - (g->width * g->cols - CM_SPACE)) / g->cols;
1902	}
1903    }
1904    else
1905	for (g = amatches; g; g = g->next)
1906	{
1907#ifdef ZSH_HEAP_DEBUG
1908	    if (memory_validate(g->heap_id)) {
1909		HEAP_ERROR(g->heap_id);
1910	    }
1911#endif
1912	    zfree(g->widths, 0);
1913	    g->widths = NULL;
1914	}
1915    listdat.valid = 1;
1916    listdat.hidden = hidden;
1917    listdat.nlist = nlist;
1918    listdat.nlines = nlines;
1919    listdat.menuacc = menuacc;
1920    listdat.onlyexpl = onlyexpl;
1921    listdat.zterm_columns = zterm_columns;
1922    listdat.zterm_lines = zterm_lines;
1923    listdat.showall = showall;
1924
1925    return 1;
1926}
1927
1928/**/
1929mod_export int
1930asklist(void)
1931{
1932    /* Set the cursor below the prompt. */
1933    trashzle();
1934    showinglist = listshown = 0;
1935
1936    clearflag = (isset(USEZLE) && !termflags && dolastprompt);
1937    lastlistlen = 0;
1938
1939    /* Maybe we have to ask if the user wants to see the list. */
1940    if ((!minfo.cur || !minfo.asked) &&
1941	((complistmax > 0 && listdat.nlist >= complistmax) ||
1942	 (complistmax < 0 && listdat.nlines <= -complistmax) ||
1943	 (!complistmax && listdat.nlines >= zterm_lines))) {
1944	int qup, l;
1945
1946	zsetterm();
1947	l = (listdat.nlist > 0 ?
1948	     fprintf(shout, "zsh: do you wish to see all %d possibilities (%d lines)? ",
1949		     listdat.nlist, listdat.nlines) :
1950	     fprintf(shout, "zsh: do you wish to see all %d lines? ",
1951		     listdat.nlines));
1952	qup = ((l + zterm_columns - 1) / zterm_columns) - 1;
1953	fflush(shout);
1954	if (!getzlequery()) {
1955	    if (clearflag) {
1956		putc('\r', shout);
1957		tcmultout(TCUP, TCMULTUP, qup);
1958		if (tccan(TCCLEAREOD))
1959		    tcout(TCCLEAREOD);
1960		tcmultout(TCUP, TCMULTUP, nlnct);
1961	    } else
1962		putc('\n', shout);
1963	    minfo.asked = 2;
1964	    return 1;
1965	}
1966	if (clearflag) {
1967	    putc('\r', shout);
1968	    tcmultout(TCUP, TCMULTUP, qup);
1969	    if (tccan(TCCLEAREOD))
1970		tcout(TCCLEAREOD);
1971	} else
1972	    putc('\n', shout);
1973	settyinfo(&shttyinfo);
1974	minfo.asked = 1;
1975    } else if (minfo.asked == 2)
1976	tcmultout(TCUP, TCMULTUP, nlnct);
1977
1978    return (minfo.asked ? minfo.asked - 1 : 0);
1979}
1980
1981/**/
1982mod_export int
1983printlist(int over, CLPrintFunc printm, int showall)
1984{
1985    Cmgroup g;
1986    Cmatch *p, m;
1987    Cexpl *e;
1988    int pnl = 0, cl = (over ? listdat.nlines : -1);
1989    int mc = 0, ml = 0, printed = 0;
1990
1991    if (cl < 2) {
1992	cl = -1;
1993	if (tccan(TCCLEAREOD))
1994	    tcout(TCCLEAREOD);
1995    }
1996    for (g = amatches; g; g = g->next) {
1997	char **pp = g->ylist;
1998
1999#ifdef ZSH_HEAP_DEBUG
2000	if (memory_validate(g->heap_id)) {
2001	    HEAP_ERROR(g->heap_id);
2002	}
2003#endif
2004	if ((e = g->expls)) {
2005	    int l;
2006
2007	    while (*e) {
2008		if (((*e)->count || (*e)->always) &&
2009		    (!listdat.onlyexpl ||
2010		     (listdat.onlyexpl & ((*e)->always > 0 ? 2 : 1)))) {
2011		    if (pnl) {
2012			putc('\n', shout);
2013			pnl = 0;
2014			ml++;
2015			if (cl >= 0 && --cl <= 1) {
2016			    cl = -1;
2017			    if (tccan(TCCLEAREOD))
2018				tcout(TCCLEAREOD);
2019			}
2020		    }
2021		    l = printfmt((*e)->str,
2022                                 ((*e)->always ? -1 : (*e)->count), 1, 1);
2023		    ml += l;
2024		    if (cl >= 0 && (cl -= l) <= 1) {
2025			cl = -1;
2026			if (tccan(TCCLEAREOD))
2027			    tcout(TCCLEAREOD);
2028		    }
2029		    pnl = 1;
2030		}
2031		e++;
2032	    }
2033	}
2034	if (!listdat.onlyexpl && pp && *pp) {
2035	    if (pnl) {
2036		putc('\n', shout);
2037		pnl = 0;
2038		ml++;
2039		if (cl >= 0 && --cl <= 1) {
2040		    cl = -1;
2041		    if (tccan(TCCLEAREOD))
2042			tcout(TCCLEAREOD);
2043		}
2044	    }
2045	    if (g->flags & CGF_LINES) {
2046                char *p;
2047
2048		while ((p = *pp++)) {
2049		    zputs(p, shout);
2050		    if (*pp) {
2051                        if (MB_METASTRWIDTH(p) % zterm_columns)
2052                            putc('\n', shout);
2053                        else
2054                            fputs(" \010", shout);
2055                    }
2056		}
2057	    } else {
2058		int n = g->lcount, nl, nc, i, a;
2059		char **pq;
2060
2061		nl = nc = g->lins;
2062
2063		while (n && nl--) {
2064		    i = g->cols;
2065		    mc = 0;
2066		    pq = pp;
2067		    while (n && i--) {
2068			if (pq - g->ylist >= g->lcount)
2069			    break;
2070			zputs(*pq, shout);
2071			if (i) {
2072			    a = (g->widths ? g->widths[mc] : g->width) -
2073				MB_METASTRWIDTH(*pq);
2074			    while (a--)
2075				putc(' ', shout);
2076			}
2077			pq += ((g->flags & CGF_ROWS) ? 1 : nc);
2078			mc++;
2079			n--;
2080		    }
2081		    if (n) {
2082			putc('\n', shout);
2083			ml++;
2084			if (cl >= 0 && --cl <= 1) {
2085			    cl = -1;
2086			    if (tccan(TCCLEAREOD))
2087				tcout(TCCLEAREOD);
2088			}
2089		    }
2090		    pp += ((g->flags & CGF_ROWS) ? g->cols : 1);
2091		}
2092	    }
2093	} else if (!listdat.onlyexpl &&
2094		   (g->lcount || (showall && g->mcount))) {
2095	    int n = g->dcount, nl, nc, i, j, wid;
2096	    Cmatch *q;
2097
2098	    nl = nc = g->lins;
2099
2100	    if (g->flags & CGF_HASDL) {
2101		for (p = g->matches; (m = *p); p++)
2102		    if (m->disp && (m->flags & CMF_DISPLINE) &&
2103                        (showall || !(m->flags & (CMF_HIDE|CMF_NOLIST)))) {
2104			if (pnl) {
2105			    putc('\n', shout);
2106			    pnl = 0;
2107			    ml++;
2108			    if (cl >= 0 && --cl <= 1) {
2109				cl = -1;
2110				if (tccan(TCCLEAREOD))
2111				    tcout(TCCLEAREOD);
2112			    }
2113			}
2114			printed++;
2115			printm(g, p, 0, ml, 1, 0);
2116			pnl = 1;
2117		    }
2118	    }
2119	    if (n && pnl) {
2120		putc('\n', shout);
2121		pnl = 0;
2122		ml++;
2123		if (cl >= 0 && --cl <= 1) {
2124		    cl = -1;
2125		    if (tccan(TCCLEAREOD))
2126			tcout(TCCLEAREOD);
2127		}
2128	    }
2129	    for (p = skipnolist(g->matches, showall); n && nl--;) {
2130		i = g->cols;
2131		mc = 0;
2132		q = p;
2133		while (n && i--) {
2134		    wid = (g->widths ? g->widths[mc] : g->width);
2135		    if (!(m = *q)) {
2136			printm(g, NULL, mc, ml, (!i), wid);
2137			break;
2138		    }
2139                    printm(g, q, mc, ml, (!i), wid);
2140
2141		    printed++;
2142
2143		    if (--n)
2144			for (j = ((g->flags & CGF_ROWS) ? 1 : nc);
2145			     j && *q; j--)
2146			    q = skipnolist(q + 1, showall);
2147		    mc++;
2148		}
2149		while (i-- > 0) {
2150		    printm(g, NULL, mc, ml, (!i),
2151			   (g->widths ? g->widths[mc] : g->width));
2152		    mc++;
2153		}
2154		if (n) {
2155		    putc('\n', shout);
2156		    ml++;
2157		    if (cl >= 0 && --cl <= 1) {
2158			cl = -1;
2159			if (tccan(TCCLEAREOD))
2160			    tcout(TCCLEAREOD);
2161		    }
2162		    if (nl)
2163			for (j = ((g->flags & CGF_ROWS) ? g->cols : 1);
2164			     j && *p; j--)
2165			    p = skipnolist(p + 1, showall);
2166		}
2167	    }
2168	} else
2169	    continue;
2170	if (g->lcount || (showall && g->mcount))
2171	    pnl = 1;
2172    }
2173    lastlistlen = 0;
2174    if (clearflag) {
2175	/* Move the cursor up to the prompt, if always_last_prompt *
2176	 * is set and all that...                                  */
2177	if ((ml = listdat.nlines + nlnct - 1) < zterm_lines) {
2178	    tcmultout(TCUP, TCMULTUP, ml);
2179	    showinglist = -1;
2180
2181	    lastlistlen = listdat.nlines;
2182	} else
2183	    clearflag = 0, putc('\n', shout);
2184    } else
2185	putc('\n', shout);
2186
2187    listshown = (clearflag ? 1 : -1);
2188
2189    return printed;
2190}
2191
2192/**/
2193mod_export void
2194bld_all_str(Cmatch all)
2195{
2196    Cmgroup g;
2197    Cmatch *mp, m;
2198    int len = zterm_columns - 5, t, add = 0;
2199    VARARR(char, buf, zterm_columns + 1);
2200
2201    buf[0] = '\0';
2202
2203    for (g = amatches; g && !g->mcount; g = g->next) {
2204#ifdef ZSH_HEAP_DEBUG
2205	if (memory_validate(g->heap_id)) {
2206	    HEAP_ERROR(g->heap_id);
2207	}
2208#endif
2209    }
2210
2211    mp = g->matches;
2212    while (1) {
2213	m = *mp;
2214	if (!(m->flags & (CMF_ALL | CMF_HIDE)) && m->str) {
2215	    t = strlen(m->str) + add;
2216	    if (len >= t) {
2217		if (add)
2218		    strcat(buf, " ");
2219		strcat(buf, m->str);
2220		len -= t;
2221		add = 1;
2222	    } else {
2223		if (len > add + 2) {
2224		    if (add)
2225			strcat(buf, " ");
2226		    strncat(buf, m->str, len);
2227		}
2228		strcat(buf, "...");
2229		break;
2230	    }
2231	}
2232	if (!*++mp) {
2233	    do {
2234		if (!(g = g->next))
2235		    break;
2236	    } while (!g->mcount);
2237	    if (!g)
2238		break;
2239	    mp = g->matches;
2240	}
2241    }
2242    zsfree(all->disp);
2243    all->disp = ztrdup(buf);
2244}
2245
2246/**/
2247static void
2248iprintm(Cmgroup g, Cmatch *mp, UNUSED(int mc), UNUSED(int ml), int lastc, int width)
2249{
2250    Cmatch m;
2251    int len = 0;
2252
2253    if (!mp)
2254	return;
2255
2256    m = *mp;
2257    if ((m->flags & CMF_ALL) && (!m->disp || !m->disp[0]))
2258	bld_all_str(m);
2259    if (m->disp) {
2260	if (m->flags & CMF_DISPLINE) {
2261	    printfmt(m->disp, 0, 1, 0);
2262	    return;
2263	}
2264#ifdef MULTIBYTE_SUPPORT
2265	len = mb_niceformat(m->disp, shout, NULL, 0);
2266#else
2267	nicezputs(m->disp, shout);
2268	len = niceztrlen(m->disp);
2269#endif
2270    } else {
2271#ifdef MULTIBYTE_SUPPORT
2272	len = mb_niceformat(m->str, shout, NULL, 0);
2273#else
2274	nicezputs(m->str, shout);
2275	len = niceztrlen(m->str);
2276#endif
2277
2278	if ((g->flags & CGF_FILES) && m->modec) {
2279	    putc(m->modec, shout);
2280	    len++;
2281	}
2282    }
2283    if (!lastc) {
2284	len = width - len;
2285
2286	while (len-- > 0)
2287	    putc(' ', shout);
2288    }
2289}
2290
2291/**/
2292int
2293ilistmatches(UNUSED(Hookdef dummy), UNUSED(Chdata dat))
2294{
2295    calclist(0);
2296
2297    if (!listdat.nlines) {
2298	showinglist = listshown = 0;
2299	return 1;
2300    }
2301    if (asklist())
2302	return 0;
2303
2304    printlist(0, iprintm, 0);
2305
2306    return 0;
2307}
2308
2309/* List the matches.  Note that the list entries are metafied. */
2310
2311/**/
2312int
2313list_matches(UNUSED(Hookdef dummy), UNUSED(void *dummy2))
2314{
2315    struct chdata dat;
2316    int ret;
2317
2318#ifdef DEBUG
2319    /* Sanity check */
2320    if (!validlist) {
2321	showmsg("BUG: listmatches called with bogus list");
2322	return 1;
2323    }
2324#endif
2325
2326    dat.matches = amatches;
2327#ifdef ZSH_HEAP_DEBUG
2328    if (memory_validate(dat.matches->heap_id)) {
2329	HEAP_ERROR(dat.matches->heap_id);
2330    }
2331#endif
2332    dat.num = nmatches;
2333    dat.cur = NULL;
2334    ret = runhookdef(COMPLISTMATCHESHOOK, (void *) &dat);
2335
2336    return ret;
2337}
2338
2339/* Invalidate the completion list. */
2340
2341/**/
2342mod_export int
2343invalidate_list(void)
2344{
2345    invcount++;
2346    if (validlist) {
2347	if (showinglist == -2) {
2348	    zrefresh();
2349	}
2350	freematches(lastmatches, 1);
2351	lastmatches = NULL;
2352	hasoldlist = 0;
2353    }
2354    lastambig = menucmp = menuacc = validlist = showinglist = fromcomp = 0;
2355    listdat.valid = 0;
2356    if (listshown < 0)
2357	listshown = 0;
2358    minfo.cur = NULL;
2359    minfo.asked = 0;
2360    zsfree(minfo.prebr);
2361    zsfree(minfo.postbr);
2362    minfo.postbr = minfo.prebr = NULL;
2363    compwidget = NULL;
2364    nmatches = 0;
2365    amatches = NULL;
2366
2367    return 0;
2368}
2369