summaryrefslogtreecommitdiff
path: root/lib/readline/complete.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/readline/complete.c')
-rw-r--r--lib/readline/complete.c824
1 files changed, 483 insertions, 341 deletions
diff --git a/lib/readline/complete.c b/lib/readline/complete.c
index 552cb6c6..985e8981 100644
--- a/lib/readline/complete.c
+++ b/lib/readline/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, &quote_char);
}
- return ((char *)NULL);
+ else
+ {
+ insert_match (matches[match_list_index], orig_start, SINGLE_MATCH, &quote_char);
+ append_to_match (matches[match_list_index], delimiter, quote_char);
+ }
+
+ completion_changed_buffer = 1;
+ return (0);
}