/* 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.
#if defined (PREFER_STDARG)
# include <stdarg.h>
#else
-# if defined (PREFER_VARARGS)
-# include <varargs.h>
-# endif
+# include <varargs.h>
#endif
#include <stdio.h>
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));
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;
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, ...)
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);
va_end (args);
}
-#endif /* USE_VARARGS */
+#endif
/* Functions to manage the item lists */
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);
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);
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;
}
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;
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;
/* 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;
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;
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))
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))
{
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;
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)
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;
{
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;
{
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;
{
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;
}
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++)
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)
{ \
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)
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;
{
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;
}
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)
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;
{
/* 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
/* 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;
}
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;
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)
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;
}
}
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);
}
}
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)
fflush(stdout);
rl_on_new_line ();
}
+#endif
}
if (cs->funcname)
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);
}
}
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);
}
}
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);
}
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
{
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);
/* 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)
{