Fix up bodgy code for printing completion matches; it used to sometimes

skip entries, print (null), run off the end of the array, or occasionally
receive SIGSEGV, and now will, hopefully at least, do none of that.

Based in part on the patch in PR 44183 from Sergio Acereda; I also
did some tidyup and fixed it to print top-to-bottom first like ls(1).
This commit is contained in:
dholland 2010-12-02 04:35:17 +00:00
parent bbee0aaae2
commit 92417c82c1
1 changed files with 32 additions and 25 deletions

View File

@ -1,4 +1,4 @@
/* $NetBSD: filecomplete.c,v 1.20 2010/11/15 21:24:31 christos Exp $ */
/* $NetBSD: filecomplete.c,v 1.21 2010/12/02 04:35:17 dholland Exp $ */
/*-
* Copyright (c) 1997 The NetBSD Foundation, Inc.
@ -31,7 +31,7 @@
#include "config.h"
#if !defined(lint) && !defined(SCCSID)
__RCSID("$NetBSD: filecomplete.c,v 1.20 2010/11/15 21:24:31 christos Exp $");
__RCSID("$NetBSD: filecomplete.c,v 1.21 2010/12/02 04:35:17 dholland Exp $");
#endif /* not lint && not SCCSID */
#include <sys/types.h>
@ -338,39 +338,45 @@ _fn_qsort_string_compare(const void *i1, const void *i2)
/*
* Display list of strings in columnar format on readline's output stream.
* 'matches' is list of strings, 'len' is number of strings in 'matches',
* 'max' is maximum length of string in 'matches'.
* 'matches' is list of strings, 'num' is number of strings in 'matches',
* 'width' is maximum length of string in 'matches'.
*
* matches[0] is not one of the match strings, so the strings are
* matches[1] *through* matches[num].
*/
void
fn_display_match_list (EditLine *el, char **matches, size_t len, size_t max)
fn_display_match_list (EditLine *el, char **matches, size_t num, size_t width)
{
size_t i, idx, limit, count;
size_t line, lines, col, cols, thisguy;
int screenwidth = el->el_term.t_size.h;
/* Ignore matches[0]. Avoid 1-based array logic below. */
matches++;
/*
* Find out how many entries can be put on one line, count
* with two spaces between strings.
* Find out how many entries can be put on one line; count
* with one space between strings the same way it's printed.
*/
limit = screenwidth / (max + 2);
if (limit == 0)
limit = 1;
cols = screenwidth / (width + 1);
if (cols == 0)
cols = 1;
/* how many lines of output */
count = len / limit;
if (count * limit < len)
count++;
/* how many lines of output, rounded up */
lines = (num + cols - 1) / cols;
/* Sort the items if they are not already sorted. */
qsort(&matches[1], (size_t)(len - 1), sizeof(char *),
_fn_qsort_string_compare);
/* Sort the items. */
qsort(matches, num, sizeof(char *), _fn_qsort_string_compare);
idx = 1;
for(; count > 0; count--) {
int more = limit > 0 && matches[0];
for(i = 0; more; i++, idx++) {
more = i < limit && matches[idx + 1];
(void)fprintf(el->el_outfile, "%-*s%s", (int)max,
matches[idx], more ? " " : "");
/*
* On the ith line print elements i, i+lines, i+lines*2, etc.
*/
for (line = 0; line < lines; line++) {
for (col = 0; col < cols; col++) {
thisguy = line + col * lines;
if (thisguy >= num)
break;
(void)fprintf(el->el_outfile, "%s%-*s",
col == 0 ? "" : " ", (int)width, matches[thisguy]);
}
(void)fprintf(el->el_outfile, "\n");
}
@ -492,6 +498,7 @@ fn_complete(EditLine *el,
if (match_len > maxlen)
maxlen = match_len;
}
/* matches[1] through matches[i-1] are available */
matches_num = i - 1;
/* newline to get on next line from command line */