]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
commit bash-20080327 snapshot
authorChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:21:08 +0000 (09:21 -0500)
committerChet Ramey <chet.ramey@case.edu>
Wed, 7 Dec 2011 14:21:08 +0000 (09:21 -0500)
38 files changed:
#pcomplete.c# [new file with mode: 0644]
CWRU/CWRU.chlog
CWRU/CWRU.chlog~
array.c
array.c~
builtins/common.h
builtins/common.h~ [new file with mode: 0644]
builtins/complete.def
builtins/complete.def~
builtins/declare.def
builtins/declare.def~
builtins/setattr.def
builtins/setattr.def~
builtins/ulimit.def
builtins/ulimit.def~
doc/bash.1
doc/bash.1~
doc/bashref.texi
doc/bashref.texi~
doc/version.texi
doc/version.texi~
lib/readline/callback.c
lib/readline/display.c
lib/readline/doc/rluser.texi
lib/readline/doc/rluser.texi~
lib/readline/readline.c
lib/readline/rlprivate.h
lib/readline/rltty.c
lib/readline/terminal.c
lib/readline/text.c
lib/readline/util.c
pcomplete.c
pcomplete.c~
pcomplete.h
pcomplete.h~
tests/RUN-ONE-TEST
variables.h
variables.h~ [new file with mode: 0644]

