Imported from ../bash-2.05b.tar.gz.
[platform/upstream/bash.git] / pcomplete.c
index 17d37d5..1811351 100644 (file)
@@ -1,7 +1,7 @@
 /* pcomplete.c - functions to generate lists of matches for programmable
                 completion. */
 
-/* Copyright (C) 1999 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2002 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -35,9 +35,7 @@
 #if defined (PREFER_STDARG)
 #  include <stdarg.h>
 #else
-#  if defined (PREFER_VARARGS)
-#    include <varargs.h>
-#  endif
+#  include <varargs.h>
 #endif
 
 #include <stdio.h>
@@ -83,9 +81,11 @@ extern int array_needs_making;
 extern STRING_INT_ALIST word_token_alist[];
 extern char *signal_names[];
 
-#if defined(PREFER_STDARG)
+#if defined (DEBUG)
+#if defined (PREFER_STDARG)
 static void debug_printf (const char *, ...)  __attribute__((__format__ (printf, 1, 2)));
 #endif
+#endif /* DEBUG */
 
 static int it_init_joblist __P((ITEMLIST *, int));
 
@@ -132,7 +132,9 @@ static void unbind_compfunc_variables __P((int));
 static WORD_LIST *build_arg_list __P((char *, const char *, WORD_LIST *, int));
 static WORD_LIST *command_line_to_word_list __P((char *, int, int, int *, int *));
 
+#ifdef DEBUG
 static int progcomp_debug = 0;
+#endif
 
 int prog_completion_enabled = 1;
 
@@ -146,34 +148,23 @@ ITEMLIST it_directories = { LIST_DYNAMIC };       /* unused */
 ITEMLIST it_disabled = { 0, it_init_disabled, (STRINGLIST *)0 };
 ITEMLIST it_enabled = { 0, it_init_enabled, (STRINGLIST *)0 };
 ITEMLIST it_exports  = { LIST_DYNAMIC, it_init_exported, (STRINGLIST *)0 };
-ITEMLIST it_files = { LIST_DYNAMIC };  /* unused */
+ITEMLIST it_files = { LIST_DYNAMIC };          /* unused */
 ITEMLIST it_functions  = { 0, it_init_functions, (STRINGLIST *)0 };
 ITEMLIST it_hostnames  = { LIST_DYNAMIC, it_init_hostnames, (STRINGLIST *)0 };
-ITEMLIST it_groups = { LIST_DYNAMIC }; /* unused */
+ITEMLIST it_groups = { LIST_DYNAMIC };         /* unused */
 ITEMLIST it_jobs = { LIST_DYNAMIC, it_init_jobs, (STRINGLIST *)0 };
 ITEMLIST it_keywords = { 0, it_init_keywords, (STRINGLIST *)0 };
 ITEMLIST it_running = { LIST_DYNAMIC, it_init_running, (STRINGLIST *)0 };
+ITEMLIST it_services = { LIST_DYNAMIC };       /* unused */
 ITEMLIST it_setopts = { 0, it_init_setopts, (STRINGLIST *)0 };
 ITEMLIST it_shopts = { 0, it_init_shopts, (STRINGLIST *)0 };
 ITEMLIST it_signals = { 0, it_init_signals, (STRINGLIST *)0 };
 ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 };
-ITEMLIST it_users = { LIST_DYNAMIC };  /* unused */
+ITEMLIST it_users = { LIST_DYNAMIC };          /* unused */
 ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 };
 
+#ifdef DEBUG
 /* Debugging code */
-#if !defined (USE_VARARGS)
-static void
-debug_printf (format, arg1, arg2, arg3, arg4, arg5)
-     char *format;
-{
-  if (progcomp_debug == 0)
-    return;
-
-  fprintf (stdout, format, arg1, arg2, arg3, arg4, arg5);
-  fprintf (stdout, "\n");
-  rl_on_new_line ();
-}
-#else
 static void
 #if defined (PREFER_STDARG)
 debug_printf (const char *format, ...)
@@ -188,11 +179,7 @@ debug_printf (format, va_alist)
   if (progcomp_debug == 0)
     return;
 
-#if defined (PREFER_STDARG)
-  va_start (args, format);
-#else
-  va_start (args);
-#endif
+  SH_VA_START (args, format);
 
   fprintf (stdout, "DEBUG: ");
   vfprintf (stdout, format, args);
@@ -202,7 +189,7 @@ debug_printf (format, va_alist)
 
   va_end (args);
 }
