mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-08-11 20:50:42 +02:00
bash-3.1 remove leftover and stray files
This commit is contained in:
@@ -1,625 +0,0 @@
|
||||
# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs.
|
||||
#
|
||||
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; either version 2, or (at your option)
|
||||
# any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
PACKAGE = @PACKAGE@
|
||||
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@
|
||||
includedir = @includedir@
|
||||
datadir = @datadir@
|
||||
localedir = $(datadir)/locale
|
||||
|
||||
# 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@
|
||||
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)
|
||||
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_INC = @INTL_INC@
|
||||
LIBINTL_H = @LIBINTL_H@
|
||||
|
||||
HELPDIR = @HELPDIR@
|
||||
MKDIRS = ${topdir}/support/mkdirs
|
||||
|
||||
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} $(LOCAL_CFLAGS)
|
||||
|
||||
CCFLAGS = $(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
|
||||
|
||||
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 \
|
||||
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
|
||||
|
||||
all: $(MKBUILTINS) libbuiltins.a
|
||||
|
||||
libbuiltins.a: $(MKBUILTINS) $(OFILES) builtins.o
|
||||
$(RM) $@
|
||||
$(AR) $(ARFLAGS) $@ $(OFILES)
|
||||
-$(RANLIB) $@
|
||||
|
||||
builtext.h builtins.c: $(MKBUILTINS) $(DEFSRC)
|
||||
@-if test -f builtins.c; then mv -f builtins.c old-builtins.c; fi
|
||||
@-if test -f builtext.h; then mv -f builtext.h old-builtext.h; fi
|
||||
./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \
|
||||
-noproduction $(DIRECTDEFINE) $(HELPDIRDEFINE) $(HELPSTRINGS) $(DEFSRC)
|
||||
@-if cmp -s old-builtext.h builtext.h 2>/dev/null; then \
|
||||
mv old-builtext.h builtext.h; \
|
||||
else \
|
||||
$(RM) old-builtext.h; \
|
||||
fi
|
||||
@-if cmp -s old-builtins.c builtins.c 2>/dev/null; then \
|
||||
mv old-builtins.c builtins.c; \
|
||||
else \
|
||||
$(RM) old-builtins.c; \
|
||||
fi
|
||||
|
||||
helpdoc: $(MKBUILTINS) $(DEFSRC)
|
||||
./$(MKBUILTINS) ${HELPDIRDEFINE} -noproduction $(DIRECTDEFINE) $(DEFSRC)
|
||||
|
||||
install-help:
|
||||
@-if test -n "${HELPDIR}" && test -d helpfiles ; then \
|
||||
test -d ${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
|
||||
|
||||
ulimit.o: pipesize.h
|
||||
|
||||
pipesize.h: psize.aux
|
||||
$(SHELL) $(srcdir)/psize.sh > $@
|
||||
|
||||
psize.aux: psize.c
|
||||
$(CC_FOR_BUILD) $(CCFLAGS_FOR_BUILD) -o $@ $(srcdir)/psize.c
|
||||
|
||||
documentation: builtins.texi
|
||||
|
||||
builtins.texi: $(MKBUILTINS)
|
||||
./$(MKBUILTINS) -documentonly $(DEFSRC)
|
||||
|
||||
clean:
|
||||
$(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS) mkbuiltins.o libbuiltins.a
|
||||
-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
|
||||
|
||||
# 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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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)/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
|
||||
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
|
||||
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
|
||||
declare.o: ./builtext.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
|
||||
echo.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
echo.o: $(BASHINCDIR)/maxpath.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
|
||||
enable.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
enable.o: $(BASHINCDIR)/maxpath.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
|
||||
eval.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
eval.o: $(BASHINCDIR)/maxpath.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
|
||||
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
|
||||
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
|
||||
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: $(BASHINCDIR)/maxpath.h ./builtext.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
|
||||
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
|
||||
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
|
||||
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
|
||||
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)/jobs.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
|
||||
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
|
||||
hash.o: $(topdir)/builtins.h $(topdir)/command.h $(topdir)/quit.h
|
||||
hash.o: $(topdir)/findcmd.h $(topdir)/hashlib.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 $(topdir)/conftypes.h
|
||||
hash.o: $(srcdir)/common.h $(BASHINCDIR)/maxpath.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 $(topdir)/conftypes.h
|
||||
help.o: ${srcdir}/common.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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
read.o: $(topdir)/arrayfunc.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
|
||||
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 $(topdir)/conftypes.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
|
||||
set.o: $(topdir)/arrayfunc.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
|
||||
setattr.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
|
||||
setattr.o: $(topdir)/arrayfunc.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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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)/test.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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
type.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
|
||||
type.o: $(topdir)/externs.h $(topdir)/hashcmd.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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
wait.o: $(BASHINCDIR)/chartypes.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
|
||||
|
||||
complete.o: ../config.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}/bashtypes.h ${topdir}/bashansi.h ${BASHINCDIR}/ansi_stdlib.h
|
||||
complete.o: ${topdir}/builtins.h
|
||||
complete.o: ${topdir}/pcomplete.h
|
||||
complete.o: ${srcdir}/common.h ${srcdir}/bashgetopt.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
|
||||
mkbuiltins.c: ${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
|
||||
@@ -1,152 +0,0 @@
|
||||
This file is caller.def, from which is created caller.c. It implements the
|
||||
builtin "caller" in Bash.
|
||||
|
||||
Copyright (C) 2002-2003 Rocky Bernstein for Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES caller.c
|
||||
|
||||
$BUILTIN caller
|
||||
$FUNCTION caller_builtin
|
||||
$DEPENDS_ON DEBUGGER
|
||||
$SHORT_DOC caller [EXPR]
|
||||
|
||||
Returns the context of the current subroutine call.
|
||||
|
||||
Without EXPR, returns returns "$line $filename". With EXPR,
|
||||
returns "$line $subroutine $filename"; this extra information
|
||||
can be used 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.
|
||||
$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;
|
||||
ARRAY_ELEMENT *ae;
|
||||
intmax_t num;
|
||||
|
||||
GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a);
|
||||
GET_ARRAY_FROM_VAR ("BASH_LINENO", bash_lineno_v, bash_lineno_a);
|
||||
|
||||
if (bash_lineno_a == 0 || array_empty (bash_lineno_a))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (bash_source_a == 0 || array_empty (bash_source_a))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend; /* skip over possible `--' */
|
||||
|
||||
/* If there is no argument list, then give short form: line filename. */
|
||||
if (list == 0)
|
||||
{
|
||||
lineno_s = array_reference (bash_lineno_a, 0);
|
||||
source_s = array_reference (bash_source_a, 1);
|
||||
printf("%s %s\n", lineno_s ? lineno_s : "NULL", source_s ? source_s : "NULL");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (funcname_a == 0 || array_empty (funcname_a))
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (legal_number (list->word->word, &num))
|
||||
{
|
||||
lineno_s = array_reference (bash_lineno_a, num);
|
||||
source_s = array_reference (bash_source_a, num+1);
|
||||
funcname_s = array_reference (funcname_a, num+1);
|
||||
|
||||
if (lineno_s == NULL|| source_s == NULL || funcname_s == NULL)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
printf("%s %s %s\n", lineno_s, funcname_s, source_s);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
static char *caller_doc[] = {
|
||||
N_("Returns the context of the current subroutine call."),
|
||||
N_(""),
|
||||
N_("Without EXPR, returns returns \"$line $filename\". With EXPR,"),
|
||||
N_("returns \"$line $subroutine $filename\"; this extra information"),
|
||||
N_("can be used used to 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 */
|
||||
@@ -1,521 +0,0 @@
|
||||
This file is cd.def, from which is created cd.c. It implements the
|
||||
builtins "cd" and "pwd" in Bash.
|
||||
|
||||
Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$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"
|
||||
#ifndef _MINIX
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int array_needs_making;
|
||||
extern char *bash_getcwd_errstr;
|
||||
|
||||
static int bindpwd __P((int));
|
||||
static void setpwd __P((char *));
|
||||
static int change_to_directory __P((char *, int));
|
||||
|
||||
static char *cdspell __P((char *));
|
||||
|
||||
/* Change this to 1 to get cd spelling correction by default. */
|
||||
int cdspelling = 0;
|
||||
|
||||
int cdable_vars;
|
||||
|
||||
$BUILTIN cd
|
||||
$FUNCTION cd_builtin
|
||||
$SHORT_DOC cd [-L|-P] [dir]
|
||||
Change the current directory to DIR. The variable $HOME is the
|
||||
default DIR. The variable CDPATH defines the search path for
|
||||
the directory containing DIR. Alternative directory names in CDPATH
|
||||
are separated by a colon (:). A null directory name is the same as
|
||||
the current directory, i.e. `.'. If DIR begins with a slash (/),
|
||||
then CDPATH is not used. If the directory is not found, and the
|
||||
shell option `cdable_vars' is set, then try the word as a variable
|
||||
name. If that variable has a value, then cd to the value of that
|
||||
variable. The -P option says to use the physical directory structure
|
||||
instead of following symbolic links; the -L option forces symbolic links
|
||||
to be followed.
|
||||
$END
|
||||
|
||||
/* Just set $PWD, don't change OLDPWD. Used by `pwd -P' in posix mode. */
|
||||
static void
|
||||
setpwd (dirname)
|
||||
char *dirname;
|
||||
{
|
||||
int old_anm;
|
||||
SHELL_VAR *tvar;
|
||||
|
||||
old_anm = array_needs_making;
|
||||
tvar = bind_variable ("PWD", dirname ? dirname : "", 0);
|
||||
if (old_anm == 0 && array_needs_making && exported_p (tvar))
|
||||
{
|
||||
update_export_env_inplace ("PWD=", 4, dirname ? dirname : "");
|
||||
array_needs_making = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
bindpwd (no_symlinks)
|
||||
int no_symlinks;
|
||||
{
|
||||
char *dirname, *pwdvar;
|
||||
int old_anm;
|
||||
SHELL_VAR *tvar;
|
||||
|
||||
#define tcwd the_current_working_directory
|
||||
dirname = tcwd ? (no_symlinks ? sh_physpath (tcwd, 0) : tcwd)
|
||||
: get_working_directory ("cd");
|
||||
#undef tcwd
|
||||
|
||||
old_anm = array_needs_making;
|
||||
pwdvar = get_string_value ("PWD");
|
||||
|
||||
tvar = bind_variable ("OLDPWD", pwdvar, 0);
|
||||
if (old_anm == 0 && array_needs_making && exported_p (tvar))
|
||||
{
|
||||
update_export_env_inplace ("OLDPWD=", 7, pwdvar);
|
||||
array_needs_making = 0;
|
||||
}
|
||||
|
||||
setpwd (dirname);
|
||||
|
||||
if (dirname && dirname != the_current_working_directory)
|
||||
free (dirname);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Call get_working_directory to reset the value of
|
||||
the_current_working_directory () */
|
||||
static char *
|
||||
resetpwd (caller)
|
||||
char *caller;
|
||||
{
|
||||
char *tdir;
|
||||
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
tdir = get_working_directory (caller);
|
||||
return (tdir);
|
||||
}
|
||||
|
||||
#define LCD_DOVARS 0x001
|
||||
#define LCD_DOSPELL 0x002
|
||||
#define LCD_PRINTPATH 0x004
|
||||
#define LCD_FREEDIRNAME 0x010
|
||||
|
||||
/* This builtin is ultimately the way that all user-visible commands should
|
||||
change the current working directory. It is called by cd_to_string (),
|
||||
so the programming interface is simple, and it handles errors and
|
||||
restrictions properly. */
|
||||
int
|
||||
cd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *dirname, *cdpath, *path, *temp;
|
||||
int path_index, no_symlinks, opt, lflag;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
no_symlinks = no_symbolic_links;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "LP")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'P':
|
||||
no_symlinks = 1;
|
||||
break;
|
||||
case 'L':
|
||||
no_symlinks = 0;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
lflag = (cdable_vars ? LCD_DOVARS : 0) |
|
||||
((interactive && cdspelling) ? LCD_DOSPELL : 0);
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
/* `cd' without arguments is equivalent to `cd $HOME' */
|
||||
dirname = get_string_value ("HOME");
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
builtin_error (_("HOME not set"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
lflag = 0;
|
||||
}
|
||||
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
|
||||
{
|
||||
/* This is `cd -', equivalent to `cd $OLDPWD' */
|
||||
dirname = get_string_value ("OLDPWD");
|
||||
|
||||
if (dirname == 0)
|
||||
{
|
||||
builtin_error (_("OLDPWD not set"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#if 0
|
||||
lflag = interactive ? LCD_PRINTPATH : 0;
|
||||
#else
|
||||
lflag = LCD_PRINTPATH; /* According to SUSv3 */
|
||||
#endif
|
||||
}
|
||||
else if (absolute_pathname (list->word->word))
|
||||
dirname = list->word->word;
|
||||
else if (cdpath = get_string_value ("CDPATH"))
|
||||
{
|
||||
dirname = list->word->word;
|
||||
|
||||
/* Find directory in $CDPATH. */
|
||||
path_index = 0;
|
||||
while (path = extract_colon_unit (cdpath, &path_index))
|
||||
{
|
||||
/* OPT is 1 if the path element is non-empty */
|
||||
opt = path[0] != '\0';
|
||||
temp = sh_makepath (path, dirname, MP_DOTILDE);
|
||||
free (path);
|
||||
|
||||
if (change_to_directory (temp, no_symlinks))
|
||||
{
|
||||
/* POSIX.2 says that if a nonempty directory from CDPATH
|
||||
is used to find the directory to change to, the new
|
||||
directory name is echoed to stdout, whether or not
|
||||
the shell is interactive. */
|
||||
if (opt && (path = no_symlinks ? temp : the_current_working_directory))
|
||||
printf ("%s\n", path);
|
||||
|
||||
free (temp);
|
||||
#if 0
|
||||
/* Posix.2 says that after using CDPATH, the resultant
|
||||
value of $PWD will not contain `.' or `..'. */
|
||||
return (bindpwd (posixly_correct || no_symlinks));
|
||||
#else
|
||||
return (bindpwd (no_symlinks));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
free (temp);
|
||||
}
|
||||
|
||||
/* POSIX.2 says that if `.' does not appear in $CDPATH, we don't
|
||||
try the current directory, so we just punt now with an error
|
||||
message if POSIXLY_CORRECT is non-zero. The check for cdpath[0]
|
||||
is so we don't mistakenly treat a CDPATH value of "" as not
|
||||
specifying the current directory. */
|
||||
if (posixly_correct && cdpath[0])
|
||||
{
|
||||
builtin_error ("%s: %s", dirname, strerror (ENOENT));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
dirname = list->word->word;
|
||||
|
||||
/* When we get here, DIRNAME is the directory to change to. If we
|
||||
chdir successfully, just return. */
|
||||
if (change_to_directory (dirname, no_symlinks))
|
||||
{
|
||||
if (lflag & LCD_PRINTPATH)
|
||||
printf ("%s\n", dirname);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
|
||||
/* If the user requests it, then perhaps this is the name of
|
||||
a shell variable, whose value contains the directory to
|
||||
change to. */
|
||||
if (lflag & LCD_DOVARS)
|
||||
{
|
||||
temp = get_string_value (dirname);
|
||||
if (temp && change_to_directory (temp, no_symlinks))
|
||||
{
|
||||
printf ("%s\n", temp);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
}
|
||||
|
||||
/* If the user requests it, try to find a directory name similar in
|
||||
spelling to the one requested, in case the user made a simple
|
||||
typo. This is similar to the UNIX 8th and 9th Edition shells. */
|
||||
if (lflag & LCD_DOSPELL)
|
||||
{
|
||||
temp = cdspell (dirname);
|
||||
if (temp && change_to_directory (temp, no_symlinks))
|
||||
{
|
||||
printf ("%s\n", temp);
|
||||
return (bindpwd (no_symlinks));
|
||||
}
|
||||
else
|
||||
FREE (temp);
|
||||
}
|
||||
|
||||
builtin_error ("%s: %s", dirname, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
$BUILTIN pwd
|
||||
$FUNCTION pwd_builtin
|
||||
$SHORT_DOC pwd [-LP]
|
||||
Print the current working directory. With the -P option, pwd prints
|
||||
the physical directory, without any symbolic links; the -L option
|
||||
makes pwd follow symbolic links.
|
||||
$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;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
#define tcwd the_current_working_directory
|
||||
|
||||
directory = tcwd ? (verbatim_pwd ? sh_physpath (tcwd, 0) : tcwd)
|
||||
: get_working_directory ("pwd");
|
||||
|
||||
/* Try again using getcwd() if canonicalization fails (for instance, if
|
||||
the file system has changed state underneath bash). */
|
||||
if ((tcwd && directory == 0) ||
|
||||
(posixly_correct && same_file (".", tcwd, (struct stat *)0, (struct stat *)0) == 0))
|
||||
directory = resetpwd ("pwd");
|
||||
|
||||
#undef tcwd
|
||||
|
||||
if (directory)
|
||||
{
|
||||
printf ("%s\n", directory);
|
||||
/* This is dumb but posix-mandated. */
|
||||
if (posixly_correct && pflag)
|
||||
setpwd (directory);
|
||||
if (directory != the_current_working_directory)
|
||||
free (directory);
|
||||
fflush (stdout);
|
||||
if (ferror (stdout))
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Do the work of changing to the directory NEWDIR. Handle symbolic
|
||||
link following, etc. This function *must* return with
|
||||
the_current_working_directory either set to NULL (in which case
|
||||
getcwd() will eventually be called), or set to a string corresponding
|
||||
to the working directory. Return 1 on success, 0 on failure. */
|
||||
|
||||
static int
|
||||
change_to_directory (newdir, nolinks)
|
||||
char *newdir;
|
||||
int nolinks;
|
||||
{
|
||||
char *t, *tdir;
|
||||
int err, canon_failed, r, ndlen, dlen;
|
||||
|
||||
tdir = (char *)NULL;
|
||||
|
||||
if (the_current_working_directory == 0)
|
||||
{
|
||||
t = get_working_directory ("chdir");
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
t = make_absolute (newdir, the_current_working_directory);
|
||||
|
||||
/* TDIR is either the canonicalized absolute pathname of NEWDIR
|
||||
(nolinks == 0) or the absolute physical pathname of NEWDIR
|
||||
(nolinks != 0). */
|
||||
tdir = nolinks ? sh_physpath (t, 0)
|
||||
: sh_canonpath (t, PATH_CHECKDOTDOT|PATH_CHECKEXISTS);
|
||||
|
||||
ndlen = strlen (newdir);
|
||||
dlen = strlen (t);
|
||||
|
||||
/* Use the canonicalized version of NEWDIR, or, if canonicalization
|
||||
failed, use the non-canonical form. */
|
||||
canon_failed = 0;
|
||||
if (tdir && *tdir)
|
||||
free (t);
|
||||
else
|
||||
{
|
||||
FREE (tdir);
|
||||
tdir = t;
|
||||
canon_failed = 1;
|
||||
}
|
||||
|
||||
/* In POSIX mode, if we're resolving symlinks logically and sh_canonpath
|
||||
returns NULL (because it checks the path, it will return NULL if the
|
||||
resolved path doesn't exist), fail immediately. */
|
||||
if (posixly_correct && nolinks == 0 && canon_failed && (errno != ENAMETOOLONG || ndlen > PATH_MAX))
|
||||
{
|
||||
#if defined ENAMETOOLONG
|
||||
if (errno != ENOENT && errno != ENAMETOOLONG)
|
||||
#else
|
||||
if (errno != ENOENT)
|
||||
#endif
|
||||
errno = ENOTDIR;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* If the chdir succeeds, update the_current_working_directory. */
|
||||
if (chdir (nolinks ? newdir : tdir) == 0)
|
||||
{
|
||||
/* If canonicalization failed, but the chdir succeeded, reset the
|
||||
shell's idea of the_current_working_directory. */
|
||||
if (canon_failed)
|
||||
{
|
||||
t = resetpwd ("cd");
|
||||
if (t == 0)
|
||||
set_working_directory (tdir);
|
||||
}
|
||||
else
|
||||
set_working_directory (tdir);
|
||||
|
||||
free (tdir);
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* We failed to change to the appropriate directory name. If we tried
|
||||
what the user passed (nolinks != 0), punt now. */
|
||||
if (nolinks)
|
||||
return (0);
|
||||
|
||||
err = errno;
|
||||
|
||||
/* We're not in physical mode (nolinks == 0), but we failed to change to
|
||||
the canonicalized directory name (TDIR). Try what the user passed
|
||||
verbatim. If we succeed, reinitialize the_current_working_directory. */
|
||||
if (chdir (newdir) == 0)
|
||||
{
|
||||
t = resetpwd ("cd");
|
||||
if (t == 0)
|
||||
set_working_directory (tdir);
|
||||
else
|
||||
free (t);
|
||||
|
||||
r = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
errno = err;
|
||||
r = 0;
|
||||
}
|
||||
|
||||
free (tdir);
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Code for cd spelling correction. Original patch submitted by
|
||||
Neil Russel (caret@c-side.com). */
|
||||
|
||||
static char *
|
||||
cdspell (dirname)
|
||||
char *dirname;
|
||||
{
|
||||
int n;
|
||||
char *guess;
|
||||
|
||||
n = (strlen (dirname) * 3 + 1) / 2 + 1;
|
||||
guess = (char *)xmalloc (n);
|
||||
|
||||
switch (spname (dirname, guess))
|
||||
{
|
||||
case -1:
|
||||
default:
|
||||
free (guess);
|
||||
return (char *)NULL;
|
||||
case 0:
|
||||
case 1:
|
||||
return guess;
|
||||
}
|
||||
}
|
||||
@@ -1,207 +0,0 @@
|
||||
This file is command.def, from which is created command.c.
|
||||
It implements the builtin "command" in Bash.
|
||||
|
||||
Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES command.c
|
||||
|
||||
$BUILTIN command
|
||||
$FUNCTION command_builtin
|
||||
$SHORT_DOC command [-pVv] command [arg ...]
|
||||
Runs COMMAND with ARGS ignoring shell functions. If you have a shell
|
||||
function called `ls', and you wish to call the command `ls', you can
|
||||
say "command ls". If the -p option is given, a default value is used
|
||||
for PATH that is guaranteed to find all of the standard utilities. If
|
||||
the -V or -v option is given, a string is printed describing COMMAND.
|
||||
The -V option produces a more verbose description.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../flags.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if defined (_CS_PATH) && defined (HAVE_CONFSTR) && !HAVE_DECL_CONFSTR
|
||||
extern size_t confstr __P((int, char *, size_t));
|
||||
#endif
|
||||
|
||||
extern int subshell_environment;
|
||||
|
||||
static void restore_path __P((char *));
|
||||
static char *get_standard_path __P((void));
|
||||
|
||||
/* Run the commands mentioned in LIST without paying attention to shell
|
||||
functions. */
|
||||
int
|
||||
command_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, verbose, use_standard_path, opt;
|
||||
char *old_path, *standard_path;
|
||||
COMMAND *command;
|
||||
|
||||
verbose = use_standard_path = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "pvV")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
use_standard_path = 1;
|
||||
break;
|
||||
case 'V':
|
||||
verbose = CDESC_SHORTDESC|CDESC_ABSPATH; /* look in common.h for constants */
|
||||
break;
|
||||
case 'v':
|
||||
verbose = CDESC_REUSABLE; /* ditto */
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int found, any_found;
|
||||
|
||||
for (any_found = 0; list; list = list->next)
|
||||
{
|
||||
found = describe_command (list->word->word, verbose);
|
||||
|
||||
if (found == 0 && verbose != CDESC_REUSABLE)
|
||||
sh_notfound (list->word->word);
|
||||
|
||||
any_found += found;
|
||||
}
|
||||
return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (use_standard_path && restricted)
|
||||
{
|
||||
sh_restricted ("-p");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
begin_unwind_frame ("command_builtin");
|
||||
|
||||
/* We don't want this to be reparsed (consider command echo 'foo &'), so
|
||||
just make a simple_command structure and call execute_command with it. */
|
||||
if (use_standard_path)
|
||||
{
|
||||
old_path = get_string_value ("PATH");
|
||||
/* If old_path is NULL, $PATH is unset. If so, we want to make sure
|
||||
it's unset after this command completes. */
|
||||
if (old_path)
|
||||
old_path = savestring (old_path);
|
||||
add_unwind_protect ((Function *)restore_path, old_path);
|
||||
|
||||
standard_path = get_standard_path ();
|
||||
bind_variable ("PATH", standard_path ? standard_path : "", 0);
|
||||
FREE (standard_path);
|
||||
}
|
||||
|
||||
#define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN)
|
||||
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= COMMAND_BUILTIN_FLAGS;
|
||||
command->value.Simple->flags |= COMMAND_BUILTIN_FLAGS;
|
||||
#if 0
|
||||
/* This breaks for things like ( cd /tmp ; command z ababa ; echo next )
|
||||
or $(command echo a ; command echo b;) or even
|
||||
{ command echo a; command echo b; } & */
|
||||
/* If we're in a subshell, see if we can get away without forking
|
||||
again, since we've already forked to run this builtin. */
|
||||
if (subshell_environment)
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
#endif
|
||||
add_unwind_protect ((char *)dispose_command, command);
|
||||
result = execute_command (command);
|
||||
|
||||
run_unwind_frame ("command_builtin");
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Restore the value of the $PATH variable after replacing it when
|
||||
executing `command -p'. */
|
||||
static void
|
||||
restore_path (var)
|
||||
char *var;
|
||||
{
|
||||
if (var)
|
||||
{
|
||||
bind_variable ("PATH", var, 0);
|
||||
free (var);
|
||||
}
|
||||
else
|
||||
unbind_variable ("PATH");
|
||||
}
|
||||
|
||||
/* Return a value for PATH that is guaranteed to find all of the standard
|
||||
utilities. This uses Posix.2 configuration variables, if present. It
|
||||
uses a value defined in config.h as a last resort. */
|
||||
static char *
|
||||
get_standard_path ()
|
||||
{
|
||||
#if defined (_CS_PATH) && defined (HAVE_CONFSTR)
|
||||
char *p;
|
||||
size_t len;
|
||||
|
||||
len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
|
||||
if (len > 0)
|
||||
{
|
||||
p = (char *)xmalloc (len + 2);
|
||||
*p = '\0';
|
||||
confstr (_CS_PATH, p, len);
|
||||
return (p);
|
||||
}
|
||||
else
|
||||
return (savestring (STANDARD_UTILS_PATH));
|
||||
#else /* !_CS_PATH || !HAVE_CONFSTR */
|
||||
# if defined (CS_PATH)
|
||||
return (savestring (CS_PATH));
|
||||
# else
|
||||
return (savestring (STANDARD_UTILS_PATH));
|
||||
# endif /* !CS_PATH */
|
||||
#endif /* !_CS_PATH || !HAVE_CONFSTR */
|
||||
}
|
||||
@@ -1,811 +0,0 @@
|
||||
/* Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <chartypes.h>
|
||||
#include "../bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#include <signal.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (PREFER_STDARG)
|
||||
# include <stdarg.h>
|
||||
#else
|
||||
# include <varargs.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "maxpath.h"
|
||||
#include "../flags.h"
|
||||
#include "../jobs.h"
|
||||
#include "../builtins.h"
|
||||
#include "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../trap.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int indirection_level, subshell_environment;
|
||||
extern int line_number;
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap;
|
||||
extern int posixly_correct;
|
||||
extern char *this_command_name, *shell_name;
|
||||
extern char *bash_getcwd_errstr;
|
||||
|
||||
/* Used by some builtins and the mainline code. */
|
||||
sh_builtin_func_t *last_shell_builtin = (sh_builtin_func_t *)NULL;
|
||||
sh_builtin_func_t *this_shell_builtin = (sh_builtin_func_t *)NULL;
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Error reporting, usage, and option processing */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* This is a lot like report_error (), but it is for shell builtins
|
||||
instead of shell control structures, and it won't ever exit the
|
||||
shell. */
|
||||
void
|
||||
#if defined (PREFER_STDARG)
|
||||
builtin_error (const char *format, ...)
|
||||
#else
|
||||
builtin_error (format, va_alist)
|
||||
const char *format;
|
||||
va_dcl
|
||||
#endif
|
||||
{
|
||||
va_list args;
|
||||
char *name;
|
||||
|
||||
name = get_name_for_error ();
|
||||
fprintf (stderr, "%s: ", name);
|
||||
|
||||
if (interactive_shell == 0)
|
||||
fprintf (stderr, "line %d: ", executing_line_number ());
|
||||
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
SH_VA_START (args, format);
|
||||
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
|
||||
/* Print a usage summary for the currently-executing builtin command. */
|
||||
void
|
||||
builtin_usage ()
|
||||
{
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: usage: ", this_command_name);
|
||||
fprintf (stderr, "%s\n", current_builtin->short_doc);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
/* Return if LIST is NULL else barf and jump to top_level. Used by some
|
||||
builtins that do not accept arguments. */
|
||||
void
|
||||
no_args (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
builtin_error (_("too many arguments"));
|
||||
jump_to_top_level (DISCARD);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check that no options were given to the currently-executing builtin,
|
||||
and return 0 if there were options. */
|
||||
int
|
||||
no_options (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
reset_internal_getopt ();
|
||||
if (internal_getopt (list, "") != -1)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (1);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
void
|
||||
sh_needarg (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: option requires an argument"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_neednumarg (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: numeric argument required"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_notfound (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: not found"), s);
|
||||
}
|
||||
|
||||
/* Function called when one of the builtin commands detects an invalid
|
||||
option. */
|
||||
void
|
||||
sh_invalidopt (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: invalid option"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_invalidoptname (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: invalid option name"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_invalidid (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("`%s': not a valid identifier"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_invalidnum (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: invalid number"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_invalidsig (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: invalid signal specification"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_badpid (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("`%s': not a pid or valid job spec"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_readonly (s)
|
||||
const char *s;
|
||||
{
|
||||
builtin_error (_("%s: readonly variable"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_erange (s, desc)
|
||||
char *s, *desc;
|
||||
{
|
||||
if (s)
|
||||
builtin_error (_("%s: %s out of range"), s, desc ? desc : _("argument"));
|
||||
else
|
||||
builtin_error (_("%s out of range"), desc ? desc : _("argument"));
|
||||
}
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
void
|
||||
sh_badjob (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: no such job"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_nojobs (s)
|
||||
char *s;
|
||||
{
|
||||
if (s)
|
||||
builtin_error (_("%s: no job control"), s);
|
||||
else
|
||||
builtin_error (_("no job control"));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
void
|
||||
sh_restricted (s)
|
||||
char *s;
|
||||
{
|
||||
if (s)
|
||||
builtin_error (_("%s: restricted"), s);
|
||||
else
|
||||
builtin_error (_("restricted"));
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
sh_notbuiltin (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: not a shell builtin"), s);
|
||||
}
|
||||
|
||||
void
|
||||
sh_wrerror ()
|
||||
{
|
||||
builtin_error (_("write error: %s"), strerror (errno));
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Shell positional parameter manipulation */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Convert a WORD_LIST into a C-style argv. Return the number of elements
|
||||
in the list in *IP, if IP is non-null. A convenience function for
|
||||
loadable builtins; also used by `test'. */
|
||||
char **
|
||||
make_builtin_argv (list, ip)
|
||||
WORD_LIST *list;
|
||||
int *ip;
|
||||
{
|
||||
char **argv;
|
||||
|
||||
argv = strvec_from_word_list (list, 0, 1, ip);
|
||||
argv[0] = this_command_name;
|
||||
return argv;
|
||||
}
|
||||
|
||||
/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
|
||||
non-zero, then discard whatever the existing arguments are, else
|
||||
only discard the ones that are to be replaced. */
|
||||
void
|
||||
remember_args (list, destructive)
|
||||
WORD_LIST *list;
|
||||
int destructive;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 1; i < 10; i++)
|
||||
{
|
||||
if ((destructive || list) && dollar_vars[i])
|
||||
{
|
||||
free (dollar_vars[i]);
|
||||
dollar_vars[i] = (char *)NULL;
|
||||
}
|
||||
|
||||
if (list)
|
||||
{
|
||||
dollar_vars[i] = savestring (list->word->word);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* If arguments remain, assign them to REST_OF_ARGS.
|
||||
Note that copy_word_list (NULL) returns NULL, and
|
||||
that dispose_words (NULL) does nothing. */
|
||||
if (destructive || list)
|
||||
{
|
||||
dispose_words (rest_of_args);
|
||||
rest_of_args = copy_word_list (list);
|
||||
}
|
||||
|
||||
if (destructive)
|
||||
set_dollar_vars_changed ();
|
||||
}
|
||||
|
||||
static int changed_dollar_vars;
|
||||
|
||||
/* Have the dollar variables been reset to new values since we last
|
||||
checked? */
|
||||
int
|
||||
dollar_vars_changed ()
|
||||
{
|
||||
return (changed_dollar_vars);
|
||||
}
|
||||
|
||||
void
|
||||
set_dollar_vars_unchanged ()
|
||||
{
|
||||
changed_dollar_vars = 0;
|
||||
}
|
||||
|
||||
void
|
||||
set_dollar_vars_changed ()
|
||||
{
|
||||
if (variable_context)
|
||||
changed_dollar_vars |= ARGS_FUNC;
|
||||
else if (this_shell_builtin == set_builtin)
|
||||
changed_dollar_vars |= ARGS_SETBLTIN;
|
||||
else
|
||||
changed_dollar_vars |= ARGS_INVOC;
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Validating numeric input and arguments */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Read a numeric arg for this_command_name, the name of the shell builtin
|
||||
that wants it. LIST is the word list that the arg is to come from.
|
||||
Accept only the numeric argument; report an error if other arguments
|
||||
follow. If FATAL is true, call throw_to_top_level, which exits the
|
||||
shell; if not, call jump_to_top_level (DISCARD), which aborts the
|
||||
current command. */
|
||||
intmax_t
|
||||
get_numeric_arg (list, fatal)
|
||||
WORD_LIST *list;
|
||||
int fatal;
|
||||
{
|
||||
intmax_t count = 1;
|
||||
|
||||
if (list && list->word && ISOPTION (list->word->word, '-'))
|
||||
list = list->next;
|
||||
|
||||
if (list)
|
||||
{
|
||||
register char *arg;
|
||||
|
||||
arg = list->word->word;
|
||||
if (arg == 0 || (legal_number (arg, &count) == 0))
|
||||
{
|
||||
sh_neednumarg (list->word->word);
|
||||
if (fatal)
|
||||
throw_to_top_level ();
|
||||
else
|
||||
jump_to_top_level (DISCARD);
|
||||
}
|
||||
no_args (list->next);
|
||||
}
|
||||
|
||||
return (count);
|
||||
}
|
||||
|
||||
/* Get an eight-bit status value from LIST */
|
||||
int
|
||||
get_exitstat (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int status;
|
||||
intmax_t sval;
|
||||
char *arg;
|
||||
|
||||
if (list && list->word && ISOPTION (list->word->word, '-'))
|
||||
list = list->next;
|
||||
|
||||
if (list == 0)
|
||||
return (last_command_exit_value);
|
||||
|
||||
arg = list->word->word;
|
||||
if (arg == 0 || legal_number (arg, &sval) == 0)
|
||||
{
|
||||
sh_neednumarg (list->word->word ? list->word->word : "`'");
|
||||
return 255;
|
||||
}
|
||||
no_args (list->next);
|
||||
|
||||
status = sval & 255;
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Return the octal number parsed from STRING, or -1 to indicate
|
||||
that the string contained a bad number. */
|
||||
int
|
||||
read_octal (string)
|
||||
char *string;
|
||||
{
|
||||
int result, digits;
|
||||
|
||||
result = digits = 0;
|
||||
while (*string && ISOCTAL (*string))
|
||||
{
|
||||
digits++;
|
||||
result = (result * 8) + (*string++ - '0');
|
||||
if (result > 0777)
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (digits == 0 || *string)
|
||||
result = -1;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Manipulating the current working directory */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Return a consed string which is the current working directory.
|
||||
FOR_WHOM is the name of the caller for error printing. */
|
||||
char *the_current_working_directory = (char *)NULL;
|
||||
|
||||
char *
|
||||
get_working_directory (for_whom)
|
||||
char *for_whom;
|
||||
{
|
||||
char *directory;
|
||||
size_t dsize;
|
||||
|
||||
if (no_symbolic_links)
|
||||
{
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
}
|
||||
|
||||
if (the_current_working_directory == 0)
|
||||
{
|
||||
the_current_working_directory = getcwd (0, 0);
|
||||
if (the_current_working_directory == 0)
|
||||
{
|
||||
fprintf (stderr, _("%s: error retrieving current directory: %s: %s\n"),
|
||||
(for_whom && *for_whom) ? for_whom : get_name_for_error (),
|
||||
_(bash_getcwd_errstr), strerror (errno));
|
||||
return (char *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (savestring (the_current_working_directory));
|
||||
}
|
||||
|
||||
/* Make NAME our internal idea of the current working directory. */
|
||||
void
|
||||
set_working_directory (name)
|
||||
char *name;
|
||||
{
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = savestring (name);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Job control support functions */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
int
|
||||
get_job_by_name (name, flags)
|
||||
const char *name;
|
||||
int flags;
|
||||
{
|
||||
register int i, wl, cl, match, job;
|
||||
register PROCESS *p;
|
||||
register JOB *j;
|
||||
|
||||
job = NO_JOB;
|
||||
wl = strlen (name);
|
||||
for (i = js.j_jobslots - 1; i >= 0; i--)
|
||||
{
|
||||
j = get_job_by_jid (i);
|
||||
if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
|
||||
continue;
|
||||
|
||||
p = j->pipe;
|
||||
do
|
||||
{
|
||||
if (flags & JM_EXACT)
|
||||
{
|
||||
cl = strlen (p->command);
|
||||
match = STREQN (p->command, name, cl);
|
||||
}
|
||||
else if (flags & JM_SUBSTRING)
|
||||
match = strindex (p->command, name) != (char *)0;
|
||||
else
|
||||
match = STREQN (p->command, name, wl);
|
||||
|
||||
if (match == 0)
|
||||
{
|
||||
p = p->next;
|
||||
continue;
|
||||
}
|
||||
else if (flags & JM_FIRSTMATCH)
|
||||
return i; /* return first match */
|
||||
else if (job != NO_JOB)
|
||||
{
|
||||
if (this_shell_builtin)
|
||||
builtin_error (_("%s: ambiguous job spec"), name);
|
||||
else
|
||||
report_error (_("%s: ambiguous job spec"), name);
|
||||
return (DUP_JOB);
|
||||
}
|
||||
else
|
||||
job = i;
|
||||
}
|
||||
while (p != j->pipe);
|
||||
}
|
||||
|
||||
return (job);
|
||||
}
|
||||
|
||||
/* Return the job spec found in LIST. */
|
||||
int
|
||||
get_job_spec (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char *word;
|
||||
int job, jflags;
|
||||
|
||||
if (list == 0)
|
||||
return (js.j_current);
|
||||
|
||||
word = list->word->word;
|
||||
|
||||
if (*word == '\0')
|
||||
return (NO_JOB);
|
||||
|
||||
if (*word == '%')
|
||||
word++;
|
||||
|
||||
if (DIGIT (*word) && all_digits (word))
|
||||
{
|
||||
job = atoi (word);
|
||||
return (job > js.j_jobslots ? NO_JOB : job - 1);
|
||||
}
|
||||
|
||||
jflags = 0;
|
||||
switch (*word)
|
||||
{
|
||||
case 0:
|
||||
case '%':
|
||||
case '+':
|
||||
return (js.j_current);
|
||||
|
||||
case '-':
|
||||
return (js.j_previous);
|
||||
|
||||
case '?': /* Substring search requested. */
|
||||
jflags |= JM_SUBSTRING;
|
||||
word++;
|
||||
/* FALLTHROUGH */
|
||||
|
||||
default:
|
||||
return get_job_by_name (word, jflags);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/*
|
||||
* NOTE: `kill' calls this function with forcecols == 0
|
||||
*/
|
||||
int
|
||||
display_signal_list (list, forcecols)
|
||||
WORD_LIST *list;
|
||||
int forcecols;
|
||||
{
|
||||
register int i, column;
|
||||
char *name;
|
||||
int result, signum, dflags;
|
||||
intmax_t lsignum;
|
||||
|
||||
result = EXECUTION_SUCCESS;
|
||||
if (!list)
|
||||
{
|
||||
for (i = 1, column = 0; i < NSIG; i++)
|
||||
{
|
||||
name = signal_name (i);
|
||||
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
|
||||
continue;
|
||||
|
||||
if (posixly_correct && !forcecols)
|
||||
{
|
||||
/* This is for the kill builtin. POSIX.2 says the signal names
|
||||
are displayed without the `SIG' prefix. */
|
||||
if (STREQN (name, "SIG", 3))
|
||||
name += 3;
|
||||
printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf ("%2d) %s", i, name);
|
||||
|
||||
if (++column < 4)
|
||||
printf ("\t");
|
||||
else
|
||||
{
|
||||
printf ("\n");
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((posixly_correct && !forcecols) || column != 0)
|
||||
printf ("\n");
|
||||
return result;
|
||||
}
|
||||
|
||||
/* List individual signal names or numbers. */
|
||||
while (list)
|
||||
{
|
||||
if (legal_number (list->word->word, &lsignum))
|
||||
{
|
||||
/* This is specified by Posix.2 so that exit statuses can be
|
||||
mapped into signal numbers. */
|
||||
if (lsignum > 128)
|
||||
lsignum -= 128;
|
||||
if (lsignum < 0 || lsignum >= NSIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
signum = lsignum;
|
||||
name = signal_name (signum);
|
||||
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
|
||||
{
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
#if defined (JOB_CONTROL)
|
||||
/* POSIX.2 says that `kill -l signum' prints the signal name without
|
||||
the `SIG' prefix. */
|
||||
printf ("%s\n", (this_shell_builtin == kill_builtin) ? name + 3 : name);
|
||||
#else
|
||||
printf ("%s\n", name);
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
dflags = DSIG_NOCASE;
|
||||
if (posixly_correct == 0 || this_shell_builtin != kill_builtin)
|
||||
dflags |= DSIG_SIGPREFIX;
|
||||
signum = decode_signal (list->word->word, dflags);
|
||||
if (signum == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
printf ("%d\n", signum);
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Finding builtin commands and their functions */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Perform a binary search and return the address of the builtin function
|
||||
whose name is NAME. If the function couldn't be found, or the builtin
|
||||
is disabled or has no function associated with it, return NULL.
|
||||
Return the address of the builtin.
|
||||
DISABLED_OKAY means find it even if the builtin is disabled. */
|
||||
struct builtin *
|
||||
builtin_address_internal (name, disabled_okay)
|
||||
char *name;
|
||||
int disabled_okay;
|
||||
{
|
||||
int hi, lo, mid, j;
|
||||
|
||||
hi = num_shell_builtins - 1;
|
||||
lo = 0;
|
||||
|
||||
while (lo <= hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
|
||||
j = shell_builtins[mid].name[0] - name[0];
|
||||
|
||||
if (j == 0)
|
||||
j = strcmp (shell_builtins[mid].name, name);
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
/* It must have a function pointer. It must be enabled, or we
|
||||
must have explicitly allowed disabled functions to be found,
|
||||
and it must not have been deleted. */
|
||||
if (shell_builtins[mid].function &&
|
||||
((shell_builtins[mid].flags & BUILTIN_DELETED) == 0) &&
|
||||
((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
|
||||
return (&shell_builtins[mid]);
|
||||
else
|
||||
return ((struct builtin *)NULL);
|
||||
}
|
||||
if (j > 0)
|
||||
hi = mid - 1;
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
return ((struct builtin *)NULL);
|
||||
}
|
||||
|
||||
/* Return the pointer to the function implementing builtin command NAME. */
|
||||
sh_builtin_func_t *
|
||||
find_shell_builtin (name)
|
||||
char *name;
|
||||
{
|
||||
current_builtin = builtin_address_internal (name, 0);
|
||||
return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
|
||||
}
|
||||
|
||||
/* Return the address of builtin with NAME, whether it is enabled or not. */
|
||||
sh_builtin_func_t *
|
||||
builtin_address (name)
|
||||
char *name;
|
||||
{
|
||||
current_builtin = builtin_address_internal (name, 1);
|
||||
return (current_builtin ? current_builtin->function : (sh_builtin_func_t *)NULL);
|
||||
}
|
||||
|
||||
/* Return the function implementing the builtin NAME, but only if it is a
|
||||
POSIX.2 special builtin. */
|
||||
sh_builtin_func_t *
|
||||
find_special_builtin (name)
|
||||
char *name;
|
||||
{
|
||||
current_builtin = builtin_address_internal (name, 0);
|
||||
return ((current_builtin && (current_builtin->flags & SPECIAL_BUILTIN)) ?
|
||||
current_builtin->function :
|
||||
(sh_builtin_func_t *)NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
shell_builtin_compare (sbp1, sbp2)
|
||||
struct builtin *sbp1, *sbp2;
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
|
||||
result = strcmp (sbp1->name, sbp2->name);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Sort the table of shell builtins so that the binary search will work
|
||||
in find_shell_builtin. */
|
||||
void
|
||||
initialize_shell_builtins ()
|
||||
{
|
||||
qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
|
||||
(QSFUNC *)shell_builtin_compare);
|
||||
}
|
||||
@@ -1,162 +0,0 @@
|
||||
/* common.h -- extern declarations for functions defined in common.c. */
|
||||
|
||||
/* Copyright (C) 1993-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#if !defined (__COMMON_H)
|
||||
# define __COMMON_H
|
||||
|
||||
#include "stdc.h"
|
||||
|
||||
#define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c)
|
||||
|
||||
/* Flag values for parse_and_execute () */
|
||||
#define SEVAL_NONINT 0x001
|
||||
#define SEVAL_INTERACT 0x002
|
||||
#define SEVAL_NOHIST 0x004
|
||||
#define SEVAL_NOFREE 0x008
|
||||
#define SEVAL_RESETLINE 0x010
|
||||
|
||||
/* Flags for describe_command, shared between type.def and command.def */
|
||||
#define CDESC_ALL 0x001 /* type -a */
|
||||
#define CDESC_SHORTDESC 0x002 /* command -V */
|
||||
#define CDESC_REUSABLE 0x004 /* command -v */
|
||||
#define CDESC_TYPE 0x008 /* type -t */
|
||||
#define CDESC_PATH_ONLY 0x010 /* type -p */
|
||||
#define CDESC_FORCE_PATH 0x020 /* type -ap or type -P */
|
||||
#define CDESC_NOFUNCS 0x040 /* type -f */
|
||||
#define CDESC_ABSPATH 0x080 /* convert to absolute path, no ./ */
|
||||
|
||||
/* Flags for get_job_by_name */
|
||||
#define JM_PREFIX 0x01 /* prefix of job name */
|
||||
#define JM_SUBSTRING 0x02 /* substring of job name */
|
||||
#define JM_EXACT 0x04 /* match job name exactly */
|
||||
#define JM_STOPPED 0x08 /* match stopped jobs only */
|
||||
#define JM_FIRSTMATCH 0x10 /* return first matching job */
|
||||
|
||||
/* Flags for remember_args and value of changed_dollar_vars */
|
||||
#define ARGS_NONE 0x0
|
||||
#define ARGS_INVOC 0x01
|
||||
#define ARGS_FUNC 0x02
|
||||
#define ARGS_SETBLTIN 0x04
|
||||
|
||||
/* Functions from common.c */
|
||||
extern void builtin_error __P((const char *, ...)) __attribute__((__format__ (printf, 1, 2)));
|
||||
extern void builtin_usage __P((void));
|
||||
extern void no_args __P((WORD_LIST *));
|
||||
extern int no_options __P((WORD_LIST *));
|
||||
|
||||
/* common error message functions */
|
||||
extern void sh_needarg __P((char *));
|
||||
extern void sh_neednumarg __P((char *));
|
||||
extern void sh_notfound __P((char *));
|
||||
extern void sh_invalidopt __P((char *));
|
||||
extern void sh_invalidoptname __P((char *));
|
||||
extern void sh_invalidid __P((char *));
|
||||
extern void sh_invalidnum __P((char *));
|
||||
extern void sh_invalidsig __P((char *));
|
||||
extern void sh_erange __P((char *, char *));
|
||||
extern void sh_badpid __P((char *));
|
||||
extern void sh_badjob __P((char *));
|
||||
extern void sh_readonly __P((const char *));
|
||||
extern void sh_nojobs __P((char *));
|
||||
extern void sh_restricted __P((char *));
|
||||
extern void sh_notbuiltin __P((char *));
|
||||
|
||||
extern char **make_builtin_argv __P((WORD_LIST *, int *));
|
||||
extern void remember_args __P((WORD_LIST *, int));
|
||||
|
||||
extern int dollar_vars_changed __P((void));
|
||||
extern void set_dollar_vars_unchanged __P((void));
|
||||
extern void set_dollar_vars_changed __P((void));
|
||||
|
||||
extern intmax_t get_numeric_arg __P((WORD_LIST *, int));
|
||||
extern int get_exitstat __P((WORD_LIST *));
|
||||
extern int read_octal __P((char *));
|
||||
|
||||
/* Keeps track of the current working directory. */
|
||||
extern char *the_current_working_directory;
|
||||
extern char *get_working_directory __P((char *));
|
||||
extern void set_working_directory __P((char *));
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int get_job_by_name __P((const char *, int));
|
||||
extern int get_job_spec __P((WORD_LIST *));
|
||||
#endif
|
||||
extern int display_signal_list __P((WORD_LIST *, int));
|
||||
|
||||
/* It's OK to declare a function as returning a Function * without
|
||||
providing a definition of what a `Function' is. */
|
||||
extern struct builtin *builtin_address_internal __P((char *, int));
|
||||
extern sh_builtin_func_t *find_shell_builtin __P((char *));
|
||||
extern sh_builtin_func_t *builtin_address __P((char *));
|
||||
extern sh_builtin_func_t *find_special_builtin __P((char *));
|
||||
extern void initialize_shell_builtins __P((void));
|
||||
|
||||
/* Functions from exit.def */
|
||||
extern void bash_logout __P((void));
|
||||
|
||||
/* Functions from getopts.def */
|
||||
extern void getopts_reset __P((int));
|
||||
|
||||
/* Functions from set.def */
|
||||
extern int minus_o_option_value __P((char *));
|
||||
extern void list_minus_o_opts __P((int, int));
|
||||
extern char **get_minus_o_opts __P((void));
|
||||
extern int set_minus_o_option __P((int, char *));
|
||||
|
||||
extern void set_shellopts __P((void));
|
||||
extern void parse_shellopts __P((char *));
|
||||
extern void initialize_shell_options __P((int));
|
||||
|
||||
extern void reset_shell_options __P((void));
|
||||
|
||||
/* Functions from shopt.def */
|
||||
extern void reset_shopt_options __P((void));
|
||||
extern char **get_shopt_options __P((void));
|
||||
|
||||
extern int shopt_setopt __P((char *, int));
|
||||
extern int shopt_listopt __P((char *, int));
|
||||
|
||||
extern int set_login_shell __P((int));
|
||||
|
||||
/* Functions from type.def */
|
||||
extern int describe_command __P((char *, int));
|
||||
|
||||
/* Functions from setattr.def */
|
||||
extern int set_or_show_attributes __P((WORD_LIST *, int, int));
|
||||
extern int show_var_attributes __P((SHELL_VAR *, int, int));
|
||||
extern int show_name_attributes __P((char *, int));
|
||||
extern void set_var_attribute __P((char *, int, int));
|
||||
|
||||
/* Functions from pushd.def */
|
||||
extern char *get_dirstack_from_string __P((char *));
|
||||
extern char *get_dirstack_element __P((intmax_t, int));
|
||||
extern void set_dirstack_element __P((intmax_t, int, char *));
|
||||
extern WORD_LIST *get_directory_stack __P((void));
|
||||
|
||||
/* Functions from evalstring.c */
|
||||
extern int parse_and_execute __P((char *, const char *, int));
|
||||
extern void parse_and_execute_cleanup __P((void));
|
||||
|
||||
/* Functions from evalfile.c */
|
||||
extern int maybe_execute_file __P((const char *, int));
|
||||
extern int source_file __P((const char *, int));
|
||||
extern int fc_execute_file __P((const char *));
|
||||
|
||||
#endif /* !__COMMON_H */
|
||||
@@ -1,470 +0,0 @@
|
||||
This file is declare.def, from which is created declare.c.
|
||||
It implements the builtins "declare" and "local" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES declare.c
|
||||
|
||||
$BUILTIN declare
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC declare [-afFirtx] [-p] [name[=value] ...]
|
||||
Declare variables and/or give them attributes. If no NAMEs are
|
||||
given, then display the values of variables instead. The -p option
|
||||
will display the attributes and values of each NAME.
|
||||
|
||||
The flags are:
|
||||
|
||||
-a to make NAMEs arrays (if supported)
|
||||
-f to select from among function names only
|
||||
-F to display function names (and line number and source file name if
|
||||
debugging) without definitions
|
||||
-i to make NAMEs have the `integer' attribute
|
||||
-r to make NAMEs readonly
|
||||
-t to make NAMEs have the `trace' attribute
|
||||
-x to make NAMEs export
|
||||
|
||||
Variables with the integer attribute have arithmetic evaluation (see
|
||||
`let') done when the variable is assigned to.
|
||||
|
||||
When displaying values of variables, -f displays a function's name
|
||||
and definition. The -F option restricts the display to function
|
||||
name only.
|
||||
|
||||
Using `+' instead of `-' turns off the given attribute instead. When
|
||||
used in a function, makes NAMEs local, as with the `local' command.
|
||||
$END
|
||||
|
||||
$BUILTIN typeset
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC typeset [-afFirtx] [-p] name[=value] ...
|
||||
Obsolete. See `declare'.
|
||||
$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 "common.h"
|
||||
#include "builtext.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int array_needs_making;
|
||||
|
||||
static int declare_internal __P((register WORD_LIST *, int));
|
||||
|
||||
/* Declare or change variable attributes. */
|
||||
int
|
||||
declare_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (declare_internal (list, 0));
|
||||
}
|
||||
|
||||
$BUILTIN local
|
||||
$FUNCTION local_builtin
|
||||
$SHORT_DOC local name[=value] ...
|
||||
Create a local variable called NAME, and give it VALUE. LOCAL
|
||||
can only be used within a function; it makes the variable NAME
|
||||
have a visible scope restricted to that function and its children.
|
||||
$END
|
||||
int
|
||||
local_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
if (variable_context)
|
||||
return (declare_internal (list, 1));
|
||||
else
|
||||
{
|
||||
builtin_error (_("can only be used in a function"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define DECLARE_OPTS "+afiprtxF"
|
||||
#else
|
||||
# define DECLARE_OPTS "+fiprtxF"
|
||||
#endif
|
||||
|
||||
/* The workhorse function. */
|
||||
static int
|
||||
declare_internal (list, local_var)
|
||||
register WORD_LIST *list;
|
||||
int local_var;
|
||||
{
|
||||
int flags_on, flags_off, *flags, any_failed, assign_error, pflag, nodefs, opt;
|
||||
char *t, *subscript_start;
|
||||
SHELL_VAR *var;
|
||||
FUNCTION_DEF *shell_fn;
|
||||
|
||||
flags_on = flags_off = any_failed = assign_error = pflag = nodefs = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, DECLARE_OPTS)) != EOF)
|
||||
{
|
||||
flags = list_opttype == '+' ? &flags_off : &flags_on;
|
||||
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
#if defined (ARRAY_VARS)
|
||||
*flags |= att_array;
|
||||
#endif
|
||||
break;
|
||||
case 'p':
|
||||
if (local_var == 0)
|
||||
pflag++;
|
||||
break;
|
||||
case 'F':
|
||||
nodefs++;
|
||||
*flags |= att_function;
|
||||
break;
|
||||
case 'f':
|
||||
*flags |= att_function;
|
||||
break;
|
||||
case 'i':
|
||||
*flags |= att_integer;
|
||||
break;
|
||||
case 'r':
|
||||
*flags |= att_readonly;
|
||||
break;
|
||||
case 't':
|
||||
*flags |= att_trace;
|
||||
break;
|
||||
case 'x':
|
||||
*flags |= att_exported;
|
||||
array_needs_making = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
/* If there are no more arguments left, then we just want to show
|
||||
some variables. */
|
||||
if (list == 0) /* declare -[afFirtx] */
|
||||
{
|
||||
/* Show local variables defined at this context level if this is
|
||||
the `local' builtin. */
|
||||
if (local_var)
|
||||
{
|
||||
register SHELL_VAR **vlist;
|
||||
register int i;
|
||||
|
||||
vlist = all_local_variables ();
|
||||
|
||||
if (vlist)
|
||||
{
|
||||
for (i = 0; vlist[i]; i++)
|
||||
print_assignment (vlist[i]);
|
||||
|
||||
free (vlist);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (flags_on == 0)
|
||||
set_builtin ((WORD_LIST *)NULL);
|
||||
else
|
||||
set_or_show_attributes ((WORD_LIST *)NULL, flags_on, nodefs);
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (pflag) /* declare -p [-afFirtx] name [name...] */
|
||||
{
|
||||
for (any_failed = 0; list; list = list->next)
|
||||
{
|
||||
pflag = show_name_attributes (list->word->word, nodefs);
|
||||
if (pflag)
|
||||
{
|
||||
sh_notfound (list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#define NEXT_VARIABLE() free (name); list = list->next; continue
|
||||
|
||||
/* There are arguments left, so we are making variables. */
|
||||
while (list) /* declare [-afFirx] name [name ...] */
|
||||
{
|
||||
char *value, *name;
|
||||
int offset, aflags;
|
||||
#if defined (ARRAY_VARS)
|
||||
int making_array_special, compound_array_assign, simple_array_assign;
|
||||
#endif
|
||||
|
||||
name = savestring (list->word->word);
|
||||
offset = assignment (name, 0);
|
||||
aflags = 0;
|
||||
|
||||
if (offset) /* declare [-afFirx] name=value */
|
||||
{
|
||||
name[offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
if (name[offset - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[offset - 1] = '\0';
|
||||
}
|
||||
}
|
||||
else
|
||||
value = "";
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
compound_array_assign = simple_array_assign = 0;
|
||||
subscript_start = (char *)NULL;
|
||||
if (t = strchr (name, '[')) /* ] */
|
||||
{
|
||||
subscript_start = t;
|
||||
*t = '\0';
|
||||
making_array_special = 1;
|
||||
}
|
||||
else
|
||||
making_array_special = 0;
|
||||
#endif
|
||||
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* If VARIABLE_CONTEXT has a non-zero value, then we are executing
|
||||
inside of a function. This means we should make local variables,
|
||||
not global ones. */
|
||||
|
||||
/* XXX - this has consequences when we're making a local copy of a
|
||||
variable that was in the temporary environment. Watch out
|
||||
for this. */
|
||||
if (variable_context && ((flags_on & att_function) == 0))
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if ((flags_on & att_array) || making_array_special)
|
||||
var = make_local_array_variable (name);
|
||||
else
|
||||
#endif
|
||||
var = make_local_variable (name);
|
||||
if (var == 0)
|
||||
{
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else
|
||||
var = (SHELL_VAR *)NULL;
|
||||
|
||||
/* If we are declaring a function, then complain about it in some way.
|
||||
We don't let people make functions by saying `typeset -f foo=bar'. */
|
||||
|
||||
/* There should be a way, however, to let people look at a particular
|
||||
function definition by saying `typeset -f foo'. */
|
||||
|
||||
if (flags_on & att_function)
|
||||
{
|
||||
if (offset) /* declare -f [-rix] foo=bar */
|
||||
{
|
||||
builtin_error (_("cannot use `-f' to make functions"));
|
||||
free (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else /* declare -f [-rx] name [name...] */
|
||||
{
|
||||
var = find_function (name);
|
||||
|
||||
if (var)
|
||||
{
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
builtin_error (_("%s: readonly function"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* declare -[Ff] name [name...] */
|
||||
if (flags_on == att_function && flags_off == 0)
|
||||
{
|
||||
#if defined (DEBUGGER)
|
||||
if (nodefs && debugging_mode)
|
||||
{
|
||||
shell_fn = find_function_def (var->name);
|
||||
if (shell_fn)
|
||||
printf ("%s %d %s\n", var->name, shell_fn->line, shell_fn->source_file);
|
||||
else
|
||||
printf ("%s\n", var->name);
|
||||
}
|
||||
else
|
||||
#endif /* DEBUGGER */
|
||||
{
|
||||
t = nodefs ? var->name
|
||||
: named_function_string (name, function_cell (var), 1);
|
||||
printf ("%s\n", t);
|
||||
}
|
||||
}
|
||||
else /* declare -[fF] -[rx] name [name...] */
|
||||
{
|
||||
VSETATTR (var, flags_on);
|
||||
VUNSETATTR (var, flags_off);
|
||||
}
|
||||
}
|
||||
else
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else /* declare -[airx] name [name...] */
|
||||
{
|
||||
/* Non-null if we just created or fetched a local variable. */
|
||||
if (var == 0)
|
||||
var = find_variable (name);
|
||||
|
||||
if (var == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if ((flags_on & att_array) || making_array_special)
|
||||
var = make_new_array_variable (name);
|
||||
else
|
||||
#endif
|
||||
var = bind_variable (name, "", 0);
|
||||
}
|
||||
|
||||
/* Cannot use declare +r to turn off readonly attribute. */
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
sh_readonly (name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Cannot use declare to assign value to readonly or noassign
|
||||
variable. */
|
||||
if ((readonly_p (var) || noassign_p (var)) && offset)
|
||||
{
|
||||
if (readonly_p (var))
|
||||
sh_readonly (name);
|
||||
assign_error++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if ((making_array_special || (flags_on & att_array) || array_p (var)) && offset)
|
||||
{
|
||||
int vlen;
|
||||
vlen = STRLEN (value);
|
||||
#if 0
|
||||
if (value[0] == '(' && strchr (value, ')'))
|
||||
#else
|
||||
if (value[0] == '(' && value[vlen-1] == ')')
|
||||
#endif
|
||||
compound_array_assign = 1;
|
||||
else
|
||||
simple_array_assign = 1;
|
||||
}
|
||||
|
||||
/* Cannot use declare +a name to remove an array variable. */
|
||||
if ((flags_off & att_array) && array_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot destroy array variables in this way"), name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* declare -a name makes name an array variable. */
|
||||
if ((making_array_special || (flags_on & att_array)) && array_p (var) == 0)
|
||||
var = convert_var_to_array (var);
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
VSETATTR (var, flags_on);
|
||||
VUNSETATTR (var, flags_off);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (offset && compound_array_assign)
|
||||
assign_array_var_from_string (var, value, aflags);
|
||||
else if (simple_array_assign && subscript_start)
|
||||
{
|
||||
/* declare [-a] name[N]=value */
|
||||
*subscript_start = '['; /* ] */
|
||||
var = assign_array_element (name, value, 0); /* XXX - not aflags */
|
||||
*subscript_start = '\0';
|
||||
}
|
||||
else if (simple_array_assign)
|
||||
/* let bind_array_variable take care of this. */
|
||||
bind_array_variable (name, 0, value, aflags);
|
||||
else
|
||||
#endif
|
||||
/* bind_variable_value duplicates the essential internals of
|
||||
bind_variable() */
|
||||
if (offset)
|
||||
bind_variable_value (var, value, aflags);
|
||||
|
||||
/* If we found this variable in the temporary environment, as with
|
||||
`var=value declare -x var', make sure it is treated identically
|
||||
to `var=value export var'. Do the same for `declare -r' and
|
||||
`readonly'. Preserve the attributes, except for att_tempvar. */
|
||||
/* XXX -- should this create a variable in the global scope, or
|
||||
modify the local variable flags? ksh93 has it modify the
|
||||
global scope.
|
||||
Need to handle case like in set_var_attribute where a temporary
|
||||
variable is in the same table as the function local vars. */
|
||||
if ((flags_on & (att_exported|att_readonly)) && tempvar_p (var))
|
||||
{
|
||||
SHELL_VAR *tv;
|
||||
char *tvalue;
|
||||
|
||||
tv = find_tempenv_variable (var->name);
|
||||
if (tv)
|
||||
{
|
||||
tvalue = var_isset (var) ? savestring (value_cell (var)) : savestring ("");
|
||||
tv = bind_variable (var->name, tvalue, 0);
|
||||
tv->attributes |= var->attributes & ~att_tempvar;
|
||||
if (tv->context > 0)
|
||||
VSETATTR (tv, att_propagate);
|
||||
free (tvalue);
|
||||
}
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
This file is echo.def, from which is created echo.c.
|
||||
It implements the builtin "echo" in Bash.
|
||||
|
||||
Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES echo.c
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
|
||||
$BUILTIN echo
|
||||
$FUNCTION echo_builtin
|
||||
$DEPENDS_ON V9_ECHO
|
||||
$SHORT_DOC echo [-neE] [arg ...]
|
||||
Output the ARGs. If -n is specified, the trailing newline is
|
||||
suppressed. If the -e option is given, interpretation of the
|
||||
following backslash-escaped characters is turned on:
|
||||
\a alert (bell)
|
||||
\b backspace
|
||||
\c suppress trailing newline
|
||||
\E escape character
|
||||
\f form feed
|
||||
\n new line
|
||||
\r carriage return
|
||||
\t horizontal tab
|
||||
\v vertical tab
|
||||
\\ backslash
|
||||
\num the character whose ASCII code is NUM (octal).
|
||||
|
||||
You can explicitly turn off the interpretation of the above characters
|
||||
with the -E option.
|
||||
$END
|
||||
|
||||
$BUILTIN echo
|
||||
$FUNCTION echo_builtin
|
||||
$DEPENDS_ON !V9_ECHO
|
||||
$SHORT_DOC echo [-n] [arg ...]
|
||||
Output the ARGs. If -n is specified, the trailing newline is suppressed.
|
||||
$END
|
||||
|
||||
#if defined (V9_ECHO)
|
||||
# define VALID_ECHO_OPTIONS "neE"
|
||||
#else /* !V9_ECHO */
|
||||
# define VALID_ECHO_OPTIONS "n"
|
||||
#endif /* !V9_ECHO */
|
||||
|
||||
/* 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)
|
||||
int xpg_echo = 1;
|
||||
#else
|
||||
int xpg_echo = 0;
|
||||
#endif /* DEFAULT_ECHO_TO_XPG */
|
||||
|
||||
extern int posixly_correct;
|
||||
|
||||
/* Print the words in LIST to standard output. If the first word is
|
||||
`-n', then don't print a trailing newline. We also support the
|
||||
echo syntax from Version 9 Unix systems. */
|
||||
int
|
||||
echo_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int display_return, do_v9, i, len;
|
||||
char *temp, *s;
|
||||
|
||||
do_v9 = xpg_echo;
|
||||
display_return = 1;
|
||||
|
||||
if (posixly_correct && xpg_echo)
|
||||
goto just_echo;
|
||||
|
||||
for (; list && (temp = list->word->word) && *temp == '-'; list = list->next)
|
||||
{
|
||||
/* If it appears that we are handling options, then make sure that
|
||||
all of the options specified are actually valid. Otherwise, the
|
||||
string should just be echoed. */
|
||||
temp++;
|
||||
|
||||
for (i = 0; temp[i]; i++)
|
||||
{
|
||||
if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
/* echo - and echo -<nonopt> both mean to just echo the arguments. */
|
||||
if (*temp == 0 || temp[i])
|
||||
break;
|
||||
|
||||
/* All of the options in TEMP are valid options to ECHO.
|
||||
Handle them. */
|
||||
while (i = *temp++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 'n':
|
||||
display_return = 0;
|
||||
break;
|
||||
#if defined (V9_ECHO)
|
||||
case 'e':
|
||||
do_v9 = 1;
|
||||
break;
|
||||
case 'E':
|
||||
do_v9 = 0;
|
||||
break;
|
||||
#endif /* V9_ECHO */
|
||||
default:
|
||||
goto just_echo; /* XXX */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
just_echo:
|
||||
|
||||
clearerr (stdout); /* clear error before writing and testing success */
|
||||
|
||||
while (list)
|
||||
{
|
||||
i = len = 0;
|
||||
temp = do_v9 ? ansicstr (list->word->word, STRLEN (list->word->word), 1, &i, &len)
|
||||
: list->word->word;
|
||||
if (temp)
|
||||
{
|
||||
if (do_v9)
|
||||
{
|
||||
for (s = temp; len > 0; len--)
|
||||
putchar (*s++);
|
||||
}
|
||||
else
|
||||
printf ("%s", temp);
|
||||
#if defined (SunOS5)
|
||||
fflush (stdout); /* Fix for bug in SunOS 5.5 printf(3) */
|
||||
#endif
|
||||
}
|
||||
if (do_v9 && temp)
|
||||
free (temp);
|
||||
list = list->next;
|
||||
if (i)
|
||||
{
|
||||
display_return = 0;
|
||||
break;
|
||||
}
|
||||
if (list)
|
||||
putchar(' ');
|
||||
}
|
||||
|
||||
if (display_return)
|
||||
putchar ('\n');
|
||||
fflush (stdout);
|
||||
if (ferror (stdout))
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -1,320 +0,0 @@
|
||||
/* Copyright (C) 1996-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (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 "../jobs.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
#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
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int indirection_level, startup_state, subshell_environment;
|
||||
extern int return_catch_flag, return_catch_value;
|
||||
extern int last_command_exit_value;
|
||||
|
||||
/* 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;
|
||||
char *string;
|
||||
struct stat finfo;
|
||||
size_t file_size;
|
||||
sh_vmsg_func_t *errfunc;
|
||||
#if defined (ARRAY_VARS)
|
||||
SHELL_VAR *funcname_v, *nfv, *bash_source_v, *bash_lineno_v;
|
||||
ARRAY *funcname_a, *bash_source_a, *bash_lineno_a;
|
||||
# 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))
|
||||
{
|
||||
file_error_and_exit:
|
||||
if (((flags & FEVAL_ENOENTOK) == 0) || errno != ENOENT)
|
||||
file_error (filename);
|
||||
|
||||
if (flags & FEVAL_LONGJMP)
|
||||
{
|
||||
last_command_exit_value = 1;
|
||||
jump_to_top_level (EXITPROG);
|
||||
}
|
||||
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE
|
||||
: ((errno == ENOENT) ? 0 : -1));
|
||||
}
|
||||
|
||||
errfunc = ((flags & FEVAL_BUILTIN) ? builtin_error : internal_error);
|
||||
|
||||
if (S_ISDIR (finfo.st_mode))
|
||||
{
|
||||
(*errfunc) (_("%s: is a directory"), filename);
|
||||
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);
|
||||
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);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_FAILURE : -1);
|
||||
}
|
||||
|
||||
#if defined (__CYGWIN__) && defined (O_TEXT)
|
||||
setmode (fd, O_TEXT);
|
||||
#endif
|
||||
|
||||
string = (char *)xmalloc (1 + file_size);
|
||||
result = read (fd, string, file_size);
|
||||
string[result] = '\0';
|
||||
|
||||
return_val = errno;
|
||||
close (fd);
|
||||
errno = return_val;
|
||||
|
||||
if (result < 0) /* XXX was != file_size, not < 0 */
|
||||
{
|
||||
free (string);
|
||||
goto file_error_and_exit;
|
||||
}
|
||||
|
||||
if (result == 0)
|
||||
{
|
||||
free (string);
|
||||
return ((flags & FEVAL_BUILTIN) ? EXECUTION_SUCCESS : 1);
|
||||
}
|
||||
|
||||
if ((flags & FEVAL_CHECKBINARY) &&
|
||||
check_binary_file (string, (result > 80) ? 80 : result))
|
||||
{
|
||||
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 */
|
||||
# if defined (DEBUGGER)
|
||||
/* Have to figure out a better way to do this when `source' is supplied
|
||||
arguments */
|
||||
if ((flags & FEVAL_NOPUSHARGS) == 0)
|
||||
{
|
||||
array_push (bash_argv_a, (char *)filename);
|
||||
tt[0] = '1'; tt[1] = '\0';
|
||||
array_push (bash_argc_a, tt);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* set the flags to be passed to parse_and_execute */
|
||||
pflags = SEVAL_RESETLINE;
|
||||
pflags |= (flags & FEVAL_HISTORY) ? 0 : SEVAL_NOHIST;
|
||||
|
||||
if (flags & FEVAL_BUILTIN)
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
return_val = setjmp (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 ();
|
||||
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;
|
||||
return_catch_flag--;
|
||||
sourcelevel--;
|
||||
COPY_PROCENV (old_return_catch, return_catch);
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* These two variables cannot be unset, and cannot be affected by the
|
||||
function. */
|
||||
array_pop (bash_source_a);
|
||||
array_pop (bash_lineno_a);
|
||||
|
||||
/* FUNCNAME can be unset, and so can potentially be changed by the
|
||||
function. */
|
||||
GET_ARRAY_FROM_VAR ("FUNCNAME", nfv, funcname_a);
|
||||
if (nfv == funcname_v)
|
||||
array_pop (funcname_a);
|
||||
# if defined (DEBUGGER)
|
||||
if ((flags & FEVAL_NOPUSHARGS) == 0)
|
||||
{
|
||||
array_pop (bash_argc_a);
|
||||
array_pop (bash_argv_a);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
#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. */
|
||||
flags = FEVAL_ENOENTOK|FEVAL_HISTORY|FEVAL_REGFILE;
|
||||
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)
|
||||
flags |= FEVAL_LONGJMP;
|
||||
rval = _evalfile (filename, flags);
|
||||
|
||||
run_return_trap ();
|
||||
return rval;
|
||||
}
|
||||
@@ -1,355 +0,0 @@
|
||||
/* Evaluate a string as one or more shell commands.
|
||||
|
||||
Copyright (C) 1996-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
||||
|
||||
#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 "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../redir.h"
|
||||
#include "../trap.h"
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define IS_BUILTIN(s) (builtin_address_internal(s, 0) != (struct builtin *)NULL)
|
||||
|
||||
extern int indirection_level, startup_state, subshell_environment;
|
||||
extern int line_number;
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap;
|
||||
extern int loop_level;
|
||||
extern int posixly_correct;
|
||||
|
||||
int parse_and_execute_level = 0;
|
||||
|
||||
static int cat_file __P((REDIRECT *));
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup ()
|
||||
{
|
||||
if (running_trap)
|
||||
{
|
||||
run_trap_cleanup (running_trap - 1);
|
||||
unfreeze_jobs_list ();
|
||||
}
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
}
|
||||
|
||||
/* 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
|
||||
*/
|
||||
|
||||
int
|
||||
parse_and_execute (string, from_file, flags)
|
||||
char *string;
|
||||
const char *from_file;
|
||||
int flags;
|
||||
{
|
||||
int code, x, lreset;
|
||||
volatile int should_jump_to_top_level, last_result;
|
||||
char *orig_string;
|
||||
COMMAND *volatile command;
|
||||
|
||||
orig_string = string;
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame ("parse_and_execute_top");
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
unwind_protect_int (line_number);
|
||||
unwind_protect_int (loop_level);
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
lreset = flags & SEVAL_RESETLINE;
|
||||
|
||||
#if defined (HISTORY)
|
||||
unwind_protect_int (remember_on_history); /* can be used in scripts */
|
||||
# if defined (BANG_HISTORY)
|
||||
if (interactive_shell)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
add_unwind_protect (pop_stream, (char *)NULL);
|
||||
if (orig_string && ((flags & SEVAL_NOFREE) == 0))
|
||||
add_unwind_protect (xfree, orig_string);
|
||||
end_unwind_frame ();
|
||||
|
||||
parse_and_execute_level++;
|
||||
|
||||
/* 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 (lreset == 0)
|
||||
line_number--;
|
||||
|
||||
indirection_level++;
|
||||
if (flags & (SEVAL_NONINT|SEVAL_INTERACT))
|
||||
interactive = (flags & SEVAL_NONINT) ? 0 : 1;
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (flags & SEVAL_NOHIST)
|
||||
bash_history_disable ();
|
||||
#endif /* HISTORY */
|
||||
|
||||
code = should_jump_to_top_level = 0;
|
||||
last_result = EXECUTION_SUCCESS;
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
while (*(bash_input.location.string))
|
||||
{
|
||||
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 (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
should_jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case ERREXIT:
|
||||
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 DISCARD:
|
||||
if (command)
|
||||
run_unwind_frame ("pe_dispose");
|
||||
last_result = last_command_exit_value = EXECUTION_FAILURE; /* XXX */
|
||||
if (subshell_environment)
|
||||
{
|
||||
should_jump_to_top_level = 1;
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if 0
|
||||
dispose_command (command); /* pe_dispose does this */
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
default:
|
||||
command_error ("parse_and_execute", CMDERR_BADJUMP, code, 0);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if (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;
|
||||
|
||||
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 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 have a simple command without redirections AND
|
||||
* the command is not being timed AND
|
||||
* the command's return status is not being inverted
|
||||
* THEN
|
||||
* tell the execution code that we don't need to fork
|
||||
*/
|
||||
if (startup_state == 2 && parse_and_execute_level == 1 &&
|
||||
running_trap == 0 &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple &&
|
||||
!command->redirects && !command->value.Simple->redirects &&
|
||||
((command->flags & CMD_TIME_PIPELINE) == 0) &&
|
||||
((command->flags & CMD_INVERT_RETURN) == 0))
|
||||
{
|
||||
itrace("parse_and_execute: turning on CMD_NO_FORK");
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
#endif /* ONESHOT */
|
||||
|
||||
/* See if this is a candidate for $( <file ). */
|
||||
if (startup_state == 2 &&
|
||||
(subshell_environment & SUBSHELL_COMSUB) &&
|
||||
*bash_input.location.string == '\0' &&
|
||||
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)
|
||||
{
|
||||
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");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
|
||||
/* Since we are shell compatible, syntax errors in a script
|
||||
abort the execution of the script. Right? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
/* An interrupt during non-interactive execution in an
|
||||
interactive shell (e.g. via $PROMPT_COMMAND) should
|
||||
not cause the shell to exit. */
|
||||
interactive = interactive_shell;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
if (should_jump_to_top_level)
|
||||
jump_to_top_level (code);
|
||||
|
||||
itrace("parse_and_execute: returning %d", last_result);
|
||||
return (last_result);
|
||||
}
|
||||
|
||||
/* 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 lbuf[128], *fn;
|
||||
int fd, rval;
|
||||
ssize_t nr;
|
||||
|
||||
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);
|
||||
return -1;
|
||||
}
|
||||
|
||||
fd = open(fn, O_RDONLY);
|
||||
if (fd < 0)
|
||||
{
|
||||
file_error (fn);
|
||||
free (fn);
|
||||
return -1;
|
||||
}
|
||||
|
||||
rval = zcatfd (fd, 1, fn);
|
||||
|
||||
free (fn);
|
||||
close (fd);
|
||||
|
||||
return (rval);
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
This file is exec.def, from which is created exec.c.
|
||||
It implements the builtin "exec" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES exec.c
|
||||
|
||||
$BUILTIN exec
|
||||
$FUNCTION exec_builtin
|
||||
$SHORT_DOC exec [-cl] [-a name] file [redirection ...]
|
||||
Exec FILE, replacing this shell with the specified program.
|
||||
If FILE is not specified, the redirections take effect in this
|
||||
shell. If the first argument is `-l', then place a dash in the
|
||||
zeroth arg passed to FILE, as login does. If the `-c' option
|
||||
is supplied, FILE is executed with a null environment. The `-a'
|
||||
option means to make set argv[0] of the executed process to NAME.
|
||||
If the file cannot be executed and the shell is not interactive,
|
||||
then the shell exits, unless the shell option `execfail' is set.
|
||||
$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 "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "../findcmd.h"
|
||||
#if defined (JOB_CONTROL)
|
||||
# include "../jobs.h"
|
||||
#endif
|
||||
#include "../flags.h"
|
||||
#include "../trap.h"
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int subshell_environment;
|
||||
extern REDIRECT *redirection_undo_list;
|
||||
|
||||
int no_exit_on_failed_exec;
|
||||
|
||||
/* If the user wants this to look like a login shell, then
|
||||
prepend a `-' onto NAME and return the new name. */
|
||||
static char *
|
||||
mkdashname (name)
|
||||
char *name;
|
||||
{
|
||||
char *ret;
|
||||
|
||||
ret = (char *)xmalloc (2 + strlen (name));
|
||||
ret[0] = '-';
|
||||
strcpy (ret + 1, name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int
|
||||
exec_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int exit_value = EXECUTION_FAILURE;
|
||||
int cleanenv, login, opt;
|
||||
char *argv0, *command, **args, **env, *newname, *com2;
|
||||
|
||||
cleanenv = login = 0;
|
||||
argv0 = (char *)NULL;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "cla:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'c':
|
||||
cleanenv = 1;
|
||||
break;
|
||||
case 'l':
|
||||
login = 1;
|
||||
break;
|
||||
case 'a':
|
||||
argv0 = list_optarg;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* First, let the redirections remain. */
|
||||
dispose_redirects (redirection_undo_list);
|
||||
redirection_undo_list = (REDIRECT *)NULL;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
sh_restricted ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
args = strvec_from_word_list (list, 1, 0, (int *)NULL);
|
||||
|
||||
/* A command with a slash anywhere in its name is not looked up in $PATH. */
|
||||
command = absolute_program (args[0]) ? args[0] : search_for_command (args[0]);
|
||||
|
||||
if (command == 0)
|
||||
{
|
||||
sh_notfound (args[0]);
|
||||
exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
|
||||
goto failed_exec;
|
||||
}
|
||||
|
||||
com2 = full_pathname (command);
|
||||
if (com2)
|
||||
{
|
||||
if (command != args[0])
|
||||
free (command);
|
||||
command = com2;
|
||||
}
|
||||
|
||||
if (argv0)
|
||||
{
|
||||
free (args[0]);
|
||||
args[0] = login ? mkdashname (argv0) : savestring (argv0);
|
||||
}
|
||||
else if (login)
|
||||
{
|
||||
newname = mkdashname (args[0]);
|
||||
free (args[0]);
|
||||
args[0] = newname;
|
||||
}
|
||||
|
||||
/* Decrement SHLVL by 1 so a new shell started here has the same value,
|
||||
preserving the appearance. After we do that, we need to change the
|
||||
exported environment to include the new value. */
|
||||
if (cleanenv == 0)
|
||||
adjust_shell_level (-1);
|
||||
|
||||
if (cleanenv)
|
||||
env = (char **)NULL;
|
||||
else
|
||||
{
|
||||
maybe_make_export_env ();
|
||||
env = export_env;
|
||||
}
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (interactive_shell && subshell_environment == 0)
|
||||
maybe_save_shell_history ();
|
||||
#endif /* HISTORY */
|
||||
|
||||
restore_original_signals ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (subshell_environment == 0)
|
||||
end_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
shell_execve (command, args, env);
|
||||
|
||||
/* We have to set this to NULL because shell_execve has called realloc()
|
||||
to stuff more items at the front of the array, which may have caused
|
||||
the memory to be freed by realloc(). We don't want to free it twice. */
|
||||
args = (char **)NULL;
|
||||
if (cleanenv == 0)
|
||||
adjust_shell_level (1);
|
||||
|
||||
if (executable_file (command) == 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot execute: %s"), command, strerror (errno));
|
||||
exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
|
||||
}
|
||||
else
|
||||
file_error (command);
|
||||
|
||||
failed_exec:
|
||||
FREE (command);
|
||||
|
||||
if (subshell_environment || (interactive == 0 && no_exit_on_failed_exec == 0))
|
||||
exit_shell (exit_value);
|
||||
|
||||
if (args)
|
||||
strvec_dispose (args);
|
||||
|
||||
initialize_traps ();
|
||||
initialize_signals (1);
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
restart_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
return (exit_value);
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
This file is exit.def, from which is created exit.c.
|
||||
It implements the builtins "exit", and "logout" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES exit.c
|
||||
|
||||
$BUILTIN exit
|
||||
$FUNCTION exit_builtin
|
||||
$SHORT_DOC exit [n]
|
||||
Exit the shell with a status of N. If N is omitted, the exit status
|
||||
is that of the last command executed.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
|
||||
#include "common.h"
|
||||
#include "builtext.h" /* for jobs_builtin */
|
||||
|
||||
extern int last_command_exit_value;
|
||||
extern int running_trap, trap_saved_exit_value;
|
||||
extern int subshell_environment;
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
extern sh_builtin_func_t *last_shell_builtin;
|
||||
|
||||
static int exit_or_logout __P((WORD_LIST *));
|
||||
static int sourced_logout;
|
||||
|
||||
int
|
||||
exit_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
fprintf (stderr, login_shell ? "logout\n" : "exit\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
return (exit_or_logout (list));
|
||||
}
|
||||
|
||||
$BUILTIN logout
|
||||
$FUNCTION logout_builtin
|
||||
$SHORT_DOC logout
|
||||
Logout of a login shell.
|
||||
$END
|
||||
|
||||
/* How to logout. */
|
||||
int
|
||||
logout_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (login_shell == 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;
|
||||
|
||||
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)
|
||||
{
|
||||
register int i;
|
||||
for (i = 0; i < js.j_jobslots; i++)
|
||||
if (jobs[i] && STOPPED (i))
|
||||
{
|
||||
fprintf (stderr, _("There are stopped jobs.\n"));
|
||||
|
||||
/* This is NOT superfluous because EOF can get here without
|
||||
going through the command parser. Set both last and this
|
||||
so that either `exit', `logout', or ^D will work to exit
|
||||
immediately if nothing intervenes. */
|
||||
this_shell_builtin = last_shell_builtin = exit_builtin;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/* Get return value if present. This means that you can type
|
||||
`logout 5' to a shell, and it returns 5. */
|
||||
|
||||
/* If we're running the exit trap (running_trap == 1, since running_trap
|
||||
gets set to SIG+1), and we don't have a argument given to `exit'
|
||||
(list == 0), use the exit status we saved before running the trap
|
||||
commands (trap_saved_exit_value). */
|
||||
exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list);
|
||||
|
||||
bash_logout ();
|
||||
|
||||
last_command_exit_value = exit_value;
|
||||
|
||||
/* Exit the program. */
|
||||
jump_to_top_level (EXITPROG);
|
||||
/*NOTREACHED*/
|
||||
}
|
||||
|
||||
void
|
||||
bash_logout ()
|
||||
{
|
||||
/* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
|
||||
if (login_shell && sourced_logout++ == 0 && subshell_environment == 0)
|
||||
{
|
||||
maybe_execute_file ("~/.bash_logout", 1);
|
||||
#ifdef SYS_BASH_LOGOUT
|
||||
maybe_execute_file (SYS_BASH_LOGOUT, 1);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,627 +0,0 @@
|
||||
This file is fc.def, from which is created fc.c.
|
||||
It implements the builtin "fc" in Bash.
|
||||
|
||||
Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES fc.c
|
||||
|
||||
$BUILTIN fc
|
||||
$FUNCTION fc_builtin
|
||||
$DEPENDS_ON HISTORY
|
||||
$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
|
||||
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.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
With the `fc -s [pat=rep ...] [command]' format, the command is
|
||||
re-executed after the substitution OLD=NEW is performed.
|
||||
|
||||
A useful alias to use with this is r='fc -s', so that typing `r cc'
|
||||
runs the last command beginning with `cc' and typing `r' re-executes
|
||||
the last command.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
#ifndef _MINIX
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
#include "../bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
#if ! defined(_MINIX) && defined (HAVE_SYS_FILE_H)
|
||||
# include <sys/file.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <chartypes.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../bashhist.h"
|
||||
#include "maxpath.h"
|
||||
#include <readline/history.h>
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int echo_input_at_read;
|
||||
extern int current_command_line_count;
|
||||
extern int literal_history;
|
||||
extern int posixly_correct;
|
||||
|
||||
extern int unlink __P((const char *));
|
||||
|
||||
extern FILE *sh_mktmpfp __P((char *, int, char **));
|
||||
extern int delete_last_history __P((void));
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* The K*rn shell style fc command (Fix Command) */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* fc builtin command (fix command) for Bash for those who
|
||||
like K*rn-style history better than csh-style.
|
||||
|
||||
fc [-e ename] [-nlr] [first] [last]
|
||||
|
||||
FIRST and LAST can be numbers specifying the range, or FIRST can be
|
||||
a string, which means the most recent command beginning with that
|
||||
string.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then the editor which corresponds to the current readline editing
|
||||
mode, then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
fc -e - [pat=rep ...] [command]
|
||||
fc -s [pat=rep ...] [command]
|
||||
|
||||
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
|
||||
*/
|
||||
|
||||
/* Data structure describing a list of global replacements to perform. */
|
||||
typedef struct repl {
|
||||
struct repl *next;
|
||||
char *pat;
|
||||
char *rep;
|
||||
} REPL;
|
||||
|
||||
/* Accessors for HIST_ENTRY lists that are called HLIST. */
|
||||
#define histline(i) (hlist[(i)]->line)
|
||||
#define histdata(i) (hlist[(i)]->data)
|
||||
|
||||
#define FREE_RLIST() \
|
||||
do { \
|
||||
for (rl = rlist; rl; ) { \
|
||||
REPL *r; \
|
||||
r = rl->next; \
|
||||
if (rl->pat) \
|
||||
free (rl->pat); \
|
||||
if (rl->rep) \
|
||||
free (rl->rep); \
|
||||
free (rl); \
|
||||
rl = r; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static char *fc_dosubs __P((char *, REPL *));
|
||||
static char *fc_gethist __P((char *, HIST_ENTRY **));
|
||||
static int fc_gethnum __P((char *, HIST_ENTRY **));
|
||||
static int fc_number __P((WORD_LIST *));
|
||||
static void fc_replhist __P((char *));
|
||||
#ifdef INCLUDE_UNUSED
|
||||
static char *fc_readline __P((FILE *));
|
||||
static void fc_addhist __P((char *));
|
||||
#endif
|
||||
|
||||
/* String to execute on a file that we want to edit. */
|
||||
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
|
||||
#define POSIX_FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-ed}}"
|
||||
|
||||
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;
|
||||
FILE *stream;
|
||||
REPL *rlist, *rl;
|
||||
char *ename, *command, *newcom, *fcedit;
|
||||
HIST_ENTRY **hlist;
|
||||
char *fn;
|
||||
|
||||
numbering = 1;
|
||||
reverse = listing = execute = 0;
|
||||
ename = (char *)NULL;
|
||||
|
||||
/* Parse out the options and set which of the two forms we're in. */
|
||||
reset_internal_getopt ();
|
||||
lcurrent = list; /* XXX */
|
||||
while (fc_number (loptend = lcurrent) == 0 &&
|
||||
(opt = internal_getopt (list, ":e:lnrs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
numbering = 0;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
listing = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
reverse = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
execute = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
ename = list_optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (ename && (*ename == '-') && (ename[1] == '\0'))
|
||||
execute = 1;
|
||||
|
||||
/* The "execute" form of the command (re-run, with possible string
|
||||
substitutions). */
|
||||
if (execute)
|
||||
{
|
||||
rlist = (REPL *)NULL;
|
||||
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
|
||||
{
|
||||
*sep++ = '\0';
|
||||
rl = (REPL *)xmalloc (sizeof (REPL));
|
||||
rl->next = (REPL *)NULL;
|
||||
rl->pat = savestring (list->word->word);
|
||||
rl->rep = savestring (sep);
|
||||
|
||||
if (rlist == NULL)
|
||||
rlist = rl;
|
||||
else
|
||||
{
|
||||
rl->next = rlist;
|
||||
rlist = rl;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* If we have a list of substitutions to do, then reverse it
|
||||
to get the replacements in the proper order. */
|
||||
|
||||
rlist = REVERSE_LIST (rlist, REPL *);
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
/* If we still have something in list, it is a command spec.
|
||||
Otherwise, we use the most recent command in time. */
|
||||
command = fc_gethist (list ? list->word->word : (char *)NULL, hlist);
|
||||
|
||||
if (command == NULL)
|
||||
{
|
||||
builtin_error (_("no command found"));
|
||||
if (rlist)
|
||||
FREE_RLIST ();
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (rlist)
|
||||
{
|
||||
newcom = fc_dosubs (command, rlist);
|
||||
free (command);
|
||||
FREE_RLIST ();
|
||||
command = newcom;
|
||||
}
|
||||
|
||||
fprintf (stderr, "%s\n", command);
|
||||
fc_replhist (command); /* replace `fc -s' with command */
|
||||
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. */
|
||||
|
||||
/* "When not listing, he fc command that caused the editing shall not be
|
||||
entered into the history list." */
|
||||
if (listing == 0 && hist_last_line_added)
|
||||
delete_last_history ();
|
||||
|
||||
last_hist = i - 1 - hist_last_line_added;
|
||||
|
||||
if (list)
|
||||
{
|
||||
histbeg = fc_gethnum (list->word->word, hlist);
|
||||
list = list->next;
|
||||
|
||||
if (list)
|
||||
histend = fc_gethnum (list->word->word, hlist);
|
||||
else
|
||||
histend = listing ? last_hist : histbeg;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The default for listing is the last 16 history items. */
|
||||
if (listing)
|
||||
{
|
||||
histend = last_hist;
|
||||
histbeg = histend - 16 + 1; /* +1 because loop below uses >= */
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
}
|
||||
else
|
||||
/* For editing, it is the last history command. */
|
||||
histbeg = histend = last_hist;
|
||||
}
|
||||
|
||||
/* We print error messages for line specifications out of range. */
|
||||
if ((histbeg < 0) || (histend < 0))
|
||||
{
|
||||
sh_erange ((char *)NULL, _("history specification"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (histend < histbeg)
|
||||
{
|
||||
i = histend;
|
||||
histend = histbeg;
|
||||
histbeg = i;
|
||||
|
||||
reverse = 1;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
stream = stdout;
|
||||
else
|
||||
{
|
||||
numbering = 0;
|
||||
stream = sh_mktmpfp ("bash-fc", MT_USERANDOM|MT_USETMPDIR, &fn);
|
||||
if (stream == 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot open temp file: %s"), fn ? fn : "", strerror (errno));
|
||||
FREE (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
for (i = reverse ? histend : histbeg; reverse ? i >= histbeg : i <= histend; reverse ? i-- : i++)
|
||||
{
|
||||
QUIT;
|
||||
if (numbering)
|
||||
fprintf (stream, "%d", i + history_base);
|
||||
if (listing)
|
||||
{
|
||||
if (posixly_correct)
|
||||
fputs ("\t", stream);
|
||||
else
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
}
|
||||
fprintf (stream, "%s\n", histline (i));
|
||||
}
|
||||
|
||||
if (listing)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
fclose (stream);
|
||||
|
||||
/* Now edit the file of commands. */
|
||||
if (ename)
|
||||
{
|
||||
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
|
||||
sprintf (command, "%s %s", ename, fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
fcedit = posixly_correct ? POSIX_FC_EDIT_COMMAND : FC_EDIT_COMMAND;
|
||||
command = (char *)xmalloc (3 + strlen (fcedit) + strlen (fn));
|
||||
sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
|
||||
}
|
||||
retval = parse_and_execute (command, "fc", SEVAL_NOHIST);
|
||||
if (retval != EXECUTION_SUCCESS)
|
||||
{
|
||||
unlink (fn);
|
||||
free (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Make sure parse_and_execute doesn't turn this off, even though a
|
||||
call to parse_and_execute farther up the function call stack (e.g.,
|
||||
if this is called by vi_edit_and_execute_command) may have already
|
||||
called bash_history_disable. */
|
||||
remember_on_history = 1;
|
||||
|
||||
/* Turn on the `v' flag while fc_execute_file runs so the commands
|
||||
will be echoed as they are read by the parser. */
|
||||
begin_unwind_frame ("fc builtin");
|
||||
add_unwind_protect ((Function *)xfree, fn);
|
||||
add_unwind_protect (unlink, fn);
|
||||
unwind_protect_int (echo_input_at_read);
|
||||
echo_input_at_read = 1;
|
||||
|
||||
retval = fc_execute_file (fn);
|
||||
|
||||
run_unwind_frame ("fc builtin");
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* Return 1 if LIST->word->word is a legal number for fc's use. */
|
||||
static int
|
||||
fc_number (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s;
|
||||
|
||||
if (list == 0)
|
||||
return 0;
|
||||
s = list->word->word;
|
||||
if (*s == '-')
|
||||
s++;
|
||||
return (legal_number (s, (intmax_t *)NULL));
|
||||
}
|
||||
|
||||
/* Return an absolute index into HLIST which corresponds to COMMAND. If
|
||||
COMMAND is a number, then it was specified in relative terms. If it
|
||||
is a string, then it is the start of a command line present in HLIST. */
|
||||
static int
|
||||
fc_gethnum (command, hlist)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
{
|
||||
int sign = 1, n, clen;
|
||||
register int i, j;
|
||||
register char *s;
|
||||
|
||||
/* Count history elements. */
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. 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. */
|
||||
i -= 1 + hist_last_line_added;
|
||||
|
||||
/* No specification defaults to most recent command. */
|
||||
if (command == NULL)
|
||||
return (i);
|
||||
|
||||
/* Otherwise, there is a specification. It can be a number relative to
|
||||
the current position, or an absolute history number. */
|
||||
s = command;
|
||||
|
||||
/* Handle possible leading minus sign. */
|
||||
if (s && (*s == '-'))
|
||||
{
|
||||
sign = -1;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (s && DIGIT(*s))
|
||||
{
|
||||
n = atoi (s);
|
||||
n *= sign;
|
||||
|
||||
/* If the value is negative or zero, then it is an offset from
|
||||
the current history item. */
|
||||
if (n < 0)
|
||||
{
|
||||
n += i + 1;
|
||||
return (n < 0 ? 0 : n);
|
||||
}
|
||||
else if (n == 0)
|
||||
return (i);
|
||||
else
|
||||
{
|
||||
n -= history_base;
|
||||
return (i < n ? i : n);
|
||||
}
|
||||
}
|
||||
|
||||
clen = strlen (command);
|
||||
for (j = i; j >= 0; j--)
|
||||
{
|
||||
if (STREQN (command, histline (j), clen))
|
||||
return (j);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Locate the most recent history line which begins with
|
||||
COMMAND in HLIST, and return a malloc()'ed copy of it. */
|
||||
static char *
|
||||
fc_gethist (command, hlist)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (hlist == 0)
|
||||
return ((char *)NULL);
|
||||
|
||||
i = fc_gethnum (command, hlist);
|
||||
|
||||
if (i >= 0)
|
||||
return (savestring (histline (i)));
|
||||
else
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
#ifdef INCLUDE_UNUSED
|
||||
/* Read the edited history lines from STREAM and return them
|
||||
one at a time. This can read unlimited length lines. The
|
||||
caller should free the storage. */
|
||||
static char *
|
||||
fc_readline (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
register int c;
|
||||
int line_len = 0, lindex = 0;
|
||||
char *line = (char *)NULL;
|
||||
|
||||
while ((c = getc (stream)) != EOF)
|
||||
{
|
||||
if ((lindex + 2) >= line_len)
|
||||
line = (char *)xrealloc (line, (line_len += 128));
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
line[lindex++] = '\n';
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
else
|
||||
line[lindex++] = c;
|
||||
}
|
||||
|
||||
if (!lindex)
|
||||
{
|
||||
if (line)
|
||||
free (line);
|
||||
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
if (lindex + 2 >= line_len)
|
||||
line = (char *)xrealloc (line, lindex + 3);
|
||||
|
||||
line[lindex++] = '\n'; /* Finish with newline if none in file */
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Perform the SUBS on COMMAND.
|
||||
SUBS is a list of substitutions, and COMMAND is a simple string.
|
||||
Return a pointer to a malloc'ed string which contains the substituted
|
||||
command. */
|
||||
static char *
|
||||
fc_dosubs (command, subs)
|
||||
char *command;
|
||||
REPL *subs;
|
||||
{
|
||||
register char *new, *t;
|
||||
register REPL *r;
|
||||
|
||||
for (new = savestring (command), r = subs; r; r = r->next)
|
||||
{
|
||||
t = strsub (new, r->pat, r->rep, 1);
|
||||
free (new);
|
||||
new = t;
|
||||
}
|
||||
return (new);
|
||||
}
|
||||
|
||||
/* Use `command' to replace the last entry in the history list, which,
|
||||
by this time, is `fc blah...'. The intent is that the new command
|
||||
become the history entry, and that `fc' should never appear in the
|
||||
history list. This way you can do `r' to your heart's content. */
|
||||
static void
|
||||
fc_replhist (command)
|
||||
char *command;
|
||||
{
|
||||
int n;
|
||||
|
||||
if (command == 0 || *command == '\0')
|
||||
return;
|
||||
|
||||
n = strlen (command);
|
||||
if (command[n - 1] == '\n')
|
||||
command[n - 1] = '\0';
|
||||
|
||||
if (command && *command)
|
||||
{
|
||||
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 */
|
||||
@@ -1,175 +0,0 @@
|
||||
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-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES fg_bg.c
|
||||
|
||||
$BUILTIN fg
|
||||
$FUNCTION fg_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC fg [job_spec]
|
||||
Place JOB_SPEC in the foreground, and make it the current job. If
|
||||
JOB_SPEC is not present, the shell's notion of the current job is
|
||||
used.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern char *this_command_name;
|
||||
|
||||
static int fg_bg __P((WORD_LIST *, int));
|
||||
|
||||
/* How to bring a job into the foreground. */
|
||||
int
|
||||
fg_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int fg_bit;
|
||||
register WORD_LIST *t;
|
||||
|
||||
if (job_control == 0)
|
||||
{
|
||||
sh_nojobs ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
/* If the last arg on the line is '&', then start this job in the
|
||||
background. Else, fg the job. */
|
||||
for (t = list; t && t->next; t = t->next)
|
||||
;
|
||||
fg_bit = (t && t->word->word[0] == '&' && t->word->word[1] == '\0') == 0;
|
||||
|
||||
return (fg_bg (list, fg_bit));
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
$BUILTIN bg
|
||||
$FUNCTION bg_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC bg [job_spec]
|
||||
Place JOB_SPEC in the background, as if it had been started with
|
||||
`&'. If JOB_SPEC is not present, the shell's notion of the current
|
||||
job is used.
|
||||
$END
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* How to put a job into the background. */
|
||||
int
|
||||
bg_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int r;
|
||||
|
||||
if (job_control == 0)
|
||||
{
|
||||
sh_nojobs ((char *)NULL);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
/* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts
|
||||
on the first member (if any) of that list. */
|
||||
do
|
||||
{
|
||||
r = fg_bg (list, 0);
|
||||
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 (status);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (foreground == 0)
|
||||
last_asynchronous_pid = old_async_pid;
|
||||
|
||||
failure:
|
||||
UNBLOCK_CHILD (oset);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
@@ -1,323 +0,0 @@
|
||||
This file is getopts.def, from which is created getopts.c.
|
||||
It implements the builtin "getopts" in Bash.
|
||||
|
||||
Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES getopts.c
|
||||
|
||||
$BUILTIN getopts
|
||||
$FUNCTION getopts_builtin
|
||||
$SHORT_DOC getopts optstring name [arg]
|
||||
Getopts is used by shell procedures to parse positional parameters.
|
||||
|
||||
OPTSTRING contains the option letters to be recognized; if a letter
|
||||
is followed by a colon, the option is expected to have an argument,
|
||||
which should be separated from it by white space.
|
||||
|
||||
Each time it is invoked, getopts will place the next option in the
|
||||
shell variable $name, initializing name if it does not exist, and
|
||||
the index of the next argument to be processed into the shell
|
||||
variable OPTIND. OPTIND is initialized to 1 each time the shell or
|
||||
a shell script is invoked. When an option requires an argument,
|
||||
getopts places that argument into the shell variable OPTARG.
|
||||
|
||||
getopts reports errors in one of two ways. If the first character
|
||||
of OPTSTRING is a colon, getopts uses silent error reporting. In
|
||||
this mode, no error messages are printed. If an 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 ($0 - $9), but if
|
||||
more arguments are given, they are parsed instead.
|
||||
$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 "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "getopt.h"
|
||||
|
||||
#define G_EOF -1
|
||||
#define G_INVALID_OPT -2
|
||||
#define G_ARG_MISSING -3
|
||||
|
||||
extern char *this_command_name;
|
||||
|
||||
static int getopts_bind_variable __P((char *, char *));
|
||||
static int dogetopts __P((int, char **));
|
||||
|
||||
/* getopts_reset is magic code for when OPTIND is reset. N is the
|
||||
value that has just been assigned to OPTIND. */
|
||||
void
|
||||
getopts_reset (newind)
|
||||
int newind;
|
||||
{
|
||||
sh_optind = newind;
|
||||
sh_badopt = 0;
|
||||
}
|
||||
|
||||
static int
|
||||
getopts_bind_variable (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
SHELL_VAR *v;
|
||||
|
||||
if (legal_identifier (name))
|
||||
{
|
||||
v = bind_variable (name, value, 0);
|
||||
return (v && (readonly_p (v) == 0)) ? EXECUTION_SUCCESS : EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidid (name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Error handling is now performed as specified by Posix.2, draft 11
|
||||
(identical to that of ksh-88). The special handling is enabled if
|
||||
the first character of the option string is a colon; this handling
|
||||
disables diagnostic messages concerning missing option arguments
|
||||
and invalid option characters. The handling is as follows.
|
||||
|
||||
INVALID OPTIONS:
|
||||
name -> "?"
|
||||
if (special_error) then
|
||||
OPTARG = option character found
|
||||
no error output
|
||||
else
|
||||
OPTARG unset
|
||||
diagnostic message
|
||||
fi
|
||||
|
||||
MISSING OPTION ARGUMENT;
|
||||
if (special_error) then
|
||||
name -> ":"
|
||||
OPTARG = option character found
|
||||
else
|
||||
name -> "?"
|
||||
OPTARG unset
|
||||
diagnostic message
|
||||
fi
|
||||
*/
|
||||
|
||||
static int
|
||||
dogetopts (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int ret, special_error, old_opterr, i, n;
|
||||
char strval[2], numval[16];
|
||||
char *optstr; /* list of options */
|
||||
char *name; /* variable to get flag val */
|
||||
char *t;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
/* argv[0] is "getopts". */
|
||||
|
||||
optstr = argv[1];
|
||||
name = argv[2];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
special_error = optstr[0] == ':';
|
||||
|
||||
if (special_error)
|
||||
{
|
||||
old_opterr = sh_opterr;
|
||||
optstr++;
|
||||
sh_opterr = 0; /* suppress diagnostic messages */
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
sh_getopt_restore_state (argv);
|
||||
t = argv[0];
|
||||
argv[0] = dollar_vars[0];
|
||||
ret = sh_getopt (argc, argv, optstr);
|
||||
argv[0] = t;
|
||||
}
|
||||
else if (rest_of_args == (WORD_LIST *)NULL)
|
||||
{
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++)
|
||||
;
|
||||
|
||||
sh_getopt_restore_state (dollar_vars);
|
||||
ret = sh_getopt (i, dollar_vars, optstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
register WORD_LIST *words;
|
||||
char **v;
|
||||
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++)
|
||||
;
|
||||
for (words = rest_of_args; words; words = words->next, i++)
|
||||
;
|
||||
v = strvec_create (i + 1);
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++)
|
||||
v[i] = dollar_vars[i];
|
||||
for (words = rest_of_args; words; words = words->next, i++)
|
||||
v[i] = words->word->word;
|
||||
v[i] = (char *)NULL;
|
||||
sh_getopt_restore_state (v);
|
||||
ret = sh_getopt (i, v, optstr);
|
||||
free (v);
|
||||
}
|
||||
|
||||
if (special_error)
|
||||
sh_opterr = old_opterr;
|
||||
|
||||
/* Set the OPTIND variable in any case, to handle "--" skipping. It's
|
||||
highly unlikely that 14 digits will be too few. */
|
||||
if (sh_optind < 10)
|
||||
{
|
||||
numval[14] = sh_optind + '0';
|
||||
numval[15] = '\0';
|
||||
i = 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
numval[i = 15] = '\0';
|
||||
n = sh_optind;
|
||||
do
|
||||
{
|
||||
numval[--i] = (n % 10) + '0';
|
||||
}
|
||||
while (n /= 10);
|
||||
}
|
||||
bind_variable ("OPTIND", numval + i, 0);
|
||||
|
||||
/* If an error occurred, decide which one it is and set the return
|
||||
code appropriately. In all cases, the option character in error
|
||||
is in OPTOPT. If an invalid option was encountered, OPTARG is
|
||||
NULL. If a required option argument was missing, OPTARG points
|
||||
to a NULL string (that is, sh_optarg[0] == 0). */
|
||||
if (ret == '?')
|
||||
{
|
||||
if (sh_optarg == NULL)
|
||||
ret = G_INVALID_OPT;
|
||||
else if (sh_optarg[0] == '\0')
|
||||
ret = G_ARG_MISSING;
|
||||
}
|
||||
|
||||
if (ret == G_EOF)
|
||||
{
|
||||
unbind_variable ("OPTARG");
|
||||
getopts_bind_variable (name, "?");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (ret == G_INVALID_OPT)
|
||||
{
|
||||
/* Invalid option encountered. */
|
||||
ret = getopts_bind_variable (name, "?");
|
||||
|
||||
if (special_error)
|
||||
{
|
||||
strval[0] = (char)sh_optopt;
|
||||
strval[1] = '\0';
|
||||
bind_variable ("OPTARG", strval, 0);
|
||||
}
|
||||
else
|
||||
unbind_variable ("OPTARG");
|
||||
|
||||
return (ret);
|
||||
}
|
||||
|
||||
if (ret == G_ARG_MISSING)
|
||||
{
|
||||
/* Required argument missing. */
|
||||
if (special_error)
|
||||
{
|
||||
ret = getopts_bind_variable (name, ":");
|
||||
|
||||
strval[0] = (char)sh_optopt;
|
||||
strval[1] = '\0';
|
||||
bind_variable ("OPTARG", strval, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
ret = getopts_bind_variable (name, "?");
|
||||
unbind_variable ("OPTARG");
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
bind_variable ("OPTARG", sh_optarg, 0);
|
||||
|
||||
strval[0] = (char) ret;
|
||||
strval[1] = '\0';
|
||||
return (getopts_bind_variable (name, strval));
|
||||
}
|
||||
|
||||
/* The getopts builtin. Build an argv, and call dogetopts with it. */
|
||||
int
|
||||
getopts_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char **av;
|
||||
int ac, ret;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return EX_USAGE;
|
||||
}
|
||||
|
||||
reset_internal_getopt ();
|
||||
if (internal_getopt (list, "") != -1)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
av = make_builtin_argv (list, &ac);
|
||||
ret = dogetopts (ac, av);
|
||||
free ((char *)av);
|
||||
|
||||
return (ret);
|
||||
}
|
||||
@@ -1,268 +0,0 @@
|
||||
This file is hash.def, from which is created hash.c.
|
||||
It implements the builtin "hash" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES hash.c
|
||||
|
||||
$BUILTIN hash
|
||||
$FUNCTION hash_builtin
|
||||
$SHORT_DOC hash [-lr] [-p pathname] [-dt] [name ...]
|
||||
For each NAME, the full pathname of the command is determined and
|
||||
remembered. If the -p option is supplied, PATHNAME is used as the
|
||||
full pathname of NAME, and no path search is performed. The -r
|
||||
option causes the shell to forget all remembered locations. The -d
|
||||
option causes the shell to forget the remembered location of each NAME.
|
||||
If the -t option is supplied the full pathname to which each NAME
|
||||
corresponds is printed. If multiple NAME arguments are supplied with
|
||||
-t, the NAME is printed before the hashed full pathname. The -l option
|
||||
causes output to be displayed in a format that may be reused as input.
|
||||
If no arguments are given, information about remembered commands is displayed.
|
||||
$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 "../flags.h"
|
||||
#include "../findcmd.h"
|
||||
#include "../hashcmd.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int dot_found_in_search;
|
||||
extern char *this_command_name;
|
||||
|
||||
static int add_hashed_command __P((char *, int));
|
||||
static int print_hash_info __P((BUCKET_CONTENTS *));
|
||||
static int print_portable_hash_info __P((BUCKET_CONTENTS *));
|
||||
static int print_hashed_commands __P((int));
|
||||
static int list_hashed_filename_targets __P((WORD_LIST *, int));
|
||||
|
||||
/* Print statistics on the current state of hashed commands. If LIST is
|
||||
not empty, then rehash (or hash in the first place) the specified
|
||||
commands. */
|
||||
int
|
||||
hash_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int expunge_hash_table, list_targets, list_portably, delete, opt;
|
||||
char *w, *pathname;
|
||||
|
||||
if (hashing_enabled == 0)
|
||||
{
|
||||
builtin_error (_("hashing disabled"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
expunge_hash_table = list_targets = list_portably = delete = 0;
|
||||
pathname = (char *)NULL;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "dlp:rt")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'd':
|
||||
delete = 1;
|
||||
break;
|
||||
case 'l':
|
||||
list_portably = 1;
|
||||
break;
|
||||
case 'p':
|
||||
pathname = list_optarg;
|
||||
break;
|
||||
case 'r':
|
||||
expunge_hash_table = 1;
|
||||
break;
|
||||
case 't':
|
||||
list_targets = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* hash -t requires at least one argument. */
|
||||
if (list == 0 && list_targets)
|
||||
{
|
||||
sh_needarg ("-t");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* We want hash -r to be silent, but hash -- to print hashing info, so
|
||||
we test expunge_hash_table. */
|
||||
if (list == 0 && expunge_hash_table == 0)
|
||||
{
|
||||
if (print_hashed_commands (list_portably) == 0)
|
||||
printf (_("%s: hash table empty\n"), this_command_name);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (expunge_hash_table)
|
||||
phash_flush ();
|
||||
|
||||
/* If someone runs `hash -r -t xyz' he will be disappointed. */
|
||||
if (list_targets)
|
||||
return (list_hashed_filename_targets (list, list_portably));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted && pathname && strchr (pathname, '/'))
|
||||
{
|
||||
sh_restricted (pathname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
for (opt = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
/* Add, remove or rehash the specified commands. */
|
||||
w = list->word->word;
|
||||
if (pathname)
|
||||
{
|
||||
if (is_directory (pathname))
|
||||
{
|
||||
#ifdef EISDIR
|
||||
builtin_error ("%s: %s", pathname, strerror (EISDIR));
|
||||
#else
|
||||
builtin_error ("%s: is a directory", pathname);
|
||||
#endif
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
phash_insert (w, pathname, 0, 0);
|
||||
}
|
||||
else if (absolute_program (w))
|
||||
continue;
|
||||
else if (delete && phash_remove (w))
|
||||
{
|
||||
sh_notfound (w);
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
else if (add_hashed_command (w, 0))
|
||||
opt = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
return (opt);
|
||||
}
|
||||
|
||||
static int
|
||||
add_hashed_command (w, quiet)
|
||||
char *w;
|
||||
int quiet;
|
||||
{
|
||||
int rv;
|
||||
char *full_path;
|
||||
|
||||
rv = 0;
|
||||
if (find_function (w) == 0 && find_shell_builtin (w) == 0)
|
||||
{
|
||||
full_path = find_user_command (w);
|
||||
if (full_path && executable_file (full_path))
|
||||
phash_insert (w, full_path, dot_found_in_search, 0);
|
||||
else
|
||||
{
|
||||
if (quiet == 0)
|
||||
sh_notfound (w);
|
||||
rv++;
|
||||
}
|
||||
FREE (full_path);
|
||||
}
|
||||
return (rv);
|
||||
}
|
||||
|
||||
/* Print information about current hashed info. */
|
||||
static int
|
||||
print_hash_info (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
printf ("%4d\t%s\n", item->times_found, pathdata(item)->path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
print_portable_hash_info (item)
|
||||
BUCKET_CONTENTS *item;
|
||||
{
|
||||
printf ("builtin hash -p %s %s\n", pathdata(item)->path, item->key);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
print_hashed_commands (fmt)
|
||||
int fmt;
|
||||
{
|
||||
if (hashed_filenames == 0 || HASH_ENTRIES (hashed_filenames) == 0)
|
||||
return (0);
|
||||
|
||||
if (fmt == 0)
|
||||
printf ("hits\tcommand\n");
|
||||
hash_walk (hashed_filenames, fmt ? print_portable_hash_info : print_hash_info);
|
||||
return (1);
|
||||
}
|
||||
|
||||
static int
|
||||
list_hashed_filename_targets (list, fmt)
|
||||
WORD_LIST *list;
|
||||
int fmt;
|
||||
{
|
||||
int all_found, multiple;
|
||||
char *target;
|
||||
WORD_LIST *l;
|
||||
|
||||
all_found = 1;
|
||||
multiple = list->next != 0;
|
||||
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
target = phash_search (l->word->word);
|
||||
if (target == 0)
|
||||
{
|
||||
all_found = 0;
|
||||
sh_notfound (l->word->word);
|
||||
continue;
|
||||
}
|
||||
if (fmt)
|
||||
printf ("builtin hash -p %s %s\n", target, l->word->word);
|
||||
else
|
||||
{
|
||||
if (multiple)
|
||||
printf ("%s\t", l->word->word);
|
||||
printf ("%s\n", target);
|
||||
}
|
||||
}
|
||||
|
||||
return (all_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
@@ -1,414 +0,0 @@
|
||||
This file is history.def, from which is created history.c.
|
||||
It implements the builtin "history" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES history.c
|
||||
|
||||
$BUILTIN history
|
||||
$FUNCTION history_builtin
|
||||
$DEPENDS_ON HISTORY
|
||||
$SHORT_DOC history [-c] [-d offset] [n] or history -awrn [filename] or history -ps arg [arg...]
|
||||
Display the history list with line numbers. Lines listed with
|
||||
with a `*' have been modified. Argument of N says to list only
|
||||
the last N lines. The `-c' option causes the history list to be
|
||||
cleared by deleting all of the entries. The `-d' option deletes
|
||||
the history entry at offset OFFSET. The `-w' option writes out the
|
||||
current history to the history file; `-r' means to read the file and
|
||||
append the contents to the history list instead. `-a' means
|
||||
to append history lines from this session to the history file.
|
||||
Argument `-n' means to read all history lines not already read
|
||||
from the history file and append them to the history list.
|
||||
|
||||
If FILENAME is given, then that is used as the history file else
|
||||
if $HISTFILE has a value, that is used, else ~/.bash_history.
|
||||
If the -s option is supplied, the non-option ARGs are appended to
|
||||
the history list as a single entry. The -p option means to perform
|
||||
history expansion on each ARG and display the result, without storing
|
||||
anything in the history list.
|
||||
|
||||
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.
|
||||
$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 "../bashhist.h"
|
||||
#include <readline/history.h>
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern int current_command_line_count;
|
||||
|
||||
int delete_last_history __P((void));
|
||||
|
||||
static char *histtime __P((HIST_ENTRY *, const char *));
|
||||
static void display_history __P((WORD_LIST *));
|
||||
static int delete_histent __P((int));
|
||||
static void push_history __P((WORD_LIST *));
|
||||
static int expand_and_print_history __P((WORD_LIST *));
|
||||
|
||||
#define AFLAG 0x01
|
||||
#define RFLAG 0x02
|
||||
#define WFLAG 0x04
|
||||
#define NFLAG 0x08
|
||||
#define SFLAG 0x10
|
||||
#define PFLAG 0x20
|
||||
#define CFLAG 0x40
|
||||
#define DFLAG 0x80
|
||||
|
||||
int
|
||||
history_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int flags, opt, result, old_history_lines, obase;
|
||||
char *filename, *delete_arg;
|
||||
intmax_t delete_offset;
|
||||
|
||||
flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "acd:npsrw")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
flags |= AFLAG;
|
||||
break;
|
||||
case 'c':
|
||||
flags |= CFLAG;
|
||||
break;
|
||||
case 'n':
|
||||
flags |= NFLAG;
|
||||
break;
|
||||
case 'r':
|
||||
flags |= RFLAG;
|
||||
break;
|
||||
case 'w':
|
||||
flags |= WFLAG;
|
||||
break;
|
||||
case 's':
|
||||
flags |= SFLAG;
|
||||
break;
|
||||
case 'd':
|
||||
flags |= DFLAG;
|
||||
delete_arg = list_optarg;
|
||||
break;
|
||||
case 'p':
|
||||
#if defined (BANG_HISTORY)
|
||||
flags |= PFLAG;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
opt = flags & (AFLAG|RFLAG|WFLAG|NFLAG);
|
||||
if (opt && opt != AFLAG && opt != RFLAG && opt != WFLAG && opt != NFLAG)
|
||||
{
|
||||
builtin_error (_("cannot use more than one of -anrw"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* clear the history, but allow other arguments to add to it again. */
|
||||
if (flags & CFLAG)
|
||||
{
|
||||
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 (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif
|
||||
else if (flags & DFLAG)
|
||||
{
|
||||
if ((legal_number (delete_arg, &delete_offset) == 0)
|
||||
|| (delete_offset < history_base)
|
||||
|| (delete_offset > (history_base + history_length)))
|
||||
{
|
||||
sh_erange (delete_arg, _("history position"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opt = delete_offset;
|
||||
result = 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)
|
||||
{
|
||||
display_history (list);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
filename = list ? list->word->word : get_string_value ("HISTFILE");
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
if (flags & AFLAG) /* Append session's history to file. */
|
||||
result = maybe_append_history (filename);
|
||||
else if (flags & WFLAG) /* Write entire history. */
|
||||
result = write_history (filename);
|
||||
else if (flags & RFLAG) /* Read entire file. */
|
||||
result = read_history (filename);
|
||||
else if (flags & NFLAG) /* Read `new' history from file. */
|
||||
{
|
||||
/* Read all of the lines in the file that we haven't already read. */
|
||||
old_history_lines = history_lines_in_file;
|
||||
obase = history_base;
|
||||
|
||||
using_history ();
|
||||
result = read_history_range (filename, history_lines_in_file, -1);
|
||||
using_history ();
|
||||
|
||||
history_lines_in_file = where_history ();
|
||||
|
||||
/* If we're rewriting the history file at shell exit rather than just
|
||||
appending the lines from this session to it, the question is whether
|
||||
we reset history_lines_this_session to 0, losing any history entries
|
||||
we had before we read the new entries from the history file, or
|
||||
whether we count the new entries we just read from the file as
|
||||
history lines added during this session.
|
||||
Right now, we do the latter. This will cause these history entries
|
||||
to be written to the history file along with any intermediate entries
|
||||
we add when we do a `history -a', but the alternative is losing
|
||||
them altogether. */
|
||||
if (force_append_history == 0)
|
||||
history_lines_this_session += history_lines_in_file - old_history_lines +
|
||||
history_base - obase;
|
||||
}
|
||||
|
||||
return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Accessors for HIST_ENTRY lists that are called HLIST. */
|
||||
#define histline(i) (hlist[(i)]->line)
|
||||
#define histdata(i) (hlist[(i)]->data)
|
||||
|
||||
static char *
|
||||
histtime (hlist, histtimefmt)
|
||||
HIST_ENTRY *hlist;
|
||||
const char *histtimefmt;
|
||||
{
|
||||
static char timestr[128];
|
||||
time_t t;
|
||||
|
||||
t = history_get_time (hlist);
|
||||
if (t)
|
||||
strftime (timestr, sizeof (timestr), histtimefmt, localtime (&t));
|
||||
else
|
||||
strcpy (timestr, "??");
|
||||
return timestr;
|
||||
}
|
||||
|
||||
static void
|
||||
display_history (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
intmax_t limit;
|
||||
HIST_ENTRY **hlist;
|
||||
char *histtimefmt, *timestr;
|
||||
|
||||
if (list)
|
||||
{
|
||||
limit = get_numeric_arg (list, 0);
|
||||
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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Delete and free the history list entry at offset I. */
|
||||
static int
|
||||
delete_histent (i)
|
||||
int i;
|
||||
{
|
||||
HIST_ENTRY *discard;
|
||||
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
free_history_entry (discard);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
delete_last_history ()
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent;
|
||||
int r;
|
||||
|
||||
hlist = history_list ();
|
||||
if (hlist == NULL)
|
||||
return 0;
|
||||
|
||||
for (i = 0; hlist[i]; i++)
|
||||
;
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that must be offset by history_base. */
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return 0;
|
||||
|
||||
r = delete_histent (i);
|
||||
|
||||
if (where_history () > history_length)
|
||||
history_set_pos (history_length);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Remove the last entry in the history list and add each argument in
|
||||
LIST to the history. */
|
||||
static void
|
||||
push_history (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *s;
|
||||
|
||||
/* Delete the last history entry if it was a single entry added to the
|
||||
history list (generally the `history -s' itself), or if `history -s'
|
||||
is being used in a compound command and the compound command was
|
||||
added to the history as a single element (command-oriented history).
|
||||
If you don't want history -s to remove the compound command from the
|
||||
history, change #if 0 to #if 1 below. */
|
||||
#if 0
|
||||
if (hist_last_line_pushed == 0 && hist_last_line_added && delete_last_history () == 0)
|
||||
#else
|
||||
if (hist_last_line_pushed == 0 &&
|
||||
(hist_last_line_added ||
|
||||
(current_command_line_count > 0 && current_command_first_line_saved && command_oriented_history))
|
||||
&& 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 && 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 */
|
||||
@@ -1,280 +0,0 @@
|
||||
This file is jobs.def, from which is created jobs.c.
|
||||
It implements the builtins "jobs" and "disown" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES jobs.c
|
||||
|
||||
$BUILTIN jobs
|
||||
$FUNCTION jobs_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args]
|
||||
Lists the active jobs. The -l option lists process id's in addition
|
||||
to the normal information; the -p option lists process id's only.
|
||||
If -n is given, only processes that have changed status since the last
|
||||
notification are printed. JOBSPEC restricts output to that job. The
|
||||
-r and -s options restrict output to running and stopped jobs only,
|
||||
respectively. Without options, the status of all active jobs is
|
||||
printed. If -x is given, COMMAND is run after all job specifications
|
||||
that appear in ARGS have been replaced with the process ID of that job's
|
||||
process group leader.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
#include "../bashtypes.h"
|
||||
#include <signal.h>
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#define JSTATE_ANY 0x0
|
||||
#define JSTATE_RUNNING 0x1
|
||||
#define JSTATE_STOPPED 0x2
|
||||
|
||||
static int execute_list_with_replacements __P((WORD_LIST *));
|
||||
|
||||
/* The `jobs' command. Prints outs a list of active jobs. If the
|
||||
argument `-l' is given, then the process id's are printed also.
|
||||
If the argument `-p' is given, print the process group leader's
|
||||
pid only. If `-n' is given, only processes that have changed
|
||||
status since the last notification are printed. If -x is given,
|
||||
replace all job specs with the pid of the appropriate process
|
||||
group leader and execute the command. The -r and -s options mean
|
||||
to print info about running and stopped jobs only, respectively. */
|
||||
int
|
||||
jobs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int form, execute, state, opt, any_failed, job;
|
||||
sigset_t set, oset;
|
||||
|
||||
execute = any_failed = 0;
|
||||
form = JLIST_STANDARD;
|
||||
state = JSTATE_ANY;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lpnxrs")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
form = JLIST_LONG;
|
||||
break;
|
||||
case 'p':
|
||||
form = JLIST_PID_ONLY;
|
||||
break;
|
||||
case 'n':
|
||||
form = JLIST_CHANGED_ONLY;
|
||||
break;
|
||||
case 'x':
|
||||
if (form != JLIST_STANDARD)
|
||||
{
|
||||
builtin_error (_("no other options allowed with `-x'"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
execute++;
|
||||
break;
|
||||
case 'r':
|
||||
state = JSTATE_RUNNING;
|
||||
break;
|
||||
case 's':
|
||||
state = JSTATE_STOPPED;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (execute)
|
||||
return (execute_list_with_replacements (list));
|
||||
|
||||
if (!list)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case JSTATE_ANY:
|
||||
list_all_jobs (form);
|
||||
break;
|
||||
case JSTATE_RUNNING:
|
||||
list_running_jobs (form);
|
||||
break;
|
||||
case JSTATE_STOPPED:
|
||||
list_stopped_jobs (form);
|
||||
break;
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
|
||||
{
|
||||
sh_badjob (list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
else if (job != DUP_JOB)
|
||||
list_one_job ((JOB *)NULL, form, 0, job);
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
list = list->next;
|
||||
}
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
execute_list_with_replacements (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register WORD_LIST *l;
|
||||
int job, result;
|
||||
COMMAND *command;
|
||||
JOB *j;
|
||||
|
||||
/* First do the replacement of job specifications with pids. */
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
if (l->word->word[0] == '%') /* we have a winner */
|
||||
{
|
||||
job = get_job_spec (l);
|
||||
|
||||
/* A bad job spec is not really a job spec! Pass it through. */
|
||||
if (INVALID_JOB (job))
|
||||
continue;
|
||||
|
||||
j = get_job_by_jid (job);
|
||||
free (l->word->word);
|
||||
l->word->word = itos (j->pgrp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next make a new simple command and execute it. */
|
||||
begin_unwind_frame ("jobs_builtin");
|
||||
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= CMD_INHIBIT_EXPANSION;
|
||||
command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
|
||||
|
||||
add_unwind_protect (dispose_command, command);
|
||||
result = execute_command (command);
|
||||
dispose_command (command);
|
||||
|
||||
discard_unwind_frame ("jobs_builtin");
|
||||
return (result);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
$BUILTIN disown
|
||||
$FUNCTION disown_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC disown [-h] [-ar] [jobspec ...]
|
||||
By default, removes each JOBSPEC argument from the table of active jobs.
|
||||
If the -h option is given, the job is not removed from the table, but is
|
||||
marked so that SIGHUP is not sent to the job if the shell receives a
|
||||
SIGHUP. The -a option, when JOBSPEC is not supplied, means to remove all
|
||||
jobs from the job table; the -r option means to remove only running jobs.
|
||||
$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;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
retval = EXECUTION_SUCCESS;
|
||||
|
||||
/* `disown -a' or `disown -r' */
|
||||
if (list == 0 && (all_jobs || running_jobs))
|
||||
{
|
||||
if (nohup_only)
|
||||
nohup_all_jobs (running_jobs);
|
||||
else
|
||||
delete_all_jobs (running_jobs);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
|
||||
? get_job_by_pid ((pid_t) pid_value, 0)
|
||||
: get_job_spec (list);
|
||||
|
||||
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
|
||||
{
|
||||
sh_badjob (list ? list->word->word : "current");
|
||||
retval = EXECUTION_FAILURE;
|
||||
}
|
||||
else if (nohup_only)
|
||||
nohup_job (job);
|
||||
else
|
||||
delete_job (job, 1);
|
||||
UNBLOCK_CHILD (oset);
|
||||
|
||||
if (list)
|
||||
list = list->next;
|
||||
}
|
||||
while (list);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
@@ -1,252 +0,0 @@
|
||||
This file is kill.def, from which is created kill.c.
|
||||
It implements the builtin "kill" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES kill.c
|
||||
|
||||
$BUILTIN kill
|
||||
$FUNCTION kill_builtin
|
||||
$SHORT_DOC kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
|
||||
Send the processes named by PID (or JOBSPEC) the signal SIGSPEC. If
|
||||
SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l'
|
||||
lists the signal names; if arguments follow `-l' they are assumed to
|
||||
be signal numbers for which names should be listed. Kill is a shell
|
||||
builtin for two reasons: it allows job IDs to be used instead of
|
||||
process IDs, and, if you have reached the limit on processes that
|
||||
you can create, you don't have to start a process to kill another one.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../trap.h"
|
||||
#include "../jobs.h"
|
||||
#include "common.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int posixly_correct;
|
||||
|
||||
static void kill_error __P((pid_t, int));
|
||||
|
||||
#if !defined (CONTINUE_AFTER_KILL_ERROR)
|
||||
# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE)
|
||||
#else
|
||||
# define CONTINUE_OR_FAIL goto continue_killing
|
||||
#endif /* CONTINUE_AFTER_KILL_ERROR */
|
||||
|
||||
/* Here is the kill builtin. We only have it so that people can type
|
||||
kill -KILL %1? No, if you fill up the process table this way you
|
||||
can still kill some. */
|
||||
int
|
||||
kill_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int sig, any_succeeded, listing, saw_signal, dflags;
|
||||
char *sigspec, *word;
|
||||
pid_t pid;
|
||||
intmax_t pid_value;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
any_succeeded = listing = saw_signal = 0;
|
||||
sig = SIGTERM;
|
||||
sigspec = "TERM";
|
||||
|
||||
dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0);
|
||||
/* Process options. */
|
||||
while (list)
|
||||
{
|
||||
word = list->word->word;
|
||||
|
||||
if (ISOPTION (word, 'l'))
|
||||
{
|
||||
listing++;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (word, 's') || ISOPTION (word, 'n'))
|
||||
{
|
||||
list = list->next;
|
||||
if (list)
|
||||
{
|
||||
sigspec = list->word->word;
|
||||
if (sigspec[0] == '0' && sigspec[1] == '\0')
|
||||
sig = 0;
|
||||
else
|
||||
sig = decode_signal (sigspec, dflags);
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_needarg (word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (ISOPTION (word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (ISOPTION (word, '?'))
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
/* If this is a signal specification then process it. We only process
|
||||
the first one seen; other arguments may signify process groups (e.g,
|
||||
-num == process group num). */
|
||||
else if ((*word == '-') && !saw_signal)
|
||||
{
|
||||
sigspec = word + 1;
|
||||
sig = decode_signal (sigspec, dflags);
|
||||
saw_signal++;
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
return (display_signal_list (list, 0));
|
||||
|
||||
/* OK, we are killing processes. */
|
||||
if (sig == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (sigspec);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
word = list->word->word;
|
||||
|
||||
if (*word == '-')
|
||||
word++;
|
||||
|
||||
/* Use the entire argument in case of minus sign presence. */
|
||||
if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value))
|
||||
{
|
||||
pid = (pid_t) pid_value;
|
||||
|
||||
if ((pid < -1 ? kill_pid (-pid, sig, 1) : kill_pid (pid, sig, 0)) < 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);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,995 +0,0 @@
|
||||
This file is printf.def, from which is created printf.c.
|
||||
It implements the builtin "printf" in Bash.
|
||||
|
||||
Copyright (C) 1997-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA
|
||||
|
||||
$PRODUCES printf.c
|
||||
|
||||
$BUILTIN printf
|
||||
$FUNCTION printf_builtin
|
||||
$SHORT_DOC printf [-v var] format [arguments]
|
||||
printf formats and prints ARGUMENTS under control of the FORMAT. FORMAT
|
||||
is a character string which contains three types of objects: plain
|
||||
characters, which are simply copied to standard output, character escape
|
||||
sequences which are converted and copied to the standard output, and
|
||||
format specifications, each of which causes printing of the next successive
|
||||
argument. In addition to the standard printf(1) formats, %b means to
|
||||
expand backslash escape sequences in the corresponding argument, and %q
|
||||
means to quote the argument in a way that can be reused as shell input.
|
||||
If the -v option is supplied, the output is placed into the value of the
|
||||
shell variable VAR rather than being sent to the standard output.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
|
||||
#include <errno.h>
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#else
|
||||
/* Assume 32-bit ints. */
|
||||
# define INT_MAX 2147483647
|
||||
# define INT_MIN (-2147483647-1)
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <chartypes.h>
|
||||
|
||||
#ifdef HAVE_INTTYPES_H
|
||||
# include <inttypes.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "stdc.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (PRIdMAX)
|
||||
# if HAVE_LONG_LONG
|
||||
# define PRIdMAX "lld"
|
||||
# else
|
||||
# define PRIdMAX "ld"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#define PC(c) \
|
||||
do { \
|
||||
char b[2]; \
|
||||
tw++; \
|
||||
b[0] = c; b[1] = '\0'; \
|
||||
if (vflag) \
|
||||
vbadd (b, 1); \
|
||||
else \
|
||||
putchar (c); \
|
||||
} while (0)
|
||||
|
||||
#define PF(f, func) \
|
||||
do { \
|
||||
char *b = 0; \
|
||||
int nw; \
|
||||
if (have_fieldwidth && have_precision) \
|
||||
nw = asprintf(&b, f, fieldwidth, precision, func); \
|
||||
else if (have_fieldwidth) \
|
||||
nw = asprintf(&b, f, fieldwidth, func); \
|
||||
else if (have_precision) \
|
||||
nw = asprintf(&b, f, precision, func); \
|
||||
else \
|
||||
nw = asprintf(&b, f, func); \
|
||||
tw += nw; \
|
||||
if (b) \
|
||||
{ \
|
||||
if (vflag) \
|
||||
(void)vbadd (b, nw); \
|
||||
else \
|
||||
(void)fputs (b, stdout); \
|
||||
free (b); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* We free the buffer used by mklong() if it's `too big'. */
|
||||
#define PRETURN(value) \
|
||||
do \
|
||||
{ \
|
||||
if (vflag) \
|
||||
{ \
|
||||
bind_variable (vname, vbuf, 0); \
|
||||
stupidly_hack_special_variables (vname); \
|
||||
} \
|
||||
if (conv_bufsize > 4096 ) \
|
||||
{ \
|
||||
free (conv_buf); \
|
||||
conv_bufsize = 0; \
|
||||
conv_buf = 0; \
|
||||
} \
|
||||
if (vbsize > 4096) \
|
||||
{ \
|
||||
free (vbuf); \
|
||||
vbsize = 0; \
|
||||
vbuf = 0; \
|
||||
} \
|
||||
fflush (stdout); \
|
||||
return (value); \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
#define SKIP1 "#'-+ 0"
|
||||
#define LENMODS "hjlLtz"
|
||||
|
||||
static void printf_erange __P((char *));
|
||||
static int printstr __P((char *, char *, int, int, int));
|
||||
static int tescape __P((char *, char *, int *));
|
||||
static char *bexpand __P((char *, int, int *, int *));
|
||||
static char *vbadd __P((char *, int));
|
||||
static char *mklong __P((char *, char *, size_t));
|
||||
static int getchr __P((void));
|
||||
static char *getstr __P((void));
|
||||
static int getint __P((void));
|
||||
static intmax_t getintmax __P((void));
|
||||
static uintmax_t getuintmax __P((void));
|
||||
|
||||
#if defined (HAVE_LONG_DOUBLE) && HAVE_DECL_STRTOLD && !defined(STRTOLD_BROKEN)
|
||||
typedef long double floatmax_t;
|
||||
# define FLOATMAX_CONV "L"
|
||||
# define strtofltmax strtold
|
||||
#else
|
||||
typedef double floatmax_t;
|
||||
# define FLOATMAX_CONV ""
|
||||
# define strtofltmax strtod
|
||||
#endif
|
||||
static floatmax_t getfloatmax __P((void));
|
||||
|
||||
static int asciicode __P((void));
|
||||
|
||||
static WORD_LIST *garglist;
|
||||
static int retval;
|
||||
static int conversion_error;
|
||||
|
||||
/* printf -v var support */
|
||||
static int vflag = 0;
|
||||
static char *vbuf, *vname;
|
||||
static size_t vbsize;
|
||||
static int vblen;
|
||||
|
||||
static intmax_t tw;
|
||||
|
||||
static char *conv_buf;
|
||||
static size_t conv_bufsize;
|
||||
|
||||
int
|
||||
printf_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int ch, fieldwidth, precision;
|
||||
int have_fieldwidth, have_precision;
|
||||
char convch, thisch, nextch, *format, *modstart, *fmt, *start;
|
||||
|
||||
conversion_error = 0;
|
||||
retval = EXECUTION_SUCCESS;
|
||||
|
||||
vflag = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((ch = internal_getopt (list, "v:")) != -1)
|
||||
{
|
||||
switch (ch)
|
||||
{
|
||||
case 'v':
|
||||
if (legal_identifier (vname = list_optarg))
|
||||
{
|
||||
vflag = 1;
|
||||
vblen = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidid (vname);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend; /* skip over possible `--' */
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
if (list->word->word == 0 || list->word->word[0] == '\0')
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
format = list->word->word;
|
||||
tw = 0;
|
||||
|
||||
garglist = list->next;
|
||||
|
||||
/* If the format string is empty after preprocessing, return immediately. */
|
||||
if (format == 0 || *format == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
/* Basic algorithm is to scan the format string for conversion
|
||||
specifications -- once one is found, find out if the field
|
||||
width or precision is a '*'; if it is, gather up value. Note,
|
||||
format strings are reused as necessary to use up the provided
|
||||
arguments, arguments of zero/null string are provided to use
|
||||
up the format string. */
|
||||
do
|
||||
{
|
||||
tw = 0;
|
||||
/* find next format specification */
|
||||
for (fmt = format; *fmt; fmt++)
|
||||
{
|
||||
precision = fieldwidth = 0;
|
||||
have_fieldwidth = have_precision = 0;
|
||||
|
||||
if (*fmt == '\\')
|
||||
{
|
||||
fmt++;
|
||||
/* A NULL third argument to tescape means to bypass the
|
||||
special processing for arguments to %b. */
|
||||
fmt += tescape (fmt, &nextch, (int *)NULL);
|
||||
PC (nextch);
|
||||
fmt--; /* for loop will increment it for us again */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*fmt != '%')
|
||||
{
|
||||
PC (*fmt);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* ASSERT(*fmt == '%') */
|
||||
start = fmt++;
|
||||
|
||||
if (*fmt == '%') /* %% prints a % */
|
||||
{
|
||||
PC ('%');
|
||||
continue;
|
||||
}
|
||||
|
||||
/* found format specification, skip to field width */
|
||||
for (; *fmt && strchr(SKIP1, *fmt); ++fmt)
|
||||
;
|
||||
|
||||
/* Skip optional field width. */
|
||||
if (*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
have_fieldwidth = 1;
|
||||
fieldwidth = getint ();
|
||||
}
|
||||
else
|
||||
while (DIGIT (*fmt))
|
||||
fmt++;
|
||||
|
||||
/* Skip optional '.' and precision */
|
||||
if (*fmt == '.')
|
||||
{
|
||||
++fmt;
|
||||
if (*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
have_precision = 1;
|
||||
precision = getint ();
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Negative precisions are allowed but treated as if the
|
||||
precision were missing; I would like to allow a leading
|
||||
`+' in the precision number as an extension, but lots
|
||||
of asprintf/fprintf implementations get this wrong. */
|
||||
#if 0
|
||||
if (*fmt == '-' || *fmt == '+')
|
||||
#else
|
||||
if (*fmt == '-')
|
||||
#endif
|
||||
fmt++;
|
||||
while (DIGIT (*fmt))
|
||||
fmt++;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip possible format modifiers */
|
||||
modstart = fmt;
|
||||
while (*fmt && strchr (LENMODS, *fmt))
|
||||
fmt++;
|
||||
|
||||
if (*fmt == 0)
|
||||
{
|
||||
builtin_error (_("`%s': missing format character"), start);
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
convch = *fmt;
|
||||
thisch = modstart[0];
|
||||
nextch = modstart[1];
|
||||
modstart[0] = convch;
|
||||
modstart[1] = '\0';
|
||||
|
||||
switch(convch)
|
||||
{
|
||||
case 'c':
|
||||
{
|
||||
char p;
|
||||
|
||||
p = getchr ();
|
||||
PF(start, p);
|
||||
break;
|
||||
}
|
||||
|
||||
case 's':
|
||||
{
|
||||
char *p;
|
||||
|
||||
p = getstr ();
|
||||
PF(start, p);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n':
|
||||
{
|
||||
char *var;
|
||||
|
||||
var = getstr ();
|
||||
if (var && *var)
|
||||
{
|
||||
if (legal_identifier (var))
|
||||
bind_var_to_int (var, tw);
|
||||
else
|
||||
{
|
||||
sh_invalidid (var);
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'b': /* expand escapes in argument */
|
||||
{
|
||||
char *p, *xp;
|
||||
int rlen, r;
|
||||
|
||||
p = getstr ();
|
||||
ch = rlen = r = 0;
|
||||
xp = bexpand (p, strlen (p), &ch, &rlen);
|
||||
|
||||
if (xp)
|
||||
{
|
||||
/* Have to use printstr because of possible NUL bytes
|
||||
in XP -- printf does not handle that well. */
|
||||
r = printstr (start, xp, rlen, fieldwidth, precision);
|
||||
if (r < 0)
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
retval = EXECUTION_FAILURE;
|
||||
}
|
||||
free (xp);
|
||||
}
|
||||
|
||||
if (ch || r < 0)
|
||||
PRETURN (retval);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'q': /* print with shell quoting */
|
||||
{
|
||||
char *p, *xp;
|
||||
int r;
|
||||
|
||||
r = 0;
|
||||
p = getstr ();
|
||||
if (ansic_shouldquote (p))
|
||||
xp = ansic_quote (p, 0, (int *)0);
|
||||
else
|
||||
xp = sh_backslash_quote (p);
|
||||
if (xp)
|
||||
{
|
||||
/* Use printstr to get fieldwidth and precision right. */
|
||||
r = printstr (start, xp, strlen (xp), fieldwidth, precision);
|
||||
if (r < 0)
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
}
|
||||
free (xp);
|
||||
}
|
||||
|
||||
if (r < 0)
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'd':
|
||||
case 'i':
|
||||
{
|
||||
char *f;
|
||||
long p;
|
||||
intmax_t pp;
|
||||
|
||||
p = pp = getintmax ();
|
||||
if (p != pp)
|
||||
{
|
||||
f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
|
||||
PF (f, pp);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Optimize the common case where the integer fits
|
||||
in "long". This also works around some long
|
||||
long and/or intmax_t library bugs in the common
|
||||
case, e.g. glibc 2.2 x86. */
|
||||
f = mklong (start, "l", 1);
|
||||
PF (f, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'o':
|
||||
case 'u':
|
||||
case 'x':
|
||||
case 'X':
|
||||
{
|
||||
char *f;
|
||||
unsigned long p;
|
||||
uintmax_t pp;
|
||||
|
||||
p = pp = getuintmax ();
|
||||
if (p != pp)
|
||||
{
|
||||
f = mklong (start, PRIdMAX, sizeof (PRIdMAX) - 2);
|
||||
PF (f, pp);
|
||||
}
|
||||
else
|
||||
{
|
||||
f = mklong (start, "l", 1);
|
||||
PF (f, p);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'e':
|
||||
case 'E':
|
||||
case 'f':
|
||||
case 'F':
|
||||
case 'g':
|
||||
case 'G':
|
||||
#if defined (HAVE_PRINTF_A_FORMAT)
|
||||
case 'a':
|
||||
case 'A':
|
||||
#endif
|
||||
{
|
||||
char *f;
|
||||
floatmax_t p;
|
||||
|
||||
p = getfloatmax ();
|
||||
f = mklong (start, FLOATMAX_CONV, sizeof(FLOATMAX_CONV) - 1);
|
||||
PF (f, p);
|
||||
break;
|
||||
}
|
||||
|
||||
/* We don't output unrecognized format characters; we print an
|
||||
error message and return a failure exit status. */
|
||||
default:
|
||||
builtin_error (_("`%c': invalid format character"), convch);
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
modstart[0] = thisch;
|
||||
modstart[1] = nextch;
|
||||
}
|
||||
|
||||
if (ferror (stdout))
|
||||
{
|
||||
sh_wrerror ();
|
||||
clearerr (stdout);
|
||||
PRETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
while (garglist && garglist != list->next);
|
||||
|
||||
if (conversion_error)
|
||||
retval = EXECUTION_FAILURE;
|
||||
|
||||
PRETURN (retval);
|
||||
}
|
||||
|
||||
static void
|
||||
printf_erange (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error ("warning: %s: %s", s, strerror(ERANGE));
|
||||
}
|
||||
|
||||
/* We duplicate a lot of what printf(3) does here. */
|
||||
static int
|
||||
printstr (fmt, string, len, fieldwidth, precision)
|
||||
char *fmt; /* format */
|
||||
char *string; /* expanded string argument */
|
||||
int len; /* length of expanded string */
|
||||
int fieldwidth; /* argument for width of `*' */
|
||||
int precision; /* argument for precision of `*' */
|
||||
{
|
||||
#if 0
|
||||
char *s;
|
||||
#endif
|
||||
int padlen, nc, ljust, i;
|
||||
int fw, pr; /* fieldwidth and precision */
|
||||
|
||||
#if 0
|
||||
if (string == 0 || *string == '\0')
|
||||
#else
|
||||
if (string == 0 || len == 0)
|
||||
#endif
|
||||
return;
|
||||
|
||||
#if 0
|
||||
s = fmt;
|
||||
#endif
|
||||
if (*fmt == '%')
|
||||
fmt++;
|
||||
|
||||
ljust = fw = 0;
|
||||
pr = -1;
|
||||
|
||||
/* skip flags */
|
||||
while (strchr (SKIP1, *fmt))
|
||||
{
|
||||
if (*fmt == '-')
|
||||
ljust = 1;
|
||||
fmt++;
|
||||
}
|
||||
|
||||
/* get fieldwidth, if present */
|
||||
if (*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
fw = fieldwidth;
|
||||
if (fw < 0)
|
||||
{
|
||||
fw = -fw;
|
||||
ljust = 1;
|
||||
}
|
||||
}
|
||||
else if (DIGIT (*fmt))
|
||||
{
|
||||
fw = *fmt++ - '0';
|
||||
while (DIGIT (*fmt))
|
||||
fw = (fw * 10) + (*fmt++ - '0');
|
||||
}
|
||||
|
||||
/* get precision, if present */
|
||||
if (*fmt == '.')
|
||||
{
|
||||
fmt++;
|
||||
if (*fmt == '*')
|
||||
{
|
||||
fmt++;
|
||||
pr = precision;
|
||||
}
|
||||
else if (DIGIT (*fmt))
|
||||
{
|
||||
pr = *fmt++ - '0';
|
||||
while (DIGIT (*fmt))
|
||||
pr = (pr * 10) + (*fmt++ - '0');
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* If we remove this, get rid of `s'. */
|
||||
if (*fmt != 'b' && *fmt != 'q')
|
||||
{
|
||||
internal_error ("format parsing problem: %s", s);
|
||||
fw = pr = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* chars from string to print */
|
||||
nc = (pr >= 0 && pr <= len) ? pr : len;
|
||||
|
||||
padlen = fw - nc;
|
||||
if (padlen < 0)
|
||||
padlen = 0;
|
||||
if (ljust)
|
||||
padlen = -padlen;
|
||||
|
||||
/* leading pad characters */
|
||||
for (; padlen > 0; padlen--)
|
||||
PC (' ');
|
||||
|
||||
/* output NC characters from STRING */
|
||||
for (i = 0; i < nc; i++)
|
||||
PC (string[i]);
|
||||
|
||||
/* output any necessary trailing padding */
|
||||
for (; padlen < 0; padlen++)
|
||||
PC (' ');
|
||||
|
||||
return (ferror (stdout) ? -1 : 0);
|
||||
}
|
||||
|
||||
/* Convert STRING by expanding the escape sequences specified by the
|
||||
POSIX standard for printf's `%b' format string. If SAWC is non-null,
|
||||
perform the processing appropriate for %b arguments. In particular,
|
||||
recognize `\c' and use that as a string terminator. If we see \c, set
|
||||
*SAWC to 1 before returning. LEN is the length of STRING. */
|
||||
|
||||
/* Translate a single backslash-escape sequence starting at ESTART (the
|
||||
character after the backslash) and return the number of characters
|
||||
consumed by the sequence. CP is the place to return the translated
|
||||
value. *SAWC is set to 1 if the escape sequence was \c, since that means
|
||||
to short-circuit the rest of the processing. If SAWC is null, we don't
|
||||
do the \c short-circuiting, and \c is treated as an unrecognized escape
|
||||
sequence; we also bypass the other processing specific to %b arguments. */
|
||||
static int
|
||||
tescape (estart, cp, sawc)
|
||||
char *estart;
|
||||
char *cp;
|
||||
int *sawc;
|
||||
{
|
||||
register char *p;
|
||||
int temp, c, evalue;
|
||||
|
||||
p = estart;
|
||||
|
||||
switch (c = *p++)
|
||||
{
|
||||
#if defined (__STDC__)
|
||||
case 'a': *cp = '\a'; break;
|
||||
#else
|
||||
case 'a': *cp = '\007'; break;
|
||||
#endif
|
||||
|
||||
case 'b': *cp = '\b'; break;
|
||||
|
||||
case 'e':
|
||||
case 'E': *cp = '\033'; break; /* ESC -- non-ANSI */
|
||||
|
||||
case 'f': *cp = '\f'; break;
|
||||
|
||||
case 'n': *cp = '\n'; break;
|
||||
|
||||
case 'r': *cp = '\r'; break;
|
||||
|
||||
case 't': *cp = '\t'; break;
|
||||
|
||||
case 'v': *cp = '\v'; break;
|
||||
|
||||
/* The octal escape sequences are `\0' followed by up to three octal
|
||||
digits (if SAWC), or `\' followed by up to three octal digits (if
|
||||
!SAWC). As an extension, we allow the latter form even if SAWC. */
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
evalue = OCTVALUE (c);
|
||||
for (temp = 2 + (!evalue && !!sawc); ISOCTAL (*p) && temp--; p++)
|
||||
evalue = (evalue * 8) + OCTVALUE (*p);
|
||||
*cp = evalue & 0xFF;
|
||||
break;
|
||||
|
||||
/* And, as another extension, we allow \xNNN, where each N is a
|
||||
hex digit. */
|
||||
case 'x':
|
||||
#if 0
|
||||
for (evalue = 0; ISXDIGIT ((unsigned char)*p); p++)
|
||||
#else
|
||||
for (temp = 2, evalue = 0; ISXDIGIT ((unsigned char)*p) && temp--; p++)
|
||||
#endif
|
||||
evalue = (evalue * 16) + HEXVALUE (*p);
|
||||
if (p == estart + 1)
|
||||
{
|
||||
builtin_error (_("missing hex digit for \\x"));
|
||||
*cp = '\\';
|
||||
return 0;
|
||||
}
|
||||
*cp = evalue & 0xFF;
|
||||
break;
|
||||
|
||||
case '\\': /* \\ -> \ */
|
||||
*cp = c;
|
||||
break;
|
||||
|
||||
/* SAWC == 0 means that \', \", and \? are recognized as escape
|
||||
sequences, though the only processing performed is backslash
|
||||
removal. */
|
||||
case '\'': case '"': case '?':
|
||||
if (!sawc)
|
||||
*cp = c;
|
||||
else
|
||||
{
|
||||
*cp = '\\';
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
if (sawc)
|
||||
{
|
||||
*sawc = 1;
|
||||
break;
|
||||
}
|
||||
/* other backslash escapes are passed through unaltered */
|
||||
default:
|
||||
*cp = '\\';
|
||||
return 0;
|
||||
}
|
||||
return (p - estart);
|
||||
}
|
||||
|
||||
static char *
|
||||
bexpand (string, len, sawc, lenp)
|
||||
char *string;
|
||||
int len, *sawc, *lenp;
|
||||
{
|
||||
int temp;
|
||||
char *ret, *r, *s, c;
|
||||
|
||||
#if 0
|
||||
if (string == 0 || *string == '\0')
|
||||
#else
|
||||
if (string == 0 || len == 0)
|
||||
#endif
|
||||
{
|
||||
if (sawc)
|
||||
*sawc = 0;
|
||||
if (lenp)
|
||||
*lenp = 0;
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
ret = (char *)xmalloc (len + 1);
|
||||
for (r = ret, s = string; s && *s; )
|
||||
{
|
||||
c = *s++;
|
||||
if (c != '\\' || *s == '\0')
|
||||
{
|
||||
*r++ = c;
|
||||
continue;
|
||||
}
|
||||
temp = 0;
|
||||
s += tescape (s, &c, &temp);
|
||||
if (temp)
|
||||
{
|
||||
if (sawc)
|
||||
*sawc = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
*r++ = c;
|
||||
}
|
||||
|
||||
*r = '\0';
|
||||
if (lenp)
|
||||
*lenp = r - ret;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
vbadd (buf, blen)
|
||||
char *buf;
|
||||
int blen;
|
||||
{
|
||||
size_t nlen;
|
||||
|
||||
nlen = vblen + blen + 1;
|
||||
if (nlen >= vbsize)
|
||||
{
|
||||
vbsize = ((nlen + 63) >> 6) << 6;
|
||||
vbuf = (char *)xrealloc (vbuf, vbsize);
|
||||
}
|
||||
|
||||
if (blen == 1)
|
||||
vbuf[vblen++] = buf[0];
|
||||
else
|
||||
{
|
||||
FASTCOPY (buf, vbuf + vblen, blen);
|
||||
vblen += blen;
|
||||
}
|
||||
vbuf[vblen] = '\0';
|
||||
|
||||
if (strlen (vbuf) != vblen)
|
||||
internal_error ("printf:vbadd: vblen (%d) != strlen (vbuf) (%d)", vblen, strlen (vbuf));
|
||||
|
||||
return vbuf;
|
||||
}
|
||||
|
||||
static char *
|
||||
mklong (str, modifiers, mlen)
|
||||
char *str;
|
||||
char *modifiers;
|
||||
size_t mlen;
|
||||
{
|
||||
size_t len, slen;
|
||||
|
||||
slen = strlen (str);
|
||||
len = slen + mlen + 1;
|
||||
|
||||
if (len > conv_bufsize)
|
||||
{
|
||||
conv_bufsize = (((len + 1023) >> 10) << 10);
|
||||
conv_buf = (char *)xrealloc (conv_buf, conv_bufsize);
|
||||
}
|
||||
|
||||
FASTCOPY (str, conv_buf, slen - 1);
|
||||
FASTCOPY (modifiers, conv_buf + slen - 1, mlen);
|
||||
|
||||
conv_buf[len - 2] = str[slen - 1];
|
||||
conv_buf[len - 1] = '\0';
|
||||
return (conv_buf);
|
||||
}
|
||||
|
||||
static int
|
||||
getchr ()
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (garglist == 0)
|
||||
return ('\0');
|
||||
|
||||
ret = (int)garglist->word->word[0];
|
||||
garglist = garglist->next;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static char *
|
||||
getstr ()
|
||||
{
|
||||
char *ret;
|
||||
|
||||
if (garglist == 0)
|
||||
return ("");
|
||||
|
||||
ret = garglist->word->word;
|
||||
garglist = garglist->next;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
getint ()
|
||||
{
|
||||
intmax_t ret;
|
||||
|
||||
ret = getintmax ();
|
||||
|
||||
if (ret > INT_MAX)
|
||||
{
|
||||
printf_erange (garglist->word->word);
|
||||
ret = INT_MAX;
|
||||
}
|
||||
else if (ret < INT_MIN)
|
||||
{
|
||||
printf_erange (garglist->word->word);
|
||||
ret = INT_MIN;
|
||||
}
|
||||
|
||||
return ((int)ret);
|
||||
}
|
||||
|
||||
static intmax_t
|
||||
getintmax ()
|
||||
{
|
||||
intmax_t ret;
|
||||
char *ep;
|
||||
|
||||
if (garglist == 0)
|
||||
return (0);
|
||||
|
||||
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
|
||||
return asciicode ();
|
||||
|
||||
errno = 0;
|
||||
ret = strtoimax (garglist->word->word, &ep, 0);
|
||||
|
||||
if (*ep)
|
||||
{
|
||||
sh_invalidnum (garglist->word->word);
|
||||
/* POSIX.2 says ``...a diagnostic message shall be written to standard
|
||||
error, and the utility shall not exit with a zero exit status, but
|
||||
shall continue processing any remaining operands and shall write the
|
||||
value accumulated at the time the error was detected to standard
|
||||
output.'' Yecch. */
|
||||
ret = 0;
|
||||
conversion_error = 1;
|
||||
}
|
||||
else if (errno == ERANGE)
|
||||
printf_erange (garglist->word->word);
|
||||
|
||||
garglist = garglist->next;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static uintmax_t
|
||||
getuintmax ()
|
||||
{
|
||||
uintmax_t ret;
|
||||
char *ep;
|
||||
|
||||
if (garglist == 0)
|
||||
return (0);
|
||||
|
||||
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
|
||||
return asciicode ();
|
||||
|
||||
errno = 0;
|
||||
ret = strtoumax (garglist->word->word, &ep, 0);
|
||||
|
||||
if (*ep)
|
||||
{
|
||||
sh_invalidnum (garglist->word->word);
|
||||
/* Same POSIX.2 conversion error requirements as getintmax(). */
|
||||
ret = 0;
|
||||
conversion_error = 1;
|
||||
}
|
||||
else if (errno == ERANGE)
|
||||
printf_erange (garglist->word->word);
|
||||
|
||||
garglist = garglist->next;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
static floatmax_t
|
||||
getfloatmax ()
|
||||
{
|
||||
floatmax_t ret;
|
||||
char *ep;
|
||||
|
||||
if (garglist == 0)
|
||||
return (0);
|
||||
|
||||
if (garglist->word->word[0] == '\'' || garglist->word->word[0] == '"')
|
||||
return asciicode ();
|
||||
|
||||
errno = 0;
|
||||
ret = strtofltmax (garglist->word->word, &ep);
|
||||
|
||||
if (*ep)
|
||||
{
|
||||
sh_invalidnum (garglist->word->word);
|
||||
/* Same thing about POSIX.2 conversion error requirements. */
|
||||
ret = 0;
|
||||
conversion_error = 1;
|
||||
}
|
||||
else if (errno == ERANGE)
|
||||
printf_erange (garglist->word->word);
|
||||
|
||||
garglist = garglist->next;
|
||||
return (ret);
|
||||
}
|
||||
|
||||
/* NO check is needed for garglist here. */
|
||||
static int
|
||||
asciicode ()
|
||||
{
|
||||
register int ch;
|
||||
|
||||
ch = garglist->word->word[1];
|
||||
garglist = garglist->next;
|
||||
return (ch);
|
||||
}
|
||||
@@ -1,748 +0,0 @@
|
||||
This file is pushd.def, from which is created pushd.c. It implements the
|
||||
builtins "pushd", "popd", and "dirs" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES pushd.c
|
||||
|
||||
$BUILTIN pushd
|
||||
$FUNCTION pushd_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC pushd [dir | +N | -N] [-n]
|
||||
Adds a directory to the top of the directory stack, or rotates
|
||||
the stack, making the new top of the stack the current working
|
||||
directory. With no arguments, exchanges the top two directories.
|
||||
|
||||
+N Rotates the stack so that the Nth directory (counting
|
||||
from the left of the list shown by `dirs', 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.
|
||||
|
||||
-n suppress the normal change of directory when adding directories
|
||||
to the stack, so only the stack is manipulated.
|
||||
|
||||
dir adds DIR to the directory stack at the top, making it the
|
||||
new current working directory.
|
||||
|
||||
You can see the directory stack with the `dirs' command.
|
||||
$END
|
||||
|
||||
$BUILTIN popd
|
||||
$FUNCTION popd_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC popd [+N | -N] [-n]
|
||||
Removes entries from the directory stack. With no arguments,
|
||||
removes the top directory from the stack, and cd's to the new
|
||||
top directory.
|
||||
|
||||
+N removes the Nth entry counting from the left of the list
|
||||
shown by `dirs', starting with zero. For example: `popd +0'
|
||||
removes the first directory, `popd +1' the second.
|
||||
|
||||
-N removes the Nth entry counting from the right of the list
|
||||
shown by `dirs', starting with zero. For example: `popd -0'
|
||||
removes the last directory, `popd -1' the next to last.
|
||||
|
||||
-n suppress the normal change of directory when removing directories
|
||||
from the stack, so only the stack is manipulated.
|
||||
|
||||
You can see the directory stack with the `dirs' command.
|
||||
$END
|
||||
|
||||
$BUILTIN dirs
|
||||
$FUNCTION dirs_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC dirs [-clpv] [+N] [-N]
|
||||
Display the list of currently remembered directories. Directories
|
||||
find their way onto the list with the `pushd' command; you can get
|
||||
back up through the list with the `popd' command.
|
||||
|
||||
The -l flag specifies that `dirs' should not print shorthand versions
|
||||
of directories which are relative to your home directory. This means
|
||||
that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag
|
||||
causes `dirs' to print the directory stack with one entry per line,
|
||||
prepending the directory name with its position in the stack. The -p
|
||||
flag does the same thing, but the stack position is not prepended.
|
||||
The -c flag clears the directory stack by deleting all of the elements.
|
||||
|
||||
+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.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
#include <stdio.h>
|
||||
#ifndef _MINIX
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashansi.h"
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "maxpath.h"
|
||||
#include "common.h"
|
||||
#include "builtext.h"
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
# include "builtins.h"
|
||||
#endif
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
/* The list of remembered directories. */
|
||||
static char **pushd_directory_list = (char **)NULL;
|
||||
|
||||
/* Number of existing slots in this list. */
|
||||
static int directory_list_size;
|
||||
|
||||
/* Offset to the end of the list. */
|
||||
static int directory_list_offset;
|
||||
|
||||
static void pushd_error __P((int, char *));
|
||||
static void clear_directory_stack __P((void));
|
||||
static int cd_to_string __P((char *));
|
||||
static int change_to_temp __P((char *));
|
||||
static void add_dirstack_element __P((char *));
|
||||
static int get_dirstack_index __P((intmax_t, int, int *));
|
||||
|
||||
#define NOCD 0x01
|
||||
#define ROTATE 0x02
|
||||
#define LONGFORM 0x04
|
||||
#define CLEARSTAK 0x08
|
||||
|
||||
int
|
||||
pushd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *temp, *current_directory, *top;
|
||||
int j, flags, skipopt;
|
||||
intmax_t num;
|
||||
char direction;
|
||||
|
||||
if (list && list->word && ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
skipopt = 1;
|
||||
}
|
||||
else
|
||||
skipopt = 0;
|
||||
|
||||
/* If there is no argument list then switch current and
|
||||
top of list. */
|
||||
if (list == 0)
|
||||
{
|
||||
if (directory_list_offset == 0)
|
||||
{
|
||||
builtin_error (_("no other directory"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (current_directory == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
j = directory_list_offset - 1;
|
||||
temp = pushd_directory_list[j];
|
||||
pushd_directory_list[j] = current_directory;
|
||||
j = change_to_temp (temp);
|
||||
free (temp);
|
||||
return j;
|
||||
}
|
||||
|
||||
for (flags = 0; skipopt == 0 && list; list = list->next)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'n'))
|
||||
{
|
||||
flags |= NOCD;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
|
||||
/* Let `pushd -' work like it used to. */
|
||||
break;
|
||||
else if (((direction = list->word->word[0]) == '+') || direction == '-')
|
||||
{
|
||||
if (legal_number (list->word->word + 1, &num) == 0)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (direction == '-')
|
||||
num = directory_list_offset - num;
|
||||
|
||||
if (num > directory_list_offset || num < 0)
|
||||
{
|
||||
pushd_error (directory_list_offset, list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
flags |= ROTATE;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
sh_invalidopt (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags & ROTATE)
|
||||
{
|
||||
/* Rotate the stack num times. Remember, the current
|
||||
directory acts like it is part of the stack. */
|
||||
temp = get_working_directory ("pushd");
|
||||
|
||||
if (num == 0)
|
||||
{
|
||||
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
|
||||
free (temp);
|
||||
return j;
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
top = pushd_directory_list[directory_list_offset - 1];
|
||||
|
||||
for (j = directory_list_offset - 2; j > -1; j--)
|
||||
pushd_directory_list[j + 1] = pushd_directory_list[j];
|
||||
|
||||
pushd_directory_list[j + 1] = temp;
|
||||
|
||||
temp = top;
|
||||
num--;
|
||||
}
|
||||
while (num);
|
||||
|
||||
j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
|
||||
free (temp);
|
||||
return j;
|
||||
}
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
/* Change to the directory in list->word->word. Save the current
|
||||
directory on the top of the stack. */
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (current_directory == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
j = ((flags & NOCD) == 0) ? cd_builtin (list) : EXECUTION_SUCCESS;
|
||||
if (j == EXECUTION_SUCCESS)
|
||||
{
|
||||
add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
if (flags & NOCD)
|
||||
free (current_directory);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
free (current_directory);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Pop the directory stack, and then change to the new top of the stack.
|
||||
If LIST is non-null it should consist of a word +N or -N, which says
|
||||
what element to delete from the stack. The default is the top one. */
|
||||
int
|
||||
popd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
intmax_t which;
|
||||
int flags;
|
||||
char direction;
|
||||
char *which_word;
|
||||
|
||||
which_word = (char *)NULL;
|
||||
for (flags = 0, which = 0, direction = '+'; list; list = list->next)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'n'))
|
||||
{
|
||||
flags |= NOCD;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (((direction = list->word->word[0]) == '+') || direction == '-')
|
||||
{
|
||||
if (legal_number (list->word->word + 1, &which) == 0)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
which_word = list->word->word;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
sh_invalidopt (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
|
||||
{
|
||||
pushd_error (directory_list_offset, which_word ? which_word : "");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle case of no specification, or top of stack specification. */
|
||||
if ((direction == '+' && which == 0) ||
|
||||
(direction == '-' && which == directory_list_offset))
|
||||
{
|
||||
i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
|
||||
: EXECUTION_SUCCESS;
|
||||
if (i != EXECUTION_SUCCESS)
|
||||
return (i);
|
||||
free (pushd_directory_list[--directory_list_offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since an offset other than the top directory was specified,
|
||||
remove that directory from the list and shift the remainder
|
||||
of the list into place. */
|
||||
i = (direction == '+') ? directory_list_offset - which : which;
|
||||
free (pushd_directory_list[i]);
|
||||
directory_list_offset--;
|
||||
|
||||
/* Shift the remainder of the list into place. */
|
||||
for (; i < directory_list_offset; i++)
|
||||
pushd_directory_list[i] = pushd_directory_list[i + 1];
|
||||
}
|
||||
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Print the current list of directories on the directory stack. */
|
||||
int
|
||||
dirs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int flags, desired_index, index_flag, vflag;
|
||||
intmax_t i;
|
||||
char *temp, *w;
|
||||
|
||||
for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'l'))
|
||||
{
|
||||
flags |= LONGFORM;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, 'c'))
|
||||
{
|
||||
flags |= CLEARSTAK;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, 'v'))
|
||||
{
|
||||
vflag |= 2;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, 'p'))
|
||||
{
|
||||
vflag |= 1;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*list->word->word == '+' || *list->word->word == '-')
|
||||
{
|
||||
int sign;
|
||||
if (legal_number (w = list->word->word + 1, &i) == 0)
|
||||
{
|
||||
sh_invalidnum (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
sign = (*list->word->word == '+') ? 1 : -1;
|
||||
desired_index = get_dirstack_index (i, sign, &index_flag);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_invalidopt (list->word->word);
|
||||
builtin_usage ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & CLEARSTAK)
|
||||
{
|
||||
clear_directory_stack ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
|
||||
{
|
||||
pushd_error (directory_list_offset, w);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#define DIRSTACK_FORMAT(temp) \
|
||||
(flags & LONGFORM) ? temp : polite_directory_format (temp)
|
||||
|
||||
/* The first directory printed is always the current working directory. */
|
||||
if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
|
||||
{
|
||||
temp = get_working_directory ("dirs");
|
||||
if (temp == 0)
|
||||
temp = savestring (_("<no current directory>"));
|
||||
if (vflag & 2)
|
||||
printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
|
||||
else
|
||||
printf ("%s", DIRSTACK_FORMAT (temp));
|
||||
free (temp);
|
||||
if (index_flag)
|
||||
{
|
||||
putchar ('\n');
|
||||
return 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');
|
||||
fflush (stdout);
|
||||
return (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;
|
||||
int result;
|
||||
|
||||
tlist = make_word_list (make_word (name), NULL);
|
||||
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 ()
|
||||
{
|
||||
register int i;
|
||||
WORD_LIST *ret;
|
||||
char *d, *t;
|
||||
|
||||
for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
|
||||
{
|
||||
d = polite_directory_format (pushd_directory_list[i]);
|
||||
ret = make_word_list (make_word (d), ret);
|
||||
}
|
||||
/* Now the current directory. */
|
||||
d = get_working_directory ("dirstack");
|
||||
i = 0; /* sentinel to decide whether or not to free d */
|
||||
if (d == 0)
|
||||
d = ".";
|
||||
else
|
||||
{
|
||||
t = polite_directory_format (d);
|
||||
/* polite_directory_format sometimes returns its argument unchanged.
|
||||
If it does not, we can free d right away. If it does, we need to
|
||||
mark d to be deleted later. */
|
||||
if (t != d)
|
||||
{
|
||||
free (d);
|
||||
d = t;
|
||||
}
|
||||
else /* t == d, so d is what we want */
|
||||
i = 1;
|
||||
}
|
||||
ret = make_word_list (make_word (d), ret);
|
||||
if (i)
|
||||
free (d);
|
||||
return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
|
||||
}
|
||||
|
||||
#ifdef LOADABLE_BUILTIN
|
||||
static 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_("The -l flag specifies that `dirs' should not print shorthand versions"),
|
||||
N_("of directories which are relative to your home directory. This means"),
|
||||
N_("that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag"),
|
||||
N_("causes `dirs' to print the directory stack with one entry per line,"),
|
||||
N_("prepending the directory name with its position in the stack. The -p"),
|
||||
N_("flag does the same thing, but the stack position is not prepended."),
|
||||
N_("The -c flag clears the directory stack by deleting all of the elements."),
|
||||
N_(""),
|
||||
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
|
||||
};
|
||||
|
||||
static 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_("+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_("-n suppress the normal change of directory when adding directories"),
|
||||
N_(" to the stack, so only the stack is manipulated."),
|
||||
N_(""),
|
||||
N_("dir adds DIR to the directory stack at the top, making it the"),
|
||||
N_(" new current working directory."),
|
||||
N_(""),
|
||||
N_("You can see the directory stack with the `dirs' command."),
|
||||
(char *)NULL
|
||||
};
|
||||
|
||||
static char * const popd_doc[] = {
|
||||
N_("Removes entries from the directory stack. With no arguments,"),
|
||||
N_("removes the top directory from the stack, and cd's to the new"),
|
||||
N_("top directory."),
|
||||
N_(""),
|
||||
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_("-n suppress the normal change of directory when removing directories"),
|
||||
N_(" from the stack, so only the stack is manipulated."),
|
||||
N_(""),
|
||||
N_("You can see the directory stack with the `dirs' command."),
|
||||
(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 */
|
||||
@@ -1,736 +0,0 @@
|
||||
This file is read.def, from which is created read.c.
|
||||
It implements the builtin "read" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES read.c
|
||||
|
||||
$BUILTIN read
|
||||
$FUNCTION read_builtin
|
||||
$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]
|
||||
One line is read from the standard input, or from file descriptor FD if the
|
||||
-u option is supplied, and the first word is assigned to the first NAME,
|
||||
the second word to the second NAME, and so on, with leftover words assigned
|
||||
to the last NAME. Only the characters found in $IFS are recognized as word
|
||||
delimiters. If no NAMEs are supplied, the line read is stored in the REPLY
|
||||
variable. If the -r option is given, this signifies `raw' input, and
|
||||
backslash escaping is disabled. The -d option causes read to continue
|
||||
until the first character of DELIM is read, rather than newline. If the -p
|
||||
option is supplied, the string PROMPT is output without a trailing newline
|
||||
before attempting to read. If -a is supplied, the words read are assigned
|
||||
to sequential indices of ARRAY, starting at zero. If -e is supplied and
|
||||
the shell is interactive, readline is used to obtain the line. If -n is
|
||||
supplied with a non-zero NCHARS argument, read returns after NCHARS
|
||||
characters have been read. The -s option causes input coming from a
|
||||
terminal to not be echoed.
|
||||
|
||||
The -t option causes read to time out and return failure if a complete line
|
||||
of input is not read within TIMEOUT seconds. If the TMOUT variable is set,
|
||||
its value is the default timeout. The return code is zero, unless end-of-file
|
||||
is encountered, read times out, or an invalid file descriptor is supplied as
|
||||
the argument to -u.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <fcntl.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#include <shtty.h>
|
||||
|
||||
#if defined (READLINE)
|
||||
#include "../bashline.h"
|
||||
#include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
#if !defined(errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
#if defined (READLINE)
|
||||
static char *edit_line __P((char *));
|
||||
static void set_eol_delim __P((int));
|
||||
static void reset_eol_delim __P((char *));
|
||||
#endif
|
||||
static SHELL_VAR *bind_read_variable __P((char *, char *));
|
||||
|
||||
static sighandler sigalrm __P((int));
|
||||
static void reset_alarm __P((void));
|
||||
|
||||
static procenv_t alrmbuf;
|
||||
static SigHandler *old_alrm;
|
||||
static unsigned char delim;
|
||||
|
||||
static sighandler
|
||||
sigalrm (s)
|
||||
int s;
|
||||
{
|
||||
longjmp (alrmbuf, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_alarm ()
|
||||
{
|
||||
set_signal_handler (SIGALRM, old_alrm);
|
||||
alarm (0);
|
||||
}
|
||||
|
||||
/* Read the value of the shell variables whose names follow.
|
||||
The reading is done from the current input stream, whatever
|
||||
that may be. Successive words of the input line are assigned
|
||||
to the variables mentioned in LIST. The last variable in LIST
|
||||
gets the remainder of the words on the line. If no variables
|
||||
are mentioned in LIST, then the default variable is $REPLY. */
|
||||
int
|
||||
read_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char *varname;
|
||||
int size, i, pass_next, saw_escape, eof, opt, retval, code;
|
||||
int input_is_tty, input_is_pipe, unbuffered_read;
|
||||
int raw, edit, nchars, silent, have_timeout, fd;
|
||||
unsigned int tmout;
|
||||
intmax_t intval;
|
||||
char c;
|
||||
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
|
||||
char *e, *t, *t1;
|
||||
struct stat tsb;
|
||||
SHELL_VAR *var;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *alist;
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
char *rlbuf;
|
||||
int rlind;
|
||||
#endif
|
||||
|
||||
USE_VAR(size);
|
||||
USE_VAR(i);
|
||||
USE_VAR(pass_next);
|
||||
USE_VAR(saw_escape);
|
||||
USE_VAR(input_is_pipe);
|
||||
/* USE_VAR(raw); */
|
||||
USE_VAR(edit);
|
||||
USE_VAR(tmout);
|
||||
USE_VAR(nchars);
|
||||
USE_VAR(silent);
|
||||
USE_VAR(ifs_chars);
|
||||
USE_VAR(prompt);
|
||||
USE_VAR(arrayname);
|
||||
#if defined (READLINE)
|
||||
USE_VAR(rlbuf);
|
||||
USE_VAR(rlind);
|
||||
#endif
|
||||
USE_VAR(list);
|
||||
|
||||
i = 0; /* Index into the string that we are reading. */
|
||||
raw = edit = 0; /* Not reading raw input by default. */
|
||||
silent = 0;
|
||||
arrayname = prompt = (char *)NULL;
|
||||
fd = 0; /* file descriptor to read from */
|
||||
|
||||
#if defined (READLINE)
|
||||
rlbuf = (char *)0;
|
||||
rlind = 0;
|
||||
#endif
|
||||
|
||||
tmout = 0; /* no timeout */
|
||||
nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
|
||||
delim = '\n'; /* read until newline */
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
case 'p':
|
||||
prompt = list_optarg;
|
||||
break;
|
||||
case 's':
|
||||
silent = 1;
|
||||
break;
|
||||
case 'e':
|
||||
#if defined (READLINE)
|
||||
edit = 1;
|
||||
#endif
|
||||
break;
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
arrayname = list_optarg;
|
||||
break;
|
||||
#endif
|
||||
case 't':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid timeout specification"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
have_timeout = 1;
|
||||
tmout = intval;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (int)intval)
|
||||
{
|
||||
sh_invalidnum (list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
nchars = intval;
|
||||
break;
|
||||
case 'u':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (int)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
fd = intval;
|
||||
if (sh_validfd (fd) == 0)
|
||||
{
|
||||
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
delim = *list_optarg;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* `read -t 0 var' returns failure immediately. XXX - should it test
|
||||
whether input is available with select/FIONREAD, and fail if those
|
||||
are unavailable? */
|
||||
if (have_timeout && tmout == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
/* IF IFS is unset, we use the default of " \t\n". */
|
||||
ifs_chars = getifs ();
|
||||
if (ifs_chars == 0) /* XXX - shouldn't happen */
|
||||
ifs_chars = "";
|
||||
|
||||
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
|
||||
|
||||
/* $TMOUT, if set, is the default timeout for read. */
|
||||
if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
|
||||
{
|
||||
code = legal_number (e, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
|
||||
tmout = 0;
|
||||
else
|
||||
tmout = intval;
|
||||
}
|
||||
|
||||
begin_unwind_frame ("read_builtin");
|
||||
|
||||
input_is_tty = isatty (fd);
|
||||
if (input_is_tty == 0)
|
||||
#ifndef __CYGWIN__
|
||||
input_is_pipe = (lseek (0, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
#else
|
||||
input_is_pipe = 1;
|
||||
#endif
|
||||
|
||||
/* If the -p, -e or -s flags were given, but input is not coming from the
|
||||
terminal, turn them off. */
|
||||
if ((prompt || edit || silent) && input_is_tty == 0)
|
||||
{
|
||||
prompt = (char *)NULL;
|
||||
edit = silent = 0;
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
add_unwind_protect (xfree, rlbuf);
|
||||
#endif
|
||||
|
||||
if (prompt && edit == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", prompt);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
pass_next = 0; /* Non-zero signifies last char was backslash. */
|
||||
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
|
||||
|
||||
if (tmout > 0)
|
||||
{
|
||||
/* Turn off the timeout if stdin is a regular file (e.g. from
|
||||
input redirection). */
|
||||
if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
|
||||
tmout = 0;
|
||||
}
|
||||
|
||||
if (tmout > 0)
|
||||
{
|
||||
code = setjmp (alrmbuf);
|
||||
if (code)
|
||||
{
|
||||
run_unwind_frame ("read_builtin");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
old_alrm = set_signal_handler (SIGALRM, sigalrm);
|
||||
add_unwind_protect (reset_alarm, (char *)NULL);
|
||||
alarm (tmout);
|
||||
}
|
||||
|
||||
/* If we've been asked to read only NCHARS chars, or we're using some
|
||||
character other than newline to terminate the line, do the right
|
||||
thing to readline or the tty. */
|
||||
if (nchars > 0 || delim != '\n')
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (nchars > 0)
|
||||
{
|
||||
unwind_protect_int (rl_num_chars_to_read);
|
||||
rl_num_chars_to_read = nchars;
|
||||
}
|
||||
if (delim != '\n')
|
||||
{
|
||||
set_eol_delim (delim);
|
||||
add_unwind_protect (reset_eol_delim, (char *)NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (input_is_tty)
|
||||
{
|
||||
ttsave ();
|
||||
if (silent)
|
||||
ttcbreak ();
|
||||
else
|
||||
ttonechar ();
|
||||
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
|
||||
}
|
||||
}
|
||||
else if (silent) /* turn off echo but leave term in canonical mode */
|
||||
{
|
||||
ttsave ();
|
||||
ttnoecho ();
|
||||
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
|
||||
}
|
||||
|
||||
/* This *must* be the top unwind-protect on the stack, so the manipulation
|
||||
of the unwind-protect stack after the realloc() works right. */
|
||||
add_unwind_protect (xfree, input_string);
|
||||
interrupt_immediately++;
|
||||
|
||||
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
|
||||
|
||||
#if defined (__CYGWIN__) && defined (O_TEXT)
|
||||
setmode (0, O_TEXT);
|
||||
#endif
|
||||
|
||||
for (eof = retval = 0;;)
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (rlbuf && rlbuf[rlind] == '\0')
|
||||
{
|
||||
xfree (rlbuf);
|
||||
rlbuf = (char *)0;
|
||||
}
|
||||
if (rlbuf == 0)
|
||||
{
|
||||
rlbuf = edit_line (prompt ? prompt : "");
|
||||
rlind = 0;
|
||||
}
|
||||
if (rlbuf == 0)
|
||||
{
|
||||
eof = 1;
|
||||
break;
|
||||
}
|
||||
c = rlbuf[rlind++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
|
||||
if (unbuffered_read)
|
||||
retval = zread (fd, &c, 1);
|
||||
else
|
||||
retval = zreadc (fd, &c);
|
||||
|
||||
if (retval <= 0)
|
||||
{
|
||||
eof = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i + 2 >= size)
|
||||
{
|
||||
input_string = (char *)xrealloc (input_string, size += 128);
|
||||
remove_unwind_protect ();
|
||||
add_unwind_protect (xfree, input_string);
|
||||
}
|
||||
|
||||
/* If the next character is to be accepted verbatim, a backslash
|
||||
newline pair still disappears from the input. */
|
||||
if (pass_next)
|
||||
{
|
||||
if (c == '\n')
|
||||
i--; /* back up over the CTLESC */
|
||||
else
|
||||
input_string[i++] = c;
|
||||
pass_next = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\\' && raw == 0)
|
||||
{
|
||||
pass_next++;
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((unsigned char)c == delim)
|
||||
break;
|
||||
|
||||
if (c == CTLESC || c == CTLNUL)
|
||||
{
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
}
|
||||
|
||||
input_string[i++] = c;
|
||||
|
||||
if (nchars > 0 && i >= nchars)
|
||||
break;
|
||||
}
|
||||
input_string[i] = '\0';
|
||||
|
||||
#if 1
|
||||
if (retval < 0)
|
||||
{
|
||||
builtin_error (_("read error: %d: %s"), fd, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tmout > 0)
|
||||
reset_alarm ();
|
||||
|
||||
if (nchars > 0 || delim != '\n')
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (nchars > 0)
|
||||
rl_num_chars_to_read = 0;
|
||||
if (delim != '\n')
|
||||
reset_eol_delim ((char *)NULL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (input_is_tty)
|
||||
ttrestore ();
|
||||
}
|
||||
else if (silent)
|
||||
ttrestore ();
|
||||
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
|
||||
interrupt_immediately--;
|
||||
discard_unwind_frame ("read_builtin");
|
||||
|
||||
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* If -a was given, take the string read, break it into a list of words,
|
||||
an assign them to `arrayname' in turn. */
|
||||
if (arrayname)
|
||||
{
|
||||
if (legal_identifier (arrayname) == 0)
|
||||
{
|
||||
sh_invalidid (arrayname);
|
||||
xfree (input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
var = find_or_make_array_variable (arrayname, 1);
|
||||
if (var == 0)
|
||||
return EXECUTION_FAILURE; /* readonly or noassign */
|
||||
array_flush (array_cell (var));
|
||||
|
||||
alist = list_string (input_string, ifs_chars, 0);
|
||||
if (alist)
|
||||
{
|
||||
word_list_remove_quoted_nulls (alist);
|
||||
assign_array_var_from_word_list (var, alist, 0);
|
||||
dispose_words (alist);
|
||||
}
|
||||
xfree (input_string);
|
||||
return (retval);
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
/* If there are no variables, save the text of the line read to the
|
||||
variable $REPLY. ksh93 strips leading and trailing IFS whitespace,
|
||||
so that `read x ; echo "$x"' and `read ; echo "$REPLY"' behave the
|
||||
same way, but I believe that the difference in behaviors is useful
|
||||
enough to not do it. Without the bash behavior, there is no way
|
||||
to read a line completely without interpretation or modification
|
||||
unless you mess with $IFS (e.g., setting it to the empty string).
|
||||
If you disagree, change the occurrences of `#if 0' to `#if 1' below. */
|
||||
if (list == 0)
|
||||
{
|
||||
#if 0
|
||||
orig_input_string = input_string;
|
||||
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
|
||||
;
|
||||
input_string = t;
|
||||
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
|
||||
#endif
|
||||
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_variable ("REPLY", t, 0);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
var = bind_variable ("REPLY", input_string, 0);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
|
||||
free (input_string);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* This code implements the Posix.2 spec for splitting the words
|
||||
read and assigning them to variables. */
|
||||
orig_input_string = input_string;
|
||||
|
||||
/* Remove IFS white space at the beginning of the input string. If
|
||||
$IFS is null, no field splitting is performed. */
|
||||
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
|
||||
;
|
||||
input_string = t;
|
||||
|
||||
for (; list->next; list = list->next)
|
||||
{
|
||||
varname = list->word->word;
|
||||
#if defined (ARRAY_VARS)
|
||||
if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
|
||||
#else
|
||||
if (legal_identifier (varname) == 0)
|
||||
#endif
|
||||
{
|
||||
sh_invalidid (varname);
|
||||
xfree (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* If there are more variables than words read from the input,
|
||||
the remaining variables are set to the empty string. */
|
||||
if (*input_string)
|
||||
{
|
||||
/* This call updates INPUT_STRING. */
|
||||
t = get_word_from_string (&input_string, ifs_chars, &e);
|
||||
if (t)
|
||||
*e = '\0';
|
||||
/* Don't bother to remove the CTLESC unless we added one
|
||||
somewhere while reading the string. */
|
||||
if (t && saw_escape)
|
||||
{
|
||||
t1 = dequote_string (t);
|
||||
var = bind_read_variable (varname, t1);
|
||||
xfree (t1);
|
||||
}
|
||||
else
|
||||
var = bind_read_variable (varname, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)0;
|
||||
var = bind_read_variable (varname, "");
|
||||
}
|
||||
|
||||
FREE (t);
|
||||
if (var == 0)
|
||||
{
|
||||
xfree (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (varname);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
}
|
||||
|
||||
/* Now assign the rest of the line to the last variable argument. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
|
||||
#else
|
||||
if (legal_identifier (list->word->word) == 0)
|
||||
#endif
|
||||
{
|
||||
sh_invalidid (list->word->word);
|
||||
xfree (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* This has to be done this way rather than using string_list
|
||||
and list_string because Posix.2 says that the last variable gets the
|
||||
remaining words and their intervening separators. */
|
||||
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
|
||||
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_read_variable (list->word->word, t);
|
||||
xfree (t);
|
||||
}
|
||||
else
|
||||
var = bind_read_variable (list->word->word, input_string);
|
||||
stupidly_hack_special_variables (list->word->word);
|
||||
if (var)
|
||||
VUNSETATTR (var, att_invisible);
|
||||
xfree (orig_input_string);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static SHELL_VAR *
|
||||
bind_read_variable (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (valid_array_reference (name) == 0)
|
||||
return (bind_variable (name, value, 0));
|
||||
else
|
||||
return (assign_array_element (name, value, 0));
|
||||
#else /* !ARRAY_VARS */
|
||||
return bind_variable (name, value, 0);
|
||||
#endif /* !ARRAY_VARS */
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
static rl_completion_func_t *old_attempted_completion_function;
|
||||
|
||||
static char *
|
||||
edit_line (p)
|
||||
char *p;
|
||||
{
|
||||
char *ret;
|
||||
int len;
|
||||
|
||||
if (!bash_readline_initialized)
|
||||
initialize_readline ();
|
||||
old_attempted_completion_function = rl_attempted_completion_function;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
ret = readline (p);
|
||||
rl_attempted_completion_function = old_attempted_completion_function;
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
len = strlen (ret);
|
||||
ret = (char *)xrealloc (ret, len + 2);
|
||||
ret[len++] = delim;
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int old_delim_ctype;
|
||||
static rl_command_func_t *old_delim_func;
|
||||
static int old_newline_ctype;
|
||||
static rl_command_func_t *old_newline_func;
|
||||
|
||||
static unsigned char delim_char;
|
||||
|
||||
static void
|
||||
set_eol_delim (c)
|
||||
int c;
|
||||
{
|
||||
Keymap cmap;
|
||||
|
||||
if (bash_readline_initialized == 0)
|
||||
initialize_readline ();
|
||||
cmap = rl_get_keymap ();
|
||||
|
||||
/* Change newline to self-insert */
|
||||
old_newline_ctype = cmap[RETURN].type;
|
||||
old_newline_func = cmap[RETURN].function;
|
||||
cmap[RETURN].type = ISFUNC;
|
||||
cmap[RETURN].function = rl_insert;
|
||||
|
||||
/* Bind the delimiter character to accept-line. */
|
||||
old_delim_ctype = cmap[c].type;
|
||||
old_delim_func = cmap[c].function;
|
||||
cmap[c].type = ISFUNC;
|
||||
cmap[c].function = rl_newline;
|
||||
|
||||
delim_char = c;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_eol_delim (cp)
|
||||
char *cp;
|
||||
{
|
||||
Keymap cmap;
|
||||
|
||||
cmap = rl_get_keymap ();
|
||||
|
||||
cmap[RETURN].type = old_newline_ctype;
|
||||
cmap[RETURN].function = old_newline_func;
|
||||
|
||||
cmap[delim_char].type = old_delim_ctype;
|
||||
cmap[delim_char].function = old_delim_func;
|
||||
}
|
||||
#endif
|
||||
@@ -1,761 +0,0 @@
|
||||
This file is read.def, from which is created read.c.
|
||||
It implements the builtin "read" in Bash.
|
||||
|
||||
Copyright (C) 1987-2005 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES read.c
|
||||
|
||||
$BUILTIN read
|
||||
$FUNCTION read_builtin
|
||||
$SHORT_DOC read [-ers] [-u fd] [-t timeout] [-p prompt] [-a array] [-n nchars] [-d delim] [name ...]
|
||||
One line is read from the standard input, or from file descriptor FD if the
|
||||
-u option is supplied, and the first word is assigned to the first NAME,
|
||||
the second word to the second NAME, and so on, with leftover words assigned
|
||||
to the last NAME. Only the characters found in $IFS are recognized as word
|
||||
delimiters. If no NAMEs are supplied, the line read is stored in the REPLY
|
||||
variable. If the -r option is given, this signifies `raw' input, and
|
||||
backslash escaping is disabled. The -d option causes read to continue
|
||||
until the first character of DELIM is read, rather than newline. If the -p
|
||||
option is supplied, the string PROMPT is output without a trailing newline
|
||||
before attempting to read. If -a is supplied, the words read are assigned
|
||||
to sequential indices of ARRAY, starting at zero. If -e is supplied and
|
||||
the shell is interactive, readline is used to obtain the line. If -n is
|
||||
supplied with a non-zero NCHARS argument, read returns after NCHARS
|
||||
characters have been read. The -s option causes input coming from a
|
||||
terminal to not be echoed.
|
||||
|
||||
The -t option causes read to time out and return failure if a complete line
|
||||
of input is not read within TIMEOUT seconds. If the TMOUT variable is set,
|
||||
its value is the default timeout. The return code is zero, unless end-of-file
|
||||
is encountered, read times out, or an invalid file descriptor is supplied as
|
||||
the argument to -u.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "bashtypes.h"
|
||||
#include "posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
# include <fcntl.h>
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#include <shtty.h>
|
||||
|
||||
#if defined (READLINE)
|
||||
#include "../bashline.h"
|
||||
#include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
# include "input.h"
|
||||
#endif
|
||||
|
||||
#if !defined(errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
#if defined (READLINE)
|
||||
static char *edit_line __P((char *));
|
||||
static void set_eol_delim __P((int));
|
||||
static void reset_eol_delim __P((char *));
|
||||
#endif
|
||||
static SHELL_VAR *bind_read_variable __P((char *, char *));
|
||||
|
||||
static sighandler sigalrm __P((int));
|
||||
static void reset_alarm __P((void));
|
||||
|
||||
static procenv_t alrmbuf;
|
||||
static SigHandler *old_alrm;
|
||||
static unsigned char delim;
|
||||
|
||||
static sighandler
|
||||
sigalrm (s)
|
||||
int s;
|
||||
{
|
||||
longjmp (alrmbuf, 1);
|
||||
}
|
||||
|
||||
static void
|
||||
reset_alarm ()
|
||||
{
|
||||
set_signal_handler (SIGALRM, old_alrm);
|
||||
alarm (0);
|
||||
}
|
||||
|
||||
/* Read the value of the shell variables whose names follow.
|
||||
The reading is done from the current input stream, whatever
|
||||
that may be. Successive words of the input line are assigned
|
||||
to the variables mentioned in LIST. The last variable in LIST
|
||||
gets the remainder of the words on the line. If no variables
|
||||
are mentioned in LIST, then the default variable is $REPLY. */
|
||||
int
|
||||
read_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char *varname;
|
||||
int size, i, nr, pass_next, saw_escape, eof, opt, retval, code;
|
||||
int input_is_tty, input_is_pipe, unbuffered_read;
|
||||
int raw, edit, nchars, silent, have_timeout, fd;
|
||||
unsigned int tmout;
|
||||
intmax_t intval;
|
||||
char c;
|
||||
char *input_string, *orig_input_string, *ifs_chars, *prompt, *arrayname;
|
||||
char *e, *t, *t1;
|
||||
struct stat tsb;
|
||||
SHELL_VAR *var;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *alist;
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
char *rlbuf;
|
||||
int rlind;
|
||||
#endif
|
||||
|
||||
USE_VAR(size);
|
||||
USE_VAR(i);
|
||||
USE_VAR(pass_next);
|
||||
USE_VAR(saw_escape);
|
||||
USE_VAR(input_is_pipe);
|
||||
/* USE_VAR(raw); */
|
||||
USE_VAR(edit);
|
||||
USE_VAR(tmout);
|
||||
USE_VAR(nchars);
|
||||
USE_VAR(silent);
|
||||
USE_VAR(ifs_chars);
|
||||
USE_VAR(prompt);
|
||||
USE_VAR(arrayname);
|
||||
#if defined (READLINE)
|
||||
USE_VAR(rlbuf);
|
||||
USE_VAR(rlind);
|
||||
#endif
|
||||
USE_VAR(list);
|
||||
|
||||
i = 0; /* Index into the string that we are reading. */
|
||||
raw = edit = 0; /* Not reading raw input by default. */
|
||||
silent = 0;
|
||||
arrayname = prompt = (char *)NULL;
|
||||
fd = 0; /* file descriptor to read from */
|
||||
|
||||
#if defined (READLINE)
|
||||
rlbuf = (char *)0;
|
||||
rlind = 0;
|
||||
#endif
|
||||
|
||||
tmout = 0; /* no timeout */
|
||||
nr = nchars = input_is_tty = input_is_pipe = unbuffered_read = have_timeout = 0;
|
||||
delim = '\n'; /* read until newline */
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "ersa:d:n:p:t:u:")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'r':
|
||||
raw = 1;
|
||||
break;
|
||||
case 'p':
|
||||
prompt = list_optarg;
|
||||
break;
|
||||
case 's':
|
||||
silent = 1;
|
||||
break;
|
||||
case 'e':
|
||||
#if defined (READLINE)
|
||||
edit = 1;
|
||||
#endif
|
||||
break;
|
||||
#if defined (ARRAY_VARS)
|
||||
case 'a':
|
||||
arrayname = list_optarg;
|
||||
break;
|
||||
#endif
|
||||
case 't':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid timeout specification"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
have_timeout = 1;
|
||||
tmout = intval;
|
||||
}
|
||||
break;
|
||||
case 'n':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (int)intval)
|
||||
{
|
||||
sh_invalidnum (list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
nchars = intval;
|
||||
break;
|
||||
case 'u':
|
||||
code = legal_number (list_optarg, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (int)intval)
|
||||
{
|
||||
builtin_error (_("%s: invalid file descriptor specification"), list_optarg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
fd = intval;
|
||||
if (sh_validfd (fd) == 0)
|
||||
{
|
||||
builtin_error (_("%d: invalid file descriptor: %s"), fd, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'd':
|
||||
delim = *list_optarg;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
/* `read -t 0 var' returns failure immediately. XXX - should it test
|
||||
whether input is available with select/FIONREAD, and fail if those
|
||||
are unavailable? */
|
||||
if (have_timeout && tmout == 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
/* IF IFS is unset, we use the default of " \t\n". */
|
||||
ifs_chars = getifs ();
|
||||
if (ifs_chars == 0) /* XXX - shouldn't happen */
|
||||
ifs_chars = "";
|
||||
|
||||
input_string = (char *)xmalloc (size = 112); /* XXX was 128 */
|
||||
|
||||
/* $TMOUT, if set, is the default timeout for read. */
|
||||
if (have_timeout == 0 && (e = get_string_value ("TMOUT")))
|
||||
{
|
||||
code = legal_number (e, &intval);
|
||||
if (code == 0 || intval < 0 || intval != (unsigned int)intval)
|
||||
tmout = 0;
|
||||
else
|
||||
tmout = intval;
|
||||
}
|
||||
|
||||
begin_unwind_frame ("read_builtin");
|
||||
|
||||
#if defined (BUFFERED_INPUT)
|
||||
if (interactive == 0 && default_buffered_input >= 0 && fd_is_bash_input (fd))
|
||||
sync_buffered_stream (default_buffered_input);
|
||||
#endif
|
||||
|
||||
input_is_tty = isatty (fd);
|
||||
if (input_is_tty == 0)
|
||||
#ifndef __CYGWIN__
|
||||
input_is_pipe = (lseek (fd, 0L, SEEK_CUR) < 0) && (errno == ESPIPE);
|
||||
#else
|
||||
input_is_pipe = 1;
|
||||
#endif
|
||||
|
||||
/* If the -p, -e or -s flags were given, but input is not coming from the
|
||||
terminal, turn them off. */
|
||||
if ((prompt || edit || silent) && input_is_tty == 0)
|
||||
{
|
||||
prompt = (char *)NULL;
|
||||
edit = silent = 0;
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
add_unwind_protect (xfree, rlbuf);
|
||||
#endif
|
||||
|
||||
if (prompt && edit == 0)
|
||||
{
|
||||
fprintf (stderr, "%s", prompt);
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
pass_next = 0; /* Non-zero signifies last char was backslash. */
|
||||
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
|
||||
|
||||
if (tmout > 0)
|
||||
{
|
||||
/* Turn off the timeout if stdin is a regular file (e.g. from
|
||||
input redirection). */
|
||||
if ((fstat (fd, &tsb) < 0) || S_ISREG (tsb.st_mode))
|
||||
tmout = 0;
|
||||
}
|
||||
|
||||
if (tmout > 0)
|
||||
{
|
||||
code = setjmp (alrmbuf);
|
||||
if (code)
|
||||
{
|
||||
run_unwind_frame ("read_builtin");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
old_alrm = set_signal_handler (SIGALRM, sigalrm);
|
||||
add_unwind_protect (reset_alarm, (char *)NULL);
|
||||
alarm (tmout);
|
||||
}
|
||||
|
||||
/* If we've been asked to read only NCHARS chars, or we're using some
|
||||
character other than newline to terminate the line, do the right
|
||||
thing to readline or the tty. */
|
||||
if (nchars > 0 || delim != '\n')
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (nchars > 0)
|
||||
{
|
||||
unwind_protect_int (rl_num_chars_to_read);
|
||||
rl_num_chars_to_read = nchars;
|
||||
}
|
||||
if (delim != '\n')
|
||||
{
|
||||
set_eol_delim (delim);
|
||||
add_unwind_protect (reset_eol_delim, (char *)NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (input_is_tty)
|
||||
{
|
||||
ttsave ();
|
||||
if (silent)
|
||||
ttcbreak ();
|
||||
else
|
||||
ttonechar ();
|
||||
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
|
||||
}
|
||||
}
|
||||
else if (silent) /* turn off echo but leave term in canonical mode */
|
||||
{
|
||||
ttsave ();
|
||||
ttnoecho ();
|
||||
add_unwind_protect ((Function *)ttrestore, (char *)NULL);
|
||||
}
|
||||
|
||||
/* This *must* be the top unwind-protect on the stack, so the manipulation
|
||||
of the unwind-protect stack after the realloc() works right. */
|
||||
add_unwind_protect (xfree, input_string);
|
||||
interrupt_immediately++;
|
||||
|
||||
unbuffered_read = (nchars > 0) || (delim != '\n') || input_is_pipe;
|
||||
|
||||
#if defined (__CYGWIN__) && defined (O_TEXT)
|
||||
setmode (0, O_TEXT);
|
||||
#endif
|
||||
|
||||
for (eof = retval = 0;;)
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (rlbuf && rlbuf[rlind] == '\0')
|
||||
{
|
||||
xfree (rlbuf);
|
||||
rlbuf = (char *)0;
|
||||
}
|
||||
if (rlbuf == 0)
|
||||
{
|
||||
rlbuf = edit_line (prompt ? prompt : "");
|
||||
rlind = 0;
|
||||
}
|
||||
if (rlbuf == 0)
|
||||
{
|
||||
eof = 1;
|
||||
break;
|
||||
}
|
||||
c = rlbuf[rlind++];
|
||||
}
|
||||
else
|
||||
{
|
||||
#endif
|
||||
|
||||
if (unbuffered_read)
|
||||
retval = zread (fd, &c, 1);
|
||||
else
|
||||
retval = zreadc (fd, &c);
|
||||
|
||||
if (retval <= 0)
|
||||
{
|
||||
eof = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (i + 2 >= size)
|
||||
{
|
||||
input_string = (char *)xrealloc (input_string, size += 128);
|
||||
remove_unwind_protect ();
|
||||
add_unwind_protect (xfree, input_string);
|
||||
}
|
||||
|
||||
/* If the next character is to be accepted verbatim, a backslash
|
||||
newline pair still disappears from the input. */
|
||||
if (pass_next)
|
||||
{
|
||||
pass_next = 0;
|
||||
if (c == '\n')
|
||||
i--; /* back up over the CTLESC */
|
||||
else
|
||||
goto add_char;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\\' && raw == 0)
|
||||
{
|
||||
pass_next++;
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((unsigned char)c == delim)
|
||||
break;
|
||||
|
||||
if (c == CTLESC || c == CTLNUL)
|
||||
{
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
}
|
||||
|
||||
add_char:
|
||||
input_string[i++] = c;
|
||||
nr++;
|
||||
|
||||
if (nchars > 0 && nr >= nchars)
|
||||
break;
|
||||
}
|
||||
input_string[i] = '\0';
|
||||
|
||||
#if 1
|
||||
if (retval < 0)
|
||||
{
|
||||
builtin_error (_("read error: %d: %s"), fd, strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (tmout > 0)
|
||||
reset_alarm ();
|
||||
|
||||
if (nchars > 0 || delim != '\n')
|
||||
{
|
||||
#if defined (READLINE)
|
||||
if (edit)
|
||||
{
|
||||
if (nchars > 0)
|
||||
rl_num_chars_to_read = 0;
|
||||
if (delim != '\n')
|
||||
reset_eol_delim ((char *)NULL);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
if (input_is_tty)
|
||||
ttrestore ();
|
||||
}
|
||||
else if (silent)
|
||||
ttrestore ();
|
||||
|
||||
if (unbuffered_read == 0)
|
||||
zsyncfd (fd);
|
||||
|
||||
interrupt_immediately--;
|
||||
discard_unwind_frame ("read_builtin");
|
||||
|
||||
retval = eof ? EXECUTION_FAILURE : EXECUTION_SUCCESS;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
/* If -a was given, take the string read, break it into a list of words,
|
||||
an assign them to `arrayname' in turn. */
|
||||
if (arrayname)
|
||||
{
|
||||
if (legal_identifier (arrayname) == 0)
|
||||
{
|
||||
sh_invalidid (arrayname);
|
||||
xfree (input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
var = find_or_make_array_variable (arrayname, 1);
|
||||
if (var == 0)
|
||||
return EXECUTION_FAILURE; /* readonly or noassign */
|
||||
array_flush (array_cell (var));
|
||||
|
||||
alist = list_string (input_string, ifs_chars, 0);
|
||||
if (alist)
|
||||
{
|
||||
word_list_remove_quoted_nulls (alist);
|
||||
assign_array_var_from_word_list (var, alist, 0);
|
||||
dispose_words (alist);
|
||||
}
|
||||
xfree (input_string);
|
||||
return (retval);
|
||||
}
|
||||
#endif /* ARRAY_VARS */
|
||||
|
||||
/* If there are no variables, save the text of the line read to the
|
||||
variable $REPLY. ksh93 strips leading and trailing IFS whitespace,
|
||||
so that `read x ; echo "$x"' and `read ; echo "$REPLY"' behave the
|
||||
same way, but I believe that the difference in behaviors is useful
|
||||
enough to not do it. Without the bash behavior, there is no way
|
||||
to read a line completely without interpretation or modification
|
||||
unless you mess with $IFS (e.g., setting it to the empty string).
|
||||
If you disagree, change the occurrences of `#if 0' to `#if 1' below. */
|
||||
if (list == 0)
|
||||
{
|
||||
#if 0
|
||||
orig_input_string = input_string;
|
||||
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
|
||||
;
|
||||
input_string = t;
|
||||
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
|
||||
#endif
|
||||
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_variable ("REPLY", t, 0);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
var = bind_variable ("REPLY", input_string, 0);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
|
||||
free (input_string);
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* This code implements the Posix.2 spec for splitting the words
|
||||
read and assigning them to variables. */
|
||||
orig_input_string = input_string;
|
||||
|
||||
/* Remove IFS white space at the beginning of the input string. If
|
||||
$IFS is null, no field splitting is performed. */
|
||||
for (t = input_string; ifs_chars && *ifs_chars && spctabnl(*t) && isifs(*t); t++)
|
||||
;
|
||||
input_string = t;
|
||||
|
||||
for (; list->next; list = list->next)
|
||||
{
|
||||
varname = list->word->word;
|
||||
#if defined (ARRAY_VARS)
|
||||
if (legal_identifier (varname) == 0 && valid_array_reference (varname) == 0)
|
||||
#else
|
||||
if (legal_identifier (varname) == 0)
|
||||
#endif
|
||||
{
|
||||
sh_invalidid (varname);
|
||||
xfree (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* If there are more variables than words read from the input,
|
||||
the remaining variables are set to the empty string. */
|
||||
if (*input_string)
|
||||
{
|
||||
/* This call updates INPUT_STRING. */
|
||||
t = get_word_from_string (&input_string, ifs_chars, &e);
|
||||
if (t)
|
||||
*e = '\0';
|
||||
/* Don't bother to remove the CTLESC unless we added one
|
||||
somewhere while reading the string. */
|
||||
if (t && saw_escape)
|
||||
{
|
||||
t1 = dequote_string (t);
|
||||
var = bind_read_variable (varname, t1);
|
||||
xfree (t1);
|
||||
}
|
||||
else
|
||||
var = bind_read_variable (varname, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)0;
|
||||
var = bind_read_variable (varname, "");
|
||||
}
|
||||
|
||||
FREE (t);
|
||||
if (var == 0)
|
||||
{
|
||||
xfree (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (varname);
|
||||
VUNSETATTR (var, att_invisible);
|
||||
}
|
||||
|
||||
/* Now assign the rest of the line to the last variable argument. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (legal_identifier (list->word->word) == 0 && valid_array_reference (list->word->word) == 0)
|
||||
#else
|
||||
if (legal_identifier (list->word->word) == 0)
|
||||
#endif
|
||||
{
|
||||
sh_invalidid (list->word->word);
|
||||
xfree (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* This has to be done this way rather than using string_list
|
||||
and list_string because Posix.2 says that the last variable gets the
|
||||
remaining words and their intervening separators. */
|
||||
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars, saw_escape);
|
||||
#else
|
||||
/* Check whether or not the number of fields is exactly the same as the
|
||||
number of variables. */
|
||||
if (*input_string)
|
||||
{
|
||||
t1 = input_string;
|
||||
t = get_word_from_string (&input_string, ifs_chars, &e);
|
||||
if (*input_string == 0)
|
||||
input_string = t;
|
||||
else
|
||||
input_string = strip_trailing_ifs_whitespace (t1, ifs_chars, saw_escape);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_read_variable (list->word->word, t);
|
||||
xfree (t);
|
||||
}
|
||||
else
|
||||
var = bind_read_variable (list->word->word, input_string);
|
||||
stupidly_hack_special_variables (list->word->word);
|
||||
if (var)
|
||||
VUNSETATTR (var, att_invisible);
|
||||
xfree (orig_input_string);
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
static SHELL_VAR *
|
||||
bind_read_variable (name, value)
|
||||
char *name, *value;
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (valid_array_reference (name) == 0)
|
||||
return (bind_variable (name, value, 0));
|
||||
else
|
||||
return (assign_array_element (name, value, 0));
|
||||
#else /* !ARRAY_VARS */
|
||||
return bind_variable (name, value, 0);
|
||||
#endif /* !ARRAY_VARS */
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
static rl_completion_func_t *old_attempted_completion_function;
|
||||
|
||||
static char *
|
||||
edit_line (p)
|
||||
char *p;
|
||||
{
|
||||
char *ret;
|
||||
int len;
|
||||
|
||||
if (bash_readline_initialized == 0)
|
||||
initialize_readline ();
|
||||
old_attempted_completion_function = rl_attempted_completion_function;
|
||||
rl_attempted_completion_function = (rl_completion_func_t *)NULL;
|
||||
ret = readline (p);
|
||||
rl_attempted_completion_function = old_attempted_completion_function;
|
||||
if (ret == 0)
|
||||
return ret;
|
||||
len = strlen (ret);
|
||||
ret = (char *)xrealloc (ret, len + 2);
|
||||
ret[len++] = delim;
|
||||
ret[len] = '\0';
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int old_delim_ctype;
|
||||
static rl_command_func_t *old_delim_func;
|
||||
static int old_newline_ctype;
|
||||
static rl_command_func_t *old_newline_func;
|
||||
|
||||
static unsigned char delim_char;
|
||||
|
||||
static void
|
||||
set_eol_delim (c)
|
||||
int c;
|
||||
{
|
||||
Keymap cmap;
|
||||
|
||||
if (bash_readline_initialized == 0)
|
||||
initialize_readline ();
|
||||
cmap = rl_get_keymap ();
|
||||
|
||||
/* Change newline to self-insert */
|
||||
old_newline_ctype = cmap[RETURN].type;
|
||||
old_newline_func = cmap[RETURN].function;
|
||||
cmap[RETURN].type = ISFUNC;
|
||||
cmap[RETURN].function = rl_insert;
|
||||
|
||||
/* Bind the delimiter character to accept-line. */
|
||||
old_delim_ctype = cmap[c].type;
|
||||
old_delim_func = cmap[c].function;
|
||||
cmap[c].type = ISFUNC;
|
||||
cmap[c].function = rl_newline;
|
||||
|
||||
delim_char = c;
|
||||
}
|
||||
|
||||
static void
|
||||
reset_eol_delim (cp)
|
||||
char *cp;
|
||||
{
|
||||
Keymap cmap;
|
||||
|
||||
cmap = rl_get_keymap ();
|
||||
|
||||
cmap[RETURN].type = old_newline_ctype;
|
||||
cmap[RETURN].function = old_newline_func;
|
||||
|
||||
cmap[delim_char].type = old_delim_ctype;
|
||||
cmap[delim_char].function = old_delim_func;
|
||||
}
|
||||
#endif
|
||||
@@ -1,203 +0,0 @@
|
||||
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-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$BUILTIN for
|
||||
$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The `for' loop executes a sequence of commands for each member in a
|
||||
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
|
||||
assumed. For each element in WORDS, NAME is set to that element, and
|
||||
the COMMANDS are executed.
|
||||
$END
|
||||
|
||||
$BUILTIN for ((
|
||||
$DOCNAME arith_for
|
||||
$SHORT_DOC for (( exp1; exp2; exp3 )); do COMMANDS; done
|
||||
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.
|
||||
$END
|
||||
|
||||
$BUILTIN select
|
||||
$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The WORDS are expanded, generating a list of words. The
|
||||
set of expanded words is printed on the standard error, each
|
||||
preceded by a number. If `in WORDS' is not present, `in "$@"'
|
||||
is assumed. The PS3 prompt is then displayed and a line read
|
||||
from the standard input. If the line consists of the number
|
||||
corresponding to one of the displayed words, then NAME is set
|
||||
to that word. If the line is empty, WORDS and the prompt are
|
||||
redisplayed. If EOF is read, the command completes. Any other
|
||||
value read causes NAME to be set to null. The line read is saved
|
||||
in the variable REPLY. COMMANDS are executed after each selection
|
||||
until a break command is executed.
|
||||
$END
|
||||
|
||||
$BUILTIN time
|
||||
$SHORT_DOC time [-p] PIPELINE
|
||||
Execute PIPELINE and print a summary of the real time, user CPU time,
|
||||
and system CPU time spent executing PIPELINE when it terminates.
|
||||
The return status is the return status of PIPELINE. The `-p' option
|
||||
prints the timing summary in a slightly different format. This uses
|
||||
the value of the TIMEFORMAT variable as the output format.
|
||||
$END
|
||||
|
||||
$BUILTIN case
|
||||
$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
|
||||
Selectively execute COMMANDS based upon WORD matching PATTERN. The
|
||||
`|' is used to separate multiple patterns.
|
||||
$END
|
||||
|
||||
$BUILTIN if
|
||||
$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
|
||||
The if COMMANDS are executed. If the exit status is zero, then the then
|
||||
COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed
|
||||
in turn, and if the exit status is zero, the corresponding then COMMANDS
|
||||
are executed and the if command completes. Otherwise, the else COMMANDS
|
||||
are executed, if present. The exit status is the exit status of the last
|
||||
command executed, or zero if no condition tested true.
|
||||
$END
|
||||
|
||||
$BUILTIN while
|
||||
$SHORT_DOC while COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`while' COMMANDS has an exit status of zero.
|
||||
$END
|
||||
|
||||
$BUILTIN until
|
||||
$SHORT_DOC until COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`until' COMMANDS has an exit status which is not zero.
|
||||
$END
|
||||
|
||||
$BUILTIN function
|
||||
$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; }
|
||||
Create a simple command invoked by NAME which runs COMMANDS.
|
||||
Arguments on the command line along with NAME are passed to the
|
||||
function as $0 .. $n.
|
||||
$END
|
||||
|
||||
$BUILTIN { ... }
|
||||
$DOCNAME grouping_braces
|
||||
$SHORT_DOC { COMMANDS ; }
|
||||
Run a set of commands in a group. This is one way to redirect an
|
||||
entire set of commands.
|
||||
$END
|
||||
|
||||
$BUILTIN %
|
||||
$DOCNAME fg_percent
|
||||
$SHORT_DOC job_spec [&]
|
||||
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'.
|
||||
$END
|
||||
|
||||
$BUILTIN (( ... ))
|
||||
$DOCNAME arith
|
||||
$SHORT_DOC (( expression ))
|
||||
The EXPRESSION is evaluated according to the rules for arithmetic
|
||||
evaluation. Equivalent to "let EXPRESSION".
|
||||
$END
|
||||
|
||||
$BUILTIN [[ ... ]]
|
||||
$DOCNAME conditional
|
||||
$SHORT_DOC [[ expression ]]
|
||||
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. The
|
||||
&& and || operators do not evaluate EXPR2 if EXPR1 is sufficient to
|
||||
determine the expression's value.
|
||||
$END
|
||||
|
||||
$BUILTIN variables
|
||||
$DOCNAME variable_help
|
||||
$SHORT_DOC variables - Some variable names and meanings
|
||||
BASH_VERSION Version information for this Bash.
|
||||
CDPATH A colon separated list of directories to search
|
||||
when the argument to `cd' is not found in the current
|
||||
directory.
|
||||
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
|
||||
@@ -1,201 +0,0 @@
|
||||
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-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$BUILTIN for
|
||||
$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The `for' loop executes a sequence of commands for each member in a
|
||||
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
|
||||
assumed. For each element in WORDS, NAME is set to that element, and
|
||||
the COMMANDS are executed.
|
||||
$END
|
||||
|
||||
$BUILTIN for ((
|
||||
$DOCNAME arith_for
|
||||
$SHORT_DOC for (( exp1; exp2; exp3 )); do COMMANDS; done
|
||||
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.
|
||||
$END
|
||||
|
||||
$BUILTIN select
|
||||
$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The WORDS are expanded, generating a list of words. The
|
||||
set of expanded words is printed on the standard error, each
|
||||
preceded by a number. If `in WORDS' is not present, `in "$@"'
|
||||
is assumed. The PS3 prompt is then displayed and a line read
|
||||
from the standard input. If the line consists of the number
|
||||
corresponding to one of the displayed words, then NAME is set
|
||||
to that word. If the line is empty, WORDS and the prompt are
|
||||
redisplayed. If EOF is read, the command completes. Any other
|
||||
value read causes NAME to be set to null. The line read is saved
|
||||
in the variable REPLY. COMMANDS are executed after each selection
|
||||
until a break command is executed.
|
||||
$END
|
||||
|
||||
$BUILTIN time
|
||||
$SHORT_DOC time [-p] PIPELINE
|
||||
Execute PIPELINE and print a summary of the real time, user CPU time,
|
||||
and system CPU time spent executing PIPELINE when it terminates.
|
||||
The return status is the return status of PIPELINE. The `-p' option
|
||||
prints the timing summary in a slightly different format. This uses
|
||||
the value of the TIMEFORMAT variable as the output format.
|
||||
$END
|
||||
|
||||
$BUILTIN case
|
||||
$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
|
||||
Selectively execute COMMANDS based upon WORD matching PATTERN. The
|
||||
`|' is used to separate multiple patterns.
|
||||
$END
|
||||
|
||||
$BUILTIN if
|
||||
$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
|
||||
The if COMMANDS are executed. If the exit status is zero, then the then
|
||||
COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed
|
||||
in turn, and if the exit status is zero, the corresponding then COMMANDS
|
||||
are executed and the if command completes. Otherwise, the else COMMANDS
|
||||
are executed, if present. The exit status is the exit status of the last
|
||||
command executed, or zero if no condition tested true.
|
||||
$END
|
||||
|
||||
$BUILTIN while
|
||||
$SHORT_DOC while COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`while' COMMANDS has an exit status of zero.
|
||||
$END
|
||||
|
||||
$BUILTIN until
|
||||
$SHORT_DOC until COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`until' COMMANDS has an exit status which is not zero.
|
||||
$END
|
||||
|
||||
$BUILTIN function
|
||||
$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; }
|
||||
Create a simple command invoked by NAME which runs COMMANDS.
|
||||
Arguments on the command line along with NAME are passed to the
|
||||
function as $0 .. $n.
|
||||
$END
|
||||
|
||||
$BUILTIN { ... }
|
||||
$DOCNAME grouping_braces
|
||||
$SHORT_DOC { COMMANDS ; }
|
||||
Run a set of commands in a group. This is one way to redirect an
|
||||
entire set of commands.
|
||||
$END
|
||||
|
||||
$BUILTIN %
|
||||
$DOCNAME fg_percent
|
||||
$SHORT_DOC %[DIGITS | WORD] [&]
|
||||
This is similar to the `fg' command. Resume a stopped or background
|
||||
job. If you specifiy DIGITS, then that job is used. If you specify
|
||||
WORD, then the job whose name begins with WORD is used. Following the
|
||||
job specification with a `&' places the job in the background.
|
||||
$END
|
||||
|
||||
$BUILTIN (( ... ))
|
||||
$DOCNAME arith
|
||||
$SHORT_DOC (( expression ))
|
||||
The EXPRESSION is evaluated according to the rules for arithmetic
|
||||
evaluation. Equivalent to "let EXPRESSION".
|
||||
$END
|
||||
|
||||
$BUILTIN [[ ... ]]
|
||||
$DOCNAME conditional
|
||||
$SHORT_DOC [[ expression ]]
|
||||
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. The
|
||||
&& and || operators do not evaluate EXPR2 if EXPR1 is sufficient to
|
||||
determine the expression's value.
|
||||
$END
|
||||
|
||||
$BUILTIN variables
|
||||
$DOCNAME variable_help
|
||||
$SHORT_DOC variables - Some variable names and meanings
|
||||
BASH_VERSION Version information for this Bash.
|
||||
CDPATH A colon-separated list of directories to search
|
||||
for directries 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
|
||||
@@ -1,831 +0,0 @@
|
||||
This file is set.def, from which is created set.c.
|
||||
It implements the "set" and "unset" builtins in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES set.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 "../flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#if defined (READLINE)
|
||||
# include "../input.h"
|
||||
# include "../bashline.h"
|
||||
# include <readline/readline.h>
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int posixly_correct, ignoreeof, eof_encountered_limit;
|
||||
#if defined (HISTORY)
|
||||
extern int dont_save_function_defs;
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
extern int no_line_editing;
|
||||
#endif /* READLINE */
|
||||
|
||||
$BUILTIN set
|
||||
$FUNCTION set_builtin
|
||||
$SHORT_DOC set [--abefhkmnptuvxBCHP] [-o option] [arg ...]
|
||||
-a Mark variables which are modified or created for export.
|
||||
-b Notify of job termination immediately.
|
||||
-e Exit immediately if a command exits with a non-zero status.
|
||||
-f Disable file name generation (globbing).
|
||||
-h Remember the location of commands as they are looked up.
|
||||
-k All assignment arguments are placed in the environment for a
|
||||
command, not just those that precede the command name.
|
||||
-m Job control is enabled.
|
||||
-n Read commands but do not execute them.
|
||||
-o option-name
|
||||
Set the variable corresponding to option-name:
|
||||
allexport same as -a
|
||||
braceexpand same as -B
|
||||
#if defined (READLINE)
|
||||
emacs use an emacs-style line editing interface
|
||||
#endif /* READLINE */
|
||||
errexit same as -e
|
||||
errtrace same as -E
|
||||
functrace same as -T
|
||||
hashall same as -h
|
||||
#if defined (BANG_HISTORY)
|
||||
histexpand same as -H
|
||||
#endif /* BANG_HISTORY */
|
||||
#if defined (HISTORY)
|
||||
history enable command history
|
||||
#endif
|
||||
ignoreeof the shell will not exit upon reading EOF
|
||||
interactive-comments
|
||||
allow comments to appear in interactive commands
|
||||
keyword same as -k
|
||||
monitor same as -m
|
||||
noclobber same as -C
|
||||
noexec same as -n
|
||||
noglob same as -f
|
||||
nolog currently accepted but ignored
|
||||
notify same as -b
|
||||
nounset same as -u
|
||||
onecmd same as -t
|
||||
physical same as -P
|
||||
pipefail the return value of a pipeline is the status of
|
||||
the last command to exit with a non-zero status,
|
||||
or zero if no command exited with a non-zero status
|
||||
posix change the behavior of bash where the default
|
||||
operation differs from the 1003.2 standard to
|
||||
match the standard
|
||||
privileged same as -p
|
||||
verbose same as -v
|
||||
#if defined (READLINE)
|
||||
vi use a vi-style line editing interface
|
||||
#endif /* READLINE */
|
||||
xtrace same as -x
|
||||
-p Turned on whenever the real and effective user ids do not match.
|
||||
Disables processing of the $ENV file and importing of shell
|
||||
functions. Turning this option off causes the effective uid and
|
||||
gid to be set to the real uid and gid.
|
||||
-t Exit after reading and executing one command.
|
||||
-u Treat unset variables as an error when substituting.
|
||||
-v Print shell input lines as they are read.
|
||||
-x Print commands and their arguments as they are executed.
|
||||
#if defined (BRACE_EXPANSION)
|
||||
-B the shell will perform brace expansion
|
||||
#endif /* BRACE_EXPANSION */
|
||||
-C If set, disallow existing regular files to be overwritten
|
||||
by redirection of output.
|
||||
-E If set, the ERR trap is inherited by shell functions.
|
||||
#if defined (BANG_HISTORY)
|
||||
-H Enable ! style history substitution. This flag is on
|
||||
by default.
|
||||
#endif /* BANG_HISTORY */
|
||||
-P If set, do not follow symbolic links when executing commands
|
||||
such as cd which change the current directory.
|
||||
-T If set, the DEBUG trap is inherited by shell functions.
|
||||
- Assign any remaining arguments to the positional parameters.
|
||||
The -x and -v options are turned off.
|
||||
|
||||
Using + rather than - causes these flags to be turned off. The
|
||||
flags can also be used upon invocation of the shell. The current
|
||||
set of flags may be found in $-. The remaining n ARGs are positional
|
||||
parameters and are assigned, in order, to $1, $2, .. $n. If no
|
||||
ARGs are given, all shell variables are printed.
|
||||
$END
|
||||
|
||||
typedef int setopt_set_func_t __P((int, char *));
|
||||
typedef int setopt_get_func_t __P((char *));
|
||||
|
||||
static void print_minus_o_option __P((char *, int, int));
|
||||
static void print_all_shell_variables __P((void));
|
||||
|
||||
static int set_ignoreeof __P((int, char *));
|
||||
static int set_posix_mode __P((int, char *));
|
||||
|
||||
#if defined (READLINE)
|
||||
static int set_edit_mode __P((int, char *));
|
||||
static int get_edit_mode __P((char *));
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
static int bash_set_history __P((int, char *));
|
||||
#endif
|
||||
|
||||
static char *on = "on";
|
||||
static char *off = "off";
|
||||
|
||||
/* A struct used to match long options for set -o to the corresponding
|
||||
option letter or internal variable. The functions can be called to
|
||||
dynamically generate values. */
|
||||
struct {
|
||||
char *name;
|
||||
int letter;
|
||||
int *variable;
|
||||
setopt_set_func_t *set_func;
|
||||
setopt_get_func_t *get_func;
|
||||
} o_options[] = {
|
||||
{ "allexport", 'a', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (BRACE_EXPANSION)
|
||||
{ "braceexpand",'B', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (READLINE)
|
||||
{ "emacs", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
|
||||
#endif
|
||||
{ "errexit", 'e', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "errtrace", 'E', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "functrace", 'T', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "hashall", 'h', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (BANG_HISTORY)
|
||||
{ "histexpand", 'H', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif /* BANG_HISTORY */
|
||||
#if defined (HISTORY)
|
||||
{ "history", '\0', &remember_on_history, bash_set_history, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
{ "ignoreeof", '\0', &ignoreeof, set_ignoreeof, (setopt_get_func_t *)NULL },
|
||||
{ "interactive-comments", '\0', &interactive_comments, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "keyword", 'k', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "monitor", 'm', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noclobber", 'C', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noexec", 'n', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "noglob", 'f', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "nolog", '\0', &dont_save_function_defs, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "notify", 'b', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#endif /* JOB_CONTROL */
|
||||
{ "nounset", 'u', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "onecmd", 't', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "physical", 'P', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "pipefail", '\0', &pipefail_opt, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "posix", '\0', &posixly_correct, set_posix_mode, (setopt_get_func_t *)NULL },
|
||||
{ "privileged", 'p', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{ "verbose", 'v', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "vi", '\0', (int *)NULL, set_edit_mode, get_edit_mode },
|
||||
#endif
|
||||
{ "xtrace", 'x', (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
{(char *)NULL, 0 , (int *)NULL, (setopt_set_func_t *)NULL, (setopt_get_func_t *)NULL },
|
||||
};
|
||||
|
||||
#define N_O_OPTIONS (sizeof (o_options) / sizeof (o_options[0]))
|
||||
|
||||
#define GET_BINARY_O_OPTION_VALUE(i, name) \
|
||||
((o_options[i].get_func) ? (*o_options[i].get_func) (name) \
|
||||
: (*o_options[i].variable))
|
||||
|
||||
#define SET_BINARY_O_OPTION_VALUE(i, onoff, name) \
|
||||
((o_options[i].set_func) ? (*o_options[i].set_func) (onoff, name) \
|
||||
: (*o_options[i].variable = (onoff == FLAG_ON)))
|
||||
|
||||
int
|
||||
minus_o_option_value (name)
|
||||
char *name;
|
||||
{
|
||||
register int i;
|
||||
int *on_or_off;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (name, o_options[i].name))
|
||||
{
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
return ((on_or_off == FLAG_UNKNOWN) ? -1 : *on_or_off);
|
||||
}
|
||||
else
|
||||
return (GET_BINARY_O_OPTION_VALUE (i, name));
|
||||
}
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#define MINUS_O_FORMAT "%-15s\t%s\n"
|
||||
|
||||
static void
|
||||
print_minus_o_option (name, value, pflag)
|
||||
char *name;
|
||||
int value, pflag;
|
||||
{
|
||||
if (pflag == 0)
|
||||
printf (MINUS_O_FORMAT, name, value ? on : off);
|
||||
else
|
||||
printf ("set %co %s\n", value ? '-' : '+', name);
|
||||
}
|
||||
|
||||
void
|
||||
list_minus_o_opts (mode, reusable)
|
||||
int mode, reusable;
|
||||
{
|
||||
register int i;
|
||||
int *on_or_off, value;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
value = 0;
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
if (on_or_off == FLAG_UNKNOWN)
|
||||
on_or_off = &value;
|
||||
if (mode == -1 || mode == *on_or_off)
|
||||
print_minus_o_option (o_options[i].name, *on_or_off, reusable);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = GET_BINARY_O_OPTION_VALUE (i, o_options[i].name);
|
||||
if (mode == -1 || mode == value)
|
||||
print_minus_o_option (o_options[i].name, value, reusable);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
char **
|
||||
get_minus_o_opts ()
|
||||
{
|
||||
char **ret;
|
||||
int i;
|
||||
|
||||
ret = strvec_create (N_O_OPTIONS + 1);
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
ret[i] = o_options[i].name;
|
||||
ret[i] = (char *)NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
set_ignoreeof (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
ignoreeof = on_or_off == FLAG_ON;
|
||||
unbind_variable ("ignoreeof");
|
||||
if (ignoreeof)
|
||||
bind_variable ("IGNOREEOF", "10", 0);
|
||||
else
|
||||
unbind_variable ("IGNOREEOF");
|
||||
sv_ignoreeof ("IGNOREEOF");
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set_posix_mode (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
posixly_correct = on_or_off == FLAG_ON;
|
||||
if (posixly_correct == 0)
|
||||
unbind_variable ("POSIXLY_CORRECT");
|
||||
else
|
||||
bind_variable ("POSIXLY_CORRECT", "y", 0);
|
||||
sv_strict_posix ("POSIXLY_CORRECT");
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
/* Magic. This code `knows' how readline handles rl_editing_mode. */
|
||||
static int
|
||||
set_edit_mode (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
int isemacs;
|
||||
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
rl_variable_bind ("editing-mode", option_name);
|
||||
|
||||
if (interactive)
|
||||
with_input_from_stdin ();
|
||||
no_line_editing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
isemacs = rl_editing_mode == 1;
|
||||
if ((isemacs && *option_name == 'e') || (!isemacs && *option_name == 'v'))
|
||||
{
|
||||
if (interactive)
|
||||
with_input_from_stream (stdin, "stdin");
|
||||
no_line_editing = 1;
|
||||
}
|
||||
}
|
||||
return 1-no_line_editing;
|
||||
}
|
||||
|
||||
static int
|
||||
get_edit_mode (name)
|
||||
char *name;
|
||||
{
|
||||
return (*name == 'e' ? no_line_editing == 0 && rl_editing_mode == 1
|
||||
: no_line_editing == 0 && rl_editing_mode == 0);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
#if defined (HISTORY)
|
||||
static int
|
||||
bash_set_history (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
bash_history_enable ();
|
||||
if (history_lines_this_session == 0)
|
||||
load_history ();
|
||||
}
|
||||
else
|
||||
bash_history_disable ();
|
||||
return (1 - remember_on_history);
|
||||
}
|
||||
#endif
|
||||
|
||||
int
|
||||
set_minus_o_option (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (option_name, o_options[i].name))
|
||||
{
|
||||
if (o_options[i].letter == 0)
|
||||
{
|
||||
SET_BINARY_O_OPTION_VALUE (i, on_or_off, option_name);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (change_flag (o_options[i].letter, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
sh_invalidoptname (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
sh_invalidoptname (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_shell_variables ()
|
||||
{
|
||||
SHELL_VAR **vars;
|
||||
|
||||
vars = all_shell_variables ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
/* POSIX.2 does not allow function names and definitions to be output when
|
||||
`set' is invoked without options (PASC Interp #202). */
|
||||
if (posixly_correct == 0)
|
||||
{
|
||||
vars = all_shell_functions ();
|
||||
if (vars)
|
||||
{
|
||||
print_func_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
set_shellopts ()
|
||||
{
|
||||
char *value;
|
||||
char tflag[N_O_OPTIONS];
|
||||
int vsize, i, vptr, *ip, exported;
|
||||
SHELL_VAR *v;
|
||||
|
||||
for (vsize = i = 0; o_options[i].name; i++)
|
||||
{
|
||||
tflag[i] = 0;
|
||||
if (o_options[i].letter)
|
||||
{
|
||||
ip = find_flag (o_options[i].letter);
|
||||
if (ip && *ip)
|
||||
{
|
||||
vsize += strlen (o_options[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
else if (GET_BINARY_O_OPTION_VALUE (i, o_options[i].name))
|
||||
{
|
||||
vsize += strlen (o_options[i].name) + 1;
|
||||
tflag[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
value = (char *)xmalloc (vsize + 1);
|
||||
|
||||
for (i = vptr = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (tflag[i])
|
||||
{
|
||||
strcpy (value + vptr, o_options[i].name);
|
||||
vptr += strlen (o_options[i].name);
|
||||
value[vptr++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
if (vptr)
|
||||
vptr--; /* cut off trailing colon */
|
||||
value[vptr] = '\0';
|
||||
|
||||
v = find_variable ("SHELLOPTS");
|
||||
|
||||
/* Turn off the read-only attribute so we can bind the new value, and
|
||||
note whether or not the variable was exported. */
|
||||
if (v)
|
||||
{
|
||||
VUNSETATTR (v, att_readonly);
|
||||
exported = exported_p (v);
|
||||
}
|
||||
else
|
||||
exported = 0;
|
||||
|
||||
v = bind_variable ("SHELLOPTS", value, 0);
|
||||
|
||||
/* Turn the read-only attribute back on, and turn off the export attribute
|
||||
if it was set implicitly by mark_modified_vars and SHELLOPTS was not
|
||||
exported before we bound the new value. */
|
||||
VSETATTR (v, att_readonly);
|
||||
if (mark_modified_vars && exported == 0 && exported_p (v))
|
||||
VUNSETATTR (v, att_exported);
|
||||
|
||||
free (value);
|
||||
}
|
||||
|
||||
void
|
||||
parse_shellopts (value)
|
||||
char *value;
|
||||
{
|
||||
char *vname;
|
||||
int vptr;
|
||||
|
||||
vptr = 0;
|
||||
while (vname = extract_colon_unit (value, &vptr))
|
||||
{
|
||||
set_minus_o_option (FLAG_ON, vname);
|
||||
free (vname);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
initialize_shell_options (no_shellopts)
|
||||
int no_shellopts;
|
||||
{
|
||||
char *temp;
|
||||
SHELL_VAR *var;
|
||||
|
||||
if (no_shellopts == 0)
|
||||
{
|
||||
var = find_variable ("SHELLOPTS");
|
||||
/* set up any shell options we may have inherited. */
|
||||
if (var && imported_p (var))
|
||||
{
|
||||
temp = (array_p (var)) ? (char *)NULL : savestring (value_cell (var));
|
||||
if (temp)
|
||||
{
|
||||
parse_shellopts (temp);
|
||||
free (temp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Set up the $SHELLOPTS variable. */
|
||||
set_shellopts ();
|
||||
}
|
||||
|
||||
/* Reset the values of the -o options that are not also shell flags. This is
|
||||
called from execute_cmd.c:initialize_subshell() when setting up a subshell
|
||||
to run an executable shell script without a leading `#!'. */
|
||||
void
|
||||
reset_shell_options ()
|
||||
{
|
||||
#if defined (HISTORY)
|
||||
remember_on_history = 1;
|
||||
#endif
|
||||
ignoreeof = 0;
|
||||
}
|
||||
|
||||
/* Set some flags from the word values in the input list. If LIST is empty,
|
||||
then print out the values of the variables instead. If LIST contains
|
||||
non-flags, then set $1 - $9 to the successive words of LIST. */
|
||||
int
|
||||
set_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int on_or_off, flag_name, force_assignment, opts_changed;
|
||||
WORD_LIST *l;
|
||||
register char *arg;
|
||||
char s[3];
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
print_all_shell_variables ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Check validity of flag arguments. */
|
||||
reset_internal_getopt ();
|
||||
while ((flag_name = internal_getopt (list, optflags)) != -1)
|
||||
{
|
||||
switch (flag_name)
|
||||
{
|
||||
case '?':
|
||||
builtin_usage ();
|
||||
return (list_optopt == '?' ? EXECUTION_SUCCESS : EX_USAGE);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Do the set command. While the list consists of words starting with
|
||||
'-' or '+' treat them as flags, otherwise, start assigning them to
|
||||
$1 ... $n. */
|
||||
for (force_assignment = opts_changed = 0; list; )
|
||||
{
|
||||
arg = list->word->word;
|
||||
|
||||
/* If the argument is `--' or `-' then signal the end of the list
|
||||
and remember the remaining arguments. */
|
||||
if (arg[0] == '-' && (!arg[1] || (arg[1] == '-' && !arg[2])))
|
||||
{
|
||||
list = list->next;
|
||||
|
||||
/* `set --' unsets the positional parameters. */
|
||||
if (arg[1] == '-')
|
||||
force_assignment = 1;
|
||||
|
||||
/* Until told differently, the old shell behaviour of
|
||||
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
|
||||
stands. Posix.2 says the behaviour is marked as obsolescent. */
|
||||
else
|
||||
{
|
||||
change_flag ('x', '+');
|
||||
change_flag ('v', '+');
|
||||
opts_changed = 1;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((on_or_off = *arg) && (on_or_off == '-' || on_or_off == '+'))
|
||||
{
|
||||
while (flag_name = *++arg)
|
||||
{
|
||||
if (flag_name == '?')
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (flag_name == 'o') /* -+o option-name */
|
||||
{
|
||||
char *option_name;
|
||||
WORD_LIST *opt;
|
||||
|
||||
opt = list->next;
|
||||
|
||||
if (opt == 0)
|
||||
{
|
||||
list_minus_o_opts (-1, (on_or_off == '+'));
|
||||
continue;
|
||||
}
|
||||
|
||||
option_name = opt->word->word;
|
||||
|
||||
if (option_name == 0 || *option_name == '\0' ||
|
||||
*option_name == '-' || *option_name == '+')
|
||||
{
|
||||
list_minus_o_opts (-1, (on_or_off == '+'));
|
||||
continue;
|
||||
}
|
||||
list = list->next; /* Skip over option name. */
|
||||
|
||||
opts_changed = 1;
|
||||
if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
|
||||
{
|
||||
set_shellopts ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
s[0] = on_or_off;
|
||||
s[1] = flag_name;
|
||||
s[2] = '\0';
|
||||
sh_invalidopt (s);
|
||||
builtin_usage ();
|
||||
set_shellopts ();
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
opts_changed = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Assigning $1 ... $n */
|
||||
if (list || force_assignment)
|
||||
remember_args (list, 1);
|
||||
/* Set up new value of $SHELLOPTS */
|
||||
if (opts_changed)
|
||||
set_shellopts ();
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
$BUILTIN unset
|
||||
$FUNCTION unset_builtin
|
||||
$SHORT_DOC unset [-f] [-v] [name ...]
|
||||
For each NAME, remove the corresponding variable or function. Given
|
||||
the `-v', unset will only act on variables. Given the `-f' flag,
|
||||
unset will only act on functions. With neither flag, unset first
|
||||
tries to unset a variable, and if that fails, then tries to unset a
|
||||
function. Some variables cannot be unset; also see readonly.
|
||||
$END
|
||||
|
||||
#define NEXT_VARIABLE() any_failed++; list = list->next; continue;
|
||||
|
||||
int
|
||||
unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function, unset_variable, unset_array, opt, any_failed;
|
||||
char *name;
|
||||
|
||||
unset_function = unset_variable = unset_array = any_failed = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
unset_function = 1;
|
||||
break;
|
||||
case 'v':
|
||||
unset_variable = 1;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (unset_function && unset_variable)
|
||||
{
|
||||
builtin_error (_("cannot simultaneously unset a function and a variable"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int tem;
|
||||
#if defined (ARRAY_VARS)
|
||||
char *t;
|
||||
#endif
|
||||
|
||||
name = list->word->word;
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
unset_array = 0;
|
||||
if (!unset_function && valid_array_reference (name))
|
||||
{
|
||||
t = strchr (name, '[');
|
||||
*t++ = '\0';
|
||||
unset_array++;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Bash allows functions with names which are not valid identifiers
|
||||
to be created when not in posix mode, so check only when in posix
|
||||
mode when unsetting a function. */
|
||||
if (((unset_function && posixly_correct) || !unset_function) && legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
var = unset_function ? find_function (name) : find_variable (name);
|
||||
|
||||
if (var && !unset_function && non_unsettable_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot unset"), name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Posix.2 says that unsetting readonly variables is an error. */
|
||||
if (var && readonly_p (var))
|
||||
{
|
||||
builtin_error (_("%s: cannot unset: readonly %s"),
|
||||
name, unset_function ? "function" : "variable");
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* Unless the -f option is supplied, the name refers to a variable. */
|
||||
#if defined (ARRAY_VARS)
|
||||
if (var && unset_array)
|
||||
{
|
||||
if (array_p (var) == 0)
|
||||
{
|
||||
builtin_error (_("%s: not an array variable"), name);
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
else
|
||||
{
|
||||
tem = unbind_array_element (var, t);
|
||||
if (tem == -1)
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* ARRAY_VARS */
|
||||
tem = unset_function ? unbind_func (name) : unbind_variable (name);
|
||||
|
||||
/* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
|
||||
is specified, the name refers to a variable; if a variable by
|
||||
that name does not exist, a function by that name, if any,
|
||||
shall be unset.'' */
|
||||
if (tem == -1 && !unset_function && !unset_variable)
|
||||
tem = unbind_func (name);
|
||||
|
||||
/* SUSv3, POSIX.1-2001 say: ``Unsetting a variable or function that
|
||||
was not previously set shall not be considered an error.'' */
|
||||
|
||||
if (unset_function == 0)
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -1,439 +0,0 @@
|
||||
This file is setattr.def, from which is created setattr.c.
|
||||
It implements the builtins "export" and "readonly", in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$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 "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int posixly_correct;
|
||||
extern int array_needs_making;
|
||||
extern char *this_command_name;
|
||||
extern sh_builtin_func_t *this_shell_builtin;
|
||||
|
||||
#ifdef ARRAY_VARS
|
||||
extern int declare_builtin __P((WORD_LIST *));
|
||||
#endif
|
||||
|
||||
#define READONLY_OR_EXPORT \
|
||||
(this_shell_builtin == readonly_builtin || this_shell_builtin == export_builtin)
|
||||
|
||||
$BUILTIN export
|
||||
$FUNCTION export_builtin
|
||||
$SHORT_DOC export [-nf] [name[=value] ...] or export -p
|
||||
NAMEs are marked for automatic export to the environment of
|
||||
subsequently executed commands. If the -f option is given,
|
||||
the NAMEs refer to functions. If no NAMEs are given, or if `-p'
|
||||
is given, a list of all names that are exported in this shell is
|
||||
printed. An argument of `-n' says to remove the export property
|
||||
from subsequent NAMEs. An argument of `--' disables further option
|
||||
processing.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable appear in the
|
||||
environment passed to simple commands. If there is no LIST, then
|
||||
print all such variables. An argument of `-n' says to remove the
|
||||
exported attribute from variables named in LIST. An argument of
|
||||
-f indicates that the names present in LIST refer to functions. */
|
||||
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 [-af] [name[=value] ...] or readonly -p
|
||||
The given NAMEs are marked readonly and the values of these NAMEs may
|
||||
not be changed by subsequent assignment. If the -f option is given,
|
||||
then functions corresponding to the NAMEs are so marked. If no
|
||||
arguments are given, or if `-p' is given, a list of all readonly names
|
||||
is printed. The `-a' option means to treat each NAME as
|
||||
an array variable. An argument of `--' disables further option
|
||||
processing.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable readonly. Given an
|
||||
empty LIST, print out all existing readonly variables. */
|
||||
int
|
||||
readonly_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_readonly, 0));
|
||||
}
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
# define ATTROPTS "afnp"
|
||||
#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, functions_only, arrays_only, any_failed, assign_error, opt;
|
||||
int aflags;
|
||||
char *name;
|
||||
#if defined (ARRAY_VARS)
|
||||
WORD_LIST *nlist, *tlist;
|
||||
WORD_DESC *w;
|
||||
#endif
|
||||
|
||||
undo = functions_only = arrays_only = 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;
|
||||
#endif
|
||||
case 'p':
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (attribute & att_exported)
|
||||
array_needs_making = 1;
|
||||
|
||||
/* Cannot undo readonly status, silently disallowed. */
|
||||
if (undo && (attribute & att_readonly))
|
||||
attribute &= ~att_readonly;
|
||||
|
||||
while (list)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
if (functions_only) /* xxx -f name */
|
||||
{
|
||||
var = find_function (name);
|
||||
if (var == 0)
|
||||
{
|
||||
builtin_error (_("%s: not a function"), name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* xxx [-np] name[=value] */
|
||||
assign = assignment (name, 0);
|
||||
|
||||
aflags = 0;
|
||||
if (assign)
|
||||
{
|
||||
name[assign] = '\0';
|
||||
if (name[assign - 1] == '+')
|
||||
{
|
||||
aflags |= ASS_APPEND;
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
sh_invalidid (name);
|
||||
if (assign)
|
||||
assign_error++;
|
||||
else
|
||||
any_failed++;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assign) /* xxx [-np] name=value */
|
||||
{
|
||||
name[assign] = '=';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '+';
|
||||
#if defined (ARRAY_VARS)
|
||||
/* Let's try something here. Turn readonly -a xxx=yyy into
|
||||
declare -ra xxx=yyy and see what that gets us. */
|
||||
if (arrays_only)
|
||||
{
|
||||
tlist = list->next;
|
||||
list->next = (WORD_LIST *)NULL;
|
||||
w = make_word ("-ra");
|
||||
nlist = make_word_list (w, list);
|
||||
opt = declare_builtin (nlist);
|
||||
if (opt != EXECUTION_SUCCESS)
|
||||
assign_error++;
|
||||
list->next = tlist;
|
||||
dispose_word (w);
|
||||
free (nlist);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
/* This word has already been expanded once with command
|
||||
and parameter expansion. Call do_assignment_no_expand (),
|
||||
which does not do command or parameter substitution. If
|
||||
the assignment is not performed correctly, flag an error. */
|
||||
if (do_assignment_no_expand (name) == 0)
|
||||
assign_error++;
|
||||
name[assign] = '\0';
|
||||
if (aflags & ASS_APPEND)
|
||||
name[assign - 1] = '\0';
|
||||
}
|
||||
|
||||
set_var_attribute (name, attribute, undo);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR **variable_list;
|
||||
register int i;
|
||||
|
||||
if ((attribute & att_function) || functions_only)
|
||||
{
|
||||
variable_list = all_shell_functions ();
|
||||
if (attribute != att_function)
|
||||
attribute &= ~att_function; /* so declare -xf works, for example */
|
||||
}
|
||||
else
|
||||
variable_list = all_shell_variables ();
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (attribute & att_array)
|
||||
{
|
||||
arrays_only++;
|
||||
if (attribute != att_array)
|
||||
attribute &= ~att_array;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (variable_list)
|
||||
{
|
||||
for (i = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (arrays_only && array_p (var) == 0)
|
||||
continue;
|
||||
#endif
|
||||
if ((var->attributes & attribute))
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
}
|
||||
free (variable_list);
|
||||
}
|
||||
}
|
||||
|
||||
return (assign_error ? EX_BADASSIGN
|
||||
: ((any_failed == 0) ? EXECUTION_SUCCESS
|
||||
: EXECUTION_FAILURE));
|
||||
}
|
||||
|
||||
/* Show the attributes for shell variable VAR. If NODEFS is non-zero,
|
||||
don't show function definitions along with the name. If PATTR is
|
||||
non-zero, it indicates we're being called from `export' or `readonly'.
|
||||
In POSIX mode, this prints the name of the calling builtin (`export'
|
||||
or `readonly') instead of `declare', and doesn't print function defs
|
||||
when called by `export' or `readonly'. */
|
||||
int
|
||||
show_var_attributes (var, pattr, nodefs)
|
||||
SHELL_VAR *var;
|
||||
int pattr, nodefs;
|
||||
{
|
||||
char flags[8], *x;
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
|
||||
/* pattr == 0 means we are called from `declare'. */
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
|
||||
if (integer_p (var))
|
||||
flags[i++] = 'i';
|
||||
|
||||
if (readonly_p (var))
|
||||
flags[i++] = 'r';
|
||||
|
||||
if (trace_p (var))
|
||||
flags[i++] = 't';
|
||||
|
||||
if (exported_p (var))
|
||||
flags[i++] = 'x';
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
flags[i++] = 'a';
|
||||
#endif
|
||||
|
||||
if (function_p (var))
|
||||
flags[i++] = 'f';
|
||||
}
|
||||
|
||||
flags[i] = '\0';
|
||||
|
||||
/* If we're printing functions with definitions, print the function def
|
||||
first, then the attributes, instead of printing output that can't be
|
||||
reused as input to recreate the current state. */
|
||||
if (function_p (var) && nodefs == 0 && (pattr == 0 || posixly_correct == 0))
|
||||
{
|
||||
printf ("%s\n", named_function_string (var->name, function_cell (var), 1));
|
||||
nodefs++;
|
||||
if (pattr == 0 && i == 1 && flags[0] == 'f')
|
||||
return 0; /* don't print `declare -f name' */
|
||||
}
|
||||
|
||||
if (pattr == 0 || posixly_correct == 0)
|
||||
printf ("declare -%s ", i ? flags : "-");
|
||||
else if (i)
|
||||
printf ("%s -%s ", this_command_name, flags);
|
||||
else
|
||||
printf ("%s ", this_command_name);
|
||||
|
||||
#if defined (ARRAY_VARS)
|
||||
if (array_p (var))
|
||||
print_array_assignment (var, 1);
|
||||
else
|
||||
#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), 1));
|
||||
else if (invisible_p (var))
|
||||
printf ("%s\n", var->name);
|
||||
else
|
||||
{
|
||||
x = sh_double_quote (var_isset (var) ? value_cell (var) : "");
|
||||
printf ("%s=%s\n", var->name, x);
|
||||
free (x);
|
||||
}
|
||||
return (0);
|
||||
}
|
||||
|
||||
int
|
||||
show_name_attributes (name, nodefs)
|
||||
char *name;
|
||||
int nodefs;
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable_internal (name, 1);
|
||||
|
||||
if (var && invisible_p (var) == 0)
|
||||
{
|
||||
show_var_attributes (var, READONLY_OR_EXPORT, nodefs);
|
||||
return (0);
|
||||
}
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
|
||||
void
|
||||
set_var_attribute (name, attribute, undo)
|
||||
char *name;
|
||||
int attribute, undo;
|
||||
{
|
||||
SHELL_VAR *var, *tv;
|
||||
char *tvalue;
|
||||
|
||||
if (undo)
|
||||
var = find_variable (name);
|
||||
else
|
||||
{
|
||||
tv = find_tempenv_variable (name);
|
||||
/* XXX -- need to handle case where tv is a temp variable in a
|
||||
function-scope context, since function_env has been merged into
|
||||
the local variables table. */
|
||||
if (tv && tempvar_p (tv))
|
||||
{
|
||||
tvalue = var_isset (tv) ? savestring (value_cell (tv)) : savestring ("");
|
||||
|
||||
var = bind_variable (tv->name, tvalue, 0);
|
||||
var->attributes |= tv->attributes & ~att_tempvar;
|
||||
VSETATTR (tv, att_propagate);
|
||||
if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
SETVARATTR (tv, attribute, undo); /* XXX */
|
||||
|
||||
free (tvalue);
|
||||
}
|
||||
else
|
||||
{
|
||||
var = find_variable_internal (name, 0);
|
||||
if (var == 0)
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL, 0);
|
||||
VSETATTR (var, att_invisible);
|
||||
}
|
||||
else if (var->context != 0)
|
||||
VSETATTR (var, att_propagate);
|
||||
}
|
||||
}
|
||||
|
||||
if (var)
|
||||
SETVARATTR (var, attribute, undo);
|
||||
|
||||
if (var && (exported_p (var) || (attribute & att_exported)))
|
||||
array_needs_making++; /* XXX */
|
||||
}
|
||||
@@ -1,540 +0,0 @@
|
||||
This file is shopt.def, from which is created shopt.c.
|
||||
It implements the Bash `shopt' builtin.
|
||||
|
||||
Copyright (C) 1994-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES shopt.c
|
||||
|
||||
$BUILTIN shopt
|
||||
$FUNCTION shopt_builtin
|
||||
$SHORT_DOC shopt [-pqsu] [-o long-option] optname [optname...]
|
||||
Toggle the values of variables controlling optional behavior.
|
||||
The -s flag means to enable (set) each OPTNAME; the -u flag
|
||||
unsets each OPTNAME. The -q flag suppresses output; the exit
|
||||
status indicates whether each OPTNAME is set or unset. The -o
|
||||
option restricts the OPTNAMEs to those defined for use with
|
||||
`set -o'. With no options, or with the -p option, a list of all
|
||||
settable options is displayed, with an indication of whether or
|
||||
not each is set.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
#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;
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
extern int extended_glob;
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
extern int literal_history, command_oriented_history;
|
||||
extern int force_append_history;
|
||||
#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 enable_hostname_completion __P((int));
|
||||
#endif
|
||||
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
extern int prog_completion_enabled;
|
||||
#endif
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
extern char *shell_name;
|
||||
#endif
|
||||
|
||||
#if defined (DEBUGGER)
|
||||
extern int debugging_mode;
|
||||
#endif
|
||||
|
||||
static void shopt_error __P((char *));
|
||||
|
||||
static int set_shellopts_after_change __P((int));
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
static int set_restricted_shell __P((int));
|
||||
#endif
|
||||
|
||||
static int shopt_login_shell;
|
||||
|
||||
typedef int shopt_set_func_t __P((int));
|
||||
|
||||
static struct {
|
||||
char *name;
|
||||
int *value;
|
||||
shopt_set_func_t *set_func;
|
||||
} shopt_vars[] = {
|
||||
{ "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 },
|
||||
{ "checkwinsize", &check_window_size, (shopt_set_func_t *)NULL },
|
||||
#if defined (HISTORY)
|
||||
{ "cmdhist", &command_oriented_history, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "dotglob", &glob_dot_filenames, (shopt_set_func_t *)NULL },
|
||||
{ "execfail", &no_exit_on_failed_exec, (shopt_set_func_t *)NULL },
|
||||
{ "expand_aliases", &expand_aliases, (shopt_set_func_t *)NULL },
|
||||
#if defined (DEBUGGER)
|
||||
{ "extdebug", &debugging_mode, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
#if defined (EXTENDED_GLOB)
|
||||
{ "extglob", &extended_glob, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "extquote", &extended_quote, (shopt_set_func_t *)NULL },
|
||||
{ "failglob", &fail_glob_expansion, (shopt_set_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "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, enable_hostname_completion },
|
||||
#endif
|
||||
{ "huponexit", &hup_on_exit, (shopt_set_func_t *)NULL },
|
||||
{ "interactive_comments", &interactive_comments, set_shellopts_after_change },
|
||||
#if defined (HISTORY)
|
||||
{ "lithist", &literal_history, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "login_shell", &shopt_login_shell, set_login_shell },
|
||||
{ "mailwarn", &mail_warning, (shopt_set_func_t *)NULL },
|
||||
#if defined (READLINE)
|
||||
{ "no_empty_cmd_completion", &no_empty_command_completion, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "nocaseglob", &glob_ignore_case, (shopt_set_func_t *)NULL },
|
||||
{ "nocasematch", &match_ignore_case, (shopt_set_func_t *)NULL },
|
||||
{ "nullglob", &allow_null_glob_expansion, (shopt_set_func_t *)NULL },
|
||||
#if defined (PROGRAMMABLE_COMPLETION)
|
||||
{ "progcomp", &prog_completion_enabled, (shopt_set_func_t *)NULL },
|
||||
#endif
|
||||
{ "promptvars", &promptvars, (shopt_set_func_t *)NULL },
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
{ "restricted_shell", &restricted_shell, set_restricted_shell },
|
||||
#endif
|
||||
{ "shift_verbose", &print_shift_error, (shopt_set_func_t *)NULL },
|
||||
{ "sourcepath", &source_uses_path, (shopt_set_func_t *)NULL },
|
||||
{ "xpg_echo", &xpg_echo, (shopt_set_func_t *)NULL },
|
||||
{ (char *)0, (int *)0, (shopt_set_func_t *)NULL }
|
||||
};
|
||||
|
||||
static char *on = "on";
|
||||
static char *off = "off";
|
||||
|
||||
static int find_shopt __P((char *));
|
||||
static int toggle_shopts __P((int, WORD_LIST *, int));
|
||||
static void print_shopt __P((char *, int, int));
|
||||
static int list_shopts __P((WORD_LIST *, int));
|
||||
static int list_some_shopts __P((int, int));
|
||||
static int list_shopt_o_options __P((WORD_LIST *, int));
|
||||
static int list_some_o_options __P((int, int));
|
||||
static int set_shopt_o_options __P((int, WORD_LIST *, int));
|
||||
|
||||
#define SFLAG 0x01
|
||||
#define UFLAG 0x02
|
||||
#define QFLAG 0x04
|
||||
#define OFLAG 0x08
|
||||
#define PFLAG 0x10
|
||||
|
||||
int
|
||||
shopt_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int opt, flags, rval;
|
||||
|
||||
flags = 0;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "psuoq")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 's':
|
||||
flags |= SFLAG;
|
||||
break;
|
||||
case 'u':
|
||||
flags |= UFLAG;
|
||||
break;
|
||||
case 'q':
|
||||
flags |= QFLAG;
|
||||
break;
|
||||
case 'o':
|
||||
flags |= OFLAG;
|
||||
break;
|
||||
case 'p':
|
||||
flags |= PFLAG;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if ((flags & (SFLAG|UFLAG)) == (SFLAG|UFLAG))
|
||||
{
|
||||
builtin_error (_("cannot set and unset shell options simultaneously"));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
rval = EXECUTION_SUCCESS;
|
||||
if ((flags & OFLAG) && ((flags & (SFLAG|UFLAG)) == 0)) /* shopt -o */
|
||||
rval = list_shopt_o_options (list, flags);
|
||||
else if (list && (flags & OFLAG)) /* shopt -so args */
|
||||
rval = set_shopt_o_options ((flags & SFLAG) ? FLAG_ON : FLAG_OFF, list, flags & QFLAG);
|
||||
else if (flags & OFLAG) /* shopt -so */
|
||||
rval = list_some_o_options ((flags & SFLAG) ? 1 : 0, flags);
|
||||
else if (list && (flags & (SFLAG|UFLAG))) /* shopt -su args */
|
||||
rval = toggle_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, list, flags & QFLAG);
|
||||
else if ((flags & (SFLAG|UFLAG)) == 0) /* shopt [args] */
|
||||
rval = list_shopts (list, flags);
|
||||
else /* shopt -su */
|
||||
rval = list_some_shopts ((flags & SFLAG) ? SETOPT : UNSETOPT, flags);
|
||||
return (rval);
|
||||
}
|
||||
|
||||
/* Reset the options managed by `shopt' to the values they would have at
|
||||
shell startup. */
|
||||
void
|
||||
reset_shopt_options ()
|
||||
{
|
||||
allow_null_glob_expansion = glob_dot_filenames = 0;
|
||||
cdable_vars = mail_warning = 0;
|
||||
no_exit_on_failed_exec = print_shift_error = 0;
|
||||
check_hashed_filenames = cdspelling = expand_aliases = check_window_size = 0;
|
||||
|
||||
source_uses_path = promptvars = 1;
|
||||
|
||||
#if defined (EXTENDED_GLOB)
|
||||
extended_glob = 0;
|
||||
#endif
|
||||
|
||||
#if defined (HISTORY)
|
||||
literal_history = force_append_history = 0;
|
||||
command_oriented_history = 1;
|
||||
#endif
|
||||
|
||||
#if defined (READLINE)
|
||||
hist_verify = history_reediting = 0;
|
||||
perform_hostname_completion = 1;
|
||||
#endif
|
||||
|
||||
shopt_login_shell = login_shell;
|
||||
}
|
||||
|
||||
static int
|
||||
find_shopt (name)
|
||||
char *name;
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; shopt_vars[i].name; i++)
|
||||
if (STREQ (name, shopt_vars[i].name))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
shopt_error (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error (_("%s: invalid shell option name"), s);
|
||||
}
|
||||
|
||||
static int
|
||||
toggle_shopts (mode, list, quiet)
|
||||
int mode;
|
||||
WORD_LIST *list;
|
||||
int quiet;
|
||||
{
|
||||
WORD_LIST *l;
|
||||
int ind, rval;
|
||||
|
||||
for (l = list, rval = EXECUTION_SUCCESS; l; l = l->next)
|
||||
{
|
||||
ind = find_shopt (l->word->word);
|
||||
if (ind < 0)
|
||||
{
|
||||
shopt_error (l->word->word);
|
||||
rval = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*shopt_vars[ind].value = mode; /* 1 for set, 0 for unset */
|
||||
if (shopt_vars[ind].set_func)
|
||||
(*shopt_vars[ind].set_func) (mode);
|
||||
}
|
||||
}
|
||||
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 (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 (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 (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 (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 (rval);
|
||||
}
|
||||
|
||||
static int
|
||||
list_some_o_options (mode, flags)
|
||||
int mode, flags;
|
||||
{
|
||||
if ((flags & QFLAG) == 0)
|
||||
list_minus_o_opts (mode, (flags & PFLAG));
|
||||
return (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 (mode)
|
||||
int mode;
|
||||
{
|
||||
set_shellopts ();
|
||||
return (0);
|
||||
}
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
/* Don't allow the value of restricted_shell to be modified. */
|
||||
|
||||
static int
|
||||
set_restricted_shell (mode)
|
||||
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 (mode)
|
||||
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 (EXECUTION_SUCCESS);
|
||||
}
|
||||
@@ -1,265 +0,0 @@
|
||||
This file is trap.def, from which is created trap.c.
|
||||
It implements the builtin "trap" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES trap.c
|
||||
|
||||
$BUILTIN trap
|
||||
$FUNCTION trap_builtin
|
||||
$SHORT_DOC trap [-lp] [arg signal_spec ...]
|
||||
The command ARG is to be read and executed when the shell receives
|
||||
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)
|
||||
the command ARG is executed on exit from the shell. If a SIGNAL_SPEC
|
||||
is DEBUG, ARG is executed after every simple command. If the`-p' option
|
||||
is supplied then the trap commands associated with each SIGNAL_SPEC are
|
||||
displayed. If no arguments are supplied or if only `-p' is given, trap
|
||||
prints the list of commands associated with each signal. 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. `trap -l' prints
|
||||
a list of signal names and their corresponding numbers. Note that a
|
||||
signal can be sent to the shell with "kill -signal $$".
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# ifdef _MINIX
|
||||
# include <sys/types.h>
|
||||
# endif
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../trap.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
static void showtrap __P((int));
|
||||
static int display_traps __P((WORD_LIST *));
|
||||
|
||||
/* The trap command:
|
||||
|
||||
trap <arg> <signal ...>
|
||||
trap <signal ...>
|
||||
trap -l
|
||||
trap -p [sigspec ...]
|
||||
trap [--]
|
||||
|
||||
Set things up so that ARG is executed when SIGNAL(s) N is recieved.
|
||||
If ARG is the empty string, then ignore the SIGNAL(s). If there is
|
||||
no ARG, then set the trap for SIGNAL(s) to its original value. Just
|
||||
plain "trap" means to print out the list of commands associated with
|
||||
each signal number. Single arg of "-l" means list the signal names. */
|
||||
|
||||
/* Possible operations to perform on the list of signals.*/
|
||||
#define SET 0 /* Set this signal to first_arg. */
|
||||
#define REVERT 1 /* Revert to this signals original value. */
|
||||
#define IGNORE 2 /* Ignore this signal. */
|
||||
|
||||
extern int posixly_correct;
|
||||
|
||||
int
|
||||
trap_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int list_signal_names, display, result, opt, first_signal;
|
||||
|
||||
list_signal_names = display = 0;
|
||||
result = EXECUTION_SUCCESS;
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
list_signal_names++;
|
||||
break;
|
||||
case 'p':
|
||||
display++;
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
opt = DSIG_NOCASE|DSIG_SIGPREFIX; /* flags for decode_signal */
|
||||
|
||||
if (list_signal_names)
|
||||
return (display_signal_list ((WORD_LIST *)NULL, 1));
|
||||
else if (display || list == 0)
|
||||
return (display_traps (list));
|
||||
else
|
||||
{
|
||||
char *first_arg;
|
||||
int operation, sig, first_signal;
|
||||
|
||||
operation = SET;
|
||||
first_arg = list->word->word;
|
||||
first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
|
||||
|
||||
/* Backwards compatibility */
|
||||
if (first_signal)
|
||||
operation = REVERT;
|
||||
/* When in posix mode, the historical behavior of looking for a
|
||||
missing first argument is disabled. To revert to the original
|
||||
signal handling disposition, use `-' as the first argument. */
|
||||
else if (posixly_correct == 0 && first_arg && *first_arg &&
|
||||
(*first_arg != '-' || first_arg[1]) &&
|
||||
signal_object_p (first_arg, opt) && list->next == 0)
|
||||
operation = REVERT;
|
||||
else
|
||||
{
|
||||
list = list->next;
|
||||
if (list == 0)
|
||||
{
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else if (*first_arg == '\0')
|
||||
operation = IGNORE;
|
||||
else if (first_arg[0] == '-' && !first_arg[1])
|
||||
operation = REVERT;
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
sig = decode_signal (list->word->word, opt);
|
||||
|
||||
if (sig == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case SET:
|
||||
set_signal (sig, first_arg);
|
||||
break;
|
||||
|
||||
case REVERT:
|
||||
restore_default_signal (sig);
|
||||
|
||||
/* Signals that the shell treats specially need special
|
||||
handling. */
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
if (interactive)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
else
|
||||
set_signal_handler (SIGINT, termination_unwind_protect);
|
||||
break;
|
||||
|
||||
case SIGQUIT:
|
||||
/* Always ignore SIGQUIT. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
break;
|
||||
case SIGTERM:
|
||||
#if defined (JOB_CONTROL)
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGTSTP:
|
||||
#endif /* JOB_CONTROL */
|
||||
if (interactive)
|
||||
set_signal_handler (sig, SIG_IGN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IGNORE:
|
||||
ignore_signal (sig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
static void
|
||||
showtrap (i)
|
||||
int i;
|
||||
{
|
||||
char *t, *p, *sn;
|
||||
|
||||
p = trap_list[i];
|
||||
if (p == (char *)DEFAULT_SIG)
|
||||
return;
|
||||
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : sh_single_quote (p);
|
||||
sn = signal_name (i);
|
||||
/* Make sure that signals whose names are unknown (for whatever reason)
|
||||
are printed as signal numbers. */
|
||||
if (STREQN (sn, "SIGJUNK", 7) || STREQN (sn, "unknown", 7))
|
||||
printf ("trap -- %s %d\n", t ? t : "''", i);
|
||||
else if (posixly_correct)
|
||||
{
|
||||
if (STREQN (sn, "SIG", 3))
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn+3);
|
||||
else
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn);
|
||||
}
|
||||
else
|
||||
printf ("trap -- %s %s\n", t ? t : "''", sn);
|
||||
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
static int
|
||||
display_traps (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, i;
|
||||
|
||||
if (list == 0)
|
||||
{
|
||||
for (i = 0; i < BASH_NSIG; i++)
|
||||
showtrap (i);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
for (result = EXECUTION_SUCCESS; list; list = list->next)
|
||||
{
|
||||
i = decode_signal (list->word->word, DSIG_NOCASE|DSIG_SIGPREFIX);
|
||||
if (i == NO_SIG)
|
||||
{
|
||||
sh_invalidsig (list->word->word);
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
else
|
||||
showtrap (i);
|
||||
}
|
||||
|
||||
return (result);
|
||||
}
|
||||
@@ -1,403 +0,0 @@
|
||||
This file is type.def, from which is created type.c.
|
||||
It implements the builtin "type" in Bash.
|
||||
|
||||
Copyright (C) 1987-2002 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES type.c
|
||||
|
||||
$BUILTIN type
|
||||
$FUNCTION type_builtin
|
||||
$SHORT_DOC type [-afptP] name [name ...]
|
||||
For each NAME, indicate how it would be interpreted if used as a
|
||||
command name.
|
||||
|
||||
If the -t option is used, `type' outputs a single word which is one of
|
||||
`alias', `keyword', `function', `builtin', `file' or `', if NAME is an
|
||||
alias, shell reserved word, shell function, shell builtin, disk file,
|
||||
or unfound, respectively.
|
||||
|
||||
If the -p flag is used, `type' either returns the name of the disk
|
||||
file that would be executed, or nothing if `type -t NAME' would not
|
||||
return `file'.
|
||||
|
||||
If the -a flag is used, `type' displays all of the places that contain
|
||||
an executable named `file'. This includes aliases, builtins, and
|
||||
functions, if and only if the -p flag is not also used.
|
||||
|
||||
The -f flag suppresses shell function lookup.
|
||||
|
||||
The -P flag forces 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.
|
||||
$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 "../findcmd.h"
|
||||
#include "../hashcmd.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
#include "../alias.h"
|
||||
#endif /* ALIAS */
|
||||
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int find_reserved_word __P((char *));
|
||||
|
||||
extern char *this_command_name;
|
||||
extern int expand_aliases, posixly_correct;
|
||||
|
||||
/* For each word in LIST, find out what the shell is going to do with
|
||||
it as a simple command. i.e., which file would this shell use to
|
||||
execve, or if it is a builtin command, or an alias. Possible flag
|
||||
arguments:
|
||||
-t Returns the "type" of the object, one of
|
||||
`alias', `keyword', `function', `builtin',
|
||||
or `file'.
|
||||
|
||||
-p Returns the pathname of the file if -type is
|
||||
a file.
|
||||
|
||||
-a Returns all occurrences of words, whether they
|
||||
be a filename in the path, alias, function,
|
||||
or builtin.
|
||||
|
||||
-f Suppress shell function lookup, like `command'.
|
||||
|
||||
-P Force a path search even in the presence of other
|
||||
definitions.
|
||||
|
||||
Order of evaluation:
|
||||
alias
|
||||
keyword
|
||||
function
|
||||
builtin
|
||||
file
|
||||
*/
|
||||
|
||||
int
|
||||
type_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int dflags, successful_finds, opt;
|
||||
WORD_LIST *this;
|
||||
|
||||
if (list == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
dflags = CDESC_SHORTDESC; /* default */
|
||||
successful_finds = 0;
|
||||
|
||||
/* Handle the obsolescent `-type', `-path', and `-all' by prescanning
|
||||
the arguments and converting those options to the form that
|
||||
internal_getopt recognizes. Converts `--type', `--path', and `--all'
|
||||
also. THIS SHOULD REALLY GO AWAY. */
|
||||
for (this = list; this && this->word->word[0] == '-'; this = this->next)
|
||||
{
|
||||
char *flag = &(this->word->word[1]);
|
||||
|
||||
if (STREQ (flag, "type") || STREQ (flag, "-type"))
|
||||
{
|
||||
this->word->word[1] = 't';
|
||||
this->word->word[2] = '\0';
|
||||
}
|
||||
else if (STREQ (flag, "path") || STREQ (flag, "-path"))
|
||||
{
|
||||
this->word->word[1] = 'p';
|
||||
this->word->word[2] = '\0';
|
||||
}
|
||||
else if (STREQ (flag, "all") || STREQ (flag, "-all"))
|
||||
{
|
||||
this->word->word[1] = 'a';
|
||||
this->word->word[2] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "afptP")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
dflags |= CDESC_ALL;
|
||||
break;
|
||||
case 'f':
|
||||
dflags |= CDESC_NOFUNCS;
|
||||
break;
|
||||
case 'p':
|
||||
dflags |= CDESC_PATH_ONLY;
|
||||
dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
|
||||
break;
|
||||
case 't':
|
||||
dflags |= CDESC_TYPE;
|
||||
dflags &= ~(CDESC_PATH_ONLY|CDESC_SHORTDESC);
|
||||
break;
|
||||
case 'P': /* shorthand for type -ap */
|
||||
dflags |= (CDESC_PATH_ONLY|CDESC_FORCE_PATH);
|
||||
dflags &= ~(CDESC_TYPE|CDESC_SHORTDESC);
|
||||
break;
|
||||
default:
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
while (list)
|
||||
{
|
||||
int found;
|
||||
|
||||
found = describe_command (list->word->word, dflags);
|
||||
|
||||
if (!found && (dflags & (CDESC_PATH_ONLY|CDESC_TYPE)) == 0)
|
||||
sh_notfound (list->word->word);
|
||||
|
||||
successful_finds += found;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
return ((successful_finds != 0) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Describe COMMAND as required by the type and command builtins.
|
||||
*
|
||||
* Behavior is controlled by DFLAGS. Flag values are
|
||||
* CDESC_ALL print all descriptions of a command
|
||||
* CDESC_SHORTDESC print the description for type and command -V
|
||||
* CDESC_REUSABLE print in a format that may be reused as input
|
||||
* CDESC_TYPE print the type for type -t
|
||||
* CDESC_PATH_ONLY print the path for type -p
|
||||
* CDESC_FORCE_PATH force a path search for type -P
|
||||
* CDESC_NOFUNCS skip function lookup for type -f
|
||||
* CDESC_ABSPATH convert to absolute path, no ./ prefix
|
||||
*
|
||||
* CDESC_ALL says whether or not to look for all occurrences of COMMAND, or
|
||||
* return after finding it once.
|
||||
*/
|
||||
int
|
||||
describe_command (command, dflags)
|
||||
char *command;
|
||||
int dflags;
|
||||
{
|
||||
int found, i, found_file, f, all;
|
||||
char *full_path, *x;
|
||||
SHELL_VAR *func;
|
||||
#if defined (ALIAS)
|
||||
alias_t *alias;
|
||||
#endif
|
||||
|
||||
all = (dflags & CDESC_ALL) != 0;
|
||||
found = found_file = 0;
|
||||
full_path = (char *)NULL;
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Command is an alias? */
|
||||
if (((dflags & CDESC_FORCE_PATH) == 0) && expand_aliases && (alias = find_alias (command)))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("alias");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is aliased to `%s'\n"), command, alias->value);
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
{
|
||||
x = sh_single_quote (alias->value);
|
||||
printf ("alias %s=%s\n", command, x);
|
||||
free (x);
|
||||
}
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
/* Command is a shell reserved word? */
|
||||
if (((dflags & CDESC_FORCE_PATH) == 0) && (i = find_reserved_word (command)) >= 0)
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("keyword");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is a shell keyword\n"), command);
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a function? */
|
||||
if (((dflags & (CDESC_FORCE_PATH|CDESC_NOFUNCS)) == 0) && (func = find_function (command)))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("function");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
{
|
||||
#define PRETTY_PRINT_FUNC 1
|
||||
char *result;
|
||||
|
||||
printf (_("%s is a function\n"), command);
|
||||
|
||||
/* We're blowing away THE_PRINTED_COMMAND here... */
|
||||
|
||||
result = named_function_string (command,
|
||||
(COMMAND *) function_cell (func),
|
||||
PRETTY_PRINT_FUNC);
|
||||
printf ("%s\n", result);
|
||||
#undef PRETTY_PRINT_FUNC
|
||||
}
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a builtin? */
|
||||
if (((dflags & CDESC_FORCE_PATH) == 0) && find_shell_builtin (command))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("builtin");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is a shell builtin\n"), command);
|
||||
else if (dflags & CDESC_REUSABLE)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (all == 0)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a disk file? */
|
||||
/* If the command name given is already an absolute command, just
|
||||
check to see if it is executable. */
|
||||
if (absolute_program (command))
|
||||
{
|
||||
f = file_status (command);
|
||||
if (f & FS_EXECABLE)
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("file");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is %s\n"), command, command);
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
|
||||
printf ("%s\n", command);
|
||||
|
||||
/* There's no use looking in the hash table or in $PATH,
|
||||
because they're not consulted when an absolute program
|
||||
name is supplied. */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the user isn't doing "-a", then we might care about
|
||||
whether the file is present in our hash table. */
|
||||
if (all == 0 || (dflags & CDESC_FORCE_PATH))
|
||||
{
|
||||
if (full_path = phash_search (command))
|
||||
{
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("file");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf (_("%s is hashed (%s)\n"), command, full_path);
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
|
||||
printf ("%s\n", full_path);
|
||||
|
||||
free (full_path);
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now search through $PATH. */
|
||||
while (1)
|
||||
{
|
||||
if (all == 0)
|
||||
full_path = find_user_command (command);
|
||||
else
|
||||
full_path =
|
||||
user_command_matches (command, FS_EXEC_ONLY, found_file);
|
||||
/* XXX - should that be FS_EXEC_PREFERRED? */
|
||||
|
||||
if (!full_path)
|
||||
break;
|
||||
|
||||
/* If we found the command as itself by looking through $PATH, it
|
||||
probably doesn't exist. Check whether or not the command is an
|
||||
executable file. If it's not, don't report a match. This is
|
||||
the default posix mode behavior */
|
||||
if (STREQ (full_path, command) || posixly_correct)
|
||||
{
|
||||
f = file_status (full_path);
|
||||
if ((f & FS_EXECABLE) == 0)
|
||||
{
|
||||
free (full_path);
|
||||
full_path = (char *)NULL;
|
||||
if (all == 0)
|
||||
break;
|
||||
}
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY|CDESC_SHORTDESC))
|
||||
{
|
||||
f = MP_DOCWD | (dflags & CDESC_ABSPATH) ? MP_RMDOT : 0;
|
||||
full_path = sh_makepath ((char *)NULL, full_path, f);
|
||||
}
|
||||
}
|
||||
/* If we require a full path and don't have one, make one */
|
||||
else if ((dflags & CDESC_ABSPATH) && ABSPATH (full_path) == 0)
|
||||
full_path = sh_makepath ((char *)NULL, full_path, MP_DOCWD|MP_RMDOT);
|
||||
|
||||
found_file++;
|
||||
found = 1;
|
||||
|
||||
if (dflags & CDESC_TYPE)
|
||||
puts ("file");
|
||||
else if (dflags & CDESC_SHORTDESC)
|
||||
printf ("%s is %s\n", command, full_path);
|
||||
else if (dflags & (CDESC_REUSABLE|CDESC_PATH_ONLY))
|
||||
printf ("%s\n", full_path);
|
||||
|
||||
free (full_path);
|
||||
full_path = (char *)NULL;
|
||||
|
||||
if (all == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
return (found);
|
||||
}
|
||||
@@ -1,737 +0,0 @@
|
||||
This file is ulimit.def, from which is created ulimit.c.
|
||||
It implements the builtin "ulimit" in Bash.
|
||||
|
||||
Copyright (C) 1987-2003 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$PRODUCES ulimit.c
|
||||
|
||||
$BUILTIN ulimit
|
||||
$FUNCTION ulimit_builtin
|
||||
$DEPENDS_ON !_MINIX
|
||||
$SHORT_DOC ulimit [-SHacdflmnpstuv] [limit]
|
||||
Ulimit provides control over the resources available to processes
|
||||
started by the shell, on systems that allow such control. If an
|
||||
option is given, it is interpreted as follows:
|
||||
|
||||
-S use the `soft' resource limit
|
||||
-H use the `hard' resource limit
|
||||
-a all current limits are reported
|
||||
-c the maximum size of core files created
|
||||
-d the maximum size of a process's data segment
|
||||
-f the maximum size of files created by the shell
|
||||
-i the maximum number of pending signals
|
||||
-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
|
||||
-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
|
||||
|
||||
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.
|
||||
$END
|
||||
|
||||
#if !defined (_MINIX)
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#ifndef _MINIX
|
||||
# include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../bashintl.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
#include "pipesize.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
/* For some reason, HPUX chose to make these definitions visible only if
|
||||
_KERNEL is defined, so we define _KERNEL before including <sys/resource.h>
|
||||
and #undef it afterward. */
|
||||
#if defined (HAVE_RESOURCE)
|
||||
# include <sys/time.h>
|
||||
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
||||
# define _KERNEL
|
||||
# endif
|
||||
# include <sys/resource.h>
|
||||
# if defined (HPUX) && defined (RLIMIT_NEEDS_KERNEL)
|
||||
# undef _KERNEL
|
||||
# endif
|
||||
#else
|
||||
# include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
/* Check for the most basic symbols. If they aren't present, this
|
||||
system's <sys/resource.h> isn't very useful to us. */
|
||||
#if !defined (RLIMIT_FSIZE) || !defined (HAVE_GETRLIMIT)
|
||||
# undef HAVE_RESOURCE
|
||||
#endif
|
||||
|
||||
#if !defined (RLIMTYPE)
|
||||
# define RLIMTYPE long
|
||||
# define string_to_rlimtype(s) strtol(s, (char **)NULL, 10)
|
||||
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
|
||||
#endif
|
||||
|
||||
/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
|
||||
# define RLIMIT_NOFILE RLIMIT_OFILE
|
||||
#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
|
||||
|
||||
/* Some systems have these, some do not. */
|
||||
#ifdef RLIMIT_FSIZE
|
||||
# define RLIMIT_FILESIZE RLIMIT_FSIZE
|
||||
#else
|
||||
# define RLIMIT_FILESIZE 256
|
||||
#endif
|
||||
|
||||
#define RLIMIT_PIPESIZE 257
|
||||
|
||||
#ifdef RLIMIT_NOFILE
|
||||
# define RLIMIT_OPENFILES RLIMIT_NOFILE
|
||||
#else
|
||||
# define RLIMIT_OPENFILES 258
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_VMEM
|
||||
# define RLIMIT_VIRTMEM RLIMIT_VMEM
|
||||
# define RLIMIT_VMBLKSZ 1024
|
||||
#else
|
||||
# ifdef RLIMIT_AS
|
||||
# define RLIMIT_VIRTMEM RLIMIT_AS
|
||||
# define RLIMIT_VMBLKSZ 1024
|
||||
# else
|
||||
# define RLIMIT_VIRTMEM 259
|
||||
# define RLIMIT_VMBLKSZ 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef RLIMIT_NPROC
|
||||
# define RLIMIT_MAXUPROC RLIMIT_NPROC
|
||||
#else
|
||||
# define RLIMIT_MAXUPROC 260
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_INFINITY)
|
||||
# define RLIM_INFINITY 0x7fffffff
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_SAVED_CUR)
|
||||
# define RLIM_SAVED_CUR RLIM_INFINITY
|
||||
#endif
|
||||
|
||||
#if !defined (RLIM_SAVED_MAX)
|
||||
# define RLIM_SAVED_MAX RLIM_INFINITY
|
||||
#endif
|
||||
|
||||
#define LIMIT_HARD 0x01
|
||||
#define LIMIT_SOFT 0x02
|
||||
|
||||
static int _findlim __P((int));
|
||||
|
||||
static int ulimit_internal __P((int, char *, int, int));
|
||||
|
||||
static int get_limit __P((int, RLIMTYPE *, RLIMTYPE *));
|
||||
static int set_limit __P((int, RLIMTYPE, int));
|
||||
|
||||
static void printone __P((int, RLIMTYPE, int));
|
||||
static void print_all_limits __P((int));
|
||||
|
||||
static int set_all_limits __P((int, RLIMTYPE));
|
||||
|
||||
static int filesize __P((RLIMTYPE *));
|
||||
static int pipesize __P((RLIMTYPE *));
|
||||
static int getmaxuprc __P((RLIMTYPE *));
|
||||
static int getmaxvm __P((RLIMTYPE *, RLIMTYPE *));
|
||||
|
||||
typedef struct {
|
||||
int option; /* The ulimit option for this limit. */
|
||||
int parameter; /* Parameter to pass to get_limit (). */
|
||||
int block_factor; /* Blocking factor for specific limit. */
|
||||
char *description; /* Descriptive string to output. */
|
||||
char *units; /* scale */
|
||||
} RESOURCE_LIMITS;
|
||||
|
||||
static RESOURCE_LIMITS limits[] = {
|
||||
#ifdef RLIMIT_CORE
|
||||
{ 'c', RLIMIT_CORE, 1024, "core file size", "blocks" },
|
||||
#endif
|
||||
#ifdef RLIMIT_DATA
|
||||
{ 'd', RLIMIT_DATA, 1024, "data seg size", "kbytes" },
|
||||
#endif
|
||||
{ 'f', RLIMIT_FILESIZE, 1024, "file size", "blocks" },
|
||||
#ifdef RLIMIT_SIGPENDING
|
||||
{ 'i', RLIMIT_SIGPENDING, 1, "pending signals", (char *)NULL },
|
||||
#endif
|
||||
#ifdef RLIMIT_MEMLOCK
|
||||
{ 'l', RLIMIT_MEMLOCK, 1024, "max locked memory", "kbytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_RSS
|
||||
{ 'm', RLIMIT_RSS, 1024, "max memory size", "kbytes" },
|
||||
#endif /* RLIMIT_RSS */
|
||||
{ 'n', RLIMIT_OPENFILES, 1, "open files", (char *)NULL},
|
||||
{ 'p', RLIMIT_PIPESIZE, 512, "pipe size", "512 bytes" },
|
||||
#ifdef RLIMIT_MSGQUEUE
|
||||
{ 'q', RLIMIT_MSGQUEUE, 1, "POSIX message queues", "bytes" },
|
||||
#endif
|
||||
#ifdef RLIMIT_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
|
||||
{ 'w', RLIMIT_LOCKS, 1, "file locks", (char *)NULL },
|
||||
#endif
|
||||
{ -1, -1, -1, (char *)NULL, (char *)NULL }
|
||||
};
|
||||
#define NCMDS (sizeof(limits) / sizeof(limits[0]))
|
||||
|
||||
typedef struct _cmd {
|
||||
int cmd;
|
||||
char *arg;
|
||||
} ULCMD;
|
||||
|
||||
static ULCMD *cmdlist;
|
||||
static int ncmd;
|
||||
static int cmdlistsz;
|
||||
|
||||
#if !defined (HAVE_RESOURCE) && !defined (HAVE_ULIMIT)
|
||||
long
|
||||
ulimit (cmd, newlim)
|
||||
int cmd;
|
||||
long newlim;
|
||||
{
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
#endif /* !HAVE_RESOURCE && !HAVE_ULIMIT */
|
||||
|
||||
static int
|
||||
_findlim (opt)
|
||||
int opt;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; limits[i].option > 0; i++)
|
||||
if (limits[i].option == opt)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char optstring[4 + 2 * NCMDS];
|
||||
|
||||
/* Report or set limits associated with certain per-process resources.
|
||||
See the help documentation in builtins.c for a full description. */
|
||||
int
|
||||
ulimit_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
register char *s;
|
||||
int c, limind, mode, opt, all_limits;
|
||||
|
||||
mode = 0;
|
||||
|
||||
all_limits = 0;
|
||||
|
||||
/* Idea stolen from pdksh -- build option string the first time called. */
|
||||
if (optstring[0] == 0)
|
||||
{
|
||||
s = optstring;
|
||||
*s++ = 'a'; *s++ = 'S'; *s++ = 'H';
|
||||
for (c = 0; limits[c].option > 0; c++)
|
||||
{
|
||||
*s++ = limits[c].option;
|
||||
*s++ = ';';
|
||||
}
|
||||
*s = '\0';
|
||||
}
|
||||
|
||||
/* Initialize the command list. */
|
||||
if (cmdlistsz == 0)
|
||||
cmdlist = (ULCMD *)xmalloc ((cmdlistsz = 16) * sizeof (ULCMD));
|
||||
ncmd = 0;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, optstring)) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'a':
|
||||
all_limits++;
|
||||
break;
|
||||
|
||||
/* -S and -H are modifiers, not real options. */
|
||||
case 'S':
|
||||
mode |= LIMIT_SOFT;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
mode |= LIMIT_HARD;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
builtin_usage ();
|
||||
return (EX_USAGE);
|
||||
|
||||
default:
|
||||
if (ncmd >= cmdlistsz)
|
||||
cmdlist = (ULCMD *)xrealloc (cmdlist, (cmdlistsz *= 2) * sizeof (ULCMD));
|
||||
cmdlist[ncmd].cmd = opt;
|
||||
cmdlist[ncmd++].arg = list_optarg;
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (all_limits)
|
||||
{
|
||||
#ifdef NOTYET
|
||||
if (list) /* setting */
|
||||
{
|
||||
if (STREQ (list->word->word, "unlimited") == 0)
|
||||
{
|
||||
builtin_error (_("%s: invalid limit argument"), list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
return (set_all_limits (mode == 0 ? LIMIT_SOFT|LIMIT_HARD : mode, RLIM_INFINITY));
|
||||
}
|
||||
#endif
|
||||
print_all_limits (mode == 0 ? LIMIT_SOFT : mode);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* default is `ulimit -f' */
|
||||
if (ncmd == 0)
|
||||
{
|
||||
cmdlist[ncmd].cmd = 'f';
|
||||
/* `ulimit something' is same as `ulimit -f something' */
|
||||
cmdlist[ncmd++].arg = list ? list->word->word : (char *)NULL;
|
||||
if (list)
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* verify each command in the list. */
|
||||
for (c = 0; c < ncmd; c++)
|
||||
{
|
||||
limind = _findlim (cmdlist[c].cmd);
|
||||
if (limind == -1)
|
||||
{
|
||||
builtin_error (_("`%c': bad command"), cmdlist[c].cmd);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
for (c = 0; c < ncmd; c++)
|
||||
if (ulimit_internal (cmdlist[c].cmd, cmdlist[c].arg, mode, ncmd > 1) == EXECUTION_FAILURE)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
ulimit_internal (cmd, cmdarg, mode, multiple)
|
||||
int cmd;
|
||||
char *cmdarg;
|
||||
int mode, multiple;
|
||||
{
|
||||
int opt, limind, setting;
|
||||
int block_factor;
|
||||
RLIMTYPE soft_limit, hard_limit, real_limit, limit;
|
||||
|
||||
setting = cmdarg != 0;
|
||||
limind = _findlim (cmd);
|
||||
if (mode == 0)
|
||||
mode = setting ? (LIMIT_HARD|LIMIT_SOFT) : LIMIT_SOFT;
|
||||
opt = get_limit (limind, &soft_limit, &hard_limit);
|
||||
if (opt < 0)
|
||||
{
|
||||
builtin_error (_("%s: cannot get limit: %s"), limits[limind].description,
|
||||
strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (setting == 0) /* print the value of the specified limit */
|
||||
{
|
||||
printone (limind, (mode & LIMIT_SOFT) ? soft_limit : hard_limit, multiple);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Setting the limit. */
|
||||
if (STREQ (cmdarg, "hard"))
|
||||
real_limit = hard_limit;
|
||||
else if (STREQ (cmdarg, "soft"))
|
||||
real_limit = soft_limit;
|
||||
else if (STREQ (cmdarg, "unlimited"))
|
||||
real_limit = RLIM_INFINITY;
|
||||
else if (all_digits (cmdarg))
|
||||
{
|
||||
limit = string_to_rlimtype (cmdarg);
|
||||
block_factor = 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 (PIPESIZE)
|
||||
/* This is defined by running a program from the Makefile. */
|
||||
*valuep = (RLIMTYPE) PIPESIZE;
|
||||
return 0;
|
||||
# else
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
# endif /* PIPESIZE */
|
||||
#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];
|
||||
|
||||
if (pdesc)
|
||||
{
|
||||
if (limits[limind].units)
|
||||
sprintf (unitstr, "(%s, -%c) ", limits[limind].units, limits[limind].option);
|
||||
else
|
||||
sprintf (unitstr, "(-%c) ", limits[limind].option);
|
||||
|
||||
printf ("%-20s %16s", limits[limind].description, unitstr);
|
||||
}
|
||||
if (curlim == RLIM_INFINITY)
|
||||
puts ("unlimited");
|
||||
else if (curlim == RLIM_SAVED_MAX)
|
||||
puts ("hard");
|
||||
else if (curlim == RLIM_SAVED_CUR)
|
||||
puts ("soft");
|
||||
else
|
||||
print_rlimtype ((curlim / limits[limind].block_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 */
|
||||
@@ -1,177 +0,0 @@
|
||||
This file is wait.def, from which is created wait.c.
|
||||
It implements the builtin "wait" in Bash.
|
||||
|
||||
Copyright (C) 1987-2004 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA.
|
||||
|
||||
$BUILTIN wait
|
||||
$FUNCTION wait_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$PRODUCES wait.c
|
||||
$SHORT_DOC wait [n]
|
||||
Wait for the specified process and report its termination status. If
|
||||
N is not given, all currently active child processes are waited for,
|
||||
and the return code is zero. N may be a process ID or a job
|
||||
specification; if a job spec is given, all processes in the job's
|
||||
pipeline are waited for.
|
||||
$END
|
||||
|
||||
$BUILTIN wait
|
||||
$FUNCTION wait_builtin
|
||||
$DEPENDS_ON !JOB_CONTROL
|
||||
$SHORT_DOC wait [n]
|
||||
Wait for the specified process and report its termination status. If
|
||||
N is not given, all currently active child processes are waited for,
|
||||
and the return code is zero. N is a process ID; if it is not given,
|
||||
all child processes of the shell are waited for.
|
||||
$END
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include <signal.h>
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <chartypes.h>
|
||||
|
||||
#include "../bashansi.h"
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int interrupt_immediately;
|
||||
extern int wait_signal_received;
|
||||
|
||||
procenv_t wait_intr_buf;
|
||||
|
||||
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
|
||||
wait for all of the active background processes of the shell and return
|
||||
0. If a list of pids or job specs are given, return the exit status of
|
||||
the last one waited for. */
|
||||
|
||||
#define WAIT_RETURN(s) \
|
||||
do \
|
||||
{ \
|
||||
interrupt_immediately = old_interrupt_immediately;\
|
||||
return (s);\
|
||||
} \
|
||||
while (0)
|
||||
|
||||
int
|
||||
wait_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int status, code;
|
||||
volatile int old_interrupt_immediately;
|
||||
|
||||
USE_VAR(list);
|
||||
|
||||
if (no_options (list))
|
||||
return (EX_USAGE);
|
||||
list = loptend;
|
||||
|
||||
old_interrupt_immediately = interrupt_immediately;
|
||||
interrupt_immediately++;
|
||||
|
||||
/* POSIX.2 says: When the shell is waiting (by means of the wait utility)
|
||||
for asynchronous commands to complete, the reception of a signal for
|
||||
which a trap has been set shall cause the wait utility to return
|
||||
immediately with an exit status greater than 128, after which the trap
|
||||
associated with the signal shall be taken.
|
||||
|
||||
We handle SIGINT here; it's the only one that needs to be treated
|
||||
specially (I think), since it's handled specially in {no,}jobs.c. */
|
||||
code = setjmp (wait_intr_buf);
|
||||
if (code)
|
||||
{
|
||||
status = 128 + wait_signal_received;
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
|
||||
/* We support jobs or pids.
|
||||
wait <pid-or-job> [pid-or-job ...] */
|
||||
|
||||
/* But wait without any arguments means to wait for all of the shell's
|
||||
currently active background processes. */
|
||||
if (list == 0)
|
||||
{
|
||||
wait_for_background_pids ();
|
||||
WAIT_RETURN (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
status = EXECUTION_SUCCESS;
|
||||
while (list)
|
||||
{
|
||||
pid_t pid;
|
||||
char *w;
|
||||
intmax_t pid_value;
|
||||
|
||||
w = list->word->word;
|
||||
if (DIGIT (*w))
|
||||
{
|
||||
if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
|
||||
{
|
||||
pid = (pid_t)pid_value;
|
||||
status = wait_for_single_pid (pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
sh_badpid (w);
|
||||
WAIT_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#if defined (JOB_CONTROL)
|
||||
else if (*w && *w == '%')
|
||||
/* Must be a job spec. Check it out. */
|
||||
{
|
||||
int job;
|
||||
sigset_t set, oset;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (INVALID_JOB (job))
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
sh_badjob (list->word->word);
|
||||
UNBLOCK_CHILD (oset);
|
||||
status = 127; /* As per Posix.2, section 4.70.2 */
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Job spec used. Wait for the last pid in the pipeline. */
|
||||
UNBLOCK_CHILD (oset);
|
||||
status = wait_for_job (job);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
else
|
||||
{
|
||||
sh_badpid (w);
|
||||
status = EXECUTION_FAILURE;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
WAIT_RETURN (status);
|
||||
}
|
||||
Reference in New Issue
Block a user