diff --git a/#pcomplete.c# b/#pcomplete.c#
new file mode 100644 (file)
index 0000000..2bca304
--- /dev/null
@@ -0,0 +1,1448 @@
+/* pcomplete.c - functions to generate lists of matches for programmable
+                completion. */
+
+/* Copyright (C) 1999-2008 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include <config.h>
+
+#if defined (PROGRAMMABLE_COMPLETION)
+
+#include "bashtypes.h"
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+#  include <unistd.h>
+#endif
+
+#include <signal.h>
+
+#if defined (PREFER_STDARG)
+#  include <stdarg.h>
+#else
+#  include <varargs.h>
+#endif
+
+#include <stdio.h>
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include "shell.h"
+#include "pcomplete.h"
+#include "alias.h"
+#include "bashline.h"
+#include "execute_cmd.h"
+#include "pathexp.h"
+
+#if defined (JOB_CONTROL)
+#  include "jobs.h"
+#endif
+
+#if !defined (NSIG)
+#  include "trap.h"
+#endif
+
+#include "builtins.h"
+#include "builtins/common.h"
+
+#include <glob/glob.h>
+#include <glob/strmatch.h>
+
+#include <readline/rlconf.h>
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#ifdef STRDUP
+#  undef STRDUP
+#endif
+#define STRDUP(x)      ((x) ? savestring (x) : (char *)NULL)
+
+typedef SHELL_VAR **SVFUNC ();
+
+#ifndef HAVE_STRPBRK
+extern char *strpbrk __P((char *, char *));
+#endif
+
+extern int array_needs_making;
+extern STRING_INT_ALIST word_token_alist[];
+extern char *signal_names[];
+
+#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 int it_init_aliases __P((ITEMLIST *));
+static int it_init_arrayvars __P((ITEMLIST *));
+static int it_init_bindings __P((ITEMLIST *));
+static int it_init_builtins __P((ITEMLIST *));
+static int it_init_disabled __P((ITEMLIST *));
+static int it_init_enabled __P((ITEMLIST *));
+static int it_init_exported __P((ITEMLIST *));
+static int it_init_functions __P((ITEMLIST *));
+static int it_init_hostnames __P((ITEMLIST *));
+static int it_init_jobs __P((ITEMLIST *));
+static int it_init_running __P((ITEMLIST *));
+static int it_init_stopped __P((ITEMLIST *));
+static int it_init_keywords __P((ITEMLIST *));
+static int it_init_signals __P((ITEMLIST *));
+static int it_init_variables __P((ITEMLIST *));
+static int it_init_setopts __P((ITEMLIST *));
+static int it_init_shopts __P((ITEMLIST *));
+
+static int shouldexp_filterpat __P((char *));
+static char *preproc_filterpat __P((char *, char *));
+
+static void init_itemlist_from_varlist __P((ITEMLIST *, SVFUNC *));
+
+static STRINGLIST *gen_matches_from_itemlist __P((ITEMLIST *, const char *));
+static STRINGLIST *gen_action_completions __P((COMPSPEC *, const char *));
+static STRINGLIST *gen_globpat_matches __P((COMPSPEC *, const char *));
+static STRINGLIST *gen_wordlist_matches __P((COMPSPEC *, const char *));
+static STRINGLIST *gen_shell_function_matches __P((COMPSPEC *, const char *,
+                                                  char *, int, WORD_LIST *,
+                                                  int, int));
+static STRINGLIST *gen_command_matches __P((COMPSPEC *, const char *, char *,
+                                           int, WORD_LIST *, int, int));
+
+static char *pcomp_filename_completion_function __P((const char *, int));
+
+#if defined (ARRAY_VARS)
+static SHELL_VAR *bind_comp_words __P((WORD_LIST *));
+#endif
+static void bind_compfunc_variables __P((char *, int, WORD_LIST *, int, int));
+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;
+
+/* These are used to manage the arrays of strings for possible completions. */
+ITEMLIST it_aliases = { 0, it_init_aliases, (STRINGLIST *)0 };
+ITEMLIST it_arrayvars  = { LIST_DYNAMIC, it_init_arrayvars, (STRINGLIST *)0 };
+ITEMLIST it_bindings  = { 0, it_init_bindings, (STRINGLIST *)0 };
+ITEMLIST it_builtins  = { 0, it_init_builtins, (STRINGLIST *)0 };
+ITEMLIST it_commands = { LIST_DYNAMIC };       /* unused */
+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_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_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_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 };
+
+COMPSPEC *pcomp_curcs;
+const char *pcomp_curcmd;
+
+#ifdef DEBUG
+/* Debugging code */
+static void
+#if defined (PREFER_STDARG)
+debug_printf (const char *format, ...)
+#else
+debug_printf (format, va_alist)
+     const char *format;
+     va_dcl
+#endif
+{
+  va_list args;
+
+  if (progcomp_debug == 0)
+    return;
+
+  SH_VA_START (args, format);
+
+  fprintf (stdout, "DEBUG: ");
+  vfprintf (stdout, format, args);
+  fprintf (stdout, "\n");
+
+  rl_on_new_line ();
+
+  va_end (args);
+}
+#endif
+
+/* Functions to manage the item lists */
+
+void
+set_itemlist_dirty (it)
+     ITEMLIST *it;
+{
+  it->flags |= LIST_DIRTY;
+}
+
+void
+initialize_itemlist (itp)
+     ITEMLIST *itp;
+{
+  (*itp->list_getter) (itp);
+  itp->flags |= LIST_INITIALIZED;
+  itp->flags &= ~LIST_DIRTY;
+}
+
+void
+clean_itemlist (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+
+  sl = itp->slist;
+  if (sl)
+    {
+      if ((itp->flags & (LIST_DONTFREEMEMBERS|LIST_DONTFREE)) == 0)
+       strvec_flush (sl->list);
+      if ((itp->flags & LIST_DONTFREE) == 0)
+       free (sl->list);
+      free (sl);
+    }
+  itp->slist = (STRINGLIST *)NULL;
+  itp->flags &= ~(LIST_DONTFREE|LIST_DONTFREEMEMBERS|LIST_INITIALIZED|LIST_DIRTY);
+}
+
+
+static int
+shouldexp_filterpat (s)
+     char *s;
+{
+  register char *p;
+
+  for (p = s; p && *p; p++)
+    {
+      if (*p == '\\')
+       p++;
+      else if (*p == '&')
+       return 1;
+    }
+  return 0;
+}
+
+/* Replace any instance of `&' in PAT with TEXT.  Backslash may be used to
+   quote a `&' and inhibit substitution.  Returns a new string.  This just
+   calls stringlib.c:strcreplace(). */
+static char *
+preproc_filterpat (pat, text)
+     char *pat;
+     char *text;
+{
+  char *ret;
+
+  ret = strcreplace (pat, '&', text, 1);
+  return ret;
+}
+       
+/* Remove any match of FILTERPAT from SL.  A `&' in FILTERPAT is replaced by
+   TEXT.  A leading `!' in FILTERPAT negates the pattern; in this case
+   any member of SL->list that does *not* match will be removed.  This returns
+   a new STRINGLIST with the matching members of SL *copied*.  Any
+   non-matching members of SL->list are *freed*. */   
+STRINGLIST *
+filter_stringlist (sl, filterpat, text)
+     STRINGLIST *sl;
+     char *filterpat, *text;
+{
+  int i, m, not;
+  STRINGLIST *ret;
+  char *npat, *t;
+
+  if (sl == 0 || sl->list == 0 || sl->list_len == 0)
+    return sl;
+
+  npat = shouldexp_filterpat (filterpat) ? preproc_filterpat (filterpat, text) : filterpat;
+
+  not = (npat[0] == '!');
+  t = not ? npat + 1 : npat;
+
+  ret = strlist_create (sl->list_size);
+  for (i = 0; i < sl->list_len; i++)
+    {
+      m = strmatch (t, sl->list[i], FNMATCH_EXTFLAG);
+      if ((not && m == FNM_NOMATCH) || (not == 0 && m != FNM_NOMATCH))
+       free (sl->list[i]);
+      else
+       ret->list[ret->list_len++] = sl->list[i];
+    }
+
+  ret->list[ret->list_len] = (char *)NULL;
+  if (npat != filterpat)
+    free (npat);
+
+  return ret;
+}
+
+/* Turn an array of strings returned by rl_completion_matches into a STRINGLIST.
+   This understands how rl_completion_matches sets matches[0] (the lcd of the
+   strings in the list, unless it's the only match). */
+STRINGLIST *
+completions_to_stringlist (matches)
+     char **matches;
+{
+  STRINGLIST *sl;
+  int mlen, i, n;
+
+  mlen = (matches == 0) ? 0 : strvec_len (matches);
+  sl = strlist_create (mlen + 1);
+
+  if (matches == 0 || matches[0] == 0)
+    return sl;
+
+  if (matches[1] == 0)
+    {
+      sl->list[0] = STRDUP (matches[0]);
+      sl->list[sl->list_len = 1] = (char *)NULL;
+      return sl;
+    }
+
+  for (i = 1, n = 0; i < mlen; i++, n++)
+    sl->list[n] = STRDUP (matches[i]);
+  sl->list_len = n;
+  sl->list[n] = (char *)NULL;
+
+  return sl;
+}
+
+/* Functions to manage the various ITEMLISTs that we populate internally.
+   The caller is responsible for setting ITP->flags correctly. */
+
+static int
+it_init_aliases (itp)
+     ITEMLIST *itp;
+{
+#ifdef ALIAS
+  alias_t **alias_list;
+  register int i, n;
+  STRINGLIST *sl;
+
+  alias_list = all_aliases ();
+  if (alias_list == 0)
+    {
+      itp->slist = (STRINGLIST *)NULL;
+      return 0;
+    }
+  for (n = 0; alias_list[n]; n++)
+    ;
+  sl = strlist_create (n+1);
+  for (i = 0; i < n; i++)
+    sl->list[i] = STRDUP (alias_list[i]->name);
+  sl->list[n] = (char *)NULL;
+  sl->list_size = sl->list_len = n;
+  itp->slist = sl;
+#else
+  itp->slist = (STRINGLIST *)NULL;
+#endif
+  return 1;
+}
+
+static void
+init_itemlist_from_varlist (itp, svfunc)
+     ITEMLIST *itp;
+     SVFUNC *svfunc;
+{
+  SHELL_VAR **vlist;
+  STRINGLIST *sl;
+  register int i, n;
+
+  vlist = (*svfunc) ();
+  if (vlist == 0)
+    {
+      itp->slist = (STRINGLIST *)NULL;
+      return;
+    }    
+  for (n = 0; vlist[n]; n++)
+    ;
+  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;
+  itp->slist = sl;
+}
+
+static int
+it_init_arrayvars (itp)
+     ITEMLIST *itp;
+{
+#if defined (ARRAY_VARS)
+  init_itemlist_from_varlist (itp, all_array_variables);
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+static int
+it_init_bindings (itp)
+     ITEMLIST *itp;
+{
+  char **blist;
+  STRINGLIST *sl;
+
+  /* rl_funmap_names allocates blist, but not its members */
+  blist = (char **)rl_funmap_names (); /* XXX fix const later */
+  sl = strlist_create (0);
+  sl->list = blist;
+  sl->list_size = 0;
+  sl->list_len = strvec_len (sl->list);
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  itp->slist = sl;
+
+  return 0;
+}
+
+static int
+it_init_builtins (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+  register int i, n;
+
+  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;
+  sl->list[sl->list_len = n] = (char *)NULL;
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  itp->slist = sl;
+  return 0;
+}
+
+static int
+it_init_enabled (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+  register int i, n;
+
+  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))
+       sl->list[n++] = shell_builtins[i].name;
+    }
+  sl->list[sl->list_len = n] = (char *)NULL;
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  itp->slist = sl;
+  return 0;
+}
+
+static int
+it_init_disabled (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+  register int i, n;
+
+  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))
+       sl->list[n++] = shell_builtins[i].name;
+    }
+  sl->list[sl->list_len = n] = (char *)NULL;
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  itp->slist = sl;
+  return 0;
+}
+
+static int
+it_init_exported (itp)
+     ITEMLIST *itp;
+{
+  init_itemlist_from_varlist (itp, all_exported_variables);
+  return 0;
+}
+
+static int
+it_init_functions (itp)
+     ITEMLIST *itp;
+{
+  init_itemlist_from_varlist (itp, all_visible_functions);
+  return 0;
+}
+
+static int
+it_init_hostnames (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+
+  sl = strlist_create (0);
+  sl->list = get_hostname_list ();
+  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;
+  return 0;
+}
+
+static int
+it_init_joblist (itp, jstate)
+     ITEMLIST *itp;
+     int jstate;
+{
+#if defined (JOB_CONTROL)
+  STRINGLIST *sl;
+  register int i;
+  register PROCESS *p;
+  char *s, *t;
+  JOB *j;
+  JOB_STATE ws;                /* wanted state */
+
+  if (jstate == 0)
+    ws = JRUNNING;
+  else if (jstate == 1)
+    ws = JSTOPPED;
+
+  sl = strlist_create (js.j_jobslots);
+  for (i = js.j_jobslots - 1; i >= 0; i--)
+    {
+      j = get_job_by_jid (i);
+      if (j == 0)
+       continue;
+      p = j->pipe;
+      if (jstate == -1 || JOBSTATE(i) == ws)
+       {
+         s = savestring (p->command);
+         t = strpbrk (s, " \t\n");
+         if (t)
+           *t = '\0';
+         sl->list[sl->list_len++] = s;
+       }
+    }
+  itp->slist = sl;
+#else
+  itp->slist = (STRINGLIST *)NULL;
+#endif
+  return 0;
+}
+
+static int
+it_init_jobs (itp)
+     ITEMLIST *itp;
+{
+  return (it_init_joblist (itp, -1));
+}
+
+static int
+it_init_running (itp)
+     ITEMLIST *itp;
+{
+  return (it_init_joblist (itp, 0));
+}
+
+static int
+it_init_stopped (itp)
+     ITEMLIST *itp;
+{
+  return (it_init_joblist (itp, 1));
+}
+
+static int
+it_init_keywords (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+  register int i, n;
+
+  for (n = 0; word_token_alist[n].word; 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;
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  itp->slist = sl;
+  return 0;
+}
+
+static int
+it_init_signals (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+
+  sl = strlist_create (0);
+  sl->list = signal_names;
+  sl->list_len = strvec_len (sl->list);
+  itp->flags |= LIST_DONTFREE;
+  itp->slist = sl;
+  return 0;
+}
+
+static int
+it_init_variables (itp)
+     ITEMLIST *itp;
+{
+  init_itemlist_from_varlist (itp, all_visible_variables);
+  return 0;
+}
+
+static int
+it_init_setopts (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+
+  sl = strlist_create (0);
+  sl->list = get_minus_o_opts ();
+  sl->list_len = strvec_len (sl->list);
+  itp->slist = sl;
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  return 0;
+}
+
+static int
+it_init_shopts (itp)
+     ITEMLIST *itp;
+{
+  STRINGLIST *sl;
+
+  sl = strlist_create (0);
+  sl->list = get_shopt_options ();
+  sl->list_len = strvec_len (sl->list);
+  itp->slist = sl;
+  itp->flags |= LIST_DONTFREEMEMBERS;
+  return 0;
+}
+
+/* Generate a list of all matches for TEXT using the STRINGLIST in itp->slist
+   as the list of possibilities.  If the itemlist has been marked dirty or
+   it should be regenerated every time, destroy the old STRINGLIST and make a
+   new one before trying the match.  TEXT is dequoted before attempting a
+   match. */
+static STRINGLIST *
+gen_matches_from_itemlist (itp, text)
+     ITEMLIST *itp;
+     const char *text;
+{
+  STRINGLIST *ret, *sl;
+  int tlen, i, n;
+  char *ntxt;
+
+  if ((itp->flags & (LIST_DIRTY|LIST_DYNAMIC)) ||
+      (itp->flags & LIST_INITIALIZED) == 0)
+    {
+      if (itp->flags & (LIST_DIRTY | LIST_DYNAMIC))
+       clean_itemlist (itp);
+      if ((itp->flags & LIST_INITIALIZED) == 0)
+       initialize_itemlist (itp);
+    }
+  if (itp->slist == 0)
+    return ((STRINGLIST *)NULL);
+  ret = strlist_create (itp->slist->list_len+1);
+  sl = itp->slist;
+
+  ntxt = bash_dequote_text (text);
+  tlen = STRLEN (ntxt);
+
+  for (i = n = 0; i < sl->list_len; i++)
+    {
+      if (tlen == 0 || STREQN (sl->list[i], ntxt, tlen))
+       ret->list[n++] = STRDUP (sl->list[i]);
+    }
+  ret->list[ret->list_len = n] = (char *)NULL;
+
+  FREE (ntxt);
+  return ret;
+}
+
+/* A wrapper for rl_filename_completion_function that dequotes the filename
+   before attempting completions. */
+static char *
+pcomp_filename_completion_function (text, state)
+     const char *text;
+     int state;
+{
+  static char *dfn;    /* dequoted filename */
+  int qc;
+
+  if (state == 0)
+    {
+      FREE (dfn);
+      /* remove backslashes quoting special characters in filenames. */
+#if 1
+      if (RL_ISSTATE (RL_STATE_COMPLETING) && rl_filename_dequoting_function)
+#else
+      if (rl_filename_dequoting_function)
+#endif
+       {
+         /* Use rl_completion_quote_character because any single or
+            double quotes have been removed by the time TEXT makes it
+            here, and we don't want to remove backslashes inside
+            quoted strings. */
+         dfn = (*rl_filename_dequoting_function) ((char *)text, rl_completion_quote_character);
+       }
+      else
+       dfn = savestring (text);
+    }
+
+  return (rl_filename_completion_function (dfn, state));
+}
+
+#define GEN_COMPS(bmap, flag, it, text, glist, tlist) \
+  do { \
+    if (bmap & flag) \
+      { \
+       tlist = gen_matches_from_itemlist (it, text); \
+       if (tlist) \
+         { \
+           glist = strlist_append (glist, tlist); \
+           strlist_dispose (tlist); \
+         } \
+      } \
+  } while (0)
+
+#define GEN_XCOMPS(bmap, flag, text, func, cmatches, glist, tlist) \
+  do { \
+    if (bmap & flag) \
+      { \
+       cmatches = rl_completion_matches (text, func); \
+       tlist = completions_to_stringlist (cmatches); \
+       glist = strlist_append (glist, tlist); \
+       strvec_dispose (cmatches); \
+       strlist_dispose (tlist); \
+      } \
+  } while (0)
+
+/* Functions to generate lists of matches from the actions member of CS. */
+
+static STRINGLIST *
+gen_action_completions (cs, text)
+     COMPSPEC *cs;
+     const char *text;
+{
+  STRINGLIST *ret, *tmatches;
+  char **cmatches;     /* from rl_completion_matches ... */
+  unsigned long flags;
+
+  ret = tmatches = (STRINGLIST *)NULL;
+  flags = cs->actions;
+
+  GEN_COMPS (flags, CA_ALIAS, &it_aliases, text, ret, tmatches);
+  GEN_COMPS (flags, CA_ARRAYVAR, &it_arrayvars, text, ret, tmatches);
+  GEN_COMPS (flags, CA_BINDING, &it_bindings, text, ret, tmatches);
+  GEN_COMPS (flags, CA_BUILTIN, &it_builtins, text, ret, tmatches);
+  GEN_COMPS (flags, CA_DISABLED, &it_disabled, text, ret, tmatches);
+  GEN_COMPS (flags, CA_ENABLED, &it_enabled, text, ret, tmatches);
+  GEN_COMPS (flags, CA_EXPORT, &it_exports, text, ret, tmatches);
+  GEN_COMPS (flags, CA_FUNCTION, &it_functions, text, ret, tmatches);
+  GEN_COMPS (flags, CA_HOSTNAME, &it_hostnames, text, ret, tmatches);
+  GEN_COMPS (flags, CA_JOB, &it_jobs, text, ret, tmatches);
+  GEN_COMPS (flags, CA_KEYWORD, &it_keywords, text, ret, tmatches);
+  GEN_COMPS (flags, CA_RUNNING, &it_running, text, ret, tmatches);
+  GEN_COMPS (flags, CA_SETOPT, &it_setopts, text, ret, tmatches);
+  GEN_COMPS (flags, CA_SHOPT, &it_shopts, text, ret, tmatches);
+  GEN_COMPS (flags, CA_SIGNAL, &it_signals, text, ret, tmatches);
+  GEN_COMPS (flags, CA_STOPPED, &it_stopped, text, ret, tmatches);
+  GEN_COMPS (flags, CA_VARIABLE, &it_variables, text, ret, tmatches);
+
+  GEN_XCOMPS(flags, CA_COMMAND, text, command_word_completion_function, cmatches, ret, tmatches);
+  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 = strlist_append (ret, tmatches);
+      strvec_dispose (cmatches);
+      strlist_dispose (tmatches);
+    }
+
+  return ret;
+}
+
+/* Generate a list of matches for CS->globpat.  Unresolved: should this use
+   TEXT as a match prefix, or just go without?  Currently, the code does not
+   use TEXT, just globs CS->globpat and returns the results.  If we do decide
+   to use TEXT, we should call quote_string_for_globbing before the call to
+   glob_filename. */
+static STRINGLIST *
+gen_globpat_matches (cs, text)
+      COMPSPEC *cs;
+      const char *text;
+{
+  STRINGLIST *sl;
+
+  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 = strvec_len (sl->list);
+  return sl;
+}
+
+/* Perform the shell word expansions on CS->words and return the results.
+   Again, this ignores TEXT. */
+static STRINGLIST *
+gen_wordlist_matches (cs, text)
+     COMPSPEC *cs;
+     const char *text;
+{
+  WORD_LIST *l, *l2;
+  STRINGLIST *sl;
+  int nw, tlen;
+  char *ntxt;          /* dequoted TEXT to use in comparisons */
+
+  if (cs->words == 0 || cs->words[0] == '\0')
+    return ((STRINGLIST *)NULL);
+
+  /* This used to be a simple expand_string(cs->words, 0), but that won't
+     do -- there's no way to split a simple list into individual words
+     that way, since the shell semantics say that word splitting is done
+     only on the results of expansion. */
+  l = split_at_delims (cs->words, strlen (cs->words), (char *)NULL, -1, (int *)NULL, (int *)NULL);
+  if (l == 0)
+    return ((STRINGLIST *)NULL);
+  /* This will jump back to the top level if the expansion fails... */
+  l2 = expand_words_shellexp (l);
+  dispose_words (l);
+
+  nw = list_length (l2);
+  sl = strlist_create (nw + 1);
+
+  ntxt = bash_dequote_text (text);
+  tlen = STRLEN (ntxt);
+
+  for (nw = 0, l = l2; l; l = l->next)
+    {
+      if (tlen == 0 || STREQN (l->word->word, ntxt, tlen))
+       sl->list[nw++] = STRDUP (l->word->word);
+    }
+  sl->list[sl->list_len = nw] = (char *)NULL;
+
+  dispose_words (l2);
+  FREE (ntxt);
+  return sl;
+}
+
+#ifdef ARRAY_VARS
+
+static SHELL_VAR *
+bind_comp_words (lwords)
+     WORD_LIST *lwords;
+{
+  SHELL_VAR *v;
+
+  v = find_variable ("COMP_WORDS");
+  if (v == 0)
+    v = make_new_array_variable ("COMP_WORDS");
+  if (readonly_p (v))
+    VUNSETATTR (v, att_readonly);
+  if (array_p (v) == 0)
+    v = convert_var_to_array (v);
+  v = assign_array_var_from_word_list (v, lwords, 0);
+
+  VUNSETATTR (v, att_invisible);
+  return v;
+}
+#endif /* ARRAY_VARS */
+
+static void
+bind_compfunc_variables (line, ind, lwords, cw, exported)
+     char *line;
+     int ind;
+     WORD_LIST *lwords;
+     int cw, exported;
+{
+  char ibuf[INT_STRLEN_BOUND(int) + 1];
+  char *value;
+  SHELL_VAR *v;
+
+  /* Set the variables that the function expects while it executes.  Maybe
+     these should be in the function environment (temporary_env). */
+  v = bind_variable ("COMP_LINE", line, 0);
+  if (v && exported)
+    VSETATTR(v, att_exported);
+
+  value = inttostr (ind, ibuf, sizeof(ibuf));
+  v = bind_int_variable ("COMP_POINT", value);
+  if (v && exported)
+    VSETATTR(v, att_exported);
+
+  value = inttostr (rl_completion_type, ibuf, sizeof (ibuf));
+  v = bind_int_variable ("COMP_TYPE", value);
+  if (v && exported)
+    VSETATTR(v, att_exported);
+
+  value = inttostr (rl_completion_invoking_key, ibuf, sizeof (ibuf));
+  v = bind_int_variable ("COMP_KEY", value);
+  if (v && exported)
+    VSETATTR(v, att_exported);
+
+  /* Since array variables can't be exported, we don't bother making the
+     array of words. */
+  if (exported == 0)
+    {
+#ifdef ARRAY_VARS
+      v = bind_comp_words (lwords);
+      value = inttostr (cw, ibuf, sizeof(ibuf));
+      bind_int_variable ("COMP_CWORD", value);
+#endif
+    }
+  else
+    array_needs_making = 1;
+}
+
+static void
+unbind_compfunc_variables (exported)
+     int exported;
+{
+  unbind_variable ("COMP_LINE");
+  unbind_variable ("COMP_POINT");
+  unbind_variable ("COMP_TYPE");
+  unbind_variable ("COMP_KEY");
+#ifdef ARRAY_VARS
+  unbind_variable ("COMP_WORDS");
+  unbind_variable ("COMP_CWORD");
+#endif
+  if (exported)
+    array_needs_making = 1;
+}
+
+/* Build the list of words to pass to a function or external command
+   as arguments.  When the function or command is invoked,
+
+       $0 == function or command being invoked
+       $1 == command name
+       $2 = word to be completed (possibly null)
+       $3 = previous word
+
+   Functions can access all of the words in the current command line
+   with the COMP_WORDS array.  External commands cannot. */
+
+static WORD_LIST *
+build_arg_list (cmd, text, lwords, ind)
+     char *cmd;
+     const char *text;
+     WORD_LIST *lwords;
+     int ind;
+{
+  WORD_LIST *ret, *cl, *l;
+  WORD_DESC *w;
+  int i;
+
+  ret = (WORD_LIST *)NULL;
+  w = make_word (cmd);
+  ret = make_word_list (w, (WORD_LIST *)NULL);
+
+  w = (lwords && lwords->word) ? copy_word (lwords->word) : make_word ("");
+  cl = ret->next = make_word_list (w, (WORD_LIST *)NULL);
+
+  w = make_word (text);
+  cl->next = make_word_list (w, (WORD_LIST *)NULL);
+  cl = cl->next;
+
+  /* Search lwords for current word */
+  for (l = lwords, i = 1; l && i < ind-1; l = l->next, i++)
+    ;
+  w = (l && l->word) ? copy_word (l->word) : make_word ("");
+  cl->next = make_word_list (w, (WORD_LIST *)NULL);
+
+  return ret;
+}
+
+/* Build a command string with
+       $0 == cs->funcname      (function to execute for completion list)
+       $1 == command name      (command being completed)
+       $2 = word to be completed (possibly null)
+       $3 = previous word
+   and run in the current shell.  The function should put its completion
+   list into the array variable COMPREPLY.  We build a STRINGLIST
+   from the results and return it.
+
+   Since the shell function should return its list of matches in an array
+   variable, this does nothing if arrays are not compiled into the shell. */
+
+static STRINGLIST *
+gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
+     COMPSPEC *cs;
+     const char *text;
+     char *line;
+     int ind;
+     WORD_LIST *lwords;
+     int nw, cw;
+{
+  char *funcname;
+  STRINGLIST *sl;
+  SHELL_VAR *f, *v;
+  WORD_LIST *cmdlist;
+  int fval;
+  sh_parser_state_t ps;
+#if defined (ARRAY_VARS)
+  ARRAY *a;
+#endif
+
+  funcname = cs->funcname;
+  f = find_function (funcname);
+  if (f == 0)
+    {
+      internal_error (_("completion: function `%s' not found"), funcname);
+      rl_ding ();
+      rl_on_new_line ();
+      return ((STRINGLIST *)NULL);
+    }
+
+#if !defined (ARRAY_VARS)
+  return ((STRINGLIST *)NULL);
+#else
+
+  /* We pass cw - 1 because command_line_to_word_list returns indices that are
+     1-based, while bash arrays are 0-based. */
+  bind_compfunc_variables (line, ind, lwords, cw - 1, 0);
+
+  cmdlist = build_arg_list (funcname, text, lwords, cw);
+
+  save_parser_state (&ps);  
+  fval = execute_shell_function (f, cmdlist);  
+  restore_parser_state (&ps);
+
+  /* Now clean up and destroy everything. */
+  dispose_words (cmdlist);
+  unbind_compfunc_variables (0);
+
+  /* The list of completions is returned in the array variable COMPREPLY. */
+  v = find_variable ("COMPREPLY");
+  if (v == 0)
+    return ((STRINGLIST *)NULL);
+  if (array_p (v) == 0)
+    v = convert_var_to_array (v);
+
+  VUNSETATTR (v, att_invisible);
+
+  a = array_cell (v);
+  if (a == 0 || array_empty (a))
+    sl = (STRINGLIST *)NULL;
+  else
+    {
+      /* XXX - should we filter the list of completions so only those matching
+        TEXT are returned?  Right now, we do not. */
+      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? */
+  unbind_variable ("COMPREPLY");
+
+  return (sl);
+#endif
+}
+
+/* Build a command string with
+       $0 == cs->command       (command to execute for completion list)
+       $1 == command name      (command being completed)
+       $2 = word to be completed (possibly null)
+       $3 = previous word
+   and run in with command substitution.  Parse the results, one word
+   per line, with backslashes allowed to escape newlines.  Build a
+   STRINGLIST from the results and return it. */
+
+static STRINGLIST *
+gen_command_matches (cs, text, line, ind, lwords, nw, cw)
+     COMPSPEC *cs;
+     const char *text;
+     char *line;
+     int ind;
+     WORD_LIST *lwords;
+     int nw, cw;
+{
+  char *csbuf, *cscmd, *t;
+  int cmdlen, cmdsize, n, ws, we;
+  WORD_LIST *cmdlist, *cl;
+  WORD_DESC *tw;
+  STRINGLIST *sl;
+
+  bind_compfunc_variables (line, ind, lwords, cw, 1);
+  cmdlist = build_arg_list (cs->command, text, lwords, cw);
+
+  /* Estimate the size needed for the buffer. */
+  n = strlen (cs->command);
+  cmdsize = n + 1;
+  for (cl = cmdlist->next; cl; cl = cl->next)
+    cmdsize += STRLEN (cl->word->word) + 3;
+  cmdsize += 2;
+
+  /* allocate the string for the command and fill it in. */
+  cscmd = (char *)xmalloc (cmdsize + 1);
+
+  strcpy (cscmd, cs->command);                 /* $0 */
+  cmdlen = n;
+  cscmd[cmdlen++] = ' ';
+  for (cl = cmdlist->next; cl; cl = cl->next)   /* $1, $2, $3, ... */
+    {
+      t = sh_single_quote (cl->word->word ? cl->word->word : "");
+      n = strlen (t);
+      RESIZE_MALLOCED_BUFFER (cscmd, cmdlen, n + 2, cmdsize, 64);
+      strcpy (cscmd + cmdlen, t);
+      cmdlen += n;
+      if (cl->next)
+       cscmd[cmdlen++] = ' ';
+      free (t);
+    }
+  cscmd[cmdlen] = '\0';
+
+  tw = command_substitute (cscmd, 0);
+  csbuf = tw ? tw->word : (char *)NULL;
+  dispose_word_desc (tw);
+
+  /* Now clean up and destroy everything. */
+  dispose_words (cmdlist);
+  free (cscmd);
+  unbind_compfunc_variables (1);
+
+  if (csbuf == 0 || *csbuf == '\0')
+    {
+      FREE (csbuf);
+      return ((STRINGLIST *)NULL);
+    }
+
+  /* Now break CSBUF up at newlines, with backslash allowed to escape a
+     newline, and put the individual words into a STRINGLIST. */
+  sl = strlist_create (16);
+  for (ws = 0; csbuf[ws]; )
+    {
+      we = ws;
+      while (csbuf[we] && csbuf[we] != '\n')
+       {
+         if (csbuf[we] == '\\' && csbuf[we+1] == '\n')
+           we++;
+         we++;
+       }
+      t = substring (csbuf, ws, we);
+      if (sl->list_len >= sl->list_size - 1)
+       strlist_resize (sl, sl->list_size + 16);
+      sl->list[sl->list_len++] = t;
+      while (csbuf[we] == '\n') we++;
+      ws = we;
+    }
+  sl->list[sl->list_len] = (char *)NULL;
+
+  free (csbuf);
+  return (sl);
+}
+
+static WORD_LIST *
+command_line_to_word_list (line, llen, sentinel, nwp, cwp)
+     char *line;
+     int llen, sentinel, *nwp, *cwp;
+{
+  WORD_LIST *ret;
+  char *delims;
+
+#if 0
+  delims = "()<>;&| \t\n";     /* shell metacharacters break words */
+#else
+  delims = rl_completer_word_break_characters;
+#endif
+  ret = split_at_delims (line, llen, delims, sentinel, nwp, cwp);
+  return (ret);
+}
+
+/* Evaluate COMPSPEC *cs and return all matches for WORD. */
+
+STRINGLIST *
+gen_compspec_completions (cs, cmd, word, start, end)
+     COMPSPEC *cs;
+     const char *cmd;
+     const char *word;
+     int start, end;
+{
+  STRINGLIST *ret, *tmatches;
+  char *line;
+  int llen, nw, cw;
+  WORD_LIST *lwords;
+  COMPSPEC *tcs;
+
+#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);
+      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);
+             strlist_print (tmatches, "\t");
+             rl_on_new_line ();
+           }
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
+         rl_filename_completion_desired = 1;
+       }
+    }
+
+  if (cs->words)
+    {
+      tmatches = gen_wordlist_matches (cs, word);
+      if (tmatches)
+       {
+#ifdef DEBUG
+         if (progcomp_debug)
+           {
+             debug_printf ("gen_wordlist_matches (%p, %s) -->", cs, word);
+             strlist_print (tmatches, "\t");
+             rl_on_new_line ();
+           }
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
+       }
+    }
+
+  lwords = (WORD_LIST *)NULL;
+  line = (char *)NULL;
+  if (cs->command || cs->funcname)
+    {
+      /* If we have a command or function to execute, we need to first break
+        the command line into individual words, find the number of words,
+        and find the word in the list containing the word to be completed. */
+      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)
+       {
+         debug_printf ("command_line_to_word_list -->");
+         printf ("\t");
+         print_word_list (lwords, "!");
+         printf ("\n");
+         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);
+             strlist_print (tmatches, "\t");
+             rl_on_new_line ();
+           }
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
+       }
+    }
+
+  if (cs->command)
+    {
+      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);
+             strlist_print (tmatches, "\t");
+             rl_on_new_line ();
+           }
+#endif
+         ret = strlist_append (ret, tmatches);
+         strlist_dispose (tmatches);
+       }
+    }
+
+  if (cs->command || cs->funcname)
+    {
+      if (lwords)
+       dispose_words (lwords);
+      FREE (line);
+    }
+
+  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);
+         strlist_print (tmatches, "\t");
+         rl_on_new_line ();
+       }
+#endif
+      if (ret && ret != tmatches)
+       {
+         FREE (ret->list);
+         free (ret);
+       }
+      ret = tmatches;
+    }
+
+  if (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
+      gen_action_completions again to generate a list of matching directory
+      names. */
+  if ((ret == 0 || ret->list_len == 0) && (cs->options & COPT_DIRNAMES))
+    {
+      tcs = compspec_create ();
+      tcs->actions = CA_DIRECTORY;
+      ret = gen_action_completions (tcs, word);
+      compspec_dispose (tcs);
+    }
+  else if (cs->options & COPT_PLUSDIRS)
+    {
+      tcs = compspec_create ();
+      tcs->actions = CA_DIRECTORY;
+      tmatches = gen_action_completions (tcs, word);
+      ret = strlist_append (ret, tmatches);
+      strlist_dispose (tmatches);
+      compspec_dispose (tcs);
+    }
+
+  return (ret);
+}
+
+void
+pcomp_set_readline_variables (flags, nval)
+     int flags, nval;
+{
+  /* If the user specified that the compspec returns filenames, make
+     sure that readline knows it. */
+  if (flags & COPT_FILENAMES)
+    rl_filename_completion_desired = nval;
+  /* If the user doesn't want a space appended, tell readline. */
+  if (flags & COPT_NOSPACE)
+    rl_completion_suppress_append = nval;
+}
+
+/* Set or unset FLAGS in the options word of the current compspec.
+   SET_OR_UNSET is 1 for setting, 0 for unsetting. */
+void
+pcomp_set_compspec_options (cs, flags, set_or_unset)
+     COMPSPEC *cs;
+     int flags, set_or_unset;
+{
+  if (cs == 0 && ((cs = pcomp_curcs) == 0))
+    return;
+  if (set_or_unset)
+    cs->options |= flags;
+  else
+    cs->options &= ~flags;
+}
+
+/* The driver function for the programmable completion code.  Returns a list
+   of matches for WORD, which is an argument to command CMD.  START and END
+   bound the command currently being completed in rl_line_buffer. */
+char **
+programmable_completions (cmd, word, start, end, foundp)
+     const char *cmd;
+     const char *word;
+     int start, end, *foundp;
+{
+  COMPSPEC *cs, *oldcs;
+  STRINGLIST *ret;
+  char **rmatches, *t;
+
+  /* We look at the basename of CMD if the full command does not have
+     an associated COMPSPEC. */
+  cs = progcomp_search (cmd);
+  if (cs == 0)
+    {
+      t = strrchr (cmd, '/');
+      if (t)
+       cs = progcomp_search (++t);
+    }
+  if (cs == 0)
+    {
+      if (foundp)
+       *foundp = 0;
+      return ((char **)NULL);
+    }
+
+  cs = compspec_copy (cs);
+
+  oldcs = pcomp_curcs;
+  oldcmd = pcomp_curcmd;
+  pcomp_curcs = cs;
+  pcomp_curcmd = cmd;
+  /* Signal the caller that we found a COMPSPEC for this command, and pass
+     back any meta-options associated with the compspec. */
+  if (foundp)
+    *foundp = 1|cs->options;
+
+  ret = gen_compspec_completions (cs, cmd, word, start, end);
+
+  pcomp_curcs = oldcs;
+  compspec_dispose (cs);
+
+  if (ret)
+    {
+      rmatches = ret->list;
+      free (ret);
+    }
+  else
+    rmatches = (char **)NULL;
+
+  return (rmatches);
+}
+
+#endif /* PROGRAMMABLE_COMPLETION */
index 63dc454e928ed079ed8f6d1c1c34cca819877da0..8ca08baa85aa2f8c53d5c6c82f49548a1bf431b3 100644 (file)
@@ -15430,3 +15430,55 @@ builtins/printf.def
 lib/readline/doc/rltech.texi
        - documented rest of readline's state flags, including RL_STATE_CALLBACK
        - documented rl_save_state and rl_restore_state
