mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-06 18:22:25 +02:00
bash-5.0 distribution sources and documentation
This commit is contained in:
+110
-25
@@ -1,6 +1,6 @@
|
||||
/* pcomplete.c - functions to generate lists of matches for programmable completion. */
|
||||
|
||||
/* Copyright (C) 1999-2012 Free Software Foundation, Inc.
|
||||
/* Copyright (C) 1999-2018 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
@@ -71,8 +71,6 @@
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
|
||||
#define PCOMP_RETRYFAIL 256
|
||||
|
||||
#ifdef STRDUP
|
||||
# undef STRDUP
|
||||
#endif
|
||||
@@ -84,10 +82,8 @@ typedef SHELL_VAR **SVFUNC ();
|
||||
extern char *strpbrk __P((char *, char *));
|
||||
#endif
|
||||
|
||||
extern int array_needs_making;
|
||||
extern STRING_INT_ALIST word_token_alist[];
|
||||
extern char *signal_names[];
|
||||
extern sh_builtin_func_t *last_shell_builtin, *this_shell_builtin;
|
||||
|
||||
#if defined (DEBUG)
|
||||
#if defined (PREFER_STDARG)
|
||||
@@ -155,6 +151,10 @@ static int progcomp_debug = 0;
|
||||
|
||||
int prog_completion_enabled = 1;
|
||||
|
||||
#ifdef ALIAS
|
||||
int progcomp_alias = 0; /* unavailable to user code for now */
|
||||
#endif
|
||||
|
||||
/* These are used to manage the arrays of strings for possible completions. */
|
||||
ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 };
|
||||
ITEMLIST it_arrayvars = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 };
|
||||
@@ -185,6 +185,9 @@ COMPSPEC *pcomp_curcs;
|
||||
const char *pcomp_curcmd;
|
||||
const char *pcomp_curtxt;
|
||||
|
||||
char *pcomp_line;
|
||||
int pcomp_ind;
|
||||
|
||||
#ifdef DEBUG
|
||||
/* Debugging code */
|
||||
static void
|
||||
@@ -728,7 +731,6 @@ pcomp_filename_completion_function (text, state)
|
||||
int state;
|
||||
{
|
||||
static char *dfn; /* dequoted filename */
|
||||
int qc;
|
||||
int iscompgen, iscompleting;
|
||||
|
||||
if (state == 0)
|
||||
@@ -954,11 +956,15 @@ bind_comp_words (lwords)
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
|
||||
v = find_variable ("COMP_WORDS");
|
||||
v = find_variable_noref ("COMP_WORDS");
|
||||
if (v == 0)
|
||||
v = make_new_array_variable ("COMP_WORDS");
|
||||
if (nameref_p (v))
|
||||
VUNSETATTR (v, att_nameref);
|
||||
#if 0
|
||||
if (readonly_p (v))
|
||||
VUNSETATTR (v, att_readonly);
|
||||
#endif
|
||||
if (array_p (v) == 0)
|
||||
v = convert_var_to_array (v);
|
||||
v = assign_array_var_from_word_list (v, lwords, 0);
|
||||
@@ -993,17 +999,17 @@ bind_compfunc_variables (line, ind, lwords, cw, exported)
|
||||
llen = MB_STRLEN (line);
|
||||
line[ind] = c;
|
||||
value = inttostr (llen, ibuf, sizeof(ibuf));
|
||||
v = bind_int_variable ("COMP_POINT", value);
|
||||
v = bind_int_variable ("COMP_POINT", value, 0);
|
||||
if (v && exported)
|
||||
VSETATTR(v, att_exported);
|
||||
|
||||
value = inttostr (rl_completion_type, ibuf, sizeof (ibuf));
|
||||
v = bind_int_variable ("COMP_TYPE", value);
|
||||
v = bind_int_variable ("COMP_TYPE", value, 0);
|
||||
if (v && exported)
|
||||
VSETATTR(v, att_exported);
|
||||
|
||||
value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf));
|
||||
v = bind_int_variable ("COMP_KEY", value);
|
||||
v = bind_int_variable ("COMP_KEY", value, 0);
|
||||
if (v && exported)
|
||||
VSETATTR(v, att_exported);
|
||||
|
||||
@@ -1014,7 +1020,7 @@ bind_compfunc_variables (line, ind, lwords, cw, exported)
|
||||
#ifdef ARRAY_VARS
|
||||
v = bind_comp_words (lwords);
|
||||
value = inttostr (cw, ibuf, sizeof(ibuf));
|
||||
bind_int_variable ("COMP_CWORD", value);
|
||||
bind_int_variable ("COMP_CWORD", value, 0);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
@@ -1165,13 +1171,13 @@ gen_shell_function_matches (cs, cmd, text, line, ind, lwords, nw, cw, foundp)
|
||||
v = find_variable ("COMPREPLY");
|
||||
if (v == 0)
|
||||
return ((STRINGLIST *)NULL);
|
||||
if (array_p (v) == 0)
|
||||
if (array_p (v) == 0 && assoc_p (v) == 0)
|
||||
v = convert_var_to_array (v);
|
||||
|
||||
VUNSETATTR (v, att_invisible);
|
||||
|
||||
a = array_cell (v);
|
||||
if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_empty (a))
|
||||
if (found == 0 || (found & PCOMP_RETRYFAIL) || a == 0 || array_p (v) == 0 || array_empty (a))
|
||||
sl = (STRINGLIST *)NULL;
|
||||
else
|
||||
{
|
||||
@@ -1243,7 +1249,7 @@ gen_command_matches (cs, cmd, text, line, ind, lwords, nw, cw)
|
||||
}
|
||||
cscmd[cmdlen] = '\0';
|
||||
|
||||
tw = command_substitute (cscmd, 0);
|
||||
tw = command_substitute (cscmd, 0, 0);
|
||||
csbuf = tw ? tw->word : (char *)NULL;
|
||||
if (tw)
|
||||
dispose_word_desc (tw);
|
||||
@@ -1379,14 +1385,14 @@ gen_compspec_completions (cs, cmd, word, start, end, foundp)
|
||||
/* If we have a command or function to execute, we need to first break
|
||||
the command line into individual words, find the number of words,
|
||||
and find the word in the list containing the word to be completed. */
|
||||
line = substring (rl_line_buffer, start, end);
|
||||
line = substring (pcomp_line, start, end);
|
||||
llen = end - start;
|
||||
|
||||
#ifdef DEBUG
|
||||
debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)",
|
||||
line, llen, rl_point - start, &nw, &cw);
|
||||
line, llen, pcomp_ind - start, &nw, &cw);
|
||||
#endif
|
||||
lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw);
|
||||
lwords = command_line_to_word_list (line, llen, pcomp_ind - start, &nw, &cw);
|
||||
/* If we skipped a NULL word at the beginning of the line, add it back */
|
||||
if (lwords && lwords->word && cmd[0] == 0 && lwords->word->word[0] != 0)
|
||||
{
|
||||
@@ -1413,7 +1419,7 @@ gen_compspec_completions (cs, cmd, word, start, end, foundp)
|
||||
if (cs->funcname)
|
||||
{
|
||||
foundf = 0;
|
||||
tmatches = gen_shell_function_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw, &foundf);
|
||||
tmatches = gen_shell_function_matches (cs, cmd, word, line, pcomp_ind - start, lwords, nw, cw, &foundf);
|
||||
if (foundf != 0)
|
||||
found = foundf;
|
||||
if (tmatches)
|
||||
@@ -1433,7 +1439,7 @@ gen_compspec_completions (cs, cmd, word, start, end, foundp)
|
||||
|
||||
if (cs->command)
|
||||
{
|
||||
tmatches = gen_command_matches (cs, cmd, word, line, rl_point - start, lwords, nw, cw);
|
||||
tmatches = gen_command_matches (cs, cmd, word, line, pcomp_ind - start, lwords, nw, cw);
|
||||
if (tmatches)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
@@ -1607,37 +1613,107 @@ gen_progcomp_completions (ocmd, cmd, word, start, end, foundp, retryp, lastcs)
|
||||
|
||||
/* 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. */
|
||||
bound the command currently being completed in pcomp_line (usually
|
||||
rl_line_buffer). */
|
||||
char **
|
||||
programmable_completions (cmd, word, start, end, foundp)
|
||||
const char *cmd;
|
||||
const char *word;
|
||||
int start, end, *foundp;
|
||||
{
|
||||
COMPSPEC *cs, *lastcs;
|
||||
COMPSPEC *lastcs;
|
||||
STRINGLIST *ret;
|
||||
char **rmatches, *t;
|
||||
int found, retry, count;
|
||||
char *ocmd;
|
||||
int oend;
|
||||
#if defined (ALIAS)
|
||||
alias_t *al;
|
||||
#endif
|
||||
|
||||
lastcs = 0;
|
||||
found = count = 0;
|
||||
|
||||
pcomp_line = rl_line_buffer;
|
||||
pcomp_ind = rl_point;
|
||||
|
||||
ocmd = (char *)cmd;
|
||||
oend = end;
|
||||
|
||||
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);
|
||||
ret = gen_progcomp_completions (ocmd, ocmd, word, start, oend, &found, &retry, &lastcs);
|
||||
if (found == 0)
|
||||
{
|
||||
t = strrchr (cmd, '/');
|
||||
t = strrchr (ocmd, '/');
|
||||
if (t && *(++t))
|
||||
ret = gen_progcomp_completions (t, cmd, word, start, end, &found, &retry, &lastcs);
|
||||
ret = gen_progcomp_completions (t, ocmd, word, start, oend, &found, &retry, &lastcs);
|
||||
}
|
||||
|
||||
if (found == 0)
|
||||
ret = gen_progcomp_completions (DEFAULTCMD, cmd, word, start, end, &found, &retry, &lastcs);
|
||||
ret = gen_progcomp_completions (DEFAULTCMD, ocmd, word, start, oend, &found, &retry, &lastcs);
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Look up any alias for CMD, try to gen completions for it */
|
||||
/* Look up the alias, find the value, build a new line replacing CMD
|
||||
with that value, offsetting PCOMP_IND and END appropriately, reset
|
||||
PCOMP_LINE to the new line and OCMD with the new command name, then
|
||||
call gen_progcomp_completions again. We could use alias_expand for
|
||||
this, but it does more (and less) than we need right now. */
|
||||
if (found == 0 && retry == 0 && progcomp_alias && (al = find_alias (ocmd)))
|
||||
{
|
||||
char *ncmd, *nline, *ntxt;
|
||||
int ind, lendiff;
|
||||
size_t nlen, olen, llen;
|
||||
|
||||
/* We found an alias for OCMD. Take the value and build a new line */
|
||||
ntxt = al->value;
|
||||
nlen = strlen (ntxt);
|
||||
if (nlen == 0)
|
||||
break;
|
||||
olen = strlen (ocmd);
|
||||
lendiff = nlen - olen; /* can be negative */
|
||||
llen = strlen (pcomp_line);
|
||||
|
||||
nline = (char *)xmalloc (llen + lendiff + 1);
|
||||
if (start > 0)
|
||||
strncpy (nline, pcomp_line, start);
|
||||
strncpy (nline + start, ntxt, nlen);
|
||||
strcpy (nline + start + nlen, pcomp_line + start + olen);
|
||||
|
||||
/* Find the first word of the alias value and use that as OCMD. We
|
||||
don't check the alias value to see whether it begins with a valid
|
||||
command name, so this can be fooled. */
|
||||
ind = skip_to_delim (ntxt, 0, "()<>;&| \t\n", SD_NOJMP|SD_COMPLETE);
|
||||
if (ind > 0)
|
||||
ncmd = substring (ntxt, 0, ind);
|
||||
else
|
||||
{
|
||||
free (nline);
|
||||
break; /* will free pcomp_line and ocmd later */
|
||||
}
|
||||
|
||||
/* Adjust PCOMP_IND and OEND appropriately */
|
||||
pcomp_ind += lendiff;
|
||||
oend += lendiff;
|
||||
|
||||
/* Set up values with new line. WORD stays the same. */
|
||||
if (ocmd != cmd)
|
||||
free (ocmd);
|
||||
if (pcomp_line != rl_line_buffer)
|
||||
free (pcomp_line);
|
||||
|
||||
ocmd = ncmd;
|
||||
pcomp_line = nline;
|
||||
|
||||
/* And go back and start over. */
|
||||
retry = 1;
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
count++;
|
||||
|
||||
@@ -1649,6 +1725,11 @@ programmable_completions (cmd, word, start, end, foundp)
|
||||
}
|
||||
while (retry);
|
||||
|
||||
if (pcomp_line != rl_line_buffer)
|
||||
free (pcomp_line);
|
||||
if (ocmd != cmd)
|
||||
free (ocmd);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
rmatches = ret->list;
|
||||
@@ -1663,6 +1744,10 @@ programmable_completions (cmd, word, start, end, foundp)
|
||||
if (lastcs) /* XXX - should be while? */
|
||||
compspec_dispose (lastcs);
|
||||
|
||||
/* XXX restore pcomp_line and pcomp_ind? */
|
||||
pcomp_line = rl_line_buffer;
|
||||
pcomp_ind = rl_point;
|
||||
|
||||
return (rmatches);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user