-#endif /* USE_VARARGS */
+#endif
 
 /* Functions to manage the item lists */
 
@@ -232,7 +219,7 @@ clean_itemlist (itp)
   if (sl)
     {
       if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0)
-       free_array_members (sl->list);
+       strvec_flush (sl->list);
       if ((itp->flags & LIST_DONTFREE) == 0)
        free (sl->list);
       free (sl);
@@ -294,7 +281,7 @@ filter_stringlist (sl, filterpat, text)
   not = (npat[0] == '!');
   t = not ? npat + 1 : npat;
 
-  ret = alloc_stringlist (sl->list_size);
+  ret = strlist_create (sl->list_size);
   for (i = 0; i < sl->list_len; i++)
     {
       m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG);
@@ -321,8 +308,8 @@ completions_to_stringlist (matches)
   STRINGLIST *sl;
   int mlen, i, n;
 
-  mlen = (matches == 0) ? 0 : array_len (matches);
-  sl = alloc_stringlist (mlen + 1);
+  mlen = (matches == 0) ? 0 : strvec_len (matches);
+  sl = strlist_create (mlen + 1);
 
   if (matches == 0 || matches[0] == 0)
     return sl;
@@ -362,7 +349,7 @@ it_init_aliases (itp)
     }
   for (n = 0; alias_list[n]; n++)
     ;
-  sl = alloc_stringlist (n+1);
+  sl = strlist_create (n+1);
   for (i = 0; i < n; i++)
     sl->list[i] = STRDUP (alias_list[i]->name);
   sl->list[n] = (char *)NULL;
@@ -386,7 +373,7 @@ init_itemlist_from_varlist (itp, svfunc)
   vlist = (*svfunc) ();
   for (n = 0; vlist[n]; n++)
     ;
-  sl = alloc_stringlist (n+1);
+  sl = strlist_create (n+1);
   for (i = 0; i < n; i++)
     sl->list[i] = savestring (vlist[i]->name);
   sl->list[sl->list_len = n] = (char *)NULL;
@@ -414,10 +401,10 @@ it_init_bindings (itp)
 
   /* rl_funmap_names allocates blist, but not its members */
   blist = (char **)rl_funmap_names (); /* XXX fix const later */
-  sl = alloc_stringlist (0);
+  sl = strlist_create (0);
   sl->list = blist;
   sl->list_size = 0;
-  sl->list_len = array_len (sl->list);
+  sl->list_len = strvec_len (sl->list);
   itp->flags |= LIST_DONTFREEMEMBERS;
   itp->slist = sl;
 
@@ -431,7 +418,7 @@ it_init_builtins (itp)
   STRINGLIST *sl;
   register int i, n;
 
-  sl = alloc_stringlist (num_shell_builtins);
+  sl = strlist_create (num_shell_builtins);
   for (i = n = 0; i < num_shell_builtins; i++)
     if (shell_builtins[i].function)
       sl->list[n++] = shell_builtins[i].name;
@@ -448,7 +435,7 @@ it_init_enabled (itp)
   STRINGLIST *sl;
   register int i, n;
 