+
+                                  3/27
+                                  ----
+lib/readline/{rlprivate.h,{display,readline,rltty,terminal,text}.c}
+       - rename readline_echoing_p to _rl_echoing_p for namespace consistency
+
+lib/readline/{rlprivate.h,{callback,readline,util}.c}
+       - rename readline_top_level to _rl_top_level for namespace consistency
+
+builtins/ulimit.def
+       - new -b (socket buffer size) and -T (number of threads) options
+
+array.c
+       - fix bug in calculation of the array element assignment string length:
+         use length of `is' instead of `indstr'.  Reported as ubuntu bug
+         #202885 by John McCabe-Dansted
+
+builtins/setattr.def
+       - new function, show_all_var_attributes, displays attributes and
+         values for all shell variables (or shell functions) in a reusable
+         format
+
+builtins/common.h
+       - new extern declaration for show_all_var_attributes
+
+builtins/declare.def
+       - change `declare -p' to print out all variable attributes and values,
+         and `declare -fp' to print out all function attributes and
+         definitions.  Inspired by request from John Love-Jensen
+         <eljay@adobe.com>
+
+doc/{bash.1,bashref.texi}
+       - document new -b and -T options to ulimit
+       - tighten up language describing AND and OR lists
+       - add description of new behavior of `declare -p'
+
+                                  3/28
+                                  ----
+pcomplete.c
+       - rename curcs -> pcomp_curcs
+       - new global completion variable, pcomp_curcmd, the current command
+         name being completed
+
+builtins/complete.def
+       - new builtin, compopt, allows completion options for command names
+         supplied as arguments or the current completion being executed to
+         be modified.  Suggested by Mika Fischer <mf+ubuntu@zoopnet.de>
+
+                                  3/30
+                                  ----
+doc/{bash.1,bashref.texi},lib/readline/doc/rluser.texi
+       - document new compopt builtin
index a00c80997b99aef552e3493fc00451591321c2bf..5d1ee69b8521e211ad9c54f6950607bd7ea86180 100644 (file)
@@ -15426,3 +15426,59 @@ builtins/printf.def
          to be written overflows the buffer, realloc the buffer and use
          vsnprintf again.  This should reduce the memory used by printf.
          Idea from Yuya Katayama <yuya999@gmail.com>
+
+lib/readline/doc/rltech.texi
+       - documented rest of readline's state flags, including RL_STATE_CALLBACK
+       - documented rl_save_state and rl_restore_state
+
+                                  3/27
+                                  ----
+lib/readline/{rlprivate.h,{display,readline,rltty,terminal,text}.c}
+       - rename readline_echoing_p to _rl_echoing_p for namespace consistency
+
+lib/readline/{rlprivate.h,{callback,readline,util}.c}
+       - rename readline_top_level to _rl_top_level for namespace consistency
+
+builtins/ulimit.def
+       - new -b (socket buffer size) and -T (number of threads) options
+
+array.c
+       - fix bug in calculation of the array element assignment string length:
+         use length of `is' instead of `indstr'.  Reported as ubuntu bug
+         #202885 by John McCabe-Dansted
+
+builtins/setattr.def
+       - new function, show_all_var_attributes, displays attributes and
+         values for all shell variables (or shell functions) in a reusable
+         format
+
+builtins/common.h
+       - new extern declaration for show_all_var_attributes
+
+builtins/declare.def
+       - change `declare -p' to print out all variable attributes and values,
+         and `declare -fp' to print out all function attributes and
+         definitions.  Inspired by request from John Love-Jensen
+         <eljay@adobe.com>
+
+doc/{bash.1,bashref.texi}
+       - document new -b and -T options to ulimit
+       - tighten up language describing AND and OR lists
+       - add description of new behavior of `declare -p'
+
+                                  3/28
+                                  ----
+pcomplete.c
+       - rename curcs -> pcomp_curcs
+       - new global completion variable, pcomp_curcmd, the current command
+         name being completed
+
+builtins/complete.def
+       - new builtin, compopt, allows completion options for command names
+         supplied as arguments or the current completion being executed to
+         be modified.  Suggested by Mika Fischer <mf+ubuntu@zoopnet.de>
+
+                                  3/30
+                                  ----
+doc/{bash.1,bashref.texi}
+       - document new compopt builtin
diff --git a/array.c b/array.c
index ee7562c5d523318febf1bde70760fad9eb981677..72d7725883be131aee115bf7c854e832c47e9c74 100644 (file)
--- a/array.c
+++ b/array.c
@@ -693,7 +693,7 @@ int quoted;
                is = inttostr (element_index(ae), indstr, sizeof(indstr));
                valstr = element_value (ae) ? sh_double_quote (element_value(ae))
                                            : (char *)NULL;
-               elen = STRLEN (indstr) + 8 + STRLEN (valstr);
+               elen = STRLEN (is) + 8 + STRLEN (valstr);
                RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize);
 
                result[rlen++] = '[';
index f3ed08bb90a6b6da0b3411b81f220241e9051afa..ee7562c5d523318febf1bde70760fad9eb981677 100644 (file)
--- a/array.c~
+++ b/array.c~
@@ -329,7 +329,7 @@ int starsub, quoted;
        ARRAY           *a2;
        ARRAY_ELEMENT   *h, *p;
        arrayind_t      i;
-       char            *ifs, sep[2], *t;
+       char            *ifs, *sep, *t;
 
        p = a ? array_head (a) : 0;
        if (p == 0 || array_empty (a) || start > array_max_index(a))
@@ -354,20 +354,31 @@ int       starsub, quoted;
 
        a2 = array_slice(a, h, p);
 
-       if (mflags & MATCH_QUOTED)
-               array_quote (a2);
+       if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))
+               array_quote(a2);
        else
-               array_quote_escapes (a2);
+               array_quote_escapes(a2);
 
        if (starsub && (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT))) {
-               ifs = getifs();
-               sep[0] = ifs ? *ifs : '\0';
-       } else
+               /* ${array[*]} */
+               sep = ifs_firstchar ((int *)NULL);
+       } else if (quoted & (Q_DOUBLE_QUOTES|Q_HERE_DOCUMENT)) {
+               /* ${array[@]} */
+               sep = ifs_firstchar ((int *)NULL);
+               ifs = getifs ();
+               if (ifs == 0 || *ifs == 0) {
+                       sep[0] = ' ';
+                       sep[1] = '\0';
+               }
+       } else {
+               sep = xmalloc (2);
                sep[0] = ' ';
-       sep[1] = '\0';
+               sep[1] = '\0';
+       }
 
        t = array_to_string (a2, sep, 0);
        array_dispose(a2);
+       free (sep);
 
        return t;
 }
@@ -380,7 +391,7 @@ int mflags;
 {
        ARRAY           *a2;
        ARRAY_ELEMENT   *e;
-       char    *t, *ifs, sifs[2];
+       char    *t, *sifs;
 
        if (a == 0 || array_head(a) == 0 || array_empty(a))
                return ((char *)NULL);
@@ -393,14 +404,13 @@ int       mflags;
        }
 
        if (mflags & MATCH_QUOTED)
-               array_quote (a2);
+               array_quote(a2);
        else
-               array_quote_escapes (a2);
+               array_quote_escapes(a2);
        if (mflags & MATCH_STARSUB) {
-               ifs = getifs();
-               sifs[0] = ifs ? *ifs : '\0';
-               sifs[1] = '\0';
+               sifs = ifs_firstchar((int *)NULL);
                t = array_to_string (a2, sifs, 0);
+               free(sifs);
        } else
                t = array_to_string (a2, " ", 0);
        array_dispose (a2);
@@ -618,8 +628,8 @@ ARRAY       *a;
 }
        
 /*
- * Return a string that is the concatenation of all the elements in A,
- * separated by SEP.
+ * Return a string that is the concatenation of the elements in A from START
+ * to END, separated by SEP.
  */
 static char *
 array_to_string_internal (start, end, sep, quoted)
index 0a46d2001ec6a43333cc767699a61256b5ded331..3a817cc2569a7c88d50e8081cc04a9f58c5edd2a 100644 (file)
@@ -142,6 +142,7 @@ extern int describe_command __P((char *, int));
 
 /* Functions from setattr.def */
 extern int set_or_show_attributes __P((WORD_LIST *, int, int));
+extern int show_all_var_attributes __P((int, int));
 extern int show_var_attributes __P((SHELL_VAR *, int, int));
 extern int show_name_attributes __P((char *, int));
 extern void set_var_attribute __P((char *, int, int));
diff --git a/builtins/common.h~ b/builtins/common.h~
new file mode 100644 (file)
index 0000000..0a46d20
--- /dev/null
@@ -0,0 +1,164 @@
+/* common.h -- extern declarations for functions defined in common.c. */
+
+/* Copyright (C) 1993-2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it under
+   the terms of the GNU General Public License as published by the Free
+   Software Foundation; either version 2, or (at your option) any later
+   version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+   WARRANTY; without even the implied warranty of MERCHANTABILITY or
+   FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+   for more details.
+
+   You should have received a copy of the GNU General Public License along
+   with Bash; see the file COPYING.  If not, write to the Free Software
+   Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if  !defined (__COMMON_H)
+#  define __COMMON_H
+
+#include "stdc.h"
+
+#define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c)
+
+/* Flag values for parse_and_execute () */
+#define SEVAL_NONINT   0x001
+#define SEVAL_INTERACT 0x002
+#define SEVAL_NOHIST   0x004
+#define SEVAL_NOFREE   0x008
+#define SEVAL_RESETLINE        0x010
+
+/* Flags for describe_command, shared between type.def and command.def */
+#define CDESC_ALL              0x001   /* type -a */
+#define CDESC_SHORTDESC                0x002   /* command -V */
+#define CDESC_REUSABLE         0x004   /* command -v */
+#define CDESC_TYPE             0x008   /* type -t */
+#define CDESC_PATH_ONLY                0x010   /* type -p */
+#define CDESC_FORCE_PATH       0x020   /* type -ap or type -P */
+#define CDESC_NOFUNCS          0x040   /* type -f */
+#define CDESC_ABSPATH          0x080   /* convert to absolute path, no ./ */
+
+/* Flags for get_job_by_name */
+#define JM_PREFIX              0x01    /* prefix of job name */
+#define JM_SUBSTRING           0x02    /* substring of job name */
+#define JM_EXACT               0x04    /* match job name exactly */
+#define JM_STOPPED             0x08    /* match stopped jobs only */
+#define JM_FIRSTMATCH          0x10    /* return first matching job */
+
+/* Flags for remember_args and value of changed_dollar_vars */
+#define ARGS_NONE              0x0
+#define ARGS_INVOC             0x01
+#define ARGS_FUNC              0x02
+#define ARGS_SETBLTIN          0x04
+
+/* Functions from common.c */
+extern void builtin_error __P((const char *, ...))  __attribute__((__format__ (printf, 1, 2)));
+extern void builtin_usage __P((void));
+extern void no_args __P((WORD_LIST *));
+extern int no_options __P((WORD_LIST *));
+
+/* common error message functions */
+extern void sh_needarg __P((char *));
+extern void sh_neednumarg __P((char *));
+extern void sh_notfound __P((char *));
+extern void sh_invalidopt __P((char *));
+extern void sh_invalidoptname __P((char *));
+extern void sh_invalidid __P((char *));
+extern void sh_invalidnum __P((char *));
+extern void sh_invalidsig __P((char *));
+extern void sh_erange __P((char *, char *));
+extern void sh_badpid __P((char *));
+extern void sh_badjob __P((char *));
+extern void sh_readonly __P((const char *));
+extern void sh_nojobs __P((char *));
+extern void sh_restricted __P((char *));
+extern void sh_notbuiltin __P((char *));
+extern void sh_wrerror __P((void));
+extern int sh_chkwrite __P((int));
+
+extern char **make_builtin_argv __P((WORD_LIST *, int *));
+extern void remember_args __P((WORD_LIST *, int));
+
+extern int dollar_vars_changed __P((void));
+extern void set_dollar_vars_unchanged __P((void));
+extern void set_dollar_vars_changed __P((void));
+
+extern intmax_t get_numeric_arg __P((WORD_LIST *, int));
+extern int get_exitstat __P((WORD_LIST *));
+extern int read_octal __P((char *));
+
+/* Keeps track of the current working directory. */
+extern char *the_current_working_directory;
+extern char *get_working_directory __P((char *));
+extern void set_working_directory __P((char *));
+
+#if defined (JOB_CONTROL)
+extern int get_job_by_name __P((const char *, int));
+extern int get_job_spec __P((WORD_LIST *));
+#endif
+extern int display_signal_list __P((WORD_LIST *, int));
+
+/* It's OK to declare a function as returning a Function * without
+   providing a definition of what a `Function' is. */
+extern struct builtin *builtin_address_internal __P((char *, int));
+extern sh_builtin_func_t *find_shell_builtin __P((char *));
+extern sh_builtin_func_t *builtin_address __P((char *));
+extern sh_builtin_func_t *find_special_builtin __P((char *));
+extern void initialize_shell_builtins __P((void));
+
+/* Functions from exit.def */
+extern void bash_logout __P((void));
+
+/* Functions from getopts.def */
+extern void getopts_reset __P((int));
+
+/* Functions from set.def */
+extern int minus_o_option_value __P((char *));
+extern void list_minus_o_opts __P((int, int));
+extern char **get_minus_o_opts __P((void));
+extern int set_minus_o_option __P((int, char *));
+
+extern void set_shellopts __P((void));
+extern void parse_shellopts __P((char *));
+extern void initialize_shell_options __P((int));
+
+extern void reset_shell_options __P((void));
+
+/* Functions from shopt.def */
+extern void reset_shopt_options __P((void));
+extern char **get_shopt_options __P((void));
+
+extern int shopt_setopt __P((char *, int));
+extern int shopt_listopt __P((char *, int));
+
+extern int set_login_shell __P((int));
+
+/* Functions from type.def */
+extern int describe_command __P((char *, int));
+
+/* Functions from setattr.def */
+extern int set_or_show_attributes __P((WORD_LIST *, int, int));
+extern int show_var_attributes __P((SHELL_VAR *, int, int));
+extern int show_name_attributes __P((char *, int));
+extern void set_var_attribute __P((char *, int, int));
+
+/* Functions from pushd.def */
+extern char *get_dirstack_from_string __P((char *));
+extern char *get_dirstack_element __P((intmax_t, int));
+extern void set_dirstack_element __P((intmax_t, int, char *));
+extern WORD_LIST *get_directory_stack __P((int));
+
+/* Functions from evalstring.c */
+extern int parse_and_execute __P((char *, const char *, int));
+extern void parse_and_execute_cleanup __P((void));
+
+/* Functions from evalfile.c */
+extern int maybe_execute_file __P((const char *, int));
+extern int source_file __P((const char *, int));
+extern int fc_execute_file __P((const char *));
+
+#endif /* !__COMMON_H */
index 6c77a6ed523b098c55ba86f5c3f292cadadca7f2..c2ef0e24a633f075139942d3cc92be4c171e6efe 100644 (file)
@@ -1,5 +1,5 @@
 This file is complete.def, from which is created complete.c.
