1
0
Fork 0

Adding upstream version 5.2.37.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
This commit is contained in:
Daniel Baumann 2025-06-21 06:49:21 +02:00
parent cf91100bce
commit fa1b3d3922
Signed by: daniel.baumann
GPG key ID: BCC918A2ABD66424
1435 changed files with 757174 additions and 0 deletions

723
builtins/Makefile.in Normal file
View file

@ -0,0 +1,723 @@
# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs.
#
# Copyright (C) 1996-2022 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 3 of the License, 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, see <http://www.gnu.org/licenses/>.
PACKAGE = @PACKAGE_NAME@
PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
PACKAGE_NAME = @PACKAGE_NAME@
PACKAGE_STRING = @PACKAGE_STRING@
PACKAGE_VERSION = @PACKAGE_VERSION@
#
SHELL = @MAKE_SHELL@
RANLIB = @RANLIB@
CC = @CC@
CC_FOR_BUILD = @CC_FOR_BUILD@
AR = @AR@
ARFLAGS = @ARFLAGS@
RM = rm -f
CP = cp
EXEEXT = @EXEEXT@
prefix = @prefix@
srcdir = @srcdir@
VPATH = @srcdir@
topdir = @top_srcdir@
datarootdir = @datarootdir@
includedir = @includedir@
datadir = @datadir@
localedir = @localedir@
loadablesdir = @loadablesdir@
# Support an alternate destination root directory for package building
DESTDIR =
INSTALL = @INSTALL@
INSTALL_DATA = @INSTALL_DATA@
BUILD_DIR = @BUILD_DIR@
LIBBUILD = ${BUILD_DIR}/lib
PROFILE_FLAGS = @PROFILE_FLAGS@
CFLAGS = @CFLAGS@
CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ @CROSS_COMPILE@
STYLE_CFLAGS = @STYLE_CFLAGS@
CPPFLAGS = @CPPFLAGS@
CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
LOCAL_CFLAGS = @LOCAL_CFLAGS@ ${DEBUG}
DEFS = @DEFS@
LOCAL_DEFS = @LOCAL_DEFS@
LIBS = @LIBS@
LDFLAGS = @LDFLAGS@ $(LOCAL_LDFLAGS) $(CFLAGS)
LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ $(LOCAL_LDFLAGS) $(CFLAGS_FOR_BUILD)
LOCAL_LDFLAGS = @LOCAL_LDFLAGS@
LIBS_FOR_BUILD = @LIBS_FOR_BUILD@
#LIBS_FOR_BUILD = $(LIBS)
BASHINCDIR = ${topdir}/include
RL_INCLUDEDIR = @RL_INCLUDEDIR@
INTL_LIBSRC = ${topdir}/lib/intl
INTL_BUILDDIR = ${LIBBUILD}/intl
INTL_LIBDIR = ${INTL_BUILDDIR}
INTL_LIBRARY = ${INTL_BUILDDIR}/libintl.a
INTL_INC = @INTL_INC@
INTL_DEP = @INTL_DEP@
LIBINTL_H = @LIBINTL_H@
HELPDIR = @HELPDIR@
MKDIRS = ${topdir}/support/mkdirs
HELPFILES_TARGET = @HELPFILES_TARGET@
INCLUDES = -I. -I.. @RL_INCLUDE@ -I$(topdir) -I$(BASHINCDIR) -I$(topdir)/lib -I$(srcdir) ${INTL_INC}
BASE_CCFLAGS = ${PROFILE_FLAGS} $(DEFS) $(LOCAL_DEFS) $(SYSTEM_FLAGS) \
${INCLUDES} $(STYLE_CFLAGS) $(LOCAL_CFLAGS)
CCFLAGS = ${ADDON_CFLAGS} $(BASE_CCFLAGS) $(CPPFLAGS) $(CFLAGS)
CCFLAGS_FOR_BUILD = $(BASE_CCFLAGS) $(CPPFLAGS_FOR_BUILD) $(CFLAGS_FOR_BUILD)
GCC_LINT_FLAGS = -Wall -Wshadow -Wpointer-arith -Wcast-qual \
-Wcast-align -Wstrict-prototypes -Wconversion \
-Wmissing-prototypes -Wtraditional -Wredundant-decls -pedantic
MKBUILTINS = mkbuiltins$(EXEEXT)
DIRECTDEFINE = -D $(srcdir)
HELPDIRDEFINE = @HELPDIRDEFINE@
HELPSTRINGS = @HELPSTRINGS@
# xxx this is bad style
RL_LIBSRC = $(topdir)/lib/readline
.SUFFIXES:
.SUFFIXES: .def .c .o
# How to make a .o file from a .def file.
.def.o:
$(RM) $@
./$(MKBUILTINS) $(DIRECTDEFINE) $<
$(CC) -c $(CCFLAGS) $*.c || ( $(RM) $*.c ; exit 1 )
$(RM) $*.c
# How to make a .c file from a .def file.
.def.c:
$(RM) $@
./$(MKBUILTINS) $(DIRECTDEFINE) $<
# default rule for making a .o file from a .c file
.c.o:
$(RM) $@
$(CC) -c $(CCFLAGS) $<
DEFSRC = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \
$(srcdir)/builtin.def $(srcdir)/caller.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 $(srcdir)/pushd.def $(srcdir)/shopt.def \
$(srcdir)/printf.def $(srcdir)/complete.def $(srcdir)/mapfile.def
STATIC_SOURCE = common.c evalstring.c evalfile.c getopt.c bashgetopt.c \
getopt.h
OFILES = builtins.o \
alias.o bind.o break.o builtin.o caller.o cd.o colon.o command.o \
common.o declare.o echo.o enable.o eval.o evalfile.o \
evalstring.o exec.o exit.o fc.o fg_bg.o hash.o help.o history.o \
jobs.o kill.o let.o mapfile.o \
pushd.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 shopt.o printf.o getopt.o bashgetopt.o complete.o
CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h tmpbuiltins.c \
tmpbuiltins.h
CREATED_OBJECTS = tmpbuiltins.o gen-helpfiles.o mkbuiltins.o
all: $(MKBUILTINS) libbuiltins.a $(HELPFILES_TARGET)
targets: libbuiltins.a $(HELPFILES_TARGET)
libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o
$(RM) $@
$(AR) $(ARFLAGS) $@ $(OFILES)
-$(RANLIB) $@
tmpbuiltins.c: $(MKBUILTINS) $(DEFSRC)
./$(MKBUILTINS) -externfile tmpbuiltins.h -structfile $@ \
-noproduction -nofunctions \
$(DIRECTDEFINE) $(HELPSTRINGS) $(DEFSRC)
tmpbuiltins.h: tmpbuiltins.c
gen-helpfiles.o: ../config.h
gen-helpfiles.o: gen-helpfiles.c
$(RM) $@
$(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $<
gen-helpfiles: tmpbuiltins.o gen-helpfiles.o
$(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $@ gen-helpfiles.o tmpbuiltins.o $(LIBS_FOR_BUILD)
builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC)
@RECPID=$$$$ ; \
NEW_BUILTEXT=builtext-$$RECPID.h NEW_BUILTINS=builtins-$$RECPID.c ; \
./$(MKBUILTINS) -externfile $$NEW_BUILTEXT \
-includefile builtext.h \
-structfile $$NEW_BUILTINS \
-noproduction $(DIRECTDEFINE) $(HELPDIRDEFINE) $(HELPSTRINGS) $(DEFSRC) ; \
if cmp -s $$NEW_BUILTEXT builtext.h 2>/dev/null; then \
$(RM) $$NEW_BUILTEXT; \
else \
mv $$NEW_BUILTEXT builtext.h; \
fi ; \
if cmp -s $$NEW_BUILTINS builtins.c 2>/dev/null; then \
$(RM) $$NEW_BUILTINS ; \
else \
mv $$NEW_BUILTINS builtins.c; \
fi
helpdoc: gen-helpfiles
./gen-helpfiles ${HELPDIRDEFINE}
install-help: $(HELPFILES_TARGET)
@-if test -n "${HELPDIR}" && test -d helpfiles ; then \
test -d $(DESTDIR)${HELPDIR} || ${SHELL} ${MKDIRS} $(DESTDIR)$(HELPDIR) ;\
( for f in helpfiles/*; do \
echo installing $$f; \
${INSTALL_DATA} $$f $(DESTDIR)$(HELPDIR); \
done; ) ; \
fi
install: @HELPINSTALL@
mkbuiltins.o: ../config.h
mkbuiltins.o: mkbuiltins.c
$(RM) $@
$(CC_FOR_BUILD) -c $(CCFLAGS_FOR_BUILD) $<
mkbuiltins$(EXEEXT): mkbuiltins.o
$(CC_FOR_BUILD) $(LDFLAGS_FOR_BUILD) -o $(MKBUILTINS) mkbuiltins.o $(LIBS_FOR_BUILD)
# rules for deficient makes, like SunOS
mkbuiltins.o: mkbuiltins.c
builtins.o: builtins.c
common.o: common.c
bashgetopt.o: bashgetopt.c
getopt.o: getopt.c
evalstring.o: evalstring.c
evalfile.o: evalfile.c
tmpbuiltins.o: tmpbuiltins.c
gen-helpfiles.o: gen-helpfiles.c
ulimit.o: pipesize.h
pipesize.h: psize.aux
$(SHELL) $(srcdir)/psize.sh > $@
# Technically this is wrong; the pipe size should be for the target system,
# not the build host.
psize.aux: psize.c
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) ${LDFLAGS_FOR_BUILD} -o $@ $(srcdir)/psize.c
documentation: builtins.texi
builtins.texi: $(MKBUILTINS)
./$(MKBUILTINS) -documentonly $(DEFSRC)
clean:
$(RM) $(OFILES) $(CREATED_FILES) libbuiltins.a
$(RM) $(MKBUILTINS) gen-helpfiles $(CREATED_OBJECTS)
-test -d helpfiles && $(RM) -r helpfiles
mostlyclean:
$(RM) $(OFILES) libbuiltins.a
distclean maintainer-clean: clean
$(RM) Makefile
$(OFILES): $(MKBUILTINS) ../config.h
../version.h: ../config.h ../Makefile Makefile
-( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h )
# maintainer special - for now
po: builtins.c
xgettext -L C -o $(topdir)/po/builtins.pot --keyword='N_' builtins.c 2>/dev/null
${LIBINTL_H}:
@echo making $@ in ${INTL_BUILDDIR}
@(cd ${INTL_BUILDDIR} && \
$(MAKE) $(MFLAGS) libintl.h) || exit 1
# dependencies
alias.o: alias.def
bind.o: bind.def
break.o: break.def
builtin.o: builtin.def
caller.o: caller.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
mapfile.o: mapfile.def
printf.o: printf.def
pushd.o: pushd.def
read.o: read.def
return.o: return.def
set.o: set.def
setattr.o: setattr.def
shift.o: shift.def
shopt.o: shopt.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
ulimit.o: ulimit.def
umask.o: umask.def
wait.o: wait.def
getopts.o: getopts.def
reserved.o: reserved.def
complete.o: complete.def
# C files
bashgetopt.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
bashgetopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h
bashgetopt.o: $(topdir)/command.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h
bashgetopt.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/quit.h $(BASHINCDIR)/maxpath.h
bashgetopt.o: $(topdir)/unwind_prot.h $(topdir)/dispose_cmd.h
bashgetopt.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/sig.h
bashgetopt.o: ../pathnames.h $(topdir)/externs.h $(srcdir)/common.h
bashgetopt.o: $(BASHINCDIR)/chartypes.h
common.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
common.o: $(topdir)/shell.h $(topdir)/syntax.h ../config.h $(topdir)/bashjmp.h $(BASHINCDIR)/posixjmp.h
common.o: $(topdir)/sig.h $(topdir)/command.h $(topdir)/parser.h
common.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/stdc.h $(BASHINCDIR)/memalloc.h
common.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/input.h
common.o: $(topdir)/siglist.h $(topdir)/bashhist.h $(topdir)/quit.h
common.o: $(topdir)/unwind_prot.h $(BASHINCDIR)/maxpath.h $(topdir)/jobs.h
common.o: $(topdir)/builtins.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
common.o: $(topdir)/subst.h $(topdir)/execute_cmd.h $(topdir)/error.h
common.o: $(topdir)/externs.h ../pathnames.h ./builtext.h
common.o: $(BASHINCDIR)/chartypes.h
evalfile.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h ${BASHINCDIR}/filecntl.h
evalfile.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
evalfile.o: $(topdir)/shell.h $(topdir)/syntax.h ../config.h $(topdir)/bashjmp.h
evalfile.o: $(topdir)/command.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h
evalfile.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/quit.h $(BASHINCDIR)/maxpath.h
evalfile.o: $(topdir)/unwind_prot.h $(topdir)/dispose_cmd.h
evalfile.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/sig.h
evalfile.o: ../pathnames.h $(topdir)/externs.h $(topdir)/parser.h
evalfile.o: $(topdir)/jobs.h $(topdir)/builtins.h $(topdir)/flags.h
evalfile.o: $(topdir)/input.h $(topdir)/execute_cmd.h
evalfile.o: $(topdir)/bashhist.h $(srcdir)/common.h
evalstring.o: ../config.h $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
evalstring.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h $(BASHINCDIR)/posixjmp.h
evalstring.o: $(topdir)/sig.h $(topdir)/command.h $(topdir)/siglist.h
evalstring.o: $(BASHINCDIR)/memalloc.h $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/input.h
evalstring.o: $(topdir)/quit.h $(topdir)/unwind_prot.h
evalstring.o: $(BASHINCDIR)/maxpath.h $(topdir)/jobs.h $(topdir)/builtins.h
evalstring.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
evalstring.o: $(topdir)/externs.h $(topdir)/jobs.h $(topdir)/builtins.h
evalstring.o: $(topdir)/flags.h $(topdir)/input.h $(topdir)/execute_cmd.h
evalstring.o: $(topdir)/bashhist.h $(srcdir)/common.h
evalstring.o: $(topdir)/trap.h $(topdir)/redir.h ../pathnames.h ./builtext.h
#evalstring.o: $(topdir)/y.tab.h
getopt.o: ../config.h $(BASHINCDIR)/memalloc.h
getopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/bashjmp.h $(topdir)/command.h
getopt.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/error.h $(topdir)/variables.h $(topdir)/conftypes.h
getopt.o: $(topdir)/quit.h $(BASHINCDIR)/maxpath.h $(topdir)/unwind_prot.h
getopt.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
getopt.o: $(topdir)/sig.h ../pathnames.h $(topdir)/externs.h
getopt.o: $(srcdir)/getopt.h
mkbuiltins.o: ../config.h $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
mkbuiltins.o: ${BASHINCDIR}/filecntl.h
mkbuiltins.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h
# def files
alias.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
alias.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h
alias.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
alias.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/common.h
alias.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
alias.o: ../pathnames.h
bind.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
bind.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
bind.o: $(topdir)/subst.h $(topdir)/externs.h $(srcdir)/bashgetopt.h
bind.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h $(topdir)/bashline.h
bind.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
break.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
break.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
break.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
break.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
break.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
break.o: ../pathnames.h $(topdir)/execute_cmd.h
builtin.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
builtin.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h
builtin.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h $(topdir)/sig.h
builtin.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
builtin.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
builtin.o: $(srcdir)/bashgetopt.h ../pathnames.h $(topdir)/execute_cmd.h
caller.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
caller.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(topdir)/dispose_cmd.h
caller.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h
caller.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
caller.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h ./builtext.h
caller.o: ${BASHINCDIR}/chartypes.h $(topdir)/bashtypes.h ../pathnames.h
cd.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
cd.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(topdir)/dispose_cmd.h
cd.o: $(topdir)/make_cmd.h $(topdir)/subst.h $(topdir)/externs.h
cd.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
cd.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h ../pathnames.h
cd.o: $(topdir)/sig.h
colon.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
colon.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
colon.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
colon.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
colon.o: $(BASHINCDIR)/maxpath.h ../pathnames.h
colon.o: $(srcdir)/common.h
command.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
command.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h
command.o: $(topdir)/quit.h $(srcdir)/bashgetopt.h $(BASHINCDIR)/maxpath.h
command.o: $(topdir)/sig.h
command.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
command.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
command.o: ../pathnames.h
declare.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
declare.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
declare.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
declare.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
declare.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
declare.o: $(topdir)/arrayfunc.h $(srcdir)/bashgetopt.h $(topdir)/flags.h
declare.o: ./builtext.h ../pathnames.h
echo.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
echo.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
echo.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
echo.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
echo.o: $(BASHINCDIR)/maxpath.h ../pathnames.h
echo.o: $(srcdir)/common.h
enable.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
enable.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
enable.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
enable.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h
enable.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
enable.o: $(BASHINCDIR)/maxpath.h ../pathnames.h
enable.o: $(topdir)/pcomplete.h
eval.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
eval.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
eval.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
eval.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h
eval.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
eval.o: $(BASHINCDIR)/maxpath.h ../pathnames.h
exec.o: $(topdir)/bashtypes.h
exec.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
exec.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h
exec.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(BASHINCDIR)/maxpath.h
exec.o: $(topdir)/findcmd.h $(topdir)/jobs.h ../pathnames.h
exit.o: $(topdir)/bashtypes.h
exit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
exit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
exit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
exit.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/jobs.h
exit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
exit.o: $(topdir)/execute_cmd.h
exit.o: $(BASHINCDIR)/maxpath.h ./builtext.h ../pathnames.h
fc.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
fc.o: $(topdir)/builtins.h $(topdir)/command.h $(srcdir)/bashgetopt.h
fc.o: $(topdir)/bashhist.h $(topdir)/parser.h
fc.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
fc.o: $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h
fc.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
fc.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/shell.h $(topdir)/syntax.h
fc.o: $(topdir)/flags.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
fc.o: $(topdir)/bashansi.h $(BASHINCDIR)/ansi_stdlib.h $(BASHINCDIR)/chartypes.h
fc.o: ../pathnames.h
fg_bg.o: $(topdir)/bashtypes.h $(srcdir)/bashgetopt.h
fg_bg.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
fg_bg.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
fg_bg.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
fg_bg.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
fg_bg.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
fg_bg.o: $(topdir)/execute_cmd.h
fg_bg.o: $(topdir)/jobs.h ../pathnames.h
getopts.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
getopts.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
getopts.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
getopts.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
getopts.o: $(topdir)/execute_cmd.h
getopts.o: ../pathnames.h
hash.o: $(topdir)/builtins.h $(topdir)/command.h $(topdir)/quit.h
hash.o: $(topdir)/findcmd.h $(topdir)/hashlib.h $(topdir)/sig.h
hash.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
hash.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
hash.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h
hash.o: $(topdir)/conftypes.h $(topdir)/execute_cmd.h
hash.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.h ../pathnames.h
help.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
help.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
help.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
help.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
help.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h
help.o: $(topdir)/conftypes.h $(topdir)/execute_cmd.h
help.o: ${srcdir}/common.h $(topdir)/sig.h ../pathnames.h
history.o: $(topdir)/bashtypes.h
history.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
history.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
history.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
history.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h $(topdir)/parser.h
history.o: ${BASHINCDIR}/filecntl.h $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h
history.o: $(topdir)/variables.h $(topdir)/conftypes.h $(topdir)/bashhist.h $(BASHINCDIR)/maxpath.h
history.o: ../pathnames.h
inlib.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
inlib.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
inlib.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
inlib.o: $(BASHINCDIR)/maxpath.h $(topdir)/subst.h $(topdir)/externs.h
inlib.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h ../pathnames.h
jobs.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
jobs.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(srcdir)/bashgetopt.h
jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h $(topdir)/jobs.h
jobs.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
jobs.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
jobs.o: $(topdir)/sig.h ../pathnames.h
kill.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
kill.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
kill.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
kill.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/trap.h $(topdir)/unwind_prot.h
kill.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/maxpath.h
kill.o: $(topdir)/jobs.h ../pathnames.h
let.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
let.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
let.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
let.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
let.o: ../pathnames.h
printf.o: ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/bashjmp.h
printf.o: $(topdir)/command.h $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
printf.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
printf.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h
printf.o: ../pathnames.h $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h
printf.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/stdc.h $(srcdir)/bashgetopt.h
printf.o: $(topdir)/bashtypes.h ${srcdir}/common.h $(BASHINCDIR)/chartypes.h
printf.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
printf.o: ../pathnames.h
pushd.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
pushd.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
pushd.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
pushd.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/sig.h
pushd.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
pushd.o: $(BASHINCDIR)/maxpath.h $(srcdir)/common.h ./builtext.h
pushd.o: ../pathnames.h
read.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
read.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
read.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
read.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
read.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
read.o: $(BASHINCDIR)/shtty.h $(topdir)/sig.h
read.o: ${BASHINCDIR}/shmbutil.h ${BASHINCDIR}/shmbchar.h
read.o: $(topdir)/arrayfunc.h ../pathnames.h
return.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
return.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
return.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
return.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
return.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h
return.o: $(topdir)/conftypes.h $(topdir)/execute_cmd.h
return.o: ../pathnames.h
set.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
set.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/externs.h
set.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
set.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
set.o: $(BASHINCDIR)/maxpath.h $(topdir)/error.h $(topdir)/sig.h
set.o: $(topdir)/arrayfunc.h ../pathnames.h $(topdir)/parser.h
setattr.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
setattr.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(BASHINCDIR)/maxpath.h
setattr.o: $(topdir)/quit.h $(srcdir)/common.h $(srcdir)/bashgetopt.h
setattr.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
setattr.o: $(topdir)/externs.h $(topdir)/flags.h $(topdir)/sig.h
setattr.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h
setattr.o: $(topdir)/conftypes.h $(topdir)/execute_cmd.h
setattr.o: $(topdir)/arrayfunc.h ../pathnames.h
shift.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
shift.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
shift.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
shift.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
shift.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
shift.o: ../pathnames.h
shopt.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
shopt.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
shopt.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
shopt.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
shopt.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
shopt.o: $(srcdir)/common.h $(srcdir)/bashgetopt.h ../pathnames.h
shopt.o: $(topdir)/bashhist.h $(topdir)/bashline.h $(topdir)/sig.h
source.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
source.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/findcmd.h
source.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
source.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
source.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
source.o: $(srcdir)/bashgetopt.h $(topdir)/flags.h $(topdir)/trap.h
source.o: $(topdir)/execute_cmd.h
source.o: ../pathnames.h
suspend.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
suspend.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
suspend.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
suspend.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
suspend.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
suspend.o: $(topdir)/jobs.h ../pathnames.h
test.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
test.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
test.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
test.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
test.o: $(topdir)/execute_cmd.h $(topdir)/test.h ../pathnames.h
times.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
times.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
times.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
times.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
times.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
times.o: $(BASHINCDIR)/posixtime.h ../pathnames.h
trap.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
trap.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/externs.h
trap.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h $(topdir)/sig.h
trap.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
trap.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
trap.o: $(topdir)/findcmd.h ../pathnames.h
type.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
type.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
type.o: $(topdir)/quit.h $(srcdir)/common.h $(BASHINCDIR)/maxpath.h $(topdir)/sig.h
type.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
type.o: $(topdir)/execute_cmd.h $(topdir)/parser.h
type.o: $(topdir)/externs.h $(topdir)/hashcmd.h ../pathnames.h
type.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
ulimit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
ulimit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
ulimit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
ulimit.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
ulimit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
ulimit.o: ../pathnames.h
umask.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
umask.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
umask.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
umask.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
umask.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
umask.o: $(BASHINCDIR)/chartypes.h ../pathnames.h
wait.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
wait.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
wait.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
wait.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
wait.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
wait.o: $(topdir)/jobs.h $(topdir)/sig.h $(topdir)/execute_cmd.h
wait.o: $(BASHINCDIR)/chartypes.h ../pathnames.h
complete.o: ../config.h ../pathnames.h
complete.o: ${topdir}/shell.h $(topdir)/syntax.h ${topdir}/bashjmp.h ${BASHINCDIR}/posixjmp.h ${topdir}/sig.h
complete.o: ${topdir}/unwind_prot.h ${topdir}/variables.h
complete.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
complete.o: ${topdir}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
complete.o: ${topdir}/builtins.h ${topdir}/general.h
complete.o: ${topdir}/bashtypes.h ${BASHINCDIR}/chartypes.h ${topdir}/xmalloc.h
complete.o: ${topdir}/pcomplete.h
complete.o: ${srcdir}/common.h ${srcdir}/bashgetopt.h
mapfile.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
mapfile.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
mapfile.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/sig.h
mapfile.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
mapfile.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/variables.h $(topdir)/conftypes.h
mapfile.o: $(topdir)/arrayfunc.h ../pathnames.h
#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h
# libintl dependencies
bind.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
break.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
caller.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
cd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
common.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
complete.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
declare.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
enable.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
evalfile.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
exec.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
exit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
fc.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
fg_bg.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
getopt.c: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
hash.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
help.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
history.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
inlib.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
jobs.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
kill.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
let.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
mapfile.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
mkbuiltins.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
printf.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
pushd.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
read.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
return.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
set.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
setattr.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
shift.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
shopt.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
source.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
suspend.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
type.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
ulimit.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
umask.o: ${topdir}/bashintl.h ${LIBINTL_H} $(BASHINCDIR)/gettext.h
cd.o: $(topdir)/config-top.h
command.o: $(topdir)/config-top.h
common.o: $(topdir)/config-top.h
declare.o: $(topdir)/config-top.h
break.o: $(topdir)/config-top.h
echo.o: $(topdir)/config-top.h
evalstring.o: $(topdir)/config-top.h
exit.o: $(topdir)/config-top.h
kill.o: $(topdir)/config-top.h
shopt.o: $(topdir)/config-top.h

241
builtins/alias.def Normal file
View file

@ -0,0 +1,241 @@
This file is alias.def, from which is created alias.c
It implements the builtins "alias" and "unalias" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$BUILTIN alias
$FUNCTION alias_builtin
$DEPENDS_ON ALIAS
$PRODUCES alias.c
$SHORT_DOC alias [-p] [name[=value] ... ]
Define or display aliases.
Without arguments, `alias' prints the list of aliases in the reusable
form `alias NAME=VALUE' on standard output.
Otherwise, 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 when the alias is expanded.
Options:
-p print all defined aliases in a reusable format
Exit Status:
alias returns true unless a NAME is supplied for which no alias has been
defined.
$END
#include <config.h>
#if defined (ALIAS)
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
# include "../bashansi.h"
# include "../bashintl.h"
# include <stdio.h>
# include "../shell.h"
# include "../alias.h"
# include "common.h"
# include "bashgetopt.h"
/* Flags for print_alias */
#define AL_REUSABLE 0x01
static void print_alias PARAMS((alias_t *, int));
/* Hack the alias command in a Korn shell way. */
int
alias_builtin (list)
WORD_LIST *list;
{
int any_failed, offset, pflag, dflags;
alias_t **alias_list, *t;
char *name, *value;
dflags = posixly_correct ? 0 : AL_REUSABLE;
pflag = 0;
reset_internal_getopt ();
while ((offset = internal_getopt (list, "p")) != -1)
{
switch (offset)
{
case 'p':
pflag = 1;
dflags |= AL_REUSABLE;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0 || pflag)
{
if (aliases == 0)
return (EXECUTION_SUCCESS);
alias_list = all_aliases ();
if (alias_list == 0)
return (EXECUTION_SUCCESS);
for (offset = 0; alias_list[offset]; offset++)
print_alias (alias_list[offset], dflags);
free (alias_list); /* XXX - Do not free the strings. */
if (list == 0)
return (sh_chkwrite (EXECUTION_SUCCESS));
}
any_failed = 0;
while (list)
{
name = list->word->word;
for (offset = 0; name[offset] && name[offset] != '='; offset++)
;
if (offset && name[offset] == '=')
{
name[offset] = '\0';
value = name + offset + 1;
if (legal_alias_name (name, 0) == 0)
{
builtin_error (_("`%s': invalid alias name"), name);
any_failed++;
}
else
add_alias (name, value);
}
else
{
t = find_alias (name);
if (t)
print_alias (t, dflags);
else
{
sh_notfound (name);
any_failed++;
}
}
list = list->next;
}
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
#endif /* ALIAS */
$BUILTIN unalias
$FUNCTION unalias_builtin
$DEPENDS_ON ALIAS
$SHORT_DOC unalias [-a] name [name ...]
Remove each NAME from the list of defined aliases.
Options:
-a remove all alias definitions
Return success unless a NAME is not an existing alias.
$END
#if defined (ALIAS)
/* Remove aliases named in LIST from the aliases database. */
int
unalias_builtin (list)
register WORD_LIST *list;
{
register alias_t *alias;
int opt, aflag;
aflag = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "a")) != -1)
{
switch (opt)
{
case 'a':
aflag = 1;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (aflag)
{
delete_all_aliases ();
return (EXECUTION_SUCCESS);
}
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
aflag = 0;
while (list)
{
alias = find_alias (list->word->word);
if (alias)
remove_alias (alias->name);
else
{
sh_notfound (list->word->word);
aflag++;
}
list = list->next;
}
return (aflag ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
/* Output ALIAS in such a way as to allow it to be read back in. */
static void
print_alias (alias, flags)
alias_t *alias;
int flags;
{
char *value;
value = sh_single_quote (alias->value);
if (flags & AL_REUSABLE)
printf ("alias %s", (alias->name && alias->name[0] == '-') ? "-- " : "");
printf ("%s=%s\n", alias->name, value);
free (value);
fflush (stdout);
}
#endif /* ALIAS */

194
builtins/bashgetopt.c Normal file
View file

@ -0,0 +1,194 @@
/* bashgetopt.c -- `getopt' for use by the builtins. */
/* Copyright (C) 1992-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include <chartypes.h>
#include <errno.h>
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#define ISOPT(s) (((*(s) == '-') || (plus && *(s) == '+')) && (s)[1])
#define NOTOPT(s) (((*(s) != '-') && (!plus || *(s) != '+')) || (s)[1] == '\0')
static int sp;
char *list_optarg;
int list_optflags;
int list_optopt;
int list_opttype;
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;
int plus; /* nonzero means to handle +option */
static char errstr[3] = { '-', '\0', '\0' };
plus = *opts == '+';
if (plus)
opts++;
if (list == 0) {
list_optarg = (char *)NULL;
list_optflags = 0;
loptend = (WORD_LIST *)NULL; /* No non-option arguments */
return -1;
}
if (list != lhead || lhead == 0) {
/* Hmmm.... called with a different word list. Reset. */
sp = 1;
lcurrent = lhead = list;
loptend = (WORD_LIST *)NULL;
}
if (sp == 1) {
if (lcurrent == 0 || NOTOPT(lcurrent->word->word)) {
lhead = (WORD_LIST *)NULL;
loptend = lcurrent;
return(-1);
} else if (ISHELP (lcurrent->word->word)) {
lhead = (WORD_LIST *)NULL;
loptend = lcurrent;
return (GETOPT_HELP);
} else if (lcurrent->word->word[0] == '-' &&
lcurrent->word->word[1] == '-' &&
lcurrent->word->word[2] == 0) {
lhead = (WORD_LIST *)NULL;
loptend = lcurrent->next;
return(-1);
}
errstr[0] = list_opttype = lcurrent->word->word[0];
}
list_optopt = c = lcurrent->word->word[sp];
if (c == ':' || (cp = strchr(opts, c)) == NULL) {
errstr[1] = c;
sh_invalidopt (errstr);
if (lcurrent->word->word[++sp] == '\0') {
lcurrent = lcurrent->next;
sp = 1;
}
list_optarg = NULL;
list_optflags = 0;
if (lcurrent)
loptend = lcurrent->next;
return('?');
}
if (*++cp == ':' || *cp == ';') {
/* `:': Option requires an argument. */
/* `;': option argument may be missing */
/* We allow -l2 as equivalent to -l 2 */
if (lcurrent->word->word[sp+1]) {
list_optarg = lcurrent->word->word + sp + 1;
list_optflags = 0;
lcurrent = lcurrent->next;
/* If the specifier is `;', don't set optarg if the next
argument looks like another option. */
#if 0
} else if (lcurrent->next && (*cp == ':' || lcurrent->next->word->word[0] != '-')) {
#else
} else if (lcurrent->next && (*cp == ':' || NOTOPT(lcurrent->next->word->word))) {
#endif
lcurrent = lcurrent->next;
list_optarg = lcurrent->word->word;
list_optflags = lcurrent->word->flags;
lcurrent = lcurrent->next;
} else if (*cp == ';') {
list_optarg = (char *)NULL;
list_optflags = 0;
lcurrent = lcurrent->next;
} else { /* lcurrent->next == NULL */
errstr[1] = c;
sh_needarg (errstr);
sp = 1;
list_optarg = (char *)NULL;
list_optflags = 0;
return('?');
}
sp = 1;
} else if (*cp == '#') {
/* option requires a numeric argument */
if (lcurrent->word->word[sp+1]) {
if (DIGIT(lcurrent->word->word[sp+1])) {
list_optarg = lcurrent->word->word + sp + 1;
list_optflags = 0;
lcurrent = lcurrent->next;
} else {
list_optarg = (char *)NULL;
list_optflags = 0;
}
} else {
if (lcurrent->next && legal_number(lcurrent->next->word->word, (intmax_t *)0)) {
lcurrent = lcurrent->next;
list_optarg = lcurrent->word->word;
list_optflags = lcurrent->word->flags;
lcurrent = lcurrent->next;
} else {
errstr[1] = c;
sh_neednumarg (errstr);
sp = 1;
list_optarg = (char *)NULL;
list_optflags = 0;
return ('?');
}
}
} else {
/* No argument, just return the option. */
if (lcurrent->word->word[++sp] == '\0') {
sp = 1;
lcurrent = lcurrent->next;
}
list_optarg = (char *)NULL;
list_optflags = 0;
}
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;
}

43
builtins/bashgetopt.h Normal file
View file

@ -0,0 +1,43 @@
/* bashgetopt.h -- extern declarations for stuff defined in bashgetopt.c. */
/* Copyright (C) 1993-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
/* See getopt.h for the explanation of these variables. */
#if !defined (__BASH_GETOPT_H)
# define __BASH_GETOPT_H
#include <stdc.h>
#define GETOPT_EOF -1
#define GETOPT_HELP -99
extern char *list_optarg;
extern int list_optflags;
extern int list_optopt;
extern int list_opttype;
extern WORD_LIST *lcurrent;
extern WORD_LIST *loptend;
extern int internal_getopt PARAMS((WORD_LIST *, char *));
extern void reset_internal_getopt PARAMS((void));
#endif /* !__BASH_GETOPT_H */

405
builtins/bind.def Normal file
View file

@ -0,0 +1,405 @@
This file is bind.def, from which is created bind.c.
It implements the builtin "bind" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES bind.c
#include <config.h>
$BUILTIN bind
$DEPENDS_ON READLINE
$FUNCTION bind_builtin
$SHORT_DOC bind [-lpsvPSVX] [-m keymap] [-f filename] [-q name] [-u name] [-r keyseq] [-x keyseq:shell-command] [keyseq:readline-function or readline-command]
Set Readline key bindings and variables.
Bind a key sequence to a Readline function or a macro, or set a
Readline variable. The non-option argument syntax is equivalent to
that found in ~/.inputrc, but must be passed as a single argument:
e.g., bind '"\C-x\C-r": re-read-init-file'.
Options:
-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.
-P List function names and bindings.
-p List functions and bindings in a form that can be
reused as input.
-S List key sequences that invoke macros and their values
-s List key sequences that invoke macros and their values
in a form that can be reused as input.
-V List variable names and values
-v List variable names and values in a form that can
be reused as input.
-q function-name Query about which keys invoke the named function.
-u function-name Unbind all keys which are bound to the named function.
-r keyseq Remove the binding for KEYSEQ.
-f filename Read key bindings from FILENAME.
-x keyseq:shell-command Cause SHELL-COMMAND to be executed when
KEYSEQ is entered.
-X List key sequences bound with -x and associated commands
in a form that can be reused as input.
Exit Status:
bind returns 0 unless an unrecognized option is given or an error occurs.
$END
#if defined (READLINE)
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include <errno.h>
#if !defined (errno)
extern int errno;
#endif /* !errno */
#include <readline/readline.h>
#include <readline/history.h>
#include "../bashintl.h"
#include "../shell.h"
#include "../bashline.h"
#include "bashgetopt.h"
#include "common.h"
static int query_bindings PARAMS((char *));
static int unbind_command PARAMS((char *));
static int unbind_keyseq PARAMS((char *));
#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0)
#define LFLAG 0x0001
#define PFLAG 0x0002
#define FFLAG 0x0004
#define VFLAG 0x0008
#define QFLAG 0x0010
#define MFLAG 0x0020
#define RFLAG 0x0040
#define PPFLAG 0x0080
#define VVFLAG 0x0100
#define SFLAG 0x0200
#define SSFLAG 0x0400
#define UFLAG 0x0800
#define XFLAG 0x1000
#define XXFLAG 0x2000
int
bind_builtin (list)
WORD_LIST *list;
{
int return_code;
Keymap kmap, saved_keymap;
int flags, opt;
char *initfile, *map_name, *fun_name, *unbind_name, *remove_seq, *cmd_seq, *t;
if (no_line_editing)
{
#if 0
builtin_error (_("line editing not enabled"));
return (EXECUTION_FAILURE);
#else
builtin_warning (_("line editing not enabled"));
#endif
}
kmap = saved_keymap = (Keymap) NULL;
flags = 0;
initfile = map_name = fun_name = unbind_name = remove_seq = cmd_seq = (char *)NULL;
return_code = EXECUTION_SUCCESS;
if (bash_readline_initialized == 0)
initialize_readline ();
begin_unwind_frame ("bind_builtin");
unwind_protect_var (rl_outstream);
rl_outstream = stdout;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "lvpVPsSXf:q:u:m:r:x:")) != -1)
{
switch (opt)
{
case 'l':
flags |= LFLAG;
break;
case 'v':
flags |= VFLAG;
break;
case 'p':
flags |= PFLAG;
break;
case 'f':
flags |= FFLAG;
initfile = list_optarg;
break;
case 'm':
flags |= MFLAG;
map_name = list_optarg;
break;
case 'q':
flags |= QFLAG;
fun_name = list_optarg;
break;
case 'u':
flags |= UFLAG;
unbind_name = list_optarg;
break;
case 'r':
flags |= RFLAG;
remove_seq = list_optarg;
break;
case 'V':
flags |= VVFLAG;
break;
case 'P':
flags |= PPFLAG;
break;
case 's':
flags |= SFLAG;
break;
case 'S':
flags |= SSFLAG;
break;
case 'x':
flags |= XFLAG;
cmd_seq = list_optarg;
break;
case 'X':
flags |= XXFLAG;
break;
case GETOPT_HELP:
default:
builtin_usage ();
BIND_RETURN (EX_USAGE);
}
}
list = loptend;
/* First, see if we need to install a special keymap for this
command. Then start on the arguments. */
if ((flags & MFLAG) && map_name)
{
kmap = rl_get_keymap_by_name (map_name);
if (kmap == 0)
{
builtin_error (_("`%s': invalid keymap name"), map_name);
BIND_RETURN (EXECUTION_FAILURE);
}
}
if (kmap)
{
saved_keymap = rl_get_keymap ();
rl_set_keymap (kmap);
}
/* XXX - we need to add exclusive use tests here. It doesn't make sense
to use some of these options together. */
/* Now hack the option arguments */
if (flags & LFLAG)
rl_list_funmap_names ();
if (flags & PFLAG)
rl_function_dumper (1);
if (flags & PPFLAG)
rl_function_dumper (0);
if (flags & SFLAG)
rl_macro_dumper (1);
if (flags & SSFLAG)
rl_macro_dumper (0);
if (flags & VFLAG)
rl_variable_dumper (1);
if (flags & VVFLAG)
rl_variable_dumper (0);
if ((flags & FFLAG) && initfile)
{
if (rl_read_init_file (initfile) != 0)
{
t = printable_filename (initfile, 0);
builtin_error (_("%s: cannot read: %s"), t, strerror (errno));
if (t != initfile)
free (t);
BIND_RETURN (EXECUTION_FAILURE);
}
}
if ((flags & QFLAG) && fun_name)
return_code = query_bindings (fun_name);
if ((flags & UFLAG) && unbind_name)
return_code = unbind_command (unbind_name);
if ((flags & RFLAG) && remove_seq)
{
opt = unbind_keyseq (remove_seq);
BIND_RETURN (opt);
}
if (flags & XFLAG)
return_code = bind_keyseq_to_unix_command (cmd_seq);
if (flags & XXFLAG)
return_code = print_unix_command_map ();
/* Process the rest of the arguments as binding specifications. */
while (list)
{
int olen, nlen, d, i;
char **obindings, **nbindings;
obindings = rl_invoking_keyseqs (bash_execute_unix_command);
olen = obindings ? strvec_len (obindings) : 0;
rl_parse_and_bind (list->word->word);
nbindings = rl_invoking_keyseqs (bash_execute_unix_command);
nlen = nbindings ? strvec_len (nbindings) : 0;
if (nlen < olen) /* fewer bind -x bindings */
for (d = olen - nlen, i = 0; i < olen && d > 0; i++)
if (nlen == 0 || strvec_search (nbindings, obindings[i]) < 0)
{
unbind_unix_command (obindings[i]);
d--;
}
strvec_dispose (obindings);
strvec_dispose (nbindings);
list = list->next;
}
bind_exit:
if (saved_keymap)
rl_set_keymap (saved_keymap);
run_unwind_frame ("bind_builtin");
if (return_code < 0)
return_code = EXECUTION_FAILURE;
return (sh_chkwrite (return_code));
}
static int
query_bindings (name)
char *name;
{
rl_command_func_t *function;
char **keyseqs;
int j;
function = rl_named_function (name);
if (function == 0)
{
builtin_error (_("`%s': unknown function name"), name);
return EXECUTION_FAILURE;
}
keyseqs = rl_invoking_keyseqs (function);
if (!keyseqs)
{
printf (_("%s is not bound to any keys.\n"), name);
return EXECUTION_FAILURE;
}
printf (_("%s can be invoked via "), name);
for (j = 0; j < 5 && keyseqs[j]; j++)
printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n");
if (keyseqs[j])
printf ("...\n");
strvec_dispose (keyseqs);
return EXECUTION_SUCCESS;
}
static int
unbind_command (name)
char *name;
{
rl_command_func_t *function;
function = rl_named_function (name);
if (function == 0)
{
builtin_error (_("`%s': unknown function name"), name);
return EXECUTION_FAILURE;
}
rl_unbind_function_in_map (function, rl_get_keymap ());
return EXECUTION_SUCCESS;
}
static int
unbind_keyseq (seq)
char *seq;
{
char *kseq;
int kslen, type;
rl_command_func_t *f;
kseq = (char *)xmalloc ((2 * strlen (seq)) + 1);
if (rl_translate_keyseq (seq, kseq, &kslen))
{
free (kseq);
builtin_error (_("`%s': cannot unbind"), seq);
return EXECUTION_FAILURE;
}
if ((f = rl_function_of_keyseq_len (kseq, kslen, (Keymap)0, &type)) == 0)
{
free (kseq);
return (EXECUTION_SUCCESS);
}
if (type == ISKMAP)
f = ((Keymap) f)[ANYOTHERKEY].function;
/* I wish this didn't have to translate the key sequence again, but readline
doesn't have a binding function that takes a translated key sequence as
an argument. */
if (rl_bind_keyseq (seq, (rl_command_func_t *)NULL) != 0)
{
free (kseq);
builtin_error (_("`%s': cannot unbind"), seq);
return (EXECUTION_FAILURE);
}
if (f == bash_execute_unix_command)
unbind_unix_command (seq);
free (kseq);
return (EXECUTION_SUCCESS);
}
#endif /* READLINE */

143
builtins/break.def Normal file
View file

@ -0,0 +1,143 @@
This file is break.def, from which is created break.c.
It implements the builtins "break" and "continue" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES break.c
$BUILTIN break
$FUNCTION break_builtin
$SHORT_DOC break [n]
Exit for, while, or until loops.
Exit a FOR, WHILE or UNTIL loop. If N is specified, break N enclosing
loops.
Exit Status:
The exit status is 0 unless N is not greater than or equal to 1.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "common.h"
static int check_loop_level PARAMS((void));
/* The depth of while's and until's. */
int loop_level = 0;
/* Non-zero when a "break" instruction is encountered. */
int breaking = 0;
/* Non-zero when we have encountered a continue instruction. */
int continuing = 0;
/* Set up to break x levels, where x defaults to 1, but can be specified
as the first argument. */
int
break_builtin (list)
WORD_LIST *list;
{
intmax_t newbreak;
CHECK_HELPOPT (list);
if (check_loop_level () == 0)
return (EXECUTION_SUCCESS);
(void)get_numeric_arg (list, 1, &newbreak);
if (newbreak <= 0)
{
sh_erange (list->word->word, _("loop count"));
breaking = loop_level;
return (EXECUTION_FAILURE);
}
if (newbreak > loop_level)
newbreak = loop_level;
breaking = newbreak;
return (EXECUTION_SUCCESS);
}
$BUILTIN continue
$FUNCTION continue_builtin
$SHORT_DOC continue [n]
Resume for, while, or until loops.
Resumes the next iteration of the enclosing FOR, WHILE or UNTIL loop.
If N is specified, resumes the Nth enclosing loop.
Exit Status:
The exit status is 0 unless N is not greater than or equal to 1.
$END
/* Set up to continue x levels, where x defaults to 1, but can be specified
as the first argument. */
int
continue_builtin (list)
WORD_LIST *list;
{
intmax_t newcont;
CHECK_HELPOPT (list);
if (check_loop_level () == 0)
return (EXECUTION_SUCCESS);
(void)get_numeric_arg (list, 1, &newcont);
if (newcont <= 0)
{
sh_erange (list->word->word, _("loop count"));
breaking = loop_level;
return (EXECUTION_FAILURE);
}
if (newcont > loop_level)
newcont = loop_level;
continuing = newcont;
return (EXECUTION_SUCCESS);
}
/* Return non-zero if a break or continue command would be okay.
Print an error message if break or continue is meaningless here. */
static int
check_loop_level ()
{
#if defined (BREAK_COMPLAINS)
if (loop_level == 0 && posixly_correct == 0)
builtin_error (_("only meaningful in a `for', `while', or `until' loop"));
#endif /* BREAK_COMPLAINS */
return (loop_level);
}

85
builtins/builtin.def Normal file
View file

@ -0,0 +1,85 @@
This file is builtin.def, from which is created builtin.c.
It implements the builtin "builtin" in Bash.
Copyright (C) 1987-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES builtin.c
$BUILTIN builtin
$FUNCTION builtin_builtin
$SHORT_DOC builtin [shell-builtin [arg ...]]
Execute shell builtins.
Execute SHELL-BUILTIN with arguments ARGs without performing command
lookup. This is useful when you wish to reimplement a shell builtin
as a shell function, but need to execute the builtin within the function.
Exit Status:
Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is
not a shell builtin.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../shell.h"
#include "../execute_cmd.h"
#include "common.h"
#include "bashgetopt.h"
/* Run the command mentioned in list directly, without going through the
normal alias/function/builtin/filename lookup process. */
int
builtin_builtin (list)
WORD_LIST *list;
{
sh_builtin_func_t *function;
register char *command;
if (no_options (list))
return (EX_USAGE);
list = loptend; /* skip over possible `--' */
if (list == 0)
return (EXECUTION_SUCCESS);
command = list->word->word;
#if defined (DISABLED_BUILTINS)
function = builtin_address (command);
#else /* !DISABLED_BUILTINS */
function = find_shell_builtin (command);
#endif /* !DISABLED_BUILTINS */
if (function == 0)
{
sh_notbuiltin (command);
return (EXECUTION_FAILURE);
}
else
{
this_command_name = command;
this_shell_builtin = function; /* overwrite "builtin" as this builtin */
list = list->next;
return ((*function) (list));
}
}

156
builtins/caller.def Normal file
View file

@ -0,0 +1,156 @@
This file is caller.def, from which is created caller.c. It implements the
builtin "caller" in Bash.
Copyright (C) 2002-2008 Rocky Bernstein for Free Software Foundation, Inc.
Copyright (C) 2008-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES caller.c
$BUILTIN caller
$FUNCTION caller_builtin
$DEPENDS_ON DEBUGGER
$SHORT_DOC caller [expr]
Return the context of the current subroutine call.
Without EXPR, returns "$line $filename". With EXPR, returns
"$line $subroutine $filename"; this extra information can be used to
provide a stack trace.
The value of EXPR indicates how many call frames to go back before the
current one; the top frame is frame 0.
Exit Status:
Returns 0 unless the shell is not executing a shell function or EXPR
is invalid.
$END
#include <config.h>
#include <stdio.h>
#include "chartypes.h"
#include "bashtypes.h"
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <errno.h>
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "builtext.h"
#include "bashgetopt.h"
#ifdef LOADABLE_BUILTIN
# include "builtins.h"
#endif
#if !defined (errno)
extern int errno;
#endif /* !errno */
int
caller_builtin (list)
WORD_LIST *list;
{
#if !defined (ARRAY_VARS)
printf ("1 NULL\n");
return (EXECUTION_FAILURE);
#else
SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
char *funcname_s, *source_s, *lineno_s;
intmax_t num;
CHECK_HELPOPT (list);
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
if (bash_lineno_a == 0 || array_empty (bash_lineno_a))
return (EXECUTION_FAILURE);
if (bash_source_a == 0 || array_empty (bash_source_a))
return (EXECUTION_FAILURE);
if (no_options (list))
return (EX_USAGE);
list = loptend; /* skip over possible `--' */
/* If there is no argument list, then give short form: line filename. */
if (list == 0)
{
lineno_s = array_reference (bash_lineno_a, 0);
source_s = array_reference (bash_source_a, 1);
printf("%s %s\n", lineno_s ? lineno_s : "NULL", source_s ? source_s : "NULL");
return (EXECUTION_SUCCESS);
}
if (funcname_a == 0 || array_empty (funcname_a))
return (EXECUTION_FAILURE);
if (legal_number (list->word->word, &num))
{
lineno_s = array_reference (bash_lineno_a, num);
source_s = array_reference (bash_source_a, num+1);
funcname_s = array_reference (funcname_a, num+1);
if (lineno_s == NULL|| source_s == NULL || funcname_s == NULL)
return (EXECUTION_FAILURE);
printf("%s %s %s\n", lineno_s, funcname_s, source_s);
}
else
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
return (EXECUTION_SUCCESS);
#endif
}
#ifdef LOADABLE_BUILTIN
static char *caller_doc[] = {
N_("Returns the context of the current subroutine call.\n\
\n\
Without EXPR, returns \"$line $filename\". With EXPR, returns\n\
\"$line $subroutine $filename\"; this extra information can be used to\n\
provide a stack trace.\n\
\n\
The value of EXPR indicates how many call frames to go back before the\n\
current one; the top frame is frame 0."),
(char *)NULL
};
struct builtin caller_struct = {
"caller",
caller_builtin,
BUILTIN_ENABLED,
caller_doc,
"caller [EXPR]",
0
};
#endif /* LOADABLE_BUILTIN */

685
builtins/cd.def Normal file
View file

@ -0,0 +1,685 @@
This file is cd.def, from which is created cd.c. It implements the
builtins "cd" and "pwd" in Bash.
Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES cd.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include "posixdir.h"
#include "posixstat.h"
#if defined (HAVE_SYS_PARAM_H)
#include <sys/param.h>
#endif
#include <fcntl.h>
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "../flags.h"
#include "maxpath.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern const char * const bash_getcwd_errstr;
static int bindpwd PARAMS((int));
static int setpwd PARAMS((char *));
static char *resetpwd PARAMS((char *));
static int change_to_directory PARAMS((char *, int, int));
static int cdxattr PARAMS((char *, char **));
static void resetxattr PARAMS((void));
/* Change this to 1 to get cd spelling correction by default. */
int cdspelling = 0;
int cdable_vars;
static int eflag; /* file scope so bindpwd() can see it */
static int xattrflag; /* O_XATTR support for openat */
static int xattrfd = -1;
$BUILTIN cd
$FUNCTION cd_builtin
$SHORT_DOC cd [-L|[-P [-e]] [-@]] [dir]
Change the shell working directory.
Change the current directory to DIR. The default DIR is the value of the
HOME shell variable. If DIR is "-", it is converted to $OLDPWD.
The variable CDPATH defines the search path for the directory containing
DIR. Alternative directory names in CDPATH are separated by a colon (:).
A null directory name is the same as the current directory. If DIR begins
with a slash (/), then CDPATH is not used.
If the directory is not found, and the shell option `cdable_vars' is set,
the word is assumed to be a variable name. If that variable has a value,
its value is used for DIR.
Options:
-L force symbolic links to be followed: resolve symbolic
links in DIR after processing instances of `..'
-P use the physical directory structure without following
symbolic links: resolve symbolic links in DIR before
processing instances of `..'
-e if the -P option is supplied, and the current working
directory cannot be determined successfully, exit with
a non-zero status
#if defined (O_XATTR)
-@ on systems that support it, present a file with extended
attributes as a directory containing the file attributes
#endif
The default is to follow symbolic links, as if `-L' were specified.
`..' is processed by removing the immediately previous pathname component
back to a slash or the beginning of DIR.
Exit Status:
Returns 0 if the directory is changed, and if $PWD is set successfully when
-P is used; non-zero otherwise.
$END
/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
static int
setpwd (dirname)
char *dirname;
{
int old_anm;
SHELL_VAR *tvar;
old_anm = array_needs_making;
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
if (tvar && readonly_p (tvar))
return EXECUTION_FAILURE;
if (tvar && old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
array_needs_making = 0;
}
return EXECUTION_SUCCESS;
}
static int
bindpwd (no_symlinks)
int no_symlinks;
{
char *dirname, *pwdvar;
int old_anm, r, canon_failed;
SHELL_VAR *tvar;
r = sh_chkwrite (EXECUTION_SUCCESS);
#define tcwd the_current_working_directory
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("cd");
#undef tcwd
/* If canonicalization fails, reset dirname to the_current_working_directory */
canon_failed = 0;
if (dirname == 0)
{
canon_failed = 1;
dirname = the_current_working_directory;
}
old_anm = array_needs_making;
pwdvar = get_string_value ("PWD");
tvar = bind_variable ("OLDPWD", pwdvar, 0);
if (tvar && readonly_p (tvar))
r = EXECUTION_FAILURE;
if (old_anm == 0 && array_needs_making && exported_p (tvar))
{
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
array_needs_making = 0;
}
if (setpwd (dirname) == EXECUTION_FAILURE)
r = EXECUTION_FAILURE;
if (canon_failed && eflag)
r = EXECUTION_FAILURE;
if (dirname && dirname != the_current_working_directory)
free (dirname);
return (r);
}
/* Call get_working_directory to reset the value of
the_current_working_directory () */
static char *
resetpwd (caller)
char *caller;
{
char *tdir;
FREE (the_current_working_directory);
the_current_working_directory = (char *)NULL;
tdir = get_working_directory (caller);
return (tdir);
}
static int
cdxattr (dir, ndirp)
char *dir; /* don't assume we can always free DIR */
char **ndirp; /* return new constructed directory name */
{
#if defined (O_XATTR)
int apfd, fd, r, e;
char buf[11+40+40]; /* construct new `fake' path for pwd */
apfd = openat (AT_FDCWD, dir, O_RDONLY|O_NONBLOCK);
if (apfd < 0)
return -1;
fd = openat (apfd, ".", O_XATTR);
e = errno;
close (apfd); /* ignore close error for now */
errno = e;
if (fd < 0)
return -1;
r = fchdir (fd); /* assume fchdir exists everywhere with O_XATTR */
if (r < 0)
{
close (fd);
return -1;
}
/* NFSv4 and ZFS extended attribute directories do not have names which are
visible in the standard Unix directory tree structure. To ensure we have
a valid name for $PWD, we synthesize one under /proc, but to keep that
path valid, we need to keep the file descriptor open as long as we are in
this directory. This imposes a certain structure on /proc. */
if (ndirp)
{
sprintf (buf, "/proc/%d/fd/%d", getpid(), fd);
*ndirp = savestring (buf);
}
if (xattrfd >= 0)
close (xattrfd);
xattrfd = fd;
return r;
#else
return -1;
#endif
}
/* Clean up the O_XATTR baggage. Currently only closes xattrfd */
static void
resetxattr ()
{
#if defined (O_XATTR)
if (xattrfd >= 0)
{
close (xattrfd);
xattrfd = -1;
}
#else
xattrfd = -1; /* not strictly necessary */
#endif
}
#define LCD_DOVARS 0x001
#define LCD_DOSPELL 0x002
#define LCD_PRINTPATH 0x004
#define LCD_FREEDIRNAME 0x008
/* This builtin is ultimately the way that all user-visible commands should
change the current working directory. It is called by cd_to_string (),
so the programming interface is simple, and it handles errors and
restrictions properly. */
int
cd_builtin (list)
WORD_LIST *list;
{
char *dirname, *cdpath, *path, *temp;
int path_index, no_symlinks, opt, lflag, e;
#if defined (RESTRICTED_SHELL)
if (restricted)
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif /* RESTRICTED_SHELL */
eflag = 0;
no_symlinks = no_symbolic_links;
xattrflag = 0;
reset_internal_getopt ();
#if defined (O_XATTR)
while ((opt = internal_getopt (list, "eLP@")) != -1)
#else
while ((opt = internal_getopt (list, "eLP")) != -1)
#endif
{
switch (opt)
{
case 'P':
no_symlinks = 1;
break;
case 'L':
no_symlinks = 0;
break;
case 'e':
eflag = 1;
break;
#if defined (O_XATTR)
case '@':
xattrflag = 1;
break;
#endif
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
lflag = (cdable_vars ? LCD_DOVARS : 0) |
((interactive && cdspelling) ? LCD_DOSPELL : 0);
if (eflag && no_symlinks == 0)
eflag = 0;
if (list == 0)
{
/* `cd' without arguments is equivalent to `cd $HOME' */
dirname = get_string_value ("HOME");
if (dirname == 0)
{
builtin_error (_("HOME not set"));
return (EXECUTION_FAILURE);
}
lflag = 0;
}
#if defined (CD_COMPLAINS)
else if (list->next)
{
builtin_error (_("too many arguments"));
return (EXECUTION_FAILURE);
}
#endif
#if 0
else if (list->word->word[0] == '\0')
{
builtin_error (_("null directory"));
return (EXECUTION_FAILURE);
}
#endif
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
{
/* This is `cd -', equivalent to `cd $OLDPWD' */
dirname = get_string_value ("OLDPWD");
if (dirname == 0)
{
builtin_error (_("OLDPWD not set"));
return (EXECUTION_FAILURE);
}
#if 0
lflag = interactive ? LCD_PRINTPATH : 0;
#else
lflag = LCD_PRINTPATH; /* According to SUSv3 */
#endif
}
else if (absolute_pathname (list->word->word))
dirname = list->word->word;
else if (privileged_mode == 0 && (cdpath = get_string_value ("CDPATH")))
{
dirname = list->word->word;
/* Find directory in $CDPATH. */
path_index = 0;
while (path = extract_colon_unit (cdpath, &path_index))
{
/* OPT is 1 if the path element is non-empty */
opt = path[0] != '\0';
temp = sh_makepath (path, dirname, MP_DOTILDE);
free (path);
if (change_to_directory (temp, no_symlinks, xattrflag))
{
/* POSIX.2 says that if a nonempty directory from CDPATH
is used to find the directory to change to, the new
directory name is echoed to stdout, whether or not
the shell is interactive. */
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
printf ("%s\n", path);
free (temp);
#if 0
/* Posix.2 says that after using CDPATH, the resultant
value of $PWD will not contain `.' or `..'. */
return (bindpwd (posixly_correct || no_symlinks));
#else
return (bindpwd (no_symlinks));
#endif
}
else
free (temp);
}
#if 0
/* changed for bash-4.2 Posix cd description steps 5-6 */
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
try the current directory, so we just punt now with an error
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
is so we don't mistakenly treat a CDPATH value of "" as not
specifying the current directory. */
if (posixly_correct && cdpath[0])
{
builtin_error ("%s: %s", dirname, strerror (ENOENT));
return (EXECUTION_FAILURE);
}
#endif
}
else
dirname = list->word->word;
/* When we get here, DIRNAME is the directory to change to. If we
chdir successfully, just return. */
if (change_to_directory (dirname, no_symlinks, xattrflag))
{
if (lflag & LCD_PRINTPATH)
printf ("%s\n", dirname);
return (bindpwd (no_symlinks));
}
/* If the user requests it, then perhaps this is the name of
a shell variable, whose value contains the directory to
change to. */
if (lflag & LCD_DOVARS)
{
temp = get_string_value (dirname);
if (temp && change_to_directory (temp, no_symlinks, xattrflag))
{
printf ("%s\n", temp);
return (bindpwd (no_symlinks));
}
}
/* If the user requests it, try to find a directory name similar in
spelling to the one requested, in case the user made a simple
typo. This is similar to the UNIX 8th and 9th Edition shells. */
if (lflag & LCD_DOSPELL)
{
temp = dirspell (dirname);
if (temp && change_to_directory (temp, no_symlinks, xattrflag))
{
printf ("%s\n", temp);
free (temp);
return (bindpwd (no_symlinks));
}
else
FREE (temp);
}
e = errno;
temp = printable_filename (dirname, 0);
builtin_error ("%s: %s", temp, strerror (e));
if (temp != dirname)
free (temp);
return (EXECUTION_FAILURE);
}
$BUILTIN pwd
$FUNCTION pwd_builtin
$SHORT_DOC pwd [-LP]
Print the name of the current working directory.
Options:
-L print the value of $PWD if it names the current working
directory
-P print the physical directory, without any symbolic links
By default, `pwd' behaves as if `-L' were specified.
Exit Status:
Returns 0 unless an invalid option is given or the current directory
cannot be read.
$END
/* Non-zero means that pwd always prints the physical directory, without
symbolic links. */
static int verbatim_pwd;
/* Print the name of the current working directory. */
int
pwd_builtin (list)
WORD_LIST *list;
{
char *directory;
int opt, pflag;
verbatim_pwd = no_symbolic_links;
pflag = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "LP")) != -1)
{
switch (opt)
{
case 'P':
verbatim_pwd = pflag = 1;
break;
case 'L':
verbatim_pwd = 0;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
#define tcwd the_current_working_directory
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
: get_working_directory ("pwd");
/* Try again using getcwd() if canonicalization fails (for instance, if
the file system has changed state underneath bash). */
if ((tcwd && directory == 0) ||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
{
if (directory && directory != tcwd)
free (directory);
directory = resetpwd ("pwd");
}
#undef tcwd
if (directory)
{
opt = EXECUTION_SUCCESS;
printf ("%s\n", directory);
/* This is dumb but posix-mandated. */
if (posixly_correct && pflag)
opt = setpwd (directory);
if (directory != the_current_working_directory)
free (directory);
return (sh_chkwrite (opt));
}
else
return (EXECUTION_FAILURE);
}
/* Do the work of changing to the directory NEWDIR. Handle symbolic
link following, etc. This function *must* return with
the_current_working_directory either set to NULL (in which case
getcwd() will eventually be called), or set to a string corresponding
to the working directory. Return 1 on success, 0 on failure. */
static int
change_to_directory (newdir, nolinks, xattr)
char *newdir;
int nolinks, xattr;
{
char *t, *tdir, *ndir;
int err, canon_failed, r, ndlen;
tdir = (char *)NULL;
if (the_current_working_directory == 0)
{
t = get_working_directory ("chdir");
FREE (t);
}
t = make_absolute (newdir, the_current_working_directory);
/* TDIR is either the canonicalized absolute pathname of NEWDIR
(nolinks == 0) or the absolute physical pathname of NEWDIR
(nolinks != 0). */
tdir = nolinks ? sh_physpath (t, 0)
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
ndlen = strlen (newdir);
/* Use the canonicalized version of NEWDIR, or, if canonicalization
failed, use the non-canonical form. */
canon_failed = 0;
if (tdir && *tdir)
free (t);
else
{
FREE (tdir);
tdir = t;
canon_failed = 1;
}
/* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
returns NULL (because it checks the path, it will return NULL if the
resolved path doesn't exist), fail immediately. */
#if defined (ENAMETOOLONG)
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
#else
if (posixly_correct && nolinks == 0 && canon_failed && ndlen > PATH_MAX)
#endif
{
#if defined ENAMETOOLONG
if (errno != ENOENT && errno != ENAMETOOLONG)
#else
if (errno != ENOENT)
#endif
errno = ENOTDIR;
free (tdir);
return (0);
}
#if defined (O_XATTR)
if (xattrflag)
{
r = cdxattr (nolinks ? newdir : tdir, &ndir);
if (r >= 0)
{
canon_failed = 0;
free (tdir);
tdir = ndir;
}
else
{
err = errno;
free (tdir);
errno = err;
return (0); /* no xattr */
}
}
else
#endif
{
r = chdir (nolinks ? newdir : tdir);
if (r >= 0)
resetxattr ();
}
/* If the chdir succeeds, update the_current_working_directory. */
if (r == 0)
{
/* If canonicalization failed, but the chdir succeeded, reset the
shell's idea of the_current_working_directory. */
if (canon_failed)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
else
free (t);
}
else
set_working_directory (tdir);
free (tdir);
return (1);
}
/* We failed to change to the appropriate directory name. If we tried
what the user passed (nolinks != 0), punt now. */
if (nolinks)
{
free (tdir);
return (0);
}
err = errno;
/* We're not in physical mode (nolinks == 0), but we failed to change to
the canonicalized directory name (TDIR). Try what the user passed
verbatim. If we succeed, reinitialize the_current_working_directory.
POSIX requires that we just fail here, so we do in posix mode. */
if (posixly_correct == 0 && chdir (newdir) == 0)
{
t = resetpwd ("cd");
if (t == 0)
set_working_directory (tdir);
else
free (t);
r = 1;
}
else
{
errno = err;
r = 0;
}
free (tdir);
return r;
}

76
builtins/colon.def Normal file
View file

@ -0,0 +1,76 @@
This file is colon.def, from which is created colon.c.
It implements the builtin ":" in Bash.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES colon.c
$BUILTIN :
$DOCNAME colon
$FUNCTION colon_builtin
$SHORT_DOC :
Null command.
No effect; the command does nothing.
Exit Status:
Always succeeds.
$END
$BUILTIN true
$FUNCTION colon_builtin
$SHORT_DOC true
Return a successful result.
Exit Status:
Always succeeds.
$END
$BUILTIN false
$FUNCTION false_builtin
$SHORT_DOC false
Return an unsuccessful result.
Exit Status:
Always fails.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../shell.h"
/* Return a successful result. */
int
colon_builtin (ignore)
WORD_LIST *ignore;
{
return (0);
}
/* Return an unsuccessful result. */
int
false_builtin (ignore)
WORD_LIST *ignore;
{
return (1);
}

143
builtins/command.def Normal file
View file

@ -0,0 +1,143 @@
This file is command.def, from which is created command.c.
It implements the builtin "command" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES command.c
$BUILTIN command
$FUNCTION command_builtin
$SHORT_DOC command [-pVv] command [arg ...]
Execute a simple command or display information about commands.
Runs COMMAND with ARGS suppressing shell function lookup, or display
information about the specified COMMANDs. Can be used to invoke commands
on disk when a function with the same name exists.
Options:
-p use a default value for PATH that is guaranteed to find all of
the standard utilities
-v print a description of COMMAND similar to the `type' builtin
-V print a more verbose description of each COMMAND
Exit Status:
Returns exit status of COMMAND, or failure if COMMAND is not found.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../flags.h"
#include "bashgetopt.h"
#include "common.h"
#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
extern size_t confstr PARAMS((int, char *, size_t));
#endif
/* Run the commands mentioned in LIST without paying attention to shell
functions. */
int
command_builtin (list)
WORD_LIST *list;
{
int result, verbose, use_standard_path, opt;
COMMAND *command;
verbose = use_standard_path = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "pvV")) != -1)
{
switch (opt)
{
case 'p':
use_standard_path = CDESC_STDPATH;
break;
case 'V':
verbose = CDESC_SHORTDESC|CDESC_ABSPATH; /* look in common.h for constants */
break;
case 'v':
verbose = CDESC_REUSABLE; /* ditto */
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
return (EXECUTION_SUCCESS);
#if defined (RESTRICTED_SHELL)
if (use_standard_path && restricted)
{
sh_restricted ("-p");
return (EXECUTION_FAILURE);
}
#endif
if (verbose)
{
int found, any_found;
for (any_found = 0; list; list = list->next)
{
found = describe_command (list->word->word, verbose|use_standard_path);
if (found == 0 && verbose != CDESC_REUSABLE)
sh_notfound (list->word->word);
any_found += found;
}
return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
begin_unwind_frame ("command_builtin");
#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0))
INTERNAL_DEBUG (("command_builtin: running execute_command for `%s'", list->word->word));
/* We don't want this to be reparsed (consider command echo 'foo &'), so
just make a simple_command structure and call execute_command with it. */
command = make_bare_simple_command ();
command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
command->value.Simple->redirects = (REDIRECT *)NULL;
command->flags |= COMMAND_BUILTIN_FLAGS;
command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
add_unwind_protect ((char *)dispose_command, command);
result = execute_command (command);
run_unwind_frame ("command_builtin");
return (result);
}

1131
builtins/common.c Normal file

File diff suppressed because it is too large Load diff

289
builtins/common.h Normal file
View file

@ -0,0 +1,289 @@
/* common.h -- extern declarations for functions defined in common.c. */
/* Copyright (C) 1993-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#if !defined (__COMMON_H)
# define __COMMON_H
#include "stdc.h"
#define ISOPTION(s, c) (s[0] == '-' && s[1] == c && !s[2])
#define ISHELP(s) (STREQ ((s), "--help"))
#define CHECK_HELPOPT(l) \
do { \
if ((l) && (l)->word && ISHELP((l)->word->word)) \
{ \
builtin_help (); \
return (EX_USAGE); \
} \
} while (0)
#define CASE_HELPOPT \
case GETOPT_HELP: \
builtin_help (); \
return (EX_USAGE)
/* Flag values for parse_and_execute () and parse_string () */
#define SEVAL_NONINT 0x001
#define SEVAL_INTERACT 0x002
#define SEVAL_NOHIST 0x004
#define SEVAL_NOFREE 0x008
#define SEVAL_RESETLINE 0x010
#define SEVAL_PARSEONLY 0x020
#define SEVAL_NOLONGJMP 0x040
#define SEVAL_FUNCDEF 0x080 /* only allow function definitions */
#define SEVAL_ONECMD 0x100 /* only allow a single command */
#define SEVAL_NOHISTEXP 0x200 /* inhibit history expansion */
#define SEVAL_NOOPTIMIZE 0x400 /* don't try to set optimization flags */
/* Flags for describe_command, shared between type.def and command.def */
#define CDESC_ALL 0x001 /* type -a */
#define CDESC_SHORTDESC 0x002 /* command -V */
#define CDESC_REUSABLE 0x004 /* command -v */
#define CDESC_TYPE 0x008 /* type -t */
#define CDESC_PATH_ONLY 0x010 /* type -p */
#define CDESC_FORCE_PATH 0x020 /* type -ap or type -P */
#define CDESC_NOFUNCS 0x040 /* type -f */
#define CDESC_ABSPATH 0x080 /* convert to absolute path, no ./ */
#define CDESC_STDPATH 0x100 /* command -p */
/* Flags for get_job_by_name */
#define JM_PREFIX 0x01 /* prefix of job name */
#define JM_SUBSTRING 0x02 /* substring of job name */
#define JM_EXACT 0x04 /* match job name exactly */
#define JM_STOPPED 0x08 /* match stopped jobs only */
#define JM_FIRSTMATCH 0x10 /* return first matching job */
/* Flags for remember_args and value of changed_dollar_vars */
#define ARGS_NONE 0x0
#define ARGS_INVOC 0x01
#define ARGS_FUNC 0x02
#define ARGS_SETBLTIN 0x04
/* Maximum number of attribute letters */
#define MAX_ATTRIBUTES 16
/* Functions from common.c */
extern void builtin_error PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
extern void builtin_warning PARAMS((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
extern void builtin_usage PARAMS((void));
extern void no_args PARAMS((WORD_LIST *));
extern int no_options PARAMS((WORD_LIST *));
/* common error message functions */
extern void sh_needarg PARAMS((char *));
extern void sh_neednumarg PARAMS((char *));
extern void sh_notfound PARAMS((char *));
extern void sh_invalidopt PARAMS((char *));
extern void sh_invalidoptname PARAMS((char *));
extern void sh_invalidid PARAMS((char *));
extern void sh_invalidnum PARAMS((char *));
extern void sh_invalidsig PARAMS((char *));
extern void sh_readonly PARAMS((const char *));
extern void sh_noassign PARAMS((const char *));
extern void sh_erange PARAMS((char *, char *));
extern void sh_badpid PARAMS((char *));
extern void sh_badjob PARAMS((char *));
extern void sh_nojobs PARAMS((char *));
extern void sh_restricted PARAMS((char *));
extern void sh_notbuiltin PARAMS((char *));
extern void sh_wrerror PARAMS((void));
extern void sh_ttyerror PARAMS((int));
extern int sh_chkwrite PARAMS((int));
extern char **make_builtin_argv PARAMS((WORD_LIST *, int *));
extern void remember_args PARAMS((WORD_LIST *, int));
extern void shift_args PARAMS((int));
extern int number_of_args PARAMS((void));
extern int dollar_vars_changed PARAMS((void));
extern void set_dollar_vars_unchanged PARAMS((void));
extern void set_dollar_vars_changed PARAMS((void));
extern int get_numeric_arg PARAMS((WORD_LIST *, int, intmax_t *));
extern int get_exitstat PARAMS((WORD_LIST *));
extern int read_octal PARAMS((char *));
/* Keeps track of the current working directory. */
extern char *the_current_working_directory;
extern char *get_working_directory PARAMS((char *));
extern void set_working_directory PARAMS((char *));
#if defined (JOB_CONTROL)
extern int get_job_by_name PARAMS((const char *, int));
extern int get_job_spec PARAMS((WORD_LIST *));
#endif
extern int display_signal_list PARAMS((WORD_LIST *, int));
/* It's OK to declare a function as returning a Function * without
providing a definition of what a `Function' is. */
extern struct builtin *builtin_address_internal PARAMS((char *, int));
extern sh_builtin_func_t *find_shell_builtin PARAMS((char *));
extern sh_builtin_func_t *builtin_address PARAMS((char *));
extern sh_builtin_func_t *find_special_builtin PARAMS((char *));
extern void initialize_shell_builtins PARAMS((void));
#if defined (ARRAY_VARS)
extern int set_expand_once PARAMS((int, int));
#endif
/* Functions from exit.def */
extern void bash_logout PARAMS((void));
/* Functions from getopts.def */
extern void getopts_reset PARAMS((int));
/* Functions from help.def */
extern void builtin_help PARAMS((void));
/* Functions from read.def */
extern void read_tty_cleanup PARAMS((void));
extern int read_tty_modified PARAMS((void));
extern int read_builtin_timeout PARAMS((int));
extern void check_read_timeout PARAMS((void));
/* Functions from set.def */
extern int minus_o_option_value PARAMS((char *));
extern void list_minus_o_opts PARAMS((int, int));
extern char **get_minus_o_opts PARAMS((void));
extern int set_minus_o_option PARAMS((int, char *));
extern void set_shellopts PARAMS((void));
extern void parse_shellopts PARAMS((char *));
extern void initialize_shell_options PARAMS((int));
extern void reset_shell_options PARAMS((void));
extern char *get_current_options PARAMS((void));
extern void set_current_options PARAMS((const char *));
/* Functions from shopt.def */
extern void reset_shopt_options PARAMS((void));
extern char **get_shopt_options PARAMS((void));
extern int shopt_setopt PARAMS((char *, int));
extern int shopt_listopt PARAMS((char *, int));
extern int set_login_shell PARAMS((char *, int));
extern void set_bashopts PARAMS((void));
extern void parse_bashopts PARAMS((char *));
extern void initialize_bashopts PARAMS((int));
extern void set_compatibility_opts PARAMS((void));
/* Functions from type.def */
extern int describe_command PARAMS((char *, int));
/* Functions from setattr.def */
extern int set_or_show_attributes PARAMS((WORD_LIST *, int, int));
extern int show_all_var_attributes PARAMS((int, int));
extern int show_local_var_attributes PARAMS((int, int));
extern int show_var_attributes PARAMS((SHELL_VAR *, int, int));
extern int show_name_attributes PARAMS((char *, int));
extern int show_localname_attributes PARAMS((char *, int));
extern int show_func_attributes PARAMS((char *, int));
extern void set_var_attribute PARAMS((char *, int, int));
extern int var_attribute_string PARAMS((SHELL_VAR *, int, char *));
/* Functions from pushd.def */
extern char *get_dirstack_from_string PARAMS((char *));
extern char *get_dirstack_element PARAMS((intmax_t, int));
extern void set_dirstack_element PARAMS((intmax_t, int, char *));
extern WORD_LIST *get_directory_stack PARAMS((int));
/* Functions from evalstring.c */
extern int parse_and_execute PARAMS((char *, const char *, int));
extern int evalstring PARAMS((char *, const char *, int));
extern void parse_and_execute_cleanup PARAMS((int));
extern int parse_string PARAMS((char *, const char *, int, COMMAND **, char **));
extern int should_suppress_fork PARAMS((COMMAND *));
extern int can_optimize_connection PARAMS((COMMAND *));
extern int can_optimize_cat_file PARAMS((COMMAND *));
extern void optimize_connection_fork PARAMS((COMMAND *));
extern void optimize_subshell_command PARAMS((COMMAND *));
extern void optimize_shell_function PARAMS((COMMAND *));
/* Functions from evalfile.c */
extern int maybe_execute_file PARAMS((const char *, int));
extern int force_execute_file PARAMS((const char *, int));
extern int source_file PARAMS((const char *, int));
extern int fc_execute_file PARAMS((const char *));
/* variables from common.c */
extern sh_builtin_func_t *this_shell_builtin;
extern sh_builtin_func_t *last_shell_builtin;
extern SHELL_VAR *builtin_bind_variable PARAMS((char *, char *, int));
extern SHELL_VAR *builtin_bind_var_to_int PARAMS((char *, intmax_t, int));
extern int builtin_unbind_variable PARAMS((const char *));
extern SHELL_VAR *builtin_find_indexed_array PARAMS((char *, int));
extern int builtin_arrayref_flags PARAMS((WORD_DESC *, int));
/* variables from evalfile.c */
extern int sourcelevel;
/* variables from evalstring.c */
extern int parse_and_execute_level;
/* variables from break.def/continue.def */
extern int breaking;
extern int continuing;
extern int loop_level;
/* variables from shift.def */
extern int print_shift_error;
/* variables from shopt.def */
#if defined (ARRAY_VARS)
extern int expand_once_flag;
#endif
#if defined (EXTENDED_GLOB)
extern int extglob_flag;
#endif
extern int expaliases_flag;
/* variables from source.def */
extern int source_searches_cwd;
extern int source_uses_path;
/* variables from wait.def */
extern int wait_intr_flag;
/* common code to set flags for valid_array_reference and builtin_bind_variable */
#if defined (ARRAY_VARS)
#define SET_VFLAGS(wordflags, vflags, bindflags) \
do { \
vflags = assoc_expand_once ? VA_NOEXPAND : 0; \
bindflags = assoc_expand_once ? ASS_NOEXPAND : 0; \
if (assoc_expand_once && (wordflags & W_ARRAYREF)) \
vflags |= VA_ONEWORD|VA_NOEXPAND; \
if (vflags & VA_NOEXPAND) \
bindflags |= ASS_NOEXPAND; \
if (vflags & VA_ONEWORD) \
bindflags |= ASS_ONEWORD; \
} while (0)
#endif
#endif /* !__COMMON_H */

892
builtins/complete.def Normal file
View file

@ -0,0 +1,892 @@
This file is complete.def, from which is created complete.c.
It implements the builtins "complete", "compgen", and "compopt" in Bash.
Copyright (C) 1999-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES complete.c
$BUILTIN complete
$DEPENDS_ON PROGRAMMABLE_COMPLETION
$FUNCTION complete_builtin
$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-DEI] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
Specify how arguments are to be completed by Readline.
For each NAME, specify how arguments are to be completed. If no options
are supplied, existing completion specifications are printed in a way that
allows them to be reused as input.
Options:
-p print existing completion specifications in a reusable format
-r remove a completion specification for each NAME, or, if no
NAMEs are supplied, all completion specifications
-D apply the completions and actions as the default for commands
without any specific completion defined
-E apply the completions and actions to "empty" commands --
completion attempted on a blank line
-I apply the completions and actions to the initial (usually the
command) word
When completion is attempted, the actions are applied in the order the
uppercase-letter options are listed above. If multiple options are supplied,
the -D option takes precedence over -E, and both take precedence over -I.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
#include <config.h>
#include <stdio.h>
#include "../bashtypes.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../builtins.h"
#include "../pcomplete.h"
#include "../bashline.h"
#include "common.h"
#include "bashgetopt.h"
#include <readline/readline.h>
#define STRDUP(x) ((x) ? savestring (x) : (char *)NULL)
/* Structure containing all the non-action (binary) options; filled in by
build_actions(). */
struct _optflags {
int pflag;
int rflag;
int Dflag;
int Eflag;
int Iflag;
};
static int find_compact PARAMS((char *));
static int find_compopt PARAMS((char *));
static int build_actions PARAMS((WORD_LIST *, struct _optflags *, unsigned long *, unsigned long *));
static int remove_cmd_completions PARAMS((WORD_LIST *));
static int print_one_completion PARAMS((char *, COMPSPEC *));
static int print_compitem PARAMS((BUCKET_CONTENTS *));
static void print_compopts PARAMS((const char *, COMPSPEC *, int));
static void print_all_completions PARAMS((void));
static int print_cmd_completions PARAMS((WORD_LIST *));
static void print_compoptions PARAMS((unsigned long, int));
static void print_compactions PARAMS((unsigned long));
static void print_arg PARAMS((const char *, const char *, int));
static void print_cmd_name PARAMS((const char *));
static char *Garg, *Warg, *Parg, *Sarg, *Xarg, *Farg, *Carg;
static const struct _compacts {
const char * const actname;
unsigned long actflag;
int actopt;
} compacts[] = {
{ "alias", CA_ALIAS, 'a' },
{ "arrayvar", CA_ARRAYVAR, 0 },
{ "binding", CA_BINDING, 0 },
{ "builtin", CA_BUILTIN, 'b' },
{ "command", CA_COMMAND, 'c' },
{ "directory", CA_DIRECTORY, 'd' },
{ "disabled", CA_DISABLED, 0 },
{ "enabled", CA_ENABLED, 0 },
{ "export", CA_EXPORT, 'e' },
{ "file", CA_FILE, 'f' },
{ "function", CA_FUNCTION, 0 },
{ "helptopic", CA_HELPTOPIC, 0 },
{ "hostname", CA_HOSTNAME, 0 },
{ "group", CA_GROUP, 'g' },
{ "job", CA_JOB, 'j' },
{ "keyword", CA_KEYWORD, 'k' },
{ "running", CA_RUNNING, 0 },
{ "service", CA_SERVICE, 's' },
{ "setopt", CA_SETOPT, 0 },
{ "shopt", CA_SHOPT, 0 },
{ "signal", CA_SIGNAL, 0 },
{ "stopped", CA_STOPPED, 0 },
{ "user", CA_USER, 'u' },
{ "variable", CA_VARIABLE, 'v' },
{ (char *)NULL, 0, 0 },
};
/* This should be a STRING_INT_ALIST */
static const struct _compopt {
const char * const optname;
unsigned long optflag;
} compopts[] = {
{ "bashdefault", COPT_BASHDEFAULT },
{ "default", COPT_DEFAULT },
{ "dirnames", COPT_DIRNAMES },
{ "filenames",COPT_FILENAMES},
{ "noquote", COPT_NOQUOTE },
{ "nosort", COPT_NOSORT },
{ "nospace", COPT_NOSPACE },
{ "plusdirs", COPT_PLUSDIRS },
{ (char *)NULL, 0 },
};
static int
find_compact (name)
char *name;
{
register int i;
for (i = 0; compacts[i].actname; i++)
if (STREQ (name, compacts[i].actname))
return i;
return -1;
}
static int
find_compopt (name)
char *name;
{
register int i;
for (i = 0; compopts[i].optname; i++)
if (STREQ (name, compopts[i].optname))
return i;
return -1;
}
/* Build the actions and compspec options from the options specified in LIST.
ACTP is a pointer to an unsigned long in which to place the bitmap of
actions. OPTP is a pointer to an unsigned long in which to place the
bitmap of compspec options (arguments to `-o'). PP, if non-null, gets 1
if -p is supplied; RP, if non-null, gets 1 if -r is supplied.
If either is null, the corresponding option generates an error.
This also sets variables corresponding to options that take arguments as
a side effect; the caller should ensure that those variables are set to
NULL before calling build_actions. Return value:
EX_USAGE = bad option
EXECUTION_SUCCESS = some options supplied
EXECUTION_FAILURE = no options supplied
*/
static int
build_actions (list, flagp, actp, optp)
WORD_LIST *list;
struct _optflags *flagp;
unsigned long *actp, *optp;
{
int opt, ind, opt_given;
unsigned long acts, copts;
WORD_DESC w;
acts = copts = (unsigned long)0L;
opt_given = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "abcdefgjko:prsuvA:G:W:P:S:X:F:C:DEI")) != -1)
{
opt_given = 1;
switch (opt)
{
case 'r':
if (flagp)
{
flagp->rflag = 1;
break;
}
else
{
sh_invalidopt ("-r");
builtin_usage ();
return (EX_USAGE);
}
case 'p':
if (flagp)
{
flagp->pflag = 1;
break;
}
else
{
sh_invalidopt ("-p");
builtin_usage ();
return (EX_USAGE);
}
case 'a':
acts |= CA_ALIAS;
break;
case 'b':
acts |= CA_BUILTIN;
break;
case 'c':
acts |= CA_COMMAND;
break;
case 'd':
acts |= CA_DIRECTORY;
break;
case 'e':
acts |= CA_EXPORT;
break;
case 'f':
acts |= CA_FILE;
break;
case 'g':
acts |= CA_GROUP;
break;
case 'j':
acts |= CA_JOB;
break;
case 'k':
acts |= CA_KEYWORD;
break;
case 's':
acts |= CA_SERVICE;
break;
case 'u':
acts |= CA_USER;
break;
case 'v':
acts |= CA_VARIABLE;
break;
case 'o':
ind = find_compopt (list_optarg);
if (ind < 0)
{
sh_invalidoptname (list_optarg);
return (EX_USAGE);
}
copts |= compopts[ind].optflag;
break;
case 'A':
ind = find_compact (list_optarg);
if (ind < 0)
{
builtin_error (_("%s: invalid action name"), list_optarg);
return (EX_USAGE);
}
acts |= compacts[ind].actflag;
break;
case 'C':
Carg = list_optarg;
break;
case 'D':
if (flagp)
{
flagp->Dflag = 1;
break;
}
else
{
sh_invalidopt ("-D");
builtin_usage ();
return (EX_USAGE);
}
case 'E':
if (flagp)
{
flagp->Eflag = 1;
break;
}
else
{
sh_invalidopt ("-E");
builtin_usage ();
return (EX_USAGE);
}
case 'I':
if (flagp)
{
flagp->Iflag = 1;
break;
}
else
{
sh_invalidopt ("-I");
builtin_usage ();
return (EX_USAGE);
}
case 'F':
w.word = Farg = list_optarg;
w.flags = 0;
if (check_identifier (&w, posixly_correct) == 0 || strpbrk (Farg, shell_break_chars) != 0)
{
sh_invalidid (Farg);
return (EX_USAGE);
}
break;
case 'G':
Garg = list_optarg;
break;
case 'P':
Parg = list_optarg;
break;
case 'S':
Sarg = list_optarg;
break;
case 'W':
Warg = list_optarg;
break;
case 'X':
Xarg = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
*actp = acts;
*optp = copts;
return (opt_given ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
/* Add, remove, and display completion specifiers. */
int
complete_builtin (list)
WORD_LIST *list;
{
int opt_given, rval;
unsigned long acts, copts;
COMPSPEC *cs;
struct _optflags oflags;
WORD_LIST *l, *wl;
if (list == 0)
{
print_all_completions ();
return (EXECUTION_SUCCESS);
}
opt_given = oflags.pflag = oflags.rflag = 0;
oflags.Dflag = oflags.Eflag = oflags.Iflag = 0;
acts = copts = (unsigned long)0L;
Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
cs = (COMPSPEC *)NULL;
/* Build the actions from the arguments. Also sets the [A-Z]arg variables
as a side effect if they are supplied as options. */
rval = build_actions (list, &oflags, &acts, &copts);
if (rval == EX_USAGE)
return (rval);
opt_given = rval != EXECUTION_FAILURE;
list = loptend;
if (oflags.Dflag)
wl = make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL);
else if (oflags.Eflag)
wl = make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL);
else if (oflags.Iflag)
wl = make_word_list (make_bare_word (INITIALWORD), (WORD_LIST *)NULL);
else
wl = (WORD_LIST *)NULL;
/* -p overrides everything else */
if (oflags.pflag || (list == 0 && opt_given == 0))
{
if (wl)
{
rval = print_cmd_completions (wl);
dispose_words (wl);
return rval;
}
else if (list == 0)
{
print_all_completions ();
return (EXECUTION_SUCCESS);
}
return (print_cmd_completions (list));
}
/* next, -r overrides everything else. */
if (oflags.rflag)
{
if (wl)
{
rval = remove_cmd_completions (wl);
dispose_words (wl);
return rval;
}
else if (list == 0)
{
progcomp_flush ();
return (EXECUTION_SUCCESS);
}
return (remove_cmd_completions (list));
}
if (wl == 0 && list == 0 && opt_given)
{
builtin_usage ();
return (EX_USAGE);
}
/* If we get here, we need to build a compspec and add it for each
remaining argument. */
cs = compspec_create ();
cs->actions = acts;
cs->options = copts;
cs->globpat = STRDUP (Garg);
cs->words = STRDUP (Warg);
cs->prefix = STRDUP (Parg);
cs->suffix = STRDUP (Sarg);
cs->funcname = STRDUP (Farg);
cs->command = STRDUP (Carg);
cs->filterpat = STRDUP (Xarg);
for (rval = EXECUTION_SUCCESS, l = wl ? wl : list ; l; l = l->next)
{
/* Add CS as the compspec for the specified commands. */
if (progcomp_insert (l->word->word, cs) == 0)
rval = EXECUTION_FAILURE;
}
dispose_words (wl);
return (rval);
}
static int
remove_cmd_completions (list)
WORD_LIST *list;
{
WORD_LIST *l;
int ret;
for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
{
if (progcomp_remove (l->word->word) == 0)
{
builtin_error (_("%s: no completion specification"), l->word->word);
ret = EXECUTION_FAILURE;
}
}
return ret;
}
static void
print_compoptions (copts, full)
unsigned long copts;
int full;
{
const struct _compopt *co;
for (co = compopts; co->optname; co++)
if (copts & co->optflag)
printf ("-o %s ", co->optname);
else if (full)
printf ("+o %s ", co->optname);
}
static void
print_compactions (acts)
unsigned long acts;
{
const struct _compacts *ca;
/* simple flags first */
for (ca = compacts; ca->actname; ca++)
if (ca->actopt && (acts & ca->actflag))
printf ("-%c ", ca->actopt);
/* then the rest of the actions */
for (ca = compacts; ca->actname; ca++)
if (ca->actopt == 0 && (acts & ca->actflag))
printf ("-A %s ", ca->actname);
}
static void
print_arg (arg, flag, quote)
const char *arg, *flag;
int quote;
{
char *x;
if (arg)
{
x = quote ? sh_single_quote (arg) : (char *)arg;
printf ("%s %s ", flag, x);
if (x != arg)
free (x);
}
}
static void
print_cmd_name (cmd)
const char *cmd;
{
char *x;
if (STREQ (cmd, DEFAULTCMD))
printf ("-D");
else if (STREQ (cmd, EMPTYCMD))
printf ("-E");
else if (STREQ (cmd, INITIALWORD))
printf ("-I");
else if (*cmd == 0) /* XXX - can this happen? */
printf ("''");
else if (sh_contains_shell_metas (cmd))
{
x = sh_single_quote (cmd);
printf ("%s", x);
free (x);
}
else
printf ("%s", cmd);
}
static int
print_one_completion (cmd, cs)
char *cmd;
COMPSPEC *cs;
{
printf ("complete ");
print_compoptions (cs->options, 0);
print_compactions (cs->actions);
/* now the rest of the arguments */
/* arguments that require quoting */
print_arg (cs->globpat, "-G", 1);
print_arg (cs->words, "-W", 1);
print_arg (cs->prefix, "-P", 1);
print_arg (cs->suffix, "-S", 1);
print_arg (cs->filterpat, "-X", 1);
print_arg (cs->command, "-C", 1);
/* simple arguments that don't require quoting */
print_arg (cs->funcname, "-F", sh_contains_shell_metas (cs->funcname) != 0);
print_cmd_name (cmd);
printf ("\n");
return (0);
}
static void
print_compopts (cmd, cs, full)
const char *cmd;
COMPSPEC *cs;
int full;
{
printf ("compopt ");
print_compoptions (cs->options, full);
print_cmd_name (cmd);
printf ("\n");
}
static int
print_compitem (item)
BUCKET_CONTENTS *item;
{
COMPSPEC *cs;
char *cmd;
cmd = item->key;
cs = (COMPSPEC *)item->data;
return (print_one_completion (cmd, cs));
}
static void
print_all_completions ()
{
progcomp_walk (print_compitem);
}
static int
print_cmd_completions (list)
WORD_LIST *list;
{
WORD_LIST *l;
COMPSPEC *cs;
int ret;
for (ret = EXECUTION_SUCCESS, l = list; l; l = l->next)
{
cs = progcomp_search (l->word->word);
if (cs)
print_one_completion (l->word->word, cs);
else
{
builtin_error (_("%s: no completion specification"), l->word->word);
ret = EXECUTION_FAILURE;
}
}
return (sh_chkwrite (ret));
}
$BUILTIN compgen
$DEPENDS_ON PROGRAMMABLE_COMPLETION
$FUNCTION compgen_builtin
$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
Display possible completions depending on the options.
Intended to be used from within a shell function generating possible
completions. If the optional WORD argument is supplied, matches against
WORD are generated.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
int
compgen_builtin (list)
WORD_LIST *list;
{
int rval;
unsigned long acts, copts;
COMPSPEC *cs;
STRINGLIST *sl;
char *word, **matches;
char *old_line;
int old_ind;
if (list == 0)
return (EXECUTION_SUCCESS);
acts = copts = (unsigned long)0L;
Garg = Warg = Parg = Sarg = Xarg = Farg = Carg = (char *)NULL;
cs = (COMPSPEC *)NULL;
/* Build the actions from the arguments. Also sets the [A-Z]arg variables
as a side effect if they are supplied as options. */
rval = build_actions (list, (struct _optflags *)NULL, &acts, &copts);
if (rval == EX_USAGE)
return (rval);
if (rval == EXECUTION_FAILURE)
return (EXECUTION_SUCCESS);
list = loptend;
word = (list && list->word) ? list->word->word : "";
if (Farg)
builtin_error (_("warning: -F option may not work as you expect"));
if (Carg)
builtin_error (_("warning: -C option may not work as you expect"));
/* If we get here, we need to build a compspec and evaluate it. */
cs = compspec_create ();
cs->actions = acts;
cs->options = copts;
cs->refcount = 1;
cs->globpat = STRDUP (Garg);
cs->words = STRDUP (Warg);
cs->prefix = STRDUP (Parg);
cs->suffix = STRDUP (Sarg);
cs->funcname = STRDUP (Farg);
cs->command = STRDUP (Carg);
cs->filterpat = STRDUP (Xarg);
rval = EXECUTION_FAILURE;
/* probably don't have to save these, just being safe */
old_line = pcomp_line;
old_ind = pcomp_ind;
pcomp_line = (char *)NULL;
pcomp_ind = 0;
sl = gen_compspec_completions (cs, "compgen", word, 0, 0, 0);
pcomp_line = old_line;
pcomp_ind = old_ind;
/* If the compspec wants the bash default completions, temporarily
turn off programmable completion and call the bash completion code. */
if ((sl == 0 || sl->list_len == 0) && (copts & COPT_BASHDEFAULT))
{
matches = bash_default_completion (word, 0, 0, 0, 0);
sl = completions_to_stringlist (matches);
strvec_dispose (matches);
}
/* This isn't perfect, but it's the best we can do, given what readline
exports from its set of completion utility functions. */
if ((sl == 0 || sl->list_len == 0) && (copts & COPT_DEFAULT))
{
matches = rl_completion_matches (word, rl_filename_completion_function);
strlist_dispose (sl);
sl = completions_to_stringlist (matches);
strvec_dispose (matches);
}
if (sl)
{
if (sl->list && sl->list_len)
{
rval = EXECUTION_SUCCESS;
strlist_print (sl, (char *)NULL);
}
strlist_dispose (sl);
}
compspec_dispose (cs);
return (rval);
}
$BUILTIN compopt
$DEPENDS_ON PROGRAMMABLE_COMPLETION
$FUNCTION compopt_builtin
$SHORT_DOC compopt [-o|+o option] [-DEI] [name ...]
Modify or display completion options.
Modify the completion options for each NAME, or, if no NAMEs are supplied,
the completion currently being executed. If no OPTIONs are given, print
the completion options for each NAME or the current completion specification.
Options:
-o option Set completion option OPTION for each NAME
-D Change options for the "default" command completion
-E Change options for the "empty" command completion
-I Change options for completion on the initial word
Using `+o' instead of `-o' turns off the specified option.
Arguments:
Each NAME refers to a command for which a completion specification must
have previously been defined using the `complete' builtin. If no NAMEs
are supplied, compopt must be called by a function currently generating
completions, and the options for that currently-executing completion
generator are modified.
Exit Status:
Returns success unless an invalid option is supplied or NAME does not
have a completion specification defined.
$END
int
compopt_builtin (list)
WORD_LIST *list;
{
int opts_on, opts_off, *opts, opt, oind, ret, Dflag, Eflag, Iflag;
WORD_LIST *l, *wl;
COMPSPEC *cs;
opts_on = opts_off = Eflag = Dflag = Iflag = 0;
ret = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "+o:DEI")) != -1)
{
opts = (list_opttype == '-') ? &opts_on : &opts_off;
switch (opt)
{
case 'o':
oind = find_compopt (list_optarg);
if (oind < 0)
{
sh_invalidoptname (list_optarg);
return (EX_USAGE);
}
*opts |= compopts[oind].optflag;
break;
case 'D':
Dflag = 1;
break;
case 'E':
Eflag = 1;
break;
case 'I':
Iflag = 1;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (Dflag)
wl = make_word_list (make_bare_word (DEFAULTCMD), (WORD_LIST *)NULL);
else if (Eflag)
wl = make_word_list (make_bare_word (EMPTYCMD), (WORD_LIST *)NULL);
else if (Iflag)
wl = make_word_list (make_bare_word (INITIALWORD), (WORD_LIST *)NULL);
else
wl = (WORD_LIST *)NULL;
if (list == 0 && wl == 0)
{
if (RL_ISSTATE (RL_STATE_COMPLETING) == 0 || pcomp_curcs == 0)
{
builtin_error (_("not currently executing completion function"));
return (EXECUTION_FAILURE);
}
cs = pcomp_curcs;
if (opts_on == 0 && opts_off == 0)
{
print_compopts (pcomp_curcmd, cs, 1);
return (sh_chkwrite (ret));
}
/* Set the compspec options */
pcomp_set_compspec_options (cs, opts_on, 1);
pcomp_set_compspec_options (cs, opts_off, 0);
/* And change the readline variables the options control */
pcomp_set_readline_variables (opts_on, 1);
pcomp_set_readline_variables (opts_off, 0);
return (ret);
}
for (l = wl ? wl : list; l; l = l->next)
{
cs = progcomp_search (l->word->word);
if (cs == 0)
{
builtin_error (_("%s: no completion specification"), l->word->word);
ret = EXECUTION_FAILURE;
continue;
}
if (opts_on == 0 && opts_off == 0)
{
print_compopts (l->word->word, cs, 1);
continue; /* XXX -- fill in later */
}
/* Set the compspec options */
pcomp_set_compspec_options (cs, opts_on, 1);
pcomp_set_compspec_options (cs, opts_off, 0);
}
if (wl)
dispose_words (wl);
return (ret);
}

1056
builtins/declare.def Normal file

File diff suppressed because it is too large Load diff

202
builtins/echo.def Normal file
View file

@ -0,0 +1,202 @@
This file is echo.def, from which is created echo.c.
It implements the builtin "echo" in Bash.
Copyright (C) 1987-2018 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES echo.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include <stdio.h>
#include "../shell.h"
#include "common.h"
$BUILTIN echo
$FUNCTION echo_builtin
$DEPENDS_ON V9_ECHO
$SHORT_DOC echo [-neE] [arg ...]
Write arguments to the standard output.
Display the ARGs, separated by a single space character and followed by a
newline, on the standard output.
Options:
-n do not append a newline
-e enable interpretation of the following backslash escapes
-E explicitly suppress interpretation of backslash escapes
`echo' interprets the following backslash-escaped characters:
\a alert (bell)
\b backspace
\c suppress further output
\e escape character
\E escape character
\f form feed
\n new line
\r carriage return
\t horizontal tab
\v vertical tab
\\ backslash
\0nnn the character whose ASCII code is NNN (octal). NNN can be
0 to 3 octal digits
\xHH the eight-bit character whose value is HH (hexadecimal). HH
can be one or two hex digits
\uHHHH the Unicode character whose value is the hexadecimal value HHHH.
HHHH can be one to four hex digits.
\UHHHHHHHH the Unicode character whose value is the hexadecimal value
HHHHHHHH. HHHHHHHH can be one to eight hex digits.
Exit Status:
Returns success unless a write error occurs.
$END
$BUILTIN echo
$FUNCTION echo_builtin
$DEPENDS_ON !V9_ECHO
$SHORT_DOC echo [-n] [arg ...]
Write arguments to the standard output.
Display the ARGs on the standard output followed by a newline.
Options:
-n do not append a newline
Exit Status:
Returns success unless a write error occurs.
$END
#if defined (V9_ECHO)
# define VALID_ECHO_OPTIONS "neE"
#else /* !V9_ECHO */
# define VALID_ECHO_OPTIONS "n"
#endif /* !V9_ECHO */
/* System V machines already have a /bin/sh with a v9 behaviour. We
give Bash the identical behaviour for these machines so that the
existing system shells won't barf. Regrettably, the SUS v2 has
standardized the Sys V echo behavior. This variable is external
so that we can have a `shopt' variable to control it at runtime. */
#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
int xpg_echo = 1;
#else
int xpg_echo = 0;
#endif /* DEFAULT_ECHO_TO_XPG */
/* Print the words in LIST to standard output. If the first word is
`-n', then don't print a trailing newline. We also support the
echo syntax from Version 9 Unix systems. */
int
echo_builtin (list)
WORD_LIST *list;
{
int display_return, do_v9, i, len;
char *temp, *s;
do_v9 = xpg_echo;
display_return = 1;
if (posixly_correct && xpg_echo)
goto just_echo;
for (; list && (temp = list->word->word) && *temp == '-'; list = list->next)
{
/* If it appears that we are handling options, then make sure that
all of the options specified are actually valid. Otherwise, the
string should just be echoed. */
temp++;
for (i = 0; temp[i]; i++)
{
if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
break;
}
/* echo - and echo -<nonopt> both mean to just echo the arguments. */
if (*temp == 0 || temp[i])
break;
/* All of the options in TEMP are valid options to ECHO.
Handle them. */
while (i = *temp++)
{
switch (i)
{
case 'n':
display_return = 0;
break;
#if defined (V9_ECHO)
case 'e':
do_v9 = 1;
break;
case 'E':
do_v9 = 0;
break;
#endif /* V9_ECHO */
default:
goto just_echo; /* XXX */
}
}
}
just_echo:
clearerr (stdout); /* clear error before writing and testing success */
while (list)
{
i = len = 0;
temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len)
: list->word->word;
if (temp)
{
if (do_v9)
{
for (s = temp; len > 0; len--)
putchar (*s++);
}
else
printf ("%s", temp);
#if defined (SunOS5)
fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */
#endif
}
QUIT;
if (do_v9 && temp)
free (temp);
list = list->next;
if (i)
{
display_return = 0;
break;
}
if (list)
putchar(' ');
QUIT;
}
if (display_return)
putchar ('\n');
return (sh_chkwrite (EXECUTION_SUCCESS));
}

586
builtins/enable.def Normal file
View file

@ -0,0 +1,586 @@
This file is enable.def, from which is created enable.c.
It implements the builtin "enable" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES enable.c
$BUILTIN enable
$FUNCTION enable_builtin
$SHORT_DOC enable [-a] [-dnps] [-f filename] [name ...]
Enable and disable shell builtins.
Enables and disables builtin shell commands. Disabling allows you to
execute a disk command which has the same name as a shell builtin
without using a full pathname.
Options:
-a print a list of builtins showing whether or not each is enabled
-n disable each NAME or display a list of disabled builtins
-p print the list of builtins in a reusable format
-s print only the names of Posix `special' builtins
Options controlling dynamic loading:
-f Load builtin NAME from shared object FILENAME
-d Remove a builtin loaded with -f
Without options, each NAME is enabled.
To use the `test' found in $PATH instead of the shell builtin
version, type `enable -n test'.
Exit Status:
Returns success unless NAME is not a shell builtin or an error occurs.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../builtins.h"
#include "../flags.h"
#include "common.h"
#include "bashgetopt.h"
#include "findcmd.h"
#if defined (PROGRAMMABLE_COMPLETION)
# include "../pcomplete.h"
#endif
#define ENABLED 1
#define DISABLED 2
#define SPECIAL 4
#define SILENT 8 /* affects dyn_load_builtin behavior */
#define AFLAG 0x01
#define DFLAG 0x02
#define FFLAG 0x04
#define NFLAG 0x08
#define PFLAG 0x10
#define SFLAG 0x20
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
static int dyn_load_builtin PARAMS((WORD_LIST *, int, char *));
#endif
#if defined (HAVE_DLCLOSE)
static int dyn_unload_builtin PARAMS((char *));
static void delete_builtin PARAMS((struct builtin *));
static int local_dlclose PARAMS((void *));
#endif
#define STRUCT_SUFFIX "_struct"
/* for now */
#define LOAD_SUFFIX "_builtin_load"
#define UNLOAD_SUFFIX "_builtin_unload"
static void list_some_builtins PARAMS((int));
static int enable_shell_command PARAMS((char *, int));
/* Enable/disable shell commands present in LIST. If list is not specified,
then print out a list of shell commands showing which are enabled and
which are disabled. */
int
enable_builtin (list)
WORD_LIST *list;
{
int result, flags;
int opt, filter;
WORD_LIST *next;
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
char *filename;
#endif
result = EXECUTION_SUCCESS;
flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "adnpsf:")) != -1)
{
switch (opt)
{
case 'a':
flags |= AFLAG;
break;
case 'n':
flags |= NFLAG;
break;
case 'p':
flags |= PFLAG;
break;
case 's':
flags |= SFLAG;
break;
case 'f':
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
flags |= FFLAG;
filename = list_optarg;
break;
#else
builtin_error (_("dynamic loading not available"));
return (EX_USAGE);
#endif
#if defined (HAVE_DLCLOSE)
case 'd':
flags |= DFLAG;
break;
#else
builtin_error (_("dynamic loading not available"));
return (EX_USAGE);
#endif /* HAVE_DLCLOSE */
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
#if defined (RESTRICTED_SHELL)
/* Restricted shells cannot load new builtins. */
if (restricted && (flags & (FFLAG|DFLAG)))
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif
if (list == 0 || (flags & PFLAG))
{
filter = (flags & AFLAG) ? (ENABLED | DISABLED)
: (flags & NFLAG) ? DISABLED : ENABLED;
if (flags & SFLAG)
filter |= SPECIAL;
list_some_builtins (filter);
result = sh_chkwrite (EXECUTION_SUCCESS);
}
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
else if (flags & FFLAG)
{
filter = (flags & NFLAG) ? DISABLED : ENABLED;
if (flags & SFLAG)
filter |= SPECIAL;
result = dyn_load_builtin (list, filter, filename);
if (result != EXECUTION_SUCCESS)
result = EXECUTION_FAILURE; /* normalize return value */
#if defined (PROGRAMMABLE_COMPLETION)
set_itemlist_dirty (&it_builtins);
#endif
}
#endif
#if defined (HAVE_DLCLOSE)
else if (flags & DFLAG)
{
while (list)
{
opt = dyn_unload_builtin (list->word->word);
if (opt == EXECUTION_FAILURE)
result = EXECUTION_FAILURE;
list = list->next;
}
#if defined (PROGRAMMABLE_COMPLETION)
set_itemlist_dirty (&it_builtins);
#endif
}
#endif
else
{
while (list)
{
opt = enable_shell_command (list->word->word, flags & NFLAG);
next = list->next;
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
/* If we try to enable a non-existent builtin, and we have dynamic
loading, try the equivalent of `enable -f name name'. */
if (opt == EX_NOTFOUND)
{
int dflags, r;
dflags = ENABLED|SILENT|((flags & SFLAG) ? SPECIAL : 0);
list->next = 0;
r = dyn_load_builtin (list, dflags, list->word->word);
list->next = next;
if (r == EXECUTION_SUCCESS)
opt = r;
#if defined (PROGRAMMABLE_COMPLETION)
set_itemlist_dirty (&it_builtins);
#endif
}
#endif
if (opt == EX_NOTFOUND)
{
sh_notbuiltin (list->word->word);
result = EXECUTION_FAILURE;
}
else if (opt != EXECUTION_SUCCESS)
result = EXECUTION_FAILURE;
list = next;
}
}
return (result);
}
/* List some builtins.
FILTER is a mask with two slots: ENABLED and DISABLED. */
static void
list_some_builtins (filter)
int filter;
{
register int i;
for (i = 0; i < num_shell_builtins; i++)
{
if (shell_builtins[i].function == 0 || (shell_builtins[i].flags & BUILTIN_DELETED))
continue;
if ((filter & SPECIAL) &&
(shell_builtins[i].flags & SPECIAL_BUILTIN) == 0)
continue;
if ((filter & ENABLED) && (shell_builtins[i].flags & BUILTIN_ENABLED))
printf ("enable %s\n", shell_builtins[i].name);
else if ((filter & DISABLED) &&
((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
printf ("enable -n %s\n", shell_builtins[i].name);
}
}
/* Enable the shell command NAME. If DISABLE_P is non-zero, then
disable NAME instead. */
static int
enable_shell_command (name, disable_p)
char *name;
int disable_p;
{
struct builtin *b;
b = builtin_address_internal (name, 1);
if (b == 0)
return (EX_NOTFOUND);
if (disable_p)
b->flags &= ~BUILTIN_ENABLED;
#if defined (RESTRICTED_SHELL)
else if (restricted && ((b->flags & BUILTIN_ENABLED) == 0))
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif
else
b->flags |= BUILTIN_ENABLED;
#if defined (PROGRAMMABLE_COMPLETION)
set_itemlist_dirty (&it_enabled);
set_itemlist_dirty (&it_disabled);
#endif
return (EXECUTION_SUCCESS);
}
#if defined (HAVE_DLOPEN) && defined (HAVE_DLSYM)
#if defined (HAVE_DLFCN_H)
# include <dlfcn.h>
#endif
static int
dyn_load_builtin (list, flags, filename)
WORD_LIST *list;
int flags;
char *filename;
{
WORD_LIST *l;
void *handle;
int total, size, new, replaced, r;
char *struct_name, *name, *funcname;
sh_load_func_t *loadfunc;
struct builtin **new_builtins, *b, *new_shell_builtins, *old_builtin;
char *loadables_path, *load_path;
if (list == 0)
return (EXECUTION_FAILURE);
#ifndef RTLD_LAZY
#define RTLD_LAZY 1
#endif
handle = 0;
if (absolute_program (filename) == 0)
{
loadables_path = get_string_value ("BASH_LOADABLES_PATH");
if (loadables_path)
{
load_path = find_in_path (filename, loadables_path, FS_NODIRS|FS_EXEC_PREFERRED);
if (load_path)
{
#if defined (_AIX)
handle = dlopen (load_path, RTLD_NOW|RTLD_GLOBAL);
#else
handle = dlopen (load_path, RTLD_LAZY);
#endif /* !_AIX */
free (load_path);
}
}
}
/* Fall back to current directory for now */
if (handle == 0)
#if defined (_AIX)
handle = dlopen (filename, RTLD_NOW|RTLD_GLOBAL);
#else
handle = dlopen (filename, RTLD_LAZY);
#endif /* !_AIX */
if (handle == 0)
{
/* If we've been told to be quiet, don't complain about not finding the
specified shared object. */
if ((flags & SILENT) == 0)
{
name = printable_filename (filename, 0);
builtin_error (_("cannot open shared object %s: %s"), name, dlerror ());
if (name != filename)
free (name);
}
return (EX_NOTFOUND);
}
for (new = 0, l = list; l; l = l->next, new++)
;
new_builtins = (struct builtin **)xmalloc (new * sizeof (struct builtin *));
/* For each new builtin in the shared object, find it and its describing
structure. If this is overwriting an existing builtin, do so, otherwise
save the loaded struct for creating the new list of builtins. */
for (replaced = new = 0; list; list = list->next)
{
name = list->word->word;
size = strlen (name);
struct_name = (char *)xmalloc (size + 8);
strcpy (struct_name, name);
strcpy (struct_name + size, STRUCT_SUFFIX);
old_builtin = builtin_address_internal (name, 1);
b = (struct builtin *)dlsym (handle, struct_name);
if (b == 0)
{
name = printable_filename (filename, 0);
builtin_error (_("cannot find %s in shared object %s: %s"),
struct_name, name, dlerror ());
if (name != filename)
free (name);
free (struct_name);
continue;
}
funcname = xrealloc (struct_name, size + sizeof (LOAD_SUFFIX) + 1);
strcpy (funcname, name);
strcpy (funcname + size, LOAD_SUFFIX);
loadfunc = (sh_load_func_t *)dlsym (handle, funcname);
if (loadfunc)
{
/* Add warning if running an init function more than once */
if (old_builtin && (old_builtin->flags & STATIC_BUILTIN) == 0)
builtin_warning (_("%s: dynamic builtin already loaded"), name);
r = (*loadfunc) (name);
if (r == 0)
{
builtin_error (_("load function for %s returns failure (%d): not loaded"), name, r);
free (funcname);
continue;
}
}
free (funcname);
b->flags &= ~STATIC_BUILTIN;
if (flags & SPECIAL)
b->flags |= SPECIAL_BUILTIN;
b->handle = handle;
if (old_builtin)
{
replaced++;
FASTCOPY ((char *)b, (char *)old_builtin, sizeof (struct builtin));
}
else
new_builtins[new++] = b;
}
if (replaced == 0 && new == 0)
{
free (new_builtins);
dlclose (handle);
return (EXECUTION_FAILURE);
}
if (new)
{
total = num_shell_builtins + new;
size = (total + 1) * sizeof (struct builtin);
new_shell_builtins = (struct builtin *)xmalloc (size);
FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
num_shell_builtins * sizeof (struct builtin));
for (replaced = 0; replaced < new; replaced++)
FASTCOPY ((char *)new_builtins[replaced],
(char *)&new_shell_builtins[num_shell_builtins + replaced],
sizeof (struct builtin));
new_shell_builtins[total].name = (char *)0;
new_shell_builtins[total].function = (sh_builtin_func_t *)0;
new_shell_builtins[total].flags = 0;
if (shell_builtins != static_shell_builtins)
free (shell_builtins);
shell_builtins = new_shell_builtins;
num_shell_builtins = total;
initialize_shell_builtins ();
}
free (new_builtins);
return (EXECUTION_SUCCESS);
}
#endif
#if defined (HAVE_DLCLOSE)
static void
delete_builtin (b)
struct builtin *b;
{
int ind, size;
struct builtin *new_shell_builtins;
/* XXX - funky pointer arithmetic - XXX */
#ifdef __STDC__
ind = b - shell_builtins;
#else
ind = ((int)b - (int)shell_builtins) / sizeof (struct builtin);
#endif
size = num_shell_builtins * sizeof (struct builtin);
new_shell_builtins = (struct builtin *)xmalloc (size);
/* Copy shell_builtins[0]...shell_builtins[ind - 1] to new_shell_builtins */
if (ind)
FASTCOPY ((char *)shell_builtins, (char *)new_shell_builtins,
ind * sizeof (struct builtin));
/* Copy shell_builtins[ind+1]...shell_builtins[num_shell_builtins to
new_shell_builtins, starting at ind. */
FASTCOPY ((char *)(&shell_builtins[ind+1]),
(char *)(&new_shell_builtins[ind]),
(num_shell_builtins - ind) * sizeof (struct builtin));
if (shell_builtins != static_shell_builtins)
free (shell_builtins);
/* The result is still sorted. */
num_shell_builtins--;
shell_builtins = new_shell_builtins;
}
/* Tenon's MachTen has a dlclose that doesn't return a value, so we
finesse it with a local wrapper. */
static int
local_dlclose (handle)
void *handle;
{
#if !defined (__MACHTEN__)
return (dlclose (handle));
#else /* __MACHTEN__ */
dlclose (handle);
return ((dlerror () != NULL) ? -1 : 0);
#endif /* __MACHTEN__ */
}
static int
dyn_unload_builtin (name)
char *name;
{
struct builtin *b;
void *handle;
char *funcname;
sh_unload_func_t *unloadfunc;
int ref, i, size;
b = builtin_address_internal (name, 1);
if (b == 0)
{
sh_notbuiltin (name);
return (EXECUTION_FAILURE);
}
if (b->flags & STATIC_BUILTIN)
{
builtin_error (_("%s: not dynamically loaded"), name);
return (EXECUTION_FAILURE);
}
handle = (void *)b->handle;
for (ref = i = 0; i < num_shell_builtins; i++)
{
if (shell_builtins[i].handle == b->handle)
ref++;
}
/* Call any unload function */
size = strlen (name);
funcname = xmalloc (size + sizeof (UNLOAD_SUFFIX) + 1);
strcpy (funcname, name);
strcpy (funcname + size, UNLOAD_SUFFIX);
unloadfunc = (sh_unload_func_t *)dlsym (handle, funcname);
if (unloadfunc)
(*unloadfunc) (name); /* void function */
free (funcname);
/* Don't remove the shared object unless the reference count of builtins
using it drops to zero. */
if (ref == 1 && local_dlclose (handle) != 0)
{
builtin_error (_("%s: cannot delete: %s"), name, dlerror ());
return (EXECUTION_FAILURE);
}
/* Now remove this entry from the builtin table and reinitialize. */
delete_builtin (b);
return (EXECUTION_SUCCESS);
}
#endif

57
builtins/eval.def Normal file
View file

@ -0,0 +1,57 @@
This file is eval.def, from which is created eval.c.
It implements the builtin "eval" in Bash.
Copyright (C) 1987-2016 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES eval.c
$BUILTIN eval
$FUNCTION eval_builtin
$SHORT_DOC eval [arg ...]
Execute arguments as a shell command.
Combine ARGs into a single string, use the result as input to the shell,
and execute the resulting commands.
Exit Status:
Returns exit status of command or success if command is null.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../shell.h"
#include "bashgetopt.h"
#include "common.h"
/* Parse the string that these words make, and execute the command found. */
int
eval_builtin (list)
WORD_LIST *list;
{
if (no_options (list))
return (EX_USAGE);
list = loptend; /* skip over possible `--' */
return (list ? evalstring (string_list (list), "eval", SEVAL_NOHIST|SEVAL_NOOPTIMIZE) : EXECUTION_SUCCESS);
}

384
builtins/evalfile.c Normal file
View file

@ -0,0 +1,384 @@
/* evalfile.c - read and evaluate commands from a file or file descriptor */
/* Copyright (C) 1996-2017 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include "posixstat.h"
#include "filecntl.h"
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../parser.h"
#include "../jobs.h"
#include "../builtins.h"
#include "../flags.h"
#include "../input.h"
#include "../execute_cmd.h"
#include "../trap.h"
#include <y.tab.h>
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#include <typemax.h>
#include "common.h"
#if !defined (errno)
extern int errno;
#endif
/* Flags for _evalfile() */
#define FEVAL_ENOENTOK 0x001
#define FEVAL_BUILTIN 0x002
#define FEVAL_UNWINDPROT 0x004
#define FEVAL_NONINT 0x008
#define FEVAL_LONGJMP 0x010
#define FEVAL_HISTORY 0x020
#define FEVAL_CHECKBINARY 0x040
#define FEVAL_REGFILE 0x080
#define FEVAL_NOPUSHARGS 0x100
/* How many `levels' of sourced files we have. */
int sourcelevel = 0;
static int
_evalfile (filename, flags)
const char *filename;
int flags;
{
volatile int old_interactive;
procenv_t old_return_catch;
int return_val, fd, result, pflags, i, nnull;
ssize_t nr; /* return value from read(2) */
char *string;
struct stat finfo;
size_t file_size;
sh_vmsg_func_t *errfunc;
#if defined (ARRAY_VARS)
SHELL_VAR *funcname_v, *bash_source_v, *bash_lineno_v;
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
struct func_array_state *fa;
# if defined (DEBUGGER)
SHELL_VAR *bash_argv_v, *bash_argc_v;
ARRAY *bash_argv_a, *bash_argc_a;
# endif
char *t, tt[2];
#endif
USE_VAR(pflags);
#if defined (ARRAY_VARS)
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
# if defined (DEBUGGER)
GET_ARRAY_FROM_VAR ("BASH_ARGV", bash_argv_v, bash_argv_a);
GET_ARRAY_FROM_VAR ("BASH_ARGC", bash_argc_v, bash_argc_a);
# endif
#endif
fd = open (filename, O_RDONLY);
if (fd < 0 || (fstat (fd, &finfo) == -1))
{
i = errno;
if (fd >= 0)
close (fd);
errno = i;
file_error_and_exit:
if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT)
file_error (filename);
if (flags & FEVAL_LONGJMP)
{
last_command_exit_value = EXECUTION_FAILURE;
jump_to_top_level (EXITPROG);
}
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE
: ((errno == ENOENT && (flags & FEVAL_ENOENTOK) != 0) ? 0 : -1));
}
errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error);
if (S_ISDIR (finfo.st_mode))
{
(*errfunc) (_("%s: is a directory"), filename);
close (fd);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
}
else if ((flags & FEVAL_REGFILE) && S_ISREG (finfo.st_mode) == 0)
{
(*errfunc) (_("%s: not a regular file"), filename);
close (fd);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
}
file_size = (size_t)finfo.st_size;
/* Check for overflow with large files. */
if (file_size != finfo.st_size || file_size + 1 < file_size)
{
(*errfunc) (_("%s: file is too large"), filename);
close (fd);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
}
if (S_ISREG (finfo.st_mode) && file_size <= SSIZE_MAX)
{
string = (char *)xmalloc (1 + file_size);
nr = read (fd, string, file_size);
if (nr >= 0)
string[nr] = '\0';
}
else
nr = zmapfd (fd, &string, 0);
return_val = errno;
close (fd);
errno = return_val;
if (nr < 0) /* XXX was != file_size, not < 0 */
{
free (string);
goto file_error_and_exit;
}
if (nr == 0)
{
free (string);
return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1);
}
if ((flags & FEVAL_CHECKBINARY) &&
check_binary_file (string, (nr > 80) ? 80 : nr))
{
free (string);
(*errfunc) (_("%s: cannot execute binary file"), filename);
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
}
i = strlen (string);
if (i < nr)
{
for (nnull = i = 0; i < nr; i++)
if (string[i] == '\0')
{
memmove (string+i, string+i+1, nr - i);
nr--;
/* Even if the `check binary' flag is not set, we want to avoid
sourcing files with more than 256 null characters -- that
probably indicates a binary file. */
if ((flags & FEVAL_BUILTIN) && ++nnull > 256)
{
free (string);
(*errfunc) (_("%s: cannot execute binary file"), filename);
return ((flags & FEVAL_BUILTIN) ? EX_BINARY_FILE : -1);
}
}
}
if (flags & FEVAL_UNWINDPROT)
{
begin_unwind_frame ("_evalfile");
unwind_protect_int (return_catch_flag);
unwind_protect_jmp_buf (return_catch);
if (flags & FEVAL_NONINT)
unwind_protect_int (interactive);
unwind_protect_int (sourcelevel);
}
else
{
COPY_PROCENV (return_catch, old_return_catch);
if (flags & FEVAL_NONINT)
old_interactive = interactive;
}
if (flags & FEVAL_NONINT)
interactive = 0;
return_catch_flag++;
sourcelevel++;
#if defined (ARRAY_VARS)
array_push (bash_source_a, (char *)filename);
t = itos (executing_line_number ());
array_push (bash_lineno_a, t);
free (t);
array_push (funcname_a, "source"); /* not exactly right */
fa = (struct func_array_state *)xmalloc (sizeof (struct func_array_state));
fa->source_a = bash_source_a;
fa->source_v = bash_source_v;
fa->lineno_a = bash_lineno_a;
fa->lineno_v = bash_lineno_v;
fa->funcname_a = funcname_a;
fa->funcname_v = funcname_v;
if (flags & FEVAL_UNWINDPROT)
add_unwind_protect (restore_funcarray_state, fa);
# if defined (DEBUGGER)
/* Have to figure out a better way to do this when `source' is supplied
arguments */
if ((flags & FEVAL_NOPUSHARGS) == 0)
{
if (shell_compatibility_level <= 44)
init_bash_argv ();
array_push (bash_argv_a, (char *)filename); /* XXX - unconditionally? */
tt[0] = '1'; tt[1] = '\0';
array_push (bash_argc_a, tt);
if (flags & FEVAL_UNWINDPROT)
add_unwind_protect (pop_args, 0);
}
# endif
#endif
/* set the flags to be passed to parse_and_execute */
pflags = SEVAL_RESETLINE|SEVAL_NOOPTIMIZE;
pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST;
if (flags & FEVAL_BUILTIN)
result = EXECUTION_SUCCESS;
return_val = setjmp_nosigs (return_catch);
/* If `return' was seen outside of a function, but in the script, then
force parse_and_execute () to clean up. */
if (return_val)
{
parse_and_execute_cleanup (-1);
result = return_catch_value;
}
else
result = parse_and_execute (string, filename, pflags);
if (flags & FEVAL_UNWINDPROT)
run_unwind_frame ("_evalfile");
else
{
if (flags & FEVAL_NONINT)
interactive = old_interactive;
#if defined (ARRAY_VARS)
restore_funcarray_state (fa);
# if defined (DEBUGGER)
if ((flags & FEVAL_NOPUSHARGS) == 0)
{
/* Don't need to call pop_args here until we do something better
when source is passed arguments (see above). */
array_pop (bash_argc_a);
array_pop (bash_argv_a);
}
# endif
#endif
return_catch_flag--;
sourcelevel--;
COPY_PROCENV (old_return_catch, return_catch);
}
/* If we end up with EOF after sourcing a file, which can happen when the file
doesn't end with a newline, pretend that it did. */
if (current_token == yacc_EOF)
push_token ('\n'); /* XXX */
return ((flags & FEVAL_BUILTIN) ? result : 1);
}
int
maybe_execute_file (fname, force_noninteractive)
const char *fname;
int force_noninteractive;
{
char *filename;
int result, flags;
filename = bash_tilde_expand (fname, 0);
flags = FEVAL_ENOENTOK;
if (force_noninteractive)
flags |= FEVAL_NONINT;
result = _evalfile (filename, flags);
free (filename);
return result;
}
int
force_execute_file (fname, force_noninteractive)
const char *fname;
int force_noninteractive;
{
char *filename;
int result, flags;
filename = bash_tilde_expand (fname, 0);
flags = 0;
if (force_noninteractive)
flags |= FEVAL_NONINT;
result = _evalfile (filename, flags);
free (filename);
return result;
}
#if defined (HISTORY)
int
fc_execute_file (filename)
const char *filename;
{
int flags;
/* We want these commands to show up in the history list if
remember_on_history is set. We use FEVAL_BUILTIN to return
the result of parse_and_execute. */
flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE|FEVAL_BUILTIN;
return (_evalfile (filename, flags));
}
#endif /* HISTORY */
int
source_file (filename, sflags)
const char *filename;
int sflags;
{
int flags, rval;
flags = FEVAL_BUILTIN|FEVAL_UNWINDPROT|FEVAL_NONINT;
if (sflags)
flags |= FEVAL_NOPUSHARGS;
/* POSIX shells exit if non-interactive and file error. */
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
flags |= FEVAL_LONGJMP;
rval = _evalfile (filename, flags);
run_return_trap ();
return rval;
}

843
builtins/evalstring.c Normal file
View file

@ -0,0 +1,843 @@
/* evalstring.c - evaluate a string as one or more shell commands. */
/* Copyright (C) 1996-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include "filecntl.h"
#include "../bashansi.h"
#include "../shell.h"
#include "../jobs.h"
#include "../builtins.h"
#include "../flags.h"
#include "../parser.h"
#include "../input.h"
#include "../execute_cmd.h"
#include "../redir.h"
#include "../trap.h"
#include "../bashintl.h"
#include <y.tab.h>
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#include "common.h"
#include "builtext.h"
#if !defined (errno)
extern int errno;
#endif
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
int parse_and_execute_level = 0;
static int cat_file PARAMS((REDIRECT *));
#define PE_TAG "parse_and_execute top"
#define PS_TAG "parse_string top"
#if defined (HISTORY)
static void
set_history_remembering ()
{
remember_on_history = enable_history_list;
}
#endif
static void
restore_lastcom (x)
char *x;
{
FREE (the_printed_command_except_trap);
the_printed_command_except_trap = x;
}
int
should_optimize_fork (command, subshell)
COMMAND *command;
int subshell;
{
return (running_trap == 0 &&
command->type == cm_simple &&
signal_is_trapped (EXIT_TRAP) == 0 &&
signal_is_trapped (ERROR_TRAP) == 0 &&
any_signals_trapped () < 0 &&
(subshell || (command->redirects == 0 && command->value.Simple->redirects == 0)) &&
((command->flags & CMD_TIME_PIPELINE) == 0) &&
((command->flags & CMD_INVERT_RETURN) == 0));
}
/* This has extra tests to account for STARTUP_STATE == 2, which is for
-c command but has been extended to command and process substitution
(basically any time you call parse_and_execute in a subshell). */
int
should_suppress_fork (command)
COMMAND *command;
{
int subshell;
subshell = subshell_environment & SUBSHELL_PROCSUB; /* salt to taste */
return (startup_state == 2 && parse_and_execute_level == 1 &&
*bash_input.location.string == '\0' &&
parser_expanding_alias () == 0 &&
should_optimize_fork (command, subshell));
}
int
can_optimize_connection (command)
COMMAND *command;
{
return (*bash_input.location.string == '\0' &&
parser_expanding_alias () == 0 &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
command->value.Connection->second->type == cm_simple);
}
void
optimize_connection_fork (command)
COMMAND *command;
{
if (command->type == cm_connection &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
(command->value.Connection->second->flags & CMD_TRY_OPTIMIZING) &&
(should_suppress_fork (command->value.Connection->second) ||
((subshell_environment & SUBSHELL_PAREN) && should_optimize_fork (command->value.Connection->second, 0))))
{
command->value.Connection->second->flags |= CMD_NO_FORK;
command->value.Connection->second->value.Simple->flags |= CMD_NO_FORK;
}
}
void
optimize_subshell_command (command)
COMMAND *command;
{
if (should_optimize_fork (command, 0))
{
command->flags |= CMD_NO_FORK;
command->value.Simple->flags |= CMD_NO_FORK;
}
else if (command->type == cm_connection &&
(command->value.Connection->connector == AND_AND || command->value.Connection->connector == OR_OR || command->value.Connection->connector == ';') &&
command->value.Connection->second->type == cm_simple &&
parser_expanding_alias () == 0)
{
command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
}
}
void
optimize_shell_function (command)
COMMAND *command;
{
COMMAND *fc;
fc = (command->type == cm_group) ? command->value.Group->command : command;
if (fc->type == cm_simple && should_suppress_fork (fc))
{
fc->flags |= CMD_NO_FORK;
fc->value.Simple->flags |= CMD_NO_FORK;
}
else if (fc->type == cm_connection && can_optimize_connection (fc) && should_suppress_fork (fc->value.Connection->second))
{
fc->value.Connection->second->flags |= CMD_NO_FORK;
fc->value.Connection->second->value.Simple->flags |= CMD_NO_FORK;
}
}
int
can_optimize_cat_file (command)
COMMAND *command;
{
return (command->type == cm_simple && !command->redirects &&
(command->flags & CMD_TIME_PIPELINE) == 0 &&
command->value.Simple->words == 0 &&
command->value.Simple->redirects &&
command->value.Simple->redirects->next == 0 &&
command->value.Simple->redirects->instruction == r_input_direction &&
command->value.Simple->redirects->redirector.dest == 0);
}
/* How to force parse_and_execute () to clean up after itself. */
void
parse_and_execute_cleanup (old_running_trap)
int old_running_trap;
{
if (running_trap > 0)
{
/* We assume if we have a different value for running_trap than when
we started (the only caller that cares is evalstring()), the
original caller will perform the cleanup, and we should not step
on them. */
if (running_trap != old_running_trap)
run_trap_cleanup (running_trap - 1);
unfreeze_jobs_list ();
}
if (have_unwind_protects ())
run_unwind_frame (PE_TAG);
else
parse_and_execute_level = 0; /* XXX */
}
static void
parse_prologue (string, flags, tag)
char *string;
int flags;
char *tag;
{
char *orig_string, *lastcom;
int x;
orig_string = string;
/* Unwind protect this invocation of parse_and_execute (). */
begin_unwind_frame (tag);
unwind_protect_int (parse_and_execute_level);
unwind_protect_jmp_buf (top_level);
unwind_protect_int (indirection_level);
unwind_protect_int (line_number);
unwind_protect_int (line_number_for_err_trap);
unwind_protect_int (loop_level);
unwind_protect_int (executing_list);
unwind_protect_int (comsub_ignore_return);
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
unwind_protect_int (interactive);
#if defined (HISTORY)
if (parse_and_execute_level == 0)
add_unwind_protect (set_history_remembering, (char *)NULL);
else
unwind_protect_int (remember_on_history); /* can be used in scripts */
# if defined (BANG_HISTORY)
unwind_protect_int (history_expansion_inhibited);
# endif /* BANG_HISTORY */
#endif /* HISTORY */
if (interactive_shell)
{
x = get_current_prompt_level ();
add_unwind_protect (set_current_prompt_level, x);
}
if (the_printed_command_except_trap)
{
lastcom = savestring (the_printed_command_except_trap);
add_unwind_protect (restore_lastcom, lastcom);
}
add_unwind_protect (pop_stream, (char *)NULL);
if (parser_expanding_alias ())
add_unwind_protect (parser_restore_alias, (char *)NULL);
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
add_unwind_protect (xfree, orig_string);
end_unwind_frame ();
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
#if defined (HISTORY)
if (flags & SEVAL_NOHIST)
bash_history_disable ();
# if defined (BANG_HISTORY)
if (flags & SEVAL_NOHISTEXP)
history_expansion_inhibited = 1;
# endif /* BANG_HISTORY */
#endif /* HISTORY */
}
/* Parse and execute the commands in STRING. Returns whatever
execute_command () returns. This frees STRING. FLAGS is a
flags word; look in common.h for the possible values. Actions
are:
(flags & SEVAL_NONINT) -> interactive = 0;
(flags & SEVAL_INTERACT) -> interactive = 1;
(flags & SEVAL_NOHIST) -> call bash_history_disable ()
(flags & SEVAL_NOFREE) -> don't free STRING when finished
(flags & SEVAL_RESETLINE) -> reset line_number to 1
(flags & SEVAL_NOHISTEXP) -> history_expansion_inhibited -> 1
(flags & SEVAL_NOOPTIMIZE) -> don't try to turn on optimizing flags
*/
int
parse_and_execute (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
int code, lreset;
volatile int should_jump_to_top_level, last_result;
COMMAND *volatile command;
volatile sigset_t pe_sigmask;
parse_prologue (string, flags, PE_TAG);
parse_and_execute_level++;
lreset = flags & SEVAL_RESETLINE;
#if defined (HAVE_POSIX_SIGNALS)
/* If we longjmp and are going to go on, use this to restore signal mask */
sigemptyset ((sigset_t *)&pe_sigmask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, (sigset_t *)&pe_sigmask);
#endif
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
0; the first line number is 1). */
push_stream (lreset);
if (parser_expanding_alias ())
/* push current shell_input_line */
parser_save_alias ();
if (lreset == 0)
line_number--;
indirection_level++;
code = should_jump_to_top_level = 0;
last_result = EXECUTION_SUCCESS;
/* We need to reset enough of the token state so we can start fresh. */
if (current_token == yacc_EOF)
current_token = '\n'; /* reset_parser() ? */
with_input_from_string (string, from_file);
clear_shell_input_line ();
while (*(bash_input.location.string) || parser_expanding_alias ())
{
command = (COMMAND *)NULL;
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_nosigs (top_level);
if (code)
{
should_jump_to_top_level = 0;
switch (code)
{
case ERREXIT:
/* variable_context -> 0 is what eval.c:reader_loop() does in
these circumstances. Don't bother with cleanup here because
we don't want to run the function execution cleanup stuff
that will cause pop_context and other functions to run.
We call reset_local_contexts() instead, which just frees
context memory.
XXX - change that if we want the function context to be
unwound. */
if (exit_immediately_on_error && variable_context)
{
discard_unwind_frame ("pe_dispose");
reset_local_contexts (); /* not in a function */
}
should_jump_to_top_level = 1;
goto out;
case FORCE_EOF:
case EXITPROG:
if (command)
run_unwind_frame ("pe_dispose");
/* Remember to call longjmp (top_level) after the old
value for it is restored. */
should_jump_to_top_level = 1;
goto out;
case EXITBLTIN:
if (command)
{
if (variable_context && signal_is_trapped (0))
{
/* Let's make sure we run the exit trap in the function
context, as we do when not running parse_and_execute.
The pe_dispose unwind frame comes before any unwind-
protects installed by the string we're evaluating, so
it will undo the current function scope. */
dispose_command (command);
discard_unwind_frame ("pe_dispose");
}
else
run_unwind_frame ("pe_dispose");
}
should_jump_to_top_level = 1;
goto out;
case DISCARD:
if (command)
run_unwind_frame ("pe_dispose");
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
set_pipestatus_from_exit (last_command_exit_value);
if (subshell_environment)
{
should_jump_to_top_level = 1;
goto out;
}
else
{
#if 0
dispose_command (command); /* pe_dispose does this */
#endif
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask (SIG_SETMASK, (sigset_t *)&pe_sigmask, (sigset_t *)NULL);
#endif
continue;
}
default:
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
break;
}
}
if (parse_command () == 0)
{
int local_expalias, local_alflag;
if ((flags & SEVAL_PARSEONLY) || (interactive_shell == 0 && read_but_dont_execute))
{
last_result = EXECUTION_SUCCESS;
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else if (command = global_command)
{
struct fd_bitmap *bitmap;
if (flags & SEVAL_FUNCDEF)
{
char *x;
/* If the command parses to something other than a straight
function definition, or if we have not consumed the entire
string, or if the parser has transformed the function
name (as parsing will if it begins or ends with shell
whitespace, for example), reject the attempt */
if (command->type != cm_function_def ||
((x = parser_remaining_input ()) && *x) ||
(STREQ (from_file, command->value.Function_def->name->word) == 0))
{
internal_warning (_("%s: ignoring function definition attempt"), from_file);
should_jump_to_top_level = 0;
last_result = last_command_exit_value = EX_BADUSAGE;
set_pipestatus_from_exit (last_command_exit_value);
reset_parser ();
break;
}
}
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
begin_unwind_frame ("pe_dispose");
add_unwind_protect (dispose_fd_bitmap, bitmap);
add_unwind_protect (dispose_command, command); /* XXX */
global_command = (COMMAND *)NULL;
if ((subshell_environment & SUBSHELL_COMSUB) && comsub_ignore_return)
command->flags |= CMD_IGNORE_RETURN;
#if defined (ONESHOT)
/*
* IF
* we were invoked as `bash -c' (startup_state == 2) AND
* parse_and_execute has not been called recursively AND
* we're not running a trap AND
* we have parsed the full command (string == '\0') AND
* we're not going to run the exit trap AND
* we have a simple command without redirections AND
* the command is not being timed AND
* the command's return status is not being inverted AND
* there aren't any traps in effect
* THEN
* tell the execution code that we don't need to fork
*/
if (should_suppress_fork (command))
{
command->flags |= CMD_NO_FORK;
command->value.Simple->flags |= CMD_NO_FORK;
}
/* Can't optimize forks out here execept for simple commands.
This knows that the parser sets up commands as left-side heavy
(&& and || are left-associative) and after the single parse,
if we are at the end of the command string, the last in a
series of connection commands is
command->value.Connection->second. */
else if (command->type == cm_connection &&
(flags & SEVAL_NOOPTIMIZE) == 0 &&
can_optimize_connection (command))
{
command->value.Connection->second->flags |= CMD_TRY_OPTIMIZING;
command->value.Connection->second->value.Simple->flags |= CMD_TRY_OPTIMIZING;
}
#endif /* ONESHOT */
/* We play tricks in the parser and command_substitute() turning
expand_aliases on and off depending on which parsing pass and
whether or not we're in posix mode. This only matters for
parsing, and we let the higher layers deal with that. We just
want to ensure that expand_aliases is set to the appropriate
global value when we go to execute this command, so we save
and restore it around the execution (we don't restore it if
the global value of the flag (expaliases_flag) changes). */
local_expalias = expand_aliases;
local_alflag = expaliases_flag;
if (subshell_environment & SUBSHELL_COMSUB)
expand_aliases = expaliases_flag;
/* See if this is a candidate for $( <file ). */
if (startup_state == 2 &&
(subshell_environment & SUBSHELL_COMSUB) &&
*bash_input.location.string == '\0' &&
can_optimize_cat_file (command))
{
int r;
r = cat_file (command->value.Simple->redirects);
last_result = (r < 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
}
else
last_result = execute_command_internal
(command, 0, NO_PIPE, NO_PIPE, bitmap);
dispose_command (command);
dispose_fd_bitmap (bitmap);
discard_unwind_frame ("pe_dispose");
/* If the global value didn't change, we restore what we had. */
if ((subshell_environment & SUBSHELL_COMSUB) && local_alflag == expaliases_flag)
expand_aliases = local_expalias;
if (flags & SEVAL_ONECMD)
{
reset_parser ();
break;
}
}
}
else
{
last_result = EX_BADUSAGE; /* was EXECUTION_FAILURE */
if (interactive_shell == 0 && this_shell_builtin &&
(this_shell_builtin == source_builtin || this_shell_builtin == eval_builtin) &&
last_command_exit_value == EX_BADSYNTAX && posixly_correct && executing_command_builtin == 0)
{
should_jump_to_top_level = 1;
code = ERREXIT;
last_command_exit_value = EX_BADUSAGE;
}
/* Since we are shell compatible, syntax errors in a script
abort the execution of the script. Right? */
break;
}
}
out:
run_unwind_frame (PE_TAG);
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 ();
}
CHECK_TERMSIG;
if (should_jump_to_top_level)
jump_to_top_level (code);
return (last_result);
}
/* Parse a command contained in STRING according to FLAGS and return the
number of characters consumed from the string. If non-NULL, set *ENDP
to the position in the string where the parse ended. Used to validate
command substitutions during parsing to obey Posix rules about finding
the end of the command and balancing parens. */
int
parse_string (string, from_file, flags, cmdp, endp)
char *string;
const char *from_file;
int flags;
COMMAND **cmdp;
char **endp;
{
int code, nc;
volatile int should_jump_to_top_level;
COMMAND *volatile command, *oglobal;
char *ostring;
volatile sigset_t ps_sigmask;
parse_prologue (string, flags, PS_TAG);
#if defined (HAVE_POSIX_SIGNALS)
/* If we longjmp and are going to go on, use this to restore signal mask */
sigemptyset ((sigset_t *)&ps_sigmask);
sigprocmask (SIG_BLOCK, (sigset_t *)NULL, (sigset_t *)&ps_sigmask);
#endif
/* Reset the line number if the caller wants us to. If we don't reset the
line number, we have to subtract one, because we will add one just
before executing the next command (resetting the line number sets it to
0; the first line number is 1). */
push_stream (0);
if (parser_expanding_alias ())
/* push current shell_input_line */
parser_save_alias ();
code = should_jump_to_top_level = 0;
oglobal = global_command;
with_input_from_string (string, from_file);
ostring = bash_input.location.string;
while (*(bash_input.location.string)) /* XXX - parser_expanding_alias () ? */
{
command = (COMMAND *)NULL;
#if 0
if (interrupt_state)
break;
#endif
/* Provide a location for functions which `longjmp (top_level)' to
jump to. */
code = setjmp_nosigs (top_level);
if (code)
{
INTERNAL_DEBUG(("parse_string: longjmp executed: code = %d", code));
should_jump_to_top_level = 0;
switch (code)
{
case FORCE_EOF:
case ERREXIT:
case EXITPROG:
case EXITBLTIN:
case DISCARD: /* XXX */
if (command)
dispose_command (command);
/* Remember to call longjmp (top_level) after the old
value for it is restored. */
should_jump_to_top_level = 1;
goto out;
default:
#if defined (HAVE_POSIX_SIGNALS)
sigprocmask (SIG_SETMASK, (sigset_t *)&ps_sigmask, (sigset_t *)NULL);
#endif
command_error ("parse_string", CMDERR_BADJUMP, code, 0);
break;
}
}
if (parse_command () == 0)
{
if (cmdp)
*cmdp = global_command;
else
dispose_command (global_command);
global_command = (COMMAND *)NULL;
}
else
{
if ((flags & SEVAL_NOLONGJMP) == 0)
{
should_jump_to_top_level = 1;
code = DISCARD;
}
else
reset_parser (); /* XXX - sets token_to_read */
break;
}
if (current_token == yacc_EOF || current_token == shell_eof_token)
{
if (current_token == shell_eof_token)
rewind_input_string ();
break;
}
}
out:
global_command = oglobal;
nc = bash_input.location.string - ostring;
if (endp)
*endp = bash_input.location.string;
run_unwind_frame (PS_TAG);
/* If we return < 0, the caller (xparse_dolparen) will jump_to_top_level for
us, after doing cleanup */
if (should_jump_to_top_level)
{
if (parse_and_execute_level == 0)
top_level_cleanup ();
if (code == DISCARD)
return -DISCARD;
jump_to_top_level (code);
}
return (nc);
}
int
open_redir_file (r, fnp)
REDIRECT *r;
char **fnp;
{
char *fn;
int fd, rval;
if (r->instruction != r_input_direction)
return -1;
/* Get the filename. */
if (posixly_correct && !interactive_shell)
disallow_filename_globbing++;
fn = redirection_expand (r->redirectee.filename);
if (posixly_correct && !interactive_shell)
disallow_filename_globbing--;
if (fn == 0)
{
redirection_error (r, AMBIGUOUS_REDIRECT, fn);
return -1;
}
fd = open(fn, O_RDONLY);
if (fd < 0)
{
file_error (fn);
free (fn);
if (fnp)
*fnp = 0;
return -1;
}
if (fnp)
*fnp = fn;
else
free (fn);
return fd;
}
/* Handle a $( < file ) command substitution. This expands the filename,
returning errors as appropriate, then just cats the file to the standard
output. */
static int
cat_file (r)
REDIRECT *r;
{
char *fn;
int fd, rval;
fd = open_redir_file (r, &fn);
if (fd < 0)
return -1;
rval = zcatfd (fd, 1, fn);
free (fn);
close (fd);
return (rval);
}
int
evalstring (string, from_file, flags)
char *string;
const char *from_file;
int flags;
{
volatile int r, rflag, rcatch;
volatile int was_trap;
/* Are we running a trap when we execute this function? */
was_trap = running_trap;
rcatch = 0;
rflag = return_catch_flag;
/* If we are in a place where `return' is valid, we have to catch
`eval "... return"' and make sure parse_and_execute cleans up. Then
we can trampoline to the previous saved return_catch location. */
if (rflag)
{
begin_unwind_frame ("evalstring");
unwind_protect_int (return_catch_flag);
unwind_protect_jmp_buf (return_catch);
return_catch_flag++; /* increment so we have a counter */
rcatch = setjmp_nosigs (return_catch);
}
if (rcatch)
{
/* We care about whether or not we are running the same trap we were
when we entered this function. */
parse_and_execute_cleanup (was_trap);
r = return_catch_value;
}
else
/* Note that parse_and_execute () frees the string it is passed. */
r = parse_and_execute (string, from_file, flags);
if (rflag)
{
run_unwind_frame ("evalstring");
if (rcatch && return_catch_flag)
{
return_catch_value = r;
sh_longjmp (return_catch, 1);
}
}
return (r);
}

276
builtins/exec.def Normal file
View file

@ -0,0 +1,276 @@
This file is exec.def, from which is created exec.c.
It implements the builtin "exec" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES exec.c
$BUILTIN exec
$FUNCTION exec_builtin
$SHORT_DOC exec [-cl] [-a name] [command [argument ...]] [redirection ...]
Replace the shell with the given command.
Execute COMMAND, replacing this shell with the specified program.
ARGUMENTS become the arguments to COMMAND. If COMMAND is not specified,
any redirections take effect in the current shell.
Options:
-a name pass NAME as the zeroth argument to COMMAND
-c execute COMMAND with an empty environment
-l place a dash in the zeroth argument to COMMAND
If the command cannot be executed, a non-interactive shell exits, unless
the shell option `execfail' is set.
Exit Status:
Returns success unless COMMAND is not found or a redirection error occurs.
$END
#include <config.h>
#include "../bashtypes.h"
#include "posixstat.h"
#include <signal.h>
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../findcmd.h"
#if defined (JOB_CONTROL)
# include "../jobs.h"
#endif
#include "../flags.h"
#include "../trap.h"
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#include "common.h"
#include "bashgetopt.h"
#include "input.h"
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern REDIRECT *redirection_undo_list;
extern char *exec_argv0;
int no_exit_on_failed_exec;
/* If the user wants this to look like a login shell, then
prepend a `-' onto NAME and return the new name. */
static char *
mkdashname (name)
char *name;
{
char *ret;
ret = (char *)xmalloc (2 + strlen (name));
ret[0] = '-';
strcpy (ret + 1, name);
return ret;
}
int
exec_builtin (list)
WORD_LIST *list;
{
int exit_value = EXECUTION_FAILURE;
int cleanenv, login, opt, orig_job_control;
char *argv0, *command, **args, **env, *newname, *com2;
cleanenv = login = orig_job_control = 0;
exec_argv0 = argv0 = (char *)NULL;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "cla:")) != -1)
{
switch (opt)
{
case 'c':
cleanenv = 1;
break;
case 'l':
login = 1;
break;
case 'a':
argv0 = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* First, let the redirections remain. */
dispose_redirects (redirection_undo_list);
redirection_undo_list = (REDIRECT *)NULL;
if (list == 0)
return (EXECUTION_SUCCESS);
#if defined (RESTRICTED_SHELL)
if (restricted)
{
sh_restricted ((char *)NULL);
return (EXECUTION_FAILURE);
}
#endif /* RESTRICTED_SHELL */
args = strvec_from_word_list (list, 1, 0, (int *)NULL);
env = (char **)0;
/* A command with a slash anywhere in its name is not looked up in $PATH. */
command = absolute_program (args[0]) ? args[0] : search_for_command (args[0], 1);
if (command == 0)
{
if (file_isdir (args[0]))
{
#if defined (EISDIR)
builtin_error (_("%s: cannot execute: %s"), args[0], strerror (EISDIR));
#else
builtin_error (_("%s: cannot execute: %s"), args[0], strerror (errno));
#endif
exit_value = EX_NOEXEC;
}
else
{
sh_notfound (args[0]);
exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
}
goto failed_exec;
}
com2 = full_pathname (command);
if (com2)
{
if (command != args[0])
free (command);
command = com2;
}
if (argv0)
{
free (args[0]);
args[0] = login ? mkdashname (argv0) : savestring (argv0);
exec_argv0 = savestring (args[0]);
}
else if (login)
{
newname = mkdashname (args[0]);
free (args[0]);
args[0] = newname;
}
/* Decrement SHLVL by 1 so a new shell started here has the same value,
preserving the appearance. After we do that, we need to change the
exported environment to include the new value. If we've already forked
and are in a subshell, we don't want to decrement the shell level,
since we are `increasing' the level */
if (cleanenv == 0 && (subshell_environment & SUBSHELL_PAREN) == 0)
adjust_shell_level (-1);
if (cleanenv)
{
env = strvec_create (1);
env[0] = (char *)0;
}
else
{
maybe_make_export_env ();
env = export_env;
}
#if defined (HISTORY)
if (interactive_shell && subshell_environment == 0)
maybe_save_shell_history ();
#endif /* HISTORY */
reset_signal_handlers (); /* leave trap strings in place */
#if defined (JOB_CONTROL)
orig_job_control = job_control; /* XXX - was also interactive_shell */
if (subshell_environment == 0)
end_job_control ();
if (interactive || job_control)
default_tty_job_signals (); /* undo initialize_job_signals */
#endif /* JOB_CONTROL */
#if defined (BUFFERED_INPUT)
if (default_buffered_input >= 0)
sync_buffered_stream (default_buffered_input);
#endif
exit_value = shell_execve (command, args, env);
/* We have to set this to NULL because shell_execve has called realloc()
to stuff more items at the front of the array, which may have caused
the memory to be freed by realloc(). We don't want to free it twice. */
args = (char **)NULL;
if (cleanenv == 0)
adjust_shell_level (1);
if (exit_value == EX_NOTFOUND) /* no duplicate error message */
goto failed_exec;
else if (executable_file (command) == 0)
{
builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
}
else
file_error (command);
failed_exec:
FREE (command);
if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
exit_shell (last_command_exit_value = exit_value);
if (args)
strvec_dispose (args);
if (env && env != export_env)
strvec_dispose (env);
/* If we're not exiting after the exec fails, we restore the shell signal
handlers and then modify the signal dispositions based on the trap strings
before the failed exec. */
initialize_signals (1);
restore_traps ();
#if defined (JOB_CONTROL)
if (orig_job_control)
restart_job_control ();
#endif /* JOB_CONTROL */
return (exit_value);
}

169
builtins/exit.def Normal file
View file

@ -0,0 +1,169 @@
This file is exit.def, from which is created exit.c.
It implements the builtins "exit", and "logout" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES exit.c
$BUILTIN exit
$FUNCTION exit_builtin
$SHORT_DOC exit [n]
Exit the shell.
Exits the shell with a status of N. If N is omitted, the exit status
is that of the last command executed.
$END
#include <config.h>
#include "../bashtypes.h"
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../jobs.h"
#include "../trap.h"
#include "common.h"
#include "builtext.h" /* for jobs_builtin */
extern int check_jobs_at_exit;
static int exit_or_logout PARAMS((WORD_LIST *));
static int sourced_logout;
int
exit_builtin (list)
WORD_LIST *list;
{
CHECK_HELPOPT (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 [n]
Exit a login shell.
Exits a login shell with exit status N. Returns an error if not executed
in a login shell.
$END
/* How to logout. */
int
logout_builtin (list)
WORD_LIST *list;
{
CHECK_HELPOPT (list);
if (login_shell == 0 /* && interactive */)
{
builtin_error (_("not login shell: use `exit'"));
return (EXECUTION_FAILURE);
}
else
return (exit_or_logout (list));
}
static int
exit_or_logout (list)
WORD_LIST *list;
{
int exit_value;
#if defined (JOB_CONTROL)
int exit_immediate_okay, stopmsg;
exit_immediate_okay = (interactive == 0 ||
last_shell_builtin == exit_builtin ||
last_shell_builtin == logout_builtin ||
last_shell_builtin == jobs_builtin);
/* Check for stopped jobs if the user wants to. */
if (exit_immediate_okay == 0)
{
register int i;
for (i = stopmsg = 0; i < js.j_jobslots; i++)
if (jobs[i] && STOPPED (i))
stopmsg = JSTOPPED;
else if (check_jobs_at_exit && stopmsg == 0 && jobs[i] && RUNNING (i))
stopmsg = JRUNNING;
if (stopmsg == JSTOPPED)
fprintf (stderr, _("There are stopped jobs.\n"));
else if (stopmsg == JRUNNING)
fprintf (stderr, _("There are running jobs.\n"));
if (stopmsg && check_jobs_at_exit)
list_all_jobs (JLIST_STANDARD);
if (stopmsg)
{
/* This is NOT superfluous because EOF can get here without
going through the command parser. Set both last and this
so that either `exit', `logout', or ^D will work to exit
immediately if nothing intervenes. */
this_shell_builtin = last_shell_builtin = exit_builtin;
return (EXECUTION_FAILURE);
}
}
#endif /* JOB_CONTROL */
/* Get return value if present. This means that you can type
`logout 5' to a shell, and it returns 5. */
/* If we're running the exit trap (running_trap == 1, since running_trap
gets set to SIG+1), and we don't have a argument given to `exit'
(list == 0), use the exit status we saved before running the trap
commands (trap_saved_exit_value). */
exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list);
bash_logout ();
last_command_exit_value = exit_value;
/* Exit the program. */
jump_to_top_level (EXITBLTIN);
/*NOTREACHED*/
}
void
bash_logout ()
{
/* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
if (login_shell && sourced_logout++ == 0 && subshell_environment == 0)
{
maybe_execute_file ("~/.bash_logout", 1);
#ifdef SYS_BASH_LOGOUT
maybe_execute_file (SYS_BASH_LOGOUT, 1);
#endif
}
}

785
builtins/fc.def Normal file
View file

@ -0,0 +1,785 @@
This file is fc.def, from which is created fc.c.
It implements the builtin "fc" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES fc.c
$BUILTIN fc
$FUNCTION fc_builtin
$DEPENDS_ON HISTORY
$SHORT_DOC fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
fc is used to list or edit and re-execute commands from the history list.
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.
Options:
-e ENAME select which editor to use. Default is FCEDIT, then EDITOR,
then vi
-l list lines instead of editing
-n omit line numbers when listing
-r reverse the order of the lines (newest listed first)
With the `fc -s [pat=rep ...] [command]' format, 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.
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
$END
#include <config.h>
#if defined (HISTORY)
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#include "../bashtypes.h"
#include "posixstat.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <chartypes.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include "../shell.h"
#include "../builtins.h"
#include "../flags.h"
#include "../parser.h"
#include "../bashhist.h"
#include "maxpath.h"
#include <readline/history.h>
#include "bashgetopt.h"
#include "common.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
#define HIST_INVALID INT_MIN
#define HIST_ERANGE INT_MIN+1
#define HIST_NOTFOUND INT_MIN+2
/* Values for the flags argument to fc_gethnum */
#define HN_LISTING 0x01
#define HN_FIRST 0x02
extern int unlink PARAMS((const char *));
extern FILE *sh_mktmpfp PARAMS((char *, int, char **));
extern int suppress_debug_trap_verbose;
/* **************************************************************** */
/* */
/* The K*rn shell style fc command (Fix Command) */
/* */
/* **************************************************************** */
/* fc builtin command (fix command) for Bash for those who
like K*rn-style history better than csh-style.
fc [-e ename] [-nlr] [first] [last]
FIRST and LAST can be numbers specifying the range, or FIRST can be
a string, which means the most recent command beginning with that
string.
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
then the editor which corresponds to the current readline editing
mode, then vi.
-l means list lines instead of editing.
-n means no line numbers listed.
-r means reverse the order of the lines (making it newest listed first).
fc -e - [pat=rep ...] [command]
fc -s [pat=rep ...] [command]
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
*/
/* Data structure describing a list of global replacements to perform. */
typedef struct repl {
struct repl *next;
char *pat;
char *rep;
} REPL;
/* Accessors for HIST_ENTRY lists that are called HLIST. */
#define histline(i) (hlist[(i)]->line)
#define histdata(i) (hlist[(i)]->data)
#define FREE_RLIST() \
do { \
for (rl = rlist; rl; ) { \
REPL *r; \
r = rl->next; \
if (rl->pat) \
free (rl->pat); \
if (rl->rep) \
free (rl->rep); \
free (rl); \
rl = r; \
} \
} while (0)
static char *fc_dosubs PARAMS((char *, REPL *));
static char *fc_gethist PARAMS((char *, HIST_ENTRY **, int));
static int fc_gethnum PARAMS((char *, HIST_ENTRY **, int));
static int fc_number PARAMS((WORD_LIST *));
static void fc_replhist PARAMS((char *));
#ifdef INCLUDE_UNUSED
static char *fc_readline PARAMS((FILE *));
static void fc_addhist PARAMS((char *));
#endif
static void
set_verbose_flag ()
{
echo_input_at_read = verbose_flag;
}
/* String to execute on a file that we want to edit. */
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
#if defined (STRICT_POSIX)
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-ed}"
#else
# define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
#endif
int
fc_builtin (list)
WORD_LIST *list;
{
register int i;
register char *sep;
int numbering, reverse, listing, execute;
int histbeg, histend, last_hist, retval, opt, rh, real_last;
FILE *stream;
REPL *rlist, *rl;
char *ename, *command, *newcom, *fcedit;
HIST_ENTRY **hlist;
char *fn;
numbering = 1;
reverse = listing = execute = 0;
ename = (char *)NULL;
/* Parse out the options and set which of the two forms we're in. */
reset_internal_getopt ();
lcurrent = list; /* XXX */
while (fc_number (loptend = lcurrent) == 0 &&
(opt = internal_getopt (list, ":e:lnrs")) != -1)
{
switch (opt)
{
case 'n':
numbering = 0;
break;
case 'l':
listing = HN_LISTING; /* for fc_gethnum */
break;
case 'r':
reverse = 1;
break;
case 's':
execute = 1;
break;
case 'e':
ename = list_optarg;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (ename && (*ename == '-') && (ename[1] == '\0'))
execute = 1;
/* The "execute" form of the command (re-run, with possible string
substitutions). */
if (execute)
{
rlist = (REPL *)NULL;
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
{
*sep++ = '\0';
rl = (REPL *)xmalloc (sizeof (REPL));
rl->next = (REPL *)NULL;
rl->pat = savestring (list->word->word);
rl->rep = savestring (sep);
if (rlist == NULL)
rlist = rl;
else
{
rl->next = rlist;
rlist = rl;
}
list = list->next;
}
/* If we have a list of substitutions to do, then reverse it
to get the replacements in the proper order. */
rlist = REVERSE_LIST (rlist, REPL *);
hlist = history_list ();
/* If we still have something in list, it is a command spec.
Otherwise, we use the most recent command in time. */
command = fc_gethist (list ? list->word->word : (char *)NULL, hlist, 0);
if (command == NULL)
{
builtin_error (_("no command found"));
if (rlist)
FREE_RLIST ();
return (EXECUTION_FAILURE);
}
if (rlist)
{
newcom = fc_dosubs (command, rlist);
free (command);
FREE_RLIST ();
command = newcom;
}
fprintf (stderr, "%s\n", command);
fc_replhist (command); /* replace `fc -s' with command */
/* Posix says that the re-executed commands should be entered into the
history. */
return (parse_and_execute (command, "fc", SEVAL_NOHIST));
}
/* This is the second form of the command (the list-or-edit-and-rerun
form). */
hlist = history_list ();
if (hlist == 0)
return (EXECUTION_SUCCESS);
for (i = 0; hlist[i]; i++);
/* With the Bash implementation of history, the current command line
("fc blah..." and so on) is already part of the history list by
the time we get to this point. This just skips over that command
and makes the last command that this deals with be the last command
the user entered before the fc. We need to check whether the
line was actually added (HISTIGNORE may have caused it to not be),
so we check hist_last_line_added. */
/* Even though command substitution through parse_and_execute turns off
remember_on_history, command substitution in a shell when set -o history
has been enabled (interactive or not) should use it in the last_hist
calculation as if it were on. */
rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
last_hist = i - rh - hist_last_line_added;
/* Make sure that real_last is calculated the same way here and in
fc_gethnum. The return value from fc_gethnum is treated specially if
it is == real_last and we are listing commands. */
real_last = i;
/* back up from the end to the last non-null history entry */
while (hlist[real_last] == 0 && real_last > 0)
real_last--;
/* XXX */
if (i == last_hist && hlist[last_hist] == 0)
while (last_hist >= 0 && hlist[last_hist] == 0)
last_hist--;
if (last_hist < 0)
last_hist = 0; /* per POSIX */
if (list)
{
histbeg = fc_gethnum (list->word->word, hlist, listing|HN_FIRST);
list = list->next;
if (list)
histend = fc_gethnum (list->word->word, hlist, listing);
else if (histbeg == real_last)
histend = listing ? real_last : histbeg;
else
histend = listing ? last_hist : histbeg;
}
else
{
/* The default for listing is the last 16 history items. */
if (listing)
{
histend = last_hist;
histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
if (histbeg < 0)
histbeg = 0;
}
else
/* For editing, it is the last history command. */
histbeg = histend = last_hist;
}
if (histbeg == HIST_INVALID || histend == HIST_INVALID)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
{
builtin_error (_("no command found"));
return (EXECUTION_FAILURE);
}
/* We don't throw an error for line specifications out of range, per POSIX */
if (histbeg < 0)
histbeg = 0;
if (histend < 0)
histend = 0;
/* "When not listing, the fc command that caused the editing shall not be
entered into the history list." */
if (listing == 0 && hist_last_line_added)
{
bash_delete_last_history ();
/* If we're editing a single command -- the last command in the
history -- and we just removed the dummy command added by
edit_and_execute_command (), we need to check whether or not we
just removed the last command in the history and need to back
the pointer up. remember_on_history is off because we're running
in parse_and_execute(). */
if (histbeg == histend && histend == last_hist && hlist[last_hist] == 0)
last_hist = histbeg = --histend;
if (hlist[last_hist] == 0)
last_hist--;
if (histend >= last_hist)
histend = last_hist;
else if (histbeg >= last_hist)
histbeg = last_hist;
}
if (histbeg == HIST_INVALID || histend == HIST_INVALID)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
else if (histbeg == HIST_ERANGE || histend == HIST_ERANGE)
{
sh_erange ((char *)NULL, _("history specification"));
return (EXECUTION_FAILURE);
}
else if (histbeg == HIST_NOTFOUND || histend == HIST_NOTFOUND)
{
builtin_error (_("no command found"));
return (EXECUTION_FAILURE);
}
/* We don't throw an error for line specifications out of range, per POSIX */
if (histbeg < 0)
histbeg = 0;
if (histend < 0)
histend = 0;
if (histend < histbeg)
{
i = histend;
histend = histbeg;
histbeg = i;
reverse = 1;
}
if (listing)
stream = stdout;
else
{
numbering = 0;
stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
if (stream == 0)
{
builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
FREE (fn);
return (EXECUTION_FAILURE);
}
}
for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
{
QUIT;
if (hlist[i] == 0)
continue;
if (numbering)
fprintf (stream, "%d", i + history_base);
if (listing)
{
if (posixly_correct)
fputs ("\t", stream);
else
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
}
if (histline (i))
fprintf (stream, "%s\n", histline (i));
}
if (listing)
return (sh_chkwrite (EXECUTION_SUCCESS));
fflush (stream);
if (ferror (stream))
{
sh_wrerror ();
fclose (stream);
FREE (fn);
return (EXECUTION_FAILURE);
}
fclose (stream);
/* Now edit the file of commands. */
if (ename)
{
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
sprintf (command, "%s %s", ename, fn);
}
else
{
fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
sprintf (command, "%s %s", fcedit, fn);
}
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
if (retval != EXECUTION_SUCCESS)
{
unlink (fn);
free (fn);
return (EXECUTION_FAILURE);
}
#if defined (READLINE)
/* If we're executing as part of a dispatched readline command like
{emacs,vi}_edit_and_execute_command, the readline state will indicate it.
We could remove the partial command from the history, but ksh93 doesn't
so we stay compatible. */
#endif
/* Make sure parse_and_execute doesn't turn this off, even though a
call to parse_and_execute farther up the function call stack (e.g.,
if this is called by vi_edit_and_execute_command) may have already
called bash_history_disable. */
remember_on_history = 1;
/* Turn on the `v' flag while fc_execute_file runs so the commands
will be echoed as they are read by the parser. */
begin_unwind_frame ("fc builtin");
add_unwind_protect (xfree, fn);
add_unwind_protect (unlink, fn);
add_unwind_protect (set_verbose_flag, (char *)NULL);
unwind_protect_int (suppress_debug_trap_verbose);
echo_input_at_read = 1;
suppress_debug_trap_verbose = 1;
retval = fc_execute_file (fn);
run_unwind_frame ("fc builtin");
return (retval);
}
/* Return 1 if LIST->word->word is a legal number for fc's use. */
static int
fc_number (list)
WORD_LIST *list;
{
char *s;
if (list == 0)
return 0;
s = list->word->word;
if (*s == '-')
s++;
return (legal_number (s, (intmax_t *)NULL));
}
/* Return an absolute index into HLIST which corresponds to COMMAND. If
COMMAND is a number, then it was specified in relative terms. If it
is a string, then it is the start of a command line present in HLIST.
MODE includes HN_LISTING if we are listing commands, and does not if we
are executing them. If MODE includes HN_FIRST we are looking for the
first history number specification. */
static int
fc_gethnum (command, hlist, mode)
char *command;
HIST_ENTRY **hlist;
int mode;
{
int sign, n, clen, rh;
register int i, j, last_hist, real_last, listing;
register char *s;
listing = mode & HN_LISTING;
sign = 1;
/* Count history elements. */
for (i = 0; hlist[i]; i++);
/* With the Bash implementation of history, the current command line
("fc blah..." and so on) is already part of the history list by
the time we get to this point. This just skips over that command
and makes the last command that this deals with be the last command
the user entered before the fc. We need to check whether the
line was actually added (HISTIGNORE may have caused it to not be),
so we check hist_last_line_added. This needs to agree with the
calculation of last_hist in fc_builtin above. */
/* Even though command substitution through parse_and_execute turns off
remember_on_history, command substitution in a shell when set -o history
has been enabled (interactive or not) should use it in the last_hist
calculation as if it were on. */
rh = remember_on_history || ((subshell_environment & SUBSHELL_COMSUB) && enable_history_list);
last_hist = i - rh - hist_last_line_added;
if (i == last_hist && hlist[last_hist] == 0)
while (last_hist >= 0 && hlist[last_hist] == 0)
last_hist--;
if (last_hist < 0)
return (-1);
real_last = i;
i = last_hist;
/* No specification defaults to most recent command. */
if (command == NULL)
return (i);
/* back up from the end to the last non-null history entry */
while (hlist[real_last] == 0 && real_last > 0)
real_last--;
/* 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;
/* We want to return something that is an offset to HISTORY_BASE. */
/* If the value is negative or zero, then it is an offset from
the current history item. */
/* We don't use HN_FIRST here, so we don't return different values
depending on whether we're looking for the first or last in a
pair of range arguments, but nobody else does, either. */
if (n < 0)
{
n += i + 1;
return (n < 0 ? 0 : n);
}
else if (n == 0)
return ((sign == -1) ? (listing ? real_last : HIST_INVALID) : i);
else
{
/* If we're out of range (greater than I (last history entry) or
less than HISTORY_BASE, we want to return different values
based on whether or not we are looking for the first or last
value in a desired range of history entries. */
n -= history_base;
if (n < 0)
return (mode & HN_FIRST ? 0 : i);
else if (n >= i)
return (mode & HN_FIRST ? 0 : i);
else
return n;
}
}
clen = strlen (command);
for (j = i; j >= 0; j--)
{
if (STREQN (command, histline (j), clen))
return (j);
}
return (HIST_NOTFOUND);
}
/* Locate the most recent history line which begins with
COMMAND in HLIST, and return a malloc()'ed copy of it.
MODE is 1 if we are listing commands, 0 if we are executing them. */
static char *
fc_gethist (command, hlist, mode)
char *command;
HIST_ENTRY **hlist;
int mode;
{
int i;
if (hlist == 0)
return ((char *)NULL);
i = fc_gethnum (command, hlist, mode);
if (i >= 0)
return (savestring (histline (i)));
else
return ((char *)NULL);
}
#ifdef INCLUDE_UNUSED
/* Read the edited history lines from STREAM and return them
one at a time. This can read unlimited length lines. The
caller should free the storage. */
static char *
fc_readline (stream)
FILE *stream;
{
register int c;
int line_len = 0, lindex = 0;
char *line = (char *)NULL;
while ((c = getc (stream)) != EOF)
{
if ((lindex + 2) >= line_len)
line = (char *)xrealloc (line, (line_len += 128));
if (c == '\n')
{
line[lindex++] = '\n';
line[lindex++] = '\0';
return (line);
}
else
line[lindex++] = c;
}
if (!lindex)
{
if (line)
free (line);
return ((char *)NULL);
}
if (lindex + 2 >= line_len)
line = (char *)xrealloc (line, lindex + 3);
line[lindex++] = '\n'; /* Finish with newline if none in file */
line[lindex++] = '\0';
return (line);
}
#endif
/* Perform the SUBS on COMMAND.
SUBS is a list of substitutions, and COMMAND is a simple string.
Return a pointer to a malloc'ed string which contains the substituted
command. */
static char *
fc_dosubs (command, subs)
char *command;
REPL *subs;
{
register char *new, *t;
register REPL *r;
for (new = savestring (command), r = subs; r; r = r->next)
{
t = strsub (new, r->pat, r->rep, 1);
free (new);
new = t;
}
return (new);
}
/* Use `command' to replace the last entry in the history list, which,
by this time, is `fc blah...'. The intent is that the new command
become the history entry, and that `fc' should never appear in the
history list. This way you can do `r' to your heart's content. */
static void
fc_replhist (command)
char *command;
{
int n;
if (command == 0 || *command == '\0')
return;
n = strlen (command);
if (command[n - 1] == '\n')
command[n - 1] = '\0';
if (command && *command)
{
bash_delete_last_history ();
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
}
}
#ifdef INCLUDE_UNUSED
/* Add LINE to the history, after removing a single trailing newline. */
static void
fc_addhist (line)
char *line;
{
register int n;
if (line == 0 || *line == 0)
return;
n = strlen (line);
if (line[n - 1] == '\n')
line[n - 1] = '\0';
if (line && *line)
maybe_add_history (line); /* Obeys HISTCONTROL setting. */
}
#endif
#endif /* HISTORY */

189
builtins/fg_bg.def Normal file
View file

@ -0,0 +1,189 @@
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-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES fg_bg.c
$BUILTIN fg
$FUNCTION fg_builtin
$DEPENDS_ON JOB_CONTROL
$SHORT_DOC fg [job_spec]
Move job to the foreground.
Place the job identified by JOB_SPEC in the foreground, making it the
current job. If JOB_SPEC is not present, the shell's notion of the
current job is used.
Exit Status:
Status of command placed in foreground, or failure if an error occurs.
$END
#include <config.h>
#include "../bashtypes.h"
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../jobs.h"
#include "common.h"
#include "bashgetopt.h"
#if defined (JOB_CONTROL)
static int fg_bg PARAMS((WORD_LIST *, int));
/* How to bring a job into the foreground. */
int
fg_builtin (list)
WORD_LIST *list;
{
int fg_bit;
register WORD_LIST *t;
CHECK_HELPOPT (list);
if (job_control == 0)
{
sh_nojobs ((char *)NULL);
return (EXECUTION_FAILURE);
}
if (no_options (list))
return (EX_USAGE);
list = loptend;
/* If the last arg on the line is '&', then start this job in the
background. Else, fg the job. */
for (t = list; t && t->next; t = t->next)
;
fg_bit = (t && t->word->word[0] == '&' && t->word->word[1] == '\0') == 0;
return (fg_bg (list, fg_bit));
}
#endif /* JOB_CONTROL */
$BUILTIN bg
$FUNCTION bg_builtin
$DEPENDS_ON JOB_CONTROL
$SHORT_DOC bg [job_spec ...]
Move jobs to the background.
Place the jobs identified by each JOB_SPEC in the background, as if they
had been started with `&'. If JOB_SPEC is not present, the shell's notion
of the current job is used.
Exit Status:
Returns success unless job control is not enabled or an error occurs.
$END
#if defined (JOB_CONTROL)
/* How to put a job into the background. */
int
bg_builtin (list)
WORD_LIST *list;
{
int r;
CHECK_HELPOPT (list);
if (job_control == 0)
{
sh_nojobs ((char *)NULL);
return (EXECUTION_FAILURE);
}
if (no_options (list))
return (EX_USAGE);
list = loptend;
/* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts
on the first member (if any) of that list. */
r = EXECUTION_SUCCESS;
do
{
if (fg_bg (list, 0) == EXECUTION_FAILURE)
r = EXECUTION_FAILURE;
if (list)
list = list->next;
}
while (list);
return r;
}
/* How to put a job into the foreground/background. */
static int
fg_bg (list, foreground)
WORD_LIST *list;
int foreground;
{
sigset_t set, oset;
int job, status, old_async_pid;
JOB *j;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list ? list->word->word : _("current"));
goto failure;
}
j = get_job_by_jid (job);
/* Or if j->pgrp == shell_pgrp. */
if (IS_JOBCONTROL (job) == 0)
{
builtin_error (_("job %d started without job control"), job + 1);
goto failure;
}
if (foreground == 0)
{
old_async_pid = last_asynchronous_pid;
last_asynchronous_pid = j->pgrp; /* As per Posix.2 5.4.2 */
}
status = start_job (job, foreground);
if (status >= 0)
{
/* win: */
UNBLOCK_CHILD (oset);
return (foreground ? status : EXECUTION_SUCCESS);
}
else
{
if (foreground == 0)
last_asynchronous_pid = old_async_pid;
failure:
UNBLOCK_CHILD (oset);
return (EXECUTION_FAILURE);
}
}
#endif /* JOB_CONTROL */

198
builtins/gen-helpfiles.c Normal file
View file

@ -0,0 +1,198 @@
/* gen-helpfiles - create files containing builtin help text */
/* Copyright (C) 2012-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
/* This links with a specially-generated version of builtins.c and takes
the long_doc members of each struct builtin element and writes those to
the file named by the `handle' member of the struct builtin element. */
#if !defined (CROSS_COMPILING)
# include <config.h>
#else /* CROSS_COMPILING */
/* A conservative set of defines based on POSIX/SUS3/XPG6 */
# define HAVE_UNISTD_H
# define HAVE_STRING_H
# define HAVE_STDLIB_H
# define HAVE_RENAME
#endif /* CROSS_COMPILING */
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#ifndef _MINIX
# include "../bashtypes.h"
# if defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
# endif
#endif
#include "posixstat.h"
#include "filecntl.h"
#include "../bashansi.h"
#include <stdio.h>
#include <errno.h>
#include "stdc.h"
#include "../builtins.h"
#include "tmpbuiltins.h"
#if defined (USING_BASH_MALLOC)
#undef xmalloc
#undef xrealloc
#undef xfree
#undef malloc
#undef free /* defined in xmalloc.h */
#endif
#ifndef errno
extern int errno;
#endif
#if !defined (__STDC__) && !defined (strcpy)
extern char *strcpy ();
#endif /* !__STDC__ && !strcpy */
#define whitespace(c) (((c) == ' ') || ((c) == '\t'))
/* Flag values that builtins can have. */
#define BUILTIN_FLAG_SPECIAL 0x01
#define BUILTIN_FLAG_ASSIGNMENT 0x02
#define BUILTIN_FLAG_POSIX_BUILTIN 0x04
#define BASE_INDENT 4
/* Non-zero means to produce separate help files for each builtin, named by
the builtin name, in `./helpfiles'. */
int separate_helpfiles = 0;
/* Non-zero means to create single C strings for each `longdoc', with
embedded newlines, for ease of translation. */
int single_longdoc_strings = 1;
/* The name of a directory into which the separate external help files will
eventually be installed. */
char *helpfile_directory;
/* Forward declarations. */
int write_helpfiles PARAMS((struct 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 necessary. */
int
main (argc, argv)
int argc;
char **argv;
{
int arg_index = 1;
while (arg_index < argc && argv[arg_index][0] == '-')
{
char *arg = argv[arg_index++];
if (strcmp (arg, "-noproduction") == 0)
;
else if (strcmp (arg, "-H") == 0)
helpfile_directory = argv[arg_index++];
else if (strcmp (arg, "-S") == 0)
single_longdoc_strings = 0;
else
{
fprintf (stderr, "%s: Unknown flag %s.\n", argv[0], arg);
exit (2);
}
}
write_helpfiles(shell_builtins);
exit (0);
}
/* Write DOCUMENTATION to STREAM, perhaps surrounding it with double-quotes
and quoting special characters in the string. Handle special things for
internationalization (gettext) and the single-string vs. multiple-strings
issues. */
void
write_documentation (stream, documentation, indentation)
FILE *stream;
char *documentation;
int indentation;
{
if (stream == 0)
return;
if (documentation)
fprintf (stream, "%*s%s\n", indentation, " ", documentation);
}
int
write_helpfiles (builtins)
struct builtin *builtins;
{
char *helpfile, *bname, *fname;
FILE *helpfp;
int i, hdlen;
struct builtin b;
i = mkdir ("helpfiles", 0777);
if (i < 0 && errno != EEXIST)
{
fprintf (stderr, "write_helpfiles: helpfiles: cannot create directory\n");
return -1;
}
hdlen = strlen ("helpfiles/");
for (i = 0; i < num_shell_builtins; i++)
{
b = builtins[i];
fname = (char *)b.handle;
helpfile = (char *)malloc (hdlen + strlen (fname) + 1);
if (helpfile == 0)
{
fprintf (stderr, "gen-helpfiles: cannot allocate memory\n");
exit (1);
}
sprintf (helpfile, "helpfiles/%s", fname);
helpfp = fopen (helpfile, "w");
if (helpfp == 0)
{
fprintf (stderr, "write_helpfiles: cannot open %s\n", helpfile);
free (helpfile);
continue;
}
write_documentation (helpfp, b.long_doc[0], 4);
fflush (helpfp);
fclose (helpfp);
free (helpfile);
}
return 0;
}

355
builtins/getopt.c Normal file
View file

@ -0,0 +1,355 @@
/* getopt.c - getopt for Bash. Used by the getopt builtin. */
/* Copyright (C) 1993-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "memalloc.h"
#include "../bashintl.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 = '?';
/* Set to 1 when we see an invalid option; public so getopts can reset it. */
int sh_badopt = 0;
/* 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;
{
char c, *temp;
sh_optarg = 0;
if (sh_optind >= argc || sh_optind < 0) /* XXX was sh_optind > argc */
{
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. */
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);
sh_optopt = c;
/* Increment `sh_optind' when we start to process its last character. */
if (nextchar == 0 || *nextchar == '\0')
{
sh_optind++;
nextchar = (char *)NULL;
}
if (sh_badopt = (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;
sh_optarg = ""; /* Needed by getopts. */
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;
}
sh_getopt_state_t *
sh_getopt_alloc_istate ()
{
sh_getopt_state_t *ret;
ret = (sh_getopt_state_t *)xmalloc (sizeof (sh_getopt_state_t));
return ret;
}
void
sh_getopt_dispose_istate (gs)
sh_getopt_state_t *gs;
{
free (gs);
}
sh_getopt_state_t *
sh_getopt_save_istate ()
{
sh_getopt_state_t *ret;
ret = sh_getopt_alloc_istate ();
ret->gs_optarg = sh_optarg;
ret->gs_optind = sh_optind;
ret->gs_curopt = sh_curopt;
ret->gs_nextchar = nextchar; /* XXX */
ret->gs_charindex = sh_charindex;
ret->gs_flags = 0; /* XXX for later use */
return ret;
}
void
sh_getopt_restore_istate (state)
sh_getopt_state_t *state;
{
sh_optarg = state->gs_optarg;
sh_optind = state->gs_optind;
sh_curopt = state->gs_curopt;
nextchar = state->gs_nextchar; /* XXX - probably not usable */
sh_charindex = state->gs_charindex;
sh_getopt_dispose_istate (state);
}
#if 0
void
sh_getopt_debug_restore_state (argv)
char **argv;
{
if (nextchar && nextchar != argv[sh_curopt] + sh_charindex)
{
itrace("sh_getopt_debug_restore_state: resetting nextchar");
nextchar = argv[sh_curopt] + sh_charindex;
}
}
#endif
#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 */

82
builtins/getopt.h Normal file
View file

@ -0,0 +1,82 @@
/* getopt.h - declarations for getopt. */
/* Copyright (C) 1989-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
/* XXX THIS HAS BEEN MODIFIED FOR INCORPORATION INTO BASH XXX */
#ifndef _SH_GETOPT_H
#define _SH_GETOPT_H 1
#include "stdc.h"
/* 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;
/* Set to 1 when an unrecognized option is encountered. */
extern int sh_badopt;
extern int sh_getopt PARAMS((int, char *const *, const char *));
typedef struct sh_getopt_state
{
char *gs_optarg;
int gs_optind;
int gs_curopt;
char *gs_nextchar;
int gs_charindex;
int gs_flags;
} sh_getopt_state_t;
extern void sh_getopt_restore_state PARAMS((char **));
extern sh_getopt_state_t *sh_getopt_alloc_istate PARAMS((void));
extern void sh_getopt_dispose_istate PARAMS((sh_getopt_state_t *));
extern sh_getopt_state_t *sh_getopt_save_istate PARAMS((void));
extern void sh_getopt_restore_istate PARAMS((sh_getopt_state_t *));
#endif /* _SH_GETOPT_H */

343
builtins/getopts.def Normal file
View file

@ -0,0 +1,343 @@
This file is getopts.def, from which is created getopts.c.
It implements the builtin "getopts" in Bash.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES getopts.c
$BUILTIN getopts
$FUNCTION getopts_builtin
$SHORT_DOC getopts optstring name [arg ...]
Parse option arguments.
Getopts is used by shell procedures to parse positional parameters
as options.
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 invalid 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 invalid option is seen, getopts places '?' into
NAME and unsets OPTARG. If a required argument 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, but if arguments
are supplied as ARG values, they are parsed instead.
Exit Status:
Returns success if an option is found; fails if the end of options is
encountered or an error occurs.
$END
#include <config.h>
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "common.h"
#include "bashgetopt.h"
#include "getopt.h"
#define G_EOF -1
#define G_INVALID_OPT -2
#define G_ARG_MISSING -3
static int getopts_unbind_variable PARAMS((char *));
static int getopts_bind_variable PARAMS((char *, char *));
static int dogetopts PARAMS((int, char **));
/* getopts_reset is magic code for when OPTIND is reset. N is the
value that has just been assigned to OPTIND. */
void
getopts_reset (newind)
int newind;
{
sh_optind = newind;
sh_badopt = 0;
}
static int
getopts_unbind_variable (name)
char *name;
{
#if 0
return (unbind_variable (name));
#else
return (unbind_variable_noref (name));
#endif
}
static int
getopts_bind_variable (name, value)
char *name, *value;
{
SHELL_VAR *v;
if (legal_identifier (name))
{
v = bind_variable (name, value, 0);
if (v && (readonly_p (v) || noassign_p (v)))
return (EX_MISCERROR);
return (v ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
else
{
sh_invalidid (name);
return (EXECUTION_FAILURE);
}
}
/* Error handling is now performed as specified by Posix.2, draft 11
(identical to that of ksh-88). The special handling is enabled if
the first character of the option string is a colon; this handling
disables diagnostic messages concerning missing option arguments
and invalid option characters. The handling is as follows.
INVALID OPTIONS:
name -> "?"
if (special_error) then
OPTARG = option character found
no error output
else
OPTARG unset
diagnostic message
fi
MISSING OPTION ARGUMENT;
if (special_error) then
name -> ":"
OPTARG = option character found
else
name -> "?"
OPTARG unset
diagnostic message
fi
*/
static int
dogetopts (argc, argv)
int argc;
char **argv;
{
int ret, special_error, old_opterr, i, n;
char strval[2], numval[16];
char *optstr; /* list of options */
char *name; /* variable to get flag val */
char *t;
if (argc < 3)
{
builtin_usage ();
return (EX_USAGE);
}
/* argv[0] is "getopts". */
optstr = argv[1];
name = argv[2];
argc -= 2;
argv += 2;
special_error = optstr[0] == ':';
if (special_error)
{
old_opterr = sh_opterr;
optstr++;
sh_opterr = 0; /* suppress diagnostic messages */
}
if (argc > 1)
{
sh_getopt_restore_state (argv);
t = argv[0];
argv[0] = dollar_vars[0];
ret = sh_getopt (argc, argv, optstr);
argv[0] = t;
}
else if (rest_of_args == (WORD_LIST *)NULL)
{
for (i = 0; i < 10 && dollar_vars[i]; i++)
;
sh_getopt_restore_state (dollar_vars);
ret = sh_getopt (i, dollar_vars, optstr);
}
else
{
register WORD_LIST *words;
char **v;
i = number_of_args () + 1; /* +1 for $0 */
v = strvec_create (i + 1);
for (i = 0; i < 10 && dollar_vars[i]; i++)
v[i] = dollar_vars[i];
for (words = rest_of_args; words; words = words->next, i++)
v[i] = words->word->word;
v[i] = (char *)NULL;
sh_getopt_restore_state (v);
ret = sh_getopt (i, v, optstr);
free (v);
}
if (special_error)
sh_opterr = old_opterr;
/* Set the OPTIND variable in any case, to handle "--" skipping. It's
highly unlikely that 14 digits will be too few. */
if (sh_optind < 10)
{
numval[14] = sh_optind + '0';
numval[15] = '\0';
i = 14;
}
else
{
numval[i = 15] = '\0';
n = sh_optind;
do
{
numval[--i] = (n % 10) + '0';
}
while (n /= 10);
}
bind_variable ("OPTIND", numval + i, 0);
/* If an error occurred, decide which one it is and set the return
code appropriately. In all cases, the option character in error
is in OPTOPT. If an invalid option was encountered, OPTARG is
NULL. If a required option argument was missing, OPTARG points
to a NULL string (that is, sh_optarg[0] == 0). */
if (ret == '?')
{
if (sh_optarg == NULL)
ret = G_INVALID_OPT;
else if (sh_optarg[0] == '\0')
ret = G_ARG_MISSING;
}
if (ret == G_EOF)
{
getopts_unbind_variable ("OPTARG");
getopts_bind_variable (name, "?");
return (EXECUTION_FAILURE);
}
if (ret == G_INVALID_OPT)
{
/* Invalid option encountered. */
ret = getopts_bind_variable (name, "?");
if (special_error)
{
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval, 0);
}
else
getopts_unbind_variable ("OPTARG");
return (ret);
}
if (ret == G_ARG_MISSING)
{
/* Required argument missing. */
if (special_error)
{
ret = getopts_bind_variable (name, ":");
strval[0] = (char)sh_optopt;
strval[1] = '\0';
bind_variable ("OPTARG", strval, 0);
}
else
{
ret = getopts_bind_variable (name, "?");
getopts_unbind_variable ("OPTARG");
}
return (ret);
}
bind_variable ("OPTARG", sh_optarg, 0);
strval[0] = (char) ret;
strval[1] = '\0';
return (getopts_bind_variable (name, strval));
}
/* The getopts builtin. Build an argv, and call dogetopts with it. */
int
getopts_builtin (list)
WORD_LIST *list;
{
char **av;
int ac, ret;
if (list == 0)
{
builtin_usage ();
return EX_USAGE;
}
reset_internal_getopt ();
if ((ret = internal_getopt (list, "")) != -1)
{
if (ret == GETOPT_HELP)
builtin_help ();
else
builtin_usage ();
return (EX_USAGE);
}
list = loptend;
av = make_builtin_argv (list, &ac);
ret = dogetopts (ac, av);
free ((char *)av);
return (ret);
}

305
builtins/hash.def Normal file
View file

@ -0,0 +1,305 @@
This file is hash.def, from which is created hash.c.
It implements the builtin "hash" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES hash.c
$BUILTIN hash
$FUNCTION hash_builtin
$SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...]
Remember or display program locations.
Determine and remember the full pathname of each command NAME. If
no arguments are given, information about remembered commands is displayed.
Options:
-d forget the remembered location of each NAME
-l display in a format that may be reused as input
-p pathname use PATHNAME as the full pathname of NAME
-r forget all remembered locations
-t print the remembered location of each NAME, preceding
each location with the corresponding NAME if multiple
NAMEs are given
Arguments:
NAME Each NAME is searched for in $PATH and added to the list
of remembered commands.
Exit Status:
Returns success unless NAME is not found or an invalid option is given.
$END
#include <config.h>
#include <stdio.h>
#include "../bashtypes.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <errno.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../builtins.h"
#include "../execute_cmd.h"
#include "../flags.h"
#include "../findcmd.h"
#include "../hashcmd.h"
#include "common.h"
#include "bashgetopt.h"
extern int dot_found_in_search;
static int add_hashed_command PARAMS((char *, int));
static int print_hash_info PARAMS((BUCKET_CONTENTS *));
static int print_portable_hash_info PARAMS((BUCKET_CONTENTS *));
static int print_hashed_commands PARAMS((int));
static int list_hashed_filename_targets PARAMS((WORD_LIST *, int));
/* Print statistics on the current state of hashed commands. If LIST is
not empty, then rehash (or hash in the first place) the specified
commands. */
int
hash_builtin (list)
WORD_LIST *list;
{
int expunge_hash_table, list_targets, list_portably, delete, opt;
char *w, *pathname;
if (hashing_enabled == 0)
{
builtin_error (_("hashing disabled"));
return (EXECUTION_FAILURE);
}
expunge_hash_table = list_targets = list_portably = delete = 0;
pathname = (char *)NULL;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "dlp:rt")) != -1)
{
switch (opt)
{
case 'd':
delete = 1;
break;
case 'l':
list_portably = 1;
break;
case 'p':
pathname = list_optarg;
break;
case 'r':
expunge_hash_table = 1;
break;
case 't':
list_targets = 1;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* hash -t requires at least one argument. */
if (list == 0 && (delete || list_targets))
{
sh_needarg (delete ? "-d" : "-t");
return (EXECUTION_FAILURE);
}
/* We want hash -r to be silent, but hash -- to print hashing info, so
we test expunge_hash_table. */
if (list == 0 && expunge_hash_table == 0)
{
opt = print_hashed_commands (list_portably);
if (opt == 0 && posixly_correct == 0 &&
(list_portably == 0 || shell_compatibility_level <= 50))
printf (_("%s: hash table empty\n"), this_command_name);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
if (expunge_hash_table)
phash_flush ();
/* If someone runs `hash -r -t xyz' he will be disappointed. */
if (list_targets)
return (list_hashed_filename_targets (list, list_portably));
#if defined (RESTRICTED_SHELL)
if (restricted && pathname)
{
if (strchr (pathname, '/'))
{
sh_restricted (pathname);
return (EXECUTION_FAILURE);
}
/* If we are changing the hash table in a restricted shell, make sure the
target pathname can be found using a $PATH search. */
w = find_user_command (pathname);
if (w == 0 || *w == 0 || executable_file (w) == 0)
{
sh_notfound (pathname);
free (w);
return (EXECUTION_FAILURE);
}
free (w);
}
#endif
for (opt = EXECUTION_SUCCESS; list; list = list->next)
{
/* Add, remove or rehash the specified commands. */
w = list->word->word;
if (absolute_program (w))
continue;
else if (pathname)
{
if (file_isdir (pathname))
{
#ifdef EISDIR
builtin_error ("%s: %s", pathname, strerror (EISDIR));
#else
builtin_error (_("%s: is a directory"), pathname);
#endif
opt = EXECUTION_FAILURE;
}
else
phash_insert (w, pathname, 0, 0);
}
else if (delete)
{
if (phash_remove (w))
{
sh_notfound (w);
opt = EXECUTION_FAILURE;
}
}
else if (add_hashed_command (w, 0))
opt = EXECUTION_FAILURE;
}
fflush (stdout);
return (opt);
}
static int
add_hashed_command (w, quiet)
char *w;
int quiet;
{
int rv;
char *full_path;
rv = 0;
if (find_function (w) == 0 && find_shell_builtin (w) == 0)
{
phash_remove (w);
full_path = find_user_command (w);
if (full_path && executable_file (full_path))
phash_insert (w, full_path, dot_found_in_search, 0);
else
{
if (quiet == 0)
sh_notfound (w);
rv++;
}
FREE (full_path);
}
return (rv);
}
/* Print information about current hashed info. */
static int
print_hash_info (item)
BUCKET_CONTENTS *item;
{
printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
return 0;
}
static int
print_portable_hash_info (item)
BUCKET_CONTENTS *item;
{
char *fp, *fn;
fp = printable_filename (pathdata(item)->path, 1);
fn = printable_filename (item->key, 1);
printf ("builtin hash -p %s %s\n", fp, fn);
if (fp != pathdata(item)->path)
free (fp);
if (fn != item->key)
free (fn);
return 0;
}
static int
print_hashed_commands (fmt)
int fmt;
{
if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
return (0);
if (fmt == 0)
printf (_("hits\tcommand\n"));
hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
return (1);
}
static int
list_hashed_filename_targets (list, fmt)
WORD_LIST *list;
int fmt;
{
int all_found, multiple;
char *target;
WORD_LIST *l;
all_found = 1;
multiple = list->next != 0;
for (l = list; l; l = l->next)
{
target = phash_search (l->word->word);
if (target == 0)
{
all_found = 0;
sh_notfound (l->word->word);
continue;
}
if (fmt)
printf ("builtin hash -p %s %s\n", target, l->word->word);
else
{
if (multiple)
printf ("%s\t", l->word->word);
printf ("%s\n", target);
}
free (target);
}
return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}

552
builtins/help.def Normal file
View file

@ -0,0 +1,552 @@
This file is help.def, from which is created help.c.
It implements the builtin "help" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES help.c
$BUILTIN help
$FUNCTION help_builtin
$DEPENDS_ON HELP_BUILTIN
$SHORT_DOC help [-dms] [pattern ...]
Display information about builtin commands.
Displays brief summaries of builtin commands. If PATTERN is
specified, gives detailed help on all commands matching PATTERN,
otherwise the list of help topics is printed.
Options:
-d output short description for each topic
-m display usage in pseudo-manpage format
-s output only a short usage synopsis for each topic matching
PATTERN
Arguments:
PATTERN Pattern specifying a help topic
Exit Status:
Returns success unless PATTERN is not found or an invalid option is given.
$END
#include <config.h>
#if defined (HELP_BUILTIN)
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <errno.h>
#include <filecntl.h>
#include <stddef.h>
#include "../bashintl.h"
#include "../shell.h"
#include "../builtins.h"
#include "../execute_cmd.h"
#include "../pathexp.h"
#include "common.h"
#include "bashgetopt.h"
#include <glob/strmatch.h>
#include <glob/glob.h>
#ifndef errno
extern int errno;
#endif
extern const char * const bash_copyright;
extern const char * const bash_license;
static void show_builtin_command_help PARAMS((void));
static int open_helpfile PARAMS((char *));
static void show_desc PARAMS((char *, int));
static void show_manpage PARAMS((char *, int));
static void show_longdoc PARAMS((int));
/* Print out a list of the known functions in the shell, and what they do.
If LIST is supplied, print out the list which matches for each pattern
specified. */
int
help_builtin (list)
WORD_LIST *list;
{
register int i;
char *pattern, *name;
int plen, match_found, sflag, dflag, mflag, m, pass, this_found;
dflag = sflag = mflag = 0;
reset_internal_getopt ();
while ((i = internal_getopt (list, "dms")) != -1)
{
switch (i)
{
case 'd':
dflag = 1;
break;
case 'm':
mflag = 1;
break;
case 's':
sflag = 1;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
{
show_shell_version (0);
show_builtin_command_help ();
return (EXECUTION_SUCCESS);
}
/* We should consider making `help bash' do something. */
if (glob_pattern_p (list->word->word) == 1)
{
printf ("%s", ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
print_word_list (list, ", ");
printf ("%s", _("'\n\n"));
}
for (match_found = 0, pattern = ""; list; list = list->next)
{
pattern = list->word->word;
plen = strlen (pattern);
for (pass = 1, this_found = 0; pass < 3; pass++)
{
for (i = 0; name = shell_builtins[i].name; i++)
{
QUIT;
/* First pass: look for exact string or pattern matches.
Second pass: look for prefix matches like bash-4.2 */
if (pass == 1)
m = (strcmp (pattern, name) == 0) ||
(strmatch (pattern, name, FNMATCH_EXTFLAG) != FNM_NOMATCH);
else
m = strncmp (pattern, name, plen) == 0;
if (m)
{
this_found = 1;
match_found++;
if (dflag)
{
show_desc (name, i);
continue;
}
else if (mflag)
{
show_manpage (name, i);
continue;
}
printf ("%s: %s\n", name, _(shell_builtins[i].short_doc));
if (sflag == 0)
show_longdoc (i);
}
}
if (pass == 1 && this_found == 1)
break;
}
}
if (match_found == 0)
{
builtin_error (_("no help topics match `%s'. Try `help help' or `man -k %s' or `info %s'."), pattern, pattern, pattern);
return (EXECUTION_FAILURE);
}
return (sh_chkwrite (EXECUTION_SUCCESS));
}
void
builtin_help ()
{
int ind;
ptrdiff_t d;
current_builtin = builtin_address_internal (this_command_name, 0);
if (current_builtin == 0)
return;
d = current_builtin - shell_builtins;
#if defined (__STDC__)
ind = (int)d;
#else
ind = (int)d / sizeof (struct builtin);
#endif
printf ("%s: %s\n", this_command_name, _(shell_builtins[ind].short_doc));
show_longdoc (ind);
}
static int
open_helpfile (name)
char *name;
{
int fd;
fd = open (name, O_RDONLY);
if (fd == -1)
{
builtin_error (_("%s: cannot open: %s"), name, strerror (errno));
return -1;
}
return fd;
}
/* By convention, enforced by mkbuiltins.c, if separate help files are being
used, the long_doc array contains one string -- the full pathname of the
help file for this builtin. */
static void
show_longdoc (i)
int i;
{
register int j;
char * const *doc;
int fd;
doc = shell_builtins[i].long_doc;
if (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL)
{
fd = open_helpfile (doc[0]);
if (fd < 0)
return;
zcatfd (fd, 1, doc[0]);
close (fd);
}
else if (doc)
for (j = 0; doc[j]; j++)
printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
}
static void
show_desc (name, i)
char *name;
int i;
{
register int j, r;
char **doc, *line;
int fd, usefile;
doc = (char **)shell_builtins[i].long_doc;
usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
if (usefile)
{
fd = open_helpfile (doc[0]);
if (fd < 0)
return;
r = zmapfd (fd, &line, doc[0]);
close (fd);
/* XXX - handle errors if zmapfd returns < 0 */
}
else
line = doc ? doc[0] : (char *)NULL;
printf ("%s - ", name);
for (j = 0; line && line[j]; j++)
{
putchar (line[j]);
if (line[j] == '\n')
break;
}
fflush (stdout);
if (usefile)
free (line);
}
/* Print builtin help in pseudo-manpage format. */
static void
show_manpage (name, i)
char *name;
int i;
{
register int j;
char **doc, *line;
int fd, usefile;
doc = (char **)shell_builtins[i].long_doc;
usefile = (doc && doc[0] && *doc[0] == '/' && doc[1] == (char *)NULL);
if (usefile)
{
fd = open_helpfile (doc[0]);
if (fd < 0)
return;
zmapfd (fd, &line, doc[0]);
close (fd);
}
else
line = doc ? _(doc[0]) : (char *)NULL;
/* NAME */
printf ("NAME\n");
printf ("%*s%s - ", BASE_INDENT, " ", name);
for (j = 0; line && line[j]; j++)
{
putchar (line[j]);
if (line[j] == '\n')
break;
}
printf ("\n");
/* SYNOPSIS */
printf ("SYNOPSIS\n");
printf ("%*s%s\n\n", BASE_INDENT, " ", _(shell_builtins[i].short_doc));
/* DESCRIPTION */
printf ("DESCRIPTION\n");
if (usefile == 0)
{
for (j = 0; doc[j]; j++)
printf ("%*s%s\n", BASE_INDENT, " ", _(doc[j]));
}
else
{
for (j = 0; line && line[j]; j++)
{
putchar (line[j]);
if (line[j] == '\n')
printf ("%*s", BASE_INDENT, " ");
}
}
putchar ('\n');
/* SEE ALSO */
printf ("SEE ALSO\n");
printf ("%*sbash(1)\n\n", BASE_INDENT, " ");
/* IMPLEMENTATION */
printf ("IMPLEMENTATION\n");
printf ("%*s", BASE_INDENT, " ");
show_shell_version (0);
printf ("%*s", BASE_INDENT, " ");
printf ("%s\n", _(bash_copyright));
printf ("%*s", BASE_INDENT, " ");
printf ("%s\n", _(bash_license));
fflush (stdout);
if (usefile)
free (line);
}
static void
dispcolumn (i, buf, bufsize, width, height)
int i;
char *buf;
size_t bufsize;
int width, height;
{
int j;
int dispcols;
char *helpdoc;
/* first column */
helpdoc = _(shell_builtins[i].short_doc);
buf[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*';
strncpy (buf + 1, helpdoc, width - 2);
buf[width - 2] = '>'; /* indicate truncation */
buf[width - 1] = '\0';
printf ("%s", buf);
if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
{
printf ("\n");
return;
}
dispcols = strlen (buf);
/* two spaces */
for (j = dispcols; j < width; j++)
putc (' ', stdout);
/* second column */
helpdoc = _(shell_builtins[i+height].short_doc);
buf[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*';
strncpy (buf + 1, helpdoc, width - 3);
buf[width - 3] = '>'; /* indicate truncation */
buf[width - 2] = '\0';
printf ("%s\n", buf);
}
#if defined (HANDLE_MULTIBYTE)
static void
wdispcolumn (i, buf, bufsize, width, height)
int i;
char *buf;
size_t bufsize;
int width, height;
{
int j;
int dispcols, dispchars;
char *helpdoc;
wchar_t *wcstr;
size_t slen, n;
/* first column */
helpdoc = _(shell_builtins[i].short_doc);
wcstr = 0;
slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
if (slen == -1)
{
dispcolumn (i, buf, bufsize, width, height);
return;
}
/* No bigger than the passed max width */
if (slen >= width)
slen = width - 2;
wcstr = (wchar_t *)xmalloc (sizeof (wchar_t) * (width + 2));
n = mbstowcs (wcstr+1, helpdoc, slen + 1);
wcstr[n+1] = L'\0';
/* Turn tabs and newlines into spaces for column display, since wcwidth
returns -1 for them */
for (j = 1; j < n; j++)
if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
wcstr[j] = L' ';
/* dispchars == number of characters that will be displayed */
dispchars = wcsnwidth (wcstr+1, slen, width - 2);
/* dispcols == number of columns required to display DISPCHARS */
dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
wcstr[0] = (shell_builtins[i].flags & BUILTIN_ENABLED) ? L' ' : L'*';
if (dispcols >= width-2)
{
wcstr[dispchars] = L'>'; /* indicate truncation */
wcstr[dispchars+1] = L'\0';
}
printf ("%ls", wcstr);
if (((i << 1) >= num_shell_builtins) || (i+height >= num_shell_builtins))
{
printf ("\n");
free (wcstr);
return;
}
/* at least one space */
for (j = dispcols; j < width; j++)
putc (' ', stdout);
/* second column */
helpdoc = _(shell_builtins[i+height].short_doc);
slen = mbstowcs ((wchar_t *)0, helpdoc, 0);
if (slen == -1)
{
/* for now */
printf ("%c%s\n", (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? ' ' : '*', helpdoc);
free (wcstr);
return;
}
/* Reuse wcstr since it is already width wide chars long */
if (slen >= width)
slen = width - 2;
n = mbstowcs (wcstr+1, helpdoc, slen + 1);
wcstr[n+1] = L'\0'; /* make sure null-terminated */
/* Turn tabs and newlines into spaces for column display */
for (j = 1; j < n; j++)
if (wcstr[j] == L'\n' || wcstr[j] == L'\t')
wcstr[j] = L' ';
/* dispchars == number of characters that will be displayed */
dispchars = wcsnwidth (wcstr+1, slen, width - 2);
dispcols = wcswidth (wcstr+1, dispchars) + 1; /* +1 for ' ' or '*' */
wcstr[0] = (shell_builtins[i+height].flags & BUILTIN_ENABLED) ? L' ' : L'*';
/* The dispchars-1 is there for terminals that behave strangely when you
have \n in the nth column for terminal width n; this is what bash-4.3
did. */
if (dispcols >= width - 2)
{
wcstr[dispchars-1] = L'>'; /* indicate truncation */
wcstr[dispchars] = L'\0';
}
printf ("%ls\n", wcstr);
free (wcstr);
}
#endif /* HANDLE_MULTIBYTE */
static void
show_builtin_command_help ()
{
int i, j;
int height, width;
char *t, blurb[128];
printf (
_("These shell commands are defined internally. Type `help' to see this list.\n\
Type `help name' to find out more about the function `name'.\n\
Use `info bash' to find out more about the shell in general.\n\
Use `man -k' or `info' to find out more about commands not in this list.\n\
\n\
A star (*) next to a name means that the command is disabled.\n\
\n"));
width = default_columns ();
width /= 2;
if (width > sizeof (blurb))
width = sizeof (blurb);
if (width <= 3)
width = 40;
height = (num_shell_builtins + 1) / 2; /* number of rows */
for (i = 0; i < height; i++)
{
QUIT;
#if defined (HANDLE_MULTIBYTE)
if (MB_CUR_MAX > 1)
wdispcolumn (i, blurb, sizeof (blurb), width, height);
else
#endif
dispcolumn (i, blurb, sizeof (blurb), width, height);
}
}
#endif /* HELP_BUILTIN */

464
builtins/history.def Normal file
View file

@ -0,0 +1,464 @@
This file is history.def, from which is created history.c.
It implements the builtin "history" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES history.c
$BUILTIN history
$FUNCTION history_builtin
$DEPENDS_ON HISTORY
$SHORT_DOC history [-c] [-d offset] [n] or history -anrw [filename] or history -ps arg [arg...]
Display or manipulate the history list.
Display the history list with line numbers, prefixing each modified
entry with a `*'. An argument of N lists only the last N entries.
Options:
-c clear the history list by deleting all of the entries
-d offset delete the history entry at position OFFSET. Negative
offsets count back from the end of the history list
-a append history lines from this session to the history file
-n read all history lines not already read from the history file
and append them to the history list
-r read the history file and append the contents to the history
list
-w write the current history to the history file
-p perform history expansion on each ARG and display the result
without storing it in the history list
-s append the ARGs to the history list as a single entry
If FILENAME is given, it is used as the history file. Otherwise,
if HISTFILE has a value, that is used, else ~/.bash_history.
If the HISTTIMEFORMAT variable is set and not null, its value is used
as a format string for strftime(3) to print the time stamp associated
with each displayed history entry. No time stamps are printed otherwise.
Exit Status:
Returns success unless an invalid option is given or an error occurs.
$END
#include <config.h>
#if defined (HISTORY)
#include "../bashtypes.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include "posixstat.h"
#include "filecntl.h"
#include <errno.h>
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../flags.h"
#include "../parser.h"
#include "../bashhist.h"
#include <readline/history.h>
#include "bashgetopt.h"
#include "common.h"
#if !defined (errno)
extern int errno;
#endif
static char *histtime PARAMS((HIST_ENTRY *, const char *));
static int display_history PARAMS((WORD_LIST *));
static void push_history PARAMS((WORD_LIST *));
static int expand_and_print_history PARAMS((WORD_LIST *));
#define AFLAG 0x01
#define RFLAG 0x02
#define WFLAG 0x04
#define NFLAG 0x08
#define SFLAG 0x10
#define PFLAG 0x20
#define CFLAG 0x40
#define DFLAG 0x80
#ifndef TIMELEN_MAX
# define TIMELEN_MAX 128
#endif
int
history_builtin (list)
WORD_LIST *list;
{
int flags, opt, result, old_history_lines, obase, ind;
char *filename, *delete_arg, *range;
intmax_t delete_offset;
flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
{
switch (opt)
{
case 'a':
flags |= AFLAG;
break;
case 'c':
flags |= CFLAG;
break;
case 'n':
flags |= NFLAG;
break;
case 'r':
flags |= RFLAG;
break;
case 'w':
flags |= WFLAG;
break;
case 's':
flags |= SFLAG;
break;
case 'd':
flags |= DFLAG;
delete_arg = list_optarg;
break;
case 'p':
#if defined (BANG_HISTORY)
flags |= PFLAG;
#endif
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
{
builtin_error (_("cannot use more than one of -anrw"));
return (EXECUTION_FAILURE);
}
/* clear the history, but allow other arguments to add to it again. */
if (flags & CFLAG)
{
bash_clear_history ();
if (list == 0)
return (EXECUTION_SUCCESS);
}
if (flags & SFLAG)
{
if (list)
push_history (list);
return (EXECUTION_SUCCESS);
}
#if defined (BANG_HISTORY)
else if (flags & PFLAG)
{
if (list)
return (expand_and_print_history (list));
return (sh_chkwrite (EXECUTION_SUCCESS));
}
#endif
else if ((flags & DFLAG) && (range = strchr ((delete_arg[0] == '-') ? delete_arg + 1 : delete_arg, '-')))
{
intmax_t delete_start, delete_end;
*range++ = '\0';
if (legal_number (delete_arg, &delete_start) == 0 || legal_number (range, &delete_end) == 0)
{
range[-1] = '-';
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
if (delete_arg[0] == '-' && delete_start < 0)
/* the_history[history_length] == 0x0, so this is correct */
delete_start += history_length;
/* numbers as displayed by display_history are offset by history_base */
else if (delete_start > 0)
delete_start -= history_base;
if (delete_start < 0 || delete_start >= history_length)
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
if (range[0] == '-' && delete_end < 0)
delete_end += history_length;
else if (delete_end > 0)
delete_end -= history_base;
if (delete_end < 0 || delete_end >= history_length)
{
sh_erange (range, _("history position"));
return (EXECUTION_FAILURE);
}
/* XXX - print error if end < start? */
result = bash_delete_history_range (delete_start, delete_end);
if (where_history () > history_length)
history_set_pos (history_length);
return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
else if (flags & DFLAG)
{
if (legal_number (delete_arg, &delete_offset) == 0)
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
/* check for negative offsets, count back from end of list */
if (delete_arg[0] == '-' && delete_offset < 0)
{
/* since the_history[history_length] == 0x0, this calculation means
that history -d -1 will delete the last history entry, which at
this point is the history -d -1 we just added. */
ind = history_length + delete_offset;
if (ind < 0) /* offset by history_base below */
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
opt = ind + history_base; /* compensate for opt - history_base below */
}
else if ((delete_offset < history_base) || (delete_offset >= (history_base + history_length)))
{
sh_erange (delete_arg, _("history position"));
return (EXECUTION_FAILURE);
}
else
opt = delete_offset;
/* Positive arguments from numbers as displayed by display_history need
to be offset by history_base */
result = bash_delete_histent (opt - history_base);
/* Since remove_history changes history_length, this can happen if
we delete the last history entry. */
if (where_history () > history_length)
history_set_pos (history_length);
return (result ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
else if ((flags & (AFLAG|RFLAG|NFLAG|WFLAG|CFLAG)) == 0)
{
result = display_history (list);
return (sh_chkwrite (result));
}
filename = list ? list->word->word : get_string_value ("HISTFILE");
result = EXECUTION_SUCCESS;
#if defined (RESTRICTED_SHELL)
if (restricted && strchr (filename, '/'))
{
sh_restricted (filename);
return (EXECUTION_FAILURE);
}
#endif
if (flags & AFLAG) /* Append session's history to file. */
result = maybe_append_history (filename);
else if (flags & WFLAG) /* Write entire history. */
result = write_history (filename);
else if (flags & RFLAG) /* Read entire file. */
{
result = read_history (filename);
history_lines_in_file = history_lines_read_from_file;
/* history_lines_in_file = where_history () + history_base - 1; */
}
else if (flags & NFLAG) /* Read `new' history from file. */
{
/* Read all of the lines in the file that we haven't already read. */
old_history_lines = history_lines_in_file;
obase = history_base;
using_history ();
result = read_history_range (filename, history_lines_in_file, -1);
using_history ();
history_lines_in_file = history_lines_read_from_file;
/* history_lines_in_file = where_history () + history_base - 1; */
/* If we're rewriting the history file at shell exit rather than just
appending the lines from this session to it, the question is whether
we reset history_lines_this_session to 0, losing any history entries
we had before we read the new entries from the history file, or
whether we count the new entries we just read from the file as
history lines added during this session.
Right now, we do the latter. This will cause these history entries
to be written to the history file along with any intermediate entries
we add when we do a `history -a', but the alternative is losing
them altogether. */
if (force_append_history == 0)
history_lines_this_session += history_lines_in_file - old_history_lines +
history_base - obase;
}
return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
/* Accessors for HIST_ENTRY lists that are called HLIST. */
#define histline(i) (hlist[(i)]->line)
#define histdata(i) (hlist[(i)]->data)
static char *
histtime (hlist, histtimefmt)
HIST_ENTRY *hlist;
const char *histtimefmt;
{
static char timestr[TIMELEN_MAX];
time_t t;
struct tm *tm;
t = history_get_time (hlist);
tm = t ? localtime (&t) : 0;
if (t && tm)
strftime (timestr, sizeof (timestr), histtimefmt, tm);
else if (hlist->timestamp && hlist->timestamp[0])
snprintf (timestr, sizeof (timestr), _("%s: invalid timestamp"),
(hlist->timestamp[0] == '#') ? hlist->timestamp + 1: hlist->timestamp);
else
strcpy (timestr, "??");
return timestr;
}
static int
display_history (list)
WORD_LIST *list;
{
register int i;
intmax_t limit;
HIST_ENTRY **hlist;
char *histtimefmt, *timestr;
if (list)
{
if (get_numeric_arg (list, 0, &limit) == 0)
return (EXECUTION_FAILURE);
if (limit < 0)
limit = -limit;
}
else
limit = -1;
hlist = history_list ();
if (hlist)
{
for (i = 0; hlist[i]; i++)
;
if (0 <= limit && limit < i)
i -= limit;
else
i = 0;
histtimefmt = get_string_value ("HISTTIMEFORMAT");
while (hlist[i])
{
QUIT;
timestr = (histtimefmt && *histtimefmt) ? histtime (hlist[i], histtimefmt) : (char *)NULL;
printf ("%5d%c %s%s\n", i + history_base,
histdata(i) ? '*' : ' ',
((timestr && *timestr) ? timestr : ""),
histline(i));
i++;
}
}
return (EXECUTION_SUCCESS);
}
/* Remove the last entry in the history list and add each argument in
LIST to the history. */
static void
push_history (list)
WORD_LIST *list;
{
char *s;
/* Delete the last history entry if it was a single entry added to the
history list (generally the `history -s' itself), or if `history -s'
is being used in a compound command and the compound command was
added to the history as a single element (command-oriented history).
If you don't want history -s to remove the compound command from the
history, change #if 0 to #if 1 below. */
#if 0
if (remember_on_history && hist_last_line_pushed == 0 &&
hist_last_line_added && bash_delete_last_history () == 0)
#else
if (remember_on_history && hist_last_line_pushed == 0 &&
(hist_last_line_added ||
(current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
&& bash_delete_last_history () == 0)
#endif
return;
s = string_list (list);
/* Call check_add_history with FORCE set to 1 to skip the check against
current_command_line_count. If history -s is used in a compound
command, the above code will delete the compound command's history
entry and this call will add the line to the history as a separate
entry. Without FORCE=1, if current_command_line_count were > 1, the
line would be appended to the entry before the just-deleted entry. */
check_add_history (s, 1); /* obeys HISTCONTROL, HISTIGNORE */
hist_last_line_pushed = 1; /* XXX */
free (s);
}
#if defined (BANG_HISTORY)
static int
expand_and_print_history (list)
WORD_LIST *list;
{
char *s;
int r, result;
if (hist_last_line_pushed == 0 && hist_last_line_added && bash_delete_last_history () == 0)
return EXECUTION_FAILURE;
result = EXECUTION_SUCCESS;
while (list)
{
r = history_expand (list->word->word, &s);
if (r < 0)
{
builtin_error (_("%s: history expansion failed"), list->word->word);
result = EXECUTION_FAILURE;
}
else
{
fputs (s, stdout);
putchar ('\n');
}
FREE (s);
list = list->next;
}
fflush (stdout);
return result;
}
#endif /* BANG_HISTORY */
#endif /* HISTORY */

300
builtins/jobs.def Normal file
View file

@ -0,0 +1,300 @@
This file is jobs.def, from which is created jobs.c.
It implements the builtins "jobs" and "disown" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES jobs.c
$BUILTIN jobs
$FUNCTION jobs_builtin
$DEPENDS_ON JOB_CONTROL
$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args]
Display status of jobs.
Lists the active jobs. JOBSPEC restricts output to that job.
Without options, the status of all active jobs is displayed.
Options:
-l lists process IDs in addition to the normal information
-n lists only processes that have changed status since the last
notification
-p lists process IDs only
-r restrict output to running jobs
-s restrict output to stopped jobs
If -x is supplied, 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.
Exit Status:
Returns success unless an invalid option is given or an error occurs.
If -x is used, returns the exit status of COMMAND.
$END
#include <config.h>
#if defined (JOB_CONTROL)
#include "../bashtypes.h"
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../jobs.h"
#include "../execute_cmd.h"
#include "bashgetopt.h"
#include "common.h"
#define JSTATE_ANY 0x0
#define JSTATE_RUNNING 0x1
#define JSTATE_STOPPED 0x2
static int execute_list_with_replacements PARAMS((WORD_LIST *));
/* The `jobs' command. Prints outs a list of active jobs. If the
argument `-l' is given, then the process id's are printed also.
If the argument `-p' is given, print the process group leader's
pid only. If `-n' is given, only processes that have changed
status since the last notification are printed. If -x is given,
replace all job specs with the pid of the appropriate process
group leader and execute the command. The -r and -s options mean
to print info about running and stopped jobs only, respectively. */
int
jobs_builtin (list)
WORD_LIST *list;
{
int form, execute, state, opt, any_failed, job;
sigset_t set, oset;
execute = any_failed = 0;
form = JLIST_STANDARD;
state = JSTATE_ANY;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "lpnxrs")) != -1)
{
switch (opt)
{
case 'l':
form = JLIST_LONG;
break;
case 'p':
form = JLIST_PID_ONLY;
break;
case 'n':
form = JLIST_CHANGED_ONLY;
break;
case 'x':
if (form != JLIST_STANDARD)
{
builtin_error (_("no other options allowed with `-x'"));
return (EXECUTION_FAILURE);
}
execute++;
break;
case 'r':
state = JSTATE_RUNNING;
break;
case 's':
state = JSTATE_STOPPED;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (execute)
return (execute_list_with_replacements (list));
if (!list)
{
switch (state)
{
case JSTATE_ANY:
list_all_jobs (form);
break;
case JSTATE_RUNNING:
list_running_jobs (form);
break;
case JSTATE_STOPPED:
list_stopped_jobs (form);
break;
}
return (EXECUTION_SUCCESS);
}
while (list)
{
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
{
sh_badjob (list->word->word);
any_failed++;
}
else if (job != DUP_JOB)
list_one_job ((JOB *)NULL, form, 0, job);
UNBLOCK_CHILD (oset);
list = list->next;
}
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
static int
execute_list_with_replacements (list)
WORD_LIST *list;
{
register WORD_LIST *l;
int job, result;
COMMAND *command;
JOB *j;
/* First do the replacement of job specifications with pids. */
for (l = list; l; l = l->next)
{
if (l->word->word[0] == '%') /* we have a winner */
{
job = get_job_spec (l);
/* A bad job spec is not really a job spec! Pass it through. */
if (INVALID_JOB (job))
continue;
j = get_job_by_jid (job);
free (l->word->word);
l->word->word = itos (j->pgrp);
}
}
/* Next make a new simple command and execute it. */
begin_unwind_frame ("jobs_builtin");
command = make_bare_simple_command ();
command->value.Simple->words = copy_word_list (list);
command->value.Simple->redirects = (REDIRECT *)NULL;
command->flags |= CMD_INHIBIT_EXPANSION;
command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
add_unwind_protect (dispose_command, command);
result = execute_command (command);
dispose_command (command);
discard_unwind_frame ("jobs_builtin");
return (result);
}
#endif /* JOB_CONTROL */
$BUILTIN disown
$FUNCTION disown_builtin
$DEPENDS_ON JOB_CONTROL
$SHORT_DOC disown [-h] [-ar] [jobspec ... | pid ...]
Remove jobs from current shell.
Removes each JOBSPEC argument from the table of active jobs. Without
any JOBSPECs, the shell uses its notion of the current job.
Options:
-a remove all jobs if JOBSPEC is not supplied
-h mark each JOBSPEC so that SIGHUP is not sent to the job if the
shell receives a SIGHUP
-r remove only running jobs
Exit Status:
Returns success unless an invalid option or JOBSPEC is given.
$END
#if defined (JOB_CONTROL)
int
disown_builtin (list)
WORD_LIST *list;
{
int opt, job, retval, nohup_only, running_jobs, all_jobs;
sigset_t set, oset;
intmax_t pid_value;
nohup_only = running_jobs = all_jobs = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "ahr")) != -1)
{
switch (opt)
{
case 'a':
all_jobs = 1;
break;
case 'h':
nohup_only = 1;
break;
case 'r':
running_jobs = 1;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
retval = EXECUTION_SUCCESS;
/* `disown -a' or `disown -r' */
if (list == 0 && (all_jobs || running_jobs))
{
if (nohup_only)
nohup_all_jobs (running_jobs);
else
delete_all_jobs (running_jobs);
return (EXECUTION_SUCCESS);
}
do
{
BLOCK_CHILD (set, oset);
job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
? get_job_by_pid ((pid_t) pid_value, 0, 0)
: get_job_spec (list);
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
{
sh_badjob (list ? list->word->word : _("current"));
retval = EXECUTION_FAILURE;
}
else if (nohup_only)
nohup_job (job);
else
delete_job (job, 1);
UNBLOCK_CHILD (oset);
if (list)
list = list->next;
}
while (list);
return (retval);
}
#endif /* JOB_CONTROL */

276
builtins/kill.def Normal file
View file

@ -0,0 +1,276 @@
This file is kill.def, from which is created kill.c.
It implements the builtin "kill" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES kill.c
$BUILTIN kill
$FUNCTION kill_builtin
$SHORT_DOC kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
Send a signal to a job.
Send the processes identified by PID or JOBSPEC the signal named by
SIGSPEC or SIGNUM. If neither SIGSPEC nor SIGNUM is present, then
SIGTERM is assumed.
Options:
-s sig SIG is a signal name
-n sig SIG is a signal number
-l list the signal names; if arguments follow `-l' they are
assumed to be signal numbers for which names should be listed
-L synonym for -l
Kill is a shell builtin for two reasons: it allows job IDs to be used
instead of process IDs, and allows processes to be killed if the limit
on processes that you can create is reached.
Exit Status:
Returns success unless an invalid option is given or an error occurs.
$END
#include <config.h>
#include <stdio.h>
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include <signal.h>
#include "../shell.h"
#include "../trap.h"
#include "../jobs.h"
#include "common.h"
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
#if !defined (errno)
extern int errno;
#endif /* !errno */
static void kill_error PARAMS((pid_t, int));
#if !defined (CONTINUE_AFTER_KILL_ERROR)
# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE)
#else
# define CONTINUE_OR_FAIL goto continue_killing
#endif /* CONTINUE_AFTER_KILL_ERROR */
/* Here is the kill builtin. We only have it so that people can type
kill -KILL %1? No, if you fill up the process table this way you
can still kill some. */
int
kill_builtin (list)
WORD_LIST *list;
{
int sig, any_succeeded, listing, saw_signal, dflags;
char *sigspec, *word;
pid_t pid;
intmax_t pid_value;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
CHECK_HELPOPT (list);
any_succeeded = listing = saw_signal = 0;
sig = SIGTERM;
sigspec = "TERM";
dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0);
/* Process options. */
while (list)
{
word = list->word->word;
if (ISOPTION (word, 'l') || ISOPTION (word, 'L'))
{
listing++;
list = list->next;
}
else if (ISOPTION (word, 's') || ISOPTION (word, 'n'))
{
list = list->next;
if (list)
{
sigspec = list->word->word;
use_sigspec:
if (sigspec[0] == '0' && sigspec[1] == '\0')
sig = 0;
else
sig = decode_signal (sigspec, dflags);
list = list->next;
saw_signal++;
}
else
{
sh_needarg (word);
return (EXECUTION_FAILURE);
}
}
else if (word[0] == '-' && word[1] == 's' && ISALPHA (word[2]))
{
sigspec = word + 2;
goto use_sigspec;
}
else if (word[0] == '-' && word[1] == 'n' && ISDIGIT (word[2]))
{
sigspec = word + 2;
goto use_sigspec;
}
else if (ISOPTION (word, '-'))
{
list = list->next;
break;
}
else if (ISOPTION (word, '?'))
{
builtin_usage ();
return (EX_USAGE);
}
/* If this is a signal specification then process it. We only process
the first one seen; other arguments may signify process groups (e.g,
-num == process group num). */
else if (*word == '-' && saw_signal == 0)
{
sigspec = word + 1;
sig = decode_signal (sigspec, dflags);
saw_signal++;
list = list->next;
}
else
break;
}
if (listing)
return (display_signal_list (list, 0));
/* OK, we are killing processes. */
if (sig == NO_SIG)
{
sh_invalidsig (sigspec);
return (EXECUTION_FAILURE);
}
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
while (list)
{
word = list->word->word;
if (*word == '-')
word++;
/* Use the entire argument in case of minus sign presence. */
if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value))
{
pid = (pid_t) pid_value;
if (kill_pid (pid, sig, pid < -1) < 0)
{
if (errno == EINVAL)
sh_invalidsig (sigspec);
else
kill_error (pid, errno);
CONTINUE_OR_FAIL;
}
else
any_succeeded++;
}
#if defined (JOB_CONTROL)
else if (*list->word->word && *list->word->word != '%')
{
builtin_error (_("%s: arguments must be process or job IDs"), list->word->word);
CONTINUE_OR_FAIL;
}
else if (*word)
/* Posix.2 says you can kill without job control active (4.32.4) */
{ /* Must be a job spec. Check it out. */
int job;
sigset_t set, oset;
JOB *j;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
UNBLOCK_CHILD (oset);
CONTINUE_OR_FAIL;
}
j = get_job_by_jid (job);
/* Job spec used. Kill the process group. If the job was started
without job control, then its pgrp == shell_pgrp, so we have
to be careful. We take the pid of the first job in the pipeline
in that case. */
pid = IS_JOBCONTROL (job) ? j->pgrp : j->pipe->pid;
UNBLOCK_CHILD (oset);
if (kill_pid (pid, sig, 1) < 0)
{
if (errno == EINVAL)
sh_invalidsig (sigspec);
else
kill_error (pid, errno);
CONTINUE_OR_FAIL;
}
else
any_succeeded++;
}
#endif /* !JOB_CONTROL */
else
{
sh_badpid (list->word->word);
CONTINUE_OR_FAIL;
}
continue_killing:
list = list->next;
}
return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
static void
kill_error (pid, e)
pid_t pid;
int e;
{
char *x;
x = strerror (e);
if (x == 0)
x = _("Unknown error");
builtin_error ("(%ld) - %s", (long)pid, x);
}

131
builtins/let.def Normal file
View file

@ -0,0 +1,131 @@
This file is let.def, from which is created let.c.
It implements the builtin "let" in Bash.
Copyright (C) 1987-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$BUILTIN let
$FUNCTION let_builtin
$PRODUCES let.c
$SHORT_DOC let arg [arg ...]
Evaluate arithmetic expressions.
Evaluate each ARG as an arithmetic expression. Evaluation is done in
fixed-width 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.
id++, id-- variable post-increment, post-decrement
++id, --id variable pre-increment, pre-decrement
-, + unary minus, plus
!, ~ logical and bitwise negation
** exponentiation
*, /, % multiplication, division, remainder
+, - addition, subtraction
<<, >> left and right bitwise shifts
<=, >=, <, > comparison
==, != equality, inequality
& bitwise AND
^ bitwise XOR
| bitwise OR
&& logical AND
|| logical OR
expr ? expr : expr
conditional operator
=, *=, /=, %=,
+=, -=, <<=, >>=,
&=, ^=, |= assignment
Shell variables are allowed as operands. The name of the variable
is replaced by its value (coerced to a fixed-width 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.
Exit Status:
If the last ARG evaluates to 0, let returns 1; let returns 0 otherwise.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
/* Arithmetic LET function. */
int
let_builtin (list)
WORD_LIST *list;
{
intmax_t ret;
int expok;
CHECK_HELPOPT (list);
/* Skip over leading `--' argument. */
if (list && list->word && ISOPTION (list->word->word, '-'))
list = list->next;
if (list == 0)
{
builtin_error (_("expression expected"));
return (EXECUTION_FAILURE);
}
for (; list; list = list->next)
{
ret = evalexp (list->word->word, EXP_EXPANDED, &expok);
if (expok == 0)
return (EXECUTION_FAILURE);
}
return ((ret == 0) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
#ifdef INCLUDE_UNUSED
int
exp_builtin (list)
WORD_LIST *list;
{
char *exp;
intmax_t ret;
int expok;
if (list == 0)
{
builtin_error (_("expression expected"));
return (EXECUTION_FAILURE);
}
exp = string_list (list);
ret = evalexp (exp, EXP_EXPANDED, &expok);
(void)free (exp);
return (((ret == 0) || (expok == 0)) ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
#endif

364
builtins/mapfile.def Normal file
View file

@ -0,0 +1,364 @@
This file is mapfile.def, from which is created mapfile.c.
It implements the builtin "mapfile" in Bash.
Copyright (C) 2005-2006 Rocky Bernstein for Free Software Foundation, Inc.
Copyright (C) 2008-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES mapfile.c
$BUILTIN mapfile
$FUNCTION mapfile_builtin
$SHORT_DOC mapfile [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
Read lines from the standard input into an indexed array variable.
Read lines from the standard input into the indexed array variable ARRAY, or
from file descriptor FD if the -u option is supplied. The variable MAPFILE
is the default ARRAY.
Options:
-d delim Use DELIM to terminate lines, instead of newline
-n count Copy at most COUNT lines. If COUNT is 0, all lines are copied
-O origin Begin assigning to ARRAY at index ORIGIN. The default index is 0
-s count Discard the first COUNT lines read
-t Remove a trailing DELIM from each line read (default newline)
-u fd Read lines from file descriptor FD instead of the standard input
-C callback Evaluate CALLBACK each time QUANTUM lines are read
-c quantum Specify the number of lines read between each call to
CALLBACK
Arguments:
ARRAY Array variable name to use for file data
If -C is supplied without -c, the default quantum is 5000. When
CALLBACK is evaluated, it is supplied the index of the next array
element to be assigned and the line to be assigned to that element
as additional arguments.
If not supplied with an explicit origin, mapfile will clear ARRAY before
assigning to it.
Exit Status:
Returns success unless an invalid option is given or ARRAY is readonly or
not an indexed array.
$END
$BUILTIN readarray
$FUNCTION mapfile_builtin
$SHORT_DOC readarray [-d delim] [-n count] [-O origin] [-s count] [-t] [-u fd] [-C callback] [-c quantum] [array]
Read lines from a file into an array variable.
A synonym for `mapfile'.
$END
#include <config.h>
#include "builtins.h"
#include "../bashtypes.h"
#include "posixstat.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "bashansi.h"
#include "bashintl.h"
#include <stdio.h>
#include <errno.h>
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#if !defined (errno)
extern int errno;
#endif
#if defined (ARRAY_VARS)
static int run_callback PARAMS((const char *, unsigned int, const char *));
#define DEFAULT_ARRAY_NAME "MAPFILE"
#define DEFAULT_VARIABLE_NAME "MAPLINE" /* not used right now */
/* The value specifying how frequently `mapfile' calls the callback. */
#define DEFAULT_QUANTUM 5000
/* Values for FLAGS */
#define MAPF_CLEARARRAY 0x01
#define MAPF_CHOP 0x02
static int delim;
static int
run_callback (callback, curindex, curline)
const char *callback;
unsigned int curindex;
const char *curline;
{
unsigned int execlen;
char *execstr, *qline;
int flags;
qline = sh_single_quote (curline);
execlen = strlen (callback) + strlen (qline) + 10;
/* 1 for each space between %s and %d,
another 1 for the last nul char for C string. */
execlen += 3;
execstr = xmalloc (execlen);
flags = SEVAL_NOHIST;
#if 0
if (interactive)
flags |= SEVAL_INTERACT;
#endif
snprintf (execstr, execlen, "%s %d %s", callback, curindex, qline);
free (qline);
return evalstring (execstr, NULL, flags);
}
static void
do_chop(line, delim)
char *line;
unsigned char delim;
{
int length;
length = strlen (line);
if (length && (unsigned char)line[length-1] == delim)
line[length-1] = '\0';
}
static int
mapfile (fd, line_count_goal, origin, nskip, callback_quantum, callback, array_name, delim, flags)
int fd;
long line_count_goal, origin, nskip, callback_quantum;
char *callback, *array_name;
int delim;
int flags;
{
char *line;
size_t line_length;
unsigned int array_index, line_count;
SHELL_VAR *entry;
struct stat sb;
int unbuffered_read;
line = NULL;
line_length = 0;
unbuffered_read = 0;
/* The following check should be done before reading any lines. Doing it
here allows us to call bind_array_element instead of bind_array_variable
and skip the variable lookup on every call. */
entry = builtin_find_indexed_array (array_name, flags & MAPF_CLEARARRAY);
if (entry == 0)
return EXECUTION_FAILURE;
#ifndef __CYGWIN__
/* If the delimiter is a newline, turn on unbuffered reads for pipes
(terminals are ok). If the delimiter is not a newline, unbuffered reads
for every file descriptor that's not a regular file. */
if (delim == '\n')
unbuffered_read = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
else
unbuffered_read = (fstat (fd, &sb) != 0) || (S_ISREG (sb.st_mode) == 0);
#else
unbuffered_read = 1;
#endif
zreset ();
/* Skip any lines at beginning of file? */
for (line_count = 0; line_count < nskip; line_count++)
if (zgetline (fd, &line, &line_length, delim, unbuffered_read) < 0)
break;
line = 0;
line_length = 0;
/* Reset the buffer for bash own stream */
for (array_index = origin, line_count = 1;
zgetline (fd, &line, &line_length, delim, unbuffered_read) != -1;
array_index++)
{
/* Remove trailing newlines? */
if (flags & MAPF_CHOP)
do_chop (line, delim);
/* Has a callback been registered and if so is it time to call it? */
if (callback && line_count && (line_count % callback_quantum) == 0)
{
/* Reset the buffer for bash own stream. */
if (unbuffered_read == 0)
zsyncfd (fd);
run_callback (callback, array_index, line);
}
/* XXX - bad things can happen if the callback modifies ENTRY, e.g.,
unsetting it or changing it to a non-indexed-array type. */
bind_array_element (entry, array_index, line, 0);
/* Have we exceeded # of lines to store? */
line_count++;
if (line_count_goal != 0 && line_count > line_count_goal)
break;
}
free (line);
if (unbuffered_read == 0)
zsyncfd (fd);
return EXECUTION_SUCCESS;
}
int
mapfile_builtin (list)
WORD_LIST *list;
{
int opt, code, fd, flags;
intmax_t intval;
long lines, origin, nskip, callback_quantum;
char *array_name, *callback;
fd = 0;
lines = origin = nskip = 0;
flags = MAPF_CLEARARRAY;
callback_quantum = DEFAULT_QUANTUM;
callback = 0;
delim = '\n';
reset_internal_getopt ();
while ((opt = internal_getopt (list, "d:u:n:O:tC:c:s:")) != -1)
{
switch (opt)
{
case 'd':
delim = *list_optarg;
break;
case 'u':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (int)intval)
{
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
return (EXECUTION_FAILURE);
}
else
fd = intval;
if (sh_validfd (fd) == 0)
{
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
return (EXECUTION_FAILURE);
}
break;
case 'n':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (unsigned)intval)
{
builtin_error (_("%s: invalid line count"), list_optarg);
return (EXECUTION_FAILURE);
}
else
lines = intval;
break;
case 'O':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (unsigned)intval)
{
builtin_error (_("%s: invalid array origin"), list_optarg);
return (EXECUTION_FAILURE);
}
else
origin = intval;
flags &= ~MAPF_CLEARARRAY;
break;
case 't':
flags |= MAPF_CHOP;
break;
case 'C':
callback = list_optarg;
break;
case 'c':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval <= 0 || intval != (unsigned)intval)
{
builtin_error (_("%s: invalid callback quantum"), list_optarg);
return (EXECUTION_FAILURE);
}
else
callback_quantum = intval;
break;
case 's':
code = legal_number (list_optarg, &intval);
if (code == 0 || intval < 0 || intval != (unsigned)intval)
{
builtin_error (_("%s: invalid line count"), list_optarg);
return (EXECUTION_FAILURE);
}
else
nskip = intval;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list == 0)
array_name = DEFAULT_ARRAY_NAME;
else if (list->word == 0 || list->word->word == 0)
{
builtin_error ("internal error: getting variable name");
return (EXECUTION_FAILURE);
}
else if (list->word->word[0] == '\0')
{
builtin_error (_("empty array variable name"));
return (EX_USAGE);
}
else
array_name = list->word->word;
if (legal_identifier (array_name) == 0)
{
sh_invalidid (array_name);
return (EXECUTION_FAILURE);
}
return mapfile (fd, lines, origin, nskip, callback_quantum, callback, array_name, delim, flags);
}
#else
int
mapfile_builtin (list)
WORD_LIST *list;
{
builtin_error (_("array variable support required"));
return (EXECUTION_FAILURE);
}
#endif /* ARRAY_VARS */

1692
builtins/mkbuiltins.c Normal file

File diff suppressed because it is too large Load diff

1355
builtins/printf.def Normal file

File diff suppressed because it is too large Load diff

79
builtins/psize.c Normal file
View file

@ -0,0 +1,79 @@
/* 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 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
*/
/* 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 <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#ifndef _MINIX
#include "../bashtypes.h"
#endif
#include <signal.h>
#include <errno.h>
#include "../command.h"
#include "../general.h"
#include "../sig.h"
#ifndef errno
extern int errno;
#endif
int nw;
sighandler
sigpipe (sig)
int sig;
{
fprintf (stderr, "%d\n", nw);
exit (0);
}
int
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;
}
return (0);
}

45
builtins/psize.sh Normal file
View file

@ -0,0 +1,45 @@
#! /bin/sh
#
# psize.sh -- determine this system's pipe size, and write a define to
# pipesize.h so ulimit.c can use it.
: ${TMPDIR:=/tmp}
# try to use mktemp(1) if the system supports it
{ TMPFILE="`mktemp $TMPDIR/pipsize.XXXXXX 2>/dev/null`"; } 2>/dev/null
used_mktemp=true
if [ -z "$TMPFILE" ]; then
TMPNAME=pipsize.$$
TMPFILE=$TMPDIR/$TMPNAME
used_mktemp=false
fi
trap 'rm -f "$TMPFILE" ; exit 1' 1 2 3 6 15
trap 'rm -f "$TMPFILE"' 0
echo "/*"
echo " * pipesize.h"
echo " *"
echo " * This file is automatically generated by psize.sh"
echo " * Do not edit!"
echo " */"
echo ""
#
# Try to avoid tempfile races. We can't really check for the file's
# existence before we run psize.aux, because `test -e' is not portable,
# `test -h' (test for symlinks) is not portable, and `test -f' only
# checks for regular files. If we used mktemp(1), we're ahead of the
# game.
#
$used_mktemp || rm -f "$TMPFILE"
./psize.aux 2>"$TMPFILE" | sleep 3
if [ -s "$TMPFILE" ]; then
echo "#define PIPESIZE `cat "$TMPFILE"`"
else
echo "#define PIPESIZE 512"
fi
exit 0

796
builtins/pushd.def Normal file
View file

@ -0,0 +1,796 @@
This file is pushd.def, from which is created pushd.c. It implements the
builtins "pushd", "popd", and "dirs" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES pushd.c
$BUILTIN pushd
$FUNCTION pushd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC pushd [-n] [+N | -N | dir]
Add directories to stack.
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.
Options:
-n Suppresses the normal change of directory when adding
directories to the stack, so only the stack is manipulated.
Arguments:
+N Rotates the stack so that the Nth directory (counting
from the left of the list shown by `dirs', starting with
zero) is at the top.
-N Rotates the stack so that the Nth directory (counting
from the right of the list shown by `dirs', starting with
zero) is at the top.
dir Adds DIR to the directory stack at the top, making it the
new current working directory.
The `dirs' builtin displays the directory stack.
Exit Status:
Returns success unless an invalid argument is supplied or the directory
change fails.
$END
$BUILTIN popd
$FUNCTION popd_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC popd [-n] [+N | -N]
Remove directories from stack.
Removes entries from the directory stack. With no arguments, removes
the top directory from the stack, and changes to the new top directory.
Options:
-n Suppresses the normal change of directory when removing
directories from the stack, so only the stack is manipulated.
Arguments:
+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.
The `dirs' builtin displays the directory stack.
Exit Status:
Returns success unless an invalid argument is supplied or the directory
change fails.
$END
$BUILTIN dirs
$FUNCTION dirs_builtin
$DEPENDS_ON PUSHD_AND_POPD
$SHORT_DOC dirs [-clpv] [+N] [-N]
Display directory stack.
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.
Options:
-c clear the directory stack by deleting all of the elements
-l do not print tilde-prefixed versions of directories relative
to your home directory
-p print the directory stack with one entry per line
-v print the directory stack with one entry per line prefixed
with its position in the stack
Arguments:
+N Displays the Nth entry counting from the left of the list
shown by dirs when invoked without options, starting with
zero.
-N Displays the Nth entry counting from the right of the list
shown by dirs when invoked without options, starting with
zero.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
#include <config.h>
#if defined (PUSHD_AND_POPD)
#include <stdio.h>
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include <errno.h>
#include <tilde/tilde.h>
#include "../shell.h"
#include "maxpath.h"
#include "common.h"
#include "builtext.h"
#ifdef LOADABLE_BUILTIN
# include "builtins.h"
#endif
#if !defined (errno)
extern int errno;
#endif /* !errno */
/* The list of remembered directories. */
static char **pushd_directory_list = (char **)NULL;
/* Number of existing slots in this list. */
static int directory_list_size;
/* Offset to the end of the list. */
static int directory_list_offset;
static void pushd_error PARAMS((int, char *));
static void clear_directory_stack PARAMS((void));
static int cd_to_string PARAMS((char *));
static int change_to_temp PARAMS((char *));
static void add_dirstack_element PARAMS((char *));
static int get_dirstack_index PARAMS((intmax_t, int, int *));
#define NOCD 0x01
#define ROTATE 0x02
#define LONGFORM 0x04
#define CLEARSTAK 0x08
int
pushd_builtin (list)
WORD_LIST *list;
{
WORD_LIST *orig_list;
char *temp, *current_directory, *top;
int j, flags, skipopt;
intmax_t num;
char direction;
orig_list = list;
CHECK_HELPOPT (list);
if (list && list->word && ISOPTION (list->word->word, '-'))
{
list = list->next;
skipopt = 1;
}
else
skipopt = 0;
/* If there is no argument list then switch current and
top of list. */
if (list == 0)
{
if (directory_list_offset == 0)
{
builtin_error (_("no other directory"));
return (EXECUTION_FAILURE);
}
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = directory_list_offset - 1;
temp = pushd_directory_list[j];
pushd_directory_list[j] = current_directory;
j = change_to_temp (temp);
free (temp);
return j;
}
for (flags = 0; skipopt == 0 && list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
/* Let `pushd -' work like it used to. */
break;
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &num) == 0)
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
if (direction == '-')
num = directory_list_offset - num;
if (num > directory_list_offset || num < 0)
{
pushd_error (directory_list_offset, list->word->word);
return (EXECUTION_FAILURE);
}
flags |= ROTATE;
}
else if (*list->word->word == '-')
{
sh_invalidopt (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
else
break;
}
if (flags & ROTATE)
{
/* Rotate the stack num times. Remember, the current
directory acts like it is part of the stack. */
temp = get_working_directory ("pushd");
if (num == 0)
{
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
do
{
top = pushd_directory_list[directory_list_offset - 1];
for (j = directory_list_offset - 2; j > -1; j--)
pushd_directory_list[j + 1] = pushd_directory_list[j];
pushd_directory_list[j + 1] = temp;
temp = top;
num--;
}
while (num);
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
free (temp);
return j;
}
if (list == 0)
return (EXECUTION_SUCCESS);
/* Change to the directory in list->word->word. Save the current
directory on the top of the stack. */
current_directory = get_working_directory ("pushd");
if (current_directory == 0)
return (EXECUTION_FAILURE);
j = ((flags & NOCD) == 0) ? cd_builtin (skipopt ? orig_list : list) : EXECUTION_SUCCESS;
if (j == EXECUTION_SUCCESS)
{
add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
dirs_builtin ((WORD_LIST *)NULL);
if (flags & NOCD)
free (current_directory);
return (EXECUTION_SUCCESS);
}
else
{
free (current_directory);
return (EXECUTION_FAILURE);
}
}
/* Pop the directory stack, and then change to the new top of the stack.
If LIST is non-null it should consist of a word +N or -N, which says
what element to delete from the stack. The default is the top one. */
int
popd_builtin (list)
WORD_LIST *list;
{
register int i;
intmax_t which;
int flags;
char direction;
char *which_word;
CHECK_HELPOPT (list);
which_word = (char *)NULL;
for (flags = 0, which = 0, direction = '+'; list; list = list->next)
{
if (ISOPTION (list->word->word, 'n'))
{
flags |= NOCD;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (((direction = list->word->word[0]) == '+') || direction == '-')
{
if (legal_number (list->word->word + 1, &which) == 0)
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
which_word = list->word->word;
}
else if (*list->word->word == '-')
{
sh_invalidopt (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
else if (*list->word->word)
{
builtin_error (_("%s: invalid argument"), list->word->word);
builtin_usage ();
return (EX_USAGE);
}
else
break;
}
if (which > directory_list_offset || (which < -directory_list_offset) || (directory_list_offset == 0 && which == 0))
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
}
/* Handle case of no specification, or top of stack specification. */
if ((direction == '+' && which == 0) ||
(direction == '-' && which == directory_list_offset))
{
i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
: EXECUTION_SUCCESS;
if (i != EXECUTION_SUCCESS)
return (i);
free (pushd_directory_list[--directory_list_offset]);
}
else
{
/* Since an offset other than the top directory was specified,
remove that directory from the list and shift the remainder
of the list into place. */
i = (direction == '+') ? directory_list_offset - which : which;
if (i < 0 || i > directory_list_offset)
{
pushd_error (directory_list_offset, which_word ? which_word : "");
return (EXECUTION_FAILURE);
}
free (pushd_directory_list[i]);
directory_list_offset--;
/* Shift the remainder of the list into place. */
for (; i < directory_list_offset; i++)
pushd_directory_list[i] = pushd_directory_list[i + 1];
}
dirs_builtin ((WORD_LIST *)NULL);
return (EXECUTION_SUCCESS);
}
/* Print the current list of directories on the directory stack. */
int
dirs_builtin (list)
WORD_LIST *list;
{
int flags, desired_index, index_flag, vflag;
intmax_t i;
char *temp, *w;
CHECK_HELPOPT (list);
for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
{
if (ISOPTION (list->word->word, 'l'))
{
flags |= LONGFORM;
}
else if (ISOPTION (list->word->word, 'c'))
{
flags |= CLEARSTAK;
}
else if (ISOPTION (list->word->word, 'v'))
{
vflag |= 2;
}
else if (ISOPTION (list->word->word, 'p'))
{
vflag |= 1;
}
else if (ISOPTION (list->word->word, '-'))
{
list = list->next;
break;
}
else if (*list->word->word == '+' || *list->word->word == '-')
{
int sign;
if (legal_number (w = list->word->word + 1, &i) == 0)
{
sh_invalidnum (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
sign = (*list->word->word == '+') ? 1 : -1;
desired_index = get_dirstack_index (i, sign, &index_flag);
}
else
{
sh_invalidopt (list->word->word);
builtin_usage ();
return (EX_USAGE);
}
}
if (flags & CLEARSTAK)
{
clear_directory_stack ();
return (EXECUTION_SUCCESS);
}
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
{
pushd_error (directory_list_offset, w);
return (EXECUTION_FAILURE);
}
#define DIRSTACK_FORMAT(temp) \
(flags & LONGFORM) ? temp : polite_directory_format (temp)
/* The first directory printed is always the current working directory. */
if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
{
temp = get_working_directory ("dirs");
if (temp == 0)
temp = savestring (_("<no current directory>"));
if (vflag & 2)
printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
else
printf ("%s", DIRSTACK_FORMAT (temp));
free (temp);
if (index_flag)
{
putchar ('\n');
return (sh_chkwrite (EXECUTION_SUCCESS));
}
}
#define DIRSTACK_ENTRY(i) \
(flags & LONGFORM) ? pushd_directory_list[i] \
: polite_directory_format (pushd_directory_list[i])
/* Now print the requested directory stack entries. */
if (index_flag)
{
if (vflag & 2)
printf ("%2d %s", directory_list_offset - desired_index,
DIRSTACK_ENTRY (desired_index));
else
printf ("%s", DIRSTACK_ENTRY (desired_index));
}
else
for (i = directory_list_offset - 1; i >= 0; i--)
if (vflag >= 2)
printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
else
printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
putchar ('\n');
return (sh_chkwrite (EXECUTION_SUCCESS));
}
static void
pushd_error (offset, arg)
int offset;
char *arg;
{
if (offset == 0)
builtin_error (_("directory stack empty"));
else
sh_erange (arg, _("directory stack index"));
}
static void
clear_directory_stack ()
{
register int i;
for (i = 0; i < directory_list_offset; i++)
free (pushd_directory_list[i]);
directory_list_offset = 0;
}
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
so if the result is EXECUTION_FAILURE then an error message has already
been printed. */
static int
cd_to_string (name)
char *name;
{
WORD_LIST *tlist;
WORD_LIST *dir;
int result;
dir = make_word_list (make_word (name), NULL);
tlist = make_word_list (make_word ("--"), dir);
result = cd_builtin (tlist);
dispose_words (tlist);
return (result);
}
static int
change_to_temp (temp)
char *temp;
{
int tt;
tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
if (tt == EXECUTION_SUCCESS)
dirs_builtin ((WORD_LIST *)NULL);
return (tt);
}
static void
add_dirstack_element (dir)
char *dir;
{
if (directory_list_offset == directory_list_size)
pushd_directory_list = strvec_resize (pushd_directory_list, directory_list_size += 10);
pushd_directory_list[directory_list_offset++] = dir;
}
static int
get_dirstack_index (ind, sign, indexp)
intmax_t ind;
int sign, *indexp;
{
if (indexp)
*indexp = sign > 0 ? 1 : 2;
/* dirs +0 prints the current working directory. */
/* dirs -0 prints last element in directory stack */
if (ind == 0 && sign > 0)
return 0;
else if (ind == directory_list_offset)
{
if (indexp)
*indexp = sign > 0 ? 2 : 1;
return 0;
}
else if (ind >= 0 && ind <= directory_list_offset)
return (sign > 0 ? directory_list_offset - ind : ind);
else
return -1;
}
/* Used by the tilde expansion code. */
char *
get_dirstack_from_string (string)
char *string;
{
int ind, sign, index_flag;
intmax_t i;
sign = 1;
if (*string == '-' || *string == '+')
{
sign = (*string == '-') ? -1 : 1;
string++;
}
if (legal_number (string, &i) == 0)
return ((char *)NULL);
index_flag = 0;
ind = get_dirstack_index (i, sign, &index_flag);
if (index_flag && (ind < 0 || ind > directory_list_offset))
return ((char *)NULL);
if (index_flag == 0 || (index_flag == 1 && ind == 0))
return (get_string_value ("PWD"));
else
return (pushd_directory_list[ind]);
}
#ifdef INCLUDE_UNUSED
char *
get_dirstack_element (ind, sign)
intmax_t ind;
int sign;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
return (i < 0 || i > directory_list_offset) ? (char *)NULL
: pushd_directory_list[i];
}
#endif
void
set_dirstack_element (ind, sign, value)
intmax_t ind;
int sign;
char *value;
{
int i;
i = get_dirstack_index (ind, sign, (int *)NULL);
if (ind == 0 || i < 0 || i > directory_list_offset)
return;
free (pushd_directory_list[i]);
pushd_directory_list[i] = savestring (value);
}
WORD_LIST *
get_directory_stack (flags)
int flags;
{
register int i;
WORD_LIST *ret;
char *d, *t;
for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
{
d = (flags&1) ? polite_directory_format (pushd_directory_list[i])
: pushd_directory_list[i];
ret = make_word_list (make_word (d), ret);
}
/* Now the current directory. */
d = get_working_directory ("dirstack");
i = 0; /* sentinel to decide whether or not to free d */
if (d == 0)
d = ".";
else
{
t = (flags&1) ? polite_directory_format (d) : d;
/* polite_directory_format sometimes returns its argument unchanged.
If it does not, we can free d right away. If it does, we need to
mark d to be deleted later. */
if (t != d)
{
free (d);
d = t;
}
else /* t == d, so d is what we want */
i = 1;
}
ret = make_word_list (make_word (d), ret);
if (i)
free (d);
return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
}
#ifdef LOADABLE_BUILTIN
char * const dirs_doc[] = {
N_("Display the list of currently remembered directories. Directories\n\
find their way onto the list with the `pushd' command; you can get\n\
back up through the list with the `popd' command.\n\
\n\
Options:\n\
-c clear the directory stack by deleting all of the elements\n\
-l do not print tilde-prefixed versions of directories relative\n\
to your home directory\n\
-p print the directory stack with one entry per line\n\
-v print the directory stack with one entry per line prefixed\n\
with its position in the stack\n\
\n\
Arguments:\n\
+N Displays the Nth entry counting from the left of the list shown by\n\
dirs when invoked without options, starting with zero.\n\
\n\
-N Displays the Nth entry counting from the right of the list shown by\n\
dirs when invoked without options, starting with zero."),
(char *)NULL
};
char * const pushd_doc[] = {
N_("Adds a directory to the top of the directory stack, or rotates\n\
the stack, making the new top of the stack the current working\n\
directory. With no arguments, exchanges the top two directories.\n\
\n\
Options:\n\
-n Suppresses the normal change of directory when adding\n\
directories to the stack, so only the stack is manipulated.\n\
\n\
Arguments:\n\
+N Rotates the stack so that the Nth directory (counting\n\
from the left of the list shown by `dirs', starting with\n\
zero) is at the top.\n\
\n\
-N Rotates the stack so that the Nth directory (counting\n\
from the right of the list shown by `dirs', starting with\n\
zero) is at the top.\n\
\n\
dir Adds DIR to the directory stack at the top, making it the\n\
new current working directory.\n\
\n\
The `dirs' builtin displays the directory stack."),
(char *)NULL
};
char * const popd_doc[] = {
N_("Removes entries from the directory stack. With no arguments, removes\n\
the top directory from the stack, and changes to the new top directory.\n\
\n\
Options:\n\
-n Suppresses the normal change of directory when removing\n\
directories from the stack, so only the stack is manipulated.\n\
\n\
Arguments:\n\
+N Removes the Nth entry counting from the left of the list\n\
shown by `dirs', starting with zero. For example: `popd +0'\n\
removes the first directory, `popd +1' the second.\n\
\n\
-N Removes the Nth entry counting from the right of the list\n\
shown by `dirs', starting with zero. For example: `popd -0'\n\
removes the last directory, `popd -1' the next to last.\n\
\n\
The `dirs' builtin displays the directory stack."),
(char *)NULL
};
struct builtin pushd_struct = {
"pushd",
pushd_builtin,
BUILTIN_ENABLED,
pushd_doc,
"pushd [+N | -N] [-n] [dir]",
0
};
struct builtin popd_struct = {
"popd",
popd_builtin,
BUILTIN_ENABLED,
popd_doc,
"popd [+N | -N] [-n]",
0
};
struct builtin dirs_struct = {
"dirs",
dirs_builtin,
BUILTIN_ENABLED,
dirs_doc,
"dirs [-clpv] [+N] [-N]",
0
};
#endif /* LOADABLE_BUILTIN */
#endif /* PUSHD_AND_POPD */

1273
builtins/read.def Normal file

File diff suppressed because it is too large Load diff

288
builtins/reserved.def Normal file
View file

@ -0,0 +1,288 @@
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-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$BUILTIN for
$SHORT_DOC for NAME [in WORDS ... ] ; do COMMANDS; done
Execute commands for each member in a list.
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.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN for ((
$DOCNAME arith_for
$SHORT_DOC for (( exp1; exp2; exp3 )); do COMMANDS; done
Arithmetic for loop.
Equivalent to
(( EXP1 ))
while (( EXP2 )); do
COMMANDS
(( EXP3 ))
done
EXP1, EXP2, and EXP3 are arithmetic expressions. If any expression is
omitted, it behaves as if it evaluates to 1.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN select
$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done
Select words from a list and execute commands.
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 command is executed.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN time
$SHORT_DOC time [-p] pipeline
Report time consumed by pipeline's execution.
Execute PIPELINE and print a summary of the real time, user CPU time,
and system CPU time spent executing PIPELINE when it terminates.
Options:
-p print the timing summary in the portable Posix format
The value of the TIMEFORMAT variable is used as the output format.
Exit Status:
The return status is the return status of PIPELINE.
$END
$BUILTIN case
$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
Execute commands based on pattern matching.
Selectively execute COMMANDS based upon WORD matching PATTERN. The
`|' is used to separate multiple patterns.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN if
$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
Execute commands based on conditional.
The `if COMMANDS' list is executed. If its exit status is zero, then the
`then COMMANDS' list is executed. Otherwise, each `elif COMMANDS' list is
executed in turn, and if its exit status is zero, the corresponding
`then COMMANDS' list is executed and the if command completes. Otherwise,
the `else COMMANDS' list is executed, if present. The exit status of the
entire construct is the exit status of the last command executed, or zero
if no condition tested true.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN while
$SHORT_DOC while COMMANDS; do COMMANDS-2; done
Execute commands as long as a test succeeds.
Expand and execute COMMANDS-2 as long as the final command in COMMANDS has
an exit status of zero.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN until
$SHORT_DOC until COMMANDS; do COMMANDS-2; done
Execute commands as long as a test does not succeed.
Expand and execute COMMANDS-2 as long as the final command in COMMANDS has
an exit status which is not zero.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN coproc
$SHORT_DOC coproc [NAME] command [redirections]
Create a coprocess named NAME.
Execute COMMAND asynchronously, with the standard output and standard
input of the command connected via a pipe to file descriptors assigned
to indices 0 and 1 of an array variable NAME in the executing shell.
The default NAME is "COPROC".
Exit Status:
The coproc command returns an exit status of 0.
$END
$BUILTIN function
$SHORT_DOC function name { COMMANDS ; } or name () { COMMANDS ; }
Define shell function.
Create a shell function named NAME. When invoked as a simple command,
NAME runs COMMANDs in the calling shell's context. When NAME is invoked,
the arguments are passed to the function as $1...$n, and the function's
name is in $FUNCNAME.
Exit Status:
Returns success unless NAME is readonly.
$END
$BUILTIN { ... }
$DOCNAME grouping_braces
$SHORT_DOC { COMMANDS ; }
Group commands as a unit.
Run a set of commands in a group. This is one way to redirect an
entire set of commands.
Exit Status:
Returns the status of the last command executed.
$END
$BUILTIN %
$DOCNAME fg_percent
$SHORT_DOC job_spec [&]
Resume job in foreground.
Equivalent to the JOB_SPEC argument to the `fg' command. Resume a
stopped or background job. JOB_SPEC can specify either a job name
or a job number. Following JOB_SPEC with a `&' places the job in
the background, as if the job specification had been supplied as an
argument to `bg'.
Exit Status:
Returns the status of the resumed job.
$END
$BUILTIN (( ... ))
$DOCNAME arith
$SHORT_DOC (( expression ))
Evaluate arithmetic expression.
The EXPRESSION is evaluated according to the rules for arithmetic
evaluation. Equivalent to `let "EXPRESSION"'.
Exit Status:
Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise.
$END
$BUILTIN [[ ... ]]
$DOCNAME conditional
$SHORT_DOC [[ expression ]]
Execute conditional command.
Returns a status of 0 or 1 depending on the evaluation of the conditional
expression EXPRESSION. Expressions are composed of the same primaries used
by the `test' builtin, and may be combined using the following operators:
( EXPRESSION ) Returns the value of EXPRESSION
! EXPRESSION True if EXPRESSION is false; else false
EXPR1 && EXPR2 True if both EXPR1 and EXPR2 are true; else false
EXPR1 || EXPR2 True if either EXPR1 or EXPR2 is true; else false
When the `==' and `!=' operators are used, the string to the right of
the operator is used as a pattern and pattern matching is performed.
When the `=~' operator is used, the string to the right of the operator
is matched as a regular expression.
The && and || operators do not evaluate EXPR2 if EXPR1 is sufficient to
determine the expression's value.
Exit Status:
0 or 1 depending on value of EXPRESSION.
$END
$BUILTIN variables
$DOCNAME variable_help
$SHORT_DOC variables - Names and meanings of some shell variables
Common shell variable names and usage.
BASH_VERSION Version information for this Bash.
CDPATH A colon-separated list of directories to search
for directories given as arguments to `cd'.
GLOBIGNORE A colon-separated list of patterns describing filenames to
be ignored by pathname expansion.
#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.
HOSTNAME The name of the current host.
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.
MACHTYPE A string describing the current system Bash is running on.
MAILCHECK How often, in seconds, Bash checks for new mail.
MAILPATH A colon-separated list of filenames which Bash checks
for new mail.
OSTYPE The version of Unix this version of Bash is running on.
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.
PWD The full pathname of the current directory.
SHELLOPTS A colon-separated list of enabled shell options.
TERM The name of the current terminal type.
TIMEFORMAT The output format for timing statistics displayed by the
`time' reserved word.
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)
# 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 */
HISTIGNORE A colon-separated list of patterns used to decide which
commands should be saved on the history list.
#endif /* HISTORY */
$END

71
builtins/return.def Normal file
View file

@ -0,0 +1,71 @@
This file is return.def, from which is created return.c.
It implements the builtin "return" in Bash.
Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES return.c
$BUILTIN return
$FUNCTION return_builtin
$SHORT_DOC return [n]
Return from a shell function.
Causes a function or sourced script to exit with the return value
specified by N. If N is omitted, the return status is that of the
last command executed within the function or script.
Exit Status:
Returns N, or failure if the shell is not executing a function or script.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "common.h"
#include "bashgetopt.h"
/* 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;
{
CHECK_HELPOPT (list);
return_catch_value = get_exitstat (list);
if (return_catch_flag)
sh_longjmp (return_catch, 1);
else
{
builtin_error (_("can only `return' from a function or sourced script"));
return (EX_USAGE);
}
}

1028
builtins/set.def Normal file

File diff suppressed because it is too large Load diff

672
builtins/setattr.def Normal file
View file

@ -0,0 +1,672 @@
This file is setattr.def, from which is created setattr.c.
It implements the builtins "export" and "readonly", in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES setattr.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../flags.h"
#include "common.h"
#include "bashgetopt.h"
extern sh_builtin_func_t *this_shell_builtin;
#ifdef ARRAY_VARS
extern int declare_builtin PARAMS((WORD_LIST *));
#endif
#define READONLY_OR_EXPORT \
(this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
$BUILTIN export
$FUNCTION export_builtin
$SHORT_DOC export [-fn] [name[=value] ...] or export -p
Set export attribute for shell variables.
Marks each NAME for automatic export to the environment of subsequently
executed commands. If VALUE is supplied, assign VALUE before exporting.
Options:
-f refer to shell functions
-n remove the export property from each NAME
-p display a list of all exported variables and functions
An argument of `--' disables further option processing.
Exit Status:
Returns success unless an invalid option is given or NAME is invalid.
$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. */
int
export_builtin (list)
register WORD_LIST *list;
{
return (set_or_show_attributes (list, att_exported, 0));
}
$BUILTIN readonly
$FUNCTION readonly_builtin
$SHORT_DOC readonly [-aAf] [name[=value] ...] or readonly -p
Mark shell variables as unchangeable.
Mark each NAME as read-only; the values of these NAMEs may not be
changed by subsequent assignment. If VALUE is supplied, assign VALUE
before marking as read-only.
Options:
-a refer to indexed array variables
-A refer to associative array variables
-f refer to shell functions
-p display a list of all readonly variables or functions,
depending on whether or not the -f option is given
An argument of `--' disables further option processing.
Exit Status:
Returns success unless an invalid option is given or NAME is invalid.
$END
/* For each variable name in LIST, make that variable readonly. Given an
empty LIST, print out all existing readonly variables. */
int
readonly_builtin (list)
register WORD_LIST *list;
{
return (set_or_show_attributes (list, att_readonly, 0));
}
#if defined (ARRAY_VARS)
# define ATTROPTS "aAfnp"
#else
# define ATTROPTS "fnp"
#endif
/* For each variable name in LIST, make that variable have the specified
ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
remaining names in LIST (doesn't work for readonly). */
int
set_or_show_attributes (list, attribute, nodefs)
register WORD_LIST *list;
int attribute, nodefs;
{
register SHELL_VAR *var;
int assign, undo, any_failed, assign_error, opt;
int functions_only, arrays_only, assoc_only;
int aflags;
char *name;
#if defined (ARRAY_VARS)
WORD_LIST *nlist, *tlist;
WORD_DESC *w;
char optw[8];
int opti;
#endif
functions_only = arrays_only = assoc_only = 0;
undo = any_failed = assign_error = 0;
/* Read arguments from the front of the list. */
reset_internal_getopt ();
while ((opt = internal_getopt (list, ATTROPTS)) != -1)
{
switch (opt)
{
case 'n':
undo = 1;
break;
case 'f':
functions_only = 1;
break;
#if defined (ARRAY_VARS)
case 'a':
arrays_only = 1;
break;
case 'A':
assoc_only = 1;
break;
#endif
case 'p':
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list)
{
if (attribute & att_exported)
array_needs_making = 1;
/* Cannot undo readonly status, silently disallowed. */
if (undo && (attribute & att_readonly))
attribute &= ~att_readonly;
while (list)
{
name = list->word->word;
if (functions_only) /* xxx -f name */
{
var = find_function (name);
if (var == 0)
{
builtin_error (_("%s: not a function"), name);
any_failed++;
}
else if ((attribute & att_exported) && undo == 0 && exportable_function_name (name) == 0)
{
builtin_error (_("%s: cannot export"), name);
any_failed++;
}
else
SETVARATTR (var, attribute, undo);
list = list->next;
continue;
}
/* xxx [-np] name[=value] */
assign = assignment (name, 0);
aflags = 0;
if (assign)
{
name[assign] = '\0';
if (name[assign - 1] == '+')
{
aflags |= ASS_APPEND;
name[assign - 1] = '\0';
}
}
if (legal_identifier (name) == 0)
{
sh_invalidid (name);
if (assign)
assign_error++;
else
any_failed++;
list = list->next;
continue;
}
if (assign) /* xxx [-np] name=value */
{
name[assign] = '=';
if (aflags & ASS_APPEND)
name[assign - 1] = '+';
#if defined (ARRAY_VARS)
/* Let's try something here. Turn readonly -a xxx=yyy into
declare -ra xxx=yyy and see what that gets us. */
if (arrays_only || assoc_only)
{
tlist = list->next;
list->next = (WORD_LIST *)NULL;
/* Add -g to avoid readonly/export creating local variables:
only local/declare/typeset create local variables */
opti = 0;
optw[opti++] = '-';
optw[opti++] = 'g';
if (attribute & att_readonly)
optw[opti++] = 'r';
if (attribute & att_exported)
optw[opti++] = 'x';
if (arrays_only)
optw[opti++] = 'a';
else
optw[opti++] = 'A';
optw[opti] = '\0';
w = make_word (optw);
nlist = make_word_list (w, list);
opt = declare_builtin (nlist);
if (opt != EXECUTION_SUCCESS)
assign_error++;
list->next = tlist;
dispose_word (w);
free (nlist);
}
else
#endif
/* This word has already been expanded once with command
and parameter expansion. Call do_assignment_no_expand (),
which does not do command or parameter substitution. If
the assignment is not performed correctly, flag an error. */
if (do_assignment_no_expand (name) == 0)
assign_error++;
name[assign] = '\0';
if (aflags & ASS_APPEND)
name[assign - 1] = '\0';
}
set_var_attribute (name, attribute, undo);
if (assign) /* restore word */
{
name[assign] = '=';
if (aflags & ASS_APPEND)
name[assign-1] = '+';
}
list = list->next;
}
}
else
{
SHELL_VAR **variable_list;
register int i;
if ((attribute & att_function) || functions_only)
{
variable_list = all_shell_functions ();
if (attribute != att_function)
attribute &= ~att_function; /* so declare -xf works, for example */
}
else
variable_list = all_shell_variables ();
#if defined (ARRAY_VARS)
if (attribute & att_array)
{
arrays_only++;
if (attribute != att_array)
attribute &= ~att_array;
}
else if (attribute & att_assoc)
{
assoc_only++;
if (attribute != att_assoc)
attribute &= ~att_assoc;
}
#endif
if (variable_list)
{
for (i = 0; var = variable_list[i]; i++)
{
#if defined (ARRAY_VARS)
if (arrays_only && array_p (var) == 0)
continue;
else if (assoc_only && assoc_p (var) == 0)
continue;
#endif
/* If we imported a variable that's not a valid identifier, don't
show it in any lists. */
if ((var->attributes & (att_invisible|att_imported)) == (att_invisible|att_imported))
continue;
if ((var->attributes & attribute))
{
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
if (any_failed = sh_chkwrite (any_failed))
break;
}
}
free (variable_list);
}
}
return (assign_error ? EX_BADASSIGN
: ((any_failed == 0) ? EXECUTION_SUCCESS
: EXECUTION_FAILURE));
}
/* Show all variable variables (v == 1) or functions (v == 0) with
attributes. */
int
show_all_var_attributes (v, nodefs)
int v, nodefs;
{
SHELL_VAR **variable_list, *var;
int any_failed;
register int i;
variable_list = v ? all_shell_variables () : all_shell_functions ();
if (variable_list == 0)
return (EXECUTION_SUCCESS);
for (i = any_failed = 0; var = variable_list[i]; i++)
{
/* There is no equivalent `declare -'. */
if (variable_context && var->context == variable_context && STREQ (var->name, "-"))
printf ("local -\n");
else
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
if (any_failed = sh_chkwrite (any_failed))
break;
}
free (variable_list);
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
/* Show all local variable variables with their attributes. This shows unset
local variables (all_local_variables called with 0 argument). */
int
show_local_var_attributes (v, nodefs)
int v, nodefs;
{
SHELL_VAR **variable_list, *var;
int any_failed;
register int i;
variable_list = all_local_variables (0);
if (variable_list == 0)
return (EXECUTION_SUCCESS);
for (i = any_failed = 0; var = variable_list[i]; i++)
{
/* There is no equivalent `declare -'. */
if (STREQ (var->name, "-"))
printf ("local -\n");
else
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
if (any_failed = sh_chkwrite (any_failed))
break;
}
free (variable_list);
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
int
var_attribute_string (var, pattr, flags)
SHELL_VAR *var;
int pattr;
char *flags; /* filled in with attributes */
{
int i;
i = 0;
/* pattr == 0 means we are called from `declare'. */
if (pattr == 0 || posixly_correct == 0)
{
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
if (assoc_p (var))
flags[i++] = 'A';
#endif
if (function_p (var))
flags[i++] = 'f';
if (integer_p (var))
flags[i++] = 'i';
if (nameref_p (var))
flags[i++] = 'n';
if (readonly_p (var))
flags[i++] = 'r';
if (trace_p (var))
flags[i++] = 't';
if (exported_p (var))
flags[i++] = 'x';
if (capcase_p (var))
flags[i++] = 'c';
if (lowercase_p (var))
flags[i++] = 'l';
if (uppercase_p (var))
flags[i++] = 'u';
}
else
{
#if defined (ARRAY_VARS)
if (array_p (var))
flags[i++] = 'a';
if (assoc_p (var))
flags[i++] = 'A';
#endif
if (function_p (var))
flags[i++] = 'f';
}
flags[i] = '\0';
return i;
}
/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
don't show function definitions along with the name. If PATTR is
non-zero, it indicates we're being called from `export' or `readonly'.
In POSIX mode, this prints the name of the calling builtin (`export'
or `readonly') instead of `declare', and doesn't print function defs
when called by `export' or `readonly'. */
int
show_var_attributes (var, pattr, nodefs)
SHELL_VAR *var;
int pattr, nodefs;
{
char flags[MAX_ATTRIBUTES], *x;
int i;
i = var_attribute_string (var, pattr, flags);
/* If we're printing functions with definitions, print the function def
first, then the attributes, instead of printing output that can't be
reused as input to recreate the current state. */
if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
{
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
nodefs++;
if (pattr == 0 && i == 1 && flags[0] == 'f')
return 0; /* don't print `declare -f name' */
}
if (pattr == 0 || posixly_correct == 0)
printf ("declare -%s ", i ? flags : "-");
else if (i)
printf ("%s -%s ", this_command_name, flags);
else
printf ("%s ", this_command_name);
#if defined (ARRAY_VARS)
if (invisible_p (var) && (array_p (var) || assoc_p (var)))
printf ("%s\n", var->name);
else if (array_p (var))
print_array_assignment (var, 0);
else if (assoc_p (var))
print_assoc_assignment (var, 0);
else
#endif
/* force `readonly' and `export' to not print out function definitions
when in POSIX mode. */
if (nodefs || (function_p (var) && pattr != 0 && posixly_correct))
printf ("%s\n", var->name);
else if (function_p (var))
printf ("%s\n", named_function_string (var->name, function_cell (var), FUNC_MULTILINE|FUNC_EXTERNAL));
else if (invisible_p (var) || var_isset (var) == 0)
printf ("%s\n", var->name);
else
{
if (ansic_shouldquote (value_cell (var)))
x = ansic_quote (value_cell (var), 0, (int *)0);
else
x = sh_double_quote (value_cell (var));
printf ("%s=%s\n", var->name, x);
free (x);
}
return (0);
}
int
show_name_attributes (name, nodefs)
char *name;
int nodefs;
{
SHELL_VAR *var;
var = find_variable_noref (name);
if (var) /* show every variable with attributes, even unset ones */
{
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
return (0);
}
else
return (1);
}
int
show_localname_attributes (name, nodefs)
char *name;
int nodefs;
{
SHELL_VAR *var;
var = find_variable_noref (name);
if (var && local_p (var) && var->context == variable_context) /* show every variable with attributes, even unset ones */
{
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
return (0);
}
else
return (1);
}
int
show_func_attributes (name, nodefs)
char *name;
int nodefs;
{
SHELL_VAR *var;
var = find_function (name);
if (var)
{
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
return (0);
}
else
return (1);
}
void
set_var_attribute (name, attribute, undo)
char *name;
int attribute, undo;
{
SHELL_VAR *var, *tv, *v, *refvar;
char *tvalue;
if (undo)
var = find_variable (name);
else
{
tv = find_tempenv_variable (name);
/* XXX -- need to handle case where tv is a temp variable in a
function-scope context, since function_env has been merged into
the local variables table. */
if (tv && tempvar_p (tv))
{
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
var = bind_variable (tv->name, tvalue, 0);
if (var == 0)
{
free (tvalue);
return; /* XXX - no error message here */
}
var->attributes |= tv->attributes & ~att_tempvar;
/* This avoids an error message when propagating a read-only var
later on. */
if (posixly_correct || shell_compatibility_level <= 44)
{
if (var->context == 0 && (attribute & att_readonly))
{
/* Don't bother to set the `propagate to the global variables
table' flag if we've just bound the variable in that
table */
v = find_global_variable (tv->name);
if (v != var)
VSETATTR (tv, att_propagate);
}
else
VSETATTR (tv, att_propagate);
if (var->context != 0)
VSETATTR (var, att_propagate);
}
SETVARATTR (tv, attribute, undo); /* XXX */
stupidly_hack_special_variables (tv->name);
free (tvalue);
}
else
{
var = find_variable_notempenv (name);
if (var == 0)
{
/* We might have a nameref pointing to something that we can't
resolve to a shell variable. If we do, skip it. We do a little
checking just so we can print an error message. */
refvar = find_variable_nameref_for_create (name, 0);
if (refvar == INVALID_NAMEREF_VALUE)
return;
/* Otherwise we probably have a nameref pointing to a variable
that hasn't been created yet. bind_variable will take care
of that. */
}
if (var == 0)
{
var = bind_variable (name, (char *)NULL, 0);
if (var)
VSETATTR (var, att_invisible);
}
else if (var->context != 0)
VSETATTR (var, att_propagate);
}
}
if (var)
SETVARATTR (var, attribute, undo);
if (var && (exported_p (var) || (attribute & att_exported)))
array_needs_making++; /* XXX */
}

90
builtins/shift.def Normal file
View file

@ -0,0 +1,90 @@
This file is shift.def, from which is created shift.c.
It implements the builtin "shift" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES shift.c
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
$BUILTIN shift
$FUNCTION shift_builtin
$SHORT_DOC shift [n]
Shift positional parameters.
Rename the positional parameters $N+1,$N+2 ... to $1,$2 ... If N is
not given, it is assumed to be 1.
Exit Status:
Returns success unless N is negative or greater than $#.
$END
int print_shift_error;
/* Shift the arguments ``left''. Shift DOLLAR_VARS down then take one
off of REST_OF_ARGS and place it into DOLLAR_VARS[9]. If LIST has
anything in it, it is a number which says where to start the
shifting. Return > 0 if `times' > $#, otherwise 0. */
int
shift_builtin (list)
WORD_LIST *list;
{
intmax_t times;
int itimes, nargs;
CHECK_HELPOPT (list);
if (get_numeric_arg (list, 0, &times) == 0)
return (EXECUTION_FAILURE);
if (times == 0)
return (EXECUTION_SUCCESS);
else if (times < 0)
{
sh_erange (list ? list->word->word : NULL, _("shift count"));
return (EXECUTION_FAILURE);
}
nargs = number_of_args ();
if (times > nargs)
{
if (print_shift_error)
sh_erange (list ? list->word->word : NULL, _("shift count"));
return (EXECUTION_FAILURE);
}
else if (times == nargs)
clear_dollar_vars ();
else
shift_args (itimes = times);
invalidate_cached_quoted_dollar_at ();
return (EXECUTION_SUCCESS);
}

966
builtins/shopt.def Normal file
View file

@ -0,0 +1,966 @@
This file is shopt.def, from which is created shopt.c.
It implements the Bash `shopt' builtin.
Copyright (C) 1994-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES shopt.c
$BUILTIN shopt
$FUNCTION shopt_builtin
$SHORT_DOC shopt [-pqsu] [-o] [optname ...]
Set and unset shell options.
Change the setting of each shell option OPTNAME. Without any option
arguments, list each supplied OPTNAME, or all shell options if no
OPTNAMEs are given, with an indication of whether or not each is set.
Options:
-o restrict OPTNAMEs to those defined for use with `set -o'
-p print each shell option with an indication of its status
-q suppress output
-s enable (set) each OPTNAME
-u disable (unset) each OPTNAME
Exit Status:
Returns success if OPTNAME is enabled; fails if an invalid option is
given or OPTNAME is disabled.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "version.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../flags.h"
#include "common.h"
#include "bashgetopt.h"
#if defined (READLINE)
# include "../bashline.h"
#endif
#if defined (HISTORY)
# include "../bashhist.h"
#endif
#define UNSETOPT 0
#define SETOPT 1
#define OPTFMT "%-15s\t%s\n"
extern int allow_null_glob_expansion, fail_glob_expansion, glob_dot_filenames;
extern int cdable_vars, mail_warning, source_uses_path;
extern int no_exit_on_failed_exec, print_shift_error;
extern int check_hashed_filenames, promptvars;
extern int cdspelling, expand_aliases;
extern int extended_quote;
extern int check_window_size;
extern int glob_ignore_case, match_ignore_case;
extern int hup_on_exit;
extern int xpg_echo;
extern int gnu_error_format;
extern int check_jobs_at_exit;
extern int autocd;
extern int glob_star;
extern int glob_asciirange;
extern int glob_always_skip_dot_and_dotdot;
extern int lastpipe_opt;
extern int inherit_errexit;
extern int localvar_inherit;
extern int localvar_unset;
extern int varassign_redir_autoclose;
extern int singlequote_translations;
extern int patsub_replacement;
#if defined (EXTENDED_GLOB)
extern int extended_glob;
#endif
#if defined (READLINE)
extern int hist_verify, history_reediting, perform_hostname_completion;
extern int no_empty_command_completion;
extern int force_fignore;
extern int dircomplete_spelling, dircomplete_expand;
extern int complete_fullquote;
extern int enable_hostname_completion PARAMS((int));
#endif
#if defined (PROGRAMMABLE_COMPLETION)
extern int prog_completion_enabled;
extern int progcomp_alias;
#endif
#if defined (DEBUGGER)
extern int debugging_mode;
#endif
#if defined (ARRAY_VARS)
extern int assoc_expand_once;
extern int array_expand_once;
int expand_once_flag;
#endif
#if defined (SYSLOG_HISTORY)
extern int syslog_history;
#endif
static void shopt_error PARAMS((char *));
static int set_shellopts_after_change PARAMS((char *, int));
static int set_compatibility_level PARAMS((char *, int));
#if defined (RESTRICTED_SHELL)
static int set_restricted_shell PARAMS((char *, int));
#endif
#if defined (READLINE)
static int shopt_enable_hostname_completion PARAMS((char *, int));
static int shopt_set_complete_direxpand PARAMS((char *, int));
#endif
#if defined (ARRAY_VARS)
static int set_assoc_expand PARAMS((char *, int));
#endif
#if defined (EXTENDED_GLOB)
int extglob_flag = EXTGLOB_DEFAULT;
static int shopt_set_extglob PARAMS((char *, int));
#endif
int expaliases_flag = 0;
static int shopt_set_expaliases PARAMS((char *, int));
static int shopt_set_debug_mode PARAMS((char *, int));
static int shopt_login_shell;
static int shopt_compat31;
static int shopt_compat32;
static int shopt_compat40;
static int shopt_compat41;
static int shopt_compat42;
static int shopt_compat43;
static int shopt_compat44;
typedef int shopt_set_func_t PARAMS((char *, int));
/* If you add a new variable name here, make sure to set the default value
appropriately in reset_shopt_options. */
static struct {
char *name;
int *value;
shopt_set_func_t *set_func;
} shopt_vars[] = {
{ "autocd", &autocd, (shopt_set_func_t *)NULL },
#if defined (ARRAY_VARS)
{ "assoc_expand_once", &expand_once_flag, set_assoc_expand },
#endif
{ "cdable_vars", &cdable_vars, (shopt_set_func_t *)NULL },
{ "cdspell", &cdspelling, (shopt_set_func_t *)NULL },
{ "checkhash", &check_hashed_filenames, (shopt_set_func_t *)NULL },
#if defined (JOB_CONTROL)
{ "checkjobs", &check_jobs_at_exit, (shopt_set_func_t *)NULL },
#endif
{ "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
{ "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
#endif
{ "compat31", &shopt_compat31, set_compatibility_level },
{ "compat32", &shopt_compat32, set_compatibility_level },
{ "compat40", &shopt_compat40, set_compatibility_level },
{ "compat41", &shopt_compat41, set_compatibility_level },
{ "compat42", &shopt_compat42, set_compatibility_level },
{ "compat43", &shopt_compat43, set_compatibility_level },
{ "compat44", &shopt_compat44, set_compatibility_level },
#if defined (READLINE)
{ "complete_fullquote", &complete_fullquote, (shopt_set_func_t *)NULL},
{ "direxpand", &dircomplete_expand, shopt_set_complete_direxpand },
{ "dirspell", &dircomplete_spelling, (shopt_set_func_t *)NULL },
#endif
{ "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
{ "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
{ "expand_aliases", &expaliases_flag, shopt_set_expaliases },
#if defined (DEBUGGER)
{ "extdebug", &debugging_mode, shopt_set_debug_mode },
#endif
#if defined (EXTENDED_GLOB)
{ "extglob", &extglob_flag, shopt_set_extglob },
#endif
{ "extquote", &extended_quote, (shopt_set_func_t *)NULL },
{ "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL },
#if defined (READLINE)
{ "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
#endif
{ "globasciiranges", &glob_asciirange, (shopt_set_func_t *)NULL },
{ "globskipdots", &glob_always_skip_dot_and_dotdot, (shopt_set_func_t *)NULL },
{ "globstar", &glob_star, (shopt_set_func_t *)NULL },
{ "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
{ "histappend", &force_append_history, (shopt_set_func_t *)NULL },
#endif
#if defined (READLINE)
{ "histreedit", &history_reediting, (shopt_set_func_t *)NULL },
{ "histverify", &hist_verify, (shopt_set_func_t *)NULL },
{ "hostcomplete", &perform_hostname_completion, shopt_enable_hostname_completion },
#endif
{ "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
{ "inherit_errexit", &inherit_errexit, (shopt_set_func_t *)NULL },
{ "interactive_comments", &interactive_comments, set_shellopts_after_change },
{ "lastpipe", &lastpipe_opt, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
{ "lithist", &literal_history, (shopt_set_func_t *)NULL },
#endif
{ "localvar_inherit", &localvar_inherit, (shopt_set_func_t *)NULL },
{ "localvar_unset", &localvar_unset, (shopt_set_func_t *)NULL },
{ "login_shell", &shopt_login_shell, set_login_shell },
{ "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
#if defined (READLINE)
{ "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL },
#endif
{ "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL },
{ "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL },
{ "noexpand_translation", &singlequote_translations, (shopt_set_func_t *)NULL },
{ "nullglob", &allow_null_glob_expansion, (shopt_set_func_t *)NULL },
{ "patsub_replacement", &patsub_replacement, (shopt_set_func_t *)NULL },
#if defined (PROGRAMMABLE_COMPLETION)
{ "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL },
# if defined (ALIAS)
{ "progcomp_alias", &progcomp_alias, (shopt_set_func_t *)NULL },
# endif
#endif
{ "promptvars", &promptvars, (shopt_set_func_t *)NULL },
#if defined (RESTRICTED_SHELL)
{ "restricted_shell", &restricted_shell, set_restricted_shell },
#endif
{ "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL },
{ "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL },
#if defined (SYSLOG_HISTORY) && defined (SYSLOG_SHOPT)
{ "syslog_history", &syslog_history, (shopt_set_func_t *)NULL },
#endif
{ "varredir_close", &varassign_redir_autoclose, (shopt_set_func_t *)NULL },
{ "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL },
{ (char *)0, (int *)0, (shopt_set_func_t *)NULL }
};
#define N_SHOPT_OPTIONS (sizeof (shopt_vars) / sizeof (shopt_vars[0]))
#define GET_SHOPT_OPTION_VALUE(i) (*shopt_vars[i].value)
static const char * const on = "on";
static const char * const off = "off";
static int find_shopt PARAMS((char *));
static int toggle_shopts PARAMS((int, WORD_LIST *, int));
static void print_shopt PARAMS((char *, int, int));
static int list_shopts PARAMS((WORD_LIST *, int));
static int list_some_shopts PARAMS((int, int));
static int list_shopt_o_options PARAMS((WORD_LIST *, int));
static int list_some_o_options PARAMS((int, int));
static int set_shopt_o_options PARAMS((int, WORD_LIST *, int));
#define SFLAG 0x01
#define UFLAG 0x02
#define QFLAG 0x04
#define OFLAG 0x08
#define PFLAG 0x10
int
shopt_builtin (list)
WORD_LIST *list;
{
int opt, flags, rval;
flags = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "psuoq")) != -1)
{
switch (opt)
{
case 's':
flags |= SFLAG;
break;
case 'u':
flags |= UFLAG;
break;
case 'q':
flags |= QFLAG;
break;
case 'o':
flags |= OFLAG;
break;
case 'p':
flags |= PFLAG;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG))
{
builtin_error (_("cannot set and unset shell options simultaneously"));
return (EXECUTION_FAILURE);
}
rval = EXECUTION_SUCCESS;
if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */
rval = list_shopt_o_options (list, flags);
else if (list && (flags & OFLAG)) /* shopt -so args */
rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG);
else if (flags & OFLAG) /* shopt -so */
rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags);
else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */
rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG);
else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */
rval = list_shopts (list, flags);
else /* shopt -su */
rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags);
return (rval);
}
/* Reset the options managed by `shopt' to the values they would have at
shell startup. Variables from shopt_vars. */
void
reset_shopt_options ()
{
autocd = cdable_vars = cdspelling = 0;
check_hashed_filenames = CHECKHASH_DEFAULT;
check_window_size = CHECKWINSIZE_DEFAULT;
allow_null_glob_expansion = glob_dot_filenames = 0;
no_exit_on_failed_exec = 0;
expand_aliases = expaliases_flag = 0;
extended_quote = 1;
fail_glob_expansion = 0;
glob_asciirange = GLOBASCII_DEFAULT;
glob_star = 0;
gnu_error_format = 0;
hup_on_exit = 0;
inherit_errexit = 0;
interactive_comments = 1;
lastpipe_opt = 0;
localvar_inherit = localvar_unset = 0;
mail_warning = 0;
glob_ignore_case = match_ignore_case = 0;
print_shift_error = 0;
source_uses_path = promptvars = 1;
varassign_redir_autoclose = 0;
singlequote_translations = 0;
patsub_replacement = 1;
#if defined (JOB_CONTROL)
check_jobs_at_exit = 0;
#endif
#if defined (EXTENDED_GLOB)
extended_glob = extglob_flag = EXTGLOB_DEFAULT;
#endif
#if defined (ARRAY_VARS)
expand_once_flag = assoc_expand_once = 0;
#endif
#if defined (HISTORY)
literal_history = 0;
force_append_history = 0;
command_oriented_history = 1;
#endif
#if defined (SYSLOG_HISTORY)
# if defined (SYSLOG_SHOPT)
syslog_history = SYSLOG_SHOPT;
# else
syslog_history = 1;
# endif /* SYSLOG_SHOPT */
#endif
#if defined (READLINE)
complete_fullquote = 1;
force_fignore = 1;
hist_verify = history_reediting = 0;
perform_hostname_completion = 1;
# if DIRCOMPLETE_EXPAND_DEFAULT
dircomplete_expand = 1;
# else
dircomplete_expand = 0;
#endif
dircomplete_spelling = 0;
no_empty_command_completion = 0;
#endif
#if defined (PROGRAMMABLE_COMPLETION)
prog_completion_enabled = 1;
# if defined (ALIAS)
progcomp_alias = 0;
# endif
#endif
#if defined (DEFAULT_ECHO_TO_XPG) || defined (STRICT_POSIX)
xpg_echo = 1;
#else
xpg_echo = 0;
#endif /* DEFAULT_ECHO_TO_XPG */
shopt_login_shell = login_shell;
}
static int
find_shopt (name)
char *name;
{
int i;
for (i = 0; shopt_vars[i].name; i++)
if (STREQ (name, shopt_vars[i].name))
return i;
return -1;
}
static void
shopt_error (s)
char *s;
{
builtin_error (_("%s: invalid shell option name"), s);
}
static int
toggle_shopts (mode, list, quiet)
int mode;
WORD_LIST *list;
int quiet;
{
WORD_LIST *l;
int ind, rval;
SHELL_VAR *v;
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
ind = find_shopt (l->word->word);
if (ind < 0)
{
shopt_error (l->word->word);
rval = EXECUTION_FAILURE;
}
else
{
*shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */
if (shopt_vars[ind].set_func)
(*shopt_vars[ind].set_func) (shopt_vars[ind].name, mode);
}
}
/* Don't set $BASHOPTS here if it hasn't already been initialized */
if (v = find_variable ("BASHOPTS"))
set_bashopts ();
return (rval);
}
static void
print_shopt (name, val, flags)
char *name;
int val, flags;
{
if (flags & PFLAG)
printf ("shopt %s %s\n", val ? "-s" : "-u", name);
else
printf (OPTFMT, name, val ? on : off);
}
/* List the values of all or any of the `shopt' options. Returns 0 if
all were listed or all variables queried were on; 1 otherwise. */
static int
list_shopts (list, flags)
WORD_LIST *list;
int flags;
{
WORD_LIST *l;
int i, val, rval;
if (list == 0)
{
for (i = 0; shopt_vars[i].name; i++)
{
val = *shopt_vars[i].value;
if ((flags & QFLAG) == 0)
print_shopt (shopt_vars[i].name, val, flags);
}
return (sh_chkwrite (EXECUTION_SUCCESS));
}
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
i = find_shopt (l->word->word);
if (i < 0)
{
shopt_error (l->word->word);
rval = EXECUTION_FAILURE;
continue;
}
val = *shopt_vars[i].value;
if (val == 0)
rval = EXECUTION_FAILURE;
if ((flags & QFLAG) == 0)
print_shopt (l->word->word, val, flags);
}
return (sh_chkwrite (rval));
}
static int
list_some_shopts (mode, flags)
int mode, flags;
{
int val, i;
for (i = 0; shopt_vars[i].name; i++)
{
val = *shopt_vars[i].value;
if (((flags & QFLAG) == 0) && mode == val)
print_shopt (shopt_vars[i].name, val, flags);
}
return (sh_chkwrite (EXECUTION_SUCCESS));
}
static int
list_shopt_o_options (list, flags)
WORD_LIST *list;
int flags;
{
WORD_LIST *l;
int val, rval;
if (list == 0)
{
if ((flags & QFLAG) == 0)
list_minus_o_opts (-1, (flags & PFLAG));
return (sh_chkwrite (EXECUTION_SUCCESS));
}
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
val = minus_o_option_value (l->word->word);
if (val == -1)
{
sh_invalidoptname (l->word->word);
rval = EXECUTION_FAILURE;
continue;
}
if (val == 0)
rval = EXECUTION_FAILURE;
if ((flags & QFLAG) == 0)
{
if (flags & PFLAG)
printf ("set %co %s\n", val ? '-' : '+', l->word->word);
else
printf (OPTFMT, l->word->word, val ? on : off);
}
}
return (sh_chkwrite (rval));
}
static int
list_some_o_options (mode, flags)
int mode, flags;
{
if ((flags & QFLAG) == 0)
list_minus_o_opts (mode, (flags & PFLAG));
return (sh_chkwrite (EXECUTION_SUCCESS));
}
static int
set_shopt_o_options (mode, list, quiet)
int mode;
WORD_LIST *list;
int quiet;
{
WORD_LIST *l;
int rval;
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
{
if (set_minus_o_option (mode, l->word->word) == EXECUTION_FAILURE)
rval = EXECUTION_FAILURE;
}
set_shellopts ();
return rval;
}
/* If we set or unset interactive_comments with shopt, make sure the
change is reflected in $SHELLOPTS. */
static int
set_shellopts_after_change (option_name, mode)
char *option_name;
int mode;
{
set_shellopts ();
return (0);
}
static int
shopt_set_debug_mode (option_name, mode)
char *option_name;
int mode;
{
#if defined (DEBUGGER)
error_trace_mode = function_trace_mode = debugging_mode;
set_shellopts ();
if (debugging_mode)
init_bash_argv ();
#endif
return (0);
}
static int
shopt_set_expaliases (option_name, mode)
char *option_name;
int mode;
{
expand_aliases = expaliases_flag;
return 0;
}
#if defined (EXTENDED_GLOB)
static int
shopt_set_extglob (option_name, mode)
char *option_name;
int mode;
{
extended_glob = extglob_flag;
return 0;
}
#endif
#if defined (READLINE)
static int
shopt_enable_hostname_completion (option_name, mode)
char *option_name;
int mode;
{
return (enable_hostname_completion (mode));
}
#endif
static int
set_compatibility_level (option_name, mode)
char *option_name;
int mode;
{
int ind, oldval;
char *rhs;
/* If we're unsetting one of the compatibility options, make sure the
current value is in the range of the compatNN space. */
if (mode == 0)
oldval = shell_compatibility_level;
/* If we're setting something, redo some of the work we did above in
toggle_shopt(). Unset everything and reset the appropriate option
based on OPTION_NAME. */
if (mode)
{
shopt_compat31 = shopt_compat32 = 0;
shopt_compat40 = shopt_compat41 = shopt_compat42 = shopt_compat43 = 0;
shopt_compat44 = 0;
ind = find_shopt (option_name);
*shopt_vars[ind].value = mode;
}
/* Then set shell_compatibility_level based on what remains */
if (shopt_compat31)
shell_compatibility_level = 31;
else if (shopt_compat32)
shell_compatibility_level = 32;
else if (shopt_compat40)
shell_compatibility_level = 40;
else if (shopt_compat41)
shell_compatibility_level = 41;
else if (shopt_compat42)
shell_compatibility_level = 42;
else if (shopt_compat43)
shell_compatibility_level = 43;
else if (shopt_compat44)
shell_compatibility_level = 44;
else if (oldval > 44 && shell_compatibility_level < DEFAULT_COMPAT_LEVEL)
;
else
shell_compatibility_level = DEFAULT_COMPAT_LEVEL;
/* Make sure the current compatibility level is reflected in BASH_COMPAT */
rhs = itos (shell_compatibility_level);
bind_variable ("BASH_COMPAT", rhs, 0);
free (rhs);
return 0;
}
/* Set and unset the various compatibility options from the value of
shell_compatibility_level; used by sv_shcompat */
void
set_compatibility_opts ()
{
shopt_compat31 = shopt_compat32 = 0;
shopt_compat40 = shopt_compat41 = shopt_compat42 = shopt_compat43 = 0;
shopt_compat44 = 0;
switch (shell_compatibility_level)
{
case DEFAULT_COMPAT_LEVEL:
case 51: /* completeness */
case 50:
break;
case 44:
shopt_compat44 = 1; break;
case 43:
shopt_compat43 = 1; break;
case 42:
shopt_compat42 = 1; break;
case 41:
shopt_compat41 = 1; break;
case 40:
shopt_compat40 = 1; break;
case 32:
shopt_compat32 = 1; break;
case 31:
shopt_compat31 = 1; break;
}
}
#if defined (READLINE)
static int
shopt_set_complete_direxpand (option_name, mode)
char *option_name;
int mode;
{
set_directory_hook ();
return 0;
}
#endif
#if defined (RESTRICTED_SHELL)
/* Don't allow the value of restricted_shell to be modified. */
static int
set_restricted_shell (option_name, mode)
char *option_name;
int mode;
{
static int save_restricted = -1;
if (save_restricted == -1)
save_restricted = shell_is_restricted (shell_name);
restricted_shell = save_restricted;
return (0);
}
#endif /* RESTRICTED_SHELL */
/* Not static so shell.c can call it to initialize shopt_login_shell */
int
set_login_shell (option_name, mode)
char *option_name;
int mode;
{
shopt_login_shell = login_shell != 0;
return (0);
}
char **
get_shopt_options ()
{
char **ret;
int n, i;
n = sizeof (shopt_vars) / sizeof (shopt_vars[0]);
ret = strvec_create (n + 1);
for (i = 0; shopt_vars[i].name; i++)
ret[i] = savestring (shopt_vars[i].name);
ret[i] = (char *)NULL;
return ret;
}
/*
* External interface for other parts of the shell. NAME is a string option;
* MODE is 0 if we want to unset an option; 1 if we want to set an option.
* REUSABLE is 1 if we want to print output in a form that may be reused.
*/
int
shopt_setopt (name, mode)
char *name;
int mode;
{
WORD_LIST *wl;
int r;
wl = add_string_to_list (name, (WORD_LIST *)NULL);
r = toggle_shopts (mode, wl, 0);
dispose_words (wl);
return r;
}
int
shopt_listopt (name, reusable)
char *name;
int reusable;
{
int i;
if (name == 0)
return (list_shopts ((WORD_LIST *)NULL, reusable ? PFLAG : 0));
i = find_shopt (name);
if (i < 0)
{
shopt_error (name);
return (EXECUTION_FAILURE);
}
print_shopt (name, *shopt_vars[i].value, reusable ? PFLAG : 0);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
void
set_bashopts ()
{
char *value;
char tflag[N_SHOPT_OPTIONS];
int vsize, i, vptr, *ip, exported;
SHELL_VAR *v;
for (vsize = i = 0; shopt_vars[i].name; i++)
{
tflag[i] = 0;
if (GET_SHOPT_OPTION_VALUE (i))
{
vsize += strlen (shopt_vars[i].name) + 1;
tflag[i] = 1;
}
}
value = (char *)xmalloc (vsize + 1);
for (i = vptr = 0; shopt_vars[i].name; i++)
{
if (tflag[i])
{
strcpy (value + vptr, shopt_vars[i].name);
vptr += strlen (shopt_vars[i].name);
value[vptr++] = ':';
}
}
if (vptr)
vptr--; /* cut off trailing colon */
value[vptr] = '\0';
v = find_variable ("BASHOPTS");
/* Turn off the read-only attribute so we can bind the new value, and
note whether or not the variable was exported. */
if (v)
{
VUNSETATTR (v, att_readonly);
exported = exported_p (v);
}
else
exported = 0;
v = bind_variable ("BASHOPTS", value, 0);
/* Turn the read-only attribute back on, and turn off the export attribute
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
exported before we bound the new value. */
VSETATTR (v, att_readonly);
if (mark_modified_vars && exported == 0 && exported_p (v))
VUNSETATTR (v, att_exported);
free (value);
}
void
parse_bashopts (value)
char *value;
{
char *vname;
int vptr, ind;
vptr = 0;
while (vname = extract_colon_unit (value, &vptr))
{
ind = find_shopt (vname);
if (ind >= 0)
{
*shopt_vars[ind].value = 1;
if (shopt_vars[ind].set_func)
(*shopt_vars[ind].set_func) (shopt_vars[ind].name, 1);
}
free (vname);
}
}
void
initialize_bashopts (no_bashopts)
int no_bashopts;
{
char *temp;
SHELL_VAR *var;
if (no_bashopts == 0)
{
var = find_variable ("BASHOPTS");
/* set up any shell options we may have inherited. */
if (var && imported_p (var))
{
temp = (array_p (var) || assoc_p (var)) ? (char *)NULL : savestring (value_cell (var));
if (temp)
{
parse_bashopts (temp);
free (temp);
}
}
}
/* Set up the $BASHOPTS variable. */
set_bashopts ();
}
#if defined (ARRAY_VARS)
static int
set_assoc_expand (option_name, mode)
char *option_name;
int mode;
{
#if 0 /* leave this disabled */
if (shell_compatibility_level <= 51)
#endif
assoc_expand_once = expand_once_flag;
return 0;
}
#endif

200
builtins/source.def Normal file
View file

@ -0,0 +1,200 @@
This file is source.def, from which is created source.c.
It implements the builtins "." and "source" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES source.c
$BUILTIN source
$FUNCTION source_builtin
$SHORT_DOC source filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.
$END
$BUILTIN .
$DOCNAME dot
$FUNCTION source_builtin
$SHORT_DOC . filename [arguments]
Execute commands from a file in the current shell.
Read and execute commands from FILENAME in the current shell. The
entries in $PATH are used to find the directory containing FILENAME.
If any ARGUMENTS are supplied, they become the positional parameters
when FILENAME is executed.
Exit Status:
Returns the status of the last command executed in FILENAME; fails if
FILENAME cannot be read.
$END
#include <config.h>
#include "../bashtypes.h"
#include "posixstat.h"
#include "filecntl.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../flags.h"
#include "../findcmd.h"
#include "common.h"
#include "bashgetopt.h"
#include "../trap.h"
#if !defined (errno)
extern int errno;
#endif /* !errno */
static void maybe_pop_dollar_vars PARAMS((void));
/* If non-zero, `.' uses $PATH to look up the script to be sourced. */
int source_uses_path = 1;
/* If non-zero, `.' looks in the current directory if the filename argument
is not found in the $PATH. */
int source_searches_cwd = 1;
/* If this . script is supplied arguments, we save the dollar vars and
replace them with the script arguments for the duration of the script's
execution. If the script does not change the dollar vars, we restore
what we saved. If the dollar vars are changed in the script, and we are
not executing a shell function, we leave the new values alone and free
the saved values. */
static void
maybe_pop_dollar_vars ()
{
if (variable_context == 0 && (dollar_vars_changed () & ARGS_SETBLTIN))
dispose_saved_dollar_vars ();
else
pop_dollar_vars ();
if (debugging_mode)
pop_args (); /* restore BASH_ARGC and BASH_ARGV */
set_dollar_vars_unchanged ();
invalidate_cached_quoted_dollar_at (); /* just invalidate to be safe */
}
/* Read and execute commands from the file passed as argument. Guess what.
This cannot be done in a subshell, since things like variable assignments
take place in there. So, I open the file, place it into a large string,
close the file, and then execute the string. */
int
source_builtin (list)
WORD_LIST *list;
{
int result;
char *filename, *debug_trap, *x;
if (no_options (list))
return (EX_USAGE);
list = loptend;
if (list == 0)
{
builtin_error (_("filename argument required"));
builtin_usage ();
return (EX_USAGE);
}
#if defined (RESTRICTED_SHELL)
if (restricted && strchr (list->word->word, '/'))
{
sh_restricted (list->word->word);
return (EXECUTION_FAILURE);
}
#endif
filename = (char *)NULL;
/* XXX -- should this be absolute_pathname? */
if (posixly_correct && strchr (list->word->word, '/'))
filename = savestring (list->word->word);
else if (absolute_pathname (list->word->word))
filename = savestring (list->word->word);
else if (source_uses_path)
filename = find_path_file (list->word->word);
if (filename == 0)
{
if (source_searches_cwd == 0)
{
x = printable_filename (list->word->word, 0);
builtin_error (_("%s: file not found"), x);
if (x != list->word->word)
free (x);
if (posixly_correct && interactive_shell == 0 && executing_command_builtin == 0)
{
last_command_exit_value = EXECUTION_FAILURE;
jump_to_top_level (EXITPROG);
}
return (EXECUTION_FAILURE);
}
else
filename = savestring (list->word->word);
}
begin_unwind_frame ("source");
add_unwind_protect (xfree, filename);
if (list->next)
{
push_dollar_vars ();
add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
if (debugging_mode || shell_compatibility_level <= 44)
init_bash_argv (); /* Initialize BASH_ARGV and BASH_ARGC */
remember_args (list->next, 1);
if (debugging_mode)
push_args (list->next); /* Update BASH_ARGV and BASH_ARGC */
}
set_dollar_vars_unchanged ();
/* Don't inherit the DEBUG trap unless function_trace_mode (overloaded)
is set. XXX - should sourced files inherit the RETURN trap? Functions
don't. */
debug_trap = TRAP_STRING (DEBUG_TRAP);
if (debug_trap && function_trace_mode == 0)
{
debug_trap = savestring (debug_trap);
add_unwind_protect (xfree, debug_trap);
add_unwind_protect (maybe_set_debug_trap, debug_trap);
restore_default_signal (DEBUG_TRAP);
}
result = source_file (filename, (list && list->next));
run_unwind_frame ("source");
return (result);
}

129
builtins/suspend.def Normal file
View file

@ -0,0 +1,129 @@
This file is suspend.def, from which is created suspend.c.
It implements the builtin "suspend" in Bash.
Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES suspend.c
$BUILTIN suspend
$DEPENDS_ON JOB_CONTROL
$FUNCTION suspend_builtin
$SHORT_DOC suspend [-f]
Suspend shell execution.
Suspend the execution of this shell until it receives a SIGCONT signal.
Unless forced, login shells and shells without job control cannot be
suspended.
Options:
-f force the suspend, even if the shell is a login shell or job
control is not enabled.
Exit Status:
Returns success unless job control is not enabled or an error occurs.
$END
#include <config.h>
#if defined (JOB_CONTROL)
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include <signal.h>
#include "../bashintl.h"
#include "../shell.h"
#include "../jobs.h"
#include "common.h"
#include "bashgetopt.h"
static sighandler suspend_continue PARAMS((int));
static SigHandler *old_cont;
#if 0
static SigHandler *old_stop;
#endif
/* Continue handler. */
static sighandler
suspend_continue (sig)
int sig;
{
set_signal_handler (SIGCONT, old_cont);
#if 0
set_signal_handler (SIGSTOP, old_stop);
#endif
SIGRETURN (0);
}
/* Suspending the shell. If -f is the arg, then do the suspend
no matter what. Otherwise, complain if a login shell. */
int
suspend_builtin (list)
WORD_LIST *list;
{
int opt, force;
reset_internal_getopt ();
force = 0;
while ((opt = internal_getopt (list, "f")) != -1)
switch (opt)
{
case 'f':
force++;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
list = loptend;
no_args (list);
if (force == 0)
{
if (job_control == 0)
{
sh_nojobs (_("cannot suspend"));
return (EXECUTION_FAILURE);
}
if (login_shell)
{
builtin_error (_("cannot suspend a login shell"));
return (EXECUTION_FAILURE);
}
}
/* XXX - should we put ourselves back into the original pgrp now? If so,
call end_job_control() here and do the right thing in suspend_continue
(that is, call restart_job_control()). */
old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
#if 0
old_stop = (SigHandler *)set_signal_handler (SIGSTOP, SIG_DFL);
#endif
killpg (shell_pgrp, SIGSTOP);
return (EXECUTION_SUCCESS);
}
#endif /* JOB_CONTROL */

159
builtins/test.def Normal file
View file

@ -0,0 +1,159 @@
This file is test.def, from which is created test.c.
It implements the builtin "test" in Bash.
Copyright (C) 1987-2015 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES test.c
$BUILTIN test
$FUNCTION test_builtin
$SHORT_DOC test [expr]
Evaluate conditional expression.
Exits with a status of 0 (true) or 1 (false) 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 and numeric comparison operators as well.
The behavior of test depends on the number of arguments. Read the
bash manual page for the complete specification.
File operators:
-a FILE True if file exists.
-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.
-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 exists and 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.
-N FILE True if the file has been modified since it was last read.
FILE1 -nt FILE2 True if file1 is newer than file2 (according to
modification date).
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
STRING True if string is not empty.
STRING1 = STRING2
True if the strings are equal.
STRING1 != STRING2
True if the strings are not equal.
STRING1 < STRING2
True if STRING1 sorts before STRING2 lexicographically.
STRING1 > STRING2
True if STRING1 sorts after STRING2 lexicographically.
Other operators:
-o OPTION True if the shell option OPTION is enabled.
-v VAR True if the shell variable VAR is set.
-R VAR True if the shell variable VAR is set and is a name
reference.
! 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.
Exit Status:
Returns success if EXPR evaluates to true; fails if EXPR evaluates to
false or an invalid argument is given.
$END
$BUILTIN [
$DOCNAME test_bracket
$FUNCTION test_builtin
$SHORT_DOC [ arg... ]
Evaluate conditional expression.
This is a synonym for the "test" builtin, but the last argument must
be a literal `]', to match the opening `['.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../test.h"
#include "common.h"
/* TEST/[ builtin. */
int
test_builtin (list)
WORD_LIST *list;
{
char **argv;
int argc, result;
/* We let Matthew Bradburn and Kevin Braunsdorf's code do the
actual test command. So turn the list of args into an array
of strings, since that is what their code wants. */
if (list == 0)
{
if (this_command_name[0] == '[' && !this_command_name[1])
{
builtin_error (_("missing `]'"));
return (EX_BADUSAGE);
}
return (EXECUTION_FAILURE);
}
argv = make_builtin_argv (list, &argc);
result = test_command (argc, argv);
free ((char *)argv);
return (result);
}

119
builtins/times.def Normal file
View file

@ -0,0 +1,119 @@
This file is times.def, from which is created times.c.
It implements the builtin "times" in Bash.
Copyright (C) 1987-2009 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES times.c
$BUILTIN times
$FUNCTION times_builtin
$SHORT_DOC times
Display process times.
Prints the accumulated user and system times for the shell and all of its
child processes.
Exit Status:
Always succeeds.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashtypes.h"
#include "../shell.h"
#include <posixtime.h>
#if defined (HAVE_SYS_TIMES_H)
# include <sys/times.h>
#endif /* HAVE_SYS_TIMES_H */
#if defined (HAVE_SYS_RESOURCE_H) && !defined (RLIMTYPE)
# include <sys/resource.h>
#endif
#include "common.h"
/* Print the totals for system and user time used. */
int
times_builtin (list)
WORD_LIST *list;
{
#if defined (HAVE_GETRUSAGE) && defined (HAVE_TIMEVAL) && defined (RUSAGE_SELF)
struct rusage self, kids;
USE_VAR(list);
if (no_options (list))
return (EX_USAGE);
getrusage (RUSAGE_SELF, &self);
getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */
print_timeval (stdout, &self.ru_utime);
putchar (' ');
print_timeval (stdout, &self.ru_stime);
putchar ('\n');
print_timeval (stdout, &kids.ru_utime);
putchar (' ');
print_timeval (stdout, &kids.ru_stime);
putchar ('\n');
#else
# if defined (HAVE_TIMES)
/* This uses the POSIX.1/XPG5 times(2) interface, which fills in a
`struct tms' with values of type clock_t. */
struct tms t;
USE_VAR(list);
if (no_options (list))
return (EX_USAGE);
times (&t);
print_clock_t (stdout, t.tms_utime);
putchar (' ');
print_clock_t (stdout, t.tms_stime);
putchar ('\n');
print_clock_t (stdout, t.tms_cutime);
putchar (' ');
print_clock_t (stdout, t.tms_cstime);
putchar ('\n');
# else /* !HAVE_TIMES */
USE_VAR(list);
if (no_options (list))
return (EX_USAGE);
printf ("0.00 0.00\n0.00 0.00\n");
# endif /* HAVE_TIMES */
#endif /* !HAVE_TIMES */
return (sh_chkwrite (EXECUTION_SUCCESS));
}

316
builtins/trap.def Normal file
View file

@ -0,0 +1,316 @@
This file is trap.def, from which is created trap.c.
It implements the builtin "trap" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES trap.c
$BUILTIN trap
$FUNCTION trap_builtin
$SHORT_DOC trap [-lp] [[arg] signal_spec ...]
Trap signals and other events.
Defines and activates handlers to be run when the shell receives signals
or other conditions.
ARG is a command to be read and executed when the shell receives the
signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC
is supplied) or `-', each specified signal is reset to its original
value. If ARG is the null string each SIGNAL_SPEC is ignored by the
shell and by the commands it invokes.
If a SIGNAL_SPEC is EXIT (0) ARG is executed on exit from the shell. If
a SIGNAL_SPEC is DEBUG, ARG is executed before every simple command. If
a SIGNAL_SPEC is RETURN, ARG is executed each time a shell function or a
script run by the . or source builtins finishes executing. A SIGNAL_SPEC
of ERR means to execute ARG each time a command's failure would cause the
shell to exit when the -e option is enabled.
If no arguments are supplied, trap prints the list of commands associated
with each signal.
Options:
-l print a list of signal names and their corresponding numbers
-p display the trap commands associated with each SIGNAL_SPEC
Each SIGNAL_SPEC is either a signal name in <signal.h> or a signal number.
Signal names are case insensitive and the SIG prefix is optional. A
signal may be sent to the shell with "kill -signal $$".
Exit Status:
Returns success unless a SIGSPEC is invalid or an invalid option is given.
$END
#include <config.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashtypes.h"
#include <signal.h>
#include <stdio.h>
#include "../bashansi.h"
#include "../shell.h"
#include "../trap.h"
#include "common.h"
#include "bashgetopt.h"
static void showtrap PARAMS((int, int));
static int display_traps PARAMS((WORD_LIST *, int));
/* The trap command:
trap <arg> <signal ...>
trap <signal ...>
trap -l
trap -p [sigspec ...]
trap [--]
Set things up so that ARG is executed when SIGNAL(s) N is received.
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. */
int
trap_builtin (list)
WORD_LIST *list;
{
int list_signal_names, display, result, opt;
list_signal_names = display = 0;
result = EXECUTION_SUCCESS;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "lp")) != -1)
{
switch (opt)
{
case 'l':
list_signal_names++;
break;
case 'p':
display++;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */
if (list_signal_names)
return (sh_chkwrite (display_signal_list ((WORD_LIST *)NULL, 1)));
else if (display || list == 0)
{
initialize_terminating_signals ();
get_all_original_signals ();
return (sh_chkwrite (display_traps (list, display && posixly_correct)));
}
else
{
char *first_arg;
int operation, sig, first_signal;
operation = SET;
first_arg = list->word->word;
first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
/* Backwards compatibility. XXX - question about whether or not we
should throw an error if an all-digit argument doesn't correspond
to a valid signal number (e.g., if it's `50' on a system with only
32 signals). */
if (first_signal)
operation = REVERT;
/* When in posix mode, the historical behavior of looking for a
missing first argument is disabled. To revert to the original
signal handling disposition, use `-' as the first argument. */
else if (posixly_correct == 0 && first_arg && *first_arg &&
(*first_arg != '-' || first_arg[1]) &&
signal_object_p (first_arg, opt) && list->next == 0)
operation = REVERT;
else
{
list = list->next;
if (list == 0)
{
builtin_usage ();
return (EX_USAGE);
}
else if (*first_arg == '\0')
operation = IGNORE;
else if (first_arg[0] == '-' && !first_arg[1])
operation = REVERT;
}
/* If we're in a command substitution, we haven't freed the trap strings
(though we reset the signal handlers). If we're setting a trap to
handle a signal here, free the rest of the trap strings since they
don't apply any more. */
if (subshell_environment & SUBSHELL_RESETTRAP)
{
free_trap_strings ();
subshell_environment &= ~SUBSHELL_RESETTRAP;
}
while (list)
{
sig = decode_signal (list->word->word, opt);
if (sig == NO_SIG)
{
sh_invalidsig (list->word->word);
result = EXECUTION_FAILURE;
}
else
{
switch (operation)
{
case SET:
set_signal (sig, first_arg);
break;
case REVERT:
restore_default_signal (sig);
/* Signals that the shell treats specially need special
handling. */
switch (sig)
{
case SIGINT:
/* XXX - should we do this if original disposition
was SIG_IGN? */
if (interactive)
set_signal_handler (SIGINT, sigint_sighandler);
/* special cases for interactive == 0 */
else if (interactive_shell && (sourcelevel||running_trap||parse_and_execute_level))
set_signal_handler (SIGINT, sigint_sighandler);
else
set_signal_handler (SIGINT, termsig_sighandler);
break;
case SIGQUIT:
/* Always ignore SIGQUIT. */
set_signal_handler (SIGQUIT, SIG_IGN);
break;
case SIGTERM:
#if defined (JOB_CONTROL)
case SIGTTIN:
case SIGTTOU:
case SIGTSTP:
#endif /* JOB_CONTROL */
if (interactive)
set_signal_handler (sig, SIG_IGN);
break;
}
break;
case IGNORE:
ignore_signal (sig);
break;
}
}
list = list->next;
}
}
return (result);
}
static void
showtrap (i, show_default)
int i, show_default;
{
char *t, *p, *sn;
int free_t;
free_t = 1;
p = trap_list[i];
if (p == (char *)DEFAULT_SIG && signal_is_hard_ignored (i) == 0)
{
if (show_default)
t = "-";
else
return;
free_t = 0;
}
else if (signal_is_hard_ignored (i))
t = (char *)NULL;
else
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
sn = signal_name (i);
/* Make sure that signals whose names are unknown (for whatever reason)
are printed as signal numbers. */
if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
printf ("trap -- %s %d\n", t ? t : "''", i);
else if (posixly_correct)
{
if (STREQN (sn, "SIG", 3))
printf ("trap -- %s %s\n", t ? t : "''", sn+3);
else
printf ("trap -- %s %s\n", t ? t : "''", sn);
}
else
printf ("trap -- %s %s\n", t ? t : "''", sn);
if (free_t)
FREE (t);
}
static int
display_traps (list, show_all)
WORD_LIST *list;
int show_all;
{
int result, i;
if (list == 0)
{
for (i = 0; i < BASH_NSIG; i++)
showtrap (i, show_all);
return (EXECUTION_SUCCESS);
}
for (result = EXECUTION_SUCCESS; list; list = list->next)
{
i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
if (i == NO_SIG)
{
sh_invalidsig (list->word->word);
result = EXECUTION_FAILURE;
}
else
showtrap (i, show_all);
}
return (result);
}

420
builtins/type.def Normal file
View file

@ -0,0 +1,420 @@
This file is type.def, from which is created type.c.
It implements the builtin "type" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES type.c
$BUILTIN type
$FUNCTION type_builtin
$SHORT_DOC type [-afptP] name [name ...]
Display information about command type.
For each NAME, indicate how it would be interpreted if used as a
command name.
Options:
-a display all locations containing an executable named NAME;
includes aliases, builtins, and functions, if and only if
the `-p' option is not also used
-f suppress shell function lookup
-P force a PATH search for each NAME, even if it is an alias,
builtin, or function, and returns the name of the disk file
that would be executed
-p returns either the name of the disk file that would be executed,
or nothing if `type -t NAME' would not return `file'
-t output 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 not found, respectively
Arguments:
NAME Command name to be interpreted.
Exit Status:
Returns success if all of the NAMEs are found; fails if any are not found.
$END
#include <config.h>
#include "../bashtypes.h"
#include "posixstat.h"
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../parser.h"
#include "../execute_cmd.h"
#include "../findcmd.h"
#include "../hashcmd.h"
#if defined (ALIAS)
#include "../alias.h"
#endif /* ALIAS */
#include "common.h"
#include "bashgetopt.h"
extern int find_reserved_word PARAMS((char *));
/* For each word in LIST, find out what the shell is going to do with
it as a simple command. i.e., which file would this shell use to
execve, or if it is a builtin command, or an alias. Possible flag
arguments:
-t Returns the "type" of the object, one of
`alias', `keyword', `function', `builtin',
or `file'.
-p Returns the pathname of the file if -type is
a file.
-a Returns all occurrences of words, whether they
be a filename in the path, alias, function,
or builtin.
-f Suppress shell function lookup, like `command'.
-P Force a path search even in the presence of other
definitions.
Order of evaluation:
alias
keyword
function
builtin
file
*/
int
type_builtin (list)
WORD_LIST *list;
{
int dflags, any_failed, opt;
WORD_LIST *this;
if (list == 0)
return (EXECUTION_SUCCESS);
dflags = CDESC_SHORTDESC; /* default */
any_failed = 0;
/* Handle the obsolescent `-type', `-path', and `-all' by prescanning
the arguments and converting those options to the form that
internal_getopt recognizes. Converts `--type', `--path', and `--all'
also. THIS SHOULD REALLY GO AWAY. */
for (this = list; this && this->word->word[0] == '-'; this = this->next)
{
char *flag = &(this->word->word[1]);
if (STREQ (flag, "type") || STREQ (flag, "-type"))
{
this->word->word[1] = 't';
this->word->word[2] = '\0';
}
else if (STREQ (flag, "path") || STREQ (flag, "-path"))
{
this->word->word[1] = 'p';
this->word->word[2] = '\0';
}
else if (STREQ (flag, "all") || STREQ (flag, "-all"))
{
this->word->word[1] = 'a';
this->word->word[2] = '\0';
}
}
reset_internal_getopt ();
while ((opt = internal_getopt (list, "afptP")) != -1)
{
switch (opt)
{
case 'a':
dflags |= CDESC_ALL;
break;
case 'f':
dflags |= CDESC_NOFUNCS;
break;
case 'p':
dflags |= CDESC_PATH_ONLY;
dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
break;
case 't':
dflags |= CDESC_TYPE;
dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
break;
case 'P': /* shorthand for type -ap */
dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
while (list)
{
int found;
found = describe_command (list->word->word, dflags);
if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
sh_notfound (list->word->word);
any_failed += found == 0;
list = list->next;
}
opt = (any_failed == 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
return (sh_chkwrite (opt));
}
/*
* Describe COMMAND as required by the type and command builtins.
*
* Behavior is controlled by DFLAGS. Flag values are
* CDESC_ALL print all descriptions of a command
* CDESC_SHORTDESC print the description for type and command -V
* CDESC_REUSABLE print in a format that may be reused as input
* CDESC_TYPE print the type for type -t
* CDESC_PATH_ONLY print the path for type -p
* CDESC_FORCE_PATH force a path search for type -P
* CDESC_NOFUNCS skip function lookup for type -f
* CDESC_ABSPATH convert to absolute path, no ./ prefix
* CDESC_STDPATH command -p standard path list
*
* CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
* return after finding it once.
*/
int
describe_command (command, dflags)
char *command;
int dflags;
{
int found, i, found_file, f, all;
char *full_path, *x, *pathlist;
SHELL_VAR *func;
#if defined (ALIAS)
alias_t *alias;
#endif
all = (dflags & CDESC_ALL) != 0;
found = found_file = 0;
full_path = (char *)NULL;
#if defined (ALIAS)
/* Command is an alias? */
if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
{
if (dflags & CDESC_TYPE)
puts ("alias");
else if (dflags & CDESC_SHORTDESC)
printf (_("%s is aliased to `%s'\n"), command, alias->value);
else if (dflags & CDESC_REUSABLE)
{
x = sh_single_quote (alias->value);
printf ("alias %s=%s\n", command, x);
free (x);
}
found = 1;
if (all == 0)
return (1);
}
#endif /* ALIAS */
/* Command is a shell reserved word? */
if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
{
if (dflags & CDESC_TYPE)
puts ("keyword");
else if (dflags & CDESC_SHORTDESC)
printf (_("%s is a shell keyword\n"), command);
else if (dflags & CDESC_REUSABLE)
printf ("%s\n", command);
found = 1;
if (all == 0)
return (1);
}
/* Command is a function? */
if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
{
if (dflags & CDESC_TYPE)
puts ("function");
else if (dflags & CDESC_SHORTDESC)
{
char *result;
printf (_("%s is a function\n"), command);
/* We're blowing away THE_PRINTED_COMMAND here... */
result = named_function_string (command, function_cell (func), FUNC_MULTILINE|FUNC_EXTERNAL);
printf ("%s\n", result);
}
else if (dflags & CDESC_REUSABLE)
printf ("%s\n", command);
found = 1;
if (all == 0)
return (1);
}
/* Command is a builtin? */
if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
{
if (dflags & CDESC_TYPE)
puts ("builtin");
else if (dflags & CDESC_SHORTDESC)
{
if (posixly_correct && find_special_builtin (command) != 0)
printf (_("%s is a special shell builtin\n"), command);
else
printf (_("%s is a shell builtin\n"), command);
}
else if (dflags & CDESC_REUSABLE)
printf ("%s\n", command);
found = 1;
if (all == 0)
return (1);
}
/* Command is a disk file? */
/* If the command name given is already an absolute command, just
check to see if it is executable. */
if (absolute_program (command))
{
f = file_status (command);
if (f & FS_EXECABLE)
{
if (dflags & CDESC_TYPE)
puts ("file");
else if (dflags & CDESC_SHORTDESC)
printf (_("%s is %s\n"), command, command);
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
printf ("%s\n", command);
/* There's no use looking in the hash table or in $PATH,
because they're not consulted when an absolute program
name is supplied. */
return (1);
}
}
/* If the user isn't doing "-a", then we might care about
whether the file is present in our hash table. */
if (all == 0 || (dflags & CDESC_FORCE_PATH))
{
if (full_path = phash_search (command))
{
if (dflags & CDESC_TYPE)
puts ("file");
else if (dflags & CDESC_SHORTDESC)
printf (_("%s is hashed (%s)\n"), command, full_path);
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
printf ("%s\n", full_path);
free (full_path);
return (1);
}
}
/* Now search through $PATH. */
while (1)
{
if (dflags & CDESC_STDPATH) /* command -p, all cannot be non-zero */
{
pathlist = conf_standard_path ();
full_path = find_in_path (command, pathlist, FS_EXEC_PREFERRED|FS_NODIRS);
free (pathlist);
/* Will only go through this once, since all == 0 if STDPATH set */
}
else if (all == 0)
full_path = find_user_command (command);
else
full_path = user_command_matches (command, FS_EXEC_ONLY, found_file); /* XXX - should that be FS_EXEC_PREFERRED? */
if (full_path == 0)
break;
/* If we found the command as itself by looking through $PATH, it
probably doesn't exist. Check whether or not the command is an
executable file. If it's not, don't report a match. This is
the default posix mode behavior */
if (STREQ (full_path, command) || posixly_correct)
{
f = file_status (full_path);
if ((f & FS_EXECABLE) == 0)
{
free (full_path);
full_path = (char *)NULL;
if (all == 0)
break;
}
else if (ABSPATH (full_path))
; /* placeholder; don't need to do anything yet */
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
{
f = MP_DOCWD | ((dflags & CDESC_ABSPATH) ? MP_RMDOT : 0);
x = sh_makepath ((char *)NULL, full_path, f);
free (full_path);
full_path = x;
}
}
/* If we require a full path and don't have one, make one */
else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
{
x = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
free (full_path);
full_path = x;
}
found_file++;
found = 1;
if (dflags & CDESC_TYPE)
puts ("file");
else if (dflags & CDESC_SHORTDESC)
printf (_("%s is %s\n"), command, full_path);
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
printf ("%s\n", full_path);
free (full_path);
full_path = (char *)NULL;
if (all == 0)
break;
}
return (found);
}

809
builtins/ulimit.def Normal file
View file

@ -0,0 +1,809 @@
This file is ulimit.def, from which is created ulimit.c.
It implements the builtin "ulimit" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES ulimit.c
$BUILTIN ulimit
$FUNCTION ulimit_builtin
$DEPENDS_ON !_MINIX
$SHORT_DOC ulimit [-SHabcdefiklmnpqrstuvxPRT] [limit]
Modify shell resource limits.
Provides control over the resources available to the shell and processes
it creates, on systems that allow such control.
Options:
-S use the `soft' resource limit
-H use the `hard' resource limit
-a all current limits are reported
-b the socket buffer size
-c the maximum size of core files created
-d the maximum size of a process's data segment
-e the maximum scheduling priority (`nice')
-f the maximum size of files written by the shell and its children
-i the maximum number of pending signals
-k the maximum number of kqueues allocated for this process
-l the maximum size a process may lock into memory
-m the maximum resident set size
-n the maximum number of open file descriptors
-p the pipe buffer size
-q the maximum number of bytes in POSIX message queues
-r the maximum real-time scheduling priority
-s the maximum stack size
-t the maximum amount of cpu time in seconds
-u the maximum number of user processes
-v the size of virtual memory
-x the maximum number of file locks
-P the maximum number of pseudoterminals
-R the maximum time a real-time process can run before blocking
-T the maximum number of threads
Not all options are available on all platforms.
If LIMIT is given, it is the new value of the specified resource; the
special LIMIT values `soft', `hard', and `unlimited' stand for the
current soft limit, the current hard limit, and no limit, respectively.
Otherwise, the current value of the specified resource is printed. If
no option is given, then -f is assumed.
Values are in 1024-byte increments, except for -t, which is in seconds,
-p, which is in increments of 512 bytes, and -u, which is an unscaled
number of processes.
Exit Status:
Returns success unless an invalid option is supplied or an error occurs.
$END
#if !defined (_MINIX)
#include <config.h>
#include "../bashtypes.h"
#if defined (HAVE_SYS_PARAM_H)
# include <sys/param.h>
#endif
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
#include <errno.h>
#include "../bashintl.h"
#include "../shell.h"
#include "common.h"
#include "bashgetopt.h"
#include "pipesize.h"
#if !defined (errno)
extern int errno;
#endif
/* For some reason, HPUX chose to make these definitions visible only if
_KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
and #undef it afterward. */
#if defined (HAVE_RESOURCE)
# include <sys/time.h>
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
# define _KERNEL
# endif
# include <sys/resource.h>
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
# undef _KERNEL
# endif
#elif defined (HAVE_SYS_TIMES_H)
# include <sys/times.h>
#endif
#if defined (HAVE_LIMITS_H)
# include <limits.h>
#endif
/* Check for the most basic symbols. If they aren't present, this
system's <sys/resource.h> isn't very useful to us. */
#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
# undef HAVE_RESOURCE
#endif
#if !defined (HAVE_RESOURCE) && defined (HAVE_ULIMIT_H)
# include <ulimit.h>
#endif
#if !defined (RLIMTYPE)
# define RLIMTYPE long
# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
#endif
/* Alternate names */
/* 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 */
#if defined (HAVE_RESOURCE) && defined (RLIMIT_POSIXLOCKS) && !defined (RLIMIT_LOCKS)
# define RLIMIT_LOCKS RLIMIT_POSIXLOCKS
#endif /* HAVE_RESOURCE && RLIMIT_POSIXLOCKS && !RLIMIT_LOCKS */
/* Some systems have these, some do not. */
#ifdef RLIMIT_FSIZE
# define RLIMIT_FILESIZE RLIMIT_FSIZE
#else
# define RLIMIT_FILESIZE 256
#endif
#define RLIMIT_PIPESIZE 257
#ifdef RLIMIT_NOFILE
# define RLIMIT_OPENFILES RLIMIT_NOFILE
#else
# define RLIMIT_OPENFILES 258
#endif
#ifdef RLIMIT_VMEM
# define RLIMIT_VIRTMEM RLIMIT_VMEM
# define RLIMIT_VMBLKSZ 1024
#else
# ifdef RLIMIT_AS
# define RLIMIT_VIRTMEM RLIMIT_AS
# define RLIMIT_VMBLKSZ 1024
# else
# define RLIMIT_VIRTMEM 259
# define RLIMIT_VMBLKSZ 1
# endif
#endif
#ifdef RLIMIT_NPROC
# define RLIMIT_MAXUPROC RLIMIT_NPROC
#else
# define RLIMIT_MAXUPROC 260
#endif
#if !defined (RLIMIT_PTHREAD) && defined (RLIMIT_NTHR)
# define RLIMIT_PTHREAD RLIMIT_NTHR
#endif
#if !defined (RLIM_INFINITY)
# define RLIM_INFINITY 0x7fffffff
#endif
#if !defined (RLIM_SAVED_CUR)
# define RLIM_SAVED_CUR RLIM_INFINITY
#endif
#if !defined (RLIM_SAVED_MAX)
# define RLIM_SAVED_MAX RLIM_INFINITY
#endif
#define LIMIT_HARD 0x01
#define LIMIT_SOFT 0x02
/* "Blocks" are defined as 512 bytes when in Posix mode and 1024 bytes
otherwise. */
#define POSIXBLK -2
#define BLOCKSIZE(x) (((x) == POSIXBLK) ? (posixly_correct ? 512 : 1024) : (x))
static int _findlim PARAMS((int));
static int ulimit_internal PARAMS((int, char *, int, int));
static int get_limit PARAMS((int, RLIMTYPE *, RLIMTYPE *));
static int set_limit PARAMS((int, RLIMTYPE, int));
static void printone PARAMS((int, RLIMTYPE, int));
static void print_all_limits PARAMS((int));
static int set_all_limits PARAMS((int, RLIMTYPE));
static int filesize PARAMS((RLIMTYPE *));
static int pipesize PARAMS((RLIMTYPE *));
static int getmaxuprc PARAMS((RLIMTYPE *));
static int getmaxvm PARAMS((RLIMTYPE *, RLIMTYPE *));
typedef struct {
int option; /* The ulimit option for this limit. */
int parameter; /* Parameter to pass to get_limit (). */
int block_factor; /* Blocking factor for specific limit. */
const char * const description; /* Descriptive string to output. */
const char * const units; /* scale */
} RESOURCE_LIMITS;
static RESOURCE_LIMITS limits[] = {
#ifdef RLIMIT_NPTS
{ 'P', RLIMIT_NPTS, 1, "number of pseudoterminals", (char *)NULL },
#endif
#ifdef RLIMIT_RTTIME
{ 'R', RLIMIT_RTTIME, 1, "real-time non-blocking time", "microseconds" },
#endif
#ifdef RLIMIT_PTHREAD
{ 'T', RLIMIT_PTHREAD, 1, "number of threads", (char *)NULL },
#endif
#ifdef RLIMIT_SBSIZE
{ 'b', RLIMIT_SBSIZE, 1, "socket buffer size", "bytes" },
#endif
#ifdef RLIMIT_CORE
{ 'c', RLIMIT_CORE, POSIXBLK, "core file size", "blocks" },
#endif
#ifdef RLIMIT_DATA
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
#endif
#ifdef RLIMIT_NICE
{ 'e', RLIMIT_NICE, 1, "scheduling priority", (char *)NULL },
#endif
{ 'f', RLIMIT_FILESIZE, POSIXBLK, "file size", "blocks" },
#ifdef RLIMIT_SIGPENDING
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
#endif
#ifdef RLIMIT_KQUEUES
{ 'k', RLIMIT_KQUEUES, 1, "max kqueues", (char *)NULL },
#endif
#ifdef RLIMIT_MEMLOCK
{ 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
#endif
#ifdef RLIMIT_RSS
{ 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" },
#endif /* RLIMIT_RSS */
{ 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL},
{ 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
#ifdef RLIMIT_MSGQUEUE
{ 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
#endif
#ifdef RLIMIT_RTPRIO
{ 'r', RLIMIT_RTPRIO, 1, "real-time priority", (char *)NULL },
#endif
#ifdef RLIMIT_STACK
{ 's', RLIMIT_STACK, 1024, "stack size", "kbytes" },
#endif
#ifdef RLIMIT_CPU
{ 't', RLIMIT_CPU, 1, "cpu time", "seconds" },
#endif /* RLIMIT_CPU */
{ 'u', RLIMIT_MAXUPROC, 1, "max user processes", (char *)NULL },
#if defined (HAVE_RESOURCE)
{ 'v', RLIMIT_VIRTMEM, RLIMIT_VMBLKSZ, "virtual memory", "kbytes" },
#endif
#ifdef RLIMIT_SWAP
{ 'w', RLIMIT_SWAP, 1024, "swap size", "kbytes" },
#endif
#ifdef RLIMIT_LOCKS
{ 'x', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
#endif
{ -1, -1, -1, (char *)NULL, (char *)NULL }
};
#define NCMDS (sizeof(limits) / sizeof(limits[0]))
typedef struct _cmd {
int cmd;
char *arg;
} ULCMD;
static ULCMD *cmdlist;
static int ncmd;
static int cmdlistsz;
#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
long
ulimit (cmd, newlim)
int cmd;
long newlim;
{
errno = EINVAL;
return -1;
}
#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
static int
_findlim (opt)
int opt;
{
register int i;
for (i = 0; limits[i].option > 0; i++)
if (limits[i].option == opt)
return i;
return -1;
}
static char optstring[4 + 2 * NCMDS];
/* Report or set limits associated with certain per-process resources.
See the help documentation in builtins.c for a full description. */
int
ulimit_builtin (list)
register WORD_LIST *list;
{
register char *s;
int c, limind, mode, opt, all_limits;
mode = 0;
all_limits = 0;
/* Idea stolen from pdksh -- build option string the first time called. */
if (optstring[0] == 0)
{
s = optstring;
*s++ = 'a'; *s++ = 'S'; *s++ = 'H';
for (c = 0; limits[c].option > 0; c++)
{
*s++ = limits[c].option;
*s++ = ';';
}
*s = '\0';
}
/* Initialize the command list. */
if (cmdlistsz == 0)
cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
ncmd = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, optstring)) != -1)
{
switch (opt)
{
case 'a':
all_limits++;
break;
/* -S and -H are modifiers, not real options. */
case 'S':
mode |= LIMIT_SOFT;
break;
case 'H':
mode |= LIMIT_HARD;
break;
CASE_HELPOPT;
case '?':
builtin_usage ();
return (EX_USAGE);
default:
if (ncmd >= cmdlistsz)
cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
cmdlist[ncmd].cmd = opt;
cmdlist[ncmd++].arg = list_optarg;
break;
}
}
list = loptend;
if (all_limits)
{
#ifdef NOTYET
if (list) /* setting */
{
if (STREQ (list->word->word, "unlimited") == 0)
{
builtin_error (_("%s: invalid limit argument"), list->word->word);
return (EXECUTION_FAILURE);
}
return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
}
#endif
print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
return (sh_chkwrite (EXECUTION_SUCCESS));
}
/* default is `ulimit -f' */
if (ncmd == 0)
{
cmdlist[ncmd].cmd = 'f';
/* `ulimit something' is same as `ulimit -f something' */
cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
if (list)
list = list->next;
}
/* verify each command in the list. */
for (c = 0; c < ncmd; c++)
{
limind = _findlim (cmdlist[c].cmd);
if (limind == -1)
{
builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
return (EX_USAGE);
}
}
/* POSIX compatibility. If the last item in cmdlist does not have an option
argument, but there is an operand (list != 0), treat the operand as if
it were an option argument for that last command. */
if (list && list->word && cmdlist[ncmd - 1].arg == 0)
{
cmdlist[ncmd - 1].arg = list->word->word;
list = list->next;
}
for (c = 0; c < ncmd; c++)
if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
return (EXECUTION_FAILURE);
return (EXECUTION_SUCCESS);
}
static int
ulimit_internal (cmd, cmdarg, mode, multiple)
int cmd;
char *cmdarg;
int mode, multiple;
{
int opt, limind, setting;
int block_factor;
RLIMTYPE soft_limit, hard_limit, real_limit, limit;
setting = cmdarg != 0;
limind = _findlim (cmd);
if (mode == 0)
mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
opt = get_limit (limind, &soft_limit, &hard_limit);
if (opt < 0)
{
builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
strerror (errno));
return (EXECUTION_FAILURE);
}
if (setting == 0) /* print the value of the specified limit */
{
printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
return (EXECUTION_SUCCESS);
}
/* Setting the limit. */
if (STREQ (cmdarg, "hard"))
real_limit = hard_limit;
else if (STREQ (cmdarg, "soft"))
real_limit = soft_limit;
else if (STREQ (cmdarg, "unlimited"))
real_limit = RLIM_INFINITY;
else if (all_digits (cmdarg))
{
limit = string_to_rlimtype (cmdarg);
block_factor = BLOCKSIZE(limits[limind].block_factor);
real_limit = limit * block_factor;
if ((real_limit / block_factor) != limit)
{
sh_erange (cmdarg, _("limit"));
return (EXECUTION_FAILURE);
}
}
else
{
sh_invalidnum (cmdarg);
return (EXECUTION_FAILURE);
}
if (set_limit (limind, real_limit, mode) < 0)
{
builtin_error (_("%s: cannot modify limit: %s"), limits[limind].description,
strerror (errno));
return (EXECUTION_FAILURE);
}
return (EXECUTION_SUCCESS);
}
static int
get_limit (ind, softlim, hardlim)
int ind;
RLIMTYPE *softlim, *hardlim;
{
RLIMTYPE value;
#if defined (HAVE_RESOURCE)
struct rlimit limit;
#endif
if (limits[ind].parameter >= 256)
{
switch (limits[ind].parameter)
{
case RLIMIT_FILESIZE:
if (filesize (&value) < 0)
return -1;
break;
case RLIMIT_PIPESIZE:
if (pipesize (&value) < 0)
return -1;
break;
case RLIMIT_OPENFILES:
value = (RLIMTYPE)getdtablesize ();
break;
case RLIMIT_VIRTMEM:
return (getmaxvm (softlim, hardlim));
case RLIMIT_MAXUPROC:
if (getmaxuprc (&value) < 0)
return -1;
break;
default:
errno = EINVAL;
return -1;
}
*softlim = *hardlim = value;
return (0);
}
else
{
#if defined (HAVE_RESOURCE)
if (getrlimit (limits[ind].parameter, &limit) < 0)
return -1;
*softlim = limit.rlim_cur;
*hardlim = limit.rlim_max;
# if defined (HPUX9)
if (limits[ind].parameter == RLIMIT_FILESIZE)
{
*softlim *= 512;
*hardlim *= 512; /* Ugh. */
}
else
# endif /* HPUX9 */
return 0;
#else
errno = EINVAL;
return -1;
#endif
}
}
static int
set_limit (ind, newlim, mode)
int ind;
RLIMTYPE newlim;
int mode;
{
#if defined (HAVE_RESOURCE)
struct rlimit limit;
RLIMTYPE val;
#endif
if (limits[ind].parameter >= 256)
switch (limits[ind].parameter)
{
case RLIMIT_FILESIZE:
#if !defined (HAVE_RESOURCE)
return (ulimit (2, newlim / 512L));
#else
errno = EINVAL;
return -1;
#endif
case RLIMIT_OPENFILES:
#if defined (HAVE_SETDTABLESIZE)
# if defined (__CYGWIN__)
/* Grrr... Cygwin declares setdtablesize as void. */
setdtablesize (newlim);
return 0;
# else
return (setdtablesize (newlim));
# endif
#endif
case RLIMIT_PIPESIZE:
case RLIMIT_VIRTMEM:
case RLIMIT_MAXUPROC:
default:
errno = EINVAL;
return -1;
}
else
{
#if defined (HAVE_RESOURCE)
if (getrlimit (limits[ind].parameter, &limit) < 0)
return -1;
# if defined (HPUX9)
if (limits[ind].parameter == RLIMIT_FILESIZE)
newlim /= 512; /* Ugh. */
# endif /* HPUX9 */
val = (current_user.euid != 0 && newlim == RLIM_INFINITY &&
(mode & LIMIT_HARD) == 0 && /* XXX -- test */
(limit.rlim_cur <= limit.rlim_max))
? limit.rlim_max : newlim;
if (mode & LIMIT_SOFT)
limit.rlim_cur = val;
if (mode & LIMIT_HARD)
limit.rlim_max = val;
return (setrlimit (limits[ind].parameter, &limit));
#else
errno = EINVAL;
return -1;
#endif
}
}
static int
getmaxvm (softlim, hardlim)
RLIMTYPE *softlim, *hardlim;
{
#if defined (HAVE_RESOURCE)
struct rlimit datalim, stacklim;
if (getrlimit (RLIMIT_DATA, &datalim) < 0)
return -1;
if (getrlimit (RLIMIT_STACK, &stacklim) < 0)
return -1;
/* Protect against overflow. */
*softlim = (datalim.rlim_cur / 1024L) + (stacklim.rlim_cur / 1024L);
*hardlim = (datalim.rlim_max / 1024L) + (stacklim.rlim_max / 1024L);
return 0;
#else
errno = EINVAL;
return -1;
#endif /* HAVE_RESOURCE */
}
static int
filesize(valuep)
RLIMTYPE *valuep;
{
#if !defined (HAVE_RESOURCE)
long result;
if ((result = ulimit (1, 0L)) < 0)
return -1;
else
*valuep = (RLIMTYPE) result * 512;
return 0;
#else
errno = EINVAL;
return -1;
#endif
}
static int
pipesize (valuep)
RLIMTYPE *valuep;
{
#if defined (PIPE_BUF)
/* This is defined on Posix systems. */
*valuep = (RLIMTYPE) PIPE_BUF;
return 0;
#else
# if defined (_POSIX_PIPE_BUF)
*valuep = (RLIMTYPE) _POSIX_PIPE_BUF;
return 0;
# else
# if defined (PIPESIZE)
/* This is defined by running a program from the Makefile. */
*valuep = (RLIMTYPE) PIPESIZE;
return 0;
# else
errno = EINVAL;
return -1;
# endif /* PIPESIZE */
# endif /* _POSIX_PIPE_BUF */
#endif /* PIPE_BUF */
}
static int
getmaxuprc (valuep)
RLIMTYPE *valuep;
{
long maxchild;
maxchild = getmaxchild ();
if (maxchild < 0)
{
errno = EINVAL;
return -1;
}
else
{
*valuep = (RLIMTYPE) maxchild;
return 0;
}
}
static void
print_all_limits (mode)
int mode;
{
register int i;
RLIMTYPE softlim, hardlim;
if (mode == 0)
mode |= LIMIT_SOFT;
for (i = 0; limits[i].option > 0; i++)
{
if (get_limit (i, &softlim, &hardlim) == 0)
printone (i, (mode & LIMIT_SOFT) ? softlim : hardlim, 1);
else if (errno != EINVAL)
builtin_error ("%s: cannot get limit: %s", limits[i].description,
strerror (errno));
}
}
static void
printone (limind, curlim, pdesc)
int limind;
RLIMTYPE curlim;
int pdesc;
{
char unitstr[64];
int factor;
factor = BLOCKSIZE(limits[limind].block_factor);
if (pdesc)
{
if (limits[limind].units)
sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
else
sprintf (unitstr, "(-%c) ", limits[limind].option);
printf ("%-20s %20s", limits[limind].description, unitstr);
}
if (curlim == RLIM_INFINITY)
puts ("unlimited");
else if (curlim == RLIM_SAVED_MAX)
puts ("hard");
else if (curlim == RLIM_SAVED_CUR)
puts ("soft");
else
print_rlimtype ((curlim / factor), 1);
}
/* Set all limits to NEWLIM. NEWLIM currently must be RLIM_INFINITY, which
causes all limits to be set as high as possible depending on mode (like
csh `unlimit'). Returns -1 if NEWLIM is invalid, 0 if all limits
were set successfully, and 1 if at least one limit could not be set.
To raise all soft limits to their corresponding hard limits, use
ulimit -S -a unlimited
To attempt to raise all hard limits to infinity (superuser-only), use
ulimit -H -a unlimited
To attempt to raise all soft and hard limits to infinity, use
ulimit -a unlimited
*/
static int
set_all_limits (mode, newlim)
int mode;
RLIMTYPE newlim;
{
register int i;
int retval = 0;
if (newlim != RLIM_INFINITY)
{
errno = EINVAL;
return -1;
}
if (mode == 0)
mode = LIMIT_SOFT|LIMIT_HARD;
for (retval = i = 0; limits[i].option > 0; i++)
if (set_limit (i, newlim, mode) < 0)
{
builtin_error (_("%s: cannot modify limit: %s"), limits[i].description,
strerror (errno));
retval = 1;
}
return retval;
}
#endif /* !_MINIX */

317
builtins/umask.def Normal file
View file

@ -0,0 +1,317 @@
This file is umask.def, from which is created umask.c.
It implements the builtin "umask" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$PRODUCES umask.c
$BUILTIN umask
$FUNCTION umask_builtin
$SHORT_DOC umask [-p] [-S] [mode]
Display or set file mode mask.
Sets the user file-creation mask to MODE. If MODE is omitted, prints
the current value of the mask.
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).
Options:
-p if MODE is omitted, output in a form that may be reused as input
-S makes the output symbolic; otherwise an octal number is output
Exit Status:
Returns success unless MODE is invalid or an invalid option is given.
$END
#include <config.h>
#include "../bashtypes.h"
#include "filecntl.h"
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
# include <sys/file.h>
#endif
#if defined (HAVE_UNISTD_H)
#include <unistd.h>
#endif
#include <stdio.h>
#include <chartypes.h>
#include "../bashintl.h"
#include "../shell.h"
#include "posixstat.h"
#include "common.h"
#include "bashgetopt.h"
/* **************************************************************** */
/* */
/* UMASK Builtin and Helpers */
/* */
/* **************************************************************** */
static void print_symbolic_umask PARAMS((mode_t));
static int symbolic_umask PARAMS((WORD_LIST *));
/* Set or display the mask used by the system when creating files. Flag
of -S means display the umask in a symbolic mode. */
int
umask_builtin (list)
WORD_LIST *list;
{
int print_symbolically, opt, umask_value, pflag;
mode_t umask_arg;
print_symbolically = pflag = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "Sp")) != -1)
{
switch (opt)
{
case 'S':
print_symbolically++;
break;
case 'p':
pflag++;
break;
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (list)
{
if (DIGIT (*list->word->word))
{
umask_value = read_octal (list->word->word);
/* Note that other shells just let you set the umask to zero
by specifying a number out of range. This is a problem
with those shells. We don't change the umask if the input
is lousy. */
if (umask_value == -1)
{
sh_erange (list->word->word, _("octal number"));
return (EXECUTION_FAILURE);
}
}
else
{
umask_value = symbolic_umask (list);
if (umask_value == -1)
return (EXECUTION_FAILURE);
}
umask_arg = (mode_t)umask_value;
umask (umask_arg);
if (print_symbolically)
print_symbolic_umask (umask_arg);
}
else /* Display the UMASK for this user. */
{
umask_arg = umask (022);
umask (umask_arg);
if (pflag)
printf ("umask%s ", (print_symbolically ? " -S" : ""));
if (print_symbolically)
print_symbolic_umask (umask_arg);
else
printf ("%04lo\n", (unsigned long)umask_arg);
}
return (sh_chkwrite (EXECUTION_SUCCESS));
}
/* Print the umask in a symbolic form. In the output, a letter is
printed if the corresponding bit is clear in the umask. */
static void
#if defined (__STDC__)
print_symbolic_umask (mode_t um)
#else
print_symbolic_umask (um)
mode_t um;
#endif
{
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
int i;
i = 0;
if ((um & S_IRUSR) == 0)
ubits[i++] = 'r';
if ((um & S_IWUSR) == 0)
ubits[i++] = 'w';
if ((um & S_IXUSR) == 0)
ubits[i++] = 'x';
ubits[i] = '\0';
i = 0;
if ((um & S_IRGRP) == 0)
gbits[i++] = 'r';
if ((um & S_IWGRP) == 0)
gbits[i++] = 'w';
if ((um & S_IXGRP) == 0)
gbits[i++] = 'x';
gbits[i] = '\0';
i = 0;
if ((um & S_IROTH) == 0)
obits[i++] = 'r';
if ((um & S_IWOTH) == 0)
obits[i++] = 'w';
if ((um & S_IXOTH) == 0)
obits[i++] = 'x';
obits[i] = '\0';
printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
}
int
parse_symbolic_mode (mode, initial_bits)
char *mode;
int initial_bits;
{
int who, op, perm, bits, c;
char *s;
for (s = mode, bits = initial_bits;;)
{
who = op = perm = 0;
/* Parse the `who' portion of the symbolic mode clause. */
while (member (*s, "agou"))
{
switch (c = *s++)
{
case 'u':
who |= S_IRWXU;
continue;
case 'g':
who |= S_IRWXG;
continue;
case 'o':
who |= S_IRWXO;
continue;
case 'a':
who |= S_IRWXU | S_IRWXG | S_IRWXO;
continue;
default:
break;
}
}
/* The operation is now sitting in *s. */
op = *s++;
switch (op)
{
case '+':
case '-':
case '=':
break;
default:
builtin_error (_("`%c': invalid symbolic mode operator"), op);
return (-1);
}
/* Parse out the `perm' section of the symbolic mode clause. */
while (member (*s, "rwx"))
{
c = *s++;
switch (c)
{
case 'r':
perm |= S_IRUGO;
break;
case 'w':
perm |= S_IWUGO;
break;
case 'x':
perm |= S_IXUGO;
break;
}
}
/* Now perform the operation or return an error for a
bad permission string. */
if (!*s || *s == ',')
{
if (who)
perm &= who;
switch (op)
{
case '+':
bits |= perm;
break;
case '-':
bits &= ~perm;
break;
case '=':
if (who == 0)
who = S_IRWXU | S_IRWXG | S_IRWXO;
bits &= ~who;
bits |= perm;
break;
/* No other values are possible. */
}
if (*s == '\0')
break;
else
s++; /* skip past ',' */
}
else
{
builtin_error (_("`%c': invalid symbolic mode character"), *s);
return (-1);
}
}
return (bits);
}
/* Set the umask from a symbolic mode string similar to that accepted
by chmod. If the -S argument is given, then print the umask in a
symbolic form. */
static int
symbolic_umask (list)
WORD_LIST *list;
{
int um, bits;
/* Get the initial umask. Don't change it yet. */
um = umask (022);
umask (um);
/* All work is done with the complement of the umask -- it's
more intuitive and easier to deal with. It is complemented
again before being returned. */
bits = parse_symbolic_mode (list->word->word, ~um & 0777);
if (bits == -1)
return (-1);
um = ~bits & 0777;
return (um);
}

381
builtins/wait.def Normal file
View file

@ -0,0 +1,381 @@
'This file is wait.def, from which is created wait.c.
It implements the builtin "wait" in Bash.
Copyright (C) 1987-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
Bash is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Bash is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Bash. If not, see <http://www.gnu.org/licenses/>.
$BUILTIN wait
$FUNCTION wait_builtin
$DEPENDS_ON JOB_CONTROL
$PRODUCES wait.c
$SHORT_DOC wait [-fn] [-p var] [id ...]
Wait for job completion and return exit status.
Waits for each process identified by an ID, which may be a process ID or a
job specification, and reports its termination status. If ID is not
given, waits for all currently active child processes, and the return
status is zero. If ID is a job specification, waits for all processes
in that job's pipeline.
If the -n option is supplied, waits for a single job from the list of IDs,
or, if no IDs are supplied, for the next job to complete and returns its
exit status.
If the -p option is supplied, the process or job identifier of the job
for which the exit status is returned is assigned to the variable VAR
named by the option argument. The variable will be unset initially, before
any assignment. This is useful only when the -n option is supplied.
If the -f option is supplied, and job control is enabled, waits for the
specified ID to terminate, instead of waiting for it to change status.
Exit Status:
Returns the status of the last ID; fails if ID is invalid or an invalid
option is given, or if -n is supplied and the shell has no unwaited-for
children.
$END
$BUILTIN wait
$FUNCTION wait_builtin
$DEPENDS_ON !JOB_CONTROL
$SHORT_DOC wait [pid ...]
Wait for process completion and return exit status.
Waits for each process specified by a PID and reports its termination status.
If PID is not given, waits for all currently active child processes,
and the return status is zero. PID must be a process ID.
Exit Status:
Returns the status of the last PID; fails if PID is invalid or an invalid
option is given.
$END
#include <config.h>
#include "../bashtypes.h"
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <chartypes.h>
#include "../bashansi.h"
#include "../shell.h"
#include "../execute_cmd.h"
#include "../jobs.h"
#include "../trap.h"
#include "../sig.h"
#include "common.h"
#include "bashgetopt.h"
extern int wait_signal_received;
procenv_t wait_intr_buf;
int wait_intr_flag;
static int set_waitlist PARAMS((WORD_LIST *));
static void unset_waitlist PARAMS((void));
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
wait for all of the active background processes of the shell and return
0. If a list of pids or job specs are given, return the exit status of
the last one waited for. */
#define WAIT_RETURN(s) \
do \
{ \
wait_signal_received = 0; \
wait_intr_flag = 0; \
return (s);\
} \
while (0)
int
wait_builtin (list)
WORD_LIST *list;
{
int status, code, opt, nflag, vflags, bindflags;
volatile int wflags;
char *vname;
SHELL_VAR *pidvar;
struct procstat pstat;
USE_VAR(list);
nflag = wflags = vflags = 0;
vname = NULL;
pidvar = (SHELL_VAR *)NULL;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "fnp:")) != -1)
{
switch (opt)
{
#if defined (JOB_CONTROL)
case 'n':
nflag = 1;
break;
case 'f':
wflags |= JWAIT_FORCE;
break;
case 'p':
vname = list_optarg;
vflags = list_optflags;
break;
#endif
CASE_HELPOPT;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
/* Sanity-check variable name if -p supplied. */
if (vname)
{
#if defined (ARRAY_VARS)
int arrayflags;
SET_VFLAGS (vflags, arrayflags, bindflags);
if (legal_identifier (vname) == 0 && valid_array_reference (vname, arrayflags) == 0)
#else
bindflags = 0;
if (legal_identifier (vname) == 0)
#endif
{
sh_invalidid (vname);
WAIT_RETURN (EXECUTION_FAILURE);
}
if (builtin_unbind_variable (vname) == -2)
WAIT_RETURN (EXECUTION_FAILURE);
}
/* POSIX.2 says: When the shell is waiting (by means of the wait utility)
for asynchronous commands to complete, the reception of a signal for
which a trap has been set shall cause the wait utility to return
immediately with an exit status greater than 128, after which the trap
associated with the signal shall be taken.
We handle SIGINT here; it's the only one that needs to be treated
specially (I think), since it's handled specially in {no,}jobs.c. */
wait_intr_flag = 1;
code = setjmp_sigs (wait_intr_buf);
if (code)
{
last_command_exit_signal = wait_signal_received;
status = 128 + wait_signal_received;
wait_sigint_cleanup ();
#if defined (JOB_CONTROL)
if (wflags & JWAIT_WAITING)
unset_waitlist ();
#endif
WAIT_RETURN (status);
}
opt = first_pending_trap ();
#if defined (SIGCHLD)
/* We special case SIGCHLD when not in posix mode because we don't break
out of the wait even when the signal is trapped; we run the trap after
the wait completes. See how it's handled in jobs.c:waitchld(). */
if (opt == SIGCHLD && posixly_correct == 0)
opt = next_pending_trap (opt+1);
#endif
if (opt != -1)
{
last_command_exit_signal = wait_signal_received = opt;
status = opt + 128;
WAIT_RETURN (status);
}
/* We support jobs or pids.
wait <pid-or-job> [pid-or-job ...] */
#if defined (JOB_CONTROL)
if (nflag)
{
if (list)
{
opt = set_waitlist (list);
if (opt == 0)
WAIT_RETURN (127);
wflags |= JWAIT_WAITING;
}
status = wait_for_any_job (wflags, &pstat);
if (vname && status >= 0)
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
if (status < 0)
status = 127;
if (list)
unset_waitlist ();
WAIT_RETURN (status);
}
#endif
/* But wait without any arguments means to wait for all of the shell's
currently active background processes. */
if (list == 0)
{
opt = wait_for_background_pids (&pstat);
#if 0
/* Compatibility with NetBSD sh: don't set VNAME since it doesn't
correspond to the return status. */
if (vname && opt)
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
#endif
WAIT_RETURN (EXECUTION_SUCCESS);
}
status = EXECUTION_SUCCESS;
while (list)
{
pid_t pid;
char *w;
intmax_t pid_value;
w = list->word->word;
if (DIGIT (*w))
{
if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
{
pid = (pid_t)pid_value;
status = wait_for_single_pid (pid, wflags|JWAIT_PERROR);
/* status > 256 means pid error */
pstat.pid = (status > 256) ? NO_PID : pid;
pstat.status = (status > 256) ? 127 : status;
if (status > 256)
status = 127;
}
else
{
sh_badpid (w);
pstat.pid = NO_PID;
pstat.status = 127;
WAIT_RETURN (EXECUTION_FAILURE);
}
}
#if defined (JOB_CONTROL)
else if (*w && *w == '%')
/* Must be a job spec. Check it out. */
{
int job;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
UNBLOCK_CHILD (oset);
status = 127; /* As per Posix.2, section 4.70.2 */
pstat.pid = NO_PID;
pstat.status = status;
list = list->next;
continue;
}
/* Job spec used. Wait for the last pid in the pipeline. */
UNBLOCK_CHILD (oset);
status = wait_for_job (job, wflags, &pstat);
}
#endif /* JOB_CONTROL */
else
{
sh_badpid (w);
pstat.pid = NO_PID;
pstat.status = 127;
status = EXECUTION_FAILURE;
}
/* Don't waste time with a longjmp. */
if (wait_signal_received)
{
last_command_exit_signal = wait_signal_received;
status = 128 + wait_signal_received;
wait_sigint_cleanup ();
WAIT_RETURN (status);
}
list = list->next;
}
if (vname && pstat.pid != NO_PID)
builtin_bind_var_to_int (vname, pstat.pid, bindflags);
WAIT_RETURN (status);
}
#if defined (JOB_CONTROL)
/* Take each valid pid or jobspec in LIST and mark the corresponding job as
J_WAITING, so wait -n knows which jobs to wait for. Return the number of
jobs we found. */
static int
set_waitlist (list)
WORD_LIST *list;
{
sigset_t set, oset;
int job, r, njob;
intmax_t pid;
WORD_LIST *l;
BLOCK_CHILD (set, oset);
njob = 0;
for (l = list; l; l = l->next)
{
job = NO_JOB;
job = (l && legal_number (l->word->word, &pid) && pid == (pid_t) pid)
? get_job_by_pid ((pid_t) pid, 0, 0)
: get_job_spec (l);
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
{
sh_badjob (l->word->word);
continue;
}
/* We don't check yet to see if one of the desired jobs has already
terminated, but we could. We wait until wait_for_any_job(). This
has the advantage of validating all the arguments. */
if ((jobs[job]->flags & J_WAITING) == 0)
{
njob++;
jobs[job]->flags |= J_WAITING;
}
}
UNBLOCK_CHILD (oset);
return (njob);
}
/* Clean up after a call to wait -n jobs */
static void
unset_waitlist ()
{
int i;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i] && (jobs[i]->flags & J_WAITING))
jobs[i]->flags &= ~J_WAITING;
UNBLOCK_CHILD (oset);
}
#endif