From f4b417c62a4f272c4cf9a074d0f7a3a97201f9db Mon Sep 17 00:00:00 2001 From: Sebastian Schmidt Date: Tue, 17 Apr 2012 11:23:35 +0200 Subject: Update to upstream bash 4.2 This upgrades bash to from 4.1-rc to 4.2-release. See CWRU/changelog for changes. Change-Id: I926269c300cf44fa25964b5b375a148fcf11c4b7 --- lib/readline/complete.c | 260 ++++++++++++++++++++++++++++++++++++------------ 1 file changed, 195 insertions(+), 65 deletions(-) (limited to 'lib/readline/complete.c') diff --git a/lib/readline/complete.c b/lib/readline/complete.c index 2c7e696..6e5b4f8 100644 --- a/lib/readline/complete.c +++ b/lib/readline/complete.c @@ -1,6 +1,6 @@ /* complete.c -- filename completion for readline. */ -/* Copyright (C) 1987-2009 Free Software Foundation, Inc. +/* Copyright (C) 1987-2011 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. @@ -119,9 +119,11 @@ static char **remove_duplicate_matches PARAMS((char **)); static void insert_match PARAMS((char *, int, int, char *)); static int append_to_match PARAMS((char *, int, int, int)); static void insert_all_matches PARAMS((char **, int, char *)); +static int complete_fncmp PARAMS((const char *, int, const char *, int)); static void display_matches PARAMS((char **)); static int compute_lcd_of_matches PARAMS((char **, int, const char *)); static int postprocess_matches PARAMS((char ***, int)); +static int complete_get_screenwidth PARAMS((void)); static char *make_quoted_replacement PARAMS((char *, int, char *)); @@ -157,10 +159,14 @@ int _rl_print_completions_horizontally; #if defined (__MSDOS__) && !defined (__DJGPP__) int _rl_completion_case_fold = 1; #else -int _rl_completion_case_fold; +int _rl_completion_case_fold = 0; #endif -/* If non-zero, don't match hidden files (filenames beginning with a `.' on +/* Non-zero means that `-' and `_' are equivalent when comparing filenames + for completion. */ +int _rl_completion_case_map = 0; + +/* If zero, don't match hidden files (filenames beginning with a `.' on Unix) when doing filename completion. */ int _rl_match_hidden_files = 1; @@ -170,6 +176,10 @@ int _rl_match_hidden_files = 1; display prefix replaced with an ellipsis. */ int _rl_completion_prefix_display_length = 0; +/* The readline-private number of screen columns to use when displaying + matches. If < 0 or > _rl_screenwidth, it is ignored. */ +int _rl_completion_columns = -1; + /* Global variables available to applications using readline. */ #if defined (VISIBLE_STATS) @@ -185,6 +195,10 @@ int rl_visible_stats = 0; after the `e' in `Makefile' won't result in `Makefilefile'. */ int _rl_skip_completed_text = 0; +/* If non-zero, menu completion displays the common prefix first in the + cycle of possible completions instead of the last. */ +int _rl_menu_complete_prefix_first = 0; + /* If non-zero, then this is the address of a function to call when completing on a directory name. The function is called with the address of a string (the current directory name) as an arg. */ @@ -467,6 +481,14 @@ get_y_or_n (for_pager) { int c; + /* For now, disable pager in callback mode, until we later convert to state + driven functions. Have to wait until next major version to add new + state definition, since it will change value of RL_STATE_DONE. */ +#if defined (READLINE_CALLBACKS) + if (RL_ISSTATE (RL_STATE_CALLBACK)) + return 1; +#endif + for (;;) { RL_SETSTATE(RL_STATE_MOREINPUT); @@ -829,7 +851,7 @@ print_filename (to_print, full_pathname, prefix_bytes) if (path_isdir (new_full_pathname)) extension_char = '/'; - free (new_full_pathname); + xfree (new_full_pathname); to_print[-1] = c; } else @@ -844,7 +866,7 @@ print_filename (to_print, full_pathname, prefix_bytes) extension_char = '/'; } - free (s); + xfree (s); if (extension_char) { putc (extension_char, rl_outstream); @@ -1081,7 +1103,7 @@ remove_duplicate_matches (matches) { if (strcmp (matches[i], matches[i + 1]) == 0) { - free (matches[i]); + xfree (matches[i]); matches[i] = (char *)&dead_slot; } else @@ -1099,7 +1121,7 @@ remove_duplicate_matches (matches) temp_array[j] = (char *)NULL; if (matches[0] != (char *)&dead_slot) - free (matches[0]); + xfree (matches[0]); /* Place the lowest common denominator back in [0]. */ temp_array[0] = lowest_common; @@ -1109,7 +1131,7 @@ remove_duplicate_matches (matches) insert. */ if (j == 2 && strcmp (temp_array[0], temp_array[1]) == 0) { - free (temp_array[1]); + xfree (temp_array[1]); temp_array[1] = (char *)NULL; } return (temp_array); @@ -1288,7 +1310,7 @@ postprocess_matches (matchesp, matching_filenames) if (rl_ignore_completion_duplicates) { temp_matches = remove_duplicate_matches (matches); - free (matches); + xfree (matches); matches = temp_matches; } @@ -1325,6 +1347,23 @@ postprocess_matches (matchesp, matching_filenames) return (1); } +static int +complete_get_screenwidth () +{ + int cols; + char *envcols; + + cols = _rl_completion_columns; + if (cols >= 0 && cols <= _rl_screenwidth) + return cols; + envcols = getenv ("COLUMNS"); + if (envcols && *envcols) + cols = atoi (envcols); + if (cols >= 0 && cols <= _rl_screenwidth) + return cols; + return _rl_screenwidth; +} + /* A convenience function for displaying a list of strings in columnar format on readline's output stream. MATCHES is the list of strings, in argv format, LEN is the number of strings in MATCHES, @@ -1334,7 +1373,7 @@ rl_display_match_list (matches, len, max) char **matches; int len, max; { - int count, limit, printed_len, lines; + int count, limit, printed_len, lines, cols; int i, j, k, l, common_length, sind; char *temp, *t; @@ -1355,12 +1394,17 @@ rl_display_match_list (matches, len, max) } /* How many items of MAX length can we fit in the screen window? */ + cols = complete_get_screenwidth (); max += 2; - limit = _rl_screenwidth / max; - if (limit != 1 && (limit * max == _rl_screenwidth)) + limit = cols / max; + if (limit != 1 && (limit * max == cols)) limit--; - /* Avoid a possible floating exception. If max > _rl_screenwidth, + /* If cols == 0, limit will end up -1 */ + if (cols < _rl_screenwidth && limit < 0) + limit = 1; + + /* Avoid a possible floating exception. If max > cols, limit will be 0 and a divide-by-zero fault will result. */ if (limit == 0) limit = 1; @@ -1608,7 +1652,7 @@ insert_match (match, start, mtype, qc) else _rl_replace_text (replacement, start, end); if (replacement != match) - free (replacement); + xfree (replacement); } } @@ -1675,7 +1719,7 @@ append_to_match (text, delimiter, quote_char, nontrivial_match) if (rl_point == rl_end && temp_string_index) rl_insert_text (temp_string); } - free (filename); + xfree (filename); } else { @@ -1711,7 +1755,7 @@ insert_all_matches (matches, point, qc) rl_insert_text (rp); rl_insert_text (" "); if (rp != matches[i]) - free (rp); + xfree (rp); } } else @@ -1720,7 +1764,7 @@ insert_all_matches (matches, point, qc) rl_insert_text (rp); rl_insert_text (" "); if (rp != matches[0]) - free (rp); + xfree (rp); } rl_end_undo_group (); } @@ -1735,8 +1779,8 @@ _rl_free_match_list (matches) return; for (i = 0; matches[i]; i++) - free (matches[i]); - free (matches); + xfree (matches[i]); + xfree (matches); } /* Complete the word at or before point. @@ -1757,6 +1801,9 @@ rl_complete_internal (what_to_do) int start, end, delimiter, found_quote, i, nontrivial_lcd; char *text, *saved_line_buffer; char quote_char; +#if 1 + int tlen, mlen; +#endif RL_SETSTATE(RL_STATE_COMPLETING); @@ -1784,7 +1831,11 @@ 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; - free (text); +#if 1 + if (what_to_do == '!' || what_to_do == '@') + tlen = strlen (text); +#endif + xfree (text); if (matches == 0) { @@ -1817,8 +1868,25 @@ 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]) + insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); + } + else if (*matches[0] && matches[1] == 0) + /* should we perform the check only if there are multiple matches? */ + insert_match (matches[0], start, matches[1] ? MULT_MATCH : SINGLE_MATCH, "e_char); + else if (*matches[0]) /* what_to_do != TAB && multiple matches */ + { + mlen = *matches[0] ? strlen (matches[0]) : 0; + 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. @@ -1872,7 +1940,7 @@ rl_complete_internal (what_to_do) if (saved_line_buffer) { completion_changed_buffer = strcmp (rl_line_buffer, saved_line_buffer) != 0; - free (saved_line_buffer); + xfree (saved_line_buffer); } RL_UNSETSTATE(RL_STATE_COMPLETING); @@ -1939,7 +2007,7 @@ rl_completion_matches (text, entry_function) compute_lcd_of_matches (match_list, matches, text); else /* There were no matches. */ { - free (match_list); + xfree (match_list); match_list = (char **)NULL; } return (match_list); @@ -2005,6 +2073,62 @@ rl_username_completion_function (text, state) #endif /* !__WIN32__ && !__OPENNT */ } +/* 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. */ +static int +complete_fncmp (convfn, convlen, filename, filename_len) + const char *convfn; + int convlen; + const char *filename; + int filename_len; +{ + register char *s1, *s2; + int d, len; + + /* 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 + { + 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); + return 1; + } + else if (_rl_completion_case_fold) + { + if ((_rl_to_lower (convfn[0]) == _rl_to_lower (filename[0])) && + (convlen >= filename_len) && + (_rl_strnicmp (filename, convfn, filename_len) == 0)) + return 1; + } + else + { + if ((convfn[0] == filename[0]) && + (convlen >= filename_len) && + (strncmp (filename, convfn, filename_len) == 0)) + return 1; + } + return 0; +} + /* Okay, now we write the entry_function for filename completion. In the general case. Note that completion in the shell is a little different because of all the pathnames that must be followed when looking up the @@ -2071,32 +2195,41 @@ rl_filename_completion_function (text, state) /* We aren't done yet. We also support the "~user" syntax. */ - /* Save the version of the directory that the user typed. */ - users_dirname = savestring (dirname); + /* Save the version of the directory that the user typed, dequoting + it if necessary. */ + if (rl_completion_found_quote && rl_filename_dequoting_function) + users_dirname = (*rl_filename_dequoting_function) (dirname, rl_completion_quote_character); + else + users_dirname = savestring (dirname); if (*dirname == '~') { temp = tilde_expand (dirname); - free (dirname); + xfree (dirname); dirname = temp; } + /* We have saved the possibly-dequoted version of the directory name + the user typed. Now transform the directory name we're going to + pass to opendir(2). The directory rewrite hook modifies only the + directory name; the directory completion hook modifies both the + directory name passed to opendir(2) and the version the user + typed. Both the directory completion and rewrite hooks should perform + any necessary dequoting. The hook functions return 1 if they modify + the directory name argument. If either hook returns 0, it should + not modify the directory name pointer passed as an argument. */ if (rl_directory_rewrite_hook) (*rl_directory_rewrite_hook) (&dirname); - - /* The directory completion hook should perform any necessary - dequoting. */ - if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname)) + else if (rl_directory_completion_hook && (*rl_directory_completion_hook) (&dirname)) { - free (users_dirname); + xfree (users_dirname); users_dirname = savestring (dirname); } else if (rl_completion_found_quote && rl_filename_dequoting_function) { /* delete single and double quotes */ - temp = (*rl_filename_dequoting_function) (users_dirname, rl_completion_quote_character); - free (users_dirname); - users_dirname = temp; + xfree (dirname); + dirname = savestring (users_dirname); } directory = opendir (dirname); @@ -2105,7 +2238,7 @@ rl_filename_completion_function (text, state) { /* delete single and double quotes */ temp = (*rl_filename_dequoting_function) (filename, rl_completion_quote_character); - free (filename); + xfree (filename); filename = temp; } filename_len = strlen (filename); @@ -2147,22 +2280,8 @@ rl_filename_completion_function (text, state) } else { - /* Otherwise, if these match up to the length of filename, then - it is a match. */ - if (_rl_completion_case_fold) - { - if ((_rl_to_lower (convfn[0]) == _rl_to_lower (filename[0])) && - (convlen >= filename_len) && - (_rl_strnicmp (filename, convfn, filename_len) == 0)) - break; - } - else - { - if ((convfn[0] == filename[0]) && - (convlen >= filename_len) && - (strncmp (filename, convfn, filename_len) == 0)) - break; - } + if (complete_fncmp (convfn, convlen, filename, filename_len)) + break; } } @@ -2175,17 +2294,17 @@ rl_filename_completion_function (text, state) } if (dirname) { - free (dirname); + xfree (dirname); dirname = (char *)NULL; } if (filename) { - free (filename); + xfree (filename); filename = (char *)NULL; } if (users_dirname) { - free (users_dirname); + xfree (users_dirname); users_dirname = (char *)NULL; } @@ -2225,7 +2344,7 @@ rl_filename_completion_function (text, state) temp = savestring (convfn); if (convfn != dentry) - free (convfn); + xfree (convfn); return (temp); } @@ -2304,14 +2423,14 @@ rl_old_menu_complete (count, invoking_key) if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0) { - rl_ding (); + rl_ding (); FREE (matches); matches = (char **)0; FREE (orig_text); orig_text = (char *)0; - completion_changed_buffer = 0; - RL_UNSETSTATE(RL_STATE_COMPLETING); - return (0); + completion_changed_buffer = 0; + RL_UNSETSTATE(RL_STATE_COMPLETING); + return (0); } RL_UNSETSTATE(RL_STATE_COMPLETING); @@ -2340,7 +2459,10 @@ rl_old_menu_complete (count, invoking_key) match_list_index += count; if (match_list_index < 0) - match_list_index += match_list_size; + { + while (match_list_index < 0) + match_list_index += match_list_size; + } else match_list_index %= match_list_size; @@ -2375,7 +2497,7 @@ rl_menu_complete (count, ignore) static int full_completion = 0; /* set to 1 if menu completion should reinitialize on next call */ static int orig_start, orig_end; static char quote_char; - static int delimiter; + static int delimiter, cstate; /* The first time through, we generate the list of matches and set things up to insert them. */ @@ -2428,14 +2550,14 @@ rl_menu_complete (count, ignore) if (matches == 0 || postprocess_matches (&matches, matching_filenames) == 0) { - rl_ding (); + rl_ding (); FREE (matches); matches = (char **)0; FREE (orig_text); orig_text = (char *)0; - completion_changed_buffer = 0; - RL_UNSETSTATE(RL_STATE_COMPLETING); - return (0); + completion_changed_buffer = 0; + RL_UNSETSTATE(RL_STATE_COMPLETING); + return (0); } RL_UNSETSTATE(RL_STATE_COMPLETING); @@ -2483,6 +2605,11 @@ rl_menu_complete (count, ignore) full_completion = 1; return (0); } + else if (_rl_menu_complete_prefix_first && match_list_size > 1) + { + rl_ding (); + return (0); + } } /* Now we have the list of matches. Replace the text between @@ -2500,7 +2627,10 @@ rl_menu_complete (count, ignore) match_list_index += count; if (match_list_index < 0) - match_list_index += match_list_size; + { + while (match_list_index < 0) + match_list_index += match_list_size; + } else match_list_index %= match_list_size; -- cgit v1.1