-It implements the builtins "complete" and "compgen" in Bash.
+It implements the builtins "complete", "compgen", and "compopt" in Bash.
 
 Copyright (C) 1999-2008 Free Software Foundation, Inc.
 
@@ -25,9 +25,11 @@ $BUILTIN complete
 $DEPENDS_ON PROGRAMMABLE_COMPLETION
 $FUNCTION complete_builtin
 $SHORT_DOC complete [-abcdefgjksuv] [-pr] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
-For each NAME, specify how arguments are to be completed by Readline.
-If no options are supplied, existing completion specifications are printed
-in a way that allows them to be reused as input.
+Specify how arguments are to be completed by Readline.
+
+For each NAME, specify how arguments are to be completed.  If no options
+are supplied, existing completion specifications are printed in a way that
+allows them to be reused as input.
 
 Options:
   -p   print existing completion specifications in a reusable format
@@ -72,6 +74,7 @@ static int remove_cmd_completions __P((WORD_LIST *));
 
 static int print_one_completion __P((char *, COMPSPEC *));
 static int print_compitem __P((BUCKET_CONTENTS *));
+static void print_compopts __P((const char *, COMPSPEC *, int));
 static void print_all_completions __P((void));
 static int print_cmd_completions __P((WORD_LIST *));
 
@@ -425,6 +428,14 @@ remove_cmd_completions (list)
       printf ("-o %s ", f); \
   } while (0)
 
+#define XPRINTCOMPOPT(a, f) \
+  do { \
+    if (copts & a) \
+      printf ("-o %s ", f); \
+    else \
+      printf ("+o %s ", f); \
+  } while (0)
+
 static int
 print_one_completion (cmd, cs)
      char *cmd;
@@ -489,11 +500,44 @@ print_one_completion (cmd, cs)
   /* simple arguments that don't require quoting */
   PRINTARG (cs->funcname, "-F");
 
-  printf ("%s\n", x);
+  printf ("%s\n", cmd);
 
   return (0);
 }
 
+static void
+print_compopts (cmd, cs, full)
+     const char *cmd;
+     COMPSPEC *cs;
+     int full;
+{
+  int copts;
+
+  printf ("compopt ");
+  copts = cs->options;
+
+  if (full)
+    {
+      XPRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
+      XPRINTCOMPOPT (COPT_DEFAULT, "default");
+      XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
+      XPRINTCOMPOPT (COPT_FILENAMES, "filenames");
+      XPRINTCOMPOPT (COPT_NOSPACE, "nospace");
+      XPRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
+    }
+  else
+    {
+      PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
+      PRINTCOMPOPT (COPT_DEFAULT, "default");
+      PRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
+      PRINTCOMPOPT (COPT_FILENAMES, "filenames");
+      PRINTCOMPOPT (COPT_NOSPACE, "nospace");
+      PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
+    }
+
+  printf ("%s\n", cmd);
+}
+
 static int
 print_compitem (item)
      BUCKET_CONTENTS *item;
@@ -540,10 +584,11 @@ $BUILTIN compgen
 $DEPENDS_ON PROGRAMMABLE_COMPLETION
 $FUNCTION compgen_builtin
 $SHORT_DOC compgen [-abcdefgjksuv] [-o option]  [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
-Display the possible completions depending on the options.  Intended
-to be used from within a shell function generating possible completions.
-If the optional WORD argument is supplied, matches against WORD are
-generated.
+Display the possible completions depending on the options.
+
+Intended to be used from within a shell function generating possible
+completions.  If the optional WORD argument is supplied, matches against
+WORD are generated.
 $END
 
 int
@@ -628,3 +673,110 @@ compgen_builtin (list)
   compspec_dispose (cs);
   return (rval);
 }
