LCOV - code coverage report
Current view: top level - bash-4.4.23 - pcomplete.c (source / functions) Hit Total Coverage
Test: cov-bash.info Lines: 3 668 0.4 %
Date: 2020-10-29 14:49:28 Functions: 1 41 2.4 %

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

Generated by: LCOV version 1.14.0.6.4058