871 lines
		
	
	
	
		
			21 KiB
		
	
	
	
		
			Modula-2
		
	
	
	
	
	
			
		
		
	
	
			871 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-2011 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] [-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 <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;
 | |
| };
 | |
| 
 | |
| 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_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;
 | |
|   int optflag;
 | |
| } compopts[] = {
 | |
|   { "bashdefault", COPT_BASHDEFAULT },
 | |
|   { "default",	COPT_DEFAULT },
 | |
|   { "dirnames", COPT_DIRNAMES },
 | |
|   { "filenames",COPT_FILENAMES},
 | |
|   { "noquote", COPT_NOQUOTE },
 | |
|   { "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);
 | |
|       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] [-DE] [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
 | |
| 
 | |
| 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);
 | |
| }
 | 