+
+$BUILTIN compopt
+$DEPENDS_ON PROGRAMMABLE_COMPLETION
+$FUNCTION compopt_builtin
+$SHORT_DOC compopt [-o|+o option] [name ...]
+Modify or display completion options.
+
+Modify the completion options for each NAME, or, if no NAMEs are supplied,
+the completion currently begin executed.  If no OPTIONs are givenm, print
+the completion options for each NAME or the current completion specification.
+
+Options:
+       -o option       Set completion option OPTION for each NAME
+
+Using `+o' instead of `-o' turns off the specified option.
+
+Arguments:
+
+Each NAME refers to a command for which a completion specification must
+have previously been defined using the `complete' builtin.  If no NAMEs
+are supplied, compopt must be called by a function currently generating
+completions, and the options for that currently-executing completion
+generator are modified.
+$END
+
+int
+compopt_builtin (list)
+     WORD_LIST *list;
+{
+  int opts_on, opts_off, *opts, opt, oind, ret;
+  WORD_LIST *l;
+  COMPSPEC *cs;
+
+  opts_on = opts_off = 0;
+  ret = EXECUTION_SUCCESS;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "+o:")) != EOF)
+    {
+      opts = (list_opttype == '-') ? &opts_on : &opts_off;
+
+      switch (opt)
+       {
+       case 'o':
+         oind = find_compopt (list_optarg);
+         if (oind < 0)
+           {
+             sh_invalidoptname (list_optarg);
+             return (EX_USAGE);
+           }
+         *opts |= compopts[oind].optflag;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list == 0)
+    {
+      if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0)
+       {
+         builtin_error (_("not currently executing completion function"));
+         return (EXECUTION_FAILURE);
+       }
+      cs = pcomp_curcs;
+
+      if (opts_on == 0 && opts_off == 0)
+       {
+         print_compopts (pcomp_curcmd, cs, 1);
+          return (sh_chkwrite (ret));
+       }
+
+      /* Set the compspec options */
+      pcomp_set_compspec_options (cs, opts_on, 1);
+      pcomp_set_compspec_options (cs, opts_off, 0);
+
+      /* And change the readline variables the options control */
+      pcomp_set_readline_variables (opts_on, 1);
+      pcomp_set_readline_variables (opts_off, 0);
+
+      return (ret);
+    }
+
+  for (l = list; l; l = l->next)
+    {
+      cs = progcomp_search (l->word->word);
+      if (cs == 0)
+       {
+         builtin_error (_("%s: no completion specification"), l->word->word);
+         ret = EXECUTION_FAILURE;
+         continue;
+       }
+      if (opts_on == 0 && opts_off == 0)
+       {
+         print_compopts (l->word->word, cs, 1);
+         continue;                     /* XXX -- fill in later */
+       }
+
+      /* Set the compspec options */
+      pcomp_set_compspec_options (cs, opts_on, 1);
+      pcomp_set_compspec_options (cs, opts_off, 0);
+    }
+
+  return (ret);
+}
index b05aac94d5a9cc605970c87a1a5359e4f02a05d5..2b1ca15c900e8cfff5aa12e48ea213ddcb32921a 100644 (file)
@@ -1,5 +1,5 @@
 This file is complete.def, from which is created complete.c.
-It implements the builtins "complete" and "compgen" in Bash.
+It implements the builtins "complete", "compgen", and "compopt" in Bash.
 
 Copyright (C) 1999-2008 Free Software Foundation, Inc.
 
@@ -25,14 +25,15 @@ $BUILTIN complete
 $DEPENDS_ON PROGRAMMABLE_COMPLETION
 $FUNCTION complete_builtin
 $SHORT_DOC complete [-abcdefgjksuv] [-pr] [-o option] [-A action] [-G globpat] [-W wordlist]  [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
-For each NAME, specify how arguments are to be completed by Readline.
+Specify how arguments are to be completed by Readline.
+
 If no options are supplied, existing completion specifications are printed
 in a way that allows them to be reused as input.
 
 Options:
   -p   print existing completion specifications in a reusable format
-  -r   remove a completion specification for each NAME, or, if no NAMEs
-       are supplied, all completion specifications
+  -r   remove a completion specification for each NAME, or, if no
+       NAMEs are supplied, all completion specifications
 
 When completion is attempted, the actions are applied in the order the
 uppercase-letter options are listed above.
@@ -72,6 +73,7 @@ static int remove_cmd_completions __P((WORD_LIST *));
 
 static int print_one_completion __P((char *, COMPSPEC *));
 static int print_compitem __P((BUCKET_CONTENTS *));
+static void print_compopts __P((const char *, COMPSPEC *, int));
 static void print_all_completions __P((void));
 static int print_cmd_completions __P((WORD_LIST *));
 
@@ -425,6 +427,14 @@ remove_cmd_completions (list)
       printf ("-o %s ", f); \
   } while (0)
 
+#define XPRINTCOMPOPT(a, f) \
+  do { \
+    if (copts & a) \
+      printf ("-o %s ", f); \
+    else \
+      printf ("+o %s ", f); \
+  } while (0)
+
 static int
 print_one_completion (cmd, cs)
      char *cmd;
@@ -489,11 +499,44 @@ print_one_completion (cmd, cs)
   /* simple arguments that don't require quoting */
   PRINTARG (cs->funcname, "-F");
 
-  printf ("%s\n", x);
+  printf ("%s\n", cmd);
 
   return (0);
 }
 
+static void
+print_compopts (cmd, cs, full)
+     const char *cmd;
+     COMPSPEC *cs;
+     int full;
+{
+  int copts;
+
+  printf ("compopt ");
+  copts = cs->options;
+
+  if (full)
+    {
+      XPRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
+      XPRINTCOMPOPT (COPT_DEFAULT, "default");
+      XPRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
+      XPRINTCOMPOPT (COPT_FILENAMES, "filenames");
+      XPRINTCOMPOPT (COPT_NOSPACE, "nospace");
+      XPRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
+    }
+  else
+    {
+      PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
+      PRINTCOMPOPT (COPT_DEFAULT, "default");
+      PRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
+      PRINTCOMPOPT (COPT_FILENAMES, "filenames");
+      PRINTCOMPOPT (COPT_NOSPACE, "nospace");
+      PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
+    }
+
+  printf ("%s\n", cmd);
+}
+
 static int
 print_compitem (item)
      BUCKET_CONTENTS *item;
@@ -628,3 +671,109 @@ compgen_builtin (list)
   compspec_dispose (cs);
   return (rval);
 }
+
+$BUILTIN compopt
+$DEPENDS_ON PROGRAMMABLE_COMPLETION
+$FUNCTION compopt_builtin
+$SHORT_DOC compopt [-o|+o option] [name ...]
+Modify or display completion options.
+
+Modify the completion options for each NAME, or, if no NAMEs are supplied,
+the completion currently begin executed.
+
+Options:
+       -o option       Set completion option OPTION for each NAME
+
+Using `+o' instead of `-o' turns off the specified option.
+
+Arguments:
+
+Each NAME refers to a command for which a completion specification must
+have previously been defined using the `complete' builtin.  If no NAMEs
+are supplied, compopt must be called by a function currently generating
+completions, and the options for that currently-executing completion
+generator are modified.
+$END
+
+int
+compopt_builtin (list)
+     WORD_LIST *list;
+{
+  int opts_on, opts_off, *opts, opt, oind, ret;
+  WORD_LIST *l;
+  COMPSPEC *cs;
+
+  opts_on = opts_off = 0;
+  ret = EXECUTION_SUCCESS;
+
+  reset_internal_getopt ();
+  while ((opt = internal_getopt (list, "+o:")) != EOF)
+    {
+      opts = (list_opttype == '-') ? &opts_on : &opts_off;
+
+      switch (opt)
+       {
+       case 'o':
+         oind = find_compopt (list_optarg);
+         if (oind < 0)
+           {
+             sh_invalidoptname (list_optarg);
+             return (EX_USAGE);
+           }
+         *opts |= compopts[oind].optflag;
+         break;
+       default:
+         builtin_usage ();
+         return (EX_USAGE);
+       }
+    }
+  list = loptend;
+
+  if (list == 0)
+    {
+      if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0)
+       {
+         builtin_error (_("not currently executing completion function"));
+         return (EXECUTION_FAILURE);
+       }
+      cs = pcomp_curcs;
+
+      if (opts_on == 0 && opts_off == 0)
+       {
+         print_compopts (pcomp_curcmd, cs, 1);
+          return (sh_chkwrite (ret));
+       }
+
+      /* Set the compspec options */
+      pcomp_set_compspec_options (cs, opts_on, 1);
+      pcomp_set_compspec_options (cs, opts_off, 0);
+
+      /* And change the readline variables the options control */
+      pcomp_set_readline_variables (opts_on, 1);
+      pcomp_set_readline_variables (opts_off, 0);
+
+      return (ret);
+    }
+
+  for (l = list; l; l = l->next)
+    {
+      cs = progcomp_search (l->word->word);
+      if (cs == 0)
+       {
+         builtin_error (_("%s: no completion specification"), l->word->word);
+         ret = EXECUTION_FAILURE;
+         continue;
+       }
+      if (opts_on == 0 && opts_off == 0)
+       {
+         print_compopts (l->word->word, cs, 1);
+         continue;                     /* XXX -- fill in later */
+       }
+
+      /* Set the compspec options */
+      pcomp_set_compspec_options (cs, opts_on, 1);
+      pcomp_set_compspec_options (cs, opts_off, 0);
+    }
+
+  return (ret);
+}
index 09c21a35e34713a7d72a191edd0f4853674c2afd..f7b0dc168a677ab3cd88c7a3b9fd10f697eeb728 100644 (file)
@@ -192,6 +192,8 @@ declare_internal (list, local_var)
              free (vlist);
            }
        }
+      else if (pflag && (flags_on == 0 || flags_on == att_function))
+       show_all_var_attributes (flags_on == 0, nodefs);
       else if (flags_on == 0)
        return (set_builtin ((WORD_LIST *)NULL));
       else
index 2c7352c2f933594580ff5784ca31e048a8a92ee2..fe98c3758af4683f2a8f003b572ff0c8c18e02fa 100644 (file)
@@ -28,14 +28,12 @@ Declare variables and give them attributes.  If no NAMEs are given,
 display the attributes and values of all variables.
 
 Options:
-
   -f   restrict action or display to function names and definitions
   -F   restrict display to function names only (plus line number and
        source file when debugging)
   -p   display the attributes and value of each NAME
 
 Options which set attributes:
-
   -a   to make NAMEs arrays (if supported)
   -i   to make NAMEs have the `integer' attribute
   -r   to make NAMEs readonly
@@ -194,6 +192,10 @@ declare_internal (list, local_var)
              free (vlist);
            }
        }
+      else if (pflag && (flags_on == 0 || flags_on == att_function))
+       {
+         show_all_var_attributes (flags_on == 0, nodefs);
+       }         
       else if (flags_on == 0)
        return (set_builtin ((WORD_LIST *)NULL));
       else
index be3d104322f3b82bfbcf02601afdb254e5f17d02..cad3bd4a4a841c377cffad2c970543284e1fc16e 100644 (file)
@@ -288,6 +288,30 @@ set_or_show_attributes (list, attribute, nodefs)
                                            : EXECUTION_FAILURE));
 }
 