-  sl = alloc_stringlist (num_shell_builtins);
+  sl = strlist_create (num_shell_builtins);
   for (i = n = 0; i < num_shell_builtins; i++)
     {
       if (shell_builtins[i].function && (shell_builtins[i].flags & BUILTIN_ENABLED))
@@ -467,7 +454,7 @@ it_init_disabled (itp)
   STRINGLIST *sl;
   register int i, n;
 
-  sl = alloc_stringlist (num_shell_builtins);
+  sl = strlist_create (num_shell_builtins);
   for (i = n = 0; i < num_shell_builtins; i++)
     {
       if (shell_builtins[i].function && ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
@@ -501,9 +488,9 @@ it_init_hostnames (itp)
 {
   STRINGLIST *sl;
 
-  sl = alloc_stringlist (0);
+  sl = strlist_create (0);
   sl->list = get_hostname_list ();
-  sl->list_len = sl->list ? array_len (sl->list) : 0;
+  sl->list_len = sl->list ? strvec_len (sl->list) : 0;
   sl->list_size = sl->list_len;
   itp->slist = sl;
   itp->flags |= LIST_DONTFREEMEMBERS|LIST_DONTFREE;
@@ -527,7 +514,7 @@ it_init_joblist (itp, jstate)
   else if (jstate == 1)
     js = JSTOPPED;
 
-  sl = alloc_stringlist (job_slots);
+  sl = strlist_create (job_slots);
   for (i = job_slots - 1; i >= 0; i--)
     {
       if (jobs[i] == 0)
@@ -579,7 +566,7 @@ it_init_keywords (itp)
 
   for (n = 0; word_token_alist[n].word; n++)
     ;
-  sl = alloc_stringlist (n);
+  sl = strlist_create (n);
   for (i = 0; i < n; i++)
     sl->list[i] = word_token_alist[i].word;
   sl->list[sl->list_len = i] = (char *)NULL;
@@ -594,9 +581,9 @@ it_init_signals (itp)
 {
   STRINGLIST *sl;
 
-  sl = alloc_stringlist (0);
+  sl = strlist_create (0);
   sl->list = signal_names;
-  sl->list_len = array_len (sl->list);
+  sl->list_len = strvec_len (sl->list);
   itp->flags |= LIST_DONTFREE;
   itp->slist = sl;
   return 0;
@@ -616,9 +603,9 @@ it_init_setopts (itp)
 {
   STRINGLIST *sl;
 
-  sl = alloc_stringlist (0);
+  sl = strlist_create (0);
   sl->list = get_minus_o_opts ();
-  sl->list_len = array_len (sl->list);
+  sl->list_len = strvec_len (sl->list);
   itp->slist = sl;
   itp->flags |= LIST_DONTFREEMEMBERS;
   return 0;
@@ -630,9 +617,9 @@ it_init_shopts (itp)
 {
   STRINGLIST *sl;
 
-  sl = alloc_stringlist (0);
+  sl = strlist_create (0);
   sl->list = get_shopt_options ();
-  sl->list_len = array_len (sl->list);
+  sl->list_len = strvec_len (sl->list);
   itp->slist = sl;
   itp->flags |= LIST_DONTFREEMEMBERS;
   return 0;
@@ -660,7 +647,7 @@ gen_matches_from_itemlist (itp, text)
     }
   if (itp->slist == 0)
     return ((STRINGLIST *)NULL);
-  ret = alloc_stringlist (itp->slist->list_len+1);
+  ret = strlist_create (itp->slist->list_len+1);
   sl = itp->slist;
   tlen = STRLEN (text);
   for (i = n = 0; i < sl->list_len; i++)
@@ -705,8 +692,8 @@ pcomp_filename_completion_function (text, state)
        tlist = gen_matches_from_itemlist (it, text); \
        if (tlist) \
          { \
-           glist = append_stringlist (glist, tlist); \
-           free_stringlist (tlist); \
+           glist = strlist_append (glist, tlist); \
+           strlist_dispose (tlist); \
          } \
       } \
   } while (0)
@@ -717,9 +704,9 @@ pcomp_filename_completion_function (text, state)
       { \
        cmatches = rl_completion_matches (text, func); \
        tlist = completions_to_stringlist (cmatches); \
-       glist = append_stringlist (glist, tlist); \
-       free_array (cmatches); \
-       free_stringlist (tlist); \
+       glist = strlist_append (glist, tlist); \
+       strvec_dispose (cmatches); \
+       strlist_dispose (tlist); \
       } \
   } while (0)
 
@@ -759,15 +746,17 @@ gen_action_completions (cs, text)
   GEN_XCOMPS(flags, CA_FILE, text, pcomp_filename_completion_function, cmatches, ret, tmatches);
   GEN_XCOMPS(flags, CA_USER, text, rl_username_completion_function, cmatches, ret, tmatches);
   GEN_XCOMPS(flags, CA_GROUP, text, bash_groupname_completion_function, cmatches, ret, tmatches);
+  GEN_XCOMPS(flags, CA_SERVICE, text, bash_servicename_completion_function, cmatches, ret, tmatches);
 
   /* And lastly, the special case for directories */
   if (flags & CA_DIRECTORY)
     {
+      rl_completion_mark_symlink_dirs = 1;     /* override user preference */
       cmatches = bash_directory_completion_matches (text);
       tmatches = completions_to_stringlist (cmatches);
-      ret = append_stringlist (ret, tmatches);
-      free_array (cmatches);
-      free_stringlist (tmatches);
+      ret = strlist_append (ret, tmatches);
+      strvec_dispose (cmatches);
+      strlist_dispose (tmatches);
     }
 
   return ret;
@@ -785,12 +774,12 @@ gen_globpat_matches (cs, text)
 {
   STRINGLIST *sl;
 
-  sl = alloc_stringlist (0);
-  sl->list = glob_filename (cs->globpat);
+  sl = strlist_create (0);
+  sl->list = glob_filename (cs->globpat, 0);
   if (GLOB_FAILED (sl->list))
     sl->list = (char **)NULL;
   if (sl->list)
-    sl->list_len = sl->list_size = array_len (sl->list);
+    sl->list_len = sl->list_size = strvec_len (sl->list);
   return sl;
 }
 
@@ -820,7 +809,7 @@ gen_wordlist_matches (cs, text)
   dispose_words (l);
 
   nw = list_length (l2);
-  sl = alloc_stringlist (nw + 1);
+  sl = strlist_create (nw + 1);
   tlen = STRLEN (text);
 
   for (nw = 0, l = l2; l; l = l->next)
@@ -893,11 +882,11 @@ static void
 unbind_compfunc_variables (exported)
      int exported;
 {
-  makunbound ("COMP_LINE", shell_variables);
-  makunbound ("COMP_POINT", shell_variables);
+  unbind_variable ("COMP_LINE");
+  unbind_variable ("COMP_POINT");
 #ifdef ARRAY_VARS
-  makunbound ("COMP_WORDS", shell_variables);
-  makunbound ("COMP_CWORD", shell_variables);
+  unbind_variable ("COMP_WORDS");
+  unbind_variable ("COMP_CWORD");
 #endif
   if (exported)
     array_needs_making = 1;
@@ -1015,13 +1004,13 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
     {
       /* XXX - should we filter the list of completions so only those matching
         TEXT are returned?  Right now, we do not. */
-      sl = alloc_stringlist (0);
+      sl = strlist_create (0);
       sl->list = array_to_argv (a);
       sl->list_len = sl->list_size = array_num_elements (a);
     }
 
   /* XXX - should we unbind COMPREPLY here? */
-  makunbound ("COMPREPLY", shell_variables);
+  unbind_variable ("COMPREPLY");
 
   return (sl);
 #endif
@@ -1094,7 +1083,7 @@ gen_command_matches (cs, text, line, ind, lwords, nw, cw)
 
   /* Now break CSBUF up at newlines, with backslash allowed to escape a
      newline, and put the individual words into a STRINGLIST. */
-  sl = alloc_stringlist (16);
+  sl = strlist_create (16);
   for (ws = 0; csbuf[ws]; )
     {
       we = ws;
@@ -1106,7 +1095,7 @@ gen_command_matches (cs, text, line, ind, lwords, nw, cw)
        }
       t = substring (csbuf, ws, we);
       if (sl->list_len >= sl->list_size - 1)
-       realloc_stringlist (sl, sl->list_size + 16);
+       strlist_resize (sl, sl->list_size + 16);
       sl->list[sl->list_len++] = t;
       while (csbuf[we] == '\n') we++;
       ws = we;
@@ -1144,15 +1133,19 @@ gen_compspec_completions (cs, cmd, word, start, end)
   int llen, nw, cw;
   WORD_LIST *lwords;
 
-  debug_printf ("programmable_completions (%s, %s, %d, %d)", cmd, word, start, end);
-  debug_printf ("programmable_completions: %s -> %p", cmd, cs);
+#ifdef DEBUG
+  debug_printf ("gen_compspec_completions (%s, %s, %d, %d)", cmd, word, start, end);
+  debug_printf ("gen_compspec_completions: %s -> %p", cmd, cs);
+#endif
   ret = gen_action_completions (cs, word);
+#ifdef DEBUG
   if (ret && progcomp_debug)
     {
       debug_printf ("gen_action_completions (%p, %s) -->", cs, word);
-      print_stringlist (ret, "\t");
+      strlist_print (ret, "\t");
       rl_on_new_line ();
     }
+#endif
 
   /* Now we start generating completions based on the other members of CS. */
   if (cs->globpat)
@@ -1160,14 +1153,16 @@ gen_compspec_completions (cs, cmd, word, start, end)
       tmatches = gen_globpat_matches (cs, word);
       if (tmatches)
        {
+#ifdef DEBUG
          if (progcomp_debug)
            {
              debug_printf ("gen_globpat_matches (%p, %s) -->", cs, word);
-             print_stringlist (tmatches, "\t");
+             strlist_print (tmatches, "\t");
              rl_on_new_line ();
            }
-         ret = append_stringlist (ret, tmatches);
-         free_stringlist (tmatches);
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
          rl_filename_completion_desired = 1;
        }
     }
@@ -1177,14 +1172,16 @@ gen_compspec_completions (cs, cmd, word, start, end)
       tmatches = gen_wordlist_matches (cs, word);
       if (tmatches)
        {
+#ifdef DEBUG
          if (progcomp_debug)
            {
              debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word);
-             print_stringlist (tmatches, "\t");
+             strlist_print (tmatches, "\t");
              rl_on_new_line ();
            }
-         ret = append_stringlist (ret, tmatches);
-         free_stringlist (tmatches);
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
        }
     }
 
@@ -1198,9 +1195,12 @@ gen_compspec_completions (cs, cmd, word, start, end)
       line = substring (rl_line_buffer, start, end);
       llen = end - start;
 
+#ifdef DEBUG
       debug_printf ("command_line_to_word_list (%s, %d, %d, %p, %p)",
                line, llen, rl_point - start, &nw, &cw);
+#endif
       lwords = command_line_to_word_list (line, llen, rl_point - start, &nw, &cw);
+#ifdef DEBUG
       if (lwords == 0 && llen > 0)
        debug_printf ("ERROR: command_line_to_word_list returns NULL");
       else if (progcomp_debug)
@@ -1212,6 +1212,7 @@ gen_compspec_completions (cs, cmd, word, start, end)
          fflush(stdout);
          rl_on_new_line ();
        }
+#endif
     }
 
   if (cs->funcname)
