From 772f20abb0a3a0979c440114bf3a1cff5b3cef03 Mon Sep 17 00:00:00 2001 From: cvpcs Date: Wed, 2 Jun 2010 11:02:31 -0500 Subject: initial import of bash 4.1 --- builtins/complete.def | 869 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 869 insertions(+) create mode 100644 builtins/complete.def (limited to 'builtins/complete.def') diff --git a/builtins/complete.def b/builtins/complete.def new file mode 100644 index 0000000..2267794 --- /dev/null +++ b/builtins/complete.def @@ -0,0 +1,869 @@ +This file is complete.def, from which is created complete.c. +It implements the builtins "complete", "compgen", and "compopt" in Bash. + +Copyright (C) 1999-2009 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 . + +$PRODUCES complete.c + +$BUILTIN complete +$DEPENDS_ON PROGRAMMABLE_COMPLETION +$FUNCTION complete_builtin +$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-DE] [-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 + +When completion is attempted, the actions are applied in the order the +uppercase-letter options are listed above. The -D option takes +precedence over -E. + +Exit Status: +Returns success unless an invalid option is supplied or an error occurs. +$END + +#include + +#include + +#include "../bashtypes.h" + +#if defined (HAVE_UNISTD_H) +# include +#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 + +#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; +}; + +static int find_compact __P((char *)); +static int find_compopt __P((char *)); + +static int build_actions __P((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *)); + +static int remove_cmd_completions __P((WORD_LIST *)); + +static int print_one_completion __P((char *, COMPSPEC *)); +static int print_compitem __P((BUCKET_CONTENTS *)); +static void print_compopts __P((const char *, COMPSPEC *, int)); +static void print_all_completions __P((void)); +static int print_cmd_completions __P((WORD_LIST *)); + +static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg; + +static const struct _compacts { + const char * const actname; + int 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_BUILTIN, 0 }, /* for now */ + { "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 */ +const static struct _compopt { + const char * const optname; + int optflag; +} compopts[] = { + { "bashdefault", COPT_BASHDEFAULT }, + { "default", COPT_DEFAULT }, + { "dirnames", COPT_DIRNAMES }, + { "filenames",COPT_FILENAMES}, + { "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 + btmap 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; + + 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:DE")) != -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 'F': + Farg = list_optarg; + 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; + 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 = oflags.Dflag = oflags.Eflag = 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; + + wl = oflags.Dflag ? make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL) + : (oflags.Eflag ? make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL) : 0); + + /* -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; +} + +#define SQPRINTARG(a, f) \ + do { \ + if (a) \ + { \ + x = sh_single_quote (a); \ + printf ("%s %s ", f, x); \ + free (x); \ + } \ + } while (0) + +#define PRINTARG(a, f) \ + do { \ + if (a) \ + printf ("%s %s ", f, a); \ + } while (0) + +#define PRINTOPT(a, f) \ + do { \ + if (acts & a) \ + printf ("%s ", f); \ + } while (0) + +#define PRINTACT(a, f) \ + do { \ + if (acts & a) \ + printf ("-A %s ", f); \ + } while (0) + +#define PRINTCOMPOPT(a, f) \ + do { \ + if (copts & a) \ + printf ("-o %s ", f); \ + } while (0) + +#define XPRINTCOMPOPT(a, f) \ + do { \ + if (copts & a) \ + printf ("-o %s ", f); \ + else \ + printf ("+o %s ", f); \ + } while (0) + +static int +print_one_completion (cmd, cs) + char *cmd; + COMPSPEC *cs; +{ + unsigned long acts, copts; + char *x; + + printf ("complete "); + + copts = cs->options; + + /* First, print the -o options. */ + PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); + PRINTCOMPOPT (COPT_DEFAULT, "default"); + PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); + PRINTCOMPOPT (COPT_FILENAMES, "filenames"); + PRINTCOMPOPT (COPT_NOSPACE, "nospace"); + PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); + + acts = cs->actions; + + /* simple flags next */ + PRINTOPT (CA_ALIAS, "-a"); + PRINTOPT (CA_BUILTIN, "-b"); + PRINTOPT (CA_COMMAND, "-c"); + PRINTOPT (CA_DIRECTORY, "-d"); + PRINTOPT (CA_EXPORT, "-e"); + PRINTOPT (CA_FILE, "-f"); + PRINTOPT (CA_GROUP, "-g"); + PRINTOPT (CA_JOB, "-j"); + PRINTOPT (CA_KEYWORD, "-k"); + PRINTOPT (CA_SERVICE, "-s"); + PRINTOPT (CA_USER, "-u"); + PRINTOPT (CA_VARIABLE, "-v"); + + /* now the rest of the actions */ + PRINTACT (CA_ARRAYVAR, "arrayvar"); + PRINTACT (CA_BINDING, "binding"); + PRINTACT (CA_DISABLED, "disabled"); + PRINTACT (CA_ENABLED, "enabled"); + PRINTACT (CA_FUNCTION, "function"); + PRINTACT (CA_HELPTOPIC, "helptopic"); + PRINTACT (CA_HOSTNAME, "hostname"); + PRINTACT (CA_RUNNING, "running"); + PRINTACT (CA_SETOPT, "setopt"); + PRINTACT (CA_SHOPT, "shopt"); + PRINTACT (CA_SIGNAL, "signal"); + PRINTACT (CA_STOPPED, "stopped"); + + /* now the rest of the arguments */ + + /* arguments that require quoting */ + SQPRINTARG (cs->globpat, "-G"); + SQPRINTARG (cs->words, "-W"); + SQPRINTARG (cs->prefix, "-P"); + SQPRINTARG (cs->suffix, "-S"); + SQPRINTARG (cs->filterpat, "-X"); + + SQPRINTARG (cs->command, "-C"); + + /* simple arguments that don't require quoting */ + PRINTARG (cs->funcname, "-F"); + + if (STREQ (cmd, EMPTYCMD)) + printf ("-E\n"); + else if (STREQ (cmd, DEFAULTCMD)) + printf ("-D\n"); + else + printf ("%s\n", cmd); + + return (0); +} + +static void +print_compopts (cmd, cs, full) + const char *cmd; + COMPSPEC *cs; + int full; +{ + int copts; + + printf ("compopt "); + copts = cs->options; + + if (full) + { + XPRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); + XPRINTCOMPOPT (COPT_DEFAULT, "default"); + XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); + XPRINTCOMPOPT (COPT_FILENAMES, "filenames"); + XPRINTCOMPOPT (COPT_NOSPACE, "nospace"); + XPRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); + } + else + { + PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault"); + PRINTCOMPOPT (COPT_DEFAULT, "default"); + PRINTCOMPOPT (COPT_DIRNAMES, "dirnames"); + PRINTCOMPOPT (COPT_FILENAMES, "filenames"); + PRINTCOMPOPT (COPT_NOSPACE, "nospace"); + PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs"); + } + + if (STREQ (cmd, EMPTYCMD)) + printf ("-E\n"); + else if (STREQ (cmd, DEFAULTCMD)) + printf ("-D\n"); + else + printf ("%s\n", cmd); +} + +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; + + 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; + sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0); + + /* 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); + 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] [-DE] [name ...] +Modify or display completion options. + +Modify the completion options for each NAME, or, if no NAMEs are supplied, +the completion currently begin executed. If no OPTIONs are givenm, 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 + +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; + WORD_LIST *l, *wl; + COMPSPEC *cs; + + opts_on = opts_off = Eflag = Dflag = 0; + ret = EXECUTION_SUCCESS; + + reset_internal_getopt (); + while ((opt = internal_getopt (list, "+o:DE")) != EOF) + { + 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; + default: + builtin_usage (); + return (EX_USAGE); + } + } + list = loptend; + + wl = Dflag ? make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL) + : (Eflag ? make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL) : 0); + + 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); + } + + return (ret); +} -- cgit v1.1