1/* complete.c, created from complete.def. */
2#line 23 "complete.def"
3
4#line 34 "complete.def"
5
6#include <config.h>
7
8#include <stdio.h>
9
10#include "../bashtypes.h"
11
12#if defined (HAVE_UNISTD_H)
13#  include <unistd.h>
14#endif
15
16#include "../bashansi.h"
17#include "../bashintl.h"
18
19#include "../shell.h"
20#include "../builtins.h"
21#include "../pcomplete.h"
22#include "../bashline.h"
23
24#include "common.h"
25#include "bashgetopt.h"
26
27#include <readline/readline.h>
28
29#define STRDUP(x)       ((x) ? savestring (x) : (char *)NULL)
30
31static int find_compact __P((char *));
32static int find_compopt __P((char *));
33
34static int build_actions __P((WORD_LIST *, int *, int *, unsigned long *, unsigned long *));
35
36static int remove_cmd_completions __P((WORD_LIST *));
37
38static int print_one_completion __P((char *, COMPSPEC *));
39static int print_compitem __P((BUCKET_CONTENTS *));
40static void print_all_completions __P((void));
41static int print_cmd_completions __P((WORD_LIST *));
42
43static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg;
44
45static struct _compacts {
46  char *actname;
47  int actflag;
48  int actopt;
49} compacts[] = {
50  { "alias",     CA_ALIAS,     'a' },
51  { "arrayvar",  CA_ARRAYVAR,   0 },
52  { "binding",   CA_BINDING,    0 },
53  { "builtin",   CA_BUILTIN,   'b' },
54  { "command",   CA_COMMAND,   'c' },
55  { "directory", CA_DIRECTORY, 'd' },
56  { "disabled",  CA_DISABLED,   0 },
57  { "enabled",   CA_ENABLED,    0 },
58  { "export",    CA_EXPORT,    'e' },
59  { "file",      CA_FILE,      'f' },
60  { "function",  CA_FUNCTION,   0 },
61  { "helptopic", CA_BUILTIN,  0 },	/* for now */
62  { "hostname",  CA_HOSTNAME,   0 },
63  { "group",     CA_GROUP,     'g' },
64  { "job",       CA_JOB,       'j' },
65  { "keyword",   CA_KEYWORD,   'k' },
66  { "running",   CA_RUNNING,    0 },
67  { "service",   CA_SERVICE,   's' },
68  { "setopt",    CA_SETOPT,     0 },
69  { "shopt",     CA_SHOPT,      0 },
70  { "signal",    CA_SIGNAL,     0 },
71  { "stopped",   CA_STOPPED,    0 },
72  { "user",      CA_USER,      'u' },
73  { "variable",  CA_VARIABLE,  'v' },
74  { (char *)NULL, 0, 0 },
75};
76
77/* This should be a STRING_INT_ALIST */
78static struct _compopt {
79  char *optname;
80  int optflag;
81} compopts[] = {
82  { "bashdefault", COPT_BASHDEFAULT },
83  { "default",	COPT_DEFAULT },
84  { "dirnames", COPT_DIRNAMES },
85  { "filenames",COPT_FILENAMES},
86  { "nospace",	COPT_NOSPACE },
87  { "plusdirs", COPT_PLUSDIRS },
88  { (char *)NULL, 0 },
89};
90
91static int
92find_compact (name)
93     char *name;
94{
95  register int i;
96
97  for (i = 0; compacts[i].actname; i++)
98    if (STREQ (name, compacts[i].actname))
99      return i;
100  return -1;
101}
102
103static int
104find_compopt (name)
105     char *name;
106{
107  register int i;
108
109  for (i = 0; compopts[i].optname; i++)
110    if (STREQ (name, compopts[i].optname))
111      return i;
112  return -1;
113}
114
115/* Build the actions and compspec options from the options specified in LIST.
116   ACTP is a pointer to an unsigned long in which to place the bitmap of
117   actions.  OPTP is a pointer to an unsigned long in which to place the
118   btmap of compspec options (arguments to `-o').  PP, if non-null, gets 1
119   if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
120   If either is null, the corresponding option generates an error.
121   This also sets variables corresponding to options that take arguments as
122   a side effect; the caller should ensure that those variables are set to
123   NULL before calling build_actions.  Return value:
124   	EX_USAGE = bad option
125   	EXECUTION_SUCCESS = some options supplied
126   	EXECUTION_FAILURE = no options supplied
127*/
128
129static int
130build_actions (list, pp, rp, actp, optp)
131     WORD_LIST *list;
132     int *pp, *rp;
133     unsigned long *actp, *optp;
134{
135  int opt, ind, opt_given;
136  unsigned long acts, copts;
137
138  acts = copts = (unsigned long)0L;
139  opt_given = 0;
140
141  reset_internal_getopt ();
142  while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:")) != -1)
143    {
144      opt_given = 1;
145      switch (opt)
146	{
147	case 'r':
148	  if (rp)
149	    {
150	      *rp = 1;
151	      break;
152	    }
153	  else
154	    {
155	      sh_invalidopt ("-r");
156	      builtin_usage ();
157	      return (EX_USAGE);
158	    }
159
160	case 'p':
161	  if (pp)
162	    {
163	      *pp = 1;
164	      break;
165	    }
166	  else
167	    {
168	      sh_invalidopt ("-p");
169	      builtin_usage ();
170	      return (EX_USAGE);
171	    }
172
173	case 'a':
174	  acts |= CA_ALIAS;
175	  break;
176	case 'b':
177	  acts |= CA_BUILTIN;
178	  break;
179	case 'c':
180	  acts |= CA_COMMAND;
181	  break;
182	case 'd':
183	  acts |= CA_DIRECTORY;
184	  break;
185	case 'e':
186	  acts |= CA_EXPORT;
187	  break;
188	case 'f':
189	  acts |= CA_FILE;
190	  break;
191	case 'g':
192	  acts |= CA_GROUP;
193	  break;
194	case 'j':
195	  acts |= CA_JOB;
196	  break;
197	case 'k':
198	  acts |= CA_KEYWORD;
199	  break;
200	case 's':
201	  acts |= CA_SERVICE;
202	  break;
203	case 'u':
204	  acts |= CA_USER;
205	  break;
206	case 'v':
207	  acts |= CA_VARIABLE;
208	  break;
209	case 'o':
210	  ind = find_compopt (list_optarg);
211	  if (ind < 0)
212	    {
213	      sh_invalidoptname (list_optarg);
214	      return (EX_USAGE);
215	    }
216	  copts |= compopts[ind].optflag;
217	  break;
218	case 'A':
219	  ind = find_compact (list_optarg);
220	  if (ind < 0)
221	    {
222	      builtin_error (_("%s: invalid action name"), list_optarg);
223	      return (EX_USAGE);
224	    }
225	  acts |= compacts[ind].actflag;
226	  break;
227	case 'C':
228	  Carg = list_optarg;
229	  break;
230	case 'F':
231	  Farg = list_optarg;
232	  break;
233	case 'G':
234	  Garg = list_optarg;
235	  break;
236	case 'P':
237	  Parg = list_optarg;
238	  break;
239	case 'S':
240	  Sarg = list_optarg;
241	  break;
242	case 'W':
243	  Warg = list_optarg;
244	  break;
245	case 'X':
246	  Xarg = list_optarg;
247	  break;
248	default:
249	  builtin_usage ();
250	  return (EX_USAGE);
251	}
252    }
253
254  *actp = acts;
255  *optp = copts;
256
257  return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
258}
259
260/* Add, remove, and display completion specifiers. */
261int
262complete_builtin (list)
263     WORD_LIST *list;
264{
265  int opt_given, pflag, rflag, rval;
266  unsigned long acts, copts;
267  COMPSPEC *cs;
268
269  if (list == 0)
270    {
271      print_all_completions ();
272      return (EXECUTION_SUCCESS);
273    }
274
275  opt_given = pflag = rflag = 0;
276  acts = copts = (unsigned long)0L;
277  Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
278  cs = (COMPSPEC *)NULL;
279
280  /* Build the actions from the arguments.  Also sets the [A-Z]arg variables
281     as a side effect if they are supplied as options. */
282  rval = build_actions (list, &pflag, &rflag, &acts, &copts);
283  if (rval == EX_USAGE)
284    return (rval);
285  opt_given = rval != EXECUTION_FAILURE;
286
287  list = loptend;
288
289  /* -p overrides everything else */
290  if (pflag || (list == 0 && opt_given == 0))
291    {
292      if (list == 0)
293	{
294	  print_all_completions ();
295	  return (EXECUTION_SUCCESS);
296	}
297      return (print_cmd_completions (list));
298    }
299
300  /* next, -r overrides everything else. */
301  if (rflag)
302    {
303      if (list == 0)
304	{
305	  progcomp_flush ();
306	  return (EXECUTION_SUCCESS);
307	}
308      return (remove_cmd_completions (list));
309    }
310
311  if (list == 0 && opt_given)
312    {
313      builtin_usage ();
314      return (EX_USAGE);
315    }
316
317  /* If we get here, we need to build a compspec and add it for each
318     remaining argument. */
319  cs = compspec_create ();
320  cs->actions = acts;
321  cs->options = copts;
322
323  cs->globpat = STRDUP (Garg);
324  cs->words = STRDUP (Warg);
325  cs->prefix = STRDUP (Parg);
326  cs->suffix = STRDUP (Sarg);
327  cs->funcname = STRDUP (Farg);
328  cs->command = STRDUP (Carg);
329  cs->filterpat = STRDUP (Xarg);
330
331  for (rval = EXECUTION_SUCCESS ; list; list = list->next)
332    {
333      /* Add CS as the compspec for the specified commands. */
334      if (progcomp_insert (list->word->word, cs) == 0)
335	rval = EXECUTION_FAILURE;
336    }
337
338  return (rval);
339}
340
341static int
342remove_cmd_completions (list)
343     WORD_LIST *list;
344{
345  WORD_LIST *l;
346  int ret;
347
348  for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
349    {
350      if (progcomp_remove (l->word->word) == 0)
351	{
352	  builtin_error (_("%s: no completion specification"), l->word->word);
353	  ret = EXECUTION_FAILURE;
354	}
355    }
356  return ret;
357}
358
359#define SQPRINTARG(a, f) \
360  do { \
361    if (a) \
362      { \
363      	x = sh_single_quote (a); \
364	printf ("%s %s ", f, x); \
365	free (x); \
366      } \
367  } while (0)
368
369#define PRINTARG(a, f) \
370  do { \
371    if (a) \
372      printf ("%s %s ", f, a); \
373  } while (0)
374
375#define PRINTOPT(a, f) \
376  do { \
377    if (acts & a) \
378      printf ("%s ", f); \
379  } while (0)
380
381#define PRINTACT(a, f) \
382  do { \
383    if (acts & a) \
384      printf ("-A %s ", f); \
385  } while (0)
386
387#define PRINTCOMPOPT(a, f) \
388  do { \
389    if (copts & a) \
390      printf ("-o %s ", f); \
391  } while (0)
392
393static int
394print_one_completion (cmd, cs)
395     char *cmd;
396     COMPSPEC *cs;
397{
398  unsigned long acts, copts;
399  char *x;
400
401  printf ("complete ");
402
403  copts = cs->options;
404
405  /* First, print the -o options. */
406  PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
407  PRINTCOMPOPT (COPT_DEFAULT, "default");
408  PRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
409  PRINTCOMPOPT (COPT_FILENAMES, "filenames");
410  PRINTCOMPOPT (COPT_NOSPACE, "nospace");
411  PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
412
413  acts = cs->actions;
414
415  /* simple flags next */
416  PRINTOPT (CA_ALIAS, "-a");
417  PRINTOPT (CA_BUILTIN, "-b");
418  PRINTOPT (CA_COMMAND, "-c");
419  PRINTOPT (CA_DIRECTORY, "-d");
420  PRINTOPT (CA_EXPORT, "-e");
421  PRINTOPT (CA_FILE, "-f");
422  PRINTOPT (CA_GROUP, "-g");
423  PRINTOPT (CA_JOB, "-j");
424  PRINTOPT (CA_KEYWORD, "-k");
425  PRINTOPT (CA_SERVICE, "-s");
426  PRINTOPT (CA_USER, "-u");
427  PRINTOPT (CA_VARIABLE, "-v");
428
429  /* now the rest of the actions */
430  PRINTACT (CA_ARRAYVAR, "arrayvar");
431  PRINTACT (CA_BINDING, "binding");
432  PRINTACT (CA_DISABLED, "disabled");
433  PRINTACT (CA_ENABLED, "enabled");
434  PRINTACT (CA_FUNCTION, "function");
435  PRINTACT (CA_HELPTOPIC, "helptopic");
436  PRINTACT (CA_HOSTNAME, "hostname");
437  PRINTACT (CA_RUNNING, "running");
438  PRINTACT (CA_SETOPT, "setopt");
439  PRINTACT (CA_SHOPT, "shopt");
440  PRINTACT (CA_SIGNAL, "signal");
441  PRINTACT (CA_STOPPED, "stopped");
442
443  /* now the rest of the arguments */
444
445  /* arguments that require quoting */
446  SQPRINTARG (cs->globpat, "-G");
447  SQPRINTARG (cs->words, "-W");
448  SQPRINTARG (cs->prefix, "-P");
449  SQPRINTARG (cs->suffix, "-S");
450  SQPRINTARG (cs->filterpat, "-X");
451
452  /* simple arguments that don't require quoting */
453  PRINTARG (cs->funcname, "-F");
454  PRINTARG (cs->command, "-C");
455
456  printf ("%s\n", cmd);
457
458  return (0);
459}
460
461static int
462print_compitem (item)
463     BUCKET_CONTENTS *item;
464{
465  COMPSPEC *cs;
466  char *cmd;
467
468  cmd = item->key;
469  cs = (COMPSPEC *)item->data;
470
471  return (print_one_completion (cmd, cs));
472}
473
474static void
475print_all_completions ()
476{
477  progcomp_walk (print_compitem);
478}
479
480static int
481print_cmd_completions (list)
482     WORD_LIST *list;
483{
484  WORD_LIST *l;
485  COMPSPEC *cs;
486  int ret;
487
488  for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
489    {
490      cs = progcomp_search (l->word->word);
491      if (cs)
492	print_one_completion (l->word->word, cs);
493      else
494	{
495	  builtin_error (_("%s: no completion specification"), l->word->word);
496	  ret = EXECUTION_FAILURE;
497	}
498    }
499  return (ret);
500}
501
502#line 540 "complete.def"
503
504int
505compgen_builtin (list)
506     WORD_LIST *list;
507{
508  int rval;
509  unsigned long acts, copts;
510  COMPSPEC *cs;
511  STRINGLIST *sl;
512  char *word, **matches;
513
514  if (list == 0)
515    return (EXECUTION_SUCCESS);
516
517  acts = copts = (unsigned long)0L;
518  Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
519  cs = (COMPSPEC *)NULL;
520
521  /* Build the actions from the arguments.  Also sets the [A-Z]arg variables
522     as a side effect if they are supplied as options. */
523  rval = build_actions (list, (int *)NULL, (int *)NULL, &acts, &copts);
524  if (rval == EX_USAGE)
525    return (rval);
526  if (rval == EXECUTION_FAILURE)
527    return (EXECUTION_SUCCESS);
528
529  list = loptend;
530
531  word = (list && list->word) ? list->word->word : "";
532
533  if (Farg)
534    builtin_error (_("warning: -F option may not work as you expect"));
535  if (Carg)
536    builtin_error (_("warning: -C option may not work as you expect"));
537
538  /* If we get here, we need to build a compspec and evaluate it. */
539  cs = compspec_create ();
540  cs->actions = acts;
541  cs->options = copts;
542  cs->refcount = 1;
543
544  cs->globpat = STRDUP (Garg);
545  cs->words = STRDUP (Warg);
546  cs->prefix = STRDUP (Parg);
547  cs->suffix = STRDUP (Sarg);
548  cs->funcname = STRDUP (Farg);
549  cs->command = STRDUP (Carg);
550  cs->filterpat = STRDUP (Xarg);
551
552  rval = EXECUTION_FAILURE;
553  sl = gen_compspec_completions (cs, "compgen", word, 0, 0);
554
555  /* If the compspec wants the bash default completions, temporarily
556     turn off programmable completion and call the bash completion code. */
557  if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT))
558    {
559      matches = bash_default_completion (word, 0, 0, 0, 0);
560      sl = completions_to_stringlist (matches);
561      strvec_dispose (matches);
562    }
563
564  /* This isn't perfect, but it's the best we can do, given what readline
565     exports from its set of completion utility functions. */
566  if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT))
567    {
568      matches = rl_completion_matches (word, rl_filename_completion_function);
569      sl = completions_to_stringlist (matches);
570      strvec_dispose (matches);
571    }
572
573  if (sl)
574    {
575      if (sl->list && sl->list_len)
576	{
577	  rval = EXECUTION_SUCCESS;
578	  strlist_print (sl, (char *)NULL);
579	}
580      strlist_dispose (sl);
581    }
582
583  compspec_dispose (cs);
584  return (rval);
585}
586