e1ccaac8678ed6cbd3c2b2496fb6ad258954482c
[platform/upstream/bash.git] / pcomplete.c
1 /* pcomplete.c - functions to generate lists of matches for programmable completion. */
2
3 /* Copyright (C) 1999-2009 Free Software Foundation, Inc.
4
5    This file is part of GNU Bash, the Bourne Again SHell.
6
7    Bash is free software: you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation, either version 3 of the License, or
10    (at your option) any later version.
11
12    Bash is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with Bash.  If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #if defined (PROGRAMMABLE_COMPLETION)
24
25 #include "bashtypes.h"
26 #include "posixstat.h"
27
28 #if defined (HAVE_UNISTD_H)
29 #  include <unistd.h>
30 #endif
31
32 #include <signal.h>
33
34 #if defined (PREFER_STDARG)
35 #  include <stdarg.h>
36 #else
37 #  include <varargs.h>
38 #endif
39
40 #include <stdio.h>
41 #include "bashansi.h"
42 #include "bashintl.h"
43
44 #include "shell.h"
45 #include "pcomplete.h"
46 #include "alias.h"
47 #include "bashline.h"
48 #include "execute_cmd.h"
49 #include "pathexp.h"
50
51 #if defined (JOB_CONTROL)
52 #  include "jobs.h"
53 #endif
54
55 #if !defined (NSIG)
56 #  include "trap.h"
57 #endif
58
59 #include "builtins.h"
60 #include "builtins/common.h"
61
62 #include <glob/glob.h>
63 #include <glob/strmatch.h>
64
65 #include <readline/rlconf.h>
66 #include <readline/readline.h>
67 #include <readline/history.h>
68
69 #ifdef STRDUP
70 #  undef STRDUP
71 #endif
72 #define STRDUP(x)       ((x) ? savestring (x) : (char *)NULL)
73
74 typedef SHELL_VAR **SVFUNC ();
75
76 #ifndef HAVE_STRPBRK
77 extern char *strpbrk __P((char *, char *));
78 #endif
79
80 extern int array_needs_making;
81 extern STRING_INT_ALIST word_token_alist[];
82 extern char *signal_names[];
83
84 #if defined (DEBUG)
85 #if defined (PREFER_STDARG)
86 static void debug_printf (const char *, ...)  __attribute__((__format__ (printf, 1, 2)));
87 #endif
88 #endif /* DEBUG */
89
90 static int it_init_joblist __P((ITEMLIST *, int));
91
92 static int it_init_aliases __P((ITEMLIST *));
93 static int it_init_arrayvars __P((ITEMLIST *));
94 static int it_init_bindings __P((ITEMLIST *));
95 static int it_init_builtins __P((ITEMLIST *));
96 static int it_init_disabled __P((ITEMLIST *));
97 static int it_init_enabled __P((ITEMLIST *));
98 static int it_init_exported __P((ITEMLIST *));
99 static int it_init_functions __P((ITEMLIST *));
100 static int it_init_hostnames __P((ITEMLIST *));
101 static int it_init_jobs __P((ITEMLIST *));
102 static int it_init_running __P((ITEMLIST *));
103 static int it_init_stopped __P((ITEMLIST *));
104 static int it_init_keywords __P((ITEMLIST *));
105 static int it_init_signals __P((ITEMLIST *));
106 static int it_init_variables __P((ITEMLIST *));
107 static int it_init_setopts __P((ITEMLIST *));
108 static int it_init_shopts __P((ITEMLIST *));
109
110 static int shouldexp_filterpat __P((char *));
111 static char *preproc_filterpat __P((char *, char *));
112
113 static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *));
114
115 static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *));
116 static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *));
117 static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *));
118 static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *));
119 static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *,
120                                                    char *, int, WORD_LIST *,
121                                                    int, int));
122 static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, char *,
123                                             int, WORD_LIST *, int, int));
124
125 static char *pcomp_filename_completion_function __P((const char *, int));
126
127 #if defined (ARRAY_VARS)
128 static SHELL_VAR *bind_comp_words __P((WORD_LIST *));
129 #endif
130 static void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int));
131 static void unbind_compfunc_variables __P((int));
132 static WORD_LIST *build_arg_list __P((char *, const char *, WORD_LIST *, int));
133 static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *));
134
135 #ifdef DEBUG
136 static int progcomp_debug = 0;
137 #endif
138
139 int prog_completion_enabled = 1;
140
141 /* These are used to manage the arrays of strings for possible completions. */
142 ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 };
143 ITEMLIST it_arrayvars  = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 };
144 ITEMLIST it_bindings  = { 0, it_init_bindings, (STRINGLIST *)0 };
145 ITEMLIST it_builtins  = { 0, it_init_builtins, (STRINGLIST *)0 };
146 ITEMLIST it_commands = { LIST_DYNAMIC };        /* unused */
147 ITEMLIST it_directories = { LIST_DYNAMIC };     /* unused */
148 ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 };
149 ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 };
150 ITEMLIST it_exports  = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 };
151 ITEMLIST it_files = { LIST_DYNAMIC };           /* unused */
152 ITEMLIST it_functions  = { 0, it_init_functions, (STRINGLIST *)0 };
153 ITEMLIST it_hostnames  = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 };
154 ITEMLIST it_groups = { LIST_DYNAMIC };          /* unused */
155 ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 };
156 ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 };
157 ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 };
158 ITEMLIST it_services = { LIST_DYNAMIC };        /* unused */
159 ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 };
160 ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 };
161 ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 };
162 ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 };
163 ITEMLIST it_users = { LIST_DYNAMIC };           /* unused */
164 ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 };
165
166 COMPSPEC *pcomp_curcs;
167 const char *pcomp_curcmd;
168
169 #ifdef DEBUG
170 /* Debugging code */
171 static void
172 #if defined (PREFER_STDARG)
173 debug_printf (const char *format, ...)
174 #else
175 debug_printf (format, va_alist)
176      const char *format;
177      va_dcl
178 #endif
179 {
180   va_list args;
181
182   if (progcomp_debug == 0)
183     return;
184
185   SH_VA_START (args, format);
186
187   fprintf (stdout, "DEBUG: ");
188   vfprintf (stdout, format, args);
189   fprintf (stdout, "\n");
190
191   rl_on_new_line ();
192
193   va_end (args);
194 }
195 #endif
196
197 /* Functions to manage the item lists */
198
199 void
200 set_itemlist_dirty (it)
201      ITEMLIST *it;
202 {
203   it->flags |= LIST_DIRTY;
204 }
205
206 void
207 initialize_itemlist (itp)
208      ITEMLIST *itp;
209 {
210   (*itp->list_getter) (itp);
211   itp->flags |= LIST_INITIALIZED;
212   itp->flags &= ~LIST_DIRTY;
213 }
214
215 void
216 clean_itemlist (itp)
217      ITEMLIST *itp;
218 {
219   STRINGLIST *sl;
220
221   sl = itp->slist;
222   if (sl)
223     {
224       if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0)
225         strvec_flush (sl->list);
226       if ((itp->flags & LIST_DONTFREE) == 0)
227         free (sl->list);
228       free (sl);
229     }
230   itp->slist = (STRINGLIST *)NULL;
231   itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY);
232 }
233
234
235 static int
236 shouldexp_filterpat (s)
237      char *s;
238 {
239   register char *p;
240
241   for (p = s; p && *p; p++)
242     {
243       if (*p == '\\')
244         p++;
245       else if (*p == '&')
246         return 1;
247     }
248   return 0;
249 }
250
251 /* Replace any instance of `&' in PAT with TEXT.  Backslash may be used to
252    quote a `&' and inhibit substitution.  Returns a new string.  This just
253    calls stringlib.c:strcreplace(). */
254 static char *
255 preproc_filterpat (pat, text)
256      char *pat;
257      char *text;
258 {
259   char *ret;
260
261   ret = strcreplace (pat, '&', text, 1);
262   return ret;
263 }
264         
265 /* Remove any match of FILTERPAT from SL.  A `&' in FILTERPAT is replaced by
266    TEXT.  A leading `!' in FILTERPAT negates the pattern; in this case
267    any member of SL->list that does *not* match will be removed.  This returns
268    a new STRINGLIST with the matching members of SL *copied*.  Any
269    non-matching members of SL->list are *freed*. */   
270 STRINGLIST *
271 filter_stringlist (sl, filterpat, text)
272      STRINGLIST *sl;
273      char *filterpat, *text;
274 {
275   int i, m, not;
276   STRINGLIST *ret;
277   char *npat, *t;
278
279   if (sl == 0 || sl->list == 0 || sl->list_len == 0)
280     return sl;
281
282   npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat;
283
284   not = (npat[0] == '!');
285   t = not ? npat + 1 : npat;
286
287   ret = strlist_create (sl->list_size);
288   for (i = 0; i < sl->list_len; i++)
289     {
290       m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG);
291       if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH))
292         free (sl->list[i]);
293       else
294         ret->list[ret->list_len++] = sl->list[i];
295     }
296
297   ret->list[ret->list_len] = (char *)NULL;
298   if (npat != filterpat)
299     free (npat);
300
301   return ret;
302 }
303
304 /* Turn an array of strings returned by rl_completion_matches into a STRINGLIST.
305    This understands how rl_completion_matches sets matches[0] (the lcd of the
306    strings in the list, unless it's the only match). */
307 STRINGLIST *
308 completions_to_stringlist (matches)
309      char **matches;
310 {
311   STRINGLIST *sl;
312   int mlen, i, n;
313
314   mlen = (matches == 0) ? 0 : strvec_len (matches);
315   sl = strlist_create (mlen + 1);
316
317   if (matches == 0 || matches[0] == 0)
318     return sl;
319
320   if (matches[1] == 0)
321     {
322       sl->list[0] = STRDUP (matches[0]);
323       sl->list[sl->list_len = 1] = (char *)NULL;
324       return sl;
325     }
326
327   for (i = 1, n = 0; i < mlen; i++, n++)
328     sl->list[n] = STRDUP (matches[i]);
329   sl->list_len = n;
330   sl->list[n] = (char *)NULL;
331
332   return sl;
333 }
334
335 /* Functions to manage the various ITEMLISTs that we populate internally.
336    The caller is responsible for setting ITP->flags correctly. */
337
338 static int
339 it_init_aliases (itp)
340      ITEMLIST *itp;
341 {
342 #ifdef ALIAS
343   alias_t **alias_list;
344   register int i, n;
345   STRINGLIST *sl;
346
347   alias_list = all_aliases ();
348   if (alias_list == 0)
349     {
350       itp->slist = (STRINGLIST *)NULL;
351       return 0;
352     }
353   for (n = 0; alias_list[n]; n++)
354     ;
355   sl = strlist_create (n+1);
356   for (i = 0; i < n; i++)
357     sl->list[i] = STRDUP (alias_list[i]->name);
358   sl->list[n] = (char *)NULL;
359   sl->list_size = sl->list_len = n;
360   itp->slist = sl;
361 #else
362   itp->slist = (STRINGLIST *)NULL;
363 #endif
364   return 1;
365 }
366
367 static void
368 init_itemlist_from_varlist (itp, svfunc)
369      ITEMLIST *itp;
370      SVFUNC *svfunc;
371 {
372   SHELL_VAR **vlist;
373   STRINGLIST *sl;
374   register int i, n;
375
376   vlist = (*svfunc) ();
377   if (vlist == 0)
378     {
379       itp->slist = (STRINGLIST *)NULL;
380       return;
381     }    
382   for (n = 0; vlist[n]; n++)
383     ;
384   sl = strlist_create (n+1);
385   for (i = 0; i < n; i++)
386     sl->list[i] = savestring (vlist[i]->name);
387   sl->list[sl->list_len = n] = (char *)NULL;
388   itp->slist = sl;
389 }
390
391 static int
392 it_init_arrayvars (itp)
393      ITEMLIST *itp;
394 {
395 #if defined (ARRAY_VARS)
396   init_itemlist_from_varlist (itp, all_array_variables);
397   return 1;
398 #else
399   return 0;
400 #endif
401 }
402
403 static int
404 it_init_bindings (itp)
405      ITEMLIST *itp;
406 {
407   char **blist;
408   STRINGLIST *sl;
409
410   /* rl_funmap_names allocates blist, but not its members */
411   blist = (char **)rl_funmap_names ();  /* XXX fix const later */
412   sl = strlist_create (0);
413   sl->list = blist;
414   sl->list_size = 0;
415   sl->list_len = strvec_len (sl->list);
416   itp->flags |= LIST_DONTFREEMEMBERS;
417   itp->slist = sl;
418
419   return 0;
420 }
421
422 static int
423 it_init_builtins (itp)
424      ITEMLIST *itp;
425 {
426   STRINGLIST *sl;
427   register int i, n;
428
429   sl = strlist_create (num_shell_builtins);
430   for (i = n = 0; i < num_shell_builtins; i++)
431     if (shell_builtins[i].function)
432       sl->list[n++] = shell_builtins[i].name;
433   sl->list[sl->list_len = n] = (char *)NULL;
434   itp->flags |= LIST_DONTFREEMEMBERS;
435   itp->slist = sl;
436   return 0;
437 }
438
439 static int
440 it_init_enabled (itp)
441      ITEMLIST *itp;
442 {
443   STRINGLIST *sl;
444   register int i, n;
445
446   sl = strlist_create (num_shell_builtins);
447   for (i = n = 0; i < num_shell_builtins; i++)
448     {
449       if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED))
450         sl->list[n++] = shell_builtins[i].name;
451     }
452   sl->list[sl->list_len = n] = (char *)NULL;
453   itp->flags |= LIST_DONTFREEMEMBERS;
454   itp->slist = sl;
455   return 0;
456 }
457
458 static int
459 it_init_disabled (itp)
460      ITEMLIST *itp;
461 {
462   STRINGLIST *sl;
463   register int i, n;
464
465   sl = strlist_create (num_shell_builtins);
466   for (i = n = 0; i < num_shell_builtins; i++)
467     {
468       if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
469         sl->list[n++] = shell_builtins[i].name;
470     }
471   sl->list[sl->list_len = n] = (char *)NULL;
472   itp->flags |= LIST_DONTFREEMEMBERS;
473   itp->slist = sl;
474   return 0;
475 }
476
477 static int
478 it_init_exported (itp)
479      ITEMLIST *itp;
480 {
481   init_itemlist_from_varlist (itp, all_exported_variables);
482   return 0;
483 }
484
485 static int
486 it_init_functions (itp)
487      ITEMLIST *itp;
488 {
489   init_itemlist_from_varlist (itp, all_visible_functions);
490   return 0;
491 }
492
493 static int
494 it_init_hostnames (itp)
495      ITEMLIST *itp;
496 {
497   STRINGLIST *sl;
498
499   sl = strlist_create (0);
500   sl->list = get_hostname_list ();
501   sl->list_len = sl->list ? strvec_len (sl->list) : 0;
502   sl->list_size = sl->list_len;
503   itp->slist = sl;
504   itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE;
505   return 0;
506 }
507
508 static int
509 it_init_joblist (itp, jstate)
510      ITEMLIST *itp;
511      int jstate;
512 {
513 #if defined (JOB_CONTROL)
514   STRINGLIST *sl;
515   register int i;
516   register PROCESS *p;
517   char *s, *t;
518   JOB *j;
519   JOB_STATE ws;         /* wanted state */
520
521   ws = JNONE;
522   if (jstate == 0)
523     ws = JRUNNING;
524   else if (jstate == 1)
525     ws = JSTOPPED;
526
527   sl = strlist_create (js.j_jobslots);
528   for (i = js.j_jobslots - 1; i >= 0; i--)
529     {
530       j = get_job_by_jid (i);
531       if (j == 0)
532         continue;
533       p = j->pipe;
534       if (jstate == -1 || JOBSTATE(i) == ws)
535         {
536           s = savestring (p->command);
537           t = strpbrk (s, " \t\n");
538           if (t)
539             *t = '\0';
540           sl->list[sl->list_len++] = s;
541         }
542     }
543   itp->slist = sl;
544 #else
545   itp->slist = (STRINGLIST *)NULL;
546 #endif
547   return 0;
548 }
549
550 static int
551 it_init_jobs (itp)
552      ITEMLIST *itp;
553 {
554   return (it_init_joblist (itp, -1));
555 }
556
557 static int
558 it_init_running (itp)
559      ITEMLIST *itp;
560 {
561   return (it_init_joblist (itp, 0));
562 }
563
564 static int
565 it_init_stopped (itp)
566      ITEMLIST *itp;
567 {
568   return (it_init_joblist (itp, 1));
569 }
570
571 static int
572 it_init_keywords (itp)
573      ITEMLIST *itp;
574 {
575   STRINGLIST *sl;
576   register int i, n;
577
578   for (n = 0; word_token_alist[n].word; n++)
579     ;
580   sl = strlist_create (n);
581   for (i = 0; i < n; i++)
582     sl->list[i] = word_token_alist[i].word;
583   sl->list[sl->list_len = i] = (char *)NULL;
584   itp->flags |= LIST_DONTFREEMEMBERS;
585   itp->slist = sl;
586   return 0;
587 }
588
589 static int
590 it_init_signals (itp)
591      ITEMLIST *itp;
592 {
593   STRINGLIST *sl;
594
595   sl = strlist_create (0);
596   sl->list = signal_names;
597   sl->list_len = strvec_len (sl->list);
598   itp->flags |= LIST_DONTFREE;
599   itp->slist = sl;
600   return 0;
601 }
602
603 static int
604 it_init_variables (itp)
605      ITEMLIST *itp;
606 {
607   init_itemlist_from_varlist (itp, all_visible_variables);
608   return 0;
609 }
610
611 static int
612 it_init_setopts (itp)
613      ITEMLIST *itp;
614 {
615   STRINGLIST *sl;
616
617   sl = strlist_create (0);
618   sl->list = get_minus_o_opts ();
619   sl->list_len = strvec_len (sl->list);
620   itp->slist = sl;
621   itp->flags |= LIST_DONTFREEMEMBERS;
622   return 0;
623 }
624
625 static int
626 it_init_shopts (itp)
627      ITEMLIST *itp;
628 {
629   STRINGLIST *sl;
630
631   sl = strlist_create (0);
632   sl->list = get_shopt_options ();
633   sl->list_len = strvec_len (sl->list);
634   itp->slist = sl;
635   itp->flags |= LIST_DONTFREEMEMBERS;
636   return 0;
637 }
638
639 /* Generate a list of all matches for TEXT using the STRINGLIST in itp->slist
640    as the list of possibilities.  If the itemlist has been marked dirty or
641    it should be regenerated every time, destroy the old STRINGLIST and make a
642    new one before trying the match.  TEXT is dequoted before attempting a
643    match. */
644 static STRINGLIST *
645 gen_matches_from_itemlist (itp, text)
646      ITEMLIST *itp;
647      const char *text;
648 {
649   STRINGLIST *ret, *sl;
650   int tlen, i, n;
651   char *ntxt;
652
653   if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) ||
654       (itp->flags & LIST_INITIALIZED) == 0)
655     {
656       if (itp->flags & (LIST_DIRTY | LIST_DYNAMIC))
657         clean_itemlist (itp);
658       if ((itp->flags & LIST_INITIALIZED) == 0)
659         initialize_itemlist (itp);
660     }
661   if (itp->slist == 0)
662     return ((STRINGLIST *)NULL);
663   ret = strlist_create (itp->slist->list_len+1);
664   sl = itp->slist;
665
666   ntxt = bash_dequote_text (text);
667   tlen = STRLEN (ntxt);
668
669   for (i = n = 0; i < sl->list_len; i++)
670     {
671       if (tlen == 0 || STREQN (sl->list[i], ntxt, tlen))
672         ret->list[n++] = STRDUP (sl->list[i]);
673     }
674   ret->list[ret->list_len = n] = (char *)NULL;
675
676   FREE (ntxt);
677   return ret;
678 }
679
680 /* A wrapper for rl_filename_completion_function that dequotes the filename
681    before attempting completions. */
682 static char *
683 pcomp_filename_completion_function (text, state)
684      const char *text;
685      int state;
686 {
687   static char *dfn;     /* dequoted filename */
688   int qc;
689
690   if (state == 0)
691     {
692       FREE (dfn);
693       /* remove backslashes quoting special characters in filenames. */
694 #if 1
695       if (RL_ISSTATE (RL_STATE_COMPLETING) && rl_filename_dequoting_function)
696 #else
697       if (rl_filename_dequoting_function)
698 #endif
699         {
700           /* Use rl_completion_quote_character because any single or
701              double quotes have been removed by the time TEXT makes it
702              here, and we don't want to remove backslashes inside
703              quoted strings. */
704           dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
705         }
706       else
707         dfn = savestring (text);
708     }
709
710   return (rl_filename_completion_function (dfn, state));
711 }
712
713 #define GEN_COMPS(bmap, flag, it, text, glist, tlist) \
714   do { \
715     if (bmap & flag) \
716       { \
717         tlist = gen_matches_from_itemlist (it, text); \
718         if (tlist) \
719           { \
720             glist = strlist_append (glist, tlist); \
721             strlist_dispose (tlist); \
722           } \
723       } \
724   } while (0)
725
726 #define GEN_XCOMPS(bmap, flag, text, func, cmatches, glist, tlist) \
727   do { \
728     if (bmap & flag) \
729       { \
730         cmatches = rl_completion_matches (text, func); \
731         tlist = completions_to_stringlist (cmatches); \
732         glist = strlist_append (glist, tlist); \
733         strvec_dispose (cmatches); \
734         strlist_dispose (tlist); \
735       } \
736   } while (0)
737
738 /* Functions to generate lists of matches from the actions member of CS. */
739
740 static STRINGLIST *
741 gen_action_completions (cs, text)
742      COMPSPEC *cs;
743      const char *text;
744 {
745   STRINGLIST *ret, *tmatches;
746   char **cmatches;      /* from rl_completion_matches ... */
747   unsigned long flags;
748
749   ret = tmatches = (STRINGLIST *)NULL;
750   flags = cs->actions;
751
752   GEN_COMPS (flags, CA_ALIAS, &it_aliases, text, ret, tmatches);
753   GEN_COMPS (flags, CA_ARRAYVAR, &it_arrayvars, text, ret, tmatches);
754   GEN_COMPS (flags, CA_BINDING, &it_bindings, text, ret, tmatches);
755   GEN_COMPS (flags, CA_BUILTIN, &it_builtins, text, ret, tmatches);
756   GEN_COMPS (flags, CA_DISABLED, &it_disabled, text, ret, tmatches);
757   GEN_COMPS (flags, CA_ENABLED, &it_enabled, text, ret, tmatches);
758   GEN_COMPS (flags, CA_EXPORT, &it_exports, text, ret, tmatches);
759   GEN_COMPS (flags, CA_FUNCTION, &it_functions, text, ret, tmatches);
760   GEN_COMPS (flags, CA_HOSTNAME, &it_hostnames, text, ret, tmatches);
761   GEN_COMPS (flags, CA_JOB, &it_jobs, text, ret, tmatches);
762   GEN_COMPS (flags, CA_KEYWORD, &it_keywords, text, ret, tmatches);
763   GEN_COMPS (flags, CA_RUNNING, &it_running, text, ret, tmatches);
764   GEN_COMPS (flags, CA_SETOPT, &it_setopts, text, ret, tmatches);
765   GEN_COMPS (flags, CA_SHOPT, &it_shopts, text, ret, tmatches);
766   GEN_COMPS (flags, CA_SIGNAL, &it_signals, text, ret, tmatches);
767   GEN_COMPS (flags, CA_STOPPED, &it_stopped, text, ret, tmatches);
768   GEN_COMPS (flags, CA_VARIABLE, &it_variables, text, ret, tmatches);
769
770   GEN_XCOMPS(flags, CA_COMMAND, text, command_word_completion_function, cmatches, ret, tmatches);
771   GEN_XCOMPS(flags, CA_FILE, text, pcomp_filename_completion_function, cmatches, ret, tmatches);
772   GEN_XCOMPS(flags, CA_USER, text, rl_username_completion_function, cmatches, ret, tmatches);
773   GEN_XCOMPS(flags, CA_GROUP, text, bash_groupname_completion_function, cmatches, ret, tmatches);
774   GEN_XCOMPS(flags, CA_SERVICE, text, bash_servicename_completion_function, cmatches, ret, tmatches);
775
776   /* And lastly, the special case for directories */
777   if (flags & CA_DIRECTORY)
778     {
779       rl_completion_mark_symlink_dirs = 1;      /* override user preference */
780       cmatches = bash_directory_completion_matches (text);
781       tmatches = completions_to_stringlist (cmatches);
782       ret = strlist_append (ret, tmatches);
783       strvec_dispose (cmatches);
784       strlist_dispose (tmatches);
785     }
786
787   return ret;
788 }
789
790 /* Generate a list of matches for CS->globpat.  Unresolved: should this use
791    TEXT as a match prefix, or just go without?  Currently, the code does not
792    use TEXT, just globs CS->globpat and returns the results.  If we do decide
793    to use TEXT, we should call quote_string_for_globbing before the call to
794    glob_filename. */
795 static STRINGLIST *
796 gen_globpat_matches (cs, text)
797       COMPSPEC *cs;
798       const char *text;
799 {
800   STRINGLIST *sl;
801
802   sl = strlist_create (0);
803   sl->list = glob_filename (cs->globpat, 0);
804   if (GLOB_FAILED (sl->list))
805     sl->list = (char **)NULL;
806   if (sl->list)
807     sl->list_len = sl->list_size = strvec_len (sl->list);
808   return sl;
809 }
810
811 /* Perform the shell word expansions on CS->words and return the results.
812    Again, this ignores TEXT. */
813 static STRINGLIST *
814 gen_wordlist_matches (cs, text)
815      COMPSPEC *cs;
816      const char *text;
817 {
818   WORD_LIST *l, *l2;
819   STRINGLIST *sl;
820   int nw, tlen;
821   char *ntxt;           /* dequoted TEXT to use in comparisons */
822
823   if (cs->words == 0 || cs->words[0] == '\0')
824     return ((STRINGLIST *)NULL);
825
826   /* This used to be a simple expand_string(cs->words, 0), but that won't
827      do -- there's no way to split a simple list into individual words
828      that way, since the shell semantics say that word splitting is done
829      only on the results of expansion. */
830   l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, (int *)NULL, (int *)NULL);
831   if (l == 0)
832     return ((STRINGLIST *)NULL);
833   /* This will jump back to the top level if the expansion fails... */
834   l2 = expand_words_shellexp (l);
835   dispose_words (l);
836
837   nw = list_length (l2);
838   sl = strlist_create (nw + 1);
839
840   ntxt = bash_dequote_text (text);
841   tlen = STRLEN (ntxt);
842
843   for (nw = 0, l = l2; l; l = l->next)
844     {
845       if (tlen == 0 || STREQN (l->word->word, ntxt, tlen))
846         sl->list[nw++] = STRDUP (l->word->word);
847     }
848   sl->list[sl->list_len = nw] = (char *)NULL;
849
850   dispose_words (l2);
851   FREE (ntxt);
852   return sl;
853 }
854
855 #ifdef ARRAY_VARS
856
857 static SHELL_VAR *
858 bind_comp_words (lwords)
859      WORD_LIST *lwords;
860 {
861   SHELL_VAR *v;
862
863   v = find_variable ("COMP_WORDS");
864   if (v == 0)
865     v = make_new_array_variable ("COMP_WORDS");
866   if (readonly_p (v))
867     VUNSETATTR (v, att_readonly);
868   if (array_p (v) == 0)
869     v = convert_var_to_array (v);
870   v = assign_array_var_from_word_list (v, lwords, 0);
871
872   VUNSETATTR (v, att_invisible);
873   return v;
874 }
875 #endif /* ARRAY_VARS */
876
877 static void
878 bind_compfunc_variables (line, ind, lwords, cw, exported)
879      char *line;
880      int ind;
881      WORD_LIST *lwords;
882      int cw, exported;
883 {
884   char ibuf[INT_STRLEN_BOUND(int) + 1];
885   char *value;
886   SHELL_VAR *v;
887
888   /* Set the variables that the function expects while it executes.  Maybe
889      these should be in the function environment (temporary_env). */
890   v = bind_variable ("COMP_LINE", line, 0);
891   if (v && exported)
892     VSETATTR(v, att_exported);
893
894   value = inttostr (ind, ibuf, sizeof(ibuf));
895   v = bind_int_variable ("COMP_POINT", value);
896   if (v && exported)
897     VSETATTR(v, att_exported);
898
899   value = inttostr (rl_completion_type, ibuf, sizeof (ibuf));
900   v = bind_int_variable ("COMP_TYPE", value);
901   if (v && exported)
902     VSETATTR(v, att_exported);
903
904   value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf));
905   v = bind_int_variable ("COMP_KEY", value);
906   if (v && exported)
907     VSETATTR(v, att_exported);
908
909   /* Since array variables can't be exported, we don't bother making the
910      array of words. */
911   if (exported == 0)
912     {
913 #ifdef ARRAY_VARS
914       v = bind_comp_words (lwords);
915       value = inttostr (cw, ibuf, sizeof(ibuf));
916       bind_int_variable ("COMP_CWORD", value);
917 #endif
918     }
919   else
920     array_needs_making = 1;
921 }
922
923 static void
924 unbind_compfunc_variables (exported)
925      int exported;
926 {
927   unbind_variable ("COMP_LINE");
928   unbind_variable ("COMP_POINT");
929   unbind_variable ("COMP_TYPE");
930   unbind_variable ("COMP_KEY");
931 #ifdef ARRAY_VARS
932   unbind_variable ("COMP_WORDS");
933   unbind_variable ("COMP_CWORD");
934 #endif
935   if (exported)
936     array_needs_making = 1;
937 }
938
939 /* Build the list of words to pass to a function or external command
940    as arguments.  When the function or command is invoked,
941
942         $0 == function or command being invoked
943         $1 == command name
944         $2 == word to be completed (possibly null)
945         $3 == previous word
946
947    Functions can access all of the words in the current command line
948    with the COMP_WORDS array.  External commands cannot; they have to
949    make do  with the COMP_LINE and COMP_POINT variables. */
950
951 static WORD_LIST *
952 build_arg_list (cmd, text, lwords, ind)
953      char *cmd;
954      const char *text;
955      WORD_LIST *lwords;
956      int ind;
957 {
958   WORD_LIST *ret, *cl, *l;
959   WORD_DESC *w;
960   int i;
961
962   ret = (WORD_LIST *)NULL;
963   w = make_word (cmd);
964   ret = make_word_list (w, (WORD_LIST *)NULL);
965
966   w = (lwords && lwords->word) ? copy_word (lwords->word) : make_word ("");
967   cl = ret->next = make_word_list (w, (WORD_LIST *)NULL);
968
969   w = make_word (text);
970   cl->next = make_word_list (w, (WORD_LIST *)NULL);
971   cl = cl->next;
972
973   /* Search lwords for current word */
974   for (l = lwords, i = 1; l && i < ind-1; l = l->next, i++)
975     ;
976   w = (l && l->word) ? copy_word (l->word) : make_word ("");
977   cl->next = make_word_list (w, (WORD_LIST *)NULL);
978
979   return ret;
980 }
981
982 /* Build a command string with
983         $0 == cs->funcname      (function to execute for completion list)
984         $1 == command name      (command being completed)
985         $2 = word to be completed (possibly null)
986         $3 = previous word
987    and run in the current shell.  The function should put its completion
988    list into the array variable COMPREPLY.  We build a STRINGLIST
989    from the results and return it.
990
991    Since the shell function should return its list of matches in an array
992    variable, this does nothing if arrays are not compiled into the shell. */
993
994 static STRINGLIST *
995 gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
996      COMPSPEC *cs;
997      const char *text;
998      char *line;
999      int ind;
1000      WORD_LIST *lwords;
1001      int nw, cw;
1002 {
1003   char *funcname;
1004   STRINGLIST *sl;
1005   SHELL_VAR *f, *v;
1006   WORD_LIST *cmdlist;
1007   int fval;
1008   sh_parser_state_t ps;
1009   sh_parser_state_t * restrict pps;
1010 #if defined (ARRAY_VARS)
1011   ARRAY *a;
1012 #endif
1013
1014   funcname = cs->funcname;
1015   f = find_function (funcname);
1016   if (f == 0)
1017     {
1018       internal_error (_("completion: function `%s' not found"), funcname);
1019       rl_ding ();
1020       rl_on_new_line ();
1021       return ((STRINGLIST *)NULL);
1022     }
1023
1024 #if !defined (ARRAY_VARS)
1025   return ((STRINGLIST *)NULL);
1026 #else
1027
1028   /* We pass cw - 1 because command_line_to_word_list returns indices that are
1029      1-based, while bash arrays are 0-based. */
1030   bind_compfunc_variables (line, ind, lwords, cw - 1, 0);
1031
1032   cmdlist = build_arg_list (funcname, text, lwords, cw);
1033
1034   pps = &ps;
1035   begin_unwind_frame ("gen-shell-function-matches");
1036   add_unwind_protect (restore_parser_state, (char *)pps);
1037   add_unwind_protect (dispose_words, (char *)cmdlist);
1038   add_unwind_protect (unbind_compfunc_variables, (char *)0);
1039
1040   fval = execute_shell_function (f, cmdlist);  
1041
1042   discard_unwind_frame ("gen-shell-function-matches");
1043   restore_parser_state (pps);
1044
1045   /* Now clean up and destroy everything. */
1046   dispose_words (cmdlist);
1047   unbind_compfunc_variables (0);
1048
1049   /* The list of completions is returned in the array variable COMPREPLY. */
1050   v = find_variable ("COMPREPLY");
1051   if (v == 0)
1052     return ((STRINGLIST *)NULL);
1053   if (array_p (v) == 0)
1054     v = convert_var_to_array (v);
1055
1056   VUNSETATTR (v, att_invisible);
1057
1058   a = array_cell (v);
1059   if (a == 0 || array_empty (a))
1060     sl = (STRINGLIST *)NULL;
1061   else
1062     {
1063       /* XXX - should we filter the list of completions so only those matching
1064          TEXT are returned?  Right now, we do not. */
1065       sl = strlist_create (0);
1066       sl->list = array_to_argv (a);
1067       sl->list_len = sl->list_size = array_num_elements (a);
1068     }
1069
1070   /* XXX - should we unbind COMPREPLY here? */
1071   unbind_variable ("COMPREPLY");
1072
1073   return (sl);
1074 #endif
1075 }
1076
1077 /* Build a command string with
1078         $0 == cs->command       (command to execute for completion list)
1079         $1 == command name      (command being completed)
1080         $2 = word to be completed (possibly null)
1081         $3 = previous word
1082    and run in with command substitution.  Parse the results, one word
1083    per line, with backslashes allowed to escape newlines.  Build a
1084    STRINGLIST from the results and return it. */
1085
1086 static STRINGLIST *
1087 gen_command_matches (cs, text, line, ind, lwords, nw, cw)
1088      COMPSPEC *cs;
1089      const char *text;
1090      char *line;
1091      int ind;
1092      WORD_LIST *lwords;
1093      int nw, cw;
1094 {
1095   char *csbuf, *cscmd, *t;
1096   int cmdlen, cmdsize, n, ws, we;
1097   WORD_LIST *cmdlist, *cl;
1098   WORD_DESC *tw;
1099   STRINGLIST *sl;
1100
1101   bind_compfunc_variables (line, ind, lwords, cw, 1);
1102   cmdlist = build_arg_list (cs->command, text, lwords, cw);
1103
1104   /* Estimate the size needed for the buffer. */
1105   n = strlen (cs->command);
1106   cmdsize = n + 1;
1107   for (cl = cmdlist->next; cl; cl = cl->next)
1108     cmdsize += STRLEN (cl->word->word) + 3;
1109   cmdsize += 2;
1110
1111   /* allocate the string for the command and fill it in. */
1112   cscmd = (char *)xmalloc (cmdsize + 1);
1113
1114   strcpy (cscmd, cs->command);                  /* $0 */
1115   cmdlen = n;
1116   cscmd[cmdlen++] = ' ';
1117   for (cl = cmdlist->next; cl; cl = cl->next)   /* $1, $2, $3, ... */
1118     {
1119       t = sh_single_quote (cl->word->word ? cl->word->word : "");
1120       n = strlen (t);
1121       RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64);
1122       strcpy (cscmd + cmdlen, t);
1123       cmdlen += n;
1124       if (cl->next)
1125         cscmd[cmdlen++] = ' ';
1126       free (t);
1127     }
1128   cscmd[cmdlen] = '\0';
1129
1130   tw = command_substitute (cscmd, 0);
1131   csbuf = tw ? tw->word : (char *)NULL;
1132   dispose_word_desc (tw);
1133
1134   /* Now clean up and destroy everything. */
1135   dispose_words (cmdlist);
1136   free (cscmd);
1137   unbind_compfunc_variables (1);
1138
1139   if (csbuf == 0 || *csbuf == '\0')
1140     {
1141       FREE (csbuf);
1142       return ((STRINGLIST *)NULL);
1143     }
1144
1145   /* Now break CSBUF up at newlines, with backslash allowed to escape a
1146      newline, and put the individual words into a STRINGLIST. */
1147   sl = strlist_create (16);
1148   for (ws = 0; csbuf[ws]; )
1149     {
1150       we = ws;
1151       while (csbuf[we] && csbuf[we] != '\n')
1152         {
1153           if (csbuf[we] == '\\' && csbuf[we+1] == '\n')
1154             we++;
1155           we++;
1156         }
1157       t = substring (csbuf, ws, we);
1158       if (sl->list_len >= sl->list_size - 1)
1159         strlist_resize (sl, sl->list_size + 16);
1160       sl->list[sl->list_len++] = t;
1161       while (csbuf[we] == '\n') we++;
1162       ws = we;
1163     }
1164   sl->list[sl->list_len] = (char *)NULL;
1165
1166   free (csbuf);
1167   return (sl);
1168 }
1169
1170 static WORD_LIST *
1171 command_line_to_word_list (line, llen, sentinel, nwp, cwp)
1172      char *line;
1173      int llen, sentinel, *nwp, *cwp;
1174 {
1175   WORD_LIST *ret;
1176   char *delims;
1177
1178 #if 0
1179   delims = "()<>;&| \t\n";      /* shell metacharacters break words */
1180 #else
1181   delims = rl_completer_word_break_characters;
1182 #endif
1183   ret = split_at_delims (line, llen, delims, sentinel, nwp, cwp);
1184   return (ret);
1185 }
1186
1187 /* Evaluate COMPSPEC *cs and return all matches for WORD. */
1188
1189 STRINGLIST *
1190 gen_compspec_completions (cs, cmd, word, start, end)
1191      COMPSPEC *cs;
1192      const char *cmd;
1193      const char *word;
1194      int start, end;
1195 {
1196   STRINGLIST *ret, *tmatches;
1197   char *line;
1198   int llen, nw, cw;
1199   WORD_LIST *lwords;
1200   COMPSPEC *tcs;
1201
1202 #ifdef DEBUG
1203   debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end);
1204   debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs);
1205 #endif
1206   ret = gen_action_completions (cs, word);
1207 #ifdef DEBUG
1208   if (ret && progcomp_debug)
1209     {
1210       debug_printf ("gen_action_completions (%p, %s) -->", cs, word);
1211       strlist_print (ret, "\t");
1212       rl_on_new_line ();
1213     }
1214 #endif
1215
1216   /* Now we start generating completions based on the other members of CS. */
1217   if (cs->globpat)
1218     {
1219       tmatches = gen_globpat_matches (cs, word);
1220       if (tmatches)
1221         {
1222 #ifdef DEBUG
1223           if (progcomp_debug)
1224             {
1225               debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word);
1226               strlist_print (tmatches, "\t");
1227               rl_on_new_line ();
1228             }
1229 #endif
1230           ret = strlist_append (ret, tmatches);
1231           strlist_dispose (tmatches);
1232           rl_filename_completion_desired = 1;
1233         }
1234     }
1235
1236   if (cs->words)
1237     {
1238       tmatches = gen_wordlist_matches (cs, word);
1239       if (tmatches)
1240         {
1241 #ifdef DEBUG
1242           if (progcomp_debug)
1243             {
1244               debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word);
1245               strlist_print (tmatches, "\t");
1246               rl_on_new_line ();
1247             }
1248 #endif
1249           ret = strlist_append (ret, tmatches);
1250           strlist_dispose (tmatches);
1251         }
1252     }
1253
1254   lwords = (WORD_LIST *)NULL;
1255   line = (char *)NULL;
1256   if (cs->command || cs->funcname)
1257     {
1258       /* If we have a command or function to execute, we need to first break
1259          the command line into individual words, find the number of words,
1260          and find the word in the list containing the word to be completed. */
1261       line = substring (rl_line_buffer, start, end);
1262       llen = end - start;
1263
1264 #ifdef DEBUG
1265       debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)",
1266                 line, llen, rl_point - start, &nw, &cw);
1267 #endif
1268       lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw);
1269 #ifdef DEBUG
1270       if (lwords == 0 && llen > 0)
1271         debug_printf ("ERROR: command_line_to_word_list returns NULL");
1272       else if (progcomp_debug)
1273         {
1274           debug_printf ("command_line_to_word_list -->");
1275           printf ("\t");
1276           print_word_list (lwords, "!");
1277           printf ("\n");
1278           fflush(stdout);
1279           rl_on_new_line ();
1280         }
1281 #endif
1282     }
1283
1284   if (cs->funcname)
1285     {
1286       tmatches = gen_shell_function_matches (cs, word, line, rl_point - start, lwords, nw, cw);
1287       if (tmatches)
1288         {
1289 #ifdef DEBUG
1290           if (progcomp_debug)
1291             {
1292               debug_printf ("gen_shell_function_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw);
1293               strlist_print (tmatches, "\t");
1294               rl_on_new_line ();
1295             }
1296 #endif
1297           ret = strlist_append (ret, tmatches);
1298           strlist_dispose (tmatches);
1299         }
1300     }
1301
1302   if (cs->command)
1303     {
1304       tmatches = gen_command_matches (cs, word, line, rl_point - start, lwords, nw, cw);
1305       if (tmatches)
1306         {
1307 #ifdef DEBUG
1308           if (progcomp_debug)
1309             {
1310               debug_printf ("gen_command_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw);
1311               strlist_print (tmatches, "\t");
1312               rl_on_new_line ();
1313             }
1314 #endif
1315           ret = strlist_append (ret, tmatches);
1316           strlist_dispose (tmatches);
1317         }
1318     }
1319
1320   if (cs->command || cs->funcname)
1321     {
1322       if (lwords)
1323         dispose_words (lwords);
1324       FREE (line);
1325     }
1326
1327   if (cs->filterpat)
1328     {
1329       tmatches = filter_stringlist (ret, cs->filterpat, word);
1330 #ifdef DEBUG
1331       if (progcomp_debug)
1332         {
1333           debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word);
1334           strlist_print (tmatches, "\t");
1335           rl_on_new_line ();
1336         }
1337 #endif
1338       if (ret && ret != tmatches)
1339         {
1340           FREE (ret->list);
1341           free (ret);
1342         }
1343       ret = tmatches;
1344     }
1345
1346   if (cs->prefix || cs->suffix)
1347     ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix);
1348
1349   /* If no matches have been generated and the user has specified that
1350       directory completion should be done as a default, call
1351       gen_action_completions again to generate a list of matching directory
1352       names. */
1353   if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES))
1354     {
1355       tcs = compspec_create ();
1356       tcs->actions = CA_DIRECTORY;
1357       ret = gen_action_completions (tcs, word);
1358       compspec_dispose (tcs);
1359     }
1360   else if (cs->options & COPT_PLUSDIRS)
1361     {
1362       tcs = compspec_create ();
1363       tcs->actions = CA_DIRECTORY;
1364       tmatches = gen_action_completions (tcs, word);
1365       ret = strlist_append (ret, tmatches);
1366       strlist_dispose (tmatches);
1367       compspec_dispose (tcs);
1368     }
1369
1370   return (ret);
1371 }
1372
1373 void
1374 pcomp_set_readline_variables (flags, nval)
1375      int flags, nval;
1376 {
1377   /* If the user specified that the compspec returns filenames, make
1378      sure that readline knows it. */
1379   if (flags & COPT_FILENAMES)
1380     rl_filename_completion_desired = nval;
1381   /* If the user doesn't want a space appended, tell readline. */
1382   if (flags & COPT_NOSPACE)
1383     rl_completion_suppress_append = nval;
1384 }
1385
1386 /* Set or unset FLAGS in the options word of the current compspec.
1387    SET_OR_UNSET is 1 for setting, 0 for unsetting. */
1388 void
1389 pcomp_set_compspec_options (cs, flags, set_or_unset)
1390      COMPSPEC *cs;
1391      int flags, set_or_unset;
1392 {
1393   if (cs == 0 && ((cs = pcomp_curcs) == 0))
1394     return;
1395   if (set_or_unset)
1396     cs->options |= flags;
1397   else
1398     cs->options &= ~flags;
1399 }
1400
1401 /* The driver function for the programmable completion code.  Returns a list
1402    of matches for WORD, which is an argument to command CMD.  START and END
1403    bound the command currently being completed in rl_line_buffer. */
1404 char **
1405 programmable_completions (cmd, word, start, end, foundp)
1406      const char *cmd;
1407      const char *word;
1408      int start, end, *foundp;
1409 {
1410   COMPSPEC *cs, *oldcs;
1411   STRINGLIST *ret;
1412   char **rmatches, *t;
1413   const char *oldcmd;
1414
1415   /* We look at the basename of CMD if the full command does not have
1416      an associated COMPSPEC. */
1417   cs = progcomp_search (cmd);
1418   if (cs == 0)
1419     {
1420       t = strrchr (cmd, '/');
1421       if (t)
1422         cs = progcomp_search (++t);
1423     }
1424   if (cs == 0)
1425     {
1426       if (foundp)
1427         *foundp = 0;
1428       return ((char **)NULL);
1429     }
1430
1431   cs = compspec_copy (cs);
1432
1433   oldcs = pcomp_curcs;
1434   oldcmd = pcomp_curcmd;
1435
1436   pcomp_curcs = cs;
1437   pcomp_curcmd = cmd;
1438
1439   /* Signal the caller that we found a COMPSPEC for this command, and pass
1440      back any meta-options associated with the compspec. */
1441   if (foundp)
1442     *foundp = 1|cs->options;
1443
1444   ret = gen_compspec_completions (cs, cmd, word, start, end);
1445
1446   pcomp_curcs = oldcs;
1447   pcomp_curcmd = oldcmd;
1448
1449   compspec_dispose (cs);
1450
1451   if (ret)
1452     {
1453       rmatches = ret->list;
1454       free (ret);
1455     }
1456   else
1457     rmatches = (char **)NULL;
1458
1459   return (rmatches);
1460 }
1461
1462 #endif /* PROGRAMMABLE_COMPLETION */