+/* Show all variable variables (v == 1) or functions (v == 0) with
+   attributes. */
+int
+show_all_var_attributes (v, nodefs)
+     int v, nodefs;
+{
+  SHELL_VAR **variable_list, *var;
+  int any_failed;
+  register int i;
+
+  variable_list = v ? all_shell_variables () : all_shell_functions ();
+  if (variable_list == 0)  
+    return (EXECUTION_SUCCESS);
+
+  for (i = any_failed = 0; var = variable_list[i]; i++)
+    {
+      show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
+      if (any_failed = sh_chkwrite (any_failed))
+        break;
+    }
+  free (variable_list);
+  return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
 /* Show the attributes for shell variable VAR.  If NODEFS is non-zero,
    don't show function definitions along with the name.  If PATTR is
    non-zero, it indicates we're being called from `export' or `readonly'.
index b577a5b36d3f0c141940ff74a7ea25a36d831bd0..4b5024a44fb95b7ee42834828c51e3f587013da1 100644 (file)
@@ -57,7 +57,6 @@ Marks each NAME for automatic export to the environment of subsequently
 executed commands.  If VALUE is supplied, assign VALUE before exporting.
 
 Options:
-
   -f   refer to shell functions
   -n   remove the export property from each NAME
   -p   display a list of all exported variables and functions
@@ -85,7 +84,6 @@ changed by subsequent assignment.  If VALUE is supplied, assign VALUE
 before marking as read-only.
 
 Options:
-
   -a   refer to array variables
   -f   refer to shell functions
   -p   display a list of all readonly variables and functions
@@ -290,6 +288,30 @@ set_or_show_attributes (list, attribute, nodefs)
                                            : EXECUTION_FAILURE));
 }
 
+/* Show all variable variables (v == 1) or functions (v == 0) with
+   attributes. */
+int
+show_all_var_attributes (v, nodefs)
+     int v, nodefs;
+{
+  SHELL_VAR **variable_list;
+  int any_failed;
+  register int i;
+
+  variable_list = v ? all_shell_variables () : all_shell_functions ();
+  if (variable_list == 0)  
+    return (EXECUTION_SUCCESS);
+
+  for (i = any_failed = 0; var = variable_list[i]; i++)
+    {
+      show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
+      if (any_failed = sh_chkwrite (any_failed))
+        break;
+    }
+  free (variable_list);
+  return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
 /* Show the attributes for shell variable VAR.  If NODEFS is non-zero,
    don't show function definitions along with the name.  If PATTR is
    non-zero, it indicates we're being called from `export' or `readonly'.
index 1ea2c2a2bd90c698c9b7c0f409bd9b8a632fd4a3..5fdd98116f3d125b41e7540cdbd05e036488d582 100644 (file)
@@ -32,6 +32,7 @@ Options:
   -S   use the `soft' resource limit
   -H   use the `hard' resource limit
   -a   all current limits are reported
+  -b   the socket buffer size
   -c   the maximum size of core files created
   -d   the maximum size of a process's data segment
   -e   the maximum scheduling priority (`nice')
@@ -199,12 +200,17 @@ typedef struct {
 } RESOURCE_LIMITS;
 
 static RESOURCE_LIMITS limits[] = {
+#ifdef RLIMIT_PTHREAD
+  { 'T',       RLIMIT_PTHREAD,  1,     "number of threads",    (char *)NULL },
+#endif
+#ifdef RLIMIT_SBSIZE
+  { 'b',       RLIMIT_SBSIZE,  1,      "socket buffer size",   "bytes" },
+#endif
 #ifdef RLIMIT_CORE
   { 'c',       RLIMIT_CORE,  512,      "core file size",       "blocks" },
 #endif
 #ifdef RLIMIT_DATA
   { 'd',       RLIMIT_DATA,  1024,     "data seg size",        "kbytes" },
-
 #endif
 #ifdef RLIMIT_NICE
   { 'e',       RLIMIT_NICE,  1,        "scheduling priority",  (char *)NULL },
index 332a06340b157afc04b73a4303611c237e880bda..310340f7d53c7b83216b260b89da9b9498f62d2a 100644 (file)
@@ -53,9 +53,11 @@ If LIMIT is given, it is the new value of the specified resource; the
 special LIMIT values `soft', `hard', and `unlimited' stand for the
 current soft limit, the current hard limit, and no limit, respectively.
 Otherwise, the current value of the specified resource is printed.  If
-no option is given, then -f is assumed.  Values are in 1024-byte
-increments, except for -t, which is in seconds, -p, which is in increments
-of 512 bytes, and -u, which is an unscaled number of processes.
+no option is given, then -f is assumed.
+
+Values are in 1024-byte increments, except for -t, which is in seconds,
+-p, which is in increments of 512 bytes, and -u, which is an unscaled
+number of processes.
 $END
 
 #if !defined (_MINIX)
@@ -202,7 +204,6 @@ static RESOURCE_LIMITS limits[] = {
 #endif
 #ifdef RLIMIT_DATA
   { 'd',       RLIMIT_DATA,  1024,     "data seg size",        "kbytes" },
-
 #endif
 #ifdef RLIMIT_NICE
   { 'e',       RLIMIT_NICE,  1,        "scheduling priority",  (char *)NULL },
index 57963c30c8a3e7137dc0405beacb14db1bb4c41a..0d1e0c6781908f92a38be96aa5f6a0e978a76d10 100644 (file)
@@ -5,12 +5,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.cwru.edu
 .\"
-.\"    Last Change: Fri Feb 22 21:45:32 EST 2008
+.\"    Last Change: Thu Mar 27 22:15:12 EDT 2008
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2008 February 22" "GNU Bash-3.2"
+.TH BASH 1 "2008 March 27" "GNU Bash-3.2"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -594,11 +594,9 @@ are executed sequentially; the shell waits for each
 command to terminate in turn.  The return status is the
 exit status of the last command executed.
 .PP
-The control operators
-.B &&
-and
-.B \(bv\(bv
-denote AND lists and OR lists, respectively.
+AND and OR lists are sequences of one of more pipelines separated by the
+\fB&&\fP and \fB\(bv\(bv\fP control operators, respectively.
+AND and OR lists are executed with left associativity.
 An AND list has the form
 .RS
 .PP
@@ -620,7 +618,8 @@ An OR list has the form
 .I command2
 is executed if and only if
 .I command1
-returns a non-zero exit status.  The return status of
+returns a non-zero exit status.
+The return status of
 AND and OR lists is the exit status of the last command
 executed in the list.
 .SS Compound Commands
@@ -6495,6 +6494,19 @@ a \fIname\fP for which no specification exists, or
 an error occurs adding a completion specification.
 .RE
 .TP
+\fBcompopt\fP [\fB\-o\fP \fIoption\fP] [\fB+o\fP \fIoption\fP] [\fIname\fP]
+Modify completion options for each \fIname\fP according to the
+\fIoption\fPs, or for the
+currently-execution completion if no \fIname\fPs are supplied.
+If no \fIoption\fPs are given, display the completion options for each
+\fIname\fP or the current completion.
+The possible values of \fIoption\fP are those valid for the \fBcomplete\fP
+builtin described above.
+.PP
+The return value is true unless an invalid option is supplied, an attempt
+is made to modify the options for a \fIname\fP for which no completion
+specification exists, or an output error occurs.
+.TP
 \fBcontinue\fP [\fIn\fP]
 Resume the next iteration of the enclosing
 .BR for ,
@@ -6528,7 +6540,15 @@ option will display the attributes and values of each
 .IR name .
 When
 .B \-p
-is used, additional options are ignored.
+is used with \fIname\fP arguments, additional options are ignored.
+When
+.B \-p
+is supplied without \fIname\fP arguments, it will display the attributes
+and values of all variables having the attributes specified by the
+additional options.
+If no other options are supplied with \fB\-p\fP, \fBdeclare\fP will display
+the attributes and values of all shell variables.  The \fB\-f\fP option
+will restrict the display to shell functions.
 The
 .B \-F
 option inhibits the display of function definitions; only the
@@ -8609,7 +8629,7 @@ option suppresses shell function lookup, as with the \fBcommand\fP builtin.
 returns true if any of the arguments are found, false if
 none are found.
 .TP
-\fBulimit\fP [\fB\-SHacdefilmnpqrstuvx\fP [\fIlimit\fP]]
+\fBulimit\fP [\fB\-HSTabcdefilmnpqrstuvx\fP [\fIlimit\fP]]
 Provides control over the resources available to the shell and to
 processes started by it, on systems that allow such control.
 The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is
@@ -8640,6 +8660,9 @@ Other options are interpreted as follows:
 .B \-a
 All current limits are reported
 .TP
+.B \-b
+The maximum socket buffer size
+.TP
 .B \-c
 The maximum size of core files created
 .TP
@@ -8688,6 +8711,9 @@ The maximum amount of virtual memory available to the shell
 .TP
 .B \-x
 The maximum number of file locks
+.TP
+.B \-T
+The maximum number of threads
 .PD
 .PP
 If
@@ -8703,7 +8729,9 @@ which is in seconds,
 .BR \-p ,
 which is in units of 512-byte blocks,
 and
-.B \-n
+.BR \-T ,
+.BR \-b ,
+.BR \-n ,
 and
 .BR \-u ,
 which are unscaled values.
index c7349b04207d400e6b0ce54cbe03470354c91714..c6df3deee245eaa59fb94f569ab4a97cb316528b 100644 (file)
@@ -5,12 +5,12 @@
 .\"    Case Western Reserve University
 .\"    chet@po.cwru.edu
 .\"
-.\"    Last Change: Wed Dec  5 22:08:48 EST 2007
+.\"    Last Change: Thu Mar 27 22:15:12 EDT 2008
 .\"
 .\" bash_builtins, strip all but Built-Ins section
 .if \n(zZ=1 .ig zZ
 .if \n(zY=1 .ig zY
-.TH BASH 1 "2007 December 5" "GNU Bash-3.2"
+.TH BASH 1 "2008 March 27" "GNU Bash-3.2"
 .\"
 .\" There's some problem with having a `@'
 .\" in a tagged paragraph with the BSD man macros.
@@ -50,8 +50,8 @@ bash \- GNU Bourne-Again SHell
 [options]
 [file]
 .SH COPYRIGHT
-.if n Bash is Copyright (C) 1989-2007 by the Free Software Foundation, Inc.
-.if t Bash is Copyright \(co 1989-2007 by the Free Software Foundation, Inc.
+.if n Bash is Copyright (C) 1989-2008 by the Free Software Foundation, Inc.
+.if t Bash is Copyright \(co 1989-2008 by the Free Software Foundation, Inc.
 .SH DESCRIPTION
 .B Bash
 is an \fBsh\fR-compatible command language interpreter that
@@ -594,11 +594,9 @@ are executed sequentially; the shell waits for each
 command to terminate in turn.  The return status is the
 exit status of the last command executed.
 .PP
-The control operators
-.B &&
-and
-.B \(bv\(bv
-denote AND lists and OR lists, respectively.
+AND and OR lists are sequences of one of more pipelines separated by the
+\fB&&\fP and \fB\(bv\(bv\fP control operators, respectively.
+AND and OR lists are executed with left associativity.
 An AND list has the form
 .RS
 .PP
@@ -620,7 +618,8 @@ An OR list has the form
 .I command2
 is executed if and only if
 .I command1
-returns a non-zero exit status.  The return status of
+returns a non-zero exit status.
+The return status of
 AND and OR lists is the exit status of the last command
 executed in the list.
 .SS Compound Commands
@@ -1188,7 +1187,7 @@ expand to nothing (i.e., they are removed).
 Expands to the number of positional parameters in decimal.
 .TP
 .B ?
-Expands to the status of the most recently executed foreground
+Expands to the exit status of the most recently executed foreground
 pipeline.
 .TP
 .B \-
@@ -1249,13 +1248,13 @@ Expands to the full file name used to invoke this instance of
 .BR bash .
 .TP
 .B BASHPID
-Expands to the process id of the current bash process.
+Expands to the process id of the current \fBbash\fP process.
 This differs from \fB$$\fP under certain circumstances, such as subshells
-that do not require bash to be re-initialized.
+that do not require \fBbash\fP to be re-initialized.
 .TP
 .B BASH_ARGC
 An array variable whose values are the number of parameters in each
-frame of the current bash execution call stack.
+frame of the current \fBbash\fP execution call stack.
 The number of
 parameters to the current subroutine (shell function or script executed
 with \fB.\fP or \fBsource\fP) is at the top of the stack.
@@ -1269,7 +1268,7 @@ option to the
 builtin below)
 .TP
 .B BASH_ARGV
-An array variable containing all of the parameters in the current bash
+An array variable containing all of the parameters in the current \fBbash\fP
 execution call stack.  The final parameter of the last subroutine call
 is at the top of the stack; the first parameter of the initial call is
 at the bottom.  When a subroutine is executed, the parameters supplied
@@ -6495,6 +6494,19 @@ a \fIname\fP for which no specification exists, or
 an error occurs adding a completion specification.
 .RE
 .TP
+\fBcompopt\fP [\fB\-o\fP \fIoption\fP] [\fB+o\fP \fIoption\fP] [\fIname\fP]
+Modify completion options for each \fIname\fP according to the
+\fIoption\fPs, or for the
+currently-execution completion if no \fIname\fPs are supplied.  If no
+\fIoption\fPs are given, display the completion options for each \fIname\fP
+or the current completion.
+The possible values of \fIoption\fP are those valid for the \fBcomplete\fP
+builtin described above.
+.PP
+The return value is true unless an invalid option is supplied, an attempt
+is made to modify the options for a \fIname\fP for which no completion
+specification exists, or an output error occurs.
+.TP
 \fBcontinue\fP [\fIn\fP]
 Resume the next iteration of the enclosing
 .BR for ,
@@ -6528,7 +6540,15 @@ option will display the attributes and values of each
 .IR name .
 When
 .B \-p
-is used, additional options are ignored.
+is used with \fIname\fP arguments, additional options are ignored.
+When
+.B \-p
+is supplied without \fIname\fP arguments, it will display the attributes
+and values of all variables having the attributes specified by the
+additional options.
+If no other options are supplied with \fB\-p\fP, \fBdeclare\fP will display
+the attributes and values of all shell variables.  The \fB\-f\fP option
+will restrict the display to shell functions.
 The
 .B \-F
 option inhibits the display of function definitions; only the
@@ -8068,7 +8088,7 @@ table exists before trying to execute it.  If a hashed command no
 longer exists, a normal path search is performed.
 .TP 8
 .B checkjobs
-If set, bash lists the status of any stopped and running jobs before
+If set, \fBbash\fP lists the status of any stopped and running jobs before
 exiting an interactive shell.  If any jobs are running, this causes
 the exit to be deferred until a second exit is attempted without an
 intervening command (see \fBJOB CONTROL\fP above).  The shell always
@@ -8090,6 +8110,12 @@ attempts to save all lines of a multiple-line
 command in the same history entry.  This allows
 easy re-editing of multi-line commands.
 .TP 8
+.B compat31
+If set,
+.B bash
+changes its behavior to that of version 3.1 with respect to quoted
+arguments to the conditional command's =~ operator.
+.TP 8
 .B dotglob
 If set, 
 .B bash
@@ -8603,7 +8629,7 @@ option suppresses shell function lookup, as with the \fBcommand\fP builtin.
 returns true if any of the arguments are found, false if
 none are found.
 .TP
-\fBulimit\fP [\fB\-SHacdefilmnpqrstuvx\fP [\fIlimit\fP]]
+\fBulimit\fP [\fB\-HSTabcdefilmnpqrstuvx\fP [\fIlimit\fP]]
 Provides control over the resources available to the shell and to
 processes started by it, on systems that allow such control.
 The \fB\-H\fP and \fB\-S\fP options specify that the hard or soft limit is
@@ -8634,6 +8660,9 @@ Other options are interpreted as follows:
 .B \-a
 All current limits are reported
 .TP
+.B \-b
+The maximum socket buffer size
+.TP
 .B \-c
 The maximum size of core files created
 .TP
@@ -8682,6 +8711,9 @@ The maximum amount of virtual memory available to the shell
 .TP
 .B \-x
 The maximum number of file locks
+.TP
+.B \-T
+The maximum number of threads
 .PD
 .PP
 If
@@ -8697,7 +8729,9 @@ which is in seconds,
 .BR \-p ,
 which is in units of 512-byte blocks,
 and
-.B \-n
+.BR \-T ,
+.BR \-b ,
+.BR \-n ,
 and
 .BR \-u ,
 which are unscaled values.
index 9b4e019428fb56d8f7acee4c47dae593353ccee1..a7571020c5614dd4ac25fb3a0181e569f751b38b 100644 (file)
@@ -681,8 +681,11 @@ Commands separated by a @samp{;} are executed sequentially; the shell
 waits for each command to terminate in turn.  The return status is the
 exit status of the last command executed.
 
-The control operators @samp{&&} and @samp{||}
-denote @sc{and} lists and @sc{or} lists, respectively.
+@sc{and} and @sc{or} lists are sequences of one or more pipelines
+separated by the control operators @samp{&&} and @samp{||},
+respectively.  @sc{and} and @sc{or} lists are executed with left
+associativity.
+
 An @sc{and} list has the form
 @example
 @var{command1} && @var{command2}
@@ -3262,7 +3265,16 @@ are given, then display the values of variables instead.
 
 The @option{-p} option will display the attributes and values of each
 @var{name}.
-When @option{-p} is used, additional options are ignored.
+When @option{-p} is used with @var{name} arguments, additional options
+are ignored.
+
+When @option{-p} is supplied without @var{name} arguments, @code{declare}
+will display the attributes and values of all variables having the
+attributes specified by the additional options.
+If no other options are supplied with @option{-p}, @code{declare} will
+display the attributes and values of all shell variables.  The @option{-f}
+option will restrict the display to shell functions.
+
 The @option{-F} option inhibits the display of function definitions;
 only the function name and attributes are printed.
 If the @code{extdebug} shell option is enabled using @code{shopt}
@@ -3596,7 +3608,7 @@ builtin command.
 @item ulimit
 @btindex ulimit
 @example
-ulimit [-acdefilmnpqrstuvxSH] [@var{limit}]
+ulimit [-abcdefilmnpqrstuvxHST] [@var{limit}]
 @end example
 @code{ulimit} provides control over the resources available to processes
 started by the shell, on systems that allow such control.  If an
@@ -3611,6 +3623,9 @@ Change and report the hard limit associated with a resource.
 @item -a
 All current limits are reported.
 
+@item -b
+The maximum socket buffer size.
+
 @item -c
 The maximum size of core files created.
 
@@ -3659,6 +3674,9 @@ The maximum amount of virtual memory available to the process.
 @item -x
 The maximum number of file locks.
 
+@item -T
+The maximum number of threads.
+
 @end table
 
 If @var{limit} is given, it is the new value of the specified resource;
@@ -7049,8 +7067,9 @@ the @code{bind} builtin.
 
 @item
 Bash provides a programmable word completion mechanism
-(@pxref{Programmable Completion}), and two builtin commands,
-@code{complete} and @code{compgen}, to manipulate it.
+(@pxref{Programmable Completion}), and builtin commands
+@code{complete}, @code{compgen}, and @code{compopt}, to
+manipulate it.
 
 @item
 Bash has command history (@pxref{Bash History Facilities}) and the
index a95a33b1235ec48886159ee4e8b4259fafe9ff95..e58e670697c5c7f8ffc46e2c78e7926c489c56b4 100644 (file)
@@ -681,8 +681,11 @@ Commands separated by a @samp{;} are executed sequentially; the shell
 waits for each command to terminate in turn.  The return status is the
 exit status of the last command executed.
 
-The control operators @samp{&&} and @samp{||}
-denote @sc{and} lists and @sc{or} lists, respectively.
+@sc{and} and @sc{or} lists are sequences of one or more pipelines
+separated by the control operators @samp{&&} and @samp{||},
+respectively.  @sc{and} and @sc{or} lists are executed with left
+associativity.
+
 An @sc{and} list has the form
 @example
 @var{command1} && @var{command2}
@@ -3262,7 +3265,16 @@ are given, then display the values of variables instead.
 
 The @option{-p} option will display the attributes and values of each
 @var{name}.
-When @option{-p} is used, additional options are ignored.
+When @option{-p} is used with @var{name} arguments, additional options
+are ignored.
+
+When @option{-p} is supplied without @var{name} arguments, @code{declare}
+will display the attributes and values of all variables having the
+attributes specified by the additional options.
+If no other options are supplied with @option{-p}, @code{declare} will
+display the attributes and values of all shell variables.  The @option{-f}
+option will restrict the display to shell functions.
+
 The @option{-F} option inhibits the display of function definitions;
 only the function name and attributes are printed.
 If the @code{extdebug} shell option is enabled using @code{shopt}
@@ -3596,7 +3608,7 @@ builtin command.
 @item ulimit
 @btindex ulimit
 @example
-ulimit [-acdefilmnpqrstuvxSH] [@var{limit}]
+ulimit [-abcdefilmnpqrstuvxHST] [@var{limit}]
 @end example
 @code{ulimit} provides control over the resources available to processes
 started by the shell, on systems that allow such control.  If an
@@ -3611,6 +3623,9 @@ Change and report the hard limit associated with a resource.
 @item -a
 All current limits are reported.
 
+@item -b
+The maximum socket buffer size.
+
 @item -c
 The maximum size of core files created.
 
@@ -3659,6 +3674,9 @@ The maximum amount of virtual memory available to the process.
 @item -x
 The maximum number of file locks.
 
+@item -T
+The maximum number of threads.
+
 @end table
 
 If @var{limit} is given, it is the new value of the specified resource;
@@ -4060,6 +4078,11 @@ attempts to save all lines of a multiple-line
 command in the same history entry.  This allows
 easy re-editing of multi-line commands.
 
+@item compat31
+If set, Bash
+changes its behavior to that of version 3.1 with respect to quoted
+arguments to the conditional command's =~ operator.
+
 @item dotglob
 If set, Bash includes filenames beginning with a `.' in
 the results of filename expansion.
index 2a7c69852cd4b7f60aac54f454861c919f209266..02791e7e0b333c83ea2705e7967aa1f9d12ca420 100644 (file)
@@ -2,9 +2,9 @@
 Copyright (C) 1988-2008 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Fri Feb 22 21:45:01 EST 2008
+@set LASTCHANGE Thu Mar 27 22:19:20 EDT 2008
 
 @set EDITION 3.2
 @set VERSION 3.2
-@set UPDATED 22 February 2008
-@set UPDATED-MONTH February 2008
+@set UPDATED 27 March 2008
+@set UPDATED-MONTH March 2008
index f8155d4a69a2c86cb89e179ec3d591ac8e151598..f1722f7807df7c78c3c4b43757d69ee5028f025b 100644 (file)
@@ -1,10 +1,10 @@
 @ignore
-Copyright (C) 1988-2007 Free Software Foundation, Inc.
+Copyright (C) 1988-2008 Free Software Foundation, Inc.
 @end ignore
 
-@set LASTCHANGE Fri Dec 14 23:10:36 EST 2007
+@set LASTCHANGE Fri Feb 22 21:45:01 EST 2008
 
 @set EDITION 3.2
 @set VERSION 3.2
-@set UPDATED 14 December 2007
-@set UPDATED-MONTH December 2007
+@set UPDATED 27 March 2008
+@set UPDATED-MONTH March 2008
index 88a107b95726ca87257c7b64c833054ee7ea955b..d40e39d2d7b75d26c75256d408497d30dbe9864d 100644 (file)
@@ -115,13 +115,13 @@ rl_callback_read_char ()
       abort ();
     }
 
-  memcpy ((void *)olevel, (void *)readline_top_level, sizeof (procenv_t));
-  jcode = setjmp (readline_top_level);
+  memcpy ((void *)olevel, (void *)_rl_top_level, sizeof (procenv_t));
+  jcode = setjmp (_rl_top_level);
   if (jcode)
     {
       (*rl_redisplay_function) ();
       _rl_want_redisplay = 0;
-      memcpy ((void *)readline_top_level, (void *)olevel, sizeof (procenv_t));
+      memcpy ((void *)_rl_top_level, (void *)olevel, sizeof (procenv_t));
       return;
     }
 
index b4d957283111f6421cfe8511281cbb923db8bd2a..24dbe839a03132fd39f3ca646e9ad70748f17171 100644 (file)
@@ -506,7 +506,7 @@ rl_redisplay ()
   int _rl_wrapped_multicolumn = 0;
 #endif
 
-  if (readline_echoing_p == 0)
+  if (_rl_echoing_p == 0)
     return;
 
   /* Block keyboard interrupts because this function manipulates global
@@ -2464,7 +2464,7 @@ _rl_redisplay_after_sigwinch ()
 void
 _rl_clean_up_for_exit ()
 {
-  if (readline_echoing_p)
+  if (_rl_echoing_p)
     {
       _rl_move_vert (_rl_vis_botlin);
       _rl_vis_botlin = 0;
index 886f837198f3c160c9374e02b31fb6800fe6788b..00a28ca64bd0b24f2dd52f63ca1d23eaf09d15a4 100644 (file)
@@ -1574,7 +1574,7 @@ the matches.
 
 Any function specified with @option{-F} is invoked first.
 The function may use any of the shell facilities, including the
-@code{compgen} builtin described below
+@code{compgen} and @code{compopt} builtins described below
 (@pxref{Programmable Completion Builtins}), to generate the matches.
 It must put the possible completions in the @env{COMPREPLY} array
 variable.
@@ -1847,4 +1847,22 @@ a @var{name} for which no specification exists, or
 an error occurs adding a completion specification.
 
 @end table
+
+@item compopt
+@btindex compopt
+@example
+@code{compopt} [-o @var{option}] [+o @var{option}] [@var{name}]
+@end example
+Modify completion options for each @var{name} according to the
+@var{option}s, or for the currently-execution completion if no @var{name}s
+are supplied.
+If no @var{option}s are given, display the completion options for each
+@var{name} or the current completion.
+The possible values of @var{option} are those valid for the @code{complete}
+builtin described above.
+
+The return value is true unless an invalid option is supplied, an attempt
+is made to modify the options for a @var{name} for which no completion
+specification exists, or an output error occurs.
+
 @end ifset
index 8851e1b335e89ce2611d3fe1762156418af899ba..886f837198f3c160c9374e02b31fb6800fe6788b 100644 (file)
@@ -1,7 +1,6 @@
 @comment %**start of header (This is for running Texinfo on a region.)
 @setfilename rluser.info
 @comment %**end of header (This is for running Texinfo on a region.)
-@setchapternewpage odd
 
 @ignore
 This file documents the end user interface to the GNU command line
index a31b092bf222ceedd14a252954937adb9e29b535..30a3ec708e878cf1b1f9a00c0ca61643feff6bd7 100644 (file)
@@ -163,7 +163,7 @@ int rl_done;
 rl_command_func_t *rl_last_func = (rl_command_func_t *)NULL;
 
 /* Top level environment for readline_internal (). */
-procenv_t readline_top_level;
+procenv_t _rl_top_level;
 
 /* The streams we interact with. */
 FILE *_rl_in_stream, *_rl_out_stream;
@@ -176,7 +176,7 @@ FILE *rl_outstream = (FILE *)NULL;
    set to 1 if there is a controlling terminal, we can get its attributes,
    and the attributes include `echo'.  Look at rltty.c:prepare_terminal_settings
    for the code that sets it. */
-int readline_echoing_p = 0;
+int _rl_echoing_p = 0;
 
 /* Current prompt. */
 char *rl_prompt = (char *)NULL;
@@ -371,7 +371,7 @@ readline_internal_setup ()
   /* If we're not echoing, we still want to at least print a prompt, because
      rl_redisplay will not do it for us.  If the calling application has a
      custom redisplay function, though, let that function handle it. */
-  if (readline_echoing_p == 0 && rl_redisplay_function == rl_redisplay)
+  if (_rl_echoing_p == 0 && rl_redisplay_function == rl_redisplay)
     {
       if (rl_prompt && rl_already_prompted == 0)
        {
@@ -484,7 +484,7 @@ readline_internal_charloop ()
 #endif
       lk = _rl_last_command_was_kill;
 
-      code = setjmp (readline_top_level);
+      code = setjmp (_rl_top_level);
 
       if (code)
        {
@@ -492,7 +492,7 @@ readline_internal_charloop ()
          _rl_want_redisplay = 0;
          /* If we get here, we're not being called from something dispatched
             from _rl_callback_read_char(), which sets up its own value of
-            readline_top_level (saving and restoring the old, of course), so
+            _rl_top_level (saving and restoring the old, of course), so
             we can just return here. */
          if (RL_ISSTATE (RL_STATE_CALLBACK))
            return (0);
index 1e26dce1d06d3aac7bb4c11383cc3c840d782d2b..9275cddf12bfc10b3a7ce43c2507fab866043eb9 100644 (file)
@@ -149,12 +149,9 @@ extern int rl_visible_stats;
 extern int rl_line_buffer_len;
 extern int rl_arg_sign;
 extern int rl_visible_prompt_length;
-extern int readline_echoing_p;
 extern int rl_key_sequence_length;
 extern int rl_byte_oriented;
 
-extern _rl_keyseq_cxt *_rl_kscxt;
-
 /* display.c */
 extern int rl_display_fixed;
 
@@ -400,6 +397,7 @@ extern int _rl_history_saved_point;
 extern _rl_arg_cxt _rl_argcxt;
 
 /* readline.c */
+extern int _rl_echoing_p;
 extern int _rl_horizontal_scroll_mode;
 extern int _rl_mark_modified_lines;
 extern int _rl_bell_preference;
@@ -415,7 +413,8 @@ extern FILE *_rl_in_stream;
 extern FILE *_rl_out_stream;
 extern int _rl_last_command_was_kill;
 extern int _rl_eof_char;
-extern procenv_t readline_top_level;
+extern procenv_t _rl_top_level;
+extern _rl_keyseq_cxt *_rl_kscxt;
 
 /* search.c */
 extern _rl_search_cxt *_rl_nscxt;
index f2120cb1ad8c6bfbb376c6f951801528699bfefa..f6b41bb3fbe4a00b5f7b85d57aa14f858a44cc99 100644 (file)
@@ -201,7 +201,7 @@ set_tty_settings (tty, tiop)
       ioctl (tty, TIOCSETN, &(tiop->sgttyb));
       tiop->flags &= ~SGTTY_SET;
     }
-  readline_echoing_p = 1;
+  _rl_echoing_p = 1;
 
 #if defined (TIOCLSET)
   if (tiop->flags & LFLAG_SET)
@@ -235,7 +235,7 @@ prepare_terminal_settings (meta_flag, oldtio, tiop)
      int meta_flag;
      TIOTYPE oldtio, *tiop;
 {
-  readline_echoing_p = (oldtio.sgttyb.sg_flags & ECHO);
+  _rl_echoing_p = (oldtio.sgttyb.sg_flags & ECHO);
 
   /* Copy the original settings to the structure we're going to use for
      our settings. */
@@ -513,7 +513,7 @@ prepare_terminal_settings (meta_flag, oldtio, tiop)
      int meta_flag;
      TIOTYPE oldtio, *tiop;
 {
-  readline_echoing_p = (oldtio.c_lflag & ECHO);
+  _rl_echoing_p = (oldtio.c_lflag & ECHO);
 
   tiop->c_lflag &= ~(ICANON | ECHO);
 
@@ -576,7 +576,7 @@ void
 rl_prep_terminal (meta_flag)
      int meta_flag;
 {
-  readline_echoing_p = 1;
+  _rl_echoing_p = 1;
 }
 
 void
@@ -609,7 +609,7 @@ rl_prep_terminal (meta_flag)
 #else
       if (errno == ENOTTY || errno == EINVAL)
 #endif
-       readline_echoing_p = 1;         /* XXX */
+       _rl_echoing_p = 1;              /* XXX */
 
       _rl_release_sigint ();
       return;
index 930882892a19d15d50ec768017656c8ffd1dc867..fb1495d141adcc49d4a30da4bc1bf97839f1614e 100644 (file)
@@ -350,7 +350,7 @@ rl_reset_screen_size ()
 void
 rl_resize_terminal ()
 {
-  if (readline_echoing_p)
+  if (_rl_echoing_p)
     {
       _rl_get_screen_size (fileno (rl_instream), 1);
       if (CUSTOM_REDISPLAY_FUNC ())
@@ -653,7 +653,7 @@ rl_crlf ()
 int
 rl_ding ()
 {
-  if (readline_echoing_p)
+  if (_rl_echoing_p)
     {
       switch (_rl_bell_preference)
         {
index 502925855ff52406b03d5cca354b645649aa7329..c8521dceaa7a3777a69e567a9e0799314b65ffa5 100644 (file)
@@ -949,7 +949,7 @@ rl_newline (count, key)
   if (rl_erase_empty_line && rl_point == 0 && rl_end == 0)
     return 0;
 
-  if (readline_echoing_p)
+  if (_rl_echoing_p)
     _rl_update_final ();
   return 0;
 }
index 922f038aeb553b9cb0bd4401275868a82261ce46..de225c0f388bbcbe890f8be82547666fd2d3add2 100644 (file)
@@ -109,7 +109,7 @@ _rl_abort_internal ()
     _rl_pop_executing_macro ();
 
   rl_last_func = (rl_command_func_t *)NULL;
-  longjmp (readline_top_level, 1);
+  longjmp (_rl_top_level, 1);
   return (0);
 }
 
index f40a6ae5f82b9a00d9f57488f5447d1a84a49b4c..7d715b0a0380c80eac48b1806b7a076166b6250e 100644 (file)
@@ -1,7 +1,7 @@
 /* pcomplete.c - functions to generate lists of matches for programmable
                 completion. */
 
-/* Copyright (C) 1999-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -164,7 +164,8 @@ ITEMLIST it_stopped = { LIST_DYNAMIC, it_init_stopped, (STRINGLIST *)0 };
 ITEMLIST it_users = { LIST_DYNAMIC };          /* unused */
 ITEMLIST it_variables = { LIST_DYNAMIC, it_init_variables, (STRINGLIST *)0 };
 
-COMPSPEC *curcs;
+COMPSPEC *pcomp_curcs;
+const char *pcomp_curcmd;
 
 #ifdef DEBUG
 /* Debugging code */
@@ -1380,7 +1381,7 @@ pcomp_set_compspec_options (cs, flags, set_or_unset)
      COMPSPEC *cs;
      int flags, set_or_unset;
 {
-  if (cs == 0 || (cs = curcs) == 0)
+  if (cs == 0 && ((cs = pcomp_curcs) == 0))
     return;
   if (set_or_unset)
     cs->options |= flags;
@@ -1400,6 +1401,7 @@ programmable_completions (cmd, word, start, end, foundp)
   COMPSPEC *cs, *oldcs;
   STRINGLIST *ret;
   char **rmatches, *t;
+  const char *oldcmd;
 
   /* We look at the basename of CMD if the full command does not have
      an associated COMPSPEC. */
@@ -1419,8 +1421,11 @@ programmable_completions (cmd, word, start, end, foundp)
 
   cs = compspec_copy (cs);
 
-  oldcs = curcs;
-  curcs = cs;
+  oldcs = pcomp_curcs;
+  oldcmd = pcomp_curcmd;
+
+  pcomp_curcs = cs;
+  pcomp_curcmd = cmd;
 
   /* Signal the caller that we found a COMPSPEC for this command, and pass
      back any meta-options associated with the compspec. */
@@ -1429,7 +1434,9 @@ programmable_completions (cmd, word, start, end, foundp)
 
   ret = gen_compspec_completions (cs, cmd, word, start, end);
 
-  curcs = oldcs;
+  pcomp_curcs = oldcs;
+  pcomp_curcmd = oldcmd;
+
   compspec_dispose (cs);
 
   if (ret)
index 80766bfe290e737e98ce3e1ce723af18f357c40a..0bc317f6891e74232c30d0a6328b59c7e5ec481e 100644 (file)
@@ -1,7 +1,7 @@
 /* pcomplete.c - functions to generate lists of matches for programmable
                 completion. */
 
-/* Copyright (C) 1999-2005 Free Software Foundation, Inc.
+/* Copyright (C) 1999-2008 Free Software Foundation, Inc.
 
    This file is part of GNU Bash, the Bourne Again SHell.
 
@@ -1376,15 +1376,16 @@ pcomp_set_readline_variables (flags, nval)
 /* Set or unset FLAGS in the options word of the current compspec.
    SET_OR_UNSET is 1 for setting, 0 for unsetting. */
 void
-pcomp_set_compspec_options (flags, set_or_unset)
+pcomp_set_compspec_options (cs, flags, set_or_unset)
+     COMPSPEC *cs;
      int flags, set_or_unset;
 {
-  if (curcs == 0)
+  if (cs == 0 && ((cs = curcs) == 0))
     return;
   if (set_or_unset)
-    curcs->options |= flags;
+    cs->options |= flags;
   else
-    curcs->options &= ~flags;
+    cs->options &= ~flags;
 }
 
 /* The driver function for the programmable completion code.  Returns a list
index 1bbb1d211249b3619c0cc44f26262b989f691ed9..f1dfcc01731c56582559e6fb7beaf846ba3eff30 100644 (file)
@@ -124,7 +124,8 @@ extern ITEMLIST it_stopped;
 extern ITEMLIST it_users;
 extern ITEMLIST it_variables;
 
-extern COMPSPEC *curcs;
+extern COMPSPEC *pcomp_curcs;
+extern const char *pcomp_curcmd;
 
 /* Functions from pcomplib.c */
 extern COMPSPEC *compspec_create __P((void));
index 3831180488e3234837ae1a20355260b8f71118b4..1bbb1d211249b3619c0cc44f26262b989f691ed9 100644 (file)
@@ -153,5 +153,5 @@ extern STRINGLIST *gen_compspec_completions __P((COMPSPEC *, const char *, const
 extern char **programmable_completions __P((const char *, const char *, int, int, int *));
 
 extern void pcomp_set_readline_variables __P((int, int));
-extern void pcomp_set_compspec_options __P((int, int));
+extern void pcomp_set_compspec_options __P((COMPSPEC *, int, int));
 #endif /* _PCOMPLETE_H_ */
index 72ec06a2c1fd8dde92acea5e8ac773e35f1d061b..3efcf32d68e9722024b6ca9d67f9e81b2aa5ac04 100755 (executable)
@@ -1,4 +1,4 @@
-BUILD_DIR=/usr/local/build/bash/bash-current
+BUILD_DIR=/usr/local/build/chet/bash/bash-current
 THIS_SH=$BUILD_DIR/bash
 PATH=$PATH:$BUILD_DIR
 
index 00e6ca27287e710f88fd00f297df68571bd71a7a..cc62174099686a67a479c598f090f1e1a64bbf91 100644 (file)
@@ -109,6 +109,8 @@ typedef struct _vlist {
 #define att_assoc      0x0000040       /* variable is an associative array */
 #define att_trace      0x0000080       /* function is traced with DEBUG trap */
 
+#define user_attrs     (att_exported|att_readonly|att_integer|att_local|att_trace)
+
 #define attmask_user   0x0000fff
 
 /* Internal attributes used for bookkeeping */
diff --git a/variables.h~ b/variables.h~
new file mode 100644 (file)
index 0000000..1ce9cea
--- /dev/null
@@ -0,0 +1,367 @@
+/* variables.h -- data structures for shell variables. */
+
+/* Copyright (C) 1987-2005 Free Software Foundation, Inc.
+
+   This file is part of GNU Bash, the Bourne Again SHell.
+
+   Bash is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   Bash is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with Bash; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#if !defined (_VARIABLES_H_)
+#define _VARIABLES_H_
+
+#include "stdc.h"
+#include "array.h"
+
+/* Shell variables and functions are stored in hash tables. */
+#include "hashlib.h"
+
+#include "conftypes.h"
+
+/* A variable context. */
+typedef struct var_context {
+  char *name;          /* empty or NULL means global context */
+  int scope;           /* 0 means global context */
+  int flags;
+  struct var_context *up;      /* previous function calls */
+  struct var_context *down;    /* down towards global context */
+  HASH_TABLE *table;           /* variables at this scope */
+} VAR_CONTEXT;
+
+/* Flags for var_context->flags */
+#define VC_HASLOCAL    0x01
+#define VC_HASTMPVAR   0x02
+#define VC_FUNCENV     0x04    /* also function if name != NULL */
+#define VC_BLTNENV     0x08    /* builtin_env */
+#define VC_TEMPENV     0x10    /* temporary_env */
+
+#define VC_TEMPFLAGS   (VC_FUNCENV|VC_BLTNENV|VC_TEMPENV)
+
+/* Accessing macros */
+#define vc_isfuncenv(vc)       (((vc)->flags & VC_FUNCENV) != 0)
+#define vc_isbltnenv(vc)       (((vc)->flags & VC_BLTNENV) != 0)
+#define vc_istempenv(vc)       (((vc)->flags & (VC_TEMPFLAGS)) == VC_TEMPENV)
+
+#define vc_istempscope(vc)     (((vc)->flags & (VC_TEMPENV|VC_BLTNENV)) != 0)
+
+#define vc_haslocals(vc)       (((vc)->flags & VC_HASLOCAL) != 0)
+#define vc_hastmpvars(vc)      (((vc)->flags & VC_HASTMPVAR) != 0)
+
+/* What a shell variable looks like. */
+
+typedef struct variable *sh_var_value_func_t __P((struct variable *));
+typedef struct variable *sh_var_assign_func_t __P((struct variable *, char *, arrayind_t));
+
+/* For the future */
+union _value {
+  char *s;                     /* string value */
+  intmax_t i;                  /* int value */
+  COMMAND *f;                  /* function */
+  ARRAY *a;                    /* array */
+  HASH_TABLE *h;               /* associative array */
+  double d;                    /* floating point number */
+#if defined (HAVE_LONG_DOUBLE)
+  long double ld;              /* long double */
+#endif
+  struct variable *v;          /* possible indirect variable use */
+  void *opaque;                        /* opaque data for future use */
+};
+
+typedef struct variable {
+  char *name;                  /* Symbol that the user types. */
+  char *value;                 /* Value that is returned. */
+  char *exportstr;             /* String for the environment. */
+  sh_var_value_func_t *dynamic_value;  /* Function called to return a `dynamic'
+                                  value for a variable, like $SECONDS
+                                  or $RANDOM. */
+  sh_var_assign_func_t *assign_func; /* Function called when this `special
+                                  variable' is assigned a value in
+                                  bind_variable. */
+  int attributes;              /* export, readonly, array, invisible... */
+  int context;                 /* Which context this variable belongs to. */
+} SHELL_VAR;
+
+typedef struct _vlist {
+  SHELL_VAR **list;
+  int list_size;       /* allocated size */
+  int list_len;                /* current number of entries */
+} VARLIST;
+
+/* The various attributes that a given variable can have. */
+/* First, the user-visible attributes */
+#define att_exported   0x0000001       /* export to environment */
+#define att_readonly   0x0000002       /* cannot change */
+#define att_array      0x0000004       /* value is an array */
+#define att_function   0x0000008       /* value is a function */
+#define att_integer    0x0000010       /* internal representation is int */
+#define att_local      0x0000020       /* variable is local to a function */
+#define att_assoc      0x0000040       /* variable is an associative array */
+#define att_trace      0x0000080       /* function is traced with DEBUG trap */
+
+#define user_attrs     (att_exported|att_readonly|att_array|att_integer|att_local|att_assoc|att_trace)
+
+#define attmask_user   0x0000fff
+
+/* Internal attributes used for bookkeeping */
+#define att_invisible  0x0001000       /* cannot see */
+#define att_nounset    0x0002000       /* cannot unset */
+#define att_noassign   0x0004000       /* assignment not allowed */
+#define att_imported   0x0008000       /* came from environment */
+#define att_special    0x0010000       /* requires special handling */
+
+#define        attmask_int     0x00ff000
+
+/* Internal attributes used for variable scoping. */
+#define att_tempvar    0x0100000       /* variable came from the temp environment */
+#define att_propagate  0x0200000       /* propagate to previous scope */
+
+#define attmask_scope  0x0f00000
+
+#define exported_p(var)                ((((var)->attributes) & (att_exported)))
+#define readonly_p(var)                ((((var)->attributes) & (att_readonly)))
+#define array_p(var)           ((((var)->attributes) & (att_array)))
+#define function_p(var)                ((((var)->attributes) & (att_function)))
+#define integer_p(var)         ((((var)->attributes) & (att_integer)))
+#define local_p(var)           ((((var)->attributes) & (att_local)))
+#define assoc_p(var)           ((((var)->attributes) & (att_assoc)))
+#define trace_p(var)           ((((var)->attributes) & (att_trace)))
+
+#define invisible_p(var)       ((((var)->attributes) & (att_invisible)))
+#define non_unsettable_p(var)  ((((var)->attributes) & (att_nounset)))
+#define noassign_p(var)                ((((var)->attributes) & (att_noassign)))
+#define imported_p(var)                ((((var)->attributes) & (att_imported)))
+#define specialvar_p(var)      ((((var)->attributes) & (att_special)))
+
+#define tempvar_p(var)         ((((var)->attributes) & (att_tempvar)))
+
+/* Acessing variable values: rvalues */
+#define value_cell(var)                ((var)->value)
+#define function_cell(var)     (COMMAND *)((var)->value)
+#define array_cell(var)                (ARRAY *)((var)->value)
+
+#define var_isnull(var)                ((var)->value == 0)
+#define var_isset(var)         ((var)->value != 0)
+
+/* Assigning variable values: lvalues */
+#define var_setvalue(var, str) ((var)->value = (str))
+#define var_setfunc(var, func) ((var)->value = (char *)(func))
+#define var_setarray(var, arr) ((var)->value = (char *)(arr))
+
+/* Make VAR be auto-exported. */
+#define set_auto_export(var) \
+  do { (var)->attributes |= att_exported; array_needs_making = 1; } while (0)
+
+#define SETVARATTR(var, attr, undo) \
+       ((undo == 0) ? ((var)->attributes |= (attr)) \
+                    : ((var)->attributes &= ~(attr)))
+
+#define VSETATTR(var, attr)    ((var)->attributes |= (attr))
+#define VUNSETATTR(var, attr)  ((var)->attributes &= ~(attr))
+
+#define VGETFLAGS(var)         ((var)->attributes)
+
+#define VSETFLAGS(var, flags)  ((var)->attributes = (flags))
+#define VCLRFLAGS(var)         ((var)->attributes = 0)
+
+/* Macros to perform various operations on `exportstr' member of a SHELL_VAR. */
+#define CLEAR_EXPORTSTR(var)   (var)->exportstr = (char *)NULL
+#define COPY_EXPORTSTR(var)    ((var)->exportstr) ? savestring ((var)->exportstr) : (char *)NULL
+#define SET_EXPORTSTR(var, value)  (var)->exportstr = (value)
+#define SAVE_EXPORTSTR(var, value) (var)->exportstr = (value) ? savestring (value) : (char *)NULL
+
+#define FREE_EXPORTSTR(var) \
+       do { if ((var)->exportstr) free ((var)->exportstr); } while (0)
+
+#define CACHE_IMPORTSTR(var, value) \
+       (var)->exportstr = savestring (value)
+
+#define INVALIDATE_EXPORTSTR(var) \
+       do { \
+         if ((var)->exportstr) \
+           { \
+             free ((var)->exportstr); \
+             (var)->exportstr = (char *)NULL; \
+           } \
+       } while (0)
+       
+/* Stuff for hacking variables. */
+typedef int sh_var_map_func_t __P((SHELL_VAR *));
+
+/* Where we keep the variables and functions */
+extern VAR_CONTEXT *global_variables;
+extern VAR_CONTEXT *shell_variables;
+
+extern HASH_TABLE *shell_functions;
+extern HASH_TABLE *temporary_env;
+
+extern int variable_context;
+extern char *dollar_vars[];
+extern char **export_env;
+
+extern void initialize_shell_variables __P((char **, int));
+extern SHELL_VAR *set_if_not __P((char *, char *));
+
+extern void sh_set_lines_and_columns __P((int, int));
+extern void set_pwd __P((void));
+extern void set_ppid __P((void));
+extern void make_funcname_visible __P((int));
+
+extern SHELL_VAR *var_lookup __P((const char *, VAR_CONTEXT *));
+
+extern SHELL_VAR *find_function __P((const char *));
+extern FUNCTION_DEF *find_function_def __P((const char *));
+extern SHELL_VAR *find_variable __P((const char *));
+extern SHELL_VAR *find_variable_internal __P((const char *, int));
+extern SHELL_VAR *find_tempenv_variable __P((const char *));
+extern SHELL_VAR *copy_variable __P((SHELL_VAR *));
+extern SHELL_VAR *make_local_variable __P((const char *));
+extern SHELL_VAR *bind_variable __P((const char *, char *, int));
+extern SHELL_VAR *bind_function __P((const char *, COMMAND *));
+
+extern void bind_function_def __P((const char *, FUNCTION_DEF *));
+
+extern SHELL_VAR **map_over __P((sh_var_map_func_t *, VAR_CONTEXT *));
+SHELL_VAR **map_over_funcs __P((sh_var_map_func_t *));
+     
+extern SHELL_VAR **all_shell_variables __P((void));
+extern SHELL_VAR **all_shell_functions __P((void));
+extern SHELL_VAR **all_visible_variables __P((void));
+extern SHELL_VAR **all_visible_functions __P((void));
+extern SHELL_VAR **all_exported_variables __P((void));
+extern SHELL_VAR **local_exported_variables __P((void));
+extern SHELL_VAR **all_local_variables __P((void));
+#if defined (ARRAY_VARS)
+extern SHELL_VAR **all_array_variables __P((void));
+#endif
+extern char **all_variables_matching_prefix __P((const char *));
+
+extern char **make_var_array __P((HASH_TABLE *));
+extern char **add_or_supercede_exported_var __P((char *, int));
+
+extern char *get_variable_value __P((SHELL_VAR *));
+extern char *get_string_value __P((const char *));
+extern char *sh_get_env_value __P((const char *));
+extern char *make_variable_value __P((SHELL_VAR *, char *, int));
+
+extern SHELL_VAR *bind_variable_value __P((SHELL_VAR *, char *, int));
+extern SHELL_VAR *bind_int_variable __P((char *, char *));
+extern SHELL_VAR *bind_var_to_int __P((char *, intmax_t));
+
+extern int assign_in_env __P((WORD_DESC *));
+
+extern int unbind_variable __P((const char *));
+extern int unbind_func __P((const char *));
+extern int unbind_function_def __P((const char *));
+extern int makunbound __P((const char *, VAR_CONTEXT *));
+extern int kill_local_variable __P((const char *));
+extern void delete_all_variables __P((HASH_TABLE *));
+extern void delete_all_contexts __P((VAR_CONTEXT *));
+
+extern VAR_CONTEXT *new_var_context __P((char *, int));
+extern void dispose_var_context __P((VAR_CONTEXT *));
+extern VAR_CONTEXT *push_var_context __P((char *, int, HASH_TABLE *));
+extern void pop_var_context __P((void));
+extern VAR_CONTEXT *push_scope __P((int, HASH_TABLE *));
+extern void pop_scope __P((int));
+
+extern void push_context __P((char *, int, HASH_TABLE *));
+extern void pop_context __P((void));
+extern void push_dollar_vars __P((void));
+extern void pop_dollar_vars __P((void));
+extern void dispose_saved_dollar_vars __P((void));
+
+extern void push_args __P((WORD_LIST *));
+extern void pop_args __P((void));
+
+extern void adjust_shell_level __P((int));
+extern void non_unsettable __P((char *));
+extern void dispose_variable __P((SHELL_VAR *));
+extern void dispose_used_env_vars __P((void));
+extern void dispose_function_env __P((void));
+extern void dispose_builtin_env __P((void));
+extern void merge_temporary_env __P((void));
+extern void merge_builtin_env __P((void));
+extern void kill_all_local_variables __P((void));
+
+extern void set_var_read_only __P((char *));
+extern void set_func_read_only __P((const char *));
+extern void set_var_auto_export __P((char *));
+extern void set_func_auto_export __P((const char *));
+
+extern void sort_variables __P((SHELL_VAR **));
+
+extern void maybe_make_export_env __P((void));
+extern void update_export_env_inplace __P((char *, int, char *));
+extern void put_command_name_into_env __P((char *));
+extern void put_gnu_argv_flags_into_env __P((intmax_t, char *));
+
+extern void print_var_list __P((SHELL_VAR **));
+extern void print_func_list __P((SHELL_VAR **));
+extern void print_assignment __P((SHELL_VAR *));
+extern void print_var_value __P((SHELL_VAR *, int));
+extern void print_var_function __P((SHELL_VAR *));
+
+#if defined (ARRAY_VARS)
+extern SHELL_VAR *make_new_array_variable __P((char *));
+extern SHELL_VAR *make_local_array_variable __P((char *));
+
+extern void set_pipestatus_array __P((int *, int));
+#endif
+
+extern void set_pipestatus_from_exit __P((int));
+
+/* The variable in NAME has just had its state changed.  Check to see if it
+   is one of the special ones where something special happens. */
+extern void stupidly_hack_special_variables __P((char *));
+
+extern int get_random_number __P((void));
+
+/* The `special variable' functions that get called when a particular
+   variable is set. */
+extern void sv_ifs __P((char *));
+extern void sv_path __P((char *));
+extern void sv_mail __P((char *));
+extern void sv_globignore __P((char *));
+extern void sv_ignoreeof __P((char *));
+extern void sv_strict_posix __P((char *));
+extern void sv_optind __P((char *));
+extern void sv_opterr __P((char *));
+extern void sv_locale __P((char *));
+
+#if defined (READLINE)
+extern void sv_comp_wordbreaks __P((char *));
+extern void sv_terminal __P((char *));
+extern void sv_hostfile __P((char *));
+extern void sv_winsize __P((char *));
+#endif
+
+#if defined (__CYGWIN__)
+extern void sv_home __P((char *));
+#endif
+
+#if defined (HISTORY)
+extern void sv_histsize __P((char *));
+extern void sv_histignore __P((char *));
+extern void sv_history_control __P((char *));
+#  if defined (BANG_HISTORY)
+extern void sv_histchars __P((char *));
+#  endif
+extern void sv_histtimefmt __P((char *));
+#endif /* HISTORY */
+
+#if defined (HAVE_TZSET) && defined (PROMPT_STRING_DECODE)
+extern void sv_tz __P((char *));
+#endif
+
+#endif /* !_VARIABLES_H_ */