@@ -1219,14 +1220,16 @@ gen_compspec_completions (cs, cmd, word, start, end)
       tmatches = gen_shell_function_matches (cs, word, line, rl_point - start, lwords, nw, cw);
       if (tmatches)
        {
+#ifdef DEBUG
          if (progcomp_debug)
            {
              debug_printf ("gen_shell_function_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw);
-             print_stringlist (tmatches, "\t");
+             strlist_print (tmatches, "\t");
              rl_on_new_line ();
            }
-         ret = append_stringlist (ret, tmatches);
-         free_stringlist (tmatches);
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
        }
     }
 
@@ -1235,14 +1238,16 @@ gen_compspec_completions (cs, cmd, word, start, end)
       tmatches = gen_command_matches (cs, word, line, rl_point - start, lwords, nw, cw);
       if (tmatches)
        {
+#ifdef DEBUG
          if (progcomp_debug)
            {
              debug_printf ("gen_command_matches (%p, %s, %p, %d, %d) -->", cs, word, lwords, nw, cw);
-             print_stringlist (tmatches, "\t");
+             strlist_print (tmatches, "\t");
              rl_on_new_line ();
            }
-         ret = append_stringlist (ret, tmatches);
-         free_stringlist (tmatches);
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
        }
     }
 
@@ -1256,12 +1261,14 @@ gen_compspec_completions (cs, cmd, word, start, end)
   if (cs->filterpat)
     {
       tmatches = filter_stringlist (ret, cs->filterpat, word);
+#ifdef DEBUG
       if (progcomp_debug)
        {
          debug_printf ("filter_stringlist (%p, %s, %s) -->", ret, cs->filterpat, word);
-         print_stringlist (tmatches, "\t");
+         strlist_print (tmatches, "\t");
          rl_on_new_line ();
        }
+#endif
       if (ret && ret != tmatches)
        {
          FREE (ret->list);
@@ -1271,7 +1278,7 @@ gen_compspec_completions (cs, cmd, word, start, end)
     }
 
   if (cs->prefix || cs->suffix)
-    ret = prefix_suffix_stringlist (ret, cs->prefix, cs->suffix);
+    ret = strlist_prefix_suffix (ret, cs->prefix, cs->suffix);
 
   /* If no matches have been generated and the user has specified that
       directory completion should be done as a default, call
@@ -1281,10 +1288,10 @@ gen_compspec_completions (cs, cmd, word, start, end)
     {
       COMPSPEC *dummy;
 
-      dummy = alloc_compspec ();
+      dummy = compspec_create ();
       dummy->actions = CA_DIRECTORY;
       ret = gen_action_completions (dummy, word);
-      free_compspec (dummy);
+      compspec_dispose (dummy);
     }
 
   return (ret);
@@ -1305,12 +1312,12 @@ programmable_completions (cmd, word, start, end, foundp)
 
   /* We look at the basename of CMD if the full command does not have
      an associated COMPSPEC. */
-  cs = find_compspec (cmd);
+  cs = progcomp_search (cmd);
   if (cs == 0)
     {
       t = strrchr (cmd, '/');
       if (t)
-       cs = find_compspec (++t);
+       cs = progcomp_search (++t);
     }
   if (cs == 0)
     {