aboutsummaryrefslogtreecommitdiffstats
path: root/pcomplete.c
diff options
context:
space:
mode:
authorChet Ramey <chet.ramey@case.edu>2011-11-21 20:51:19 -0500
committerChet Ramey <chet.ramey@case.edu>2011-11-21 20:51:19 -0500
commit0001803f0b9523c94fa2ede48eaecb047fef4524 (patch)
treef334332811e033ff966d94f6268f0629a94304b3 /pcomplete.c
parent89a92869e56aba4e4cab2d639c00a86f0545c862 (diff)
downloadandroid_external_bash-0001803f0b9523c94fa2ede48eaecb047fef4524.tar.gz
android_external_bash-0001803f0b9523c94fa2ede48eaecb047fef4524.tar.bz2
android_external_bash-0001803f0b9523c94fa2ede48eaecb047fef4524.zip
Bash-4.1 distribution source
Diffstat (limited to 'pcomplete.c')
-rw-r--r--pcomplete.c175
1 files changed, 128 insertions, 47 deletions
diff --git a/pcomplete.c b/pcomplete.c
index 40fcc34..e4f2059 100644
--- a/pcomplete.c
+++ b/pcomplete.c
@@ -66,6 +66,8 @@
#include <readline/readline.h>
#include <readline/history.h>
+#define PCOMP_RETRYFAIL 256
+
#ifdef STRDUP
# undef STRDUP
#endif
@@ -118,10 +120,15 @@ static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *));
static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *));
static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *,
char *, int, WORD_LIST *,
- int, int));
+ int, int, int *));
static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, char *,
int, WORD_LIST *, int, int));
+static STRINGLIST *gen_progcomp_completions __P((const char *, const char *,
+ const char *,
+ int, int, int *, int *,
+ COMPSPEC **));
+
static char *pcomp_filename_completion_function __P((const char *, int));
#if defined (ARRAY_VARS)
@@ -653,7 +660,7 @@ gen_matches_from_itemlist (itp, text)
if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) ||
(itp->flags & LIST_INITIALIZED) == 0)
{
- if (itp->flags & (LIST_DIRTY | LIST_DYNAMIC))
+ if (itp->flags & (LIST_DIRTY|LIST_DYNAMIC))
clean_itemlist (itp);
if ((itp->flags & LIST_INITIALIZED) == 0)
initialize_itemlist (itp);
@@ -827,7 +834,7 @@ gen_wordlist_matches (cs, text)
do -- there's no way to split a simple list into individual words
that way, since the shell semantics say that word splitting is done
only on the results of expansion. */
- l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, (int *)NULL, (int *)NULL);
+ l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, 0, (int *)NULL, (int *)NULL);
if (l == 0)
return ((STRINGLIST *)NULL);
/* This will jump back to the top level if the expansion fails... */
@@ -992,25 +999,30 @@ build_arg_list (cmd, text, lwords, ind)
variable, this does nothing if arrays are not compiled into the shell. */
static STRINGLIST *
-gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
+gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw, foundp)
COMPSPEC *cs;
const char *text;
char *line;
int ind;
WORD_LIST *lwords;
int nw, cw;
+ int *foundp;
{
char *funcname;
STRINGLIST *sl;
SHELL_VAR *f, *v;
WORD_LIST *cmdlist;
- int fval;
+ int fval, found;
sh_parser_state_t ps;
sh_parser_state_t * restrict pps;
#if defined (ARRAY_VARS)
ARRAY *a;
#endif
+ found = 0;
+ if (foundp)
+ *foundp = found;
+
funcname = cs->funcname;
f = find_function (funcname);
if (f == 0)
@@ -1043,6 +1055,12 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
discard_unwind_frame ("gen-shell-function-matches");
restore_parser_state (pps);
+ found = fval != EX_NOTFOUND;
+ if (fval == EX_RETRYFAIL)
+ found |= PCOMP_RETRYFAIL;
+ if (foundp)
+ *foundp = found;
+
/* Now clean up and destroy everything. */
dispose_words (cmdlist);
unbind_compfunc_variables (0);
@@ -1057,7 +1075,7 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
VUNSETATTR (v, att_invisible);
a = array_cell (v);
- if (a == 0 || array_empty (a))
+ if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_empty (a))
sl = (STRINGLIST *)NULL;
else
{
@@ -1175,33 +1193,34 @@ command_line_to_word_list (line, llen, sentinel, nwp, cwp)
{
WORD_LIST *ret;
char *delims;
- int i, j;
-
- delims = xmalloc (strlen (rl_completer_word_break_characters) + 1);
- for (i = j = 0; rl_completer_word_break_characters[i]; i++)
- if (rl_completer_word_break_characters[i] != '\'' && rl_completer_word_break_characters[i] != '"')
- delims[j++] = rl_completer_word_break_characters[i];
- delims[j] = '\0';
- ret = split_at_delims (line, llen, delims, sentinel, nwp, cwp);
- free (delims);
+
+#if 0
+ delims = "()<>;&| \t\n"; /* shell metacharacters break words */
+#else
+ delims = rl_completer_word_break_characters;
+#endif
+ ret = split_at_delims (line, llen, delims, sentinel, SD_NOQUOTEDELIM, nwp, cwp);
return (ret);
}
/* Evaluate COMPSPEC *cs and return all matches for WORD. */
STRINGLIST *
-gen_compspec_completions (cs, cmd, word, start, end)
+gen_compspec_completions (cs, cmd, word, start, end, foundp)
COMPSPEC *cs;
const char *cmd;
const char *word;
int start, end;
+ int *foundp;
{
STRINGLIST *ret, *tmatches;
char *line;
- int llen, nw, cw;
+ int llen, nw, cw, found, foundf;
WORD_LIST *lwords;
COMPSPEC *tcs;
+ found = 1;
+
#ifdef DEBUG
debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end);
debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs);
@@ -1286,7 +1305,10 @@ gen_compspec_completions (cs, cmd, word, start, end)
if (cs->funcname)
{
- tmatches = gen_shell_function_matches (cs, word, line, rl_point - start, lwords, nw, cw);
+ foundf = 0;
+ tmatches = gen_shell_function_matches (cs, word, line, rl_point - start, lwords, nw, cw, &foundf);
+ if (foundf != 0)
+ found = foundf;
if (tmatches)
{
#ifdef DEBUG
@@ -1327,6 +1349,15 @@ gen_compspec_completions (cs, cmd, word, start, end)
FREE (line);
}
+ if (foundp)
+ *foundp = found;
+
+ if (found == 0 || (found & PCOMP_RETRYFAIL))
+ {
+ strlist_dispose (ret);
+ return NULL;
+ }
+
if (cs->filterpat)
{
tmatches = filter_stringlist (ret, cs->filterpat, word);
@@ -1401,35 +1432,28 @@ pcomp_set_compspec_options (cs, flags, set_or_unset)
cs->options &= ~flags;
}
-/* The driver function for the programmable completion code. Returns a list
- of matches for WORD, which is an argument to command CMD. START and END
- bound the command currently being completed in rl_line_buffer. */
-char **
-programmable_completions (cmd, word, start, end, foundp)
+static STRINGLIST *
+gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs)
+ const char *ocmd;
const char *cmd;
const char *word;
- int start, end, *foundp;
+ int start, end;
+ int *foundp, *retryp;
+ COMPSPEC **lastcs;
{
COMPSPEC *cs, *oldcs;
- STRINGLIST *ret;
- char **rmatches, *t;
const char *oldcmd;
+ STRINGLIST *ret;
- /* We look at the basename of CMD if the full command does not have
- an associated COMPSPEC. */
- cs = progcomp_search (cmd);
- if (cs == 0)
- {
- t = strrchr (cmd, '/');
- if (t)
- cs = progcomp_search (++t);
- }
- if (cs == 0)
- {
- if (foundp)
- *foundp = 0;
- return ((char **)NULL);
- }
+ cs = progcomp_search (ocmd);
+
+ if (cs == 0 || cs == *lastcs)
+ return (NULL);
+
+ if (*lastcs)
+ compspec_dispose (*lastcs);
+ cs->refcount++; /* XXX */
+ *lastcs = cs;
cs = compspec_copy (cs);
@@ -1439,17 +1463,68 @@ programmable_completions (cmd, word, start, end, foundp)
pcomp_curcs = cs;
pcomp_curcmd = cmd;
- /* Signal the caller that we found a COMPSPEC for this command, and pass
- back any meta-options associated with the compspec. */
- if (foundp)
- *foundp = 1|cs->options;
-
- ret = gen_compspec_completions (cs, cmd, word, start, end);
+ ret = gen_compspec_completions (cs, cmd, word, start, end, foundp);
pcomp_curcs = oldcs;
pcomp_curcmd = oldcmd;
+ /* We need to conditionally handle setting *retryp here */
+ if (retryp)
+ *retryp = foundp && (*foundp & PCOMP_RETRYFAIL);
+
+ if (foundp)
+ {
+ *foundp &= ~PCOMP_RETRYFAIL;
+ *foundp |= cs->options;
+ }
+
compspec_dispose (cs);
+ return ret;
+}
+
+/* The driver function for the programmable completion code. Returns a list
+ of matches for WORD, which is an argument to command CMD. START and END
+ bound the command currently being completed in rl_line_buffer. */
+char **
+programmable_completions (cmd, word, start, end, foundp)
+ const char *cmd;
+ const char *word;
+ int start, end, *foundp;
+{
+ COMPSPEC *cs, *lastcs;
+ STRINGLIST *ret;
+ char **rmatches, *t;
+ int found, retry, count;
+
+ lastcs = 0;
+ found = count = 0;
+
+ do
+ {
+ retry = 0;
+
+ /* We look at the basename of CMD if the full command does not have
+ an associated COMPSPEC. */
+ ret = gen_progcomp_completions (cmd, cmd, word, start, end, &found, &retry, &lastcs);
+ if (found == 0)
+ {
+ t = strrchr (cmd, '/');
+ if (t && *(++t))
+ ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs);
+ }
+
+ if (found == 0)
+ ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs);
+
+ count++;
+
+ if (count > 32)
+ {
+ internal_warning ("programmable_completion: %s: possible retry loop", cmd);
+ break;
+ }
+ }
+ while (retry);
if (ret)
{
@@ -1459,6 +1534,12 @@ programmable_completions (cmd, word, start, end, foundp)
else
rmatches = (char **)NULL;
+ if (foundp)
+ *foundp = found;
+
+ if (lastcs) /* XXX - should be while? */
+ compspec_dispose (lastcs);
+
return (rmatches);
}