mirror of https://github.com/n-hys/bash.git
885 lines
21 KiB
Modula-2
885 lines
21 KiB
Modula-2
This file is complete.def, from which is created complete.c.
|
|
It implements the builtins "complete", "compgen", and "compopt" in Bash.
|
|
|
|
Copyright (C) 1999-2020 Free Software Foundation, Inc.
|
|
|
|
This file is part of GNU Bash, the Bourne Again SHell.
|
|
|
|
Bash is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
Bash is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with Bash. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
$PRODUCES complete.c
|
|
|
|
$BUILTIN complete
|
|
$DEPENDS_ON PROGRAMMABLE_COMPLETION
|
|
$FUNCTION complete_builtin
|
|
$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-DEI] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
|
|
Specify how arguments are to be completed by Readline.
|
|
|
|
For each NAME, specify how arguments are to be completed. If no options
|
|
are supplied, existing completion specifications are printed in a way that
|
|
allows them to be reused as input.
|
|
|
|
Options:
|
|
-p print existing completion specifications in a reusable format
|
|
-r remove a completion specification for each NAME, or, if no
|
|
NAMEs are supplied, all completion specifications
|
|
-D apply the completions and actions as the default for commands
|
|
without any specific completion defined
|
|
-E apply the completions and actions to "empty" commands --
|
|
completion attempted on a blank line
|
|
-I apply the completions and actions to the initial (usually the
|
|
command) word
|
|
|
|
When completion is attempted, the actions are applied in the order the
|
|
uppercase-letter options are listed above. If multiple options are supplied,
|
|
the -D option takes precedence over -E, and both take precedence over -I.
|
|
|
|
Exit Status:
|
|
Returns success unless an invalid option is supplied or an error occurs.
|
|
$END
|
|
|
|
#include <config.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include "../bashtypes.h"
|
|
|
|
#if defined (HAVE_UNISTD_H)
|
|
# include <unistd.h>
|
|
#endif
|
|
|
|
#include "../bashansi.h"
|
|
#include "../bashintl.h"
|
|
|
|
#include "../shell.h"
|
|
#include "../builtins.h"
|
|
#include "../pcomplete.h"
|
|
#include "../bashline.h"
|
|
|
|
#include "common.h"
|
|
#include "bashgetopt.h"
|
|
|
|
#include <readline/readline.h>
|
|
|
|
#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)
|
|
|
|
/* Structure containing all the non-action (binary) options; filled in by
|
|
build_actions(). */
|
|
struct _optflags {
|
|
int pflag;
|
|
int rflag;
|
|
int Dflag;
|
|
int Eflag;
|
|
int Iflag;
|
|
};
|
|
|
|
static int find_compact PARAMS((char *));
|
|
static int find_compopt PARAMS((char *));
|
|
|
|
static int build_actions PARAMS((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *));
|
|
|
|
static int remove_cmd_completions PARAMS((WORD_LIST *));
|
|
|
|
static int print_one_completion PARAMS((char *, COMPSPEC *));
|
|
static int print_compitem PARAMS((BUCKET_CONTENTS *));
|
|
static void print_compopts PARAMS((const char *, COMPSPEC *, int));
|
|
static void print_all_completions PARAMS((void));
|
|
static int print_cmd_completions PARAMS((WORD_LIST *));
|
|
|
|
static void print_compoptions PARAMS((unsigned long, int));
|
|
static void print_compactions PARAMS((unsigned long));
|
|
static void print_arg PARAMS((const char *, const char *, int));
|
|
static void print_cmd_name PARAMS((const char *));
|
|
|
|
static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg;
|
|
|
|
static const struct _compacts {
|
|
const char * const actname;
|
|
unsigned long actflag;
|
|
int actopt;
|
|
} compacts[] = {
|
|
{ "alias", CA_ALIAS, 'a' },
|
|
{ "arrayvar", CA_ARRAYVAR, 0 },
|
|
{ "binding", CA_BINDING, 0 },
|
|
{ "builtin", CA_BUILTIN, 'b' },
|
|
{ "command", CA_COMMAND, 'c' },
|
|
{ "directory", CA_DIRECTORY, 'd' },
|
|
{ "disabled", CA_DISABLED, 0 },
|
|
{ "enabled", CA_ENABLED, 0 },
|
|
{ "export", CA_EXPORT, 'e' },
|
|
{ "file", CA_FILE, 'f' },
|
|
{ "function", CA_FUNCTION, 0 },
|
|
{ "helptopic", CA_HELPTOPIC, 0 },
|
|
{ "hostname", CA_HOSTNAME, 0 },
|
|
{ "group", CA_GROUP, 'g' },
|
|
{ "job", CA_JOB, 'j' },
|
|
{ "keyword", CA_KEYWORD, 'k' },
|
|
{ "running", CA_RUNNING, 0 },
|
|
{ "service", CA_SERVICE, 's' },
|
|
{ "setopt", CA_SETOPT, 0 },
|
|
{ "shopt", CA_SHOPT, 0 },
|
|
{ "signal", CA_SIGNAL, 0 },
|
|
{ "stopped", CA_STOPPED, 0 },
|
|
{ "user", CA_USER, 'u' },
|
|
{ "variable", CA_VARIABLE, 'v' },
|
|
{ (char *)NULL, 0, 0 },
|
|
};
|
|
|
|
/* This should be a STRING_INT_ALIST */
|
|
static const struct _compopt {
|
|
const char * const optname;
|
|
unsigned long optflag;
|
|
} compopts[] = {
|
|
{ "bashdefault", COPT_BASHDEFAULT },
|
|
{ "default", COPT_DEFAULT },
|
|
{ "dirnames", COPT_DIRNAMES },
|
|
{ "filenames",COPT_FILENAMES},
|
|
{ "noquote", COPT_NOQUOTE },
|
|
{ "nosort", COPT_NOSORT },
|
|
{ "nospace", COPT_NOSPACE },
|
|
{ "plusdirs", COPT_PLUSDIRS },
|
|
{ (char *)NULL, 0 },
|
|
};
|
|
|
|
static int
|
|
find_compact (name)
|
|
char *name;
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; compacts[i].actname; i++)
|
|
if (STREQ (name, compacts[i].actname))
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
static int
|
|
find_compopt (name)
|
|
char *name;
|
|
{
|
|
register int i;
|
|
|
|
for (i = 0; compopts[i].optname; i++)
|
|
if (STREQ (name, compopts[i].optname))
|
|
return i;
|
|
return -1;
|
|
}
|
|
|
|
/* Build the actions and compspec options from the options specified in LIST.
|
|
ACTP is a pointer to an unsigned long in which to place the bitmap of
|
|
actions. OPTP is a pointer to an unsigned long in which to place the
|
|
bitmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
|
|
if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
|
|
If either is null, the corresponding option generates an error.
|
|
This also sets variables corresponding to options that take arguments as
|
|
a side effect; the caller should ensure that those variables are set to
|
|
NULL before calling build_actions. Return value:
|
|
EX_USAGE = bad option
|
|
EXECUTION_SUCCESS = some options supplied
|
|
EXECUTION_FAILURE = no options supplied
|
|
*/
|
|
|
|
static int
|
|
build_actions (list, flagp, actp, optp)
|
|
WORD_LIST *list;
|
|
struct _optflags *flagp;
|
|
unsigned long *actp, *optp;
|
|
{
|
|
int opt, ind, opt_given;
|
|
unsigned long acts, copts;
|
|
WORD_DESC w;
|
|
|
|
acts = copts = (unsigned long)0L;
|
|
opt_given = 0;
|
|
|
|
reset_internal_getopt ();
|
|
while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI")) != -1)
|
|
{
|
|
opt_given = 1;
|
|
switch (opt)
|
|
{
|
|
case 'r':
|
|
if (flagp)
|
|
{
|
|
flagp->rflag = 1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sh_invalidopt ("-r");
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
|
|
case 'p':
|
|
if (flagp)
|
|
{
|
|
flagp->pflag = 1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sh_invalidopt ("-p");
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
|
|
case 'a':
|
|
acts |= CA_ALIAS;
|
|
break;
|
|
case 'b':
|
|
acts |= CA_BUILTIN;
|
|
break;
|
|
case 'c':
|
|
acts |= CA_COMMAND;
|
|
break;
|
|
case 'd':
|
|
acts |= CA_DIRECTORY;
|
|
break;
|
|
case 'e':
|
|
acts |= CA_EXPORT;
|
|
break;
|
|
case 'f':
|
|
acts |= CA_FILE;
|
|
break;
|
|
case 'g':
|
|
acts |= CA_GROUP;
|
|
break;
|
|
case 'j':
|
|
acts |= CA_JOB;
|
|
break;
|
|
case 'k':
|
|
acts |= CA_KEYWORD;
|
|
break;
|
|
case 's':
|
|
acts |= CA_SERVICE;
|
|
break;
|
|
case 'u':
|
|
acts |= CA_USER;
|
|
break;
|
|
case 'v':
|
|
acts |= CA_VARIABLE;
|
|
break;
|
|
case 'o':
|
|
ind = find_compopt (list_optarg);
|
|
if (ind < 0)
|
|
{
|
|
sh_invalidoptname (list_optarg);
|
|
return (EX_USAGE);
|
|
}
|
|
copts |= compopts[ind].optflag;
|
|
break;
|
|
case 'A':
|
|
ind = find_compact (list_optarg);
|
|
if (ind < 0)
|
|
{
|
|
builtin_error (_("%s: invalid action name"), list_optarg);
|
|
return (EX_USAGE);
|
|
}
|
|
acts |= compacts[ind].actflag;
|
|
break;
|
|
case 'C':
|
|
Carg = list_optarg;
|
|
break;
|
|
case 'D':
|
|
if (flagp)
|
|
{
|
|
flagp->Dflag = 1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sh_invalidopt ("-D");
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
case 'E':
|
|
if (flagp)
|
|
{
|
|
flagp->Eflag = 1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sh_invalidopt ("-E");
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
case 'I':
|
|
if (flagp)
|
|
{
|
|
flagp->Iflag = 1;
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
sh_invalidopt ("-I");
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
case 'F':
|
|
w.word = Farg = list_optarg;
|
|
w.flags = 0;
|
|
if (check_identifier (&w, posixly_correct) == 0 || strpbrk (Farg, shell_break_chars) != 0)
|
|
{
|
|
sh_invalidid (Farg);
|
|
return (EX_USAGE);
|
|
}
|
|
break;
|
|
case 'G':
|
|
Garg = list_optarg;
|
|
break;
|
|
case 'P':
|
|
Parg = list_optarg;
|
|
break;
|
|
case 'S':
|
|
Sarg = list_optarg;
|
|
break;
|
|
case 'W':
|
|
Warg = list_optarg;
|
|
break;
|
|
case 'X':
|
|
Xarg = list_optarg;
|
|
break;
|
|
CASE_HELPOPT;
|
|
default:
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
}
|
|
|
|
*actp = acts;
|
|
*optp = copts;
|
|
|
|
return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
|
}
|
|
|
|
/* Add, remove, and display completion specifiers. */
|
|
int
|
|
complete_builtin (list)
|
|
WORD_LIST *list;
|
|
{
|
|
int opt_given, rval;
|
|
unsigned long acts, copts;
|
|
COMPSPEC *cs;
|
|
struct _optflags oflags;
|
|
WORD_LIST *l, *wl;
|
|
|
|
if (list == 0)
|
|
{
|
|
print_all_completions ();
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
|
|
opt_given = oflags.pflag = oflags.rflag = 0;
|
|
oflags.Dflag = oflags.Eflag = oflags.Iflag = 0;
|
|
|
|
acts = copts = (unsigned long)0L;
|
|
Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
|
|
cs = (COMPSPEC *)NULL;
|
|
|
|
/* Build the actions from the arguments. Also sets the [A-Z]arg variables
|
|
as a side effect if they are supplied as options. */
|
|
rval = build_actions (list, &oflags, &acts, &copts);
|
|
if (rval == EX_USAGE)
|
|
return (rval);
|
|
opt_given = rval != EXECUTION_FAILURE;
|
|
|
|
list = loptend;
|
|
|
|
if (oflags.Dflag)
|
|
wl = make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL);
|
|
else if (oflags.Eflag)
|
|
wl = make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL);
|
|
else if (oflags.Iflag)
|
|
wl = make_word_list (make_bare_word (INITIALWORD), (WORD_LIST *)NULL);
|
|
else
|
|
wl = (WORD_LIST *)NULL;
|
|
|
|
/* -p overrides everything else */
|
|
if (oflags.pflag || (list == 0 && opt_given == 0))
|
|
{
|
|
if (wl)
|
|
{
|
|
rval = print_cmd_completions (wl);
|
|
dispose_words (wl);
|
|
return rval;
|
|
}
|
|
else if (list == 0)
|
|
{
|
|
print_all_completions ();
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
return (print_cmd_completions (list));
|
|
}
|
|
|
|
/* next, -r overrides everything else. */
|
|
if (oflags.rflag)
|
|
{
|
|
if (wl)
|
|
{
|
|
rval = remove_cmd_completions (wl);
|
|
dispose_words (wl);
|
|
return rval;
|
|
}
|
|
else if (list == 0)
|
|
{
|
|
progcomp_flush ();
|
|
return (EXECUTION_SUCCESS);
|
|
}
|
|
return (remove_cmd_completions (list));
|
|
}
|
|
|
|
if (wl == 0 && list == 0 && opt_given)
|
|
{
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
|
|
/* If we get here, we need to build a compspec and add it for each
|
|
remaining argument. */
|
|
cs = compspec_create ();
|
|
cs->actions = acts;
|
|
cs->options = copts;
|
|
|
|
cs->globpat = STRDUP (Garg);
|
|
cs->words = STRDUP (Warg);
|
|
cs->prefix = STRDUP (Parg);
|
|
cs->suffix = STRDUP (Sarg);
|
|
cs->funcname = STRDUP (Farg);
|
|
cs->command = STRDUP (Carg);
|
|
cs->filterpat = STRDUP (Xarg);
|
|
|
|
for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next)
|
|
{
|
|
/* Add CS as the compspec for the specified commands. */
|
|
if (progcomp_insert (l->word->word, cs) == 0)
|
|
rval = EXECUTION_FAILURE;
|
|
}
|
|
|
|
dispose_words (wl);
|
|
return (rval);
|
|
}
|
|
|
|
static int
|
|
remove_cmd_completions (list)
|
|
WORD_LIST *list;
|
|
{
|
|
WORD_LIST *l;
|
|
int ret;
|
|
|
|
for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
|
{
|
|
if (progcomp_remove (l->word->word) == 0)
|
|
{
|
|
builtin_error (_("%s: no completion specification"), l->word->word);
|
|
ret = EXECUTION_FAILURE;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
static void
|
|
print_compoptions (copts, full)
|
|
unsigned long copts;
|
|
int full;
|
|
{
|
|
const struct _compopt *co;
|
|
|
|
for (co = compopts; co->optname; co++)
|
|
if (copts & co->optflag)
|
|
printf ("-o %s ", co->optname);
|
|
else if (full)
|
|
printf ("+o %s ", co->optname);
|
|
}
|
|
|
|
static void
|
|
print_compactions (acts)
|
|
unsigned long acts;
|
|
{
|
|
const struct _compacts *ca;
|
|
|
|
/* simple flags first */
|
|
for (ca = compacts; ca->actname; ca++)
|
|
if (ca->actopt && (acts & ca->actflag))
|
|
printf ("-%c ", ca->actopt);
|
|
|
|
/* then the rest of the actions */
|
|
for (ca = compacts; ca->actname; ca++)
|
|
if (ca->actopt == 0 && (acts & ca->actflag))
|
|
printf ("-A %s ", ca->actname);
|
|
}
|
|
|
|
static void
|
|
print_arg (arg, flag, quote)
|
|
const char *arg, *flag;
|
|
int quote;
|
|
{
|
|
char *x;
|
|
|
|
if (arg)
|
|
{
|
|
x = quote ? sh_single_quote (arg) : (char *)arg;
|
|
printf ("%s %s ", flag, x);
|
|
if (x != arg)
|
|
free (x);
|
|
}
|
|
}
|
|
|
|
static void
|
|
print_cmd_name (cmd)
|
|
const char *cmd;
|
|
{
|
|
if (STREQ (cmd, DEFAULTCMD))
|
|
printf ("-D");
|
|
else if (STREQ (cmd, EMPTYCMD))
|
|
printf ("-E");
|
|
else if (STREQ (cmd, INITIALWORD))
|
|
printf ("-I");
|
|
else if (*cmd == 0) /* XXX - can this happen? */
|
|
printf ("''");
|
|
else
|
|
printf ("%s", cmd);
|
|
}
|
|
|
|
static int
|
|
print_one_completion (cmd, cs)
|
|
char *cmd;
|
|
COMPSPEC *cs;
|
|
{
|
|
printf ("complete ");
|
|
|
|
print_compoptions (cs->options, 0);
|
|
print_compactions (cs->actions);
|
|
|
|
/* now the rest of the arguments */
|
|
|
|
/* arguments that require quoting */
|
|
print_arg (cs->globpat, "-G", 1);
|
|
print_arg (cs->words, "-W", 1);
|
|
print_arg (cs->prefix, "-P", 1);
|
|
print_arg (cs->suffix, "-S", 1);
|
|
print_arg (cs->filterpat, "-X", 1);
|
|
|
|
print_arg (cs->command, "-C", 1);
|
|
|
|
/* simple arguments that don't require quoting */
|
|
print_arg (cs->funcname, "-F", 0);
|
|
|
|
print_cmd_name (cmd);
|
|
printf ("\n");
|
|
|
|
return (0);
|
|
}
|
|
|
|
static void
|
|
print_compopts (cmd, cs, full)
|
|
const char *cmd;
|
|
COMPSPEC *cs;
|
|
int full;
|
|
{
|
|
printf ("compopt ");
|
|
|
|
print_compoptions (cs->options, full);
|
|
print_cmd_name (cmd);
|
|
|
|
printf ("\n");
|
|
}
|
|
|
|
static int
|
|
print_compitem (item)
|
|
BUCKET_CONTENTS *item;
|
|
{
|
|
COMPSPEC *cs;
|
|
char *cmd;
|
|
|
|
cmd = item->key;
|
|
cs = (COMPSPEC *)item->data;
|
|
|
|
return (print_one_completion (cmd, cs));
|
|
}
|
|
|
|
static void
|
|
print_all_completions ()
|
|
{
|
|
progcomp_walk (print_compitem);
|
|
}
|
|
|
|
static int
|
|
print_cmd_completions (list)
|
|
WORD_LIST *list;
|
|
{
|
|
WORD_LIST *l;
|
|
COMPSPEC *cs;
|
|
int ret;
|
|
|
|
for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
|
|
{
|
|
cs = progcomp_search (l->word->word);
|
|
if (cs)
|
|
print_one_completion (l->word->word, cs);
|
|
else
|
|
{
|
|
builtin_error (_("%s: no completion specification"), l->word->word);
|
|
ret = EXECUTION_FAILURE;
|
|
}
|
|
}
|
|
|
|
return (sh_chkwrite (ret));
|
|
}
|
|
|
|
$BUILTIN compgen
|
|
$DEPENDS_ON PROGRAMMABLE_COMPLETION
|
|
$FUNCTION compgen_builtin
|
|
$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
|
|
Display possible completions depending on the options.
|
|
|
|
Intended to be used from within a shell function generating possible
|
|
completions. If the optional WORD argument is supplied, matches against
|
|
WORD are generated.
|
|
|
|
Exit Status:
|
|
Returns success unless an invalid option is supplied or an error occurs.
|
|
$END
|
|
|
|
int
|
|
compgen_builtin (list)
|
|
WORD_LIST *list;
|
|
{
|
|
int rval;
|
|
unsigned long acts, copts;
|
|
COMPSPEC *cs;
|
|
STRINGLIST *sl;
|
|
char *word, **matches;
|
|
char *old_line;
|
|
int old_ind;
|
|
|
|
if (list == 0)
|
|
return (EXECUTION_SUCCESS);
|
|
|
|
acts = copts = (unsigned long)0L;
|
|
Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
|
|
cs = (COMPSPEC *)NULL;
|
|
|
|
/* Build the actions from the arguments. Also sets the [A-Z]arg variables
|
|
as a side effect if they are supplied as options. */
|
|
rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts);
|
|
if (rval == EX_USAGE)
|
|
return (rval);
|
|
if (rval == EXECUTION_FAILURE)
|
|
return (EXECUTION_SUCCESS);
|
|
|
|
list = loptend;
|
|
|
|
word = (list && list->word) ? list->word->word : "";
|
|
|
|
if (Farg)
|
|
builtin_error (_("warning: -F option may not work as you expect"));
|
|
if (Carg)
|
|
builtin_error (_("warning: -C option may not work as you expect"));
|
|
|
|
/* If we get here, we need to build a compspec and evaluate it. */
|
|
cs = compspec_create ();
|
|
cs->actions = acts;
|
|
cs->options = copts;
|
|
cs->refcount = 1;
|
|
|
|
cs->globpat = STRDUP (Garg);
|
|
cs->words = STRDUP (Warg);
|
|
cs->prefix = STRDUP (Parg);
|
|
cs->suffix = STRDUP (Sarg);
|
|
cs->funcname = STRDUP (Farg);
|
|
cs->command = STRDUP (Carg);
|
|
cs->filterpat = STRDUP (Xarg);
|
|
|
|
rval = EXECUTION_FAILURE;
|
|
|
|
/* probably don't have to save these, just being safe */
|
|
old_line = pcomp_line;
|
|
old_ind = pcomp_ind;
|
|
pcomp_line = (char *)NULL;
|
|
pcomp_ind = 0;
|
|
sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0);
|
|
pcomp_line = old_line;
|
|
pcomp_ind = old_ind;
|
|
|
|
/* If the compspec wants the bash default completions, temporarily
|
|
turn off programmable completion and call the bash completion code. */
|
|
if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT))
|
|
{
|
|
matches = bash_default_completion (word, 0, 0, 0, 0);
|
|
sl = completions_to_stringlist (matches);
|
|
strvec_dispose (matches);
|
|
}
|
|
|
|
/* This isn't perfect, but it's the best we can do, given what readline
|
|
exports from its set of completion utility functions. */
|
|
if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT))
|
|
{
|
|
matches = rl_completion_matches (word, rl_filename_completion_function);
|
|
strlist_dispose (sl);
|
|
sl = completions_to_stringlist (matches);
|
|
strvec_dispose (matches);
|
|
}
|
|
|
|
if (sl)
|
|
{
|
|
if (sl->list && sl->list_len)
|
|
{
|
|
rval = EXECUTION_SUCCESS;
|
|
strlist_print (sl, (char *)NULL);
|
|
}
|
|
strlist_dispose (sl);
|
|
}
|
|
|
|
compspec_dispose (cs);
|
|
return (rval);
|
|
}
|
|
|
|
$BUILTIN compopt
|
|
$DEPENDS_ON PROGRAMMABLE_COMPLETION
|
|
$FUNCTION compopt_builtin
|
|
$SHORT_DOC compopt [-o|+o option] [-DEI] [name ...]
|
|
Modify or display completion options.
|
|
|
|
Modify the completion options for each NAME, or, if no NAMEs are supplied,
|
|
the completion currently being executed. If no OPTIONs are given, print
|
|
the completion options for each NAME or the current completion specification.
|
|
|
|
Options:
|
|
-o option Set completion option OPTION for each NAME
|
|
-D Change options for the "default" command completion
|
|
-E Change options for the "empty" command completion
|
|
-I Change options for completion on the initial word
|
|
|
|
Using `+o' instead of `-o' turns off the specified option.
|
|
|
|
Arguments:
|
|
|
|
Each NAME refers to a command for which a completion specification must
|
|
have previously been defined using the `complete' builtin. If no NAMEs
|
|
are supplied, compopt must be called by a function currently generating
|
|
completions, and the options for that currently-executing completion
|
|
generator are modified.
|
|
|
|
Exit Status:
|
|
Returns success unless an invalid option is supplied or NAME does not
|
|
have a completion specification defined.
|
|
$END
|
|
|
|
int
|
|
compopt_builtin (list)
|
|
WORD_LIST *list;
|
|
{
|
|
int opts_on, opts_off, *opts, opt, oind, ret, Dflag, Eflag, Iflag;
|
|
WORD_LIST *l, *wl;
|
|
COMPSPEC *cs;
|
|
|
|
opts_on = opts_off = Eflag = Dflag = Iflag = 0;
|
|
ret = EXECUTION_SUCCESS;
|
|
|
|
reset_internal_getopt ();
|
|
while ((opt = internal_getopt (list, "+o:DEI")) != -1)
|
|
{
|
|
opts = (list_opttype == '-') ? &opts_on : &opts_off;
|
|
|
|
switch (opt)
|
|
{
|
|
case 'o':
|
|
oind = find_compopt (list_optarg);
|
|
if (oind < 0)
|
|
{
|
|
sh_invalidoptname (list_optarg);
|
|
return (EX_USAGE);
|
|
}
|
|
*opts |= compopts[oind].optflag;
|
|
break;
|
|
case 'D':
|
|
Dflag = 1;
|
|
break;
|
|
case 'E':
|
|
Eflag = 1;
|
|
break;
|
|
case 'I':
|
|
Iflag = 1;
|
|
break;
|
|
CASE_HELPOPT;
|
|
default:
|
|
builtin_usage ();
|
|
return (EX_USAGE);
|
|
}
|
|
}
|
|
list = loptend;
|
|
|
|
if (Dflag)
|
|
wl = make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL);
|
|
else if (Eflag)
|
|
wl = make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL);
|
|
else if (Iflag)
|
|
wl = make_word_list (make_bare_word (INITIALWORD), (WORD_LIST *)NULL);
|
|
else
|
|
wl = (WORD_LIST *)NULL;
|
|
|
|
if (list == 0 && wl == 0)
|
|
{
|
|
if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0)
|
|
{
|
|
builtin_error (_("not currently executing completion function"));
|
|
return (EXECUTION_FAILURE);
|
|
}
|
|
cs = pcomp_curcs;
|
|
|
|
if (opts_on == 0 && opts_off == 0)
|
|
{
|
|
print_compopts (pcomp_curcmd, cs, 1);
|
|
return (sh_chkwrite (ret));
|
|
}
|
|
|
|
/* Set the compspec options */
|
|
pcomp_set_compspec_options (cs, opts_on, 1);
|
|
pcomp_set_compspec_options (cs, opts_off, 0);
|
|
|
|
/* And change the readline variables the options control */
|
|
pcomp_set_readline_variables (opts_on, 1);
|
|
pcomp_set_readline_variables (opts_off, 0);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
for (l = wl ? wl : list; l; l = l->next)
|
|
{
|
|
cs = progcomp_search (l->word->word);
|
|
if (cs == 0)
|
|
{
|
|
builtin_error (_("%s: no completion specification"), l->word->word);
|
|
ret = EXECUTION_FAILURE;
|
|
continue;
|
|
}
|
|
if (opts_on == 0 && opts_off == 0)
|
|
{
|
|
print_compopts (l->word->word, cs, 1);
|
|
continue; /* XXX -- fill in later */
|
|
}
|
|
|
|
/* Set the compspec options */
|
|
pcomp_set_compspec_options (cs, opts_on, 1);
|
|
pcomp_set_compspec_options (cs, opts_off, 0);
|
|
}
|
|
|
|
if (wl)
|
|
dispose_words (wl);
|
|
|
|
return (ret);
|
|
}
|