diff options
Diffstat (limited to 'complete.c')
-rw-r--r-- | complete.c | 373 |
1 files changed, 302 insertions, 71 deletions
@@ -1,6 +1,6 @@ /* complete.c -- filename completion for readline. */ -/* Copyright (C) 1987-2011 Free Software Foundation, Inc. +/* Copyright (C) 1987-2012 Free Software Foundation, Inc. This file is part of the GNU Readline Library (Readline), a library for reading lines of text with interactive input and history editing. @@ -31,6 +31,8 @@ # include <sys/file.h> #endif +#include <signal.h> + #if defined (HAVE_UNISTD_H) # include <unistd.h> #endif /* HAVE_UNISTD_H */ @@ -64,6 +66,10 @@ extern int errno; #include "xmalloc.h" #include "rlprivate.h" +#if defined (COLOR_SUPPORT) +# include "colors.h" +#endif + #ifdef __STDC__ typedef int QSFUNC (const void *, const void *); #else @@ -94,17 +100,27 @@ extern struct passwd *getpwent PARAMS((void)); longest string in that array. */ rl_compdisp_func_t *rl_completion_display_matches_hook = (rl_compdisp_func_t *)NULL; -#if defined (VISIBLE_STATS) +#if defined (VISIBLE_STATS) || defined (COLOR_SUPPORT) # if !defined (X_OK) # define X_OK 1 # endif +#endif + +#if defined (VISIBLE_STATS) static int stat_char PARAMS((char *)); #endif +#if defined (COLOR_SUPPORT) +static int colored_stat_start PARAMS((char *)); +static void colored_stat_end PARAMS((void)); +#endif + static int path_isdir PARAMS((const char *)); static char *rl_quote_filename PARAMS((char *, int, char *)); +static void _rl_complete_sigcleanup PARAMS((int, void *)); + static void set_completion_defaults PARAMS((int)); static int get_y_or_n PARAMS((int)); static int _rl_internal_pager PARAMS((int)); @@ -189,6 +205,12 @@ int _rl_completion_columns = -1; int rl_visible_stats = 0; #endif /* VISIBLE_STATS */ +#if defined (COLOR_SUPPORT) +/* Non-zero means to use colors to indicate file type when listing possible + completions. The colors used are taken from $LS_COLORS, if set. */ +int _rl_colored_stats = 0; +#endif + /* If non-zero, when completing in the middle of a word, don't insert characters from the match that match characters following point in the word. This means, for instance, completing when the cursor is @@ -206,6 +228,8 @@ rl_icppfunc_t *rl_directory_completion_hook = (rl_icppfunc_t *)NULL; rl_icppfunc_t *rl_directory_rewrite_hook = (rl_icppfunc_t *)NULL; +rl_icppfunc_t *rl_filename_stat_hook = (rl_icppfunc_t *)NULL; + /* If non-zero, this is the address of a function to call when reading directory entries from the filesystem for completion and comparing them to the partial word to be completed. The function should @@ -457,6 +481,15 @@ _rl_reset_completion_state () rl_completion_quote_character = 0; } +static void +_rl_complete_sigcleanup (sig, ptr) + int sig; + void *ptr; +{ + if (sig == SIGINT) /* XXX - for now */ + _rl_free_match_list ((char **)ptr); +} + /* Set default values for readline word completion. These are the variables that application completion functions can change or inspect. */ static void @@ -551,6 +584,8 @@ stat_char (filename) { struct stat finfo; int character, r; + char *f; + const char *fn; /* Short-circuit a //server on cygwin, since that will always behave as a directory. */ @@ -559,10 +594,20 @@ stat_char (filename) return '/'; #endif + f = 0; + if (rl_filename_stat_hook) + { + f = savestring (filename); + (*rl_filename_stat_hook) (&f); + fn = f; + } + else + fn = filename; + #if defined (HAVE_LSTAT) && defined (S_ISLNK) - r = lstat (filename, &finfo); + r = lstat (fn, &finfo); #else - r = stat (filename, &finfo); + r = stat (fn, &finfo); #endif if (r == -1) @@ -596,10 +641,29 @@ stat_char (filename) if (access (filename, X_OK) == 0) character = '*'; } + + free (f); return (character); } #endif /* VISIBLE_STATS */ +#if defined (COLOR_SUPPORT) +static int +colored_stat_start (filename) + char *filename; +{ + _rl_set_normal_color (); + return (_rl_print_color_indicator (filename)); +} + +static void +colored_stat_end () +{ + _rl_prep_non_filename_text (); + _rl_put_indicator (&_rl_color_indicator[C_CLR_TO_EOL]); +} +#endif + /* Return the portion of PATHNAME that should be output when listing possible completions. If we are hacking filename completion, we are only interested in the basename, the portion following the @@ -679,7 +743,7 @@ fnwidth (string) else { pos += clen; - w = wcwidth (wc); + w = WCWIDTH (wc); width += (w >= 0) ? w : 1; } #else @@ -766,7 +830,7 @@ fnprint (to_print, prefix_bytes) break; else { - w = wcwidth (wc); + w = WCWIDTH (wc); width = (w >= 0) ? w : 1; } fwrite (s, 1, tlen, rl_outstream); @@ -796,13 +860,20 @@ print_filename (to_print, full_pathname, prefix_bytes) char *s, c, *new_full_pathname, *dn; extension_char = 0; - printed_len = fnprint (to_print, prefix_bytes); +#if defined (COLOR_SUPPORT) + /* Defer printing if we want to prefix with a color indicator */ + if (_rl_colored_stats == 0 || rl_filename_completion_desired == 0) +#endif + printed_len = fnprint (to_print, prefix_bytes); + if (rl_filename_completion_desired && ( #if defined (VISIBLE_STATS) - if (rl_filename_completion_desired && (rl_visible_stats || _rl_complete_mark_directories)) -#else - if (rl_filename_completion_desired && _rl_complete_mark_directories) + rl_visible_stats || #endif +#if defined (COLOR_SUPPORT) + _rl_colored_stats || +#endif + _rl_complete_mark_directories)) { /* If to_print != full_pathname, to_print is the basename of the path passed. In this case, we try to expand the directory @@ -848,8 +919,28 @@ print_filename (to_print, full_pathname, prefix_bytes) extension_char = stat_char (new_full_pathname); else #endif - if (path_isdir (new_full_pathname)) - extension_char = '/'; + if (_rl_complete_mark_directories) + { + dn = 0; + if (rl_directory_completion_hook == 0 && rl_filename_stat_hook) + { + dn = savestring (new_full_pathname); + (*rl_filename_stat_hook) (&dn); + free (new_full_pathname); + new_full_pathname = dn; + } + if (path_isdir (new_full_pathname)) + extension_char = '/'; + } + +#if defined (COLOR_SUPPORT) + if (_rl_colored_stats) + { + colored_stat_start (new_full_pathname); + printed_len = fnprint (to_print, prefix_bytes); + colored_stat_end (); + } +#endif xfree (new_full_pathname); to_print[-1] = c; @@ -862,8 +953,18 @@ print_filename (to_print, full_pathname, prefix_bytes) extension_char = stat_char (s); else #endif - if (path_isdir (s)) + if (_rl_complete_mark_directories && path_isdir (s)) extension_char = '/'; + +#if defined (COLOR_SUPPORT) + if (_rl_colored_stats) + { + colored_stat_start (s); + printed_len = fnprint (to_print, prefix_bytes); + colored_stat_end (); + } +#endif + } xfree (s); @@ -1058,10 +1159,13 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char) variable rl_attempted_completion_function. */ if (rl_attempted_completion_function) { - _rl_interrupt_immediately++; matches = (*rl_attempted_completion_function) (text, start, end); - if (_rl_interrupt_immediately > 0) - _rl_interrupt_immediately--; + if (RL_SIG_RECEIVED()) + { + _rl_free_match_list (matches); + matches = 0; + RL_CHECK_SIGNALS (); + } if (matches || rl_attempted_completion_over) { @@ -1072,7 +1176,15 @@ gen_completion_matches (text, start, end, our_func, found_quote, quote_char) /* XXX -- filename dequoting moved into rl_filename_completion_function */ + /* rl_completion_matches will check for signals as well to avoid a long + delay while reading a directory. */ matches = rl_completion_matches (text, our_func); + if (RL_SIG_RECEIVED()) + { + _rl_free_match_list (matches); + matches = 0; + RL_CHECK_SIGNALS (); + } return matches; } @@ -1147,9 +1259,11 @@ compute_lcd_of_matches (match_list, matches, text) { register int i, c1, c2, si; int low; /* Count of max-matched characters. */ + int lx; char *dtext; /* dequoted TEXT, if needed */ #if defined (HANDLE_MULTIBYTE) int v; + size_t v1, v2; mbstate_t ps1, ps2; wchar_t wc1, wc2; #endif @@ -1182,14 +1296,20 @@ compute_lcd_of_matches (match_list, matches, text) #if defined (HANDLE_MULTIBYTE) if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) { - v = mbrtowc (&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1); - mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2); + v1 = mbrtowc(&wc1, match_list[i]+si, strlen (match_list[i]+si), &ps1); + v2 = mbrtowc (&wc2, match_list[i+1]+si, strlen (match_list[i+1]+si), &ps2); + if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2)) + { + if (c1 != c2) /* do byte comparison */ + break; + continue; + } wc1 = towlower (wc1); wc2 = towlower (wc2); if (wc1 != wc2) break; - else if (v > 1) - si += v - 1; + else if (v1 > 1) + si += v1 - 1; } else #endif @@ -1264,21 +1384,20 @@ compute_lcd_of_matches (match_list, matches, text) qsort (match_list+1, matches, sizeof(char *), (QSFUNC *)_rl_qsort_string_compare); si = strlen (text); - if (si <= low) - { - for (i = 1; i <= matches; i++) - if (strncmp (match_list[i], text, si) == 0) - { - strncpy (match_list[0], match_list[i], low); - break; - } - /* no casematch, use first entry */ - if (i > matches) - strncpy (match_list[0], match_list[1], low); - } - else - /* otherwise, just use the text the user typed. */ - strncpy (match_list[0], text, low); + lx = (si <= low) ? si : low; /* check shorter of text and matches */ + /* Try to preserve the case of what the user typed in the presence of + multiple matches: check each match for something that matches + what the user typed taking case into account; use it up to common + length of matches if one is found. If not, just use first match. */ + for (i = 1; i <= matches; i++) + if (strncmp (match_list[i], text, lx) == 0) + { + strncpy (match_list[0], match_list[i], low); + break; + } + /* no casematch, use first entry */ + if (i > matches) + strncpy (match_list[0], match_list[1], low); FREE (dtext); } @@ -1305,7 +1424,7 @@ postprocess_matches (matchesp, matching_filenames) return 0; /* It seems to me that in all the cases we handle we would like - to ignore duplicate possiblilities. Scan for the text to + to ignore duplicate possibilities. Scan for the text to insert being identical to the other completions. */ if (rl_ignore_completion_duplicates) { @@ -1463,7 +1582,7 @@ rl_display_match_list (matches, len, max) /* Have we reached the end of this line? */ if (matches[i+1]) { - if (i && (limit > 1) && (i % limit) == 0) + if (limit == 1 || (i && (limit > 1) && (i % limit) == 0)) { rl_crlf (); lines++; @@ -1672,7 +1791,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) char *text; int delimiter, quote_char, nontrivial_match; { - char temp_string[4], *filename; + char temp_string[4], *filename, *fn; int temp_string_index, s; struct stat finfo; @@ -1691,6 +1810,13 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) if (rl_filename_completion_desired) { filename = tilde_expand (text); + if (rl_filename_stat_hook) + { + fn = savestring (filename); + (*rl_filename_stat_hook) (&fn); + xfree (filename); + filename = fn; + } s = (nontrivial_match && rl_completion_mark_symlink_dirs == 0) ? LSTAT (filename, &finfo) : stat (filename, &finfo); @@ -1710,8 +1836,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) #ifdef S_ISLNK /* Don't add anything if the filename is a symlink and resolves to a directory. */ - else if (s == 0 && S_ISLNK (finfo.st_mode) && - stat (filename, &finfo) == 0 && S_ISDIR (finfo.st_mode)) + else if (s == 0 && S_ISLNK (finfo.st_mode) && path_isdir (filename)) ; #endif else @@ -1831,10 +1956,8 @@ rl_complete_internal (what_to_do) /* nontrivial_lcd is set if the common prefix adds something to the word being completed. */ nontrivial_lcd = matches && strcmp (text, matches[0]) != 0; -#if 1 if (what_to_do == '!' || what_to_do == '@') tlen = strlen (text); -#endif xfree (text); if (matches == 0) @@ -1868,10 +1991,6 @@ rl_complete_internal (what_to_do) case '!': case '@': /* Insert the first match with proper quoting. */ -#if 0 - if (*matches[0]) - insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); -#else if (what_to_do == TAB) { if (*matches[0]) @@ -1886,7 +2005,6 @@ rl_complete_internal (what_to_do) if (mlen >= tlen) insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); } -#endif /* If there are more matches, ring the bell to indicate. If we are in vi mode, Posix.2 says to not ring the bell. @@ -1922,7 +2040,14 @@ rl_complete_internal (what_to_do) break; case '?': + if (rl_completion_display_matches_hook == 0) + { + _rl_sigcleanup = _rl_complete_sigcleanup; + _rl_sigcleanarg = matches; + } display_matches (matches); + _rl_sigcleanup = 0; + _rl_sigcleanarg = 0; break; default: @@ -1930,6 +2055,7 @@ rl_complete_internal (what_to_do) rl_ding (); FREE (saved_line_buffer); RL_UNSETSTATE(RL_STATE_COMPLETING); + _rl_free_match_list (matches); _rl_reset_completion_state (); return 1; } @@ -1971,6 +2097,8 @@ rl_completion_matches (text, entry_function) const char *text; rl_compentry_func_t *entry_function; { + register int i; + /* Number of slots in match_list. */ int match_list_size; @@ -1988,18 +2116,36 @@ rl_completion_matches (text, entry_function) match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); match_list[1] = (char *)NULL; - _rl_interrupt_immediately++; while (string = (*entry_function) (text, matches)) { - if (matches + 1 == match_list_size) + if (RL_SIG_RECEIVED ()) + { + /* Start at 1 because we don't set matches[0] in this function. + Only free the list members if we're building match list from + rl_filename_completion_function, since we know that doesn't + free the strings it returns. */ + if (entry_function == rl_filename_completion_function) + { + for (i = 1; match_list[i]; i++) + xfree (match_list[i]); + } + xfree (match_list); + match_list = 0; + match_list_size = 0; + matches = 0; + RL_CHECK_SIGNALS (); + } + + if (matches + 1 >= match_list_size) match_list = (char **)xrealloc (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); + if (match_list == 0) + return (match_list); + match_list[++matches] = string; match_list[matches + 1] = (char *)NULL; } - if (_rl_interrupt_immediately > 0) - _rl_interrupt_immediately--; /* If there were any matches, then look through them finding out the lowest common denominator. That then becomes match_list[0]. */ @@ -2038,7 +2184,9 @@ rl_username_completion_function (text, state) username = savestring (&text[first_char_loc]); namelen = strlen (username); +#if defined (HAVE_GETPWENT) setpwent (); +#endif } #if defined (HAVE_GETPWENT) @@ -2075,8 +2223,9 @@ rl_username_completion_function (text, state) /* Return non-zero if CONVFN matches FILENAME up to the length of FILENAME (FILENAME_LEN). If _rl_completion_case_fold is set, compare without - regard to the alphabetic case of characters. CONVFN is the possibly- - converted directory entry; FILENAME is what the user typed. */ + regard to the alphabetic case of characters. If + _rl_completion_case_map is set, make `-' and `_' equivalent. CONVFN is + the possibly-converted directory entry; FILENAME is what the user typed. */ static int complete_fncmp (convfn, convlen, filename, filename_len) const char *convfn; @@ -2086,34 +2235,110 @@ complete_fncmp (convfn, convlen, filename, filename_len) { register char *s1, *s2; int d, len; +#if defined (HANDLE_MULTIBYTE) + size_t v1, v2; + mbstate_t ps1, ps2; + wchar_t wc1, wc2; +#endif + +#if defined (HANDLE_MULTIBYTE) + memset (&ps1, 0, sizeof (mbstate_t)); + memset (&ps2, 0, sizeof (mbstate_t)); +#endif + + if (filename_len == 0) + return 1; + if (convlen < filename_len) + return 0; + + len = filename_len; + s1 = (char *)convfn; + s2 = (char *)filename; /* Otherwise, if these match up to the length of filename, then it is a match. */ if (_rl_completion_case_fold && _rl_completion_case_map) { /* Case-insensitive comparison treating _ and - as equivalent */ - if (filename_len == 0) - return 1; - if (convlen < filename_len) - return 0; - s1 = (char *)convfn; - s2 = (char *)filename; - len = filename_len; - do +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + do + { + v1 = mbrtowc (&wc1, s1, convlen, &ps1); + v2 = mbrtowc (&wc2, s2, filename_len, &ps2); + if (v1 == 0 && v2 == 0) + return 1; + else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2)) + { + if (*s1 != *s2) /* do byte comparison */ + return 0; + else if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_')) + return 0; + s1++; s2++; len--; + continue; + } + wc1 = towlower (wc1); + wc2 = towlower (wc2); + s1 += v1; + s2 += v1; + len -= v1; + if ((wc1 == L'-' || wc1 == L'_') && (wc2 == L'-' || wc2 == L'_')) + continue; + if (wc1 != wc2) + return 0; + } + while (len != 0); + } + else +#endif { - d = _rl_to_lower (*s1) - _rl_to_lower (*s2); - /* *s1 == [-_] && *s2 == [-_] */ - if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_')) - d = 0; - if (d != 0) - return 0; - s1++; s2++; /* already checked convlen >= filename_len */ + do + { + d = _rl_to_lower (*s1) - _rl_to_lower (*s2); + /* *s1 == [-_] && *s2 == [-_] */ + if ((*s1 == '-' || *s1 == '_') && (*s2 == '-' || *s2 == '_')) + d = 0; + if (d != 0) + return 0; + s1++; s2++; /* already checked convlen >= filename_len */ + } + while (--len != 0); } - while (--len != 0); + return 1; } else if (_rl_completion_case_fold) { +#if defined (HANDLE_MULTIBYTE) + if (MB_CUR_MAX > 1 && rl_byte_oriented == 0) + { + do + { + v1 = mbrtowc (&wc1, s1, convlen, &ps1); + v2 = mbrtowc (&wc2, s2, filename_len, &ps2); + if (v1 == 0 && v2 == 0) + return 1; + else if (MB_INVALIDCH (v1) || MB_INVALIDCH (v2)) + { + if (*s1 != *s2) /* do byte comparison */ + return 0; + s1++; s2++; len--; + continue; + } + wc1 = towlower (wc1); + wc2 = towlower (wc2); + if (wc1 != wc2) + return 0; + s1 += v1; + s2 += v1; + len -= v1; + } + while (len != 0); + return 1; + } + else +#endif if ((_rl_to_lower (convfn[0]) == _rl_to_lower (filename[0])) && (convlen >= filename_len) && (_rl_strnicmp (filename, convfn, filename_len) == 0)) @@ -2233,8 +2458,9 @@ rl_filename_completion_function (text, state) } directory = opendir (dirname); - /* Now dequote a non-null filename. */ - if (filename && *filename && rl_completion_found_quote && rl_filename_dequoting_function) + /* Now dequote a non-null filename. FILENAME will not be NULL, but may + be empty. */ + if (*filename && rl_completion_found_quote && rl_filename_dequoting_function) { /* delete single and double quotes */ temp = (*rl_filename_dequoting_function) (filename, rl_completion_quote_character); @@ -2598,6 +2824,11 @@ rl_menu_complete (count, ignore) full_completion = 1; return (0); } + else if (_rl_menu_complete_prefix_first) + { + rl_ding (); + return (0); + } } else if (match_list_size <= 1) { |