aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk45
-rw-r--r--bashline.c8
-rw-r--r--builtins/Android.mk72
-rw-r--r--builtins/alias.c192
-rw-r--r--builtins/bind.c278
-rw-r--r--builtins/break.c102
-rw-r--r--builtins/builtext.h192
-rw-r--r--builtins/builtin.c54
-rw-r--r--builtins/builtins.c2028
-rw-r--r--builtins/caller.c118
-rw-r--r--builtins/cd.c453
-rw-r--r--builtins/colon.c24
-rw-r--r--builtins/command.c183
-rw-r--r--builtins/complete.c785
-rw-r--r--builtins/declare.c489
-rw-r--r--builtins/echo.c135
-rw-r--r--builtins/enable.c438
-rw-r--r--builtins/eval.c29
-rw-r--r--builtins/exec.c198
-rw-r--r--builtins/exit.c135
-rw-r--r--builtins/fc.c619
-rw-r--r--builtins/fg_bg.c143
-rw-r--r--builtins/getopts.c270
-rw-r--r--builtins/hash.c240
-rw-r--r--builtins/help.c345
-rw-r--r--builtins/history.c328
-rw-r--r--builtins/inlib.c46
-rw-r--r--builtins/jobs.c238
-rw-r--r--builtins/kill.c225
-rw-r--r--builtins/let.c66
-rw-r--r--builtins/mapfile.c294
-rw-r--r--builtins/pipesize.h8
-rw-r--r--builtins/printf.c1075
-rw-r--r--builtins/pushd.c674
-rw-r--r--builtins/read.c925
-rw-r--r--builtins/return.c45
-rw-r--r--builtins/set.c725
-rw-r--r--builtins/setattr.c459
-rw-r--r--builtins/shift.c72
-rw-r--r--builtins/shopt.c677
-rw-r--r--builtins/source.c144
-rw-r--r--builtins/suspend.c94
-rw-r--r--builtins/test.c53
-rw-r--r--builtins/times.c90
-rw-r--r--builtins/trap.c231
-rw-r--r--builtins/type.c356
-rw-r--r--builtins/ulimit.c710
-rw-r--r--builtins/umask.c280
-rw-r--r--builtins/wait.c138
-rw-r--r--config.h1115
-rw-r--r--lib/Android.mk2
-rw-r--r--lib/glob/Android.mk27
-rw-r--r--lib/readline/Android.mk82
-rw-r--r--lib/readline/complete.c2
-rw-r--r--lib/sh/Android.mk34
-rw-r--r--lib/tilde/Android.mk24
-rw-r--r--pathnames.h33
-rw-r--r--signames.h78
-rw-r--r--subst.c1
-rw-r--r--syntax.c269
-rw-r--r--version.h17
61 files changed, 17207 insertions, 5 deletions
diff --git a/Android.mk b/Android.mk
new file mode 100644
index 0000000..7cd200e
--- /dev/null
+++ b/Android.mk
@@ -0,0 +1,45 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ========================================================
+# bash
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ shell.c eval.c y.tab.c general.c make_cmd.c print_cmd.c \
+ dispose_cmd.c execute_cmd.c variables.c copy_cmd.c error.c \
+ expr.c flags.c jobs.c subst.c hashcmd.c hashlib.c mailcheck.c \
+ trap.c input.c unwind_prot.c pathexp.c sig.c test.c version.c \
+ alias.c array.c arrayfunc.c assoc.c braces.c bracecomp.c \
+ bashhist.c bashline.c list.c stringlib.c locale.c findcmd.c \
+ redir.c pcomplete.c pcomplib.c syntax.c xmalloc.c
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/include \
+ $(LOCAL_PATH)/lib
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H \
+ -DPROGRAM=\"bash\" \
+ -DPACKAGE=\"bash\" \
+ -DCONF_HOSTTYPE=\"arm\" \
+ -DCONF_OSTYPE=\"android-eabi\" \
+ -DCONF_MACHTYPE=\"arm-android-eabi\" \
+ -DCONF_VENDOR=\"unknown\" \
+ -DLOCALEDIR=\"/data/locale\" \
+ -DSHELL
+LOCAL_SHARED_LIBRARIES += \
+ libncurses
+LOCAL_STATIC_LIBRARIES += \
+ libbuiltins \
+ libglob \
+ libsh \
+ libtilde \
+ libhistory \
+ libreadline \
+ libclearsilverregex
+LOCAL_MODULE := bash
+LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
+include $(BUILD_EXECUTABLE)
+
+# ========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/bashline.c b/bashline.c
index 9b49d0b..174ea80 100644
--- a/bashline.c
+++ b/bashline.c
@@ -2102,9 +2102,9 @@ bash_groupname_completion_function (text, state)
const char *text;
int state;
{
-#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H)
+//#if defined (__WIN32__) || defined (__OPENNT) || !defined (HAVE_GRP_H)
return ((char *)NULL);
-#else
+/*#else
static char *gname = (char *)NULL;
static struct group *grent;
static int gnamelen;
@@ -2133,7 +2133,7 @@ bash_groupname_completion_function (text, state)
value = savestring (grent->gr_name);
return (value);
-#endif
+#endif*/
}
/* Functions to perform history and alias expansions on the current line. */
@@ -3421,7 +3421,7 @@ static int
putx(c)
int c;
{
- putc (c, rl_outstream);
+ return putc (c, rl_outstream);
}
static int
diff --git a/builtins/Android.mk b/builtins/Android.mk
new file mode 100644
index 0000000..ad04399
--- /dev/null
+++ b/builtins/Android.mk
@@ -0,0 +1,72 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ========================================================
+# libbuiltins.a
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ alias.c \
+ bashgetopt.c \
+ bind.c \
+ break.c \
+ builtin.c \
+ builtins.c \
+ caller.c \
+ cd.c \
+ colon.c \
+ command.c \
+ common.c \
+ complete.c \
+ declare.c \
+ echo.c \
+ enable.c \
+ eval.c \
+ evalfile.c \
+ evalstring.c \
+ exec.c \
+ exit.c \
+ fc.c \
+ fg_bg.c \
+ getopt.c \
+ getopts.c \
+ hash.c \
+ help.c \
+ history.c \
+ jobs.c \
+ kill.c \
+ let.c \
+ mapfile.c \
+ printf.c \
+ pushd.c \
+ read.c \
+ return.c \
+ setattr.c \
+ set.c \
+ shift.c \
+ shopt.c \
+ source.c \
+ suspend.c \
+ test.c \
+ times.c \
+ trap.c \
+ type.c \
+ ulimit.c \
+ umask.c \
+ wait.c
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../ \
+ $(LOCAL_PATH)/../include \
+ $(LOCAL_PATH)/../lib
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H \
+ -DPROGRAM=\"bash\" \
+ -DCONF_HOSTTYPE=\"arm\" \
+ -DCONF_OSTYPE=\"android-eabi\" \
+ -DCONF_MACHTYPE=\"arm-android-eabi\" \
+ -DCONF_VENDOR=\"unknown\"
+LOCAL_MODULE := libbuiltins
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/builtins/alias.c b/builtins/alias.c
new file mode 100644
index 0000000..7e56405
--- /dev/null
+++ b/builtins/alias.c
@@ -0,0 +1,192 @@
+/* alias.c, created from alias.def. */
+#line 42 "./alias.def"
+
+#include <config.h>
+
+#if defined (ALIAS)
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+# include "../bashansi.h"
+# include "../bashintl.h"
+
+# include <stdio.h>
+# include "../shell.h"
+# include "../alias.h"
+# include "common.h"
+# include "bashgetopt.h"
+
+/* Flags for print_alias */
+#define AL_REUSABLE 0x01
+
+static void print_alias __P((alias_t *, int));
+
+extern int posixly_correct;
+
+/* Hack the alias command in a Korn shell way. */
+int
+alias_builtin (list)
+ WORD_LIST *list;
+{
+ int any_failed, offset, pflag, dflags;
+ alias_t **alias_list, *t;
+ char *name, *value;
+
+ dflags = posixly_correct ? 0 : AL_REUSABLE;
+ pflag = 0;
+ reset_internal_getopt ();
+ while ((offset = internal_getopt (list, "p")) != -1)
+ {
+ switch (offset)
+ {
+ case 'p':
+ pflag = 1;
+ dflags |= AL_REUSABLE;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (list == 0 || pflag)
+ {
+ if (aliases == 0)
+ return (EXECUTION_SUCCESS);
+
+ alias_list = all_aliases ();
+
+ if (alias_list == 0)
+ return (EXECUTION_SUCCESS);
+
+ for (offset = 0; alias_list[offset]; offset++)
+ print_alias (alias_list[offset], dflags);
+
+ free (alias_list); /* XXX - Do not free the strings. */
+
+ if (list == 0)
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+
+ any_failed = 0;
+ while (list)
+ {
+ name = list->word->word;
+
+ for (offset = 0; name[offset] && name[offset] != '='; offset++)
+ ;
+
+ if (offset && name[offset] == '=')
+ {
+ name[offset] = '\0';
+ value = name + offset + 1;
+
+ if (legal_alias_name (name, 0) == 0)
+ {
+ builtin_error (_("`%s': invalid alias name"), name);
+ any_failed++;
+ }
+ else
+ add_alias (name, value);
+ }
+ else
+ {
+ t = find_alias (name);
+ if (t)
+ print_alias (t, dflags);
+ else
+ {
+ sh_notfound (name);
+ any_failed++;
+ }
+ }
+ list = list->next;
+ }
+
+ return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+#endif /* ALIAS */
+
+#line 167 "./alias.def"
+
+#if defined (ALIAS)
+/* Remove aliases named in LIST from the aliases database. */
+int
+unalias_builtin (list)
+ register WORD_LIST *list;
+{
+ register alias_t *alias;
+ int opt, aflag;
+
+ aflag = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "a")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ aflag = 1;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (aflag)
+ {
+ delete_all_aliases ();
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ aflag = 0;
+ while (list)
+ {
+ alias = find_alias (list->word->word);
+
+ if (alias)
+ remove_alias (alias->name);
+ else
+ {
+ sh_notfound (list->word->word);
+ aflag++;
+ }
+
+ list = list->next;
+ }
+
+ return (aflag ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+/* Output ALIAS in such a way as to allow it to be read back in. */
+static void
+print_alias (alias, flags)
+ alias_t *alias;
+ int flags;
+{
+ char *value;
+
+ value = sh_single_quote (alias->value);
+ if (flags & AL_REUSABLE)
+ printf ("alias ");
+ printf ("%s=%s\n", alias->name, value);
+ free (value);
+
+ fflush (stdout);
+}
+#endif /* ALIAS */
diff --git a/builtins/bind.c b/builtins/bind.c
new file mode 100644
index 0000000..60a3a0b
--- /dev/null
+++ b/builtins/bind.c
@@ -0,0 +1,278 @@
+/* bind.c, created from bind.def. */
+#line 22 "./bind.def"
+
+#include <config.h>
+
+#line 61 "./bind.def"
+
+#if defined (READLINE)
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../bashline.h"
+#include "bashgetopt.h"
+#include "common.h"
+
+static int query_bindings __P((char *));
+static int unbind_command __P((char *));
+
+extern int no_line_editing;
+
+#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0)
+
+#define LFLAG 0x0001
+#define PFLAG 0x0002
+#define FFLAG 0x0004
+#define VFLAG 0x0008
+#define QFLAG 0x0010
+#define MFLAG 0x0020
+#define RFLAG 0x0040
+#define PPFLAG 0x0080
+#define VVFLAG 0x0100
+#define SFLAG 0x0200
+#define SSFLAG 0x0400
+#define UFLAG 0x0800
+#define XFLAG 0x1000
+
+int
+bind_builtin (list)
+ WORD_LIST *list;
+{
+ int return_code;
+ Keymap kmap, saved_keymap;
+ int flags, opt;
+ char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq;
+
+ if (no_line_editing)
+ {
+#if 0
+ builtin_error (_("line editing not enabled"));
+ return (EXECUTION_FAILURE);
+#else
+ builtin_warning (_("line editing not enabled"));
+#endif
+ }
+
+ kmap = saved_keymap = (Keymap) NULL;
+ flags = 0;
+ initfile = map_name = fun_name = unbind_name = remove_seq = (char *)NULL;
+ return_code = EXECUTION_SUCCESS;
+
+ if (bash_readline_initialized == 0)
+ initialize_readline ();
+
+ begin_unwind_frame ("bind_builtin");
+ unwind_protect_var (rl_outstream);
+
+ rl_outstream = stdout;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "lvpVPsSf:q:u:m:r:x:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'l':
+ flags |= LFLAG;
+ break;
+ case 'v':
+ flags |= VFLAG;
+ break;
+ case 'p':
+ flags |= PFLAG;
+ break;
+ case 'f':
+ flags |= FFLAG;
+ initfile = list_optarg;
+ break;
+ case 'm':
+ flags |= MFLAG;
+ map_name = list_optarg;
+ break;
+ case 'q':
+ flags |= QFLAG;
+ fun_name = list_optarg;
+ break;
+ case 'u':
+ flags |= UFLAG;
+ unbind_name = list_optarg;
+ break;
+ case 'r':
+ flags |= RFLAG;
+ remove_seq = list_optarg;
+ break;
+ case 'V':
+ flags |= VVFLAG;
+ break;
+ case 'P':
+ flags |= PPFLAG;
+ break;
+ case 's':
+ flags |= SFLAG;
+ break;
+ case 'S':
+ flags |= SSFLAG;
+ break;
+ case 'x':
+ flags |= XFLAG;
+ cmd_seq = list_optarg;
+ break;
+ default:
+ builtin_usage ();
+ BIND_RETURN (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ /* First, see if we need to install a special keymap for this
+ command. Then start on the arguments. */
+
+ if ((flags & MFLAG) && map_name)
+ {
+ kmap = rl_get_keymap_by_name (map_name);
+ if (!kmap)
+ {
+ builtin_error (_("`%s': invalid keymap name"), map_name);
+ BIND_RETURN (EXECUTION_FAILURE);
+ }
+ }
+
+ if (kmap)
+ {
+ saved_keymap = rl_get_keymap ();
+ rl_set_keymap (kmap);
+ }
+
+ /* XXX - we need to add exclusive use tests here. It doesn't make sense
+ to use some of these options together. */
+ /* Now hack the option arguments */
+ if (flags & LFLAG)
+ rl_list_funmap_names ();
+
+ if (flags & PFLAG)
+ rl_function_dumper (1);
+
+ if (flags & PPFLAG)
+ rl_function_dumper (0);
+
+ if (flags & SFLAG)
+ rl_macro_dumper (1);
+
+ if (flags & SSFLAG)
+ rl_macro_dumper (0);
+
+ if (flags & VFLAG)
+ rl_variable_dumper (1);
+
+ if (flags & VVFLAG)
+ rl_variable_dumper (0);
+
+ if ((flags & FFLAG) && initfile)
+ {
+ if (rl_read_init_file (initfile) != 0)
+ {
+ builtin_error (_("%s: cannot read: %s"), initfile, strerror (errno));
+ BIND_RETURN (EXECUTION_FAILURE);
+ }
+ }
+
+ if ((flags & QFLAG) && fun_name)
+ return_code = query_bindings (fun_name);
+
+ if ((flags & UFLAG) && unbind_name)
+ return_code = unbind_command (unbind_name);
+
+ if ((flags & RFLAG) && remove_seq)
+ {
+ if (rl_bind_keyseq (remove_seq, (rl_command_func_t *)NULL) != 0)
+ {
+ builtin_error (_("`%s': cannot unbind"), remove_seq);
+ BIND_RETURN (EXECUTION_FAILURE);
+ }
+ }
+
+ if (flags & XFLAG)
+ return_code = bind_keyseq_to_unix_command (cmd_seq);
+
+ /* Process the rest of the arguments as binding specifications. */
+ while (list)
+ {
+ rl_parse_and_bind (list->word->word);
+ list = list->next;
+ }
+
+ bind_exit:
+ if (saved_keymap)
+ rl_set_keymap (saved_keymap);
+
+ run_unwind_frame ("bind_builtin");
+
+ return (sh_chkwrite (return_code));
+}
+
+static int
+query_bindings (name)
+ char *name;
+{
+ rl_command_func_t *function;
+ char **keyseqs;
+ int j;
+
+ function = rl_named_function (name);
+ if (function == 0)
+ {
+ builtin_error (_("`%s': unknown function name"), name);
+ return EXECUTION_FAILURE;
+ }
+
+ keyseqs = rl_invoking_keyseqs (function);
+
+ if (!keyseqs)
+ {
+ printf (_("%s is not bound to any keys.\n"), name);
+ return EXECUTION_FAILURE;
+ }
+
+ printf (_("%s can be invoked via "), name);
+ for (j = 0; j < 5 && keyseqs[j]; j++)
+ printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n");
+ if (keyseqs[j])
+ printf ("...\n");
+ strvec_dispose (keyseqs);
+ return EXECUTION_SUCCESS;
+}
+
+static int
+unbind_command (name)
+ char *name;
+{
+ rl_command_func_t *function;
+
+ function = rl_named_function (name);
+ if (function == 0)
+ {
+ builtin_error (_("`%s': unknown function name"), name);
+ return EXECUTION_FAILURE;
+ }
+
+ rl_unbind_function_in_map (function, rl_get_keymap ());
+ return EXECUTION_SUCCESS;
+}
+#endif /* READLINE */
diff --git a/builtins/break.c b/builtins/break.c
new file mode 100644
index 0000000..b4b0569
--- /dev/null
+++ b/builtins/break.c
@@ -0,0 +1,102 @@
+/* break.c, created from break.def. */
+#line 22 "./break.def"
+
+#line 34 "./break.def"
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+
+extern char *this_command_name;
+extern int posixly_correct;
+
+static int check_loop_level __P((void));
+
+/* The depth of while's and until's. */
+int loop_level = 0;
+
+/* Non-zero when a "break" instruction is encountered. */
+int breaking = 0;
+
+/* Non-zero when we have encountered a continue instruction. */
+int continuing = 0;
+
+/* Set up to break x levels, where x defaults to 1, but can be specified
+ as the first argument. */
+int
+break_builtin (list)
+ WORD_LIST *list;
+{
+ intmax_t newbreak;
+
+ if (check_loop_level () == 0)
+ return (EXECUTION_SUCCESS);
+
+ (void)get_numeric_arg (list, 1, &newbreak);
+
+ if (newbreak <= 0)
+ {
+ sh_erange (list->word->word, _("loop count"));
+ breaking = loop_level;
+ return (EXECUTION_FAILURE);
+ }
+
+ if (newbreak > loop_level)
+ newbreak = loop_level;
+
+ breaking = newbreak;
+
+ return (EXECUTION_SUCCESS);
+}
+
+#line 101 "./break.def"
+
+/* Set up to continue x levels, where x defaults to 1, but can be specified
+ as the first argument. */
+int
+continue_builtin (list)
+ WORD_LIST *list;
+{
+ intmax_t newcont;
+
+ if (check_loop_level () == 0)
+ return (EXECUTION_SUCCESS);
+
+ (void)get_numeric_arg (list, 1, &newcont);
+
+ if (newcont <= 0)
+ {
+ sh_erange (list->word->word, _("loop count"));
+ breaking = loop_level;
+ return (EXECUTION_FAILURE);
+ }
+
+ if (newcont > loop_level)
+ newcont = loop_level;
+
+ continuing = newcont;
+
+ return (EXECUTION_SUCCESS);
+}
+
+/* Return non-zero if a break or continue command would be okay.
+ Print an error message if break or continue is meaningless here. */
+static int
+check_loop_level ()
+{
+#if defined (BREAK_COMPLAINS)
+ if (loop_level == 0 && posixly_correct == 0)
+ builtin_error (_("only meaningful in a `for', `while', or `until' loop"));
+#endif /* BREAK_COMPLAINS */
+
+ return (loop_level);
+}
diff --git a/builtins/builtext.h b/builtins/builtext.h
new file mode 100644
index 0000000..08f81f7
--- /dev/null
+++ b/builtins/builtext.h
@@ -0,0 +1,192 @@
+/* builtext.h - The list of builtins found in libbuiltins.a. */
+#if defined (ALIAS)
+extern int alias_builtin __P((WORD_LIST *));
+extern char * const alias_doc[];
+#endif /* ALIAS */
+#if defined (ALIAS)
+extern int unalias_builtin __P((WORD_LIST *));
+extern char * const unalias_doc[];
+#endif /* ALIAS */
+#if defined (READLINE)
+extern int bind_builtin __P((WORD_LIST *));
+extern char * const bind_doc[];
+#endif /* READLINE */
+extern int break_builtin __P((WORD_LIST *));
+extern char * const break_doc[];
+extern int continue_builtin __P((WORD_LIST *));
+extern char * const continue_doc[];
+extern int builtin_builtin __P((WORD_LIST *));
+extern char * const builtin_doc[];
+#if defined (DEBUGGER)
+extern int caller_builtin __P((WORD_LIST *));
+extern char * const caller_doc[];
+#endif /* DEBUGGER */
+extern int cd_builtin __P((WORD_LIST *));
+extern char * const cd_doc[];
+extern int pwd_builtin __P((WORD_LIST *));
+extern char * const pwd_doc[];
+extern int colon_builtin __P((WORD_LIST *));
+extern char * const colon_doc[];
+extern int colon_builtin __P((WORD_LIST *));
+extern char * const true_doc[];
+extern int false_builtin __P((WORD_LIST *));
+extern char * const false_doc[];
+extern int command_builtin __P((WORD_LIST *));
+extern char * const command_doc[];
+#if defined (PROGRAMMABLE_COMPLETION)
+extern int complete_builtin __P((WORD_LIST *));
+extern char * const complete_doc[];
+#endif /* PROGRAMMABLE_COMPLETION */
+#if defined (PROGRAMMABLE_COMPLETION)
+extern int compgen_builtin __P((WORD_LIST *));
+extern char * const compgen_doc[];
+#endif /* PROGRAMMABLE_COMPLETION */
+#if defined (PROGRAMMABLE_COMPLETION)
+extern int compopt_builtin __P((WORD_LIST *));
+extern char * const compopt_doc[];
+#endif /* PROGRAMMABLE_COMPLETION */
+extern int declare_builtin __P((WORD_LIST *));
+extern char * const declare_doc[];
+extern int declare_builtin __P((WORD_LIST *));
+extern char * const typeset_doc[];
+extern int local_builtin __P((WORD_LIST *));
+extern char * const local_doc[];
+#if defined (V9_ECHO)
+extern int echo_builtin __P((WORD_LIST *));
+extern char * const echo_doc[];
+#endif /* V9_ECHO */
+#if !defined (V9_ECHO)
+extern int echo_builtin __P((WORD_LIST *));
+extern char * const echo_doc[];
+#endif /* !V9_ECHO */
+extern int enable_builtin __P((WORD_LIST *));
+extern char * const enable_doc[];
+extern int eval_builtin __P((WORD_LIST *));
+extern char * const eval_doc[];
+extern int exec_builtin __P((WORD_LIST *));
+extern char * const exec_doc[];
+extern int exit_builtin __P((WORD_LIST *));
+extern char * const exit_doc[];
+extern int logout_builtin __P((WORD_LIST *));
+extern char * const logout_doc[];
+#if defined (HISTORY)
+extern int fc_builtin __P((WORD_LIST *));
+extern char * const fc_doc[];
+#endif /* HISTORY */
+#if defined (JOB_CONTROL)
+extern int fg_builtin __P((WORD_LIST *));
+extern char * const fg_doc[];
+#endif /* JOB_CONTROL */
+#if defined (JOB_CONTROL)
+extern int bg_builtin __P((WORD_LIST *));
+extern char * const bg_doc[];
+#endif /* JOB_CONTROL */
+extern int getopts_builtin __P((WORD_LIST *));
+extern char * const getopts_doc[];
+extern int hash_builtin __P((WORD_LIST *));
+extern char * const hash_doc[];
+#if defined (HELP_BUILTIN)
+extern int help_builtin __P((WORD_LIST *));
+extern char * const help_doc[];
+#endif /* HELP_BUILTIN */
+#if defined (HISTORY)
+extern int history_builtin __P((WORD_LIST *));
+extern char * const history_doc[];
+#endif /* HISTORY */
+#if defined (apollo)
+extern int inlib_builtin __P((WORD_LIST *));
+extern char * const inlib_doc[];
+#endif /* apollo */
+#if defined (JOB_CONTROL)
+extern int jobs_builtin __P((WORD_LIST *));
+extern char * const jobs_doc[];
+#endif /* JOB_CONTROL */
+#if defined (JOB_CONTROL)
+extern int disown_builtin __P((WORD_LIST *));
+extern char * const disown_doc[];
+#endif /* JOB_CONTROL */
+extern int kill_builtin __P((WORD_LIST *));
+extern char * const kill_doc[];
+extern int let_builtin __P((WORD_LIST *));
+extern char * const let_doc[];
+extern int mapfile_builtin __P((WORD_LIST *));
+extern char * const mapfile_doc[];
+extern int mapfile_builtin __P((WORD_LIST *));
+extern char * const readarray_doc[];
+extern int printf_builtin __P((WORD_LIST *));
+extern char * const printf_doc[];
+#if defined (PUSHD_AND_POPD)
+extern int pushd_builtin __P((WORD_LIST *));
+extern char * const pushd_doc[];
+#endif /* PUSHD_AND_POPD */
+#if defined (PUSHD_AND_POPD)
+extern int popd_builtin __P((WORD_LIST *));
+extern char * const popd_doc[];
+#endif /* PUSHD_AND_POPD */
+#if defined (PUSHD_AND_POPD)
+extern int dirs_builtin __P((WORD_LIST *));
+extern char * const dirs_doc[];
+#endif /* PUSHD_AND_POPD */
+extern int read_builtin __P((WORD_LIST *));
+extern char * const read_doc[];
+extern char * const for_doc[];
+extern char * const arith_for_doc[];
+extern char * const select_doc[];
+extern char * const time_doc[];
+extern char * const case_doc[];
+extern char * const if_doc[];
+extern char * const while_doc[];
+extern char * const until_doc[];
+extern char * const coproc_doc[];
+extern char * const function_doc[];
+extern char * const grouping_braces_doc[];
+extern char * const fg_percent_doc[];
+extern char * const arith_doc[];
+extern char * const conditional_doc[];
+extern char * const variable_help_doc[];
+extern int return_builtin __P((WORD_LIST *));
+extern char * const return_doc[];
+extern int export_builtin __P((WORD_LIST *));
+extern char * const export_doc[];
+extern int readonly_builtin __P((WORD_LIST *));
+extern char * const readonly_doc[];
+extern int set_builtin __P((WORD_LIST *));
+extern char * const set_doc[];
+extern int unset_builtin __P((WORD_LIST *));
+extern char * const unset_doc[];
+extern int shift_builtin __P((WORD_LIST *));
+extern char * const shift_doc[];
+extern int shopt_builtin __P((WORD_LIST *));
+extern char * const shopt_doc[];
+extern int source_builtin __P((WORD_LIST *));
+extern char * const source_doc[];
+extern int source_builtin __P((WORD_LIST *));
+extern char * const dot_doc[];
+#if defined (JOB_CONTROL)
+extern int suspend_builtin __P((WORD_LIST *));
+extern char * const suspend_doc[];
+#endif /* JOB_CONTROL */
+extern int test_builtin __P((WORD_LIST *));
+extern char * const test_doc[];
+extern int test_builtin __P((WORD_LIST *));
+extern char * const test_bracket_doc[];
+extern int times_builtin __P((WORD_LIST *));
+extern char * const times_doc[];
+extern int trap_builtin __P((WORD_LIST *));
+extern char * const trap_doc[];
+extern int type_builtin __P((WORD_LIST *));
+extern char * const type_doc[];
+#if !defined (_MINIX)
+extern int ulimit_builtin __P((WORD_LIST *));
+extern char * const ulimit_doc[];
+#endif /* !_MINIX */
+extern int umask_builtin __P((WORD_LIST *));
+extern char * const umask_doc[];
+#if defined (JOB_CONTROL)
+extern int wait_builtin __P((WORD_LIST *));
+extern char * const wait_doc[];
+#endif /* JOB_CONTROL */
+#if !defined (JOB_CONTROL)
+extern int wait_builtin __P((WORD_LIST *));
+extern char * const wait_doc[];
+#endif /* !JOB_CONTROL */
diff --git a/builtins/builtin.c b/builtins/builtin.c
new file mode 100644
index 0000000..3a75014
--- /dev/null
+++ b/builtins/builtin.c
@@ -0,0 +1,54 @@
+/* builtin.c, created from builtin.def. */
+#line 22 "./builtin.def"
+
+#line 36 "./builtin.def"
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern char *this_command_name;
+
+/* Run the command mentioned in list directly, without going through the
+ normal alias/function/builtin/filename lookup process. */
+int
+builtin_builtin (list)
+ WORD_LIST *list;
+{
+ sh_builtin_func_t *function;
+ register char *command;
+
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend; /* skip over possible `--' */
+
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+
+ command = list->word->word;
+#if defined (DISABLED_BUILTINS)
+ function = builtin_address (command);
+#else /* !DISABLED_BUILTINS */
+ function = find_shell_builtin (command);
+#endif /* !DISABLED_BUILTINS */
+
+ if (!function)
+ {
+ sh_notbuiltin (command);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ {
+ this_command_name = command;
+ list = list->next;
+ return ((*function) (list));
+ }
+}
diff --git a/builtins/builtins.c b/builtins/builtins.c
new file mode 100644
index 0000000..1d6ec74
--- /dev/null
+++ b/builtins/builtins.c
@@ -0,0 +1,2028 @@
+/* builtins.c -- the built in shell commands. */
+
+/* This file is manufactured by ./mkbuiltins, and should not be
+ edited by hand. See the source to mkbuiltins for details. */
+
+/* Copyright (C) 1987-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/* The list of shell builtins. Each element is name, function, flags,
+ long-doc, short-doc. The long-doc field contains a pointer to an array
+ of help lines. The function takes a WORD_LIST *; the first word in the
+ list is the first arg to the command. The list has already had word
+ expansion performed.
+
+ Functions which need to look at only the simple commands (e.g.
+ the enable_builtin ()), should ignore entries where
+ (array[i].function == (sh_builtin_func_t *)NULL). Such entries are for
+ the list of shell reserved control structures, like `if' and `while'.
+ The end of the list is denoted with a NULL name field. */
+
+#include "../builtins.h"
+#include "builtext.h"
+#include "bashintl.h"
+
+struct builtin static_shell_builtins[] = {
+#if defined (ALIAS)
+ { "alias", alias_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | ASSIGNMENT_BUILTIN | POSIX_BUILTIN, alias_doc,
+ N_("alias [-p] [name[=value] ... ]"), (char *)NULL },
+#endif /* ALIAS */
+#if defined (ALIAS)
+ { "unalias", unalias_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, unalias_doc,
+ N_("unalias [-a] name [name ...]"), (char *)NULL },
+#endif /* ALIAS */
+#if defined (READLINE)
+ { "bind", bind_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, bind_doc,
+ N_("bind [-lpvsPVS] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]"), (char *)NULL },
+#endif /* READLINE */
+ { "break", break_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, break_doc,
+ N_("break [n]"), (char *)NULL },
+ { "continue", continue_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, continue_doc,
+ N_("continue [n]"), (char *)NULL },
+ { "builtin", builtin_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, builtin_doc,
+ N_("builtin [shell-builtin [arg ...]]"), (char *)NULL },
+#if defined (DEBUGGER)
+ { "caller", caller_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, caller_doc,
+ N_("caller [expr]"), (char *)NULL },
+#endif /* DEBUGGER */
+ { "cd", cd_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, cd_doc,
+ N_("cd [-L|-P] [dir]"), (char *)NULL },
+ { "pwd", pwd_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, pwd_doc,
+ N_("pwd [-LP]"), (char *)NULL },
+ { ":", colon_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, colon_doc,
+ N_(":"), (char *)NULL },
+ { "true", colon_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, true_doc,
+ N_("true"), (char *)NULL },
+ { "false", false_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, false_doc,
+ N_("false"), (char *)NULL },
+ { "command", command_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, command_doc,
+ N_("command [-pVv] command [arg ...]"), (char *)NULL },
+#if defined (PROGRAMMABLE_COMPLETION)
+ { "complete", complete_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, complete_doc,
+ N_("complete [-abcdefgjksuv] [-pr] [-DE] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]"), (char *)NULL },
+#endif /* PROGRAMMABLE_COMPLETION */
+#if defined (PROGRAMMABLE_COMPLETION)
+ { "compgen", compgen_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, compgen_doc,
+ N_("compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]"), (char *)NULL },
+#endif /* PROGRAMMABLE_COMPLETION */
+#if defined (PROGRAMMABLE_COMPLETION)
+ { "compopt", compopt_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, compopt_doc,
+ N_("compopt [-o|+o option] [-DE] [name ...]"), (char *)NULL },
+#endif /* PROGRAMMABLE_COMPLETION */
+ { "declare", declare_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | ASSIGNMENT_BUILTIN, declare_doc,
+ N_("declare [-aAfFilrtux] [-p] [name[=value] ...]"), (char *)NULL },
+ { "typeset", declare_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | ASSIGNMENT_BUILTIN, typeset_doc,
+ N_("typeset [-aAfFilrtux] [-p] name[=value] ..."), (char *)NULL },
+ { "local", local_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | ASSIGNMENT_BUILTIN, local_doc,
+ N_("local [option] name[=value] ..."), (char *)NULL },
+#if defined (V9_ECHO)
+ { "echo", echo_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, echo_doc,
+ N_("echo [-neE] [arg ...]"), (char *)NULL },
+#endif /* V9_ECHO */
+#if !defined (V9_ECHO)
+ { "echo", echo_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, echo_doc,
+ N_("echo [-n] [arg ...]"), (char *)NULL },
+#endif /* !V9_ECHO */
+ { "enable", enable_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, enable_doc,
+ N_("enable [-a] [-dnps] [-f filename] [name ...]"), (char *)NULL },
+ { "eval", eval_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, eval_doc,
+ N_("eval [arg ...]"), (char *)NULL },
+ { "exec", exec_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, exec_doc,
+ N_("exec [-cl] [-a name] [command [arguments ...]] [redirection ...]"), (char *)NULL },
+ { "exit", exit_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, exit_doc,
+ N_("exit [n]"), (char *)NULL },
+ { "logout", logout_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, logout_doc,
+ N_("logout [n]"), (char *)NULL },
+#if defined (HISTORY)
+ { "fc", fc_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, fc_doc,
+ N_("fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]"), (char *)NULL },
+#endif /* HISTORY */
+#if defined (JOB_CONTROL)
+ { "fg", fg_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, fg_doc,
+ N_("fg [job_spec]"), (char *)NULL },
+#endif /* JOB_CONTROL */
+#if defined (JOB_CONTROL)
+ { "bg", bg_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, bg_doc,
+ N_("bg [job_spec ...]"), (char *)NULL },
+#endif /* JOB_CONTROL */
+ { "getopts", getopts_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, getopts_doc,
+ N_("getopts optstring name [arg]"), (char *)NULL },
+ { "hash", hash_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, hash_doc,
+ N_("hash [-lr] [-p pathname] [-dt] [name ...]"), (char *)NULL },
+#if defined (HELP_BUILTIN)
+ { "help", help_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, help_doc,
+ N_("help [-dms] [pattern ...]"), (char *)NULL },
+#endif /* HELP_BUILTIN */
+#if defined (HISTORY)
+ { "history", history_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, history_doc,
+ N_("history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]"), (char *)NULL },
+#endif /* HISTORY */
+#if defined (apollo)
+ { "inlib", inlib_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, inlib_doc,
+ N_("inlib pathname [pathname...]"), (char *)NULL },
+#endif /* apollo */
+#if defined (JOB_CONTROL)
+ { "jobs", jobs_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, jobs_doc,
+ N_("jobs [-lnprs] [jobspec ...] or jobs -x command [args]"), (char *)NULL },
+#endif /* JOB_CONTROL */
+#if defined (JOB_CONTROL)
+ { "disown", disown_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, disown_doc,
+ N_("disown [-h] [-ar] [jobspec ...]"), (char *)NULL },
+#endif /* JOB_CONTROL */
+ { "kill", kill_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, kill_doc,
+ N_("kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]"), (char *)NULL },
+ { "let", let_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, let_doc,
+ N_("let arg [arg ...]"), (char *)NULL },
+ { "mapfile", mapfile_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, mapfile_doc,
+ N_("mapfile [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]"), (char *)NULL },
+ { "readarray", mapfile_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, readarray_doc,
+ N_("readarray [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]"), (char *)NULL },
+ { "printf", printf_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, printf_doc,
+ N_("printf [-v var] format [arguments]"), (char *)NULL },
+#if defined (PUSHD_AND_POPD)
+ { "pushd", pushd_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, pushd_doc,
+ N_("pushd [-n] [+N | -N | dir]"), (char *)NULL },
+#endif /* PUSHD_AND_POPD */
+#if defined (PUSHD_AND_POPD)
+ { "popd", popd_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, popd_doc,
+ N_("popd [-n] [+N | -N]"), (char *)NULL },
+#endif /* PUSHD_AND_POPD */
+#if defined (PUSHD_AND_POPD)
+ { "dirs", dirs_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, dirs_doc,
+ N_("dirs [-clpv] [+N] [-N]"), (char *)NULL },
+#endif /* PUSHD_AND_POPD */
+ { "read", read_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, read_doc,
+ N_("read [-ers] [-a array] [-d delim] [-i text] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [-u fd] [name ...]"), (char *)NULL },
+ { "for", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, for_doc,
+ N_("for NAME [in WORDS ... ] ; do COMMANDS; done"), (char *)NULL },
+ { "for ((", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, arith_for_doc,
+ N_("for (( exp1; exp2; exp3 )); do COMMANDS; done"), (char *)NULL },
+ { "select", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, select_doc,
+ N_("select NAME [in WORDS ... ;] do COMMANDS; done"), (char *)NULL },
+ { "time", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, time_doc,
+ N_("time [-p] pipeline"), (char *)NULL },
+ { "case", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, case_doc,
+ N_("case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac"), (char *)NULL },
+ { "if", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, if_doc,
+ N_("if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi"), (char *)NULL },
+ { "while", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, while_doc,
+ N_("while COMMANDS; do COMMANDS; done"), (char *)NULL },
+ { "until", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, until_doc,
+ N_("until COMMANDS; do COMMANDS; done"), (char *)NULL },
+ { "coproc", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, coproc_doc,
+ N_("coproc [NAME] command [redirections]"), (char *)NULL },
+ { "function", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, function_doc,
+ N_("function name { COMMANDS ; } or name () { COMMANDS ; }"), (char *)NULL },
+ { "{ ... }", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, grouping_braces_doc,
+ N_("{ COMMANDS ; }"), (char *)NULL },
+ { "%", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, fg_percent_doc,
+ N_("job_spec [&]"), (char *)NULL },
+ { "(( ... ))", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, arith_doc,
+ N_("(( expression ))"), (char *)NULL },
+ { "[[ ... ]]", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, conditional_doc,
+ N_("[[ expression ]]"), (char *)NULL },
+ { "variables", (sh_builtin_func_t *)0x0, BUILTIN_ENABLED | STATIC_BUILTIN, variable_help_doc,
+ N_("variables - Names and meanings of some shell variables"), (char *)NULL },
+ { "return", return_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, return_doc,
+ N_("return [n]"), (char *)NULL },
+ { "export", export_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN | ASSIGNMENT_BUILTIN, export_doc,
+ N_("export [-fn] [name[=value] ...] or export -p"), (char *)NULL },
+ { "readonly", readonly_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN | ASSIGNMENT_BUILTIN, readonly_doc,
+ N_("readonly [-af] [name[=value] ...] or readonly -p"), (char *)NULL },
+ { "set", set_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, set_doc,
+ N_("set [--abefhkmnptuvxBCHP] [-o option-name] [arg ...]"), (char *)NULL },
+ { "unset", unset_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, unset_doc,
+ N_("unset [-f] [-v] [name ...]"), (char *)NULL },
+ { "shift", shift_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, shift_doc,
+ N_("shift [n]"), (char *)NULL },
+ { "shopt", shopt_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, shopt_doc,
+ N_("shopt [-pqsu] [-o] [optname ...]"), (char *)NULL },
+ { "source", source_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, source_doc,
+ N_("source filename [arguments]"), (char *)NULL },
+ { ".", source_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, dot_doc,
+ N_(". filename [arguments]"), (char *)NULL },
+#if defined (JOB_CONTROL)
+ { "suspend", suspend_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, suspend_doc,
+ N_("suspend [-f]"), (char *)NULL },
+#endif /* JOB_CONTROL */
+ { "test", test_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, test_doc,
+ N_("test [expr]"), (char *)NULL },
+ { "[", test_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, test_bracket_doc,
+ N_("[ arg... ]"), (char *)NULL },
+ { "times", times_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, times_doc,
+ N_("times"), (char *)NULL },
+ { "trap", trap_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN, trap_doc,
+ N_("trap [-lp] [[arg] signal_spec ...]"), (char *)NULL },
+ { "type", type_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, type_doc,
+ N_("type [-afptP] name [name ...]"), (char *)NULL },
+#if !defined (_MINIX)
+ { "ulimit", ulimit_builtin, BUILTIN_ENABLED | STATIC_BUILTIN, ulimit_doc,
+ N_("ulimit [-SHacdefilmnpqrstuvx] [limit]"), (char *)NULL },
+#endif /* !_MINIX */
+ { "umask", umask_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, umask_doc,
+ N_("umask [-p] [-S] [mode]"), (char *)NULL },
+#if defined (JOB_CONTROL)
+ { "wait", wait_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, wait_doc,
+ N_("wait [id]"), (char *)NULL },
+#endif /* JOB_CONTROL */
+#if !defined (JOB_CONTROL)
+ { "wait", wait_builtin, BUILTIN_ENABLED | STATIC_BUILTIN | POSIX_BUILTIN, wait_doc,
+ N_("wait [pid]"), (char *)NULL },
+#endif /* !JOB_CONTROL */
+ { (char *)0x0, (sh_builtin_func_t *)0x0, 0, (char **)0x0, (char *)0x0 }
+};
+
+struct builtin *shell_builtins = static_shell_builtins;
+struct builtin *current_builtin;
+
+int num_shell_builtins =
+ sizeof (static_shell_builtins) / sizeof (struct builtin) - 1;
+#if defined (ALIAS)
+char * const alias_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Define or display aliases.\n\
+ \n\
+ Without arguments, `alias' prints the list of aliases in the reusable\n\
+ form `alias NAME=VALUE' on standard output.\n\
+ \n\
+ Otherwise, an alias is defined for each NAME whose VALUE is given.\n\
+ A trailing space in VALUE causes the next word to be checked for\n\
+ alias substitution when the alias is expanded.\n\
+ \n\
+ Options:\n\
+ -p Print all defined aliases in a reusable format\n\
+ \n\
+ Exit Status:\n\
+ alias returns true unless a NAME is supplied for which no alias has been\n\
+ defined."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* ALIAS */
+#if defined (ALIAS)
+char * const unalias_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Remove each NAME from the list of defined aliases.\n\
+ \n\
+ Options:\n\
+ -a remove all alias definitions.\n\
+ \n\
+ Return success unless a NAME is not an existing alias."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* ALIAS */
+#if defined (READLINE)
+char * const bind_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Set Readline key bindings and variables.\n\
+ \n\
+ Bind a key sequence to a Readline function or a macro, or set a\n\
+ Readline variable. The non-option argument syntax is equivalent to\n\
+ that found in ~/.inputrc, but must be passed as a single argument:\n\
+ e.g., bind '\"\\C-x\\C-r\": re-read-init-file'.\n\
+ \n\
+ Options:\n\
+ -m keymap Use KEYMAP as the keymap for the duration of this\n\
+ command. Acceptable keymap names are emacs,\n\
+ emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,\n\
+ vi-command, and vi-insert.\n\
+ -l List names of functions.\n\
+ -P List function names and bindings.\n\
+ -p List functions and bindings in a form that can be\n\
+ reused as input.\n\
+ -S List key sequences that invoke macros and their values\n\
+ -s List key sequences that invoke macros and their values\n\
+ in a form that can be reused as input.\n\
+ -V List variable names and values\n\
+ -v List variable names and values in a form that can\n\
+ be reused as input.\n\
+ -q function-name Query about which keys invoke the named function.\n\
+ -u function-name Unbind all keys which are bound to the named function.\n\
+ -r keyseq Remove the binding for KEYSEQ.\n\
+ -f filename Read key bindings from FILENAME.\n\
+ -x keyseq:shell-command Cause SHELL-COMMAND to be executed when\n\
+ KEYSEQ is entered.\n\
+ \n\
+ Exit Status:\n\
+ bind returns 0 unless an unrecognized option is given or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* READLINE */
+char * const break_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Exit for, while, or until loops.\n\
+ \n\
+ Exit a FOR, WHILE or UNTIL loop. If N is specified, break N enclosing\n\
+ loops.\n\
+ \n\
+ Exit Status:\n\
+ The exit status is 0 unless N is not greater than or equal to 1."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const continue_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Resume for, while, or until loops.\n\
+ \n\
+ Resumes the next iteration of the enclosing FOR, WHILE or UNTIL loop.\n\
+ If N is specified, resumes the Nth enclosing loop.\n\
+ \n\
+ Exit Status:\n\
+ The exit status is 0 unless N is not greater than or equal to 1."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const builtin_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute shell builtins.\n\
+ \n\
+ Execute SHELL-BUILTIN with arguments ARGs without performing command\n\
+ lookup. This is useful when you wish to reimplement a shell builtin\n\
+ as a shell function, but need to execute the builtin within the function.\n\
+ \n\
+ Exit Status:\n\
+ Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is\n\
+ not a shell builtin.."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (DEBUGGER)
+char * const caller_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Return the context of the current subroutine call.\n\
+ \n\
+ Without EXPR, returns \"$line $filename\". With EXPR, returns\n\
+ \"$line $subroutine $filename\"; this extra information can be used to\n\
+ provide a stack trace.\n\
+ \n\
+ The value of EXPR indicates how many call frames to go back before the\n\
+ current one; the top frame is frame 0.\n\
+ \n\
+ Exit Status:\n\
+ Returns 0 unless the shell is not executing a shell function or EXPR\n\
+ is invalid."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* DEBUGGER */
+char * const cd_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Change the shell working directory.\n\
+ \n\
+ Change the current directory to DIR. The default DIR is the value of the\n\
+ HOME shell variable.\n\
+ \n\
+ The variable CDPATH defines the search path for the directory containing\n\
+ DIR. Alternative directory names in CDPATH are separated by a colon (:).\n\
+ A null directory name is the same as the current directory. If DIR begins\n\
+ with a slash (/), then CDPATH is not used.\n\
+ \n\
+ If the directory is not found, and the shell option `cdable_vars' is set,\n\
+ the word is assumed to be a variable name. If that variable has a value,\n\
+ its value is used for DIR.\n\
+ \n\
+ Options:\n\
+ -L force symbolic links to be followed\n\
+ -P use the physical directory structure without following symbolic\n\
+ links\n\
+ \n\
+ The default is to follow symbolic links, as if `-L' were specified.\n\
+ \n\
+ Exit Status:\n\
+ Returns 0 if the directory is changed; non-zero otherwise."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const pwd_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Print the name of the current working directory.\n\
+ \n\
+ Options:\n\
+ -L print the value of $PWD if it names the current working\n\
+ directory\n\
+ -P print the physical directory, without any symbolic links\n\
+ \n\
+ By default, `pwd' behaves as if `-L' were specified.\n\
+ \n\
+ Exit Status:\n\
+ Returns 0 unless an invalid option is given or the current directory\n\
+ cannot be read."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const colon_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Null command.\n\
+ \n\
+ No effect; the command does nothing.\n\
+ \n\
+ Exit Status:\n\
+ Always succeeds."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const true_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Return a successful result.\n\
+ \n\
+ Exit Status:\n\
+ Always succeeds."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const false_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Return an unsuccessful result.\n\
+ \n\
+ Exit Status:\n\
+ Always fails."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const command_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute a simple command or display information about commands.\n\
+ \n\
+ Runs COMMAND with ARGS suppressing shell function lookup, or display\n\
+ information about the specified COMMANDs. Can be used to invoke commands\n\
+ on disk when a function with the same name exists.\n\
+ \n\
+ Options:\n\
+ -p use a default value for PATH that is guaranteed to find all of\n\
+ the standard utilities\n\
+ -v print a description of COMMAND similar to the `type' builtin\n\
+ -V print a more verbose description of each COMMAND\n\
+ \n\
+ Exit Status:\n\
+ Returns exit status of COMMAND, or failure if COMMAND is not found."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (PROGRAMMABLE_COMPLETION)
+char * const complete_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Specify how arguments are to be completed by Readline.\n\
+ \n\
+ For each NAME, specify how arguments are to be completed. If no options\n\
+ are supplied, existing completion specifications are printed in a way that\n\
+ allows them to be reused as input.\n\
+ \n\
+ Options:\n\
+ -p print existing completion specifications in a reusable format\n\
+ -r remove a completion specification for each NAME, or, if no\n\
+ NAMEs are supplied, all completion specifications\n\
+ -D apply the completions and actions as the default for commands\n\
+ without any specific completion defined\n\
+ -E apply the completions and actions to \"empty\" commands --\n\
+ completion attempted on a blank line\n\
+ \n\
+ When completion is attempted, the actions are applied in the order the\n\
+ uppercase-letter options are listed above. The -D option takes\n\
+ precedence over -E.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* PROGRAMMABLE_COMPLETION */
+#if defined (PROGRAMMABLE_COMPLETION)
+char * const compgen_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display possible completions depending on the options.\n\
+ \n\
+ Intended to be used from within a shell function generating possible\n\
+ completions. If the optional WORD argument is supplied, matches against\n\
+ WORD are generated.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* PROGRAMMABLE_COMPLETION */
+#if defined (PROGRAMMABLE_COMPLETION)
+char * const compopt_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Modify or display completion options.\n\
+ \n\
+ Modify the completion options for each NAME, or, if no NAMEs are supplied,\n\
+ the completion currently begin executed. If no OPTIONs are givenm, print\n\
+ the completion options for each NAME or the current completion specification.\n\
+ \n\
+ Options:\n\
+ -o option Set completion option OPTION for each NAME\n\
+ -D Change options for the \"default\" command completion\n\
+ -E Change options for the \"empty\" command completion\n\
+ \n\
+ Using `+o' instead of `-o' turns off the specified option.\n\
+ \n\
+ Arguments:\n\
+ \n\
+ Each NAME refers to a command for which a completion specification must\n\
+ have previously been defined using the `complete' builtin. If no NAMEs\n\
+ are supplied, compopt must be called by a function currently generating\n\
+ completions, and the options for that currently-executing completion\n\
+ generator are modified.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied or NAME does not\n\
+ have a completion specification defined."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* PROGRAMMABLE_COMPLETION */
+char * const declare_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Set variable values and attributes.\n\
+ \n\
+ Declare variables and give them attributes. If no NAMEs are given,\n\
+ display the attributes and values of all variables.\n\
+ \n\
+ Options:\n\
+ -f restrict action or display to function names and definitions\n\
+ -F restrict display to function names only (plus line number and\n\
+ source file when debugging)\n\
+ -p display the attributes and value of each NAME\n\
+ \n\
+ Options which set attributes:\n\
+ -a to make NAMEs indexed arrays (if supported)\n\
+ -A to make NAMEs associative arrays (if supported)\n\
+ -i to make NAMEs have the `integer' attribute\n\
+ -l to convert NAMEs to lower case on assignment\n\
+ -r to make NAMEs readonly\n\
+ -t to make NAMEs have the `trace' attribute\n\
+ -u to convert NAMEs to upper case on assignment\n\
+ -x to make NAMEs export\n\
+ \n\
+ Using `+' instead of `-' turns off the given attribute.\n\
+ \n\
+ Variables with the integer attribute have arithmetic evaluation (see\n\
+ the `let' command) performed when the variable is assigned a value.\n\
+ \n\
+ When used in a function, `declare' makes NAMEs local, as with the `local'\n\
+ command.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const typeset_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Set variable values and attributes.\n\
+ \n\
+ Obsolete. See `help declare'."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const local_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Define local variables.\n\
+ \n\
+ Create a local variable called NAME, and give it VALUE. OPTION can\n\
+ be any option accepted by `declare'.\n\
+ \n\
+ Local variables can only be used within a function; they are visible\n\
+ only to the function where they are defined and its children.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied, an error occurs,\n\
+ or the shell is not executing a function."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (V9_ECHO)
+char * const echo_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Write arguments to the standard output.\n\
+ \n\
+ Display the ARGs on the standard output followed by a newline.\n\
+ \n\
+ Options:\n\
+ -n do not append a newline\n\
+ -e enable interpretation of the following backslash escapes\n\
+ -E explicitly suppress interpretation of backslash escapes\n\
+ \n\
+ `echo' interprets the following backslash-escaped characters:\n\
+ \\a alert (bell)\n\
+ \\b backspace\n\
+ \\c suppress further output\n\
+ \\e escape character\n\
+ \\f form feed\n\
+ \\n new line\n\
+ \\r carriage return\n\
+ \\t horizontal tab\n\
+ \\v vertical tab\n\
+ \\\\ backslash\n\
+ \\0nnn the character whose ASCII code is NNN (octal). NNN can be\n\
+ 0 to 3 octal digits\n\
+ \\xHH the eight-bit character whose value is HH (hexadecimal). HH\n\
+ can be one or two hex digits\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless a write error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* V9_ECHO */
+#if !defined (V9_ECHO)
+char * const echo_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Write arguments to the standard output.\n\
+ \n\
+ Display the ARGs on the standard output followed by a newline.\n\
+ \n\
+ Options:\n\
+ -n do not append a newline\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless a write error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* !V9_ECHO */
+char * const enable_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Enable and disable shell builtins.\n\
+ \n\
+ Enables and disables builtin shell commands. Disabling allows you to\n\
+ execute a disk command which has the same name as a shell builtin\n\
+ without using a full pathname.\n\
+ \n\
+ Options:\n\
+ -a print a list of builtins showing whether or not each is enabled\n\
+ -n disable each NAME or display a list of disabled builtins\n\
+ -p print the list of builtins in a reusable format\n\
+ -s print only the names of Posix `special' builtins\n\
+ \n\
+ Options controlling dynamic loading:\n\
+ -f Load builtin NAME from shared object FILENAME\n\
+ -d Remove a builtin loaded with -f\n\
+ \n\
+ Without options, each NAME is enabled.\n\
+ \n\
+ To use the `test' found in $PATH instead of the shell builtin\n\
+ version, type `enable -n test'.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless NAME is not a shell builtin or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const eval_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute arguments as a shell command.\n\
+ \n\
+ Combine ARGs into a single string, use the result as input to the shell,\n\
+ and execute the resulting commands.\n\
+ \n\
+ Exit Status:\n\
+ Returns exit status of command or success if command is null."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const exec_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Replace the shell with the given command.\n\
+ \n\
+ Execute COMMAND, replacing this shell with the specified program.\n\
+ ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,\n\
+ any redirections take effect in the current shell.\n\
+ \n\
+ Options:\n\
+ -a name pass NAME as the zeroth argument to COMMAND\n\
+ -c execute COMMAND with an empty environment\n\
+ -l place a dash in the zeroth argument to COMMAND\n\
+ \n\
+ If the command cannot be executed, a non-interactive shell exits, unless\n\
+ the shell option `execfail' is set.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless COMMAND is not found or a redirection error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const exit_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Exit the shell.\n\
+ \n\
+ Exits the shell with a status of N. If N is omitted, the exit status\n\
+ is that of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const logout_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Exit a login shell.\n\
+ \n\
+ Exits a login shell with exit status N. Returns an error if not executed\n\
+ in a login shell."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (HISTORY)
+char * const fc_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display or execute commands from the history list.\n\
+ \n\
+ fc is used to list or edit and re-execute commands from the history list.\n\
+ FIRST and LAST can be numbers specifying the range, or FIRST can be a\n\
+ string, which means the most recent command beginning with that\n\
+ string.\n\
+ \n\
+ Options:\n\
+ -e ENAME select which editor to use. Default is FCEDIT, then EDITOR,\n\
+ then vi\n\
+ -l list lines instead of editing\n\
+ -n omit line numbers when listing\n\
+ -r reverse the order of the lines (newest listed first)\n\
+ \n\
+ With the `fc -s [pat=rep ...] [command]' format, COMMAND is\n\
+ re-executed after the substitution OLD=NEW is performed.\n\
+ \n\
+ A useful alias to use with this is r='fc -s', so that typing `r cc'\n\
+ runs the last command beginning with `cc' and typing `r' re-executes\n\
+ the last command.\n\
+ \n\
+ Exit Status:\n\
+ Returns success or status of executed command; non-zero if an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* HISTORY */
+#if defined (JOB_CONTROL)
+char * const fg_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Move job to the foreground.\n\
+ \n\
+ Place the job identified by JOB_SPEC in the foreground, making it the\n\
+ current job. If JOB_SPEC is not present, the shell's notion of the\n\
+ current job is used.\n\
+ \n\
+ Exit Status:\n\
+ Status of command placed in foreground, or failure if an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* JOB_CONTROL */
+#if defined (JOB_CONTROL)
+char * const bg_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Move jobs to the background.\n\
+ \n\
+ Place the jobs identified by each JOB_SPEC in the background, as if they\n\
+ had been started with `&'. If JOB_SPEC is not present, the shell's notion\n\
+ of the current job is used.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless job control is not enabled or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* JOB_CONTROL */
+char * const getopts_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Parse option arguments.\n\
+ \n\
+ Getopts is used by shell procedures to parse positional parameters\n\
+ as options.\n\
+ \n\
+ OPTSTRING contains the option letters to be recognized; if a letter\n\
+ is followed by a colon, the option is expected to have an argument,\n\
+ which should be separated from it by white space.\n\
+ \n\
+ Each time it is invoked, getopts will place the next option in the\n\
+ shell variable $name, initializing name if it does not exist, and\n\
+ the index of the next argument to be processed into the shell\n\
+ variable OPTIND. OPTIND is initialized to 1 each time the shell or\n\
+ a shell script is invoked. When an option requires an argument,\n\
+ getopts places that argument into the shell variable OPTARG.\n\
+ \n\
+ getopts reports errors in one of two ways. If the first character\n\
+ of OPTSTRING is a colon, getopts uses silent error reporting. In\n\
+ this mode, no error messages are printed. If an invalid option is\n\
+ seen, getopts places the option character found into OPTARG. If a\n\
+ required argument is not found, getopts places a ':' into NAME and\n\
+ sets OPTARG to the option character found. If getopts is not in\n\
+ silent mode, and an invalid option is seen, getopts places '?' into\n\
+ NAME and unsets OPTARG. If a required argument is not found, a '?'\n\
+ is placed in NAME, OPTARG is unset, and a diagnostic message is\n\
+ printed.\n\
+ \n\
+ If the shell variable OPTERR has the value 0, getopts disables the\n\
+ printing of error messages, even if the first character of\n\
+ OPTSTRING is not a colon. OPTERR has the value 1 by default.\n\
+ \n\
+ Getopts normally parses the positional parameters ($0 - $9), but if\n\
+ more arguments are given, they are parsed instead.\n\
+ \n\
+ Exit Status:\n\
+ Returns success if an option is found; fails if the end of options is\n\
+ encountered or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const hash_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Remember or display program locations.\n\
+ \n\
+ Determine and remember the full pathname of each command NAME. If\n\
+ no arguments are given, information about remembered commands is displayed.\n\
+ \n\
+ Options:\n\
+ -d forget the remembered location of each NAME\n\
+ -l display in a format that may be reused as input\n\
+ -p pathname use PATHNAME is the full pathname of NAME\n\
+ -r forget all remembered locations\n\
+ -t print the remembered location of each NAME, preceding\n\
+ each location with the corresponding NAME if multiple\n\
+ NAMEs are given\n\
+ Arguments:\n\
+ NAME Each NAME is searched for in $PATH and added to the list\n\
+ of remembered commands.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless NAME is not found or an invalid option is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (HELP_BUILTIN)
+char * const help_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display information about builtin commands.\n\
+ \n\
+ Displays brief summaries of builtin commands. If PATTERN is\n\
+ specified, gives detailed help on all commands matching PATTERN,\n\
+ otherwise the list of help topics is printed.\n\
+ \n\
+ Options:\n\
+ -d output short description for each topic\n\
+ -m display usage in pseudo-manpage format\n\
+ -s output only a short usage synopsis for each topic matching\n\
+ PATTERN\n\
+ \n\
+ Arguments:\n\
+ PATTERN Pattern specifiying a help topic\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless PATTERN is not found or an invalid option is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* HELP_BUILTIN */
+#if defined (HISTORY)
+char * const history_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display or manipulate the history list.\n\
+ \n\
+ Display the history list with line numbers, prefixing each modified\n\
+ entry with a `*'. An argument of N lists only the last N entries.\n\
+ \n\
+ Options:\n\
+ -c clear the history list by deleting all of the entries\n\
+ -d offset delete the history entry at offset OFFSET.\n\
+ \n\
+ -a append history lines from this session to the history file\n\
+ -n read all history lines not already read from the history file\n\
+ -r read the history file and append the contents to the history\n\
+ list\n\
+ -w write the current history to the history file\n\
+ and append them to the history list\n\
+ \n\
+ -p perform history expansion on each ARG and display the result\n\
+ without storing it in the history list\n\
+ -s append the ARGs to the history list as a single entry\n\
+ \n\
+ If FILENAME is given, it is used as the history file. Otherwise,\n\
+ if $HISTFILE has a value, that is used, else ~/.bash_history.\n\
+ \n\
+ If the $HISTTIMEFORMAT variable is set and not null, its value is used\n\
+ as a format string for strftime(3) to print the time stamp associated\n\
+ with each displayed history entry. No time stamps are printed otherwise.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* HISTORY */
+#if defined (apollo)
+char * const inlib_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Install user-supplied library.\n\
+ \n\
+ Install a user-supplied library specified by pathname in the current\n\
+ shell process. The library is used to resolve external references\n\
+ in programs and libraries loaded after its installation. Note\n\
+ that the library is not loaded into the address space unless it is\n\
+ needed to resolve an external reference. The list of inlibed\n\
+ libraries is passed to all children of the current shell.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless PATHNAME is not found or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* apollo */
+#if defined (JOB_CONTROL)
+char * const jobs_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display status of jobs.\n\
+ \n\
+ Lists the active jobs. JOBSPEC restricts output to that job.\n\
+ Without options, the status of all active jobs is displayed.\n\
+ \n\
+ Options:\n\
+ -l lists process IDs in addition to the normal information\n\
+ -n list only processes that have changed status since the last\n\
+ notification\n\
+ -p lists process IDs only\n\
+ -r restrict output to running jobs\n\
+ -s restrict output to stopped jobs\n\
+ \n\
+ If -x is supplied, COMMAND is run after all job specifications that\n\
+ appear in ARGS have been replaced with the process ID of that job's\n\
+ process group leader.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or an error occurs.\n\
+ If -x is used, returns the exit status of COMMAND."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* JOB_CONTROL */
+#if defined (JOB_CONTROL)
+char * const disown_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Remove jobs from current shell.\n\
+ \n\
+ Removes each JOBSPEC argument from the table of active jobs. Without\n\
+ any JOBSPECs, the shell uses its notion of the current job.\n\
+ \n\
+ Options:\n\
+ -a remove all jobs if JOBSPEC is not supplied\n\
+ -h mark each JOBSPEC so that SIGHUP is not sent to the job if the\n\
+ shell receives a SIGHUP\n\
+ -r remove only running jobs\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option or JOBSPEC is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* JOB_CONTROL */
+char * const kill_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Send a signal to a job.\n\
+ \n\
+ Send the processes identified by PID or JOBSPEC the signal named by\n\
+ SIGSPEC or SIGNUM. If neither SIGSPEC nor SIGNUM is present, then\n\
+ SIGTERM is assumed.\n\
+ \n\
+ Options:\n\
+ -s sig SIG is a signal name\n\
+ -n sig SIG is a signal number\n\
+ -l list the signal names; if arguments follow `-l' they are\n\
+ assumed to be signal numbers for which names should be listed\n\
+ \n\
+ Kill is a shell builtin for two reasons: it allows job IDs to be used\n\
+ instead of process IDs, and allows processes to be killed if the limit\n\
+ on processes that you can create is reached.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const let_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Evaluate arithmetic expressions.\n\
+ \n\
+ Evaluate each ARG as an arithmetic expression. Evaluation is done in\n\
+ fixed-width integers with no check for overflow, though division by 0\n\
+ is trapped and flagged as an error. The following list of operators is\n\
+ grouped into levels of equal-precedence operators. The levels are listed\n\
+ in order of decreasing precedence.\n\
+ \n\
+ id++, id-- variable post-increment, post-decrement\n\
+ ++id, --id variable pre-increment, pre-decrement\n\
+ -, + unary minus, plus\n\
+ !, ~ logical and bitwise negation\n\
+ ** exponentiation\n\
+ *, /, % multiplication, division, remainder\n\
+ +, - addition, subtraction\n\
+ <<, >> left and right bitwise shifts\n\
+ <=, >=, <, > comparison\n\
+ ==, != equality, inequality\n\
+ & bitwise AND\n\
+ ^ bitwise XOR\n\
+ | bitwise OR\n\
+ && logical AND\n\
+ || logical OR\n\
+ expr ? expr : expr\n\
+ conditional operator\n\
+ =, *=, /=, %=,\n\
+ +=, -=, <<=, >>=,\n\
+ &=, ^=, |= assignment\n\
+ \n\
+ Shell variables are allowed as operands. The name of the variable\n\
+ is replaced by its value (coerced to a fixed-width integer) within\n\
+ an expression. The variable need not have its integer attribute\n\
+ turned on to be used in an expression.\n\
+ \n\
+ Operators are evaluated in order of precedence. Sub-expressions in\n\
+ parentheses are evaluated first and may override the precedence\n\
+ rules above.\n\
+ \n\
+ Exit Status:\n\
+ If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const mapfile_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Read lines from the standard input into an indexed array variable.\n\
+ \n\
+ Read lines from the standard input into the indexed array variable ARRAY, or\n\
+ from file descriptor FD if the -u option is supplied. The variable MAPFILE\n\
+ is the default ARRAY.\n\
+ \n\
+ Options:\n\
+ -n count Copy at most COUNT lines. If COUNT is 0, all lines are copied.\n\
+ -O origin Begin assigning to ARRAY at index ORIGIN. The default index is 0.\n\
+ -s count Discard the first COUNT lines read.\n\
+ -t Remove a trailing newline from each line read.\n\
+ -u fd Read lines from file descriptor FD instead of the standard input.\n\
+ -C callback Evaluate CALLBACK each time QUANTUM lines are read.\n\
+ -c quantum Specify the number of lines read between each call to CALLBACK.\n\
+ \n\
+ Arguments:\n\
+ ARRAY Array variable name to use for file data.\n\
+ \n\
+ If -C is supplied without -c, the default quantum is 5000. When\n\
+ CALLBACK is evaluated, it is supplied the index of the next array\n\
+ element to be assigned as an additional argument.\n\
+ \n\
+ If not supplied with an explicit origin, mapfile will clear ARRAY before\n\
+ assigning to it.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or ARRAY is readonly or\n\
+ not an indexed array."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const readarray_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Read lines from a file into an array variable.\n\
+ \n\
+ A synonym for `mapfile'."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const printf_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Formats and prints ARGUMENTS under control of the FORMAT.\n\
+ \n\
+ Options:\n\
+ -v var assign the output to shell variable VAR rather than\n\
+ display it on the standard output\n\
+ \n\
+ FORMAT is a character string which contains three types of objects: plain\n\
+ characters, which are simply copied to standard output; character escape\n\
+ sequences, which are converted and copied to the standard output; and\n\
+ format specifications, each of which causes printing of the next successive\n\
+ argument.\n\
+ \n\
+ In addition to the standard format specifications described in printf(1)\n\
+ and printf(3), printf interprets:\n\
+ \n\
+ %b expand backslash escape sequences in the corresponding argument\n\
+ %q quote the argument in a way that can be reused as shell input\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or a write or assignment\n\
+ error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (PUSHD_AND_POPD)
+char * const pushd_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Add directories to stack.\n\
+ \n\
+ Adds a directory to the top of the directory stack, or rotates\n\
+ the stack, making the new top of the stack the current working\n\
+ directory. With no arguments, exchanges the top two directories.\n\
+ \n\
+ Options:\n\
+ -n Suppresses the normal change of directory when adding\n\
+ directories to the stack, so only the stack is manipulated.\n\
+ \n\
+ Arguments:\n\
+ +N Rotates the stack so that the Nth directory (counting\n\
+ from the left of the list shown by `dirs', starting with\n\
+ zero) is at the top.\n\
+ \n\
+ -N Rotates the stack so that the Nth directory (counting\n\
+ from the right of the list shown by `dirs', starting with\n\
+ zero) is at the top.\n\
+ \n\
+ dir Adds DIR to the directory stack at the top, making it the\n\
+ new current working directory.\n\
+ \n\
+ The `dirs' builtin displays the directory stack.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid argument is supplied or the directory\n\
+ change fails."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* PUSHD_AND_POPD */
+#if defined (PUSHD_AND_POPD)
+char * const popd_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Remove directories from stack.\n\
+ \n\
+ Removes entries from the directory stack. With no arguments, removes\n\
+ the top directory from the stack, and changes to the new top directory.\n\
+ \n\
+ Options:\n\
+ -n Suppresses the normal change of directory when removing\n\
+ directories from the stack, so only the stack is manipulated.\n\
+ \n\
+ Arguments:\n\
+ +N Removes the Nth entry counting from the left of the list\n\
+ shown by `dirs', starting with zero. For example: `popd +0'\n\
+ removes the first directory, `popd +1' the second.\n\
+ \n\
+ -N Removes the Nth entry counting from the right of the list\n\
+ shown by `dirs', starting with zero. For example: `popd -0'\n\
+ removes the last directory, `popd -1' the next to last.\n\
+ \n\
+ The `dirs' builtin displays the directory stack.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid argument is supplied or the directory\n\
+ change fails."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* PUSHD_AND_POPD */
+#if defined (PUSHD_AND_POPD)
+char * const dirs_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display directory stack.\n\
+ \n\
+ Display the list of currently remembered directories. Directories\n\
+ find their way onto the list with the `pushd' command; you can get\n\
+ back up through the list with the `popd' command.\n\
+ \n\
+ Options:\n\
+ -c clear the directory stack by deleting all of the elements\n\
+ -l do not print tilde-prefixed versions of directories relative\n\
+ to your home directory\n\
+ -p print the directory stack with one entry per line\n\
+ -v print the directory stack with one entry per line prefixed\n\
+ with its position in the stack\n\
+ \n\
+ Arguments:\n\
+ +N Displays the Nth entry counting from the left of the list shown by\n\
+ dirs when invoked without options, starting with zero.\n\
+ \n\
+ -N Displays the Nth entry counting from the right of the list shown by\n\
+ dirs when invoked without options, starting with zero.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* PUSHD_AND_POPD */
+char * const read_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Read a line from the standard input and split it into fields.\n\
+ \n\
+ Reads a single line from the standard input, or from file descriptor FD\n\
+ if the -u option is supplied. The line is split into fields as with word\n\
+ splitting, and the first word is assigned to the first NAME, the second\n\
+ word to the second NAME, and so on, with any leftover words assigned to\n\
+ the last NAME. Only the characters found in $IFS are recognized as word\n\
+ delimiters.\n\
+ \n\
+ If no NAMEs are supplied, the line read is stored in the REPLY variable.\n\
+ \n\
+ Options:\n\
+ -a array assign the words read to sequential indices of the array\n\
+ variable ARRAY, starting at zero\n\
+ -d delim continue until the first character of DELIM is read, rather\n\
+ than newline\n\
+ -e use Readline to obtain the line in an interactive shell\n\
+ -i text Use TEXT as the initial text for Readline\n\
+ -n nchars return after reading NCHARS characters rather than waiting\n\
+ for a newline, but honor a delimiter if fewer than NCHARS\n\
+ characters are read before the delimiter\n\
+ -N nchars return only after reading exactly NCHARS characters, unless\n\
+ EOF is encountered or read times out, ignoring any delimiter\n\
+ -p prompt output the string PROMPT without a trailing newline before\n\
+ attempting to read\n\
+ -r do not allow backslashes to escape any characters\n\
+ -s do not echo input coming from a terminal\n\
+ -t timeout time out and return failure if a complete line of input is\n\
+ not read withint TIMEOUT seconds. The value of the TMOUT\n\
+ variable is the default timeout. TIMEOUT may be a\n\
+ fractional number. If TIMEOUT is 0, read returns success only\n\
+ if input is available on the specified file descriptor. The\n\
+ exit status is greater than 128 if the timeout is exceeded\n\
+ -u fd read from file descriptor FD instead of the standard input\n\
+ \n\
+ Exit Status:\n\
+ The return code is zero, unless end-of-file is encountered, read times out,\n\
+ or an invalid file descriptor is supplied as the argument to -u."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const for_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands for each member in a list.\n\
+ \n\
+ The `for' loop executes a sequence of commands for each member in a\n\
+ list of items. If `in WORDS ...;' is not present, then `in \"$@\"' is\n\
+ assumed. For each element in WORDS, NAME is set to that element, and\n\
+ the COMMANDS are executed.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const arith_for_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Arithmetic for loop.\n\
+ \n\
+ Equivalent to\n\
+ (( EXP1 ))\n\
+ while (( EXP2 )); do\n\
+ COMMANDS\n\
+ (( EXP3 ))\n\
+ done\n\
+ EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is\n\
+ omitted, it behaves as if it evaluates to 1.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const select_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Select words from a list and execute commands.\n\
+ \n\
+ The WORDS are expanded, generating a list of words. The\n\
+ set of expanded words is printed on the standard error, each\n\
+ preceded by a number. If `in WORDS' is not present, `in \"$@\"'\n\
+ is assumed. The PS3 prompt is then displayed and a line read\n\
+ from the standard input. If the line consists of the number\n\
+ corresponding to one of the displayed words, then NAME is set\n\
+ to that word. If the line is empty, WORDS and the prompt are\n\
+ redisplayed. If EOF is read, the command completes. Any other\n\
+ value read causes NAME to be set to null. The line read is saved\n\
+ in the variable REPLY. COMMANDS are executed after each selection\n\
+ until a break command is executed.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const time_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Report time consumed by pipeline's execution.\n\
+ \n\
+ Execute PIPELINE and print a summary of the real time, user CPU time,\n\
+ and system CPU time spent executing PIPELINE when it terminates.\n\
+ \n\
+ Options:\n\
+ -p print the timing summary in the portable Posix format\n\
+ \n\
+ The value of the TIMEFORMAT variable is used as the output format.\n\
+ \n\
+ Exit Status:\n\
+ The return status is the return status of PIPELINE."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const case_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands based on pattern matching.\n\
+ \n\
+ Selectively execute COMMANDS based upon WORD matching PATTERN. The\n\
+ `|' is used to separate multiple patterns.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const if_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands based on conditional.\n\
+ \n\
+ The `if COMMANDS' list is executed. If its exit status is zero, then the\n\
+ `then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is\n\
+ executed in turn, and if its exit status is zero, the corresponding\n\
+ `then COMMANDS' list is executed and the if command completes. Otherwise,\n\
+ the `else COMMANDS' list is executed, if present. The exit status of the\n\
+ entire construct is the exit status of the last command executed, or zero\n\
+ if no condition tested true.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const while_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands as long as a test succeeds.\n\
+ \n\
+ Expand and execute COMMANDS as long as the final command in the\n\
+ `while' COMMANDS has an exit status of zero.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const until_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands as long as a test does not succeed.\n\
+ \n\
+ Expand and execute COMMANDS as long as the final command in the\n\
+ `until' COMMANDS has an exit status which is not zero.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const coproc_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Create a coprocess named NAME.\n\
+ \n\
+ Execute COMMAND asynchronously, with the standard output and standard\n\
+ input of the command connected via a pipe to file descriptors assigned\n\
+ to indices 0 and 1 of an array variable NAME in the executing shell.\n\
+ The default NAME is \"COPROC\".\n\
+ \n\
+ Exit Status:\n\
+ Returns the exit status of COMMAND."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const function_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Define shell function.\n\
+ \n\
+ Create a shell function named NAME. When invoked as a simple command,\n\
+ NAME runs COMMANDs in the calling shell's context. When NAME is invoked,\n\
+ the arguments are passed to the function as $1...$n, and the function's\n\
+ name is in $FUNCNAME.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless NAME is readonly."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const grouping_braces_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Group commands as a unit.\n\
+ \n\
+ Run a set of commands in a group. This is one way to redirect an\n\
+ entire set of commands.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const fg_percent_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Resume job in foreground.\n\
+ \n\
+ Equivalent to the JOB_SPEC argument to the `fg' command. Resume a\n\
+ stopped or background job. JOB_SPEC can specify either a job name\n\
+ or a job number. Following JOB_SPEC with a `&' places the job in\n\
+ the background, as if the job specification had been supplied as an\n\
+ argument to `bg'.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the resumed job."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const arith_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Evaluate arithmetic expression.\n\
+ \n\
+ The EXPRESSION is evaluated according to the rules for arithmetic\n\
+ evaluation. Equivalent to \"let EXPRESSION\".\n\
+ \n\
+ Exit Status:\n\
+ Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const conditional_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute conditional command.\n\
+ \n\
+ Returns a status of 0 or 1 depending on the evaluation of the conditional\n\
+ expression EXPRESSION. Expressions are composed of the same primaries used\n\
+ by the `test' builtin, and may be combined using the following operators:\n\
+ \n\
+ ( EXPRESSION ) Returns the value of EXPRESSION\n\
+ ! EXPRESSION True if EXPRESSION is false; else false\n\
+ EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false\n\
+ EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false\n\
+ \n\
+ When the `==' and `!=' operators are used, the string to the right of\n\
+ the operator is used as a pattern and pattern matching is performed.\n\
+ When the `=~' operator is used, the string to the right of the operator\n\
+ is matched as a regular expression.\n\
+ \n\
+ The && and || operators do not evaluate EXPR2 if EXPR1 is sufficient to\n\
+ determine the expression's value.\n\
+ \n\
+ Exit Status:\n\
+ 0 or 1 depending on value of EXPRESSION."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const variable_help_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Common shell variable names and usage.\n\
+ \n\
+ BASH_VERSION Version information for this Bash.\n\
+ CDPATH A colon-separated list of directories to search\n\
+ for directories given as arguments to `cd'.\n\
+ GLOBIGNORE A colon-separated list of patterns describing filenames to\n\
+ be ignored by pathname expansion.\n\
+ HISTFILE The name of the file where your command history is stored.\n\
+ HISTFILESIZE The maximum number of lines this file can contain.\n\
+ HISTSIZE The maximum number of history lines that a running\n\
+ shell can access.\n\
+ HOME The complete pathname to your login directory.\n\
+ HOSTNAME The name of the current host.\n\
+ HOSTTYPE The type of CPU this version of Bash is running under.\n\
+ IGNOREEOF Controls the action of the shell on receipt of an EOF\n\
+ character as the sole input. If set, then the value\n\
+ of it is the number of EOF characters that can be seen\n\
+ in a row on an empty line before the shell will exit\n\
+ (default 10). When unset, EOF signifies the end of input.\n\
+ MACHTYPE A string describing the current system Bash is running on.\n\
+ MAILCHECK How often, in seconds, Bash checks for new mail.\n\
+ MAILPATH A colon-separated list of filenames which Bash checks\n\
+ for new mail.\n\
+ OSTYPE The version of Unix this version of Bash is running on.\n\
+ PATH A colon-separated list of directories to search when\n\
+ looking for commands.\n\
+ PROMPT_COMMAND A command to be executed before the printing of each\n\
+ primary prompt.\n\
+ PS1 The primary prompt string.\n\
+ PS2 The secondary prompt string.\n\
+ PWD The full pathname of the current directory.\n\
+ SHELLOPTS A colon-separated list of enabled shell options.\n\
+ TERM The name of the current terminal type.\n\
+ TIMEFORMAT The output format for timing statistics displayed by the\n\
+ `time' reserved word.\n\
+ auto_resume Non-null means a command word appearing on a line by\n\
+ itself is first looked for in the list of currently\n\
+ stopped jobs. If found there, that job is foregrounded.\n\
+ A value of `exact' means that the command word must\n\
+ exactly match a command in the list of stopped jobs. A\n\
+ value of `substring' means that the command word must\n\
+ match a substring of the job. Any other value means that\n\
+ the command must be a prefix of a stopped job.\n\
+ histchars Characters controlling history expansion and quick\n\
+ substitution. The first character is the history\n\
+ substitution character, usually `!'. The second is\n\
+ the `quick substitution' character, usually `^'. The\n\
+ third is the `history comment' character, usually `#'.\n\
+ HISTIGNORE A colon-separated list of patterns used to decide which\n\
+ commands should be saved on the history list.\n\
+"),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const return_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Return from a shell function.\n\
+ \n\
+ Causes a function or sourced script to exit with the return value\n\
+ specified by N. If N is omitted, the return status is that of the\n\
+ last command executed within the function or script.\n\
+ \n\
+ Exit Status:\n\
+ Returns N, or failure if the shell is not executing a function or script."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const export_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Set export attribute for shell variables.\n\
+ \n\
+ Marks each NAME for automatic export to the environment of subsequently\n\
+ executed commands. If VALUE is supplied, assign VALUE before exporting.\n\
+ \n\
+ Options:\n\
+ -f refer to shell functions\n\
+ -n remove the export property from each NAME\n\
+ -p display a list of all exported variables and functions\n\
+ \n\
+ An argument of `--' disables further option processing.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or NAME is invalid."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const readonly_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Mark shell variables as unchangeable.\n\
+ \n\
+ Mark each NAME as read-only; the values of these NAMEs may not be\n\
+ changed by subsequent assignment. If VALUE is supplied, assign VALUE\n\
+ before marking as read-only.\n\
+ \n\
+ Options:\n\
+ -a refer to indexed array variables\n\
+ -A refer to associative array variables\n\
+ -f refer to shell functions\n\
+ -p display a list of all readonly variables and functions\n\
+ \n\
+ An argument of `--' disables further option processing.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or NAME is invalid."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const set_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Set or unset values of shell options and positional parameters.\n\
+ \n\
+ Change the value of shell attributes and positional parameters, or\n\
+ display the names and values of shell variables.\n\
+ \n\
+ Options:\n\
+ -a Mark variables which are modified or created for export.\n\
+ -b Notify of job termination immediately.\n\
+ -e Exit immediately if a command exits with a non-zero status.\n\
+ -f Disable file name generation (globbing).\n\
+ -h Remember the location of commands as they are looked up.\n\
+ -k All assignment arguments are placed in the environment for a\n\
+ command, not just those that precede the command name.\n\
+ -m Job control is enabled.\n\
+ -n Read commands but do not execute them.\n\
+ -o option-name\n\
+ Set the variable corresponding to option-name:\n\
+ allexport same as -a\n\
+ braceexpand same as -B\n\
+ emacs use an emacs-style line editing interface\n\
+ errexit same as -e\n\
+ errtrace same as -E\n\
+ functrace same as -T\n\
+ hashall same as -h\n\
+ histexpand same as -H\n\
+ history enable command history\n\
+ ignoreeof the shell will not exit upon reading EOF\n\
+ interactive-comments\n\
+ allow comments to appear in interactive commands\n\
+ keyword same as -k\n\
+ monitor same as -m\n\
+ noclobber same as -C\n\
+ noexec same as -n\n\
+ noglob same as -f\n\
+ nolog currently accepted but ignored\n\
+ notify same as -b\n\
+ nounset same as -u\n\
+ onecmd same as -t\n\
+ physical same as -P\n\
+ pipefail the return value of a pipeline is the status of\n\
+ the last command to exit with a non-zero status,\n\
+ or zero if no command exited with a non-zero status\n\
+ posix change the behavior of bash where the default\n\
+ operation differs from the Posix standard to\n\
+ match the standard\n\
+ privileged same as -p\n\
+ verbose same as -v\n\
+ vi use a vi-style line editing interface\n\
+ xtrace same as -x\n\
+ -p Turned on whenever the real and effective user ids do not match.\n\
+ Disables processing of the $ENV file and importing of shell\n\
+ functions. Turning this option off causes the effective uid and\n\
+ gid to be set to the real uid and gid.\n\
+ -t Exit after reading and executing one command.\n\
+ -u Treat unset variables as an error when substituting.\n\
+ -v Print shell input lines as they are read.\n\
+ -x Print commands and their arguments as they are executed.\n\
+ -B the shell will perform brace expansion\n\
+ -C If set, disallow existing regular files to be overwritten\n\
+ by redirection of output.\n\
+ -E If set, the ERR trap is inherited by shell functions.\n\
+ -H Enable ! style history substitution. This flag is on\n\
+ by default when the shell is interactive.\n\
+ -P If set, do not follow symbolic links when executing commands\n\
+ such as cd which change the current directory.\n\
+ -T If set, the DEBUG trap is inherited by shell functions.\n\
+ - Assign any remaining arguments to the positional parameters.\n\
+ The -x and -v options are turned off.\n\
+ \n\
+ Using + rather than - causes these flags to be turned off. The\n\
+ flags can also be used upon invocation of the shell. The current\n\
+ set of flags may be found in $-. The remaining n ARGs are positional\n\
+ parameters and are assigned, in order, to $1, $2, .. $n. If no\n\
+ ARGs are given, all shell variables are printed.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const unset_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Unset values and attributes of shell variables and functions.\n\
+ \n\
+ For each NAME, remove the corresponding variable or function.\n\
+ \n\
+ Options:\n\
+ -f treat each NAME as a shell function\n\
+ -v treat each NAME as a shell variable\n\
+ \n\
+ Without options, unset first tries to unset a variable, and if that fails,\n\
+ tries to unset a function.\n\
+ \n\
+ Some variables cannot be unset; also see `readonly'.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is given or a NAME is read-only."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const shift_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Shift positional parameters.\n\
+ \n\
+ Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is\n\
+ not given, it is assumed to be 1.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless N is negative or greater than $#."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const shopt_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Set and unset shell options.\n\
+ \n\
+ Change the setting of each shell option OPTNAME. Without any option\n\
+ arguments, list all shell options with an indication of whether or not each\n\
+ is set.\n\
+ \n\
+ Options:\n\
+ -o restrict OPTNAMEs to those defined for use with `set -o'\n\
+ -p print each shell option with an indication of its status\n\
+ -q suppress output\n\
+ -s enable (set) each OPTNAME\n\
+ -u disable (unset) each OPTNAME\n\
+ \n\
+ Exit Status:\n\
+ Returns success if OPTNAME is enabled; fails if an invalid option is\n\
+ given or OPTNAME is disabled."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const source_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands from a file in the current shell.\n\
+ \n\
+ Read and execute commands from FILENAME in the current shell. The\n\
+ entries in $PATH are used to find the directory containing FILENAME.\n\
+ If any ARGUMENTS are supplied, they become the positional parameters\n\
+ when FILENAME is executed.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed in FILENAME; fails if\n\
+ FILENAME cannot be read."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const dot_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Execute commands from a file in the current shell.\n\
+ \n\
+ Read and execute commands from FILENAME in the current shell. The\n\
+ entries in $PATH are used to find the directory containing FILENAME.\n\
+ If any ARGUMENTS are supplied, they become the positional parameters\n\
+ when FILENAME is executed.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of the last command executed in FILENAME; fails if\n\
+ FILENAME cannot be read."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (JOB_CONTROL)
+char * const suspend_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Suspend shell execution.\n\
+ \n\
+ Suspend the execution of this shell until it receives a SIGCONT signal.\n\
+ Unless forced, login shells cannot be suspended.\n\
+ \n\
+ Options:\n\
+ -f force the suspend, even if the shell is a login shell\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless job control is not enabled or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* JOB_CONTROL */
+char * const test_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Evaluate conditional expression.\n\
+ \n\
+ Exits with a status of 0 (true) or 1 (false) depending on\n\
+ the evaluation of EXPR. Expressions may be unary or binary. Unary\n\
+ expressions are often used to examine the status of a file. There\n\
+ are string operators as well, and numeric comparison operators.\n\
+ \n\
+ File operators:\n\
+ \n\
+ -a FILE True if file exists.\n\
+ -b FILE True if file is block special.\n\
+ -c FILE True if file is character special.\n\
+ -d FILE True if file is a directory.\n\
+ -e FILE True if file exists.\n\
+ -f FILE True if file exists and is a regular file.\n\
+ -g FILE True if file is set-group-id.\n\
+ -h FILE True if file is a symbolic link.\n\
+ -L FILE True if file is a symbolic link.\n\
+ -k FILE True if file has its `sticky' bit set.\n\
+ -p FILE True if file is a named pipe.\n\
+ -r FILE True if file is readable by you.\n\
+ -s FILE True if file exists and is not empty.\n\
+ -S FILE True if file is a socket.\n\
+ -t FD True if FD is opened on a terminal.\n\
+ -u FILE True if the file is set-user-id.\n\
+ -w FILE True if the file is writable by you.\n\
+ -x FILE True if the file is executable by you.\n\
+ -O FILE True if the file is effectively owned by you.\n\
+ -G FILE True if the file is effectively owned by your group.\n\
+ -N FILE True if the file has been modified since it was last read.\n\
+ \n\
+ FILE1 -nt FILE2 True if file1 is newer than file2 (according to\n\
+ modification date).\n\
+ \n\
+ FILE1 -ot FILE2 True if file1 is older than file2.\n\
+ \n\
+ FILE1 -ef FILE2 True if file1 is a hard link to file2.\n\
+ \n\
+ String operators:\n\
+ \n\
+ -z STRING True if string is empty.\n\
+ \n\
+ -n STRING\n\
+ STRING True if string is not empty.\n\
+ \n\
+ STRING1 = STRING2\n\
+ True if the strings are equal.\n\
+ STRING1 != STRING2\n\
+ True if the strings are not equal.\n\
+ STRING1 < STRING2\n\
+ True if STRING1 sorts before STRING2 lexicographically.\n\
+ STRING1 > STRING2\n\
+ True if STRING1 sorts after STRING2 lexicographically.\n\
+ \n\
+ Other operators:\n\
+ \n\
+ -o OPTION True if the shell option OPTION is enabled.\n\
+ ! EXPR True if expr is false.\n\
+ EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.\n\
+ EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.\n\
+ \n\
+ arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,\n\
+ -lt, -le, -gt, or -ge.\n\
+ \n\
+ Arithmetic binary operators return true if ARG1 is equal, not-equal,\n\
+ less-than, less-than-or-equal, greater-than, or greater-than-or-equal\n\
+ than ARG2.\n\
+ \n\
+ Exit Status:\n\
+ Returns success if EXPR evaluates to true; fails if EXPR evaluates to\n\
+ false or an invalid argument is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const test_bracket_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Evaluate conditional expression.\n\
+ \n\
+ This is a synonym for the \"test\" builtin, but the last argument must\n\
+ be a literal `]', to match the opening `['."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const times_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display process times.\n\
+ \n\
+ Prints the accumulated user and system times for the shell and all of its\n\
+ child processes.\n\
+ \n\
+ Exit Status:\n\
+ Always succeeds."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const trap_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Trap signals and other events.\n\
+ \n\
+ Defines and activates handlers to be run when the shell receives signals\n\
+ or other conditions.\n\
+ \n\
+ ARG is a command to be read and executed when the shell receives the\n\
+ signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC\n\
+ is supplied) or `-', each specified signal is reset to its original\n\
+ value. If ARG is the null string each SIGNAL_SPEC is ignored by the\n\
+ shell and by the commands it invokes.\n\
+ \n\
+ If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If\n\
+ a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command.\n\
+ \n\
+ If no arguments are supplied, trap prints the list of commands associated\n\
+ with each signal.\n\
+ \n\
+ Options:\n\
+ -l print a list of signal names and their corresponding numbers\n\
+ -p display the trap commands associated with each SIGNAL_SPEC\n\
+ \n\
+ Each SIGNAL_SPEC is either a signal name in <signal.h> or a signal number.\n\
+ Signal names are case insensitive and the SIG prefix is optional. A\n\
+ signal may be sent to the shell with \"kill -signal $$\".\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless a SIGSPEC is invalid or an invalid option is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+char * const type_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display information about command type.\n\
+ \n\
+ For each NAME, indicate how it would be interpreted if used as a\n\
+ command name.\n\
+ \n\
+ Options:\n\
+ -a display all locations containing an executable named NAME;\n\
+ includes aliases, builtins, and functions, if and only if\n\
+ the `-p' option is not also used\n\
+ -f suppress shell function lookup\n\
+ -P force a PATH search for each NAME, even if it is an alias,\n\
+ builtin, or function, and returns the name of the disk file\n\
+ that would be executed\n\
+ -p returns either the name of the disk file that would be executed,\n\
+ or nothing if `type -t NAME' would not return `file'.\n\
+ -t output a single word which is one of `alias', `keyword',\n\
+ `function', `builtin', `file' or `', if NAME is an alias, shell\n\
+ reserved word, shell function, shell builtin, disk file, or not\n\
+ found, respectively\n\
+ \n\
+ Arguments:\n\
+ NAME Command name to be interpreted.\n\
+ \n\
+ Exit Status:\n\
+ Returns success if all of the NAMEs are found; fails if any are not found."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if !defined (_MINIX)
+char * const ulimit_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Modify shell resource limits.\n\
+ \n\
+ Provides control over the resources available to the shell and processes\n\
+ it creates, on systems that allow such control.\n\
+ \n\
+ Options:\n\
+ -S use the `soft' resource limit\n\
+ -H use the `hard' resource limit\n\
+ -a all current limits are reported\n\
+ -b the socket buffer size\n\
+ -c the maximum size of core files created\n\
+ -d the maximum size of a process's data segment\n\
+ -e the maximum scheduling priority (`nice')\n\
+ -f the maximum size of files written by the shell and its children\n\
+ -i the maximum number of pending signals\n\
+ -l the maximum size a process may lock into memory\n\
+ -m the maximum resident set size\n\
+ -n the maximum number of open file descriptors\n\
+ -p the pipe buffer size\n\
+ -q the maximum number of bytes in POSIX message queues\n\
+ -r the maximum real-time scheduling priority\n\
+ -s the maximum stack size\n\
+ -t the maximum amount of cpu time in seconds\n\
+ -u the maximum number of user processes\n\
+ -v the size of virtual memory\n\
+ -x the maximum number of file locks\n\
+ \n\
+ If LIMIT is given, it is the new value of the specified resource; the\n\
+ special LIMIT values `soft', `hard', and `unlimited' stand for the\n\
+ current soft limit, the current hard limit, and no limit, respectively.\n\
+ Otherwise, the current value of the specified resource is printed. If\n\
+ no option is given, then -f is assumed.\n\
+ \n\
+ Values are in 1024-byte increments, except for -t, which is in seconds,\n\
+ -p, which is in increments of 512 bytes, and -u, which is an unscaled\n\
+ number of processes.\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless an invalid option is supplied or an error occurs."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* !_MINIX */
+char * const umask_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Display or set file mode mask.\n\
+ \n\
+ Sets the user file-creation mask to MODE. If MODE is omitted, prints\n\
+ the current value of the mask.\n\
+ \n\
+ If MODE begins with a digit, it is interpreted as an octal number;\n\
+ otherwise it is a symbolic mode string like that accepted by chmod(1).\n\
+ \n\
+ Options:\n\
+ -p if MODE is omitted, output in a form that may be reused as input\n\
+ -S makes the output symbolic; otherwise an octal number is output\n\
+ \n\
+ Exit Status:\n\
+ Returns success unless MODE is invalid or an invalid option is given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#if defined (JOB_CONTROL)
+char * const wait_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Wait for job completion and return exit status.\n\
+ \n\
+ Waits for the process identified by ID, which may be a process ID or a\n\
+ job specification, and reports its termination status. If ID is not\n\
+ given, waits for all currently active child processes, and the return\n\
+ status is zero. If ID is a a job specification, waits for all processes\n\
+ in the job's pipeline.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of ID; fails if ID is invalid or an invalid option is\n\
+ given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* JOB_CONTROL */
+#if !defined (JOB_CONTROL)
+char * const wait_doc[] = {
+#if defined (HELP_BUILTIN)
+N_("Wait for process completion and return exit status.\n\
+ \n\
+ Waits for the specified process and reports its termination status. If\n\
+ PID is not given, all currently active child processes are waited for,\n\
+ and the return code is zero. PID must be a process ID.\n\
+ \n\
+ Exit Status:\n\
+ Returns the status of ID; fails if ID is invalid or an invalid option is\n\
+ given."),
+#endif /* HELP_BUILTIN */
+ (char *)NULL
+};
+#endif /* !JOB_CONTROL */
diff --git a/builtins/caller.c b/builtins/caller.c
new file mode 100644
index 0000000..d40438c
--- /dev/null
+++ b/builtins/caller.c
@@ -0,0 +1,118 @@
+/* caller.c, created from caller.def. */
+#line 22 "./caller.def"
+
+#line 40 "./caller.def"
+
+#include <config.h>
+#include <stdio.h>
+#include "chartypes.h"
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "builtext.h"
+#include "bashgetopt.h"
+
+#ifdef LOADABLE_BUILTIN
+# include "builtins.h"
+#endif
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+int
+caller_builtin (list)
+ WORD_LIST *list;
+{
+#if !defined (ARRAY_VARS)
+ printf ("1 NULL\n");
+ return (EXECUTION_FAILURE);
+#else
+ SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
+ ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
+ char *funcname_s, *source_s, *lineno_s;
+ intmax_t num;
+
+ GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
+ GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
+ GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
+
+ if (bash_lineno_a == 0 || array_empty (bash_lineno_a))
+ return (EXECUTION_FAILURE);
+
+ if (bash_source_a == 0 || array_empty (bash_source_a))
+ return (EXECUTION_FAILURE);
+
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend; /* skip over possible `--' */
+
+ /* If there is no argument list, then give short form: line filename. */
+ if (list == 0)
+ {
+ lineno_s = array_reference (bash_lineno_a, 0);
+ source_s = array_reference (bash_source_a, 1);
+ printf("%s %s\n", lineno_s ? lineno_s : "NULL", source_s ? source_s : "NULL");
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (funcname_a == 0 || array_empty (funcname_a))
+ return (EXECUTION_FAILURE);
+
+ if (legal_number (list->word->word, &num))
+ {
+ lineno_s = array_reference (bash_lineno_a, num);
+ source_s = array_reference (bash_source_a, num+1);
+ funcname_s = array_reference (funcname_a, num+1);
+
+ if (lineno_s == NULL|| source_s == NULL || funcname_s == NULL)
+ return (EXECUTION_FAILURE);
+
+ printf("%s %s %s\n", lineno_s, funcname_s, source_s);
+ }
+ else
+ {
+ sh_invalidnum (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+
+ return (EXECUTION_SUCCESS);
+#endif
+}
+
+#ifdef LOADABLE_BUILTIN
+static char *caller_doc[] = {
+N_("Returns the context of the current subroutine call.\n\
+ \n\
+ Without EXPR, returns "$line $filename". With EXPR, returns\n\
+ "$line $subroutine $filename"; this extra information can be used to\n\
+ provide a stack trace.\n\
+ \n\
+ The value of EXPR indicates how many call frames to go back before the\n\
+ current one; the top frame is frame 0."),
+ (char *)NULL
+};
+
+struct builtin caller_struct = {
+ "caller",
+ caller_builtin,
+ BUILTIN_ENABLED,
+ caller_doc,
+ "caller [EXPR]",
+ 0
+};
+
+#endif /* LOADABLE_BUILTIN */
diff --git a/builtins/cd.c b/builtins/cd.c
new file mode 100644
index 0000000..85be7d1
--- /dev/null
+++ b/builtins/cd.c
@@ -0,0 +1,453 @@
+/* cd.c, created from cd.def. */
+#line 22 "./cd.def"
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include "posixdir.h"
+#include "posixstat.h"
+#ifndef _MINIX
+#include <sys/param.h>
+#endif
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include <errno.h>
+#include <tilde/tilde.h>
+
+#include "../shell.h"
+#include "../flags.h"
+#include "maxpath.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int posixly_correct;
+extern int array_needs_making;
+extern const char * const bash_getcwd_errstr;
+
+static int bindpwd __P((int));
+static void setpwd __P((char *));
+static char *resetpwd __P((char *));
+static int change_to_directory __P((char *, int));
+
+/* Change this to 1 to get cd spelling correction by default. */
+int cdspelling = 0;
+
+int cdable_vars;
+
+#line 97 "./cd.def"
+
+/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
+static void
+setpwd (dirname)
+ char *dirname;
+{
+ int old_anm;
+ SHELL_VAR *tvar;
+
+ old_anm = array_needs_making;
+ tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
+ if (old_anm == 0 && array_needs_making && exported_p (tvar))
+ {
+ update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
+ array_needs_making = 0;
+ }
+}
+
+static int
+bindpwd (no_symlinks)
+ int no_symlinks;
+{
+ char *dirname, *pwdvar;
+ int old_anm, r;
+ SHELL_VAR *tvar;
+
+ r = sh_chkwrite (EXECUTION_SUCCESS);
+
+#define tcwd the_current_working_directory
+ dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
+ : get_working_directory ("cd");
+#undef tcwd
+
+ old_anm = array_needs_making;
+ pwdvar = get_string_value ("PWD");
+
+ tvar = bind_variable ("OLDPWD", pwdvar, 0);
+ if (old_anm == 0 && array_needs_making && exported_p (tvar))
+ {
+ update_export_env_inplace ("OLDPWD=", 7, pwdvar);
+ array_needs_making = 0;
+ }
+
+ setpwd (dirname);
+
+ if (dirname && dirname != the_current_working_directory)
+ free (dirname);
+
+ return (r);
+}
+
+/* Call get_working_directory to reset the value of
+ the_current_working_directory () */
+static char *
+resetpwd (caller)
+ char *caller;
+{
+ char *tdir;
+
+ FREE (the_current_working_directory);
+ the_current_working_directory = (char *)NULL;
+ tdir = get_working_directory (caller);
+ return (tdir);
+}
+
+#define LCD_DOVARS 0x001
+#define LCD_DOSPELL 0x002
+#define LCD_PRINTPATH 0x004
+#define LCD_FREEDIRNAME 0x010
+
+/* This builtin is ultimately the way that all user-visible commands should
+ change the current working directory. It is called by cd_to_string (),
+ so the programming interface is simple, and it handles errors and
+ restrictions properly. */
+int
+cd_builtin (list)
+ WORD_LIST *list;
+{
+ char *dirname, *cdpath, *path, *temp;
+ int path_index, no_symlinks, opt, lflag;
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted)
+ {
+ sh_restricted ((char *)NULL);
+ return (EXECUTION_FAILURE);
+ }
+#endif /* RESTRICTED_SHELL */
+
+ no_symlinks = no_symbolic_links;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "LP")) != -1)
+ {
+ switch (opt)
+ {
+ case 'P':
+ no_symlinks = 1;
+ break;
+ case 'L':
+ no_symlinks = 0;
+ break;
+ default:
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ }
+ list = loptend;
+
+ lflag = (cdable_vars ? LCD_DOVARS : 0) |
+ ((interactive && cdspelling) ? LCD_DOSPELL : 0);
+
+ if (list == 0)
+ {
+ /* `cd' without arguments is equivalent to `cd $HOME' */
+ dirname = get_string_value ("HOME");
+
+ if (dirname == 0)
+ {
+ builtin_error (_("HOME not set"));
+ return (EXECUTION_FAILURE);
+ }
+ lflag = 0;
+ }
+ else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
+ {
+ /* This is `cd -', equivalent to `cd $OLDPWD' */
+ dirname = get_string_value ("OLDPWD");
+
+ if (dirname == 0)
+ {
+ builtin_error (_("OLDPWD not set"));
+ return (EXECUTION_FAILURE);
+ }
+#if 0
+ lflag = interactive ? LCD_PRINTPATH : 0;
+#else
+ lflag = LCD_PRINTPATH; /* According to SUSv3 */
+#endif
+ }
+ else if (absolute_pathname (list->word->word))
+ dirname = list->word->word;
+ else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
+ {
+ dirname = list->word->word;
+
+ /* Find directory in $CDPATH. */
+ path_index = 0;
+ while (path = extract_colon_unit (cdpath, &path_index))
+ {
+ /* OPT is 1 if the path element is non-empty */
+ opt = path[0] != '\0';
+ temp = sh_makepath (path, dirname, MP_DOTILDE);
+ free (path);
+
+ if (change_to_directory (temp, no_symlinks))
+ {
+ /* POSIX.2 says that if a nonempty directory from CDPATH
+ is used to find the directory to change to, the new
+ directory name is echoed to stdout, whether or not
+ the shell is interactive. */
+ if (opt && (path = no_symlinks ? temp : the_current_working_directory))
+ printf ("%s\n", path);
+
+ free (temp);
+#if 0
+ /* Posix.2 says that after using CDPATH, the resultant
+ value of $PWD will not contain `.' or `..'. */
+ return (bindpwd (posixly_correct || no_symlinks));
+#else
+ return (bindpwd (no_symlinks));
+#endif
+ }
+ else
+ free (temp);
+ }
+
+ /* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
+ try the current directory, so we just punt now with an error
+ message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
+ is so we don't mistakenly treat a CDPATH value of "" as not
+ specifying the current directory. */
+ if (posixly_correct && cdpath[0])
+ {
+ builtin_error ("%s: %s", dirname, strerror (ENOENT));
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else
+ dirname = list->word->word;
+
+ /* When we get here, DIRNAME is the directory to change to. If we
+ chdir successfully, just return. */
+ if (change_to_directory (dirname, no_symlinks))
+ {
+ if (lflag & LCD_PRINTPATH)
+ printf ("%s\n", dirname);
+ return (bindpwd (no_symlinks));
+ }
+
+ /* If the user requests it, then perhaps this is the name of
+ a shell variable, whose value contains the directory to
+ change to. */
+ if (lflag & LCD_DOVARS)
+ {
+ temp = get_string_value (dirname);
+ if (temp && change_to_directory (temp, no_symlinks))
+ {
+ printf ("%s\n", temp);
+ return (bindpwd (no_symlinks));
+ }
+ }
+
+ /* If the user requests it, try to find a directory name similar in
+ spelling to the one requested, in case the user made a simple
+ typo. This is similar to the UNIX 8th and 9th Edition shells. */
+ if (lflag & LCD_DOSPELL)
+ {
+ temp = dirspell (dirname);
+ if (temp && change_to_directory (temp, no_symlinks))
+ {
+ printf ("%s\n", temp);
+ return (bindpwd (no_symlinks));
+ }
+ else
+ FREE (temp);
+ }
+
+ builtin_error ("%s: %s", dirname, strerror (errno));
+ return (EXECUTION_FAILURE);
+}
+
+#line 344 "./cd.def"
+
+/* Non-zero means that pwd always prints the physical directory, without
+ symbolic links. */
+static int verbatim_pwd;
+
+/* Print the name of the current working directory. */
+int
+pwd_builtin (list)
+ WORD_LIST *list;
+{
+ char *directory;
+ int opt, pflag;
+
+ verbatim_pwd = no_symbolic_links;
+ pflag = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "LP")) != -1)
+ {
+ switch (opt)
+ {
+ case 'P':
+ verbatim_pwd = pflag = 1;
+ break;
+ case 'L':
+ verbatim_pwd = 0;
+ break;
+ default:
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ }
+ list = loptend;
+
+#define tcwd the_current_working_directory
+
+ directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
+ : get_working_directory ("pwd");
+
+ /* Try again using getcwd() if canonicalization fails (for instance, if
+ the file system has changed state underneath bash). */
+ if ((tcwd && directory == 0) ||
+ (posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
+ directory = resetpwd ("pwd");
+
+#undef tcwd
+
+ if (directory)
+ {
+ printf ("%s\n", directory);
+ /* This is dumb but posix-mandated. */
+ if (posixly_correct && pflag)
+ setpwd (directory);
+ if (directory != the_current_working_directory)
+ free (directory);
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+ else
+ return (EXECUTION_FAILURE);
+}
+
+/* Do the work of changing to the directory NEWDIR. Handle symbolic
+ link following, etc. This function *must* return with
+ the_current_working_directory either set to NULL (in which case
+ getcwd() will eventually be called), or set to a string corresponding
+ to the working directory. Return 1 on success, 0 on failure. */
+
+static int
+change_to_directory (newdir, nolinks)
+ char *newdir;
+ int nolinks;
+{
+ char *t, *tdir;
+ int err, canon_failed, r, ndlen, dlen;
+
+ tdir = (char *)NULL;
+
+ if (the_current_working_directory == 0)
+ {
+ t = get_working_directory ("chdir");
+ FREE (t);
+ }
+
+ t = make_absolute (newdir, the_current_working_directory);
+
+ /* TDIR is either the canonicalized absolute pathname of NEWDIR
+ (nolinks == 0) or the absolute physical pathname of NEWDIR
+ (nolinks != 0). */
+ tdir = nolinks ? sh_physpath (t, 0)
+ : sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
+
+ ndlen = strlen (newdir);
+ dlen = strlen (t);
+
+ /* Use the canonicalized version of NEWDIR, or, if canonicalization
+ failed, use the non-canonical form. */
+ canon_failed = 0;
+ if (tdir && *tdir)
+ free (t);
+ else
+ {
+ FREE (tdir);
+ tdir = t;
+ canon_failed = 1;
+ }
+
+ /* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
+ returns NULL (because it checks the path, it will return NULL if the
+ resolved path doesn't exist), fail immediately. */
+ if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
+ {
+#if defined ENAMETOOLONG
+ if (errno != ENOENT && errno != ENAMETOOLONG)
+#else
+ if (errno != ENOENT)
+#endif
+ errno = ENOTDIR;
+ free (tdir);
+ return (0);
+ }
+
+ /* If the chdir succeeds, update the_current_working_directory. */
+ if (chdir (nolinks ? newdir : tdir) == 0)
+ {
+ /* If canonicalization failed, but the chdir succeeded, reset the
+ shell's idea of the_current_working_directory. */
+ if (canon_failed)
+ {
+ t = resetpwd ("cd");
+ if (t == 0)
+ set_working_directory (tdir);
+ }
+ else
+ set_working_directory (tdir);
+
+ free (tdir);
+ return (1);
+ }
+
+ /* We failed to change to the appropriate directory name. If we tried
+ what the user passed (nolinks != 0), punt now. */
+ if (nolinks)
+ {
+ free (tdir);
+ return (0);
+ }
+
+ err = errno;
+
+ /* We're not in physical mode (nolinks == 0), but we failed to change to
+ the canonicalized directory name (TDIR). Try what the user passed
+ verbatim. If we succeed, reinitialize the_current_working_directory. */
+ if (chdir (newdir) == 0)
+ {
+ t = resetpwd ("cd");
+ if (t == 0)
+ set_working_directory (tdir);
+ else
+ free (t);
+
+ r = 1;
+ }
+ else
+ {
+ errno = err;
+ r = 0;
+ }
+
+ free (tdir);
+ return r;
+}
diff --git a/builtins/colon.c b/builtins/colon.c
new file mode 100644
index 0000000..d1ca614
--- /dev/null
+++ b/builtins/colon.c
@@ -0,0 +1,24 @@
+/* colon.c, created from colon.def. */
+#line 22 "./colon.def"
+
+#line 34 "./colon.def"
+
+#line 43 "./colon.def"
+
+#line 52 "./colon.def"
+
+/* Return a successful result. */
+int
+colon_builtin (ignore)
+ char *ignore;
+{
+ return (0);
+}
+
+/* Return an unsuccessful result. */
+int
+false_builtin (ignore)
+ char *ignore;
+{
+ return (1);
+}
diff --git a/builtins/command.c b/builtins/command.c
new file mode 100644
index 0000000..5a5b745
--- /dev/null
+++ b/builtins/command.c
@@ -0,0 +1,183 @@
+/* command.c, created from command.def. */
+#line 22 "./command.def"
+
+#line 41 "./command.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+
+#include "../shell.h"
+#include "../execute_cmd.h"
+#include "../flags.h"
+#include "bashgetopt.h"
+#include "common.h"
+
+#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
+extern size_t confstr __P((int, char *, size_t));
+#endif
+
+extern int subshell_environment;
+
+static void restore_path __P((char *));
+static char *get_standard_path __P((void));
+
+/* Run the commands mentioned in LIST without paying attention to shell
+ functions. */
+int
+command_builtin (list)
+ WORD_LIST *list;
+{
+ int result, verbose, use_standard_path, opt;
+ char *old_path, *standard_path;
+ COMMAND *command;
+
+ verbose = use_standard_path = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "pvV")) != -1)
+ {
+ switch (opt)
+ {
+ case 'p':
+ use_standard_path = 1;
+ break;
+ case 'V':
+ verbose = CDESC_SHORTDESC|CDESC_ABSPATH; /* look in common.h for constants */
+ break;
+ case 'v':
+ verbose = CDESC_REUSABLE; /* ditto */
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+
+#if defined (RESTRICTED_SHELL)
+ if (use_standard_path && restricted)
+ {
+ sh_restricted ("-p");
+ return (EXECUTION_FAILURE);
+ }
+#endif
+
+ begin_unwind_frame ("command_builtin");
+
+ if (use_standard_path)
+ {
+ old_path = get_string_value ("PATH");
+ /* If old_path is NULL, $PATH is unset. If so, we want to make sure
+ it's unset after this command completes. */
+ if (old_path)
+ old_path = savestring (old_path);
+ add_unwind_protect ((Function *)restore_path, old_path);
+
+ standard_path = get_standard_path ();
+ bind_variable ("PATH", standard_path ? standard_path : "", 0);
+ stupidly_hack_special_variables ("PATH");
+ FREE (standard_path);
+ }
+
+ if (verbose)
+ {
+ int found, any_found;
+
+ for (any_found = 0; list; list = list->next)
+ {
+ found = describe_command (list->word->word, verbose);
+
+ if (found == 0 && verbose != CDESC_REUSABLE)
+ sh_notfound (list->word->word);
+
+ any_found += found;
+ }
+
+ run_unwind_frame ("command_builtin");
+ return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+ }
+
+#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN)
+
+ /* We don't want this to be reparsed (consider command echo 'foo &'), so
+ just make a simple_command structure and call execute_command with it. */
+ command = make_bare_simple_command ();
+ command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
+ command->value.Simple->redirects = (REDIRECT *)NULL;
+ command->flags |= COMMAND_BUILTIN_FLAGS;
+ command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
+#if 0
+ /* This breaks for things like ( cd /tmp ; command z ababa ; echo next )
+ or $(command echo a ; command echo b;) or even
+ { command echo a; command echo b; } & */
+ /* If we're in a subshell, see if we can get away without forking
+ again, since we've already forked to run this builtin. */
+ if (subshell_environment)
+ {
+ command->flags |= CMD_NO_FORK;
+ command->value.Simple->flags |= CMD_NO_FORK;
+ }
+#endif
+ add_unwind_protect ((char *)dispose_command, command);
+ result = execute_command (command);
+
+ run_unwind_frame ("command_builtin");
+
+ return (result);
+}
+
+/* Restore the value of the $PATH variable after replacing it when
+ executing `command -p'. */
+static void
+restore_path (var)
+ char *var;
+{
+ if (var)
+ {
+ bind_variable ("PATH", var, 0);
+ free (var);
+ }
+ else
+ unbind_variable ("PATH");
+
+ stupidly_hack_special_variables ("PATH");
+}
+
+/* Return a value for PATH that is guaranteed to find all of the standard
+ utilities. This uses Posix.2 configuration variables, if present. It
+ uses a value defined in config.h as a last resort. */
+static char *
+get_standard_path ()
+{
+#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
+ char *p;
+ size_t len;
+
+ len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
+ if (len > 0)
+ {
+ p = (char *)xmalloc (len + 2);
+ *p = '\0';
+ confstr (_CS_PATH, p, len);
+ return (p);
+ }
+ else
+ return (savestring (STANDARD_UTILS_PATH));
+#else /* !_CS_PATH || !HAVE_CONFSTR */
+# if defined (CS_PATH)
+ return (savestring (CS_PATH));
+# else
+ return (savestring (STANDARD_UTILS_PATH));
+# endif /* !CS_PATH */
+#endif /* !_CS_PATH || !HAVE_CONFSTR */
+}
diff --git a/builtins/complete.c b/builtins/complete.c
new file mode 100644
index 0000000..582bd96
--- /dev/null
+++ b/builtins/complete.c
@@ -0,0 +1,785 @@
+/* complete.c, created from complete.def. */
+#line 22 "./complete.def"
+
+#line 49 "./complete.def"
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "../bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../pcomplete.h"
+#include "../bashline.h"
+
+#include "common.h"
+#include "bashgetopt.h"
+
+#include <readline/readline.h>
+
+#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)
+
+/* Structure containing all the non-action (binary) options; filled in by
+ build_actions(). */
+struct _optflags {
+ int pflag;
+ int rflag;
+ int Dflag;
+ int Eflag;
+};
+
+static int find_compact __P((char *));
+static int find_compopt __P((char *));
+
+static int build_actions __P((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *));
+
+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 *));
+
+static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg;
+
+static const struct _compacts {
+ const char * const actname;
+ int actflag;
+ int actopt;
+} compacts[] = {
+ { "alias", CA_ALIAS, 'a' },
+ { "arrayvar", CA_ARRAYVAR, 0 },
+ { "binding", CA_BINDING, 0 },
+ { "builtin", CA_BUILTIN, 'b' },
+ { "command", CA_COMMAND, 'c' },
+ { "directory", CA_DIRECTORY, 'd' },
+ { "disabled", CA_DISABLED, 0 },
+ { "enabled", CA_ENABLED, 0 },
+ { "export", CA_EXPORT, 'e' },
+ { "file", CA_FILE, 'f' },
+ { "function", CA_FUNCTION, 0 },
+ { "helptopic", CA_BUILTIN, 0 }, /* for now */
+ { "hostname", CA_HOSTNAME, 0 },
+ { "group", CA_GROUP, 'g' },
+ { "job", CA_JOB, 'j' },
+ { "keyword", CA_KEYWORD, 'k' },
+ { "running", CA_RUNNING, 0 },
+ { "service", CA_SERVICE, 's' },
+ { "setopt", CA_SETOPT, 0 },
+ { "shopt", CA_SHOPT, 0 },
+ { "signal", CA_SIGNAL, 0 },
+ { "stopped", CA_STOPPED, 0 },
+ { "user", CA_USER, 'u' },
+ { "variable", CA_VARIABLE, 'v' },
+ { (char *)NULL, 0, 0 },
+};
+
+/* This should be a STRING_INT_ALIST */
+const static struct _compopt {
+ const char * const optname;
+ int optflag;
+} compopts[] = {
+ { "bashdefault", COPT_BASHDEFAULT },
+ { "default", COPT_DEFAULT },
+ { "dirnames", COPT_DIRNAMES },
+ { "filenames",COPT_FILENAMES},
+ { "nospace", COPT_NOSPACE },
+ { "plusdirs", COPT_PLUSDIRS },
+ { (char *)NULL, 0 },
+};
+
+static int
+find_compact (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; compacts[i].actname; i++)
+ if (STREQ (name, compacts[i].actname))
+ return i;
+ return -1;
+}
+
+static int
+find_compopt (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; compopts[i].optname; i++)
+ if (STREQ (name, compopts[i].optname))
+ return i;
+ return -1;
+}
+
+/* Build the actions and compspec options from the options specified in LIST.
+ ACTP is a pointer to an unsigned long in which to place the bitmap of
+ actions. OPTP is a pointer to an unsigned long in which to place the
+ btmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
+ if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
+ If either is null, the corresponding option generates an error.
+ This also sets variables corresponding to options that take arguments as
+ a side effect; the caller should ensure that those variables are set to
+ NULL before calling build_actions. Return value:
+ EX_USAGE = bad option
+ EXECUTION_SUCCESS = some options supplied
+ EXECUTION_FAILURE = no options supplied
+*/
+
+static int
+build_actions (list, flagp, actp, optp)
+ WORD_LIST *list;
+ struct _optflags *flagp;
+ unsigned long *actp, *optp;
+{
+ int opt, ind, opt_given;
+ unsigned long acts, copts;
+
+ acts = copts = (unsigned long)0L;
+ opt_given = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DE")) != -1)
+ {
+ opt_given = 1;
+ switch (opt)
+ {
+ case 'r':
+ if (flagp)
+ {
+ flagp->rflag = 1;
+ break;
+ }
+ else
+ {
+ sh_invalidopt ("-r");
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ case 'p':
+ if (flagp)
+ {
+ flagp->pflag = 1;
+ break;
+ }
+ else
+ {
+ sh_invalidopt ("-p");
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ case 'a':
+ acts |= CA_ALIAS;
+ break;
+ case 'b':
+ acts |= CA_BUILTIN;
+ break;
+ case 'c':
+ acts |= CA_COMMAND;
+ break;
+ case 'd':
+ acts |= CA_DIRECTORY;
+ break;
+ case 'e':
+ acts |= CA_EXPORT;
+ break;
+ case 'f':
+ acts |= CA_FILE;
+ break;
+ case 'g':
+ acts |= CA_GROUP;
+ break;
+ case 'j':
+ acts |= CA_JOB;
+ break;
+ case 'k':
+ acts |= CA_KEYWORD;
+ break;
+ case 's':
+ acts |= CA_SERVICE;
+ break;
+ case 'u':
+ acts |= CA_USER;
+ break;
+ case 'v':
+ acts |= CA_VARIABLE;
+ break;
+ case 'o':
+ ind = find_compopt (list_optarg);
+ if (ind < 0)
+ {
+ sh_invalidoptname (list_optarg);
+ return (EX_USAGE);
+ }
+ copts |= compopts[ind].optflag;
+ break;
+ case 'A':
+ ind = find_compact (list_optarg);
+ if (ind < 0)
+ {
+ builtin_error (_("%s: invalid action name"), list_optarg);
+ return (EX_USAGE);
+ }
+ acts |= compacts[ind].actflag;
+ break;
+ case 'C':
+ Carg = list_optarg;
+ break;
+ case 'D':
+ if (flagp)
+ {
+ flagp->Dflag = 1;
+ break;
+ }
+ else
+ {
+ sh_invalidopt ("-D");
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ case 'E':
+ if (flagp)
+ {
+ flagp->Eflag = 1;
+ break;
+ }
+ else
+ {
+ sh_invalidopt ("-E");
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ case 'F':
+ Farg = list_optarg;
+ break;
+ case 'G':
+ Garg = list_optarg;
+ break;
+ case 'P':
+ Parg = list_optarg;
+ break;
+ case 'S':
+ Sarg = list_optarg;
+ break;
+ case 'W':
+ Warg = list_optarg;
+ break;
+ case 'X':
+ Xarg = list_optarg;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ *actp = acts;
+ *optp = copts;
+
+ return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
+/* Add, remove, and display completion specifiers. */
+int
+complete_builtin (list)
+ WORD_LIST *list;
+{
+ int opt_given, rval;
+ unsigned long acts, copts;
+ COMPSPEC *cs;
+ struct _optflags oflags;
+ WORD_LIST *l, *wl;
+
+ if (list == 0)
+ {
+ print_all_completions ();
+ return (EXECUTION_SUCCESS);
+ }
+
+ opt_given = oflags.pflag = oflags.rflag = oflags.Dflag = oflags.Eflag = 0;
+
+ acts = copts = (unsigned long)0L;
+ Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
+ cs = (COMPSPEC *)NULL;
+
+ /* Build the actions from the arguments. Also sets the [A-Z]arg variables
+ as a side effect if they are supplied as options. */
+ rval = build_actions (list, &oflags, &acts, &copts);
+ if (rval == EX_USAGE)
+ return (rval);
+ opt_given = rval != EXECUTION_FAILURE;
+
+ list = loptend;
+
+ wl = oflags.Dflag ? make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL)
+ : (oflags.Eflag ? make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL) : 0);
+
+ /* -p overrides everything else */
+ if (oflags.pflag || (list == 0 && opt_given == 0))
+ {
+ if (wl)
+ {
+ rval = print_cmd_completions (wl);
+ dispose_words (wl);
+ return rval;
+ }
+ else if (list == 0)
+ {
+ print_all_completions ();
+ return (EXECUTION_SUCCESS);
+ }
+ return (print_cmd_completions (list));
+ }
+
+ /* next, -r overrides everything else. */
+ if (oflags.rflag)
+ {
+ if (wl)
+ {
+ rval = remove_cmd_completions (wl);
+ dispose_words (wl);
+ return rval;
+ }
+ else if (list == 0)
+ {
+ progcomp_flush ();
+ return (EXECUTION_SUCCESS);
+ }
+ return (remove_cmd_completions (list));
+ }
+
+ if (wl == 0 && list == 0 && opt_given)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ /* If we get here, we need to build a compspec and add it for each
+ remaining argument. */
+ cs = compspec_create ();
+ cs->actions = acts;
+ cs->options = copts;
+
+ cs->globpat = STRDUP (Garg);
+ cs->words = STRDUP (Warg);
+ cs->prefix = STRDUP (Parg);
+ cs->suffix = STRDUP (Sarg);
+ cs->funcname = STRDUP (Farg);
+ cs->command = STRDUP (Carg);
+ cs->filterpat = STRDUP (Xarg);
+
+ for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next)
+ {
+ /* Add CS as the compspec for the specified commands. */
+ if (progcomp_insert (l->word->word, cs) == 0)
+ rval = EXECUTION_FAILURE;
+ }
+
+ dispose_words (wl);
+ return (rval);
+}
+
+static int
+remove_cmd_completions (list)
+ WORD_LIST *list;
+{
+ WORD_LIST *l;
+ int ret;
+
+ for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
+ {
+ if (progcomp_remove (l->word->word) == 0)
+ {
+ builtin_error (_("%s: no completion specification"), l->word->word);
+ ret = EXECUTION_FAILURE;
+ }
+ }
+ return ret;
+}
+
+#define SQPRINTARG(a, f) \
+ do { \
+ if (a) \
+ { \
+ x = sh_single_quote (a); \
+ printf ("%s %s ", f, x); \
+ free (x); \
+ } \
+ } while (0)
+
+#define PRINTARG(a, f) \
+ do { \
+ if (a) \
+ printf ("%s %s ", f, a); \
+ } while (0)
+
+#define PRINTOPT(a, f) \
+ do { \
+ if (acts & a) \
+ printf ("%s ", f); \
+ } while (0)
+
+#define PRINTACT(a, f) \
+ do { \
+ if (acts & a) \
+ printf ("-A %s ", f); \
+ } while (0)
+
+#define PRINTCOMPOPT(a, f) \
+ do { \
+ if (copts & a) \
+ 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;
+ COMPSPEC *cs;
+{
+ unsigned long acts, copts;
+ char *x;
+
+ printf ("complete ");
+
+ copts = cs->options;
+
+ /* First, print the -o options. */
+ PRINTCOMPOPT (COPT_BASHDEFAULT, "bashdefault");
+ PRINTCOMPOPT (COPT_DEFAULT, "default");
+ PRINTCOMPOPT (COPT_DIRNAMES, "dirnames");
+ PRINTCOMPOPT (COPT_FILENAMES, "filenames");
+ PRINTCOMPOPT (COPT_NOSPACE, "nospace");
+ PRINTCOMPOPT (COPT_PLUSDIRS, "plusdirs");
+
+ acts = cs->actions;
+
+ /* simple flags next */
+ PRINTOPT (CA_ALIAS, "-a");
+ PRINTOPT (CA_BUILTIN, "-b");
+ PRINTOPT (CA_COMMAND, "-c");
+ PRINTOPT (CA_DIRECTORY, "-d");
+ PRINTOPT (CA_EXPORT, "-e");
+ PRINTOPT (CA_FILE, "-f");
+ PRINTOPT (CA_GROUP, "-g");
+ PRINTOPT (CA_JOB, "-j");
+ PRINTOPT (CA_KEYWORD, "-k");
+ PRINTOPT (CA_SERVICE, "-s");
+ PRINTOPT (CA_USER, "-u");
+ PRINTOPT (CA_VARIABLE, "-v");
+
+ /* now the rest of the actions */
+ PRINTACT (CA_ARRAYVAR, "arrayvar");
+ PRINTACT (CA_BINDING, "binding");
+ PRINTACT (CA_DISABLED, "disabled");
+ PRINTACT (CA_ENABLED, "enabled");
+ PRINTACT (CA_FUNCTION, "function");
+ PRINTACT (CA_HELPTOPIC, "helptopic");
+ PRINTACT (CA_HOSTNAME, "hostname");
+ PRINTACT (CA_RUNNING, "running");
+ PRINTACT (CA_SETOPT, "setopt");
+ PRINTACT (CA_SHOPT, "shopt");
+ PRINTACT (CA_SIGNAL, "signal");
+ PRINTACT (CA_STOPPED, "stopped");
+
+ /* now the rest of the arguments */
+
+ /* arguments that require quoting */
+ SQPRINTARG (cs->globpat, "-G");
+ SQPRINTARG (cs->words, "-W");
+ SQPRINTARG (cs->prefix, "-P");
+ SQPRINTARG (cs->suffix, "-S");
+ SQPRINTARG (cs->filterpat, "-X");
+
+ SQPRINTARG (cs->command, "-C");
+
+ /* simple arguments that don't require quoting */
+ PRINTARG (cs->funcname, "-F");
+
+ if (STREQ (cmd, EMPTYCMD))
+ printf ("-E\n");
+ else if (STREQ (cmd, DEFAULTCMD))
+ printf ("-D\n");
+ else
+ 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");
+ }
+
+ if (STREQ (cmd, EMPTYCMD))
+ printf ("-E\n");
+ else if (STREQ (cmd, DEFAULTCMD))
+ printf ("-D\n");
+ else
+ printf ("%s\n", cmd);
+}
+
+static int
+print_compitem (item)
+ BUCKET_CONTENTS *item;
+{
+ COMPSPEC *cs;
+ char *cmd;
+
+ cmd = item->key;
+ cs = (COMPSPEC *)item->data;
+
+ return (print_one_completion (cmd, cs));
+}
+
+static void
+print_all_completions ()
+{
+ progcomp_walk (print_compitem);
+}
+
+static int
+print_cmd_completions (list)
+ WORD_LIST *list;
+{
+ WORD_LIST *l;
+ COMPSPEC *cs;
+ int ret;
+
+ for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
+ {
+ cs = progcomp_search (l->word->word);
+ if (cs)
+ print_one_completion (l->word->word, cs);
+ else
+ {
+ builtin_error (_("%s: no completion specification"), l->word->word);
+ ret = EXECUTION_FAILURE;
+ }
+ }
+
+ return (sh_chkwrite (ret));
+}
+
+#line 665 "./complete.def"
+
+int
+compgen_builtin (list)
+ WORD_LIST *list;
+{
+ int rval;
+ unsigned long acts, copts;
+ COMPSPEC *cs;
+ STRINGLIST *sl;
+ char *word, **matches;
+
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+
+ acts = copts = (unsigned long)0L;
+ Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
+ cs = (COMPSPEC *)NULL;
+
+ /* Build the actions from the arguments. Also sets the [A-Z]arg variables
+ as a side effect if they are supplied as options. */
+ rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts);
+ if (rval == EX_USAGE)
+ return (rval);
+ if (rval == EXECUTION_FAILURE)
+ return (EXECUTION_SUCCESS);
+
+ list = loptend;
+
+ word = (list && list->word) ? list->word->word : "";
+
+ if (Farg)
+ builtin_error (_("warning: -F option may not work as you expect"));
+ if (Carg)
+ builtin_error (_("warning: -C option may not work as you expect"));
+
+ /* If we get here, we need to build a compspec and evaluate it. */
+ cs = compspec_create ();
+ cs->actions = acts;
+ cs->options = copts;
+ cs->refcount = 1;
+
+ cs->globpat = STRDUP (Garg);
+ cs->words = STRDUP (Warg);
+ cs->prefix = STRDUP (Parg);
+ cs->suffix = STRDUP (Sarg);
+ cs->funcname = STRDUP (Farg);
+ cs->command = STRDUP (Carg);
+ cs->filterpat = STRDUP (Xarg);
+
+ rval = EXECUTION_FAILURE;
+ sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0);
+
+ /* If the compspec wants the bash default completions, temporarily
+ turn off programmable completion and call the bash completion code. */
+ if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT))
+ {
+ matches = bash_default_completion (word, 0, 0, 0, 0);
+ sl = completions_to_stringlist (matches);
+ strvec_dispose (matches);
+ }
+
+ /* This isn't perfect, but it's the best we can do, given what readline
+ exports from its set of completion utility functions. */
+ if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT))
+ {
+ matches = rl_completion_matches (word, rl_filename_completion_function);
+ sl = completions_to_stringlist (matches);
+ strvec_dispose (matches);
+ }
+
+ if (sl)
+ {
+ if (sl->list && sl->list_len)
+ {
+ rval = EXECUTION_SUCCESS;
+ strlist_print (sl, (char *)NULL);
+ }
+ strlist_dispose (sl);
+ }
+
+ compspec_dispose (cs);
+ return (rval);
+}
+
+#line 778 "./complete.def"
+
+int
+compopt_builtin (list)
+ WORD_LIST *list;
+{
+ int opts_on, opts_off, *opts, opt, oind, ret, Dflag, Eflag;
+ WORD_LIST *l, *wl;
+ COMPSPEC *cs;
+
+ opts_on = opts_off = Eflag = Dflag = 0;
+ ret = EXECUTION_SUCCESS;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "+o:DE")) != 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;
+ case 'D':
+ Dflag = 1;
+ break;
+ case 'E':
+ Eflag = 1;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ wl = Dflag ? make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL)
+ : (Eflag ? make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL) : 0);
+
+ if (list == 0 && wl == 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 = wl ? wl : 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);
+}
diff --git a/builtins/declare.c b/builtins/declare.c
new file mode 100644
index 0000000..11004d6
--- /dev/null
+++ b/builtins/declare.c
@@ -0,0 +1,489 @@
+/* declare.c, created from declare.def. */
+#line 22 "./declare.def"
+
+#line 58 "./declare.def"
+
+#line 66 "./declare.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "builtext.h"
+#include "bashgetopt.h"
+
+extern int array_needs_making;
+extern int posixly_correct;
+
+static int declare_internal __P((register WORD_LIST *, int));
+
+/* Declare or change variable attributes. */
+int
+declare_builtin (list)
+ register WORD_LIST *list;
+{
+ return (declare_internal (list, 0));
+}
+
+#line 114 "./declare.def"
+int
+local_builtin (list)
+ register WORD_LIST *list;
+{
+ if (variable_context)
+ return (declare_internal (list, 1));
+ else
+ {
+ builtin_error (_("can only be used in a function"));
+ return (EXECUTION_FAILURE);
+ }
+}
+
+#if defined (ARRAY_VARS)
+# define DECLARE_OPTS "+acfilprtuxAF"
+#else
+# define DECLARE_OPTS "+cfilprtuxF"
+#endif
+
+/* The workhorse function. */
+static int
+declare_internal (list, local_var)
+ register WORD_LIST *list;
+ int local_var;
+{
+ int flags_on, flags_off, *flags;
+ int any_failed, assign_error, pflag, nodefs, opt;
+ char *t, *subscript_start;
+ SHELL_VAR *var;
+ FUNCTION_DEF *shell_fn;
+
+ flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
+ {
+ flags = list_opttype == '+' ? &flags_off : &flags_on;
+
+ switch (opt)
+ {
+ case 'a':
+#if defined (ARRAY_VARS)
+ *flags |= att_array;
+ break;
+#else
+ builtin_usage ();
+ return (EX_USAGE);
+#endif
+ case 'A':
+#if defined (ARRAY_VARS)
+ *flags |= att_assoc;
+ break;
+#else
+ builtin_usage ();
+ return (EX_USAGE);
+#endif
+ case 'p':
+ if (local_var == 0)
+ pflag++;
+ break;
+ case 'F':
+ nodefs++;
+ *flags |= att_function;
+ break;
+ case 'f':
+ *flags |= att_function;
+ break;
+ case 'i':
+ *flags |= att_integer;
+ break;
+ case 'r':
+ *flags |= att_readonly;
+ break;
+ case 't':
+ *flags |= att_trace;
+ break;
+ case 'x':
+ *flags |= att_exported;
+ array_needs_making = 1;
+ break;
+#if defined (CASEMOD_ATTRS)
+# if defined (CASEMOD_CAPCASE)
+ case 'c':
+ *flags |= att_capcase;
+ if (flags == &flags_on)
+ flags_off |= att_uppercase|att_lowercase;
+ break;
+# endif
+ case 'l':
+ *flags |= att_lowercase;
+ if (flags == &flags_on)
+ flags_off |= att_capcase|att_uppercase;
+ break;
+ case 'u':
+ *flags |= att_uppercase;
+ if (flags == &flags_on)
+ flags_off |= att_capcase|att_lowercase;
+ break;
+#endif /* CASEMOD_ATTRS */
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ /* If there are no more arguments left, then we just want to show
+ some variables. */
+ if (list == 0) /* declare -[aAfFirtx] */
+ {
+ /* Show local variables defined at this context level if this is
+ the `local' builtin. */
+ if (local_var)
+ {
+ register SHELL_VAR **vlist;
+ register int i;
+
+ vlist = all_local_variables ();
+
+ if (vlist)
+ {
+ for (i = 0; vlist[i]; i++)
+ print_assignment (vlist[i]);
+
+ 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
+ set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
+
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+
+ if (pflag) /* declare -p [-aAfFirtx] name [name...] */
+ {
+ for (any_failed = 0; list; list = list->next)
+ {
+ pflag = show_name_attributes (list->word->word, nodefs);
+ if (pflag)
+ {
+ sh_notfound (list->word->word);
+ any_failed++;
+ }
+ }
+ return (sh_chkwrite (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS));
+ }
+
+#define NEXT_VARIABLE() free (name); list = list->next; continue
+
+ /* There are arguments left, so we are making variables. */
+ while (list) /* declare [-aAfFirx] name [name ...] */
+ {
+ char *value, *name;
+ int offset, aflags;
+#if defined (ARRAY_VARS)
+ int making_array_special, compound_array_assign, simple_array_assign;
+#endif
+
+ name = savestring (list->word->word);
+ offset = assignment (name, 0);
+ aflags = 0;
+
+ if (offset) /* declare [-aAfFirx] name=value */
+ {
+ name[offset] = '\0';
+ value = name + offset + 1;
+ if (name[offset - 1] == '+')
+ {
+ aflags |= ASS_APPEND;
+ name[offset - 1] = '\0';
+ }
+ }
+ else
+ value = "";
+
+#if defined (ARRAY_VARS)
+ compound_array_assign = simple_array_assign = 0;
+ subscript_start = (char *)NULL;
+ if (t = strchr (name, '[')) /* ] */
+ {
+ /* If offset != 0 we have already validated any array reference */
+ if (offset == 0 && valid_array_reference (name) == 0)
+ {
+ sh_invalidid (name);
+ assign_error++;
+ NEXT_VARIABLE ();
+ }
+ subscript_start = t;
+ *t = '\0';
+ making_array_special = 1;
+ }
+ else
+ making_array_special = 0;
+#endif
+
+ /* If we're in posix mode or not looking for a shell function (since
+ shell function names don't have to be valid identifiers when the
+ shell's not in posix mode), check whether or not the argument is a
+ valid, well-formed shell identifier. */
+ if ((posixly_correct || (flags_on & att_function) == 0) && legal_identifier (name) == 0)
+ {
+ sh_invalidid (name);
+ assign_error++;
+ NEXT_VARIABLE ();
+ }
+
+ /* If VARIABLE_CONTEXT has a non-zero value, then we are executing
+ inside of a function. This means we should make local variables,
+ not global ones. */
+
+ /* XXX - this has consequences when we're making a local copy of a
+ variable that was in the temporary environment. Watch out
+ for this. */
+ if (variable_context && ((flags_on & att_function) == 0))
+ {
+#if defined (ARRAY_VARS)
+ if (flags_on & att_assoc)
+ var = make_local_assoc_variable (name);
+ else if ((flags_on & att_array) || making_array_special)
+ var = make_local_array_variable (name);
+ else
+#endif
+ var = make_local_variable (name);
+ if (var == 0)
+ {
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+ }
+ else
+ var = (SHELL_VAR *)NULL;
+
+ /* If we are declaring a function, then complain about it in some way.
+ We don't let people make functions by saying `typeset -f foo=bar'. */
+
+ /* There should be a way, however, to let people look at a particular
+ function definition by saying `typeset -f foo'. */
+
+ if (flags_on & att_function)
+ {
+ if (offset) /* declare -f [-rix] foo=bar */
+ {
+ builtin_error (_("cannot use `-f' to make functions"));
+ free (name);
+ return (EXECUTION_FAILURE);
+ }
+ else /* declare -f [-rx] name [name...] */
+ {
+ var = find_function (name);
+
+ if (var)
+ {
+ if (readonly_p (var) && (flags_off & att_readonly))
+ {
+ builtin_error (_("%s: readonly function"), name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+
+ /* declare -[Ff] name [name...] */
+ if (flags_on == att_function && flags_off == 0)
+ {
+#if defined (DEBUGGER)
+ if (nodefs && debugging_mode)
+ {
+ shell_fn = find_function_def (var->name);
+ if (shell_fn)
+ printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
+ else
+ printf ("%s\n", var->name);
+ }
+ else
+#endif /* DEBUGGER */
+ {
+ t = nodefs ? var->name
+ : named_function_string (name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL);
+ printf ("%s\n", t);
+ any_failed = sh_chkwrite (any_failed);
+ }
+ }
+ else /* declare -[fF] -[rx] name [name...] */
+ {
+ VSETATTR (var, flags_on);
+ VUNSETATTR (var, flags_off);
+ }
+ }
+ else
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+ }
+ else /* declare -[aAirx] name [name...] */
+ {
+ /* Non-null if we just created or fetched a local variable. */
+ if (var == 0)
+ var = find_variable (name);
+
+ if (var == 0)
+ {
+#if defined (ARRAY_VARS)
+ if (flags_on & att_assoc)
+ var = make_new_assoc_variable (name);
+ else if ((flags_on & att_array) || making_array_special)
+ var = make_new_array_variable (name);
+ else
+#endif
+
+ if (offset)
+ var = bind_variable (name, "", 0);
+ else
+ {
+ var = bind_variable (name, (char *)NULL, 0);
+ VSETATTR (var, att_invisible);
+ }
+ }
+
+ /* Cannot use declare +r to turn off readonly attribute. */
+ if (readonly_p (var) && (flags_off & att_readonly))
+ {
+ sh_readonly (name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+
+ /* Cannot use declare to assign value to readonly or noassign
+ variable. */
+ if ((readonly_p (var) || noassign_p (var)) && offset)
+ {
+ if (readonly_p (var))
+ sh_readonly (name);
+ assign_error++;
+ NEXT_VARIABLE ();
+ }
+
+#if defined (ARRAY_VARS)
+ if ((making_array_special || (flags_on & (att_array|att_assoc)) || array_p (var) || assoc_p (var)) && offset)
+ {
+ int vlen;
+ vlen = STRLEN (value);
+
+ if (value[0] == '(' && value[vlen-1] == ')')
+ compound_array_assign = 1;
+ else
+ simple_array_assign = 1;
+ }
+
+ /* Cannot use declare +a name or declare +A name to remove an
+ array variable. */
+ if (((flags_off & att_array) && array_p (var)) || ((flags_off & att_assoc) && assoc_p (var)))
+ {
+ builtin_error (_("%s: cannot destroy array variables in this way"), name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+
+ if ((flags_on & att_array) && assoc_p (var))
+ {
+ builtin_error (_("%s: cannot convert associative to indexed array"), name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+ if ((flags_on & att_assoc) && array_p (var))
+ {
+ builtin_error (_("%s: cannot convert indexed to associative array"), name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+
+ /* declare -A name[[n]] makes name an associative array variable. */
+ if (flags_on & att_assoc)
+ {
+ if (assoc_p (var) == 0)
+ var = convert_var_to_assoc (var);
+ }
+ /* declare -a name[[n]] or declare name[n] makes name an indexed
+ array variable. */
+ else if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0 && assoc_p (var) == 0)
+ var = convert_var_to_array (var);
+#endif /* ARRAY_VARS */
+
+ VSETATTR (var, flags_on);
+ VUNSETATTR (var, flags_off);
+
+#if defined (ARRAY_VARS)
+ if (offset && compound_array_assign)
+ assign_array_var_from_string (var, value, aflags);
+ else if (simple_array_assign && subscript_start)
+ {
+ /* declare [-aA] name[N]=value */
+ *subscript_start = '['; /* ] */
+ var = assign_array_element (name, value, 0); /* XXX - not aflags */
+ *subscript_start = '\0';
+ }
+ else if (simple_array_assign)
+ {
+ /* let bind_{array,assoc}_variable take care of this. */
+ if (assoc_p (var))
+ bind_assoc_variable (var, name, "0", value, aflags);
+ else
+ bind_array_variable (name, 0, value, aflags);
+ }
+ else
+#endif
+ /* bind_variable_value duplicates the essential internals of
+ bind_variable() */
+ if (offset)
+ bind_variable_value (var, value, aflags);
+
+ /* If we found this variable in the temporary environment, as with
+ `var=value declare -x var', make sure it is treated identically
+ to `var=value export var'. Do the same for `declare -r' and
+ `readonly'. Preserve the attributes, except for att_tempvar. */
+ /* XXX -- should this create a variable in the global scope, or
+ modify the local variable flags? ksh93 has it modify the
+ global scope.
+ Need to handle case like in set_var_attribute where a temporary
+ variable is in the same table as the function local vars. */
+ if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
+ {
+ SHELL_VAR *tv;
+ char *tvalue;
+
+ tv = find_tempenv_variable (var->name);
+ if (tv)
+ {
+ tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
+ tv = bind_variable (var->name, tvalue, 0);
+ tv->attributes |= var->attributes & ~att_tempvar;
+ if (tv->context > 0)
+ VSETATTR (tv, att_propagate);
+ free (tvalue);
+ }
+ VSETATTR (var, att_propagate);
+ }
+ }
+
+ stupidly_hack_special_variables (name);
+
+ NEXT_VARIABLE ();
+ }
+
+ return (assign_error ? EX_BADASSIGN
+ : ((any_failed == 0) ? EXECUTION_SUCCESS
+ : EXECUTION_FAILURE));
+}
diff --git a/builtins/echo.c b/builtins/echo.c
new file mode 100644
index 0000000..442ca41
--- /dev/null
+++ b/builtins/echo.c
@@ -0,0 +1,135 @@
+/* echo.c, created from echo.def. */
+#line 22 "./echo.def"
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+
+#include <stdio.h>
+#include "../shell.h"
+
+#include "common.h"
+
+#line 67 "./echo.def"
+
+#line 82 "./echo.def"
+
+#if defined (V9_ECHO)
+# define VALID_ECHO_OPTIONS "neE"
+#else /* !V9_ECHO */
+# define VALID_ECHO_OPTIONS "n"
+#endif /* !V9_ECHO */
+
+/* System V machines already have a /bin/sh with a v9 behaviour. We
+ give Bash the identical behaviour for these machines so that the
+ existing system shells won't barf. Regrettably, the SUS v2 has
+ standardized the Sys V echo behavior. This variable is external
+ so that we can have a `shopt' variable to control it at runtime. */
+#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
+int xpg_echo = 1;
+#else
+int xpg_echo = 0;
+#endif /* DEFAULT_ECHO_TO_XPG */
+
+extern int posixly_correct;
+
+/* Print the words in LIST to standard output. If the first word is
+ `-n', then don't print a trailing newline. We also support the
+ echo syntax from Version 9 Unix systems. */
+int
+echo_builtin (list)
+ WORD_LIST *list;
+{
+ int display_return, do_v9, i, len;
+ char *temp, *s;
+
+ do_v9 = xpg_echo;
+ display_return = 1;
+
+ if (posixly_correct && xpg_echo)
+ goto just_echo;
+
+ for (; list && (temp = list->word->word) && *temp == '-'; list = list->next)
+ {
+ /* If it appears that we are handling options, then make sure that
+ all of the options specified are actually valid. Otherwise, the
+ string should just be echoed. */
+ temp++;
+
+ for (i = 0; temp[i]; i++)
+ {
+ if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
+ break;
+ }
+
+ /* echo - and echo -<nonopt> both mean to just echo the arguments. */
+ if (*temp == 0 || temp[i])
+ break;
+
+ /* All of the options in TEMP are valid options to ECHO.
+ Handle them. */
+ while (i = *temp++)
+ {
+ switch (i)
+ {
+ case 'n':
+ display_return = 0;
+ break;
+#if defined (V9_ECHO)
+ case 'e':
+ do_v9 = 1;
+ break;
+ case 'E':
+ do_v9 = 0;
+ break;
+#endif /* V9_ECHO */
+ default:
+ goto just_echo; /* XXX */
+ }
+ }
+ }
+
+just_echo:
+
+ clearerr (stdout); /* clear error before writing and testing success */
+
+ terminate_immediately++;
+ while (list)
+ {
+ i = len = 0;
+ temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len)
+ : list->word->word;
+ if (temp)
+ {
+ if (do_v9)
+ {
+ for (s = temp; len > 0; len--)
+ putchar (*s++);
+ }
+ else
+ printf ("%s", temp);
+#if defined (SunOS5)
+ fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */
+#endif
+ }
+ if (do_v9 && temp)
+ free (temp);
+ list = list->next;
+ if (i)
+ {
+ display_return = 0;
+ break;
+ }
+ if (list)
+ putchar(' ');
+ }
+
+ if (display_return)
+ putchar ('\n');
+
+ terminate_immediately--;
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
diff --git a/builtins/enable.c b/builtins/enable.c
new file mode 100644
index 0000000..8e8d0f3
--- /dev/null
+++ b/builtins/enable.c
@@ -0,0 +1,438 @@
+/* enable.c, created from enable.def. */
+#line 22 "./enable.def"
+
+#line 50 "./enable.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../flags.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if defined (PROGRAMMABLE_COMPLETION)
+# include "../pcomplete.h"
+#endif
+
+#define ENABLED 1
+#define DISABLED 2
+#define SPECIAL 4
+
+#define AFLAG 0x01
+#define DFLAG 0x02
+#define FFLAG 0x04
+#define NFLAG 0x08
+#define PFLAG 0x10
+#define SFLAG 0x20
+
+#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
+static int dyn_load_builtin __P((WORD_LIST *, int, char *));
+#endif
+
+#if defined (HAVE_DLCLOSE)
+static int dyn_unload_builtin __P((char *));
+static void delete_builtin __P((struct builtin *));
+static int local_dlclose __P((void *));
+#endif
+
+static void list_some_builtins __P((int));
+static int enable_shell_command __P((char *, int));
+
+/* Enable/disable shell commands present in LIST. If list is not specified,
+ then print out a list of shell commands showing which are enabled and
+ which are disabled. */
+int
+enable_builtin (list)
+ WORD_LIST *list;
+{
+ int result, flags;
+ int opt, filter;
+#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
+ char *filename;
+#endif
+
+ result = EXECUTION_SUCCESS;
+ flags = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "adnpsf:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ flags |= AFLAG;
+ break;
+ case 'n':
+ flags |= NFLAG;
+ break;
+ case 'p':
+ flags |= PFLAG;
+ break;
+ case 's':
+ flags |= SFLAG;
+ break;
+ case 'f':
+#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
+ flags |= FFLAG;
+ filename = list_optarg;
+ break;
+#else
+ builtin_error (_("dynamic loading not available"));
+ return (EX_USAGE);
+#endif
+#if defined (HAVE_DLCLOSE)
+ case 'd':
+ flags |= DFLAG;
+ break;
+#else
+ builtin_error (_("dynamic loading not available"));
+ return (EX_USAGE);
+#endif /* HAVE_DLCLOSE */
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+#if defined (RESTRICTED_SHELL)
+ /* Restricted shells cannot load new builtins. */
+ if (restricted && (flags & (FFLAG|DFLAG)))
+ {
+ sh_restricted ((char *)NULL);
+ return (EXECUTION_FAILURE);
+ }
+#endif
+
+ if (list == 0 || (flags & PFLAG))
+ {
+ filter = (flags & AFLAG) ? (ENABLED | DISABLED)
+ : (flags & NFLAG) ? DISABLED : ENABLED;
+
+ if (flags & SFLAG)
+ filter |= SPECIAL;
+
+ list_some_builtins (filter);
+ }
+#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
+ else if (flags & FFLAG)
+ {
+ filter = (flags & NFLAG) ? DISABLED : ENABLED;
+ if (flags & SFLAG)
+ filter |= SPECIAL;
+
+ result = dyn_load_builtin (list, filter, filename);
+#if defined (PROGRAMMABLE_COMPLETION)
+ set_itemlist_dirty (&it_builtins);
+#endif
+ }
+#endif
+#if defined (HAVE_DLCLOSE)
+ else if (flags & DFLAG)
+ {
+ while (list)
+ {
+ opt = dyn_unload_builtin (list->word->word);
+ if (opt == EXECUTION_FAILURE)
+ result = EXECUTION_FAILURE;
+ list = list->next;
+ }
+#if defined (PROGRAMMABLE_COMPLETION)
+ set_itemlist_dirty (&it_builtins);
+#endif
+ }
+#endif
+ else
+ {
+ while (list)
+ {
+ opt = enable_shell_command (list->word->word, flags & NFLAG);
+
+ if (opt == EXECUTION_FAILURE)
+ {
+ sh_notbuiltin (list->word->word);
+ result = EXECUTION_FAILURE;
+ }
+ list = list->next;
+ }
+ }
+ return (result);
+}
+
+/* List some builtins.
+ FILTER is a mask with two slots: ENABLED and DISABLED. */
+static void
+list_some_builtins (filter)
+ int filter;
+{
+ register int i;
+
+ for (i = 0; i < num_shell_builtins; i++)
+ {
+ if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED))
+ continue;
+
+ if ((filter & SPECIAL) &&
+ (shell_builtins[i].flags & SPECIAL_BUILTIN) == 0)
+ continue;
+
+ if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED))
+ printf ("enable %s\n", shell_builtins[i].name);
+ else if ((filter & DISABLED) &&
+ ((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
+ printf ("enable -n %s\n", shell_builtins[i].name);
+ }
+}
+
+/* Enable the shell command NAME. If DISABLE_P is non-zero, then
+ disable NAME instead. */
+static int
+enable_shell_command (name, disable_p)
+ char *name;
+ int disable_p;
+{
+ struct builtin *b;
+
+ b = builtin_address_internal (name, 1);
+ if (b == 0)
+ return (EXECUTION_FAILURE);
+
+ if (disable_p)
+ b->flags &= ~BUILTIN_ENABLED;
+#if defined (RESTRICTED_SHELL)
+ else if (restricted && ((b->flags & BUILTIN_ENABLED) == 0))
+ {
+ sh_restricted ((char *)NULL);
+ return (EXECUTION_FAILURE);
+ }
+#endif
+ else
+ b->flags |= BUILTIN_ENABLED;
+
+#if defined (PROGRAMMABLE_COMPLETION)
+ set_itemlist_dirty (&it_enabled);
+ set_itemlist_dirty (&it_disabled);
+#endif
+
+ return (EXECUTION_SUCCESS);
+}
+
+#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
+
+#if defined (HAVE_DLFCN_H)
+# include <dlfcn.h>
+#endif
+
+static int
+dyn_load_builtin (list, flags, filename)
+ WORD_LIST *list;
+ int flags;
+ char *filename;
+{
+ WORD_LIST *l;
+ void *handle;
+
+ int total, size, new, replaced;
+ char *struct_name, *name;
+ struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin;
+
+ if (list == 0)
+ return (EXECUTION_FAILURE);
+
+#ifndef RTLD_LAZY
+#define RTLD_LAZY 1
+#endif
+
+#if defined (_AIX)
+ handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
+#else
+ handle = dlopen (filename, RTLD_LAZY);
+#endif /* !_AIX */
+
+ if (handle == 0)
+ {
+ builtin_error (_("cannot open shared object %s: %s"), filename, dlerror ());
+ return (EXECUTION_FAILURE);
+ }
+
+ for (new = 0, l = list; l; l = l->next, new++)
+ ;
+ new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *));
+
+ /* For each new builtin in the shared object, find it and its describing
+ structure. If this is overwriting an existing builtin, do so, otherwise
+ save the loaded struct for creating the new list of builtins. */
+ for (replaced = new = 0; list; list = list->next)
+ {
+ name = list->word->word;
+
+ size = strlen (name);
+ struct_name = (char *)xmalloc (size + 8);
+ strcpy (struct_name, name);
+ strcpy (struct_name + size, "_struct");
+
+ b = (struct builtin *)dlsym (handle, struct_name);
+ if (b == 0)
+ {
+ builtin_error (_("cannot find %s in shared object %s: %s"),
+ struct_name, filename, dlerror ());
+ free (struct_name);
+ continue;
+ }
+
+ free (struct_name);
+
+ b->flags &= ~STATIC_BUILTIN;
+ if (flags & SPECIAL)
+ b->flags |= SPECIAL_BUILTIN;
+ b->handle = handle;
+
+ if (old_builtin = builtin_address_internal (name, 1))
+ {
+ replaced++;
+ FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin));
+ }
+ else
+ new_builtins[new++] = b;
+ }
+
+ if (replaced == 0 && new == 0)
+ {
+ free (new_builtins);
+ dlclose (handle);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (new)
+ {
+ total = num_shell_builtins + new;
+ size = (total + 1) * sizeof (struct builtin);
+
+ new_shell_builtins = (struct builtin *)xmalloc (size);
+ FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
+ num_shell_builtins * sizeof (struct builtin));
+ for (replaced = 0; replaced < new; replaced++)
+ FASTCOPY ((char *)new_builtins[replaced],
+ (char *)&new_shell_builtins[num_shell_builtins + replaced],
+ sizeof (struct builtin));
+
+ new_shell_builtins[total].name = (char *)0;
+ new_shell_builtins[total].function = (sh_builtin_func_t *)0;
+ new_shell_builtins[total].flags = 0;
+
+ if (shell_builtins != static_shell_builtins)
+ free (shell_builtins);
+
+ shell_builtins = new_shell_builtins;
+ num_shell_builtins = total;
+ initialize_shell_builtins ();
+ }
+
+ free (new_builtins);
+ return (EXECUTION_SUCCESS);
+}
+#endif
+
+#if defined (HAVE_DLCLOSE)
+static void
+delete_builtin (b)
+ struct builtin *b;
+{
+ int ind, size;
+ struct builtin *new_shell_builtins;
+
+ /* XXX - funky pointer arithmetic - XXX */
+#ifdef __STDC__
+ ind = b - shell_builtins;
+#else
+ ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin);
+#endif
+ size = num_shell_builtins * sizeof (struct builtin);
+ new_shell_builtins = (struct builtin *)xmalloc (size);
+
+ /* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */
+ if (ind)
+ FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
+ ind * sizeof (struct builtin));
+ /* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to
+ new_shell_builtins, starting at ind. */
+ FASTCOPY ((char *)(&shell_builtins[ind+1]),
+ (char *)(&new_shell_builtins[ind]),
+ (num_shell_builtins - ind) * sizeof (struct builtin));
+
+ if (shell_builtins != static_shell_builtins)
+ free (shell_builtins);
+
+ /* The result is still sorted. */
+ num_shell_builtins--;
+ shell_builtins = new_shell_builtins;
+}
+
+/* Tenon's MachTen has a dlclose that doesn't return a value, so we
+ finesse it with a local wrapper. */
+static int
+local_dlclose (handle)
+ void *handle;
+{
+#if !defined (__MACHTEN__)
+ return (dlclose (handle));
+#else /* __MACHTEN__ */
+ dlclose (handle);
+ return ((dlerror () != NULL) ? -1 : 0);
+#endif /* __MACHTEN__ */
+}
+
+static int
+dyn_unload_builtin (name)
+ char *name;
+{
+ struct builtin *b;
+ void *handle;
+ int ref, i;
+
+ b = builtin_address_internal (name, 1);
+ if (b == 0)
+ {
+ sh_notbuiltin (name);
+ return (EXECUTION_FAILURE);
+ }
+ if (b->flags & STATIC_BUILTIN)
+ {
+ builtin_error (_("%s: not dynamically loaded"), name);
+ return (EXECUTION_FAILURE);
+ }
+
+ handle = (void *)b->handle;
+ for (ref = i = 0; i < num_shell_builtins; i++)
+ {
+ if (shell_builtins[i].handle == b->handle)
+ ref++;
+ }
+
+ /* Don't remove the shared object unless the reference count of builtins
+ using it drops to zero. */
+ if (ref == 1 && local_dlclose (handle) != 0)
+ {
+ builtin_error (_("%s: cannot delete: %s"), name, dlerror ());
+ return (EXECUTION_FAILURE);
+ }
+
+ /* Now remove this entry from the builtin table and reinitialize. */
+ delete_builtin (b);
+
+ return (EXECUTION_SUCCESS);
+}
+#endif
diff --git a/builtins/eval.c b/builtins/eval.c
new file mode 100644
index 0000000..0d74d0b
--- /dev/null
+++ b/builtins/eval.c
@@ -0,0 +1,29 @@
+/* eval.c, created from eval.def. */
+#line 22 "./eval.def"
+
+#line 34 "./eval.def"
+
+#include <config.h>
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../shell.h"
+#include "bashgetopt.h"
+#include "common.h"
+
+/* Parse the string that these words make, and execute the command found. */
+int
+eval_builtin (list)
+ WORD_LIST *list;
+{
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend; /* skip over possible `--' */
+
+ /* Note that parse_and_execute () frees the string it is passed. */
+ return (list ? parse_and_execute (string_list (list), "eval", SEVAL_NOHIST) : EXECUTION_SUCCESS);
+}
diff --git a/builtins/exec.c b/builtins/exec.c
new file mode 100644
index 0000000..681eee3
--- /dev/null
+++ b/builtins/exec.c
@@ -0,0 +1,198 @@
+/* exec.c, created from exec.def. */
+#line 22 "./exec.def"
+
+#line 43 "./exec.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include "posixstat.h"
+#include <signal.h>
+#include <errno.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../execute_cmd.h"
+#include "../findcmd.h"
+#if defined (JOB_CONTROL)
+# include "../jobs.h"
+#endif
+#include "../flags.h"
+#include "../trap.h"
+#if defined (HISTORY)
+# include "../bashhist.h"
+#endif
+#include "common.h"
+#include "bashgetopt.h"
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int subshell_environment;
+extern REDIRECT *redirection_undo_list;
+
+int no_exit_on_failed_exec;
+
+/* If the user wants this to look like a login shell, then
+ prepend a `-' onto NAME and return the new name. */
+static char *
+mkdashname (name)
+ char *name;
+{
+ char *ret;
+
+ ret = (char *)xmalloc (2 + strlen (name));
+ ret[0] = '-';
+ strcpy (ret + 1, name);
+ return ret;
+}
+
+int
+exec_builtin (list)
+ WORD_LIST *list;
+{
+ int exit_value = EXECUTION_FAILURE;
+ int cleanenv, login, opt;
+ char *argv0, *command, **args, **env, *newname, *com2;
+
+ cleanenv = login = 0;
+ argv0 = (char *)NULL;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "cla:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'c':
+ cleanenv = 1;
+ break;
+ case 'l':
+ login = 1;
+ break;
+ case 'a':
+ argv0 = list_optarg;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ /* First, let the redirections remain. */
+ dispose_redirects (redirection_undo_list);
+ redirection_undo_list = (REDIRECT *)NULL;
+
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted)
+ {
+ sh_restricted ((char *)NULL);
+ return (EXECUTION_FAILURE);
+ }
+#endif /* RESTRICTED_SHELL */
+
+ args = strvec_from_word_list (list, 1, 0, (int *)NULL);
+
+ /* A command with a slash anywhere in its name is not looked up in $PATH. */
+ command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]);
+
+ if (command == 0)
+ {
+ sh_notfound (args[0]);
+ exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
+ goto failed_exec;
+ }
+
+ com2 = full_pathname (command);
+ if (com2)
+ {
+ if (command != args[0])
+ free (command);
+ command = com2;
+ }
+
+ if (argv0)
+ {
+ free (args[0]);
+ args[0] = login ? mkdashname (argv0) : savestring (argv0);
+ }
+ else if (login)
+ {
+ newname = mkdashname (args[0]);
+ free (args[0]);
+ args[0] = newname;
+ }
+
+ /* Decrement SHLVL by 1 so a new shell started here has the same value,
+ preserving the appearance. After we do that, we need to change the
+ exported environment to include the new value. */
+ if (cleanenv == 0)
+ adjust_shell_level (-1);
+
+ if (cleanenv)
+ env = (char **)NULL;
+ else
+ {
+ maybe_make_export_env ();
+ env = export_env;
+ }
+
+#if defined (HISTORY)
+ if (interactive_shell && subshell_environment == 0)
+ maybe_save_shell_history ();
+#endif /* HISTORY */
+
+ restore_original_signals ();
+
+#if defined (JOB_CONTROL)
+ if (subshell_environment == 0)
+ end_job_control ();
+#endif /* JOB_CONTROL */
+
+ shell_execve (command, args, env);
+
+ /* We have to set this to NULL because shell_execve has called realloc()
+ to stuff more items at the front of the array, which may have caused
+ the memory to be freed by realloc(). We don't want to free it twice. */
+ args = (char **)NULL;
+ if (cleanenv == 0)
+ adjust_shell_level (1);
+
+ if (executable_file (command) == 0)
+ {
+ builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
+ exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
+ }
+ else
+ file_error (command);
+
+failed_exec:
+ FREE (command);
+
+ if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
+ exit_shell (exit_value);
+
+ if (args)
+ strvec_dispose (args);
+
+ initialize_traps ();
+ initialize_signals (1);
+
+#if defined (JOB_CONTROL)
+ if (interactive_shell || job_control)
+ restart_job_control ();
+#endif /* JOB_CONTROL */
+
+ return (exit_value);
+}
diff --git a/builtins/exit.c b/builtins/exit.c
new file mode 100644
index 0000000..3a48509
--- /dev/null
+++ b/builtins/exit.c
@@ -0,0 +1,135 @@
+/* exit.c, created from exit.def. */
+#line 22 "./exit.def"
+
+#line 31 "./exit.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../jobs.h"
+
+#include "common.h"
+#include "builtext.h" /* for jobs_builtin */
+
+extern int check_jobs_at_exit;
+extern int last_command_exit_value;
+extern int running_trap, trap_saved_exit_value;
+extern int subshell_environment;
+extern sh_builtin_func_t *this_shell_builtin;
+extern sh_builtin_func_t *last_shell_builtin;
+
+static int exit_or_logout __P((WORD_LIST *));
+static int sourced_logout;
+
+int
+exit_builtin (list)
+ WORD_LIST *list;
+{
+ if (interactive)
+ {
+ fprintf (stderr, login_shell ? _("logout\n") : "exit\n");
+ fflush (stderr);
+ }
+
+ return (exit_or_logout (list));
+}
+
+#line 80 "./exit.def"
+
+/* How to logout. */
+int
+logout_builtin (list)
+ WORD_LIST *list;
+{
+ if (login_shell == 0 /* && interactive */)
+ {
+ builtin_error (_("not login shell: use `exit'"));
+ return (EXECUTION_FAILURE);
+ }
+ else
+ return (exit_or_logout (list));
+}
+
+static int
+exit_or_logout (list)
+ WORD_LIST *list;
+{
+ int exit_value;
+
+#if defined (JOB_CONTROL)
+ int exit_immediate_okay, stopmsg;
+
+ exit_immediate_okay = (interactive == 0 ||
+ last_shell_builtin == exit_builtin ||
+ last_shell_builtin == logout_builtin ||
+ last_shell_builtin == jobs_builtin);
+
+ /* Check for stopped jobs if the user wants to. */
+ if (exit_immediate_okay == 0)
+ {
+ register int i;
+ for (i = stopmsg = 0; i < js.j_jobslots; i++)
+ if (jobs[i] && STOPPED (i))
+ stopmsg = JSTOPPED;
+ else if (check_jobs_at_exit && stopmsg == 0 && jobs[i] && RUNNING (i))
+ stopmsg = JRUNNING;
+
+ if (stopmsg == JSTOPPED)
+ fprintf (stderr, _("There are stopped jobs.\n"));
+ else if (stopmsg == JRUNNING)
+ fprintf (stderr, _("There are running jobs.\n"));
+
+ if (stopmsg && check_jobs_at_exit)
+ list_all_jobs (JLIST_STANDARD);
+
+ if (stopmsg)
+ {
+ /* This is NOT superfluous because EOF can get here without
+ going through the command parser. Set both last and this
+ so that either `exit', `logout', or ^D will work to exit
+ immediately if nothing intervenes. */
+ this_shell_builtin = last_shell_builtin = exit_builtin;
+ return (EXECUTION_FAILURE);
+ }
+ }
+#endif /* JOB_CONTROL */
+
+ /* Get return value if present. This means that you can type
+ `logout 5' to a shell, and it returns 5. */
+
+ /* If we're running the exit trap (running_trap == 1, since running_trap
+ gets set to SIG+1), and we don't have a argument given to `exit'
+ (list == 0), use the exit status we saved before running the trap
+ commands (trap_saved_exit_value). */
+ exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list);
+
+ bash_logout ();
+
+ last_command_exit_value = exit_value;
+
+ /* Exit the program. */
+ jump_to_top_level (EXITPROG);
+ /*NOTREACHED*/
+}
+
+void
+bash_logout ()
+{
+ /* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
+ if (login_shell && sourced_logout++ == 0 && subshell_environment == 0)
+ {
+ maybe_execute_file ("~/.bash_logout", 1);
+#ifdef SYS_BASH_LOGOUT
+ maybe_execute_file (SYS_BASH_LOGOUT, 1);
+#endif
+ }
+}
diff --git a/builtins/fc.c b/builtins/fc.c
new file mode 100644
index 0000000..b0f9361
--- /dev/null
+++ b/builtins/fc.c
@@ -0,0 +1,619 @@
+/* fc.c, created from fc.def. */
+#line 22 "./fc.def"
+
+#line 51 "./fc.def"
+
+#include <config.h>
+
+#if defined (HISTORY)
+#ifndef _MINIX
+# include <sys/param.h>
+#endif
+#include "../bashtypes.h"
+#include "posixstat.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <chartypes.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+#include <errno.h>
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../flags.h"
+#include "../bashhist.h"
+#include "maxpath.h"
+#include <readline/history.h>
+#include "bashgetopt.h"
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int current_command_line_count;
+extern int literal_history;
+extern int posixly_correct;
+extern int subshell_environment, interactive_shell;
+
+extern int unlink __P((const char *));
+
+extern FILE *sh_mktmpfp __P((char *, int, char **));
+
+/* **************************************************************** */
+/* */
+/* The K*rn shell style fc command (Fix Command) */
+/* */
+/* **************************************************************** */
+
+/* fc builtin command (fix command) for Bash for those who
+ like K*rn-style history better than csh-style.
+
+ fc [-e ename] [-nlr] [first] [last]
+
+ FIRST and LAST can be numbers specifying the range, or FIRST can be
+ a string, which means the most recent command beginning with that
+ string.
+
+ -e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
+ then the editor which corresponds to the current readline editing
+ mode, then vi.
+
+ -l means list lines instead of editing.
+ -n means no line numbers listed.
+ -r means reverse the order of the lines (making it newest listed first).
+
+ fc -e - [pat=rep ...] [command]
+ fc -s [pat=rep ...] [command]
+
+ Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
+*/
+
+/* Data structure describing a list of global replacements to perform. */
+typedef struct repl {
+ struct repl *next;
+ char *pat;
+ char *rep;
+} REPL;
+
+/* Accessors for HIST_ENTRY lists that are called HLIST. */
+#define histline(i) (hlist[(i)]->line)
+#define histdata(i) (hlist[(i)]->data)
+
+#define FREE_RLIST() \
+ do { \
+ for (rl = rlist; rl; ) { \
+ REPL *r; \
+ r = rl->next; \
+ if (rl->pat) \
+ free (rl->pat); \
+ if (rl->rep) \
+ free (rl->rep); \
+ free (rl); \
+ rl = r; \
+ } \
+ } while (0)
+
+static char *fc_dosubs __P((char *, REPL *));
+static char *fc_gethist __P((char *, HIST_ENTRY **));
+static int fc_gethnum __P((char *, HIST_ENTRY **));
+static int fc_number __P((WORD_LIST *));
+static void fc_replhist __P((char *));
+#ifdef INCLUDE_UNUSED
+static char *fc_readline __P((FILE *));
+static void fc_addhist __P((char *));
+#endif
+
+/* String to execute on a file that we want to edit. */
+#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
+#if defined (STRICT_POSIX)
+# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
+#else
+# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
+#endif
+
+int
+fc_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ register char *sep;
+ int numbering, reverse, listing, execute;
+ int histbeg, histend, last_hist, retval, opt, rh;
+ FILE *stream;
+ REPL *rlist, *rl;
+ char *ename, *command, *newcom, *fcedit;
+ HIST_ENTRY **hlist;
+ char *fn;
+
+ numbering = 1;
+ reverse = listing = execute = 0;
+ ename = (char *)NULL;
+
+ /* Parse out the options and set which of the two forms we're in. */
+ reset_internal_getopt ();
+ lcurrent = list; /* XXX */
+ while (fc_number (loptend = lcurrent) == 0 &&
+ (opt = internal_getopt (list, ":e:lnrs")) != -1)
+ {
+ switch (opt)
+ {
+ case 'n':
+ numbering = 0;
+ break;
+
+ case 'l':
+ listing = 1;
+ break;
+
+ case 'r':
+ reverse = 1;
+ break;
+
+ case 's':
+ execute = 1;
+ break;
+
+ case 'e':
+ ename = list_optarg;
+ break;
+
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (ename && (*ename == '-') && (ename[1] == '\0'))
+ execute = 1;
+
+ /* The "execute" form of the command (re-run, with possible string
+ substitutions). */
+ if (execute)
+ {
+ rlist = (REPL *)NULL;
+ while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
+ {
+ *sep++ = '\0';
+ rl = (REPL *)xmalloc (sizeof (REPL));
+ rl->next = (REPL *)NULL;
+ rl->pat = savestring (list->word->word);
+ rl->rep = savestring (sep);
+
+ if (rlist == NULL)
+ rlist = rl;
+ else
+ {
+ rl->next = rlist;
+ rlist = rl;
+ }
+ list = list->next;
+ }
+
+ /* If we have a list of substitutions to do, then reverse it
+ to get the replacements in the proper order. */
+
+ rlist = REVERSE_LIST (rlist, REPL *);
+
+ hlist = history_list ();
+
+ /* If we still have something in list, it is a command spec.
+ Otherwise, we use the most recent command in time. */
+ command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
+
+ if (command == NULL)
+ {
+ builtin_error (_("no command found"));
+ if (rlist)
+ FREE_RLIST ();
+
+ return (EXECUTION_FAILURE);
+ }
+
+ if (rlist)
+ {
+ newcom = fc_dosubs (command, rlist);
+ free (command);
+ FREE_RLIST ();
+ command = newcom;
+ }
+
+ fprintf (stderr, "%s\n", command);
+ fc_replhist (command); /* replace `fc -s' with command */
+ /* Posix says that the re-executed commands should be entered into the
+ history. */
+ return (parse_and_execute (command, "fc", SEVAL_NOHIST));
+ }
+
+ /* This is the second form of the command (the list-or-edit-and-rerun
+ form). */
+ hlist = history_list ();
+ if (hlist == 0)
+ return (EXECUTION_SUCCESS);
+ for (i = 0; hlist[i]; i++);
+
+ /* With the Bash implementation of history, the current command line
+ ("fc blah..." and so on) is already part of the history list by
+ the time we get to this point. This just skips over that command
+ and makes the last command that this deals with be the last command
+ the user entered before the fc. We need to check whether the
+ line was actually added (HISTIGNORE may have caused it to not be),
+ so we check hist_last_line_added. */
+
+ /* Even though command substitution through parse_and_execute turns off
+ remember_on_history, command substitution in a shell when set -o history
+ has been enabled (interactive or not) should use it in the last_hist
+ calculation as if it were on. */
+ rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
+ last_hist = i - rh - hist_last_line_added;
+
+ if (list)
+ {
+ histbeg = fc_gethnum (list->word->word, hlist);
+ list = list->next;
+
+ if (list)
+ histend = fc_gethnum (list->word->word, hlist);
+ else
+ histend = listing ? last_hist : histbeg;
+ }
+ else
+ {
+ /* The default for listing is the last 16 history items. */
+ if (listing)
+ {
+ histend = last_hist;
+ histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
+ if (histbeg < 0)
+ histbeg = 0;
+ }
+ else
+ /* For editing, it is the last history command. */
+ histbeg = histend = last_hist;
+ }
+
+ /* "When not listing, the fc command that caused the editing shall not be
+ entered into the history list." */
+ if (listing == 0 && hist_last_line_added)
+ {
+ bash_delete_last_history ();
+ /* If we're editing a single command -- the last command in the
+ history -- and we just removed the dummy command added by
+ edit_and_execute_command (), we need to check whether or not we
+ just removed the last command in the history and need to back
+ the pointer up. remember_on_history is off because we're running
+ in parse_and_execute(). */
+ if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
+ last_hist = histbeg = --histend;
+ }
+
+ /* We print error messages for line specifications out of range. */
+ if ((histbeg < 0) || (histend < 0))
+ {
+ sh_erange ((char *)NULL, _("history specification"));
+ return (EXECUTION_FAILURE);
+ }
+
+ if (histend < histbeg)
+ {
+ i = histend;
+ histend = histbeg;
+ histbeg = i;
+
+ reverse = 1;
+ }
+
+ if (listing)
+ stream = stdout;
+ else
+ {
+ numbering = 0;
+ stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
+ if (stream == 0)
+ {
+ builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
+ FREE (fn);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
+ {
+ QUIT;
+ if (numbering)
+ fprintf (stream, "%d", i + history_base);
+ if (listing)
+ {
+ if (posixly_correct)
+ fputs ("\t", stream);
+ else
+ fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
+ }
+ fprintf (stream, "%s\n", histline (i));
+ }
+
+ if (listing)
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+
+ fflush (stream);
+ if (ferror (stream))
+ {
+ sh_wrerror ();
+ fclose (stream);
+ return (EXECUTION_FAILURE);
+ }
+ fclose (stream);
+
+ /* Now edit the file of commands. */
+ if (ename)
+ {
+ command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
+ sprintf (command, "%s %s", ename, fn);
+ }
+ else
+ {
+ fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
+ command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
+ sprintf (command, "%s %s", fcedit, fn);
+ }
+ retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
+ if (retval != EXECUTION_SUCCESS)
+ {
+ unlink (fn);
+ free (fn);
+ return (EXECUTION_FAILURE);
+ }
+
+ /* Make sure parse_and_execute doesn't turn this off, even though a
+ call to parse_and_execute farther up the function call stack (e.g.,
+ if this is called by vi_edit_and_execute_command) may have already
+ called bash_history_disable. */
+ remember_on_history = 1;
+
+ /* Turn on the `v' flag while fc_execute_file runs so the commands
+ will be echoed as they are read by the parser. */
+ begin_unwind_frame ("fc builtin");
+ add_unwind_protect ((Function *)xfree, fn);
+ add_unwind_protect (unlink, fn);
+ unwind_protect_int (echo_input_at_read);
+ echo_input_at_read = 1;
+
+ retval = fc_execute_file (fn);
+
+ run_unwind_frame ("fc builtin");
+
+ return (retval);
+}
+
+/* Return 1 if LIST->word->word is a legal number for fc's use. */
+static int
+fc_number (list)
+ WORD_LIST *list;
+{
+ char *s;
+
+ if (list == 0)
+ return 0;
+ s = list->word->word;
+ if (*s == '-')
+ s++;
+ return (legal_number (s, (intmax_t *)NULL));
+}
+
+/* Return an absolute index into HLIST which corresponds to COMMAND. If
+ COMMAND is a number, then it was specified in relative terms. If it
+ is a string, then it is the start of a command line present in HLIST. */
+static int
+fc_gethnum (command, hlist)
+ char *command;
+ HIST_ENTRY **hlist;
+{
+ int sign, n, clen, rh;
+ register int i, j;
+ register char *s;
+
+ sign = 1;
+ /* Count history elements. */
+ for (i = 0; hlist[i]; i++);
+
+ /* With the Bash implementation of history, the current command line
+ ("fc blah..." and so on) is already part of the history list by
+ the time we get to this point. This just skips over that command
+ and makes the last command that this deals with be the last command
+ the user entered before the fc. We need to check whether the
+ line was actually added (HISTIGNORE may have caused it to not be),
+ so we check hist_last_line_added. This needs to agree with the
+ calculation of last_hist in fc_builtin above. */
+ /* Even though command substitution through parse_and_execute turns off
+ remember_on_history, command substitution in a shell when set -o history
+ has been enabled (interactive or not) should use it in the last_hist
+ calculation as if it were on. */
+ rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
+ i -= rh + hist_last_line_added;
+
+ /* No specification defaults to most recent command. */
+ if (command == NULL)
+ return (i);
+
+ /* Otherwise, there is a specification. It can be a number relative to
+ the current position, or an absolute history number. */
+ s = command;
+
+ /* Handle possible leading minus sign. */
+ if (s && (*s == '-'))
+ {
+ sign = -1;
+ s++;
+ }
+
+ if (s && DIGIT(*s))
+ {
+ n = atoi (s);
+ n *= sign;
+
+ /* If the value is negative or zero, then it is an offset from
+ the current history item. */
+ if (n < 0)
+ {
+ n += i + 1;
+ return (n < 0 ? 0 : n);
+ }
+ else if (n == 0)
+ return (i);
+ else
+ {
+ n -= history_base;
+ return (i < n ? i : n);
+ }
+ }
+
+ clen = strlen (command);
+ for (j = i; j >= 0; j--)
+ {
+ if (STREQN (command, histline (j), clen))
+ return (j);
+ }
+ return (-1);
+}
+
+/* Locate the most recent history line which begins with
+ COMMAND in HLIST, and return a malloc()'ed copy of it. */
+static char *
+fc_gethist (command, hlist)
+ char *command;
+ HIST_ENTRY **hlist;
+{
+ int i;
+
+ if (hlist == 0)
+ return ((char *)NULL);
+
+ i = fc_gethnum (command, hlist);
+
+ if (i >= 0)
+ return (savestring (histline (i)));
+ else
+ return ((char *)NULL);
+}
+
+#ifdef INCLUDE_UNUSED
+/* Read the edited history lines from STREAM and return them
+ one at a time. This can read unlimited length lines. The
+ caller should free the storage. */
+static char *
+fc_readline (stream)
+ FILE *stream;
+{
+ register int c;
+ int line_len = 0, lindex = 0;
+ char *line = (char *)NULL;
+
+ while ((c = getc (stream)) != EOF)
+ {
+ if ((lindex + 2) >= line_len)
+ line = (char *)xrealloc (line, (line_len += 128));
+
+ if (c == '\n')
+ {
+ line[lindex++] = '\n';
+ line[lindex++] = '\0';
+ return (line);
+ }
+ else
+ line[lindex++] = c;
+ }
+
+ if (!lindex)
+ {
+ if (line)
+ free (line);
+
+ return ((char *)NULL);
+ }
+
+ if (lindex + 2 >= line_len)
+ line = (char *)xrealloc (line, lindex + 3);
+
+ line[lindex++] = '\n'; /* Finish with newline if none in file */
+ line[lindex++] = '\0';
+ return (line);
+}
+#endif
+
+/* Perform the SUBS on COMMAND.
+ SUBS is a list of substitutions, and COMMAND is a simple string.
+ Return a pointer to a malloc'ed string which contains the substituted
+ command. */
+static char *
+fc_dosubs (command, subs)
+ char *command;
+ REPL *subs;
+{
+ register char *new, *t;
+ register REPL *r;
+
+ for (new = savestring (command), r = subs; r; r = r->next)
+ {
+ t = strsub (new, r->pat, r->rep, 1);
+ free (new);
+ new = t;
+ }
+ return (new);
+}
+
+/* Use `command' to replace the last entry in the history list, which,
+ by this time, is `fc blah...'. The intent is that the new command
+ become the history entry, and that `fc' should never appear in the
+ history list. This way you can do `r' to your heart's content. */
+static void
+fc_replhist (command)
+ char *command;
+{
+ int n;
+
+ if (command == 0 || *command == '\0')
+ return;
+
+ n = strlen (command);
+ if (command[n - 1] == '\n')
+ command[n - 1] = '\0';
+
+ if (command && *command)
+ {
+ bash_delete_last_history ();
+ maybe_add_history (command); /* Obeys HISTCONTROL setting. */
+ }
+}
+
+#ifdef INCLUDE_UNUSED
+/* Add LINE to the history, after removing a single trailing newline. */
+static void
+fc_addhist (line)
+ char *line;
+{
+ register int n;
+
+ if (line == 0 || *line == 0)
+ return;
+
+ n = strlen (line);
+
+ if (line[n - 1] == '\n')
+ line[n - 1] = '\0';
+
+ if (line && *line)
+ maybe_add_history (line); /* Obeys HISTCONTROL setting. */
+}
+#endif
+
+#endif /* HISTORY */
diff --git a/builtins/fg_bg.c b/builtins/fg_bg.c
new file mode 100644
index 0000000..874bdc2
--- /dev/null
+++ b/builtins/fg_bg.c
@@ -0,0 +1,143 @@
+/* fg_bg.c, created from fg_bg.def. */
+#line 22 "./fg_bg.def"
+
+#line 36 "./fg_bg.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include <signal.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../jobs.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if defined (JOB_CONTROL)
+extern char *this_command_name;
+
+static int fg_bg __P((WORD_LIST *, int));
+
+/* How to bring a job into the foreground. */
+int
+fg_builtin (list)
+ WORD_LIST *list;
+{
+ int fg_bit;
+ register WORD_LIST *t;
+
+ if (job_control == 0)
+ {
+ sh_nojobs ((char *)NULL);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
+
+ /* If the last arg on the line is '&', then start this job in the
+ background. Else, fg the job. */
+ for (t = list; t && t->next; t = t->next)
+ ;
+ fg_bit = (t && t->word->word[0] == '&' && t->word->word[1] == '\0') == 0;
+
+ return (fg_bg (list, fg_bit));
+}
+#endif /* JOB_CONTROL */
+
+#line 99 "./fg_bg.def"
+
+#if defined (JOB_CONTROL)
+/* How to put a job into the background. */
+int
+bg_builtin (list)
+ WORD_LIST *list;
+{
+ int r;
+
+ if (job_control == 0)
+ {
+ sh_nojobs ((char *)NULL);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
+
+ /* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts
+ on the first member (if any) of that list. */
+ r = EXECUTION_SUCCESS;
+ do
+ {
+ if (fg_bg (list, 0) == EXECUTION_FAILURE)
+ r = EXECUTION_FAILURE;
+ if (list)
+ list = list->next;
+ }
+ while (list);
+
+ return r;
+}
+
+/* How to put a job into the foreground/background. */
+static int
+fg_bg (list, foreground)
+ WORD_LIST *list;
+ int foreground;
+{
+ sigset_t set, oset;
+ int job, status, old_async_pid;
+ JOB *j;
+
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if (INVALID_JOB (job))
+ {
+ if (job != DUP_JOB)
+ sh_badjob (list ? list->word->word : _("current"));
+
+ goto failure;
+ }
+
+ j = get_job_by_jid (job);
+ /* Or if j->pgrp == shell_pgrp. */
+ if (IS_JOBCONTROL (job) == 0)
+ {
+ builtin_error (_("job %d started without job control"), job + 1);
+ goto failure;
+ }
+
+ if (foreground == 0)
+ {
+ old_async_pid = last_asynchronous_pid;
+ last_asynchronous_pid = j->pgrp; /* As per Posix.2 5.4.2 */
+ }
+
+ status = start_job (job, foreground);
+
+ if (status >= 0)
+ {
+ /* win: */
+ UNBLOCK_CHILD (oset);
+ return (foreground ? status : EXECUTION_SUCCESS);
+ }
+ else
+ {
+ if (foreground == 0)
+ last_asynchronous_pid = old_async_pid;
+
+ failure:
+ UNBLOCK_CHILD (oset);
+ return (EXECUTION_FAILURE);
+ }
+}
+#endif /* JOB_CONTROL */
diff --git a/builtins/getopts.c b/builtins/getopts.c
new file mode 100644
index 0000000..ce50c1a
--- /dev/null
+++ b/builtins/getopts.c
@@ -0,0 +1,270 @@
+/* getopts.c, created from getopts.def. */
+#line 22 "./getopts.def"
+
+#line 64 "./getopts.def"
+
+#include <config.h>
+
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+#include "getopt.h"
+
+#define G_EOF -1
+#define G_INVALID_OPT -2
+#define G_ARG_MISSING -3
+
+extern char *this_command_name;
+
+static int getopts_bind_variable __P((char *, char *));
+static int dogetopts __P((int, char **));
+
+/* getopts_reset is magic code for when OPTIND is reset. N is the
+ value that has just been assigned to OPTIND. */
+void
+getopts_reset (newind)
+ int newind;
+{
+ sh_optind = newind;
+ sh_badopt = 0;
+}
+
+static int
+getopts_bind_variable (name, value)
+ char *name, *value;
+{
+ SHELL_VAR *v;
+
+ if (legal_identifier (name))
+ {
+ v = bind_variable (name, value, 0);
+ return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
+ }
+ else
+ {
+ sh_invalidid (name);
+ return (EXECUTION_FAILURE);
+ }
+}
+
+/* Error handling is now performed as specified by Posix.2, draft 11
+ (identical to that of ksh-88). The special handling is enabled if
+ the first character of the option string is a colon; this handling
+ disables diagnostic messages concerning missing option arguments
+ and invalid option characters. The handling is as follows.
+
+ INVALID OPTIONS:
+ name -> "?"
+ if (special_error) then
+ OPTARG = option character found
+ no error output
+ else
+ OPTARG unset
+ diagnostic message
+ fi
+
+ MISSING OPTION ARGUMENT;
+ if (special_error) then
+ name -> ":"
+ OPTARG = option character found
+ else
+ name -> "?"
+ OPTARG unset
+ diagnostic message
+ fi
+ */
+
+static int
+dogetopts (argc, argv)
+ int argc;
+ char **argv;
+{
+ int ret, special_error, old_opterr, i, n;
+ char strval[2], numval[16];
+ char *optstr; /* list of options */
+ char *name; /* variable to get flag val */
+ char *t;
+
+ if (argc < 3)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ /* argv[0] is "getopts". */
+
+ optstr = argv[1];
+ name = argv[2];
+ argc -= 2;
+ argv += 2;
+
+ special_error = optstr[0] == ':';
+
+ if (special_error)
+ {
+ old_opterr = sh_opterr;
+ optstr++;
+ sh_opterr = 0; /* suppress diagnostic messages */
+ }
+
+ if (argc > 1)
+ {
+ sh_getopt_restore_state (argv);
+ t = argv[0];
+ argv[0] = dollar_vars[0];
+ ret = sh_getopt (argc, argv, optstr);
+ argv[0] = t;
+ }
+ else if (rest_of_args == (WORD_LIST *)NULL)
+ {
+ for (i = 0; i < 10 && dollar_vars[i]; i++)
+ ;
+
+ sh_getopt_restore_state (dollar_vars);
+ ret = sh_getopt (i, dollar_vars, optstr);
+ }
+ else
+ {
+ register WORD_LIST *words;
+ char **v;
+
+ for (i = 0; i < 10 && dollar_vars[i]; i++)
+ ;
+ for (words = rest_of_args; words; words = words->next, i++)
+ ;
+ v = strvec_create (i + 1);
+ for (i = 0; i < 10 && dollar_vars[i]; i++)
+ v[i] = dollar_vars[i];
+ for (words = rest_of_args; words; words = words->next, i++)
+ v[i] = words->word->word;
+ v[i] = (char *)NULL;
+ sh_getopt_restore_state (v);
+ ret = sh_getopt (i, v, optstr);
+ free (v);
+ }
+
+ if (special_error)
+ sh_opterr = old_opterr;
+
+ /* Set the OPTIND variable in any case, to handle "--" skipping. It's
+ highly unlikely that 14 digits will be too few. */
+ if (sh_optind < 10)
+ {
+ numval[14] = sh_optind + '0';
+ numval[15] = '\0';
+ i = 14;
+ }
+ else
+ {
+ numval[i = 15] = '\0';
+ n = sh_optind;
+ do
+ {
+ numval[--i] = (n % 10) + '0';
+ }
+ while (n /= 10);
+ }
+ bind_variable ("OPTIND", numval + i, 0);
+
+ /* If an error occurred, decide which one it is and set the return
+ code appropriately. In all cases, the option character in error
+ is in OPTOPT. If an invalid option was encountered, OPTARG is
+ NULL. If a required option argument was missing, OPTARG points
+ to a NULL string (that is, sh_optarg[0] == 0). */
+ if (ret == '?')
+ {
+ if (sh_optarg == NULL)
+ ret = G_INVALID_OPT;
+ else if (sh_optarg[0] == '\0')
+ ret = G_ARG_MISSING;
+ }
+
+ if (ret == G_EOF)
+ {
+ unbind_variable ("OPTARG");
+ getopts_bind_variable (name, "?");
+ return (EXECUTION_FAILURE);
+ }
+
+ if (ret == G_INVALID_OPT)
+ {
+ /* Invalid option encountered. */
+ ret = getopts_bind_variable (name, "?");
+
+ if (special_error)
+ {
+ strval[0] = (char)sh_optopt;
+ strval[1] = '\0';
+ bind_variable ("OPTARG", strval, 0);
+ }
+ else
+ unbind_variable ("OPTARG");
+
+ return (ret);
+ }
+
+ if (ret == G_ARG_MISSING)
+ {
+ /* Required argument missing. */
+ if (special_error)
+ {
+ ret = getopts_bind_variable (name, ":");
+
+ strval[0] = (char)sh_optopt;
+ strval[1] = '\0';
+ bind_variable ("OPTARG", strval, 0);
+ }
+ else
+ {
+ ret = getopts_bind_variable (name, "?");
+ unbind_variable ("OPTARG");
+ }
+ return (ret);
+ }
+
+ bind_variable ("OPTARG", sh_optarg, 0);
+
+ strval[0] = (char) ret;
+ strval[1] = '\0';
+ return (getopts_bind_variable (name, strval));
+}
+
+/* The getopts builtin. Build an argv, and call dogetopts with it. */
+int
+getopts_builtin (list)
+ WORD_LIST *list;
+{
+ char **av;
+ int ac, ret;
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return EX_USAGE;
+ }
+
+ reset_internal_getopt ();
+ if (internal_getopt (list, "") != -1)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ list = loptend;
+
+ av = make_builtin_argv (list, &ac);
+ ret = dogetopts (ac, av);
+ free ((char *)av);
+
+ return (ret);
+}
diff --git a/builtins/hash.c b/builtins/hash.c
new file mode 100644
index 0000000..05e5aa9
--- /dev/null
+++ b/builtins/hash.c
@@ -0,0 +1,240 @@
+/* hash.c, created from hash.def. */
+#line 22 "./hash.def"
+
+#line 46 "./hash.def"
+
+#include <config.h>
+
+#include <stdio.h>
+
+#include "../bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../flags.h"
+#include "../findcmd.h"
+#include "../hashcmd.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int posixly_correct;
+extern int dot_found_in_search;
+extern char *this_command_name;
+
+static int add_hashed_command __P((char *, int));
+static int print_hash_info __P((BUCKET_CONTENTS *));
+static int print_portable_hash_info __P((BUCKET_CONTENTS *));
+static int print_hashed_commands __P((int));
+static int list_hashed_filename_targets __P((WORD_LIST *, int));
+
+/* Print statistics on the current state of hashed commands. If LIST is
+ not empty, then rehash (or hash in the first place) the specified
+ commands. */
+int
+hash_builtin (list)
+ WORD_LIST *list;
+{
+ int expunge_hash_table, list_targets, list_portably, delete, opt;
+ char *w, *pathname;
+
+ if (hashing_enabled == 0)
+ {
+ builtin_error (_("hashing disabled"));
+ return (EXECUTION_FAILURE);
+ }
+
+ expunge_hash_table = list_targets = list_portably = delete = 0;
+ pathname = (char *)NULL;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "dlp:rt")) != -1)
+ {
+ switch (opt)
+ {
+ case 'd':
+ delete = 1;
+ break;
+ case 'l':
+ list_portably = 1;
+ break;
+ case 'p':
+ pathname = list_optarg;
+ break;
+ case 'r':
+ expunge_hash_table = 1;
+ break;
+ case 't':
+ list_targets = 1;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ /* hash -t requires at least one argument. */
+ if (list == 0 && list_targets)
+ {
+ sh_needarg ("-t");
+ return (EXECUTION_FAILURE);
+ }
+
+ /* We want hash -r to be silent, but hash -- to print hashing info, so
+ we test expunge_hash_table. */
+ if (list == 0 && expunge_hash_table == 0)
+ {
+ opt = print_hashed_commands (list_portably);
+ if (opt == 0 && posixly_correct == 0)
+ printf (_("%s: hash table empty\n"), this_command_name);
+
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (expunge_hash_table)
+ phash_flush ();
+
+ /* If someone runs `hash -r -t xyz' he will be disappointed. */
+ if (list_targets)
+ return (list_hashed_filename_targets (list, list_portably));
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted && pathname && strchr (pathname, '/'))
+ {
+ sh_restricted (pathname);
+ return (EXECUTION_FAILURE);
+ }
+#endif
+
+ for (opt = EXECUTION_SUCCESS; list; list = list->next)
+ {
+ /* Add, remove or rehash the specified commands. */
+ w = list->word->word;
+ if (pathname)
+ {
+ if (is_directory (pathname))
+ {
+#ifdef EISDIR
+ builtin_error ("%s: %s", pathname, strerror (EISDIR));
+#else
+ builtin_error (_("%s: is a directory"), pathname);
+#endif
+ opt = EXECUTION_FAILURE;
+ }
+ else
+ phash_insert (w, pathname, 0, 0);
+ }
+ else if (absolute_program (w))
+ continue;
+ else if (delete)
+ {
+ if (phash_remove (w))
+ {
+ sh_notfound (w);
+ opt = EXECUTION_FAILURE;
+ }
+ }
+ else if (add_hashed_command (w, 0))
+ opt = EXECUTION_FAILURE;
+ }
+
+ fflush (stdout);
+ return (opt);
+}
+
+static int
+add_hashed_command (w, quiet)
+ char *w;
+ int quiet;
+{
+ int rv;
+ char *full_path;
+
+ rv = 0;
+ if (find_function (w) == 0 && find_shell_builtin (w) == 0)
+ {
+ full_path = find_user_command (w);
+ if (full_path && executable_file (full_path))
+ phash_insert (w, full_path, dot_found_in_search, 0);
+ else
+ {
+ if (quiet == 0)
+ sh_notfound (w);
+ rv++;
+ }
+ FREE (full_path);
+ }
+ return (rv);
+}
+
+/* Print information about current hashed info. */
+static int
+print_hash_info (item)
+ BUCKET_CONTENTS *item;
+{
+ printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
+ return 0;
+}
+
+static int
+print_portable_hash_info (item)
+ BUCKET_CONTENTS *item;
+{
+ printf ("builtin hash -p %s %s\n", pathdata(item)->path, item->key);
+ return 0;
+}
+
+static int
+print_hashed_commands (fmt)
+ int fmt;
+{
+ if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
+ return (0);
+
+ if (fmt == 0)
+ printf (_("hits\tcommand\n"));
+ hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
+ return (1);
+}
+
+static int
+list_hashed_filename_targets (list, fmt)
+ WORD_LIST *list;
+ int fmt;
+{
+ int all_found, multiple;
+ char *target;
+ WORD_LIST *l;
+
+ all_found = 1;
+ multiple = list->next != 0;
+
+ for (l = list; l; l = l->next)
+ {
+ target = phash_search (l->word->word);
+ if (target == 0)
+ {
+ all_found = 0;
+ sh_notfound (l->word->word);
+ continue;
+ }
+ if (fmt)
+ printf ("builtin hash -p %s %s\n", target, l->word->word);
+ else
+ {
+ if (multiple)
+ printf ("%s\t", l->word->word);
+ printf ("%s\n", target);
+ }
+ }
+
+ return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
diff --git a/builtins/help.c b/builtins/help.c
new file mode 100644
index 0000000..d274535
--- /dev/null
+++ b/builtins/help.c
@@ -0,0 +1,345 @@
+/* help.c, created from help.def. */
+#line 22 "./help.def"
+
+#line 45 "./help.def"
+
+#include <config.h>
+
+#if defined (HELP_BUILTIN)
+#include <stdio.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#include <filecntl.h>
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../pathexp.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#include <glob/strmatch.h>
+#include <glob/glob.h>
+
+#ifndef errno
+extern int errno;
+#endif
+
+extern const char * const bash_copyright;
+extern const char * const bash_license;
+
+static void show_builtin_command_help __P((void));
+static int open_helpfile __P((char *));
+static void show_desc __P((char *, int));
+static void show_manpage __P((char *, int));
+static void show_longdoc __P((int));
+
+/* Print out a list of the known functions in the shell, and what they do.
+ If LIST is supplied, print out the list which matches for each pattern
+ specified. */
+int
+help_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ char *pattern, *name;
+ int plen, match_found, sflag, dflag, mflag;
+
+ dflag = sflag = mflag = 0;
+ reset_internal_getopt ();
+ while ((i = internal_getopt (list, "dms")) != -1)
+ {
+ switch (i)
+ {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'm':
+ mflag = 1;
+ break;
+ case 's':
+ sflag = 1;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list == 0)
+ {
+ show_shell_version (0);
+ show_builtin_command_help ();
+ return (EXECUTION_SUCCESS);
+ }
+
+ /* We should consider making `help bash' do something. */
+
+ if (glob_pattern_p (list->word->word))
+ {
+ printf (ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
+ print_word_list (list, ", ");
+ printf ("'\n\n");
+ }
+
+ for (match_found = 0, pattern = ""; list; list = list->next)
+ {
+ pattern = list->word->word;
+ plen = strlen (pattern);
+
+ for (i = 0; name = shell_builtins[i].name; i++)
+ {
+ QUIT;
+ if ((strncmp (pattern, name, plen) == 0) ||
+ (strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH))
+ {
+ match_found++;
+ if (dflag)
+ {
+ show_desc (name, i);
+ continue;
+ }
+ else if (mflag)
+ {
+ show_manpage (name, i);
+ continue;
+ }
+
+ printf ("%s: %s\n", name, shell_builtins[i].short_doc);
+
+ if (sflag == 0)
+ show_longdoc (i);
+ }
+ }
+ }
+
+ if (match_found == 0)
+ {
+ builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
+ return (EXECUTION_FAILURE);
+ }
+
+ fflush (stdout);
+ return (EXECUTION_SUCCESS);
+}
+
+static int
+open_helpfile (name)
+ char *name;
+{
+ int fd;
+
+ fd = open (name, O_RDONLY);
+ if (fd == -1)
+ {
+ builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
+ return -1;
+ }
+ return fd;
+}
+
+/* By convention, enforced by mkbuiltins.c, if separate help files are being
+ used, the long_doc array contains one string -- the full pathname of the
+ help file for this builtin. */
+static void
+show_longdoc (i)
+ int i;
+{
+ register int j;
+ char * const *doc;
+ int fd;
+
+ doc = shell_builtins[i].long_doc;
+
+ if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
+ {
+ fd = open_helpfile (doc[0]);
+ if (fd < 0)
+ return;
+ zcatfd (fd, 1, doc[0]);
+ close (fd);
+ }
+ else
+ for (j = 0; doc[j]; j++)
+ printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
+}
+
+static void
+show_desc (name, i)
+ char *name;
+ int i;
+{
+ register int j;
+ char **doc, *line;
+ int fd, usefile;
+
+ doc = (char **)shell_builtins[i].long_doc;
+
+ usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
+ if (usefile)
+ {
+ fd = open_helpfile (doc[0]);
+ if (fd < 0)
+ return;
+ zmapfd (fd, &line, doc[0]);
+ close (fd);
+ }
+ else
+ line = doc ? doc[0] : (char *)NULL;
+
+ printf ("%s - ", name);
+ for (j = 0; line && line[j]; j++)
+ {
+ putchar (line[j]);
+ if (line[j] == '\n')
+ break;
+ }
+
+ fflush (stdout);
+
+ if (usefile)
+ free (line);
+}
+
+/* Print builtin help in pseudo-manpage format. */
+static void
+show_manpage (name, i)
+ char *name;
+ int i;
+{
+ register int j;
+ char **doc, *line;
+ int fd, usefile;
+
+ doc = (char **)shell_builtins[i].long_doc;
+
+ usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
+ if (usefile)
+ {
+ fd = open_helpfile (doc[0]);
+ if (fd < 0)
+ return;
+ zmapfd (fd, &line, doc[0]);
+ close (fd);
+ }
+ else
+ line = doc ? _(doc[0]) : (char *)NULL;
+
+ /* NAME */
+ printf ("NAME\n");
+ printf ("%*s%s - ", BASE_INDENT, " ", name);
+ for (j = 0; line && line[j]; j++)
+ {
+ putchar (line[j]);
+ if (line[j] == '\n')
+ break;
+ }
+ printf ("\n");
+
+ /* SYNOPSIS */
+ printf ("SYNOPSIS\n");
+ printf ("%*s%s\n\n", BASE_INDENT, " ", shell_builtins[i].short_doc);
+
+ /* DESCRIPTION */
+ printf ("DESCRIPTION\n");
+ if (usefile == 0)
+ {
+ for (j = 0; doc[j]; j++)
+ printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
+ }
+ else
+ {
+ for (j = 0; line && line[j]; j++)
+ {
+ putchar (line[j]);
+ if (line[j] == '\n')
+ printf ("%*s", BASE_INDENT, " ");
+ }
+ }
+ putchar ('\n');
+
+ /* SEE ALSO */
+ printf ("SEE ALSO\n");
+ printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
+
+ /* IMPLEMENTATION */
+ printf ("IMPLEMENTATION\n");
+ printf ("%*s", BASE_INDENT, " ");
+ show_shell_version (0);
+ printf ("%*s", BASE_INDENT, " ");
+ printf ("%s\n", _(bash_copyright));
+ printf ("%*s", BASE_INDENT, " ");
+ printf ("%s\n", _(bash_license));
+
+ fflush (stdout);
+ if (usefile)
+ free (line);
+}
+
+static void
+show_builtin_command_help ()
+{
+ int i, j;
+ int height, width;
+ char *t, blurb[128];
+
+ printf (
+_("These shell commands are defined internally. Type `help' to see this list.\n\
+Type `help name' to find out more about the function `name'.\n\
+Use `info bash' to find out more about the shell in general.\n\
+Use `man -k' or `info' to find out more about commands not in this list.\n\
+\n\
+A star (*) next to a name means that the command is disabled.\n\
+\n"));
+
+ t = get_string_value ("COLUMNS");
+ width = (t && *t) ? atoi (t) : 80;
+ if (width <= 0)
+ width = 80;
+
+ width /= 2;
+ if (width > sizeof (blurb))
+ width = sizeof (blurb);
+ if (width <= 3)
+ width = 40;
+ height = (num_shell_builtins + 1) / 2; /* number of rows */
+
+ for (i = 0; i < height; i++)
+ {
+ QUIT;
+
+ /* first column */
+ blurb[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
+ strncpy (blurb + 1, shell_builtins[i].short_doc, width - 2);
+ blurb[width - 2] = '>'; /* indicate truncation */
+ blurb[width - 1] = '\0';
+ printf ("%s", blurb);
+ if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
+ {
+ printf ("\n");
+ break;
+ }
+
+ /* two spaces */
+ for (j = strlen (blurb); j < width; j++)
+ putc (' ', stdout);
+
+ /* second column */
+ blurb[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
+ strncpy (blurb + 1, shell_builtins[i+height].short_doc, width - 3);
+ blurb[width - 3] = '>'; /* indicate truncation */
+ blurb[width - 2] = '\0';
+ printf ("%s\n", blurb);
+ }
+}
+#endif /* HELP_BUILTIN */
diff --git a/builtins/history.c b/builtins/history.c
new file mode 100644
index 0000000..c5c5818
--- /dev/null
+++ b/builtins/history.c
@@ -0,0 +1,328 @@
+/* history.c, created from history.def. */
+#line 22 "./history.def"
+
+#line 57 "./history.def"
+
+#include <config.h>
+
+#if defined (HISTORY)
+#include "../bashtypes.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+#include "posixstat.h"
+#include "filecntl.h"
+#include <errno.h>
+#include <stdio.h>
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../bashhist.h"
+#include <readline/history.h>
+#include "bashgetopt.h"
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+extern int current_command_line_count;
+extern int force_append_history; /* shopt -s histappend */
+
+static char *histtime __P((HIST_ENTRY *, const char *));
+static int display_history __P((WORD_LIST *));
+static void push_history __P((WORD_LIST *));
+static int expand_and_print_history __P((WORD_LIST *));
+
+#define AFLAG 0x01
+#define RFLAG 0x02
+#define WFLAG 0x04
+#define NFLAG 0x08
+#define SFLAG 0x10
+#define PFLAG 0x20
+#define CFLAG 0x40
+#define DFLAG 0x80
+
+int
+history_builtin (list)
+ WORD_LIST *list;
+{
+ int flags, opt, result, old_history_lines, obase;
+ char *filename, *delete_arg;
+ intmax_t delete_offset;
+
+ flags = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ flags |= AFLAG;
+ break;
+ case 'c':
+ flags |= CFLAG;
+ break;
+ case 'n':
+ flags |= NFLAG;
+ break;
+ case 'r':
+ flags |= RFLAG;
+ break;
+ case 'w':
+ flags |= WFLAG;
+ break;
+ case 's':
+ flags |= SFLAG;
+ break;
+ case 'd':
+ flags |= DFLAG;
+ delete_arg = list_optarg;
+ break;
+ case 'p':
+#if defined (BANG_HISTORY)
+ flags |= PFLAG;
+#endif
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
+ if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
+ {
+ builtin_error (_("cannot use more than one of -anrw"));
+ return (EXECUTION_FAILURE);
+ }
+
+ /* clear the history, but allow other arguments to add to it again. */
+ if (flags & CFLAG)
+ {
+ bash_clear_history ();
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (flags & SFLAG)
+ {
+ if (list)
+ push_history (list);
+ return (EXECUTION_SUCCESS);
+ }
+#if defined (BANG_HISTORY)
+ else if (flags & PFLAG)
+ {
+ if (list)
+ return (expand_and_print_history (list));
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+#endif
+ else if (flags & DFLAG)
+ {
+ if ((legal_number (delete_arg, &delete_offset) == 0)
+ || (delete_offset < history_base)
+ || (delete_offset > (history_base + history_length)))
+ {
+ sh_erange (delete_arg, _("history position"));
+ return (EXECUTION_FAILURE);
+ }
+ opt = delete_offset;
+ result = bash_delete_histent (opt - history_base);
+ /* Since remove_history changes history_length, this can happen if
+ we delete the last history entry. */
+ if (where_history () > history_length)
+ history_set_pos (history_length);
+ return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+ }
+ else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
+ {
+ result = display_history (list);
+ return (sh_chkwrite (result));
+ }
+
+ filename = list ? list->word->word : get_string_value ("HISTFILE");
+ result = EXECUTION_SUCCESS;
+
+ if (flags & AFLAG) /* Append session's history to file. */
+ result = maybe_append_history (filename);
+ else if (flags & WFLAG) /* Write entire history. */
+ result = write_history (filename);
+ else if (flags & RFLAG) /* Read entire file. */
+ result = read_history (filename);
+ else if (flags & NFLAG) /* Read `new' history from file. */
+ {
+ /* Read all of the lines in the file that we haven't already read. */
+ old_history_lines = history_lines_in_file;
+ obase = history_base;
+
+ using_history ();
+ result = read_history_range (filename, history_lines_in_file, -1);
+ using_history ();
+
+ history_lines_in_file = where_history ();
+
+ /* If we're rewriting the history file at shell exit rather than just
+ appending the lines from this session to it, the question is whether
+ we reset history_lines_this_session to 0, losing any history entries
+ we had before we read the new entries from the history file, or
+ whether we count the new entries we just read from the file as
+ history lines added during this session.
+ Right now, we do the latter. This will cause these history entries
+ to be written to the history file along with any intermediate entries
+ we add when we do a `history -a', but the alternative is losing
+ them altogether. */
+ if (force_append_history == 0)
+ history_lines_this_session += history_lines_in_file - old_history_lines +
+ history_base - obase;
+ }
+
+ return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+/* Accessors for HIST_ENTRY lists that are called HLIST. */
+#define histline(i) (hlist[(i)]->line)
+#define histdata(i) (hlist[(i)]->data)
+
+static char *
+histtime (hlist, histtimefmt)
+ HIST_ENTRY *hlist;
+ const char *histtimefmt;
+{
+ static char timestr[128];
+ time_t t;
+
+ t = history_get_time (hlist);
+ if (t)
+ strftime (timestr, sizeof (timestr), histtimefmt, localtime (&t));
+ else
+ strcpy (timestr, "??");
+ return timestr;
+}
+
+static int
+display_history (list)
+ WORD_LIST *list;
+{
+ register int i;
+ intmax_t limit;
+ HIST_ENTRY **hlist;
+ char *histtimefmt, *timestr;
+
+ if (list)
+ {
+ if (get_numeric_arg (list, 0, &limit) == 0)
+ return (EXECUTION_FAILURE);
+
+ if (limit < 0)
+ limit = -limit;
+ }
+ else
+ limit = -1;
+
+ hlist = history_list ();
+
+ if (hlist)
+ {
+ for (i = 0; hlist[i]; i++)
+ ;
+
+ if (0 <= limit && limit < i)
+ i -= limit;
+ else
+ i = 0;
+
+ histtimefmt = get_string_value ("HISTTIMEFORMAT");
+
+ while (hlist[i])
+ {
+ QUIT;
+
+ timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL;
+ printf ("%5d%c %s%s\n", i + history_base,
+ histdata(i) ? '*' : ' ',
+ ((timestr && *timestr) ? timestr : ""),
+ histline(i));
+ i++;
+ }
+ }
+
+ return (EXECUTION_SUCCESS);
+}
+
+/* Remove the last entry in the history list and add each argument in
+ LIST to the history. */
+static void
+push_history (list)
+ WORD_LIST *list;
+{
+ char *s;
+
+ /* Delete the last history entry if it was a single entry added to the
+ history list (generally the `history -s' itself), or if `history -s'
+ is being used in a compound command and the compound command was
+ added to the history as a single element (command-oriented history).
+ If you don't want history -s to remove the compound command from the
+ history, change #if 0 to #if 1 below. */
+#if 0
+ if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
+#else
+ if (hist_last_line_pushed == 0 &&
+ (hist_last_line_added ||
+ (current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
+ && bash_delete_last_history () == 0)
+#endif
+ return;
+
+ s = string_list (list);
+ /* Call check_add_history with FORCE set to 1 to skip the check against
+ current_command_line_count. If history -s is used in a compound
+ command, the above code will delete the compound command's history
+ entry and this call will add the line to the history as a separate
+ entry. Without FORCE=1, if current_command_line_count were > 1, the
+ line would be appended to the entry before the just-deleted entry. */
+ check_add_history (s, 1); /* obeys HISTCONTROL, HISTIGNORE */
+
+ hist_last_line_pushed = 1; /* XXX */
+ free (s);
+}
+
+#if defined (BANG_HISTORY)
+static int
+expand_and_print_history (list)
+ WORD_LIST *list;
+{
+ char *s;
+ int r, result;
+
+ if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
+ return EXECUTION_FAILURE;
+ result = EXECUTION_SUCCESS;
+ while (list)
+ {
+ r = history_expand (list->word->word, &s);
+ if (r < 0)
+ {
+ builtin_error (_("%s: history expansion failed"), list->word->word);
+ result = EXECUTION_FAILURE;
+ }
+ else
+ {
+ fputs (s, stdout);
+ putchar ('\n');
+ }
+ FREE (s);
+ list = list->next;
+ }
+ fflush (stdout);
+ return result;
+}
+#endif /* BANG_HISTORY */
+#endif /* HISTORY */
diff --git a/builtins/inlib.c b/builtins/inlib.c
new file mode 100644
index 0000000..8e218b1
--- /dev/null
+++ b/builtins/inlib.c
@@ -0,0 +1,46 @@
+/* inlib.c, created from inlib.def. */
+#line 22 "./inlib.def"
+#include <config.h>
+
+#include <stdio.h>
+#include "../shell.h"
+
+#line 43 "./inlib.def"
+
+#if defined (apollo)
+
+#include <apollo/base.h>
+#include <apollo/loader.h>
+
+inlib_builtin (list)
+ WORD_LIST *list;
+{
+ status_$t status;
+ int return_value;
+ short len;
+
+ if (!list)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ return_value = EXECUTION_SUCCESS;
+
+ while (list)
+ {
+ len = (short)strlen (list->word->word);
+ loader_$inlib (list->word->word, len, &status);
+
+ if (status.all != status_$ok)
+ {
+ builtin_error (_("%s: inlib failed"), list->word->word);
+ return_value = EXECUTION_FAILURE;
+ }
+
+ list = list->next;
+ }
+
+ return (return_value);
+}
+#endif /* apollo */
diff --git a/builtins/jobs.c b/builtins/jobs.c
new file mode 100644
index 0000000..176e12a
--- /dev/null
+++ b/builtins/jobs.c
@@ -0,0 +1,238 @@
+/* jobs.c, created from jobs.def. */
+#line 22 "./jobs.def"
+
+#line 48 "./jobs.def"
+
+#include <config.h>
+
+#if defined (JOB_CONTROL)
+#include "../bashtypes.h"
+#include <signal.h>
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../jobs.h"
+#include "../execute_cmd.h"
+#include "bashgetopt.h"
+#include "common.h"
+
+#define JSTATE_ANY 0x0
+#define JSTATE_RUNNING 0x1
+#define JSTATE_STOPPED 0x2
+
+static int execute_list_with_replacements __P((WORD_LIST *));
+
+/* The `jobs' command. Prints outs a list of active jobs. If the
+ argument `-l' is given, then the process id's are printed also.
+ If the argument `-p' is given, print the process group leader's
+ pid only. If `-n' is given, only processes that have changed
+ status since the last notification are printed. If -x is given,
+ replace all job specs with the pid of the appropriate process
+ group leader and execute the command. The -r and -s options mean
+ to print info about running and stopped jobs only, respectively. */
+int
+jobs_builtin (list)
+ WORD_LIST *list;
+{
+ int form, execute, state, opt, any_failed, job;
+ sigset_t set, oset;
+
+ execute = any_failed = 0;
+ form = JLIST_STANDARD;
+ state = JSTATE_ANY;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "lpnxrs")) != -1)
+ {
+ switch (opt)
+ {
+ case 'l':
+ form = JLIST_LONG;
+ break;
+ case 'p':
+ form = JLIST_PID_ONLY;
+ break;
+ case 'n':
+ form = JLIST_CHANGED_ONLY;
+ break;
+ case 'x':
+ if (form != JLIST_STANDARD)
+ {
+ builtin_error (_("no other options allowed with `-x'"));
+ return (EXECUTION_FAILURE);
+ }
+ execute++;
+ break;
+ case 'r':
+ state = JSTATE_RUNNING;
+ break;
+ case 's':
+ state = JSTATE_STOPPED;
+ break;
+
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (execute)
+ return (execute_list_with_replacements (list));
+
+ if (!list)
+ {
+ switch (state)
+ {
+ case JSTATE_ANY:
+ list_all_jobs (form);
+ break;
+ case JSTATE_RUNNING:
+ list_running_jobs (form);
+ break;
+ case JSTATE_STOPPED:
+ list_stopped_jobs (form);
+ break;
+ }
+ return (EXECUTION_SUCCESS);
+ }
+
+ while (list)
+ {
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
+ {
+ sh_badjob (list->word->word);
+ any_failed++;
+ }
+ else if (job != DUP_JOB)
+ list_one_job ((JOB *)NULL, form, 0, job);
+
+ UNBLOCK_CHILD (oset);
+ list = list->next;
+ }
+ return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+static int
+execute_list_with_replacements (list)
+ WORD_LIST *list;
+{
+ register WORD_LIST *l;
+ int job, result;
+ COMMAND *command;
+ JOB *j;
+
+ /* First do the replacement of job specifications with pids. */
+ for (l = list; l; l = l->next)
+ {
+ if (l->word->word[0] == '%') /* we have a winner */
+ {
+ job = get_job_spec (l);
+
+ /* A bad job spec is not really a job spec! Pass it through. */
+ if (INVALID_JOB (job))
+ continue;
+
+ j = get_job_by_jid (job);
+ free (l->word->word);
+ l->word->word = itos (j->pgrp);
+ }
+ }
+
+ /* Next make a new simple command and execute it. */
+ begin_unwind_frame ("jobs_builtin");
+
+ command = make_bare_simple_command ();
+ command->value.Simple->words = copy_word_list (list);
+ command->value.Simple->redirects = (REDIRECT *)NULL;
+ command->flags |= CMD_INHIBIT_EXPANSION;
+ command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
+
+ add_unwind_protect (dispose_command, command);
+ result = execute_command (command);
+ dispose_command (command);
+
+ discard_unwind_frame ("jobs_builtin");
+ return (result);
+}
+#endif /* JOB_CONTROL */
+
+#line 230 "./jobs.def"
+
+#if defined (JOB_CONTROL)
+int
+disown_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, job, retval, nohup_only, running_jobs, all_jobs;
+ sigset_t set, oset;
+ intmax_t pid_value;
+
+ nohup_only = running_jobs = all_jobs = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "ahr")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ all_jobs = 1;
+ break;
+ case 'h':
+ nohup_only = 1;
+ break;
+ case 'r':
+ running_jobs = 1;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+ retval = EXECUTION_SUCCESS;
+
+ /* `disown -a' or `disown -r' */
+ if (list == 0 && (all_jobs || running_jobs))
+ {
+ if (nohup_only)
+ nohup_all_jobs (running_jobs);
+ else
+ delete_all_jobs (running_jobs);
+ return (EXECUTION_SUCCESS);
+ }
+
+ do
+ {
+ BLOCK_CHILD (set, oset);
+ job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
+ ? get_job_by_pid ((pid_t) pid_value, 0)
+ : get_job_spec (list);
+
+ if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
+ {
+ sh_badjob (list ? list->word->word : _("current"));
+ retval = EXECUTION_FAILURE;
+ }
+ else if (nohup_only)
+ nohup_job (job);
+ else
+ delete_job (job, 1);
+ UNBLOCK_CHILD (oset);
+
+ if (list)
+ list = list->next;
+ }
+ while (list);
+
+ return (retval);
+}
+#endif /* JOB_CONTROL */
diff --git a/builtins/kill.c b/builtins/kill.c
new file mode 100644
index 0000000..e68b345
--- /dev/null
+++ b/builtins/kill.c
@@ -0,0 +1,225 @@
+/* kill.c, created from kill.def. */
+#line 22 "./kill.def"
+
+#line 45 "./kill.def"
+
+#include <config.h>
+
+#include <stdio.h>
+#include <errno.h>
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../trap.h"
+#include "../jobs.h"
+#include "common.h"
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int posixly_correct;
+
+static void kill_error __P((pid_t, int));
+
+#if !defined (CONTINUE_AFTER_KILL_ERROR)
+# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE)
+#else
+# define CONTINUE_OR_FAIL goto continue_killing
+#endif /* CONTINUE_AFTER_KILL_ERROR */
+
+/* Here is the kill builtin. We only have it so that people can type
+ kill -KILL %1? No, if you fill up the process table this way you
+ can still kill some. */
+int
+kill_builtin (list)
+ WORD_LIST *list;
+{
+ int sig, any_succeeded, listing, saw_signal, dflags;
+ char *sigspec, *word;
+ pid_t pid;
+ intmax_t pid_value;
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+
+ any_succeeded = listing = saw_signal = 0;
+ sig = SIGTERM;
+ sigspec = "TERM";
+
+ dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0);
+ /* Process options. */
+ while (list)
+ {
+ word = list->word->word;
+
+ if (ISOPTION (word, 'l'))
+ {
+ listing++;
+ list = list->next;
+ }
+ else if (ISOPTION (word, 's') || ISOPTION (word, 'n'))
+ {
+ list = list->next;
+ if (list)
+ {
+ sigspec = list->word->word;
+ if (sigspec[0] == '0' && sigspec[1] == '\0')
+ sig = 0;
+ else
+ sig = decode_signal (sigspec, dflags);
+ list = list->next;
+#if 0
+ saw_signal++; /* XXX - for bash-4.2 */
+#endif
+ }
+ else
+ {
+ sh_needarg (word);
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else if (ISOPTION (word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (ISOPTION (word, '?'))
+ {
+ builtin_usage ();
+ return (EXECUTION_SUCCESS);
+ }
+ /* If this is a signal specification then process it. We only process
+ the first one seen; other arguments may signify process groups (e.g,
+ -num == process group num). */
+ else if (*word == '-' && saw_signal == 0)
+ {
+ sigspec = word + 1;
+ sig = decode_signal (sigspec, dflags);
+ saw_signal++;
+ list = list->next;
+ }
+ else
+ break;
+ }
+
+ if (listing)
+ return (display_signal_list (list, 0));
+
+ /* OK, we are killing processes. */
+ if (sig == NO_SIG)
+ {
+ sh_invalidsig (sigspec);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+
+ while (list)
+ {
+ word = list->word->word;
+
+ if (*word == '-')
+ word++;
+
+ /* Use the entire argument in case of minus sign presence. */
+ if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value))
+ {
+ pid = (pid_t) pid_value;
+
+ if (kill_pid (pid, sig, pid < -1) < 0)
+ {
+ if (errno == EINVAL)
+ sh_invalidsig (sigspec);
+ else
+ kill_error (pid, errno);
+ CONTINUE_OR_FAIL;
+ }
+ else
+ any_succeeded++;
+ }
+#if defined (JOB_CONTROL)
+ else if (*list->word->word && *list->word->word != '%')
+ {
+ builtin_error (_("%s: arguments must be process or job IDs"), list->word->word);
+ CONTINUE_OR_FAIL;
+ }
+ else if (*word)
+ /* Posix.2 says you can kill without job control active (4.32.4) */
+ { /* Must be a job spec. Check it out. */
+ int job;
+ sigset_t set, oset;
+ JOB *j;
+
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if (INVALID_JOB (job))
+ {
+ if (job != DUP_JOB)
+ sh_badjob (list->word->word);
+ UNBLOCK_CHILD (oset);
+ CONTINUE_OR_FAIL;
+ }
+
+ j = get_job_by_jid (job);
+ /* Job spec used. Kill the process group. If the job was started
+ without job control, then its pgrp == shell_pgrp, so we have
+ to be careful. We take the pid of the first job in the pipeline
+ in that case. */
+ pid = IS_JOBCONTROL (job) ? j->pgrp : j->pipe->pid;
+
+ UNBLOCK_CHILD (oset);
+
+ if (kill_pid (pid, sig, 1) < 0)
+ {
+ if (errno == EINVAL)
+ sh_invalidsig (sigspec);
+ else
+ kill_error (pid, errno);
+ CONTINUE_OR_FAIL;
+ }
+ else
+ any_succeeded++;
+ }
+#endif /* !JOB_CONTROL */
+ else
+ {
+ sh_badpid (list->word->word);
+ CONTINUE_OR_FAIL;
+ }
+ continue_killing:
+ list = list->next;
+ }
+
+ return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
+static void
+kill_error (pid, e)
+ pid_t pid;
+ int e;
+{
+ char *x;
+
+ x = strerror (e);
+ if (x == 0)
+ x = _("Unknown error");
+ builtin_error ("(%ld) - %s", (long)pid, x);
+}
diff --git a/builtins/let.c b/builtins/let.c
new file mode 100644
index 0000000..ea3caf3
--- /dev/null
+++ b/builtins/let.c
@@ -0,0 +1,66 @@
+/* let.c, created from let.def. */
+#line 66 "./let.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+
+/* Arithmetic LET function. */
+int
+let_builtin (list)
+ WORD_LIST *list;
+{
+ intmax_t ret;
+ int expok;
+
+ /* Skip over leading `--' argument. */
+ if (list && list->word && ISOPTION (list->word->word, '-'))
+ list = list->next;
+
+ if (list == 0)
+ {
+ builtin_error (_("expression expected"));
+ return (EXECUTION_FAILURE);
+ }
+
+ for (; list; list = list->next)
+ {
+ ret = evalexp (list->word->word, &expok);
+ if (expok == 0)
+ return (EXECUTION_FAILURE);
+ }
+
+ return ((ret == 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+#ifdef INCLUDE_UNUSED
+int
+exp_builtin (list)
+ WORD_LIST *list;
+{
+ char *exp;
+ intmax_t ret;
+ int expok;
+
+ if (list == 0)
+ {
+ builtin_error (_("expression expected"));
+ return (EXECUTION_FAILURE);
+ }
+
+ exp = string_list (list);
+ ret = evalexp (exp, &expok);
+ (void)free (exp);
+ return (((ret == 0) || (expok == 0)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+#endif
diff --git a/builtins/mapfile.c b/builtins/mapfile.c
new file mode 100644
index 0000000..8b79c37
--- /dev/null
+++ b/builtins/mapfile.c
@@ -0,0 +1,294 @@
+/* mapfile.c, created from mapfile.def. */
+#line 23 "./mapfile.def"
+
+#line 56 "./mapfile.def"
+
+#line 64 "./mapfile.def"
+
+#include <config.h>
+
+#include "builtins.h"
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "../bashintl.h"
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#if defined (ARRAY_VARS)
+
+#define DEFAULT_ARRAY_NAME "MAPFILE"
+
+/* The value specifying how frequently `mapfile' calls the callback. */
+#define DEFAULT_QUANTUM 5000
+
+/* Values for FLAGS */
+#define MAPF_CLEARARRAY 0x01
+#define MAPF_CHOP 0x02
+
+static int
+run_callback(callback, current_index)
+ const char *callback;
+ unsigned int current_index;
+{
+ unsigned int execlen;
+ char *execstr;
+ int flags;
+
+ execlen = strlen (callback) + 10;
+ /* 1 for space between %s and %d,
+ another 1 for the last nul char for C string. */
+ execlen += 2;
+ execstr = xmalloc (execlen);
+
+ flags = SEVAL_NOHIST;
+#if 0
+ if (interactive)
+ flags |= SEVAL_INTERACT;
+#endif
+ snprintf (execstr, execlen, "%s %d", callback, current_index);
+ return parse_and_execute(execstr, NULL, flags);
+}
+
+static void
+do_chop(line)
+ char * line;
+{
+ int length;
+
+ length = strlen (line);
+ if (length && line[length-1] == '\n')
+ line[length-1] = '\0';
+}
+
+static int
+mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, flags)
+ int fd;
+ long line_count_goal, origin, nskip, callback_quantum;
+ char *callback, *array_name;
+ int flags;
+{
+ char *line;
+ size_t line_length;
+ unsigned int array_index, line_count;
+ SHELL_VAR *entry;
+ int unbuffered_read;
+
+ line = NULL;
+ line_length = 0;
+ unbuffered_read = 0;
+
+ /* The following check should be done before reading any lines. Doing it
+ here allows us to call bind_array_element instead of bind_array_variable
+ and skip the variable lookup on every call. */
+ entry = find_or_make_array_variable (array_name, 1);
+ if (entry == 0 || readonly_p (entry) || noassign_p (entry))
+ {
+ if (entry && readonly_p (entry))
+ err_readonly (array_name);
+
+ return (EXECUTION_FAILURE);
+ }
+ else if (array_p (entry) == 0)
+ {
+ builtin_error (_("%s: not an indexed array"), array_name);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (flags & MAPF_CLEARARRAY)
+ array_flush (array_cell (entry));
+
+#ifndef __CYGWIN__
+ unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
+#else
+ unbuffered_read = 1;
+#endif
+
+ zreset ();
+
+ /* Skip any lines at beginning of file? */
+ for (line_count = 0; line_count < nskip; line_count++)
+ if (zgetline (fd, &line, &line_length, unbuffered_read) < 0)
+ break;
+
+ line = 0;
+ line_length = 0;
+
+ /* Reset the buffer for bash own stream */
+ interrupt_immediately++;
+ for (array_index = origin, line_count = 1;
+ zgetline (fd, &line, &line_length, unbuffered_read) != -1;
+ array_index++, line_count++)
+ {
+ /* Have we exceeded # of lines to store? */
+ if (line_count_goal != 0 && line_count > line_count_goal)
+ break;
+
+ /* Remove trailing newlines? */
+ if (flags & MAPF_CHOP)
+ do_chop (line);
+
+ /* Has a callback been registered and if so is it time to call it? */
+ if (callback && line_count && (line_count % callback_quantum) == 0)
+ {
+ run_callback (callback, array_index);
+
+ /* Reset the buffer for bash own stream. */
+ if (unbuffered_read == 0)
+ zsyncfd (fd);
+ }
+
+ bind_array_element (entry, array_index, line, 0);
+ }
+
+ xfree (line);
+
+ if (unbuffered_read == 0)
+ zsyncfd (fd);
+
+ interrupt_immediately--;
+ return EXECUTION_SUCCESS;
+}
+
+int
+mapfile_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, code, fd, clear_array, flags;
+ intmax_t intval;
+ long lines, origin, nskip, callback_quantum;
+ char *array_name, *callback;
+
+ clear_array = 1;
+ fd = 0;
+ lines = origin = nskip = 0;
+ flags = MAPF_CLEARARRAY;
+ callback_quantum = DEFAULT_QUANTUM;
+ callback = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "u:n:O:tC:c:s:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'u':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval < 0 || intval != (int)intval)
+ {
+ builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ fd = intval;
+
+ if (sh_validfd (fd) == 0)
+ {
+ builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+ break;
+
+ case 'n':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval < 0 || intval != (unsigned)intval)
+ {
+ builtin_error (_("%s: invalid line count"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ lines = intval;
+ break;
+
+ case 'O':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval < 0 || intval != (unsigned)intval)
+ {
+ builtin_error (_("%s: invalid array origin"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ origin = intval;
+ flags &= ~MAPF_CLEARARRAY;
+ break;
+ case 't':
+ flags |= MAPF_CHOP;
+ break;
+ case 'C':
+ callback = list_optarg;
+ break;
+ case 'c':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval <= 0 || intval != (unsigned)intval)
+ {
+ builtin_error (_("%s: invalid callback quantum"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ callback_quantum = intval;
+ break;
+ case 's':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval < 0 || intval != (unsigned)intval)
+ {
+ builtin_error (_("%s: invalid line count"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ nskip = intval;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list == 0)
+ array_name = DEFAULT_ARRAY_NAME;
+ else if (list->word == 0 || list->word->word == 0)
+ {
+ builtin_error ("internal error: getting variable name");
+ return (EXECUTION_FAILURE);
+ }
+ else if (list->word->word[0] == '\0')
+ {
+ builtin_error (_("empty array variable name"));
+ return (EX_USAGE);
+ }
+ else
+ array_name = list->word->word;
+
+ if (legal_identifier (array_name) == 0 && valid_array_reference (array_name) == 0)
+ {
+ sh_invalidid (array_name);
+ return (EXECUTION_FAILURE);
+ }
+
+ return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, flags);
+}
+
+#else
+
+int
+mapfile_builtin (list)
+ WORD_LIST *list;
+{
+ builtin_error (_("array variable support required"));
+ return (EXECUTION_FAILURE);
+}
+
+#endif /* ARRAY_VARS */
diff --git a/builtins/pipesize.h b/builtins/pipesize.h
new file mode 100644
index 0000000..816a0b2
--- /dev/null
+++ b/builtins/pipesize.h
@@ -0,0 +1,8 @@
+/*
+ * pipesize.h
+ *
+ * This file is automatically generated by psize.sh
+ * Do not edit!
+ */
+
+#define PIPESIZE 65536
diff --git a/builtins/printf.c b/builtins/printf.c
new file mode 100644
index 0000000..2bb1178
--- /dev/null
+++ b/builtins/printf.c
@@ -0,0 +1,1075 @@
+/* printf.c, created from printf.def. */
+#line 22 "./printf.def"
+
+#line 48 "./printf.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+
+#include <errno.h>
+#if defined (HAVE_LIMITS_H)
+# include <limits.h>
+#else
+ /* Assume 32-bit ints. */
+# define INT_MAX 2147483647
+# define INT_MIN (-2147483647-1)
+#endif
+
+#if defined (PREFER_STDARG)
+# include <stdarg.h>
+#else
+# include <varargs.h>
+#endif
+
+#include <stdio.h>
+#include <chartypes.h>
+
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "shmbutil.h"
+#include "stdc.h"
+#include "bashgetopt.h"
+#include "common.h"
+
+#if defined (PRI_MACROS_BROKEN)
+# undef PRIdMAX
+#endif
+
+#if !defined (PRIdMAX)
+# if HAVE_LONG_LONG
+# define PRIdMAX "lld"
+# else
+# define PRIdMAX "ld"
+# endif
+#endif
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define PC(c) \
+ do { \
+ char b[2]; \
+ tw++; \
+ b[0] = c; b[1] = '\0'; \
+ if (vflag) \
+ vbadd (b, 1); \
+ else \
+ putchar (c); \
+ } while (0)
+
+#define PF(f, func) \
+ do { \
+ int nw; \
+ clearerr (stdout); \
+ if (have_fieldwidth && have_precision) \
+ nw = vflag ? vbprintf (f, fieldwidth, precision, func) : printf (f, fieldwidth, precision, func); \
+ else if (have_fieldwidth) \
+ nw = vflag ? vbprintf (f, fieldwidth, func) : printf (f, fieldwidth, func); \
+ else if (have_precision) \
+ nw = vflag ? vbprintf (f, precision, func) : printf (f, precision, func); \
+ else \
+ nw = vflag ? vbprintf (f, func) : printf (f, func); \
+ tw += nw; \
+ if (ferror (stdout)) \
+ { \
+ sh_wrerror (); \
+ clearerr (stdout); \
+ return (EXECUTION_FAILURE); \
+ } \
+ } while (0)
+
+/* We free the buffer used by mklong() if it's `too big'. */
+#define PRETURN(value) \
+ do \
+ { \
+ if (vflag) \
+ { \
+ bind_printf_variable (vname, vbuf, 0); \
+ stupidly_hack_special_variables (vname); \
+ } \
+ if (conv_bufsize > 4096 ) \
+ { \
+ free (conv_buf); \
+ conv_bufsize = 0; \
+ conv_buf = 0; \
+ } \
+ if (vbsize > 4096) \
+ { \
+ free (vbuf); \
+ vbsize = 0; \
+ vbuf = 0; \
+ } \
+ else if (vbuf) \
+ vbuf[0] = 0; \
+ terminate_immediately--; \
+ fflush (stdout); \
+ if (ferror (stdout)) \
+ { \
+ sh_wrerror (); \
+ clearerr (stdout); \
+ return (EXECUTION_FAILURE); \
+ } \
+ return (value); \
+ } \
+ while (0)
+
+#define SKIP1 "#'-+ 0"
+#define LENMODS "hjlLtz"
+
+#if !HAVE_ASPRINTF
+extern int asprintf __P((char **, const char *, ...)) __attribute__((__format__ (printf, 2, 3)));
+#endif
+
+#if !HAVE_VSNPRINTF
+extern int vsnprintf __P((char *, size_t, const char *, va_list)) __attribute__((__format__ (printf, 3, 0)));
+#endif
+
+static void printf_erange __P((char *));
+static int printstr __P((char *, char *, int, int, int));
+static int tescape __P((char *, char *, int *));
+static char *bexpand __P((char *, int, int *, int *));
+static char *vbadd __P((char *, int));
+static int vbprintf __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
+static char *mklong __P((char *, char *, size_t));
+static int getchr __P((void));
+static char *getstr __P((void));
+static int getint __P((void));
+static intmax_t getintmax __P((void));
+static uintmax_t getuintmax __P((void));
+static SHELL_VAR *bind_printf_variable __P((char *, char *, int));
+
+#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
+typedef long double floatmax_t;
+# define FLOATMAX_CONV "L"
+# define strtofltmax strtold
+#else
+typedef double floatmax_t;
+# define FLOATMAX_CONV ""
+# define strtofltmax strtod
+#endif
+static floatmax_t getfloatmax __P((void));
+
+static intmax_t asciicode __P((void));
+
+static WORD_LIST *garglist;
+static int retval;
+static int conversion_error;
+
+/* printf -v var support */
+static int vflag = 0;
+static char *vbuf, *vname;
+static size_t vbsize;
+static int vblen;
+
+static intmax_t tw;
+
+static char *conv_buf;
+static size_t conv_bufsize;
+
+int
+printf_builtin (list)
+ WORD_LIST *list;
+{
+ int ch, fieldwidth, precision;
+ int have_fieldwidth, have_precision;
+ char convch, thisch, nextch, *format, *modstart, *fmt, *start;
+
+ conversion_error = 0;
+ retval = EXECUTION_SUCCESS;
+
+ vflag = 0;
+
+ reset_internal_getopt ();
+ while ((ch = internal_getopt (list, "v:")) != -1)
+ {
+ switch (ch)
+ {
+ case 'v':
+ vname = list_optarg;
+#if defined (ARRAY_VARS)
+ if (legal_identifier (vname) || valid_array_reference (vname))
+#else
+ if (legal_identifier (vname))
+#endif
+ {
+ vflag = 1;
+ vblen = 0;
+ if (vbuf)
+ vbuf[0] = 0;
+ }
+ else
+ {
+ sh_invalidid (vname);
+ return (EX_USAGE);
+ }
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend; /* skip over possible `--' */
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (list->word->word == 0 || list->word->word[0] == '\0')
+ return (EXECUTION_SUCCESS);
+
+ format = list->word->word;
+ tw = 0;
+
+ garglist = list->next;
+
+ /* If the format string is empty after preprocessing, return immediately. */
+ if (format == 0 || *format == 0)
+ return (EXECUTION_SUCCESS);
+
+ terminate_immediately++;
+
+ /* Basic algorithm is to scan the format string for conversion
+ specifications -- once one is found, find out if the field
+ width or precision is a '*'; if it is, gather up value. Note,
+ format strings are reused as necessary to use up the provided
+ arguments, arguments of zero/null string are provided to use
+ up the format string. */
+ do
+ {
+ tw = 0;
+ /* find next format specification */
+ for (fmt = format; *fmt; fmt++)
+ {
+ precision = fieldwidth = 0;
+ have_fieldwidth = have_precision = 0;
+
+ if (*fmt == '\\')
+ {
+ fmt++;
+ /* A NULL third argument to tescape means to bypass the
+ special processing for arguments to %b. */
+ fmt += tescape (fmt, &nextch, (int *)NULL);
+ PC (nextch);
+ fmt--; /* for loop will increment it for us again */
+ continue;
+ }
+
+ if (*fmt != '%')
+ {
+ PC (*fmt);
+ continue;
+ }
+
+ /* ASSERT(*fmt == '%') */
+ start = fmt++;
+
+ if (*fmt == '%') /* %% prints a % */
+ {
+ PC ('%');
+ continue;
+ }
+
+ /* found format specification, skip to field width */
+ for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
+ ;
+
+ /* Skip optional field width. */
+ if (*fmt == '*')
+ {
+ fmt++;
+ have_fieldwidth = 1;
+ fieldwidth = getint ();
+ }
+ else
+ while (DIGIT (*fmt))
+ fmt++;
+
+ /* Skip optional '.' and precision */
+ if (*fmt == '.')
+ {
+ ++fmt;
+ if (*fmt == '*')
+ {
+ fmt++;
+ have_precision = 1;
+ precision = getint ();
+ }
+ else
+ {
+ /* Negative precisions are allowed but treated as if the
+ precision were missing; I would like to allow a leading
+ `+' in the precision number as an extension, but lots
+ of asprintf/fprintf implementations get this wrong. */
+#if 0
+ if (*fmt == '-' || *fmt == '+')
+#else
+ if (*fmt == '-')
+#endif
+ fmt++;
+ while (DIGIT (*fmt))
+ fmt++;
+ }
+ }
+
+ /* skip possible format modifiers */
+ modstart = fmt;
+ while (*fmt && strchr (LENMODS, *fmt))
+ fmt++;
+
+ if (*fmt == 0)
+ {
+ builtin_error (_("`%s': missing format character"), start);
+ PRETURN (EXECUTION_FAILURE);
+ }
+
+ convch = *fmt;
+ thisch = modstart[0];
+ nextch = modstart[1];
+ modstart[0] = convch;
+ modstart[1] = '\0';
+
+ switch(convch)
+ {
+ case 'c':
+ {
+ char p;
+
+ p = getchr ();
+ PF(start, p);
+ break;
+ }
+
+ case 's':
+ {
+ char *p;
+
+ p = getstr ();
+ PF(start, p);
+ break;
+ }
+
+ case 'n':
+ {
+ char *var;
+
+ var = getstr ();
+ if (var && *var)
+ {
+ if (legal_identifier (var))
+ bind_var_to_int (var, tw);
+ else
+ {
+ sh_invalidid (var);
+ PRETURN (EXECUTION_FAILURE);
+ }
+ }
+ break;
+ }
+
+ case 'b': /* expand escapes in argument */
+ {
+ char *p, *xp;
+ int rlen, r;
+
+ p = getstr ();
+ ch = rlen = r = 0;
+ xp = bexpand (p, strlen (p), &ch, &rlen);
+
+ if (xp)
+ {
+ /* Have to use printstr because of possible NUL bytes
+ in XP -- printf does not handle that well. */
+ r = printstr (start, xp, rlen, fieldwidth, precision);
+ if (r < 0)
+ {
+ sh_wrerror ();
+ clearerr (stdout);
+ retval = EXECUTION_FAILURE;
+ }
+ free (xp);
+ }
+
+ if (ch || r < 0)
+ PRETURN (retval);
+ break;
+ }
+
+ case 'q': /* print with shell quoting */
+ {
+ char *p, *xp;
+ int r;
+
+ r = 0;
+ p = getstr ();
+ if (p && *p == 0) /* XXX - getstr never returns null */
+ xp = savestring ("''");
+ else if (ansic_shouldquote (p))
+ xp = ansic_quote (p, 0, (int *)0);
+ else
+ xp = sh_backslash_quote (p);
+ if (xp)
+ {
+ /* Use printstr to get fieldwidth and precision right. */
+ r = printstr (start, xp, strlen (xp), fieldwidth, precision);
+ if (r < 0)
+ {
+ sh_wrerror ();
+ clearerr (stdout);
+ }
+ free (xp);
+ }
+
+ if (r < 0)
+ PRETURN (EXECUTION_FAILURE);
+ break;
+ }
+
+ case 'd':
+ case 'i':
+ {
+ char *f;
+ long p;
+ intmax_t pp;
+
+ p = pp = getintmax ();
+ if (p != pp)
+ {
+ f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
+ PF (f, pp);
+ }
+ else
+ {
+ /* Optimize the common case where the integer fits
+ in "long". This also works around some long
+ long and/or intmax_t library bugs in the common
+ case, e.g. glibc 2.2 x86. */
+ f = mklong (start, "l", 1);
+ PF (f, p);
+ }
+ break;
+ }
+
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ {
+ char *f;
+ unsigned long p;
+ uintmax_t pp;
+
+ p = pp = getuintmax ();
+ if (p != pp)
+ {
+ f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
+ PF (f, pp);
+ }
+ else
+ {
+ f = mklong (start, "l", 1);
+ PF (f, p);
+ }
+ break;
+ }
+
+ case 'e':
+ case 'E':
+ case 'f':
+ case 'F':
+ case 'g':
+ case 'G':
+#if defined (HAVE_PRINTF_A_FORMAT)
+ case 'a':
+ case 'A':
+#endif
+ {
+ char *f;
+ floatmax_t p;
+
+ p = getfloatmax ();
+ f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1);
+ PF (f, p);
+ break;
+ }
+
+ /* We don't output unrecognized format characters; we print an
+ error message and return a failure exit status. */
+ default:
+ builtin_error (_("`%c': invalid format character"), convch);
+ PRETURN (EXECUTION_FAILURE);
+ }
+
+ modstart[0] = thisch;
+ modstart[1] = nextch;
+ }
+
+ if (ferror (stdout))
+ {
+ sh_wrerror ();
+ clearerr (stdout);
+ PRETURN (EXECUTION_FAILURE);
+ }
+ }
+ while (garglist && garglist != list->next);
+
+ if (conversion_error)
+ retval = EXECUTION_FAILURE;
+
+ PRETURN (retval);
+}
+
+static void
+printf_erange (s)
+ char *s;
+{
+ builtin_error (_("warning: %s: %s"), s, strerror(ERANGE));
+}
+
+/* We duplicate a lot of what printf(3) does here. */
+static int
+printstr (fmt, string, len, fieldwidth, precision)
+ char *fmt; /* format */
+ char *string; /* expanded string argument */
+ int len; /* length of expanded string */
+ int fieldwidth; /* argument for width of `*' */
+ int precision; /* argument for precision of `*' */
+{
+#if 0
+ char *s;
+#endif
+ int padlen, nc, ljust, i;
+ int fw, pr; /* fieldwidth and precision */
+
+#if 0
+ if (string == 0 || *string == '\0')
+#else
+ if (string == 0 || len == 0)
+#endif
+ return 0;
+
+#if 0
+ s = fmt;
+#endif
+ if (*fmt == '%')
+ fmt++;
+
+ ljust = fw = 0;
+ pr = -1;
+
+ /* skip flags */
+ while (strchr (SKIP1, *fmt))
+ {
+ if (*fmt == '-')
+ ljust = 1;
+ fmt++;
+ }
+
+ /* get fieldwidth, if present */
+ if (*fmt == '*')
+ {
+ fmt++;
+ fw = fieldwidth;
+ if (fw < 0)
+ {
+ fw = -fw;
+ ljust = 1;
+ }
+ }
+ else if (DIGIT (*fmt))
+ {
+ fw = *fmt++ - '0';
+ while (DIGIT (*fmt))
+ fw = (fw * 10) + (*fmt++ - '0');
+ }
+
+ /* get precision, if present */
+ if (*fmt == '.')
+ {
+ fmt++;
+ if (*fmt == '*')
+ {
+ fmt++;
+ pr = precision;
+ }
+ else if (DIGIT (*fmt))
+ {
+ pr = *fmt++ - '0';
+ while (DIGIT (*fmt))
+ pr = (pr * 10) + (*fmt++ - '0');
+ }
+ }
+
+#if 0
+ /* If we remove this, get rid of `s'. */
+ if (*fmt != 'b' && *fmt != 'q')
+ {
+ internal_error ("format parsing problem: %s", s);
+ fw = pr = 0;
+ }
+#endif
+
+ /* chars from string to print */
+ nc = (pr >= 0 && pr <= len) ? pr : len;
+
+ padlen = fw - nc;
+ if (padlen < 0)
+ padlen = 0;
+ if (ljust)
+ padlen = -padlen;
+
+ /* leading pad characters */
+ for (; padlen > 0; padlen--)
+ PC (' ');
+
+ /* output NC characters from STRING */
+ for (i = 0; i < nc; i++)
+ PC (string[i]);
+
+ /* output any necessary trailing padding */
+ for (; padlen < 0; padlen++)
+ PC (' ');
+
+ return (ferror (stdout) ? -1 : 0);
+}
+
+/* Convert STRING by expanding the escape sequences specified by the
+ POSIX standard for printf's `%b' format string. If SAWC is non-null,
+ perform the processing appropriate for %b arguments. In particular,
+ recognize `\c' and use that as a string terminator. If we see \c, set
+ *SAWC to 1 before returning. LEN is the length of STRING. */
+
+/* Translate a single backslash-escape sequence starting at ESTART (the
+ character after the backslash) and return the number of characters
+ consumed by the sequence. CP is the place to return the translated
+ value. *SAWC is set to 1 if the escape sequence was \c, since that means
+ to short-circuit the rest of the processing. If SAWC is null, we don't
+ do the \c short-circuiting, and \c is treated as an unrecognized escape
+ sequence; we also bypass the other processing specific to %b arguments. */
+static int
+tescape (estart, cp, sawc)
+ char *estart;
+ char *cp;
+ int *sawc;
+{
+ register char *p;
+ int temp, c, evalue;
+
+ p = estart;
+
+ switch (c = *p++)
+ {
+#if defined (__STDC__)
+ case 'a': *cp = '\a'; break;
+#else
+ case 'a': *cp = '\007'; break;
+#endif
+
+ case 'b': *cp = '\b'; break;
+
+ case 'e':
+ case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */
+
+ case 'f': *cp = '\f'; break;
+
+ case 'n': *cp = '\n'; break;
+
+ case 'r': *cp = '\r'; break;
+
+ case 't': *cp = '\t'; break;
+
+ case 'v': *cp = '\v'; break;
+
+ /* The octal escape sequences are `\0' followed by up to three octal
+ digits (if SAWC), or `\' followed by up to three octal digits (if
+ !SAWC). As an extension, we allow the latter form even if SAWC. */
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ evalue = OCTVALUE (c);
+ for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++)
+ evalue = (evalue * 8) + OCTVALUE (*p);
+ *cp = evalue & 0xFF;
+ break;
+
+ /* And, as another extension, we allow \xNNN, where each N is a
+ hex digit. */
+ case 'x':
+#if 0
+ for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++)
+#else
+ for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++)
+#endif
+ evalue = (evalue * 16) + HEXVALUE (*p);
+ if (p == estart + 1)
+ {
+ builtin_error (_("missing hex digit for \\x"));
+ *cp = '\\';
+ return 0;
+ }
+ *cp = evalue & 0xFF;
+ break;
+
+ case '\\': /* \\ -> \ */
+ *cp = c;
+ break;
+
+ /* SAWC == 0 means that \', \", and \? are recognized as escape
+ sequences, though the only processing performed is backslash
+ removal. */
+ case '\'': case '"': case '?':
+ if (!sawc)
+ *cp = c;
+ else
+ {
+ *cp = '\\';
+ return 0;
+ }
+ break;
+
+ case 'c':
+ if (sawc)
+ {
+ *sawc = 1;
+ break;
+ }
+ /* other backslash escapes are passed through unaltered */
+ default:
+ *cp = '\\';
+ return 0;
+ }
+ return (p - estart);
+}
+
+static char *
+bexpand (string, len, sawc, lenp)
+ char *string;
+ int len, *sawc, *lenp;
+{
+ int temp;
+ char *ret, *r, *s, c;
+
+#if 0
+ if (string == 0 || *string == '\0')
+#else
+ if (string == 0 || len == 0)
+#endif
+ {
+ if (sawc)
+ *sawc = 0;
+ if (lenp)
+ *lenp = 0;
+ return ((char *)NULL);
+ }
+
+ ret = (char *)xmalloc (len + 1);
+ for (r = ret, s = string; s && *s; )
+ {
+ c = *s++;
+ if (c != '\\' || *s == '\0')
+ {
+ *r++ = c;
+ continue;
+ }
+ temp = 0;
+ s += tescape (s, &c, &temp);
+ if (temp)
+ {
+ if (sawc)
+ *sawc = 1;
+ break;
+ }
+
+ *r++ = c;
+ }
+
+ *r = '\0';
+ if (lenp)
+ *lenp = r - ret;
+ return ret;
+}
+
+static char *
+vbadd (buf, blen)
+ char *buf;
+ int blen;
+{
+ size_t nlen;
+
+ nlen = vblen + blen + 1;
+ if (nlen >= vbsize)
+ {
+ vbsize = ((nlen + 63) >> 6) << 6;
+ vbuf = (char *)xrealloc (vbuf, vbsize);
+ }
+
+ if (blen == 1)
+ vbuf[vblen++] = buf[0];
+ else if (blen > 1)
+ {
+ FASTCOPY (buf, vbuf + vblen, blen);
+ vblen += blen;
+ }
+ vbuf[vblen] = '\0';
+
+#ifdef DEBUG
+ if (strlen (vbuf) != vblen)
+ internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf));
+#endif
+
+ return vbuf;
+}
+
+static int
+#if defined (PREFER_STDARG)
+vbprintf (const char *format, ...)
+#else
+vbprintf (format, va_alist)
+ const char *format;
+ va_dcl
+#endif
+{
+ va_list args;
+ size_t nlen;
+ int blen;
+
+ SH_VA_START (args, format);
+ blen = vsnprintf (vbuf + vblen, vbsize - vblen, format, args);
+ va_end (args);
+
+ nlen = vblen + blen + 1;
+ if (nlen >= vbsize)
+ {
+ vbsize = ((nlen + 63) >> 6) << 6;
+ vbuf = (char *)xrealloc (vbuf, vbsize);
+ SH_VA_START (args, format);
+ blen = vsnprintf (vbuf + vblen, vbsize - vblen, format, args);
+ va_end (args);
+ }
+
+ vblen += blen;
+ vbuf[vblen] = '\0';
+
+#ifdef DEBUG
+ if (strlen (vbuf) != vblen)
+ internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, (int)strlen (vbuf));
+#endif
+
+ return (blen);
+}
+
+static char *
+mklong (str, modifiers, mlen)
+ char *str;
+ char *modifiers;
+ size_t mlen;
+{
+ size_t len, slen;
+
+ slen = strlen (str);
+ len = slen + mlen + 1;
+
+ if (len > conv_bufsize)
+ {
+ conv_bufsize = (((len + 1023) >> 10) << 10);
+ conv_buf = (char *)xrealloc (conv_buf, conv_bufsize);
+ }
+
+ FASTCOPY (str, conv_buf, slen - 1);
+ FASTCOPY (modifiers, conv_buf + slen - 1, mlen);
+
+ conv_buf[len - 2] = str[slen - 1];
+ conv_buf[len - 1] = '\0';
+ return (conv_buf);
+}
+
+static int
+getchr ()
+{
+ int ret;
+
+ if (garglist == 0)
+ return ('\0');
+
+ ret = (int)garglist->word->word[0];
+ garglist = garglist->next;
+ return ret;
+}
+
+static char *
+getstr ()
+{
+ char *ret;
+
+ if (garglist == 0)
+ return ("");
+
+ ret = garglist->word->word;
+ garglist = garglist->next;
+ return ret;
+}
+
+static int
+getint ()
+{
+ intmax_t ret;
+
+ ret = getintmax ();
+
+ if (ret > INT_MAX)
+ {
+ printf_erange (garglist->word->word);
+ ret = INT_MAX;
+ }
+ else if (ret < INT_MIN)
+ {
+ printf_erange (garglist->word->word);
+ ret = INT_MIN;
+ }
+
+ return ((int)ret);
+}
+
+static intmax_t
+getintmax ()
+{
+ intmax_t ret;
+ char *ep;
+
+ if (garglist == 0)
+ return (0);
+
+ if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+ return asciicode ();
+
+ errno = 0;
+ ret = strtoimax (garglist->word->word, &ep, 0);
+
+ if (*ep)
+ {
+ sh_invalidnum (garglist->word->word);
+ /* POSIX.2 says ``...a diagnostic message shall be written to standard
+ error, and the utility shall not exit with a zero exit status, but
+ shall continue processing any remaining operands and shall write the
+ value accumulated at the time the error was detected to standard
+ output.'' Yecch. */
+#if 0
+ ret = 0; /* return partially-converted value from strtoimax */
+#endif
+ conversion_error = 1;
+ }
+ else if (errno == ERANGE)
+ printf_erange (garglist->word->word);
+
+ garglist = garglist->next;
+ return (ret);
+}
+
+static uintmax_t
+getuintmax ()
+{
+ uintmax_t ret;
+ char *ep;
+
+ if (garglist == 0)
+ return (0);
+
+ if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+ return asciicode ();
+
+ errno = 0;
+ ret = strtoumax (garglist->word->word, &ep, 0);
+
+ if (*ep)
+ {
+ sh_invalidnum (garglist->word->word);
+ /* Same POSIX.2 conversion error requirements as getintmax(). */
+ ret = 0;
+ conversion_error = 1;
+ }
+ else if (errno == ERANGE)
+ printf_erange (garglist->word->word);
+
+ garglist = garglist->next;
+ return (ret);
+}
+
+static floatmax_t
+getfloatmax ()
+{
+ floatmax_t ret;
+ char *ep;
+
+ if (garglist == 0)
+ return (0);
+
+ if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
+ return asciicode ();
+
+ errno = 0;
+ ret = strtofltmax (garglist->word->word, &ep);
+
+ if (*ep)
+ {
+ sh_invalidnum (garglist->word->word);
+ /* Same thing about POSIX.2 conversion error requirements. */
+ ret = 0;
+ conversion_error = 1;
+ }
+ else if (errno == ERANGE)
+ printf_erange (garglist->word->word);
+
+ garglist = garglist->next;
+ return (ret);
+}
+
+/* NO check is needed for garglist here. */
+static intmax_t
+asciicode ()
+{
+ register intmax_t ch;
+#if defined (HANDLE_MULTIBYTE)
+ wchar_t wc;
+ size_t mblength, slen;
+#endif
+ DECLARE_MBSTATE;
+
+#if defined (HANDLE_MULTIBYTE)
+ slen = strlen (garglist->word->word+1);
+ mblength = MBLEN (garglist->word->word+1, slen);
+ if (mblength > 1)
+ {
+ mblength = mbtowc (&wc, garglist->word->word+1, slen);
+ ch = wc; /* XXX */
+ }
+ else
+#endif
+ ch = (unsigned char)garglist->word->word[1];
+
+ garglist = garglist->next;
+ return (ch);
+}
+
+static SHELL_VAR *
+bind_printf_variable (name, value, flags)
+ char *name;
+ char *value;
+ int flags;
+{
+#if defined (ARRAY_VARS)
+ if (valid_array_reference (name) == 0)
+ return (bind_variable (name, value, flags));
+ else
+ return (assign_array_element (name, value, flags));
+#else /* !ARRAY_VARS */
+ return bind_variable (name, value, flags);
+#endif /* !ARRAY_VARS */
+}
diff --git a/builtins/pushd.c b/builtins/pushd.c
new file mode 100644
index 0000000..2de6b64
--- /dev/null
+++ b/builtins/pushd.c
@@ -0,0 +1,674 @@
+/* pushd.c, created from pushd.def. */
+#line 22 "./pushd.def"
+
+#line 55 "./pushd.def"
+
+#line 84 "./pushd.def"
+
+#line 113 "./pushd.def"
+
+#include <config.h>
+
+#if defined (PUSHD_AND_POPD)
+#include <stdio.h>
+#ifndef _MINIX
+# include <sys/param.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include <errno.h>
+
+#include <tilde/tilde.h>
+
+#include "../shell.h"
+#include "maxpath.h"
+#include "common.h"
+#include "builtext.h"
+
+#ifdef LOADABLE_BUILTIN
+# include "builtins.h"
+#endif
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* The list of remembered directories. */
+static char **pushd_directory_list = (char **)NULL;
+
+/* Number of existing slots in this list. */
+static int directory_list_size;
+
+/* Offset to the end of the list. */
+static int directory_list_offset;
+
+static void pushd_error __P((int, char *));
+static void clear_directory_stack __P((void));
+static int cd_to_string __P((char *));
+static int change_to_temp __P((char *));
+static void add_dirstack_element __P((char *));
+static int get_dirstack_index __P((intmax_t, int, int *));
+
+#define NOCD 0x01
+#define ROTATE 0x02
+#define LONGFORM 0x04
+#define CLEARSTAK 0x08
+
+int
+pushd_builtin (list)
+ WORD_LIST *list;
+{
+ WORD_LIST *orig_list;
+ char *temp, *current_directory, *top;
+ int j, flags, skipopt;
+ intmax_t num;
+ char direction;
+
+ orig_list = list;
+ if (list && list->word && ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ skipopt = 1;
+ }
+ else
+ skipopt = 0;
+
+ /* If there is no argument list then switch current and
+ top of list. */
+ if (list == 0)
+ {
+ if (directory_list_offset == 0)
+ {
+ builtin_error (_("no other directory"));
+ return (EXECUTION_FAILURE);
+ }
+
+ current_directory = get_working_directory ("pushd");
+ if (current_directory == 0)
+ return (EXECUTION_FAILURE);
+
+ j = directory_list_offset - 1;
+ temp = pushd_directory_list[j];
+ pushd_directory_list[j] = current_directory;
+ j = change_to_temp (temp);
+ free (temp);
+ return j;
+ }
+
+ for (flags = 0; skipopt == 0 && list; list = list->next)
+ {
+ if (ISOPTION (list->word->word, 'n'))
+ {
+ flags |= NOCD;
+ }
+ else if (ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
+ /* Let `pushd -' work like it used to. */
+ break;
+ else if (((direction = list->word->word[0]) == '+') || direction == '-')
+ {
+ if (legal_number (list->word->word + 1, &num) == 0)
+ {
+ sh_invalidnum (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+
+ if (direction == '-')
+ num = directory_list_offset - num;
+
+ if (num > directory_list_offset || num < 0)
+ {
+ pushd_error (directory_list_offset, list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ flags |= ROTATE;
+ }
+ else if (*list->word->word == '-')
+ {
+ sh_invalidopt (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ else
+ break;
+ }
+
+ if (flags & ROTATE)
+ {
+ /* Rotate the stack num times. Remember, the current
+ directory acts like it is part of the stack. */
+ temp = get_working_directory ("pushd");
+
+ if (num == 0)
+ {
+ j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
+ free (temp);
+ return j;
+ }
+
+ do
+ {
+ top = pushd_directory_list[directory_list_offset - 1];
+
+ for (j = directory_list_offset - 2; j > -1; j--)
+ pushd_directory_list[j + 1] = pushd_directory_list[j];
+
+ pushd_directory_list[j + 1] = temp;
+
+ temp = top;
+ num--;
+ }
+ while (num);
+
+ j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
+ free (temp);
+ return j;
+ }
+
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+
+ /* Change to the directory in list->word->word. Save the current
+ directory on the top of the stack. */
+ current_directory = get_working_directory ("pushd");
+ if (current_directory == 0)
+ return (EXECUTION_FAILURE);
+
+ j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS;
+ if (j == EXECUTION_SUCCESS)
+ {
+ add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
+ dirs_builtin ((WORD_LIST *)NULL);
+ if (flags & NOCD)
+ free (current_directory);
+ return (EXECUTION_SUCCESS);
+ }
+ else
+ {
+ free (current_directory);
+ return (EXECUTION_FAILURE);
+ }
+}
+
+/* Pop the directory stack, and then change to the new top of the stack.
+ If LIST is non-null it should consist of a word +N or -N, which says
+ what element to delete from the stack. The default is the top one. */
+int
+popd_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ intmax_t which;
+ int flags;
+ char direction;
+ char *which_word;
+
+ which_word = (char *)NULL;
+ for (flags = 0, which = 0, direction = '+'; list; list = list->next)
+ {
+ if (ISOPTION (list->word->word, 'n'))
+ {
+ flags |= NOCD;
+ }
+ else if (ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (((direction = list->word->word[0]) == '+') || direction == '-')
+ {
+ if (legal_number (list->word->word + 1, &which) == 0)
+ {
+ sh_invalidnum (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ which_word = list->word->word;
+ }
+ else if (*list->word->word == '-')
+ {
+ sh_invalidopt (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ else
+ break;
+ }
+
+ if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
+ {
+ pushd_error (directory_list_offset, which_word ? which_word : "");
+ return (EXECUTION_FAILURE);
+ }
+
+ /* Handle case of no specification, or top of stack specification. */
+ if ((direction == '+' && which == 0) ||
+ (direction == '-' && which == directory_list_offset))
+ {
+ i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
+ : EXECUTION_SUCCESS;
+ if (i != EXECUTION_SUCCESS)
+ return (i);
+ free (pushd_directory_list[--directory_list_offset]);
+ }
+ else
+ {
+ /* Since an offset other than the top directory was specified,
+ remove that directory from the list and shift the remainder
+ of the list into place. */
+ i = (direction == '+') ? directory_list_offset - which : which;
+ free (pushd_directory_list[i]);
+ directory_list_offset--;
+
+ /* Shift the remainder of the list into place. */
+ for (; i < directory_list_offset; i++)
+ pushd_directory_list[i] = pushd_directory_list[i + 1];
+ }
+
+ dirs_builtin ((WORD_LIST *)NULL);
+ return (EXECUTION_SUCCESS);
+}
+
+/* Print the current list of directories on the directory stack. */
+int
+dirs_builtin (list)
+ WORD_LIST *list;
+{
+ int flags, desired_index, index_flag, vflag;
+ intmax_t i;
+ char *temp, *w;
+
+ for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
+ {
+ if (ISOPTION (list->word->word, 'l'))
+ {
+ flags |= LONGFORM;
+ }
+ else if (ISOPTION (list->word->word, 'c'))
+ {
+ flags |= CLEARSTAK;
+ }
+ else if (ISOPTION (list->word->word, 'v'))
+ {
+ vflag |= 2;
+ }
+ else if (ISOPTION (list->word->word, 'p'))
+ {
+ vflag |= 1;
+ }
+ else if (ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (*list->word->word == '+' || *list->word->word == '-')
+ {
+ int sign;
+ if (legal_number (w = list->word->word + 1, &i) == 0)
+ {
+ sh_invalidnum (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ sign = (*list->word->word == '+') ? 1 : -1;
+ desired_index = get_dirstack_index (i, sign, &index_flag);
+ }
+ else
+ {
+ sh_invalidopt (list->word->word);
+ builtin_usage ();
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ if (flags & CLEARSTAK)
+ {
+ clear_directory_stack ();
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
+ {
+ pushd_error (directory_list_offset, w);
+ return (EXECUTION_FAILURE);
+ }
+
+#define DIRSTACK_FORMAT(temp) \
+ (flags & LONGFORM) ? temp : polite_directory_format (temp)
+
+ /* The first directory printed is always the current working directory. */
+ if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
+ {
+ temp = get_working_directory ("dirs");
+ if (temp == 0)
+ temp = savestring (_("<no current directory>"));
+ if (vflag & 2)
+ printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
+ else
+ printf ("%s", DIRSTACK_FORMAT (temp));
+ free (temp);
+ if (index_flag)
+ {
+ putchar ('\n');
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+ }
+
+#define DIRSTACK_ENTRY(i) \
+ (flags & LONGFORM) ? pushd_directory_list[i] \
+ : polite_directory_format (pushd_directory_list[i])
+
+ /* Now print the requested directory stack entries. */
+ if (index_flag)
+ {
+ if (vflag & 2)
+ printf ("%2d %s", directory_list_offset - desired_index,
+ DIRSTACK_ENTRY (desired_index));
+ else
+ printf ("%s", DIRSTACK_ENTRY (desired_index));
+ }
+ else
+ for (i = directory_list_offset - 1; i >= 0; i--)
+ if (vflag >= 2)
+ printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
+ else
+ printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
+
+ putchar ('\n');
+
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+static void
+pushd_error (offset, arg)
+ int offset;
+ char *arg;
+{
+ if (offset == 0)
+ builtin_error (_("directory stack empty"));
+ else
+ sh_erange (arg, _("directory stack index"));
+}
+
+static void
+clear_directory_stack ()
+{
+ register int i;
+
+ for (i = 0; i < directory_list_offset; i++)
+ free (pushd_directory_list[i]);
+ directory_list_offset = 0;
+}
+
+/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
+ so if the result is EXECUTION_FAILURE then an error message has already
+ been printed. */
+static int
+cd_to_string (name)
+ char *name;
+{
+ WORD_LIST *tlist;
+ WORD_LIST *dir;
+ int result;
+
+ dir = make_word_list (make_word (name), NULL);
+ tlist = make_word_list (make_word ("--"), dir);
+ result = cd_builtin (tlist);
+ dispose_words (tlist);
+ return (result);
+}
+
+static int
+change_to_temp (temp)
+ char *temp;
+{
+ int tt;
+
+ tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
+
+ if (tt == EXECUTION_SUCCESS)
+ dirs_builtin ((WORD_LIST *)NULL);
+
+ return (tt);
+}
+
+static void
+add_dirstack_element (dir)
+ char *dir;
+{
+ if (directory_list_offset == directory_list_size)
+ pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10);
+ pushd_directory_list[directory_list_offset++] = dir;
+}
+
+static int
+get_dirstack_index (ind, sign, indexp)
+ intmax_t ind;
+ int sign, *indexp;
+{
+ if (indexp)
+ *indexp = sign > 0 ? 1 : 2;
+
+ /* dirs +0 prints the current working directory. */
+ /* dirs -0 prints last element in directory stack */
+ if (ind == 0 && sign > 0)
+ return 0;
+ else if (ind == directory_list_offset)
+ {
+ if (indexp)
+ *indexp = sign > 0 ? 2 : 1;
+ return 0;
+ }
+ else if (ind >= 0 && ind <= directory_list_offset)
+ return (sign > 0 ? directory_list_offset - ind : ind);
+ else
+ return -1;
+}
+
+/* Used by the tilde expansion code. */
+char *
+get_dirstack_from_string (string)
+ char *string;
+{
+ int ind, sign, index_flag;
+ intmax_t i;
+
+ sign = 1;
+ if (*string == '-' || *string == '+')
+ {
+ sign = (*string == '-') ? -1 : 1;
+ string++;
+ }
+ if (legal_number (string, &i) == 0)
+ return ((char *)NULL);
+
+ index_flag = 0;
+ ind = get_dirstack_index (i, sign, &index_flag);
+ if (index_flag && (ind < 0 || ind > directory_list_offset))
+ return ((char *)NULL);
+ if (index_flag == 0 || (index_flag == 1 && ind == 0))
+ return (get_string_value ("PWD"));
+ else
+ return (pushd_directory_list[ind]);
+}
+
+#ifdef INCLUDE_UNUSED
+char *
+get_dirstack_element (ind, sign)
+ intmax_t ind;
+ int sign;
+{
+ int i;
+
+ i = get_dirstack_index (ind, sign, (int *)NULL);
+ return (i < 0 || i > directory_list_offset) ? (char *)NULL
+ : pushd_directory_list[i];
+}
+#endif
+
+void
+set_dirstack_element (ind, sign, value)
+ intmax_t ind;
+ int sign;
+ char *value;
+{
+ int i;
+
+ i = get_dirstack_index (ind, sign, (int *)NULL);
+ if (ind == 0 || i < 0 || i > directory_list_offset)
+ return;
+ free (pushd_directory_list[i]);
+ pushd_directory_list[i] = savestring (value);
+}
+
+WORD_LIST *
+get_directory_stack (flags)
+ int flags;
+{
+ register int i;
+ WORD_LIST *ret;
+ char *d, *t;
+
+ for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
+ {
+ d = (flags&1) ? polite_directory_format (pushd_directory_list[i])
+ : pushd_directory_list[i];
+ ret = make_word_list (make_word (d), ret);
+ }
+ /* Now the current directory. */
+ d = get_working_directory ("dirstack");
+ i = 0; /* sentinel to decide whether or not to free d */
+ if (d == 0)
+ d = ".";
+ else
+ {
+ t = polite_directory_format (d);
+ /* polite_directory_format sometimes returns its argument unchanged.
+ If it does not, we can free d right away. If it does, we need to
+ mark d to be deleted later. */
+ if (t != d)
+ {
+ free (d);
+ d = t;
+ }
+ else /* t == d, so d is what we want */
+ i = 1;
+ }
+ ret = make_word_list (make_word (d), ret);
+ if (i)
+ free (d);
+ return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
+}
+
+#ifdef LOADABLE_BUILTIN
+char * const dirs_doc[] = {
+N_("Display the list of currently remembered directories. Directories\n\
+ find their way onto the list with the `pushd' command; you can get\n\
+ back up through the list with the `popd' command.\n\
+ \n\
+ Options:\n\
+ -c clear the directory stack by deleting all of the elements\n\
+ -l do not print tilde-prefixed versions of directories relative\n\
+ to your home directory\n\
+ -p print the directory stack with one entry per line\n\
+ -v print the directory stack with one entry per line prefixed\n\
+ with its position in the stack\n\
+ \n\
+ Arguments:\n\
+ +N Displays the Nth entry counting from the left of the list shown by\n\
+ dirs when invoked without options, starting with zero.\n\
+ \n\
+ -N Displays the Nth entry counting from the right of the list shown by\n\
+ dirs when invoked without options, starting with zero."),
+ (char *)NULL
+};
+
+char * const pushd_doc[] = {
+N_("Adds a directory to the top of the directory stack, or rotates\n\
+ the stack, making the new top of the stack the current working\n\
+ directory. With no arguments, exchanges the top two directories.\n\
+ \n\
+ Options:\n\
+ -n Suppresses the normal change of directory when adding\n\
+ directories to the stack, so only the stack is manipulated.\n\
+ \n\
+ Arguments:\n\
+ +N Rotates the stack so that the Nth directory (counting\n\
+ from the left of the list shown by `dirs', starting with\n\
+ zero) is at the top.\n\
+ \n\
+ -N Rotates the stack so that the Nth directory (counting\n\
+ from the right of the list shown by `dirs', starting with\n\
+ zero) is at the top.\n\
+ \n\
+ dir Adds DIR to the directory stack at the top, making it the\n\
+ new current working directory.\n\
+ \n\
+ The `dirs' builtin displays the directory stack."),
+ (char *)NULL
+};
+
+char * const popd_doc[] = {
+N_("Removes entries from the directory stack. With no arguments, removes\n\
+ the top directory from the stack, and changes to the new top directory.\n\
+ \n\
+ Options:\n\
+ -n Suppresses the normal change of directory when removing\n\
+ directories from the stack, so only the stack is manipulated.\n\
+ \n\
+ Arguments:\n\
+ +N Removes the Nth entry counting from the left of the list\n\
+ shown by `dirs', starting with zero. For example: `popd +0'\n\
+ removes the first directory, `popd +1' the second.\n\
+ \n\
+ -N Removes the Nth entry counting from the right of the list\n\
+ shown by `dirs', starting with zero. For example: `popd -0'\n\
+ removes the last directory, `popd -1' the next to last.\n\
+ \n\
+ The `dirs' builtin displays the directory stack."),
+ (char *)NULL
+};
+
+struct builtin pushd_struct = {
+ "pushd",
+ pushd_builtin,
+ BUILTIN_ENABLED,
+ pushd_doc,
+ "pushd [+N | -N] [-n] [dir]",
+ 0
+};
+
+struct builtin popd_struct = {
+ "popd",
+ popd_builtin,
+ BUILTIN_ENABLED,
+ popd_doc,
+ "popd [+N | -N] [-n]",
+ 0
+};
+
+struct builtin dirs_struct = {
+ "dirs",
+ dirs_builtin,
+ BUILTIN_ENABLED,
+ dirs_doc,
+ "dirs [-clpv] [+N] [-N]",
+ 0
+};
+#endif /* LOADABLE_BUILTIN */
+
+#endif /* PUSHD_AND_POPD */
diff --git a/builtins/read.c b/builtins/read.c
new file mode 100644
index 0000000..3eb4ceb
--- /dev/null
+++ b/builtins/read.c
@@ -0,0 +1,925 @@
+/* read.c, created from read.def. */
+#line 22 "./read.def"
+
+#line 65 "./read.def"
+
+#include <config.h>
+
+#include "bashtypes.h"
+#include "posixstat.h"
+
+#include <stdio.h>
+
+#include "bashansi.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <signal.h>
+#include <errno.h>
+
+#ifdef __CYGWIN__
+# include <fcntl.h>
+# include <io.h>
+#endif
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#include <shtty.h>
+
+#if defined (READLINE)
+#include "../bashline.h"
+#include <readline/readline.h>
+#endif
+
+#if defined (BUFFERED_INPUT)
+# include "input.h"
+#endif
+
+#if !defined(errno)
+extern int errno;
+#endif
+
+struct ttsave
+{
+ int fd;
+ TTYSTRUCT *attrs;
+};
+
+#if defined (READLINE)
+static void reset_attempted_completion_function __P((char *));
+static int set_itext __P((void));
+static char *edit_line __P((char *, char *));
+static void set_eol_delim __P((int));
+static void reset_eol_delim __P((char *));
+#endif
+static SHELL_VAR *bind_read_variable __P((char *, char *));
+#if defined (HANDLE_MULTIBYTE)
+static int read_mbchar __P((int, char *, int, int, int));
+#endif
+static void ttyrestore __P((struct ttsave *));
+
+static sighandler sigalrm __P((int));
+static void reset_alarm __P((void));
+
+static procenv_t alrmbuf;
+static SigHandler *old_alrm;
+static unsigned char delim;
+
+static sighandler
+sigalrm (s)
+ int s;
+{
+ longjmp (alrmbuf, 1);
+}
+
+static void
+reset_alarm ()
+{
+ set_signal_handler (SIGALRM, old_alrm);
+ falarm (0, 0);
+}
+
+/* Read the value of the shell variables whose names follow.
+ The reading is done from the current input stream, whatever
+ that may be. Successive words of the input line are assigned
+ to the variables mentioned in LIST. The last variable in LIST
+ gets the remainder of the words on the line. If no variables
+ are mentioned in LIST, then the default variable is $REPLY. */
+int
+read_builtin (list)
+ WORD_LIST *list;
+{
+ register char *varname;
+ int size, i, nr, pass_next, saw_escape, eof, opt, retval, code, print_ps2;
+ int input_is_tty, input_is_pipe, unbuffered_read, skip_ctlesc, skip_ctlnul;
+ int raw, edit, nchars, silent, have_timeout, ignore_delim, fd;
+ unsigned int tmsec, tmusec;
+ long ival, uval;
+ intmax_t intval;
+ char c;
+ char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
+ char *e, *t, *t1, *ps2, *tofree;
+ struct stat tsb;
+ SHELL_VAR *var;
+ TTYSTRUCT ttattrs, ttset;
+ struct ttsave termsave;
+#if defined (ARRAY_VARS)
+ WORD_LIST *alist;
+#endif
+#if defined (READLINE)
+ char *rlbuf, *itext;
+ int rlind;
+#endif
+
+ USE_VAR(size);
+ USE_VAR(i);
+ USE_VAR(pass_next);
+ USE_VAR(print_ps2);
+ USE_VAR(saw_escape);
+ USE_VAR(input_is_pipe);
+/* USE_VAR(raw); */
+ USE_VAR(edit);
+ USE_VAR(tmsec);
+ USE_VAR(tmusec);
+ USE_VAR(nchars);
+ USE_VAR(silent);
+ USE_VAR(ifs_chars);
+ USE_VAR(prompt);
+ USE_VAR(arrayname);
+#if defined (READLINE)
+ USE_VAR(rlbuf);
+ USE_VAR(rlind);
+ USE_VAR(itext);
+#endif
+ USE_VAR(list);
+ USE_VAR(ps2);
+
+ i = 0; /* Index into the string that we are reading. */
+ raw = edit = 0; /* Not reading raw input by default. */
+ silent = 0;
+ arrayname = prompt = (char *)NULL;
+ fd = 0; /* file descriptor to read from */
+
+#if defined (READLINE)
+ rlbuf = itext = (char *)0;
+ rlind = 0;
+#endif
+
+ tmsec = tmusec = 0; /* no timeout */
+ nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
+ delim = '\n'; /* read until newline */
+ ignore_delim = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "ersa:d:i:n:p:t:u:N:")) != -1)
+ {
+ switch (opt)
+ {
+ case 'r':
+ raw = 1;
+ break;
+ case 'p':
+ prompt = list_optarg;
+ break;
+ case 's':
+ silent = 1;
+ break;
+ case 'e':
+#if defined (READLINE)
+ edit = 1;
+#endif
+ break;
+ case 'i':
+#if defined (READLINE)
+ itext = list_optarg;
+#endif
+ break;
+#if defined (ARRAY_VARS)
+ case 'a':
+ arrayname = list_optarg;
+ break;
+#endif
+ case 't':
+ code = uconvert (list_optarg, &ival, &uval);
+ if (code == 0 || ival < 0 || uval < 0)
+ {
+ builtin_error (_("%s: invalid timeout specification"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ {
+ have_timeout = 1;
+ tmsec = ival;
+ tmusec = uval;
+ }
+ break;
+ case 'N':
+ ignore_delim = 1;
+ delim = -1;
+ case 'n':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval < 0 || intval != (int)intval)
+ {
+ sh_invalidnum (list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ nchars = intval;
+ break;
+ case 'u':
+ code = legal_number (list_optarg, &intval);
+ if (code == 0 || intval < 0 || intval != (int)intval)
+ {
+ builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ fd = intval;
+ if (sh_validfd (fd) == 0)
+ {
+ builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+ break;
+ case 'd':
+ delim = *list_optarg;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ /* `read -t 0 var' tests whether input is available with select/FIONREAD,
+ and fails if those are unavailable */
+ if (have_timeout && tmsec == 0 && tmusec == 0)
+#if 0
+ return (EXECUTION_FAILURE);
+#else
+ return (input_avail (fd) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+#endif
+
+ /* If we're asked to ignore the delimiter, make sure we do. */
+ if (ignore_delim)
+ delim = -1;
+
+ /* IF IFS is unset, we use the default of " \t\n". */
+ ifs_chars = getifs ();
+ if (ifs_chars == 0) /* XXX - shouldn't happen */
+ ifs_chars = "";
+ /* If we want to read exactly NCHARS chars, don't split on IFS */
+ if (ignore_delim)
+ ifs_chars = "";
+ for (skip_ctlesc = skip_ctlnul = 0, e = ifs_chars; *e; e++)
+ skip_ctlesc |= *e == CTLESC, skip_ctlnul |= *e == CTLNUL;
+
+ input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
+ input_string[0] = '\0';
+
+ /* $TMOUT, if set, is the default timeout for read. */
+ if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
+ {
+ code = uconvert (e, &ival, &uval);
+ if (code == 0 || ival < 0 || uval < 0)
+ tmsec = tmusec = 0;
+ else
+ {
+ tmsec = ival;
+ tmusec = uval;
+ }
+ }
+
+ begin_unwind_frame ("read_builtin");
+
+#if defined (BUFFERED_INPUT)
+ if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd))
+ sync_buffered_stream (default_buffered_input);
+#endif
+
+ input_is_tty = isatty (fd);
+ if (input_is_tty == 0)
+#ifndef __CYGWIN__
+ input_is_pipe = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
+#else
+ input_is_pipe = 1;
+#endif
+
+ /* If the -p, -e or -s flags were given, but input is not coming from the
+ terminal, turn them off. */
+ if ((prompt || edit || silent) && input_is_tty == 0)
+ {
+ prompt = (char *)NULL;
+#if defined (READLINE)
+ itext = (char *)NULL;
+#endif
+ edit = silent = 0;
+ }
+
+#if defined (READLINE)
+ if (edit)
+ add_unwind_protect (xfree, rlbuf);
+#endif
+
+ pass_next = 0; /* Non-zero signifies last char was backslash. */
+ saw_escape = 0; /* Non-zero signifies that we saw an escape char */
+
+ if (tmsec > 0 || tmusec > 0)
+ {
+ /* Turn off the timeout if stdin is a regular file (e.g. from
+ input redirection). */
+ if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
+ tmsec = tmusec = 0;
+ }
+
+ if (tmsec > 0 || tmusec > 0)
+ {
+ code = setjmp (alrmbuf);
+ if (code)
+ {
+ /* Tricky. The top of the unwind-protect stack is the free of
+ input_string. We want to run all the rest and use input_string,
+ so we have to remove it from the stack. */
+ remove_unwind_protect ();
+ run_unwind_frame ("read_builtin");
+ input_string[i] = '\0'; /* make sure it's terminated */
+ retval = 128+SIGALRM;
+ goto assign_vars;
+ }
+ old_alrm = set_signal_handler (SIGALRM, sigalrm);
+ add_unwind_protect (reset_alarm, (char *)NULL);
+#if defined (READLINE)
+ if (edit)
+ add_unwind_protect (reset_attempted_completion_function, (char *)NULL);
+#endif
+ falarm (tmsec, tmusec);
+ }
+
+ /* If we've been asked to read only NCHARS chars, or we're using some
+ character other than newline to terminate the line, do the right
+ thing to readline or the tty. */
+ if (nchars > 0 || delim != '\n')
+ {
+#if defined (READLINE)
+ if (edit)
+ {
+ if (nchars > 0)
+ {
+ unwind_protect_int (rl_num_chars_to_read);
+ rl_num_chars_to_read = nchars;
+ }
+ if (delim != '\n')
+ {
+ set_eol_delim (delim);
+ add_unwind_protect (reset_eol_delim, (char *)NULL);
+ }
+ }
+ else
+#endif
+ if (input_is_tty)
+ {
+ /* ttsave() */
+ termsave.fd = fd;
+ ttgetattr (fd, &ttattrs);
+ termsave.attrs = &ttattrs;
+
+ ttset = ttattrs;
+ i = silent ? ttfd_cbreak (fd, &ttset) : ttfd_onechar (fd, &ttset);
+ if (i < 0)
+ sh_ttyerror (1);
+ add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
+ }
+ }
+ else if (silent) /* turn off echo but leave term in canonical mode */
+ {
+ /* ttsave (); */
+ termsave.fd = fd;
+ ttgetattr (fd, &ttattrs);
+ termsave.attrs = &ttattrs;
+
+ ttset = ttattrs;
+ i = ttfd_noecho (fd, &ttset); /* ttnoecho (); */
+ if (i < 0)
+ sh_ttyerror (1);
+
+ add_unwind_protect ((Function *)ttyrestore, (char *)&termsave);
+ }
+
+ /* This *must* be the top unwind-protect on the stack, so the manipulation
+ of the unwind-protect stack after the realloc() works right. */
+ add_unwind_protect (xfree, input_string);
+ interrupt_immediately++;
+ terminate_immediately++;
+
+ unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
+
+ if (prompt && edit == 0)
+ {
+ fprintf (stderr, "%s", prompt);
+ fflush (stderr);
+ }
+
+#if defined (__CYGWIN__) && defined (O_TEXT)
+ setmode (0, O_TEXT);
+#endif
+
+ ps2 = 0;
+ for (print_ps2 = eof = retval = 0;;)
+ {
+#if defined (READLINE)
+ if (edit)
+ {
+ if (rlbuf && rlbuf[rlind] == '\0')
+ {
+ xfree (rlbuf);
+ rlbuf = (char *)0;
+ }
+ if (rlbuf == 0)
+ {
+ rlbuf = edit_line (prompt ? prompt : "", itext);
+ rlind = 0;
+ }
+ if (rlbuf == 0)
+ {
+ eof = 1;
+ break;
+ }
+ c = rlbuf[rlind++];
+ }
+ else
+ {
+#endif
+
+ if (print_ps2)
+ {
+ if (ps2 == 0)
+ ps2 = get_string_value ("PS2");
+ fprintf (stderr, "%s", ps2 ? ps2 : "");
+ fflush (stderr);
+ print_ps2 = 0;
+ }
+
+ if (unbuffered_read)
+ retval = zread (fd, &c, 1);
+ else
+ retval = zreadc (fd, &c);
+
+ if (retval <= 0)
+ {
+ eof = 1;
+ break;
+ }
+
+#if defined (READLINE)
+ }
+#endif
+
+ if (i + 4 >= size) /* XXX was i + 2; use i + 4 for multibyte/read_mbchar */
+ {
+ input_string = (char *)xrealloc (input_string, size += 128);
+ remove_unwind_protect ();
+ add_unwind_protect (xfree, input_string);
+ }
+
+ /* If the next character is to be accepted verbatim, a backslash
+ newline pair still disappears from the input. */
+ if (pass_next)
+ {
+ pass_next = 0;
+ if (c == '\n')
+ {
+ i--; /* back up over the CTLESC */
+ if (interactive && input_is_tty && raw == 0)
+ print_ps2 = 1;
+ }
+ else
+ goto add_char;
+ continue;
+ }
+
+ /* This may cause problems if IFS contains CTLESC */
+ if (c == '\\' && raw == 0)
+ {
+ pass_next++;
+ if (skip_ctlesc == 0)
+ {
+ saw_escape++;
+ input_string[i++] = CTLESC;
+ }
+ continue;
+ }
+
+ if ((unsigned char)c == delim)
+ break;
+
+ if ((skip_ctlesc == 0 && c == CTLESC) || (skip_ctlnul == 0 && c == CTLNUL))
+ {
+ saw_escape++;
+ input_string[i++] = CTLESC;
+ }
+
+add_char:
+ input_string[i++] = c;
+
+#if defined (HANDLE_MULTIBYTE)
+ if (nchars > 0 && MB_CUR_MAX > 1)
+ {
+ input_string[i] = '\0'; /* for simplicity and debugging */
+ i += read_mbchar (fd, input_string, i, c, unbuffered_read);
+ }
+#endif
+
+ nr++;
+
+ if (nchars > 0 && nr >= nchars)
+ break;
+ }
+ input_string[i] = '\0';
+
+#if 1
+ if (retval < 0)
+ {
+ builtin_error (_("read error: %d: %s"), fd, strerror (errno));
+ run_unwind_frame ("read_builtin");
+ return (EXECUTION_FAILURE);
+ }
+#endif
+
+ if (tmsec > 0 || tmusec > 0)
+ reset_alarm ();
+
+ if (nchars > 0 || delim != '\n')
+ {
+#if defined (READLINE)
+ if (edit)
+ {
+ if (nchars > 0)
+ rl_num_chars_to_read = 0;
+ if (delim != '\n')
+ reset_eol_delim ((char *)NULL);
+ }
+ else
+#endif
+ if (input_is_tty)
+ ttyrestore (&termsave);
+ }
+ else if (silent)
+ ttyrestore (&termsave);
+
+ if (unbuffered_read == 0)
+ zsyncfd (fd);
+
+ discard_unwind_frame ("read_builtin");
+
+ retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
+
+assign_vars:
+
+ interrupt_immediately--;
+ terminate_immediately--;
+
+#if defined (ARRAY_VARS)
+ /* If -a was given, take the string read, break it into a list of words,
+ an assign them to `arrayname' in turn. */
+ if (arrayname)
+ {
+ if (legal_identifier (arrayname) == 0)
+ {
+ sh_invalidid (arrayname);
+ xfree (input_string);
+ return (EXECUTION_FAILURE);
+ }
+
+ var = find_or_make_array_variable (arrayname, 1);
+ if (var == 0)
+ {
+ xfree (input_string);
+ return EXECUTION_FAILURE; /* readonly or noassign */
+ }
+ array_flush (array_cell (var));
+
+ alist = list_string (input_string, ifs_chars, 0);
+ if (alist)
+ {
+ if (saw_escape)
+ dequote_list (alist);
+ else
+ word_list_remove_quoted_nulls (alist);
+ assign_array_var_from_word_list (var, alist, 0);
+ dispose_words (alist);
+ }
+ xfree (input_string);
+ return (retval);
+ }
+#endif /* ARRAY_VARS */
+
+ /* If there are no variables, save the text of the line read to the
+ variable $REPLY. ksh93 strips leading and trailing IFS whitespace,
+ so that `read x ; echo "$x"' and `read ; echo "$REPLY"' behave the
+ same way, but I believe that the difference in behaviors is useful
+ enough to not do it. Without the bash behavior, there is no way
+ to read a line completely without interpretation or modification
+ unless you mess with $IFS (e.g., setting it to the empty string).
+ If you disagree, change the occurrences of `#if 0' to `#if 1' below. */
+ if (list == 0)
+ {
+#if 0
+ orig_input_string = input_string;
+ for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
+ ;
+ input_string = t;
+ input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
+#endif
+
+ if (saw_escape)
+ {
+ t = dequote_string (input_string);
+ var = bind_variable ("REPLY", t, 0);
+ free (t);
+ }
+ else
+ var = bind_variable ("REPLY", input_string, 0);
+ VUNSETATTR (var, att_invisible);
+
+ free (input_string);
+ return (retval);
+ }
+
+ /* This code implements the Posix.2 spec for splitting the words
+ read and assigning them to variables. */
+ orig_input_string = input_string;
+
+ /* Remove IFS white space at the beginning of the input string. If
+ $IFS is null, no field splitting is performed. */
+ for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
+ ;
+ input_string = t;
+ for (; list->next; list = list->next)
+ {
+ varname = list->word->word;
+#if defined (ARRAY_VARS)
+ if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
+#else
+ if (legal_identifier (varname) == 0)
+#endif
+ {
+ sh_invalidid (varname);
+ xfree (orig_input_string);
+ return (EXECUTION_FAILURE);
+ }
+
+ /* If there are more variables than words read from the input,
+ the remaining variables are set to the empty string. */
+ if (*input_string)
+ {
+ /* This call updates INPUT_STRING. */
+ t = get_word_from_string (&input_string, ifs_chars, &e);
+ if (t)
+ *e = '\0';
+ /* Don't bother to remove the CTLESC unless we added one
+ somewhere while reading the string. */
+ if (t && saw_escape)
+ {
+ t1 = dequote_string (t);
+ var = bind_read_variable (varname, t1);
+ xfree (t1);
+ }
+ else
+ var = bind_read_variable (varname, t);
+ }
+ else
+ {
+ t = (char *)0;
+ var = bind_read_variable (varname, "");
+ }
+
+ FREE (t);
+ if (var == 0)
+ {
+ xfree (orig_input_string);
+ return (EXECUTION_FAILURE);
+ }
+
+ stupidly_hack_special_variables (varname);
+ VUNSETATTR (var, att_invisible);
+ }
+
+ /* Now assign the rest of the line to the last variable argument. */
+#if defined (ARRAY_VARS)
+ if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
+#else
+ if (legal_identifier (list->word->word) == 0)
+#endif
+ {
+ sh_invalidid (list->word->word);
+ xfree (orig_input_string);
+ return (EXECUTION_FAILURE);
+ }
+
+#if 0
+ /* This has to be done this way rather than using string_list
+ and list_string because Posix.2 says that the last variable gets the
+ remaining words and their intervening separators. */
+ input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
+#else
+ /* Check whether or not the number of fields is exactly the same as the
+ number of variables. */
+ tofree = NULL;
+ if (*input_string)
+ {
+ t1 = input_string;
+ t = get_word_from_string (&input_string, ifs_chars, &e);
+ if (*input_string == 0)
+ tofree = input_string = t;
+ else
+ {
+ input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
+ tofree = t;
+ }
+ }
+#endif
+
+ if (saw_escape)
+ {
+ t = dequote_string (input_string);
+ var = bind_read_variable (list->word->word, t);
+ xfree (t);
+ }
+ else
+ var = bind_read_variable (list->word->word, input_string);
+ stupidly_hack_special_variables (list->word->word);
+ FREE (tofree);
+
+ if (var)
+ VUNSETATTR (var, att_invisible);
+ xfree (orig_input_string);
+
+ return (retval);
+}
+
+static SHELL_VAR *
+bind_read_variable (name, value)
+ char *name, *value;
+{
+#if defined (ARRAY_VARS)
+ if (valid_array_reference (name) == 0)
+ return (bind_variable (name, value, 0));
+ else
+ return (assign_array_element (name, value, 0));
+#else /* !ARRAY_VARS */
+ return bind_variable (name, value, 0);
+#endif /* !ARRAY_VARS */
+}
+
+#if defined (HANDLE_MULTIBYTE)
+static int
+read_mbchar (fd, string, ind, ch, unbuffered)
+ int fd;
+ char *string;
+ int ind, ch, unbuffered;
+{
+ char mbchar[MB_LEN_MAX + 1];
+ int i, n, r;
+ char c;
+ size_t ret;
+ mbstate_t ps, ps_back;
+ wchar_t wc;
+
+ memset (&ps, '\0', sizeof (mbstate_t));
+ memset (&ps_back, '\0', sizeof (mbstate_t));
+
+ mbchar[0] = ch;
+ i = 1;
+ for (n = 0; n <= MB_LEN_MAX; n++)
+ {
+ ps_back = ps;
+ ret = mbrtowc (&wc, mbchar, i, &ps);
+ if (ret == (size_t)-2)
+ {
+ ps = ps_back;
+ if (unbuffered)
+ r = zread (fd, &c, 1);
+ else
+ r = zreadc (fd, &c);
+ if (r < 0)
+ goto mbchar_return;
+ mbchar[i++] = c;
+ continue;
+ }
+ else if (ret == (size_t)-1 || ret == (size_t)0 || ret > (size_t)0)
+ break;
+ }
+
+mbchar_return:
+ if (i > 1) /* read a multibyte char */
+ /* mbchar[0] is already string[ind-1] */
+ for (r = 1; r < i; r++)
+ string[ind+r-1] = mbchar[r];
+ return i - 1;
+}
+#endif
+
+
+static void
+ttyrestore (ttp)
+ struct ttsave *ttp;
+{
+ ttsetattr (ttp->fd, ttp->attrs);
+}
+
+#if defined (READLINE)
+static rl_completion_func_t *old_attempted_completion_function = 0;
+static rl_hook_func_t *old_startup_hook;
+static char *deftext;
+
+static void
+reset_attempted_completion_function (cp)
+ char *cp;
+{
+ if (rl_attempted_completion_function == 0 && old_attempted_completion_function)
+ rl_attempted_completion_function = old_attempted_completion_function;
+}
+
+static int
+set_itext ()
+{
+ int r1, r2;
+
+ r1 = r2 = 0;
+ if (old_startup_hook)
+ r1 = (*old_startup_hook) ();
+ if (deftext)
+ {
+ r2 = rl_insert_text (deftext);
+ deftext = (char *)NULL;
+ rl_startup_hook = old_startup_hook;
+ old_startup_hook = (rl_hook_func_t *)NULL;
+ }
+ return (r1 || r2);
+}
+
+static char *
+edit_line (p, itext)
+ char *p;
+ char *itext;
+{
+ char *ret;
+ int len;
+
+ if (bash_readline_initialized == 0)
+ initialize_readline ();
+
+ old_attempted_completion_function = rl_attempted_completion_function;
+ rl_attempted_completion_function = (rl_completion_func_t *)NULL;
+ if (itext)
+ {
+ old_startup_hook = rl_startup_hook;
+ rl_startup_hook = set_itext;
+ deftext = itext;
+ }
+ ret = readline (p);
+ rl_attempted_completion_function = old_attempted_completion_function;
+ old_attempted_completion_function = (rl_completion_func_t *)NULL;
+
+ if (ret == 0)
+ return ret;
+ len = strlen (ret);
+ ret = (char *)xrealloc (ret, len + 2);
+ ret[len++] = delim;
+ ret[len] = '\0';
+ return ret;
+}
+
+static int old_delim_ctype;
+static rl_command_func_t *old_delim_func;
+static int old_newline_ctype;
+static rl_command_func_t *old_newline_func;
+
+static unsigned char delim_char;
+
+static void
+set_eol_delim (c)
+ int c;
+{
+ Keymap cmap;
+
+ if (bash_readline_initialized == 0)
+ initialize_readline ();
+ cmap = rl_get_keymap ();
+
+ /* Change newline to self-insert */
+ old_newline_ctype = cmap[RETURN].type;
+ old_newline_func = cmap[RETURN].function;
+ cmap[RETURN].type = ISFUNC;
+ cmap[RETURN].function = rl_insert;
+
+ /* Bind the delimiter character to accept-line. */
+ old_delim_ctype = cmap[c].type;
+ old_delim_func = cmap[c].function;
+ cmap[c].type = ISFUNC;
+ cmap[c].function = rl_newline;
+
+ delim_char = c;
+}
+
+static void
+reset_eol_delim (cp)
+ char *cp;
+{
+ Keymap cmap;
+
+ cmap = rl_get_keymap ();
+
+ cmap[RETURN].type = old_newline_ctype;
+ cmap[RETURN].function = old_newline_func;
+
+ cmap[delim_char].type = old_delim_ctype;
+ cmap[delim_char].function = old_delim_func;
+}
+#endif
diff --git a/builtins/return.c b/builtins/return.c
new file mode 100644
index 0000000..d48b198
--- /dev/null
+++ b/builtins/return.c
@@ -0,0 +1,45 @@
+/* return.c, created from return.def. */
+#line 22 "./return.def"
+
+#line 36 "./return.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int last_command_exit_value;
+extern int subshell_environment;
+extern int return_catch_flag, return_catch_value;
+
+/* If we are executing a user-defined function then exit with the value
+ specified as an argument. if no argument is given, then the last
+ exit status is used. */
+int
+return_builtin (list)
+ WORD_LIST *list;
+{
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend; /* skip over possible `--' */
+
+ return_catch_value = get_exitstat (list);
+
+ if (return_catch_flag)
+ longjmp (return_catch, 1);
+ else
+ {
+ builtin_error (_("can only `return' from a function or sourced script"));
+ return (EXECUTION_FAILURE);
+ }
+}
diff --git a/builtins/set.c b/builtins/set.c
new file mode 100644
index 0000000..e460223
--- /dev/null
+++ b/builtins/set.c
@@ -0,0 +1,725 @@
+/* set.c, created from set.def. */
+#line 22 "./set.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../flags.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if defined (READLINE)
+# include "../input.h"
+# include "../bashline.h"
+# include <readline/readline.h>
+#endif
+
+#if defined (HISTORY)
+# include "../bashhist.h"
+#endif
+
+extern int posixly_correct, ignoreeof, eof_encountered_limit;
+#if defined (HISTORY)
+extern int dont_save_function_defs;
+#endif
+#if defined (READLINE)
+extern int no_line_editing;
+#endif /* READLINE */
+
+#line 153 "./set.def"
+
+typedef int setopt_set_func_t __P((int, char *));
+typedef int setopt_get_func_t __P((char *));
+
+static void print_minus_o_option __P((char *, int, int));
+static void print_all_shell_variables __P((void));
+
+static int set_ignoreeof __P((int, char *));
+static int set_posix_mode __P((int, char *));
+
+#if defined (READLINE)
+static int set_edit_mode __P((int, char *));
+static int get_edit_mode __P((char *));
+#endif
+
+#if defined (HISTORY)
+static int bash_set_history __P((int, char *));
+#endif
+
+static const char * const on = "on";
+static const char * const off = "off";
+
+/* A struct used to match long options for set -o to the corresponding
+ option letter or internal variable. The functions can be called to
+ dynamically generate values. */
+const struct {
+ char *name;
+ int letter;
+ int *variable;
+ setopt_set_func_t *set_func;
+ setopt_get_func_t *get_func;
+} o_options[] = {
+ { "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#if defined (BRACE_EXPANSION)
+ { "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#endif
+#if defined (READLINE)
+ { "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
+#endif
+ { "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#if defined (BANG_HISTORY)
+ { "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#endif /* BANG_HISTORY */
+#if defined (HISTORY)
+ { "history", '\0', &enable_history_list, bash_set_history, (setopt_get_func_t *)NULL },
+#endif
+ { "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
+ { "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#if defined (HISTORY)
+ { "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#endif
+#if defined (JOB_CONTROL)
+ { "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#endif /* JOB_CONTROL */
+ { "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
+ { "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ { "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+#if defined (READLINE)
+ { "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
+#endif
+ { "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+ {(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
+};
+
+#define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0]))
+
+#define GET_BINARY_O_OPTION_VALUE(i, name) \
+ ((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
+ : (*o_options[i].variable))
+
+#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
+ ((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
+ : (*o_options[i].variable = (onoff == FLAG_ON)))
+
+int
+minus_o_option_value (name)
+ char *name;
+{
+ register int i;
+ int *on_or_off;
+
+ for (i = 0; o_options[i].name; i++)
+ {
+ if (STREQ (name, o_options[i].name))
+ {
+ if (o_options[i].letter)
+ {
+ on_or_off = find_flag (o_options[i].letter);
+ return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
+ }
+ else
+ return (GET_BINARY_O_OPTION_VALUE (i, name));
+ }
+ }
+
+ return (-1);
+}
+
+#define MINUS_O_FORMAT "%-15s\t%s\n"
+
+static void
+print_minus_o_option (name, value, pflag)
+ char *name;
+ int value, pflag;
+{
+ if (pflag == 0)
+ printf (MINUS_O_FORMAT, name, value ? on : off);
+ else
+ printf ("set %co %s\n", value ? '-' : '+', name);
+}
+
+void
+list_minus_o_opts (mode, reusable)
+ int mode, reusable;
+{
+ register int i;
+ int *on_or_off, value;
+
+ for (i = 0; o_options[i].name; i++)
+ {
+ if (o_options[i].letter)
+ {
+ value = 0;
+ on_or_off = find_flag (o_options[i].letter);
+ if (on_or_off == FLAG_UNKNOWN)
+ on_or_off = &value;
+ if (mode == -1 || mode == *on_or_off)
+ print_minus_o_option (o_options[i].name, *on_or_off, reusable);
+ }
+ else
+ {
+ value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
+ if (mode == -1 || mode == value)
+ print_minus_o_option (o_options[i].name, value, reusable);
+ }
+ }
+}
+
+char **
+get_minus_o_opts ()
+{
+ char **ret;
+ int i;
+
+ ret = strvec_create (N_O_OPTIONS + 1);
+ for (i = 0; o_options[i].name; i++)
+ ret[i] = o_options[i].name;
+ ret[i] = (char *)NULL;
+ return ret;
+}
+
+static int
+set_ignoreeof (on_or_off, option_name)
+ int on_or_off;
+ char *option_name;
+{
+ ignoreeof = on_or_off == FLAG_ON;
+ unbind_variable ("ignoreeof");
+ if (ignoreeof)
+ bind_variable ("IGNOREEOF", "10", 0);
+ else
+ unbind_variable ("IGNOREEOF");
+ sv_ignoreeof ("IGNOREEOF");
+ return 0;
+}
+
+static int
+set_posix_mode (on_or_off, option_name)
+ int on_or_off;
+ char *option_name;
+{
+ posixly_correct = on_or_off == FLAG_ON;
+ if (posixly_correct == 0)
+ unbind_variable ("POSIXLY_CORRECT");
+ else
+ bind_variable ("POSIXLY_CORRECT", "y", 0);
+ sv_strict_posix ("POSIXLY_CORRECT");
+ return (0);
+}
+
+#if defined (READLINE)
+/* Magic. This code `knows' how readline handles rl_editing_mode. */
+static int
+set_edit_mode (on_or_off, option_name)
+ int on_or_off;
+ char *option_name;
+{
+ int isemacs;
+
+ if (on_or_off == FLAG_ON)
+ {
+ rl_variable_bind ("editing-mode", option_name);
+
+ if (interactive)
+ with_input_from_stdin ();
+ no_line_editing = 0;
+ }
+ else
+ {
+ isemacs = rl_editing_mode == 1;
+ if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
+ {
+ if (interactive)
+ with_input_from_stream (stdin, "stdin");
+ no_line_editing = 1;
+ }
+ }
+ return 1-no_line_editing;
+}
+
+static int
+get_edit_mode (name)
+ char *name;
+{
+ return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
+ : no_line_editing == 0 && rl_editing_mode == 0);
+}
+#endif /* READLINE */
+
+#if defined (HISTORY)
+static int
+bash_set_history (on_or_off, option_name)
+ int on_or_off;
+ char *option_name;
+{
+ if (on_or_off == FLAG_ON)
+ {
+ enable_history_list = 1;
+ bash_history_enable ();
+ if (history_lines_this_session == 0)
+ load_history ();
+ }
+ else
+ {
+ enable_history_list = 0;
+ bash_history_disable ();
+ }
+ return (1 - enable_history_list);
+}
+#endif
+
+int
+set_minus_o_option (on_or_off, option_name)
+ int on_or_off;
+ char *option_name;
+{
+ register int i;
+
+ for (i = 0; o_options[i].name; i++)
+ {
+ if (STREQ (option_name, o_options[i].name))
+ {
+ if (o_options[i].letter == 0)
+ {
+ SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
+ return (EXECUTION_SUCCESS);
+ }
+ else
+ {
+ if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
+ {
+ sh_invalidoptname (option_name);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ return (EXECUTION_SUCCESS);
+ }
+
+ }
+ }
+
+ sh_invalidoptname (option_name);
+ return (EX_USAGE);
+}
+
+static void
+print_all_shell_variables ()
+{
+ SHELL_VAR **vars;
+
+ vars = all_shell_variables ();
+ if (vars)
+ {
+ print_var_list (vars);
+ free (vars);
+ }
+
+ /* POSIX.2 does not allow function names and definitions to be output when
+ `set' is invoked without options (PASC Interp #202). */
+ if (posixly_correct == 0)
+ {
+ vars = all_shell_functions ();
+ if (vars)
+ {
+ print_func_list (vars);
+ free (vars);
+ }
+ }
+}
+
+void
+set_shellopts ()
+{
+ char *value;
+ char tflag[N_O_OPTIONS];
+ int vsize, i, vptr, *ip, exported;
+ SHELL_VAR *v;
+
+ for (vsize = i = 0; o_options[i].name; i++)
+ {
+ tflag[i] = 0;
+ if (o_options[i].letter)
+ {
+ ip = find_flag (o_options[i].letter);
+ if (ip && *ip)
+ {
+ vsize += strlen (o_options[i].name) + 1;
+ tflag[i] = 1;
+ }
+ }
+ else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
+ {
+ vsize += strlen (o_options[i].name) + 1;
+ tflag[i] = 1;
+ }
+ }
+
+ value = (char *)xmalloc (vsize + 1);
+
+ for (i = vptr = 0; o_options[i].name; i++)
+ {
+ if (tflag[i])
+ {
+ strcpy (value + vptr, o_options[i].name);
+ vptr += strlen (o_options[i].name);
+ value[vptr++] = ':';
+ }
+ }
+
+ if (vptr)
+ vptr--; /* cut off trailing colon */
+ value[vptr] = '\0';
+
+ v = find_variable ("SHELLOPTS");
+
+ /* Turn off the read-only attribute so we can bind the new value, and
+ note whether or not the variable was exported. */
+ if (v)
+ {
+ VUNSETATTR (v, att_readonly);
+ exported = exported_p (v);
+ }
+ else
+ exported = 0;
+
+ v = bind_variable ("SHELLOPTS", value, 0);
+
+ /* Turn the read-only attribute back on, and turn off the export attribute
+ if it was set implicitly by mark_modified_vars and SHELLOPTS was not
+ exported before we bound the new value. */
+ VSETATTR (v, att_readonly);
+ if (mark_modified_vars && exported == 0 && exported_p (v))
+ VUNSETATTR (v, att_exported);
+
+ free (value);
+}
+
+void
+parse_shellopts (value)
+ char *value;
+{
+ char *vname;
+ int vptr;
+
+ vptr = 0;
+ while (vname = extract_colon_unit (value, &vptr))
+ {
+ set_minus_o_option (FLAG_ON, vname);
+ free (vname);
+ }
+}
+
+void
+initialize_shell_options (no_shellopts)
+ int no_shellopts;
+{
+ char *temp;
+ SHELL_VAR *var;
+
+ if (no_shellopts == 0)
+ {
+ var = find_variable ("SHELLOPTS");
+ /* set up any shell options we may have inherited. */
+ if (var && imported_p (var))
+ {
+ temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
+ if (temp)
+ {
+ parse_shellopts (temp);
+ free (temp);
+ }
+ }
+ }
+
+ /* Set up the $SHELLOPTS variable. */
+ set_shellopts ();
+}
+
+/* Reset the values of the -o options that are not also shell flags. This is
+ called from execute_cmd.c:initialize_subshell() when setting up a subshell
+ to run an executable shell script without a leading `#!'. */
+void
+reset_shell_options ()
+{
+#if defined (HISTORY)
+ remember_on_history = enable_history_list = 1;
+#endif
+ ignoreeof = 0;
+}
+
+/* Set some flags from the word values in the input list. If LIST is empty,
+ then print out the values of the variables instead. If LIST contains
+ non-flags, then set $1 - $9 to the successive words of LIST. */
+int
+set_builtin (list)
+ WORD_LIST *list;
+{
+ int on_or_off, flag_name, force_assignment, opts_changed, rv, r;
+ register char *arg;
+ char s[3];
+
+ if (list == 0)
+ {
+ print_all_shell_variables ();
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+
+ /* Check validity of flag arguments. */
+ rv = EXECUTION_SUCCESS;
+ reset_internal_getopt ();
+ while ((flag_name = internal_getopt (list, optflags)) != -1)
+ {
+ switch (flag_name)
+ {
+ case '?':
+ builtin_usage ();
+ return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
+ default:
+ break;
+ }
+ }
+
+ /* Do the set command. While the list consists of words starting with
+ '-' or '+' treat them as flags, otherwise, start assigning them to
+ $1 ... $n. */
+ for (force_assignment = opts_changed = 0; list; )
+ {
+ arg = list->word->word;
+
+ /* If the argument is `--' or `-' then signal the end of the list
+ and remember the remaining arguments. */
+ if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
+ {
+ list = list->next;
+
+ /* `set --' unsets the positional parameters. */
+ if (arg[1] == '-')
+ force_assignment = 1;
+
+ /* Until told differently, the old shell behaviour of
+ `set - [arg ...]' being equivalent to `set +xv [arg ...]'
+ stands. Posix.2 says the behaviour is marked as obsolescent. */
+ else
+ {
+ change_flag ('x', '+');
+ change_flag ('v', '+');
+ opts_changed = 1;
+ }
+
+ break;
+ }
+
+ if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
+ {
+ while (flag_name = *++arg)
+ {
+ if (flag_name == '?')
+ {
+ builtin_usage ();
+ return (EXECUTION_SUCCESS);
+ }
+ else if (flag_name == 'o') /* -+o option-name */
+ {
+ char *option_name;
+ WORD_LIST *opt;
+
+ opt = list->next;
+
+ if (opt == 0)
+ {
+ list_minus_o_opts (-1, (on_or_off == '+'));
+ rv = sh_chkwrite (rv);
+ continue;
+ }
+
+ option_name = opt->word->word;
+
+ if (option_name == 0 || *option_name == '\0' ||
+ *option_name == '-' || *option_name == '+')
+ {
+ list_minus_o_opts (-1, (on_or_off == '+'));
+ continue;
+ }
+ list = list->next; /* Skip over option name. */
+
+ opts_changed = 1;
+ if ((r = set_minus_o_option (on_or_off, option_name)) != EXECUTION_SUCCESS)
+ {
+ set_shellopts ();
+ return (r);
+ }
+ }
+ else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
+ {
+ s[0] = on_or_off;
+ s[1] = flag_name;
+ s[2] = '\0';
+ sh_invalidopt (s);
+ builtin_usage ();
+ set_shellopts ();
+ return (EXECUTION_FAILURE);
+ }
+ opts_changed = 1;
+ }
+ }
+ else
+ {
+ break;
+ }
+ list = list->next;
+ }
+
+ /* Assigning $1 ... $n */
+ if (list || force_assignment)
+ remember_args (list, 1);
+ /* Set up new value of $SHELLOPTS */
+ if (opts_changed)
+ set_shellopts ();
+ return (rv);
+}
+
+#line 735 "./set.def"
+
+#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
+
+int
+unset_builtin (list)
+ WORD_LIST *list;
+{
+ int unset_function, unset_variable, unset_array, opt, any_failed;
+ char *name;
+
+ unset_function = unset_variable = unset_array = any_failed = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "fv")) != -1)
+ {
+ switch (opt)
+ {
+ case 'f':
+ unset_function = 1;
+ break;
+ case 'v':
+ unset_variable = 1;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (unset_function && unset_variable)
+ {
+ builtin_error (_("cannot simultaneously unset a function and a variable"));
+ return (EXECUTION_FAILURE);
+ }
+
+ while (list)
+ {
+ SHELL_VAR *var;
+ int tem;
+#if defined (ARRAY_VARS)
+ char *t;
+#endif
+
+ name = list->word->word;
+
+#if defined (ARRAY_VARS)
+ unset_array = 0;
+ if (!unset_function && valid_array_reference (name))
+ {
+ t = strchr (name, '[');
+ *t++ = '\0';
+ unset_array++;
+ }
+#endif
+
+ /* Bash allows functions with names which are not valid identifiers
+ to be created when not in posix mode, so check only when in posix
+ mode when unsetting a function. */
+ if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
+ {
+ sh_invalidid (name);
+ NEXT_VARIABLE ();
+ }
+
+ var = unset_function ? find_function (name) : find_variable (name);
+
+ if (var && !unset_function && non_unsettable_p (var))
+ {
+ builtin_error (_("%s: cannot unset"), name);
+ NEXT_VARIABLE ();
+ }
+
+ /* Posix.2 says that unsetting readonly variables is an error. */
+ if (var && readonly_p (var))
+ {
+ builtin_error (_("%s: cannot unset: readonly %s"),
+ name, unset_function ? "function" : "variable");
+ NEXT_VARIABLE ();
+ }
+
+ /* Unless the -f option is supplied, the name refers to a variable. */
+#if defined (ARRAY_VARS)
+ if (var && unset_array)
+ {
+ if (array_p (var) == 0 && assoc_p (var) == 0)
+ {
+ builtin_error (_("%s: not an array variable"), name);
+ NEXT_VARIABLE ();
+ }
+ else
+ {
+ tem = unbind_array_element (var, t);
+ if (tem == -1)
+ any_failed++;
+ }
+ }
+ else
+#endif /* ARRAY_VARS */
+ tem = unset_function ? unbind_func (name) : unbind_variable (name);
+
+ /* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
+ is specified, the name refers to a variable; if a variable by
+ that name does not exist, a function by that name, if any,
+ shall be unset.'' */
+ if (tem == -1 && !unset_function && !unset_variable)
+ tem = unbind_func (name);
+
+ /* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
+ was not previously set shall not be considered an error.'' */
+
+ if (unset_function == 0)
+ stupidly_hack_special_variables (name);
+
+ list = list->next;
+ }
+
+ return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
diff --git a/builtins/setattr.c b/builtins/setattr.c
new file mode 100644
index 0000000..9d64132
--- /dev/null
+++ b/builtins/setattr.c
@@ -0,0 +1,459 @@
+/* setattr.c, created from setattr.def. */
+#line 22 "./setattr.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int posixly_correct;
+extern int array_needs_making;
+extern char *this_command_name;
+extern sh_builtin_func_t *this_shell_builtin;
+
+#ifdef ARRAY_VARS
+extern int declare_builtin __P((WORD_LIST *));
+#endif
+
+#define READONLY_OR_EXPORT \
+ (this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
+
+#line 70 "./setattr.def"
+
+/* For each variable name in LIST, make that variable appear in the
+ environment passed to simple commands. If there is no LIST, then
+ print all such variables. An argument of `-n' says to remove the
+ exported attribute from variables named in LIST. An argument of
+ -f indicates that the names present in LIST refer to functions. */
+int
+export_builtin (list)
+ register WORD_LIST *list;
+{
+ return (set_or_show_attributes (list, att_exported, 0));
+}
+
+#line 103 "./setattr.def"
+
+/* For each variable name in LIST, make that variable readonly. Given an
+ empty LIST, print out all existing readonly variables. */
+int
+readonly_builtin (list)
+ register WORD_LIST *list;
+{
+ return (set_or_show_attributes (list, att_readonly, 0));
+}
+
+#if defined (ARRAY_VARS)
+# define ATTROPTS "aAfnp"
+#else
+# define ATTROPTS "fnp"
+#endif
+
+/* For each variable name in LIST, make that variable have the specified
+ ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
+ remaining names in LIST (doesn't work for readonly). */
+int
+set_or_show_attributes (list, attribute, nodefs)
+ register WORD_LIST *list;
+ int attribute, nodefs;
+{
+ register SHELL_VAR *var;
+ int assign, undo, any_failed, assign_error, opt;
+ int functions_only, arrays_only, assoc_only;
+ int aflags;
+ char *name;
+#if defined (ARRAY_VARS)
+ WORD_LIST *nlist, *tlist;
+ WORD_DESC *w;
+#endif
+
+ functions_only = arrays_only = assoc_only = 0;
+ undo = any_failed = assign_error = 0;
+ /* Read arguments from the front of the list. */
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, ATTROPTS)) != -1)
+ {
+ switch (opt)
+ {
+ case 'n':
+ undo = 1;
+ break;
+ case 'f':
+ functions_only = 1;
+ break;
+#if defined (ARRAY_VARS)
+ case 'a':
+ arrays_only = 1;
+ break;
+ case 'A':
+ assoc_only = 1;
+ break;
+#endif
+ case 'p':
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list)
+ {
+ if (attribute & att_exported)
+ array_needs_making = 1;
+
+ /* Cannot undo readonly status, silently disallowed. */
+ if (undo && (attribute & att_readonly))
+ attribute &= ~att_readonly;
+
+ while (list)
+ {
+ name = list->word->word;
+
+ if (functions_only) /* xxx -f name */
+ {
+ var = find_function (name);
+ if (var == 0)
+ {
+ builtin_error (_("%s: not a function"), name);
+ any_failed++;
+ }
+ else
+ SETVARATTR (var, attribute, undo);
+
+ list = list->next;
+ continue;
+ }
+
+ /* xxx [-np] name[=value] */
+ assign = assignment (name, 0);
+
+ aflags = 0;
+ if (assign)
+ {
+ name[assign] = '\0';
+ if (name[assign - 1] == '+')
+ {
+ aflags |= ASS_APPEND;
+ name[assign - 1] = '\0';
+ }
+ }
+
+ if (legal_identifier (name) == 0)
+ {
+ sh_invalidid (name);
+ if (assign)
+ assign_error++;
+ else
+ any_failed++;
+ list = list->next;
+ continue;
+ }
+
+ if (assign) /* xxx [-np] name=value */
+ {
+ name[assign] = '=';
+ if (aflags & ASS_APPEND)
+ name[assign - 1] = '+';
+#if defined (ARRAY_VARS)
+ /* Let's try something here. Turn readonly -a xxx=yyy into
+ declare -ra xxx=yyy and see what that gets us. */
+ if (arrays_only || assoc_only)
+ {
+ tlist = list->next;
+ list->next = (WORD_LIST *)NULL;
+ w = arrays_only ? make_word ("-ra") : make_word ("-rA");
+ nlist = make_word_list (w, list);
+ opt = declare_builtin (nlist);
+ if (opt != EXECUTION_SUCCESS)
+ assign_error++;
+ list->next = tlist;
+ dispose_word (w);
+ free (nlist);
+ }
+ else
+#endif
+ /* This word has already been expanded once with command
+ and parameter expansion. Call do_assignment_no_expand (),
+ which does not do command or parameter substitution. If
+ the assignment is not performed correctly, flag an error. */
+ if (do_assignment_no_expand (name) == 0)
+ assign_error++;
+ name[assign] = '\0';
+ if (aflags & ASS_APPEND)
+ name[assign - 1] = '\0';
+ }
+
+ set_var_attribute (name, attribute, undo);
+ list = list->next;
+ }
+ }
+ else
+ {
+ SHELL_VAR **variable_list;
+ register int i;
+
+ if ((attribute & att_function) || functions_only)
+ {
+ variable_list = all_shell_functions ();
+ if (attribute != att_function)
+ attribute &= ~att_function; /* so declare -xf works, for example */
+ }
+ else
+ variable_list = all_shell_variables ();
+
+#if defined (ARRAY_VARS)
+ if (attribute & att_array)
+ {
+ arrays_only++;
+ if (attribute != att_array)
+ attribute &= ~att_array;
+ }
+ else if (attribute & att_assoc)
+ {
+ assoc_only++;
+ if (attribute != att_assoc)
+ attribute &= ~att_assoc;
+ }
+#endif
+
+ if (variable_list)
+ {
+ for (i = 0; var = variable_list[i]; i++)
+ {
+#if defined (ARRAY_VARS)
+ if (arrays_only && array_p (var) == 0)
+ continue;
+ else if (assoc_only && assoc_p (var) == 0)
+ continue;
+#endif
+ if ((var->attributes & attribute))
+ {
+ show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
+ if (any_failed = sh_chkwrite (any_failed))
+ break;
+ }
+ }
+ free (variable_list);
+ }
+ }
+
+ return (assign_error ? EX_BADASSIGN
+ : ((any_failed == 0) ? EXECUTION_SUCCESS
+ : 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'.
+ In POSIX mode, this prints the name of the calling builtin (`export'
+ or `readonly') instead of `declare', and doesn't print function defs
+ when called by `export' or `readonly'. */
+int
+show_var_attributes (var, pattr, nodefs)
+ SHELL_VAR *var;
+ int pattr, nodefs;
+{
+ char flags[16], *x;
+ int i;
+
+ i = 0;
+
+ /* pattr == 0 means we are called from `declare'. */
+ if (pattr == 0 || posixly_correct == 0)
+ {
+#if defined (ARRAY_VARS)
+ if (array_p (var))
+ flags[i++] = 'a';
+
+ if (assoc_p (var))
+ flags[i++] = 'A';
+#endif
+
+ if (function_p (var))
+ flags[i++] = 'f';
+
+ if (integer_p (var))
+ flags[i++] = 'i';
+
+ if (readonly_p (var))
+ flags[i++] = 'r';
+
+ if (trace_p (var))
+ flags[i++] = 't';
+
+ if (exported_p (var))
+ flags[i++] = 'x';
+
+ if (capcase_p (var))
+ flags[i++] = 'c';
+
+ if (lowercase_p (var))
+ flags[i++] = 'l';
+
+ if (uppercase_p (var))
+ flags[i++] = 'u';
+ }
+ else
+ {
+#if defined (ARRAY_VARS)
+ if (array_p (var))
+ flags[i++] = 'a';
+
+ if (assoc_p (var))
+ flags[i++] = 'A';
+#endif
+
+ if (function_p (var))
+ flags[i++] = 'f';
+ }
+
+ flags[i] = '\0';
+
+ /* If we're printing functions with definitions, print the function def
+ first, then the attributes, instead of printing output that can't be
+ reused as input to recreate the current state. */
+ if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
+ {
+ printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
+ nodefs++;
+ if (pattr == 0 && i == 1 && flags[0] == 'f')
+ return 0; /* don't print `declare -f name' */
+ }
+
+ if (pattr == 0 || posixly_correct == 0)
+ printf ("declare -%s ", i ? flags : "-");
+ else if (i)
+ printf ("%s -%s ", this_command_name, flags);
+ else
+ printf ("%s ", this_command_name);
+
+#if defined (ARRAY_VARS)
+ if (array_p (var))
+ print_array_assignment (var, 1);
+ else if (assoc_p (var))
+ print_assoc_assignment (var, 1);
+ else
+#endif
+ /* force `readonly' and `export' to not print out function definitions
+ when in POSIX mode. */
+ if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
+ printf ("%s\n", var->name);
+ else if (function_p (var))
+ printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
+ else if (invisible_p (var))
+ printf ("%s\n", var->name);
+ else
+ {
+ x = sh_double_quote (var_isset (var) ? value_cell (var) : "");
+ printf ("%s=%s\n", var->name, x);
+ free (x);
+ }
+ return (0);
+}
+
+int
+show_name_attributes (name, nodefs)
+ char *name;
+ int nodefs;
+{
+ SHELL_VAR *var;
+
+ var = find_variable_internal (name, 1);
+
+ if (var && invisible_p (var) == 0)
+ {
+ show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
+ return (0);
+ }
+ else
+ return (1);
+}
+
+void
+set_var_attribute (name, attribute, undo)
+ char *name;
+ int attribute, undo;
+{
+ SHELL_VAR *var, *tv;
+ char *tvalue;
+
+ if (undo)
+ var = find_variable (name);
+ else
+ {
+ tv = find_tempenv_variable (name);
+ /* XXX -- need to handle case where tv is a temp variable in a
+ function-scope context, since function_env has been merged into
+ the local variables table. */
+ if (tv && tempvar_p (tv))
+ {
+ tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
+
+ var = bind_variable (tv->name, tvalue, 0);
+ var->attributes |= tv->attributes & ~att_tempvar;
+ VSETATTR (tv, att_propagate);
+ if (var->context != 0)
+ VSETATTR (var, att_propagate);
+ SETVARATTR (tv, attribute, undo); /* XXX */
+
+ stupidly_hack_special_variables (tv->name);
+
+ free (tvalue);
+ }
+ else
+ {
+ var = find_variable_internal (name, 0);
+ if (var == 0)
+ {
+ var = bind_variable (name, (char *)NULL, 0);
+ VSETATTR (var, att_invisible);
+ }
+ else if (var->context != 0)
+ VSETATTR (var, att_propagate);
+ }
+ }
+
+ if (var)
+ SETVARATTR (var, attribute, undo);
+
+ if (var && (exported_p (var) || (attribute & att_exported)))
+ array_needs_making++; /* XXX */
+}
diff --git a/builtins/shift.c b/builtins/shift.c
new file mode 100644
index 0000000..e07e8e9
--- /dev/null
+++ b/builtins/shift.c
@@ -0,0 +1,72 @@
+/* shift.c, created from shift.def. */
+#line 22 "./shift.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+
+#line 49 "./shift.def"
+
+int print_shift_error;
+
+/* Shift the arguments ``left''. Shift DOLLAR_VARS down then take one
+ off of REST_OF_ARGS and place it into DOLLAR_VARS[9]. If LIST has
+ anything in it, it is a number which says where to start the
+ shifting. Return > 0 if `times' > $#, otherwise 0. */
+int
+shift_builtin (list)
+ WORD_LIST *list;
+{
+ intmax_t times;
+ register int count;
+ WORD_LIST *temp;
+
+ if (get_numeric_arg (list, 0, &times) == 0)
+ return (EXECUTION_FAILURE);
+
+ if (times == 0)
+ return (EXECUTION_SUCCESS);
+ else if (times < 0)
+ {
+ sh_erange (list ? list->word->word : NULL, _("shift count"));
+ return (EXECUTION_FAILURE);
+ }
+ else if (times > number_of_args ())
+ {
+ if (print_shift_error)
+ sh_erange (list ? list->word->word : NULL, _("shift count"));
+ return (EXECUTION_FAILURE);
+ }
+
+ while (times-- > 0)
+ {
+ if (dollar_vars[1])
+ free (dollar_vars[1]);
+
+ for (count = 1; count < 9; count++)
+ dollar_vars[count] = dollar_vars[count + 1];
+
+ if (rest_of_args)
+ {
+ temp = rest_of_args;
+ dollar_vars[9] = savestring (temp->word->word);
+ rest_of_args = rest_of_args->next;
+ temp->next = (WORD_LIST *)NULL;
+ dispose_words (temp);
+ }
+ else
+ dollar_vars[9] = (char *)NULL;
+ }
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/shopt.c b/builtins/shopt.c
new file mode 100644
index 0000000..7d5a398
--- /dev/null
+++ b/builtins/shopt.c
@@ -0,0 +1,677 @@
+/* shopt.c, created from shopt.def. */
+#line 22 "./shopt.def"
+
+#line 43 "./shopt.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#include "version.h"
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../flags.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#if defined (HISTORY)
+# include "../bashhist.h"
+#endif
+
+#define UNSETOPT 0
+#define SETOPT 1
+
+#define OPTFMT "%-15s\t%s\n"
+
+extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
+extern int cdable_vars, mail_warning, source_uses_path;
+extern int no_exit_on_failed_exec, print_shift_error;
+extern int check_hashed_filenames, promptvars;
+extern int cdspelling, expand_aliases;
+extern int extended_quote;
+extern int check_window_size;
+extern int glob_ignore_case, match_ignore_case;
+extern int hup_on_exit;
+extern int xpg_echo;
+extern int gnu_error_format;
+extern int check_jobs_at_exit;
+extern int autocd;
+extern int glob_star;
+
+#if defined (EXTENDED_GLOB)
+extern int extended_glob;
+#endif
+
+#if defined (READLINE)
+extern int hist_verify, history_reediting, perform_hostname_completion;
+extern int no_empty_command_completion;
+extern int force_fignore;
+extern int dircomplete_spelling;
+
+extern int enable_hostname_completion __P((int));
+#endif
+
+#if defined (PROGRAMMABLE_COMPLETION)
+extern int prog_completion_enabled;
+#endif
+
+#if defined (RESTRICTED_SHELL)
+extern char *shell_name;
+#endif
+
+#if defined (DEBUGGER)
+extern int debugging_mode;
+#endif
+
+static void shopt_error __P((char *));
+
+static int set_shellopts_after_change __P((char *, int));
+static int shopt_enable_hostname_completion __P((char *, int));
+static int set_compatibility_level __P((char *, int));
+
+#if defined (RESTRICTED_SHELL)
+static int set_restricted_shell __P((char *, int));
+#endif
+
+static int shopt_login_shell;
+static int shopt_compat31;
+static int shopt_compat32;
+static int shopt_compat40;
+
+typedef int shopt_set_func_t __P((char *, int));
+
+static struct {
+ char *name;
+ int *value;
+ shopt_set_func_t *set_func;
+} shopt_vars[] = {
+ { "autocd", &autocd, (shopt_set_func_t *)NULL },
+ { "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL },
+ { "cdspell", &cdspelling, (shopt_set_func_t *)NULL },
+ { "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL },
+#if defined (JOB_CONTROL)
+ { "checkjobs", &check_jobs_at_exit, (shopt_set_func_t *)NULL },
+#endif
+ { "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
+#if defined (HISTORY)
+ { "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
+#endif
+ { "compat31", &shopt_compat31, set_compatibility_level },
+ { "compat32", &shopt_compat32, set_compatibility_level },
+ { "compat40", &shopt_compat40, set_compatibility_level },
+#if defined (READLINE)
+ { "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL },
+#endif
+ { "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
+ { "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
+ { "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
+#if defined (DEBUGGER)
+ { "extdebug", &debugging_mode, (shopt_set_func_t *)NULL },
+#endif
+#if defined (EXTENDED_GLOB)
+ { "extglob", &extended_glob, (shopt_set_func_t *)NULL },
+#endif
+ { "extquote", &extended_quote, (shopt_set_func_t *)NULL },
+ { "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL },
+#if defined (READLINE)
+ { "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
+#endif
+ { "globstar", &glob_star, (shopt_set_func_t *)NULL },
+ { "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
+#if defined (HISTORY)
+ { "histappend", &force_append_history, (shopt_set_func_t *)NULL },
+#endif
+#if defined (READLINE)
+ { "histreedit", &history_reediting, (shopt_set_func_t *)NULL },
+ { "histverify", &hist_verify, (shopt_set_func_t *)NULL },
+ { "hostcomplete", &perform_hostname_completion, shopt_enable_hostname_completion },
+#endif
+ { "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
+ { "interactive_comments", &interactive_comments, set_shellopts_after_change },
+#if defined (HISTORY)
+ { "lithist", &literal_history, (shopt_set_func_t *)NULL },
+#endif
+ { "login_shell", &shopt_login_shell, set_login_shell },
+ { "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
+#if defined (READLINE)
+ { "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL },
+#endif
+ { "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL },
+ { "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL },
+ { "nullglob", &allow_null_glob_expansion, (shopt_set_func_t *)NULL },
+#if defined (PROGRAMMABLE_COMPLETION)
+ { "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL },
+#endif
+ { "promptvars", &promptvars, (shopt_set_func_t *)NULL },
+#if defined (RESTRICTED_SHELL)
+ { "restricted_shell", &restricted_shell, set_restricted_shell },
+#endif
+ { "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL },
+ { "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL },
+ { "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL },
+ { (char *)0, (int *)0, (shopt_set_func_t *)NULL }
+};
+
+#define N_SHOPT_OPTIONS (sizeof (shopt_vars) / sizeof (shopt_vars[0]))
+
+#define GET_SHOPT_OPTION_VALUE(i) (*shopt_vars[i].value)
+
+static const char * const on = "on";
+static const char * const off = "off";
+
+static int find_shopt __P((char *));
+static int toggle_shopts __P((int, WORD_LIST *, int));
+static void print_shopt __P((char *, int, int));
+static int list_shopts __P((WORD_LIST *, int));
+static int list_some_shopts __P((int, int));
+static int list_shopt_o_options __P((WORD_LIST *, int));
+static int list_some_o_options __P((int, int));
+static int set_shopt_o_options __P((int, WORD_LIST *, int));
+
+#define SFLAG 0x01
+#define UFLAG 0x02
+#define QFLAG 0x04
+#define OFLAG 0x08
+#define PFLAG 0x10
+
+int
+shopt_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, flags, rval;
+
+ flags = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "psuoq")) != -1)
+ {
+ switch (opt)
+ {
+ case 's':
+ flags |= SFLAG;
+ break;
+ case 'u':
+ flags |= UFLAG;
+ break;
+ case 'q':
+ flags |= QFLAG;
+ break;
+ case 'o':
+ flags |= OFLAG;
+ break;
+ case 'p':
+ flags |= PFLAG;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG))
+ {
+ builtin_error (_("cannot set and unset shell options simultaneously"));
+ return (EXECUTION_FAILURE);
+ }
+
+ rval = EXECUTION_SUCCESS;
+ if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */
+ rval = list_shopt_o_options (list, flags);
+ else if (list && (flags & OFLAG)) /* shopt -so args */
+ rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG);
+ else if (flags & OFLAG) /* shopt -so */
+ rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags);
+ else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */
+ rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG);
+ else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */
+ rval = list_shopts (list, flags);
+ else /* shopt -su */
+ rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags);
+ return (rval);
+}
+
+/* Reset the options managed by `shopt' to the values they would have at
+ shell startup. */
+void
+reset_shopt_options ()
+{
+ allow_null_glob_expansion = glob_dot_filenames = 0;
+ cdable_vars = mail_warning = 0;
+ no_exit_on_failed_exec = print_shift_error = 0;
+ check_hashed_filenames = cdspelling = expand_aliases = check_window_size = 0;
+
+ source_uses_path = promptvars = 1;
+
+#if defined (EXTENDED_GLOB)
+ extended_glob = 0;
+#endif
+
+#if defined (HISTORY)
+ literal_history = force_append_history = 0;
+ command_oriented_history = 1;
+#endif
+
+#if defined (READLINE)
+ hist_verify = history_reediting = 0;
+ perform_hostname_completion = 1;
+#endif
+
+ shopt_login_shell = login_shell;
+}
+
+static int
+find_shopt (name)
+ char *name;
+{
+ int i;
+
+ for (i = 0; shopt_vars[i].name; i++)
+ if (STREQ (name, shopt_vars[i].name))
+ return i;
+ return -1;
+}
+
+static void
+shopt_error (s)
+ char *s;
+{
+ builtin_error (_("%s: invalid shell option name"), s);
+}
+
+static int
+toggle_shopts (mode, list, quiet)
+ int mode;
+ WORD_LIST *list;
+ int quiet;
+{
+ WORD_LIST *l;
+ int ind, rval;
+
+ for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
+ {
+ ind = find_shopt (l->word->word);
+ if (ind < 0)
+ {
+ shopt_error (l->word->word);
+ rval = EXECUTION_FAILURE;
+ }
+ else
+ {
+ *shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */
+ if (shopt_vars[ind].set_func)
+ (*shopt_vars[ind].set_func) (shopt_vars[ind].name, mode);
+ }
+ }
+
+ set_bashopts ();
+ return (rval);
+}
+
+static void
+print_shopt (name, val, flags)
+ char *name;
+ int val, flags;
+{
+ if (flags & PFLAG)
+ printf ("shopt %s %s\n", val ? "-s" : "-u", name);
+ else
+ printf (OPTFMT, name, val ? on : off);
+}
+
+/* List the values of all or any of the `shopt' options. Returns 0 if
+ all were listed or all variables queried were on; 1 otherwise. */
+static int
+list_shopts (list, flags)
+ WORD_LIST *list;
+ int flags;
+{
+ WORD_LIST *l;
+ int i, val, rval;
+
+ if (list == 0)
+ {
+ for (i = 0; shopt_vars[i].name; i++)
+ {
+ val = *shopt_vars[i].value;
+ if ((flags & QFLAG) == 0)
+ print_shopt (shopt_vars[i].name, val, flags);
+ }
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+
+ for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
+ {
+ i = find_shopt (l->word->word);
+ if (i < 0)
+ {
+ shopt_error (l->word->word);
+ rval = EXECUTION_FAILURE;
+ continue;
+ }
+ val = *shopt_vars[i].value;
+ if (val == 0)
+ rval = EXECUTION_FAILURE;
+ if ((flags & QFLAG) == 0)
+ print_shopt (l->word->word, val, flags);
+ }
+
+ return (sh_chkwrite (rval));
+}
+
+static int
+list_some_shopts (mode, flags)
+ int mode, flags;
+{
+ int val, i;
+
+ for (i = 0; shopt_vars[i].name; i++)
+ {
+ val = *shopt_vars[i].value;
+ if (((flags & QFLAG) == 0) && mode == val)
+ print_shopt (shopt_vars[i].name, val, flags);
+ }
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+static int
+list_shopt_o_options (list, flags)
+ WORD_LIST *list;
+ int flags;
+{
+ WORD_LIST *l;
+ int val, rval;
+
+ if (list == 0)
+ {
+ if ((flags & QFLAG) == 0)
+ list_minus_o_opts (-1, (flags & PFLAG));
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+
+ for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
+ {
+ val = minus_o_option_value (l->word->word);
+ if (val == -1)
+ {
+ sh_invalidoptname (l->word->word);
+ rval = EXECUTION_FAILURE;
+ continue;
+ }
+ if (val == 0)
+ rval = EXECUTION_FAILURE;
+ if ((flags & QFLAG) == 0)
+ {
+ if (flags & PFLAG)
+ printf ("set %co %s\n", val ? '-' : '+', l->word->word);
+ else
+ printf (OPTFMT, l->word->word, val ? on : off);
+ }
+ }
+ return (sh_chkwrite (rval));
+}
+
+static int
+list_some_o_options (mode, flags)
+ int mode, flags;
+{
+ if ((flags & QFLAG) == 0)
+ list_minus_o_opts (mode, (flags & PFLAG));
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+static int
+set_shopt_o_options (mode, list, quiet)
+ int mode;
+ WORD_LIST *list;
+ int quiet;
+{
+ WORD_LIST *l;
+ int rval;
+
+ for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
+ {
+ if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE)
+ rval = EXECUTION_FAILURE;
+ }
+ set_shellopts ();
+ return rval;
+}
+
+/* If we set or unset interactive_comments with shopt, make sure the
+ change is reflected in $SHELLOPTS. */
+static int
+set_shellopts_after_change (option_name, mode)
+ char *option_name;
+ int mode;
+{
+ set_shellopts ();
+ return (0);
+}
+
+static int
+shopt_enable_hostname_completion (option_name, mode)
+ char *option_name;
+ int mode;
+{
+ return (enable_hostname_completion (mode));
+}
+
+static int
+set_compatibility_level (option_name, mode)
+ char *option_name;
+ int mode;
+{
+ /* Need to change logic here as we add more compatibility levels */
+
+ /* First, check option_name so we can turn off other compat options when
+ one is set. */
+ if (mode && option_name[6] == '3' && option_name[7] == '1')
+ shopt_compat32 = shopt_compat40 = 0;
+ else if (mode && option_name[6] == '3' && option_name[7] == '2')
+ shopt_compat31 = shopt_compat40 = 0;
+ else if (mode && option_name[6] == '4' && option_name[7] == '0')
+ shopt_compat31 = shopt_compat32 = 0;
+
+ /* Then set shell_compatibility_level based on what remains */
+ if (shopt_compat31)
+ shell_compatibility_level = 31;
+ else if (shopt_compat32)
+ shell_compatibility_level = 32;
+ else if (shopt_compat40)
+ shell_compatibility_level = 40;
+ else
+ shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
+ return 0;
+}
+
+#if defined (RESTRICTED_SHELL)
+/* Don't allow the value of restricted_shell to be modified. */
+
+static int
+set_restricted_shell (option_name, mode)
+ char *option_name;
+ int mode;
+{
+ static int save_restricted = -1;
+
+ if (save_restricted == -1)
+ save_restricted = shell_is_restricted (shell_name);
+
+ restricted_shell = save_restricted;
+ return (0);
+}
+#endif /* RESTRICTED_SHELL */
+
+/* Not static so shell.c can call it to initialize shopt_login_shell */
+int
+set_login_shell (option_name, mode)
+ char *option_name;
+ int mode;
+{
+ shopt_login_shell = login_shell != 0;
+ return (0);
+}
+
+char **
+get_shopt_options ()
+{
+ char **ret;
+ int n, i;
+
+ n = sizeof (shopt_vars) / sizeof (shopt_vars[0]);
+ ret = strvec_create (n + 1);
+ for (i = 0; shopt_vars[i].name; i++)
+ ret[i] = savestring (shopt_vars[i].name);
+ ret[i] = (char *)NULL;
+ return ret;
+}
+
+/*
+ * External interface for other parts of the shell. NAME is a string option;
+ * MODE is 0 if we want to unset an option; 1 if we want to set an option.
+ * REUSABLE is 1 if we want to print output in a form that may be reused.
+ */
+int
+shopt_setopt (name, mode)
+ char *name;
+ int mode;
+{
+ WORD_LIST *wl;
+ int r;
+
+ wl = add_string_to_list (name, (WORD_LIST *)NULL);
+ r = toggle_shopts (mode, wl, 0);
+ dispose_words (wl);
+ return r;
+}
+
+int
+shopt_listopt (name, reusable)
+ char *name;
+ int reusable;
+{
+ int i;
+
+ if (name == 0)
+ return (list_shopts ((WORD_LIST *)NULL, reusable ? PFLAG : 0));
+
+ i = find_shopt (name);
+ if (i < 0)
+ {
+ shopt_error (name);
+ return (EXECUTION_FAILURE);
+ }
+
+ print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0);
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+void
+set_bashopts ()
+{
+ char *value;
+ char tflag[N_SHOPT_OPTIONS];
+ int vsize, i, vptr, *ip, exported;
+ SHELL_VAR *v;
+
+ for (vsize = i = 0; shopt_vars[i].name; i++)
+ {
+ tflag[i] = 0;
+ if (GET_SHOPT_OPTION_VALUE (i))
+ {
+ vsize += strlen (shopt_vars[i].name) + 1;
+ tflag[i] = 1;
+ }
+ }
+
+ value = (char *)xmalloc (vsize + 1);
+
+ for (i = vptr = 0; shopt_vars[i].name; i++)
+ {
+ if (tflag[i])
+ {
+ strcpy (value + vptr, shopt_vars[i].name);
+ vptr += strlen (shopt_vars[i].name);
+ value[vptr++] = ':';
+ }
+ }
+
+ if (vptr)
+ vptr--; /* cut off trailing colon */
+ value[vptr] = '\0';
+
+ v = find_variable ("BASHOPTS");
+
+ /* Turn off the read-only attribute so we can bind the new value, and
+ note whether or not the variable was exported. */
+ if (v)
+ {
+ VUNSETATTR (v, att_readonly);
+ exported = exported_p (v);
+ }
+ else
+ exported = 0;
+
+ v = bind_variable ("BASHOPTS", value, 0);
+
+ /* Turn the read-only attribute back on, and turn off the export attribute
+ if it was set implicitly by mark_modified_vars and SHELLOPTS was not
+ exported before we bound the new value. */
+ VSETATTR (v, att_readonly);
+ if (mark_modified_vars && exported == 0 && exported_p (v))
+ VUNSETATTR (v, att_exported);
+
+ free (value);
+}
+
+void
+parse_bashopts (value)
+ char *value;
+{
+ char *vname;
+ int vptr, ind;
+
+ vptr = 0;
+ while (vname = extract_colon_unit (value, &vptr))
+ {
+ ind = find_shopt (vname);
+ if (ind >= 0)
+ *shopt_vars[ind].value = 1;
+ free (vname);
+ }
+}
+
+void
+initialize_bashopts (no_bashopts)
+ int no_bashopts;
+{
+ char *temp;
+ SHELL_VAR *var;
+
+ if (no_bashopts == 0)
+ {
+ var = find_variable ("BASHOPTS");
+ /* set up any shell options we may have inherited. */
+ if (var && imported_p (var))
+ {
+ temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
+ if (temp)
+ {
+ parse_bashopts (temp);
+ free (temp);
+ }
+ }
+ }
+
+ /* Set up the $BASHOPTS variable. */
+ set_bashopts ();
+}
diff --git a/builtins/source.c b/builtins/source.c
new file mode 100644
index 0000000..2926553
--- /dev/null
+++ b/builtins/source.c
@@ -0,0 +1,144 @@
+/* source.c, created from source.def. */
+#line 22 "./source.def"
+
+#line 37 "./source.def"
+
+#line 53 "./source.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include "posixstat.h"
+#include "filecntl.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+#include <errno.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../flags.h"
+#include "../findcmd.h"
+#include "common.h"
+#include "bashgetopt.h"
+#include "../trap.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+extern int posixly_correct;
+
+static void maybe_pop_dollar_vars __P((void));
+
+/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
+int source_uses_path = 1;
+
+/* If non-zero, `.' looks in the current directory if the filename argument
+ is not found in the $PATH. */
+int source_searches_cwd = 1;
+
+/* If this . script is supplied arguments, we save the dollar vars and
+ replace them with the script arguments for the duration of the script's
+ execution. If the script does not change the dollar vars, we restore
+ what we saved. If the dollar vars are changed in the script, and we are
+ not executing a shell function, we leave the new values alone and free
+ the saved values. */
+static void
+maybe_pop_dollar_vars ()
+{
+ if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
+ dispose_saved_dollar_vars ();
+ else
+ pop_dollar_vars ();
+ if (debugging_mode)
+ pop_args (); /* restore BASH_ARGC and BASH_ARGV */
+ set_dollar_vars_unchanged ();
+}
+
+/* Read and execute commands from the file passed as argument. Guess what.
+ This cannot be done in a subshell, since things like variable assignments
+ take place in there. So, I open the file, place it into a large string,
+ close the file, and then execute the string. */
+int
+source_builtin (list)
+ WORD_LIST *list;
+{
+ int result;
+ char *filename, *debug_trap;
+
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
+
+ if (list == 0)
+ {
+ builtin_error (_("filename argument required"));
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted && strchr (list->word->word, '/'))
+ {
+ sh_restricted (list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+#endif
+
+ filename = (char *)NULL;
+ /* XXX -- should this be absolute_pathname? */
+ if (posixly_correct && strchr (list->word->word, '/'))
+ filename = savestring (list->word->word);
+ else if (absolute_pathname (list->word->word))
+ filename = savestring (list->word->word);
+ else if (source_uses_path)
+ filename = find_path_file (list->word->word);
+ if (filename == 0)
+ {
+ if (source_searches_cwd == 0)
+ {
+ builtin_error (_("%s: file not found"), list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ filename = savestring (list->word->word);
+ }
+
+ begin_unwind_frame ("source");
+ add_unwind_protect ((Function *)xfree, filename);
+
+ if (list->next)
+ {
+ push_dollar_vars ();
+ add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
+ remember_args (list->next, 1);
+ if (debugging_mode)
+ push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
+ }
+ set_dollar_vars_unchanged ();
+
+ /* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
+ is set. XXX - should sourced files inherit the RETURN trap? Functions
+ don't. */
+ debug_trap = TRAP_STRING (DEBUG_TRAP);
+ if (debug_trap && function_trace_mode == 0)
+ {
+ debug_trap = savestring (debug_trap);
+ add_unwind_protect (xfree, debug_trap);
+ add_unwind_protect (set_debug_trap, debug_trap);
+ restore_default_signal (DEBUG_TRAP);
+ }
+
+ result = source_file (filename, (list && list->next));
+
+ run_unwind_frame ("source");
+
+ return (result);
+}
diff --git a/builtins/suspend.c b/builtins/suspend.c
new file mode 100644
index 0000000..93ce68e
--- /dev/null
+++ b/builtins/suspend.c
@@ -0,0 +1,94 @@
+/* suspend.c, created from suspend.def. */
+#line 22 "./suspend.def"
+
+#line 38 "./suspend.def"
+
+#include <config.h>
+
+#if defined (JOB_CONTROL)
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include <signal.h>
+#include "../bashintl.h"
+#include "../shell.h"
+#include "../jobs.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+static sighandler suspend_continue __P((int));
+
+static SigHandler *old_cont;
+#if 0
+static SigHandler *old_stop;
+#endif
+
+/* Continue handler. */
+static sighandler
+suspend_continue (sig)
+ int sig;
+{
+ set_signal_handler (SIGCONT, old_cont);
+#if 0
+ set_signal_handler (SIGSTOP, old_stop);
+#endif
+ SIGRETURN (0);
+}
+
+/* Suspending the shell. If -f is the arg, then do the suspend
+ no matter what. Otherwise, complain if a login shell. */
+int
+suspend_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, force;
+
+ reset_internal_getopt ();
+ force = 0;
+ while ((opt = internal_getopt (list, "f")) != -1)
+ switch (opt)
+ {
+ case 'f':
+ force++;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ list = loptend;
+
+ if (job_control == 0)
+ {
+ sh_nojobs (_("cannot suspend"));
+ return (EXECUTION_FAILURE);
+ }
+
+ if (force == 0)
+ {
+ no_args (list);
+
+ if (login_shell)
+ {
+ builtin_error (_("cannot suspend a login shell"));
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ /* XXX - should we put ourselves back into the original pgrp now? If so,
+ call end_job_control() here and do the right thing in suspend_continue
+ (that is, call restart_job_control()). */
+ old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
+#if 0
+ old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL);
+#endif
+ killpg (shell_pgrp, SIGSTOP);
+ return (EXECUTION_SUCCESS);
+}
+
+#endif /* JOB_CONTROL */
diff --git a/builtins/test.c b/builtins/test.c
new file mode 100644
index 0000000..e893bee
--- /dev/null
+++ b/builtins/test.c
@@ -0,0 +1,53 @@
+/* test.c, created from test.def. */
+#line 22 "./test.def"
+
+#line 98 "./test.def"
+
+#line 108 "./test.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../test.h"
+#include "common.h"
+
+extern char *this_command_name;
+
+/* TEST/[ builtin. */
+int
+test_builtin (list)
+ WORD_LIST *list;
+{
+ char **argv;
+ int argc, result;
+
+ /* We let Matthew Bradburn and Kevin Braunsdorf's code do the
+ actual test command. So turn the list of args into an array
+ of strings, since that is what their code wants. */
+ if (list == 0)
+ {
+ if (this_command_name[0] == '[' && !this_command_name[1])
+ {
+ builtin_error (_("missing `]'"));
+ return (EX_BADUSAGE);
+ }
+
+ return (EXECUTION_FAILURE);
+ }
+
+ argv = make_builtin_argv (list, &argc);
+ result = test_command (argc, argv);
+ free ((char *)argv);
+
+ return (result);
+}
diff --git a/builtins/times.c b/builtins/times.c
new file mode 100644
index 0000000..4e8b490
--- /dev/null
+++ b/builtins/times.c
@@ -0,0 +1,90 @@
+/* times.c, created from times.def. */
+#line 22 "./times.def"
+
+#line 34 "./times.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "../bashtypes.h"
+#include "../shell.h"
+
+#include <posixtime.h>
+
+#if defined (HAVE_SYS_TIMES_H)
+# include <sys/times.h>
+#endif /* HAVE_SYS_TIMES_H */
+
+#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE)
+# include <sys/resource.h>
+#endif
+
+#include "common.h"
+
+/* Print the totals for system and user time used. */
+int
+times_builtin (list)
+ WORD_LIST *list;
+{
+#if defined (HAVE_GETRUSAGE) && defined (HAVE_TIMEVAL) && defined (RUSAGE_SELF)
+ struct rusage self, kids;
+
+ USE_VAR(list);
+
+ if (no_options (list))
+ return (EX_USAGE);
+
+ getrusage (RUSAGE_SELF, &self);
+ getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */
+
+ print_timeval (stdout, &self.ru_utime);
+ putchar (' ');
+ print_timeval (stdout, &self.ru_stime);
+ putchar ('\n');
+ print_timeval (stdout, &kids.ru_utime);
+ putchar (' ');
+ print_timeval (stdout, &kids.ru_stime);
+ putchar ('\n');
+
+#else
+# if defined (HAVE_TIMES)
+ /* This uses the POSIX.1/XPG5 times(2) interface, which fills in a
+ `struct tms' with values of type clock_t. */
+ struct tms t;
+
+ USE_VAR(list);
+
+ if (no_options (list))
+ return (EX_USAGE);
+
+ times (&t);
+
+ print_clock_t (stdout, t.tms_utime);
+ putchar (' ');
+ print_clock_t (stdout, t.tms_stime);
+ putchar ('\n');
+ print_clock_t (stdout, t.tms_cutime);
+ putchar (' ');
+ print_clock_t (stdout, t.tms_cstime);
+ putchar ('\n');
+
+# else /* !HAVE_TIMES */
+
+ USE_VAR(list);
+
+ if (no_options (list))
+ return (EX_USAGE);
+ printf ("0.00 0.00\n0.00 0.00\n");
+
+# endif /* HAVE_TIMES */
+#endif /* !HAVE_TIMES */
+
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
diff --git a/builtins/trap.c b/builtins/trap.c
new file mode 100644
index 0000000..f12fae4
--- /dev/null
+++ b/builtins/trap.c
@@ -0,0 +1,231 @@
+/* trap.c, created from trap.def. */
+#line 22 "./trap.def"
+
+#line 54 "./trap.def"
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# ifdef _MINIX
+# include <sys/types.h>
+# endif
+# include <unistd.h>
+#endif
+
+#include "../bashtypes.h"
+#include <signal.h>
+#include <stdio.h>
+#include "../bashansi.h"
+
+#include "../shell.h"
+#include "../trap.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+static void showtrap __P((int));
+static int display_traps __P((WORD_LIST *));
+
+/* The trap command:
+
+ trap <arg> <signal ...>
+ trap <signal ...>
+ trap -l
+ trap -p [sigspec ...]
+ trap [--]
+
+ Set things up so that ARG is executed when SIGNAL(s) N is recieved.
+ If ARG is the empty string, then ignore the SIGNAL(s). If there is
+ no ARG, then set the trap for SIGNAL(s) to its original value. Just
+ plain "trap" means to print out the list of commands associated with
+ each signal number. Single arg of "-l" means list the signal names. */
+
+/* Possible operations to perform on the list of signals.*/
+#define SET 0 /* Set this signal to first_arg. */
+#define REVERT 1 /* Revert to this signals original value. */
+#define IGNORE 2 /* Ignore this signal. */
+
+extern int posixly_correct;
+
+int
+trap_builtin (list)
+ WORD_LIST *list;
+{
+ int list_signal_names, display, result, opt;
+
+ list_signal_names = display = 0;
+ result = EXECUTION_SUCCESS;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "lp")) != -1)
+ {
+ switch (opt)
+ {
+ case 'l':
+ list_signal_names++;
+ break;
+ case 'p':
+ display++;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */
+
+ if (list_signal_names)
+ return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
+ else if (display || list == 0)
+ return (sh_chkwrite (display_traps (list)));
+ else
+ {
+ char *first_arg;
+ int operation, sig, first_signal;
+
+ operation = SET;
+ first_arg = list->word->word;
+ first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
+
+ /* Backwards compatibility. XXX - question about whether or not we
+ should throw an error if an all-digit argument doesn't correspond
+ to a valid signal number (e.g., if it's `50' on a system with only
+ 32 signals). */
+ if (first_signal)
+ operation = REVERT;
+ /* When in posix mode, the historical behavior of looking for a
+ missing first argument is disabled. To revert to the original
+ signal handling disposition, use `-' as the first argument. */
+ else if (posixly_correct == 0 && first_arg && *first_arg &&
+ (*first_arg != '-' || first_arg[1]) &&
+ signal_object_p (first_arg, opt) && list->next == 0)
+ operation = REVERT;
+ else
+ {
+ list = list->next;
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ else if (*first_arg == '\0')
+ operation = IGNORE;
+ else if (first_arg[0] == '-' && !first_arg[1])
+ operation = REVERT;
+ }
+
+ while (list)
+ {
+ sig = decode_signal (list->word->word, opt);
+
+ if (sig == NO_SIG)
+ {
+ sh_invalidsig (list->word->word);
+ result = EXECUTION_FAILURE;
+ }
+ else
+ {
+ switch (operation)
+ {
+ case SET:
+ set_signal (sig, first_arg);
+ break;
+
+ case REVERT:
+ restore_default_signal (sig);
+
+ /* Signals that the shell treats specially need special
+ handling. */
+ switch (sig)
+ {
+ case SIGINT:
+ if (interactive)
+ set_signal_handler (SIGINT, sigint_sighandler);
+ else
+ set_signal_handler (SIGINT, termsig_sighandler);
+ break;
+
+ case SIGQUIT:
+ /* Always ignore SIGQUIT. */
+ set_signal_handler (SIGQUIT, SIG_IGN);
+ break;
+ case SIGTERM:
+#if defined (JOB_CONTROL)
+ case SIGTTIN:
+ case SIGTTOU:
+ case SIGTSTP:
+#endif /* JOB_CONTROL */
+ if (interactive)
+ set_signal_handler (sig, SIG_IGN);
+ break;
+ }
+ break;
+
+ case IGNORE:
+ ignore_signal (sig);
+ break;
+ }
+ }
+ list = list->next;
+ }
+ }
+
+ return (result);
+}
+
+static void
+showtrap (i)
+ int i;
+{
+ char *t, *p, *sn;
+
+ p = trap_list[i];
+ if (p == (char *)DEFAULT_SIG)
+ return;
+
+ t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
+ sn = signal_name (i);
+ /* Make sure that signals whose names are unknown (for whatever reason)
+ are printed as signal numbers. */
+ if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
+ printf ("trap -- %s %d\n", t ? t : "''", i);
+ else if (posixly_correct)
+ {
+ if (STREQN (sn, "SIG", 3))
+ printf ("trap -- %s %s\n", t ? t : "''", sn+3);
+ else
+ printf ("trap -- %s %s\n", t ? t : "''", sn);
+ }
+ else
+ printf ("trap -- %s %s\n", t ? t : "''", sn);
+
+ FREE (t);
+}
+
+static int
+display_traps (list)
+ WORD_LIST *list;
+{
+ int result, i;
+
+ if (list == 0)
+ {
+ for (i = 0; i < BASH_NSIG; i++)
+ showtrap (i);
+ return (EXECUTION_SUCCESS);
+ }
+
+ for (result = EXECUTION_SUCCESS; list; list = list->next)
+ {
+ i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
+ if (i == NO_SIG)
+ {
+ sh_invalidsig (list->word->word);
+ result = EXECUTION_FAILURE;
+ }
+ else
+ showtrap (i);
+ }
+
+ return (result);
+}
diff --git a/builtins/type.c b/builtins/type.c
new file mode 100644
index 0000000..7fcd397
--- /dev/null
+++ b/builtins/type.c
@@ -0,0 +1,356 @@
+/* type.c, created from type.def. */
+#line 22 "./type.def"
+
+#line 52 "./type.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include "../bashansi.h"
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "../findcmd.h"
+#include "../hashcmd.h"
+
+#if defined (ALIAS)
+#include "../alias.h"
+#endif /* ALIAS */
+
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int find_reserved_word __P((char *));
+
+extern char *this_command_name;
+extern int expand_aliases, posixly_correct;
+
+/* For each word in LIST, find out what the shell is going to do with
+ it as a simple command. i.e., which file would this shell use to
+ execve, or if it is a builtin command, or an alias. Possible flag
+ arguments:
+ -t Returns the "type" of the object, one of
+ `alias', `keyword', `function', `builtin',
+ or `file'.
+
+ -p Returns the pathname of the file if -type is
+ a file.
+
+ -a Returns all occurrences of words, whether they
+ be a filename in the path, alias, function,
+ or builtin.
+
+ -f Suppress shell function lookup, like `command'.
+
+ -P Force a path search even in the presence of other
+ definitions.
+
+ Order of evaluation:
+ alias
+ keyword
+ function
+ builtin
+ file
+ */
+
+int
+type_builtin (list)
+ WORD_LIST *list;
+{
+ int dflags, any_failed, opt;
+ WORD_LIST *this;
+
+ if (list == 0)
+ return (EXECUTION_SUCCESS);
+
+ dflags = CDESC_SHORTDESC; /* default */
+ any_failed = 0;
+
+ /* Handle the obsolescent `-type', `-path', and `-all' by prescanning
+ the arguments and converting those options to the form that
+ internal_getopt recognizes. Converts `--type', `--path', and `--all'
+ also. THIS SHOULD REALLY GO AWAY. */
+ for (this = list; this && this->word->word[0] == '-'; this = this->next)
+ {
+ char *flag = &(this->word->word[1]);
+
+ if (STREQ (flag, "type") || STREQ (flag, "-type"))
+ {
+ this->word->word[1] = 't';
+ this->word->word[2] = '\0';
+ }
+ else if (STREQ (flag, "path") || STREQ (flag, "-path"))
+ {
+ this->word->word[1] = 'p';
+ this->word->word[2] = '\0';
+ }
+ else if (STREQ (flag, "all") || STREQ (flag, "-all"))
+ {
+ this->word->word[1] = 'a';
+ this->word->word[2] = '\0';
+ }
+ }
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "afptP")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ dflags |= CDESC_ALL;
+ break;
+ case 'f':
+ dflags |= CDESC_NOFUNCS;
+ break;
+ case 'p':
+ dflags |= CDESC_PATH_ONLY;
+ dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
+ break;
+ case 't':
+ dflags |= CDESC_TYPE;
+ dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
+ break;
+ case 'P': /* shorthand for type -ap */
+ dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
+ dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ while (list)
+ {
+ int found;
+
+ found = describe_command (list->word->word, dflags);
+
+ if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
+ sh_notfound (list->word->word);
+
+ any_failed += found == 0;
+ list = list->next;
+ }
+
+ opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
+ return (sh_chkwrite (opt));
+}
+
+/*
+ * Describe COMMAND as required by the type and command builtins.
+ *
+ * Behavior is controlled by DFLAGS. Flag values are
+ * CDESC_ALL print all descriptions of a command
+ * CDESC_SHORTDESC print the description for type and command -V
+ * CDESC_REUSABLE print in a format that may be reused as input
+ * CDESC_TYPE print the type for type -t
+ * CDESC_PATH_ONLY print the path for type -p
+ * CDESC_FORCE_PATH force a path search for type -P
+ * CDESC_NOFUNCS skip function lookup for type -f
+ * CDESC_ABSPATH convert to absolute path, no ./ prefix
+ *
+ * CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
+ * return after finding it once.
+ */
+int
+describe_command (command, dflags)
+ char *command;
+ int dflags;
+{
+ int found, i, found_file, f, all;
+ char *full_path, *x;
+ SHELL_VAR *func;
+#if defined (ALIAS)
+ alias_t *alias;
+#endif
+
+ all = (dflags & CDESC_ALL) != 0;
+ found = found_file = 0;
+ full_path = (char *)NULL;
+
+#if defined (ALIAS)
+ /* Command is an alias? */
+ if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
+ {
+ if (dflags & CDESC_TYPE)
+ puts ("alias");
+ else if (dflags & CDESC_SHORTDESC)
+ printf (_("%s is aliased to `%s'\n"), command, alias->value);
+ else if (dflags & CDESC_REUSABLE)
+ {
+ x = sh_single_quote (alias->value);
+ printf ("alias %s=%s\n", command, x);
+ free (x);
+ }
+
+ found = 1;
+
+ if (all == 0)
+ return (1);
+ }
+#endif /* ALIAS */
+
+ /* Command is a shell reserved word? */
+ if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
+ {
+ if (dflags & CDESC_TYPE)
+ puts ("keyword");
+ else if (dflags & CDESC_SHORTDESC)
+ printf (_("%s is a shell keyword\n"), command);
+ else if (dflags & CDESC_REUSABLE)
+ printf ("%s\n", command);
+
+ found = 1;
+
+ if (all == 0)
+ return (1);
+ }
+
+ /* Command is a function? */
+ if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
+ {
+ if (dflags & CDESC_TYPE)
+ puts ("function");
+ else if (dflags & CDESC_SHORTDESC)
+ {
+ char *result;
+
+ printf (_("%s is a function\n"), command);
+
+ /* We're blowing away THE_PRINTED_COMMAND here... */
+
+ result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL);
+ printf ("%s\n", result);
+ }
+ else if (dflags & CDESC_REUSABLE)
+ printf ("%s\n", command);
+
+ found = 1;
+
+ if (all == 0)
+ return (1);
+ }
+
+ /* Command is a builtin? */
+ if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
+ {
+ if (dflags & CDESC_TYPE)
+ puts ("builtin");
+ else if (dflags & CDESC_SHORTDESC)
+ printf (_("%s is a shell builtin\n"), command);
+ else if (dflags & CDESC_REUSABLE)
+ printf ("%s\n", command);
+
+ found = 1;
+
+ if (all == 0)
+ return (1);
+ }
+
+ /* Command is a disk file? */
+ /* If the command name given is already an absolute command, just
+ check to see if it is executable. */
+ if (absolute_program (command))
+ {
+ f = file_status (command);
+ if (f & FS_EXECABLE)
+ {
+ if (dflags & CDESC_TYPE)
+ puts ("file");
+ else if (dflags & CDESC_SHORTDESC)
+ printf (_("%s is %s\n"), command, command);
+ else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
+ printf ("%s\n", command);
+
+ /* There's no use looking in the hash table or in $PATH,
+ because they're not consulted when an absolute program
+ name is supplied. */
+ return (1);
+ }
+ }
+
+ /* If the user isn't doing "-a", then we might care about
+ whether the file is present in our hash table. */
+ if (all == 0 || (dflags & CDESC_FORCE_PATH))
+ {
+ if (full_path = phash_search (command))
+ {
+ if (dflags & CDESC_TYPE)
+ puts ("file");
+ else if (dflags & CDESC_SHORTDESC)
+ printf (_("%s is hashed (%s)\n"), command, full_path);
+ else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
+ printf ("%s\n", full_path);
+
+ free (full_path);
+ return (1);
+ }
+ }
+
+ /* Now search through $PATH. */
+ while (1)
+ {
+ if (all == 0)
+ full_path = find_user_command (command);
+ else
+ full_path =
+ user_command_matches (command, FS_EXEC_ONLY, found_file);
+ /* XXX - should that be FS_EXEC_PREFERRED? */
+
+ if (!full_path)
+ break;
+
+ /* If we found the command as itself by looking through $PATH, it
+ probably doesn't exist. Check whether or not the command is an
+ executable file. If it's not, don't report a match. This is
+ the default posix mode behavior */
+ if (STREQ (full_path, command) || posixly_correct)
+ {
+ f = file_status (full_path);
+ if ((f & FS_EXECABLE) == 0)
+ {
+ free (full_path);
+ full_path = (char *)NULL;
+ if (all == 0)
+ break;
+ }
+ else if (ABSPATH (full_path))
+ ; /* placeholder; don't need to do anything yet */
+ else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
+ {
+ f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
+ full_path = sh_makepath ((char *)NULL, full_path, f);
+ }
+ }
+ /* If we require a full path and don't have one, make one */
+ else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
+ full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
+
+ found_file++;
+ found = 1;
+
+ if (dflags & CDESC_TYPE)
+ puts ("file");
+ else if (dflags & CDESC_SHORTDESC)
+ printf (_("%s is %s\n"), command, full_path);
+ else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
+ printf ("%s\n", full_path);
+
+ free (full_path);
+ full_path = (char *)NULL;
+
+ if (all == 0)
+ break;
+ }
+
+ return (found);
+}
diff --git a/builtins/ulimit.c b/builtins/ulimit.c
new file mode 100644
index 0000000..44f0b34
--- /dev/null
+++ b/builtins/ulimit.c
@@ -0,0 +1,710 @@
+/* ulimit.c, created from ulimit.def. */
+#line 22 "./ulimit.def"
+
+#line 67 "./ulimit.def"
+
+#if !defined (_MINIX)
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#ifndef _MINIX
+# include <sys/param.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+#include "pipesize.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+/* For some reason, HPUX chose to make these definitions visible only if
+ _KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
+ and #undef it afterward. */
+#if defined (HAVE_RESOURCE)
+# include <sys/time.h>
+# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
+# define _KERNEL
+# endif
+# include <sys/resource.h>
+# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
+# undef _KERNEL
+# endif
+#elif defined (HAVE_SYS_TIMES_H)
+# include <sys/times.h>
+#endif
+
+#if defined (HAVE_LIMITS_H)
+# include <limits.h>
+#endif
+
+/* Check for the most basic symbols. If they aren't present, this
+ system's <sys/resource.h> isn't very useful to us. */
+#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
+# undef HAVE_RESOURCE
+#endif
+
+#if !defined (RLIMTYPE)
+# define RLIMTYPE long
+# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
+# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
+#endif
+
+/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
+#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
+# define RLIMIT_NOFILE RLIMIT_OFILE
+#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
+
+/* Some systems have these, some do not. */
+#ifdef RLIMIT_FSIZE
+# define RLIMIT_FILESIZE RLIMIT_FSIZE
+#else
+# define RLIMIT_FILESIZE 256
+#endif
+
+#define RLIMIT_PIPESIZE 257
+
+#ifdef RLIMIT_NOFILE
+# define RLIMIT_OPENFILES RLIMIT_NOFILE
+#else
+# define RLIMIT_OPENFILES 258
+#endif
+
+#ifdef RLIMIT_VMEM
+# define RLIMIT_VIRTMEM RLIMIT_VMEM
+# define RLIMIT_VMBLKSZ 1024
+#else
+# ifdef RLIMIT_AS
+# define RLIMIT_VIRTMEM RLIMIT_AS
+# define RLIMIT_VMBLKSZ 1024
+# else
+# define RLIMIT_VIRTMEM 259
+# define RLIMIT_VMBLKSZ 1
+# endif
+#endif
+
+#ifdef RLIMIT_NPROC
+# define RLIMIT_MAXUPROC RLIMIT_NPROC
+#else
+# define RLIMIT_MAXUPROC 260
+#endif
+
+#if !defined (RLIM_INFINITY)
+# define RLIM_INFINITY 0x7fffffff
+#endif
+
+#if !defined (RLIM_SAVED_CUR)
+# define RLIM_SAVED_CUR RLIM_INFINITY
+#endif
+
+#if !defined (RLIM_SAVED_MAX)
+# define RLIM_SAVED_MAX RLIM_INFINITY
+#endif
+
+#define LIMIT_HARD 0x01
+#define LIMIT_SOFT 0x02
+
+/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
+ otherwise. */
+#define POSIXBLK -2
+
+#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
+
+extern int posixly_correct;
+
+static int _findlim __P((int));
+
+static int ulimit_internal __P((int, char *, int, int));
+
+static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *));
+static int set_limit __P((int, RLIMTYPE, int));
+
+static void printone __P((int, RLIMTYPE, int));
+static void print_all_limits __P((int));
+
+static int set_all_limits __P((int, RLIMTYPE));
+
+static int filesize __P((RLIMTYPE *));
+static int pipesize __P((RLIMTYPE *));
+static int getmaxuprc __P((RLIMTYPE *));
+static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *));
+
+typedef struct {
+ int option; /* The ulimit option for this limit. */
+ int parameter; /* Parameter to pass to get_limit (). */
+ int block_factor; /* Blocking factor for specific limit. */
+ const char * const description; /* Descriptive string to output. */
+ const char * const units; /* scale */
+} 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, POSIXBLK, "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 },
+#endif
+ { 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
+#ifdef RLIMIT_SIGPENDING
+ { 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
+#endif
+#ifdef RLIMIT_MEMLOCK
+ { 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
+#endif
+#ifdef RLIMIT_RSS
+ { 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" },
+#endif /* RLIMIT_RSS */
+ { 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL},
+ { 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
+#ifdef RLIMIT_MSGQUEUE
+ { 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
+#endif
+#ifdef RLIMIT_RTPRIO
+ { 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL },
+#endif
+#ifdef RLIMIT_STACK
+ { 's', RLIMIT_STACK, 1024, "stack size", "kbytes" },
+#endif
+#ifdef RLIMIT_CPU
+ { 't', RLIMIT_CPU, 1, "cpu time", "seconds" },
+#endif /* RLIMIT_CPU */
+ { 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL },
+#if defined (HAVE_RESOURCE)
+ { 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
+#endif
+#ifdef RLIMIT_SWAP
+ { 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" },
+#endif
+#ifdef RLIMIT_LOCKS
+ { 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
+#endif
+ { -1, -1, -1, (char *)NULL, (char *)NULL }
+};
+#define NCMDS (sizeof(limits) / sizeof(limits[0]))
+
+typedef struct _cmd {
+ int cmd;
+ char *arg;
+} ULCMD;
+
+static ULCMD *cmdlist;
+static int ncmd;
+static int cmdlistsz;
+
+#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
+long
+ulimit (cmd, newlim)
+ int cmd;
+ long newlim;
+{
+ errno = EINVAL;
+ return -1;
+}
+#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
+
+static int
+_findlim (opt)
+ int opt;
+{
+ register int i;
+
+ for (i = 0; limits[i].option > 0; i++)
+ if (limits[i].option == opt)
+ return i;
+ return -1;
+}
+
+static char optstring[4 + 2 * NCMDS];
+
+/* Report or set limits associated with certain per-process resources.
+ See the help documentation in builtins.c for a full description. */
+int
+ulimit_builtin (list)
+ register WORD_LIST *list;
+{
+ register char *s;
+ int c, limind, mode, opt, all_limits;
+
+ mode = 0;
+
+ all_limits = 0;
+
+ /* Idea stolen from pdksh -- build option string the first time called. */
+ if (optstring[0] == 0)
+ {
+ s = optstring;
+ *s++ = 'a'; *s++ = 'S'; *s++ = 'H';
+ for (c = 0; limits[c].option > 0; c++)
+ {
+ *s++ = limits[c].option;
+ *s++ = ';';
+ }
+ *s = '\0';
+ }
+
+ /* Initialize the command list. */
+ if (cmdlistsz == 0)
+ cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
+ ncmd = 0;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, optstring)) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ all_limits++;
+ break;
+
+ /* -S and -H are modifiers, not real options. */
+ case 'S':
+ mode |= LIMIT_SOFT;
+ break;
+
+ case 'H':
+ mode |= LIMIT_HARD;
+ break;
+
+ case '?':
+ builtin_usage ();
+ return (EX_USAGE);
+
+ default:
+ if (ncmd >= cmdlistsz)
+ cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
+ cmdlist[ncmd].cmd = opt;
+ cmdlist[ncmd++].arg = list_optarg;
+ break;
+ }
+ }
+ list = loptend;
+
+ if (all_limits)
+ {
+#ifdef NOTYET
+ if (list) /* setting */
+ {
+ if (STREQ (list->word->word, "unlimited") == 0)
+ {
+ builtin_error (_("%s: invalid limit argument"), list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
+ }
+#endif
+ print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+ }
+
+ /* default is `ulimit -f' */
+ if (ncmd == 0)
+ {
+ cmdlist[ncmd].cmd = 'f';
+ /* `ulimit something' is same as `ulimit -f something' */
+ cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
+ if (list)
+ list = list->next;
+ }
+
+ /* verify each command in the list. */
+ for (c = 0; c < ncmd; c++)
+ {
+ limind = _findlim (cmdlist[c].cmd);
+ if (limind == -1)
+ {
+ builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
+ return (EX_USAGE);
+ }
+ }
+
+ for (c = 0; c < ncmd; c++)
+ if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
+ return (EXECUTION_FAILURE);
+
+ return (EXECUTION_SUCCESS);
+}
+
+static int
+ulimit_internal (cmd, cmdarg, mode, multiple)
+ int cmd;
+ char *cmdarg;
+ int mode, multiple;
+{
+ int opt, limind, setting;
+ int block_factor;
+ RLIMTYPE soft_limit, hard_limit, real_limit, limit;
+
+ setting = cmdarg != 0;
+ limind = _findlim (cmd);
+ if (mode == 0)
+ mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
+ opt = get_limit (limind, &soft_limit, &hard_limit);
+ if (opt < 0)
+ {
+ builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
+ strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+
+ if (setting == 0) /* print the value of the specified limit */
+ {
+ printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
+ return (EXECUTION_SUCCESS);
+ }
+
+ /* Setting the limit. */
+ if (STREQ (cmdarg, "hard"))
+ real_limit = hard_limit;
+ else if (STREQ (cmdarg, "soft"))
+ real_limit = soft_limit;
+ else if (STREQ (cmdarg, "unlimited"))
+ real_limit = RLIM_INFINITY;
+ else if (all_digits (cmdarg))
+ {
+ limit = string_to_rlimtype (cmdarg);
+ block_factor = BLOCKSIZE(limits[limind].block_factor);
+ real_limit = limit * block_factor;
+
+ if ((real_limit / block_factor) != limit)
+ {
+ sh_erange (cmdarg, _("limit"));
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else
+ {
+ sh_invalidnum (cmdarg);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (set_limit (limind, real_limit, mode) < 0)
+ {
+ builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
+ strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+
+ return (EXECUTION_SUCCESS);
+}
+
+static int
+get_limit (ind, softlim, hardlim)
+ int ind;
+ RLIMTYPE *softlim, *hardlim;
+{
+ RLIMTYPE value;
+#if defined (HAVE_RESOURCE)
+ struct rlimit limit;
+#endif
+
+ if (limits[ind].parameter >= 256)
+ {
+ switch (limits[ind].parameter)
+ {
+ case RLIMIT_FILESIZE:
+ if (filesize (&value) < 0)
+ return -1;
+ break;
+ case RLIMIT_PIPESIZE:
+ if (pipesize (&value) < 0)
+ return -1;
+ break;
+ case RLIMIT_OPENFILES:
+ value = (RLIMTYPE)getdtablesize ();
+ break;
+ case RLIMIT_VIRTMEM:
+ return (getmaxvm (softlim, hardlim));
+ case RLIMIT_MAXUPROC:
+ if (getmaxuprc (&value) < 0)
+ return -1;
+ break;
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ *softlim = *hardlim = value;
+ return (0);
+ }
+ else
+ {
+#if defined (HAVE_RESOURCE)
+ if (getrlimit (limits[ind].parameter, &limit) < 0)
+ return -1;
+ *softlim = limit.rlim_cur;
+ *hardlim = limit.rlim_max;
+# if defined (HPUX9)
+ if (limits[ind].parameter == RLIMIT_FILESIZE)
+ {
+ *softlim *= 512;
+ *hardlim *= 512; /* Ugh. */
+ }
+ else
+# endif /* HPUX9 */
+ return 0;
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+ }
+}
+
+static int
+set_limit (ind, newlim, mode)
+ int ind;
+ RLIMTYPE newlim;
+ int mode;
+{
+#if defined (HAVE_RESOURCE)
+ struct rlimit limit;
+ RLIMTYPE val;
+#endif
+
+ if (limits[ind].parameter >= 256)
+ switch (limits[ind].parameter)
+ {
+ case RLIMIT_FILESIZE:
+#if !defined (HAVE_RESOURCE)
+ return (ulimit (2, newlim / 512L));
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+
+ case RLIMIT_OPENFILES:
+#if defined (HAVE_SETDTABLESIZE)
+# if defined (__CYGWIN__)
+ /* Grrr... Cygwin declares setdtablesize as void. */
+ setdtablesize (newlim);
+ return 0;
+# else
+ return (setdtablesize (newlim));
+# endif
+#endif
+ case RLIMIT_PIPESIZE:
+ case RLIMIT_VIRTMEM:
+ case RLIMIT_MAXUPROC:
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+ else
+ {
+#if defined (HAVE_RESOURCE)
+ if (getrlimit (limits[ind].parameter, &limit) < 0)
+ return -1;
+# if defined (HPUX9)
+ if (limits[ind].parameter == RLIMIT_FILESIZE)
+ newlim /= 512; /* Ugh. */
+# endif /* HPUX9 */
+ val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
+ (mode & LIMIT_HARD) == 0 && /* XXX -- test */
+ (limit.rlim_cur <= limit.rlim_max))
+ ? limit.rlim_max : newlim;
+ if (mode & LIMIT_SOFT)
+ limit.rlim_cur = val;
+ if (mode & LIMIT_HARD)
+ limit.rlim_max = val;
+
+ return (setrlimit (limits[ind].parameter, &limit));
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+ }
+}
+
+static int
+getmaxvm (softlim, hardlim)
+ RLIMTYPE *softlim, *hardlim;
+{
+#if defined (HAVE_RESOURCE)
+ struct rlimit datalim, stacklim;
+
+ if (getrlimit (RLIMIT_DATA, &datalim) < 0)
+ return -1;
+
+ if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
+ return -1;
+
+ /* Protect against overflow. */
+ *softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
+ *hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
+ return 0;
+#else
+ errno = EINVAL;
+ return -1;
+#endif /* HAVE_RESOURCE */
+}
+
+static int
+filesize(valuep)
+ RLIMTYPE *valuep;
+{
+#if !defined (HAVE_RESOURCE)
+ long result;
+ if ((result = ulimit (1, 0L)) < 0)
+ return -1;
+ else
+ *valuep = (RLIMTYPE) result * 512;
+ return 0;
+#else
+ errno = EINVAL;
+ return -1;
+#endif
+}
+
+static int
+pipesize (valuep)
+ RLIMTYPE *valuep;
+{
+#if defined (PIPE_BUF)
+ /* This is defined on Posix systems. */
+ *valuep = (RLIMTYPE) PIPE_BUF;
+ return 0;
+#else
+# if defined (_POSIX_PIPE_BUF)
+ *valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
+ return 0;
+# else
+# if defined (PIPESIZE)
+ /* This is defined by running a program from the Makefile. */
+ *valuep = (RLIMTYPE) PIPESIZE;
+ return 0;
+# else
+ errno = EINVAL;
+ return -1;
+# endif /* PIPESIZE */
+# endif /* _POSIX_PIPE_BUF */
+#endif /* PIPE_BUF */
+}
+
+static int
+getmaxuprc (valuep)
+ RLIMTYPE *valuep;
+{
+ long maxchild;
+
+ maxchild = getmaxchild ();
+ if (maxchild < 0)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ else
+ {
+ *valuep = (RLIMTYPE) maxchild;
+ return 0;
+ }
+}
+
+static void
+print_all_limits (mode)
+ int mode;
+{
+ register int i;
+ RLIMTYPE softlim, hardlim;
+
+ if (mode == 0)
+ mode |= LIMIT_SOFT;
+
+ for (i = 0; limits[i].option > 0; i++)
+ {
+ if (get_limit (i, &softlim, &hardlim) == 0)
+ printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
+ else if (errno != EINVAL)
+ builtin_error ("%s: cannot get limit: %s", limits[i].description,
+ strerror (errno));
+ }
+}
+
+static void
+printone (limind, curlim, pdesc)
+ int limind;
+ RLIMTYPE curlim;
+ int pdesc;
+{
+ char unitstr[64];
+ int factor;
+
+ factor = BLOCKSIZE(limits[limind].block_factor);
+ if (pdesc)
+ {
+ if (limits[limind].units)
+ sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
+ else
+ sprintf (unitstr, "(-%c) ", limits[limind].option);
+
+ printf ("%-20s %16s", limits[limind].description, unitstr);
+ }
+ if (curlim == RLIM_INFINITY)
+ puts ("unlimited");
+ else if (curlim == RLIM_SAVED_MAX)
+ puts ("hard");
+ else if (curlim == RLIM_SAVED_CUR)
+ puts ("soft");
+ else
+ print_rlimtype ((curlim / factor), 1);
+}
+
+/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which
+ causes all limits to be set as high as possible depending on mode (like
+ csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits
+ were set successfully, and 1 if at least one limit could not be set.
+
+ To raise all soft limits to their corresponding hard limits, use
+ ulimit -S -a unlimited
+ To attempt to raise all hard limits to infinity (superuser-only), use
+ ulimit -H -a unlimited
+ To attempt to raise all soft and hard limits to infinity, use
+ ulimit -a unlimited
+*/
+
+static int
+set_all_limits (mode, newlim)
+ int mode;
+ RLIMTYPE newlim;
+{
+ register int i;
+ int retval = 0;
+
+ if (newlim != RLIM_INFINITY)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (mode == 0)
+ mode = LIMIT_SOFT|LIMIT_HARD;
+
+ for (retval = i = 0; limits[i].option > 0; i++)
+ if (set_limit (i, newlim, mode) < 0)
+ {
+ builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
+ strerror (errno));
+ retval = 1;
+ }
+ return retval;
+}
+
+#endif /* !_MINIX */
diff --git a/builtins/umask.c b/builtins/umask.c
new file mode 100644
index 0000000..b53c5b8
--- /dev/null
+++ b/builtins/umask.c
@@ -0,0 +1,280 @@
+/* umask.c, created from umask.def. */
+#line 22 "./umask.def"
+
+#line 41 "./umask.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include "filecntl.h"
+#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <chartypes.h>
+
+#include "../bashintl.h"
+
+#include "../shell.h"
+#include "posixstat.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#ifdef __LCC__
+#define mode_t int
+#endif
+
+/* **************************************************************** */
+/* */
+/* UMASK Builtin and Helpers */
+/* */
+/* **************************************************************** */
+
+static void print_symbolic_umask __P((mode_t));
+static int symbolic_umask __P((WORD_LIST *));
+
+/* Set or display the mask used by the system when creating files. Flag
+ of -S means display the umask in a symbolic mode. */
+int
+umask_builtin (list)
+ WORD_LIST *list;
+{
+ int print_symbolically, opt, umask_value, pflag;
+ mode_t umask_arg;
+
+ print_symbolically = pflag = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "Sp")) != -1)
+ {
+ switch (opt)
+ {
+ case 'S':
+ print_symbolically++;
+ break;
+ case 'p':
+ pflag++;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (list)
+ {
+ if (DIGIT (*list->word->word))
+ {
+ umask_value = read_octal (list->word->word);
+
+ /* Note that other shells just let you set the umask to zero
+ by specifying a number out of range. This is a problem
+ with those shells. We don't change the umask if the input
+ is lousy. */
+ if (umask_value == -1)
+ {
+ sh_erange (list->word->word, _("octal number"));
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else
+ {
+ umask_value = symbolic_umask (list);
+ if (umask_value == -1)
+ return (EXECUTION_FAILURE);
+ }
+ umask_arg = (mode_t)umask_value;
+ umask (umask_arg);
+ if (print_symbolically)
+ print_symbolic_umask (umask_arg);
+ }
+ else /* Display the UMASK for this user. */
+ {
+ umask_arg = umask (022);
+ umask (umask_arg);
+
+ if (pflag)
+ printf ("umask%s ", (print_symbolically ? " -S" : ""));
+ if (print_symbolically)
+ print_symbolic_umask (umask_arg);
+ else
+ printf ("%04lo\n", (unsigned long)umask_arg);
+ }
+
+ return (sh_chkwrite (EXECUTION_SUCCESS));
+}
+
+/* Print the umask in a symbolic form. In the output, a letter is
+ printed if the corresponding bit is clear in the umask. */
+static void
+print_symbolic_umask (um)
+ mode_t um;
+{
+ char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
+ int i;
+
+ i = 0;
+ if ((um & S_IRUSR) == 0)
+ ubits[i++] = 'r';
+ if ((um & S_IWUSR) == 0)
+ ubits[i++] = 'w';
+ if ((um & S_IXUSR) == 0)
+ ubits[i++] = 'x';
+ ubits[i] = '\0';
+
+ i = 0;
+ if ((um & S_IRGRP) == 0)
+ gbits[i++] = 'r';
+ if ((um & S_IWGRP) == 0)
+ gbits[i++] = 'w';
+ if ((um & S_IXGRP) == 0)
+ gbits[i++] = 'x';
+ gbits[i] = '\0';
+
+ i = 0;
+ if ((um & S_IROTH) == 0)
+ obits[i++] = 'r';
+ if ((um & S_IWOTH) == 0)
+ obits[i++] = 'w';
+ if ((um & S_IXOTH) == 0)
+ obits[i++] = 'x';
+ obits[i] = '\0';
+
+ printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
+}
+
+int
+parse_symbolic_mode (mode, initial_bits)
+ char *mode;
+ int initial_bits;
+{
+ int who, op, perm, bits, c;
+ char *s;
+
+ for (s = mode, bits = initial_bits;;)
+ {
+ who = op = perm = 0;
+
+ /* Parse the `who' portion of the symbolic mode clause. */
+ while (member (*s, "agou"))
+ {
+ switch (c = *s++)
+ {
+ case 'u':
+ who |= S_IRWXU;
+ continue;
+ case 'g':
+ who |= S_IRWXG;
+ continue;
+ case 'o':
+ who |= S_IRWXO;
+ continue;
+ case 'a':
+ who |= S_IRWXU | S_IRWXG | S_IRWXO;
+ continue;
+ default:
+ break;
+ }
+ }
+
+ /* The operation is now sitting in *s. */
+ op = *s++;
+ switch (op)
+ {
+ case '+':
+ case '-':
+ case '=':
+ break;
+ default:
+ builtin_error (_("`%c': invalid symbolic mode operator"), op);
+ return (-1);
+ }
+
+ /* Parse out the `perm' section of the symbolic mode clause. */
+ while (member (*s, "rwx"))
+ {
+ c = *s++;
+
+ switch (c)
+ {
+ case 'r':
+ perm |= S_IRUGO;
+ break;
+ case 'w':
+ perm |= S_IWUGO;
+ break;
+ case 'x':
+ perm |= S_IXUGO;
+ break;
+ }
+ }
+
+ /* Now perform the operation or return an error for a
+ bad permission string. */
+ if (!*s || *s == ',')
+ {
+ if (who)
+ perm &= who;
+
+ switch (op)
+ {
+ case '+':
+ bits |= perm;
+ break;
+ case '-':
+ bits &= ~perm;
+ break;
+ case '=':
+ if (who == 0)
+ who = S_IRWXU | S_IRWXG | S_IRWXO;
+ bits &= ~who;
+ bits |= perm;
+ break;
+
+ /* No other values are possible. */
+ }
+
+ if (*s == '\0')
+ break;
+ else
+ s++; /* skip past ',' */
+ }
+ else
+ {
+ builtin_error (_("`%c': invalid symbolic mode character"), *s);
+ return (-1);
+ }
+ }
+
+ return (bits);
+}
+
+/* Set the umask from a symbolic mode string similar to that accepted
+ by chmod. If the -S argument is given, then print the umask in a
+ symbolic form. */
+static int
+symbolic_umask (list)
+ WORD_LIST *list;
+{
+ int um, bits;
+
+ /* Get the initial umask. Don't change it yet. */
+ um = umask (022);
+ umask (um);
+
+ /* All work is done with the complement of the umask -- it's
+ more intuitive and easier to deal with. It is complemented
+ again before being returned. */
+ bits = parse_symbolic_mode (list->word->word, ~um & 0777);
+ if (bits == -1)
+ return (-1);
+
+ um = ~bits & 0777;
+ return (um);
+}
diff --git a/builtins/wait.c b/builtins/wait.c
new file mode 100644
index 0000000..60043df
--- /dev/null
+++ b/builtins/wait.c
@@ -0,0 +1,138 @@
+/* wait.c, created from wait.def. */
+#line 38 "./wait.def"
+
+#line 53 "./wait.def"
+
+#include <config.h>
+
+#include "../bashtypes.h"
+#include <signal.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <chartypes.h>
+
+#include "../bashansi.h"
+
+#include "../shell.h"
+#include "../jobs.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int wait_signal_received;
+
+procenv_t wait_intr_buf;
+
+/* Wait for the pid in LIST to stop or die. If no arguments are given, then
+ wait for all of the active background processes of the shell and return
+ 0. If a list of pids or job specs are given, return the exit status of
+ the last one waited for. */
+
+#define WAIT_RETURN(s) \
+ do \
+ { \
+ interrupt_immediately = old_interrupt_immediately;\
+ return (s);\
+ } \
+ while (0)
+
+int
+wait_builtin (list)
+ WORD_LIST *list;
+{
+ int status, code;
+ volatile int old_interrupt_immediately;
+
+ USE_VAR(list);
+
+ if (no_options (list))
+ return (EX_USAGE);
+ list = loptend;
+
+ old_interrupt_immediately = interrupt_immediately;
+ interrupt_immediately++;
+
+ /* POSIX.2 says: When the shell is waiting (by means of the wait utility)
+ for asynchronous commands to complete, the reception of a signal for
+ which a trap has been set shall cause the wait utility to return
+ immediately with an exit status greater than 128, after which the trap
+ associated with the signal shall be taken.
+
+ We handle SIGINT here; it's the only one that needs to be treated
+ specially (I think), since it's handled specially in {no,}jobs.c. */
+ code = setjmp (wait_intr_buf);
+ if (code)
+ {
+ status = 128 + wait_signal_received;
+ WAIT_RETURN (status);
+ }
+
+ /* We support jobs or pids.
+ wait <pid-or-job> [pid-or-job ...] */
+
+ /* But wait without any arguments means to wait for all of the shell's
+ currently active background processes. */
+ if (list == 0)
+ {
+ wait_for_background_pids ();
+ WAIT_RETURN (EXECUTION_SUCCESS);
+ }
+
+ status = EXECUTION_SUCCESS;
+ while (list)
+ {
+ pid_t pid;
+ char *w;
+ intmax_t pid_value;
+
+ w = list->word->word;
+ if (DIGIT (*w))
+ {
+ if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
+ {
+ pid = (pid_t)pid_value;
+ status = wait_for_single_pid (pid);
+ }
+ else
+ {
+ sh_badpid (w);
+ WAIT_RETURN (EXECUTION_FAILURE);
+ }
+ }
+#if defined (JOB_CONTROL)
+ else if (*w && *w == '%')
+ /* Must be a job spec. Check it out. */
+ {
+ int job;
+ sigset_t set, oset;
+
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if (INVALID_JOB (job))
+ {
+ if (job != DUP_JOB)
+ sh_badjob (list->word->word);
+ UNBLOCK_CHILD (oset);
+ status = 127; /* As per Posix.2, section 4.70.2 */
+ list = list->next;
+ continue;
+ }
+
+ /* Job spec used. Wait for the last pid in the pipeline. */
+ UNBLOCK_CHILD (oset);
+ status = wait_for_job (job);
+ }
+#endif /* JOB_CONTROL */
+ else
+ {
+ sh_badpid (w);
+ status = EXECUTION_FAILURE;
+ }
+ list = list->next;
+ }
+
+ WAIT_RETURN (status);
+}
diff --git a/config.h b/config.h
new file mode 100644
index 0000000..7386d70
--- /dev/null
+++ b/config.h
@@ -0,0 +1,1115 @@
+/* config.h. Generated from config.h.in by configure. */
+/* config.h -- Configuration file for bash. */
+
+/* Copyright (C) 1987-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _CONFIG_H_
+#define _CONFIG_H_
+
+/* Configuration feature settings controllable by autoconf. */
+
+/* Define JOB_CONTROL if your operating system supports
+ BSD-like job control. */
+#define JOB_CONTROL 1
+
+/* Define ALIAS if you want the alias features. */
+#define ALIAS 1
+
+/* Define PUSHD_AND_POPD if you want those commands to be compiled in.
+ (Also the `dirs' commands.) */
+#define PUSHD_AND_POPD 1
+
+/* Define BRACE_EXPANSION if you want curly brace expansion a la Csh:
+ foo{a,b} -> fooa foob. Even if this is compiled in (the default) you
+ can turn it off at shell startup with `-nobraceexpansion', or during
+ shell execution with `set +o braceexpand'. */
+#define BRACE_EXPANSION 1
+
+/* Define READLINE to get the nifty/glitzy editing features.
+ This is on by default. You can turn it off interactively
+ with the -nolineediting flag. */
+#define READLINE 1
+
+/* Define BANG_HISTORY if you want to have Csh style "!" history expansion.
+ This is unrelated to READLINE. */
+#define BANG_HISTORY 1
+
+/* Define HISTORY if you want to have access to previously typed commands.
+
+ If both HISTORY and READLINE are defined, you can get at the commands
+ with line editing commands, and you can directly manipulate the history
+ from the command line.
+
+ If only HISTORY is defined, the `fc' and `history' builtins are
+ available. */
+#define HISTORY 1
+
+/* Define this if you want completion that puts all alternatives into
+ a brace expansion shell expression. */
+#if defined (BRACE_EXPANSION) && defined (READLINE)
+# define BRACE_COMPLETION
+#endif /* BRACE_EXPANSION */
+
+/* Define DEFAULT_ECHO_TO_XPG if you want the echo builtin to interpret
+ the backslash-escape characters by default, like the XPG Single Unix
+ Specification V2 for echo.
+ This requires that V9_ECHO be defined. */
+/* #undef DEFAULT_ECHO_TO_XPG */
+
+/* Define HELP_BUILTIN if you want the `help' shell builtin and the long
+ documentation strings compiled into the shell. */
+#define HELP_BUILTIN 1
+
+/* Define RESTRICTED_SHELL if you want the generated shell to have the
+ ability to be a restricted one. The shell thus generated can become
+ restricted by being run with the name "rbash", or by setting the -r
+ flag. */
+#define RESTRICTED_SHELL 1
+
+/* Define DISABLED_BUILTINS if you want "builtin foo" to always run the
+ shell builtin "foo", even if it has been disabled with "enable -n foo". */
+/* #undef DISABLED_BUILTINS */
+
+/* Define PROCESS_SUBSTITUTION if you want the K*rn shell-like process
+ substitution features "<(file)". */
+/* Right now, you cannot do this on machines without fully operational
+ FIFO support. This currently include NeXT and Alliant. */
+#define PROCESS_SUBSTITUTION 1
+
+/* Define PROMPT_STRING_DECODE if you want the backslash-escaped special
+ characters in PS1 and PS2 expanded. Variable expansion will still be
+ performed. */
+#define PROMPT_STRING_DECODE 1
+
+/* Define SELECT_COMMAND if you want the Korn-shell style `select' command:
+ select word in word_list; do command_list; done */
+#define SELECT_COMMAND 1
+
+/* Define COMMAND_TIMING of you want the ksh-style `time' reserved word and
+ the ability to time pipelines, functions, and builtins. */
+#define COMMAND_TIMING 1
+
+/* Define ARRAY_VARS if you want ksh-style one-dimensional array variables. */
+#define ARRAY_VARS 1
+
+/* Define DPAREN_ARITHMETIC if you want the ksh-style ((...)) arithmetic
+ evaluation command. */
+#define DPAREN_ARITHMETIC 1
+
+/* Define EXTENDED_GLOB if you want the ksh-style [*+@?!](patlist) extended
+ pattern matching. */
+#define EXTENDED_GLOB 1
+
+/* Define EXTGLOB_DEFAULT to the value you'd like the extglob shell option
+ to have by default */
+#define EXTGLOB_DEFAULT 0
+
+/* Define COND_COMMAND if you want the ksh-style [[...]] conditional
+ command. */
+#define COND_COMMAND 1
+
+/* Define COND_REGEXP if you want extended regular expression matching and the
+ =~ binary operator in the [[...]] conditional command. */
+#define COND_REGEXP 1
+
+/* Define COPROCESS_SUPPORT if you want support for ksh-like coprocesses and
+ the `coproc' reserved word */
+#define COPROCESS_SUPPORT 1
+
+/* Define ARITH_FOR_COMMAND if you want the ksh93-style
+ for (( init; test; step )) do list; done
+ arithmetic for command. */
+#define ARITH_FOR_COMMAND 1
+
+/* Define NETWORK_REDIRECTIONS if you want /dev/(tcp|udp)/host/port to open
+ socket connections when used in redirections */
+#define NETWORK_REDIRECTIONS 1
+
+/* Define PROGRAMMABLE_COMPLETION for the programmable completion features
+ and the complete builtin. */
+#define PROGRAMMABLE_COMPLETION 1
+
+/* Define NO_MULTIBYTE_SUPPORT to not compile in support for multibyte
+ characters, even if the OS supports them. */
+/* #undef NO_MULTIBYTE_SUPPORT */
+
+/* Define DEBUGGER if you want to compile in some features used only by the
+ bash debugger. */
+#define DEBUGGER 1
+
+/* Define STRICT_POSIX if you want bash to be strictly posix.2 conformant by
+ default (except for echo; that is controlled separately). */
+/* #undef STRICT_POSIX */
+
+/* Define MEMSCRAMBLE if you want the bash malloc and free to scramble
+ memory contents on malloc() and free(). */
+#define MEMSCRAMBLE 1
+
+/* Define AFS if you are using Transarc's AFS. */
+/* #undef AFS */
+
+/* Define for case-modifying variable attributes; variables modified on
+ assignment */
+#define CASEMOD_ATTRS 1
+
+/* Define for case-modifying word expansions */
+#define CASEMOD_EXPANSIONS 1
+
+/* #undef ENABLE_NLS */
+
+/* End of configuration settings controllable by autoconf. */
+/* Other settable options appear in config-top.h. */
+
+#include "config-top.h"
+
+/* Beginning of autoconf additions. */
+
+/* Characteristics of the C compiler */
+/* #undef const */
+
+/* #undef inline */
+
+#define restrict __restrict
+
+/* #undef volatile */
+
+/* Define if cpp supports the ANSI-C stringizing `#' operator */
+#define HAVE_STRINGIZE 1
+
+/* Define if the compiler supports `long double' variables. */
+#define HAVE_LONG_DOUBLE 1
+
+#define PROTOTYPES 1
+
+/* #undef __CHAR_UNSIGNED__ */
+
+/* Define if the compiler supports `long long' variables. */
+#define HAVE_LONG_LONG 1
+
+#define HAVE_UNSIGNED_LONG_LONG 1
+
+/* The number of bytes in a int. */
+#define SIZEOF_INT 4
+
+/* The number of bytes in a long. */
+#define SIZEOF_LONG 8
+
+/* The number of bytes in a pointer to char. */
+#define SIZEOF_CHAR_P 8
+
+/* The number of bytes in a double (hopefully 8). */
+#define SIZEOF_DOUBLE 8
+
+/* The number of bytes in a `long long', if we have one. */
+#define SIZEOF_LONG_LONG 8
+
+/* System paths */
+
+#define DEFAULT_MAIL_DIRECTORY "/var/mail"
+
+/* Characteristics of the system's header files and libraries that affect
+ the compilation environment. */
+
+/* Define if the system does not provide POSIX.1 features except
+ with this defined. */
+/* #undef _POSIX_1_SOURCE */
+
+/* Define if you need to in order for stat and other things to work. */
+/* #undef _POSIX_SOURCE */
+
+/* Define to use GNU libc extensions */
+#define _GNU_SOURCE 1
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Memory management functions. */
+
+/* Define if using the bash version of malloc in lib/malloc/malloc.c */
+/* #undef USING_BASH_MALLOC */
+
+/* #undef DISABLE_MALLOC_WRAPPERS */
+
+/* Define if using alloca.c. */
+/* #undef C_ALLOCA */
+
+/* Define to one of _getb67, GETB67, getb67 for Cray-2 and Cray-YMP systems.
+ This function is required for alloca.c support on those systems. */
+/* #undef CRAY_STACKSEG_END */
+
+/* Define if you have alloca, as a function or macro. */
+#define HAVE_ALLOCA 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#define HAVE_ALLOCA_H 1
+
+
+/* SYSTEM TYPES */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef off_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef mode_t */
+
+/* Define to `int' if <signal.h> doesn't define. */
+/* #undef sigset_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef pid_t */
+
+/* Define to `short' if <sys/types.h> doesn't define. */
+#define bits16_t short
+
+/* Define to `unsigned short' if <sys/types.h> doesn't define. */
+#define u_bits16_t unsigned short
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+#define bits32_t int
+
+/* Define to `unsigned int' if <sys/types.h> doesn't define. */
+#define u_bits32_t unsigned int
+
+/* Define to `double' if <sys/types.h> doesn't define. */
+#define bits64_t char *
+
+/* Define to `unsigned int' if <sys/types.h> doesn't define. */
+/* #undef u_int */
+
+/* Define to `unsigned long' if <sys/types.h> doesn't define. */
+/* #undef u_long */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef ptrdiff_t */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef ssize_t */
+
+/* Define to `long' if <stdint.h> doesn't define. */
+/* #undef intmax_t */
+
+/* Define to `unsigned long' if <stdint.h> doesn't define. */
+/* #undef uintmax_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef uid_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef clock_t */
+
+/* Define to `long' if <sys/types.h> doesn't define. */
+/* #undef time_t */
+
+/* Define to `int' if <sys/types.h> doesn't define. */
+/* #undef gid_t */
+
+/* Define to `unsigned int' if <sys/socket.h> doesn't define. */
+/* #undef socklen_t */
+
+/* Define to `int' if <signal.h> doesn't define. */
+/* #undef sig_atomic_t */
+
+#define HAVE_MBSTATE_T 1
+
+/* Define if you have quad_t in <sys/types.h>. */
+#define HAVE_QUAD_T 1
+
+/* Define if you have wchar_t in <wctype.h>. */
+#define HAVE_WCHAR_T 1
+
+/* Define if you have wctype_t in <wctype.h>. */
+#define HAVE_WCTYPE_T 1
+
+/* Define if you have wint_t in <wctype.h>. */
+#define HAVE_WINT_T 1
+
+#define RLIMTYPE __rlim_t
+
+/* Define to the type of elements in the array set by `getgroups'.
+ Usually this is either `int' or `gid_t'. */
+#define GETGROUPS_T gid_t
+
+/* Characteristics of the machine archictecture. */
+
+/* If using the C implementation of alloca, define if you know the
+ direction of stack growth for your system; otherwise it will be
+ automatically deduced at run-time.
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+ */
+/* #undef STACK_DIRECTION */
+
+/* Define if the machine architecture is big-endian. */
+/* #undef WORDS_BIGENDIAN */
+
+/* Check for the presence of certain non-function symbols in the system
+ libraries. */
+
+/* Define if `sys_siglist' is declared by <signal.h> or <unistd.h>. */
+#define HAVE_DECL_SYS_SIGLIST 1
+/* #undef SYS_SIGLIST_DECLARED */
+
+/* Define if `_sys_siglist' is declared by <signal.h> or <unistd.h>. */
+#define UNDER_SYS_SIGLIST_DECLARED 1
+
+#define HAVE_SYS_SIGLIST 1
+
+#define HAVE_UNDER_SYS_SIGLIST 1
+
+#define HAVE_SYS_ERRLIST 1
+
+/* #undef HAVE_TZNAME */
+/* #undef HAVE_DECL_TZNAME */
+
+/* Characteristics of some of the system structures. */
+
+#define HAVE_STRUCT_DIRENT_D_INO 1
+
+#define HAVE_STRUCT_DIRENT_D_FILENO 1
+
+/* #undef HAVE_STRUCT_DIRENT_D_NAMLEN */
+
+/* #undef TIOCSTAT_IN_SYS_IOCTL */
+
+#define FIONREAD_IN_SYS_IOCTL 1
+
+#define GWINSZ_IN_SYS_IOCTL 1
+
+/* #undef STRUCT_WINSIZE_IN_SYS_IOCTL */
+
+/* #undef TM_IN_SYS_TIME */
+
+#define STRUCT_WINSIZE_IN_TERMIOS 1
+
+/* #undef SPEED_T_IN_SYS_TYPES */
+
+#define TERMIOS_LDISC 1
+
+#define TERMIO_LDISC 1
+
+#define HAVE_STRUCT_STAT_ST_BLOCKS 1
+
+#define HAVE_STRUCT_TM_TM_ZONE 1
+#define HAVE_TM_ZONE 1
+
+#define HAVE_TIMEVAL 1
+
+#define HAVE_STRUCT_TIMEZONE 1
+
+/* Characteristics of definitions in the system header files. */
+
+#define HAVE_GETPW_DECLS 1
+
+/* #undef HAVE_RESOURCE */
+
+/* #undef HAVE_LIBC_FNM_EXTMATCH */
+
+#define HAVE_DECL_CONFSTR 1
+
+#define HAVE_DECL_PRINTF 1
+
+#define HAVE_DECL_SBRK 1
+
+#define HAVE_DECL_STRCPY 1
+
+#define HAVE_DECL_STRSIGNAL 1
+
+/* #undef HAVE_DECL_STRTOLD */
+
+/* #undef PRI_MACROS_BROKEN */
+
+/* #undef STRTOLD_BROKEN */
+
+/* Define if WCONTINUED is defined in system headers, but rejected by waitpid */
+/* #undef WCONTINUED_BROKEN */
+
+/* These are checked with BASH_CHECK_DECL */
+
+#define HAVE_DECL_STRTOIMAX 1
+#define HAVE_DECL_STRTOL 1
+#define HAVE_DECL_STRTOLL 1
+#define HAVE_DECL_STRTOUL 1
+#define HAVE_DECL_STRTOULL 1
+#define HAVE_DECL_STRTOUMAX 1
+
+/* Characteristics of system calls and C library functions. */
+
+/* Define if the `getpgrp' function takes no argument. */
+#define GETPGRP_VOID 1
+
+/* #undef NAMED_PIPES_MISSING */
+
+/* #undef OPENDIR_NOT_ROBUST */
+
+#define PGRP_PIPE 1
+
+/* Define if the setvbuf function takes the buffering type as its second
+ argument and the buffer pointer as the third, as on System V
+ before release 3. */
+/* #undef SETVBUF_REVERSED */
+
+/* #undef STAT_MACROS_BROKEN */
+
+#define ULIMIT_MAXFDS 1
+
+#define CAN_REDEFINE_GETENV 1
+
+/* #undef HAVE_STD_PUTENV */
+
+#define HAVE_STD_UNSETENV 1
+
+#define HAVE_PRINTF_A_FORMAT 1
+
+#define CTYPE_NON_ASCII 1
+
+/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
+#define HAVE_LANGINFO_CODESET 1
+
+/* Characteristics of properties exported by the kernel. */
+
+/* Define if the kernel can exec files beginning with #! */
+#define HAVE_HASH_BANG_EXEC 1
+
+/* Define if you have the /dev/fd devices to map open files into the file system. */
+#define HAVE_DEV_FD 1
+
+/* Defined to /dev/fd or /proc/self/fd (linux). */
+#define DEV_FD_PREFIX "/dev/fd/"
+
+/* Define if you have the /dev/stdin device. */
+#define HAVE_DEV_STDIN 1
+
+/* The type of iconv's `inbuf' argument */
+#define ICONV_CONST
+
+/* Type and behavior of signal handling functions. */
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define if return type of signal handlers is void */
+#define VOID_SIGHANDLER 1
+
+/* #undef MUST_REINSTALL_SIGHANDLERS */
+
+/* #undef HAVE_BSD_SIGNALS */
+
+#define HAVE_POSIX_SIGNALS 1
+
+/* #undef HAVE_USG_SIGHOLD */
+
+/* #undef UNUSABLE_RT_SIGNALS */
+
+
+/* Presence of system and C library functions. */
+
+/* Define if you have the asprintf function. */
+#define HAVE_ASPRINTF 1
+
+/* Define if you have the bcopy function. */
+#define HAVE_BCOPY 1
+
+/* Define if you have the bzero function. */
+#define HAVE_BZERO 1
+
+/* Define if you have the confstr function. */
+#define HAVE_CONFSTR 1
+
+/* Define if you have the dlclose function. */
+/* #undef HAVE_DLCLOSE */
+
+/* Define if you have the dlopen function. */
+/* #undef HAVE_DLOPEN */
+
+/* Define if you have the dlsym function. */
+/* #undef HAVE_DLSYM */
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #undef HAVE_DOPRNT */
+
+/* Define if you have the dup2 function. */
+#define HAVE_DUP2 1
+
+/* Define if you have the eaccess function. */
+/* #undef HAVE_EACCESS */
+
+/* Define if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define if you have the fdprintf function. */
+/* #undef HAVE_FDPRINTF */
+
+/* Define if you have the fpurge/__fpurge function. */
+#define HAVE_FPURGE 1
+/* #undef HAVE___FPURGE */
+#define HAVE_DECL_FPURGE 0
+
+/* Define if you have the getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define if you have the getcwd function. */
+#define HAVE_GETCWD 1
+
+/* Define if you have the getdtablesize function. */
+#define HAVE_GETDTABLESIZE 1
+
+/* Define if you have the getgroups function. */
+#define HAVE_GETGROUPS 1
+
+/* Define if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the getpagesize function. */
+#define HAVE_GETPAGESIZE 1
+
+/* Define if you have the getpeername function. */
+#define HAVE_GETPEERNAME 1
+
+/* Define if you have the getpwent function. */
+/* #undef HAVE_GETPWENT */
+
+/* Define if you have the getpwnam function. */
+#define HAVE_GETPWNAM 1
+
+/* Define if you have the getpwuid function. */
+#define HAVE_GETPWUID 1
+
+/* Define if you have the getrlimit function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define if you have the getrusage function. */
+#define HAVE_GETRUSAGE 1
+
+/* Define if you have the getservbyname function. */
+#define HAVE_GETSERVBYNAME 1
+
+/* Define if you have the getservent function. */
+#define HAVE_GETSERVENT 1
+
+/* Define if you have the gettimeofday function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* Define if you have the getwd function. */
+/* #undef HAVE_GETWD */
+
+/* Define if you have the iconv function. */
+/* #undef HAVE_ICONV */
+
+/* Define if you have the inet_aton function. */
+#define HAVE_INET_ATON 1
+
+/* Define if you have the isascii function. */
+#define HAVE_ISASCII 1
+
+/* Define if you have the isblank function. */
+#define HAVE_ISBLANK 1
+
+/* Define if you have the isgraph function. */
+#define HAVE_ISGRAPH 1
+
+/* Define if you have the isinf function in libc */
+#define HAVE_ISINF_IN_LIBC 1
+
+/* Define if you have the isnan function in libc */
+#define HAVE_ISNAN_IN_LIBC 1
+
+/* Define if you have the isprint function. */
+#define HAVE_ISPRINT 1
+
+/* Define if you have the isspace function. */
+#define HAVE_ISSPACE 1
+
+/* Define if you have the iswctype function. */
+#define HAVE_ISWCTYPE 1
+
+/* Define if you have the iswlower function. */
+#define HAVE_ISWLOWER 1
+
+/* Define if you have the iswupper function. */
+#define HAVE_ISWUPPER 1
+
+/* Define if you have the isxdigit function. */
+#define HAVE_ISXDIGIT 1
+
+/* Define if you have the kill function. */
+#define HAVE_KILL 1
+
+/* Define if you have the killpg function. */
+/* #undef HAVE_KILLPG */
+
+/* Define if you have the lstat function. */
+#define HAVE_LSTAT 1
+
+/* Define if you have the locale_charset function. */
+/* #undef HAVE_LOCALE_CHARSET */
+
+/* Define if you have the mbrlen function. */
+#define HAVE_MBRLEN 1
+
+/* Define if you have the mbrtowc function. */
+#define HAVE_MBRTOWC 1
+
+/* Define if you have the mbscasecmp function. */
+/* #undef HAVE_MBSCASECMP */
+
+/* Define if you have the mbschr function. */
+/* #undef HAVE_MBSCHR */
+
+/* Define if you have the mbscmp function. */
+/* #undef HAVE_MBSCMP */
+
+/* Define if you have the mbsrtowcs function. */
+#define HAVE_MBSRTOWCS 1
+
+/* Define if you have the memmove function. */
+#define HAVE_MEMMOVE 1
+
+/* Define if you have the memset function. */
+#define HAVE_MEMSET 1
+
+/* Define if you have the mkfifo function. */
+#define HAVE_MKFIFO 1
+
+/* Define if you have the pathconf function. */
+#define HAVE_PATHCONF 1
+
+/* Define if you have the putenv function. */
+#define HAVE_PUTENV 1
+
+/* Define if you have the raise function. */
+#define HAVE_RAISE 1
+
+/* Define if you have the readlink function. */
+#define HAVE_READLINK 1
+
+/* Define if you have the regcomp function. */
+#define HAVE_REGCOMP 1
+
+/* Define if you have the regexec function. */
+#define HAVE_REGEXEC 1
+
+/* Define if you have the rename function. */
+#define HAVE_RENAME 1
+
+/* Define if you have the sbrk function. */
+#define HAVE_SBRK 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setdtablesize function. */
+/* #undef HAVE_SETDTABLESIZE */
+
+/* Define if you have the setenv function. */
+#define HAVE_SETENV 1
+
+/* Define if you have the setitimer function. */
+#define HAVE_SETITIMER 1
+
+/* Define if you have the setlinebuf function. */
+#define HAVE_SETLINEBUF 1
+
+/* Define if you have the setlocale function. */
+#define HAVE_SETLOCALE 1
+
+/* Define if you have the setostype function. */
+/* #undef HAVE_SETOSTYPE */
+
+/* Define if you have the setregid function. */
+/* #undef HAVE_SETREGID */
+#define HAVE_DECL_SETREGID 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define if you have the POSIX.1-style sigsetjmp function. */
+#define HAVE_POSIX_SIGSETJMP 1
+
+/* Define if you have the snprintf function. */
+#define HAVE_SNPRINTF 1
+
+/* Define if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define if you have the strcasestr function. */
+#define HAVE_STRCASESTR 1
+
+/* Define if you have the strchr function. */
+#define HAVE_STRCHR 1
+
+/* Define if you have the strcoll function. */
+#define HAVE_STRCOLL 1
+
+/* Define if you have the strerror function. */
+#define HAVE_STRERROR 1
+
+/* Define if you have the strftime function. */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the strnlen function. */
+#define HAVE_STRNLEN 1
+
+/* Define if you have the strpbrk function. */
+#define HAVE_STRPBRK 1
+
+/* Define if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define if you have the strtod function. */
+#define HAVE_STRTOD 1
+
+/* Define if you have the strtoimax function. */
+#define HAVE_STRTOIMAX 1
+
+/* Define if you have the strtol function. */
+#define HAVE_STRTOL 1
+
+/* Define if you have the strtoll function. */
+#define HAVE_STRTOLL 1
+
+/* Define if you have the strtoul function. */
+#define HAVE_STRTOUL 1
+
+/* Define if you have the strtoull function. */
+#define HAVE_STRTOULL 1
+
+/* Define if you have the strtoumax function. */
+#define HAVE_STRTOUMAX 1
+
+/* Define if you have the strsignal function or macro. */
+#define HAVE_STRSIGNAL 1
+
+/* Define if you have the sysconf function. */
+#define HAVE_SYSCONF 1
+
+/* Define if you have the syslog function. */
+#define HAVE_SYSLOG 1
+
+/* Define if you have the tcgetattr function. */
+#define HAVE_TCGETATTR 1
+
+/* Define if you have the tcgetpgrp function. */
+#define HAVE_TCGETPGRP 1
+
+/* Define if you have the times function. */
+#define HAVE_TIMES 1
+
+/* Define if you have the towlower function. */
+#define HAVE_TOWLOWER 1
+
+/* Define if you have the towupper function. */
+#define HAVE_TOWUPPER 1
+
+/* Define if you have the ttyname function. */
+#define HAVE_TTYNAME 1
+
+/* Define if you have the tzset function. */
+#define HAVE_TZSET 1
+
+/* Define if you have the ulimit function. */
+#define HAVE_ULIMIT 1
+
+/* Define if you have the uname function. */
+#define HAVE_UNAME 1
+
+/* Define if you have the unsetenv function. */
+#define HAVE_UNSETENV 1
+
+/* Define if you have the vasprintf function. */
+#define HAVE_VASPRINTF 1
+
+/* Define if you have the vprintf function. */
+#define HAVE_VPRINTF 1
+
+/* Define if you have the vsnprintf function. */
+#define HAVE_VSNPRINTF 1
+
+/* Define if you have the waitpid function. */
+#define HAVE_WAITPID 1
+
+/* Define if you have the wait3 function. */
+#define HAVE_WAIT3 1
+
+/* Define if you have the wcrtomb function. */
+#define HAVE_WCRTOMB 1
+
+/* Define if you have the wcscoll function. */
+#define HAVE_WCSCOLL 1
+
+/* Define if you have the wcsdup function. */
+#define HAVE_WCSDUP 1
+
+/* Define if you have the wctype function. */
+#define HAVE_WCTYPE 1
+
+/* Define if you have the wcwidth function. */
+#define HAVE_WCWIDTH 1
+
+/* Presence of certain system include files. */
+
+/* Define if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define if you have the <dirent.h> header file. */
+#define HAVE_DIRENT_H 1
+
+/* Define if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define if you have the <grp.h> header file. */
+#define HAVE_GRP_H 1
+
+/* Define if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define if you have the <langinfo.h> header file. */
+#define HAVE_LANGINFO_H 1
+
+/* Define if you have the <libintl.h> header file. */
+/* #undef HAVE_LIBINTL_H */
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define if you have the <ndir.h> header file. */
+/* #undef HAVE_NDIR_H */
+
+/* Define if you have the <netdh.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define if you have the <regex.h> header file. */
+#define HAVE_REGEX_H 1
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <stdarg.h> header file. */
+#define HAVE_STDARG_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define if you have the <stddef.h> header file. */
+#define HAVE_STDDEF_H 1
+
+/* Define if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define if you have the <syslog.h> header file. */
+#define HAVE_SYSLOG_H 1
+
+/* Define if you have the <sys/dir.h> header file. */
+/* #undef HAVE_SYS_DIR_H */
+
+/* Define if you have the <sys/file.h> header file. */
+#define HAVE_SYS_FILE_H 1
+
+/* Define if you have the <sys/ndir.h> header file. */
+/* #undef HAVE_SYS_NDIR_H */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define if you have the <sys/pte.h> header file. */
+/* #undef HAVE_SYS_PTE_H */
+
+/* Define if you have the <sys/ptem.h> header file. */
+/* #undef HAVE_SYS_PTEM_H */
+
+/* Define if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/stream.h> header file. */
+/* #undef HAVE_SYS_STREAM_H */
+
+/* Define if you have <sys/time.h> */
+#define HAVE_SYS_TIME_H 1
+
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you have <sys/times.h> */
+#define HAVE_SYS_TIMES_H 1
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have <sys/wait.h> that is POSIX.1 compatible. */
+#define HAVE_SYS_WAIT_H 1
+
+/* Define if you have the <termcap.h> header file. */
+/* #undef HAVE_TERMCAP_H */
+
+/* Define if you have the <termio.h> header file. */
+#ifndef HAVE_TERMIO_H
+#define HAVE_TERMIO_H 1
+#endif
+
+/* Define if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define if you have the <varargs.h> header file. */
+/* #undef HAVE_VARARGS_H */
+
+/* Define if you have the <wchar.h> header file. */
+#define HAVE_WCHAR_H 1
+
+/* Define if you have the <varargs.h> header file. */
+#define HAVE_WCTYPE_H 1
+
+/* Presence of certain system libraries. */
+
+/* #undef HAVE_LIBDL */
+
+/* #undef HAVE_LIBSUN */
+
+/* #undef HAVE_LIBSOCKET */
+
+
+/* Define if on MINIX. */
+/* #undef _MINIX */
+
+/* Are we running SVR5 (UnixWare 7)? */
+/* #undef SVR5 */
+
+/* Are we running SVR4.2? */
+/* #undef SVR4_2 */
+
+/* Are we running some version of SVR4? */
+/* #undef SVR4 */
+
+/* Define if job control is unusable or unsupported. */
+/* #undef JOB_CONTROL_MISSING */
+
+/* Do we need to define _KERNEL to get the RLIMIT_* defines from
+ <sys/resource.h>? */
+/* #undef RLIMIT_NEEDS_KERNEL */
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Do strcoll(3) and strcmp(3) give different results in the default locale? */
+/* #undef STRCOLL_BROKEN */
+
+/* #undef DUP2_BROKEN */
+
+/* #undef GETCWD_BROKEN */
+
+/* Additional defines for configuring lib/intl, maintained by autoscan/autoheader */
+
+/* Define if you have the <argz.h> header file. */
+#define HAVE_ARGZ_H 1
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <malloc.h> header file. */
+#ifndef HAVE_MALLOC_H
+#define HAVE_MALLOC_H 1
+#endif
+
+/* Define if you have the <stdio_ext.h> header file. */
+#define HAVE_STDIO_EXT_H 1
+
+/* Define if you have the `dcgettext' function. */
+#define HAVE_DCGETTEXT 1
+
+/* Define if you have the `localeconv' function. */
+#define HAVE_LOCALECONV 1
+
+/* Define if your system has a working `malloc' function. */
+/* #undef HAVE_MALLOC */
+
+/* Define if you have the `mempcpy' function. */
+#define HAVE_MEMPCPY 1
+
+/* Define if you have a working `mmap' system call. */
+#define HAVE_MMAP 1
+
+/* Define if you have the `munmap' function. */
+#define HAVE_MUNMAP 1
+
+/* Define if you have the `nl_langinfo' function. */
+/* #undef HAVE_NL_LANGINFO */
+
+/* Define if you have the `stpcpy' function. */
+#define HAVE_STPCPY 1
+
+/* Define if you have the `strcspn' function. */
+#define HAVE_STRCSPN 1
+
+/* Define if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the `__argz_count' function. */
+#define HAVE___ARGZ_COUNT 1
+
+/* Define if you have the `__argz_next' function. */
+#define HAVE___ARGZ_NEXT 1
+
+/* Define if you have the `__argz_stringify' function. */
+#define HAVE___ARGZ_STRINGIFY 1
+
+/* End additions for lib/intl */
+
+#include "config-bot.h"
+
+#endif /* _CONFIG_H_ */
diff --git a/lib/Android.mk b/lib/Android.mk
new file mode 100644
index 0000000..cfd03be
--- /dev/null
+++ b/lib/Android.mk
@@ -0,0 +1,2 @@
+LOCAL_PATH:= $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/lib/glob/Android.mk b/lib/glob/Android.mk
new file mode 100644
index 0000000..8f67c5a
--- /dev/null
+++ b/lib/glob/Android.mk
@@ -0,0 +1,27 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ========================================================
+# libglob.a
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ glob.c \
+ smatch.c \
+ strmatch.c \
+ xmbsrtowcs.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../.. \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../lib
+
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H
+
+LOCAL_MODULE := libglob
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/lib/readline/Android.mk b/lib/readline/Android.mk
new file mode 100644
index 0000000..853ee21
--- /dev/null
+++ b/lib/readline/Android.mk
@@ -0,0 +1,82 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ========================================================
+# libhistory.a
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ history.c \
+ histexpand.c \
+ histfile.c \
+ histsearch.c \
+ shell.c \
+ savestring.c \
+ mbutil.c \
+ xmalloc.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../.. \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../lib
+
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H
+
+LOCAL_MODULE := libhistory
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+# libreadline.a
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ readline.c \
+ vi_mode.c \
+ funmap.c \
+ keymaps.c \
+ parens.c \
+ search.c \
+ rltty.c \
+ complete.c \
+ bind.c \
+ isearch.c \
+ display.c \
+ signals.c \
+ util.c \
+ kill.c \
+ undo.c \
+ macro.c \
+ input.c \
+ callback.c \
+ terminal.c \
+ text.c \
+ nls.c \
+ misc.c \
+ history.c \
+ histexpand.c \
+ histfile.c \
+ histsearch.c \
+ shell.c \
+ savestring.c \
+ mbutil.c \
+ tilde.c \
+ xmalloc.c \
+ compat.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../.. \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../lib
+
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H
+
+LOCAL_MODULE := libreadline
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/lib/readline/complete.c b/lib/readline/complete.c
index bda2204..38249d2 100644
--- a/lib/readline/complete.c
+++ b/lib/readline/complete.c
@@ -1970,7 +1970,7 @@ rl_username_completion_function (text, state)
username = savestring (&text[first_char_loc]);
namelen = strlen (username);
- setpwent ();
+// setpwent ();
}
#if defined (HAVE_GETPWENT)
diff --git a/lib/sh/Android.mk b/lib/sh/Android.mk
new file mode 100644
index 0000000..3a6d894
--- /dev/null
+++ b/lib/sh/Android.mk
@@ -0,0 +1,34 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ========================================================
+# libsh.a
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ clktck.c clock.c getenv.c oslib.c setlinebuf.c strnlen.c \
+ itos.c zread.c zwrite.c shtty.c shmatch.c eaccess.c \
+ netconn.c netopen.c timeval.c makepath.c pathcanon.c \
+ pathphys.c tmpfile.c stringlist.c stringvec.c spell.c shquote.c \
+ strtrans.c snprintf.c mailstat.c fmtulong.c \
+ fmtullong.c fmtumax.c zcatfd.c zmapfd.c winsize.c wcsdup.c \
+ fpurge.c zgetline.c mbscmp.c uconvert.c ufuncs.c casemod.c \
+ fdprintf.c input_avail.c mbscasecmp.c fnxform.c fdprintf.c \
+ mbschr.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../.. \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../lib \
+ external/clearsilver \
+ external/clearsilver/util/regex
+
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H
+
+LOCAL_MODULE := libsh
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/lib/tilde/Android.mk b/lib/tilde/Android.mk
new file mode 100644
index 0000000..ba03d8b
--- /dev/null
+++ b/lib/tilde/Android.mk
@@ -0,0 +1,24 @@
+LOCAL_PATH:= $(call my-dir)
+
+# ========================================================
+# libtilde.a
+# ========================================================
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ tilde.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/../.. \
+ $(LOCAL_PATH)/../../include \
+ $(LOCAL_PATH)/../../lib
+
+LOCAL_CFLAGS += \
+ -DHAVE_CONFIG_H
+
+LOCAL_MODULE := libtilde
+
+include $(BUILD_STATIC_LIBRARY)
+
+# ========================================================
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/pathnames.h b/pathnames.h
new file mode 100644
index 0000000..e7da15e
--- /dev/null
+++ b/pathnames.h
@@ -0,0 +1,33 @@
+/* pathnames.h -- absolute filenames that bash wants for various defaults. */
+
+/* Copyright (C) 1987-2009 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 3 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#if !defined (_PATHNAMES_H_)
+#define _PATHNAMES_H_
+
+/* The default file for hostname completion. */
+#define DEFAULT_HOSTS_FILE "/system/etc/hosts"
+
+/* The default login shell startup file. */
+#define SYS_PROFILE "/system/etc/.bash_profile"
+
+/* The default location of the bash debugger initialization/startup file. */
+#define DEBUGGER_START_FILE ""
+
+#endif /* _PATHNAMES_H */
diff --git a/signames.h b/signames.h
new file mode 100644
index 0000000..9f9eb21
--- /dev/null
+++ b/signames.h
@@ -0,0 +1,78 @@
+/* This file was automatically created by ./mksignames.
+ Do not edit. Edit support/mksignames.c instead. */
+
+/* A translation list so we can be polite to our users. */
+char *signal_names[NSIG + 4] = {
+ "EXIT",
+ "SIGHUP",
+ "SIGINT",
+ "SIGQUIT",
+ "SIGILL",
+ "SIGTRAP",
+ "SIGABRT",
+ "SIGBUS",
+ "SIGFPE",
+ "SIGKILL",
+ "SIGUSR1",
+ "SIGSEGV",
+ "SIGUSR2",
+ "SIGPIPE",
+ "SIGALRM",
+ "SIGTERM",
+ "SIGSTKFLT",
+ "SIGCHLD",
+ "SIGCONT",
+ "SIGSTOP",
+ "SIGTSTP",
+ "SIGTTIN",
+ "SIGTTOU",
+ "SIGURG",
+ "SIGXCPU",
+ "SIGXFSZ",
+ "SIGVTALRM",
+ "SIGPROF",
+ "SIGWINCH",
+ "SIGIO",
+ "SIGPWR",
+ "SIGSYS",
+ "SIGJUNK(32)",
+ "SIGJUNK(33)",
+ "SIGRTMIN",
+ "SIGRTMIN+1",
+ "SIGRTMIN+2",
+ "SIGRTMIN+3",
+ "SIGRTMIN+4",
+ "SIGRTMIN+5",
+ "SIGRTMIN+6",
+ "SIGRTMIN+7",
+ "SIGRTMIN+8",
+ "SIGRTMIN+9",
+ "SIGRTMIN+10",
+ "SIGRTMIN+11",
+ "SIGRTMIN+12",
+ "SIGRTMIN+13",
+ "SIGRTMIN+14",
+ "SIGRTMIN+15",
+ "SIGRTMAX-14",
+ "SIGRTMAX-13",
+ "SIGRTMAX-12",
+ "SIGRTMAX-11",
+ "SIGRTMAX-10",
+ "SIGRTMAX-9",
+ "SIGRTMAX-8",
+ "SIGRTMAX-7",
+ "SIGRTMAX-6",
+ "SIGRTMAX-5",
+ "SIGRTMAX-4",
+ "SIGRTMAX-3",
+ "SIGRTMAX-2",
+ "SIGRTMAX-1",
+ "SIGRTMAX",
+ "DEBUG",
+ "ERR",
+ "RETURN",
+ (char *)0x0
+};
+
+#define initialize_signames()
+
diff --git a/subst.c b/subst.c
index 81a3256..89c4d7b 100644
--- a/subst.c
+++ b/subst.c
@@ -3137,6 +3137,7 @@ call_expand_word_internal (w, q, i, c, e)
last_command_exit_value = EXECUTION_FAILURE;
exp_jump_to_top_level ((result == &expand_word_error) ? DISCARD : FORCE_EOF);
/* NOTREACHED */
+ return (NULL);
}
else
return (result);
diff --git a/syntax.c b/syntax.c
new file mode 100644
index 0000000..c14e068
--- /dev/null
+++ b/syntax.c
@@ -0,0 +1,269 @@
+/*
+ * This file was generated by mksyntax. DO NOT EDIT.
+ */
+
+
+#include "config.h"
+#include "stdc.h"
+#include "syntax.h"
+
+
+int sh_syntabsiz = 256;
+int sh_syntaxtab[256] = {
+ CWORD, /* 0 */
+ CSPECL, /* CTLESC */
+ CWORD, /* 2 */
+ CWORD, /* 3 */
+ CWORD, /* 4 */
+ CWORD, /* 5 */
+ CWORD, /* 6 */
+ CWORD, /* \a */
+ CWORD, /* \b */
+ CSHBRK|CBLANK, /* \t */
+ CSHBRK|CBSDQUOTE, /* \n */
+ CWORD, /* \v */
+ CWORD, /* \f */
+ CWORD, /* \r */
+ CWORD, /* 14 */
+ CWORD, /* 15 */
+ CWORD, /* 16 */
+ CWORD, /* 17 */
+ CWORD, /* 18 */
+ CWORD, /* 19 */
+ CWORD, /* 20 */
+ CWORD, /* 21 */
+ CWORD, /* 22 */
+ CWORD, /* 23 */
+ CWORD, /* 24 */
+ CWORD, /* 25 */
+ CWORD, /* 26 */
+ CWORD, /* ESC */
+ CWORD, /* 28 */
+ CWORD, /* 29 */
+ CWORD, /* 30 */
+ CWORD, /* 31 */
+ CSHBRK|CBLANK, /* SPC */
+ CXGLOB|CSPECVAR, /* ! */
+ CQUOTE|CBSDQUOTE|CXQUOTE, /* " */
+ CSPECVAR, /* # */
+ CEXP|CBSDQUOTE|CBSHDOC|CSPECVAR, /* $ */
+ CWORD, /* % */
+ CSHMETA|CSHBRK, /* & */
+ CQUOTE|CXQUOTE, /* ' */
+ CSHMETA|CSHBRK, /* ( */
+ CSHMETA|CSHBRK, /* ) */
+ CGLOB|CXGLOB|CSPECVAR, /* * */
+ CXGLOB|CSUBSTOP, /* + */
+ CWORD, /* , */
+ CSPECVAR|CSUBSTOP, /* - */
+ CWORD, /* . */
+ CWORD, /* / */
+ CWORD, /* 0 */
+ CWORD, /* 1 */
+ CWORD, /* 2 */
+ CWORD, /* 3 */
+ CWORD, /* 4 */
+ CWORD, /* 5 */
+ CWORD, /* 6 */
+ CWORD, /* 7 */
+ CWORD, /* 8 */
+ CWORD, /* 9 */
+ CWORD, /* : */
+ CSHMETA|CSHBRK, /* ; */
+ CSHMETA|CSHBRK|CEXP, /* < */
+ CSUBSTOP, /* = */
+ CSHMETA|CSHBRK|CEXP, /* > */
+ CGLOB|CXGLOB|CSPECVAR|CSUBSTOP, /* ? */
+ CXGLOB|CSPECVAR, /* @ */
+ CWORD, /* A */
+ CWORD, /* B */
+ CWORD, /* C */
+ CWORD, /* D */
+ CWORD, /* E */
+ CWORD, /* F */
+ CWORD, /* G */
+ CWORD, /* H */
+ CWORD, /* I */
+ CWORD, /* J */
+ CWORD, /* K */
+ CWORD, /* L */
+ CWORD, /* M */
+ CWORD, /* N */
+ CWORD, /* O */
+ CWORD, /* P */
+ CWORD, /* Q */
+ CWORD, /* R */
+ CWORD, /* S */
+ CWORD, /* T */
+ CWORD, /* U */
+ CWORD, /* V */
+ CWORD, /* W */
+ CWORD, /* X */
+ CWORD, /* Y */
+ CWORD, /* Z */
+ CGLOB, /* [ */
+ CBSDQUOTE|CBSHDOC|CXQUOTE, /* \ */
+ CGLOB, /* ] */
+ CGLOB, /* ^ */
+ CWORD, /* _ */
+ CBACKQ|CQUOTE|CBSDQUOTE|CBSHDOC|CXQUOTE, /* ` */
+ CWORD, /* a */
+ CWORD, /* b */
+ CWORD, /* c */
+ CWORD, /* d */
+ CWORD, /* e */
+ CWORD, /* f */
+ CWORD, /* g */
+ CWORD, /* h */
+ CWORD, /* i */
+ CWORD, /* j */
+ CWORD, /* k */
+ CWORD, /* l */
+ CWORD, /* m */
+ CWORD, /* n */
+ CWORD, /* o */
+ CWORD, /* p */
+ CWORD, /* q */
+ CWORD, /* r */
+ CWORD, /* s */
+ CWORD, /* t */
+ CWORD, /* u */
+ CWORD, /* v */
+ CWORD, /* w */
+ CWORD, /* x */
+ CWORD, /* y */
+ CWORD, /* z */
+ CWORD, /* { */
+ CSHMETA|CSHBRK, /* | */
+ CWORD, /* } */
+ CWORD, /* ~ */
+ CSPECL, /* CTLNUL */
+ CWORD, /* 128 */
+ CWORD, /* 129 */
+ CWORD, /* 130 */
+ CWORD, /* 131 */
+ CWORD, /* 132 */
+ CWORD, /* 133 */
+ CWORD, /* 134 */
+ CWORD, /* 135 */
+ CWORD, /* 136 */
+ CWORD, /* 137 */
+ CWORD, /* 138 */
+ CWORD, /* 139 */
+ CWORD, /* 140 */
+ CWORD, /* 141 */
+ CWORD, /* 142 */
+ CWORD, /* 143 */
+ CWORD, /* 144 */
+ CWORD, /* 145 */
+ CWORD, /* 146 */
+ CWORD, /* 147 */
+ CWORD, /* 148 */
+ CWORD, /* 149 */
+ CWORD, /* 150 */
+ CWORD, /* 151 */
+ CWORD, /* 152 */
+ CWORD, /* 153 */
+ CWORD, /* 154 */
+ CWORD, /* 155 */
+ CWORD, /* 156 */
+ CWORD, /* 157 */
+ CWORD, /* 158 */
+ CWORD, /* 159 */
+ CWORD, /* 160 */
+ CWORD, /* 161 */
+ CWORD, /* 162 */
+ CWORD, /* 163 */
+ CWORD, /* 164 */
+ CWORD, /* 165 */
+ CWORD, /* 166 */
+ CWORD, /* 167 */
+ CWORD, /* 168 */
+ CWORD, /* 169 */
+ CWORD, /* 170 */
+ CWORD, /* 171 */
+ CWORD, /* 172 */
+ CWORD, /* 173 */
+ CWORD, /* 174 */
+ CWORD, /* 175 */
+ CWORD, /* 176 */
+ CWORD, /* 177 */
+ CWORD, /* 178 */
+ CWORD, /* 179 */
+ CWORD, /* 180 */
+ CWORD, /* 181 */
+ CWORD, /* 182 */
+ CWORD, /* 183 */
+ CWORD, /* 184 */
+ CWORD, /* 185 */
+ CWORD, /* 186 */
+ CWORD, /* 187 */
+ CWORD, /* 188 */
+ CWORD, /* 189 */
+ CWORD, /* 190 */
+ CWORD, /* 191 */
+ CWORD, /* 192 */
+ CWORD, /* 193 */
+ CWORD, /* 194 */
+ CWORD, /* 195 */
+ CWORD, /* 196 */
+ CWORD, /* 197 */
+ CWORD, /* 198 */
+ CWORD, /* 199 */
+ CWORD, /* 200 */
+ CWORD, /* 201 */
+ CWORD, /* 202 */
+ CWORD, /* 203 */
+ CWORD, /* 204 */
+ CWORD, /* 205 */
+ CWORD, /* 206 */
+ CWORD, /* 207 */
+ CWORD, /* 208 */
+ CWORD, /* 209 */
+ CWORD, /* 210 */
+ CWORD, /* 211 */
+ CWORD, /* 212 */
+ CWORD, /* 213 */
+ CWORD, /* 214 */
+ CWORD, /* 215 */
+ CWORD, /* 216 */
+ CWORD, /* 217 */
+ CWORD, /* 218 */
+ CWORD, /* 219 */
+ CWORD, /* 220 */
+ CWORD, /* 221 */
+ CWORD, /* 222 */
+ CWORD, /* 223 */
+ CWORD, /* 224 */
+ CWORD, /* 225 */
+ CWORD, /* 226 */
+ CWORD, /* 227 */
+ CWORD, /* 228 */
+ CWORD, /* 229 */
+ CWORD, /* 230 */
+ CWORD, /* 231 */
+ CWORD, /* 232 */
+ CWORD, /* 233 */
+ CWORD, /* 234 */
+ CWORD, /* 235 */
+ CWORD, /* 236 */
+ CWORD, /* 237 */
+ CWORD, /* 238 */
+ CWORD, /* 239 */
+ CWORD, /* 240 */
+ CWORD, /* 241 */
+ CWORD, /* 242 */
+ CWORD, /* 243 */
+ CWORD, /* 244 */
+ CWORD, /* 245 */
+ CWORD, /* 246 */
+ CWORD, /* 247 */
+ CWORD, /* 248 */
+ CWORD, /* 249 */
+ CWORD, /* 250 */
+ CWORD, /* 251 */
+ CWORD, /* 252 */
+ CWORD, /* 253 */
+ CWORD, /* 254 */
+ CWORD, /* 255 */
+};
diff --git a/version.h b/version.h
new file mode 100644
index 0000000..dc89af6
--- /dev/null
+++ b/version.h
@@ -0,0 +1,17 @@
+/* Version control for the shell. This file gets changed when you say
+ `make version.h' to the Makefile. It is created by mkversion. */
+
+/* The distribution version number of this shell. */
+#define DISTVERSION "4.1"
+
+/* The last built version of this shell. */
+#define BUILDVERSION 1
+
+/* The release status of this shell. */
+#define RELSTATUS "release"
+
+/* The default shell compatibility-level (the current version) */
+#define DEFAULT_COMPAT_LEVEL 41
+
+/* A version string for use by sccs and the what command. */
+#define SCCSVERSION "@(#)Bash version 4.1.7(1) release GNU"