diff options
Diffstat (limited to 'contrib/libreadline/complete.c')
-rw-r--r-- | contrib/libreadline/complete.c | 824 |
1 files changed, 483 insertions, 341 deletions
diff --git a/contrib/libreadline/complete.c b/contrib/libreadline/complete.c index 552cb6c..985e898 100644 --- a/contrib/libreadline/complete.c +++ b/contrib/libreadline/complete.c @@ -75,6 +75,7 @@ extern char *tilde_expand (); extern char *rl_copy_text (); extern void _rl_abort_internal (); extern int _rl_qsort_string_compare (); +extern void _rl_replace_text (); extern Function *rl_last_func; extern int rl_editing_mode; @@ -88,26 +89,32 @@ extern int rl_display_fixed; char *filename_completion_function (); char **completion_matches (); +#if defined (VISIBLE_STATS) +# if !defined (X_OK) +# define X_OK 1 +# endif +static int stat_char (); +#endif + static char *rl_quote_filename (); static char *rl_strpbrk (); static char **remove_duplicate_matches (); -static void insert_text (); static void insert_match (); -static void append_to_match (); +static int append_to_match (); static void insert_all_matches (); static void display_matches (); static int compute_lcd_of_matches (); extern char *xmalloc (), *xrealloc (); -/* 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. */ -Function *rl_directory_completion_hook = (Function *)NULL; +/* **************************************************************** */ +/* */ +/* Completion matching, from readline's point of view. */ +/* */ +/* **************************************************************** */ -/* Non-zero means readline completion functions perform tilde expansion. */ -int rl_complete_with_tilde_expansion = 0; +/* Variables known only to the readline library. */ /* If non-zero, non-unique completions always show the list of matches. */ int _rl_complete_show_all = 0; @@ -115,27 +122,29 @@ int _rl_complete_show_all = 0; /* If non-zero, completed directory names have a slash appended. */ int _rl_complete_mark_directories = 1; -#if defined (VISIBLE_STATS) -# if !defined (X_OK) -# define X_OK 1 -# endif +/* If non-zero, completions are printed horizontally in alphabetical order, + like `ls -x'. */ +int _rl_print_completions_horizontally; -static int stat_char (); +/* Non-zero means that case is not significant in filename completion. */ +int _rl_completion_case_fold; + +/* Global variables available to applications using readline. */ +#if defined (VISIBLE_STATS) /* Non-zero means add an additional character to each filename displayed during listing completion iff rl_filename_completion_desired which helps to indicate the type of file being listed. */ int rl_visible_stats = 0; #endif /* VISIBLE_STATS */ -/* **************************************************************** */ -/* */ -/* Completion matching, from readline's point of view. */ -/* */ -/* **************************************************************** */ +/* 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. */ +Function *rl_directory_completion_hook = (Function *)NULL; -/* Local variable states what happened during the last completion attempt. */ -static int completion_changed_buffer; +/* Non-zero means readline completion functions perform tilde expansion. */ +int rl_complete_with_tilde_expansion = 0; /* Pointer to the generator function for completion_matches (). NULL means to use filename_completion_function (), the default filename @@ -242,6 +251,17 @@ int rl_completion_append_character = ' '; /* If non-zero, inhibit completion (temporarily). */ int rl_inhibit_completion; +/* Variables local to this file. */ + +/* Local variable states what happened during the last completion attempt. */ +static int completion_changed_buffer; + +/*************************************/ +/* */ +/* Bindable completion functions */ +/* */ +/*************************************/ + /* Complete the word at or before point. You have supplied the function that does the initial simple matching selection algorithm (see completion_matches ()). The default is to do filename completion. */ @@ -274,6 +294,33 @@ rl_insert_completions (ignore, invoking_key) return (rl_complete_internal ('*')); } +/************************************/ +/* */ +/* Completion utility functions */ +/* */ +/************************************/ + +/* Find the first occurrence in STRING1 of any character from STRING2. + Return a pointer to the character in STRING1. */ +static char * +rl_strpbrk (string1, string2) + char *string1, *string2; +{ + register char *scan; + + for (; *string1; string1++) + { + for (scan = string2; *scan; scan++) + { + if (*string1 == *scan) + { + return (string1); + } + } + } + return ((char *)NULL); +} + /* The user must press "y" or "n". Non-zero return means "y" pressed. */ static int get_y_or_n () @@ -293,6 +340,63 @@ get_y_or_n () } } +#if defined (VISIBLE_STATS) +/* Return the character which best describes FILENAME. + `@' for symbolic links + `/' for directories + `*' for executables + `=' for sockets + `|' for FIFOs + `%' for character special devices + `#' for block special devices */ +static int +stat_char (filename) + char *filename; +{ + struct stat finfo; + int character, r; + +#if defined (HAVE_LSTAT) && defined (S_ISLNK) + r = lstat (filename, &finfo); +#else + r = stat (filename, &finfo); +#endif + + if (r == -1) + return (0); + + character = 0; + if (S_ISDIR (finfo.st_mode)) + character = '/'; +#if defined (S_ISCHR) + else if (S_ISCHR (finfo.st_mode)) + character = '%'; +#endif /* S_ISCHR */ +#if defined (S_ISBLK) + else if (S_ISBLK (finfo.st_mode)) + character = '#'; +#endif /* S_ISBLK */ +#if defined (S_ISLNK) + else if (S_ISLNK (finfo.st_mode)) + character = '@'; +#endif /* S_ISLNK */ +#if defined (S_ISSOCK) + else if (S_ISSOCK (finfo.st_mode)) + character = '='; +#endif /* S_ISSOCK */ +#if defined (S_ISFIFO) + else if (S_ISFIFO (finfo.st_mode)) + character = '|'; +#endif + else if (S_ISREG (finfo.st_mode)) + { + if (access (filename, X_OK) == 0) + character = '*'; + } + return (character); +} +#endif /* VISIBLE_STATS */ + /* 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 @@ -309,26 +413,34 @@ printable_part (pathname) /* Output TO_PRINT to rl_outstream. If VISIBLE_STATS is defined and we are using it, check for and output a single character for `special' - filenames. Return 1 if we printed an extension character, 0 if not. */ + filenames. Return the number of characters we output. */ #define PUTX(c) \ + do { \ if (CTRL_CHAR (c)) \ { \ putc ('^', rl_outstream); \ putc (UNCTRL (c), rl_outstream); \ + printed_len += 2; \ } \ else if (c == RUBOUT) \ { \ putc ('^', rl_outstream); \ putc ('?', rl_outstream); \ + printed_len += 2; \ } \ else \ - putc (c, rl_outstream) + { \ + putc (c, rl_outstream); \ + printed_len++; \ + } \ + } while (0) static int print_filename (to_print, full_pathname) char *to_print, *full_pathname; { + int printed_len = 0; #if !defined (VISIBLE_STATS) char *s; @@ -336,7 +448,6 @@ print_filename (to_print, full_pathname) { PUTX (*s); } - return 0; #else char *s, c, *new_full_pathname; int extension_char, slen, tlen; @@ -381,12 +492,13 @@ print_filename (to_print, full_pathname) free (s); if (extension_char) - putc (extension_char, rl_outstream); - return (extension_char != 0); + { + putc (extension_char, rl_outstream); + printed_len++; + } } - else - return 0; #endif /* VISIBLE_STATS */ + return printed_len; } static char * @@ -636,6 +748,125 @@ remove_duplicate_matches (matches) return (temp_array); } +/* Find the common prefix of the list of matches, and put it into + matches[0]. */ +static int +compute_lcd_of_matches (match_list, matches, text) + char **match_list; + int matches; + char *text; +{ + register int i, c1, c2, si; + int low; /* Count of max-matched characters. */ + + /* If only one match, just use that. Otherwise, compare each + member of the list with the next, finding out where they + stop matching. */ + if (matches == 1) + { + match_list[0] = match_list[1]; + match_list[1] = (char *)NULL; + return 1; + } + + for (i = 1, low = 100000; i < matches; i++) + { + if (_rl_completion_case_fold) + { + for (si = 0; + (c1 = _rl_to_lower(match_list[i][si])) && + (c2 = _rl_to_lower(match_list[i + 1][si])); + si++) + if (c1 != c2) + break; + } + else + { + for (si = 0; + (c1 = match_list[i][si]) && + (c2 = match_list[i + 1][si]); + si++) + if (c1 != c2) + break; + } + + if (low > si) + low = si; + } + + /* If there were multiple matches, but none matched up to even the + first character, and the user typed something, use that as the + value of matches[0]. */ + if (low == 0 && text && *text) + { + match_list[0] = xmalloc (strlen (text) + 1); + strcpy (match_list[0], text); + } + else + { + match_list[0] = xmalloc (low + 1); + strncpy (match_list[0], match_list[1], low); + match_list[0][low] = '\0'; + } + + return matches; +} + +static int +postprocess_matches (text, matchesp, matching_filenames) + char *text; + char ***matchesp; + int matching_filenames; +{ + char *t, **matches, **temp_matches; + int nmatch, i; + + matches = *matchesp; + + /* It seems to me that in all the cases we handle we would like + to ignore duplicate possiblilities. Scan for the text to + insert being identical to the other completions. */ + if (rl_ignore_completion_duplicates) + { + temp_matches = remove_duplicate_matches (matches); + free (matches); + matches = temp_matches; + } + + /* If we are matching filenames, then here is our chance to + do clever processing by re-examining the list. Call the + ignore function with the array as a parameter. It can + munge the array, deleting matches as it desires. */ + if (rl_ignore_some_completions_function && matching_filenames) + { + for (nmatch = 1; matches[nmatch]; nmatch++) + ; + (void)(*rl_ignore_some_completions_function) (matches); + if (matches == 0 || matches[0] == 0) + { + FREE (matches); + ding (); + *matchesp = (char **)0; + return 0; + } + else + { + /* If we removed some matches, recompute the common prefix. */ + for (i = 1; matches[i]; i++) + ; + if (i > 1 && i < nmatch) + { + t = matches[0]; + compute_lcd_of_matches (matches, i - 1, text); + FREE (t); + } + } + } + + *matchesp = matches; + return (1); +} + static void display_matches (matches) char **matches; @@ -718,25 +949,47 @@ display_matches (matches) if (rl_ignore_completion_duplicates == 0) qsort (matches + 1, len, sizeof (char *), _rl_qsort_string_compare); - /* Print the sorted items, up-and-down alphabetically, like ls. */ crlf (); - for (i = 1; i <= count; i++) + if (_rl_print_completions_horizontally == 0) { - for (j = 0, l = i; j < limit; j++) + /* Print the sorted items, up-and-down alphabetically, like ls. */ + for (i = 1; i <= count; i++) { - if (l > len || matches[l] == 0) - break; - else + for (j = 0, l = i; j < limit; j++) { - temp = printable_part (matches[l]); - printed_len = strlen (temp) + print_filename (temp, matches[l]); + if (l > len || matches[l] == 0) + break; + else + { + temp = printable_part (matches[l]); + printed_len = print_filename (temp, matches[l]); - if (j + 1 < limit) + if (j + 1 < limit) + for (k = 0; k < max - printed_len; k++) + putc (' ', rl_outstream); + } + l += count; + } + crlf (); + } + } + else + { + /* Print the sorted items, across alphabetically, like ls -x. */ + for (i = 1; matches[i]; i++) + { + temp = printable_part (matches[i]); + printed_len = print_filename (temp, matches[i]); + /* Have we reached the end of this line? */ + if (matches[i+1]) + { + if (i && (limit > 1) && (i % limit) == 0) + crlf (); + else for (k = 0; k < max - printed_len; k++) putc (' ', rl_outstream); } - l += count; } crlf (); } @@ -749,18 +1002,6 @@ display_matches (matches) #endif } -static void -insert_text (text, start, end) - char *text; - int start, end; -{ - rl_begin_undo_group (); - rl_delete_text (start, end + 1); - rl_point = start; - rl_insert_text (text); - rl_end_undo_group (); -} - static char * make_quoted_replacement (match, mtype, qc) char *match; @@ -833,7 +1074,7 @@ insert_match (match, start, mtype, qc) else if (qc && (*qc != oqc) && start && rl_line_buffer[start - 1] == oqc && replacement[0] != oqc) start--; - insert_text (replacement, start, rl_point - 1); + _rl_replace_text (replacement, start, rl_point - 1); if (replacement != match) free (replacement); } @@ -842,8 +1083,9 @@ insert_match (match, start, mtype, qc) /* Append any necessary closing quote and a separator character to the just-inserted match. If the user has specified that directories should be marked by a trailing `/', append one of those instead. The - default trailing character */ -static void + default trailing character is a space. Returns the number of characters + appended. */ +static int append_to_match (text, delimiter, quote_char) char *text; int delimiter, quote_char; @@ -883,6 +1125,8 @@ append_to_match (text, delimiter, quote_char) if (rl_point == rl_end) rl_insert_text (temp_string); } + + return (temp_string_index); } static void @@ -935,27 +1179,24 @@ int rl_complete_internal (what_to_do) int what_to_do; { - char **matches, **temp_matches; + char **matches; Function *our_func; - int start, end, delimiter, found_quote, nmatch, i; - char *text, *saved_line_buffer, *t; + int start, end, delimiter, found_quote, i; + char *text, *saved_line_buffer; char quote_char; - saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; - - our_func = rl_completion_entry_function - ? rl_completion_entry_function - : (Function *)filename_completion_function; - /* Only the completion entry function can change these. */ rl_filename_completion_desired = 0; rl_filename_quoting_desired = 1; - rl_completion_type = what_to_do; + saved_line_buffer = rl_line_buffer ? savestring (rl_line_buffer) : (char *)NULL; + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : (Function *)filename_completion_function; + /* We now look backwards for the start of a filename/variable word. */ end = rl_point; - found_quote = delimiter = 0; quote_char = '\0'; @@ -975,50 +1216,19 @@ rl_complete_internal (what_to_do) ding (); FREE (saved_line_buffer); free (text); - 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 - insert being identical to the other completions. */ - if (rl_ignore_completion_duplicates) - { - temp_matches = remove_duplicate_matches (matches); - free (matches); - matches = temp_matches; + return (0); } - /* If we are matching filenames, then here is our chance to - do clever processing by re-examining the list. Call the - ignore function with the array as a parameter. It can - munge the array, deleting matches as it desires. */ - if (rl_ignore_some_completions_function && - our_func == (Function *)filename_completion_function) + /* If we are matching filenames, our_func will have been set to + filename_completion_function */ + i = our_func == (Function *)filename_completion_function; + if (postprocess_matches (text, &matches, i) == 0) { - for (nmatch = 1; matches[nmatch]; nmatch++) - ; - (void)(*rl_ignore_some_completions_function) (matches); - if (matches == 0 || matches[0] == 0) - { - FREE (matches); - ding (); - FREE (saved_line_buffer); - FREE (text); - return 0; - } - else - { - /* If we removed some matches, recompute the common prefix. */ - for (i = 1; matches[i]; i++) - ; - if (i > 1 && i < nmatch) - { - t = matches[0]; - compute_lcd_of_matches (matches, i - 1, text); - FREE (t); - } - } + FREE (saved_line_buffer); + free (text); + return (0); } + free (text); switch (what_to_do) @@ -1081,62 +1291,67 @@ rl_complete_internal (what_to_do) return 0; } -#if defined (VISIBLE_STATS) -/* Return the character which best describes FILENAME. - `@' for symbolic links - `/' for directories - `*' for executables - `=' for sockets - `|' for FIFOs - `%' for character special devices - `#' for block special devices */ -static int -stat_char (filename) - char *filename; +/***************************************************************/ +/* */ +/* Application-callable completion match generator functions */ +/* */ +/***************************************************************/ + +/* Return an array of (char *) which is a list of completions for TEXT. + If there are no completions, return a NULL pointer. + The first entry in the returned array is the substitution for TEXT. + The remaining entries are the possible completions. + The array is terminated with a NULL pointer. + + ENTRY_FUNCTION is a function of two args, and returns a (char *). + The first argument is TEXT. + The second is a state argument; it should be zero on the first call, and + non-zero on subsequent calls. It returns a NULL pointer to the caller + when there are no more matches. + */ +char ** +completion_matches (text, entry_function) + char *text; + CPFunction *entry_function; { - struct stat finfo; - int character, r; + /* Number of slots in match_list. */ + int match_list_size; -#if defined (HAVE_LSTAT) && defined (S_ISLNK) - r = lstat (filename, &finfo); -#else - r = stat (filename, &finfo); -#endif + /* The list of matches. */ + char **match_list; - if (r == -1) - return (0); + /* Number of matches actually found. */ + int matches; - character = 0; - if (S_ISDIR (finfo.st_mode)) - character = '/'; -#if defined (S_ISCHR) - else if (S_ISCHR (finfo.st_mode)) - character = '%'; -#endif /* S_ISCHR */ -#if defined (S_ISBLK) - else if (S_ISBLK (finfo.st_mode)) - character = '#'; -#endif /* S_ISBLK */ -#if defined (S_ISLNK) - else if (S_ISLNK (finfo.st_mode)) - character = '@'; -#endif /* S_ISLNK */ -#if defined (S_ISSOCK) - else if (S_ISSOCK (finfo.st_mode)) - character = '='; -#endif /* S_ISSOCK */ -#if defined (S_ISFIFO) - else if (S_ISFIFO (finfo.st_mode)) - character = '|'; -#endif - else if (S_ISREG (finfo.st_mode)) + /* Temporary string binder. */ + char *string; + + matches = 0; + match_list_size = 10; + match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); + match_list[1] = (char *)NULL; + + while (string = (*entry_function) (text, matches)) { - if (access (filename, X_OK) == 0) - character = '*'; + if (matches + 1 == match_list_size) + match_list = (char **)xrealloc + (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); + + match_list[++matches] = string; + match_list[matches + 1] = (char *)NULL; } - return (character); + + /* If there were any matches, then look through them finding out the + lowest common denominator. That then becomes match_list[0]. */ + if (matches) + compute_lcd_of_matches (match_list, matches, text); + else /* There were no matches. */ + { + free (match_list); + match_list = (char **)NULL; + } + return (match_list); } -#endif /* VISIBLE_STATS */ /* A completion function for usernames. TEXT contains a partial username preceded by a random @@ -1194,135 +1409,6 @@ username_completion_function (text, state) #endif /* !__GO32__ */ } -/* **************************************************************** */ -/* */ -/* Completion */ -/* */ -/* **************************************************************** */ - -/* Non-zero means that case is not significant in completion. */ -int completion_case_fold = 0; - -/* Find the common prefix of the list of matches, and put it into - matches[0]. */ -static int -compute_lcd_of_matches (match_list, matches, text) - char **match_list; - int matches; - char *text; -{ - register int i, c1, c2, si; - int low; /* Count of max-matched characters. */ - - /* If only one match, just use that. Otherwise, compare each - member of the list with the next, finding out where they - stop matching. */ - if (matches == 1) - { - match_list[0] = match_list[1]; - match_list[1] = (char *)NULL; - return 1; - } - - for (i = 1, low = 100000; i < matches; i++) - { - if (completion_case_fold) - { - for (si = 0; - (c1 = _rl_to_lower(match_list[i][si])) && - (c2 = _rl_to_lower(match_list[i + 1][si])); - si++) - if (c1 != c2) - break; - } - else - { - for (si = 0; - (c1 = match_list[i][si]) && - (c2 = match_list[i + 1][si]); - si++) - if (c1 != c2) - break; - } - - if (low > si) - low = si; - } - - /* If there were multiple matches, but none matched up to even the - first character, and the user typed something, use that as the - value of matches[0]. */ - if (low == 0 && text && *text) - { - match_list[0] = xmalloc (strlen (text) + 1); - strcpy (match_list[0], text); - } - else - { - match_list[0] = xmalloc (low + 1); - strncpy (match_list[0], match_list[1], low); - match_list[0][low] = '\0'; - } - - return matches; -} - -/* Return an array of (char *) which is a list of completions for TEXT. - If there are no completions, return a NULL pointer. - The first entry in the returned array is the substitution for TEXT. - The remaining entries are the possible completions. - The array is terminated with a NULL pointer. - - ENTRY_FUNCTION is a function of two args, and returns a (char *). - The first argument is TEXT. - The second is a state argument; it should be zero on the first call, and - non-zero on subsequent calls. It returns a NULL pointer to the caller - when there are no more matches. - */ -char ** -completion_matches (text, entry_function) - char *text; - CPFunction *entry_function; -{ - /* Number of slots in match_list. */ - int match_list_size; - - /* The list of matches. */ - char **match_list; - - /* Number of matches actually found. */ - int matches; - - /* Temporary string binder. */ - char *string; - - matches = 0; - match_list_size = 10; - match_list = (char **)xmalloc ((match_list_size + 1) * sizeof (char *)); - match_list[1] = (char *)NULL; - - while (string = (*entry_function) (text, matches)) - { - if (matches + 1 == match_list_size) - match_list = (char **)xrealloc - (match_list, ((match_list_size += 10) + 1) * sizeof (char *)); - - match_list[++matches] = string; - match_list[matches + 1] = (char *)NULL; - } - - /* If there were any matches, then look through them finding out the - lowest common denominator. That then becomes match_list[0]. */ - if (matches) - compute_lcd_of_matches (match_list, matches, text); - else /* There were no matches. */ - { - free (match_list); - match_list = (char **)NULL; - } - return (match_list); -} - /* 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 @@ -1421,10 +1507,20 @@ filename_completion_function (text, state) { /* Otherwise, if these match up to the length of filename, then it is a match. */ - if ((entry->d_name[0] == filename[0]) && - (((int)D_NAMLEN (entry)) >= filename_len) && - (strncmp (filename, entry->d_name, filename_len) == 0)) - break; + if (_rl_completion_case_fold) + { + if ((_rl_to_lower (entry->d_name[0]) == _rl_to_lower (filename[0])) && + (((int)D_NAMLEN (entry)) >= filename_len) && + (_rl_strnicmp (filename, entry->d_name, filename_len) == 0)) + break; + } + else + { + if ((entry->d_name[0] == filename[0]) && + (((int)D_NAMLEN (entry)) >= filename_len) && + (strncmp (filename, entry->d_name, filename_len) == 0)) + break; + } } } @@ -1487,74 +1583,120 @@ filename_completion_function (text, state) } } -/* A function for simple tilde expansion. */ +/* An initial implementation of a menu completion function a la tcsh. The + first time (if the last readline command was not rl_menu_complete), we + generate the list of matches. This code is very similar to the code in + rl_complete_internal -- there should be a way to combine the two. Then, + for each item in the list of matches, we insert the match in an undoable + fashion, with the appropriate character appended (this happens on the + second and subsequent consecutive calls to rl_menu_complete). When we + hit the end of the match list, we restore the original unmatched text, + ring the bell, and reset the counter to zero. */ int -rl_tilde_expand (ignore, key) - int ignore, key; +rl_menu_complete (count, ignore) + int count, ignore; { - register int start, end; - char *homedir, *temp; - int len; + Function *our_func; + int matching_filenames, found_quote; + + static char *orig_text; + static char **matches = (char **)0; + static int match_list_index = 0; + static int match_list_size = 0; + static int orig_start, orig_end; + static char quote_char; + static int delimiter; + + /* The first time through, we generate the list of matches and set things + up to insert them. */ + if (rl_last_func != rl_menu_complete) + { + /* Clean up from previous call, if any. */ + FREE (orig_text); + if (matches) + { + for (match_list_index = 0; matches[match_list_index]; match_list_index++) + free (matches[match_list_index]); + free (matches); + } - end = rl_point; - start = end - 1; + match_list_index = match_list_size = 0; + matches = (char **)NULL; - if (rl_point == rl_end && rl_line_buffer[rl_point] == '~') - { - homedir = tilde_expand ("~"); - insert_text (homedir, start, end); - return (0); - } - else if (rl_line_buffer[start] != '~') - { - for (; !whitespace (rl_line_buffer[start]) && start >= 0; start--) + /* Only the completion entry function can change these. */ + rl_filename_completion_desired = 0; + rl_filename_quoting_desired = 1; + rl_completion_type = '%'; + + our_func = rl_completion_entry_function + ? rl_completion_entry_function + : (Function *)filename_completion_function; + + /* We now look backwards for the start of a filename/variable word. */ + orig_end = rl_point; + found_quote = delimiter = 0; + quote_char = '\0'; + + if (rl_point) + /* This (possibly) changes rl_point. If it returns a non-zero char, + we know we have an open quote. */ + quote_char = find_completion_word (&found_quote, &delimiter); + + orig_start = rl_point; + rl_point = orig_end; + + orig_text = rl_copy_text (orig_start, orig_end); + matches = gen_completion_matches (orig_text, orig_start, orig_end, + our_func, found_quote, quote_char); + + /* If we are matching filenames, our_func will have been set to + filename_completion_function */ + matching_filenames = our_func == (Function *)filename_completion_function; + if (matches == 0 || postprocess_matches (orig_text, &matches, matching_filenames) == 0) + { + ding (); + FREE (matches); + matches = (char **)0; + FREE (orig_text); + orig_text = (char *)0; + completion_changed_buffer = 0; + return (0); + } + + for (match_list_size = 0; matches[match_list_size]; match_list_size++) ; - start++; + /* matches[0] is lcd if match_list_size > 1, but the circular buffer + code below should take care of it. */ } - end = start; - do - end++; - while (whitespace (rl_line_buffer[end]) == 0 && end < rl_end); - - if (whitespace (rl_line_buffer[end]) || end >= rl_end) - end--; + /* Now we have the list of matches. Replace the text between + rl_line_buffer[orig_start] and rl_line_buffer[rl_point] with + matches[match_list_index], and add any necessary closing char. */ - /* If the first character of the current word is a tilde, perform - tilde expansion and insert the result. If not a tilde, do - nothing. */ - if (rl_line_buffer[start] == '~') + if (matches == 0 || match_list_size == 0) { - len = end - start + 1; - temp = xmalloc (len + 1); - strncpy (temp, rl_line_buffer + start, len); - temp[len] = '\0'; - homedir = tilde_expand (temp); - free (temp); - - insert_text (homedir, start, end); + ding (); + FREE (matches); + matches = (char **)0; + completion_changed_buffer = 0; + return (0); } - return (0); -} - -/* Find the first occurrence in STRING1 of any character from STRING2. - Return a pointer to the character in STRING1. */ -static char * -rl_strpbrk (string1, string2) - char *string1, *string2; -{ - register char *scan; + match_list_index = (match_list_index + count) % match_list_size; + if (match_list_index < 0) + match_list_index += match_list_size; - for (; *string1; string1++) + if (match_list_index == 0) { - for (scan = string2; *scan; scan++) - { - if (*string1 == *scan) - { - return (string1); - } - } + ding (); + insert_match (orig_text, orig_start, MULT_MATCH, "e_char); } - return ((char *)NULL); + else + { + insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, "e_char); + append_to_match (matches[match_list_index], delimiter, quote_char); + } + + completion_changed_buffer = 1; + return (0); } |