diff options
Diffstat (limited to 'lib/libedit/filecomplete.c')
-rw-r--r-- | lib/libedit/filecomplete.c | 305 |
1 files changed, 169 insertions, 136 deletions
diff --git a/lib/libedit/filecomplete.c b/lib/libedit/filecomplete.c index bf0d759..10d44e4 100644 --- a/lib/libedit/filecomplete.c +++ b/lib/libedit/filecomplete.c @@ -1,3 +1,5 @@ +/* $NetBSD: filecomplete.c,v 1.34 2014/10/18 15:07:02 riz Exp $ */ + /*- * Copyright (c) 1997 The NetBSD Foundation, Inc. * All rights reserved. @@ -25,10 +27,12 @@ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. - * - * $NetBSD: filecomplete.c,v 1.19 2010/06/01 18:20:26 christos Exp $ */ +#include "config.h" +#if !defined(lint) && !defined(SCCSID) +__RCSID("$NetBSD: filecomplete.c,v 1.34 2014/10/18 15:07:02 riz Exp $"); +#endif /* not lint && not SCCSID */ #include <sys/cdefs.h> __FBSDID("$FreeBSD$"); @@ -44,16 +48,16 @@ __FBSDID("$FreeBSD$"); #include <limits.h> #include <errno.h> #include <fcntl.h> -#include <vis.h> + #include "el.h" #include "fcns.h" /* for EL_NUM_FCNS */ #include "histedit.h" #include "filecomplete.h" -static char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', - '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; +static const Char break_chars[] = { ' ', '\t', '\n', '"', '\\', '\'', '`', '@', + '$', '>', '<', '=', ';', '|', '&', '{', '(', '\0' }; /* Tilde is deliberately omitted here, we treat it specially. */ -static char extra_quote_chars[] = { ')', '}', '*', '?', '[', '$', '\0' }; +static const Char extra_quote_chars[] = { ')', '}', '*', '?', '[', '$', '\0' }; /********************************/ @@ -64,18 +68,21 @@ static char extra_quote_chars[] = { ')', '}', '*', '?', '[', '$', '\0' }; * if ``user'' isn't valid user name or ``txt'' doesn't start * w/ '~', returns pointer to strdup()ed copy of ``txt'' * - * it's callers's responsibility to free() returned string + * it's the caller's responsibility to free() the returned string */ char * fn_tilde_expand(const char *txt) { - struct passwd pwres, *pass; +#if defined(HAVE_GETPW_R_POSIX) || defined(HAVE_GETPW_R_DRAFT) + struct passwd pwres; + char pwbuf[1024]; +#endif + struct passwd *pass; char *temp; size_t len = 0; - char pwbuf[1024]; if (txt[0] != '~') - return (strdup(txt)); + return strdup(txt); temp = strchr(txt + 1, '/'); if (temp == NULL) { @@ -83,34 +90,49 @@ fn_tilde_expand(const char *txt) if (temp == NULL) return NULL; } else { - len = temp - txt + 1; /* text until string after slash */ - temp = malloc(len); + /* text until string after slash */ + len = (size_t)(temp - txt + 1); + temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; (void)strncpy(temp, txt + 1, len - 2); temp[len - 2] = '\0'; } if (temp[0] == 0) { - if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) - pass = NULL; +#ifdef HAVE_GETPW_R_POSIX + if (getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf), + &pass) != 0) + pass = NULL; +#elif HAVE_GETPW_R_DRAFT + pass = getpwuid_r(getuid(), &pwres, pwbuf, sizeof(pwbuf)); +#else + pass = getpwuid(getuid()); +#endif } else { +#ifdef HAVE_GETPW_R_POSIX if (getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf), &pass) != 0) pass = NULL; +#elif HAVE_GETPW_R_DRAFT + pass = getpwnam_r(temp, &pwres, pwbuf, sizeof(pwbuf)); +#else + pass = getpwnam(temp); +#endif } - free(temp); /* value no more needed */ + el_free(temp); /* value no more needed */ if (pass == NULL) - return (strdup(txt)); + return strdup(txt); - /* update pointer txt to point at string immediately following */ + /* update pointer txt to point at string immedially following */ /* first slash */ txt += len; - temp = malloc(strlen(pass->pw_dir) + 1 + strlen(txt) + 1); + len = strlen(pass->pw_dir) + 1 + strlen(txt) + 1; + temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; - (void)sprintf(temp, "%s/%s", pass->pw_dir, txt); + (void)snprintf(temp, len, "%s/%s", pass->pw_dir, txt); - return (temp); + return temp; } @@ -119,7 +141,7 @@ fn_tilde_expand(const char *txt) * such file can be found * value of ``state'' is ignored * - * it's caller's responsibility to free returned string + * it's the caller's responsibility to free the returned string */ char * fn_filename_completion_function(const char *text, int state) @@ -136,19 +158,21 @@ fn_filename_completion_function(const char *text, int state) if (temp) { char *nptr; temp++; - nptr = realloc(filename, strlen(temp) + 1); + nptr = el_realloc(filename, (strlen(temp) + 1) * + sizeof(*nptr)); if (nptr == NULL) { - free(filename); + el_free(filename); filename = NULL; return NULL; } filename = nptr; (void)strcpy(filename, temp); - len = temp - text; /* including last slash */ + len = (size_t)(temp - text); /* including last slash */ - nptr = realloc(dirname, len + 1); + nptr = el_realloc(dirname, (len + 1) * + sizeof(*nptr)); if (nptr == NULL) { - free(dirname); + el_free(dirname); dirname = NULL; return NULL; } @@ -156,7 +180,7 @@ fn_filename_completion_function(const char *text, int state) (void)strncpy(dirname, text, len); dirname[len] = '\0'; } else { - free(filename); + el_free(filename); if (*text == 0) filename = NULL; else { @@ -164,7 +188,7 @@ fn_filename_completion_function(const char *text, int state) if (filename == NULL) return NULL; } - free(dirname); + el_free(dirname); dirname = NULL; } @@ -175,7 +199,7 @@ fn_filename_completion_function(const char *text, int state) /* support for ``~user'' syntax */ - free(dirpath); + el_free(dirpath); dirpath = NULL; if (dirname == NULL) { if ((dirname = strdup("")) == NULL) @@ -191,7 +215,7 @@ fn_filename_completion_function(const char *text, int state) dir = opendir(dirpath); if (!dir) - return (NULL); /* cannot open the directory */ + return NULL; /* cannot open the directory */ /* will be used in cycle */ filename_len = filename ? strlen(filename) : 0; @@ -208,26 +232,36 @@ fn_filename_completion_function(const char *text, int state) /* otherwise, get first entry where first */ /* filename_len characters are equal */ if (entry->d_name[0] == filename[0] +#if HAVE_STRUCT_DIRENT_D_NAMLEN && entry->d_namlen >= filename_len +#else + && strlen(entry->d_name) >= filename_len +#endif && strncmp(entry->d_name, filename, filename_len) == 0) break; } if (entry) { /* match found */ + +#if HAVE_STRUCT_DIRENT_D_NAMLEN len = entry->d_namlen; +#else + len = strlen(entry->d_name); +#endif - temp = malloc(strlen(dirname) + len + 1); + len = strlen(dirname) + len + 1; + temp = el_malloc(len * sizeof(*temp)); if (temp == NULL) return NULL; - (void)sprintf(temp, "%s%s", dirname, entry->d_name); + (void)snprintf(temp, len, "%s%s", dirname, entry->d_name); } else { (void)closedir(dir); dir = NULL; temp = NULL; } - return (temp); + return temp; } @@ -244,11 +278,9 @@ append_char_function(const char *name) rs = "/"; out: if (expname) - free(expname); + el_free(expname); return rs; } - - /* * returns list of completions for text given * non-static for readline. @@ -269,10 +301,10 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) char **nmatch_list; while (matches + 3 >= match_list_len) match_list_len <<= 1; - nmatch_list = realloc(match_list, - match_list_len * sizeof(char *)); + nmatch_list = el_realloc(match_list, + match_list_len * sizeof(*nmatch_list)); if (nmatch_list == NULL) { - free(match_list); + el_free(match_list); return NULL; } match_list = nmatch_list; @@ -295,9 +327,9 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) max_equal = i; } - retstr = malloc(max_equal + 1); + retstr = el_malloc((max_equal + 1) * sizeof(*retstr)); if (retstr == NULL) { - free(match_list); + el_free(match_list); return NULL; } (void)strncpy(retstr, match_list[1], max_equal); @@ -305,12 +337,11 @@ completion_matches(const char *text, char *(*genfunc)(const char *, int)) match_list[0] = retstr; /* add NULL as last pointer to the array */ - match_list[matches + 1] = (char *) NULL; + match_list[matches + 1] = NULL; - return (match_list); + return match_list; } - /* * Sort function for qsort(). Just wrapper around strcasecmp(). */ @@ -323,47 +354,53 @@ _fn_qsort_string_compare(const void *i1, const void *i2) return strcasecmp(s1, s2); } - /* * 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, but it is counted in + * num, so the strings are matches[1] *through* matches[num-1]. */ 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; - int screenwidth = el->el_term.t_size.h; + size_t line, lines, col, cols, thisguy; + int screenwidth = el->el_terminal.t_size.h; + + /* Ignore matches[0]. Avoid 1-based array logic below. */ + matches++; + num--; + + /* + * Find out how many entries can be put on one line; count + * with one space between strings the same way it's printed. + */ + cols = (size_t)screenwidth / (width + 1); + if (cols == 0) + cols = 1; + + /* how many lines of output, rounded up */ + lines = (num + cols - 1) / cols; + + /* Sort the items. */ + qsort(matches, num, sizeof(char *), _fn_qsort_string_compare); /* - * Find out how many entries can be put on one line, count - * with two spaces between strings. + * On the ith line print elements i, i+lines, i+lines*2, etc. */ - limit = screenwidth / (max + 2); - if (limit == 0) - limit = 1; - - /* how many lines of output */ - count = len / limit; - if (count * limit < len) - count++; - - /* Sort the items if they are not already sorted. */ - qsort(&matches[1], len, sizeof(char *), _fn_qsort_string_compare); - - idx = 1; - for(; count > 0; count--) { - int more = limit > 0 && matches[0]; - for(i = 0; more; idx++) { - more = ++i < limit && matches[idx + 1]; - (void)fprintf(el->el_outfile, "%-*s%s", (int)max, - matches[idx], more ? " " : ""); + 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"); } } - /* * Complete the word at or before point, * 'what_to_do' says what to do with the completion. @@ -380,18 +417,18 @@ int fn_complete(EditLine *el, char *(*complet_func)(const char *, int), char **(*attempted_completion_function)(const char *, int, int), - const char *word_break, const char *special_prefixes, + const Char *word_break, const Char *special_prefixes, const char *(*app_func)(const char *), size_t query_items, int *completion_type, int *over, int *point, int *end, - const char *(*find_word_start_func)(const char *, const char *), - char *(*dequoting_func)(const char *), + const Char *(*find_word_start_func)(const Char *, const Char *), + Char *(*dequoting_func)(const Char *), char *(*quoting_func)(const char *)) { - const LineInfo *li; - char *temp; - char *dequoted_temp; - char **matches; - const char *ctemp; + const TYPE(LineInfo) *li; + Char *temp; + Char *dequoted_temp; + char **matches; + const Char *ctemp; size_t len; int what_to_do = '\t'; int retval = CC_NORM; @@ -409,26 +446,20 @@ fn_complete(EditLine *el, app_func = append_char_function; /* We now look backwards for the start of a filename/variable word */ - li = el_line(el); + li = FUN(el,line)(el); if (find_word_start_func) ctemp = find_word_start_func(li->buffer, li->cursor); else { ctemp = li->cursor; while (ctemp > li->buffer - && !strchr(word_break, ctemp[-1]) - && (!special_prefixes || !strchr(special_prefixes, ctemp[-1]) ) ) + && !Strchr(word_break, ctemp[-1]) + && (!special_prefixes || !Strchr(special_prefixes, ctemp[-1]) ) ) ctemp--; } - len = li->cursor - ctemp; -#if defined(__SSP__) || defined(__SSP_ALL__) - temp = malloc(sizeof(*temp) * (len + 1)); - if (temp == NULL) - return retval; -#else - temp = alloca(sizeof(*temp) * (len + 1)); -#endif - (void)strncpy(temp, ctemp, len); + len = (size_t)(li->cursor - ctemp); + temp = el_malloc((len + 1) * sizeof(*temp)); + (void)Strncpy(temp, ctemp, len); temp[len] = '\0'; if (dequoting_func) { @@ -447,13 +478,17 @@ fn_complete(EditLine *el, if (attempted_completion_function) { int cur_off = (int)(li->cursor - li->buffer); - matches = (*attempted_completion_function) (dequoted_temp ? dequoted_temp : temp, - (int)(cur_off - len), cur_off); + matches = (*attempted_completion_function)( + ct_encode_string(dequoted_temp ? dequoted_temp : temp, + &el->el_scratch), + cur_off - (int)len, cur_off); } else matches = 0; if (!attempted_completion_function || (over != NULL && !*over && !matches)) - matches = completion_matches(dequoted_temp ? dequoted_temp : temp, complet_func); + matches = completion_matches( + ct_encode_string(dequoted_temp ? dequoted_temp : temp, + &el->el_scratch), complet_func); if (over != NULL) *over = 0; @@ -475,23 +510,25 @@ fn_complete(EditLine *el, goto free_matches; } else quoted_match = NULL; - el_deletestr(el, (int) len); - el_insertstr(el, quoted_match ? quoted_match : matches[0]); - - free(quoted_match); + FUN(el,insertstr)(el, + ct_decode_string(quoted_match ? quoted_match : + matches[0] , &el->el_scratch)); } if (what_to_do == '?') goto display_matches; - if (matches[2] == NULL && strcmp(matches[0], matches[1]) == 0) { + if (matches[2] == NULL && + (matches[1] == NULL || strcmp(matches[0], matches[1]) == 0)) { /* * We found exact match. Add a space after * it, unless we do filename completion and the * object is a directory. */ - el_insertstr(el, (*app_func)(matches[0])); + FUN(el,insertstr)(el, + ct_decode_string((*app_func)(matches[0]), + &el->el_scratch)); } else if (what_to_do == '!') { display_matches: /* @@ -504,7 +541,8 @@ fn_complete(EditLine *el, if (match_len > maxlen) maxlen = match_len; } - matches_num = i - 1; + /* matches[1] through matches[i-1] are available */ + matches_num = (size_t)(i - 1); /* newline to get on next line from command line */ (void)fprintf(el->el_outfile, "\n"); @@ -523,9 +561,17 @@ fn_complete(EditLine *el, (void)fprintf(el->el_outfile, "\n"); } - if (match_display) - fn_display_match_list(el, matches, matches_num, - maxlen); + if (match_display) { + /* + * Interface of this function requires the + * strings be matches[1..num-1] for compat. + * We have matches_num strings not counting + * the prefix in matches[0], so we need to + * add 1 to matches_num for the call. + */ + fn_display_match_list(el, matches, + matches_num+1, maxlen); + } retval = CC_REDISPLAY; } else if (matches[0][0]) { /* @@ -544,18 +590,15 @@ fn_complete(EditLine *el, free_matches: /* free elements of array and the array itself */ for (i = 0; matches[i]; i++) - free(matches[i]); - free(matches); + el_free(matches[i]); + el_free(matches); matches = NULL; } free(dequoted_temp); -#if defined(__SSP__) || defined(__SSP_ALL__) - free(temp); -#endif + el_free(temp); return retval; } - /* * el-compatible wrapper around rl_complete; needed for key binding */ @@ -564,30 +607,26 @@ unsigned char _el_fn_complete(EditLine *el, int ch __attribute__((__unused__))) { return (unsigned char)fn_complete(el, NULL, NULL, - break_chars, NULL, NULL, 100, + break_chars, NULL, NULL, (size_t)100, NULL, NULL, NULL, NULL, NULL, NULL, NULL); } - -static const char * -sh_find_word_start(const char *buffer, const char *cursor) +static const Char * +sh_find_word_start(const Char *buffer, const Char *cursor) { - const char *word_start = buffer; + const Char *word_start = buffer; while (buffer < cursor) { if (*buffer == '\\') buffer++; - else if (strchr(break_chars, *buffer)) + else if (Strchr(break_chars, *buffer)) word_start = buffer + 1; - buffer++; } - return word_start; } - static char * sh_quote(const char *str) { @@ -595,24 +634,20 @@ sh_quote(const char *str) int extra_len = 0; char *quoted_str, *dst; - if (*str == '-' || *str == '+') - extra_len += 2; - for (src = str; *src != '\0'; src++) - if (strchr(break_chars, *src) || - strchr(extra_quote_chars, *src)) + for (src = str; *src != '\0'; src++) + if (Strchr(break_chars, *src) || + Strchr(extra_quote_chars, *src)) extra_len++; quoted_str = malloc(sizeof(*quoted_str) * - (strlen(str) + extra_len + 1)); + (strlen(str) + extra_len + 1)); if (quoted_str == NULL) return NULL; dst = quoted_str; - if (*str == '-' || *str == '+') - *dst++ = '.', *dst++ = '/'; for (src = str; *src != '\0'; src++) { - if (strchr(break_chars, *src) || - strchr(extra_quote_chars, *src)) + if (Strchr(break_chars, *src) || + Strchr(extra_quote_chars, *src)) *dst++ = '\\'; *dst++ = *src; } @@ -621,14 +656,13 @@ sh_quote(const char *str) return quoted_str; } - -static char * -sh_dequote(const char *str) +static Char * +sh_dequote(const Char *str) { - char *dequoted_str, *dst; + Char *dequoted_str, *dst; /* save extra space to replace \~ with ./~ */ - dequoted_str = malloc(sizeof(*dequoted_str) * (strlen(str) + 1 + 1)); + dequoted_str = malloc(sizeof(*dequoted_str) * (Strlen(str) + 1 + 1)); if (dequoted_str == NULL) return NULL; @@ -652,7 +686,6 @@ sh_dequote(const char *str) return dequoted_str; } - /* * completion function using sh quoting rules; for key binding */ |