aboutsummaryrefslogtreecommitdiffstats
path: root/builtins
diff options
context:
space:
mode:
authorJari Aalto <jari.aalto@cante.net>1996-08-26 18:22:31 +0000
committerJari Aalto <jari.aalto@cante.net>2009-09-12 16:46:49 +0000
commit726f63884db0132f01745f1fb4465e6621088ccf (patch)
tree6c2f7765a890a97e0e513cb539df43283a8f7c4d /builtins
downloadandroid_external_bash-726f63884db0132f01745f1fb4465e6621088ccf.tar.gz
android_external_bash-726f63884db0132f01745f1fb4465e6621088ccf.tar.bz2
android_external_bash-726f63884db0132f01745f1fb4465e6621088ccf.zip
Imported from ../bash-1.14.7.tar.gz.
Diffstat (limited to 'builtins')
-rw-r--r--builtins/ChangeLog0
-rw-r--r--builtins/Makefile267
-rw-r--r--builtins/alias.def180
-rw-r--r--builtins/bashgetopt.c136
-rw-r--r--builtins/bashgetopt.h37
-rw-r--r--builtins/bind.def219
-rw-r--r--builtins/break.def110
-rw-r--r--builtins/builtin.def67
-rw-r--r--builtins/cd.def689
-rw-r--r--builtins/colon.def37
-rw-r--r--builtins/command.def177
-rw-r--r--builtins/common.c829
-rw-r--r--builtins/common.h69
-rw-r--r--builtins/declare.def290
-rw-r--r--builtins/echo.def168
-rw-r--r--builtins/enable.def156
-rw-r--r--builtins/eval.def45
-rw-r--r--builtins/exec.def163
-rw-r--r--builtins/exit.def129
-rw-r--r--builtins/fc.def691
-rw-r--r--builtins/fg_bg.def145
-rw-r--r--builtins/getopt.c283
-rw-r--r--builtins/getopt.h57
-rw-r--r--builtins/getopts.def300
-rw-r--r--builtins/hash.def222
-rw-r--r--builtins/hashcom.h32
-rw-r--r--builtins/help.def134
-rw-r--r--builtins/history.def179
-rw-r--r--builtins/inlib.def74
-rw-r--r--builtins/jobs.def171
-rw-r--r--builtins/kill.def281
-rw-r--r--builtins/let.def77
-rw-r--r--builtins/mkbuiltins.c1311
-rw-r--r--builtins/psize.c63
-rwxr-xr-xbuiltins/psize.sh24
-rw-r--r--builtins/read.def276
-rw-r--r--builtins/reserved.def154
-rw-r--r--builtins/return.def57
-rw-r--r--builtins/set.def528
-rw-r--r--builtins/setattr.def253
-rw-r--r--builtins/shift.def95
-rw-r--r--builtins/source.def186
-rw-r--r--builtins/suspend.def86
-rw-r--r--builtins/test.def144
-rw-r--r--builtins/times.def89
-rw-r--r--builtins/trap.def204
-rw-r--r--builtins/type.def325
-rw-r--r--builtins/ulimit.def731
-rw-r--r--builtins/umask.def288
-rw-r--r--builtins/wait.def132
50 files changed, 11360 insertions, 0 deletions
diff --git a/builtins/ChangeLog b/builtins/ChangeLog
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/builtins/ChangeLog
diff --git a/builtins/Makefile b/builtins/Makefile
new file mode 100644
index 0000000..6472f7d
--- /dev/null
+++ b/builtins/Makefile
@@ -0,0 +1,267 @@
+# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs.
+#
+MKBUILTINS = mkbuiltins
+RANLIB = /usr/bin/ranlib
+CFLAGS = -g -I.. -I.
+SHELL = /bin/sh
+# CC = cc
+AR = ar
+RM = rm -f
+CP = cp
+
+srcdir = .
+VPATH = .:$(srcdir)
+
+.SUFFIXES:
+.SUFFIXES: .def .c .o
+# How to make a .o file from a .def file.
+.def.o:
+ $(RM) $@
+ ./$(MKBUILTINS) $(DIRECTDEFINE) $<
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $*.c || ( $(RM) $*.c ; exit 1 )
+ $(RM) $*.c
+
+# How to make a .c file from a .def file.
+.def.c:
+ $(RM) $@
+ ./$(MKBUILTINS) $(DIRECTDEFINE) $<
+
+# Here is a rule for making .o files from .c files that does not
+# force the type of the machine (like -M_MACHINE) into the flags.
+.c.o:
+ $(RM) $@
+ $(CC) -c $(CFLAGS) $(CPPFLAGS) $<
+
+DEFS = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \
+ $(srcdir)/builtin.def $(srcdir)/cd.def $(srcdir)/colon.def \
+ $(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \
+ $(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \
+ $(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \
+ $(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \
+ $(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \
+ $(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \
+ $(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \
+ $(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \
+ $(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \
+ $(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \
+ $(srcdir)/reserved.def
+
+STATIC_SOURCE = common.c getopt.c bashgetopt.c getopt.h
+
+OFILES = builtins.o \
+ alias.o bind.o break.o builtin.o cd.o colon.o command.o \
+ common.o declare.o echo.o enable.o eval.o exec.o exit.o \
+ fc.o fg_bg.o hash.o help.o history.o jobs.o kill.o \
+ let.o read.o return.o set.o setattr.o shift.o source.o \
+ suspend.o test.o times.o trap.o type.o ulimit.o umask.o \
+ wait.o getopts.o getopt.o bashgetopt.o
+
+THINGS_TO_TAR = $(DEFS) $(STATIC_SOURCE) Makefile ChangeLog
+
+CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h
+
+all: $(MKBUILTINS) libbuiltins.a
+
+libbuiltins.a: $(MKBUILTINS) $(OFILES)
+ $(RM) $@
+ $(AR) cq $@ $(OFILES)
+ -$(RANLIB) $@
+
+builtext.h builtins.c: $(MKBUILTINS) $(DEFS)
+ $(RM) builtext.h builtins.c
+ ./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \
+ -noproduction $(DIRECTDEFINE) $(DEFS)
+
+mkbuiltins: $(srcdir)/mkbuiltins.c ../config.h
+ $(CC) $(CFLAGS) -o $(MKBUILTINS) $(srcdir)/mkbuiltins.c
+
+ulimit.o: ulimit.def pipesize.h
+
+pipesize.h: psize.aux
+ $(SHELL) $(srcdir)/psize.sh > pipesize.h
+
+psize.aux: psize.c
+ $(CC) $(CFLAGS) -o $@ $(srcdir)/psize.c
+
+documentation: builtins.texi
+
+$(OFILES): $(MKBUILTINS) ../config.h
+
+builtins.texi: $(MKBUILTINS)
+ ./$(MKBUILTINS) -documentonly $(DEFS)
+
+clean:
+ $(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS)
+
+mostlyclean:
+ $(RM) $(OFILES) libbuiltins.a
+
+distclean realclean maintainer-clean: clean
+ $(RM) libbuiltins.a
+
+alias.o: alias.def
+bind.o: bind.def
+break.o: break.def
+builtin.o: builtin.def
+cd.o: cd.def
+colon.o: colon.def
+command.o: command.def
+declare.o: declare.def
+echo.o: echo.def
+enable.o: enable.def
+eval.o: eval.def
+exec.o: exec.def
+exit.o: exit.def
+fc.o: fc.def
+fg_bg.o: fg_bg.def
+hash.o: hash.def
+help.o: help.def
+history.o: history.def
+jobs.o: jobs.def
+kill.o: kill.def
+let.o: let.def
+read.o: read.def
+return.o: return.def
+set.o: set.def
+setattr.o: setattr.def
+shift.o: shift.def
+source.o: source.def
+suspend.o: suspend.def
+test.o: test.def
+times.o: times.def
+trap.o: trap.def
+type.o: type.def
+umask.o: umask.def
+wait.o: wait.def
+getopts.o: getopts.def
+reserved.o: reserved.def
+
+common.o: ../shell.h ../command.h ../config.h ../memalloc.h ../general.h
+common.o: ../variables.h ../input.h hashcom.h ../bashhist.h
+common.o: ../quit.h ../unwind_prot.h ../maxpath.h ../jobs.h ../builtins.h
+common.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+common.o: ../execute_cmd.h ../error.h
+alias.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+alias.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+alias.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h
+bind.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+bind.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+bind.o: ../maxpath.h
+bind.o: ../shell.h ../unwind_prot.h ../variables.h bashgetopt.h
+break.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+break.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+break.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+builtin.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+builtin.o: ../quit.h common.h ../maxpath.h
+builtin.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+builtin.o: ../shell.h ../unwind_prot.h ../variables.h
+cd.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+cd.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+cd.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h
+command.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+command.o: ../quit.h bashgetopt.h ../maxpath.h
+command.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+command.o: ../shell.h ../unwind_prot.h ../variables.h
+declare.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+declare.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+declare.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+echo.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+echo.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+echo.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+enable.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+enable.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+enable.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+eval.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+eval.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+eval.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+exec.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+exec.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+exec.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../execute_cmd.h
+exec.o: ../maxpath.h ../flags.h
+exit.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+exit.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+exit.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+fc.o: ../builtins.h ../command.h bashgetopt.h ../bashhist.h
+fc.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+fc.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+fc.o: ../flags.h ../unwind_prot.h ../variables.h ../shell.h ../maxpath.h
+fg_bg.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+fg_bg.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+fg_bg.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+getopts.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+getopts.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+getopts.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+hash.o: ../builtins.h ../command.h ../quit.h ../execute_cmd.h
+hash.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+hash.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h
+help.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+help.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+help.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+history.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+history.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+history.o: ../filecntl.h ../shell.h ../unwind_prot.h ../variables.h
+history.o: ../bashhist.h ../maxpath.h
+inlib.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+inlib.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+inlib.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+jobs.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+jobs.o: ../quit.h bashgetopt.h ../maxpath.h
+jobs.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+jobs.o: ../shell.h ../unwind_prot.h ../variables.h
+kill.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+kill.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+kill.o: ../shell.h ../trap.h ../unwind_prot.h ../variables.h ../maxpath.h
+let.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+let.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+let.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+read.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+read.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+read.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+return.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+return.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+return.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+set.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+set.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+set.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+setattr.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+setattr.o: ../quit.h common.h bashgetopt.h ../maxpath.h
+setattr.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+setattr.o: ../shell.h ../unwind_prot.h ../variables.h
+shift.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+shift.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+shift.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+source.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+source.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+source.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+suspend.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+suspend.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+suspend.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+test.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+test.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+test.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+times.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+times.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+times.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+trap.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+trap.o: ../quit.h common.h ../maxpath.h
+trap.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+trap.o: ../shell.h ../unwind_prot.h ../variables.h ../execute_cmd.h
+type.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+type.o: ../quit.h common.h ../maxpath.h
+type.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+type.o: ../shell.h ../unwind_prot.h ../variables.h
+ulimit.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+ulimit.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+ulimit.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+umask.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+umask.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+umask.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+wait.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
+wait.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
+wait.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
+
+bashgetopt.o: ../bashansi.h ../ansi_stdlib.h
+mkbuiltins.o: ../bashansi.h ../ansi_stdlib.h
+fc.o: ../bashansi.h ../ansi_stdlib.h
+
+#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h
diff --git a/builtins/alias.def b/builtins/alias.def
new file mode 100644
index 0000000..a878c70
--- /dev/null
+++ b/builtins/alias.def
@@ -0,0 +1,180 @@
+This file is alias.def, from which is created alias.c
+It implements the builtins "alias" and "unalias" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$BUILTIN alias
+$FUNCTION alias_builtin
+$DEPENDS_ON ALIAS
+$PRODUCES alias.c
+$SHORT_DOC alias [ name[=value] ... ]
+`alias' with no arguments prints the list of aliases in the form
+NAME=VALUE on standard output. An alias is defined for each NAME
+whose VALUE is given. A trailing space in VALUE causes the next
+word to be checked for alias substitution. Alias returns true
+unless a NAME is given for which no alias has been defined.
+$END
+
+#include "../config.h"
+
+#if defined (ALIAS)
+# include <stdio.h>
+# include "../shell.h"
+# include "../alias.h"
+# include "common.h"
+
+extern int interactive;
+static void print_alias ();
+
+/* Hack the alias command in a Korn shell way. */
+alias_builtin (list)
+ WORD_LIST *list;
+{
+ int any_failed = 0;
+
+ if (!list)
+ {
+ register int i;
+ ASSOC **alias_list;
+
+ if (!aliases)
+ return (EXECUTION_FAILURE);
+
+ alias_list = all_aliases ();
+
+ if (!alias_list)
+ return (EXECUTION_FAILURE);
+
+ for (i = 0; alias_list[i]; i++)
+ print_alias (alias_list[i]);
+
+ free (alias_list); /* XXX - Do not free the strings. */
+ }
+ else
+ {
+ while (list)
+ {
+ register char *value, *name = list->word->word;
+ register int offset;
+
+ for (offset = 0; name[offset] && name[offset] != '='; offset++)
+ ;
+
+ if (offset && name[offset] == '=')
+ {
+ name[offset] = '\0';
+ value = name + offset + 1;
+
+ add_alias (name, value);
+ }
+ else
+ {
+ ASSOC *t = find_alias (name);
+ if (t)
+ print_alias (t);
+ else
+ {
+ if (interactive)
+ builtin_error ("`%s' not found", name);
+ any_failed++;
+ }
+ }
+ list = list->next;
+ }
+ }
+ if (any_failed)
+ return (EXECUTION_FAILURE);
+ else
+ return (EXECUTION_SUCCESS);
+}
+#endif /* ALIAS */
+
+$BUILTIN unalias
+$FUNCTION unalias_builtin
+$DEPENDS_ON ALIAS
+$SHORT_DOC unalias [-a] [name ...]
+Remove NAMEs from the list of defined aliases. If the -a option is given,
+then remove all alias definitions.
+$END
+
+#if defined (ALIAS)
+/* Remove aliases named in LIST from the aliases database. */
+unalias_builtin (list)
+ register WORD_LIST *list;
+{
+ register ASSOC *alias;
+ int any_failed = 0;
+
+ while (list && *list->word->word == '-')
+ {
+ register char *word = list->word->word;
+
+ if (ISOPTION (word, 'a'))
+ {
+ delete_all_aliases ();
+ list = list->next;
+ }
+ else if (ISOPTION (word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else
+ {
+ bad_option (word);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ while (list)
+ {
+ alias = find_alias (list->word->word);
+
+ if (alias)
+ remove_alias (alias->name);
+ else
+ {
+ if (interactive)
+ builtin_error ("`%s' not an alias", list->word->word);
+
+ any_failed++;
+ }
+
+ list = list->next;
+ }
+
+ if (any_failed)
+ return (EXECUTION_FAILURE);
+ else
+ return (EXECUTION_SUCCESS);
+}
+
+/* Output ALIAS in such a way as to allow it to be read back in. */
+static void
+print_alias (alias)
+ ASSOC *alias;
+{
+ char *value = single_quote (alias->value);
+
+ printf ("alias %s=%s\n", alias->name, value);
+ free (value);
+
+ fflush (stdout);
+}
+#endif /* ALIAS */
diff --git a/builtins/bashgetopt.c b/builtins/bashgetopt.c
new file mode 100644
index 0000000..95dcaac
--- /dev/null
+++ b/builtins/bashgetopt.c
@@ -0,0 +1,136 @@
+/* bashgetopt.c -- `getopt' for use by the builtins. */
+
+/* Copyright (C) 1992 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <errno.h>
+#include "shell.h"
+
+#include "bashansi.h"
+
+#define ERR(S, C) builtin_error("%s%c", (S), (C))
+
+static int sp;
+
+char *list_optarg;
+int list_optopt;
+
+static WORD_LIST *lhead = (WORD_LIST *)NULL;
+WORD_LIST *lcurrent = (WORD_LIST *)NULL;
+WORD_LIST *loptend; /* Points to the first non-option argument in the list */
+
+int
+internal_getopt(list, opts)
+WORD_LIST *list;
+char *opts;
+{
+ register int c;
+ register char *cp;
+
+ if (!list) {
+ list_optarg = (char *)NULL;
+ loptend = (WORD_LIST *)NULL; /* No non-option arguments */
+ return -1;
+ }
+
+ if (list != lhead || !lhead) {
+ /* Hmmm.... called with a different word list. Reset. */
+ sp = 1;
+ lcurrent = lhead = list;
+ loptend = (WORD_LIST *)NULL;
+ }
+
+ if (sp == 1) {
+ if (!lcurrent ||
+ (lcurrent->word->word[0] != '-' || lcurrent->word->word[1] == '\0')) {
+ lhead = (WORD_LIST *)NULL;
+ loptend = lcurrent;
+ return(-1);
+ } else if (lcurrent->word->word[0] == '-' &&
+ lcurrent->word->word[1] == '-' &&
+ lcurrent->word->word[2] == 0) {
+ lhead = (WORD_LIST *)NULL;
+ loptend = lcurrent->next;
+ return(-1);
+ }
+ }
+
+ list_optopt = c = lcurrent->word->word[sp];
+
+ if (c == ':' || (cp = strchr(opts, c)) == NULL) {
+ ERR("illegal option: -", c);
+ if (lcurrent->word->word[++sp] == '\0') {
+ lcurrent = lcurrent->next;
+ sp = 1;
+ }
+ list_optarg = NULL;
+ if (lcurrent)
+ loptend = lcurrent->next;
+ return('?');
+ }
+
+ if (*++cp == ':') {
+ /* Option requires an argument. */
+ /* We allow -l2 as equivalent to -l 2 */
+ if (lcurrent->word->word[sp+1] != '\0') {
+ list_optarg = &(lcurrent->word->word[sp+1]);
+ lcurrent = lcurrent->next;
+ } else if (lcurrent->next == NULL) {
+ ERR("option requires an argument: -", c);
+ sp = 1;
+ list_optarg = (char *)NULL;
+ return('?');
+ } else {
+ lcurrent = lcurrent->next;
+ list_optarg = lcurrent->word->word;
+ lcurrent = lcurrent->next;
+ }
+ sp = 1;
+ } else {
+ /* No argument, just return the option. */
+ if (lcurrent->word->word[++sp] == '\0') {
+ sp = 1;
+ lcurrent = lcurrent->next;
+ }
+ list_optarg = (char *)NULL;
+ }
+
+ return(c);
+}
+
+/*
+ * reset_internal_getopt -- force the in[ft]ernal getopt to reset
+ */
+
+void
+reset_internal_getopt ()
+{
+ lhead = lcurrent = loptend = (WORD_LIST *)NULL;
+ sp = 1;
+}
+
+void
+report_bad_option ()
+{
+ char s[3];
+
+ s[0] = '-';
+ s[1] = list_optopt;
+ s[2] = '\0';
+ bad_option (s);
+}
diff --git a/builtins/bashgetopt.h b/builtins/bashgetopt.h
new file mode 100644
index 0000000..0360dbb
--- /dev/null
+++ b/builtins/bashgetopt.h
@@ -0,0 +1,37 @@
+/* bashgetopt.h -- extern declarations for stuff defined in bashgetopt.c. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* See getopt.h for the explanation of these variables. */
+
+#if !defined (__BASH_GETOPT_H)
+# define __BASH_GETOPT_H
+
+extern char *list_optarg;
+
+extern int list_optopt;
+
+extern WORD_LIST *lcurrent;
+extern WORD_LIST *loptend;
+
+extern int internal_getopt ();
+extern void reset_internal_getopt ();
+extern void report_bad_option ();
+
+#endif /* !__BASH_GETOPT_H */
diff --git a/builtins/bind.def b/builtins/bind.def
new file mode 100644
index 0000000..cdcd6a3
--- /dev/null
+++ b/builtins/bind.def
@@ -0,0 +1,219 @@
+This file is bind.def, from which is created bind.c.
+It implements the builtin "bind" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES bind.c
+
+$BUILTIN bind
+$DEPENDS_ON READLINE
+$FUNCTION bind_builtin
+$SHORT_DOC bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline-function]
+Bind a key sequence to a Readline function, or to a macro. The
+syntax is equivalent to that found in ~/.inputrc, but must be
+passed as a single argument: bind '"\C-x\C-r": re-read-init-file'.
+Arguments we accept:
+ -m keymap Use `keymap' as the keymap for the duration of this
+ command. Acceptable keymap names are emacs,
+ emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,
+ vi-command, and vi-insert.
+ -l List names of functions.
+ -v List function names and bindings.
+ -d Dump functions and bindings such that they
+ can be read back in.
+ -f filename Read key bindings from FILENAME.
+ -q function-name Query about which keys invoke the named function.
+$END
+
+#include <stdio.h>
+#include "../shell.h"
+#if defined (READLINE)
+#include <errno.h>
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+#include <readline/readline.h>
+#include <readline/history.h>
+#include "bashgetopt.h"
+
+static int query_bindings ();
+
+extern int bash_readline_initialized;
+extern int no_line_editing;
+
+#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0)
+
+#define USAGE "usage: bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline_func]"
+
+int
+bind_builtin (list)
+ WORD_LIST *list;
+{
+ int return_code = EXECUTION_SUCCESS;
+ FILE *old_rl_outstream;
+ Keymap kmap, saved_keymap;
+ int lflag, dflag, fflag, vflag, qflag, mflag, opt;
+ char *initfile, *map_name, *fun_name;
+
+ if (no_line_editing)
+ return (EXECUTION_FAILURE);
+
+ kmap = saved_keymap = (Keymap) NULL;
+ lflag = dflag = vflag = fflag = qflag = mflag = 0;
+ initfile = map_name = fun_name = (char *)NULL;
+
+ if (!bash_readline_initialized)
+ initialize_readline ();
+
+ /* Cannot use unwind_protect_pointer () on "FILE *", it is only
+ guaranteed to work for strings. */
+ /* XXX -- see if we can use unwind_protect here */
+ old_rl_outstream = rl_outstream;
+ rl_outstream = stdout;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "lvdf:q:m:")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'l':
+ lflag++;
+ break;
+
+ case 'v':
+ vflag++;
+ break;
+
+ case 'd':
+ dflag++;
+ break;
+
+ case 'f':
+ fflag++;
+ initfile = list_optarg;
+ break;
+
+ case 'm':
+ mflag++;
+ map_name = list_optarg;
+ break;
+
+ case 'q':
+ qflag++;
+ fun_name = list_optarg;
+ break;
+
+ default:
+ builtin_error (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 (mflag && map_name)
+ {
+ kmap = rl_get_keymap_by_name (map_name);
+ if (!kmap)
+ {
+ builtin_error ("`%s': illegal 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 (lflag)
+ rl_list_funmap_names (0);
+
+ if (vflag)
+ rl_function_dumper (0);
+
+ if (dflag)
+ rl_function_dumper (1);
+
+ if (fflag && initfile)
+ {
+ if (rl_read_init_file (initfile) != 0)
+ {
+ builtin_error ("cannot read %s: %s", initfile, strerror (errno));
+ BIND_RETURN (EXECUTION_FAILURE);
+ }
+ }
+
+ if (qflag && fun_name)
+ return_code = query_bindings (fun_name);
+
+ /* 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);
+
+ rl_outstream = old_rl_outstream;
+ return (return_code);
+}
+
+static int
+query_bindings (name)
+ char *name;
+{
+ Function *function;
+ char **keyseqs;
+ int j;
+
+ function = rl_named_function (name);
+ if (!function)
+ {
+ builtin_error ("unknown function name `%s'", 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");
+ free_array (keyseqs);
+ return EXECUTION_SUCCESS;
+}
+#endif /* READLINE */
diff --git a/builtins/break.def b/builtins/break.def
new file mode 100644
index 0000000..d72f9e3
--- /dev/null
+++ b/builtins/break.def
@@ -0,0 +1,110 @@
+This file is break.def, from which is created break.c.
+It implements the builtins "break" and "continue" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES break.c
+
+$BUILTIN break
+$FUNCTION break_builtin
+$SHORT_DOC break [n]
+Exit from within a FOR, WHILE or UNTIL loop. If N is specified,
+break N levels.
+$END
+
+#include "../shell.h"
+
+extern char *this_command_name;
+
+static int check_loop_level ();
+
+/* 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. */
+break_builtin (list)
+ WORD_LIST *list;
+{
+ int newbreak;
+
+ if (!check_loop_level ())
+ return (EXECUTION_FAILURE);
+
+ newbreak = get_numeric_arg (list);
+
+ if (newbreak <= 0)
+ return (EXECUTION_FAILURE);
+
+ if (newbreak > loop_level)
+ newbreak = loop_level;
+
+ breaking = newbreak;
+
+ return (EXECUTION_SUCCESS);
+}
+
+$BUILTIN continue
+$FUNCTION continue_builtin
+$SHORT_DOC continue [n]
+Resume the next iteration of the enclosing FOR, WHILE or UNTIL loop.
+If N is specified, resume at the N-th enclosing loop.
+$END
+
+/* Set up to continue x levels, where x defaults to 1, but can be specified
+ as the first argument. */
+continue_builtin (list)
+ WORD_LIST *list;
+{
+ int newcont;
+
+ if (!check_loop_level ())
+ return (EXECUTION_FAILURE);
+
+ newcont = get_numeric_arg (list);
+
+ if (newcont <= 0)
+ 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)
+ builtin_error ("Only meaningful in a `for', `while', or `until' loop");
+#endif /* BREAK_COMPLAINS */
+
+ return (loop_level);
+}
diff --git a/builtins/builtin.def b/builtins/builtin.def
new file mode 100644
index 0000000..824b30d
--- /dev/null
+++ b/builtins/builtin.def
@@ -0,0 +1,67 @@
+This file is builtin.def, from which is created builtin.c.
+It implements the builtin "builtin" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES builtin.c
+
+$BUILTIN builtin
+$FUNCTION builtin_builtin
+$SHORT_DOC builtin [shell-builtin [arg ...]]
+Run a shell builtin. This is useful when you wish to rename a
+shell builtin to be a function, but need the functionality of the
+builtin within the function itself.
+$END
+
+#include "../shell.h"
+
+#include "common.h"
+
+extern char *this_command_name;
+
+/* Run the command mentioned in list directly, without going through the
+ normal alias/function/builtin/filename lookup process. */
+builtin_builtin (list)
+ WORD_LIST *list;
+{
+ Function *function;
+ register char *command;
+
+ if (!list)
+ 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)
+ {
+ builtin_error ("%s: not a shell builtin", command);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ {
+ this_command_name = command;
+ list = list->next;
+ return ((*function) (list));
+ }
+}
diff --git a/builtins/cd.def b/builtins/cd.def
new file mode 100644
index 0000000..338f694
--- /dev/null
+++ b/builtins/cd.def
@@ -0,0 +1,689 @@
+This file is cd.def, from which is created cd.c. It implements the
+builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES cd.c
+
+#include <stdio.h>
+#include <sys/param.h>
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include <errno.h>
+#include <tilde/tilde.h>
+
+#include "../shell.h"
+#include "../flags.h"
+#include "../maxpath.h"
+#include "common.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+static int change_to_directory (), cd_to_string ();
+
+$BUILTIN cd
+$FUNCTION cd_builtin
+$SHORT_DOC cd [dir]
+Change the current directory to DIR. The variable $HOME is the
+default DIR. The variable $CDPATH defines the search path for
+the directory containing DIR. Alternative directory names are
+separated by a colon (:). A null directory name is the same as
+the current directory, i.e. `.'. If DIR begins with a slash (/),
+then $CDPATH is not used. If the directory is not found, and the
+shell variable `cdable_vars' exists, then try the word as a variable
+name. If that variable has a value, then cd to the value of that
+variable.
+$END
+
+/* 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;
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted)
+ {
+ builtin_error ("restricted");
+ return (EXECUTION_FAILURE);
+ }
+#endif /* RESTRICTED_SHELL */
+
+ if (list)
+ {
+ char *extract_colon_unit ();
+ char *path_string = get_string_value ("CDPATH");
+ char *path;
+ int path_index = 0, dirlen, pathlen;
+
+ dirname = list->word->word;
+
+ if (path_string && !absolute_pathname (dirname))
+ {
+ while ((path = extract_colon_unit (path_string, &path_index)))
+ {
+ char *dir;
+
+ if (*path == '~')
+ {
+ char *te_string = tilde_expand (path);
+
+ free (path);
+ path = te_string;
+ }
+
+ if (!*path)
+ {
+ free (path);
+ path = xmalloc (2);
+ path[0] = '.'; /* by definition. */
+ path[1] = '\0';
+ }
+
+ dirlen = strlen (dirname);
+ pathlen = strlen (path);
+ dir = xmalloc (2 + dirlen + pathlen);
+ strcpy (dir, path);
+ if (path[pathlen - 1] != '/')
+ {
+ dir[pathlen++] = '/';
+ dir[pathlen] = '\0';
+ }
+ strcpy (dir + pathlen, dirname);
+ free (path);
+
+ if (change_to_directory (dir))
+ {
+ /* replaces (strncmp (dir, "./", 2) != 0) */
+ if (dir[0] != '.' || dir[1] != '/')
+ printf ("%s\n", dir);
+
+ free (dir);
+ goto bind_and_exit;
+ }
+ else
+ free (dir);
+ }
+ }
+
+ if (!change_to_directory (dirname))
+ {
+ /* Maybe this is `cd -', equivalent to `cd $OLDPWD' */
+ if (dirname[0] == '-' && dirname[1] == '\0')
+ {
+ char *t = get_string_value ("OLDPWD");
+
+ if (t && change_to_directory (t))
+ goto bind_and_exit;
+ }
+
+ /* If the user requests it, then perhaps this is the name of
+ a shell variable, whose value contains the directory to
+ change to. If that is the case, then change to that
+ directory. */
+ if (find_variable ("cdable_vars"))
+ {
+ char *t = get_string_value (dirname);
+
+ if (t && change_to_directory (t))
+ {
+ printf ("%s\n", t);
+ goto bind_and_exit;
+ }
+ }
+
+ file_error (dirname);
+ return (EXECUTION_FAILURE);
+ }
+ goto bind_and_exit;
+ }
+ else
+ {
+ dirname = get_string_value ("HOME");
+
+ if (!dirname)
+ return (EXECUTION_FAILURE);
+
+ if (!change_to_directory (dirname))
+ {
+ file_error (dirname);
+ return (EXECUTION_FAILURE);
+ }
+
+ bind_and_exit:
+ {
+ char *directory;
+
+ directory = get_working_directory ("cd");
+
+ bind_variable ("OLDPWD", get_string_value ("PWD"));
+ bind_variable ("PWD", directory);
+
+ FREE (directory);
+ }
+ return (EXECUTION_SUCCESS);
+ }
+}
+
+$BUILTIN pwd
+$FUNCTION pwd_builtin
+$SHORT_DOC pwd
+Print the current working directory.
+$END
+
+/* Non-zero means that pwd always give verbatim directory, regardless of
+ symbolic link following. */
+static int verbatim_pwd;
+
+/* Print the name of the current working directory. */
+pwd_builtin (list)
+ WORD_LIST *list;
+{
+ char *directory, *s;
+
+#if 0
+ no_args (list);
+#else
+ verbatim_pwd = no_symbolic_links;
+ if (list && (s = list->word->word) && s[0] == '-' && s[1] == 'P' && !s[2])
+ verbatim_pwd = 1;
+#endif
+
+ if (verbatim_pwd)
+ {
+ char *buffer = xmalloc (MAXPATHLEN);
+ directory = getwd (buffer);
+
+ if (!directory)
+ {
+ builtin_error ("%s", buffer);
+ free (buffer);
+ }
+ }
+ else
+ directory = get_working_directory ("pwd");
+
+ if (directory)
+ {
+ printf ("%s\n", directory);
+ fflush (stdout);
+ free (directory);
+ return (EXECUTION_SUCCESS);
+ }
+ else
+ return (EXECUTION_FAILURE);
+}
+
+$BUILTIN pushd
+$FUNCTION pushd_builtin
+$DEPENDS_ON PUSHD_AND_POPD
+$SHORT_DOC pushd [dir | +n | -n]
+Adds a directory to the top of the directory stack, or rotates
+the stack, making the new top of the stack the current working
+directory. With no arguments, exchanges the top two directories.
+
++n Rotates the stack so that the Nth directory (counting
+ from the left of the list shown by `dirs') is at the top.
+
+-n Rotates the stack so that the Nth directory (counting
+ from the right) is at the top.
+
+dir adds DIR to the directory stack at the top, making it the
+ new current working directory.
+
+You can see the directory stack with the `dirs' command.
+$END
+
+#if defined (PUSHD_AND_POPD)
+/* Some useful commands whose behaviour has been observed in Csh. */
+
+/* The list of remembered directories. */
+static char **pushd_directory_list = (char **)NULL;
+
+/* Number of existing slots in this list. */
+static int directory_list_size = 0;
+
+/* Offset to the end of the list. */
+static int directory_list_offset = 0;
+
+pushd_builtin (list)
+ WORD_LIST *list;
+{
+ char *temp, *current_directory;
+ int j = directory_list_offset - 1;
+ char direction = '+';
+
+ /* If there is no argument list then switch current and
+ top of list. */
+ if (!list)
+ {
+ if (!directory_list_offset)
+ {
+ builtin_error ("No other directory");
+ return (EXECUTION_FAILURE);
+ }
+
+ current_directory = get_working_directory ("pushd");
+ if (!current_directory)
+ return (EXECUTION_FAILURE);
+
+ temp = pushd_directory_list[j];
+ pushd_directory_list[j] = current_directory;
+ goto change_to_temp;
+ }
+ else
+ {
+ direction = *(list->word->word);
+ if (direction == '+' || direction == '-')
+ {
+ int num;
+ if (1 == sscanf (&(list->word->word)[1], "%d", &num))
+ {
+ if (direction == '-')
+ num = directory_list_offset - num;
+
+ if (num > directory_list_offset || num < 0)
+ {
+ if (!directory_list_offset)
+ builtin_error ("Directory stack empty");
+ else
+ builtin_error ("Stack contains only %d directories",
+ directory_list_offset + 1);
+ return (EXECUTION_FAILURE);
+ }
+ else
+ {
+ /* Rotate the stack num times. Remember, the
+ current directory acts like it is part of the
+ stack. */
+ temp = get_working_directory ("pushd");
+
+ if (!num)
+ goto change_to_temp;
+
+ do
+ {
+ char *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);
+
+ temp = savestring (temp);
+ change_to_temp:
+ {
+ int tt = EXECUTION_FAILURE;
+
+ if (temp)
+ {
+ tt = cd_to_string (temp);
+ free (temp);
+ }
+
+ if ((tt == EXECUTION_SUCCESS))
+ dirs_builtin ((WORD_LIST *)NULL);
+
+ return (tt);
+ }
+ }
+ }
+ }
+
+ /* 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)
+ return (EXECUTION_FAILURE);
+
+ if (cd_builtin (list) == EXECUTION_SUCCESS)
+ {
+ if (directory_list_offset == directory_list_size)
+ {
+ pushd_directory_list = (char **)
+ xrealloc (pushd_directory_list,
+ (directory_list_size += 10) * sizeof (char *));
+ }
+ pushd_directory_list[directory_list_offset++] = current_directory;
+
+ dirs_builtin ((WORD_LIST *)NULL);
+
+ return (EXECUTION_SUCCESS);
+ }
+ else
+ {
+ free (current_directory);
+ return (EXECUTION_FAILURE);
+ }
+ }
+}
+#endif /* PUSHD_AND_POPD */
+
+$BUILTIN dirs
+$FUNCTION dirs_builtin
+$DEPENDS_ON PUSHD_AND_POPD
+$SHORT_DOC dirs [-l]
+Display the list of currently remembered directories. Directories
+find their way onto the list with the `pushd' command; you can get
+back up through the list with the `popd' command.
+
+The -l flag specifies that `dirs' should not print shorthand versions
+of directories which are relative to your home directory. This means
+that `~/bin' might be displayed as `/homes/bfox/bin'.
+$END
+
+#if defined (PUSHD_AND_POPD)
+/* Print the current list of directories on the directory stack. */
+dirs_builtin (list)
+ WORD_LIST *list;
+{
+ int i, format, desired_index, index_flag;
+ char *temp, *w;
+
+ format = index_flag = 0;
+ desired_index = -1;
+ /* Maybe do long form or print specific dir stack entry? */
+ while (list)
+ {
+ if (strcmp (list->word->word, "-l") == 0)
+ {
+ format++;
+ list = list->next;
+ }
+ else if (*list->word->word == '+' && all_digits (list->word->word + 1))
+ {
+ w = list->word->word + 1;
+ index_flag = 1;
+ i = atoi (w);
+ /* dirs +0 prints the current working directory. */
+ if (i == 0)
+ desired_index = i;
+ else if (i == directory_list_offset)
+ {
+ desired_index = 0;
+ index_flag = 2;
+ }
+ else
+ desired_index = directory_list_offset - i;
+ list = list->next;
+ }
+ else if (*list->word->word == '-' && all_digits (list->word->word + 1))
+ {
+ w = list->word->word + 1;
+ i = atoi (w);
+ index_flag = 2;
+ /* dirs -X where X is directory_list_offset prints the current
+ working directory. */
+ if (i == directory_list_offset)
+ {
+ index_flag = 1;
+ desired_index = 0;
+ }
+ else
+ desired_index = i;
+ list = list->next;
+ }
+ else
+ {
+ bad_option (list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
+ {
+ if (directory_list_offset == 0)
+ builtin_error ("directory stack empty");
+ else
+ builtin_error ("%s: bad directory stack index", w);
+ return (EXECUTION_FAILURE);
+ }
+
+ /* The first directory printed is always the current working directory. */
+ if (!index_flag || (index_flag == 1 && desired_index == 0))
+ {
+ temp = get_working_directory ("dirs");
+ if (!temp)
+ temp = savestring ("<no directory>");
+ printf ("%s", format ? temp : polite_directory_format (temp));
+ free (temp);
+ if (index_flag)
+ {
+ putchar ('\n');
+ return EXECUTION_SUCCESS;
+ }
+ }
+
+#define DIRSTACK_ENTRY(i) \
+ format ? pushd_directory_list[i] \
+ : polite_directory_format (pushd_directory_list[i])
+
+ /* Now print the requested directory stack entries. */
+ if (index_flag)
+ printf ("%s", DIRSTACK_ENTRY (desired_index));
+ else
+ for (i = (directory_list_offset - 1); i > -1; i--)
+ printf (" %s", DIRSTACK_ENTRY (i));
+
+ putchar ('\n');
+ fflush (stdout);
+ return (EXECUTION_SUCCESS);
+}
+#endif /* PUSHD_AND_POPD */
+
+$BUILTIN popd
+$FUNCTION popd_builtin
+$DEPENDS_ON PUSHD_AND_POPD
+$SHORT_DOC popd [+n | -n]
+Removes entries from the directory stack. With no arguments,
+removes the top directory from the stack, and cd's to the new
+top directory.
+
++n removes the Nth entry counting from the left of the list
+ shown by `dirs', starting with zero. For example: `popd +0'
+ removes the first directory, `popd +1' the second.
+
+-n removes the Nth entry counting from the right of the list
+ shown by `dirs', starting with zero. For example: `popd -0'
+ removes the last directory, `popd -1' the next to last.
+
+You can see the directory stack with the `dirs' command.
+$END
+
+#if defined (PUSHD_AND_POPD)
+/* 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. */
+popd_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ int which = 0;
+ char direction = '+';
+
+ if (list)
+ {
+ direction = *(list->word->word);
+
+ if ((direction != '+' && direction != '-') ||
+ (1 != sscanf (&((list->word->word)[1]), "%d", &which)))
+ {
+ builtin_error ("bad arg `%s'", list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ if (which > directory_list_offset || (!directory_list_offset && !which))
+ {
+ if (!directory_list_offset)
+ builtin_error ("Directory stack empty");
+ else
+ builtin_error ("Stack contains only %d directories",
+ directory_list_offset + 1);
+ return (EXECUTION_FAILURE);
+ }
+
+ /* Handle case of no specification, or top of stack specification. */
+ if ((direction == '+' && which == 0) ||
+ (direction == '-' && which == directory_list_offset))
+ {
+ i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
+ 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. */
+
+ if (direction == '+')
+ i = directory_list_offset - which;
+ else
+ i = 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);
+}
+#endif /* PUSHD_AND_POPD */
+
+/* Do the work of changing to the directory NEWDIR. Handle symbolic
+ link following, etc. */
+
+static int
+change_to_directory (newdir)
+ char *newdir;
+{
+ char *t;
+
+ if (!no_symbolic_links)
+ {
+ int chdir_return = 0;
+ char *tdir = (char *)NULL;
+
+ if (!the_current_working_directory)
+ {
+ t = get_working_directory ("cd_links");
+ FREE (t);
+ }
+
+ if (the_current_working_directory)
+ t = make_absolute (newdir, the_current_working_directory);
+ else
+ t = savestring (newdir);
+
+ /* TDIR is the canonicalized absolute pathname of the NEWDIR. */
+ tdir = canonicalize_pathname (t);
+
+ /* Use the canonicalized version of NEWDIR, or, if canonicalization
+ failed, use the non-canonical form. */
+ if (tdir && *tdir)
+ free (t);
+ else
+ {
+ FREE (tdir);
+
+ tdir = t;
+ }
+
+ if (chdir (tdir) < 0)
+ {
+ int err;
+
+ chdir_return = 0;
+ free (tdir);
+
+ err = errno;
+
+ /* We failed changing to the canonicalized directory name. Try
+ what the user passed verbatim. If we succeed, reinitialize
+ the_current_working_directory. */
+ if (chdir (newdir) == 0)
+ {
+ chdir_return = 1;
+ if (the_current_working_directory)
+ {
+ free (the_current_working_directory);
+ the_current_working_directory = (char *)NULL;
+ }
+
+ tdir = get_working_directory ("cd");
+ FREE (tdir);
+ }
+ else
+ errno = err;
+ }
+ else
+ {
+ chdir_return = 1;
+
+ FREE (the_current_working_directory);
+ the_current_working_directory = tdir;
+ }
+
+ return (chdir_return);
+ }
+ else
+ {
+ if (chdir (newdir) < 0)
+ return (0);
+ else
+ return (1);
+ }
+}
+
+/* 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 = make_word_list (make_word (name), NULL);
+ int result = (cd_builtin (tlist));
+ dispose_words (tlist);
+ return (result);
+}
diff --git a/builtins/colon.def b/builtins/colon.def
new file mode 100644
index 0000000..4ae5b65
--- /dev/null
+++ b/builtins/colon.def
@@ -0,0 +1,37 @@
+This file is colon.def, from which is created colon.c.
+It implements the builtin ":" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES colon.c
+
+$BUILTIN :
+$DOCNAME colon_builtin
+$FUNCTION colon_builtin
+$SHORT_DOC :
+No effect; the command does nothing. A zero exit code is returned.
+$END
+
+/* Do nothing. This command is a no-op. */
+int
+colon_builtin (ignore)
+ char *ignore;
+{
+ return (0);
+}
diff --git a/builtins/command.def b/builtins/command.def
new file mode 100644
index 0000000..b84613e
--- /dev/null
+++ b/builtins/command.def
@@ -0,0 +1,177 @@
+This file is command.def, from which is created command.c.
+It implements the builtin "command" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES command.c
+
+$BUILTIN command
+$FUNCTION command_builtin
+$SHORT_DOC command [-pVv] [command [arg ...]]
+Runs COMMAND with ARGS ignoring shell functions. If you have a shell
+function called `ls', and you wish to call the command `ls', you can
+say "command ls". If the -p option is given, a default value is used
+for PATH that is guaranteed to find all of the standard utilities. If
+the -V or -v option is given, a string is printed describing COMMAND.
+The -V option produces a more verbose description.
+$END
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+#include "bashgetopt.h"
+
+extern int subshell_environment;
+
+static void restore_path ();
+static char *get_standard_path ();
+
+/* Run the commands mentioned in LIST without paying attention to shell
+ functions. */
+int
+command_builtin (list)
+ WORD_LIST *list;
+{
+ int result, verbose = 0, use_standard_path = 0, opt;
+ char *old_path;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "pvV")) != -1)
+ {
+ switch (opt)
+ {
+ case 'p':
+ use_standard_path = 1;
+ break;
+ case 'V':
+ verbose = 2;
+ break;
+ case 'v':
+ verbose = 4;
+ break;
+
+ default:
+ report_bad_option ();
+ builtin_error ("usage: command [-pvV] [command [arg...]]");
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (!list)
+ return (EXECUTION_SUCCESS);
+
+ if (verbose)
+ {
+ int found, any_found = 0;
+
+ while (list)
+ {
+
+ found = describe_command (list->word->word, verbose, 0);
+
+ if (!found)
+ builtin_error ("%s: not found", list->word->word);
+
+ any_found += found;
+ list = list->next;
+ }
+ return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+ }
+
+ begin_unwind_frame ("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 *command;
+
+ if (use_standard_path)
+ {
+ char *standard_path;
+
+ old_path = get_string_value ("PATH");
+ if (old_path)
+ old_path = savestring (old_path);
+ else
+ old_path = savestring ("");
+ add_unwind_protect ((Function *)restore_path, old_path);
+
+ standard_path = get_standard_path ();
+ bind_variable ("PATH", standard_path);
+ free (standard_path);
+ }
+ command = make_bare_simple_command ();
+ command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
+ command->value.Simple->redirects = (REDIRECT *)NULL;
+ command->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION);
+ command->value.Simple->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION);
+ /* 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;
+ }
+ 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;
+{
+ bind_variable ("PATH", var);
+ free (var);
+}
+
+/* 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 (hpux_7) && !defined (NetBSD)
+ char *p;
+ size_t len;
+
+ len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
+ p = xmalloc ((int)len + 2);
+ *p = '\0';
+ confstr (_CS_PATH, p, len);
+ return (p);
+#else /* !_CSPATH || hpux_7 || NetBSD */
+# if defined (CS_PATH)
+ return (savestring (CS_PATH));
+# else
+ return (savestring (STANDARD_UTILS_PATH));
+# endif /* !CS_PATH */
+#endif /* !_CS_PATH || hpux_7 */
+}
diff --git a/builtins/common.c b/builtins/common.c
new file mode 100644
index 0000000..ff940b5
--- /dev/null
+++ b/builtins/common.c
@@ -0,0 +1,829 @@
+/* Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "../posixstat.h"
+#if defined (HAVE_VFPRINTF)
+#include <varargs.h>
+#endif /* VFPRINTF */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+#include "../unwind_prot.h"
+#include "../maxpath.h"
+#include "../jobs.h"
+#include "../builtins.h"
+#include "../input.h"
+#include "../execute_cmd.h"
+#include "hashcom.h"
+#include "common.h"
+#include <tilde/tilde.h>
+
+#if defined (HISTORY)
+# include "../bashhist.h"
+#endif
+
+extern int no_symbolic_links, interactive, interactive_shell;
+extern int indirection_level, startup_state;
+extern int last_command_exit_value;
+extern int hashing_disabled;
+extern int variable_context;
+extern char *this_command_name, *shell_name;
+extern COMMAND *global_command;
+extern HASH_TABLE *hashed_filenames;
+
+/* Read a numeric arg for this_command_name, the name of the shell builtin
+ that wants it. LIST is the word list that the arg is to come from. */
+int
+get_numeric_arg (list)
+ WORD_LIST *list;
+{
+ int count = 1;
+
+ if (list)
+ {
+ register char *arg;
+ int sign = 1;
+
+ arg = list->word->word;
+ if (!arg)
+ goto bad_number;
+
+ /* Skip optional leading white space. */
+ while (whitespace (*arg))
+ arg++;
+
+ if (!*arg)
+ goto bad_number;
+
+ /* We allow leading `-' or `+'. */
+ if (*arg == '-' || *arg == '+')
+ {
+ if (!digit (arg[1]))
+ goto bad_number;
+
+ if (*arg == '-')
+ sign = -1;
+
+ arg++;
+ }
+
+ for (count = 0; digit (*arg); arg++)
+ count = (count * 10) + digit_value (*arg);
+
+ /* Skip trailing whitespace, if any. */
+ while (whitespace (*arg))
+ arg++;
+
+ if (!*arg)
+ count = count * sign;
+ else
+ {
+ bad_number:
+ builtin_error ("bad non-numeric arg `%s'", list->word->word);
+ throw_to_top_level ();
+ }
+ no_args (list->next);
+ }
+ return (count);
+}
+
+/* This is a lot like report_error (), but it is for shell builtins
+ instead of shell control structures, and it won't ever exit the
+ shell. */
+#if defined (HAVE_VFPRINTF)
+void
+builtin_error (va_alist)
+ va_dcl
+{
+ char *format;
+ va_list args;
+
+ if (this_command_name && *this_command_name)
+ fprintf (stderr, "%s: ", this_command_name);
+
+ va_start (args);
+ format = va_arg (args, char *);
+ vfprintf (stderr, format, args);
+ va_end (args);
+ fprintf (stderr, "\n");
+}
+#else /* !HAVE_VFPRINTF */
+void
+builtin_error (format, arg1, arg2, arg3, arg4, arg5)
+ char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
+{
+ if (this_command_name && *this_command_name)
+ fprintf (stderr, "%s: ", this_command_name);
+
+ fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+}
+#endif /* !HAVE_VFPRINTF */
+
+/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
+ non-zero, then discard whatever the existing arguments are, else
+ only discard the ones that are to be replaced. */
+void
+remember_args (list, destructive)
+ WORD_LIST *list;
+ int destructive;
+{
+ register int i;
+
+ for (i = 1; i < 10; i++)
+ {
+ if (destructive && dollar_vars[i])
+ {
+ free (dollar_vars[i]);
+ dollar_vars[i] = (char *)NULL;
+ }
+
+ if (list)
+ {
+ if (!destructive && dollar_vars[i])
+ free (dollar_vars[i]);
+
+ dollar_vars[i] = savestring (list->word->word);
+ list = list->next;
+ }
+ }
+
+ /* If arguments remain, assign them to REST_OF_ARGS.
+ Note that copy_word_list (NULL) returns NULL, and
+ that dispose_words (NULL) does nothing. */
+ if (destructive || list)
+ {
+ dispose_words (rest_of_args);
+ rest_of_args = copy_word_list (list);
+ }
+
+ if (destructive)
+ set_dollar_vars_changed ();
+}
+
+/* Return if LIST is NULL else barf and jump to top_level. */
+void
+no_args (list)
+ WORD_LIST *list;
+{
+ if (list)
+ {
+ builtin_error ("extra arguments");
+ longjmp (top_level, DISCARD);
+ }
+}
+
+/* Return the octal number parsed from STRING, or -1 to indicate
+ that the string contained a bad number. */
+int
+read_octal (string)
+ char *string;
+{
+ int result = 0;
+ int digits = 0;
+
+ while (*string && *string >= '0' && *string < '8')
+ {
+ digits++;
+ result = (result * 8) + *string++ - '0';
+ }
+
+ if (!digits || result > 0777 || *string)
+ result = -1;
+
+ return (result);
+}
+
+/* Temporary static. */
+static char *dotted_filename = (char *)NULL;
+
+/* Return the full pathname that FILENAME hashes to. If FILENAME
+ is hashed, but data->check_dot is non-zero, check ./FILENAME
+ and return that if it is executable. */
+char *
+find_hashed_filename (filename)
+ char *filename;
+{
+ register BUCKET_CONTENTS *item;
+
+ if (hashing_disabled)
+ return ((char *)NULL);
+
+ item = find_hash_item (filename, hashed_filenames);
+
+ if (item)
+ {
+ /* If this filename is hashed, but `.' comes before it in the path,
+ then see if `./filename' is an executable. */
+ if (pathdata(item)->check_dot)
+ {
+ if (dotted_filename)
+ free (dotted_filename);
+
+ dotted_filename = (char *)xmalloc (3 + strlen (filename));
+ strcpy (dotted_filename, "./");
+ strcat (dotted_filename, filename);
+
+ if (executable_file (dotted_filename))
+ return (dotted_filename);
+
+ /* Watch out. If this file was hashed to "./filename", and
+ "./filename" is not executable, then return NULL. */
+
+ /* Since we already know "./filename" is not executable, what
+ we're really interested in is whether or not the `path'
+ portion of the hashed filename is equivalent to the current
+ directory, but only if it starts with a `.'. (This catches
+ ./. and so on.) same_file () is in execute_cmd.c; it tests
+ general Unix file equivalence -- same device and inode. */
+ {
+ char *path = pathdata (item)->path;
+
+ if (*path == '.')
+ {
+ int same = 0;
+ char *tail;
+
+ tail = (char *) strrchr (path, '/');
+
+ if (tail)
+ {
+ *tail = '\0';
+ same = same_file
+ (".", path, (struct stat *)NULL, (struct stat *)NULL);
+ *tail = '/';
+ }
+ if (same)
+ return ((char *)NULL);
+ }
+ }
+ }
+ return (pathdata (item)->path);
+ }
+ else
+ return ((char *)NULL);
+}
+
+/* Remove FILENAME from the table of hashed commands. */
+void
+remove_hashed_filename (filename)
+ char *filename;
+{
+ register BUCKET_CONTENTS *item;
+
+ if (hashing_disabled)
+ return;
+
+ item = remove_hash_item (filename, hashed_filenames);
+ if (item)
+ {
+ if (item->data)
+ {
+ free (pathdata(item)->path);
+ free (item->data);
+ }
+ if (item->key)
+ free (item->key);
+ free (item);
+ }
+}
+
+/* **************************************************************** */
+/* */
+/* Pushing and Popping a Context */
+/* */
+/* **************************************************************** */
+
+static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
+static int dollar_arg_stack_slots = 0;
+static int dollar_arg_stack_index = 0;
+
+void
+push_context ()
+{
+ push_dollar_vars ();
+ variable_context++;
+}
+
+void
+pop_context ()
+{
+ pop_dollar_vars ();
+ kill_all_local_variables ();
+ variable_context--;
+}
+
+/* Save the existing positional parameters on a stack. */
+void
+push_dollar_vars ()
+{
+ if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
+ {
+ dollar_arg_stack = (WORD_LIST **)
+ xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
+ * sizeof (WORD_LIST **));
+ }
+ dollar_arg_stack[dollar_arg_stack_index] = list_rest_of_args ();
+ dollar_arg_stack[++dollar_arg_stack_index] = (WORD_LIST *)NULL;
+}
+
+/* Restore the positional parameters from our stack. */
+void
+pop_dollar_vars ()
+{
+ if (!dollar_arg_stack || !dollar_arg_stack_index)
+ return;
+
+ remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
+ dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
+ dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
+}
+
+void
+dispose_saved_dollar_vars ()
+{
+ if (!dollar_arg_stack || !dollar_arg_stack_index)
+ return;
+
+ dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
+ dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
+}
+
+static int changed_dollar_vars = 0;
+
+/* Have the dollar variables been reset to new values since we last
+ checked? */
+dollar_vars_changed ()
+{
+ return (changed_dollar_vars);
+}
+
+void
+set_dollar_vars_unchanged ()
+{
+ changed_dollar_vars = 0;
+}
+
+void
+set_dollar_vars_changed ()
+{
+ changed_dollar_vars = 1;
+}
+
+/* Function called when one of the builtin commands detects a bad
+ option. */
+void
+bad_option (s)
+ char *s;
+{
+ builtin_error ("unknown option: %s", s);
+}
+
+/* Return a consed string which is the current working directory.
+ FOR_WHOM is the name of the caller for error printing. */
+char *the_current_working_directory = (char *)NULL;
+
+char *
+get_working_directory (for_whom)
+ char *for_whom;
+{
+ if (no_symbolic_links)
+ {
+ if (the_current_working_directory)
+ free (the_current_working_directory);
+
+ the_current_working_directory = (char *)NULL;
+ }
+
+ if (!the_current_working_directory)
+ {
+ char *directory;
+
+ the_current_working_directory = xmalloc (MAXPATHLEN);
+ directory = getwd (the_current_working_directory);
+ if (!directory)
+ {
+ if (for_whom && *for_whom)
+ fprintf (stderr, "%s: ", for_whom);
+ else
+ fprintf (stderr, "%s: ", get_name_for_error ());
+
+ fprintf (stderr, "could not get current directory: %s\n",
+ the_current_working_directory);
+
+ free (the_current_working_directory);
+ the_current_working_directory = (char *)NULL;
+ return (char *)NULL;
+ }
+ }
+
+ return (savestring (the_current_working_directory));
+}
+
+/* Make NAME our internal idea of the current working directory. */
+void
+set_working_directory (name)
+ char *name;
+{
+ if (the_current_working_directory)
+ free (the_current_working_directory);
+
+ the_current_working_directory = savestring (name);
+}
+
+#if defined (JOB_CONTROL)
+/* Return the job spec found in LIST. */
+get_job_spec (list)
+ WORD_LIST *list;
+{
+ register char *word;
+ int job = NO_JOB;
+ int substring = 0;
+
+ if (!list)
+ return (current_job);
+
+ word = list->word->word;
+
+ if (!*word)
+ return (current_job);
+
+ if (*word == '%')
+ word++;
+
+ if (digit (*word) && (sscanf (word, "%d", &job) == 1))
+ return (job - 1);
+
+ switch (*word)
+ {
+ case 0:
+ case '%':
+ case '+':
+ return (current_job);
+
+ case '-':
+ return (previous_job);
+
+ case '?': /* Substring search requested. */
+ substring++;
+ word++;
+ goto find_string;
+
+ default:
+ find_string:
+ {
+ register int i, wl = strlen (word);
+ for (i = 0; i < job_slots; i++)
+ {
+ if (jobs[i])
+ {
+ register PROCESS *p = jobs[i]->pipe;
+ do
+ {
+ if ((substring && strindex (p->command, word)) ||
+ (strncmp (p->command, word, wl) == 0))
+ if (job != NO_JOB)
+ {
+ builtin_error ("ambigious job spec: %s", word);
+ return (DUP_JOB);
+ }
+ else
+ job = i;
+
+ p = p->next;
+ }
+ while (p != jobs[i]->pipe);
+ }
+ }
+ return (job);
+ }
+ }
+}
+#endif /* JOB_CONTROL */
+
+int parse_and_execute_level = 0;
+
+/* How to force parse_and_execute () to clean up after itself. */
+void
+parse_and_execute_cleanup ()
+{
+ run_unwind_frame ("parse_and_execute_top");
+}
+
+/* Parse and execute the commands in STRING. Returns whatever
+ execute_command () returns. This frees STRING. INTERACT is
+ the new value for `interactive' while the commands are being
+ executed. A value of -1 means don't change it. */
+int
+parse_and_execute (string, from_file, interact)
+ char *string;
+ char *from_file;
+ int interact;
+{
+ int last_result = EXECUTION_SUCCESS;
+ int code = 0, jump_to_top_level = 0;
+ char *orig_string = string;
+
+ /* Unwind protect this invocation of parse_and_execute (). */
+ begin_unwind_frame ("parse_and_execute_top");
+ unwind_protect_int (parse_and_execute_level);
+ unwind_protect_jmp_buf (top_level);
+ unwind_protect_int (indirection_level);
+ if (interact != -1 && interactive != interact)
+ unwind_protect_int (interactive);
+
+#if defined (HISTORY)
+ if (interactive_shell)
+ {
+ unwind_protect_int (remember_on_history);
+# if defined (BANG_HISTORY)
+ unwind_protect_int (history_expansion_inhibited);
+# endif /* BANG_HISTORY */
+ }
+#endif /* HISTORY */
+
+ add_unwind_protect (pop_stream, (char *)NULL);
+ if (orig_string)
+ add_unwind_protect (xfree, orig_string);
+ end_unwind_frame ();
+
+ parse_and_execute_level++;
+ push_stream ();
+ indirection_level++;
+ if (interact != -1)
+ interactive = interact;
+
+#if defined (HISTORY)
+ /* We don't remember text read by the shell this way on
+ the history list, and we don't use !$ in shell scripts. */
+ remember_on_history = 0;
+# if defined (BANG_HISTORY)
+ history_expansion_inhibited = 1;
+# endif /* BANG_HISTORY */
+#endif /* HISTORY */
+
+ with_input_from_string (string, from_file);
+ {
+ COMMAND *command;
+
+ while (*(bash_input.location.string))
+ {
+ if (interrupt_state)
+ {
+ last_result = EXECUTION_FAILURE;
+ break;
+ }
+
+ /* Provide a location for functions which `longjmp (top_level)' to
+ jump to. This prevents errors in substitution from restarting
+ the reader loop directly, for example. */
+ code = setjmp (top_level);
+
+ if (code)
+ {
+ jump_to_top_level = 0;
+ switch (code)
+ {
+ case FORCE_EOF:
+ case EXITPROG:
+ run_unwind_frame ("pe_dispose");
+ /* Remember to call longjmp (top_level) after the old
+ value for it is restored. */
+ jump_to_top_level = 1;
+ goto out;
+
+ case DISCARD:
+ dispose_command (command);
+ run_unwind_frame ("pe_dispose");
+ last_command_exit_value = 1;
+ continue;
+
+ default:
+ programming_error ("bad jump to top_level: %d", code);
+ break;
+ }
+ }
+
+ if (parse_command () == 0)
+ {
+ if ((command = global_command) != (COMMAND *)NULL)
+ {
+ struct fd_bitmap *bitmap;
+
+ bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
+ begin_unwind_frame ("pe_dispose");
+ add_unwind_protect (dispose_fd_bitmap, bitmap);
+
+ global_command = (COMMAND *)NULL;
+
+#if defined (ONESHOT)
+ if (startup_state == 2 && *bash_input.location.string == '\0' &&
+ command->type == cm_simple && !command->redirects &&
+ !command->value.Simple->redirects)
+ {
+ command->flags |= CMD_NO_FORK;
+ command->value.Simple->flags |= CMD_NO_FORK;
+ }
+#endif /* ONESHOT */
+
+ last_result = execute_command_internal
+ (command, 0, NO_PIPE, NO_PIPE, bitmap);
+
+ dispose_command (command);
+ run_unwind_frame ("pe_dispose");
+ }
+ }
+ else
+ {
+ last_result = EXECUTION_FAILURE;
+
+ /* Since we are shell compatible, syntax errors in a script
+ abort the execution of the script. Right? */
+ break;
+ }
+ }
+ }
+
+ out:
+
+ run_unwind_frame ("parse_and_execute_top");
+
+ if (interrupt_state && parse_and_execute_level == 0)
+ {
+ /* An interrupt during non-interactive execution in an
+ interactive shell (e.g. via $PROMPT_COMMAND) should
+ not cause the shell to exit. */
+ interactive = interactive_shell;
+ throw_to_top_level ();
+ }
+
+ if (jump_to_top_level)
+ longjmp (top_level, code);
+
+ return (last_result);
+}
+
+/* Return the address of the builtin named NAME.
+ DISABLED_OKAY means find it even if the builtin is disabled. */
+static Function *
+builtin_address_internal (name, disabled_okay)
+ char *name;
+ int disabled_okay;
+{
+ int hi, lo, mid, j;
+
+ hi = num_shell_builtins - 1;
+ lo = 0;
+
+ while (lo <= hi)
+ {
+ mid = (lo + hi) / 2;
+
+ j = shell_builtins[mid].name[0] - name[0];
+
+ if (j == 0)
+ j = strcmp (shell_builtins[mid].name, name);
+
+ if (j == 0)
+ {
+ /* It must have a function pointer. It must be enabled, or we
+ must have explicitly allowed disabled functions to be found. */
+ if (shell_builtins[mid].function &&
+ ((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
+ return (shell_builtins[mid].function);
+ else
+ return ((Function *)NULL);
+ }
+ if (j > 0)
+ hi = mid - 1;
+ else
+ lo = mid + 1;
+ }
+ return ((Function *)NULL);
+}
+
+/* Perform a binary search and return the address of the builtin function
+ whose name is NAME. If the function couldn't be found, or the builtin
+ is disabled or has no function associated with it, return NULL. */
+Function *
+find_shell_builtin (name)
+ char *name;
+{
+ return (builtin_address_internal (name, 0));
+}
+
+/* Return the address of builtin with NAME, irregardless of its state of
+ enableness. */
+Function *
+builtin_address (name)
+ char *name;
+{
+ return (builtin_address_internal (name, 1));
+}
+
+static int
+shell_builtin_compare (sbp1, sbp2)
+ struct builtin *sbp1, *sbp2;
+{
+ int result;
+
+ if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
+ result = strcmp (sbp1->name, sbp2->name);
+
+ return (result);
+}
+
+/* Sort the table of shell builtins so that the binary search will work
+ in find_shell_builtin. */
+void
+initialize_shell_builtins ()
+{
+ qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
+ shell_builtin_compare);
+}
+
+/* Return a new string which is the quoted version of STRING. This is used
+ by alias and trap. */
+char *
+single_quote (string)
+ char *string;
+{
+ register int i, j, c;
+ char *result;
+
+ result = (char *)xmalloc (3 + (3 * strlen (string)));
+
+ result[0] = '\'';
+
+ for (i = 0, j = 1; string && (c = string[i]); i++)
+ {
+ result[j++] = c;
+
+ if (c == '\'')
+ {
+ result[j++] = '\\'; /* insert escaped single quote */
+ result[j++] = '\'';
+ result[j++] = '\''; /* start new quoted string */
+ }
+ }
+
+ result[j++] = '\'';
+ result[j] = '\0';
+
+ return (result);
+}
+
+char *
+double_quote (string)
+ char *string;
+{
+ register int i, j, c;
+ char *result;
+
+ result = (char *)xmalloc (3 + (3 * strlen (string)));
+
+ result[0] = '"';
+
+ for (i = 0, j = 1; string && (c = string[i]); i++)
+ {
+ switch (c)
+ {
+ case '"':
+ case '$':
+ case '`':
+ case '\\':
+ result[j++] = '\\';
+ default:
+ result[j++] = c;
+ break;
+ }
+ }
+
+ result[j++] = '"';
+ result[j] = '\0';
+
+ return (result);
+}
diff --git a/builtins/common.h b/builtins/common.h
new file mode 100644
index 0000000..c7c99e7
--- /dev/null
+++ b/builtins/common.h
@@ -0,0 +1,69 @@
+/* common.h -- extern declarations for functions defined in common.c. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if !defined (__COMMON_H)
+# define __COMMON_H
+
+#define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c)
+
+extern void builtin_error ();
+extern void bad_option ();
+
+extern int get_numeric_arg ();
+
+extern void remember_args ();
+
+extern void no_args ();
+
+extern int read_octal ();
+
+extern char *find_hashed_filename ();
+extern void remove_hashed_filename ();
+extern void remember_filename ();
+
+extern void push_context (), pop_context ();
+extern void push_dollar_vars (), pop_dollar_vars ();
+extern void dispose_saved_dollar_vars ();
+extern int dollar_vars_changed ();
+extern void set_dollar_vars_unchanged (), set_dollar_vars_changed ();
+
+/* Keeps track of the current working directory. */
+extern char *the_current_working_directory;
+extern char *get_working_directory ();
+extern void set_working_directory ();
+
+#if defined (JOB_CONTROL)
+extern int get_job_spec ();
+#endif
+
+extern int parse_and_execute ();
+extern void parse_and_execute_cleanup ();
+
+extern void initialize_shell_builtins ();
+
+/* It's OK to declare a function as returning a Function * without
+ providing a definition of what a `Function' is. */
+extern Function *find_shell_builtin ();
+extern Function *builtin_address ();
+
+extern char *single_quote ();
+extern char *double_quote ();
+
+#endif /* !__COMMON_H */
diff --git a/builtins/declare.def b/builtins/declare.def
new file mode 100644
index 0000000..17b7ea2
--- /dev/null
+++ b/builtins/declare.def
@@ -0,0 +1,290 @@
+This file is declare.def, from which is created declare.c.
+It implements the builtins "declare" and "local" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES declare.c
+
+$BUILTIN declare
+$FUNCTION declare_builtin
+$SHORT_DOC declare [-[frxi]] name[=value] ...
+Declare variables and/or give them attributes. If no NAMEs are
+given, then display the values of variables instead.
+
+The flags are:
+
+ -f to select from among function names only,
+ -r to make NAMEs readonly,
+ -x to make NAMEs export,
+ -i to make NAMEs have the `integer' attribute set.
+
+Variables with the integer attribute have arithmetic evaluation (see
+`let') done when the variable is assigned to.
+
+Using `+' instead of `-' turns off the given attribute instead. When
+used in a function, makes NAMEs local, as with the `local' command.
+$END
+
+$BUILTIN typeset
+$FUNCTION declare_builtin
+$SHORT_DOC typeset [-[frxi]] name[=value] ...
+Obsolete. See `declare'.
+$END
+
+#include <stdio.h>
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+
+extern int variable_context, array_needs_making;
+
+static int declare_internal ();
+
+/* Declare or change variable attributes. */
+int
+declare_builtin (list)
+ register WORD_LIST *list;
+{
+ return (declare_internal (list, 0));
+}
+
+$BUILTIN local
+$FUNCTION local_builtin
+$SHORT_DOC local name[=value] ...
+Create a local variable called NAME, and give it VALUE. LOCAL
+can only be used within a function; it makes the variable NAME
+have a visible scope restricted to that function and its children.
+$END
+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);
+ }
+}
+
+/* The workhorse function. */
+static int
+declare_internal (list, local_var)
+ register WORD_LIST *list;
+ int local_var;
+{
+ int flags_on = 0, flags_off = 0;
+ int any_failed = 0;
+
+ while (list)
+ {
+ register char *t = list->word->word;
+ int *flags;
+
+ if (t[0] == '-' && t[1] == '-' && t[2] == '\0')
+ {
+ list = list->next;
+ break;
+ }
+
+ if (*t != '+' && *t != '-')
+ break;
+
+ if (*t == '+')
+ flags = &flags_off;
+ else
+ flags = &flags_on;
+
+ t++;
+
+ while (*t)
+ {
+ if (*t == 'f')
+ *flags |= att_function, t++;
+ else if (*t == 'x')
+ *flags |= att_exported, t++, array_needs_making = 1;
+ else if (*t == 'r')
+ *flags |= att_readonly, t++;
+ else if (*t == 'i')
+ *flags |= att_integer, t++;
+ else
+ {
+ builtin_error ("unknown option: `-%c'", *t);
+ return (EX_USAGE);
+ }
+ }
+
+ list = list->next;
+ }
+
+ /* If there are no more arguments left, then we just want to show
+ some variables. */
+ if (!list)
+ {
+ /* 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 = map_over (variable_in_context, shell_variables);
+
+ if (vlist)
+ {
+ for (i = 0; vlist[i]; i++)
+ print_assignment (vlist[i]);
+
+ free (vlist);
+ }
+ }
+ else
+ {
+ if (!flags_on)
+ set_builtin ((WORD_LIST *)NULL);
+ else
+ set_or_show_attributes ((WORD_LIST *)NULL, flags_on);
+ }
+
+ fflush (stdout);
+ return (EXECUTION_SUCCESS);
+ }
+
+#define NEXT_VARIABLE() free (name); list = list->next; continue
+
+ /* There are arguments left, so we are making variables. */
+ while (list)
+ {
+ char *value, *name = savestring (list->word->word);
+ int offset = assignment (name);
+
+ if (offset)
+ {
+ name[offset] = '\0';
+ value = name + offset + 1;
+ }
+ else
+ value = "";
+
+ if (legal_identifier (name) == 0)
+ {
+ builtin_error ("%s: not a legal variable name", name);
+ any_failed++;
+ 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. */
+
+ if (variable_context)
+ make_local_variable (name);
+
+ /* 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)
+ {
+ builtin_error ("Can't use `-f' to make functions");
+ return (EXECUTION_FAILURE);
+ }
+ else
+ {
+ SHELL_VAR *find_function (), *funvar;
+
+ funvar = find_function (name);
+
+ if (funvar)
+ {
+ if (readonly_p (funvar) && (flags_off & att_readonly))
+ {
+ builtin_error ("%s: readonly function", name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+
+ if (flags_on == att_function && flags_off == 0)
+ {
+ char *result = named_function_string
+ (name, (COMMAND *)function_cell (funvar), 1);
+ printf ("%s\n", result);
+ }
+ else
+ {
+ funvar->attributes |= flags_on;
+ funvar->attributes &= ~flags_off;
+ }
+ }
+ else
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+ }
+ else
+ {
+ SHELL_VAR *var;
+
+ var = find_variable (name);
+
+ if (!var)
+ var = bind_variable (name, "");
+
+ if (readonly_p (var) && (flags_off & att_readonly))
+ {
+ builtin_error ("%s: readonly variable", name);
+ any_failed++;
+ NEXT_VARIABLE ();
+ }
+
+ var->attributes |= flags_on;
+ var->attributes &= ~flags_off;
+
+ if (offset)
+ {
+ free (var->value);
+ if (integer_p (var))
+ {
+ long val, evalexp ();
+ char *itos ();
+
+ val = evalexp (value);
+ var->value = itos ((int)val);
+ }
+ else
+ var->value = savestring (value);
+ }
+ }
+
+ stupidly_hack_special_variables (name);
+
+ NEXT_VARIABLE ();
+ }
+ return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
diff --git a/builtins/echo.def b/builtins/echo.def
new file mode 100644
index 0000000..7539103
--- /dev/null
+++ b/builtins/echo.def
@@ -0,0 +1,168 @@
+This file is echo.def, from which is created echo.c.
+It implements the builtin "echo" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES echo.c
+#include <stdio.h>
+#include "../shell.h"
+
+$BUILTIN echo
+$FUNCTION echo_builtin
+$DEPENDS_ON V9_ECHO
+$SHORT_DOC echo [-neE] [arg ...]
+Output the ARGs. If -n is specified, the trailing newline is
+suppressed. If the -e option is given, interpretation of the
+following backslash-escaped characters is turned on:
+ \a alert (bell)
+ \b backspace
+ \c suppress trailing newline
+ \f form feed
+ \n new line
+ \r carriage return
+ \t horizontal tab
+ \v vertical tab
+ \\ backslash
+ \num the character whose ASCII code is NUM (octal).
+
+You can explicitly turn off the interpretation of the above characters
+with the -E option.
+$END
+
+$BUILTIN echo
+$FUNCTION echo_builtin
+$DEPENDS_ON !V9_ECHO
+$SHORT_DOC echo [-n] [arg ...]
+Output the ARGs. If -n is specified, the trailing newline is suppressed.
+$END
+
+#if defined (V9_ECHO)
+# define VALID_ECHO_OPTIONS "neE"
+#else /* !V9_ECHO */
+# define VALID_ECHO_OPTIONS "n"
+#endif /* !V9_ECHO */
+
+/* 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. */
+echo_builtin (list)
+ WORD_LIST *list;
+{
+ int display_return = 1, do_v9 = 0;
+
+#if defined (DEFAULT_ECHO_TO_USG)
+/* 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. */
+ do_v9 = 1;
+#endif /* DEFAULT_ECHO_TO_USG */
+
+ while (list && list->word->word[0] == '-')
+ {
+ register char *temp;
+ register int i;
+
+ /* 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 = &(list->word->word[1]);
+
+ for (i = 0; temp[i]; i++)
+ {
+ if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
+ goto just_echo;
+ }
+
+ if (!*temp)
+ goto just_echo;
+
+ /* All of the options in TEMP are valid options to ECHO.
+ Handle them. */
+ while (*temp)
+ {
+ if (*temp == 'n')
+ display_return = 0;
+#if defined (V9_ECHO)
+ else if (*temp == 'e')
+ do_v9 = 1;
+ else if (*temp == 'E')
+ do_v9 = 0;
+#endif /* V9_ECHO */
+ else
+ goto just_echo;
+
+ temp++;
+ }
+ list = list->next;
+ }
+
+just_echo:
+
+ if (list)
+ {
+#if defined (V9_ECHO)
+ if (do_v9)
+ {
+ while (list)
+ {
+ register char *s = list->word->word;
+ register int c;
+
+ while (c = *s++)
+ {
+ if (c == '\\' && *s)
+ {
+ switch (c = *s++)
+ {
+ case 'a': c = '\007'; break;
+ case 'b': c = '\b'; break;
+ case 'c': display_return = 0; continue;
+ case 'f': c = '\f'; break;
+ case 'n': c = '\n'; break;
+ case 'r': c = '\r'; break;
+ case 't': c = '\t'; break;
+ case 'v': c = (int) 0x0B; break;
+ case '0': case '1': case '2': case '3':
+ case '4': case '5': case '6': case '7':
+ c -= '0';
+ if (*s >= '0' && *s <= '7')
+ c = c * 8 + (*s++ - '0');
+ if (*s >= '0' && *s <= '7')
+ c = c * 8 + (*s++ - '0');
+ break;
+ case '\\': break;
+ default: putchar ('\\'); break;
+ }
+ }
+ putchar(c);
+ }
+ list = list->next;
+ if (list)
+ putchar(' ');
+ }
+ }
+ else
+#endif /* V9_ECHO */
+ print_word_list (list, " ");
+ }
+ if (display_return)
+ printf ("\n");
+ fflush (stdout);
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/enable.def b/builtins/enable.def
new file mode 100644
index 0000000..2aeae39
--- /dev/null
+++ b/builtins/enable.def
@@ -0,0 +1,156 @@
+This file is enable.def, from which is created enable.c.
+It implements the builtin "enable" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES enable.c
+
+$BUILTIN enable
+$FUNCTION enable_builtin
+$SHORT_DOC enable [-n] [name ...]
+Enable and disable builtin shell commands. This allows
+you to use a disk command which has the same name as a shell
+builtin. If -n is used, the NAMEs become disabled. Otherwise
+NAMEs are enabled. For example, to use the `test' found on your
+path instead of the shell builtin version, you type `enable -n test'.
+$END
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "common.h"
+
+#define ENABLED 1
+#define DISABLED 2
+
+static int enable_shell_command ();
+static void list_some_builtins ();
+
+/* 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. */
+enable_builtin (list)
+ WORD_LIST *list;
+{
+ int result = 0, any_failed = 0;
+ int disable_p, all_p;
+
+ disable_p = all_p = 0;
+
+ while (list && list->word->word && list->word->word[0] == '-')
+ {
+ char *arg = list->word->word;
+
+ list = list->next;
+
+ if (ISOPTION (arg, 'n'))
+ disable_p = 1;
+ else if (arg[1] == 'a' && (arg[2] == 0 || strcmp (arg + 2, "ll") == 0))
+ all_p = 1;
+ else if (ISOPTION (arg, '-'))
+ break;
+ else
+ {
+ bad_option (arg);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ if (!list)
+ {
+ int filter;
+
+ if (all_p)
+ filter = ENABLED | DISABLED;
+ else if (disable_p)
+ filter = DISABLED;
+ else
+ filter = ENABLED;
+
+ list_some_builtins (filter);
+ }
+ else
+ {
+ while (list)
+ {
+ result = enable_shell_command (list->word->word, disable_p);
+
+ if (!result)
+ {
+ builtin_error ("%s: not a shell builtin", list->word->word);
+ any_failed++;
+ }
+ list = list->next;
+ }
+ }
+ return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+}
+
+/* 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)
+ 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;
+{
+ register int i;
+ int found = 0;
+
+ for (i = 0; i < num_shell_builtins; i++)
+ {
+ if (!shell_builtins[i].function)
+ continue;
+
+ if (STREQ (name, shell_builtins[i].name))
+ {
+ found++;
+
+ if (disable_p)
+ shell_builtins[i].flags &= ~BUILTIN_ENABLED;
+ else
+ shell_builtins[i].flags |= BUILTIN_ENABLED;
+ }
+ }
+ return (found);
+}
diff --git a/builtins/eval.def b/builtins/eval.def
new file mode 100644
index 0000000..5c3eda8
--- /dev/null
+++ b/builtins/eval.def
@@ -0,0 +1,45 @@
+This file is eval.def, from which is created eval.c.
+It implements the builtin "eval" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES eval.c
+
+$BUILTIN eval
+$FUNCTION eval_builtin
+$SHORT_DOC eval [arg ...]
+Read ARGs as input to the shell and execute the resulting command(s).
+$END
+
+#include "../shell.h"
+
+/* Parse the string that these words make, and execute the command found. */
+int
+eval_builtin (list)
+ WORD_LIST *list;
+{
+ int result;
+
+ /* Note that parse_and_execute () frees the string it is passed. */
+ if (list)
+ result = parse_and_execute (string_list (list), "eval", -1);
+ else
+ result = EXECUTION_SUCCESS;
+ return (result);
+}
diff --git a/builtins/exec.def b/builtins/exec.def
new file mode 100644
index 0000000..f950afc
--- /dev/null
+++ b/builtins/exec.def
@@ -0,0 +1,163 @@
+This file is exec.def, from which is created exec.c.
+It implements the builtin "exec" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES exec.c
+
+$BUILTIN exec
+$FUNCTION exec_builtin
+$SHORT_DOC exec [ [-] file [redirection ...]]
+Exec FILE, replacing this shell with the specified program.
+If FILE is not specified, the redirections take effect in this
+shell. If the first argument is `-', then place a dash in the
+zeroth arg passed to FILE. If the file cannot be exec'ed and
+the shell is not interactive, then the shell exits, unless the
+shell variable "no_exit_on_failed_exec" exists.
+$END
+
+#include "../shell.h"
+#include <sys/types.h>
+#include "../posixstat.h"
+#include <signal.h>
+#include <errno.h>
+
+#include "../execute_cmd.h"
+#include "common.h"
+#include "../flags.h"
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+extern int interactive, subshell_environment;
+extern REDIRECT *redirection_undo_list;
+
+int
+exec_builtin (list)
+ WORD_LIST *list;
+{
+ int exit_value = EXECUTION_FAILURE;
+
+ maybe_make_export_env ();
+
+ /* First, let the redirections remain. */
+ dispose_redirects (redirection_undo_list);
+ redirection_undo_list = (REDIRECT *)NULL;
+
+ if (!list)
+ return (EXECUTION_SUCCESS);
+ else
+ {
+ /* Otherwise, execve the new command with args. */
+ char *command, **args;
+ int dash_name = 0;
+
+ if (list->word->word[0] == '-' && !list->word->word[1])
+ {
+ /* The user would like to exec this command as if it was a
+ login command. Do so. */
+ list = list->next;
+ dash_name++;
+ }
+
+ if (!list)
+ return (EXECUTION_SUCCESS);
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted)
+ {
+ builtin_error ("restricted");
+ return (EXECUTION_FAILURE);
+ }
+#endif /* RESTRICTED_SHELL */
+
+ args = make_word_array (list);
+
+ /* A command with a slash anywhere in its name is not looked up in
+ the search path. */
+ if (absolute_program (args[0]))
+ command = args[0];
+ else
+ command = find_user_command (args[0]);
+ if (!command)
+ {
+ builtin_error ("%s: not found", args[0]);
+ exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
+ goto failed_exec;
+ }
+
+ command = full_pathname (command);
+ /* If the user wants this to look like a login shell, then
+ prepend a `-' onto the first argument (argv[0]). */
+ if (dash_name)
+ {
+ char *new_name = xmalloc (2 + strlen (args[0]));
+ new_name[0] = '-';
+ strcpy (new_name + 1, args[0]);
+ free (args[0]);
+ args[0] = new_name;
+ }
+
+ /* 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. */
+ adjust_shell_level (-1);
+ maybe_make_export_env ();
+
+#if defined (HISTORY)
+ 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, export_env);
+
+ adjust_shell_level (1);
+
+ if (!executable_file (command))
+ {
+ 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:
+ if (command)
+ free (command);
+
+ if (subshell_environment ||
+ (!interactive && !find_variable ("no_exit_on_failed_exec")))
+ exit (exit_value);
+
+ initialize_traps ();
+ reinitialize_signals ();
+
+#if defined (JOB_CONTROL)
+ restart_job_control ();
+#endif /* JOB_CONTROL */
+
+ return (exit_value);
+ }
+}
diff --git a/builtins/exit.def b/builtins/exit.def
new file mode 100644
index 0000000..25a3b63
--- /dev/null
+++ b/builtins/exit.def
@@ -0,0 +1,129 @@
+This file is exit.def, from which is created exit.c.
+It implements the builtins "exit" and "logout" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES exit.c
+
+$BUILTIN exit
+$FUNCTION exit_builtin
+$SHORT_DOC exit [n]
+Exit the shell with a status of N. If N is omitted, the exit status
+is that of the last command executed.
+$END
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "../shell.h"
+#include "../jobs.h"
+
+#include "builtext.h" /* for jobs_builtin */
+
+extern int interactive, login_shell;
+extern int last_command_exit_value;
+
+static int exit_or_logout ();
+static int sourced_logout = 0;
+
+int
+exit_builtin (list)
+ WORD_LIST *list;
+{
+ if (interactive)
+ {
+ fprintf (stderr, login_shell ? "logout\n" : "exit\n");
+ fflush (stderr);
+ }
+
+ return (exit_or_logout (list));
+}
+
+$BUILTIN logout
+$FUNCTION logout_builtin
+$SHORT_DOC logout
+Logout of a login shell.
+$END
+
+/* How to logout. */
+int
+logout_builtin (list)
+ WORD_LIST *list;
+{
+ if (!login_shell && interactive)
+ {
+ builtin_error ("Not login shell: use `exit'");
+ return (EXECUTION_FAILURE);
+ }
+ else
+ return (exit_or_logout (list));
+}
+
+/* Clean up work for exiting or logging out. */
+Function *last_shell_builtin = (Function *)NULL;
+Function *this_shell_builtin = (Function *)NULL;
+
+static int
+exit_or_logout (list)
+ WORD_LIST *list;
+{
+ int exit_value;
+
+#if defined (JOB_CONTROL)
+ int exit_immediate_okay;
+
+ exit_immediate_okay = (!interactive ||
+ 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)
+ {
+ register int i;
+ for (i = 0; i < job_slots; i++)
+ if (jobs[i] && (jobs[i]->state == JSTOPPED))
+ {
+ fprintf (stderr, "There are stopped jobs.\n");
+
+ /* 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 (list)
+ exit_value = get_numeric_arg (list);
+ else
+ exit_value = last_command_exit_value;
+
+ /* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
+ if (login_shell && sourced_logout++ == 0)
+ maybe_execute_file ("~/.bash_logout", 1);
+
+ last_command_exit_value = exit_value;
+
+ /* Exit the program. */
+ longjmp (top_level, EXITPROG);
+}
diff --git a/builtins/fc.def b/builtins/fc.def
new file mode 100644
index 0000000..1f6db68
--- /dev/null
+++ b/builtins/fc.def
@@ -0,0 +1,691 @@
+This file is fc.def, from which is created fc.c.
+It implements the builtin "fc" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES fc.c
+
+$BUILTIN fc
+$FUNCTION fc_builtin
+$DEPENDS_ON HISTORY
+$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
+
+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).
+
+With the `fc -s [pat=rep ...] [command]' format, the command is
+re-executed after the substitution OLD=NEW is performed.
+
+A useful alias to use with this is r='fc -s', so that typing `r cc'
+runs the last command beginning with `cc' and typing `r' re-executes
+the last command.
+$END
+
+#include <stdio.h>
+#include "../bashansi.h"
+#include "../shell.h"
+#if defined (HISTORY)
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/file.h>
+#include <errno.h>
+#include "../builtins.h"
+#include "../flags.h"
+#include "../maxpath.h"
+#include "../bashhist.h"
+#include <readline/history.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 echo_input_at_read;
+
+extern int unlink ();
+
+/* **************************************************************** */
+/* */
+/* 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.
+*/
+
+static char *fc_dosubs (), *fc_replace (), *fc_gethist (), *fc_readline ();
+static int fc_gethnum ();
+static void fc_replhist (), fc_addhist ();
+
+/* Data structure describing a list of global replacements to perform. */
+typedef struct repl {
+ struct repl *next;
+ char *pat;
+ char *rep;
+} REPL;
+
+#define USAGE "usage: fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [command]"
+
+/* 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)
+
+/* String to execute on a file that we want to edit. */
+#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
+
+int
+fc_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ register char *sep;
+ int numbering, reverse, listing, execute;
+ int histbeg, histend, last_hist, retval, first, opt;
+ FILE *stream;
+ REPL *rlist = (REPL *) NULL, *rl;
+ char *ename = NULL, *command, *newcom, *line;
+ HIST_ENTRY **hlist;
+ char fn[MAXPATHLEN];
+
+ numbering = 1;
+ reverse = listing = execute = 0;
+
+ /* Parse out the options and set which of the two forms we're in. */
+
+ while (list && *list->word->word == '-')
+ {
+ register char *s = &((list->word->word)[1]);
+
+ if (!isletter (*s))
+ break;
+
+ while (opt = *s++)
+ {
+ switch (opt)
+ {
+ case 'n':
+ numbering = 0;
+ break;
+
+ case 'l':
+ listing = 1;
+ break;
+
+ case 'r':
+ reverse = 1;
+ break;
+
+ case 's':
+ execute = 1;
+ break;
+
+ case 'e':
+ list = list->next;
+ if (list == NULL)
+ {
+ builtin_error (USAGE);
+ return (EX_USAGE);
+ }
+ ename = list->word->word;
+ break;
+
+ default:
+ builtin_error (USAGE);
+ return (EX_USAGE);
+ }
+ }
+ list = list->next;
+ }
+
+ if (ename && (*ename == '-') && (ename[1] == '\0'))
+ execute = 1;
+
+ /* The "execute" form of the command (re-run, with possible string
+ substitutions). */
+ if (execute)
+ {
+ 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. */
+
+ if (rlist && rlist->next)
+ rlist = (REPL *) reverse_list ((GENERIC_LIST *) rlist);
+
+ hlist = history_list ();
+
+ /* If we still have something in list, it is a command spec.
+ Otherwise, we use the most recent command in time. */
+ if (list)
+ command = fc_gethist (list->word->word, hlist);
+ else
+ command = fc_gethist ((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;
+ }
+
+ printf ("%s\n", command);
+ fc_replhist (command); /* replace `fc -e -' with command */
+ return (parse_and_execute (command, "fc", -1));
+ }
+
+ /* 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. */
+
+ last_hist = i - 2;
+
+ if (list)
+ {
+ histbeg = fc_gethnum (list->word->word, hlist);
+ list = list->next;
+
+ if (list)
+ histend = fc_gethnum (list->word->word, hlist);
+ else
+ {
+ if (listing)
+ histend = last_hist;
+ else
+ histend = histbeg;
+ }
+ }
+ else
+ {
+ /* The default for listing is the last 16 history items. */
+ if (listing)
+ {
+ histend = last_hist;
+ histbeg = histend - 16;
+ if (histbeg < 0)
+ histbeg = 0;
+ }
+ else
+ {
+ /* For editing, it is the last history command. */
+ histbeg = histend = last_hist;
+ }
+ }
+
+ /* We print error messages for line specifications out of range. */
+ if ((histbeg < 0) || (histend < 0) ||
+ (histbeg > last_hist) || (histend > last_hist))
+ {
+ builtin_error ("history specification out of range");
+ return (EXECUTION_FAILURE);
+ }
+
+ if (histend < histbeg)
+ {
+ int t = histend;
+
+ histend = histbeg;
+ histbeg = t;
+ reverse = 1;
+ }
+
+ if (listing)
+ stream = stdout;
+ else
+ {
+ numbering = 0;
+ sprintf (fn, "/tmp/bash%d", (int)time ((long *) 0) + (int)getpid ());
+
+ stream = fopen (fn, "w");
+
+ if (!stream)
+ {
+ builtin_error ("cannot open temp file %s", fn);
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ if (!reverse)
+ {
+ for (i = histbeg; i <= histend; i++)
+ {
+ QUIT;
+ if (numbering)
+ fprintf (stream, "%d", i + history_base);
+ if (listing)
+ fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
+ fprintf (stream, "%s\n", histline (i));
+ }
+ }
+ else
+ {
+ for (i = histend; i >= histbeg; i--)
+ {
+ QUIT;
+ if (numbering)
+ fprintf (stream, "%d", i + history_base);
+ if (listing)
+ fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
+ fprintf (stream, "%s\n", histline (i));
+ }
+ }
+
+ if (listing)
+ return (EXECUTION_SUCCESS);
+
+ 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
+ {
+ command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
+ sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
+ }
+ parse_and_execute (command, "fc", -1);
+
+ /* Now reopen the file and execute the edited commands. */
+
+ stream = fopen (fn, "r");
+
+ if (stream == NULL)
+ {
+ builtin_error ("cannot reopen temp file %s", fn);
+ unlink (fn);
+ return (EXECUTION_FAILURE);
+ }
+
+ retval = EXECUTION_SUCCESS;
+ first = 1;
+
+ /* First, write the commands to the history file. This will not happen
+ when we call parse_and_execute, since parse_and_execute disables
+ the command line history while it executes. */
+
+ while ((line = fc_readline (stream)) != NULL)
+ {
+ if (line[0] == '\n')
+ {
+ free (line);
+ continue; /* Skip blank lines. */
+ }
+
+ if (first)
+ {
+ first = 0;
+ fc_replhist (line);
+ }
+ else
+ fc_addhist (line);
+
+ free (line);
+ }
+ fclose (stream);
+
+ /* Turn on the `v' flag while maybe_execute_file runs so the commands
+ will be echoed as they are read by the parser. */
+ begin_unwind_frame ("fc builtin");
+ add_unwind_protect (unlink, fn);
+ unwind_protect_int (echo_input_at_read);
+ echo_input_at_read = 1;
+
+ retval = maybe_execute_file (fn, 0);
+
+ run_unwind_frame ("fc builtin");
+
+ return (retval);
+}
+
+/* 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 = 1, n, clen;
+ register int i, j;
+ register char *s;
+
+ /* 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. */
+ i -= 2;
+
+ /* 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;
+
+ /* Anything specified greater than the last history element that we
+ deal with is an error. */
+ if (n > i + history_base)
+ return (-1);
+
+ /* If the value is negative or zero, then it is an offset from
+ the current history item. */
+ if (n < 0)
+ return (i + n + 1);
+ else if (n == 0)
+ return (i);
+ else
+ return (n - history_base);
+ }
+
+ 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)
+ return ((char *)NULL);
+
+ i = fc_gethnum (command, hlist);
+
+ if (i >= 0)
+ return (savestring (histline (i)));
+ else
+ return ((char *)NULL);
+}
+
+/* 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);
+}
+
+/* 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 = savestring (command);
+ register REPL *r;
+
+ for (r = subs; r; r = r->next)
+ {
+ register char *t;
+
+ t = fc_replace (r->pat, r->rep, new);
+ free (new);
+ new = t;
+ }
+ return (new);
+}
+
+/* Replace the occurrences of PAT with REP in COMMAND.
+ This returns a new string; the caller should free it. */
+static char *
+fc_replace (pat, rep, command)
+ char *pat, *rep, *command;
+{
+ register int i;
+ int patlen, replen, templen;
+ char *new, *temp;
+
+ patlen = strlen (pat);
+ replen = strlen (rep);
+
+ temp = savestring (command);
+ templen = strlen (temp);
+ i = 0;
+
+ for (; (i + patlen) <= templen; i++)
+ {
+ if (STREQN (temp + i, pat, patlen))
+ {
+ new = (char *) xmalloc (1 + (replen - patlen) + templen);
+
+ strncpy (new, temp, i);
+ strncpy (new + i, rep, replen);
+ strncpy (new + i + replen,
+ temp + i + patlen, templen - (i + patlen));
+ new[templen + (replen - patlen)] = '\0'; /* just in case */
+
+ free (temp);
+ temp = new;
+ i += replen;
+ templen = strlen (temp);
+ }
+ }
+ return (temp);
+}
+
+/* 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;
+{
+ register int i;
+ HIST_ENTRY **hlist, *histent, *discard;
+ char *data;
+ int n;
+
+ if (!command || !*command)
+ return;
+
+ hlist = history_list ();
+
+ if (hlist == NULL)
+ return;
+
+ for (i = 0; hlist[i]; i++);
+ i--;
+
+ /* History_get () takes a parameter that should be
+ offset by history_base. */
+
+ histent = history_get (history_base + i); /* Don't free this */
+ if (histent == NULL)
+ return;
+
+ n = strlen (command);
+
+ if (command[n - 1] == '\n')
+ command[n - 1] = '\0';
+
+ if (command && *command)
+ {
+ discard = remove_history (i);
+ if (discard)
+ {
+ if (discard->line)
+ free (discard->line);
+ free ((char *) discard);
+ }
+ maybe_add_history (command); /* Obeys HISTCONTROL setting. */
+ }
+}
+
+/* Add LINE to the history, after removing a single trailing newline. */
+static void
+fc_addhist (line)
+ char *line;
+{
+ register int n;
+
+ n = strlen (line);
+
+ if (line[n - 1] == '\n')
+ line[n - 1] = '\0';
+
+ if (line && *line)
+ maybe_add_history (line);
+}
+#endif /* HISTORY */
diff --git a/builtins/fg_bg.def b/builtins/fg_bg.def
new file mode 100644
index 0000000..e48af38
--- /dev/null
+++ b/builtins/fg_bg.def
@@ -0,0 +1,145 @@
+This file is fg_bg.def, from which is created fg_bg.c.
+It implements the builtins "bg" and "fg" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES fg_bg.c
+
+$BUILTIN fg
+$FUNCTION fg_builtin
+$DEPENDS_ON JOB_CONTROL
+$SHORT_DOC fg [job_spec]
+Place JOB_SPEC in the foreground, and make it the current job. If
+JOB_SPEC is not present, the shell's notion of the current job is
+used.
+$END
+
+#include <sys/types.h>
+#include <signal.h>
+#include "../shell.h"
+#include "../jobs.h"
+
+#if defined (JOB_CONTROL)
+extern char *this_command_name;
+
+static int fg_bg ();
+
+/* How to bring a job into the foreground. */
+int
+fg_builtin (list)
+ WORD_LIST *list;
+{
+ int fg_bit = 1;
+ register WORD_LIST *t = list;
+
+ if (!job_control)
+ {
+ builtin_error ("no job control");
+ return (EXECUTION_FAILURE);
+ }
+
+ /* If the last arg on the line is '&', then start this job in the
+ background. Else, fg the job. */
+
+ while (t && t->next)
+ t = t->next;
+
+ if (t && t->word->word[0] == '&' && !t->word->word[1])
+ fg_bit = 0;
+
+ return (fg_bg (list, fg_bit));
+}
+#endif /* JOB_CONTROL */
+
+$BUILTIN bg
+$FUNCTION bg_builtin
+$DEPENDS_ON JOB_CONTROL
+$SHORT_DOC bg [job_spec]
+Place JOB_SPEC in the background, as if it had been started with
+`&'. If JOB_SPEC is not present, the shell's notion of the current
+job is used.
+$END
+
+#if defined (JOB_CONTROL)
+/* How to put a job into the background. */
+int
+bg_builtin (list)
+ WORD_LIST *list;
+{
+ if (!job_control)
+ {
+ builtin_error ("no job control");
+ return (EXECUTION_FAILURE);
+ }
+
+ return (fg_bg (list, 0));
+}
+
+/* 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 = EXECUTION_SUCCESS, old_async_pid;
+
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if (job < 0 || job >= job_slots || !jobs[job])
+ {
+ if (job != DUP_JOB)
+ builtin_error ("No such job %s", list ? list->word->word : "");
+
+ goto failure;
+ }
+
+ /* Or if jobs[job]->pgrp == shell_pgrp. */
+ if (!(jobs[job]->flags & J_JOBCONTROL))
+ {
+ builtin_error ("job %%%d started without job control", job + 1);
+ goto failure;
+ }
+
+ if (!foreground)
+ {
+ old_async_pid = last_asynchronous_pid;
+ last_asynchronous_pid = jobs[job]->pgrp; /* As per Posix.2 5.4.2 */
+ }
+
+ status = start_job (job, foreground);
+
+ if (status >= 0)
+ {
+ /* win: */
+ UNBLOCK_CHILD (oset);
+ return (status);
+ }
+ else
+ {
+ if (!foreground)
+ last_asynchronous_pid = old_async_pid;
+
+ failure:
+ UNBLOCK_CHILD (oset);
+ return (EXECUTION_FAILURE);
+ }
+}
+#endif /* JOB_CONTROL */
diff --git a/builtins/getopt.c b/builtins/getopt.c
new file mode 100644
index 0000000..7603430
--- /dev/null
+++ b/builtins/getopt.c
@@ -0,0 +1,283 @@
+/* getopt for BASH.
+
+ Copyright (C) 1993, 1994
+ Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include <stdio.h>
+#include "../memalloc.h"
+#include "../shell.h"
+#include "getopt.h"
+
+/* For communication from `sh_getopt' to the caller.
+ When `sh_getopt' finds an option that takes an argument,
+ the argument value is returned here. */
+char *sh_optarg = 0;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `sh_getopt'.
+
+ On entry to `sh_getopt', zero means this is the first call; initialize.
+
+ When `sh_getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `sh_optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+/* XXX 1003.2 says this must be 1 before any call. */
+int sh_optind = 0;
+
+/* Index of the current argument. */
+static int sh_curopt;
+
+/* The next char to be scanned in the option-element
+ in which the last option character we returned was found.
+ This allows us to pick up the scan where we left off.
+
+ If this is zero, or a null string, it means resume the scan
+ by advancing to the next ARGV-element. */
+
+static char *nextchar;
+static int sh_charindex;
+
+/* Callers store zero here to inhibit the error message
+ for unrecognized options. */
+
+int sh_opterr = 1;
+
+/* Set to an option character which was unrecognized.
+ This must be initialized on some systems to avoid linking in the
+ system's own getopt implementation. */
+
+int sh_optopt = '?';
+
+/* Scan elements of ARGV (whose length is ARGC) for option characters
+ given in OPTSTRING.
+
+ If an element of ARGV starts with '-', and is not exactly "-" or "--",
+ then it is an option element. The characters of this element
+ (aside from the initial '-') are option characters. If `sh_getopt'
+ is called repeatedly, it returns successively each of the option characters
+ from each of the option elements.
+
+ If `sh_getopt' finds another option character, it returns that character,
+ updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can
+ resume the scan with the following option character or ARGV-element.
+
+ If there are no more option characters, `sh_getopt' returns `EOF'.
+ Then `sh_optind' is the index in ARGV of the first ARGV-element
+ that is not an option.
+
+ OPTSTRING is a string containing the legitimate option characters.
+ If an option character is seen that is not listed in OPTSTRING,
+ return '?' after printing an error message. If you set `sh_opterr' to
+ zero, the error message is suppressed but we still return '?'.
+
+ If a char in OPTSTRING is followed by a colon, that means it wants an arg,
+ so the following text in the same ARGV-element, or the text of the following
+ ARGV-element, is returned in `sh_optarg'. */
+
+/* 1003.2 specifies the format of this message. */
+#define BADOPT(x) fprintf (stderr, "%s: illegal option -- %c\n", argv[0], x)
+#define NEEDARG(x) fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], x)
+
+int
+sh_getopt (argc, argv, optstring)
+ int argc;
+ char *const *argv;
+ const char *optstring;
+{
+ int option_index;
+ char c, *temp;
+
+ sh_optarg = 0;
+
+ if (sh_optind > argc || sh_optind < 0)
+ {
+ sh_optind = argc;
+ return (EOF);
+ }
+
+ /* Initialize the internal data when the first call is made.
+ Start processing options with ARGV-element 1 (since ARGV-element 0
+ is the program name); the sequence of previously skipped
+ non-option ARGV-elements is empty. */
+
+ if (sh_optind == 0)
+ {
+ sh_optind = 1;
+ nextchar = (char *)NULL;
+ }
+
+ if (nextchar == 0 || *nextchar == '\0')
+ {
+ /* If we have done all the ARGV-elements, stop the scan
+ and back over any non-options that we skipped and permuted. */
+ if (sh_optind == argc)
+ return EOF;
+
+ temp = argv[sh_optind];
+
+ /* Special ARGV-element `--' means premature end of options.
+ Skip it like a null option, and return EOF. */
+ if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
+ {
+ sh_optind++;
+ return EOF;
+ }
+
+ /* If we have come to a non-option, either stop the scan or describe
+ it to the caller and pass it by. This makes the pseudo-option
+ `-' mean the end of options, but does not skip over it. */
+ if (temp[0] != '-' || temp[1] == '\0')
+ return EOF;
+
+ /* We have found another option-ARGV-element.
+ Start decoding its characters. */
+ nextchar = argv[sh_curopt = sh_optind] + 1;
+ sh_charindex = 1;
+ }
+
+ /* Look at and handle the next option-character. */
+
+ c = *nextchar++; sh_charindex++;
+ temp = strchr (optstring, c);
+
+ /* Increment `sh_optind' when we start to process its last character. */
+ if (nextchar == 0 || *nextchar == '\0')
+ {
+ sh_optind++;
+ nextchar = (char *)NULL;
+ }
+
+ sh_optopt = c;
+
+ if (temp == NULL || c == ':')
+ {
+ if (sh_opterr)
+ BADOPT (c);
+
+ return '?';
+ }
+
+ if (temp[1] == ':')
+ {
+ if (nextchar && *nextchar)
+ {
+ /* This is an option that requires an argument. */
+ sh_optarg = nextchar;
+ /* If we end this ARGV-element by taking the rest as an arg,
+ we must advance to the next element now. */
+ sh_optind++;
+ }
+ else if (sh_optind == argc)
+ {
+ if (sh_opterr)
+ NEEDARG (c);
+
+ sh_optopt = c;
+ c = (optstring[0] == ':') ? ':' : '?';
+ }
+ else
+ /* We already incremented `sh_optind' once;
+ increment it again when taking next ARGV-elt as argument. */
+ sh_optarg = argv[sh_optind++];
+ nextchar = (char *)NULL;
+ }
+ return c;
+}
+
+void
+sh_getopt_restore_state (argv)
+ char **argv;
+{
+ if (nextchar)
+ nextchar = argv[sh_curopt] + sh_charindex;
+}
+
+#ifdef TEST
+
+/* Compile with -DTEST to make an executable for use in testing
+ the above definition of `sh_getopt'. */
+
+int
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int c;
+ int digit_sh_optind = 0;
+
+ while (1)
+ {
+ int this_option_sh_optind = sh_optind ? sh_optind : 1;
+
+ c = sh_getopt (argc, argv, "abc:d:0123456789");
+ if (c == EOF)
+ break;
+
+ switch (c)
+ {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
+ printf ("digits occur in two different argv-elements.\n");
+ digit_sh_optind = this_option_sh_optind;
+ printf ("option %c\n", c);
+ break;
+
+ case 'a':
+ printf ("option a\n");
+ break;
+
+ case 'b':
+ printf ("option b\n");
+ break;
+
+ case 'c':
+ printf ("option c with value `%s'\n", sh_optarg);
+ break;
+
+ case '?':
+ break;
+
+ default:
+ printf ("?? sh_getopt returned character code 0%o ??\n", c);
+ }
+ }
+
+ if (sh_optind < argc)
+ {
+ printf ("non-option ARGV-elements: ");
+ while (sh_optind < argc)
+ printf ("%s ", argv[sh_optind++]);
+ printf ("\n");
+ }
+
+ exit (0);
+}
+
+#endif /* TEST */
diff --git a/builtins/getopt.h b/builtins/getopt.h
new file mode 100644
index 0000000..fa9878c
--- /dev/null
+++ b/builtins/getopt.h
@@ -0,0 +1,57 @@
+/* Declarations for getopt.
+ Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 2, or (at your option) any
+ later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* XXX THIS HAS BEEN MODIFIED FOR INCORPORATION INTO BASH XXX */
+
+#ifndef _GETOPT_H
+#define _GETOPT_H 1
+
+/* For communication from `getopt' to the caller.
+ When `getopt' finds an option that takes an argument,
+ the argument value is returned here.
+ Also, when `ordering' is RETURN_IN_ORDER,
+ each non-option ARGV-element is returned here. */
+
+extern char *sh_optarg;
+
+/* Index in ARGV of the next element to be scanned.
+ This is used for communication to and from the caller
+ and for communication between successive calls to `getopt'.
+
+ On entry to `getopt', zero means this is the first call; initialize.
+
+ When `getopt' returns EOF, this is the index of the first of the
+ non-option elements that the caller should itself scan.
+
+ Otherwise, `sh_optind' communicates from one call to the next
+ how much of ARGV has been scanned so far. */
+
+extern int sh_optind;
+
+/* Callers store zero here to inhibit the error message `getopt' prints
+ for unrecognized options. */
+
+extern int sh_opterr;
+
+/* Set to an option character which was unrecognized. */
+
+extern int sh_optopt;
+
+extern int sh_getopt ();
+extern void sh_getopt_restore_state ();
+
+#endif /* _GETOPT_H */
diff --git a/builtins/getopts.def b/builtins/getopts.def
new file mode 100644
index 0000000..0f2b82f
--- /dev/null
+++ b/builtins/getopts.def
@@ -0,0 +1,300 @@
+This file is getopts.def, from which is created getopts.c.
+It implements the builtin "getopts" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES getopts.c
+
+$BUILTIN getopts
+$DEPENDS_ON GETOPTS_BUILTIN
+$FUNCTION getopts_builtin
+$SHORT_DOC getopts optstring name [arg]
+Getopts is used by shell procedures to parse positional parameters.
+
+OPTSTRING contains the option letters to be recognized; if a letter
+is followed by a colon, the option is expected to have an argument,
+which should be separated from it by white space.
+
+Each time it is invoked, getopts will place the next option in the
+shell variable $name, initializing name if it does not exist, and
+the index of the next argument to be processed into the shell
+variable OPTIND. OPTIND is initialized to 1 each time the shell or
+a shell script is invoked. When an option requires an argument,
+getopts places that argument into the shell variable OPTARG.
+
+getopts reports errors in one of two ways. If the first character
+of OPTSTRING is a colon, getopts uses silent error reporting. In
+this mode, no error messages are printed. If an illegal option is
+seen, getopts places the option character found into OPTARG. If a
+required argument is not found, getopts places a ':' into NAME and
+sets OPTARG to the option character found. If getopts is not in
+silent mode, and an illegal option is seen, getopts places '?' into
+NAME and unsets OPTARG. If a required option is not found, a '?'
+is placed in NAME, OPTARG is unset, and a diagnostic message is
+printed.
+
+If the shell variable OPTERR has the value 0, getopts disables the
+printing of error messages, even if the first character of
+OPTSTRING is not a colon. OPTERR has the value 1 by default.
+
+Getopts normally parses the positional parameters ($0 - $9), but if
+more arguments are given, they are parsed instead.
+$END
+
+#include <stdio.h>
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+
+#if defined (GETOPTS_BUILTIN)
+#include "getopt.h"
+
+#define G_EOF (-1)
+#define G_ILLEGAL_OPT (-2)
+#define G_ARG_MISSING (-3)
+
+extern char *this_command_name;
+extern WORD_LIST *rest_of_args;
+
+/* 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;
+}
+
+/* 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 illegal option characters. The handling is as follows.
+
+ ILLEGAL 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 = 0, 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_error("usage: getopts optstring name [arg]");
+ 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)
+ {
+ register int i;
+
+ for (i = 0; i < 10 && dollar_vars[i]; i++);
+ ret = sh_getopt (i, dollar_vars, optstr);
+ }
+ else
+ {
+ register int i;
+ 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 = (char **)xmalloc ((i + 1) * sizeof (char *));
+ 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;
+ 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. */
+ 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);
+
+ /* 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 SH_OPTOPT. If an illegal option was encountered, OPTARG is
+ NULL. If a required option argument was missing, OPTARG points
+ to a NULL string (that is, optarg[0] == 0). */
+ if (ret == '?')
+ {
+ if (sh_optarg == NULL)
+ ret = G_ILLEGAL_OPT;
+ else if (sh_optarg[0] == '\0')
+ ret = G_ARG_MISSING;
+ }
+
+ if (ret == G_EOF)
+ {
+ bind_variable (name, "?");
+ return (EXECUTION_FAILURE);
+ }
+
+ if (ret == G_ILLEGAL_OPT)
+ {
+ /* Illegal option encountered. */
+ strval[0] = '?';
+ strval[1] = '\0';
+ bind_variable (name, strval);
+
+ if (special_error)
+ {
+ strval[0] = (char) sh_optopt;
+ strval[1] = '\0';
+ bind_variable ("OPTARG", strval);
+ }
+ else
+ makunbound ("OPTARG", shell_variables);
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (ret == G_ARG_MISSING)
+ {
+ /* Required argument missing. */
+ if (special_error)
+ {
+ strval[0] = ':';
+ strval[1] = '\0';
+ bind_variable (name, strval);
+
+ strval[0] = (char) sh_optopt;
+ strval[1] = '\0';
+ bind_variable ("OPTARG", strval);
+ }
+ else
+ {
+ strval[0] = '?';
+ strval[1] = '\0';
+ bind_variable (name, strval);
+ makunbound ("OPTARG", shell_variables);
+ }
+ return (EXECUTION_SUCCESS);
+ }
+
+ bind_variable ("OPTARG", sh_optarg);
+
+ strval[0] = (char) ret;
+ strval[1] = '\0';
+ bind_variable (name, strval);
+
+ return (EXECUTION_SUCCESS);
+}
+
+/* The getopts builtin. Build an argv, and call dogetopts with it. */
+int
+getopts_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ char **av;
+ int ac, ret;
+ WORD_LIST *t;
+
+ if (list == 0)
+ return EXECUTION_FAILURE;
+
+ for (t = list, ac = 0; t; t = t->next, ac++);
+
+ ac++;
+ av = (char **)xmalloc ((1 + ac) * sizeof (char *));
+ av[ac] = (char *) NULL;
+ av[0] = this_command_name;
+
+ for (t = list, i = 1; t; t = t->next, i++)
+ av[i] = t->word->word;
+
+ ret = dogetopts (ac, av);
+ free ((char *)av);
+ return (ret);
+}
+#endif /* GETOPTS_BUILTIN */
diff --git a/builtins/hash.def b/builtins/hash.def
new file mode 100644
index 0000000..f4d319b
--- /dev/null
+++ b/builtins/hash.def
@@ -0,0 +1,222 @@
+This file is hash.def, from which is created hash.c.
+It implements the builtin "hash" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES hash.c
+
+$BUILTIN hash
+$FUNCTION hash_builtin
+$SHORT_DOC hash [-r] [name ...]
+For each NAME, the full pathname of the command is determined and
+remembered. The -r option causes the shell to forget all remembered
+locations. If no arguments are given, information about remembered
+commands is presented.
+$END
+
+#include <sys/types.h>
+#include "../posixstat.h"
+
+#include <stdio.h>
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+#include "../builtins.h"
+#include "../flags.h"
+#include "hashcom.h"
+#include "common.h"
+#include "../execute_cmd.h"
+
+extern int dot_found_in_search;
+
+void
+initialize_filename_hashing ()
+{
+ hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS);
+}
+
+/* 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. */
+hash_builtin (list)
+ WORD_LIST *list;
+{
+ int expunge_hash_table = 0;
+ int any_failed = 0;
+
+ if (hashing_disabled)
+ {
+ builtin_error ("hashing disabled");
+ return (EXECUTION_FAILURE);
+ }
+
+ while (list)
+ {
+ char *arg = list->word->word;
+
+ if (ISOPTION (arg, 'r'))
+ {
+ expunge_hash_table = 1;
+ list = list->next;
+ }
+ else if (ISOPTION (arg, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (*arg == '-')
+ {
+ bad_option (list->word->word);
+ builtin_error ("usage: hash [-r] [command ...]");
+ return (EX_USAGE);
+ }
+ else
+ break;
+ }
+
+ /* We want hash -r to be silent, but hash -- to print hashing info. That
+ is the reason for the !expunge_hash_table. */
+ if (!list && !expunge_hash_table)
+ {
+ /* Print information about current hashed info. */
+ int any_printed = 0;
+ int bucket = 0;
+ register BUCKET_CONTENTS *item_list;
+
+ while (bucket < hashed_filenames->nbuckets)
+ {
+ item_list = get_hash_bucket (bucket, hashed_filenames);
+ if (item_list)
+ {
+ if (!any_printed)
+ {
+ printf ("hits\tcommand\n");
+ any_printed++;
+ }
+ while (item_list)
+ {
+ printf ("%4d\t%s\n",
+ item_list->times_found, pathdata(item_list)->path);
+ item_list = item_list->next;
+ }
+ }
+ bucket++;
+ }
+
+ if (!any_printed)
+ printf ("No commands in hash table.\n");
+
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (expunge_hash_table)
+ {
+ int bucket = 0;
+ register BUCKET_CONTENTS *item_list, *prev;
+
+ while (bucket < hashed_filenames->nbuckets)
+ {
+ item_list = get_hash_bucket (bucket, hashed_filenames);
+ if (item_list)
+ {
+ while (item_list)
+ {
+ prev = item_list;
+ free (item_list->key);
+ free (pathdata(item_list)->path);
+ free (item_list->data);
+ item_list = item_list->next;
+ free (prev);
+ }
+ hashed_filenames->bucket_array[bucket] = (BUCKET_CONTENTS *)NULL;
+ }
+ bucket++;
+ }
+ }
+
+ while (list)
+ {
+ /* Add or rehash the specified commands. */
+ char *word;
+ char *full_path;
+ SHELL_VAR *var;
+
+ word = list->word->word;
+ if (absolute_program (word))
+ {
+ list = list->next;
+ continue;
+ }
+ full_path = find_user_command (word);
+ var = find_function (word);
+
+ if (!find_shell_builtin (word) && (!var))
+ {
+ if (full_path && executable_file (full_path))
+ remember_filename (word, full_path, dot_found_in_search, 0);
+ else
+ {
+ builtin_error ("%s: not found", word);
+ any_failed++;
+ }
+ }
+ if (full_path)
+ free (full_path);
+
+ list = list->next;
+ }
+
+ fflush (stdout);
+
+ if (any_failed)
+ return (EXECUTION_FAILURE);
+ else
+ return (EXECUTION_SUCCESS);
+}
+
+/* Place FILENAME (key) and FULL_PATHNAME (data->path) into the
+ hash table. CHECK_DOT if non-null is for future calls to
+ find_hashed_filename (). FOUND is the initial value for
+ times_found. */
+void
+remember_filename (filename, full_pathname, check_dot, found)
+ char *filename, *full_pathname;
+ int check_dot, found;
+{
+ register BUCKET_CONTENTS *item;
+
+ if (hashing_disabled)
+ return;
+ item = add_hash_item (filename, hashed_filenames);
+ if (item->data)
+ free (pathdata(item)->path);
+ else
+ {
+ item->key = savestring (filename);
+ item->data = (char *)xmalloc (sizeof (PATH_DATA));
+ }
+ pathdata(item)->path = savestring (full_pathname);
+ pathdata(item)->check_dot = check_dot;
+ item->times_found = found;
+}
diff --git a/builtins/hashcom.h b/builtins/hashcom.h
new file mode 100644
index 0000000..defe2fc
--- /dev/null
+++ b/builtins/hashcom.h
@@ -0,0 +1,32 @@
+/* hashcom.h - Common defines for hashing filenames. */
+
+/* Copyright (C) 1993 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation; either version 2, or (at your option) any later
+ version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+ for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../hash.h"
+
+#define FILENAME_HASH_BUCKETS 631
+
+extern HASH_TABLE *hashed_filenames;
+
+typedef struct {
+ char *path; /* The full pathname of the file. */
+ int check_dot; /* Whether `.' appeared before this one in $PATH. */
+} PATH_DATA;
+
+#define pathdata(x) ((PATH_DATA *)(x)->data)
diff --git a/builtins/help.def b/builtins/help.def
new file mode 100644
index 0000000..c9f1db8
--- /dev/null
+++ b/builtins/help.def
@@ -0,0 +1,134 @@
+This file is help.def, from which is created help.c.
+It implements the builtin "help" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES help.c
+
+$BUILTIN help
+$FUNCTION help_builtin
+$SHORT_DOC help [pattern ...]
+Display helpful information about builtin commands. If PATTERN is
+specified, gives detailed help on all commands matching PATTERN,
+otherwise a list of the builtins is printed.
+$END
+
+#include <stdio.h>
+#include "../shell.h"
+#include "../builtins.h"
+
+#if defined (USE_GLOB_LIBRARY)
+# include <glob/glob.h>
+#else
+# define FNM_NOMATCH 1
+#endif /* USE_GLOB_LIBRARY */
+
+/* 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. */
+help_builtin (list)
+ WORD_LIST *list;
+{
+ if (!list)
+ {
+ register int i, j;
+ char blurb[256];
+
+ show_shell_version ();
+ printf (
+"Shell commands that 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\
+\n\
+A star (*) next to a name means that the command is disabled.\n\
+\n");
+
+ for (i = 0; i < num_shell_builtins; i++)
+ {
+ QUIT;
+ sprintf (blurb, "%c%s",
+ (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*',
+ shell_builtins[i].short_doc);
+
+ blurb[35] = '\0';
+ printf ("%s", blurb);
+
+ if (i % 2)
+ printf ("\n");
+ else
+ for (j = strlen (blurb); j < 35; j++)
+ putc (' ', stdout);
+
+ }
+ if (i % 2)
+ printf ("\n");
+ }
+ else
+ {
+ int match_found = 0;
+ char *pattern = "";
+
+ if (glob_pattern_p (list->word->word))
+ {
+ printf ("Shell commands matching keyword%s `",
+ list->next ? "s" : "");
+ print_word_list (list, ", ");
+ printf ("'\n\n");
+ }
+
+ while (list)
+ {
+ register int i = 0, plen;
+ char *name;
+
+ pattern = list->word->word;
+ plen = strlen (pattern);
+
+ while (name = shell_builtins[i].name)
+ {
+ int doc_index;
+
+ QUIT;
+ if ((strncmp (pattern, name, plen) == 0) ||
+ (fnmatch (pattern, name, 0) != FNM_NOMATCH))
+ {
+ printf ("%s: %s\n", name, shell_builtins[i].short_doc);
+
+ for (doc_index = 0;
+ shell_builtins[i].long_doc[doc_index]; doc_index++)
+ printf (" %s\n", shell_builtins[i].long_doc[doc_index]);
+
+ match_found++;
+ }
+ i++;
+ }
+ list = list->next;
+ }
+
+ if (!match_found)
+ {
+ fprintf (stderr, "No help topics match `%s'. Try `help help'.\n",
+ pattern);
+ fflush (stderr);
+ return (EXECUTION_FAILURE);
+ }
+ }
+ fflush (stdout);
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/history.def b/builtins/history.def
new file mode 100644
index 0000000..814e705
--- /dev/null
+++ b/builtins/history.def
@@ -0,0 +1,179 @@
+This file is history.def, from which is created history.c.
+It implements the builtin "history" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES history.c
+
+$BUILTIN history
+$FUNCTION history_builtin
+$DEPENDS_ON HISTORY
+$SHORT_DOC history [n] [ [-awrn] [filename]]
+Display the history list with line numbers. Lines listed with
+with a `*' have been modified. Argument of N says to list only
+the last N lines. Argument `-w' means to write out the current
+history file; `-r' means to read it instead. Argument `-a' means
+to append history lines from this session to the history file.
+Argument `-n' means to read all history lines not already read
+from the history file. If FILENAME is given, then use that file,
+else if $HISTFILE has a value, use that, else use ~/.bash_history.
+$END
+
+#include "../shell.h"
+#if defined (HISTORY)
+#include <sys/types.h>
+#include <sys/file.h>
+#include "../filecntl.h"
+#include "../posixstat.h"
+#include "../bashhist.h"
+#include <readline/history.h>
+
+/* History. Arg of -w FILENAME means write file, arg of -r FILENAME
+ means read file. Arg of N means only display that many items. */
+
+history_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ int limited = 0, limit = 0;
+ HIST_ENTRY **hlist;
+
+ while (list)
+ {
+ char *arg = list->word->word;
+
+ if ((arg[0] == '-') &&
+ (strlen (arg) == 2) &&
+ (member (arg[1], "rwan")))
+ {
+ char *file;
+ int result = EXECUTION_SUCCESS;
+
+ if (list->next)
+ file = list->next->word->word;
+ else
+ file = get_string_value ("HISTFILE");
+
+ switch (arg[1])
+ {
+ case 'a': /* Append `new' lines to file. */
+ {
+ if (history_lines_this_session)
+ {
+ void using_history ();
+
+ if (history_lines_this_session < where_history ())
+ {
+ /* If the filename was supplied, then create it
+ if it doesn't already exist. */
+ if (file)
+ {
+ struct stat buf;
+
+ if (stat (file, &buf) == -1)
+ {
+ int tem;
+
+ tem = open (file, O_CREAT, 0666);
+ close (tem);
+ }
+ }
+
+ result =
+ append_history (history_lines_this_session, file);
+ history_lines_in_file += history_lines_this_session;
+ history_lines_this_session = 0;
+ }
+ }
+ break;
+ }
+
+ case 'w': /* Write entire history. */
+ {
+ result = write_history (file);
+ break;
+ }
+
+ case 'r': /* Read entire file. */
+ {
+ result = read_history (file);
+ break;
+ }
+
+ case 'n': /* Read `new' history from file. */
+ {
+ /* Read all of the lines in the file that we haven't
+ already read. */
+ using_history ();
+ result = read_history_range (file, history_lines_in_file, -1);
+ using_history ();
+ history_lines_in_file = where_history ();
+
+ break;
+ }
+ }
+ return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
+ }
+ else if (strcmp (list->word->word, "--") == 0)
+ {
+ list = list->next;
+ break;
+ }
+ else if (*list->word->word == '-')
+ {
+ bad_option (list->word->word);
+ builtin_error ("usage: history [n] [-rwan [filename]]");
+ return (EX_USAGE);
+ }
+ else
+ break;
+ }
+
+ if (list)
+ {
+ limited = 1;
+ limit = get_numeric_arg (list);
+ }
+
+ hlist = history_list ();
+
+ if (hlist)
+ {
+ for (i = 0; hlist[i]; i++);
+
+ if (limit < 0)
+ limit = -limit;
+
+ if (!limited)
+ i = 0;
+ else
+ if ((i -= limit) < 0)
+ i = 0;
+
+ while (hlist[i])
+ {
+ QUIT;
+ printf ("%5d%c %s\n", i + history_base,
+ hlist[i]->data ? '*' : ' ', hlist[i]->line);
+ i++;
+ }
+ }
+ return (EXECUTION_SUCCESS);
+}
+#endif /* HISTORY */
diff --git a/builtins/inlib.def b/builtins/inlib.def
new file mode 100644
index 0000000..023945b
--- /dev/null
+++ b/builtins/inlib.def
@@ -0,0 +1,74 @@
+This file is inlib.def, from which is created inlib.c.
+It implements the Apollo-specific builtin "inlib" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES inlib.c
+#include <stdio.h>
+#include "../shell.h"
+
+$BUILTIN inlib
+$FUNCTION inlib_builtin
+$DEPENDS_ON apollo
+$SHORT_DOC inlib pathname [pathname...]
+Install a user-supplied library specified by pathname in the current
+shell process. The library is used to resolve external references
+in programs and libraries loaded after its installation. Note
+that the library is not loaded into the address space unless it is
+needed to resolve an external reference. The list of inlibed
+libraries is passed to all children of the current shell.
+$END
+
+#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_error ("usage: inlib pathname [pathname...]");
+ 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 ("inlib failed for %s", list->word->word);
+ return_value = EXECUTION_FAILURE;
+ }
+
+ list = list->next;
+ }
+
+ return (return_value);
+}
+#endif /* apollo */
diff --git a/builtins/jobs.def b/builtins/jobs.def
new file mode 100644
index 0000000..8a293da
--- /dev/null
+++ b/builtins/jobs.def
@@ -0,0 +1,171 @@
+This file is jobs.def, from which is created jobs.c.
+It implements the builtin "jobs" in Bash.
+
+Copyright (C) 1987, 1989, 1991, 1992 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES jobs.c
+
+$BUILTIN jobs
+$FUNCTION jobs_builtin
+$DEPENDS_ON JOB_CONTROL
+$SHORT_DOC jobs [-lnp] [jobspec ...] | jobs -x command [args]
+Lists the active jobs. The -l option lists process id's in addition
+to the normal information; the -p option lists process id's only.
+If -n is given, only processes that have changed status since the last
+notification are printed. JOBSPEC restricts output to that job.
+If -x is given, COMMAND is run after all job specifications that appear
+in ARGS have been replaced with the process ID of that job's process group
+leader.
+$END
+
+#include "../shell.h"
+
+#if defined (JOB_CONTROL)
+#include <sys/types.h>
+#include <signal.h>
+#include "../jobs.h"
+
+#include "bashgetopt.h"
+
+extern int job_control, interactive_shell;
+static int execute_list_with_replacements ();
+
+/* 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. */
+int
+jobs_builtin (list)
+ WORD_LIST *list;
+{
+ int form = JLIST_STANDARD, execute = 0;
+ int opt;
+ int any_failed = 0;
+
+ if (!job_control && !interactive_shell)
+ return (EXECUTION_SUCCESS);
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "lpnx")) != -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 ("Other options not allowed with `-x'");
+ return (EXECUTION_FAILURE);
+ }
+ execute++;
+ break;
+
+ default:
+ builtin_error ("usage: jobs [-lpn [jobspec]] [-x command [args]]");
+ return (EX_USAGE);
+ }
+ }
+
+ list = loptend;
+
+ if (execute)
+ return (execute_list_with_replacements (list));
+
+ if (!list)
+ {
+ list_jobs (form);
+ return (EXECUTION_SUCCESS);
+ }
+
+ while (list)
+ {
+ int job;
+ sigset_t set, oset;
+
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if ((job == NO_JOB) || !jobs || !jobs[job])
+ {
+ builtin_error ("No such job %s", 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;
+
+ /* 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 (job < 0 || job >= job_slots || !jobs[job])
+ continue;
+
+ free (l->word->word);
+ l->word->word = itos (jobs[job]->pgrp);
+ }
+ }
+
+ /* Next make a new simple command and execute it. */
+ begin_unwind_frame ("jobs_builtin");
+ {
+ COMMAND *command = (COMMAND *)NULL;
+
+ add_unwind_protect (dispose_command, command);
+
+ 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;
+
+ result = execute_command (command);
+ }
+
+ run_unwind_frame ("jobs_builtin");
+ return (result);
+}
+#endif /* JOB_CONTROL */
diff --git a/builtins/kill.def b/builtins/kill.def
new file mode 100644
index 0000000..53d5c8f
--- /dev/null
+++ b/builtins/kill.def
@@ -0,0 +1,281 @@
+This file is kill.def, from which is created kill.c.
+It implements the builtin "kill" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES kill.c
+
+$BUILTIN kill
+$FUNCTION kill_builtin
+$DEPENDS_ON JOB_CONTROL
+$SHORT_DOC kill [-s sigspec | -sigspec] [pid | job]... | -l [signum]
+Send the processes named by PID (or JOB) the signal SIGSPEC. If
+SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l'
+lists the signal names; if arguments follow `-l' they are assumed to
+be signal numbers for which names should be listed. Kill is a shell
+builtin for two reasons: it allows job IDs to be used instead of
+process IDs, and, if you have reached the limit on processes that
+you can create, you don't have to start a process to kill another one.
+$END
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+#include "../bashtypes.h"
+#include "../shell.h"
+#include "../trap.h"
+#include "../jobs.h"
+#include "common.h"
+#include <errno.h>
+
+#if defined (JOB_CONTROL)
+extern int interactive;
+extern int posixly_correct;
+
+#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 signal = SIGTERM;
+ int any_succeeded = 0, listing = 0, saw_signal = 0;
+ char *sigspec = "TERM", *word;
+ pid_t pid;
+
+ if (!list)
+ return (EXECUTION_SUCCESS);
+
+ /* Process options. */
+ while (list)
+ {
+ word = list->word->word;
+
+ if (ISOPTION (word, 'l'))
+ {
+ listing++;
+ list = list->next;
+ }
+ else if (ISOPTION (word, 's'))
+ {
+ list = list->next;
+ if (list)
+ {
+ sigspec = list->word->word;
+ if (sigspec[0] == '0' && !sigspec[1])
+ signal = 0;
+ else
+ signal = decode_signal (sigspec);
+ list = list->next;
+ }
+ else
+ {
+ builtin_error ("-s requires an argument");
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else if (ISOPTION (word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ /* 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)
+ {
+ sigspec = word + 1;
+ signal = decode_signal (sigspec);
+ saw_signal++;
+ list = list->next;
+ }
+ else
+ break;
+ }
+
+ if (listing)
+ {
+ if (!list)
+ {
+ register int i;
+ register int column = 0;
+ char *name;
+
+ for (i = 1; i < NSIG; i++)
+ {
+ name = signal_name (i);
+ if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
+ continue;
+
+ if (posixly_correct)
+ printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
+ else
+ {
+ printf ("%2d) %s", i, name);
+
+ if (++column < 4)
+ printf ("\t");
+ else
+ {
+ printf ("\n");
+ column = 0;
+ }
+ }
+ }
+
+ if (posixly_correct || column != 0)
+ printf ("\n");
+ }
+ else
+ {
+ /* List individual signal names. */
+ while (list)
+ {
+ int signum;
+ char *name;
+
+ if ((sscanf (list->word->word, "%d", &signum) != 1) ||
+ (signum <= 0))
+ {
+ list_error:
+ builtin_error ("bad signal number: %s", list->word->word);
+ list = list->next;
+ continue;
+ }
+
+ /* This is specified by Posix.2 so that exit statuses can be
+ mapped into signal numbers. */
+ if (signum > 128)
+ signum -= 128;
+
+ if (signum >= NSIG)
+ goto list_error;
+
+ name = signal_name (signum);
+ if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
+ {
+ list = list->next;
+ continue;
+ }
+ printf ("%s\n", name);
+ list = list->next;
+ }
+ }
+ return (EXECUTION_SUCCESS);
+ }
+
+ /* OK, we are killing processes. */
+ if (signal == NO_SIG)
+ {
+ builtin_error ("bad signal spec `%s'", sigspec);
+ return (EXECUTION_FAILURE);
+ }
+
+ while (list)
+ {
+ word = list->word->word;
+
+ if (*word == '-')
+ word++;
+
+ if (all_digits (word))
+ {
+ /* Use the entire argument in case of minus sign presence. */
+ pid = (pid_t) atoi (list->word->word);
+
+ if (kill_pid (pid, signal, 0) < 0)
+ goto signal_error;
+ else
+ any_succeeded++;
+ }
+ else if (*list->word->word != '%')
+ {
+ builtin_error ("No such pid %s", list->word->word);
+ CONTINUE_OR_FAIL;
+ }
+#if 1
+ else if (interactive)
+ /* Posix.2 says you can kill without job control active (4.32.4) */
+#else
+ else if (job_control) /* can't kill jobs if not using job control */
+#endif
+ { /* Must be a job spec. Check it out. */
+ int job;
+ sigset_t set, oset;
+
+ BLOCK_CHILD (set, oset);
+ job = get_job_spec (list);
+
+ if (job < 0 || job >= job_slots || !jobs[job])
+ {
+ if (job != DUP_JOB)
+ builtin_error ("No such job %s", list->word->word);
+ UNBLOCK_CHILD (oset);
+ CONTINUE_OR_FAIL;
+ }
+
+ /* 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. */
+ if (jobs[job]->flags & J_JOBCONTROL)
+ pid = jobs[job]->pgrp;
+ else
+ pid = jobs[job]->pipe->pid;
+
+ UNBLOCK_CHILD (oset);
+
+ if (kill_pid (pid, signal, 1) < 0)
+ {
+ signal_error:
+ if (errno == EPERM)
+ builtin_error ("(%d) - Not owner", (int)pid);
+ else if (errno == ESRCH)
+ builtin_error ("(%d) - No such pid", (int)pid);
+ else
+ builtin_error ("Invalid signal %d", signal);
+ CONTINUE_OR_FAIL;
+ }
+ else
+ any_succeeded++;
+ }
+ else
+ {
+ builtin_error ("bad process specification `%s'", list->word->word);
+ CONTINUE_OR_FAIL;
+ }
+ continue_killing:
+ list = list->next;
+ }
+
+ if (any_succeeded)
+ return (EXECUTION_SUCCESS);
+ else
+ return (EXECUTION_FAILURE);
+}
+#endif /* JOB_CONTROL */
diff --git a/builtins/let.def b/builtins/let.def
new file mode 100644
index 0000000..fdb3a6f
--- /dev/null
+++ b/builtins/let.def
@@ -0,0 +1,77 @@
+This file is let.def, from which is created let.c.
+It implements the builtin "let" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$BUILTIN let
+$FUNCTION let_builtin
+$PRODUCES let.c
+$SHORT_DOC let arg [arg ...]
+Each ARG is an arithmetic expression to be evaluated. Evaluation
+is done in long integers with no check for overflow, though division
+by 0 is trapped and flagged as an error. The following list of
+operators is grouped into levels of equal-precedence operators.
+The levels are listed in order of decreasing precedence.
+
+ - unary minus
+ ! logical NOT
+ * / % multiplication, division, remainder
+ + - addition, subtraction
+ <= >= < > comparison
+ == != equality inequality
+ = assignment
+
+Shell variables are allowed as operands. The name of the variable
+is replaced by its value (coerced to a long integer) within
+an expression. The variable need not have its integer attribute
+turned on to be used in an expression.
+
+Operators are evaluated in order of precedence. Sub-expressions in
+parentheses are evaluated first and may override the precedence
+rules above.
+
+If the last ARG evaluates to 0, let returns 1; 0 is returned
+otherwise.
+$END
+
+#include "../shell.h"
+
+/* Arithmetic LET function. */
+let_builtin (list)
+ WORD_LIST *list;
+{
+ long ret = 0L;
+
+ if (!list)
+ {
+ builtin_error ("argument (expression) expected");
+ return (EXECUTION_FAILURE);
+ }
+
+ while (list)
+ {
+ ret = evalexp (list->word->word);
+ list = list->next;
+ }
+
+ if (ret == 0L)
+ return (EXECUTION_FAILURE);
+ else
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/mkbuiltins.c b/builtins/mkbuiltins.c
new file mode 100644
index 0000000..572d01e
--- /dev/null
+++ b/builtins/mkbuiltins.c
@@ -0,0 +1,1311 @@
+/* mkbuiltins.c - Create builtins.c, builtext.h, and builtdoc.c from
+ a single source file called builtins.def. */
+
+/* Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#include "../bashansi.h"
+#include "../config.h"
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include "../filecntl.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif /* HAVE_UNISTD_H */
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#define DOCFILE "builtins.texi"
+
+static char *xmalloc (), *xrealloc ();
+
+#if !defined (__STDC__) && !defined (strcpy)
+extern char *strcpy ();
+#endif /* !__STDC__ && !strcpy */
+
+#define savestring(x) strcpy (xmalloc (1 + strlen (x)), (x))
+#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
+
+/* Flag values that builtins can have. */
+#define BUILTIN_FLAG_SPECIAL 0x01
+
+/* If this stream descriptor is non-zero, then write
+ texinfo documentation to it. */
+FILE *documentation_file = (FILE *)NULL;
+
+/* Non-zero means to only produce documentation. */
+int only_documentation = 0;
+
+/* Non-zero means to not do any productions. */
+int inhibit_production = 0;
+
+#if !defined (OLDCODE)
+int no_long_document = 0;
+#endif /* !OLDCODE */
+
+/* The name of a directory to precede the filename when reporting
+ errors. */
+char *error_directory = (char *)NULL;
+
+/* The name of the structure file. */
+char *struct_filename = (char *)NULL;
+
+/* The name of the external declaration file. */
+char *extern_filename = (char *)NULL;
+
+/* Here is a structure for manipulating arrays of data. */
+typedef struct {
+ int size; /* Number of slots allocated to array. */
+ int sindex; /* Current location in array. */
+ int width; /* Size of each element. */
+ int growth_rate; /* How fast to grow. */
+ char **array; /* The array itself. */
+} ARRAY;
+
+/* Here is a structure defining a single BUILTIN. */
+typedef struct {
+ char *name; /* The name of this builtin. */
+ char *function; /* The name of the function to call. */
+ char *shortdoc; /* The short documentation for this builtin. */
+ char *docname; /* Possible name for documentation string. */
+ ARRAY *longdoc; /* The long documentation for this builtin. */
+ ARRAY *dependencies; /* Null terminated array of #define names. */
+ int flags; /* Flags for this builtin. */
+} BUILTIN_DESC;
+
+/* Here is a structure which defines a DEF file. */
+typedef struct {
+ char *filename; /* The name of the input def file. */
+ ARRAY *lines; /* The contents of the file. */
+ int line_number; /* The current line number. */
+ char *production; /* The name of the production file. */
+ FILE *output; /* Open file stream for PRODUCTION. */
+ ARRAY *builtins; /* Null terminated array of BUILTIN_DESC *. */
+} DEF_FILE;
+
+/* The array of all builtins encountered during execution of this code. */
+ARRAY *saved_builtins = (ARRAY *)NULL;
+
+/* The Posix.2 so-called `special' builtins. */
+char *special_builtins[] =
+{
+ ":", ".", "source", "break", "continue", "eval", "exec", "exit",
+ "export", "readonly", "return", "set", "shift", "trap", "unset",
+ (char *)NULL
+};
+static int is_special_builtin ();
+
+
+/* For each file mentioned on the command line, process it and
+ write the information to STRUCTFILE and EXTERNFILE, while
+ creating the production file if neccessary. */
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ int arg_index = 1;
+ FILE *structfile, *externfile;
+ char *documentation_filename, *temp_struct_filename;
+
+ structfile = externfile = (FILE *)NULL;
+ documentation_filename = DOCFILE;
+ temp_struct_filename = (char *)NULL;
+
+ while (arg_index < argc && argv[arg_index][0] == '-')
+ {
+ char *arg = argv[arg_index++];
+
+ if (strcmp (arg, "-externfile") == 0)
+ extern_filename = argv[arg_index++];
+ else if (strcmp (arg, "-structfile") == 0)
+ struct_filename = argv[arg_index++];
+ else if (strcmp (arg, "-noproduction") == 0)
+ inhibit_production = 1;
+ else if (strcmp (arg, "-document") == 0)
+ documentation_file = fopen (documentation_filename, "w");
+ else if (strcmp (arg, "-D") == 0)
+ {
+ int len;
+
+ if (error_directory)
+ free (error_directory);
+
+ error_directory = xmalloc (2 + strlen (argv[arg_index]));
+ strcpy (error_directory, argv[arg_index]);
+ len = strlen (error_directory);
+
+ if (len && error_directory[len - 1] != '/')
+ strcat (error_directory, "/");
+
+ arg_index++;
+ }
+ else if (strcmp (arg, "-documentonly") == 0)
+ {
+ only_documentation = 1;
+ documentation_file = fopen (documentation_filename, "w");
+ }
+#if !defined (OLDCODE)
+ else if (strcmp (arg, "-nodocument") == 0)
+ no_long_document = 1;
+#endif /* !OLDCODE */
+ else
+ {
+ fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg);
+ exit (2);
+ }
+ }
+
+ /* If there are no files to process, just quit now. */
+ if (arg_index == argc)
+ exit (0);
+
+ if (!only_documentation)
+ {
+ /* Open the files. */
+ if (struct_filename)
+ {
+ temp_struct_filename = xmalloc (15);
+ sprintf (temp_struct_filename, "mk-%d", (int) getpid ());
+ structfile = fopen (temp_struct_filename, "w");
+
+ if (!structfile)
+ file_error (temp_struct_filename);
+ }
+
+ if (extern_filename)
+ {
+ externfile = fopen (extern_filename, "w");
+
+ if (!externfile)
+ file_error (extern_filename);
+ }
+
+ /* Write out the headers. */
+ write_file_headers (structfile, externfile);
+ }
+
+ if (documentation_file)
+ {
+ fprintf (documentation_file, "@c Table of builtins created with %s.\n",
+ argv[0]);
+ fprintf (documentation_file, "@ftable @asis\n");
+ }
+
+ /* Process the .def files. */
+ while (arg_index < argc)
+ {
+ register char *arg;
+
+ arg = argv[arg_index++];
+
+ extract_info (arg, structfile, externfile);
+ }
+
+ /* Close the files. */
+ if (!only_documentation)
+ {
+ /* Write the footers. */
+ write_file_footers (structfile, externfile);
+
+ if (structfile)
+ {
+ write_longdocs (structfile, saved_builtins);
+ fclose (structfile);
+ link (temp_struct_filename, struct_filename);
+ unlink (temp_struct_filename);
+ }
+
+ if (externfile)
+ fclose (externfile);
+ }
+
+ if (documentation_file)
+ {
+ fprintf (documentation_file, "@end ftable\n");
+ fclose (documentation_file);
+ }
+
+ exit (0);
+}
+
+/* **************************************************************** */
+/* */
+/* Array Functions and Manipulators */
+/* */
+/* **************************************************************** */
+
+/* Make a new array, and return a pointer to it. The array will
+ contain elements of size WIDTH, and is initialized to no elements. */
+ARRAY *
+array_create (width)
+ int width;
+{
+ ARRAY *array;
+
+ array = (ARRAY *)xmalloc (sizeof (ARRAY));
+ array->size = 0;
+ array->sindex = 0;
+ array->width = width;
+
+ /* Default to increasing size in units of 20. */
+ array->growth_rate = 20;
+
+ array->array = (char **)NULL;
+
+ return (array);
+}
+
+/* Copy the array of strings in ARRAY. */
+ARRAY *
+copy_string_array (array)
+ ARRAY *array;
+{
+ register int i;
+ ARRAY *copy;
+
+ if (!array)
+ return (ARRAY *)NULL;
+
+ copy = array_create (sizeof (char *));
+
+ copy->size = array->size;
+ copy->sindex = array->sindex;
+ copy->width = array->width;
+
+ copy->array = (char **)xmalloc ((1 + array->sindex) * sizeof (char *));
+
+ for (i = 0; i < array->sindex; i++)
+ copy->array[i] = savestring (array->array[i]);
+
+ copy->array[i] = (char *)NULL;
+
+ return (copy);
+}
+
+/* Add ELEMENT to ARRAY, growing the array if neccessary. */
+array_add (element, array)
+ char *element;
+ ARRAY *array;
+{
+ if (array->sindex + 2 > array->size)
+ array->array = (char **)xrealloc
+ (array->array, (array->size += array->growth_rate) * array->width);
+
+#if defined (HAVE_BCOPY)
+ bcopy (&element, &(array->array[array->sindex]), array->width);
+ array->sindex++;
+ bzero (&(array->array[array->sindex]), array->width);
+#else
+ array->array[array->sindex++] = element;
+ array->array[array->sindex] = (char *)NULL;
+#endif /* !HAVE_BCOPY */
+}
+
+/* Free an allocated array and data pointer. */
+array_free (array)
+ ARRAY *array;
+{
+ if (array->array)
+ free (array->array);
+
+ free (array);
+}
+
+/* **************************************************************** */
+/* */
+/* Processing a DEF File */
+/* */
+/* **************************************************************** */
+
+/* The definition of a function. */
+typedef int Function ();
+
+/* Structure handles processor directives. */
+typedef struct {
+ char *directive;
+ Function *function;
+} HANDLER_ENTRY;
+
+extern int
+ builtin_handler (), function_handler (), short_doc_handler (),
+ comment_handler (), depends_on_handler (), produces_handler (),
+ end_handler (), docname_handler ();
+
+HANDLER_ENTRY handlers[] = {
+ { "BUILTIN", builtin_handler },
+ { "DOCNAME", docname_handler },
+ { "FUNCTION", function_handler },
+ { "SHORT_DOC", short_doc_handler },
+ { "$", comment_handler },
+ { "COMMENT", comment_handler },
+ { "DEPENDS_ON", depends_on_handler },
+ { "PRODUCES", produces_handler },
+ { "END", end_handler },
+ { (char *)NULL, (Function *)NULL }
+};
+
+/* Return the entry in the table of handlers for NAME. */
+HANDLER_ENTRY *
+find_directive (directive)
+ char *directive;
+{
+ register int i;
+
+ for (i = 0; handlers[i].directive; i++)
+ if (strcmp (handlers[i].directive, directive) == 0)
+ return (&handlers[i]);
+
+ return ((HANDLER_ENTRY *)NULL);
+}
+
+/* Non-zero indicates that a $BUILTIN has been seen, but not
+ the corresponding $END. */
+static int building_builtin = 0;
+
+/* Non-zero means to output cpp line and file information before
+ printing the current line to the production file. */
+int output_cpp_line_info = 0;
+
+/* The main function of this program. Read FILENAME and act on what is
+ found. Lines not starting with a dollar sign are copied to the
+ $PRODUCES target, if one is present. Lines starting with a dollar sign
+ are directives to this program, specifying the name of the builtin, the
+ function to call, the short documentation and the long documentation
+ strings. FILENAME can contain multiple $BUILTINs, but only one $PRODUCES
+ target. After the file has been processed, write out the names of
+ builtins found in each $BUILTIN. Plain text found before the $PRODUCES
+ is ignored, as is "$$ comment text". */
+extract_info (filename, structfile, externfile)
+ char *filename;
+ FILE *structfile, *externfile;
+{
+ register int i;
+ DEF_FILE *defs;
+ struct stat finfo;
+ char *buffer, *line;
+ int fd;
+
+ if (stat (filename, &finfo) == -1)
+ file_error (filename);
+
+ fd = open (filename, O_RDONLY, 0666);
+
+ if (fd == -1)
+ file_error (filename);
+
+ buffer = xmalloc (1 + (int)finfo.st_size);
+
+ if (read (fd, buffer, finfo.st_size) != finfo.st_size)
+ file_error (filename);
+
+ close (fd);
+
+ /* Create and fill in the initial structure describing this file. */
+ defs = (DEF_FILE *)xmalloc (sizeof (DEF_FILE));
+ defs->filename = filename;
+ defs->lines = array_create (sizeof (char *));
+ defs->line_number = 0;
+ defs->production = (char *)NULL;
+ defs->output = (FILE *)NULL;
+ defs->builtins = (ARRAY *)NULL;
+
+ /* Build the array of lines. */
+ i = 0;
+ while (i < finfo.st_size)
+ {
+ array_add (&buffer[i], defs->lines);
+
+ while (buffer[i] != '\n' && i < finfo.st_size)
+ i++;
+ buffer[i++] = '\0';
+ }
+
+ /* Begin processing the input file. We don't write any output
+ until we have a file to write output to. */
+ output_cpp_line_info = 1;
+
+ /* Process each line in the array. */
+ for (i = 0; line = defs->lines->array[i]; i++)
+ {
+ defs->line_number = i;
+
+ if (*line == '$')
+ {
+ register int j;
+ char *directive;
+ HANDLER_ENTRY *handler;
+
+ /* Isolate the directive. */
+ for (j = 0; line[j] && !whitespace (line[j]); j++);
+
+ directive = xmalloc (j);
+ strncpy (directive, line + 1, j - 1);
+ directive[j -1] = '\0';
+
+ /* Get the function handler and call it. */
+ handler = find_directive (directive);
+
+ if (!handler)
+ {
+ line_error (defs, "Unknown directive `%s'", directive);
+ free (directive);
+ continue;
+ }
+ else
+ {
+ /* Advance to the first non-whitespace character. */
+ while (whitespace (line[j]))
+ j++;
+
+ /* Call the directive handler with the FILE, and ARGS. */
+ (*(handler->function)) (directive, defs, line + j);
+ }
+ free (directive);
+ }
+ else
+ {
+ if (building_builtin)
+ add_documentation (defs, line);
+ else if (defs->output)
+ {
+ if (output_cpp_line_info)
+ {
+ /* If we're handed an absolute pathname, don't prepend
+ the directory name. */
+ if (defs->filename[0] == '/')
+ fprintf (defs->output, "#line %d \"%s\"\n",
+ defs->line_number + 1, defs->filename);
+ else
+ fprintf (defs->output, "#line %d \"%s%s\"\n",
+ defs->line_number + 1,
+ error_directory ? error_directory : "./",
+ defs->filename);
+ output_cpp_line_info = 0;
+ }
+
+ fprintf (defs->output, "%s\n", line);
+ }
+ }
+ }
+
+ /* Close the production file. */
+ if (defs->output)
+ fclose (defs->output);
+
+ /* The file has been processed. Write the accumulated builtins to
+ the builtins.c file, and write the extern definitions to the
+ builtext.h file. */
+ write_builtins (defs, structfile, externfile);
+
+ free (buffer);
+ free_defs (defs);
+}
+
+#define free_safely(x) if (x) free (x)
+
+static void
+free_builtin (builtin)
+ BUILTIN_DESC *builtin;
+{
+ register int i;
+
+ free_safely (builtin->name);
+ free_safely (builtin->function);
+ free_safely (builtin->shortdoc);
+ free_safely (builtin->docname);
+
+ if (builtin->longdoc)
+ array_free (builtin->longdoc);
+
+ if (builtin->dependencies)
+ {
+ for (i = 0; builtin->dependencies->array[i]; i++)
+ free (builtin->dependencies->array[i]);
+ array_free (builtin->dependencies);
+ }
+}
+
+/* Free all of the memory allocated to a DEF_FILE. */
+free_defs (defs)
+ DEF_FILE *defs;
+{
+ register int i;
+ register BUILTIN_DESC *builtin;
+
+ if (defs->production)
+ free (defs->production);
+
+ if (defs->lines)
+ array_free (defs->lines);
+
+ if (defs->builtins)
+ {
+ for (i = 0; builtin = (BUILTIN_DESC *)defs->builtins->array[i]; i++)
+ {
+ free_builtin (builtin);
+ free (builtin);
+ }
+ array_free (defs->builtins);
+ }
+ free (defs);
+}
+
+/* **************************************************************** */
+/* */
+/* The Handler Functions Themselves */
+/* */
+/* **************************************************************** */
+
+/* Strip surrounding whitespace from STRING, and
+ return a pointer to the start of it. */
+char *
+strip_whitespace (string)
+ char *string;
+{
+ while (whitespace (*string))
+ string++;
+
+ remove_trailing_whitespace (string);
+ return (string);
+}
+
+/* Remove only the trailing whitespace from STRING. */
+remove_trailing_whitespace (string)
+ char *string;
+{
+ register int i;
+
+ i = strlen (string) - 1;
+
+ while (i > 0 && whitespace (string[i]))
+ i--;
+
+ string[++i] = '\0';
+}
+
+/* Ensure that there is a argument in STRING and return it.
+ FOR_WHOM is the name of the directive which needs the argument.
+ DEFS is the DEF_FILE in which the directive is found.
+ If there is no argument, produce an error. */
+char *
+get_arg (for_whom, defs, string)
+ char *for_whom, *string;
+ DEF_FILE *defs;
+{
+ char *new;
+
+ new = strip_whitespace (string);
+
+ if (!*new)
+ line_error (defs, "%s requires an argument", for_whom);
+
+ return (savestring (new));
+}
+
+/* Error if not building a builtin. */
+must_be_building (directive, defs)
+ char *directive;
+ DEF_FILE *defs;
+{
+ if (!building_builtin)
+ line_error (defs, "%s must be inside of a $BUILTIN block", directive);
+}
+
+/* Return the current builtin. */
+BUILTIN_DESC *
+current_builtin (directive, defs)
+ char *directive;
+ DEF_FILE *defs;
+{
+ must_be_building (directive, defs);
+ return ((BUILTIN_DESC *)defs->builtins->array[defs->builtins->sindex - 1]);
+}
+
+/* Add LINE to the long documentation for the current builtin.
+ Ignore blank lines until the first non-blank line has been seen. */
+add_documentation (defs, line)
+ DEF_FILE *defs;
+ char *line;
+{
+ register BUILTIN_DESC *builtin;
+
+ builtin = current_builtin ("(implied LONGDOC)", defs);
+
+ remove_trailing_whitespace (line);
+
+ if (!*line && !builtin->longdoc)
+ return;
+
+ if (!builtin->longdoc)
+ builtin->longdoc = array_create (sizeof (char *));
+
+ array_add (line, builtin->longdoc);
+}
+
+/* How to handle the $BUILTIN directive. */
+int
+builtin_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ /* If we are already building a builtin, we cannot start a new one. */
+ if (building_builtin)
+ return (line_error (defs, "%s found before $END", self));
+
+ output_cpp_line_info++;
+
+ /* Get the name of this builtin, and stick it in the array. */
+ {
+ BUILTIN_DESC *new;
+ char *name;
+
+ name = get_arg (self, defs, arg);
+
+ /* If this is the first builtin, create the array to hold them. */
+ if (!defs->builtins)
+ defs->builtins = array_create (sizeof (BUILTIN_DESC *));
+
+ new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
+ new->name = name;
+ new->function = (char *)NULL;
+ new->shortdoc = (char *)NULL;
+ new->docname = (char *)NULL;
+ new->longdoc = (ARRAY *)NULL;
+ new->dependencies = (ARRAY *)NULL;
+ new->flags = 0;
+
+ if (is_special_builtin (name))
+ new->flags |= BUILTIN_FLAG_SPECIAL;
+
+ array_add ((char *)new, defs->builtins);
+ building_builtin = 1;
+ }
+ return (0);
+}
+
+/* How to handle the $FUNCTION directive. */
+int
+function_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ register BUILTIN_DESC *builtin;
+
+ builtin = current_builtin (self, defs);
+
+ if (builtin->function)
+ line_error (defs, "%s already has a function (%s)",
+ builtin->name, builtin->function);
+ else
+ builtin->function = get_arg (self, defs, arg);
+
+ return (0);
+}
+
+/* How to handle the $DOCNAME directive. */
+int
+docname_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ register BUILTIN_DESC *builtin;
+
+ builtin = current_builtin (self, defs);
+
+ if (builtin->docname)
+ line_error (defs, "%s already had a docname (%s)",
+ builtin->name, builtin->docname);
+ else
+ builtin->docname = get_arg (self, defs, arg);
+
+ return (0);
+}
+
+/* How to handle the $SHORT_DOC directive. */
+short_doc_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ register BUILTIN_DESC *builtin;
+
+ builtin = current_builtin (self, defs);
+
+ if (builtin->shortdoc)
+ line_error (defs, "%s already has short documentation (%s)",
+ builtin->name, builtin->shortdoc);
+ else
+ builtin->shortdoc = get_arg (self, defs, arg);
+
+ return (0);
+}
+
+/* How to handle the $COMMENT directive. */
+comment_handler (self, defs)
+ char *self;
+ DEF_FILE *defs;
+{
+}
+
+/* How to handle the $DEPENDS_ON directive. */
+depends_on_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ register BUILTIN_DESC *builtin;
+ char *dependent;
+
+ builtin = current_builtin (self, defs);
+ dependent = get_arg (self, defs, arg);
+
+ if (!builtin->dependencies)
+ builtin->dependencies = array_create (sizeof (char *));
+
+ array_add (dependent, builtin->dependencies);
+
+ return (0);
+}
+
+/* How to handle the $PRODUCES directive. */
+produces_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ /* If just hacking documentation, don't change any of the production
+ files. */
+ if (only_documentation)
+ return (0);
+
+ output_cpp_line_info++;
+
+ if (defs->production)
+ line_error (defs, "%s already has a %s definition", defs->filename, self);
+ else
+ {
+ defs->production = get_arg (self, defs, arg);
+
+ if (inhibit_production)
+ return (0);
+
+ defs->output = fopen (defs->production, "w");
+
+ if (!defs->output)
+ file_error (defs->production);
+
+ fprintf (defs->output, "/* %s, created from %s. */\n",
+ defs->production, defs->filename);
+ }
+ return (0);
+}
+
+/* How to handle the $END directive. */
+end_handler (self, defs, arg)
+ char *self, *arg;
+ DEF_FILE *defs;
+{
+ must_be_building (self, defs);
+ building_builtin = 0;
+}
+
+/* **************************************************************** */
+/* */
+/* Error Handling Functions */
+/* */
+/* **************************************************************** */
+
+/* Produce an error for DEFS with FORMAT and ARGS. */
+line_error (defs, format, arg1, arg2)
+ DEF_FILE *defs;
+ char *format, *arg1, *arg2;
+{
+ if (defs->filename[0] != '/')
+ fprintf (stderr, "%s", error_directory ? error_directory : "./");
+ fprintf (stderr, "%s:%d:", defs->filename, defs->line_number + 1);
+ fprintf (stderr, format, arg1, arg2);
+ fprintf (stderr, "\n");
+ fflush (stderr);
+}
+
+/* Print error message for FILENAME. */
+file_error (filename)
+ char *filename;
+{
+ perror (filename);
+ exit (2);
+}
+
+/* **************************************************************** */
+/* */
+/* xmalloc and xrealloc () */
+/* */
+/* **************************************************************** */
+
+static void memory_error_and_abort ();
+
+static char *
+xmalloc (bytes)
+ int bytes;
+{
+ char *temp = (char *)malloc (bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+ return (temp);
+}
+
+static char *
+xrealloc (pointer, bytes)
+ char *pointer;
+ int bytes;
+{
+ char *temp;
+
+ if (!pointer)
+ temp = (char *)malloc (bytes);
+ else
+ temp = (char *)realloc (pointer, bytes);
+
+ if (!temp)
+ memory_error_and_abort ();
+
+ return (temp);
+}
+
+static void
+memory_error_and_abort ()
+{
+ fprintf (stderr, "mkbuiltins: Out of virtual memory!\n");
+ abort ();
+}
+
+/* **************************************************************** */
+/* */
+/* Creating the Struct and Extern Files */
+/* */
+/* **************************************************************** */
+
+/* Return a pointer to a newly allocated builtin which is
+ an exact copy of BUILTIN. */
+BUILTIN_DESC *
+copy_builtin (builtin)
+ BUILTIN_DESC *builtin;
+{
+ BUILTIN_DESC *new;
+
+ new = (BUILTIN_DESC *)xmalloc (sizeof (BUILTIN_DESC));
+
+ new->name = savestring (builtin->name);
+ new->shortdoc = savestring (builtin->shortdoc);
+ new->longdoc = copy_string_array (builtin->longdoc);
+ new->dependencies = copy_string_array (builtin->dependencies);
+
+ new->function =
+ builtin->function ? savestring (builtin->function) : (char *)NULL;
+ new->docname =
+ builtin->docname ? savestring (builtin->docname) : (char *)NULL;
+
+ return (new);
+}
+
+/* How to save away a builtin. */
+save_builtin (builtin)
+ BUILTIN_DESC *builtin;
+{
+ BUILTIN_DESC *newbuiltin;
+
+ newbuiltin = copy_builtin (builtin);
+
+ /* If this is the first builtin to be saved, create the array
+ to hold it. */
+ if (!saved_builtins)
+ saved_builtins = array_create (sizeof (BUILTIN_DESC *));
+
+ array_add ((char *)newbuiltin, saved_builtins);
+}
+
+/* Flags that mean something to write_documentation (). */
+#define STRING_ARRAY 1
+#define TEXINFO 2
+
+char *structfile_header[] = {
+ "/* 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, 1991, 1992 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 1, or (at your option)",
+ " any later version.",
+ "",
+ " Bash is distributed in the hope that it will be useful, but WITHOUT",
+ " ANY WARRANTY; without even the implied warranty of MERCHANTABILITY",
+ " or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public",
+ " License for more details.",
+ "",
+ " You should have received a copy of the GNU General Public License",
+ " along with Bash; see the file COPYING. If not, write to the Free",
+ " Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */",
+ "",
+ "/* The list of shell builtins. Each element is name, function, enabled-p,",
+ " 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 == (Function *)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\"",
+ (char *)NULL
+ };
+
+char *structfile_footer[] = {
+ " { (char *)0x0, (Function *)0x0, 0, (char **)0x0, (char *)0x0 }",
+ "};",
+ "",
+ "int num_shell_builtins =",
+ "\tsizeof (shell_builtins) / sizeof (struct builtin) - 1;",
+ (char *)NULL
+};
+
+/* Write out any neccessary opening information for
+ STRUCTFILE and EXTERNFILE. */
+write_file_headers (structfile, externfile)
+ FILE *structfile, *externfile;
+{
+ register int i;
+
+ if (structfile)
+ {
+ for (i = 0; structfile_header[i]; i++)
+ fprintf (structfile, "%s\n", structfile_header[i]);
+
+ fprintf (structfile, "#include \"%s\"\n",
+ extern_filename ? extern_filename : "builtext.h");
+ fprintf (structfile, "\nstruct builtin shell_builtins[] = {\n");
+ }
+
+ if (externfile)
+ fprintf (externfile,
+ "/* %s - The list of builtins found in libbuiltins.a. */\n",
+ extern_filename ? extern_filename : "builtext.h");
+}
+
+/* Write out any necessary closing information for
+ STRUCTFILE and EXTERNFILE. */
+write_file_footers (structfile, externfile)
+ FILE *structfile, *externfile;
+{
+ register int i;
+
+ /* Write out the footers. */
+ if (structfile)
+ {
+ for (i = 0; structfile_footer[i]; i++)
+ fprintf (structfile, "%s\n", structfile_footer[i]);
+ }
+}
+
+/* Write out the information accumulated in DEFS to
+ STRUCTFILE and EXTERNFILE. */
+write_builtins (defs, structfile, externfile)
+ DEF_FILE *defs;
+ FILE *structfile, *externfile;
+{
+ register int i;
+
+ /* Write out the information. */
+ if (defs->builtins)
+ {
+ register BUILTIN_DESC *builtin;
+
+ for (i = 0; i < defs->builtins->sindex; i++)
+ {
+ builtin = (BUILTIN_DESC *)defs->builtins->array[i];
+
+ /* Write out any #ifdefs that may be there. */
+ if (!only_documentation)
+ {
+ if (builtin->dependencies)
+ {
+ if (builtin->function)
+ write_ifdefs (externfile, builtin->dependencies->array);
+ write_ifdefs (structfile, builtin->dependencies->array);
+ }
+
+ /* Write the extern definition. */
+ if (externfile)
+ {
+ if (builtin->function)
+ fprintf (externfile, "extern int %s ();\n",
+ builtin->function);
+
+ fprintf (externfile, "extern char *%s_doc[];\n",
+ builtin->docname ?builtin->docname : builtin->name);
+ }
+
+ /* Write the structure definition. */
+ if (structfile)
+ {
+ fprintf (structfile, " { \"%s\", ", builtin->name);
+
+ if (builtin->function)
+ fprintf (structfile, "%s, ", builtin->function);
+ else
+ fprintf (structfile, "(Function *)0x0, ");
+
+#define SPECIAL_FLAG_STRING "BUILTIN_ENABLED | STATIC_BUILTIN | SPECIAL_BUILTIN"
+#define NORMAL_FLAG_STRING "BUILTIN_ENABLED | STATIC_BUILTIN"
+
+ fprintf (structfile, "%s, %s_doc,\n",
+ (builtin->flags & BUILTIN_FLAG_SPECIAL) ?
+ SPECIAL_FLAG_STRING :
+ NORMAL_FLAG_STRING,
+ builtin->docname ? builtin->docname : builtin->name);
+
+#undef SPECIAL_FLAG_STRING
+#undef NORMAL_FLAG_STRING
+
+ fprintf
+ (structfile, " \"%s\" },\n",
+ builtin->shortdoc ? builtin->shortdoc : builtin->name);
+
+ /* Save away this builtin for later writing of the
+ long documentation strings. */
+ save_builtin (builtin);
+ }
+
+ /* Write out the matching #endif, if neccessary. */
+ if (builtin->dependencies)
+ {
+ if (externfile)
+ write_endifs (externfile, builtin->dependencies->array);
+
+ if (structfile)
+ write_endifs (structfile, builtin->dependencies->array);
+ }
+ }
+
+ if (documentation_file)
+ {
+ fprintf (documentation_file, "@item %s\n", builtin->name);
+ write_documentation
+ (documentation_file, builtin->longdoc->array, 0, TEXINFO);
+ }
+ }
+ }
+}
+
+/* Write out the long documentation strings in BUILTINS to STREAM. */
+write_longdocs (stream, builtins)
+ FILE *stream;
+ ARRAY *builtins;
+{
+ register int i;
+ register BUILTIN_DESC *builtin;
+
+ for (i = 0; i < builtins->sindex; i++)
+ {
+ builtin = (BUILTIN_DESC *)builtins->array[i];
+
+ if (builtin->dependencies)
+ write_ifdefs (stream, builtin->dependencies->array);
+
+ /* Write the long documentation strings. */
+ fprintf (stream, "char *%s_doc[] =",
+ builtin->docname ? builtin->docname : builtin->name);
+ write_documentation (stream, builtin->longdoc->array, 0, STRING_ARRAY);
+
+ if (builtin->dependencies)
+ write_endifs (stream, builtin->dependencies->array);
+
+ }
+}
+
+/* Write an #ifdef string saying what needs to be defined (or not defined)
+ in order to allow compilation of the code that will follow.
+ STREAM is the stream to write the information to,
+ DEFINES is a null terminated array of define names.
+ If a define is preceded by an `!', then the sense of the test is
+ reversed. */
+write_ifdefs (stream, defines)
+ FILE *stream;
+ char **defines;
+{
+ register int i;
+
+ if (!stream)
+ return;
+
+ fprintf (stream, "#if ");
+
+ for (i = 0; defines[i]; i++)
+ {
+ char *def = defines[i];
+
+ if (*def == '!')
+ fprintf (stream, "!defined (%s)", def + 1);
+ else
+ fprintf (stream, "defined (%s)", def);
+
+ if (defines[i + 1])
+ fprintf (stream, " && ");
+ }
+ fprintf (stream, "\n");
+}
+
+/* Write an #endif string saying what defines controlled the compilation
+ of the immediately preceding code.
+ STREAM is the stream to write the information to.
+ DEFINES is a null terminated array of define names. */
+write_endifs (stream, defines)
+ FILE *stream;
+ char **defines;
+{
+ register int i;
+
+ if (!stream)
+ return;
+
+ fprintf (stream, "#endif /* ");
+
+ for (i = 0; defines[i]; i++)
+ {
+ fprintf (stream, "%s", defines[i]);
+
+ if (defines[i + 1])
+ fprintf (stream, " && ");
+ }
+
+ fprintf (stream, " */\n");
+}
+
+/* Write DOCUMENTAION to STREAM, perhaps surrounding it with double-quotes
+ and quoting special characters in the string. */
+write_documentation (stream, documentation, indentation, flags)
+ FILE *stream;
+ char **documentation;
+ int indentation, flags;
+{
+ register int i, j;
+ register char *line;
+ int string_array = (flags & STRING_ARRAY); /* Mutually exclusive. */
+ int texinfo = (flags & TEXINFO);
+
+ if (!stream)
+ return;
+
+ if (string_array)
+ fprintf (stream, " {\n");
+
+#if !defined (OLDCODE)
+ /* XXX -- clean me up; for experiment only */
+ if (no_long_document)
+ goto end_of_document;
+#endif /* !OLDCODE */
+
+ for (i = 0; line = documentation[i]; i++)
+ {
+ /* Allow #ifdef's to be written out verbatim. */
+ if (*line == '#')
+ {
+ if (string_array)
+ fprintf (stream, "%s\n", line);
+ continue;
+ }
+
+ if (string_array)
+ fprintf (stream, " \"");
+
+ if (indentation)
+ for (j = 0; j < indentation; j++)
+ fprintf (stream, " ");
+
+ if (string_array)
+ {
+ for (j = 0; line[j]; j++)
+ {
+ switch (line[j])
+ {
+ case '\\':
+ case '"':
+ fprintf (stream, "\\%c", line[j]);
+ break;
+
+ default:
+ fprintf (stream, "%c", line[j]);
+ }
+ }
+
+ fprintf (stream, "\",\n");
+ }
+ else if (texinfo)
+ {
+ for (j = 0; line[j]; j++)
+ {
+ switch (line[j])
+ {
+ case '@':
+ case '{':
+ case '}':
+ fprintf (stream, "@%c", line[j]);
+ break;
+
+ default:
+ fprintf (stream, "%c", line[j]);
+ }
+ }
+ fprintf (stream, "\n");
+ }
+ else
+ fprintf (stream, "%s\n", line);
+ }
+
+#if !defined (OLDCODE)
+end_of_document:
+#endif /* !OLDCODE */
+
+ if (string_array)
+ fprintf (stream, " (char *)NULL\n};\n");
+}
+
+static int
+is_special_builtin (name)
+ char *name;
+{
+ register int i;
+
+ for (i = 0; special_builtins[i]; i++)
+ if (strcmp (name, special_builtins[i]) == 0)
+ return 1;
+ return 0;
+}
diff --git a/builtins/psize.c b/builtins/psize.c
new file mode 100644
index 0000000..03a4f6e
--- /dev/null
+++ b/builtins/psize.c
@@ -0,0 +1,63 @@
+/* psize.c - Find pipe size. */
+
+/* Copyright (C) 1987, 1991 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 1, or (at your option)
+ any later version.
+
+ Bash is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
+ License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Bash; see the file COPYING. If not, write to the Free
+ Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Write output in 128-byte chunks until we get a sigpipe or write gets an
+ EPIPE. Then report how many bytes we wrote. We assume that this is the
+ pipe size. */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <signal.h>
+#include <errno.h>
+
+#include "../command.h"
+#include "../general.h"
+extern int errno;
+
+int nw;
+
+sighandler
+sigpipe (sig)
+ int sig;
+{
+ fprintf (stderr, "%d\n", nw);
+ exit (0);
+}
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ char buf[128];
+ register int i;
+
+ for (i = 0; i < 128; i++)
+ buf[i] = ' ';
+
+ signal (SIGPIPE, sigpipe);
+
+ nw = 0;
+ for (;;)
+ {
+ int n;
+ n = write (1, buf, 128);
+ nw += n;
+ }
+}
diff --git a/builtins/psize.sh b/builtins/psize.sh
new file mode 100755
index 0000000..961becd
--- /dev/null
+++ b/builtins/psize.sh
@@ -0,0 +1,24 @@
+#! /bin/sh
+#
+# psize.sh -- determine this system's pipe size, and write a define to
+# pipesize.h so ulimit.c can use it.
+
+echo "/*"
+echo " * pipesize.h"
+echo " *"
+echo " * This file is automatically generated by psize.sh"
+echo " * Do not edit!"
+echo " */"
+echo ""
+
+./psize.aux 2>/tmp/pipesize | sleep 3
+
+if [ -s /tmp/pipesize ]; then
+ echo "#define PIPESIZE `cat /tmp/pipesize`"
+else
+ echo "#define PIPESIZE 512"
+fi
+
+rm -f /tmp/pipesize
+
+exit 0
diff --git a/builtins/read.def b/builtins/read.def
new file mode 100644
index 0000000..7b6dfc9
--- /dev/null
+++ b/builtins/read.def
@@ -0,0 +1,276 @@
+This file is read.def, from which is created read.c.
+It implements the builtin "read" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES read.c
+
+$BUILTIN read
+$FUNCTION read_builtin
+$SHORT_DOC read [-r] [name ...]
+One line is read from the standard input, and the first word is
+assigned to the first NAME, the second word to the second NAME, etc.
+with leftover words assigned to the last NAME. Only the characters
+found in $IFS are recognized as word delimiters. The return code is
+zero, unless end-of-file is encountered. If the -r option is given,
+this signifies `raw' input, and backslash processing is disabled.
+$END
+
+#include <stdio.h>
+#include "../shell.h"
+#include "common.h"
+
+#define issep(c) (strchr (ifs_chars, (c)) != (char *)0)
+
+static int stream_close ();
+
+extern int interrupt_immediately;
+
+/* 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.
+
+ S. R. Bourne's shell complains if you don't name a variable
+ to receive the stuff that is read. GNU's shell doesn't. This
+ allows you to let the user type random things. */
+read_builtin (list)
+ WORD_LIST *list;
+{
+ register char *varname;
+ int size, c, i, fildes, raw_mode, pass_next, saw_escape, retval;
+ char *input_string, *orig_input_string, *ifs_chars, *t;
+ FILE *input_stream;
+ SHELL_VAR *var;
+
+ i = 0; /* Index into the string that we are reading. */
+ raw_mode = 0; /* Not reading raw input be default. */
+
+ while (list)
+ {
+ if (ISOPTION (list->word->word, 'r'))
+ {
+ raw_mode = 1;
+ list = list->next;
+ }
+ else if (ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (*list->word->word == '-')
+ {
+ bad_option (list->word->word);
+ builtin_error ("usage: read [-r] [name ...]");
+ return (EX_USAGE);
+ }
+ else
+ break;
+ }
+
+ /* We need unbuffered input from stdin. So we make a new stream with
+ the same file descriptor as stdin, then unbuffer it. */
+ fildes = dup (fileno (stdin));
+
+ if (fildes == -1)
+ return (EXECUTION_FAILURE);
+
+ input_stream = fdopen (fildes, "r");
+
+ if (!input_stream)
+ {
+ close (fildes);
+ return (EXECUTION_FAILURE);
+ }
+
+ var = find_variable ("IFS");
+ ifs_chars = var ? value_cell (var) : " \t\n";
+
+ input_string = xmalloc (size = 128);
+
+ setbuf (input_stream, (char *)NULL);
+
+ begin_unwind_frame ("read_builtin");
+ add_unwind_protect (xfree, input_string);
+ add_unwind_protect (stream_close, input_stream);
+ interrupt_immediately++;
+
+ pass_next = 0; /* Non-zero signifies last char was backslash. */
+ saw_escape = 0; /* Non-zero signifies that we saw an escape char */
+
+ while ((c = getc (input_stream)) != EOF)
+ {
+ if (i + 2 >= size)
+ input_string = xrealloc (input_string, size += 128);
+
+ /* If the next character is to be accepted verbatim, a backslash
+ newline pair still disappears from the input. */
+ if (pass_next)
+ {
+ if (c == '\n')
+ i--; /* back up over the CTLESC */
+ else
+ input_string[i++] = c;
+ pass_next = 0;
+ continue;
+ }
+
+ if (c == '\\' && !raw_mode)
+ {
+ pass_next++;
+ saw_escape++;
+ input_string[i++] = CTLESC;
+ continue;
+ }
+
+ if (c == '\n')
+ break;
+
+ if (c == CTLESC || c == CTLNUL)
+ {
+ saw_escape++;
+ input_string[i++] = CTLESC;
+ }
+
+ input_string[i++] = c;
+ }
+ input_string[i] = '\0';
+
+ interrupt_immediately--;
+ discard_unwind_frame ("read_builtin");
+
+ fclose (input_stream);
+
+ if (c == EOF)
+ {
+ retval = EXECUTION_FAILURE;
+ /* input_string[0] = '\0'; */
+ }
+ else
+ retval = EXECUTION_SUCCESS;
+
+ if (!list)
+ {
+ if (saw_escape)
+ {
+ t = dequote_string (input_string);
+ var = bind_variable ("REPLY", t);
+ free (t);
+ }
+ else
+ var = bind_variable ("REPLY", input_string);
+ var->attributes &= ~att_invisible;
+ free (input_string);
+ }
+ else
+ {
+ /* This code implements the Posix.2 spec for splitting the words
+ read and assigning them to variables. If $IFS is unset, we
+ use the default value of " \t\n". */
+ 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 && spctabnl (*t) && issep (*t); t++)
+ ;
+ input_string = t;
+
+ for (; list->next; list = list->next)
+ {
+ char *e, *t1;
+
+ varname = list->word->word;
+ if (legal_identifier (varname) == 0)
+ {
+ builtin_error ("%s: not a legal variable name", varname);
+ free (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_variable (varname, t1);
+ free (t1);
+ }
+ else
+ var = bind_variable (varname, t);
+ }
+ else
+ {
+ t = (char *)0;
+ var = bind_variable (varname, "");
+ }
+
+ stupidly_hack_special_variables (varname);
+ var->attributes &= ~att_invisible;
+
+ if (t)
+ free (t);
+ }
+
+ if (legal_identifier (list->word->word) == 0)
+ {
+ builtin_error ("%s: not a legal variable name", list->word->word);
+ free (orig_input_string);
+ return (EXECUTION_FAILURE);
+ }
+
+ /* 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);
+
+ if (saw_escape)
+ {
+ t = dequote_string (input_string);
+ var = bind_variable (list->word->word, t);
+ free (t);
+ }
+ else
+ var = bind_variable (list->word->word, input_string);
+ stupidly_hack_special_variables (list->word->word);
+ var->attributes &= ~att_invisible;
+ free (orig_input_string);
+ }
+
+ return (retval);
+}
+
+/* This way I don't have to know whether fclose () is a
+ function or a macro. */
+static int
+stream_close (file)
+ FILE *file;
+{
+ return (fclose (file));
+}
diff --git a/builtins/reserved.def b/builtins/reserved.def
new file mode 100644
index 0000000..4074ae0
--- /dev/null
+++ b/builtins/reserved.def
@@ -0,0 +1,154 @@
+This file is reserved.def, in which the shell reserved words are defined.
+It has no direct C file production, but defines builtins for the Bash
+builtin help command.
+
+Copyright (C) 1987, 1989, 1991, 1992 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$BUILTIN for
+$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done
+The `for' loop executes a sequence of commands for each member in a
+list of items. If `in WORDS ...;' is not present, then `in "$@"' is
+assumed. For each element in WORDS, NAME is set to that element, and
+the COMMANDS are executed.
+$END
+
+$BUILTIN select
+$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done
+The WORDS are expanded, generating a list of words. The
+set of expanded words is printed on the standard error, each
+preceded by a number. If `in WORDS' is not present, `in "$@"'
+is assumed. The PS3 prompt is then displayed and a line read
+from the standard input. If the line consists of the number
+corresponding to one of the displayed words, then NAME is set
+to that word. If the line is empty, WORDS and the prompt are
+redisplayed. If EOF is read, the command completes. Any other
+value read causes NAME to be set to null. The line read is saved
+in the variable REPLY. COMMANDS are executed after each selection
+until a break or return command is executed.
+$END
+
+$BUILTIN case
+$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
+Selectively execute COMMANDS based upon WORD matching PATTERN. The
+`|' is used to separate multiple patterns.
+$END
+
+$BUILTIN if
+$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
+The if COMMANDS are executed. If the exit status is zero, then the then
+COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed
+in turn, and if the exit status is zero, the corresponding then COMMANDS
+are executed and the if command completes. Otherwise, the else COMMANDS
+are executed, if present. The exit status is the exit status of the last
+command executed, or zero if no condition tested true.
+$END
+
+$BUILTIN while
+$SHORT_DOC while COMMANDS; do COMMANDS; done
+Expand and execute COMMANDS as long as the final command in the
+`while' COMMANDS has an exit status of zero.
+$END
+
+$BUILTIN until
+$SHORT_DOC until COMMANDS; do COMMANDS; done
+Expand and execute COMMANDS as long as the final command in the
+`until' COMMANDS has an exit status which is not zero.
+$END
+
+$BUILTIN function
+$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; }
+Create a simple command invoked by NAME which runs COMMANDS.
+Arguments on the command line along with NAME are passed to the
+function as $0 .. $n.
+$END
+
+$BUILTIN { ... }
+$DOCNAME grouping_braces
+$SHORT_DOC { COMMANDS }
+Run a set of commands in a group. This is one way to redirect an
+entire set of commands.
+$END
+
+$BUILTIN %
+$DOCNAME fg_percent
+$SHORT_DOC %[DIGITS | WORD] [&]
+This is similar to the `fg' command. Resume a stopped or background
+job. If you specifiy DIGITS, then that job is used. If you specify
+WORD, then the job whose name begins with WORD is used. Following the
+job specification with a `&' places the job in the background.
+$END
+
+$BUILTIN variables
+$DOCNAME variable_help
+$SHORT_DOC variables - Some variable names and meanings
+BASH_VERSION The version numbers of this Bash.
+CDPATH A colon separated list of directories to search
+ when the argument to `cd' is not found in the current
+ directory.
+#if defined (HISTORY)
+HISTFILE The name of the file where your command history is stored.
+HISTFILESIZE The maximum number of lines this file can contain.
+HISTSIZE The maximum number of history lines that a running
+ shell can access.
+#endif /* HISTORY */
+HOME The complete pathname to your login directory.
+HOSTTYPE The type of CPU this version of Bash is running under.
+IGNOREEOF Controls the action of the shell on receipt of an EOF
+ character as the sole input. If set, then the value
+ of it is the number of EOF characters that can be seen
+ in a row on an empty line before the shell will exit
+ (default 10). When unset, EOF signifies the end of input.
+MAILCHECK How often, in seconds, Bash checks for new mail.
+MAILPATH A colon-separated list of filenames which Bash checks
+ for new mail.
+PATH A colon-separated list of directories to search when
+ looking for commands.
+PROMPT_COMMAND A command to be executed before the printing of each
+ primary prompt.
+PS1 The primary prompt string.
+PS2 The secondary prompt string.
+TERM The name of the current terminal type.
+auto_resume Non-null means a command word appearing on a line by
+ itself is first looked for in the list of currently
+ stopped jobs. If found there, that job is foregrounded.
+ A value of `exact' means that the command word must
+ exactly match a command in the list of stopped jobs. A
+ value of `substring' means that the command word must
+ match a substring of the job. Any other value means that
+ the command must be a prefix of a stopped job.
+#if defined (HISTORY)
+command_oriented_history
+ Non-null means to save multiple-line commands together on
+ a single history line.
+# if defined (BANG_HISTORY)
+histchars Characters controlling history expansion and quick
+ substitution. The first character is the history
+ substitution character, usually `!'. The second is
+ the `quick substitution' character, usually `^'. The
+ third is the `history comment' character, usually `#'.
+# endif /* BANG_HISTORY */
+HISTCONTROL Set to a value of `ignorespace', it means don't enter
+ lines which begin with a space or tab on the history
+ list. Set to a value of `ignoredups', it means don't
+ enter lines which match the last entered line. Set to
+ `ignoreboth' means to combine the two options. Unset,
+ or set to any other value than those above means to save
+ all lines on the history list.
+#endif /* HISTORY */
+$END
diff --git a/builtins/return.def b/builtins/return.def
new file mode 100644
index 0000000..8340a44
--- /dev/null
+++ b/builtins/return.def
@@ -0,0 +1,57 @@
+This file is return.def, from which is created return.c.
+It implements the builtin "return" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES return.c
+
+$BUILTIN return
+
+$FUNCTION return_builtin
+$SHORT_DOC return [n]
+Causes a function to exit with the return value specified by N. If N
+is omitted, the return status is that of the last command.
+$END
+
+#include "../shell.h"
+
+extern int last_command_exit_value;
+extern int return_catch_flag, return_catch_value;
+extern jmp_buf return_catch;
+
+/* 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;
+{
+ return_catch_value = get_numeric_arg (list);
+
+ if (!list)
+ return_catch_value = last_command_exit_value;
+
+ if (return_catch_flag)
+ longjmp (return_catch, 1);
+ else
+ {
+ builtin_error ("Can only `return' from a function");
+ return (EXECUTION_FAILURE);
+ }
+}
diff --git a/builtins/set.def b/builtins/set.def
new file mode 100644
index 0000000..a97168c
--- /dev/null
+++ b/builtins/set.def
@@ -0,0 +1,528 @@
+This file is set.def, from which is created set.c.
+It implements the "set" and "unset" builtins in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES set.c
+
+#include <stdio.h>
+#include "../shell.h"
+#include "../flags.h"
+
+#include "bashgetopt.h"
+
+extern int interactive;
+extern int noclobber, no_brace_expansion, posixly_correct;
+#if defined (READLINE)
+extern int rl_editing_mode, no_line_editing;
+#endif /* READLINE */
+
+#define USAGE_STRING "set [--abefhknotuvxldHCP] [-o option] [arg ...]"
+
+$BUILTIN set
+$FUNCTION set_builtin
+$SHORT_DOC set [--abefhknotuvxldHCP] [-o option] [arg ...]
+ -a Mark variables which are modified or created for export.
+ -b Notify of job termination immediately.
+ -e Exit immediately if a command exits with a non-zero status.
+ -f Disable file name generation (globbing).
+ -h Locate and remember function commands as functions are
+ defined. Function commands are normally looked up when
+ the function is executed.
+ -i Force the shell to be an "interactive" one. Interactive shells
+ always read `~/.bashrc' on startup.
+ -k All keyword arguments are placed in the environment for a
+ command, not just those that precede the command name.
+ -m Job control is enabled.
+ -n Read commands but do not execute them.
+ -o option-name
+ Set the variable corresponding to option-name:
+ allexport same as -a
+ braceexpand the shell will perform brace expansion
+#if defined (READLINE)
+ emacs use an emacs-style line editing interface
+#endif /* READLINE */
+ errexit same as -e
+#if defined (BANG_HISTORY)
+ histexpand same as -H
+#endif /* BANG_HISTORY */
+ ignoreeof the shell will not exit upon reading EOF
+ interactive-comments
+ allow comments to appear in interactive commands
+ monitor same as -m
+ noclobber disallow redirection to existing files
+ noexec same as -n
+ noglob same as -f
+ nohash same as -d
+ notify save as -b
+ nounset same as -u
+ physical same as -P
+ posix change the behavior of bash where the default
+ operation differs from the 1003.2 standard to
+ match the standard
+ privileged same as -p
+ verbose same as -v
+#if defined (READLINE)
+ vi use a vi-style line editing interface
+#endif /* READLINE */
+ xtrace same as -x
+ -p Turned on whenever the real and effective user ids do not match.
+ Disables processing of the $ENV file and importing of shell
+ functions. Turning this option off causes the effective uid and
+ gid to be set to the real uid and gid.
+ -t Exit after reading and executing one command.
+ -u Treat unset variables as an error when substituting.
+ -v Print shell input lines as they are read.
+ -x Print commands and their arguments as they are executed.
+ -l Save and restore the binding of the NAME in a FOR command.
+ -d Disable the hashing of commands that are looked up for execution.
+ Normally, commands are remembered in a hash table, and once
+ found, do not have to be looked up again.
+#if defined (BANG_HISTORY)
+ -H Enable ! style history substitution. This flag is on
+ by default.
+#endif /* BANG_HISTORY */
+ -C If set, disallow existing regular files to be overwritten
+ by redirection of output.
+ -P If set, do not follow symbolic links when executing commands
+ such as cd which change the current directory.
+
+Using + rather than - causes these flags to be turned off. The
+flags can also be used upon invocation of the shell. The current
+set of flags may be found in $-. The remaining n ARGs are positional
+parameters and are assigned, in order, to $1, $2, .. $n. If no
+ARGs are given, all shell variables are printed.
+$END
+
+/* An a-list used to match long options for set -o to the corresponding
+ option letter. */
+struct {
+ char *name;
+ int letter;
+} o_options[] = {
+ { "allexport", 'a' },
+ { "errexit", 'e' },
+#if defined (BANG_HISTORY)
+ { "histexpand", 'H' },
+#endif /* BANG_HISTORY */
+ { "monitor", 'm' },
+ { "noexec", 'n' },
+ { "noglob", 'f' },
+ { "nohash", 'd' },
+#if defined (JOB_CONTROL)
+ { "notify", 'b' },
+#endif /* JOB_CONTROL */
+ {"nounset", 'u' },
+ {"physical", 'P' },
+ {"privileged", 'p' },
+ {"verbose", 'v' },
+ {"xtrace", 'x' },
+ {(char *)NULL, 0},
+};
+
+#define MINUS_O_FORMAT "%-15s\t%s\n"
+
+void
+list_minus_o_opts ()
+{
+ register int i;
+ char *on = "on", *off = "off";
+
+ printf (MINUS_O_FORMAT, "braceexpand", (no_brace_expansion == 0) ? on : off);
+ printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off);
+
+ if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF"))
+ printf (MINUS_O_FORMAT, "ignoreeof", on);
+ else
+ printf (MINUS_O_FORMAT, "ignoreeof", off);
+
+ printf (MINUS_O_FORMAT, "interactive-comments",
+ interactive_comments ? on : off);
+
+ printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off);
+
+#if defined (READLINE)
+ if (no_line_editing)
+ {
+ printf (MINUS_O_FORMAT, "emacs", off);
+ printf (MINUS_O_FORMAT, "vi", off);
+ }
+ else
+ {
+ /* Magic. This code `knows' how readline handles rl_editing_mode. */
+ printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off);
+ printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off);
+ }
+#endif /* READLINE */
+
+ for (i = 0; o_options[i].name; i++)
+ {
+ int *on_or_off, zero = 0;
+
+ on_or_off = find_flag (o_options[i].letter);
+ if (on_or_off == FLAG_UNKNOWN)
+ on_or_off = &zero;
+ printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off);
+ }
+}
+
+set_minus_o_option (on_or_off, option_name)
+ int on_or_off;
+ char *option_name;
+{
+ int option_char = -1;
+
+ if (STREQ (option_name, "braceexpand"))
+ {
+ if (on_or_off == FLAG_ON)
+ no_brace_expansion = 0;
+ else
+ no_brace_expansion = 1;
+ }
+ else if (STREQ (option_name, "noclobber"))
+ {
+ if (on_or_off == FLAG_ON)
+ bind_variable ("noclobber", "");
+ else
+ unbind_variable ("noclobber");
+ stupidly_hack_special_variables ("noclobber");
+ }
+ else if (STREQ (option_name, "ignoreeof"))
+ {
+ unbind_variable ("ignoreeof");
+ unbind_variable ("IGNOREEOF");
+ if (on_or_off == FLAG_ON)
+ bind_variable ("IGNOREEOF", "10");
+ stupidly_hack_special_variables ("IGNOREEOF");
+ }
+
+#if defined (READLINE)
+ else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi")))
+ {
+ if (on_or_off == FLAG_ON)
+ {
+ rl_variable_bind ("editing-mode", option_name);
+
+ if (interactive)
+ with_input_from_stdin ();
+ no_line_editing = 0;
+ }
+ else
+ {
+ int isemacs = (rl_editing_mode == 1);
+ if ((isemacs && STREQ (option_name, "emacs")) ||
+ (!isemacs && STREQ (option_name, "vi")))
+ {
+ if (interactive)
+ with_input_from_stream (stdin, "stdin");
+ no_line_editing = 1;
+ }
+ else
+ builtin_error ("not in %s editing mode", option_name);
+ }
+ }
+#endif /* READLINE */
+ else if (STREQ (option_name, "interactive-comments"))
+ interactive_comments = (on_or_off == FLAG_ON);
+ else if (STREQ (option_name, "posix"))
+ {
+ posixly_correct = (on_or_off == FLAG_ON);
+ unbind_variable ("POSIXLY_CORRECT");
+ unbind_variable ("POSIX_PEDANTIC");
+ if (on_or_off == FLAG_ON)
+ {
+ bind_variable ("POSIXLY_CORRECT", "");
+ stupidly_hack_special_variables ("POSIXLY_CORRECT");
+ }
+ }
+ else
+ {
+ register int i;
+ for (i = 0; o_options[i].name; i++)
+ {
+ if (STREQ (option_name, o_options[i].name))
+ {
+ option_char = o_options[i].letter;
+ break;
+ }
+ }
+ if (option_char == -1)
+ {
+ builtin_error ("%s: unknown option name", option_name);
+ return (EXECUTION_FAILURE);
+ }
+ if (change_flag (option_char, on_or_off) == FLAG_ERROR)
+ {
+ bad_option (option_name);
+ return (EXECUTION_FAILURE);
+ }
+ }
+ return (EXECUTION_SUCCESS);
+}
+
+/* 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. */
+set_builtin (list)
+ WORD_LIST *list;
+{
+ int on_or_off, flag_name, force_assignment = 0;
+
+ if (!list)
+ {
+ SHELL_VAR **vars;
+
+ vars = all_shell_variables ();
+ if (vars)
+ {
+ print_var_list (vars);
+ free (vars);
+ }
+
+ vars = all_shell_functions ();
+ if (vars)
+ {
+ print_var_list (vars);
+ free (vars);
+ }
+
+ return (EXECUTION_SUCCESS);
+ }
+
+ /* Check validity of flag arguments. */
+ if (*list->word->word == '-' || *list->word->word == '+')
+ {
+ register char *arg;
+ WORD_LIST *save_list = list;
+
+ while (list && (arg = list->word->word))
+ {
+ char c;
+
+ if (arg[0] != '-' && arg[0] != '+')
+ break;
+
+ /* `-' or `--' signifies end of flag arguments. */
+ if (arg[0] == '-' &&
+ (!arg[1] || (arg[1] == '-' && !arg[2])))
+ break;
+
+ while (c = *++arg)
+ {
+ if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
+ {
+ char s[2];
+ s[0] = c; s[1] = '\0';
+ bad_option (s);
+ if (c == '?')
+ printf ("usage: %s\n", USAGE_STRING);
+ return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+ }
+ }
+ list = list->next;
+ }
+ list = save_list;
+ }
+
+ /* Do the set command. While the list consists of words starting with
+ '-' or '+' treat them as flags, otherwise, start assigning them to
+ $1 ... $n. */
+ while (list)
+ {
+ char *string = list->word->word;
+
+ /* If the argument is `--' or `-' then signal the end of the list
+ and remember the remaining arguments. */
+ if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2])))
+ {
+ list = list->next;
+
+ /* `set --' unsets the positional parameters. */
+ if (string[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', '+');
+ }
+
+ break;
+ }
+
+ if ((on_or_off = *string) &&
+ (on_or_off == '-' || on_or_off == '+'))
+ {
+ int i = 1;
+ while (flag_name = string[i++])
+ {
+ if (flag_name == '?')
+ {
+ printf ("usage: %s\n", USAGE_STRING);
+ return (EXECUTION_SUCCESS);
+ }
+ else if (flag_name == 'o') /* -+o option-name */
+ {
+ char *option_name;
+ WORD_LIST *opt;
+
+ opt = list->next;
+
+ if (!opt)
+ {
+ list_minus_o_opts ();
+ continue;
+ }
+
+ option_name = opt->word->word;
+
+ if (!option_name || !*option_name || (*option_name == '-'))
+ {
+ list_minus_o_opts ();
+ continue;
+ }
+ list = list->next; /* Skip over option name. */
+
+ if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
+ return (EXECUTION_FAILURE);
+ }
+ else
+ {
+ if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
+ {
+ char opt[3];
+ opt[0] = on_or_off;
+ opt[1] = flag_name;
+ opt[2] = '\0';
+ bad_option (opt);
+ return (EXECUTION_FAILURE);
+ }
+ }
+ }
+ }
+ else
+ {
+ break;
+ }
+ list = list->next;
+ }
+
+ /* Assigning $1 ... $n */
+ if (list || force_assignment)
+ remember_args (list, 1);
+ return (EXECUTION_SUCCESS);
+}
+
+$BUILTIN unset
+$FUNCTION unset_builtin
+$SHORT_DOC unset [-f] [-v] [name ...]
+For each NAME, remove the corresponding variable or function. Given
+the `-v', unset will only act on variables. Given the `-f' flag,
+unset will only act on functions. With neither flag, unset first
+tries to unset a variable, and if that fails, then tries to unset a
+function. Some variables (such as PATH and IFS) cannot be unset; also
+see readonly.
+$END
+
+unset_builtin (list)
+ WORD_LIST *list;
+{
+ int unset_function = 0, unset_variable = 0, opt;
+ int any_failed = 0;
+ char *name;
+
+ 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:
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ list = loptend;
+
+ if (unset_function && unset_variable)
+ {
+ builtin_error ("cannot simultaneously unset a function and a variable");
+ return (EXECUTION_FAILURE);
+ }
+
+ while (list)
+ {
+ name = list->word->word;
+
+ if (!unset_function &&
+ find_name_in_list (name, non_unsettable_vars) > -1)
+ {
+ builtin_error ("%s: cannot unset", name);
+ any_failed++;
+ }
+ else
+ {
+ SHELL_VAR *var;
+ int tem;
+
+ var = unset_function ? find_function (name) : find_variable (name);
+
+ /* 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");
+ any_failed++;
+ list = list->next;
+ continue;
+ }
+
+ /* Unless the -f option is supplied, the name refers to a
+ variable. */
+ tem = makunbound
+ (name, unset_function ? shell_functions : shell_variables);
+
+ /* 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 = makunbound (name, shell_functions);
+
+ if (tem == -1)
+ any_failed++;
+ else if (!unset_function)
+ stupidly_hack_special_variables (name);
+ }
+ list = list->next;
+ }
+
+ if (any_failed)
+ return (EXECUTION_FAILURE);
+ else
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/setattr.def b/builtins/setattr.def
new file mode 100644
index 0000000..2340e1a
--- /dev/null
+++ b/builtins/setattr.def
@@ -0,0 +1,253 @@
+This file is setattr.def, from which is created setattr.c.
+It implements the builtins "export" and "readonly", in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES setattr.c
+
+#include "../shell.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+extern int array_needs_making;
+extern char *this_command_name;
+
+$BUILTIN export
+$FUNCTION export_builtin
+$SHORT_DOC export [-n] [-f] [name ...] or export -p
+NAMEs are marked for automatic export to the environment of
+subsequently executed commands. If the -f option is given,
+the NAMEs refer to functions. If no NAMEs are given, or if `-p'
+is given, a list of all names that are exported in this shell is
+printed. An argument of `-n' says to remove the export property
+from subsequent NAMEs. An argument of `--' disables further option
+processing.
+$END
+
+/* 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. */
+export_builtin (list)
+ register WORD_LIST *list;
+{
+ return (set_or_show_attributes (list, att_exported));
+}
+
+$BUILTIN readonly
+$FUNCTION readonly_builtin
+$SHORT_DOC readonly [-n] [-f] [name ...] or readonly -p
+The given NAMEs are marked readonly and the values of these NAMEs may
+not be changed by subsequent assignment. If the -f option is given,
+then functions corresponding to the NAMEs are so marked. If no
+arguments are given, or if `-p' is given, a list of all readonly names
+is printed. An argument of `-n' says to remove the readonly property
+from subsequent NAMEs. An argument of `--' disables further option
+processing.
+$END
+
+/* For each variable name in LIST, make that variable readonly. Given an
+ empty LIST, print out all existing readonly variables. */
+readonly_builtin (list)
+ register WORD_LIST *list;
+{
+ return (set_or_show_attributes (list, att_readonly));
+}
+
+/* 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. */
+int
+set_or_show_attributes (list, attribute)
+ register WORD_LIST *list;
+ int attribute;
+{
+ register SHELL_VAR *var;
+ int assign, undo = 0, functions_only = 0, any_failed = 0, opt;
+
+ /* Read arguments from the front of the list. */
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "nfp")) != -1)
+ {
+ switch (opt)
+ {
+ case 'n':
+ undo = 1;
+ break;
+ case 'f':
+ functions_only = 1;
+ break;
+ case 'p':
+ break;
+ default:
+ builtin_error ("usage: %s [-nfp] [varname]", this_command_name);
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list)
+ {
+ if (attribute & att_exported)
+ array_needs_making = 1;
+
+ /* Cannot undo readonly status. */
+ if (undo && (attribute & att_readonly))
+ attribute &= ~att_readonly;
+
+ while (list)
+ {
+ register char *name = list->word->word;
+
+ if (functions_only)
+ {
+ var = find_function (name);
+ if (!var)
+ {
+ builtin_error ("%s: not a function", name);
+ any_failed++;
+ }
+ else
+ {
+ if (undo)
+ var->attributes &= ~attribute;
+ else
+ var->attributes |= attribute;
+ }
+ list = list->next;
+ if (attribute == att_exported)
+ array_needs_making++;
+ continue;
+ }
+
+ assign = assignment (name);
+
+ if (assign)
+ name[assign] = '\0';
+ if (legal_identifier (name) == 0)
+ {
+ builtin_error ("%s: not a legal variable name", name);
+ any_failed++;
+ list = list->next;
+ continue;
+ }
+
+ if (assign)
+ {
+ name[assign] = '=';
+ /* 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. */
+ do_assignment_no_expand (name);
+ name[assign] = '\0';
+ }
+
+ if (undo)
+ {
+ var = find_variable (name);
+ if (var)
+ var->attributes &= ~attribute;
+ }
+ else
+ {
+ SHELL_VAR *find_tempenv_variable (), *tv;
+
+ if (tv = find_tempenv_variable (name))
+ {
+ var = bind_variable (tv->name, tv->value);
+ dispose_variable (tv);
+ }
+ else
+ var = find_variable (name);
+
+ if (!var)
+ {
+ var = bind_variable (name, (char *)NULL);
+ var->attributes |= att_invisible;
+ }
+
+ var->attributes |= attribute;
+ }
+
+ array_needs_making++; /* XXX */
+ 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 (variable_list)
+ {
+ for (i = 0; var = variable_list[i]; i++)
+ {
+ if ((var->attributes & attribute) && !invisible_p (var))
+ {
+ char flags[6];
+
+ flags[0] = '\0';
+
+ if (exported_p (var))
+ strcat (flags, "x");
+
+ if (readonly_p (var))
+ strcat (flags, "r");
+
+ if (function_p (var))
+ strcat (flags, "f");
+
+ if (integer_p (var))
+ strcat (flags, "i");
+
+ if (flags[0])
+ {
+ printf ("declare -%s ", flags);
+
+ if (!function_p (var))
+ {
+ char *x = double_quote (value_cell (var));
+ printf ("%s=%s\n", var->name, x);
+ free (x);
+ }
+ else
+ {
+ char *named_function_string ();
+
+ printf ("%s\n", named_function_string
+ (var->name, function_cell (var), 1));
+ }
+ }
+ }
+ }
+ free (variable_list);
+ }
+ }
+ return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
diff --git a/builtins/shift.def b/builtins/shift.def
new file mode 100644
index 0000000..4d8fed0
--- /dev/null
+++ b/builtins/shift.def
@@ -0,0 +1,95 @@
+This file is shift.def, from which is created shift.c.
+It implements the builtin "shift" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES shift.c
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+
+$BUILTIN shift
+$FUNCTION shift_builtin
+$SHORT_DOC shift [n]
+The positional parameters from $N+1 ... are renamed to $1 ... If N is
+not given, it is assumed to be 1.
+$END
+
+/* 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;
+{
+ int times, number;
+ WORD_LIST *args;
+
+ times = get_numeric_arg (list);
+
+ if (!times)
+ return (EXECUTION_SUCCESS);
+
+ if (times < 0)
+ {
+ builtin_error ("shift count must be >= 0");
+ return (EXECUTION_FAILURE);
+ }
+
+ args = list_rest_of_args ();
+ number = list_length (args);
+ dispose_words (args);
+
+ if (times > number)
+ {
+ builtin_error ("shift count must be <= $#");
+ return (EXECUTION_FAILURE);
+ }
+
+ while (times-- > 0)
+ {
+ register int count;
+
+ 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)
+ {
+ WORD_LIST *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/source.def b/builtins/source.def
new file mode 100644
index 0000000..895e98b
--- /dev/null
+++ b/builtins/source.def
@@ -0,0 +1,186 @@
+This file is source.def, from which is created source.c.
+It implements the builtins "." and "source" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES source.c
+
+$BUILTIN source
+$FUNCTION source_builtin
+$SHORT_DOC source filename
+Read and execute commands from FILENAME and return. The pathnames
+in $PATH are used to find the directory containing FILENAME.
+$END
+$BUILTIN .
+$DOCNAME dot
+$FUNCTION source_builtin
+$SHORT_DOC . filename
+Read and execute commands from FILENAME and return. The pathnames
+in $PATH are used to find the directory containing FILENAME.
+$END
+/* source.c - Implements the `.' and `source' builtins. */
+
+#include <sys/types.h>
+#include <sys/file.h>
+#include <errno.h>
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+#include "../posixstat.h"
+#include "../filecntl.h"
+#include "../execute_cmd.h"
+
+/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* Variables used here but defined in other files. */
+extern int return_catch_flag, return_catch_value;
+extern jmp_buf return_catch;
+extern int posixly_correct;
+extern int interactive, interactive_shell, last_command_exit_value;
+
+/* How many `levels' of sourced files we have. */
+int sourcelevel = 0;
+
+/* 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, we leave
+ the new values alone and free the saved values. */
+static void
+maybe_pop_dollar_vars ()
+{
+ if (dollar_vars_changed ())
+ {
+ dispose_saved_dollar_vars ();
+ set_dollar_vars_unchanged ();
+ }
+ else
+ pop_dollar_vars ();
+}
+
+/* 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. */
+source_builtin (list)
+ WORD_LIST *list;
+{
+ int result, return_val;
+
+ /* Assume the best. */
+ result = EXECUTION_SUCCESS;
+
+ if (list)
+ {
+ char *string, *filename;
+ struct stat finfo;
+ int fd, tt;
+
+ filename = find_path_file (list->word->word);
+ if (!filename)
+ filename = savestring (list->word->word);
+
+ if (((fd = open (filename, O_RDONLY)) < 0) || (fstat (fd, &finfo) < 0))
+ goto file_error_exit;
+
+ string = (char *)xmalloc (1 + (int)finfo.st_size);
+ tt = read (fd, string, finfo.st_size);
+ string[finfo.st_size] = '\0';
+
+ /* Close the open file, preserving the state of errno. */
+ { int temp = errno; close (fd); errno = temp; }
+
+ if (tt != finfo.st_size)
+ {
+ free (string);
+
+ file_error_exit:
+ file_error (filename);
+ free (filename);
+
+ /* POSIX shells exit if non-interactive and file error. */
+ if (posixly_correct && !interactive_shell)
+ {
+ last_command_exit_value = 1;
+ longjmp (top_level, EXITPROG);
+ }
+
+ return (EXECUTION_FAILURE);
+ }
+
+ if (tt > 80)
+ tt = 80;
+
+ if (check_binary_file ((unsigned char *)string, tt))
+ {
+ free (string);
+ builtin_error ("%s: cannot execute binary file", filename);
+ free (filename);
+ return (EX_BINARY_FILE);
+ }
+
+ begin_unwind_frame ("File Sourcing");
+
+ if (list->next)
+ {
+ push_dollar_vars ();
+ add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
+ remember_args (list->next, 1);
+ }
+
+ unwind_protect_int (return_catch_flag);
+ unwind_protect_jmp_buf (return_catch);
+ unwind_protect_int (interactive);
+ unwind_protect_int (sourcelevel);
+ add_unwind_protect ((Function *)xfree, filename);
+ interactive = 0;
+ sourcelevel++;
+
+ set_dollar_vars_unchanged ();
+
+ return_catch_flag++;
+ return_val = setjmp (return_catch);
+
+ if (return_val)
+ parse_and_execute_cleanup ();
+ else
+ result = parse_and_execute (string, filename, -1);
+
+ run_unwind_frame ("File Sourcing");
+
+ /* If RETURN_VAL is non-zero, then we return the value given
+ to return_builtin (), since that is how we got here. */
+ if (return_val)
+ result = return_catch_value;
+ }
+ else
+ {
+ builtin_error ("filename argument required");
+ result = EXECUTION_FAILURE;
+ }
+ return (result);
+}
diff --git a/builtins/suspend.def b/builtins/suspend.def
new file mode 100644
index 0000000..48edc20
--- /dev/null
+++ b/builtins/suspend.def
@@ -0,0 +1,86 @@
+This file is suspend.def, from which is created suspend.c.
+It implements the builtin "suspend" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES suspend.c
+
+$BUILTIN suspend
+$DEPENDS_ON JOB_CONTROL
+$FUNCTION suspend_builtin
+$SHORT_DOC suspend [-f]
+Suspend the execution of this shell until it receives a SIGCONT
+signal. The `-f' if specified says not to complain about this
+being a login shell if it is; just suspend anyway.
+$END
+
+#include <sys/types.h>
+#include <signal.h>
+#include "../shell.h"
+#include "../jobs.h"
+
+#if defined (JOB_CONTROL)
+extern int job_control;
+
+static SigHandler *old_cont, *old_tstp;
+
+/* Continue handler. */
+sighandler
+suspend_continue (sig)
+ int sig;
+{
+ set_signal_handler (SIGCONT, old_cont);
+ set_signal_handler (SIGTSTP, old_tstp);
+#if !defined (VOID_SIGHANDLER)
+ return (0);
+#endif /* !VOID_SIGHANDLER */
+}
+
+/* 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;
+{
+ if (!job_control)
+ {
+ builtin_error ("Cannot suspend a shell without job control");
+ return (EXECUTION_FAILURE);
+ }
+
+ if (list)
+ if (strcmp (list->word->word, "-f") == 0)
+ goto do_suspend;
+
+ no_args (list);
+
+ if (login_shell)
+ {
+ builtin_error ("Can't suspend a login shell");
+ return (EXECUTION_FAILURE);
+ }
+
+do_suspend:
+ old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
+ old_tstp = (SigHandler *)set_signal_handler (SIGTSTP, SIG_DFL);
+ killpg (shell_pgrp, SIGTSTP);
+ return (EXECUTION_SUCCESS);
+}
+
+#endif /* JOB_CONTROL */
diff --git a/builtins/test.def b/builtins/test.def
new file mode 100644
index 0000000..2b1457b
--- /dev/null
+++ b/builtins/test.def
@@ -0,0 +1,144 @@
+This file is test.def, from which is created test.c.
+It implements the builtin "test" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES test.c
+
+$BUILTIN test
+$FUNCTION test_builtin
+$SHORT_DOC test [expr]
+Exits with a status of 0 (trueness) or 1 (falseness) depending on
+the evaluation of EXPR. Expressions may be unary or binary. Unary
+expressions are often used to examine the status of a file. There
+are string operators as well, and numeric comparison operators.
+
+File operators:
+
+ -b FILE True if file is block special.
+ -c FILE True if file is character special.
+ -d FILE True if file is a directory.
+ -e FILE True if file exists.
+ -f FILE True if file exists and is a regular file.
+ -g FILE True if file is set-group-id.
+ -h FILE True if file is a symbolic link. Use "-L".
+ -L FILE True if file is a symbolic link.
+ -k FILE True if file has its "sticky" bit set.
+ -p FILE True if file is a named pipe.
+ -r FILE True if file is readable by you.
+ -s FILE True if file is not empty.
+ -S FILE True if file is a socket.
+ -t FD True if FD is opened on a terminal.
+ -u FILE True if the file is set-user-id.
+ -w FILE True if the file is writable by you.
+ -x FILE True if the file is executable by you.
+ -O FILE True if the file is effectively owned by you.
+ -G FILE True if the file is effectively owned by your group.
+
+ FILE1 -nt FILE2 True if file1 is newer than (according to
+ modification date) file2.
+
+ FILE1 -ot FILE2 True if file1 is older than file2.
+
+ FILE1 -ef FILE2 True if file1 is a hard link to file2.
+
+String operators:
+
+ -z STRING True if string is empty.
+
+ -n STRING
+ or STRING True if string is not empty.
+
+ STRING1 = STRING2
+ True if the strings are equal.
+ STRING1 != STRING2
+ True if the strings are not equal.
+
+Other operators:
+
+ ! EXPR True if expr is false.
+ EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
+ EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.
+
+ arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
+ -lt, -le, -gt, or -ge.
+
+Arithmetic binary operators return true if ARG1 is equal, not-equal,
+less-than, less-than-or-equal, greater-than, or greater-than-or-equal
+than ARG2.
+$END
+
+$BUILTIN [
+$DOCNAME test_bracket
+$FUNCTION test_builtin
+$SHORT_DOC [ arg... ]
+This is a synonym for the "test" shell builtin, excepting that the
+last argument must be literally `]', to match the `[' which invoked
+the test.
+$END
+
+#if defined (HAVE_STRING_H)
+# include <string.h>
+#else /* !HAVE_STRING_H */
+# include <strings.h>
+#endif /* !HAVE_STRING_H */
+
+#include "../shell.h"
+extern char *this_command_name;
+
+/* TEST/[ builtin. */
+int
+test_builtin (list)
+ WORD_LIST *list;
+{
+ char **argv;
+ int argc, result;
+ WORD_LIST *t = list;
+
+ /* 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 his code wants. */
+ if (!list)
+ {
+ if (this_command_name[0] == '[' && !this_command_name[1])
+ builtin_error ("missing `]'");
+
+ return (EXECUTION_FAILURE);
+ }
+
+ /* Get the length of the argument list. */
+ for (argc = 0; t; t = t->next, argc++);
+
+ /* Account for argv[0] being a command name. This makes our life easier. */
+ argc++;
+ argv = (char **)xmalloc ((1 + argc) * sizeof (char *));
+ argv[argc] = (char *)NULL;
+
+ /* this_command_name is the name of the command that invoked this
+ function. So you can't call test_builtin () directly from
+ within this code, there are too many things to worry about. */
+ argv[0] = savestring (this_command_name);
+
+ for (t = list, argc = 1; t; t = t->next, argc++)
+ argv[argc] = savestring (t->word->word);
+
+ result = test_command (argc, argv);
+ free_array (argv);
+ return (result);
+}
diff --git a/builtins/times.def b/builtins/times.def
new file mode 100644
index 0000000..9c42768
--- /dev/null
+++ b/builtins/times.def
@@ -0,0 +1,89 @@
+This file is times.def, from which is created times.c.
+It implements the builtin "times" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES times.c
+
+$BUILTIN times
+$FUNCTION times_builtin
+$SHORT_DOC times
+Print the accumulated user and system times for processes run from
+the shell.
+$END
+
+#include "../shell.h"
+#include <sys/types.h>
+
+#if defined (hpux) || defined (USGr4) || defined (XD88) || defined (USGr3)
+# undef HAVE_RESOURCE
+#endif /* hpux || USGr4 || XD88 || USGr3 */
+
+#if defined (_POSIX_VERSION) || !defined (HAVE_RESOURCE)
+# include <sys/times.h>
+#else /* !_POSIX_VERSION && HAVE_RESOURCE */
+# include <sys/time.h>
+# include <sys/resource.h>
+#endif /* !_POSIX_VERSION && HAVE_RESOURCE */
+
+/* Print the totals for system and user time used. The
+ information comes from variables in jobs.c used to keep
+ track of this stuff. */
+times_builtin (list)
+ WORD_LIST *list;
+{
+#if !defined (_POSIX_VERSION) && defined (HAVE_RESOURCE) && defined (RUSAGE_SELF)
+ struct rusage self, kids;
+
+ getrusage (RUSAGE_SELF, &self);
+ getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */
+
+ print_timeval (&self.ru_utime);
+ putchar (' ');
+ print_timeval (&self.ru_stime);
+ putchar ('\n');
+ print_timeval (&kids.ru_utime);
+ putchar (' ');
+ print_timeval (&kids.ru_stime);
+ putchar ('\n');
+
+#else /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */
+# if !defined (BrainDeath)
+ struct tms t;
+
+ times (&t);
+
+ /* As of System V.3, HP-UX 6.5, and other ATT-like systems, this stuff is
+ returned in terms of clock ticks (HZ from sys/param.h). C'mon, guys.
+ This kind of stupid clock-dependent stuff is exactly the reason 4.2BSD
+ introduced the `timeval' struct. */
+
+ print_time_in_hz (t.tms_utime);
+ putchar (' ');
+ print_time_in_hz (t.tms_stime);
+ putchar ('\n');
+ print_time_in_hz (t.tms_cutime);
+ putchar (' ');
+ print_time_in_hz (t.tms_cstime);
+ putchar ('\n');
+# endif /* BrainDeath */
+#endif /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */
+
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/trap.def b/builtins/trap.def
new file mode 100644
index 0000000..b81651d
--- /dev/null
+++ b/builtins/trap.def
@@ -0,0 +1,204 @@
+This file is trap.def, from which is created trap.c.
+It implements the builtin "trap" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES trap.c
+
+$BUILTIN trap
+$FUNCTION trap_builtin
+$SHORT_DOC trap [arg] [signal_spec]
+The command ARG is to be read and executed when the shell receives
+signal(s) SIGNAL_SPEC. If ARG is absent all specified signals are
+reset to their original values. If ARG is the null string this
+signal is ignored by the shell and by the commands it invokes. If
+SIGNAL_SPEC is EXIT (0) the command ARG is executed on exit from
+the shell. The trap command with no arguments prints the list of
+commands associated with each signal number. SIGNAL_SPEC is either
+a signal name in <signal.h>, or a signal number. The syntax `trap -l'
+prints a list of signal names and their corresponding numbers.
+Note that a signal can be sent to the shell with "kill -signal $$".
+$END
+
+#include <sys/types.h>
+#include <signal.h>
+#include "../shell.h"
+#include "../trap.h"
+#include "common.h"
+
+/* The trap command:
+
+ trap <arg> <signal ...>
+ trap <signal ...>
+ trap -l
+ 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 interactive;
+
+trap_builtin (list)
+ WORD_LIST *list;
+{
+ register int i;
+ int list_signal_names = 0;
+
+ while (list)
+ {
+ if (ISOPTION (list->word->word, 'l'))
+ {
+ list_signal_names++;
+ list = list->next;
+ }
+ else if (ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if ((*list->word->word == '-') && list->word->word[1])
+ {
+ bad_option (list->word->word);
+ builtin_error ("usage: trap [-l] [arg] [sigspec]");
+ return (EX_USAGE);
+ }
+ else
+ break;
+ }
+
+ if (list_signal_names)
+ {
+ int column = 0;
+
+ for (i = 0; i < NSIG; i++)
+ {
+ printf ("%2d) %s", i, signal_name (i));
+ if (++column < 4)
+ printf ("\t");
+ else
+ {
+ printf ("\n");
+ column = 0;
+ }
+ }
+ if (column != 0)
+ printf ("\n");
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (list)
+ {
+ char *first_arg = list->word->word;
+ int operation = SET, any_failed = 0;
+
+ if (signal_object_p (first_arg))
+ operation = REVERT;
+ else
+ {
+ list = list->next;
+ if (*first_arg == '\0')
+ operation = IGNORE;
+ else if (first_arg[0] == '-' && !first_arg[1])
+ operation = REVERT;
+ }
+
+ while (list)
+ {
+ int sig;
+
+ sig = decode_signal (list->word->word);
+
+ if (sig == NO_SIG)
+ {
+ builtin_error ("%s: not a signal specification",
+ list->word->word);
+ any_failed++;
+ }
+ 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, termination_unwind_protect);
+ 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 ((!any_failed) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+ }
+
+ for (i = 0; i < NSIG; i++)
+ {
+ char *t, *p;
+
+ p = trap_list[i];
+
+ if (p == (char *)DEFAULT_SIG)
+ continue;
+
+ t = (p == (char *)IGNORE_SIG) ? (char *)NULL : single_quote (p);
+ printf ("trap -- %s %s\n", t ? t : "''", signal_name (i));
+ if (t)
+ free (t);
+ }
+ return (EXECUTION_SUCCESS);
+}
diff --git a/builtins/type.def b/builtins/type.def
new file mode 100644
index 0000000..aecc303
--- /dev/null
+++ b/builtins/type.def
@@ -0,0 +1,325 @@
+This file is type.def, from which is created type.c.
+It implements the builtin "type" in Bash.
+
+Copyright (C) 1987, 1989, 1991, 1992 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES type.c
+
+$BUILTIN type
+$FUNCTION type_builtin
+$SHORT_DOC type [-all] [-type | -path] [name ...]
+For each NAME, indicate how it would be interpreted if used as a
+command name.
+
+If the -type flag is used, returns a single word which is one of
+`alias', `keyword', `function', `builtin', `file' or `', if NAME is an
+alias, shell reserved word, shell function, shell builtin, disk file,
+or unfound, respectively.
+
+If the -path flag is used, either returns the name of the disk file
+that would be exec'ed, or nothing if -type wouldn't return `file'.
+
+If the -all flag is used, displays all of the places that contain an
+executable named `file'. This includes aliases and functions, if and
+only if the -path flag is not also used.
+$END
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "../posixstat.h"
+#include "../shell.h"
+#include "../execute_cmd.h"
+
+#if defined (ALIAS)
+#include "../alias.h"
+#endif /* ALIAS */
+
+#include "common.h"
+
+extern STRING_INT_ALIST word_token_alist[];
+
+/* 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:
+ -type Returns the "type" of the object, one of
+ `alias', `keyword', `function', `builtin',
+ or `file'.
+
+ -path Returns the pathname of the file if -type is
+ a file.
+
+ -all Returns all occurrences of words, whether they
+ be a filename in the path, alias, function,
+ or builtin.
+ Order of evaluation:
+ alias
+ keyword
+ function
+ builtin
+ file
+ */
+type_builtin (list)
+ WORD_LIST *list;
+{
+ int path_only, type_only, all, verbose;
+ int successful_finds;
+
+ path_only = type_only = all = 0;
+ successful_finds = 0;
+
+ if (!list)
+ return (EXECUTION_SUCCESS);
+
+ while (list && *(list->word->word) == '-')
+ {
+ char *flag = &(list->word->word[1]);
+
+ if (flag[0] == 't' && (!flag[1] || strcmp (flag + 1, "ype") == 0))
+ {
+ type_only = 1;
+ path_only = 0;
+ }
+ else if (flag[0] == 'p' && (!flag[1] || strcmp (flag + 1, "ath") == 0))
+ {
+ path_only = 1;
+ type_only = 0;
+ }
+ else if (flag[0] == 'a' && (!flag[1] || strcmp (flag + 1, "ll") == 0))
+ {
+ all = 1;
+ }
+ else
+ {
+ bad_option (flag);
+ builtin_error ("usage: type [-all | -path | -type ] name [name ...]");
+ return (EX_USAGE);
+ }
+ list = list->next;
+ }
+
+ if (type_only)
+ verbose = 1;
+ else if (!path_only)
+ verbose = 2;
+ else if (path_only)
+ verbose = 3;
+ else
+ verbose = 0;
+
+ while (list)
+ {
+ int found;
+
+ found = describe_command (list->word->word, verbose, all);
+
+ if (!found && !path_only && !type_only)
+ builtin_error ("%s: not found", list->word->word);
+
+ successful_finds += found;
+ list = list->next;
+ }
+
+ fflush (stdout);
+
+ if (successful_finds != 0)
+ return (EXECUTION_SUCCESS);
+ else
+ return (EXECUTION_FAILURE);
+}
+
+/*
+ * Describe COMMAND as required by the type builtin.
+ *
+ * If VERBOSE == 0, don't print anything
+ * If VERBOSE == 1, print short description as for `type -t'
+ * If VERBOSE == 2, print long description as for `type' and `command -V'
+ * If VERBOSE == 3, print path name only for disk files
+ * If VERBOSE == 4, print string used to invoke COMMAND, for `command -v'
+ *
+ * ALL says whether or not to look for all occurrences of COMMAND, or
+ * return after finding it once.
+ */
+describe_command (command, verbose, all)
+ char *command;
+ int verbose, all;
+{
+ int found = 0, i, found_file = 0;
+ char *full_path = (char *)NULL;
+ SHELL_VAR *func;
+
+#if defined (ALIAS)
+ /* Command is an alias? */
+ ASSOC *alias = find_alias (command);
+
+ if (alias)
+ {
+ if (verbose == 1)
+ printf ("alias\n");
+ else if (verbose == 2)
+ printf ("%s is aliased to `%s'\n", command, alias->value);
+ else if (verbose == 4)
+ {
+ char *x = single_quote (alias->value);
+ printf ("alias %s=%s\n", command, x);
+ free (x);
+ }
+
+ found = 1;
+
+ if (!all)
+ return (1);
+ }
+#endif /* ALIAS */
+
+ /* Command is a shell reserved word? */
+ i = find_reserved_word (command);
+ if (i >= 0)
+ {
+ if (verbose == 1)
+ printf ("keyword\n");
+ else if (verbose == 2)
+ printf ("%s is a shell keyword\n", command);
+ else if (verbose == 4)
+ printf ("%s\n", command);
+
+ found = 1;
+
+ if (!all)
+ return (1);
+ }
+
+ /* Command is a function? */
+ func = find_function (command);
+
+ if (func)
+ {
+ if (verbose == 1)
+ printf ("function\n");
+ else if (verbose == 2)
+ {
+#define PRETTY_PRINT_FUNC 1
+ char *result;
+
+ printf ("%s is a function\n", command);
+
+ /* We're blowing away THE_PRINTED_COMMAND here... */
+
+ result = named_function_string (command,
+ (COMMAND *) function_cell (func),
+ PRETTY_PRINT_FUNC);
+ printf ("%s\n", result);
+#undef PRETTY_PRINT_FUNC
+ }
+ else if (verbose == 4)
+ printf ("%s\n", command);
+
+ found = 1;
+
+ if (!all)
+ return (1);
+ }
+
+ /* Command is a builtin? */
+ if (find_shell_builtin (command))
+ {
+ if (verbose == 1)
+ printf ("builtin\n");
+ else if (verbose == 2)
+ printf ("%s is a shell builtin\n", command);
+ else if (verbose == 4)
+ printf ("%s\n", command);
+
+ found = 1;
+
+ if (!all)
+ 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))
+ {
+ int f = file_status (command);
+ if (f & FS_EXECABLE)
+ {
+ if (verbose == 1)
+ printf ("file\n");
+ else if (verbose == 2)
+ printf ("%s is %s\n", command, command);
+ else if (verbose == 3 || verbose == 4)
+ 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 "-all", then we might care about
+ whether the file is present in our hash table. */
+ if (!all)
+ {
+ if ((full_path = find_hashed_filename (command)) != (char *)NULL)
+ {
+ if (verbose == 1)
+ printf ("file\n");
+ else if (verbose == 2)
+ printf ("%s is hashed (%s)\n", command, full_path);
+ else if (verbose == 3 || verbose == 4)
+ printf ("%s\n", full_path);
+
+ return (1);
+ }
+ }
+
+ /* Now search through $PATH. */
+ while (1)
+ {
+ if (!all)
+ 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;
+
+ found_file++;
+ found = 1;
+
+ if (verbose == 1)
+ printf ("file\n");
+ else if (verbose == 2)
+ printf ("%s is %s\n", command, full_path);
+ else if (verbose == 3 || verbose == 4)
+ printf ("%s\n", full_path);
+
+ free (full_path);
+ full_path = (char *)NULL;
+
+ if (!all)
+ break;
+ }
+
+ return (found);
+}
diff --git a/builtins/ulimit.def b/builtins/ulimit.def
new file mode 100644
index 0000000..1947c36
--- /dev/null
+++ b/builtins/ulimit.def
@@ -0,0 +1,731 @@
+This file is ulimit.def, from which is created ulimit.c.
+It implements the builtin "ulimit" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES ulimit.c
+
+$BUILTIN ulimit
+$FUNCTION ulimit_builtin
+$DEPENDS_ON !MINIX
+$SHORT_DOC ulimit [-SHacdfmstpnuv [limit]]
+Ulimit provides control over the resources available to processes
+started by the shell, on systems that allow such control. If an
+option is given, it is interpreted as follows:
+
+ -S use the `soft' resource limit
+ -H use the `hard' resource limit
+ -a all current limits are reported
+ -c the maximum size of core files created
+ -d the maximum size of a process's data segment
+ -m the maximum resident set size
+ -s the maximum stack size
+ -t the maximum amount of cpu time in seconds
+ -f the maximum size of files created by the shell
+ -p the pipe buffer size
+ -n the maximum number of open file descriptors
+ -u the maximum number of user processes
+ -v the size of virtual memory
+
+If LIMIT is given, it is the new value of the specified resource.
+Otherwise, the current value of the specified resource is printed.
+If no option is given, then -f is assumed. Values are in 1k
+increments, except for -t, which is in seconds, -p, which is in
+increments of 512 bytes, and -u, which is an unscaled number of
+processes.
+$END
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <errno.h>
+#include "../shell.h"
+#include "pipesize.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#if defined (HAVE_RESOURCE)
+# include <sys/time.h>
+# include <sys/resource.h>
+#else
+# include <sys/times.h>
+#endif
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.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 (GETRLIMIT_MISSING)
+# undef HAVE_RESOURCE
+#endif
+
+#if !defined (RLIMTYPE)
+# define RLIMTYPE long
+# define string_to_rlimtype string_to_long
+# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
+#endif
+
+static void print_long ();
+
+/* **************************************************************** */
+/* */
+/* Ulimit builtin and Hacks. */
+/* */
+/* **************************************************************** */
+
+/* Block size for ulimit operations. */
+#define ULIMIT_BLOCK_SIZE ((long)1024)
+
+#define u_FILE_SIZE 0x001
+#define u_MAX_BREAK_VAL 0x002
+#define u_PIPE_SIZE 0x004
+#define u_CORE_FILE_SIZE 0x008
+#define u_DATA_SEG_SIZE 0x010
+#define u_PHYS_MEM_SIZE 0x020
+#define u_CPU_TIME_LIMIT 0x040
+#define u_STACK_SIZE 0x080
+#define u_NUM_OPEN_FILES 0x100
+#define u_MAX_VIRTUAL_MEM 0x200
+#define u_MAX_USER_PROCS 0x400
+
+#define u_ALL_LIMITS 0x7ff
+
+#if !defined (RLIM_INFINITY)
+# define RLIM_INFINITY 0x7fffffff
+#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 */
+
+#define LIMIT_HARD 0x01
+#define LIMIT_SOFT 0x02
+
+static RLIMTYPE shell_ulimit ();
+static RLIMTYPE pipesize ();
+static RLIMTYPE open_files ();
+
+#if defined (HAVE_RESOURCE)
+static RLIMTYPE getmaxvm ();
+#endif /* HAVE_RESOURCE */
+
+static void print_specific_limits ();
+static void print_all_limits ();
+
+static char t[2];
+
+/* Return 1 if the limit associated with CMD can be raised from CURRENT
+ to NEW. This is for USG systems without HAVE_RESOURCE, most of which
+ do not allow any user other than root to raise limits. There are,
+ however, exceptions. */
+#if !defined (HAVE_RESOURCE)
+static int
+canraise (cmd, current, new)
+ int cmd;
+ RLIMTYPE current, new;
+{
+# if defined (HAVE_SETDTABLESIZE)
+ if (cmd == u_NUM_OPEN_FILES)
+ return (1);
+# endif /* HAVE_SETDTABLSIZE */
+
+ return ((current > new) || (current_user.uid == 0));
+}
+#endif /* !HAVE_RESOURCE */
+
+/* Report or set limits associated with certain per-process resources.
+ See the help documentation in builtins.c for a full description.
+
+ Rewritten by Chet Ramey 6/30/91. */
+int
+ulimit_builtin (list)
+ register WORD_LIST *list;
+{
+ register char *s;
+ int c, setting, cmd, mode, verbose_print, opt_eof;
+ int all_limits, specific_limits;
+ long block_factor;
+ RLIMTYPE current_limit, real_limit, limit;
+
+ c = mode = verbose_print = opt_eof = 0;
+ limit = (RLIMTYPE)-1;
+
+ do
+ {
+ cmd = setting = all_limits = specific_limits = 0;
+ block_factor = ULIMIT_BLOCK_SIZE;
+
+ /* read_options: */
+ if (list && !opt_eof && *list->word->word == '-')
+ {
+ s = &(list->word->word[1]);
+ list = list->next;
+
+ while (*s && (c = *s++))
+ {
+ switch (c)
+ {
+#define ADD_CMD(x) { if (cmd) specific_limits++; cmd |= (x); }
+
+ case '-': /* ulimit -- */
+ opt_eof++;
+ break;
+
+ case 'a':
+ all_limits++;
+ break;
+
+ case 'f':
+ ADD_CMD (u_FILE_SIZE);
+ break;
+
+#if defined (HAVE_RESOURCE)
+ /* -S and -H are modifiers, not real options. */
+ case 'S':
+ mode |= LIMIT_SOFT;
+ break;
+
+ case 'H':
+ mode |= LIMIT_HARD;
+ break;
+
+ case 'c':
+ ADD_CMD (u_CORE_FILE_SIZE);
+ break;
+
+ case 'd':
+ ADD_CMD (u_DATA_SEG_SIZE);
+ break;
+
+#if !defined (USGr4)
+ case 'm':
+ ADD_CMD (u_PHYS_MEM_SIZE);
+ break;
+#endif /* USGr4 */
+
+ case 't':
+ ADD_CMD (u_CPU_TIME_LIMIT);
+ block_factor = 1; /* seconds */
+ break;
+
+ case 's':
+ ADD_CMD (u_STACK_SIZE);
+ break;
+
+ case 'v':
+ ADD_CMD (u_MAX_VIRTUAL_MEM);
+ block_factor = 1;
+ break;
+
+ case 'u':
+ ADD_CMD (u_MAX_USER_PROCS);
+ block_factor = 1;
+ break;
+
+#endif /* HAVE_RESOURCE */
+
+ case 'p':
+ ADD_CMD (u_PIPE_SIZE);
+ block_factor = 512;
+ break;
+
+ case 'n':
+ ADD_CMD (u_NUM_OPEN_FILES);
+ block_factor = 1;
+ break;
+
+ default: /* error_case: */
+ t[0] = c;
+ t[1] = '\0';
+ bad_option (t);
+#if !defined (HAVE_RESOURCE)
+ builtin_error("usage: ulimit [-afnp] [new limit]");
+#else
+ builtin_error("usage: ulimit [-SHacmdstfnpuv] [new limit]");
+#endif
+ return (EX_USAGE);
+ }
+ }
+ }
+
+ if (all_limits)
+ {
+ print_all_limits (mode);
+ return (EXECUTION_SUCCESS);
+ }
+
+ if (specific_limits)
+ {
+ print_specific_limits (cmd, mode);
+ if (list)
+ verbose_print++;
+ continue;
+ }
+
+ if (cmd == 0)
+ cmd = u_FILE_SIZE;
+
+ /* If an argument was supplied for the command, then we want to
+ set the limit. Note that `ulimit something' means a command
+ of -f with argument `something'. */
+ if (list)
+ {
+ if (opt_eof || (*list->word->word != '-'))
+ {
+ s = list->word->word;
+ list = list->next;
+
+ if (STREQ (s, "unlimited"))
+ limit = RLIM_INFINITY;
+ else if (all_digits (s))
+ limit = string_to_rlimtype (s);
+ else
+ {
+ builtin_error ("bad non-numeric arg `%s'", s);
+ return (EXECUTION_FAILURE);
+ }
+ setting++;
+ }
+ else if (!opt_eof)
+ verbose_print++;
+ }
+
+ if (limit == RLIM_INFINITY)
+ block_factor = 1;
+
+ real_limit = limit * block_factor;
+
+ /* If more than one option is given, list each in a verbose format,
+ the same that is used for -a. */
+ if (!setting && verbose_print)
+ {
+ print_specific_limits (cmd, mode);
+ continue;
+ }
+
+ current_limit = shell_ulimit (cmd, real_limit, 0, mode);
+
+ if (setting)
+ {
+#if !defined (HAVE_RESOURCE)
+ /* Most USG systems do not most allow limits to be raised by any
+ user other than root. There are, however, exceptions. */
+ if (canraise (cmd, current_limit, real_limit) == 0)
+ {
+ builtin_error ("cannot raise limit: %s", strerror (EPERM));
+ return (EXECUTION_FAILURE);
+ }
+#endif /* !HAVE_RESOURCE */
+
+ if (shell_ulimit (cmd, real_limit, 1, mode) == (RLIMTYPE)-1)
+ {
+ builtin_error ("cannot raise limit: %s", strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+
+ continue;
+ }
+ else
+ {
+ if (current_limit < 0)
+ builtin_error ("cannot get limit: %s", strerror (errno));
+ else if (current_limit != RLIM_INFINITY)
+ print_rlimtype ((current_limit / block_factor), 1);
+ else
+ printf ("unlimited\n");
+ }
+ }
+ while (list);
+
+ return (EXECUTION_SUCCESS);
+}
+
+/* The ulimit that we call from within Bash.
+
+ WHICH says which limit to twiddle; SETTING is non-zero if NEWLIM
+ contains the desired new limit. Otherwise, the existing limit is
+ returned. If mode & LIMIT_HARD, the hard limit is used; if
+ mode & LIMIT_SOFT, the soft limit. Both may be set by specifying
+ -H and -S; if both are specified, or if neither is specified, the
+ soft limit will be returned.
+
+ Systems without BSD resource limits can specify only u_FILE_SIZE.
+ This includes most USG systems.
+
+ Chet Ramey supplied the BSD resource limit code. */
+static RLIMTYPE
+shell_ulimit (which, newlim, setting, mode)
+ int which, setting, mode;
+ RLIMTYPE newlim;
+{
+#if defined (HAVE_RESOURCE)
+ struct rlimit limit;
+ int cmd;
+
+ if (mode == 0)
+ mode |= LIMIT_SOFT;
+#endif
+
+ switch (which)
+ {
+#if !defined (HAVE_RESOURCE)
+
+ case u_FILE_SIZE:
+ if (!setting)
+ {
+ /* ulimit () returns a number that is in 512 byte blocks, thus we
+ must multiply it by 512 to get back to bytes. This is false
+ only under HP/UX 6.x. */
+ RLIMTYPE result;
+
+ result = ulimit (1, 0L);
+
+# if defined (hpux) && !defined (_POSIX_VERSION)
+ return (result);
+# else
+ return (result * 512);
+# endif /* hpux 6.x */
+ }
+ else
+ return (ulimit (2, newlim / 512L));
+
+ break;
+
+#else /* defined (HAVE_RESOURCE) */
+
+ case u_FILE_SIZE:
+ cmd = RLIMIT_FSIZE;
+ goto do_ulimit;
+
+ case u_CORE_FILE_SIZE:
+ cmd = RLIMIT_CORE;
+ goto do_ulimit;
+
+ case u_DATA_SEG_SIZE:
+ cmd = RLIMIT_DATA;
+ goto do_ulimit;
+
+#if !defined (USGr4)
+ case u_PHYS_MEM_SIZE:
+# if defined (RLIMIT_RSS)
+ cmd = RLIMIT_RSS;
+# else /* !RLIMIT_RSS */
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+# endif /* !RLIMIT_RSS */
+
+ goto do_ulimit;
+#endif /* USGr4 */
+
+ case u_CPU_TIME_LIMIT:
+#if defined (RLIMIT_CPU)
+ cmd = RLIMIT_CPU;
+ goto do_ulimit;
+#else
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+# endif /* !RLIMIT_CPU */
+
+
+ case u_STACK_SIZE:
+ cmd = RLIMIT_STACK;
+
+ do_ulimit:
+
+ if (getrlimit (cmd, &limit) != 0)
+ return ((RLIMTYPE)-1);
+
+ if (!setting)
+ {
+ if (mode & LIMIT_SOFT)
+ return (limit.rlim_cur);
+ else
+ return (limit.rlim_max);
+ }
+ else
+ {
+ if (mode & LIMIT_SOFT)
+ {
+ /* Non-root users are only allowed to raise a limit up to the
+ hard limit, not to infinity. */
+ if (current_user.euid != 0 && newlim == RLIM_INFINITY)
+ limit.rlim_cur = limit.rlim_max;
+ else
+ limit.rlim_cur = newlim;
+ }
+ if (mode & LIMIT_HARD)
+ limit.rlim_max = newlim;
+
+ return (setrlimit (cmd, &limit));
+ }
+
+ break;
+
+#endif /* HAVE_RESOURCE */
+
+ /* You can't get or set the pipe size with getrlimit, so we have to
+ cheat. */
+ case u_PIPE_SIZE:
+ if (setting)
+ {
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+ }
+ return (pipesize ());
+
+ case u_NUM_OPEN_FILES:
+ if (setting)
+ {
+#if defined (HAVE_RESOURCE) && defined (RLIMIT_NOFILE)
+ cmd = RLIMIT_NOFILE;
+ goto do_ulimit;
+#else
+# if defined (HAVE_SETDTABLESIZE)
+ return (setdtablesize (newlim));
+# else
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+# endif /* HAVE_SETDTABLESIZE */
+#endif /* !HAVE_RESOURCE || !RLIMIT_NOFILE */
+ }
+ else
+ return (open_files (mode));
+
+ case u_MAX_VIRTUAL_MEM:
+ if (setting)
+ {
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+ }
+ else
+ {
+#if defined (HAVE_RESOURCE)
+ return (getmaxvm (mode));
+#else /* !HAVE_RESOURCE */
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+#endif /* !HAVE_RESOURCE */
+ }
+
+ case u_MAX_USER_PROCS:
+#if defined (HAVE_RESOURCE) && defined (RLIMIT_NPROC)
+ cmd = RLIMIT_NPROC;
+ goto do_ulimit;
+#else /* !HAVE_RESOURCE || !RLIMIT_NPROC */
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+#endif /* !HAVE_RESOURCE || !RLIMIT_NPROC */
+
+ default:
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+ }
+}
+
+#if defined (HAVE_RESOURCE)
+static RLIMTYPE
+getmaxvm (mode)
+ int mode;
+{
+ struct rlimit rl;
+
+#if defined (RLIMIT_VMEM)
+ if (getrlimit (RLIMIT_VMEM, &rl) < 0)
+ return ((RLIMTYPE)-1);
+ else
+ return (((mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max) / 1024L);
+#else /* !RLIMIT_VMEM */
+ RLIMTYPE maxdata, maxstack;
+
+ if (getrlimit (RLIMIT_DATA, &rl) < 0)
+ return ((RLIMTYPE)-1);
+ else
+ maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
+
+ if (getrlimit (RLIMIT_STACK, &rl) < 0)
+ return ((RLIMTYPE)-1);
+ else
+ maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
+
+ /* Protect against overflow. */
+ return ((maxdata / 1024L) + (maxstack / 1024L));
+#endif /* !RLIMIT_VMEM */
+}
+#endif /* HAVE_RESOURCE */
+
+static RLIMTYPE
+open_files (mode)
+ int mode;
+{
+#if !defined (RLIMIT_NOFILE)
+ return ((RLIMTYPE)getdtablesize ());
+#else
+ struct rlimit rl;
+
+ getrlimit (RLIMIT_NOFILE, &rl);
+ if (mode & LIMIT_SOFT)
+ return (rl.rlim_cur);
+ else
+ return (rl.rlim_max);
+#endif
+}
+
+static RLIMTYPE
+pipesize ()
+{
+#if defined (PIPE_BUF)
+ /* This is defined on Posix systems. */
+ return ((RLIMTYPE) PIPE_BUF);
+#else
+# if defined (PIPESIZE)
+ /* This is defined by running a program from the Makefile. */
+ return ((RLIMTYPE) PIPESIZE);
+# else
+ errno = EINVAL;
+ return ((RLIMTYPE)-1);
+# endif /* PIPESIZE */
+#endif /* PIPE_BUF */
+}
+
+/* ulimit(2) returns information about file size limits in terms of 512-byte
+ blocks. This is the factor by which to divide to turn it into information
+ in terms of 1024-byte blocks. Except for hpux 6.x, which returns it in
+ terms of bytes. */
+#if !defined (hpux) || defined (_POSIX_VERSION)
+# define ULIMIT_DIVISOR 2
+#else
+# define ULIMIT_DIVISOR 1024
+#endif
+
+#if defined (HAVE_RESOURCE)
+
+typedef struct {
+ int option_cmd; /* The ulimit command for this limit. */
+ int parameter; /* Parameter to pass to getrlimit (). */
+ int block_factor; /* Blocking factor for specific limit. */
+ char *description; /* Descriptive string to output. */
+} BSD_RESOURCE_LIMITS;
+
+static BSD_RESOURCE_LIMITS limits[] = {
+ { u_CORE_FILE_SIZE, RLIMIT_CORE, 1024, "core file size (blocks)" },
+ { u_DATA_SEG_SIZE, RLIMIT_DATA, 1024, "data seg size (kbytes)" },
+ { u_FILE_SIZE, RLIMIT_FSIZE, 1024, "file size (blocks)" },
+#if !defined (USGr4) && defined (RLIMIT_RSS)
+ { u_PHYS_MEM_SIZE, RLIMIT_RSS, 1024, "max memory size (kbytes)" },
+#endif /* USGr4 && RLIMIT_RSS */
+ { u_STACK_SIZE, RLIMIT_STACK, 1024, "stack size (kbytes)" },
+#if defined (RLIMIT_CPU)
+ { u_CPU_TIME_LIMIT, RLIMIT_CPU, 1, "cpu time (seconds)" },
+#endif /* RLIMIT_CPU */
+#if defined (RLIMIT_NPROC)
+ { u_MAX_USER_PROCS, RLIMIT_NPROC, 1, "max user processes" },
+#endif /* RLIMIT_NPROC */
+ { 0, 0, 0, (char *)NULL }
+};
+
+static void
+print_bsd_limit (i, mode)
+ int i, mode;
+{
+ struct rlimit rl;
+ RLIMTYPE limit;
+
+ getrlimit (limits[i].parameter, &rl);
+ if (mode & LIMIT_HARD)
+ limit = rl.rlim_max;
+ else
+ limit = rl.rlim_cur;
+ printf ("%-25s", limits[i].description);
+ if (limit == RLIM_INFINITY)
+ printf ("unlimited\n");
+ else
+ print_rlimtype ((limit / limits[i].block_factor), 1);
+}
+
+static void
+print_specific_bsd_limits (cmd, mode)
+ int cmd, mode;
+{
+ register int i;
+
+ for (i = 0; limits[i].option_cmd; i++)
+ if (cmd & limits[i].option_cmd)
+ print_bsd_limit (i, mode);
+}
+#endif /* HAVE_RESOURCE */
+
+/* Print the limits corresponding to a specific set of resources. This is
+ called when an option string contains more than one character (e.g. -at),
+ because limits may not be specified with that kind of argument. */
+static void
+print_specific_limits (cmd, mode)
+ int cmd, mode;
+{
+ if (mode == 0)
+ mode = LIMIT_SOFT;
+
+#if defined (HAVE_RESOURCE)
+ print_specific_bsd_limits (cmd, mode);
+#else /* !HAVE_RESOURCE */
+ if (cmd & u_FILE_SIZE)
+ {
+ printf ("%-25s", "file size (blocks)");
+ print_rlimtype ((ulimit (1, 0L) / ULIMIT_DIVISOR), 1);
+ }
+#endif /* !HAVE_RESOURCE */
+
+ if (cmd & u_PIPE_SIZE)
+ {
+ printf ("%-25s", "pipe size (512 bytes)");
+ print_rlimtype ((pipesize () / 512), 1);
+ }
+
+ if (cmd & u_NUM_OPEN_FILES)
+ {
+ printf ("%-25s", "open files");
+ print_rlimtype (open_files (mode), 1);
+ }
+
+#if defined (HAVE_RESOURCE)
+ if (cmd & u_MAX_VIRTUAL_MEM)
+ {
+ printf ("%-25s", "virtual memory (kbytes)");
+ print_rlimtype (getmaxvm (mode), 1);
+ }
+#endif /* HAVE_RESOURCE */
+}
+
+static void
+print_all_limits (mode)
+ int mode;
+{
+ if (mode == 0)
+ mode |= LIMIT_SOFT;
+
+ print_specific_limits (u_ALL_LIMITS, mode);
+}
diff --git a/builtins/umask.def b/builtins/umask.def
new file mode 100644
index 0000000..1d84aa9
--- /dev/null
+++ b/builtins/umask.def
@@ -0,0 +1,288 @@
+This file is umask.def, from which is created umask.c.
+It implements the builtin "umask" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+$PRODUCES umask.c
+
+$BUILTIN umask
+$FUNCTION umask_builtin
+$SHORT_DOC umask [-S] [mode]
+The user file-creation mask is set to MODE. If MODE is omitted, or if
+`-S' is supplied, the current value of the mask is printed. The `-S'
+option makes the output symbolic; otherwise an octal number is output.
+If MODE begins with a digit, it is interpreted as an octal number,
+otherwise it is a symbolic mode string like that accepted by chmod(1).
+$END
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/file.h>
+#include "../shell.h"
+#include "../posixstat.h"
+#include "common.h"
+
+/* **************************************************************** */
+/* */
+/* UMASK Builtin and Helpers */
+/* */
+/* **************************************************************** */
+
+static void print_symbolic_umask ();
+static int symbolic_umask ();
+
+/* Set or display the mask used by the system when creating files. Flag
+ of -S means display the umask in a symbolic mode. */
+umask_builtin (list)
+ WORD_LIST *list;
+{
+ int print_symbolically = 0;
+
+ while (list)
+ {
+ if (ISOPTION (list->word->word, 'S'))
+ {
+ list = list->next;
+ print_symbolically++;
+ continue;
+ }
+ else if (ISOPTION (list->word->word, '-'))
+ {
+ list = list->next;
+ break;
+ }
+ else if (*(list->word->word) == '-')
+ {
+ bad_option (list->word->word);
+ builtin_error ("usage: umask [-S] [mode]");
+ return (EX_USAGE);
+ }
+ else
+ break;
+ }
+
+ if (list)
+ {
+ int new_umask;
+
+ if (digit (*list->word->word))
+ {
+ new_umask = 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 (new_umask == -1)
+ {
+ builtin_error ("`%s' is not an octal number from 000 to 777",
+ list->word->word);
+ return (EXECUTION_FAILURE);
+ }
+ }
+ else
+ {
+ new_umask = symbolic_umask (list);
+ if (new_umask == -1)
+ return (EXECUTION_FAILURE);
+ }
+ umask (new_umask);
+ if (print_symbolically)
+ print_symbolic_umask (new_umask);
+ }
+ else /* Display the UMASK for this user. */
+ {
+ int old_umask;
+
+ old_umask = umask (022);
+ umask (old_umask);
+
+ if (print_symbolically)
+ print_symbolic_umask (old_umask);
+ else
+ printf ("%03o\n", old_umask);
+ }
+ fflush (stdout);
+ return (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)
+ int 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);
+}
+
+/* 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, umc, c;
+ int who, op, perm, mask;
+ char *s;
+
+ /* Get the initial umask. Don't change it yet. */
+ um = umask (022);
+ umask (um);
+
+ /* All work below is done with the complement of the umask -- its
+ more intuitive and easier to deal with. It is complemented
+ again before being returned. */
+ umc = ~um;
+
+ s = list->word->word;
+
+ for (;;)
+ {
+ who = op = perm = mask = 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 ("bad symbolic mode operator: %c", 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 '+':
+ umc |= perm;
+ break;
+
+ case '-':
+ umc &= ~perm;
+ break;
+
+ case '=':
+ umc &= ~who;
+ umc |= perm;
+ break;
+
+ default:
+ builtin_error ("bad operation character: %c", op);
+ return (-1);
+ }
+
+ if (!*s)
+ {
+ um = ~umc & 0777;
+ break;
+ }
+ else
+ s++; /* skip past ',' */
+ }
+ else
+ {
+ builtin_error ("bad character in symbolic mode: %c", *s);
+ return (-1);
+ }
+ }
+ return (um);
+}
diff --git a/builtins/wait.def b/builtins/wait.def
new file mode 100644
index 0000000..f613179
--- /dev/null
+++ b/builtins/wait.def
@@ -0,0 +1,132 @@
+This file is wait.def, from which is created wait.c.
+It implements the builtin "wait" in Bash.
+
+Copyright (C) 1987, 1989, 1991 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 1, or (at your option) any later
+version.
+
+Bash is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License along
+with Bash; see the file COPYING. If not, write to the Free Software
+Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+$BUILTIN wait
+$FUNCTION wait_builtin
+$DEPENDS_ON JOB_CONTROL
+$PRODUCES wait.c
+$SHORT_DOC wait [n]
+Wait for the specified process and report its termination status. If
+N is not given, all currently active child processes are waited for,
+and the return code is zero. N may be a process ID or a job
+specification; if a job spec is given, all processes in the job's
+pipeline are waited for.
+$END
+
+$BUILTIN wait
+$FUNCTION wait_builtin
+$DEPENDS_ON !JOB_CONTROL
+$SHORT_DOC wait [n]
+Wait for the specified process and report its termination status. If
+N is not given, all currently active child processes are waited for,
+and the return code is zero. N is a process ID; if it is not given,
+all child processes of the shell are waited for.
+$END
+
+#include <sys/types.h>
+#include <signal.h>
+#include "../shell.h"
+#include "../jobs.h"
+
+extern int interrupt_immediately;
+
+/* 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. */
+wait_builtin (list)
+ WORD_LIST *list;
+{
+ int status = EXECUTION_SUCCESS;
+
+ begin_unwind_frame ("wait_builtin");
+ unwind_protect_int (interrupt_immediately);
+ interrupt_immediately++;
+
+ /* 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)
+ {
+ wait_for_background_pids ();
+ status = EXECUTION_SUCCESS;
+ goto return_status;
+ }
+
+ while (list)
+ {
+ pid_t pid;
+ char *w;
+
+ w = list->word->word;
+ if (digit (*w))
+ {
+ if (all_digits (w + 1))
+ {
+ pid = (pid_t)atoi (w);
+ status = wait_for_single_pid (pid);
+ }
+ else
+ {
+ builtin_error ("`%s' is not a pid or legal job spec", w);
+ status = EXECUTION_FAILURE;
+ goto return_status;
+ }
+ }
+#if defined (JOB_CONTROL)
+ else if (job_control && *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 (job < 0 || job >= job_slots || !jobs[job])
+ {
+ if (job != DUP_JOB)
+ builtin_error ("No such job %s", 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
+ {
+ builtin_error ("`%s' is not a pid or legal job spec", w);
+ status = EXECUTION_FAILURE;
+ }
+ list = list->next;
+ }
+ return_status:
+ run_unwind_frame ("wait_builtin");
+ return (status);
+}