Imported from ../bash-1.14.7.tar.gz.
This commit is contained in:
commit
726f63884d
402 changed files with 150297 additions and 0 deletions
0
builtins/ChangeLog
Normal file
0
builtins/ChangeLog
Normal file
267
builtins/Makefile
Normal file
267
builtins/Makefile
Normal file
|
@ -0,0 +1,267 @@
|
|||
# This Makefile for building libbuiltins.a is in -*- text -*- for Emacs.
|
||||
#
|
||||
MKBUILTINS = mkbuiltins
|
||||
RANLIB = /usr/bin/ranlib
|
||||
CFLAGS = -g -I.. -I.
|
||||
SHELL = /bin/sh
|
||||
# CC = cc
|
||||
AR = ar
|
||||
RM = rm -f
|
||||
CP = cp
|
||||
|
||||
srcdir = .
|
||||
VPATH = .:$(srcdir)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .def .c .o
|
||||
# How to make a .o file from a .def file.
|
||||
.def.o:
|
||||
$(RM) $@
|
||||
./$(MKBUILTINS) $(DIRECTDEFINE) $<
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) $*.c || ( $(RM) $*.c ; exit 1 )
|
||||
$(RM) $*.c
|
||||
|
||||
# How to make a .c file from a .def file.
|
||||
.def.c:
|
||||
$(RM) $@
|
||||
./$(MKBUILTINS) $(DIRECTDEFINE) $<
|
||||
|
||||
# Here is a rule for making .o files from .c files that does not
|
||||
# force the type of the machine (like -M_MACHINE) into the flags.
|
||||
.c.o:
|
||||
$(RM) $@
|
||||
$(CC) -c $(CFLAGS) $(CPPFLAGS) $<
|
||||
|
||||
DEFS = $(srcdir)/alias.def $(srcdir)/bind.def $(srcdir)/break.def \
|
||||
$(srcdir)/builtin.def $(srcdir)/cd.def $(srcdir)/colon.def \
|
||||
$(srcdir)/command.def $(srcdir)/declare.def $(srcdir)/echo.def \
|
||||
$(srcdir)/enable.def $(srcdir)/eval.def $(srcdir)/getopts.def \
|
||||
$(srcdir)/exec.def $(srcdir)/exit.def $(srcdir)/fc.def \
|
||||
$(srcdir)/fg_bg.def $(srcdir)/hash.def $(srcdir)/help.def \
|
||||
$(srcdir)/history.def $(srcdir)/jobs.def $(srcdir)/kill.def \
|
||||
$(srcdir)/let.def $(srcdir)/read.def $(srcdir)/return.def \
|
||||
$(srcdir)/set.def $(srcdir)/setattr.def $(srcdir)/shift.def \
|
||||
$(srcdir)/source.def $(srcdir)/suspend.def $(srcdir)/test.def \
|
||||
$(srcdir)/times.def $(srcdir)/trap.def $(srcdir)/type.def \
|
||||
$(srcdir)/ulimit.def $(srcdir)/umask.def $(srcdir)/wait.def \
|
||||
$(srcdir)/reserved.def
|
||||
|
||||
STATIC_SOURCE = common.c getopt.c bashgetopt.c getopt.h
|
||||
|
||||
OFILES = builtins.o \
|
||||
alias.o bind.o break.o builtin.o cd.o colon.o command.o \
|
||||
common.o declare.o echo.o enable.o eval.o exec.o exit.o \
|
||||
fc.o fg_bg.o hash.o help.o history.o jobs.o kill.o \
|
||||
let.o read.o return.o set.o setattr.o shift.o source.o \
|
||||
suspend.o test.o times.o trap.o type.o ulimit.o umask.o \
|
||||
wait.o getopts.o getopt.o bashgetopt.o
|
||||
|
||||
THINGS_TO_TAR = $(DEFS) $(STATIC_SOURCE) Makefile ChangeLog
|
||||
|
||||
CREATED_FILES = builtext.h builtins.c psize.aux pipesize.h
|
||||
|
||||
all: $(MKBUILTINS) libbuiltins.a
|
||||
|
||||
libbuiltins.a: $(MKBUILTINS) $(OFILES)
|
||||
$(RM) $@
|
||||
$(AR) cq $@ $(OFILES)
|
||||
-$(RANLIB) $@
|
||||
|
||||
builtext.h builtins.c: $(MKBUILTINS) $(DEFS)
|
||||
$(RM) builtext.h builtins.c
|
||||
./$(MKBUILTINS) -externfile builtext.h -structfile builtins.c \
|
||||
-noproduction $(DIRECTDEFINE) $(DEFS)
|
||||
|
||||
mkbuiltins: $(srcdir)/mkbuiltins.c ../config.h
|
||||
$(CC) $(CFLAGS) -o $(MKBUILTINS) $(srcdir)/mkbuiltins.c
|
||||
|
||||
ulimit.o: ulimit.def pipesize.h
|
||||
|
||||
pipesize.h: psize.aux
|
||||
$(SHELL) $(srcdir)/psize.sh > pipesize.h
|
||||
|
||||
psize.aux: psize.c
|
||||
$(CC) $(CFLAGS) -o $@ $(srcdir)/psize.c
|
||||
|
||||
documentation: builtins.texi
|
||||
|
||||
$(OFILES): $(MKBUILTINS) ../config.h
|
||||
|
||||
builtins.texi: $(MKBUILTINS)
|
||||
./$(MKBUILTINS) -documentonly $(DEFS)
|
||||
|
||||
clean:
|
||||
$(RM) $(OFILES) $(CREATED_FILES) $(MKBUILTINS)
|
||||
|
||||
mostlyclean:
|
||||
$(RM) $(OFILES) libbuiltins.a
|
||||
|
||||
distclean realclean maintainer-clean: clean
|
||||
$(RM) libbuiltins.a
|
||||
|
||||
alias.o: alias.def
|
||||
bind.o: bind.def
|
||||
break.o: break.def
|
||||
builtin.o: builtin.def
|
||||
cd.o: cd.def
|
||||
colon.o: colon.def
|
||||
command.o: command.def
|
||||
declare.o: declare.def
|
||||
echo.o: echo.def
|
||||
enable.o: enable.def
|
||||
eval.o: eval.def
|
||||
exec.o: exec.def
|
||||
exit.o: exit.def
|
||||
fc.o: fc.def
|
||||
fg_bg.o: fg_bg.def
|
||||
hash.o: hash.def
|
||||
help.o: help.def
|
||||
history.o: history.def
|
||||
jobs.o: jobs.def
|
||||
kill.o: kill.def
|
||||
let.o: let.def
|
||||
read.o: read.def
|
||||
return.o: return.def
|
||||
set.o: set.def
|
||||
setattr.o: setattr.def
|
||||
shift.o: shift.def
|
||||
source.o: source.def
|
||||
suspend.o: suspend.def
|
||||
test.o: test.def
|
||||
times.o: times.def
|
||||
trap.o: trap.def
|
||||
type.o: type.def
|
||||
umask.o: umask.def
|
||||
wait.o: wait.def
|
||||
getopts.o: getopts.def
|
||||
reserved.o: reserved.def
|
||||
|
||||
common.o: ../shell.h ../command.h ../config.h ../memalloc.h ../general.h
|
||||
common.o: ../variables.h ../input.h hashcom.h ../bashhist.h
|
||||
common.o: ../quit.h ../unwind_prot.h ../maxpath.h ../jobs.h ../builtins.h
|
||||
common.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
common.o: ../execute_cmd.h ../error.h
|
||||
alias.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
alias.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
alias.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h
|
||||
bind.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
bind.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
bind.o: ../maxpath.h
|
||||
bind.o: ../shell.h ../unwind_prot.h ../variables.h bashgetopt.h
|
||||
break.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
break.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
break.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
builtin.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
builtin.o: ../quit.h common.h ../maxpath.h
|
||||
builtin.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
builtin.o: ../shell.h ../unwind_prot.h ../variables.h
|
||||
cd.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
cd.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
cd.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h
|
||||
command.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
command.o: ../quit.h bashgetopt.h ../maxpath.h
|
||||
command.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
command.o: ../shell.h ../unwind_prot.h ../variables.h
|
||||
declare.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
declare.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
declare.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
echo.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
echo.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
echo.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
enable.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
enable.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
enable.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
eval.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
eval.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
eval.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
exec.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
exec.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
exec.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../execute_cmd.h
|
||||
exec.o: ../maxpath.h ../flags.h
|
||||
exit.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
exit.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
exit.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
fc.o: ../builtins.h ../command.h bashgetopt.h ../bashhist.h
|
||||
fc.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
fc.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
fc.o: ../flags.h ../unwind_prot.h ../variables.h ../shell.h ../maxpath.h
|
||||
fg_bg.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
fg_bg.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
fg_bg.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
getopts.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
getopts.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
getopts.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
hash.o: ../builtins.h ../command.h ../quit.h ../execute_cmd.h
|
||||
hash.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
hash.o: ../shell.h ../unwind_prot.h ../variables.h common.h ../maxpath.h
|
||||
help.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
help.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
help.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
history.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
history.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
history.o: ../filecntl.h ../shell.h ../unwind_prot.h ../variables.h
|
||||
history.o: ../bashhist.h ../maxpath.h
|
||||
inlib.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
inlib.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
inlib.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
jobs.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
jobs.o: ../quit.h bashgetopt.h ../maxpath.h
|
||||
jobs.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
jobs.o: ../shell.h ../unwind_prot.h ../variables.h
|
||||
kill.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
kill.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
kill.o: ../shell.h ../trap.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
let.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
let.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
let.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
read.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
read.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
read.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
return.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
return.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
return.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
set.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
set.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
set.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
setattr.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
setattr.o: ../quit.h common.h bashgetopt.h ../maxpath.h
|
||||
setattr.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
setattr.o: ../shell.h ../unwind_prot.h ../variables.h
|
||||
shift.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
shift.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
shift.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
source.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
source.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
source.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
suspend.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
suspend.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
suspend.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
test.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
test.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
test.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
times.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
times.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
times.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
trap.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
trap.o: ../quit.h common.h ../maxpath.h
|
||||
trap.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
trap.o: ../shell.h ../unwind_prot.h ../variables.h ../execute_cmd.h
|
||||
type.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
type.o: ../quit.h common.h ../maxpath.h
|
||||
type.o: ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
type.o: ../shell.h ../unwind_prot.h ../variables.h
|
||||
ulimit.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
ulimit.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
ulimit.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
umask.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
umask.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
umask.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
wait.o: ../command.h ../config.h ../memalloc.h ../error.h ../general.h
|
||||
wait.o: ../quit.h ../dispose_cmd.h ../make_cmd.h ../subst.h ../externs.h
|
||||
wait.o: ../shell.h ../unwind_prot.h ../variables.h ../maxpath.h
|
||||
|
||||
bashgetopt.o: ../bashansi.h ../ansi_stdlib.h
|
||||
mkbuiltins.o: ../bashansi.h ../ansi_stdlib.h
|
||||
fc.o: ../bashansi.h ../ansi_stdlib.h
|
||||
|
||||
#bind.o: $(RL_LIBSRC)chardefs.h $(RL_LIBSRC)readline.h $(RL_LIBSRC)keymaps.h
|
180
builtins/alias.def
Normal file
180
builtins/alias.def
Normal file
|
@ -0,0 +1,180 @@
|
|||
This file is alias.def, from which is created alias.c
|
||||
It implements the builtins "alias" and "unalias" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$BUILTIN alias
|
||||
$FUNCTION alias_builtin
|
||||
$DEPENDS_ON ALIAS
|
||||
$PRODUCES alias.c
|
||||
$SHORT_DOC alias [ name[=value] ... ]
|
||||
`alias' with no arguments prints the list of aliases in the form
|
||||
NAME=VALUE on standard output. An alias is defined for each NAME
|
||||
whose VALUE is given. A trailing space in VALUE causes the next
|
||||
word to be checked for alias substitution. Alias returns true
|
||||
unless a NAME is given for which no alias has been defined.
|
||||
$END
|
||||
|
||||
#include "../config.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
# include <stdio.h>
|
||||
# include "../shell.h"
|
||||
# include "../alias.h"
|
||||
# include "common.h"
|
||||
|
||||
extern int interactive;
|
||||
static void print_alias ();
|
||||
|
||||
/* Hack the alias command in a Korn shell way. */
|
||||
alias_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int any_failed = 0;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
register int i;
|
||||
ASSOC **alias_list;
|
||||
|
||||
if (!aliases)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
alias_list = all_aliases ();
|
||||
|
||||
if (!alias_list)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
for (i = 0; alias_list[i]; i++)
|
||||
print_alias (alias_list[i]);
|
||||
|
||||
free (alias_list); /* XXX - Do not free the strings. */
|
||||
}
|
||||
else
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
register char *value, *name = list->word->word;
|
||||
register int offset;
|
||||
|
||||
for (offset = 0; name[offset] && name[offset] != '='; offset++)
|
||||
;
|
||||
|
||||
if (offset && name[offset] == '=')
|
||||
{
|
||||
name[offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
|
||||
add_alias (name, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSOC *t = find_alias (name);
|
||||
if (t)
|
||||
print_alias (t);
|
||||
else
|
||||
{
|
||||
if (interactive)
|
||||
builtin_error ("`%s' not found", name);
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
if (any_failed)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
$BUILTIN unalias
|
||||
$FUNCTION unalias_builtin
|
||||
$DEPENDS_ON ALIAS
|
||||
$SHORT_DOC unalias [-a] [name ...]
|
||||
Remove NAMEs from the list of defined aliases. If the -a option is given,
|
||||
then remove all alias definitions.
|
||||
$END
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Remove aliases named in LIST from the aliases database. */
|
||||
unalias_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
register ASSOC *alias;
|
||||
int any_failed = 0;
|
||||
|
||||
while (list && *list->word->word == '-')
|
||||
{
|
||||
register char *word = list->word->word;
|
||||
|
||||
if (ISOPTION (word, 'a'))
|
||||
{
|
||||
delete_all_aliases ();
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_option (word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
alias = find_alias (list->word->word);
|
||||
|
||||
if (alias)
|
||||
remove_alias (alias->name);
|
||||
else
|
||||
{
|
||||
if (interactive)
|
||||
builtin_error ("`%s' not an alias", list->word->word);
|
||||
|
||||
any_failed++;
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (any_failed)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Output ALIAS in such a way as to allow it to be read back in. */
|
||||
static void
|
||||
print_alias (alias)
|
||||
ASSOC *alias;
|
||||
{
|
||||
char *value = single_quote (alias->value);
|
||||
|
||||
printf ("alias %s=%s\n", alias->name, value);
|
||||
free (value);
|
||||
|
||||
fflush (stdout);
|
||||
}
|
||||
#endif /* ALIAS */
|
136
builtins/bashgetopt.c
Normal file
136
builtins/bashgetopt.c
Normal file
|
@ -0,0 +1,136 @@
|
|||
/* bashgetopt.c -- `getopt' for use by the builtins. */
|
||||
|
||||
/* Copyright (C) 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <errno.h>
|
||||
#include "shell.h"
|
||||
|
||||
#include "bashansi.h"
|
||||
|
||||
#define ERR(S, C) builtin_error("%s%c", (S), (C))
|
||||
|
||||
static int sp;
|
||||
|
||||
char *list_optarg;
|
||||
int list_optopt;
|
||||
|
||||
static WORD_LIST *lhead = (WORD_LIST *)NULL;
|
||||
WORD_LIST *lcurrent = (WORD_LIST *)NULL;
|
||||
WORD_LIST *loptend; /* Points to the first non-option argument in the list */
|
||||
|
||||
int
|
||||
internal_getopt(list, opts)
|
||||
WORD_LIST *list;
|
||||
char *opts;
|
||||
{
|
||||
register int c;
|
||||
register char *cp;
|
||||
|
||||
if (!list) {
|
||||
list_optarg = (char *)NULL;
|
||||
loptend = (WORD_LIST *)NULL; /* No non-option arguments */
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (list != lhead || !lhead) {
|
||||
/* Hmmm.... called with a different word list. Reset. */
|
||||
sp = 1;
|
||||
lcurrent = lhead = list;
|
||||
loptend = (WORD_LIST *)NULL;
|
||||
}
|
||||
|
||||
if (sp == 1) {
|
||||
if (!lcurrent ||
|
||||
(lcurrent->word->word[0] != '-' || lcurrent->word->word[1] == '\0')) {
|
||||
lhead = (WORD_LIST *)NULL;
|
||||
loptend = lcurrent;
|
||||
return(-1);
|
||||
} else if (lcurrent->word->word[0] == '-' &&
|
||||
lcurrent->word->word[1] == '-' &&
|
||||
lcurrent->word->word[2] == 0) {
|
||||
lhead = (WORD_LIST *)NULL;
|
||||
loptend = lcurrent->next;
|
||||
return(-1);
|
||||
}
|
||||
}
|
||||
|
||||
list_optopt = c = lcurrent->word->word[sp];
|
||||
|
||||
if (c == ':' || (cp = strchr(opts, c)) == NULL) {
|
||||
ERR("illegal option: -", c);
|
||||
if (lcurrent->word->word[++sp] == '\0') {
|
||||
lcurrent = lcurrent->next;
|
||||
sp = 1;
|
||||
}
|
||||
list_optarg = NULL;
|
||||
if (lcurrent)
|
||||
loptend = lcurrent->next;
|
||||
return('?');
|
||||
}
|
||||
|
||||
if (*++cp == ':') {
|
||||
/* Option requires an argument. */
|
||||
/* We allow -l2 as equivalent to -l 2 */
|
||||
if (lcurrent->word->word[sp+1] != '\0') {
|
||||
list_optarg = &(lcurrent->word->word[sp+1]);
|
||||
lcurrent = lcurrent->next;
|
||||
} else if (lcurrent->next == NULL) {
|
||||
ERR("option requires an argument: -", c);
|
||||
sp = 1;
|
||||
list_optarg = (char *)NULL;
|
||||
return('?');
|
||||
} else {
|
||||
lcurrent = lcurrent->next;
|
||||
list_optarg = lcurrent->word->word;
|
||||
lcurrent = lcurrent->next;
|
||||
}
|
||||
sp = 1;
|
||||
} else {
|
||||
/* No argument, just return the option. */
|
||||
if (lcurrent->word->word[++sp] == '\0') {
|
||||
sp = 1;
|
||||
lcurrent = lcurrent->next;
|
||||
}
|
||||
list_optarg = (char *)NULL;
|
||||
}
|
||||
|
||||
return(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* reset_internal_getopt -- force the in[ft]ernal getopt to reset
|
||||
*/
|
||||
|
||||
void
|
||||
reset_internal_getopt ()
|
||||
{
|
||||
lhead = lcurrent = loptend = (WORD_LIST *)NULL;
|
||||
sp = 1;
|
||||
}
|
||||
|
||||
void
|
||||
report_bad_option ()
|
||||
{
|
||||
char s[3];
|
||||
|
||||
s[0] = '-';
|
||||
s[1] = list_optopt;
|
||||
s[2] = '\0';
|
||||
bad_option (s);
|
||||
}
|
37
builtins/bashgetopt.h
Normal file
37
builtins/bashgetopt.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
/* bashgetopt.h -- extern declarations for stuff defined in bashgetopt.c. */
|
||||
|
||||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* See getopt.h for the explanation of these variables. */
|
||||
|
||||
#if !defined (__BASH_GETOPT_H)
|
||||
# define __BASH_GETOPT_H
|
||||
|
||||
extern char *list_optarg;
|
||||
|
||||
extern int list_optopt;
|
||||
|
||||
extern WORD_LIST *lcurrent;
|
||||
extern WORD_LIST *loptend;
|
||||
|
||||
extern int internal_getopt ();
|
||||
extern void reset_internal_getopt ();
|
||||
extern void report_bad_option ();
|
||||
|
||||
#endif /* !__BASH_GETOPT_H */
|
219
builtins/bind.def
Normal file
219
builtins/bind.def
Normal file
|
@ -0,0 +1,219 @@
|
|||
This file is bind.def, from which is created bind.c.
|
||||
It implements the builtin "bind" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES bind.c
|
||||
|
||||
$BUILTIN bind
|
||||
$DEPENDS_ON READLINE
|
||||
$FUNCTION bind_builtin
|
||||
$SHORT_DOC bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline-function]
|
||||
Bind a key sequence to a Readline function, or to a macro. The
|
||||
syntax is equivalent to that found in ~/.inputrc, but must be
|
||||
passed as a single argument: bind '"\C-x\C-r": re-read-init-file'.
|
||||
Arguments we accept:
|
||||
-m keymap Use `keymap' as the keymap for the duration of this
|
||||
command. Acceptable keymap names are emacs,
|
||||
emacs-standard, emacs-meta, emacs-ctlx, vi, vi-move,
|
||||
vi-command, and vi-insert.
|
||||
-l List names of functions.
|
||||
-v List function names and bindings.
|
||||
-d Dump functions and bindings such that they
|
||||
can be read back in.
|
||||
-f filename Read key bindings from FILENAME.
|
||||
-q function-name Query about which keys invoke the named function.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#if defined (READLINE)
|
||||
#include <errno.h>
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include "bashgetopt.h"
|
||||
|
||||
static int query_bindings ();
|
||||
|
||||
extern int bash_readline_initialized;
|
||||
extern int no_line_editing;
|
||||
|
||||
#define BIND_RETURN(x) do { return_code = x; goto bind_exit; } while (0)
|
||||
|
||||
#define USAGE "usage: bind [-lvd] [-m keymap] [-f filename] [-q name] [keyseq:readline_func]"
|
||||
|
||||
int
|
||||
bind_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int return_code = EXECUTION_SUCCESS;
|
||||
FILE *old_rl_outstream;
|
||||
Keymap kmap, saved_keymap;
|
||||
int lflag, dflag, fflag, vflag, qflag, mflag, opt;
|
||||
char *initfile, *map_name, *fun_name;
|
||||
|
||||
if (no_line_editing)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
kmap = saved_keymap = (Keymap) NULL;
|
||||
lflag = dflag = vflag = fflag = qflag = mflag = 0;
|
||||
initfile = map_name = fun_name = (char *)NULL;
|
||||
|
||||
if (!bash_readline_initialized)
|
||||
initialize_readline ();
|
||||
|
||||
/* Cannot use unwind_protect_pointer () on "FILE *", it is only
|
||||
guaranteed to work for strings. */
|
||||
/* XXX -- see if we can use unwind_protect here */
|
||||
old_rl_outstream = rl_outstream;
|
||||
rl_outstream = stdout;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lvdf:q:m:")) != EOF)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
lflag++;
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
vflag++;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
dflag++;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
fflag++;
|
||||
initfile = list_optarg;
|
||||
break;
|
||||
|
||||
case 'm':
|
||||
mflag++;
|
||||
map_name = list_optarg;
|
||||
break;
|
||||
|
||||
case 'q':
|
||||
qflag++;
|
||||
fun_name = list_optarg;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_error (USAGE);
|
||||
BIND_RETURN (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
/* First, see if we need to install a special keymap for this
|
||||
command. Then start on the arguments. */
|
||||
|
||||
if (mflag && map_name)
|
||||
{
|
||||
kmap = rl_get_keymap_by_name (map_name);
|
||||
if (!kmap)
|
||||
{
|
||||
builtin_error ("`%s': illegal keymap name", map_name);
|
||||
BIND_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (kmap)
|
||||
{
|
||||
saved_keymap = rl_get_keymap ();
|
||||
rl_set_keymap (kmap);
|
||||
}
|
||||
|
||||
/* XXX - we need to add exclusive use tests here. It doesn't make sense
|
||||
to use some of these options together. */
|
||||
/* Now hack the option arguments */
|
||||
if (lflag)
|
||||
rl_list_funmap_names (0);
|
||||
|
||||
if (vflag)
|
||||
rl_function_dumper (0);
|
||||
|
||||
if (dflag)
|
||||
rl_function_dumper (1);
|
||||
|
||||
if (fflag && initfile)
|
||||
{
|
||||
if (rl_read_init_file (initfile) != 0)
|
||||
{
|
||||
builtin_error ("cannot read %s: %s", initfile, strerror (errno));
|
||||
BIND_RETURN (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (qflag && fun_name)
|
||||
return_code = query_bindings (fun_name);
|
||||
|
||||
/* Process the rest of the arguments as binding specifications. */
|
||||
while (list)
|
||||
{
|
||||
rl_parse_and_bind (list->word->word);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
bind_exit:
|
||||
if (saved_keymap)
|
||||
rl_set_keymap (saved_keymap);
|
||||
|
||||
rl_outstream = old_rl_outstream;
|
||||
return (return_code);
|
||||
}
|
||||
|
||||
static int
|
||||
query_bindings (name)
|
||||
char *name;
|
||||
{
|
||||
Function *function;
|
||||
char **keyseqs;
|
||||
int j;
|
||||
|
||||
function = rl_named_function (name);
|
||||
if (!function)
|
||||
{
|
||||
builtin_error ("unknown function name `%s'", name);
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
keyseqs = rl_invoking_keyseqs (function);
|
||||
|
||||
if (!keyseqs)
|
||||
{
|
||||
printf ("%s is not bound to any keys.\n", name);
|
||||
return EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
printf ("%s can be invoked via ", name);
|
||||
for (j = 0; j < 5 && keyseqs[j]; j++)
|
||||
printf ("\"%s\"%s", keyseqs[j], keyseqs[j + 1] ? ", " : ".\n");
|
||||
if (keyseqs[j])
|
||||
printf ("...\n");
|
||||
free_array (keyseqs);
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
#endif /* READLINE */
|
110
builtins/break.def
Normal file
110
builtins/break.def
Normal file
|
@ -0,0 +1,110 @@
|
|||
This file is break.def, from which is created break.c.
|
||||
It implements the builtins "break" and "continue" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES break.c
|
||||
|
||||
$BUILTIN break
|
||||
$FUNCTION break_builtin
|
||||
$SHORT_DOC break [n]
|
||||
Exit from within a FOR, WHILE or UNTIL loop. If N is specified,
|
||||
break N levels.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
extern char *this_command_name;
|
||||
|
||||
static int check_loop_level ();
|
||||
|
||||
/* The depth of while's and until's. */
|
||||
int loop_level = 0;
|
||||
|
||||
/* Non-zero when a "break" instruction is encountered. */
|
||||
int breaking = 0;
|
||||
|
||||
/* Non-zero when we have encountered a continue instruction. */
|
||||
int continuing = 0;
|
||||
|
||||
/* Set up to break x levels, where x defaults to 1, but can be specified
|
||||
as the first argument. */
|
||||
break_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int newbreak;
|
||||
|
||||
if (!check_loop_level ())
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
newbreak = get_numeric_arg (list);
|
||||
|
||||
if (newbreak <= 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (newbreak > loop_level)
|
||||
newbreak = loop_level;
|
||||
|
||||
breaking = newbreak;
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
$BUILTIN continue
|
||||
$FUNCTION continue_builtin
|
||||
$SHORT_DOC continue [n]
|
||||
Resume the next iteration of the enclosing FOR, WHILE or UNTIL loop.
|
||||
If N is specified, resume at the N-th enclosing loop.
|
||||
$END
|
||||
|
||||
/* Set up to continue x levels, where x defaults to 1, but can be specified
|
||||
as the first argument. */
|
||||
continue_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int newcont;
|
||||
|
||||
if (!check_loop_level ())
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
newcont = get_numeric_arg (list);
|
||||
|
||||
if (newcont <= 0)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (newcont > loop_level)
|
||||
newcont = loop_level;
|
||||
|
||||
continuing = newcont;
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Return non-zero if a break or continue command would be okay.
|
||||
Print an error message if break or continue is meaningless here. */
|
||||
static int
|
||||
check_loop_level ()
|
||||
{
|
||||
#if defined (BREAK_COMPLAINS)
|
||||
if (!loop_level)
|
||||
builtin_error ("Only meaningful in a `for', `while', or `until' loop");
|
||||
#endif /* BREAK_COMPLAINS */
|
||||
|
||||
return (loop_level);
|
||||
}
|
67
builtins/builtin.def
Normal file
67
builtins/builtin.def
Normal file
|
@ -0,0 +1,67 @@
|
|||
This file is builtin.def, from which is created builtin.c.
|
||||
It implements the builtin "builtin" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES builtin.c
|
||||
|
||||
$BUILTIN builtin
|
||||
$FUNCTION builtin_builtin
|
||||
$SHORT_DOC builtin [shell-builtin [arg ...]]
|
||||
Run a shell builtin. This is useful when you wish to rename a
|
||||
shell builtin to be a function, but need the functionality of the
|
||||
builtin within the function itself.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern char *this_command_name;
|
||||
|
||||
/* Run the command mentioned in list directly, without going through the
|
||||
normal alias/function/builtin/filename lookup process. */
|
||||
builtin_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
Function *function;
|
||||
register char *command;
|
||||
|
||||
if (!list)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
command = (list->word->word);
|
||||
#if defined (DISABLED_BUILTINS)
|
||||
function = builtin_address (command);
|
||||
#else /* !DISABLED_BUILTINS */
|
||||
function = find_shell_builtin (command);
|
||||
#endif /* !DISABLED_BUILTINS */
|
||||
|
||||
if (!function)
|
||||
{
|
||||
builtin_error ("%s: not a shell builtin", command);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
this_command_name = command;
|
||||
list = list->next;
|
||||
return ((*function) (list));
|
||||
}
|
||||
}
|
689
builtins/cd.def
Normal file
689
builtins/cd.def
Normal file
|
@ -0,0 +1,689 @@
|
|||
This file is cd.def, from which is created cd.c. It implements the
|
||||
builtins "cd", "pwd", "pushd", "popd", and "dirs" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES cd.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/param.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include <errno.h>
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
#include "../maxpath.h"
|
||||
#include "common.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
static int change_to_directory (), cd_to_string ();
|
||||
|
||||
$BUILTIN cd
|
||||
$FUNCTION cd_builtin
|
||||
$SHORT_DOC cd [dir]
|
||||
Change the current directory to DIR. The variable $HOME is the
|
||||
default DIR. The variable $CDPATH defines the search path for
|
||||
the directory containing DIR. Alternative directory names are
|
||||
separated by a colon (:). A null directory name is the same as
|
||||
the current directory, i.e. `.'. If DIR begins with a slash (/),
|
||||
then $CDPATH is not used. If the directory is not found, and the
|
||||
shell variable `cdable_vars' exists, then try the word as a variable
|
||||
name. If that variable has a value, then cd to the value of that
|
||||
variable.
|
||||
$END
|
||||
|
||||
/* This builtin is ultimately the way that all user-visible commands should
|
||||
change the current working directory. It is called by cd_to_string (),
|
||||
so the programming interface is simple, and it handles errors and
|
||||
restrictions properly. */
|
||||
int
|
||||
cd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *dirname;
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
builtin_error ("restricted");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
if (list)
|
||||
{
|
||||
char *extract_colon_unit ();
|
||||
char *path_string = get_string_value ("CDPATH");
|
||||
char *path;
|
||||
int path_index = 0, dirlen, pathlen;
|
||||
|
||||
dirname = list->word->word;
|
||||
|
||||
if (path_string && !absolute_pathname (dirname))
|
||||
{
|
||||
while ((path = extract_colon_unit (path_string, &path_index)))
|
||||
{
|
||||
char *dir;
|
||||
|
||||
if (*path == '~')
|
||||
{
|
||||
char *te_string = tilde_expand (path);
|
||||
|
||||
free (path);
|
||||
path = te_string;
|
||||
}
|
||||
|
||||
if (!*path)
|
||||
{
|
||||
free (path);
|
||||
path = xmalloc (2);
|
||||
path[0] = '.'; /* by definition. */
|
||||
path[1] = '\0';
|
||||
}
|
||||
|
||||
dirlen = strlen (dirname);
|
||||
pathlen = strlen (path);
|
||||
dir = xmalloc (2 + dirlen + pathlen);
|
||||
strcpy (dir, path);
|
||||
if (path[pathlen - 1] != '/')
|
||||
{
|
||||
dir[pathlen++] = '/';
|
||||
dir[pathlen] = '\0';
|
||||
}
|
||||
strcpy (dir + pathlen, dirname);
|
||||
free (path);
|
||||
|
||||
if (change_to_directory (dir))
|
||||
{
|
||||
/* replaces (strncmp (dir, "./", 2) != 0) */
|
||||
if (dir[0] != '.' || dir[1] != '/')
|
||||
printf ("%s\n", dir);
|
||||
|
||||
free (dir);
|
||||
goto bind_and_exit;
|
||||
}
|
||||
else
|
||||
free (dir);
|
||||
}
|
||||
}
|
||||
|
||||
if (!change_to_directory (dirname))
|
||||
{
|
||||
/* Maybe this is `cd -', equivalent to `cd $OLDPWD' */
|
||||
if (dirname[0] == '-' && dirname[1] == '\0')
|
||||
{
|
||||
char *t = get_string_value ("OLDPWD");
|
||||
|
||||
if (t && change_to_directory (t))
|
||||
goto bind_and_exit;
|
||||
}
|
||||
|
||||
/* If the user requests it, then perhaps this is the name of
|
||||
a shell variable, whose value contains the directory to
|
||||
change to. If that is the case, then change to that
|
||||
directory. */
|
||||
if (find_variable ("cdable_vars"))
|
||||
{
|
||||
char *t = get_string_value (dirname);
|
||||
|
||||
if (t && change_to_directory (t))
|
||||
{
|
||||
printf ("%s\n", t);
|
||||
goto bind_and_exit;
|
||||
}
|
||||
}
|
||||
|
||||
file_error (dirname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
goto bind_and_exit;
|
||||
}
|
||||
else
|
||||
{
|
||||
dirname = get_string_value ("HOME");
|
||||
|
||||
if (!dirname)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (!change_to_directory (dirname))
|
||||
{
|
||||
file_error (dirname);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
bind_and_exit:
|
||||
{
|
||||
char *directory;
|
||||
|
||||
directory = get_working_directory ("cd");
|
||||
|
||||
bind_variable ("OLDPWD", get_string_value ("PWD"));
|
||||
bind_variable ("PWD", directory);
|
||||
|
||||
FREE (directory);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
}
|
||||
|
||||
$BUILTIN pwd
|
||||
$FUNCTION pwd_builtin
|
||||
$SHORT_DOC pwd
|
||||
Print the current working directory.
|
||||
$END
|
||||
|
||||
/* Non-zero means that pwd always give verbatim directory, regardless of
|
||||
symbolic link following. */
|
||||
static int verbatim_pwd;
|
||||
|
||||
/* Print the name of the current working directory. */
|
||||
pwd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *directory, *s;
|
||||
|
||||
#if 0
|
||||
no_args (list);
|
||||
#else
|
||||
verbatim_pwd = no_symbolic_links;
|
||||
if (list && (s = list->word->word) && s[0] == '-' && s[1] == 'P' && !s[2])
|
||||
verbatim_pwd = 1;
|
||||
#endif
|
||||
|
||||
if (verbatim_pwd)
|
||||
{
|
||||
char *buffer = xmalloc (MAXPATHLEN);
|
||||
directory = getwd (buffer);
|
||||
|
||||
if (!directory)
|
||||
{
|
||||
builtin_error ("%s", buffer);
|
||||
free (buffer);
|
||||
}
|
||||
}
|
||||
else
|
||||
directory = get_working_directory ("pwd");
|
||||
|
||||
if (directory)
|
||||
{
|
||||
printf ("%s\n", directory);
|
||||
fflush (stdout);
|
||||
free (directory);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
$BUILTIN pushd
|
||||
$FUNCTION pushd_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC pushd [dir | +n | -n]
|
||||
Adds a directory to the top of the directory stack, or rotates
|
||||
the stack, making the new top of the stack the current working
|
||||
directory. With no arguments, exchanges the top two directories.
|
||||
|
||||
+n Rotates the stack so that the Nth directory (counting
|
||||
from the left of the list shown by `dirs') is at the top.
|
||||
|
||||
-n Rotates the stack so that the Nth directory (counting
|
||||
from the right) is at the top.
|
||||
|
||||
dir adds DIR to the directory stack at the top, making it the
|
||||
new current working directory.
|
||||
|
||||
You can see the directory stack with the `dirs' command.
|
||||
$END
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
/* Some useful commands whose behaviour has been observed in Csh. */
|
||||
|
||||
/* The list of remembered directories. */
|
||||
static char **pushd_directory_list = (char **)NULL;
|
||||
|
||||
/* Number of existing slots in this list. */
|
||||
static int directory_list_size = 0;
|
||||
|
||||
/* Offset to the end of the list. */
|
||||
static int directory_list_offset = 0;
|
||||
|
||||
pushd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char *temp, *current_directory;
|
||||
int j = directory_list_offset - 1;
|
||||
char direction = '+';
|
||||
|
||||
/* If there is no argument list then switch current and
|
||||
top of list. */
|
||||
if (!list)
|
||||
{
|
||||
if (!directory_list_offset)
|
||||
{
|
||||
builtin_error ("No other directory");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (!current_directory)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
temp = pushd_directory_list[j];
|
||||
pushd_directory_list[j] = current_directory;
|
||||
goto change_to_temp;
|
||||
}
|
||||
else
|
||||
{
|
||||
direction = *(list->word->word);
|
||||
if (direction == '+' || direction == '-')
|
||||
{
|
||||
int num;
|
||||
if (1 == sscanf (&(list->word->word)[1], "%d", &num))
|
||||
{
|
||||
if (direction == '-')
|
||||
num = directory_list_offset - num;
|
||||
|
||||
if (num > directory_list_offset || num < 0)
|
||||
{
|
||||
if (!directory_list_offset)
|
||||
builtin_error ("Directory stack empty");
|
||||
else
|
||||
builtin_error ("Stack contains only %d directories",
|
||||
directory_list_offset + 1);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Rotate the stack num times. Remember, the
|
||||
current directory acts like it is part of the
|
||||
stack. */
|
||||
temp = get_working_directory ("pushd");
|
||||
|
||||
if (!num)
|
||||
goto change_to_temp;
|
||||
|
||||
do
|
||||
{
|
||||
char *top =
|
||||
pushd_directory_list[directory_list_offset - 1];
|
||||
|
||||
for (j = directory_list_offset - 2; j > -1; j--)
|
||||
pushd_directory_list[j + 1] = pushd_directory_list[j];
|
||||
|
||||
pushd_directory_list[j + 1] = temp;
|
||||
|
||||
temp = top;
|
||||
num--;
|
||||
}
|
||||
while (num);
|
||||
|
||||
temp = savestring (temp);
|
||||
change_to_temp:
|
||||
{
|
||||
int tt = EXECUTION_FAILURE;
|
||||
|
||||
if (temp)
|
||||
{
|
||||
tt = cd_to_string (temp);
|
||||
free (temp);
|
||||
}
|
||||
|
||||
if ((tt == EXECUTION_SUCCESS))
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (tt);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Change to the directory in list->word->word. Save the current
|
||||
directory on the top of the stack. */
|
||||
current_directory = get_working_directory ("pushd");
|
||||
if (!current_directory)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
if (cd_builtin (list) == EXECUTION_SUCCESS)
|
||||
{
|
||||
if (directory_list_offset == directory_list_size)
|
||||
{
|
||||
pushd_directory_list = (char **)
|
||||
xrealloc (pushd_directory_list,
|
||||
(directory_list_size += 10) * sizeof (char *));
|
||||
}
|
||||
pushd_directory_list[directory_list_offset++] = current_directory;
|
||||
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else
|
||||
{
|
||||
free (current_directory);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
|
||||
$BUILTIN dirs
|
||||
$FUNCTION dirs_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC dirs [-l]
|
||||
Display the list of currently remembered directories. Directories
|
||||
find their way onto the list with the `pushd' command; you can get
|
||||
back up through the list with the `popd' command.
|
||||
|
||||
The -l flag specifies that `dirs' should not print shorthand versions
|
||||
of directories which are relative to your home directory. This means
|
||||
that `~/bin' might be displayed as `/homes/bfox/bin'.
|
||||
$END
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
/* Print the current list of directories on the directory stack. */
|
||||
dirs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int i, format, desired_index, index_flag;
|
||||
char *temp, *w;
|
||||
|
||||
format = index_flag = 0;
|
||||
desired_index = -1;
|
||||
/* Maybe do long form or print specific dir stack entry? */
|
||||
while (list)
|
||||
{
|
||||
if (strcmp (list->word->word, "-l") == 0)
|
||||
{
|
||||
format++;
|
||||
list = list->next;
|
||||
}
|
||||
else if (*list->word->word == '+' && all_digits (list->word->word + 1))
|
||||
{
|
||||
w = list->word->word + 1;
|
||||
index_flag = 1;
|
||||
i = atoi (w);
|
||||
/* dirs +0 prints the current working directory. */
|
||||
if (i == 0)
|
||||
desired_index = i;
|
||||
else if (i == directory_list_offset)
|
||||
{
|
||||
desired_index = 0;
|
||||
index_flag = 2;
|
||||
}
|
||||
else
|
||||
desired_index = directory_list_offset - i;
|
||||
list = list->next;
|
||||
}
|
||||
else if (*list->word->word == '-' && all_digits (list->word->word + 1))
|
||||
{
|
||||
w = list->word->word + 1;
|
||||
i = atoi (w);
|
||||
index_flag = 2;
|
||||
/* dirs -X where X is directory_list_offset prints the current
|
||||
working directory. */
|
||||
if (i == directory_list_offset)
|
||||
{
|
||||
index_flag = 1;
|
||||
desired_index = 0;
|
||||
}
|
||||
else
|
||||
desired_index = i;
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
|
||||
{
|
||||
if (directory_list_offset == 0)
|
||||
builtin_error ("directory stack empty");
|
||||
else
|
||||
builtin_error ("%s: bad directory stack index", w);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* The first directory printed is always the current working directory. */
|
||||
if (!index_flag || (index_flag == 1 && desired_index == 0))
|
||||
{
|
||||
temp = get_working_directory ("dirs");
|
||||
if (!temp)
|
||||
temp = savestring ("<no directory>");
|
||||
printf ("%s", format ? temp : polite_directory_format (temp));
|
||||
free (temp);
|
||||
if (index_flag)
|
||||
{
|
||||
putchar ('\n');
|
||||
return EXECUTION_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
#define DIRSTACK_ENTRY(i) \
|
||||
format ? pushd_directory_list[i] \
|
||||
: polite_directory_format (pushd_directory_list[i])
|
||||
|
||||
/* Now print the requested directory stack entries. */
|
||||
if (index_flag)
|
||||
printf ("%s", DIRSTACK_ENTRY (desired_index));
|
||||
else
|
||||
for (i = (directory_list_offset - 1); i > -1; i--)
|
||||
printf (" %s", DIRSTACK_ENTRY (i));
|
||||
|
||||
putchar ('\n');
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
|
||||
$BUILTIN popd
|
||||
$FUNCTION popd_builtin
|
||||
$DEPENDS_ON PUSHD_AND_POPD
|
||||
$SHORT_DOC popd [+n | -n]
|
||||
Removes entries from the directory stack. With no arguments,
|
||||
removes the top directory from the stack, and cd's to the new
|
||||
top directory.
|
||||
|
||||
+n removes the Nth entry counting from the left of the list
|
||||
shown by `dirs', starting with zero. For example: `popd +0'
|
||||
removes the first directory, `popd +1' the second.
|
||||
|
||||
-n removes the Nth entry counting from the right of the list
|
||||
shown by `dirs', starting with zero. For example: `popd -0'
|
||||
removes the last directory, `popd -1' the next to last.
|
||||
|
||||
You can see the directory stack with the `dirs' command.
|
||||
$END
|
||||
|
||||
#if defined (PUSHD_AND_POPD)
|
||||
/* Pop the directory stack, and then change to the new top of the stack.
|
||||
If LIST is non-null it should consist of a word +N or -N, which says
|
||||
what element to delete from the stack. The default is the top one. */
|
||||
popd_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
int which = 0;
|
||||
char direction = '+';
|
||||
|
||||
if (list)
|
||||
{
|
||||
direction = *(list->word->word);
|
||||
|
||||
if ((direction != '+' && direction != '-') ||
|
||||
(1 != sscanf (&((list->word->word)[1]), "%d", &which)))
|
||||
{
|
||||
builtin_error ("bad arg `%s'", list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (which > directory_list_offset || (!directory_list_offset && !which))
|
||||
{
|
||||
if (!directory_list_offset)
|
||||
builtin_error ("Directory stack empty");
|
||||
else
|
||||
builtin_error ("Stack contains only %d directories",
|
||||
directory_list_offset + 1);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Handle case of no specification, or top of stack specification. */
|
||||
if ((direction == '+' && which == 0) ||
|
||||
(direction == '-' && which == directory_list_offset))
|
||||
{
|
||||
i = cd_to_string (pushd_directory_list[directory_list_offset - 1]);
|
||||
if (i != EXECUTION_SUCCESS)
|
||||
return (i);
|
||||
free (pushd_directory_list[--directory_list_offset]);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Since an offset other than the top directory was specified,
|
||||
remove that directory from the list and shift the remainder
|
||||
of the list into place. */
|
||||
|
||||
if (direction == '+')
|
||||
i = directory_list_offset - which;
|
||||
else
|
||||
i = which;
|
||||
|
||||
free (pushd_directory_list[i]);
|
||||
directory_list_offset--;
|
||||
|
||||
/* Shift the remainder of the list into place. */
|
||||
for (; i < directory_list_offset; i++)
|
||||
pushd_directory_list[i] = pushd_directory_list[i + 1];
|
||||
}
|
||||
|
||||
dirs_builtin ((WORD_LIST *)NULL);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* PUSHD_AND_POPD */
|
||||
|
||||
/* Do the work of changing to the directory NEWDIR. Handle symbolic
|
||||
link following, etc. */
|
||||
|
||||
static int
|
||||
change_to_directory (newdir)
|
||||
char *newdir;
|
||||
{
|
||||
char *t;
|
||||
|
||||
if (!no_symbolic_links)
|
||||
{
|
||||
int chdir_return = 0;
|
||||
char *tdir = (char *)NULL;
|
||||
|
||||
if (!the_current_working_directory)
|
||||
{
|
||||
t = get_working_directory ("cd_links");
|
||||
FREE (t);
|
||||
}
|
||||
|
||||
if (the_current_working_directory)
|
||||
t = make_absolute (newdir, the_current_working_directory);
|
||||
else
|
||||
t = savestring (newdir);
|
||||
|
||||
/* TDIR is the canonicalized absolute pathname of the NEWDIR. */
|
||||
tdir = canonicalize_pathname (t);
|
||||
|
||||
/* Use the canonicalized version of NEWDIR, or, if canonicalization
|
||||
failed, use the non-canonical form. */
|
||||
if (tdir && *tdir)
|
||||
free (t);
|
||||
else
|
||||
{
|
||||
FREE (tdir);
|
||||
|
||||
tdir = t;
|
||||
}
|
||||
|
||||
if (chdir (tdir) < 0)
|
||||
{
|
||||
int err;
|
||||
|
||||
chdir_return = 0;
|
||||
free (tdir);
|
||||
|
||||
err = errno;
|
||||
|
||||
/* We failed changing to the canonicalized directory name. Try
|
||||
what the user passed verbatim. If we succeed, reinitialize
|
||||
the_current_working_directory. */
|
||||
if (chdir (newdir) == 0)
|
||||
{
|
||||
chdir_return = 1;
|
||||
if (the_current_working_directory)
|
||||
{
|
||||
free (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
}
|
||||
|
||||
tdir = get_working_directory ("cd");
|
||||
FREE (tdir);
|
||||
}
|
||||
else
|
||||
errno = err;
|
||||
}
|
||||
else
|
||||
{
|
||||
chdir_return = 1;
|
||||
|
||||
FREE (the_current_working_directory);
|
||||
the_current_working_directory = tdir;
|
||||
}
|
||||
|
||||
return (chdir_return);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (chdir (newdir) < 0)
|
||||
return (0);
|
||||
else
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
|
||||
so if the result is EXECUTION_FAILURE then an error message has already
|
||||
been printed. */
|
||||
static int
|
||||
cd_to_string (name)
|
||||
char *name;
|
||||
{
|
||||
WORD_LIST *tlist = make_word_list (make_word (name), NULL);
|
||||
int result = (cd_builtin (tlist));
|
||||
dispose_words (tlist);
|
||||
return (result);
|
||||
}
|
37
builtins/colon.def
Normal file
37
builtins/colon.def
Normal file
|
@ -0,0 +1,37 @@
|
|||
This file is colon.def, from which is created colon.c.
|
||||
It implements the builtin ":" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES colon.c
|
||||
|
||||
$BUILTIN :
|
||||
$DOCNAME colon_builtin
|
||||
$FUNCTION colon_builtin
|
||||
$SHORT_DOC :
|
||||
No effect; the command does nothing. A zero exit code is returned.
|
||||
$END
|
||||
|
||||
/* Do nothing. This command is a no-op. */
|
||||
int
|
||||
colon_builtin (ignore)
|
||||
char *ignore;
|
||||
{
|
||||
return (0);
|
||||
}
|
177
builtins/command.def
Normal file
177
builtins/command.def
Normal file
|
@ -0,0 +1,177 @@
|
|||
This file is command.def, from which is created command.c.
|
||||
It implements the builtin "command" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES command.c
|
||||
|
||||
$BUILTIN command
|
||||
$FUNCTION command_builtin
|
||||
$SHORT_DOC command [-pVv] [command [arg ...]]
|
||||
Runs COMMAND with ARGS ignoring shell functions. If you have a shell
|
||||
function called `ls', and you wish to call the command `ls', you can
|
||||
say "command ls". If the -p option is given, a default value is used
|
||||
for PATH that is guaranteed to find all of the standard utilities. If
|
||||
the -V or -v option is given, a string is printed describing COMMAND.
|
||||
The -V option produces a more verbose description.
|
||||
$END
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int subshell_environment;
|
||||
|
||||
static void restore_path ();
|
||||
static char *get_standard_path ();
|
||||
|
||||
/* Run the commands mentioned in LIST without paying attention to shell
|
||||
functions. */
|
||||
int
|
||||
command_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, verbose = 0, use_standard_path = 0, opt;
|
||||
char *old_path;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "pvV")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'p':
|
||||
use_standard_path = 1;
|
||||
break;
|
||||
case 'V':
|
||||
verbose = 2;
|
||||
break;
|
||||
case 'v':
|
||||
verbose = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
report_bad_option ();
|
||||
builtin_error ("usage: command [-pvV] [command [arg...]]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (!list)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
if (verbose)
|
||||
{
|
||||
int found, any_found = 0;
|
||||
|
||||
while (list)
|
||||
{
|
||||
|
||||
found = describe_command (list->word->word, verbose, 0);
|
||||
|
||||
if (!found)
|
||||
builtin_error ("%s: not found", list->word->word);
|
||||
|
||||
any_found += found;
|
||||
list = list->next;
|
||||
}
|
||||
return (any_found ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
begin_unwind_frame ("command_builtin");
|
||||
|
||||
/* We don't want this to be reparsed (consider command echo 'foo &'), so
|
||||
just make a simple_command structure and call execute_command with it. */
|
||||
{
|
||||
COMMAND *command;
|
||||
|
||||
if (use_standard_path)
|
||||
{
|
||||
char *standard_path;
|
||||
|
||||
old_path = get_string_value ("PATH");
|
||||
if (old_path)
|
||||
old_path = savestring (old_path);
|
||||
else
|
||||
old_path = savestring ("");
|
||||
add_unwind_protect ((Function *)restore_path, old_path);
|
||||
|
||||
standard_path = get_standard_path ();
|
||||
bind_variable ("PATH", standard_path);
|
||||
free (standard_path);
|
||||
}
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = (WORD_LIST *)copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION);
|
||||
command->value.Simple->flags |= (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION);
|
||||
/* If we're in a subshell, see if we can get away without forking
|
||||
again, since we've already forked to run this builtin. */
|
||||
if (subshell_environment)
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
add_unwind_protect ((char *)dispose_command, command);
|
||||
result = execute_command (command);
|
||||
}
|
||||
|
||||
run_unwind_frame ("command_builtin");
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Restore the value of the $PATH variable after replacing it when
|
||||
executing `command -p'. */
|
||||
static void
|
||||
restore_path (var)
|
||||
char *var;
|
||||
{
|
||||
bind_variable ("PATH", var);
|
||||
free (var);
|
||||
}
|
||||
|
||||
/* Return a value for PATH that is guaranteed to find all of the standard
|
||||
utilities. This uses Posix.2 configuration variables, if present. It
|
||||
uses a value defined in config.h as a last resort. */
|
||||
static char *
|
||||
get_standard_path ()
|
||||
{
|
||||
#if defined (_CS_PATH) && !defined (hpux_7) && !defined (NetBSD)
|
||||
char *p;
|
||||
size_t len;
|
||||
|
||||
len = (size_t)confstr (_CS_PATH, (char *)NULL, (size_t)0);
|
||||
p = xmalloc ((int)len + 2);
|
||||
*p = '\0';
|
||||
confstr (_CS_PATH, p, len);
|
||||
return (p);
|
||||
#else /* !_CSPATH || hpux_7 || NetBSD */
|
||||
# if defined (CS_PATH)
|
||||
return (savestring (CS_PATH));
|
||||
# else
|
||||
return (savestring (STANDARD_UTILS_PATH));
|
||||
# endif /* !CS_PATH */
|
||||
#endif /* !_CS_PATH || hpux_7 */
|
||||
}
|
829
builtins/common.c
Normal file
829
builtins/common.c
Normal file
|
@ -0,0 +1,829 @@
|
|||
/* Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "../posixstat.h"
|
||||
#if defined (HAVE_VFPRINTF)
|
||||
#include <varargs.h>
|
||||
#endif /* VFPRINTF */
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../unwind_prot.h"
|
||||
#include "../maxpath.h"
|
||||
#include "../jobs.h"
|
||||
#include "../builtins.h"
|
||||
#include "../input.h"
|
||||
#include "../execute_cmd.h"
|
||||
#include "hashcom.h"
|
||||
#include "common.h"
|
||||
#include <tilde/tilde.h>
|
||||
|
||||
#if defined (HISTORY)
|
||||
# include "../bashhist.h"
|
||||
#endif
|
||||
|
||||
extern int no_symbolic_links, interactive, interactive_shell;
|
||||
extern int indirection_level, startup_state;
|
||||
extern int last_command_exit_value;
|
||||
extern int hashing_disabled;
|
||||
extern int variable_context;
|
||||
extern char *this_command_name, *shell_name;
|
||||
extern COMMAND *global_command;
|
||||
extern HASH_TABLE *hashed_filenames;
|
||||
|
||||
/* Read a numeric arg for this_command_name, the name of the shell builtin
|
||||
that wants it. LIST is the word list that the arg is to come from. */
|
||||
int
|
||||
get_numeric_arg (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int count = 1;
|
||||
|
||||
if (list)
|
||||
{
|
||||
register char *arg;
|
||||
int sign = 1;
|
||||
|
||||
arg = list->word->word;
|
||||
if (!arg)
|
||||
goto bad_number;
|
||||
|
||||
/* Skip optional leading white space. */
|
||||
while (whitespace (*arg))
|
||||
arg++;
|
||||
|
||||
if (!*arg)
|
||||
goto bad_number;
|
||||
|
||||
/* We allow leading `-' or `+'. */
|
||||
if (*arg == '-' || *arg == '+')
|
||||
{
|
||||
if (!digit (arg[1]))
|
||||
goto bad_number;
|
||||
|
||||
if (*arg == '-')
|
||||
sign = -1;
|
||||
|
||||
arg++;
|
||||
}
|
||||
|
||||
for (count = 0; digit (*arg); arg++)
|
||||
count = (count * 10) + digit_value (*arg);
|
||||
|
||||
/* Skip trailing whitespace, if any. */
|
||||
while (whitespace (*arg))
|
||||
arg++;
|
||||
|
||||
if (!*arg)
|
||||
count = count * sign;
|
||||
else
|
||||
{
|
||||
bad_number:
|
||||
builtin_error ("bad non-numeric arg `%s'", list->word->word);
|
||||
throw_to_top_level ();
|
||||
}
|
||||
no_args (list->next);
|
||||
}
|
||||
return (count);
|
||||
}
|
||||
|
||||
/* This is a lot like report_error (), but it is for shell builtins
|
||||
instead of shell control structures, and it won't ever exit the
|
||||
shell. */
|
||||
#if defined (HAVE_VFPRINTF)
|
||||
void
|
||||
builtin_error (va_alist)
|
||||
va_dcl
|
||||
{
|
||||
char *format;
|
||||
va_list args;
|
||||
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
va_start (args);
|
||||
format = va_arg (args, char *);
|
||||
vfprintf (stderr, format, args);
|
||||
va_end (args);
|
||||
fprintf (stderr, "\n");
|
||||
}
|
||||
#else /* !HAVE_VFPRINTF */
|
||||
void
|
||||
builtin_error (format, arg1, arg2, arg3, arg4, arg5)
|
||||
char *format, *arg1, *arg2, *arg3, *arg4, *arg5;
|
||||
{
|
||||
if (this_command_name && *this_command_name)
|
||||
fprintf (stderr, "%s: ", this_command_name);
|
||||
|
||||
fprintf (stderr, format, arg1, arg2, arg3, arg4, arg5);
|
||||
fprintf (stderr, "\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
#endif /* !HAVE_VFPRINTF */
|
||||
|
||||
/* Remember LIST in $0 ... $9, and REST_OF_ARGS. If DESTRUCTIVE is
|
||||
non-zero, then discard whatever the existing arguments are, else
|
||||
only discard the ones that are to be replaced. */
|
||||
void
|
||||
remember_args (list, destructive)
|
||||
WORD_LIST *list;
|
||||
int destructive;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 1; i < 10; i++)
|
||||
{
|
||||
if (destructive && dollar_vars[i])
|
||||
{
|
||||
free (dollar_vars[i]);
|
||||
dollar_vars[i] = (char *)NULL;
|
||||
}
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (!destructive && dollar_vars[i])
|
||||
free (dollar_vars[i]);
|
||||
|
||||
dollar_vars[i] = savestring (list->word->word);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
|
||||
/* If arguments remain, assign them to REST_OF_ARGS.
|
||||
Note that copy_word_list (NULL) returns NULL, and
|
||||
that dispose_words (NULL) does nothing. */
|
||||
if (destructive || list)
|
||||
{
|
||||
dispose_words (rest_of_args);
|
||||
rest_of_args = copy_word_list (list);
|
||||
}
|
||||
|
||||
if (destructive)
|
||||
set_dollar_vars_changed ();
|
||||
}
|
||||
|
||||
/* Return if LIST is NULL else barf and jump to top_level. */
|
||||
void
|
||||
no_args (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (list)
|
||||
{
|
||||
builtin_error ("extra arguments");
|
||||
longjmp (top_level, DISCARD);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the octal number parsed from STRING, or -1 to indicate
|
||||
that the string contained a bad number. */
|
||||
int
|
||||
read_octal (string)
|
||||
char *string;
|
||||
{
|
||||
int result = 0;
|
||||
int digits = 0;
|
||||
|
||||
while (*string && *string >= '0' && *string < '8')
|
||||
{
|
||||
digits++;
|
||||
result = (result * 8) + *string++ - '0';
|
||||
}
|
||||
|
||||
if (!digits || result > 0777 || *string)
|
||||
result = -1;
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Temporary static. */
|
||||
static char *dotted_filename = (char *)NULL;
|
||||
|
||||
/* Return the full pathname that FILENAME hashes to. If FILENAME
|
||||
is hashed, but data->check_dot is non-zero, check ./FILENAME
|
||||
and return that if it is executable. */
|
||||
char *
|
||||
find_hashed_filename (filename)
|
||||
char *filename;
|
||||
{
|
||||
register BUCKET_CONTENTS *item;
|
||||
|
||||
if (hashing_disabled)
|
||||
return ((char *)NULL);
|
||||
|
||||
item = find_hash_item (filename, hashed_filenames);
|
||||
|
||||
if (item)
|
||||
{
|
||||
/* If this filename is hashed, but `.' comes before it in the path,
|
||||
then see if `./filename' is an executable. */
|
||||
if (pathdata(item)->check_dot)
|
||||
{
|
||||
if (dotted_filename)
|
||||
free (dotted_filename);
|
||||
|
||||
dotted_filename = (char *)xmalloc (3 + strlen (filename));
|
||||
strcpy (dotted_filename, "./");
|
||||
strcat (dotted_filename, filename);
|
||||
|
||||
if (executable_file (dotted_filename))
|
||||
return (dotted_filename);
|
||||
|
||||
/* Watch out. If this file was hashed to "./filename", and
|
||||
"./filename" is not executable, then return NULL. */
|
||||
|
||||
/* Since we already know "./filename" is not executable, what
|
||||
we're really interested in is whether or not the `path'
|
||||
portion of the hashed filename is equivalent to the current
|
||||
directory, but only if it starts with a `.'. (This catches
|
||||
./. and so on.) same_file () is in execute_cmd.c; it tests
|
||||
general Unix file equivalence -- same device and inode. */
|
||||
{
|
||||
char *path = pathdata (item)->path;
|
||||
|
||||
if (*path == '.')
|
||||
{
|
||||
int same = 0;
|
||||
char *tail;
|
||||
|
||||
tail = (char *) strrchr (path, '/');
|
||||
|
||||
if (tail)
|
||||
{
|
||||
*tail = '\0';
|
||||
same = same_file
|
||||
(".", path, (struct stat *)NULL, (struct stat *)NULL);
|
||||
*tail = '/';
|
||||
}
|
||||
if (same)
|
||||
return ((char *)NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (pathdata (item)->path);
|
||||
}
|
||||
else
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
/* Remove FILENAME from the table of hashed commands. */
|
||||
void
|
||||
remove_hashed_filename (filename)
|
||||
char *filename;
|
||||
{
|
||||
register BUCKET_CONTENTS *item;
|
||||
|
||||
if (hashing_disabled)
|
||||
return;
|
||||
|
||||
item = remove_hash_item (filename, hashed_filenames);
|
||||
if (item)
|
||||
{
|
||||
if (item->data)
|
||||
{
|
||||
free (pathdata(item)->path);
|
||||
free (item->data);
|
||||
}
|
||||
if (item->key)
|
||||
free (item->key);
|
||||
free (item);
|
||||
}
|
||||
}
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Pushing and Popping a Context */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static WORD_LIST **dollar_arg_stack = (WORD_LIST **)NULL;
|
||||
static int dollar_arg_stack_slots = 0;
|
||||
static int dollar_arg_stack_index = 0;
|
||||
|
||||
void
|
||||
push_context ()
|
||||
{
|
||||
push_dollar_vars ();
|
||||
variable_context++;
|
||||
}
|
||||
|
||||
void
|
||||
pop_context ()
|
||||
{
|
||||
pop_dollar_vars ();
|
||||
kill_all_local_variables ();
|
||||
variable_context--;
|
||||
}
|
||||
|
||||
/* Save the existing positional parameters on a stack. */
|
||||
void
|
||||
push_dollar_vars ()
|
||||
{
|
||||
if (dollar_arg_stack_index + 2 > dollar_arg_stack_slots)
|
||||
{
|
||||
dollar_arg_stack = (WORD_LIST **)
|
||||
xrealloc (dollar_arg_stack, (dollar_arg_stack_slots += 10)
|
||||
* sizeof (WORD_LIST **));
|
||||
}
|
||||
dollar_arg_stack[dollar_arg_stack_index] = list_rest_of_args ();
|
||||
dollar_arg_stack[++dollar_arg_stack_index] = (WORD_LIST *)NULL;
|
||||
}
|
||||
|
||||
/* Restore the positional parameters from our stack. */
|
||||
void
|
||||
pop_dollar_vars ()
|
||||
{
|
||||
if (!dollar_arg_stack || !dollar_arg_stack_index)
|
||||
return;
|
||||
|
||||
remember_args (dollar_arg_stack[--dollar_arg_stack_index], 1);
|
||||
dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
|
||||
dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
|
||||
}
|
||||
|
||||
void
|
||||
dispose_saved_dollar_vars ()
|
||||
{
|
||||
if (!dollar_arg_stack || !dollar_arg_stack_index)
|
||||
return;
|
||||
|
||||
dispose_words (dollar_arg_stack[dollar_arg_stack_index]);
|
||||
dollar_arg_stack[dollar_arg_stack_index] = (WORD_LIST *)NULL;
|
||||
}
|
||||
|
||||
static int changed_dollar_vars = 0;
|
||||
|
||||
/* Have the dollar variables been reset to new values since we last
|
||||
checked? */
|
||||
dollar_vars_changed ()
|
||||
{
|
||||
return (changed_dollar_vars);
|
||||
}
|
||||
|
||||
void
|
||||
set_dollar_vars_unchanged ()
|
||||
{
|
||||
changed_dollar_vars = 0;
|
||||
}
|
||||
|
||||
void
|
||||
set_dollar_vars_changed ()
|
||||
{
|
||||
changed_dollar_vars = 1;
|
||||
}
|
||||
|
||||
/* Function called when one of the builtin commands detects a bad
|
||||
option. */
|
||||
void
|
||||
bad_option (s)
|
||||
char *s;
|
||||
{
|
||||
builtin_error ("unknown option: %s", s);
|
||||
}
|
||||
|
||||
/* Return a consed string which is the current working directory.
|
||||
FOR_WHOM is the name of the caller for error printing. */
|
||||
char *the_current_working_directory = (char *)NULL;
|
||||
|
||||
char *
|
||||
get_working_directory (for_whom)
|
||||
char *for_whom;
|
||||
{
|
||||
if (no_symbolic_links)
|
||||
{
|
||||
if (the_current_working_directory)
|
||||
free (the_current_working_directory);
|
||||
|
||||
the_current_working_directory = (char *)NULL;
|
||||
}
|
||||
|
||||
if (!the_current_working_directory)
|
||||
{
|
||||
char *directory;
|
||||
|
||||
the_current_working_directory = xmalloc (MAXPATHLEN);
|
||||
directory = getwd (the_current_working_directory);
|
||||
if (!directory)
|
||||
{
|
||||
if (for_whom && *for_whom)
|
||||
fprintf (stderr, "%s: ", for_whom);
|
||||
else
|
||||
fprintf (stderr, "%s: ", get_name_for_error ());
|
||||
|
||||
fprintf (stderr, "could not get current directory: %s\n",
|
||||
the_current_working_directory);
|
||||
|
||||
free (the_current_working_directory);
|
||||
the_current_working_directory = (char *)NULL;
|
||||
return (char *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return (savestring (the_current_working_directory));
|
||||
}
|
||||
|
||||
/* Make NAME our internal idea of the current working directory. */
|
||||
void
|
||||
set_working_directory (name)
|
||||
char *name;
|
||||
{
|
||||
if (the_current_working_directory)
|
||||
free (the_current_working_directory);
|
||||
|
||||
the_current_working_directory = savestring (name);
|
||||
}
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* Return the job spec found in LIST. */
|
||||
get_job_spec (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char *word;
|
||||
int job = NO_JOB;
|
||||
int substring = 0;
|
||||
|
||||
if (!list)
|
||||
return (current_job);
|
||||
|
||||
word = list->word->word;
|
||||
|
||||
if (!*word)
|
||||
return (current_job);
|
||||
|
||||
if (*word == '%')
|
||||
word++;
|
||||
|
||||
if (digit (*word) && (sscanf (word, "%d", &job) == 1))
|
||||
return (job - 1);
|
||||
|
||||
switch (*word)
|
||||
{
|
||||
case 0:
|
||||
case '%':
|
||||
case '+':
|
||||
return (current_job);
|
||||
|
||||
case '-':
|
||||
return (previous_job);
|
||||
|
||||
case '?': /* Substring search requested. */
|
||||
substring++;
|
||||
word++;
|
||||
goto find_string;
|
||||
|
||||
default:
|
||||
find_string:
|
||||
{
|
||||
register int i, wl = strlen (word);
|
||||
for (i = 0; i < job_slots; i++)
|
||||
{
|
||||
if (jobs[i])
|
||||
{
|
||||
register PROCESS *p = jobs[i]->pipe;
|
||||
do
|
||||
{
|
||||
if ((substring && strindex (p->command, word)) ||
|
||||
(strncmp (p->command, word, wl) == 0))
|
||||
if (job != NO_JOB)
|
||||
{
|
||||
builtin_error ("ambigious job spec: %s", word);
|
||||
return (DUP_JOB);
|
||||
}
|
||||
else
|
||||
job = i;
|
||||
|
||||
p = p->next;
|
||||
}
|
||||
while (p != jobs[i]->pipe);
|
||||
}
|
||||
}
|
||||
return (job);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
int parse_and_execute_level = 0;
|
||||
|
||||
/* How to force parse_and_execute () to clean up after itself. */
|
||||
void
|
||||
parse_and_execute_cleanup ()
|
||||
{
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
}
|
||||
|
||||
/* Parse and execute the commands in STRING. Returns whatever
|
||||
execute_command () returns. This frees STRING. INTERACT is
|
||||
the new value for `interactive' while the commands are being
|
||||
executed. A value of -1 means don't change it. */
|
||||
int
|
||||
parse_and_execute (string, from_file, interact)
|
||||
char *string;
|
||||
char *from_file;
|
||||
int interact;
|
||||
{
|
||||
int last_result = EXECUTION_SUCCESS;
|
||||
int code = 0, jump_to_top_level = 0;
|
||||
char *orig_string = string;
|
||||
|
||||
/* Unwind protect this invocation of parse_and_execute (). */
|
||||
begin_unwind_frame ("parse_and_execute_top");
|
||||
unwind_protect_int (parse_and_execute_level);
|
||||
unwind_protect_jmp_buf (top_level);
|
||||
unwind_protect_int (indirection_level);
|
||||
if (interact != -1 && interactive != interact)
|
||||
unwind_protect_int (interactive);
|
||||
|
||||
#if defined (HISTORY)
|
||||
if (interactive_shell)
|
||||
{
|
||||
unwind_protect_int (remember_on_history);
|
||||
# if defined (BANG_HISTORY)
|
||||
unwind_protect_int (history_expansion_inhibited);
|
||||
# endif /* BANG_HISTORY */
|
||||
}
|
||||
#endif /* HISTORY */
|
||||
|
||||
add_unwind_protect (pop_stream, (char *)NULL);
|
||||
if (orig_string)
|
||||
add_unwind_protect (xfree, orig_string);
|
||||
end_unwind_frame ();
|
||||
|
||||
parse_and_execute_level++;
|
||||
push_stream ();
|
||||
indirection_level++;
|
||||
if (interact != -1)
|
||||
interactive = interact;
|
||||
|
||||
#if defined (HISTORY)
|
||||
/* We don't remember text read by the shell this way on
|
||||
the history list, and we don't use !$ in shell scripts. */
|
||||
remember_on_history = 0;
|
||||
# if defined (BANG_HISTORY)
|
||||
history_expansion_inhibited = 1;
|
||||
# endif /* BANG_HISTORY */
|
||||
#endif /* HISTORY */
|
||||
|
||||
with_input_from_string (string, from_file);
|
||||
{
|
||||
COMMAND *command;
|
||||
|
||||
while (*(bash_input.location.string))
|
||||
{
|
||||
if (interrupt_state)
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Provide a location for functions which `longjmp (top_level)' to
|
||||
jump to. This prevents errors in substitution from restarting
|
||||
the reader loop directly, for example. */
|
||||
code = setjmp (top_level);
|
||||
|
||||
if (code)
|
||||
{
|
||||
jump_to_top_level = 0;
|
||||
switch (code)
|
||||
{
|
||||
case FORCE_EOF:
|
||||
case EXITPROG:
|
||||
run_unwind_frame ("pe_dispose");
|
||||
/* Remember to call longjmp (top_level) after the old
|
||||
value for it is restored. */
|
||||
jump_to_top_level = 1;
|
||||
goto out;
|
||||
|
||||
case DISCARD:
|
||||
dispose_command (command);
|
||||
run_unwind_frame ("pe_dispose");
|
||||
last_command_exit_value = 1;
|
||||
continue;
|
||||
|
||||
default:
|
||||
programming_error ("bad jump to top_level: %d", code);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parse_command () == 0)
|
||||
{
|
||||
if ((command = global_command) != (COMMAND *)NULL)
|
||||
{
|
||||
struct fd_bitmap *bitmap;
|
||||
|
||||
bitmap = new_fd_bitmap (FD_BITMAP_SIZE);
|
||||
begin_unwind_frame ("pe_dispose");
|
||||
add_unwind_protect (dispose_fd_bitmap, bitmap);
|
||||
|
||||
global_command = (COMMAND *)NULL;
|
||||
|
||||
#if defined (ONESHOT)
|
||||
if (startup_state == 2 && *bash_input.location.string == '\0' &&
|
||||
command->type == cm_simple && !command->redirects &&
|
||||
!command->value.Simple->redirects)
|
||||
{
|
||||
command->flags |= CMD_NO_FORK;
|
||||
command->value.Simple->flags |= CMD_NO_FORK;
|
||||
}
|
||||
#endif /* ONESHOT */
|
||||
|
||||
last_result = execute_command_internal
|
||||
(command, 0, NO_PIPE, NO_PIPE, bitmap);
|
||||
|
||||
dispose_command (command);
|
||||
run_unwind_frame ("pe_dispose");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
last_result = EXECUTION_FAILURE;
|
||||
|
||||
/* Since we are shell compatible, syntax errors in a script
|
||||
abort the execution of the script. Right? */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
run_unwind_frame ("parse_and_execute_top");
|
||||
|
||||
if (interrupt_state && parse_and_execute_level == 0)
|
||||
{
|
||||
/* An interrupt during non-interactive execution in an
|
||||
interactive shell (e.g. via $PROMPT_COMMAND) should
|
||||
not cause the shell to exit. */
|
||||
interactive = interactive_shell;
|
||||
throw_to_top_level ();
|
||||
}
|
||||
|
||||
if (jump_to_top_level)
|
||||
longjmp (top_level, code);
|
||||
|
||||
return (last_result);
|
||||
}
|
||||
|
||||
/* Return the address of the builtin named NAME.
|
||||
DISABLED_OKAY means find it even if the builtin is disabled. */
|
||||
static Function *
|
||||
builtin_address_internal (name, disabled_okay)
|
||||
char *name;
|
||||
int disabled_okay;
|
||||
{
|
||||
int hi, lo, mid, j;
|
||||
|
||||
hi = num_shell_builtins - 1;
|
||||
lo = 0;
|
||||
|
||||
while (lo <= hi)
|
||||
{
|
||||
mid = (lo + hi) / 2;
|
||||
|
||||
j = shell_builtins[mid].name[0] - name[0];
|
||||
|
||||
if (j == 0)
|
||||
j = strcmp (shell_builtins[mid].name, name);
|
||||
|
||||
if (j == 0)
|
||||
{
|
||||
/* It must have a function pointer. It must be enabled, or we
|
||||
must have explicitly allowed disabled functions to be found. */
|
||||
if (shell_builtins[mid].function &&
|
||||
((shell_builtins[mid].flags & BUILTIN_ENABLED) || disabled_okay))
|
||||
return (shell_builtins[mid].function);
|
||||
else
|
||||
return ((Function *)NULL);
|
||||
}
|
||||
if (j > 0)
|
||||
hi = mid - 1;
|
||||
else
|
||||
lo = mid + 1;
|
||||
}
|
||||
return ((Function *)NULL);
|
||||
}
|
||||
|
||||
/* Perform a binary search and return the address of the builtin function
|
||||
whose name is NAME. If the function couldn't be found, or the builtin
|
||||
is disabled or has no function associated with it, return NULL. */
|
||||
Function *
|
||||
find_shell_builtin (name)
|
||||
char *name;
|
||||
{
|
||||
return (builtin_address_internal (name, 0));
|
||||
}
|
||||
|
||||
/* Return the address of builtin with NAME, irregardless of its state of
|
||||
enableness. */
|
||||
Function *
|
||||
builtin_address (name)
|
||||
char *name;
|
||||
{
|
||||
return (builtin_address_internal (name, 1));
|
||||
}
|
||||
|
||||
static int
|
||||
shell_builtin_compare (sbp1, sbp2)
|
||||
struct builtin *sbp1, *sbp2;
|
||||
{
|
||||
int result;
|
||||
|
||||
if ((result = sbp1->name[0] - sbp2->name[0]) == 0)
|
||||
result = strcmp (sbp1->name, sbp2->name);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* Sort the table of shell builtins so that the binary search will work
|
||||
in find_shell_builtin. */
|
||||
void
|
||||
initialize_shell_builtins ()
|
||||
{
|
||||
qsort (shell_builtins, num_shell_builtins, sizeof (struct builtin),
|
||||
shell_builtin_compare);
|
||||
}
|
||||
|
||||
/* Return a new string which is the quoted version of STRING. This is used
|
||||
by alias and trap. */
|
||||
char *
|
||||
single_quote (string)
|
||||
char *string;
|
||||
{
|
||||
register int i, j, c;
|
||||
char *result;
|
||||
|
||||
result = (char *)xmalloc (3 + (3 * strlen (string)));
|
||||
|
||||
result[0] = '\'';
|
||||
|
||||
for (i = 0, j = 1; string && (c = string[i]); i++)
|
||||
{
|
||||
result[j++] = c;
|
||||
|
||||
if (c == '\'')
|
||||
{
|
||||
result[j++] = '\\'; /* insert escaped single quote */
|
||||
result[j++] = '\'';
|
||||
result[j++] = '\''; /* start new quoted string */
|
||||
}
|
||||
}
|
||||
|
||||
result[j++] = '\'';
|
||||
result[j] = '\0';
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
char *
|
||||
double_quote (string)
|
||||
char *string;
|
||||
{
|
||||
register int i, j, c;
|
||||
char *result;
|
||||
|
||||
result = (char *)xmalloc (3 + (3 * strlen (string)));
|
||||
|
||||
result[0] = '"';
|
||||
|
||||
for (i = 0, j = 1; string && (c = string[i]); i++)
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
case '"':
|
||||
case '$':
|
||||
case '`':
|
||||
case '\\':
|
||||
result[j++] = '\\';
|
||||
default:
|
||||
result[j++] = c;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
result[j++] = '"';
|
||||
result[j] = '\0';
|
||||
|
||||
return (result);
|
||||
}
|
69
builtins/common.h
Normal file
69
builtins/common.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
/* common.h -- extern declarations for functions defined in common.c. */
|
||||
|
||||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#if !defined (__COMMON_H)
|
||||
# define __COMMON_H
|
||||
|
||||
#define ISOPTION(s, c) (s[0] == '-' && !s[2] && s[1] == c)
|
||||
|
||||
extern void builtin_error ();
|
||||
extern void bad_option ();
|
||||
|
||||
extern int get_numeric_arg ();
|
||||
|
||||
extern void remember_args ();
|
||||
|
||||
extern void no_args ();
|
||||
|
||||
extern int read_octal ();
|
||||
|
||||
extern char *find_hashed_filename ();
|
||||
extern void remove_hashed_filename ();
|
||||
extern void remember_filename ();
|
||||
|
||||
extern void push_context (), pop_context ();
|
||||
extern void push_dollar_vars (), pop_dollar_vars ();
|
||||
extern void dispose_saved_dollar_vars ();
|
||||
extern int dollar_vars_changed ();
|
||||
extern void set_dollar_vars_unchanged (), set_dollar_vars_changed ();
|
||||
|
||||
/* Keeps track of the current working directory. */
|
||||
extern char *the_current_working_directory;
|
||||
extern char *get_working_directory ();
|
||||
extern void set_working_directory ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int get_job_spec ();
|
||||
#endif
|
||||
|
||||
extern int parse_and_execute ();
|
||||
extern void parse_and_execute_cleanup ();
|
||||
|
||||
extern void initialize_shell_builtins ();
|
||||
|
||||
/* It's OK to declare a function as returning a Function * without
|
||||
providing a definition of what a `Function' is. */
|
||||
extern Function *find_shell_builtin ();
|
||||
extern Function *builtin_address ();
|
||||
|
||||
extern char *single_quote ();
|
||||
extern char *double_quote ();
|
||||
|
||||
#endif /* !__COMMON_H */
|
290
builtins/declare.def
Normal file
290
builtins/declare.def
Normal file
|
@ -0,0 +1,290 @@
|
|||
This file is declare.def, from which is created declare.c.
|
||||
It implements the builtins "declare" and "local" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES declare.c
|
||||
|
||||
$BUILTIN declare
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC declare [-[frxi]] name[=value] ...
|
||||
Declare variables and/or give them attributes. If no NAMEs are
|
||||
given, then display the values of variables instead.
|
||||
|
||||
The flags are:
|
||||
|
||||
-f to select from among function names only,
|
||||
-r to make NAMEs readonly,
|
||||
-x to make NAMEs export,
|
||||
-i to make NAMEs have the `integer' attribute set.
|
||||
|
||||
Variables with the integer attribute have arithmetic evaluation (see
|
||||
`let') done when the variable is assigned to.
|
||||
|
||||
Using `+' instead of `-' turns off the given attribute instead. When
|
||||
used in a function, makes NAMEs local, as with the `local' command.
|
||||
$END
|
||||
|
||||
$BUILTIN typeset
|
||||
$FUNCTION declare_builtin
|
||||
$SHORT_DOC typeset [-[frxi]] name[=value] ...
|
||||
Obsolete. See `declare'.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
extern int variable_context, array_needs_making;
|
||||
|
||||
static int declare_internal ();
|
||||
|
||||
/* Declare or change variable attributes. */
|
||||
int
|
||||
declare_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (declare_internal (list, 0));
|
||||
}
|
||||
|
||||
$BUILTIN local
|
||||
$FUNCTION local_builtin
|
||||
$SHORT_DOC local name[=value] ...
|
||||
Create a local variable called NAME, and give it VALUE. LOCAL
|
||||
can only be used within a function; it makes the variable NAME
|
||||
have a visible scope restricted to that function and its children.
|
||||
$END
|
||||
int
|
||||
local_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
if (variable_context)
|
||||
return (declare_internal (list, 1));
|
||||
else
|
||||
{
|
||||
builtin_error ("Can only be used in a function");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
/* The workhorse function. */
|
||||
static int
|
||||
declare_internal (list, local_var)
|
||||
register WORD_LIST *list;
|
||||
int local_var;
|
||||
{
|
||||
int flags_on = 0, flags_off = 0;
|
||||
int any_failed = 0;
|
||||
|
||||
while (list)
|
||||
{
|
||||
register char *t = list->word->word;
|
||||
int *flags;
|
||||
|
||||
if (t[0] == '-' && t[1] == '-' && t[2] == '\0')
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
|
||||
if (*t != '+' && *t != '-')
|
||||
break;
|
||||
|
||||
if (*t == '+')
|
||||
flags = &flags_off;
|
||||
else
|
||||
flags = &flags_on;
|
||||
|
||||
t++;
|
||||
|
||||
while (*t)
|
||||
{
|
||||
if (*t == 'f')
|
||||
*flags |= att_function, t++;
|
||||
else if (*t == 'x')
|
||||
*flags |= att_exported, t++, array_needs_making = 1;
|
||||
else if (*t == 'r')
|
||||
*flags |= att_readonly, t++;
|
||||
else if (*t == 'i')
|
||||
*flags |= att_integer, t++;
|
||||
else
|
||||
{
|
||||
builtin_error ("unknown option: `-%c'", *t);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* If there are no more arguments left, then we just want to show
|
||||
some variables. */
|
||||
if (!list)
|
||||
{
|
||||
/* Show local variables defined at this context level if this is
|
||||
the `local' builtin. */
|
||||
if (local_var)
|
||||
{
|
||||
register SHELL_VAR **vlist;
|
||||
register int i;
|
||||
|
||||
vlist = map_over (variable_in_context, shell_variables);
|
||||
|
||||
if (vlist)
|
||||
{
|
||||
for (i = 0; vlist[i]; i++)
|
||||
print_assignment (vlist[i]);
|
||||
|
||||
free (vlist);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!flags_on)
|
||||
set_builtin ((WORD_LIST *)NULL);
|
||||
else
|
||||
set_or_show_attributes ((WORD_LIST *)NULL, flags_on);
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#define NEXT_VARIABLE() free (name); list = list->next; continue
|
||||
|
||||
/* There are arguments left, so we are making variables. */
|
||||
while (list)
|
||||
{
|
||||
char *value, *name = savestring (list->word->word);
|
||||
int offset = assignment (name);
|
||||
|
||||
if (offset)
|
||||
{
|
||||
name[offset] = '\0';
|
||||
value = name + offset + 1;
|
||||
}
|
||||
else
|
||||
value = "";
|
||||
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
builtin_error ("%s: not a legal variable name", name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
/* If VARIABLE_CONTEXT has a non-zero value, then we are executing
|
||||
inside of a function. This means we should make local variables,
|
||||
not global ones. */
|
||||
|
||||
if (variable_context)
|
||||
make_local_variable (name);
|
||||
|
||||
/* If we are declaring a function, then complain about it in some way.
|
||||
We don't let people make functions by saying `typeset -f foo=bar'. */
|
||||
|
||||
/* There should be a way, however, to let people look at a particular
|
||||
function definition by saying `typeset -f foo'. */
|
||||
|
||||
if (flags_on & att_function)
|
||||
{
|
||||
if (offset)
|
||||
{
|
||||
builtin_error ("Can't use `-f' to make functions");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR *find_function (), *funvar;
|
||||
|
||||
funvar = find_function (name);
|
||||
|
||||
if (funvar)
|
||||
{
|
||||
if (readonly_p (funvar) && (flags_off & att_readonly))
|
||||
{
|
||||
builtin_error ("%s: readonly function", name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
if (flags_on == att_function && flags_off == 0)
|
||||
{
|
||||
char *result = named_function_string
|
||||
(name, (COMMAND *)function_cell (funvar), 1);
|
||||
printf ("%s\n", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
funvar->attributes |= flags_on;
|
||||
funvar->attributes &= ~flags_off;
|
||||
}
|
||||
}
|
||||
else
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
|
||||
var = find_variable (name);
|
||||
|
||||
if (!var)
|
||||
var = bind_variable (name, "");
|
||||
|
||||
if (readonly_p (var) && (flags_off & att_readonly))
|
||||
{
|
||||
builtin_error ("%s: readonly variable", name);
|
||||
any_failed++;
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
|
||||
var->attributes |= flags_on;
|
||||
var->attributes &= ~flags_off;
|
||||
|
||||
if (offset)
|
||||
{
|
||||
free (var->value);
|
||||
if (integer_p (var))
|
||||
{
|
||||
long val, evalexp ();
|
||||
char *itos ();
|
||||
|
||||
val = evalexp (value);
|
||||
var->value = itos ((int)val);
|
||||
}
|
||||
else
|
||||
var->value = savestring (value);
|
||||
}
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (name);
|
||||
|
||||
NEXT_VARIABLE ();
|
||||
}
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
168
builtins/echo.def
Normal file
168
builtins/echo.def
Normal file
|
@ -0,0 +1,168 @@
|
|||
This file is echo.def, from which is created echo.c.
|
||||
It implements the builtin "echo" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES echo.c
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
|
||||
$BUILTIN echo
|
||||
$FUNCTION echo_builtin
|
||||
$DEPENDS_ON V9_ECHO
|
||||
$SHORT_DOC echo [-neE] [arg ...]
|
||||
Output the ARGs. If -n is specified, the trailing newline is
|
||||
suppressed. If the -e option is given, interpretation of the
|
||||
following backslash-escaped characters is turned on:
|
||||
\a alert (bell)
|
||||
\b backspace
|
||||
\c suppress trailing newline
|
||||
\f form feed
|
||||
\n new line
|
||||
\r carriage return
|
||||
\t horizontal tab
|
||||
\v vertical tab
|
||||
\\ backslash
|
||||
\num the character whose ASCII code is NUM (octal).
|
||||
|
||||
You can explicitly turn off the interpretation of the above characters
|
||||
with the -E option.
|
||||
$END
|
||||
|
||||
$BUILTIN echo
|
||||
$FUNCTION echo_builtin
|
||||
$DEPENDS_ON !V9_ECHO
|
||||
$SHORT_DOC echo [-n] [arg ...]
|
||||
Output the ARGs. If -n is specified, the trailing newline is suppressed.
|
||||
$END
|
||||
|
||||
#if defined (V9_ECHO)
|
||||
# define VALID_ECHO_OPTIONS "neE"
|
||||
#else /* !V9_ECHO */
|
||||
# define VALID_ECHO_OPTIONS "n"
|
||||
#endif /* !V9_ECHO */
|
||||
|
||||
/* Print the words in LIST to standard output. If the first word is
|
||||
`-n', then don't print a trailing newline. We also support the
|
||||
echo syntax from Version 9 unix systems. */
|
||||
echo_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int display_return = 1, do_v9 = 0;
|
||||
|
||||
#if defined (DEFAULT_ECHO_TO_USG)
|
||||
/* System V machines already have a /bin/sh with a v9 behaviour. We
|
||||
give Bash the identical behaviour for these machines so that the
|
||||
existing system shells won't barf. */
|
||||
do_v9 = 1;
|
||||
#endif /* DEFAULT_ECHO_TO_USG */
|
||||
|
||||
while (list && list->word->word[0] == '-')
|
||||
{
|
||||
register char *temp;
|
||||
register int i;
|
||||
|
||||
/* If it appears that we are handling options, then make sure that
|
||||
all of the options specified are actually valid. Otherwise, the
|
||||
string should just be echoed. */
|
||||
temp = &(list->word->word[1]);
|
||||
|
||||
for (i = 0; temp[i]; i++)
|
||||
{
|
||||
if (strchr (VALID_ECHO_OPTIONS, temp[i]) == 0)
|
||||
goto just_echo;
|
||||
}
|
||||
|
||||
if (!*temp)
|
||||
goto just_echo;
|
||||
|
||||
/* All of the options in TEMP are valid options to ECHO.
|
||||
Handle them. */
|
||||
while (*temp)
|
||||
{
|
||||
if (*temp == 'n')
|
||||
display_return = 0;
|
||||
#if defined (V9_ECHO)
|
||||
else if (*temp == 'e')
|
||||
do_v9 = 1;
|
||||
else if (*temp == 'E')
|
||||
do_v9 = 0;
|
||||
#endif /* V9_ECHO */
|
||||
else
|
||||
goto just_echo;
|
||||
|
||||
temp++;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
just_echo:
|
||||
|
||||
if (list)
|
||||
{
|
||||
#if defined (V9_ECHO)
|
||||
if (do_v9)
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
register char *s = list->word->word;
|
||||
register int c;
|
||||
|
||||
while (c = *s++)
|
||||
{
|
||||
if (c == '\\' && *s)
|
||||
{
|
||||
switch (c = *s++)
|
||||
{
|
||||
case 'a': c = '\007'; break;
|
||||
case 'b': c = '\b'; break;
|
||||
case 'c': display_return = 0; continue;
|
||||
case 'f': c = '\f'; break;
|
||||
case 'n': c = '\n'; break;
|
||||
case 'r': c = '\r'; break;
|
||||
case 't': c = '\t'; break;
|
||||
case 'v': c = (int) 0x0B; break;
|
||||
case '0': case '1': case '2': case '3':
|
||||
case '4': case '5': case '6': case '7':
|
||||
c -= '0';
|
||||
if (*s >= '0' && *s <= '7')
|
||||
c = c * 8 + (*s++ - '0');
|
||||
if (*s >= '0' && *s <= '7')
|
||||
c = c * 8 + (*s++ - '0');
|
||||
break;
|
||||
case '\\': break;
|
||||
default: putchar ('\\'); break;
|
||||
}
|
||||
}
|
||||
putchar(c);
|
||||
}
|
||||
list = list->next;
|
||||
if (list)
|
||||
putchar(' ');
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif /* V9_ECHO */
|
||||
print_word_list (list, " ");
|
||||
}
|
||||
if (display_return)
|
||||
printf ("\n");
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
156
builtins/enable.def
Normal file
156
builtins/enable.def
Normal file
|
@ -0,0 +1,156 @@
|
|||
This file is enable.def, from which is created enable.c.
|
||||
It implements the builtin "enable" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES enable.c
|
||||
|
||||
$BUILTIN enable
|
||||
$FUNCTION enable_builtin
|
||||
$SHORT_DOC enable [-n] [name ...]
|
||||
Enable and disable builtin shell commands. This allows
|
||||
you to use a disk command which has the same name as a shell
|
||||
builtin. If -n is used, the NAMEs become disabled. Otherwise
|
||||
NAMEs are enabled. For example, to use the `test' found on your
|
||||
path instead of the shell builtin version, you type `enable -n test'.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../builtins.h"
|
||||
#include "common.h"
|
||||
|
||||
#define ENABLED 1
|
||||
#define DISABLED 2
|
||||
|
||||
static int enable_shell_command ();
|
||||
static void list_some_builtins ();
|
||||
|
||||
/* Enable/disable shell commands present in LIST. If list is not specified,
|
||||
then print out a list of shell commands showing which are enabled and
|
||||
which are disabled. */
|
||||
enable_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result = 0, any_failed = 0;
|
||||
int disable_p, all_p;
|
||||
|
||||
disable_p = all_p = 0;
|
||||
|
||||
while (list && list->word->word && list->word->word[0] == '-')
|
||||
{
|
||||
char *arg = list->word->word;
|
||||
|
||||
list = list->next;
|
||||
|
||||
if (ISOPTION (arg, 'n'))
|
||||
disable_p = 1;
|
||||
else if (arg[1] == 'a' && (arg[2] == 0 || strcmp (arg + 2, "ll") == 0))
|
||||
all_p = 1;
|
||||
else if (ISOPTION (arg, '-'))
|
||||
break;
|
||||
else
|
||||
{
|
||||
bad_option (arg);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!list)
|
||||
{
|
||||
int filter;
|
||||
|
||||
if (all_p)
|
||||
filter = ENABLED | DISABLED;
|
||||
else if (disable_p)
|
||||
filter = DISABLED;
|
||||
else
|
||||
filter = ENABLED;
|
||||
|
||||
list_some_builtins (filter);
|
||||
}
|
||||
else
|
||||
{
|
||||
while (list)
|
||||
{
|
||||
result = enable_shell_command (list->word->word, disable_p);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
builtin_error ("%s: not a shell builtin", list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* List some builtins.
|
||||
FILTER is a mask with two slots: ENABLED and DISABLED. */
|
||||
static void
|
||||
list_some_builtins (filter)
|
||||
int filter;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < num_shell_builtins; i++)
|
||||
{
|
||||
if (!shell_builtins[i].function)
|
||||
continue;
|
||||
|
||||
if ((filter & ENABLED) &&
|
||||
(shell_builtins[i].flags & BUILTIN_ENABLED))
|
||||
{
|
||||
printf ("enable %s\n", shell_builtins[i].name);
|
||||
}
|
||||
else if ((filter & DISABLED) &&
|
||||
((shell_builtins[i].flags & BUILTIN_ENABLED) == 0))
|
||||
{
|
||||
printf ("enable -n %s\n", shell_builtins[i].name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable the shell command NAME. If DISABLE_P is non-zero, then
|
||||
disable NAME instead. */
|
||||
static int
|
||||
enable_shell_command (name, disable_p)
|
||||
char *name;
|
||||
int disable_p;
|
||||
{
|
||||
register int i;
|
||||
int found = 0;
|
||||
|
||||
for (i = 0; i < num_shell_builtins; i++)
|
||||
{
|
||||
if (!shell_builtins[i].function)
|
||||
continue;
|
||||
|
||||
if (STREQ (name, shell_builtins[i].name))
|
||||
{
|
||||
found++;
|
||||
|
||||
if (disable_p)
|
||||
shell_builtins[i].flags &= ~BUILTIN_ENABLED;
|
||||
else
|
||||
shell_builtins[i].flags |= BUILTIN_ENABLED;
|
||||
}
|
||||
}
|
||||
return (found);
|
||||
}
|
45
builtins/eval.def
Normal file
45
builtins/eval.def
Normal file
|
@ -0,0 +1,45 @@
|
|||
This file is eval.def, from which is created eval.c.
|
||||
It implements the builtin "eval" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES eval.c
|
||||
|
||||
$BUILTIN eval
|
||||
$FUNCTION eval_builtin
|
||||
$SHORT_DOC eval [arg ...]
|
||||
Read ARGs as input to the shell and execute the resulting command(s).
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
/* Parse the string that these words make, and execute the command found. */
|
||||
int
|
||||
eval_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result;
|
||||
|
||||
/* Note that parse_and_execute () frees the string it is passed. */
|
||||
if (list)
|
||||
result = parse_and_execute (string_list (list), "eval", -1);
|
||||
else
|
||||
result = EXECUTION_SUCCESS;
|
||||
return (result);
|
||||
}
|
163
builtins/exec.def
Normal file
163
builtins/exec.def
Normal file
|
@ -0,0 +1,163 @@
|
|||
This file is exec.def, from which is created exec.c.
|
||||
It implements the builtin "exec" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES exec.c
|
||||
|
||||
$BUILTIN exec
|
||||
$FUNCTION exec_builtin
|
||||
$SHORT_DOC exec [ [-] file [redirection ...]]
|
||||
Exec FILE, replacing this shell with the specified program.
|
||||
If FILE is not specified, the redirections take effect in this
|
||||
shell. If the first argument is `-', then place a dash in the
|
||||
zeroth arg passed to FILE. If the file cannot be exec'ed and
|
||||
the shell is not interactive, then the shell exits, unless the
|
||||
shell variable "no_exit_on_failed_exec" exists.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
#include <sys/types.h>
|
||||
#include "../posixstat.h"
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../execute_cmd.h"
|
||||
#include "common.h"
|
||||
#include "../flags.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
extern int interactive, subshell_environment;
|
||||
extern REDIRECT *redirection_undo_list;
|
||||
|
||||
int
|
||||
exec_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int exit_value = EXECUTION_FAILURE;
|
||||
|
||||
maybe_make_export_env ();
|
||||
|
||||
/* First, let the redirections remain. */
|
||||
dispose_redirects (redirection_undo_list);
|
||||
redirection_undo_list = (REDIRECT *)NULL;
|
||||
|
||||
if (!list)
|
||||
return (EXECUTION_SUCCESS);
|
||||
else
|
||||
{
|
||||
/* Otherwise, execve the new command with args. */
|
||||
char *command, **args;
|
||||
int dash_name = 0;
|
||||
|
||||
if (list->word->word[0] == '-' && !list->word->word[1])
|
||||
{
|
||||
/* The user would like to exec this command as if it was a
|
||||
login command. Do so. */
|
||||
list = list->next;
|
||||
dash_name++;
|
||||
}
|
||||
|
||||
if (!list)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
#if defined (RESTRICTED_SHELL)
|
||||
if (restricted)
|
||||
{
|
||||
builtin_error ("restricted");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* RESTRICTED_SHELL */
|
||||
|
||||
args = make_word_array (list);
|
||||
|
||||
/* A command with a slash anywhere in its name is not looked up in
|
||||
the search path. */
|
||||
if (absolute_program (args[0]))
|
||||
command = args[0];
|
||||
else
|
||||
command = find_user_command (args[0]);
|
||||
if (!command)
|
||||
{
|
||||
builtin_error ("%s: not found", args[0]);
|
||||
exit_value = EX_NOTFOUND; /* As per Posix.2, 3.14.6 */
|
||||
goto failed_exec;
|
||||
}
|
||||
|
||||
command = full_pathname (command);
|
||||
/* If the user wants this to look like a login shell, then
|
||||
prepend a `-' onto the first argument (argv[0]). */
|
||||
if (dash_name)
|
||||
{
|
||||
char *new_name = xmalloc (2 + strlen (args[0]));
|
||||
new_name[0] = '-';
|
||||
strcpy (new_name + 1, args[0]);
|
||||
free (args[0]);
|
||||
args[0] = new_name;
|
||||
}
|
||||
|
||||
/* Decrement SHLVL by 1 so a new shell started here has the same value,
|
||||
preserving the appearance. After we do that, we need to change the
|
||||
exported environment to include the new value. */
|
||||
adjust_shell_level (-1);
|
||||
maybe_make_export_env ();
|
||||
|
||||
#if defined (HISTORY)
|
||||
maybe_save_shell_history ();
|
||||
#endif /* HISTORY */
|
||||
restore_original_signals ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
if (subshell_environment == 0)
|
||||
end_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
shell_execve (command, args, export_env);
|
||||
|
||||
adjust_shell_level (1);
|
||||
|
||||
if (!executable_file (command))
|
||||
{
|
||||
builtin_error ("%s: cannot execute: %s", command, strerror (errno));
|
||||
exit_value = EX_NOEXEC; /* As per Posix.2, 3.14.6 */
|
||||
}
|
||||
else
|
||||
file_error (command);
|
||||
|
||||
failed_exec:
|
||||
if (command)
|
||||
free (command);
|
||||
|
||||
if (subshell_environment ||
|
||||
(!interactive && !find_variable ("no_exit_on_failed_exec")))
|
||||
exit (exit_value);
|
||||
|
||||
initialize_traps ();
|
||||
reinitialize_signals ();
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
restart_job_control ();
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
return (exit_value);
|
||||
}
|
||||
}
|
129
builtins/exit.def
Normal file
129
builtins/exit.def
Normal file
|
@ -0,0 +1,129 @@
|
|||
This file is exit.def, from which is created exit.c.
|
||||
It implements the builtins "exit" and "logout" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES exit.c
|
||||
|
||||
$BUILTIN exit
|
||||
$FUNCTION exit_builtin
|
||||
$SHORT_DOC exit [n]
|
||||
Exit the shell with a status of N. If N is omitted, the exit status
|
||||
is that of the last command executed.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
|
||||
#include "builtext.h" /* for jobs_builtin */
|
||||
|
||||
extern int interactive, login_shell;
|
||||
extern int last_command_exit_value;
|
||||
|
||||
static int exit_or_logout ();
|
||||
static int sourced_logout = 0;
|
||||
|
||||
int
|
||||
exit_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (interactive)
|
||||
{
|
||||
fprintf (stderr, login_shell ? "logout\n" : "exit\n");
|
||||
fflush (stderr);
|
||||
}
|
||||
|
||||
return (exit_or_logout (list));
|
||||
}
|
||||
|
||||
$BUILTIN logout
|
||||
$FUNCTION logout_builtin
|
||||
$SHORT_DOC logout
|
||||
Logout of a login shell.
|
||||
$END
|
||||
|
||||
/* How to logout. */
|
||||
int
|
||||
logout_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (!login_shell && interactive)
|
||||
{
|
||||
builtin_error ("Not login shell: use `exit'");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
return (exit_or_logout (list));
|
||||
}
|
||||
|
||||
/* Clean up work for exiting or logging out. */
|
||||
Function *last_shell_builtin = (Function *)NULL;
|
||||
Function *this_shell_builtin = (Function *)NULL;
|
||||
|
||||
static int
|
||||
exit_or_logout (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int exit_value;
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
int exit_immediate_okay;
|
||||
|
||||
exit_immediate_okay = (!interactive ||
|
||||
last_shell_builtin == exit_builtin ||
|
||||
last_shell_builtin == logout_builtin ||
|
||||
last_shell_builtin == jobs_builtin);
|
||||
|
||||
/* Check for stopped jobs if the user wants to. */
|
||||
if (!exit_immediate_okay)
|
||||
{
|
||||
register int i;
|
||||
for (i = 0; i < job_slots; i++)
|
||||
if (jobs[i] && (jobs[i]->state == JSTOPPED))
|
||||
{
|
||||
fprintf (stderr, "There are stopped jobs.\n");
|
||||
|
||||
/* This is NOT superfluous because EOF can get here without
|
||||
going through the command parser. Set both last and this
|
||||
so that either `exit', `logout', or ^D will work to exit
|
||||
immediately if nothing intervenes. */
|
||||
this_shell_builtin = last_shell_builtin = exit_builtin;
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
/* Get return value if present. This means that you can type
|
||||
`logout 5' to a shell, and it returns 5. */
|
||||
if (list)
|
||||
exit_value = get_numeric_arg (list);
|
||||
else
|
||||
exit_value = last_command_exit_value;
|
||||
|
||||
/* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
|
||||
if (login_shell && sourced_logout++ == 0)
|
||||
maybe_execute_file ("~/.bash_logout", 1);
|
||||
|
||||
last_command_exit_value = exit_value;
|
||||
|
||||
/* Exit the program. */
|
||||
longjmp (top_level, EXITPROG);
|
||||
}
|
691
builtins/fc.def
Normal file
691
builtins/fc.def
Normal file
|
@ -0,0 +1,691 @@
|
|||
This file is fc.def, from which is created fc.c.
|
||||
It implements the builtin "fc" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES fc.c
|
||||
|
||||
$BUILTIN fc
|
||||
$FUNCTION fc_builtin
|
||||
$DEPENDS_ON HISTORY
|
||||
$SHORT_DOC fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [cmd]
|
||||
|
||||
FIRST and LAST can be numbers specifying the range, or FIRST can be a
|
||||
string, which means the most recent command beginning with that
|
||||
string.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then the editor which corresponds to the current readline editing
|
||||
mode, then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
With the `fc -s [pat=rep ...] [command]' format, the command is
|
||||
re-executed after the substitution OLD=NEW is performed.
|
||||
|
||||
A useful alias to use with this is r='fc -s', so that typing `r cc'
|
||||
runs the last command beginning with `cc' and typing `r' re-executes
|
||||
the last command.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../bashansi.h"
|
||||
#include "../shell.h"
|
||||
#if defined (HISTORY)
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/file.h>
|
||||
#include <errno.h>
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "../maxpath.h"
|
||||
#include "../bashhist.h"
|
||||
#include <readline/history.h>
|
||||
#include "bashgetopt.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
extern int echo_input_at_read;
|
||||
|
||||
extern int unlink ();
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* The K*rn shell style fc command (Fix Command) */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* fc builtin command (fix command) for Bash for those who
|
||||
like K*rn-style history better than csh-style.
|
||||
|
||||
fc [-e ename] [-nlr] [first] [last]
|
||||
|
||||
FIRST and LAST can be numbers specifying the range, or FIRST can be
|
||||
a string, which means the most recent command beginning with that
|
||||
string.
|
||||
|
||||
-e ENAME selects which editor to use. Default is FCEDIT, then EDITOR,
|
||||
then the editor which corresponds to the current readline editing
|
||||
mode, then vi.
|
||||
|
||||
-l means list lines instead of editing.
|
||||
-n means no line numbers listed.
|
||||
-r means reverse the order of the lines (making it newest listed first).
|
||||
|
||||
fc -e - [pat=rep ...] [command]
|
||||
fc -s [pat=rep ...] [command]
|
||||
|
||||
Equivalent to !command:sg/pat/rep execpt there can be multiple PAT=REP's.
|
||||
*/
|
||||
|
||||
static char *fc_dosubs (), *fc_replace (), *fc_gethist (), *fc_readline ();
|
||||
static int fc_gethnum ();
|
||||
static void fc_replhist (), fc_addhist ();
|
||||
|
||||
/* Data structure describing a list of global replacements to perform. */
|
||||
typedef struct repl {
|
||||
struct repl *next;
|
||||
char *pat;
|
||||
char *rep;
|
||||
} REPL;
|
||||
|
||||
#define USAGE "usage: fc [-e ename] [-nlr] [first] [last] or fc -s [pat=rep] [command]"
|
||||
|
||||
/* Accessors for HIST_ENTRY lists that are called HLIST. */
|
||||
#define histline(i) (hlist[(i)]->line)
|
||||
#define histdata(i) (hlist[(i)]->data)
|
||||
|
||||
#define FREE_RLIST() \
|
||||
do { \
|
||||
for (rl = rlist; rl; ) { \
|
||||
REPL *r; \
|
||||
r = rl->next; \
|
||||
if (rl->pat) \
|
||||
free (rl->pat); \
|
||||
if (rl->rep) \
|
||||
free (rl->rep); \
|
||||
free (rl); \
|
||||
rl = r; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* String to execute on a file that we want to edit. */
|
||||
#define FC_EDIT_COMMAND "${FCEDIT:-${EDITOR:-vi}}"
|
||||
|
||||
int
|
||||
fc_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
register char *sep;
|
||||
int numbering, reverse, listing, execute;
|
||||
int histbeg, histend, last_hist, retval, first, opt;
|
||||
FILE *stream;
|
||||
REPL *rlist = (REPL *) NULL, *rl;
|
||||
char *ename = NULL, *command, *newcom, *line;
|
||||
HIST_ENTRY **hlist;
|
||||
char fn[MAXPATHLEN];
|
||||
|
||||
numbering = 1;
|
||||
reverse = listing = execute = 0;
|
||||
|
||||
/* Parse out the options and set which of the two forms we're in. */
|
||||
|
||||
while (list && *list->word->word == '-')
|
||||
{
|
||||
register char *s = &((list->word->word)[1]);
|
||||
|
||||
if (!isletter (*s))
|
||||
break;
|
||||
|
||||
while (opt = *s++)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
numbering = 0;
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
listing = 1;
|
||||
break;
|
||||
|
||||
case 'r':
|
||||
reverse = 1;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
execute = 1;
|
||||
break;
|
||||
|
||||
case 'e':
|
||||
list = list->next;
|
||||
if (list == NULL)
|
||||
{
|
||||
builtin_error (USAGE);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
ename = list->word->word;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_error (USAGE);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (ename && (*ename == '-') && (ename[1] == '\0'))
|
||||
execute = 1;
|
||||
|
||||
/* The "execute" form of the command (re-run, with possible string
|
||||
substitutions). */
|
||||
if (execute)
|
||||
{
|
||||
while (list && ((sep = (char *)strchr (list->word->word, '=')) != NULL))
|
||||
{
|
||||
*sep++ = '\0';
|
||||
rl = (REPL *)xmalloc (sizeof (REPL));
|
||||
rl->next = (REPL *)NULL;
|
||||
rl->pat = savestring (list->word->word);
|
||||
rl->rep = savestring (sep);
|
||||
|
||||
if (rlist == NULL)
|
||||
rlist = rl;
|
||||
else
|
||||
{
|
||||
rl->next = rlist;
|
||||
rlist = rl;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* If we have a list of substitutions to do, then reverse it
|
||||
to get the replacements in the proper order. */
|
||||
|
||||
if (rlist && rlist->next)
|
||||
rlist = (REPL *) reverse_list ((GENERIC_LIST *) rlist);
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
/* If we still have something in list, it is a command spec.
|
||||
Otherwise, we use the most recent command in time. */
|
||||
if (list)
|
||||
command = fc_gethist (list->word->word, hlist);
|
||||
else
|
||||
command = fc_gethist ((char *) NULL, hlist);
|
||||
|
||||
if (command == NULL)
|
||||
{
|
||||
builtin_error ("no command found");
|
||||
if (rlist)
|
||||
FREE_RLIST ();
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (rlist)
|
||||
{
|
||||
newcom = fc_dosubs (command, rlist);
|
||||
free (command);
|
||||
FREE_RLIST ();
|
||||
command = newcom;
|
||||
}
|
||||
|
||||
printf ("%s\n", command);
|
||||
fc_replhist (command); /* replace `fc -e -' with command */
|
||||
return (parse_and_execute (command, "fc", -1));
|
||||
}
|
||||
|
||||
/* This is the second form of the command (the list-or-edit-and-rerun
|
||||
form). */
|
||||
hlist = history_list ();
|
||||
if (hlist == 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. */
|
||||
|
||||
last_hist = i - 2;
|
||||
|
||||
if (list)
|
||||
{
|
||||
histbeg = fc_gethnum (list->word->word, hlist);
|
||||
list = list->next;
|
||||
|
||||
if (list)
|
||||
histend = fc_gethnum (list->word->word, hlist);
|
||||
else
|
||||
{
|
||||
if (listing)
|
||||
histend = last_hist;
|
||||
else
|
||||
histend = histbeg;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The default for listing is the last 16 history items. */
|
||||
if (listing)
|
||||
{
|
||||
histend = last_hist;
|
||||
histbeg = histend - 16;
|
||||
if (histbeg < 0)
|
||||
histbeg = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For editing, it is the last history command. */
|
||||
histbeg = histend = last_hist;
|
||||
}
|
||||
}
|
||||
|
||||
/* We print error messages for line specifications out of range. */
|
||||
if ((histbeg < 0) || (histend < 0) ||
|
||||
(histbeg > last_hist) || (histend > last_hist))
|
||||
{
|
||||
builtin_error ("history specification out of range");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (histend < histbeg)
|
||||
{
|
||||
int t = histend;
|
||||
|
||||
histend = histbeg;
|
||||
histbeg = t;
|
||||
reverse = 1;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
stream = stdout;
|
||||
else
|
||||
{
|
||||
numbering = 0;
|
||||
sprintf (fn, "/tmp/bash%d", (int)time ((long *) 0) + (int)getpid ());
|
||||
|
||||
stream = fopen (fn, "w");
|
||||
|
||||
if (!stream)
|
||||
{
|
||||
builtin_error ("cannot open temp file %s", fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
if (!reverse)
|
||||
{
|
||||
for (i = histbeg; i <= histend; i++)
|
||||
{
|
||||
QUIT;
|
||||
if (numbering)
|
||||
fprintf (stream, "%d", i + history_base);
|
||||
if (listing)
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
fprintf (stream, "%s\n", histline (i));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (i = histend; i >= histbeg; i--)
|
||||
{
|
||||
QUIT;
|
||||
if (numbering)
|
||||
fprintf (stream, "%d", i + history_base);
|
||||
if (listing)
|
||||
fprintf (stream, "\t%c", histdata (i) ? '*' : ' ');
|
||||
fprintf (stream, "%s\n", histline (i));
|
||||
}
|
||||
}
|
||||
|
||||
if (listing)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
fclose (stream);
|
||||
|
||||
/* Now edit the file of commands. */
|
||||
if (ename)
|
||||
{
|
||||
command = (char *)xmalloc (strlen (ename) + strlen (fn) + 2);
|
||||
sprintf (command, "%s %s", ename, fn);
|
||||
}
|
||||
else
|
||||
{
|
||||
command = (char *)xmalloc (3 + strlen (FC_EDIT_COMMAND) + strlen (fn));
|
||||
sprintf (command, "%s %s", FC_EDIT_COMMAND, fn);
|
||||
}
|
||||
parse_and_execute (command, "fc", -1);
|
||||
|
||||
/* Now reopen the file and execute the edited commands. */
|
||||
|
||||
stream = fopen (fn, "r");
|
||||
|
||||
if (stream == NULL)
|
||||
{
|
||||
builtin_error ("cannot reopen temp file %s", fn);
|
||||
unlink (fn);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
retval = EXECUTION_SUCCESS;
|
||||
first = 1;
|
||||
|
||||
/* First, write the commands to the history file. This will not happen
|
||||
when we call parse_and_execute, since parse_and_execute disables
|
||||
the command line history while it executes. */
|
||||
|
||||
while ((line = fc_readline (stream)) != NULL)
|
||||
{
|
||||
if (line[0] == '\n')
|
||||
{
|
||||
free (line);
|
||||
continue; /* Skip blank lines. */
|
||||
}
|
||||
|
||||
if (first)
|
||||
{
|
||||
first = 0;
|
||||
fc_replhist (line);
|
||||
}
|
||||
else
|
||||
fc_addhist (line);
|
||||
|
||||
free (line);
|
||||
}
|
||||
fclose (stream);
|
||||
|
||||
/* Turn on the `v' flag while maybe_execute_file runs so the commands
|
||||
will be echoed as they are read by the parser. */
|
||||
begin_unwind_frame ("fc builtin");
|
||||
add_unwind_protect (unlink, fn);
|
||||
unwind_protect_int (echo_input_at_read);
|
||||
echo_input_at_read = 1;
|
||||
|
||||
retval = maybe_execute_file (fn, 0);
|
||||
|
||||
run_unwind_frame ("fc builtin");
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* Return an absolute index into HLIST which corresponds to COMMAND. If
|
||||
COMMAND is a number, then it was specified in relative terms. If it
|
||||
is a string, then it is the start of a command line present in HLIST. */
|
||||
static int
|
||||
fc_gethnum (command, hlist)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
{
|
||||
int sign = 1, n, clen;
|
||||
register int i, j;
|
||||
register char *s;
|
||||
|
||||
/* Count history elements. */
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
/* With the Bash implementation of history, the current command line
|
||||
("fc blah..." and so on) is already part of the history list by
|
||||
the time we get to this point. This just skips over that command
|
||||
and makes the last command that this deals with be the last command
|
||||
the user entered before the fc. */
|
||||
i -= 2;
|
||||
|
||||
/* No specification defaults to most recent command. */
|
||||
if (command == NULL)
|
||||
return (i);
|
||||
|
||||
/* Otherwise, there is a specification. It can be a number relative to
|
||||
the current position, or an absolute history number. */
|
||||
s = command;
|
||||
|
||||
/* Handle possible leading minus sign. */
|
||||
if (s && (*s == '-'))
|
||||
{
|
||||
sign = -1;
|
||||
s++;
|
||||
}
|
||||
|
||||
if (s && digit(*s))
|
||||
{
|
||||
n = atoi (s);
|
||||
n *= sign;
|
||||
|
||||
/* Anything specified greater than the last history element that we
|
||||
deal with is an error. */
|
||||
if (n > i + history_base)
|
||||
return (-1);
|
||||
|
||||
/* If the value is negative or zero, then it is an offset from
|
||||
the current history item. */
|
||||
if (n < 0)
|
||||
return (i + n + 1);
|
||||
else if (n == 0)
|
||||
return (i);
|
||||
else
|
||||
return (n - history_base);
|
||||
}
|
||||
|
||||
clen = strlen (command);
|
||||
for (j = i; j >= 0; j--)
|
||||
{
|
||||
if (STREQN (command, histline (j), clen))
|
||||
return (j);
|
||||
}
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Locate the most recent history line which begins with
|
||||
COMMAND in HLIST, and return a malloc()'ed copy of it. */
|
||||
static char *
|
||||
fc_gethist (command, hlist)
|
||||
char *command;
|
||||
HIST_ENTRY **hlist;
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!hlist)
|
||||
return ((char *)NULL);
|
||||
|
||||
i = fc_gethnum (command, hlist);
|
||||
|
||||
if (i >= 0)
|
||||
return (savestring (histline (i)));
|
||||
else
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
/* Read the edited history lines from STREAM and return them
|
||||
one at a time. This can read unlimited length lines. The
|
||||
caller should free the storage. */
|
||||
static char *
|
||||
fc_readline (stream)
|
||||
FILE *stream;
|
||||
{
|
||||
register int c;
|
||||
int line_len = 0, lindex = 0;
|
||||
char *line = (char *)NULL;
|
||||
|
||||
while ((c = getc (stream)) != EOF)
|
||||
{
|
||||
if ((lindex + 2) >= line_len)
|
||||
line = (char *) xrealloc (line, (line_len += 128));
|
||||
|
||||
if (c == '\n')
|
||||
{
|
||||
line[lindex++] = '\n';
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
else
|
||||
line[lindex++] = c;
|
||||
}
|
||||
|
||||
if (!lindex)
|
||||
{
|
||||
if (line)
|
||||
free (line);
|
||||
|
||||
return ((char *)NULL);
|
||||
}
|
||||
|
||||
if (lindex + 2 >= line_len)
|
||||
line = (char *)xrealloc (line, lindex + 3);
|
||||
|
||||
line[lindex++] = '\n'; /* Finish with newline if none in file */
|
||||
line[lindex++] = '\0';
|
||||
return (line);
|
||||
}
|
||||
|
||||
/* Perform the SUBS on COMMAND.
|
||||
SUBS is a list of substitutions, and COMMAND is a simple string.
|
||||
Return a pointer to a malloc'ed string which contains the substituted
|
||||
command. */
|
||||
static char *
|
||||
fc_dosubs (command, subs)
|
||||
char *command;
|
||||
REPL *subs;
|
||||
{
|
||||
register char *new = savestring (command);
|
||||
register REPL *r;
|
||||
|
||||
for (r = subs; r; r = r->next)
|
||||
{
|
||||
register char *t;
|
||||
|
||||
t = fc_replace (r->pat, r->rep, new);
|
||||
free (new);
|
||||
new = t;
|
||||
}
|
||||
return (new);
|
||||
}
|
||||
|
||||
/* Replace the occurrences of PAT with REP in COMMAND.
|
||||
This returns a new string; the caller should free it. */
|
||||
static char *
|
||||
fc_replace (pat, rep, command)
|
||||
char *pat, *rep, *command;
|
||||
{
|
||||
register int i;
|
||||
int patlen, replen, templen;
|
||||
char *new, *temp;
|
||||
|
||||
patlen = strlen (pat);
|
||||
replen = strlen (rep);
|
||||
|
||||
temp = savestring (command);
|
||||
templen = strlen (temp);
|
||||
i = 0;
|
||||
|
||||
for (; (i + patlen) <= templen; i++)
|
||||
{
|
||||
if (STREQN (temp + i, pat, patlen))
|
||||
{
|
||||
new = (char *) xmalloc (1 + (replen - patlen) + templen);
|
||||
|
||||
strncpy (new, temp, i);
|
||||
strncpy (new + i, rep, replen);
|
||||
strncpy (new + i + replen,
|
||||
temp + i + patlen, templen - (i + patlen));
|
||||
new[templen + (replen - patlen)] = '\0'; /* just in case */
|
||||
|
||||
free (temp);
|
||||
temp = new;
|
||||
i += replen;
|
||||
templen = strlen (temp);
|
||||
}
|
||||
}
|
||||
return (temp);
|
||||
}
|
||||
|
||||
/* Use `command' to replace the last entry in the history list, which,
|
||||
by this time, is `fc blah...'. The intent is that the new command
|
||||
become the history entry, and that `fc' should never appear in the
|
||||
history list. This way you can do `r' to your heart's content. */
|
||||
static void
|
||||
fc_replhist (command)
|
||||
char *command;
|
||||
{
|
||||
register int i;
|
||||
HIST_ENTRY **hlist, *histent, *discard;
|
||||
char *data;
|
||||
int n;
|
||||
|
||||
if (!command || !*command)
|
||||
return;
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
if (hlist == NULL)
|
||||
return;
|
||||
|
||||
for (i = 0; hlist[i]; i++);
|
||||
i--;
|
||||
|
||||
/* History_get () takes a parameter that should be
|
||||
offset by history_base. */
|
||||
|
||||
histent = history_get (history_base + i); /* Don't free this */
|
||||
if (histent == NULL)
|
||||
return;
|
||||
|
||||
n = strlen (command);
|
||||
|
||||
if (command[n - 1] == '\n')
|
||||
command[n - 1] = '\0';
|
||||
|
||||
if (command && *command)
|
||||
{
|
||||
discard = remove_history (i);
|
||||
if (discard)
|
||||
{
|
||||
if (discard->line)
|
||||
free (discard->line);
|
||||
free ((char *) discard);
|
||||
}
|
||||
maybe_add_history (command); /* Obeys HISTCONTROL setting. */
|
||||
}
|
||||
}
|
||||
|
||||
/* Add LINE to the history, after removing a single trailing newline. */
|
||||
static void
|
||||
fc_addhist (line)
|
||||
char *line;
|
||||
{
|
||||
register int n;
|
||||
|
||||
n = strlen (line);
|
||||
|
||||
if (line[n - 1] == '\n')
|
||||
line[n - 1] = '\0';
|
||||
|
||||
if (line && *line)
|
||||
maybe_add_history (line);
|
||||
}
|
||||
#endif /* HISTORY */
|
145
builtins/fg_bg.def
Normal file
145
builtins/fg_bg.def
Normal file
|
@ -0,0 +1,145 @@
|
|||
This file is fg_bg.def, from which is created fg_bg.c.
|
||||
It implements the builtins "bg" and "fg" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES fg_bg.c
|
||||
|
||||
$BUILTIN fg
|
||||
$FUNCTION fg_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC fg [job_spec]
|
||||
Place JOB_SPEC in the foreground, and make it the current job. If
|
||||
JOB_SPEC is not present, the shell's notion of the current job is
|
||||
used.
|
||||
$END
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern char *this_command_name;
|
||||
|
||||
static int fg_bg ();
|
||||
|
||||
/* How to bring a job into the foreground. */
|
||||
int
|
||||
fg_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int fg_bit = 1;
|
||||
register WORD_LIST *t = list;
|
||||
|
||||
if (!job_control)
|
||||
{
|
||||
builtin_error ("no job control");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* If the last arg on the line is '&', then start this job in the
|
||||
background. Else, fg the job. */
|
||||
|
||||
while (t && t->next)
|
||||
t = t->next;
|
||||
|
||||
if (t && t->word->word[0] == '&' && !t->word->word[1])
|
||||
fg_bit = 0;
|
||||
|
||||
return (fg_bg (list, fg_bit));
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
|
||||
$BUILTIN bg
|
||||
$FUNCTION bg_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC bg [job_spec]
|
||||
Place JOB_SPEC in the background, as if it had been started with
|
||||
`&'. If JOB_SPEC is not present, the shell's notion of the current
|
||||
job is used.
|
||||
$END
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
/* How to put a job into the background. */
|
||||
int
|
||||
bg_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (!job_control)
|
||||
{
|
||||
builtin_error ("no job control");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
return (fg_bg (list, 0));
|
||||
}
|
||||
|
||||
/* How to put a job into the foreground/background. */
|
||||
static int
|
||||
fg_bg (list, foreground)
|
||||
WORD_LIST *list;
|
||||
int foreground;
|
||||
{
|
||||
sigset_t set, oset;
|
||||
int job, status = EXECUTION_SUCCESS, old_async_pid;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (job < 0 || job >= job_slots || !jobs[job])
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
builtin_error ("No such job %s", list ? list->word->word : "");
|
||||
|
||||
goto failure;
|
||||
}
|
||||
|
||||
/* Or if jobs[job]->pgrp == shell_pgrp. */
|
||||
if (!(jobs[job]->flags & J_JOBCONTROL))
|
||||
{
|
||||
builtin_error ("job %%%d started without job control", job + 1);
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if (!foreground)
|
||||
{
|
||||
old_async_pid = last_asynchronous_pid;
|
||||
last_asynchronous_pid = jobs[job]->pgrp; /* As per Posix.2 5.4.2 */
|
||||
}
|
||||
|
||||
status = start_job (job, foreground);
|
||||
|
||||
if (status >= 0)
|
||||
{
|
||||
/* win: */
|
||||
UNBLOCK_CHILD (oset);
|
||||
return (status);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!foreground)
|
||||
last_asynchronous_pid = old_async_pid;
|
||||
|
||||
failure:
|
||||
UNBLOCK_CHILD (oset);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
283
builtins/getopt.c
Normal file
283
builtins/getopt.c
Normal file
|
@ -0,0 +1,283 @@
|
|||
/* getopt for BASH.
|
||||
|
||||
Copyright (C) 1993, 1994
|
||||
Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../memalloc.h"
|
||||
#include "../shell.h"
|
||||
#include "getopt.h"
|
||||
|
||||
/* For communication from `sh_getopt' to the caller.
|
||||
When `sh_getopt' finds an option that takes an argument,
|
||||
the argument value is returned here. */
|
||||
char *sh_optarg = 0;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `sh_getopt'.
|
||||
|
||||
On entry to `sh_getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `sh_getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `sh_optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
/* XXX 1003.2 says this must be 1 before any call. */
|
||||
int sh_optind = 0;
|
||||
|
||||
/* Index of the current argument. */
|
||||
static int sh_curopt;
|
||||
|
||||
/* The next char to be scanned in the option-element
|
||||
in which the last option character we returned was found.
|
||||
This allows us to pick up the scan where we left off.
|
||||
|
||||
If this is zero, or a null string, it means resume the scan
|
||||
by advancing to the next ARGV-element. */
|
||||
|
||||
static char *nextchar;
|
||||
static int sh_charindex;
|
||||
|
||||
/* Callers store zero here to inhibit the error message
|
||||
for unrecognized options. */
|
||||
|
||||
int sh_opterr = 1;
|
||||
|
||||
/* Set to an option character which was unrecognized.
|
||||
This must be initialized on some systems to avoid linking in the
|
||||
system's own getopt implementation. */
|
||||
|
||||
int sh_optopt = '?';
|
||||
|
||||
/* Scan elements of ARGV (whose length is ARGC) for option characters
|
||||
given in OPTSTRING.
|
||||
|
||||
If an element of ARGV starts with '-', and is not exactly "-" or "--",
|
||||
then it is an option element. The characters of this element
|
||||
(aside from the initial '-') are option characters. If `sh_getopt'
|
||||
is called repeatedly, it returns successively each of the option characters
|
||||
from each of the option elements.
|
||||
|
||||
If `sh_getopt' finds another option character, it returns that character,
|
||||
updating `sh_optind' and `nextchar' so that the next call to `sh_getopt' can
|
||||
resume the scan with the following option character or ARGV-element.
|
||||
|
||||
If there are no more option characters, `sh_getopt' returns `EOF'.
|
||||
Then `sh_optind' is the index in ARGV of the first ARGV-element
|
||||
that is not an option.
|
||||
|
||||
OPTSTRING is a string containing the legitimate option characters.
|
||||
If an option character is seen that is not listed in OPTSTRING,
|
||||
return '?' after printing an error message. If you set `sh_opterr' to
|
||||
zero, the error message is suppressed but we still return '?'.
|
||||
|
||||
If a char in OPTSTRING is followed by a colon, that means it wants an arg,
|
||||
so the following text in the same ARGV-element, or the text of the following
|
||||
ARGV-element, is returned in `sh_optarg'. */
|
||||
|
||||
/* 1003.2 specifies the format of this message. */
|
||||
#define BADOPT(x) fprintf (stderr, "%s: illegal option -- %c\n", argv[0], x)
|
||||
#define NEEDARG(x) fprintf (stderr, "%s: option requires an argument -- %c\n", argv[0], x)
|
||||
|
||||
int
|
||||
sh_getopt (argc, argv, optstring)
|
||||
int argc;
|
||||
char *const *argv;
|
||||
const char *optstring;
|
||||
{
|
||||
int option_index;
|
||||
char c, *temp;
|
||||
|
||||
sh_optarg = 0;
|
||||
|
||||
if (sh_optind > argc || sh_optind < 0)
|
||||
{
|
||||
sh_optind = argc;
|
||||
return (EOF);
|
||||
}
|
||||
|
||||
/* Initialize the internal data when the first call is made.
|
||||
Start processing options with ARGV-element 1 (since ARGV-element 0
|
||||
is the program name); the sequence of previously skipped
|
||||
non-option ARGV-elements is empty. */
|
||||
|
||||
if (sh_optind == 0)
|
||||
{
|
||||
sh_optind = 1;
|
||||
nextchar = (char *)NULL;
|
||||
}
|
||||
|
||||
if (nextchar == 0 || *nextchar == '\0')
|
||||
{
|
||||
/* If we have done all the ARGV-elements, stop the scan
|
||||
and back over any non-options that we skipped and permuted. */
|
||||
if (sh_optind == argc)
|
||||
return EOF;
|
||||
|
||||
temp = argv[sh_optind];
|
||||
|
||||
/* Special ARGV-element `--' means premature end of options.
|
||||
Skip it like a null option, and return EOF. */
|
||||
if (temp[0] == '-' && temp[1] == '-' && temp[2] == '\0')
|
||||
{
|
||||
sh_optind++;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
/* If we have come to a non-option, either stop the scan or describe
|
||||
it to the caller and pass it by. This makes the pseudo-option
|
||||
`-' mean the end of options, but does not skip over it. */
|
||||
if (temp[0] != '-' || temp[1] == '\0')
|
||||
return EOF;
|
||||
|
||||
/* We have found another option-ARGV-element.
|
||||
Start decoding its characters. */
|
||||
nextchar = argv[sh_curopt = sh_optind] + 1;
|
||||
sh_charindex = 1;
|
||||
}
|
||||
|
||||
/* Look at and handle the next option-character. */
|
||||
|
||||
c = *nextchar++; sh_charindex++;
|
||||
temp = strchr (optstring, c);
|
||||
|
||||
/* Increment `sh_optind' when we start to process its last character. */
|
||||
if (nextchar == 0 || *nextchar == '\0')
|
||||
{
|
||||
sh_optind++;
|
||||
nextchar = (char *)NULL;
|
||||
}
|
||||
|
||||
sh_optopt = c;
|
||||
|
||||
if (temp == NULL || c == ':')
|
||||
{
|
||||
if (sh_opterr)
|
||||
BADOPT (c);
|
||||
|
||||
return '?';
|
||||
}
|
||||
|
||||
if (temp[1] == ':')
|
||||
{
|
||||
if (nextchar && *nextchar)
|
||||
{
|
||||
/* This is an option that requires an argument. */
|
||||
sh_optarg = nextchar;
|
||||
/* If we end this ARGV-element by taking the rest as an arg,
|
||||
we must advance to the next element now. */
|
||||
sh_optind++;
|
||||
}
|
||||
else if (sh_optind == argc)
|
||||
{
|
||||
if (sh_opterr)
|
||||
NEEDARG (c);
|
||||
|
||||
sh_optopt = c;
|
||||
c = (optstring[0] == ':') ? ':' : '?';
|
||||
}
|
||||
else
|
||||
/* We already incremented `sh_optind' once;
|
||||
increment it again when taking next ARGV-elt as argument. */
|
||||
sh_optarg = argv[sh_optind++];
|
||||
nextchar = (char *)NULL;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void
|
||||
sh_getopt_restore_state (argv)
|
||||
char **argv;
|
||||
{
|
||||
if (nextchar)
|
||||
nextchar = argv[sh_curopt] + sh_charindex;
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/* Compile with -DTEST to make an executable for use in testing
|
||||
the above definition of `sh_getopt'. */
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int c;
|
||||
int digit_sh_optind = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
int this_option_sh_optind = sh_optind ? sh_optind : 1;
|
||||
|
||||
c = sh_getopt (argc, argv, "abc:d:0123456789");
|
||||
if (c == EOF)
|
||||
break;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case '0':
|
||||
case '1':
|
||||
case '2':
|
||||
case '3':
|
||||
case '4':
|
||||
case '5':
|
||||
case '6':
|
||||
case '7':
|
||||
case '8':
|
||||
case '9':
|
||||
if (digit_sh_optind != 0 && digit_sh_optind != this_option_sh_optind)
|
||||
printf ("digits occur in two different argv-elements.\n");
|
||||
digit_sh_optind = this_option_sh_optind;
|
||||
printf ("option %c\n", c);
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
printf ("option a\n");
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
printf ("option b\n");
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
printf ("option c with value `%s'\n", sh_optarg);
|
||||
break;
|
||||
|
||||
case '?':
|
||||
break;
|
||||
|
||||
default:
|
||||
printf ("?? sh_getopt returned character code 0%o ??\n", c);
|
||||
}
|
||||
}
|
||||
|
||||
if (sh_optind < argc)
|
||||
{
|
||||
printf ("non-option ARGV-elements: ");
|
||||
while (sh_optind < argc)
|
||||
printf ("%s ", argv[sh_optind++]);
|
||||
printf ("\n");
|
||||
}
|
||||
|
||||
exit (0);
|
||||
}
|
||||
|
||||
#endif /* TEST */
|
57
builtins/getopt.h
Normal file
57
builtins/getopt.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/* Declarations for getopt.
|
||||
Copyright (C) 1989, 1990, 1991, 1992, 1993 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the
|
||||
Free Software Foundation; either version 2, or (at your option) any
|
||||
later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* XXX THIS HAS BEEN MODIFIED FOR INCORPORATION INTO BASH XXX */
|
||||
|
||||
#ifndef _GETOPT_H
|
||||
#define _GETOPT_H 1
|
||||
|
||||
/* For communication from `getopt' to the caller.
|
||||
When `getopt' finds an option that takes an argument,
|
||||
the argument value is returned here.
|
||||
Also, when `ordering' is RETURN_IN_ORDER,
|
||||
each non-option ARGV-element is returned here. */
|
||||
|
||||
extern char *sh_optarg;
|
||||
|
||||
/* Index in ARGV of the next element to be scanned.
|
||||
This is used for communication to and from the caller
|
||||
and for communication between successive calls to `getopt'.
|
||||
|
||||
On entry to `getopt', zero means this is the first call; initialize.
|
||||
|
||||
When `getopt' returns EOF, this is the index of the first of the
|
||||
non-option elements that the caller should itself scan.
|
||||
|
||||
Otherwise, `sh_optind' communicates from one call to the next
|
||||
how much of ARGV has been scanned so far. */
|
||||
|
||||
extern int sh_optind;
|
||||
|
||||
/* Callers store zero here to inhibit the error message `getopt' prints
|
||||
for unrecognized options. */
|
||||
|
||||
extern int sh_opterr;
|
||||
|
||||
/* Set to an option character which was unrecognized. */
|
||||
|
||||
extern int sh_optopt;
|
||||
|
||||
extern int sh_getopt ();
|
||||
extern void sh_getopt_restore_state ();
|
||||
|
||||
#endif /* _GETOPT_H */
|
300
builtins/getopts.def
Normal file
300
builtins/getopts.def
Normal file
|
@ -0,0 +1,300 @@
|
|||
This file is getopts.def, from which is created getopts.c.
|
||||
It implements the builtin "getopts" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES getopts.c
|
||||
|
||||
$BUILTIN getopts
|
||||
$DEPENDS_ON GETOPTS_BUILTIN
|
||||
$FUNCTION getopts_builtin
|
||||
$SHORT_DOC getopts optstring name [arg]
|
||||
Getopts is used by shell procedures to parse positional parameters.
|
||||
|
||||
OPTSTRING contains the option letters to be recognized; if a letter
|
||||
is followed by a colon, the option is expected to have an argument,
|
||||
which should be separated from it by white space.
|
||||
|
||||
Each time it is invoked, getopts will place the next option in the
|
||||
shell variable $name, initializing name if it does not exist, and
|
||||
the index of the next argument to be processed into the shell
|
||||
variable OPTIND. OPTIND is initialized to 1 each time the shell or
|
||||
a shell script is invoked. When an option requires an argument,
|
||||
getopts places that argument into the shell variable OPTARG.
|
||||
|
||||
getopts reports errors in one of two ways. If the first character
|
||||
of OPTSTRING is a colon, getopts uses silent error reporting. In
|
||||
this mode, no error messages are printed. If an illegal option is
|
||||
seen, getopts places the option character found into OPTARG. If a
|
||||
required argument is not found, getopts places a ':' into NAME and
|
||||
sets OPTARG to the option character found. If getopts is not in
|
||||
silent mode, and an illegal option is seen, getopts places '?' into
|
||||
NAME and unsets OPTARG. If a required option is not found, a '?'
|
||||
is placed in NAME, OPTARG is unset, and a diagnostic message is
|
||||
printed.
|
||||
|
||||
If the shell variable OPTERR has the value 0, getopts disables the
|
||||
printing of error messages, even if the first character of
|
||||
OPTSTRING is not a colon. OPTERR has the value 1 by default.
|
||||
|
||||
Getopts normally parses the positional parameters ($0 - $9), but if
|
||||
more arguments are given, they are parsed instead.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
#if defined (GETOPTS_BUILTIN)
|
||||
#include "getopt.h"
|
||||
|
||||
#define G_EOF (-1)
|
||||
#define G_ILLEGAL_OPT (-2)
|
||||
#define G_ARG_MISSING (-3)
|
||||
|
||||
extern char *this_command_name;
|
||||
extern WORD_LIST *rest_of_args;
|
||||
|
||||
/* getopts_reset is magic code for when OPTIND is reset. N is the
|
||||
value that has just been assigned to OPTIND. */
|
||||
void
|
||||
getopts_reset (newind)
|
||||
int newind;
|
||||
{
|
||||
sh_optind = newind;
|
||||
}
|
||||
|
||||
/* Error handling is now performed as specified by Posix.2, draft 11
|
||||
(identical to that of ksh-88). The special handling is enabled if
|
||||
the first character of the option string is a colon; this handling
|
||||
disables diagnostic messages concerning missing option arguments
|
||||
and illegal option characters. The handling is as follows.
|
||||
|
||||
ILLEGAL OPTIONS:
|
||||
name -> "?"
|
||||
if (special_error) then
|
||||
OPTARG = option character found
|
||||
no error output
|
||||
else
|
||||
OPTARG unset
|
||||
diagnostic message
|
||||
fi
|
||||
|
||||
MISSING OPTION ARGUMENT;
|
||||
if (special_error) then
|
||||
name -> ":"
|
||||
OPTARG = option character found
|
||||
else
|
||||
name -> "?"
|
||||
OPTARG unset
|
||||
diagnostic message
|
||||
fi
|
||||
*/
|
||||
|
||||
static int
|
||||
dogetopts (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
int ret, special_error, old_opterr = 0, i, n;
|
||||
char strval[2], numval[16];
|
||||
char *optstr; /* list of options */
|
||||
char *name; /* variable to get flag val */
|
||||
char *t;
|
||||
|
||||
if (argc < 3)
|
||||
{
|
||||
builtin_error("usage: getopts optstring name [arg]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
/* argv[0] is "getopts". */
|
||||
|
||||
optstr = argv[1];
|
||||
name = argv[2];
|
||||
argc -= 2;
|
||||
argv += 2;
|
||||
|
||||
special_error = optstr[0] == ':';
|
||||
|
||||
if (special_error)
|
||||
{
|
||||
old_opterr = sh_opterr;
|
||||
optstr++;
|
||||
sh_opterr = 0; /* suppress diagnostic messages */
|
||||
}
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
sh_getopt_restore_state (argv);
|
||||
t = argv[0];
|
||||
argv[0] = dollar_vars[0];
|
||||
ret = sh_getopt (argc, argv, optstr);
|
||||
argv[0] = t;
|
||||
}
|
||||
else if (rest_of_args == (WORD_LIST *)NULL)
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++);
|
||||
ret = sh_getopt (i, dollar_vars, optstr);
|
||||
}
|
||||
else
|
||||
{
|
||||
register int i;
|
||||
register WORD_LIST *words;
|
||||
char **v;
|
||||
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++);
|
||||
for (words = rest_of_args; words; words = words->next, i++);
|
||||
v = (char **)xmalloc ((i + 1) * sizeof (char *));
|
||||
for (i = 0; i < 10 && dollar_vars[i]; i++)
|
||||
v[i] = dollar_vars[i];
|
||||
for (words = rest_of_args; words; words = words->next, i++)
|
||||
v[i] = words->word->word;
|
||||
v[i] = (char *)NULL;
|
||||
ret = sh_getopt (i, v, optstr);
|
||||
free (v);
|
||||
}
|
||||
|
||||
if (special_error)
|
||||
sh_opterr = old_opterr;
|
||||
|
||||
/* Set the OPTIND variable in any case, to handle "--" skipping. */
|
||||
if (sh_optind < 10)
|
||||
{
|
||||
numval[14] = sh_optind + '0';
|
||||
numval[15] = '\0';
|
||||
i = 14;
|
||||
}
|
||||
else
|
||||
{
|
||||
numval[i = 15] = '\0';
|
||||
n = sh_optind;
|
||||
do
|
||||
{
|
||||
numval[--i] = (n % 10) + '0';
|
||||
}
|
||||
while (n /= 10);
|
||||
}
|
||||
bind_variable ("OPTIND", numval + i);
|
||||
|
||||
/* If an error occurred, decide which one it is and set the return
|
||||
code appropriately. In all cases, the option character in error
|
||||
is in SH_OPTOPT. If an illegal option was encountered, OPTARG is
|
||||
NULL. If a required option argument was missing, OPTARG points
|
||||
to a NULL string (that is, optarg[0] == 0). */
|
||||
if (ret == '?')
|
||||
{
|
||||
if (sh_optarg == NULL)
|
||||
ret = G_ILLEGAL_OPT;
|
||||
else if (sh_optarg[0] == '\0')
|
||||
ret = G_ARG_MISSING;
|
||||
}
|
||||
|
||||
if (ret == G_EOF)
|
||||
{
|
||||
bind_variable (name, "?");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (ret == G_ILLEGAL_OPT)
|
||||
{
|
||||
/* Illegal option encountered. */
|
||||
strval[0] = '?';
|
||||
strval[1] = '\0';
|
||||
bind_variable (name, strval);
|
||||
|
||||
if (special_error)
|
||||
{
|
||||
strval[0] = (char) sh_optopt;
|
||||
strval[1] = '\0';
|
||||
bind_variable ("OPTARG", strval);
|
||||
}
|
||||
else
|
||||
makunbound ("OPTARG", shell_variables);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (ret == G_ARG_MISSING)
|
||||
{
|
||||
/* Required argument missing. */
|
||||
if (special_error)
|
||||
{
|
||||
strval[0] = ':';
|
||||
strval[1] = '\0';
|
||||
bind_variable (name, strval);
|
||||
|
||||
strval[0] = (char) sh_optopt;
|
||||
strval[1] = '\0';
|
||||
bind_variable ("OPTARG", strval);
|
||||
}
|
||||
else
|
||||
{
|
||||
strval[0] = '?';
|
||||
strval[1] = '\0';
|
||||
bind_variable (name, strval);
|
||||
makunbound ("OPTARG", shell_variables);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
bind_variable ("OPTARG", sh_optarg);
|
||||
|
||||
strval[0] = (char) ret;
|
||||
strval[1] = '\0';
|
||||
bind_variable (name, strval);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* The getopts builtin. Build an argv, and call dogetopts with it. */
|
||||
int
|
||||
getopts_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
char **av;
|
||||
int ac, ret;
|
||||
WORD_LIST *t;
|
||||
|
||||
if (list == 0)
|
||||
return EXECUTION_FAILURE;
|
||||
|
||||
for (t = list, ac = 0; t; t = t->next, ac++);
|
||||
|
||||
ac++;
|
||||
av = (char **)xmalloc ((1 + ac) * sizeof (char *));
|
||||
av[ac] = (char *) NULL;
|
||||
av[0] = this_command_name;
|
||||
|
||||
for (t = list, i = 1; t; t = t->next, i++)
|
||||
av[i] = t->word->word;
|
||||
|
||||
ret = dogetopts (ac, av);
|
||||
free ((char *)av);
|
||||
return (ret);
|
||||
}
|
||||
#endif /* GETOPTS_BUILTIN */
|
222
builtins/hash.def
Normal file
222
builtins/hash.def
Normal file
|
@ -0,0 +1,222 @@
|
|||
This file is hash.def, from which is created hash.c.
|
||||
It implements the builtin "hash" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES hash.c
|
||||
|
||||
$BUILTIN hash
|
||||
$FUNCTION hash_builtin
|
||||
$SHORT_DOC hash [-r] [name ...]
|
||||
For each NAME, the full pathname of the command is determined and
|
||||
remembered. The -r option causes the shell to forget all remembered
|
||||
locations. If no arguments are given, information about remembered
|
||||
commands is presented.
|
||||
$END
|
||||
|
||||
#include <sys/types.h>
|
||||
#include "../posixstat.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../builtins.h"
|
||||
#include "../flags.h"
|
||||
#include "hashcom.h"
|
||||
#include "common.h"
|
||||
#include "../execute_cmd.h"
|
||||
|
||||
extern int dot_found_in_search;
|
||||
|
||||
void
|
||||
initialize_filename_hashing ()
|
||||
{
|
||||
hashed_filenames = make_hash_table (FILENAME_HASH_BUCKETS);
|
||||
}
|
||||
|
||||
/* Print statistics on the current state of hashed commands. If LIST is
|
||||
not empty, then rehash (or hash in the first place) the specified
|
||||
commands. */
|
||||
hash_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int expunge_hash_table = 0;
|
||||
int any_failed = 0;
|
||||
|
||||
if (hashing_disabled)
|
||||
{
|
||||
builtin_error ("hashing disabled");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
char *arg = list->word->word;
|
||||
|
||||
if (ISOPTION (arg, 'r'))
|
||||
{
|
||||
expunge_hash_table = 1;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (arg, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*arg == '-')
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
builtin_error ("usage: hash [-r] [command ...]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* We want hash -r to be silent, but hash -- to print hashing info. That
|
||||
is the reason for the !expunge_hash_table. */
|
||||
if (!list && !expunge_hash_table)
|
||||
{
|
||||
/* Print information about current hashed info. */
|
||||
int any_printed = 0;
|
||||
int bucket = 0;
|
||||
register BUCKET_CONTENTS *item_list;
|
||||
|
||||
while (bucket < hashed_filenames->nbuckets)
|
||||
{
|
||||
item_list = get_hash_bucket (bucket, hashed_filenames);
|
||||
if (item_list)
|
||||
{
|
||||
if (!any_printed)
|
||||
{
|
||||
printf ("hits\tcommand\n");
|
||||
any_printed++;
|
||||
}
|
||||
while (item_list)
|
||||
{
|
||||
printf ("%4d\t%s\n",
|
||||
item_list->times_found, pathdata(item_list)->path);
|
||||
item_list = item_list->next;
|
||||
}
|
||||
}
|
||||
bucket++;
|
||||
}
|
||||
|
||||
if (!any_printed)
|
||||
printf ("No commands in hash table.\n");
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (expunge_hash_table)
|
||||
{
|
||||
int bucket = 0;
|
||||
register BUCKET_CONTENTS *item_list, *prev;
|
||||
|
||||
while (bucket < hashed_filenames->nbuckets)
|
||||
{
|
||||
item_list = get_hash_bucket (bucket, hashed_filenames);
|
||||
if (item_list)
|
||||
{
|
||||
while (item_list)
|
||||
{
|
||||
prev = item_list;
|
||||
free (item_list->key);
|
||||
free (pathdata(item_list)->path);
|
||||
free (item_list->data);
|
||||
item_list = item_list->next;
|
||||
free (prev);
|
||||
}
|
||||
hashed_filenames->bucket_array[bucket] = (BUCKET_CONTENTS *)NULL;
|
||||
}
|
||||
bucket++;
|
||||
}
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
/* Add or rehash the specified commands. */
|
||||
char *word;
|
||||
char *full_path;
|
||||
SHELL_VAR *var;
|
||||
|
||||
word = list->word->word;
|
||||
if (absolute_program (word))
|
||||
{
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
full_path = find_user_command (word);
|
||||
var = find_function (word);
|
||||
|
||||
if (!find_shell_builtin (word) && (!var))
|
||||
{
|
||||
if (full_path && executable_file (full_path))
|
||||
remember_filename (word, full_path, dot_found_in_search, 0);
|
||||
else
|
||||
{
|
||||
builtin_error ("%s: not found", word);
|
||||
any_failed++;
|
||||
}
|
||||
}
|
||||
if (full_path)
|
||||
free (full_path);
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
if (any_failed)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Place FILENAME (key) and FULL_PATHNAME (data->path) into the
|
||||
hash table. CHECK_DOT if non-null is for future calls to
|
||||
find_hashed_filename (). FOUND is the initial value for
|
||||
times_found. */
|
||||
void
|
||||
remember_filename (filename, full_pathname, check_dot, found)
|
||||
char *filename, *full_pathname;
|
||||
int check_dot, found;
|
||||
{
|
||||
register BUCKET_CONTENTS *item;
|
||||
|
||||
if (hashing_disabled)
|
||||
return;
|
||||
item = add_hash_item (filename, hashed_filenames);
|
||||
if (item->data)
|
||||
free (pathdata(item)->path);
|
||||
else
|
||||
{
|
||||
item->key = savestring (filename);
|
||||
item->data = (char *)xmalloc (sizeof (PATH_DATA));
|
||||
}
|
||||
pathdata(item)->path = savestring (full_pathname);
|
||||
pathdata(item)->check_dot = check_dot;
|
||||
item->times_found = found;
|
||||
}
|
32
builtins/hashcom.h
Normal file
32
builtins/hashcom.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* hashcom.h - Common defines for hashing filenames. */
|
||||
|
||||
/* Copyright (C) 1993 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
#include "../hash.h"
|
||||
|
||||
#define FILENAME_HASH_BUCKETS 631
|
||||
|
||||
extern HASH_TABLE *hashed_filenames;
|
||||
|
||||
typedef struct {
|
||||
char *path; /* The full pathname of the file. */
|
||||
int check_dot; /* Whether `.' appeared before this one in $PATH. */
|
||||
} PATH_DATA;
|
||||
|
||||
#define pathdata(x) ((PATH_DATA *)(x)->data)
|
134
builtins/help.def
Normal file
134
builtins/help.def
Normal file
|
@ -0,0 +1,134 @@
|
|||
This file is help.def, from which is created help.c.
|
||||
It implements the builtin "help" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES help.c
|
||||
|
||||
$BUILTIN help
|
||||
$FUNCTION help_builtin
|
||||
$SHORT_DOC help [pattern ...]
|
||||
Display helpful information about builtin commands. If PATTERN is
|
||||
specified, gives detailed help on all commands matching PATTERN,
|
||||
otherwise a list of the builtins is printed.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#include "../builtins.h"
|
||||
|
||||
#if defined (USE_GLOB_LIBRARY)
|
||||
# include <glob/glob.h>
|
||||
#else
|
||||
# define FNM_NOMATCH 1
|
||||
#endif /* USE_GLOB_LIBRARY */
|
||||
|
||||
/* Print out a list of the known functions in the shell, and what they do.
|
||||
If LIST is supplied, print out the list which matches for each pattern
|
||||
specified. */
|
||||
help_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
register int i, j;
|
||||
char blurb[256];
|
||||
|
||||
show_shell_version ();
|
||||
printf (
|
||||
"Shell commands that are defined internally. Type `help' to see this list.\n\
|
||||
Type `help name' to find out more about the function `name'.\n\
|
||||
Use `info bash' to find out more about the shell in general.\n\
|
||||
\n\
|
||||
A star (*) next to a name means that the command is disabled.\n\
|
||||
\n");
|
||||
|
||||
for (i = 0; i < num_shell_builtins; i++)
|
||||
{
|
||||
QUIT;
|
||||
sprintf (blurb, "%c%s",
|
||||
(shell_builtins[i].flags & BUILTIN_ENABLED) ? ' ' : '*',
|
||||
shell_builtins[i].short_doc);
|
||||
|
||||
blurb[35] = '\0';
|
||||
printf ("%s", blurb);
|
||||
|
||||
if (i % 2)
|
||||
printf ("\n");
|
||||
else
|
||||
for (j = strlen (blurb); j < 35; j++)
|
||||
putc (' ', stdout);
|
||||
|
||||
}
|
||||
if (i % 2)
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
int match_found = 0;
|
||||
char *pattern = "";
|
||||
|
||||
if (glob_pattern_p (list->word->word))
|
||||
{
|
||||
printf ("Shell commands matching keyword%s `",
|
||||
list->next ? "s" : "");
|
||||
print_word_list (list, ", ");
|
||||
printf ("'\n\n");
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
register int i = 0, plen;
|
||||
char *name;
|
||||
|
||||
pattern = list->word->word;
|
||||
plen = strlen (pattern);
|
||||
|
||||
while (name = shell_builtins[i].name)
|
||||
{
|
||||
int doc_index;
|
||||
|
||||
QUIT;
|
||||
if ((strncmp (pattern, name, plen) == 0) ||
|
||||
(fnmatch (pattern, name, 0) != FNM_NOMATCH))
|
||||
{
|
||||
printf ("%s: %s\n", name, shell_builtins[i].short_doc);
|
||||
|
||||
for (doc_index = 0;
|
||||
shell_builtins[i].long_doc[doc_index]; doc_index++)
|
||||
printf (" %s\n", shell_builtins[i].long_doc[doc_index]);
|
||||
|
||||
match_found++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (!match_found)
|
||||
{
|
||||
fprintf (stderr, "No help topics match `%s'. Try `help help'.\n",
|
||||
pattern);
|
||||
fflush (stderr);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
179
builtins/history.def
Normal file
179
builtins/history.def
Normal file
|
@ -0,0 +1,179 @@
|
|||
This file is history.def, from which is created history.c.
|
||||
It implements the builtin "history" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES history.c
|
||||
|
||||
$BUILTIN history
|
||||
$FUNCTION history_builtin
|
||||
$DEPENDS_ON HISTORY
|
||||
$SHORT_DOC history [n] [ [-awrn] [filename]]
|
||||
Display the history list with line numbers. Lines listed with
|
||||
with a `*' have been modified. Argument of N says to list only
|
||||
the last N lines. Argument `-w' means to write out the current
|
||||
history file; `-r' means to read it instead. Argument `-a' means
|
||||
to append history lines from this session to the history file.
|
||||
Argument `-n' means to read all history lines not already read
|
||||
from the history file. If FILENAME is given, then use that file,
|
||||
else if $HISTFILE has a value, use that, else use ~/.bash_history.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
#if defined (HISTORY)
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include "../filecntl.h"
|
||||
#include "../posixstat.h"
|
||||
#include "../bashhist.h"
|
||||
#include <readline/history.h>
|
||||
|
||||
/* History. Arg of -w FILENAME means write file, arg of -r FILENAME
|
||||
means read file. Arg of N means only display that many items. */
|
||||
|
||||
history_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
int limited = 0, limit = 0;
|
||||
HIST_ENTRY **hlist;
|
||||
|
||||
while (list)
|
||||
{
|
||||
char *arg = list->word->word;
|
||||
|
||||
if ((arg[0] == '-') &&
|
||||
(strlen (arg) == 2) &&
|
||||
(member (arg[1], "rwan")))
|
||||
{
|
||||
char *file;
|
||||
int result = EXECUTION_SUCCESS;
|
||||
|
||||
if (list->next)
|
||||
file = list->next->word->word;
|
||||
else
|
||||
file = get_string_value ("HISTFILE");
|
||||
|
||||
switch (arg[1])
|
||||
{
|
||||
case 'a': /* Append `new' lines to file. */
|
||||
{
|
||||
if (history_lines_this_session)
|
||||
{
|
||||
void using_history ();
|
||||
|
||||
if (history_lines_this_session < where_history ())
|
||||
{
|
||||
/* If the filename was supplied, then create it
|
||||
if it doesn't already exist. */
|
||||
if (file)
|
||||
{
|
||||
struct stat buf;
|
||||
|
||||
if (stat (file, &buf) == -1)
|
||||
{
|
||||
int tem;
|
||||
|
||||
tem = open (file, O_CREAT, 0666);
|
||||
close (tem);
|
||||
}
|
||||
}
|
||||
|
||||
result =
|
||||
append_history (history_lines_this_session, file);
|
||||
history_lines_in_file += history_lines_this_session;
|
||||
history_lines_this_session = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'w': /* Write entire history. */
|
||||
{
|
||||
result = write_history (file);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'r': /* Read entire file. */
|
||||
{
|
||||
result = read_history (file);
|
||||
break;
|
||||
}
|
||||
|
||||
case 'n': /* Read `new' history from file. */
|
||||
{
|
||||
/* Read all of the lines in the file that we haven't
|
||||
already read. */
|
||||
using_history ();
|
||||
result = read_history_range (file, history_lines_in_file, -1);
|
||||
using_history ();
|
||||
history_lines_in_file = where_history ();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (result ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (strcmp (list->word->word, "--") == 0)
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
builtin_error ("usage: history [n] [-rwan [filename]]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (list)
|
||||
{
|
||||
limited = 1;
|
||||
limit = get_numeric_arg (list);
|
||||
}
|
||||
|
||||
hlist = history_list ();
|
||||
|
||||
if (hlist)
|
||||
{
|
||||
for (i = 0; hlist[i]; i++);
|
||||
|
||||
if (limit < 0)
|
||||
limit = -limit;
|
||||
|
||||
if (!limited)
|
||||
i = 0;
|
||||
else
|
||||
if ((i -= limit) < 0)
|
||||
i = 0;
|
||||
|
||||
while (hlist[i])
|
||||
{
|
||||
QUIT;
|
||||
printf ("%5d%c %s\n", i + history_base,
|
||||
hlist[i]->data ? '*' : ' ', hlist[i]->line);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
#endif /* HISTORY */
|
74
builtins/inlib.def
Normal file
74
builtins/inlib.def
Normal file
|
@ -0,0 +1,74 @@
|
|||
This file is inlib.def, from which is created inlib.c.
|
||||
It implements the Apollo-specific builtin "inlib" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES inlib.c
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
|
||||
$BUILTIN inlib
|
||||
$FUNCTION inlib_builtin
|
||||
$DEPENDS_ON apollo
|
||||
$SHORT_DOC inlib pathname [pathname...]
|
||||
Install a user-supplied library specified by pathname in the current
|
||||
shell process. The library is used to resolve external references
|
||||
in programs and libraries loaded after its installation. Note
|
||||
that the library is not loaded into the address space unless it is
|
||||
needed to resolve an external reference. The list of inlibed
|
||||
libraries is passed to all children of the current shell.
|
||||
$END
|
||||
|
||||
#if defined (apollo)
|
||||
|
||||
#include <apollo/base.h>
|
||||
#include <apollo/loader.h>
|
||||
|
||||
inlib_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
status_$t status;
|
||||
int return_value;
|
||||
short len;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
builtin_error ("usage: inlib pathname [pathname...]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
|
||||
return_value = EXECUTION_SUCCESS;
|
||||
|
||||
while (list)
|
||||
{
|
||||
len = (short)strlen (list->word->word);
|
||||
loader_$inlib (list->word->word, len, &status);
|
||||
|
||||
if (status.all != status_$ok)
|
||||
{
|
||||
builtin_error ("inlib failed for %s", list->word->word);
|
||||
return_value = EXECUTION_FAILURE;
|
||||
}
|
||||
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
return (return_value);
|
||||
}
|
||||
#endif /* apollo */
|
171
builtins/jobs.def
Normal file
171
builtins/jobs.def
Normal file
|
@ -0,0 +1,171 @@
|
|||
This file is jobs.def, from which is created jobs.c.
|
||||
It implements the builtin "jobs" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES jobs.c
|
||||
|
||||
$BUILTIN jobs
|
||||
$FUNCTION jobs_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC jobs [-lnp] [jobspec ...] | jobs -x command [args]
|
||||
Lists the active jobs. The -l option lists process id's in addition
|
||||
to the normal information; the -p option lists process id's only.
|
||||
If -n is given, only processes that have changed status since the last
|
||||
notification are printed. JOBSPEC restricts output to that job.
|
||||
If -x is given, COMMAND is run after all job specifications that appear
|
||||
in ARGS have been replaced with the process ID of that job's process group
|
||||
leader.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include "../jobs.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int job_control, interactive_shell;
|
||||
static int execute_list_with_replacements ();
|
||||
|
||||
/* The `jobs' command. Prints outs a list of active jobs. If the
|
||||
argument `-l' is given, then the process id's are printed also.
|
||||
If the argument `-p' is given, print the process group leader's
|
||||
pid only. If `-n' is given, only processes that have changed
|
||||
status since the last notification are printed. If -x is given,
|
||||
replace all job specs with the pid of the appropriate process
|
||||
group leader and execute the command. */
|
||||
int
|
||||
jobs_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int form = JLIST_STANDARD, execute = 0;
|
||||
int opt;
|
||||
int any_failed = 0;
|
||||
|
||||
if (!job_control && !interactive_shell)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "lpnx")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'l':
|
||||
form = JLIST_LONG;
|
||||
break;
|
||||
case 'p':
|
||||
form = JLIST_PID_ONLY;
|
||||
break;
|
||||
case 'n':
|
||||
form = JLIST_CHANGED_ONLY;
|
||||
break;
|
||||
case 'x':
|
||||
if (form != JLIST_STANDARD)
|
||||
{
|
||||
builtin_error ("Other options not allowed with `-x'");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
execute++;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_error ("usage: jobs [-lpn [jobspec]] [-x command [args]]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (execute)
|
||||
return (execute_list_with_replacements (list));
|
||||
|
||||
if (!list)
|
||||
{
|
||||
list_jobs (form);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
int job;
|
||||
sigset_t set, oset;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if ((job == NO_JOB) || !jobs || !jobs[job])
|
||||
{
|
||||
builtin_error ("No such job %s", list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
else if (job != DUP_JOB)
|
||||
list_one_job ((JOB *)NULL, form, 0, job);
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
list = list->next;
|
||||
}
|
||||
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
static int
|
||||
execute_list_with_replacements (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register WORD_LIST *l;
|
||||
int job, result;
|
||||
|
||||
/* First do the replacement of job specifications with pids. */
|
||||
for (l = list; l; l = l->next)
|
||||
{
|
||||
if (l->word->word[0] == '%') /* we have a winner */
|
||||
{
|
||||
job = get_job_spec (l);
|
||||
|
||||
/* A bad job spec is not really a job spec! Pass it through. */
|
||||
if (job < 0 || job >= job_slots || !jobs[job])
|
||||
continue;
|
||||
|
||||
free (l->word->word);
|
||||
l->word->word = itos (jobs[job]->pgrp);
|
||||
}
|
||||
}
|
||||
|
||||
/* Next make a new simple command and execute it. */
|
||||
begin_unwind_frame ("jobs_builtin");
|
||||
{
|
||||
COMMAND *command = (COMMAND *)NULL;
|
||||
|
||||
add_unwind_protect (dispose_command, command);
|
||||
|
||||
command = make_bare_simple_command ();
|
||||
command->value.Simple->words = copy_word_list (list);
|
||||
command->value.Simple->redirects = (REDIRECT *)NULL;
|
||||
command->flags |= CMD_INHIBIT_EXPANSION;
|
||||
command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
|
||||
|
||||
result = execute_command (command);
|
||||
}
|
||||
|
||||
run_unwind_frame ("jobs_builtin");
|
||||
return (result);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
281
builtins/kill.def
Normal file
281
builtins/kill.def
Normal file
|
@ -0,0 +1,281 @@
|
|||
This file is kill.def, from which is created kill.c.
|
||||
It implements the builtin "kill" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES kill.c
|
||||
|
||||
$BUILTIN kill
|
||||
$FUNCTION kill_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$SHORT_DOC kill [-s sigspec | -sigspec] [pid | job]... | -l [signum]
|
||||
Send the processes named by PID (or JOB) the signal SIGSPEC. If
|
||||
SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l'
|
||||
lists the signal names; if arguments follow `-l' they are assumed to
|
||||
be signal numbers for which names should be listed. Kill is a shell
|
||||
builtin for two reasons: it allows job IDs to be used instead of
|
||||
process IDs, and, if you have reached the limit on processes that
|
||||
you can create, you don't have to start a process to kill another one.
|
||||
$END
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
#include "../bashtypes.h"
|
||||
#include "../shell.h"
|
||||
#include "../trap.h"
|
||||
#include "../jobs.h"
|
||||
#include "common.h"
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int interactive;
|
||||
extern int posixly_correct;
|
||||
|
||||
#if !defined (CONTINUE_AFTER_KILL_ERROR)
|
||||
# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE)
|
||||
#else
|
||||
# define CONTINUE_OR_FAIL goto continue_killing
|
||||
#endif /* CONTINUE_AFTER_KILL_ERROR */
|
||||
|
||||
/* Here is the kill builtin. We only have it so that people can type
|
||||
kill -KILL %1? No, if you fill up the process table this way you
|
||||
can still kill some. */
|
||||
int
|
||||
kill_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int signal = SIGTERM;
|
||||
int any_succeeded = 0, listing = 0, saw_signal = 0;
|
||||
char *sigspec = "TERM", *word;
|
||||
pid_t pid;
|
||||
|
||||
if (!list)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
/* Process options. */
|
||||
while (list)
|
||||
{
|
||||
word = list->word->word;
|
||||
|
||||
if (ISOPTION (word, 'l'))
|
||||
{
|
||||
listing++;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (word, 's'))
|
||||
{
|
||||
list = list->next;
|
||||
if (list)
|
||||
{
|
||||
sigspec = list->word->word;
|
||||
if (sigspec[0] == '0' && !sigspec[1])
|
||||
signal = 0;
|
||||
else
|
||||
signal = decode_signal (sigspec);
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error ("-s requires an argument");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (ISOPTION (word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
/* If this is a signal specification then process it. We only process
|
||||
the first one seen; other arguments may signify process groups (e.g,
|
||||
-num == process group num). */
|
||||
else if ((*word == '-') && !saw_signal)
|
||||
{
|
||||
sigspec = word + 1;
|
||||
signal = decode_signal (sigspec);
|
||||
saw_signal++;
|
||||
list = list->next;
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (listing)
|
||||
{
|
||||
if (!list)
|
||||
{
|
||||
register int i;
|
||||
register int column = 0;
|
||||
char *name;
|
||||
|
||||
for (i = 1; i < NSIG; i++)
|
||||
{
|
||||
name = signal_name (i);
|
||||
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
|
||||
continue;
|
||||
|
||||
if (posixly_correct)
|
||||
printf ("%s%s", name, (i == NSIG - 1) ? "" : " ");
|
||||
else
|
||||
{
|
||||
printf ("%2d) %s", i, name);
|
||||
|
||||
if (++column < 4)
|
||||
printf ("\t");
|
||||
else
|
||||
{
|
||||
printf ("\n");
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (posixly_correct || column != 0)
|
||||
printf ("\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
/* List individual signal names. */
|
||||
while (list)
|
||||
{
|
||||
int signum;
|
||||
char *name;
|
||||
|
||||
if ((sscanf (list->word->word, "%d", &signum) != 1) ||
|
||||
(signum <= 0))
|
||||
{
|
||||
list_error:
|
||||
builtin_error ("bad signal number: %s", list->word->word);
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* This is specified by Posix.2 so that exit statuses can be
|
||||
mapped into signal numbers. */
|
||||
if (signum > 128)
|
||||
signum -= 128;
|
||||
|
||||
if (signum >= NSIG)
|
||||
goto list_error;
|
||||
|
||||
name = signal_name (signum);
|
||||
if (STREQN (name, "SIGJUNK", 7) || STREQN (name, "Unknown", 7))
|
||||
{
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
printf ("%s\n", name);
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* OK, we are killing processes. */
|
||||
if (signal == NO_SIG)
|
||||
{
|
||||
builtin_error ("bad signal spec `%s'", sigspec);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
word = list->word->word;
|
||||
|
||||
if (*word == '-')
|
||||
word++;
|
||||
|
||||
if (all_digits (word))
|
||||
{
|
||||
/* Use the entire argument in case of minus sign presence. */
|
||||
pid = (pid_t) atoi (list->word->word);
|
||||
|
||||
if (kill_pid (pid, signal, 0) < 0)
|
||||
goto signal_error;
|
||||
else
|
||||
any_succeeded++;
|
||||
}
|
||||
else if (*list->word->word != '%')
|
||||
{
|
||||
builtin_error ("No such pid %s", list->word->word);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
#if 1
|
||||
else if (interactive)
|
||||
/* Posix.2 says you can kill without job control active (4.32.4) */
|
||||
#else
|
||||
else if (job_control) /* can't kill jobs if not using job control */
|
||||
#endif
|
||||
{ /* Must be a job spec. Check it out. */
|
||||
int job;
|
||||
sigset_t set, oset;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (job < 0 || job >= job_slots || !jobs[job])
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
builtin_error ("No such job %s", list->word->word);
|
||||
UNBLOCK_CHILD (oset);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
|
||||
/* Job spec used. Kill the process group. If the job was started
|
||||
without job control, then its pgrp == shell_pgrp, so we have
|
||||
to be careful. We take the pid of the first job in the pipeline
|
||||
in that case. */
|
||||
if (jobs[job]->flags & J_JOBCONTROL)
|
||||
pid = jobs[job]->pgrp;
|
||||
else
|
||||
pid = jobs[job]->pipe->pid;
|
||||
|
||||
UNBLOCK_CHILD (oset);
|
||||
|
||||
if (kill_pid (pid, signal, 1) < 0)
|
||||
{
|
||||
signal_error:
|
||||
if (errno == EPERM)
|
||||
builtin_error ("(%d) - Not owner", (int)pid);
|
||||
else if (errno == ESRCH)
|
||||
builtin_error ("(%d) - No such pid", (int)pid);
|
||||
else
|
||||
builtin_error ("Invalid signal %d", signal);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
else
|
||||
any_succeeded++;
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error ("bad process specification `%s'", list->word->word);
|
||||
CONTINUE_OR_FAIL;
|
||||
}
|
||||
continue_killing:
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (any_succeeded)
|
||||
return (EXECUTION_SUCCESS);
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
77
builtins/let.def
Normal file
77
builtins/let.def
Normal file
|
@ -0,0 +1,77 @@
|
|||
This file is let.def, from which is created let.c.
|
||||
It implements the builtin "let" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$BUILTIN let
|
||||
$FUNCTION let_builtin
|
||||
$PRODUCES let.c
|
||||
$SHORT_DOC let arg [arg ...]
|
||||
Each ARG is an arithmetic expression to be evaluated. Evaluation
|
||||
is done in long integers with no check for overflow, though division
|
||||
by 0 is trapped and flagged as an error. The following list of
|
||||
operators is grouped into levels of equal-precedence operators.
|
||||
The levels are listed in order of decreasing precedence.
|
||||
|
||||
- unary minus
|
||||
! logical NOT
|
||||
* / % multiplication, division, remainder
|
||||
+ - addition, subtraction
|
||||
<= >= < > comparison
|
||||
== != equality inequality
|
||||
= assignment
|
||||
|
||||
Shell variables are allowed as operands. The name of the variable
|
||||
is replaced by its value (coerced to a long integer) within
|
||||
an expression. The variable need not have its integer attribute
|
||||
turned on to be used in an expression.
|
||||
|
||||
Operators are evaluated in order of precedence. Sub-expressions in
|
||||
parentheses are evaluated first and may override the precedence
|
||||
rules above.
|
||||
|
||||
If the last ARG evaluates to 0, let returns 1; 0 is returned
|
||||
otherwise.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
/* Arithmetic LET function. */
|
||||
let_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
long ret = 0L;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
builtin_error ("argument (expression) expected");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
ret = evalexp (list->word->word);
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (ret == 0L)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
1311
builtins/mkbuiltins.c
Normal file
1311
builtins/mkbuiltins.c
Normal file
File diff suppressed because it is too large
Load diff
63
builtins/psize.c
Normal file
63
builtins/psize.c
Normal file
|
@ -0,0 +1,63 @@
|
|||
/* psize.c - Find pipe size. */
|
||||
|
||||
/* Copyright (C) 1987, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 1, or (at your option)
|
||||
any later version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with Bash; see the file COPYING. If not, write to the Free
|
||||
Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Write output in 128-byte chunks until we get a sigpipe or write gets an
|
||||
EPIPE. Then report how many bytes we wrote. We assume that this is the
|
||||
pipe size. */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "../command.h"
|
||||
#include "../general.h"
|
||||
extern int errno;
|
||||
|
||||
int nw;
|
||||
|
||||
sighandler
|
||||
sigpipe (sig)
|
||||
int sig;
|
||||
{
|
||||
fprintf (stderr, "%d\n", nw);
|
||||
exit (0);
|
||||
}
|
||||
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char **argv;
|
||||
{
|
||||
char buf[128];
|
||||
register int i;
|
||||
|
||||
for (i = 0; i < 128; i++)
|
||||
buf[i] = ' ';
|
||||
|
||||
signal (SIGPIPE, sigpipe);
|
||||
|
||||
nw = 0;
|
||||
for (;;)
|
||||
{
|
||||
int n;
|
||||
n = write (1, buf, 128);
|
||||
nw += n;
|
||||
}
|
||||
}
|
24
builtins/psize.sh
Executable file
24
builtins/psize.sh
Executable file
|
@ -0,0 +1,24 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# psize.sh -- determine this system's pipe size, and write a define to
|
||||
# pipesize.h so ulimit.c can use it.
|
||||
|
||||
echo "/*"
|
||||
echo " * pipesize.h"
|
||||
echo " *"
|
||||
echo " * This file is automatically generated by psize.sh"
|
||||
echo " * Do not edit!"
|
||||
echo " */"
|
||||
echo ""
|
||||
|
||||
./psize.aux 2>/tmp/pipesize | sleep 3
|
||||
|
||||
if [ -s /tmp/pipesize ]; then
|
||||
echo "#define PIPESIZE `cat /tmp/pipesize`"
|
||||
else
|
||||
echo "#define PIPESIZE 512"
|
||||
fi
|
||||
|
||||
rm -f /tmp/pipesize
|
||||
|
||||
exit 0
|
276
builtins/read.def
Normal file
276
builtins/read.def
Normal file
|
@ -0,0 +1,276 @@
|
|||
This file is read.def, from which is created read.c.
|
||||
It implements the builtin "read" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES read.c
|
||||
|
||||
$BUILTIN read
|
||||
$FUNCTION read_builtin
|
||||
$SHORT_DOC read [-r] [name ...]
|
||||
One line is read from the standard input, and the first word is
|
||||
assigned to the first NAME, the second word to the second NAME, etc.
|
||||
with leftover words assigned to the last NAME. Only the characters
|
||||
found in $IFS are recognized as word delimiters. The return code is
|
||||
zero, unless end-of-file is encountered. If the -r option is given,
|
||||
this signifies `raw' input, and backslash processing is disabled.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
|
||||
#define issep(c) (strchr (ifs_chars, (c)) != (char *)0)
|
||||
|
||||
static int stream_close ();
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
/* Read the value of the shell variables whose names follow.
|
||||
The reading is done from the current input stream, whatever
|
||||
that may be. Successive words of the input line are assigned
|
||||
to the variables mentioned in LIST. The last variable in LIST
|
||||
gets the remainder of the words on the line. If no variables
|
||||
are mentioned in LIST, then the default variable is $REPLY.
|
||||
|
||||
S. R. Bourne's shell complains if you don't name a variable
|
||||
to receive the stuff that is read. GNU's shell doesn't. This
|
||||
allows you to let the user type random things. */
|
||||
read_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register char *varname;
|
||||
int size, c, i, fildes, raw_mode, pass_next, saw_escape, retval;
|
||||
char *input_string, *orig_input_string, *ifs_chars, *t;
|
||||
FILE *input_stream;
|
||||
SHELL_VAR *var;
|
||||
|
||||
i = 0; /* Index into the string that we are reading. */
|
||||
raw_mode = 0; /* Not reading raw input be default. */
|
||||
|
||||
while (list)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'r'))
|
||||
{
|
||||
raw_mode = 1;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*list->word->word == '-')
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
builtin_error ("usage: read [-r] [name ...]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need unbuffered input from stdin. So we make a new stream with
|
||||
the same file descriptor as stdin, then unbuffer it. */
|
||||
fildes = dup (fileno (stdin));
|
||||
|
||||
if (fildes == -1)
|
||||
return (EXECUTION_FAILURE);
|
||||
|
||||
input_stream = fdopen (fildes, "r");
|
||||
|
||||
if (!input_stream)
|
||||
{
|
||||
close (fildes);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
var = find_variable ("IFS");
|
||||
ifs_chars = var ? value_cell (var) : " \t\n";
|
||||
|
||||
input_string = xmalloc (size = 128);
|
||||
|
||||
setbuf (input_stream, (char *)NULL);
|
||||
|
||||
begin_unwind_frame ("read_builtin");
|
||||
add_unwind_protect (xfree, input_string);
|
||||
add_unwind_protect (stream_close, input_stream);
|
||||
interrupt_immediately++;
|
||||
|
||||
pass_next = 0; /* Non-zero signifies last char was backslash. */
|
||||
saw_escape = 0; /* Non-zero signifies that we saw an escape char */
|
||||
|
||||
while ((c = getc (input_stream)) != EOF)
|
||||
{
|
||||
if (i + 2 >= size)
|
||||
input_string = xrealloc (input_string, size += 128);
|
||||
|
||||
/* If the next character is to be accepted verbatim, a backslash
|
||||
newline pair still disappears from the input. */
|
||||
if (pass_next)
|
||||
{
|
||||
if (c == '\n')
|
||||
i--; /* back up over the CTLESC */
|
||||
else
|
||||
input_string[i++] = c;
|
||||
pass_next = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\\' && !raw_mode)
|
||||
{
|
||||
pass_next++;
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
if (c == CTLESC || c == CTLNUL)
|
||||
{
|
||||
saw_escape++;
|
||||
input_string[i++] = CTLESC;
|
||||
}
|
||||
|
||||
input_string[i++] = c;
|
||||
}
|
||||
input_string[i] = '\0';
|
||||
|
||||
interrupt_immediately--;
|
||||
discard_unwind_frame ("read_builtin");
|
||||
|
||||
fclose (input_stream);
|
||||
|
||||
if (c == EOF)
|
||||
{
|
||||
retval = EXECUTION_FAILURE;
|
||||
/* input_string[0] = '\0'; */
|
||||
}
|
||||
else
|
||||
retval = EXECUTION_SUCCESS;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_variable ("REPLY", t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
var = bind_variable ("REPLY", input_string);
|
||||
var->attributes &= ~att_invisible;
|
||||
free (input_string);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This code implements the Posix.2 spec for splitting the words
|
||||
read and assigning them to variables. If $IFS is unset, we
|
||||
use the default value of " \t\n". */
|
||||
orig_input_string = input_string;
|
||||
|
||||
/* Remove IFS white space at the beginning of the input string. If
|
||||
$IFS is null, no field splitting is performed. */
|
||||
for (t = input_string; *ifs_chars && spctabnl (*t) && issep (*t); t++)
|
||||
;
|
||||
input_string = t;
|
||||
|
||||
for (; list->next; list = list->next)
|
||||
{
|
||||
char *e, *t1;
|
||||
|
||||
varname = list->word->word;
|
||||
if (legal_identifier (varname) == 0)
|
||||
{
|
||||
builtin_error ("%s: not a legal variable name", varname);
|
||||
free (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* If there are more variables than words read from the input,
|
||||
the remaining variables are set to the empty string. */
|
||||
if (*input_string)
|
||||
{
|
||||
/* This call updates INPUT_STRING. */
|
||||
t = get_word_from_string (&input_string, ifs_chars, &e);
|
||||
if (t)
|
||||
*e = '\0';
|
||||
/* Don't bother to remove the CTLESC unless we added one
|
||||
somewhere while reading the string. */
|
||||
if (t && saw_escape)
|
||||
{
|
||||
t1 = dequote_string (t);
|
||||
var = bind_variable (varname, t1);
|
||||
free (t1);
|
||||
}
|
||||
else
|
||||
var = bind_variable (varname, t);
|
||||
}
|
||||
else
|
||||
{
|
||||
t = (char *)0;
|
||||
var = bind_variable (varname, "");
|
||||
}
|
||||
|
||||
stupidly_hack_special_variables (varname);
|
||||
var->attributes &= ~att_invisible;
|
||||
|
||||
if (t)
|
||||
free (t);
|
||||
}
|
||||
|
||||
if (legal_identifier (list->word->word) == 0)
|
||||
{
|
||||
builtin_error ("%s: not a legal variable name", list->word->word);
|
||||
free (orig_input_string);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* This has to be done this way rather than using string_list
|
||||
and list_string because Posix.2 says that the last variable gets the
|
||||
remaining words and their intervening separators. */
|
||||
input_string = strip_trailing_ifs_whitespace (input_string, ifs_chars,
|
||||
saw_escape);
|
||||
|
||||
if (saw_escape)
|
||||
{
|
||||
t = dequote_string (input_string);
|
||||
var = bind_variable (list->word->word, t);
|
||||
free (t);
|
||||
}
|
||||
else
|
||||
var = bind_variable (list->word->word, input_string);
|
||||
stupidly_hack_special_variables (list->word->word);
|
||||
var->attributes &= ~att_invisible;
|
||||
free (orig_input_string);
|
||||
}
|
||||
|
||||
return (retval);
|
||||
}
|
||||
|
||||
/* This way I don't have to know whether fclose () is a
|
||||
function or a macro. */
|
||||
static int
|
||||
stream_close (file)
|
||||
FILE *file;
|
||||
{
|
||||
return (fclose (file));
|
||||
}
|
154
builtins/reserved.def
Normal file
154
builtins/reserved.def
Normal file
|
@ -0,0 +1,154 @@
|
|||
This file is reserved.def, in which the shell reserved words are defined.
|
||||
It has no direct C file production, but defines builtins for the Bash
|
||||
builtin help command.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$BUILTIN for
|
||||
$SHORT_DOC for NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The `for' loop executes a sequence of commands for each member in a
|
||||
list of items. If `in WORDS ...;' is not present, then `in "$@"' is
|
||||
assumed. For each element in WORDS, NAME is set to that element, and
|
||||
the COMMANDS are executed.
|
||||
$END
|
||||
|
||||
$BUILTIN select
|
||||
$SHORT_DOC select NAME [in WORDS ... ;] do COMMANDS; done
|
||||
The WORDS are expanded, generating a list of words. The
|
||||
set of expanded words is printed on the standard error, each
|
||||
preceded by a number. If `in WORDS' is not present, `in "$@"'
|
||||
is assumed. The PS3 prompt is then displayed and a line read
|
||||
from the standard input. If the line consists of the number
|
||||
corresponding to one of the displayed words, then NAME is set
|
||||
to that word. If the line is empty, WORDS and the prompt are
|
||||
redisplayed. If EOF is read, the command completes. Any other
|
||||
value read causes NAME to be set to null. The line read is saved
|
||||
in the variable REPLY. COMMANDS are executed after each selection
|
||||
until a break or return command is executed.
|
||||
$END
|
||||
|
||||
$BUILTIN case
|
||||
$SHORT_DOC case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
|
||||
Selectively execute COMMANDS based upon WORD matching PATTERN. The
|
||||
`|' is used to separate multiple patterns.
|
||||
$END
|
||||
|
||||
$BUILTIN if
|
||||
$SHORT_DOC if COMMANDS; then COMMANDS; [ elif COMMANDS; then COMMANDS; ]... [ else COMMANDS; ] fi
|
||||
The if COMMANDS are executed. If the exit status is zero, then the then
|
||||
COMMANDS are executed. Otherwise, each of the elif COMMANDS are executed
|
||||
in turn, and if the exit status is zero, the corresponding then COMMANDS
|
||||
are executed and the if command completes. Otherwise, the else COMMANDS
|
||||
are executed, if present. The exit status is the exit status of the last
|
||||
command executed, or zero if no condition tested true.
|
||||
$END
|
||||
|
||||
$BUILTIN while
|
||||
$SHORT_DOC while COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`while' COMMANDS has an exit status of zero.
|
||||
$END
|
||||
|
||||
$BUILTIN until
|
||||
$SHORT_DOC until COMMANDS; do COMMANDS; done
|
||||
Expand and execute COMMANDS as long as the final command in the
|
||||
`until' COMMANDS has an exit status which is not zero.
|
||||
$END
|
||||
|
||||
$BUILTIN function
|
||||
$SHORT_DOC function NAME { COMMANDS ; } or NAME () { COMMANDS ; }
|
||||
Create a simple command invoked by NAME which runs COMMANDS.
|
||||
Arguments on the command line along with NAME are passed to the
|
||||
function as $0 .. $n.
|
||||
$END
|
||||
|
||||
$BUILTIN { ... }
|
||||
$DOCNAME grouping_braces
|
||||
$SHORT_DOC { COMMANDS }
|
||||
Run a set of commands in a group. This is one way to redirect an
|
||||
entire set of commands.
|
||||
$END
|
||||
|
||||
$BUILTIN %
|
||||
$DOCNAME fg_percent
|
||||
$SHORT_DOC %[DIGITS | WORD] [&]
|
||||
This is similar to the `fg' command. Resume a stopped or background
|
||||
job. If you specifiy DIGITS, then that job is used. If you specify
|
||||
WORD, then the job whose name begins with WORD is used. Following the
|
||||
job specification with a `&' places the job in the background.
|
||||
$END
|
||||
|
||||
$BUILTIN variables
|
||||
$DOCNAME variable_help
|
||||
$SHORT_DOC variables - Some variable names and meanings
|
||||
BASH_VERSION The version numbers of this Bash.
|
||||
CDPATH A colon separated list of directories to search
|
||||
when the argument to `cd' is not found in the current
|
||||
directory.
|
||||
#if defined (HISTORY)
|
||||
HISTFILE The name of the file where your command history is stored.
|
||||
HISTFILESIZE The maximum number of lines this file can contain.
|
||||
HISTSIZE The maximum number of history lines that a running
|
||||
shell can access.
|
||||
#endif /* HISTORY */
|
||||
HOME The complete pathname to your login directory.
|
||||
HOSTTYPE The type of CPU this version of Bash is running under.
|
||||
IGNOREEOF Controls the action of the shell on receipt of an EOF
|
||||
character as the sole input. If set, then the value
|
||||
of it is the number of EOF characters that can be seen
|
||||
in a row on an empty line before the shell will exit
|
||||
(default 10). When unset, EOF signifies the end of input.
|
||||
MAILCHECK How often, in seconds, Bash checks for new mail.
|
||||
MAILPATH A colon-separated list of filenames which Bash checks
|
||||
for new mail.
|
||||
PATH A colon-separated list of directories to search when
|
||||
looking for commands.
|
||||
PROMPT_COMMAND A command to be executed before the printing of each
|
||||
primary prompt.
|
||||
PS1 The primary prompt string.
|
||||
PS2 The secondary prompt string.
|
||||
TERM The name of the current terminal type.
|
||||
auto_resume Non-null means a command word appearing on a line by
|
||||
itself is first looked for in the list of currently
|
||||
stopped jobs. If found there, that job is foregrounded.
|
||||
A value of `exact' means that the command word must
|
||||
exactly match a command in the list of stopped jobs. A
|
||||
value of `substring' means that the command word must
|
||||
match a substring of the job. Any other value means that
|
||||
the command must be a prefix of a stopped job.
|
||||
#if defined (HISTORY)
|
||||
command_oriented_history
|
||||
Non-null means to save multiple-line commands together on
|
||||
a single history line.
|
||||
# if defined (BANG_HISTORY)
|
||||
histchars Characters controlling history expansion and quick
|
||||
substitution. The first character is the history
|
||||
substitution character, usually `!'. The second is
|
||||
the `quick substitution' character, usually `^'. The
|
||||
third is the `history comment' character, usually `#'.
|
||||
# endif /* BANG_HISTORY */
|
||||
HISTCONTROL Set to a value of `ignorespace', it means don't enter
|
||||
lines which begin with a space or tab on the history
|
||||
list. Set to a value of `ignoredups', it means don't
|
||||
enter lines which match the last entered line. Set to
|
||||
`ignoreboth' means to combine the two options. Unset,
|
||||
or set to any other value than those above means to save
|
||||
all lines on the history list.
|
||||
#endif /* HISTORY */
|
||||
$END
|
57
builtins/return.def
Normal file
57
builtins/return.def
Normal file
|
@ -0,0 +1,57 @@
|
|||
This file is return.def, from which is created return.c.
|
||||
It implements the builtin "return" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES return.c
|
||||
|
||||
$BUILTIN return
|
||||
|
||||
$FUNCTION return_builtin
|
||||
$SHORT_DOC return [n]
|
||||
Causes a function to exit with the return value specified by N. If N
|
||||
is omitted, the return status is that of the last command.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
extern int last_command_exit_value;
|
||||
extern int return_catch_flag, return_catch_value;
|
||||
extern jmp_buf return_catch;
|
||||
|
||||
/* If we are executing a user-defined function then exit with the value
|
||||
specified as an argument. if no argument is given, then the last
|
||||
exit status is used. */
|
||||
int
|
||||
return_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
return_catch_value = get_numeric_arg (list);
|
||||
|
||||
if (!list)
|
||||
return_catch_value = last_command_exit_value;
|
||||
|
||||
if (return_catch_flag)
|
||||
longjmp (return_catch, 1);
|
||||
else
|
||||
{
|
||||
builtin_error ("Can only `return' from a function");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
528
builtins/set.def
Normal file
528
builtins/set.def
Normal file
|
@ -0,0 +1,528 @@
|
|||
This file is set.def, from which is created set.c.
|
||||
It implements the "set" and "unset" builtins in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES set.c
|
||||
|
||||
#include <stdio.h>
|
||||
#include "../shell.h"
|
||||
#include "../flags.h"
|
||||
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int interactive;
|
||||
extern int noclobber, no_brace_expansion, posixly_correct;
|
||||
#if defined (READLINE)
|
||||
extern int rl_editing_mode, no_line_editing;
|
||||
#endif /* READLINE */
|
||||
|
||||
#define USAGE_STRING "set [--abefhknotuvxldHCP] [-o option] [arg ...]"
|
||||
|
||||
$BUILTIN set
|
||||
$FUNCTION set_builtin
|
||||
$SHORT_DOC set [--abefhknotuvxldHCP] [-o option] [arg ...]
|
||||
-a Mark variables which are modified or created for export.
|
||||
-b Notify of job termination immediately.
|
||||
-e Exit immediately if a command exits with a non-zero status.
|
||||
-f Disable file name generation (globbing).
|
||||
-h Locate and remember function commands as functions are
|
||||
defined. Function commands are normally looked up when
|
||||
the function is executed.
|
||||
-i Force the shell to be an "interactive" one. Interactive shells
|
||||
always read `~/.bashrc' on startup.
|
||||
-k All keyword arguments are placed in the environment for a
|
||||
command, not just those that precede the command name.
|
||||
-m Job control is enabled.
|
||||
-n Read commands but do not execute them.
|
||||
-o option-name
|
||||
Set the variable corresponding to option-name:
|
||||
allexport same as -a
|
||||
braceexpand the shell will perform brace expansion
|
||||
#if defined (READLINE)
|
||||
emacs use an emacs-style line editing interface
|
||||
#endif /* READLINE */
|
||||
errexit same as -e
|
||||
#if defined (BANG_HISTORY)
|
||||
histexpand same as -H
|
||||
#endif /* BANG_HISTORY */
|
||||
ignoreeof the shell will not exit upon reading EOF
|
||||
interactive-comments
|
||||
allow comments to appear in interactive commands
|
||||
monitor same as -m
|
||||
noclobber disallow redirection to existing files
|
||||
noexec same as -n
|
||||
noglob same as -f
|
||||
nohash same as -d
|
||||
notify save as -b
|
||||
nounset same as -u
|
||||
physical same as -P
|
||||
posix change the behavior of bash where the default
|
||||
operation differs from the 1003.2 standard to
|
||||
match the standard
|
||||
privileged same as -p
|
||||
verbose same as -v
|
||||
#if defined (READLINE)
|
||||
vi use a vi-style line editing interface
|
||||
#endif /* READLINE */
|
||||
xtrace same as -x
|
||||
-p Turned on whenever the real and effective user ids do not match.
|
||||
Disables processing of the $ENV file and importing of shell
|
||||
functions. Turning this option off causes the effective uid and
|
||||
gid to be set to the real uid and gid.
|
||||
-t Exit after reading and executing one command.
|
||||
-u Treat unset variables as an error when substituting.
|
||||
-v Print shell input lines as they are read.
|
||||
-x Print commands and their arguments as they are executed.
|
||||
-l Save and restore the binding of the NAME in a FOR command.
|
||||
-d Disable the hashing of commands that are looked up for execution.
|
||||
Normally, commands are remembered in a hash table, and once
|
||||
found, do not have to be looked up again.
|
||||
#if defined (BANG_HISTORY)
|
||||
-H Enable ! style history substitution. This flag is on
|
||||
by default.
|
||||
#endif /* BANG_HISTORY */
|
||||
-C If set, disallow existing regular files to be overwritten
|
||||
by redirection of output.
|
||||
-P If set, do not follow symbolic links when executing commands
|
||||
such as cd which change the current directory.
|
||||
|
||||
Using + rather than - causes these flags to be turned off. The
|
||||
flags can also be used upon invocation of the shell. The current
|
||||
set of flags may be found in $-. The remaining n ARGs are positional
|
||||
parameters and are assigned, in order, to $1, $2, .. $n. If no
|
||||
ARGs are given, all shell variables are printed.
|
||||
$END
|
||||
|
||||
/* An a-list used to match long options for set -o to the corresponding
|
||||
option letter. */
|
||||
struct {
|
||||
char *name;
|
||||
int letter;
|
||||
} o_options[] = {
|
||||
{ "allexport", 'a' },
|
||||
{ "errexit", 'e' },
|
||||
#if defined (BANG_HISTORY)
|
||||
{ "histexpand", 'H' },
|
||||
#endif /* BANG_HISTORY */
|
||||
{ "monitor", 'm' },
|
||||
{ "noexec", 'n' },
|
||||
{ "noglob", 'f' },
|
||||
{ "nohash", 'd' },
|
||||
#if defined (JOB_CONTROL)
|
||||
{ "notify", 'b' },
|
||||
#endif /* JOB_CONTROL */
|
||||
{"nounset", 'u' },
|
||||
{"physical", 'P' },
|
||||
{"privileged", 'p' },
|
||||
{"verbose", 'v' },
|
||||
{"xtrace", 'x' },
|
||||
{(char *)NULL, 0},
|
||||
};
|
||||
|
||||
#define MINUS_O_FORMAT "%-15s\t%s\n"
|
||||
|
||||
void
|
||||
list_minus_o_opts ()
|
||||
{
|
||||
register int i;
|
||||
char *on = "on", *off = "off";
|
||||
|
||||
printf (MINUS_O_FORMAT, "braceexpand", (no_brace_expansion == 0) ? on : off);
|
||||
printf (MINUS_O_FORMAT, "noclobber", (noclobber == 1) ? on : off);
|
||||
|
||||
if (find_variable ("ignoreeof") || find_variable ("IGNOREEOF"))
|
||||
printf (MINUS_O_FORMAT, "ignoreeof", on);
|
||||
else
|
||||
printf (MINUS_O_FORMAT, "ignoreeof", off);
|
||||
|
||||
printf (MINUS_O_FORMAT, "interactive-comments",
|
||||
interactive_comments ? on : off);
|
||||
|
||||
printf (MINUS_O_FORMAT, "posix", posixly_correct ? on : off);
|
||||
|
||||
#if defined (READLINE)
|
||||
if (no_line_editing)
|
||||
{
|
||||
printf (MINUS_O_FORMAT, "emacs", off);
|
||||
printf (MINUS_O_FORMAT, "vi", off);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Magic. This code `knows' how readline handles rl_editing_mode. */
|
||||
printf (MINUS_O_FORMAT, "emacs", (rl_editing_mode == 1) ? on : off);
|
||||
printf (MINUS_O_FORMAT, "vi", (rl_editing_mode == 0) ? on : off);
|
||||
}
|
||||
#endif /* READLINE */
|
||||
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
int *on_or_off, zero = 0;
|
||||
|
||||
on_or_off = find_flag (o_options[i].letter);
|
||||
if (on_or_off == FLAG_UNKNOWN)
|
||||
on_or_off = &zero;
|
||||
printf (MINUS_O_FORMAT, o_options[i].name, (*on_or_off == 1) ? on : off);
|
||||
}
|
||||
}
|
||||
|
||||
set_minus_o_option (on_or_off, option_name)
|
||||
int on_or_off;
|
||||
char *option_name;
|
||||
{
|
||||
int option_char = -1;
|
||||
|
||||
if (STREQ (option_name, "braceexpand"))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
no_brace_expansion = 0;
|
||||
else
|
||||
no_brace_expansion = 1;
|
||||
}
|
||||
else if (STREQ (option_name, "noclobber"))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
bind_variable ("noclobber", "");
|
||||
else
|
||||
unbind_variable ("noclobber");
|
||||
stupidly_hack_special_variables ("noclobber");
|
||||
}
|
||||
else if (STREQ (option_name, "ignoreeof"))
|
||||
{
|
||||
unbind_variable ("ignoreeof");
|
||||
unbind_variable ("IGNOREEOF");
|
||||
if (on_or_off == FLAG_ON)
|
||||
bind_variable ("IGNOREEOF", "10");
|
||||
stupidly_hack_special_variables ("IGNOREEOF");
|
||||
}
|
||||
|
||||
#if defined (READLINE)
|
||||
else if ((STREQ (option_name, "emacs")) || (STREQ (option_name, "vi")))
|
||||
{
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
rl_variable_bind ("editing-mode", option_name);
|
||||
|
||||
if (interactive)
|
||||
with_input_from_stdin ();
|
||||
no_line_editing = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
int isemacs = (rl_editing_mode == 1);
|
||||
if ((isemacs && STREQ (option_name, "emacs")) ||
|
||||
(!isemacs && STREQ (option_name, "vi")))
|
||||
{
|
||||
if (interactive)
|
||||
with_input_from_stream (stdin, "stdin");
|
||||
no_line_editing = 1;
|
||||
}
|
||||
else
|
||||
builtin_error ("not in %s editing mode", option_name);
|
||||
}
|
||||
}
|
||||
#endif /* READLINE */
|
||||
else if (STREQ (option_name, "interactive-comments"))
|
||||
interactive_comments = (on_or_off == FLAG_ON);
|
||||
else if (STREQ (option_name, "posix"))
|
||||
{
|
||||
posixly_correct = (on_or_off == FLAG_ON);
|
||||
unbind_variable ("POSIXLY_CORRECT");
|
||||
unbind_variable ("POSIX_PEDANTIC");
|
||||
if (on_or_off == FLAG_ON)
|
||||
{
|
||||
bind_variable ("POSIXLY_CORRECT", "");
|
||||
stupidly_hack_special_variables ("POSIXLY_CORRECT");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
register int i;
|
||||
for (i = 0; o_options[i].name; i++)
|
||||
{
|
||||
if (STREQ (option_name, o_options[i].name))
|
||||
{
|
||||
option_char = o_options[i].letter;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (option_char == -1)
|
||||
{
|
||||
builtin_error ("%s: unknown option name", option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
if (change_flag (option_char, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
bad_option (option_name);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Set some flags from the word values in the input list. If LIST is empty,
|
||||
then print out the values of the variables instead. If LIST contains
|
||||
non-flags, then set $1 - $9 to the successive words of LIST. */
|
||||
set_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int on_or_off, flag_name, force_assignment = 0;
|
||||
|
||||
if (!list)
|
||||
{
|
||||
SHELL_VAR **vars;
|
||||
|
||||
vars = all_shell_variables ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
vars = all_shell_functions ();
|
||||
if (vars)
|
||||
{
|
||||
print_var_list (vars);
|
||||
free (vars);
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Check validity of flag arguments. */
|
||||
if (*list->word->word == '-' || *list->word->word == '+')
|
||||
{
|
||||
register char *arg;
|
||||
WORD_LIST *save_list = list;
|
||||
|
||||
while (list && (arg = list->word->word))
|
||||
{
|
||||
char c;
|
||||
|
||||
if (arg[0] != '-' && arg[0] != '+')
|
||||
break;
|
||||
|
||||
/* `-' or `--' signifies end of flag arguments. */
|
||||
if (arg[0] == '-' &&
|
||||
(!arg[1] || (arg[1] == '-' && !arg[2])))
|
||||
break;
|
||||
|
||||
while (c = *++arg)
|
||||
{
|
||||
if (find_flag (c) == FLAG_UNKNOWN && c != 'o')
|
||||
{
|
||||
char s[2];
|
||||
s[0] = c; s[1] = '\0';
|
||||
bad_option (s);
|
||||
if (c == '?')
|
||||
printf ("usage: %s\n", USAGE_STRING);
|
||||
return (c == '?' ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
list = save_list;
|
||||
}
|
||||
|
||||
/* Do the set command. While the list consists of words starting with
|
||||
'-' or '+' treat them as flags, otherwise, start assigning them to
|
||||
$1 ... $n. */
|
||||
while (list)
|
||||
{
|
||||
char *string = list->word->word;
|
||||
|
||||
/* If the argument is `--' or `-' then signal the end of the list
|
||||
and remember the remaining arguments. */
|
||||
if (string[0] == '-' && (!string[1] || (string[1] == '-' && !string[2])))
|
||||
{
|
||||
list = list->next;
|
||||
|
||||
/* `set --' unsets the positional parameters. */
|
||||
if (string[1] == '-')
|
||||
force_assignment = 1;
|
||||
|
||||
/* Until told differently, the old shell behaviour of
|
||||
`set - [arg ...]' being equivalent to `set +xv [arg ...]'
|
||||
stands. Posix.2 says the behaviour is marked as obsolescent. */
|
||||
else
|
||||
{
|
||||
change_flag ('x', '+');
|
||||
change_flag ('v', '+');
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if ((on_or_off = *string) &&
|
||||
(on_or_off == '-' || on_or_off == '+'))
|
||||
{
|
||||
int i = 1;
|
||||
while (flag_name = string[i++])
|
||||
{
|
||||
if (flag_name == '?')
|
||||
{
|
||||
printf ("usage: %s\n", USAGE_STRING);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
else if (flag_name == 'o') /* -+o option-name */
|
||||
{
|
||||
char *option_name;
|
||||
WORD_LIST *opt;
|
||||
|
||||
opt = list->next;
|
||||
|
||||
if (!opt)
|
||||
{
|
||||
list_minus_o_opts ();
|
||||
continue;
|
||||
}
|
||||
|
||||
option_name = opt->word->word;
|
||||
|
||||
if (!option_name || !*option_name || (*option_name == '-'))
|
||||
{
|
||||
list_minus_o_opts ();
|
||||
continue;
|
||||
}
|
||||
list = list->next; /* Skip over option name. */
|
||||
|
||||
if (set_minus_o_option (on_or_off, option_name) != EXECUTION_SUCCESS)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (change_flag (flag_name, on_or_off) == FLAG_ERROR)
|
||||
{
|
||||
char opt[3];
|
||||
opt[0] = on_or_off;
|
||||
opt[1] = flag_name;
|
||||
opt[2] = '\0';
|
||||
bad_option (opt);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
/* Assigning $1 ... $n */
|
||||
if (list || force_assignment)
|
||||
remember_args (list, 1);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
$BUILTIN unset
|
||||
$FUNCTION unset_builtin
|
||||
$SHORT_DOC unset [-f] [-v] [name ...]
|
||||
For each NAME, remove the corresponding variable or function. Given
|
||||
the `-v', unset will only act on variables. Given the `-f' flag,
|
||||
unset will only act on functions. With neither flag, unset first
|
||||
tries to unset a variable, and if that fails, then tries to unset a
|
||||
function. Some variables (such as PATH and IFS) cannot be unset; also
|
||||
see readonly.
|
||||
$END
|
||||
|
||||
unset_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int unset_function = 0, unset_variable = 0, opt;
|
||||
int any_failed = 0;
|
||||
char *name;
|
||||
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "fv")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'f':
|
||||
unset_function = 1;
|
||||
break;
|
||||
case 'v':
|
||||
unset_variable = 1;
|
||||
break;
|
||||
default:
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
list = loptend;
|
||||
|
||||
if (unset_function && unset_variable)
|
||||
{
|
||||
builtin_error ("cannot simultaneously unset a function and a variable");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
name = list->word->word;
|
||||
|
||||
if (!unset_function &&
|
||||
find_name_in_list (name, non_unsettable_vars) > -1)
|
||||
{
|
||||
builtin_error ("%s: cannot unset", name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR *var;
|
||||
int tem;
|
||||
|
||||
var = unset_function ? find_function (name) : find_variable (name);
|
||||
|
||||
/* Posix.2 says that unsetting readonly variables is an error. */
|
||||
if (var && readonly_p (var))
|
||||
{
|
||||
builtin_error ("%s: cannot unset: readonly %s",
|
||||
name, unset_function ? "function" : "variable");
|
||||
any_failed++;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Unless the -f option is supplied, the name refers to a
|
||||
variable. */
|
||||
tem = makunbound
|
||||
(name, unset_function ? shell_functions : shell_variables);
|
||||
|
||||
/* This is what Posix.2 draft 11+ says. ``If neither -f nor -v
|
||||
is specified, the name refers to a variable; if a variable by
|
||||
that name does not exist, a function by that name, if any,
|
||||
shall be unset.'' */
|
||||
if ((tem == -1) && !unset_function && !unset_variable)
|
||||
tem = makunbound (name, shell_functions);
|
||||
|
||||
if (tem == -1)
|
||||
any_failed++;
|
||||
else if (!unset_function)
|
||||
stupidly_hack_special_variables (name);
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (any_failed)
|
||||
return (EXECUTION_FAILURE);
|
||||
else
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
253
builtins/setattr.def
Normal file
253
builtins/setattr.def
Normal file
|
@ -0,0 +1,253 @@
|
|||
This file is setattr.def, from which is created setattr.c.
|
||||
It implements the builtins "export" and "readonly", in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES setattr.c
|
||||
|
||||
#include "../shell.h"
|
||||
#include "common.h"
|
||||
#include "bashgetopt.h"
|
||||
|
||||
extern int array_needs_making;
|
||||
extern char *this_command_name;
|
||||
|
||||
$BUILTIN export
|
||||
$FUNCTION export_builtin
|
||||
$SHORT_DOC export [-n] [-f] [name ...] or export -p
|
||||
NAMEs are marked for automatic export to the environment of
|
||||
subsequently executed commands. If the -f option is given,
|
||||
the NAMEs refer to functions. If no NAMEs are given, or if `-p'
|
||||
is given, a list of all names that are exported in this shell is
|
||||
printed. An argument of `-n' says to remove the export property
|
||||
from subsequent NAMEs. An argument of `--' disables further option
|
||||
processing.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable appear in the
|
||||
environment passed to simple commands. If there is no LIST, then
|
||||
print all such variables. An argument of `-n' says to remove the
|
||||
exported attribute from variables named in LIST. An argument of
|
||||
-f indicates that the names present in LIST refer to functions. */
|
||||
export_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_exported));
|
||||
}
|
||||
|
||||
$BUILTIN readonly
|
||||
$FUNCTION readonly_builtin
|
||||
$SHORT_DOC readonly [-n] [-f] [name ...] or readonly -p
|
||||
The given NAMEs are marked readonly and the values of these NAMEs may
|
||||
not be changed by subsequent assignment. If the -f option is given,
|
||||
then functions corresponding to the NAMEs are so marked. If no
|
||||
arguments are given, or if `-p' is given, a list of all readonly names
|
||||
is printed. An argument of `-n' says to remove the readonly property
|
||||
from subsequent NAMEs. An argument of `--' disables further option
|
||||
processing.
|
||||
$END
|
||||
|
||||
/* For each variable name in LIST, make that variable readonly. Given an
|
||||
empty LIST, print out all existing readonly variables. */
|
||||
readonly_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
return (set_or_show_attributes (list, att_readonly));
|
||||
}
|
||||
|
||||
/* For each variable name in LIST, make that variable have the specified
|
||||
ATTRIBUTE. An arg of `-n' says to remove the attribute from the the
|
||||
remaining names in LIST. */
|
||||
int
|
||||
set_or_show_attributes (list, attribute)
|
||||
register WORD_LIST *list;
|
||||
int attribute;
|
||||
{
|
||||
register SHELL_VAR *var;
|
||||
int assign, undo = 0, functions_only = 0, any_failed = 0, opt;
|
||||
|
||||
/* Read arguments from the front of the list. */
|
||||
reset_internal_getopt ();
|
||||
while ((opt = internal_getopt (list, "nfp")) != -1)
|
||||
{
|
||||
switch (opt)
|
||||
{
|
||||
case 'n':
|
||||
undo = 1;
|
||||
break;
|
||||
case 'f':
|
||||
functions_only = 1;
|
||||
break;
|
||||
case 'p':
|
||||
break;
|
||||
default:
|
||||
builtin_error ("usage: %s [-nfp] [varname]", this_command_name);
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
list = loptend;
|
||||
|
||||
if (list)
|
||||
{
|
||||
if (attribute & att_exported)
|
||||
array_needs_making = 1;
|
||||
|
||||
/* Cannot undo readonly status. */
|
||||
if (undo && (attribute & att_readonly))
|
||||
attribute &= ~att_readonly;
|
||||
|
||||
while (list)
|
||||
{
|
||||
register char *name = list->word->word;
|
||||
|
||||
if (functions_only)
|
||||
{
|
||||
var = find_function (name);
|
||||
if (!var)
|
||||
{
|
||||
builtin_error ("%s: not a function", name);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (undo)
|
||||
var->attributes &= ~attribute;
|
||||
else
|
||||
var->attributes |= attribute;
|
||||
}
|
||||
list = list->next;
|
||||
if (attribute == att_exported)
|
||||
array_needs_making++;
|
||||
continue;
|
||||
}
|
||||
|
||||
assign = assignment (name);
|
||||
|
||||
if (assign)
|
||||
name[assign] = '\0';
|
||||
if (legal_identifier (name) == 0)
|
||||
{
|
||||
builtin_error ("%s: not a legal variable name", name);
|
||||
any_failed++;
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assign)
|
||||
{
|
||||
name[assign] = '=';
|
||||
/* This word has already been expanded once with command
|
||||
and parameter expansion. Call do_assignment_no_expand (),
|
||||
which does not do command or parameter substitution. */
|
||||
do_assignment_no_expand (name);
|
||||
name[assign] = '\0';
|
||||
}
|
||||
|
||||
if (undo)
|
||||
{
|
||||
var = find_variable (name);
|
||||
if (var)
|
||||
var->attributes &= ~attribute;
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR *find_tempenv_variable (), *tv;
|
||||
|
||||
if (tv = find_tempenv_variable (name))
|
||||
{
|
||||
var = bind_variable (tv->name, tv->value);
|
||||
dispose_variable (tv);
|
||||
}
|
||||
else
|
||||
var = find_variable (name);
|
||||
|
||||
if (!var)
|
||||
{
|
||||
var = bind_variable (name, (char *)NULL);
|
||||
var->attributes |= att_invisible;
|
||||
}
|
||||
|
||||
var->attributes |= attribute;
|
||||
}
|
||||
|
||||
array_needs_making++; /* XXX */
|
||||
list = list->next;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SHELL_VAR **variable_list;
|
||||
register int i;
|
||||
|
||||
if ((attribute & att_function) || functions_only)
|
||||
{
|
||||
variable_list = all_shell_functions ();
|
||||
if (attribute != att_function)
|
||||
attribute &= ~att_function; /* so declare -xf works, for example */
|
||||
}
|
||||
else
|
||||
variable_list = all_shell_variables ();
|
||||
|
||||
if (variable_list)
|
||||
{
|
||||
for (i = 0; var = variable_list[i]; i++)
|
||||
{
|
||||
if ((var->attributes & attribute) && !invisible_p (var))
|
||||
{
|
||||
char flags[6];
|
||||
|
||||
flags[0] = '\0';
|
||||
|
||||
if (exported_p (var))
|
||||
strcat (flags, "x");
|
||||
|
||||
if (readonly_p (var))
|
||||
strcat (flags, "r");
|
||||
|
||||
if (function_p (var))
|
||||
strcat (flags, "f");
|
||||
|
||||
if (integer_p (var))
|
||||
strcat (flags, "i");
|
||||
|
||||
if (flags[0])
|
||||
{
|
||||
printf ("declare -%s ", flags);
|
||||
|
||||
if (!function_p (var))
|
||||
{
|
||||
char *x = double_quote (value_cell (var));
|
||||
printf ("%s=%s\n", var->name, x);
|
||||
free (x);
|
||||
}
|
||||
else
|
||||
{
|
||||
char *named_function_string ();
|
||||
|
||||
printf ("%s\n", named_function_string
|
||||
(var->name, function_cell (var), 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
free (variable_list);
|
||||
}
|
||||
}
|
||||
return (any_failed == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
95
builtins/shift.def
Normal file
95
builtins/shift.def
Normal file
|
@ -0,0 +1,95 @@
|
|||
This file is shift.def, from which is created shift.c.
|
||||
It implements the builtin "shift" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES shift.c
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
|
||||
$BUILTIN shift
|
||||
$FUNCTION shift_builtin
|
||||
$SHORT_DOC shift [n]
|
||||
The positional parameters from $N+1 ... are renamed to $1 ... If N is
|
||||
not given, it is assumed to be 1.
|
||||
$END
|
||||
|
||||
/* Shift the arguments ``left''. Shift DOLLAR_VARS down then take one
|
||||
off of REST_OF_ARGS and place it into DOLLAR_VARS[9]. If LIST has
|
||||
anything in it, it is a number which says where to start the
|
||||
shifting. Return > 0 if `times' > $#, otherwise 0. */
|
||||
int
|
||||
shift_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int times, number;
|
||||
WORD_LIST *args;
|
||||
|
||||
times = get_numeric_arg (list);
|
||||
|
||||
if (!times)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
if (times < 0)
|
||||
{
|
||||
builtin_error ("shift count must be >= 0");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
args = list_rest_of_args ();
|
||||
number = list_length (args);
|
||||
dispose_words (args);
|
||||
|
||||
if (times > number)
|
||||
{
|
||||
builtin_error ("shift count must be <= $#");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
while (times-- > 0)
|
||||
{
|
||||
register int count;
|
||||
|
||||
if (dollar_vars[1])
|
||||
free (dollar_vars[1]);
|
||||
|
||||
for (count = 1; count < 9; count++)
|
||||
dollar_vars[count] = dollar_vars[count + 1];
|
||||
|
||||
if (rest_of_args)
|
||||
{
|
||||
WORD_LIST *temp = rest_of_args;
|
||||
|
||||
dollar_vars[9] = savestring (temp->word->word);
|
||||
rest_of_args = rest_of_args->next;
|
||||
temp->next = (WORD_LIST *)NULL;
|
||||
dispose_words (temp);
|
||||
}
|
||||
else
|
||||
dollar_vars[9] = (char *)NULL;
|
||||
}
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
186
builtins/source.def
Normal file
186
builtins/source.def
Normal file
|
@ -0,0 +1,186 @@
|
|||
This file is source.def, from which is created source.c.
|
||||
It implements the builtins "." and "source" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES source.c
|
||||
|
||||
$BUILTIN source
|
||||
$FUNCTION source_builtin
|
||||
$SHORT_DOC source filename
|
||||
Read and execute commands from FILENAME and return. The pathnames
|
||||
in $PATH are used to find the directory containing FILENAME.
|
||||
$END
|
||||
$BUILTIN .
|
||||
$DOCNAME dot
|
||||
$FUNCTION source_builtin
|
||||
$SHORT_DOC . filename
|
||||
Read and execute commands from FILENAME and return. The pathnames
|
||||
in $PATH are used to find the directory containing FILENAME.
|
||||
$END
|
||||
/* source.c - Implements the `.' and `source' builtins. */
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include <errno.h>
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
#include "../posixstat.h"
|
||||
#include "../filecntl.h"
|
||||
#include "../execute_cmd.h"
|
||||
|
||||
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif /* !errno */
|
||||
|
||||
/* Variables used here but defined in other files. */
|
||||
extern int return_catch_flag, return_catch_value;
|
||||
extern jmp_buf return_catch;
|
||||
extern int posixly_correct;
|
||||
extern int interactive, interactive_shell, last_command_exit_value;
|
||||
|
||||
/* How many `levels' of sourced files we have. */
|
||||
int sourcelevel = 0;
|
||||
|
||||
/* If this . script is supplied arguments, we save the dollar vars and
|
||||
replace them with the script arguments for the duration of the script's
|
||||
execution. If the script does not change the dollar vars, we restore
|
||||
what we saved. If the dollar vars are changed in the script, we leave
|
||||
the new values alone and free the saved values. */
|
||||
static void
|
||||
maybe_pop_dollar_vars ()
|
||||
{
|
||||
if (dollar_vars_changed ())
|
||||
{
|
||||
dispose_saved_dollar_vars ();
|
||||
set_dollar_vars_unchanged ();
|
||||
}
|
||||
else
|
||||
pop_dollar_vars ();
|
||||
}
|
||||
|
||||
/* Read and execute commands from the file passed as argument. Guess what.
|
||||
This cannot be done in a subshell, since things like variable assignments
|
||||
take place in there. So, I open the file, place it into a large string,
|
||||
close the file, and then execute the string. */
|
||||
source_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int result, return_val;
|
||||
|
||||
/* Assume the best. */
|
||||
result = EXECUTION_SUCCESS;
|
||||
|
||||
if (list)
|
||||
{
|
||||
char *string, *filename;
|
||||
struct stat finfo;
|
||||
int fd, tt;
|
||||
|
||||
filename = find_path_file (list->word->word);
|
||||
if (!filename)
|
||||
filename = savestring (list->word->word);
|
||||
|
||||
if (((fd = open (filename, O_RDONLY)) < 0) || (fstat (fd, &finfo) < 0))
|
||||
goto file_error_exit;
|
||||
|
||||
string = (char *)xmalloc (1 + (int)finfo.st_size);
|
||||
tt = read (fd, string, finfo.st_size);
|
||||
string[finfo.st_size] = '\0';
|
||||
|
||||
/* Close the open file, preserving the state of errno. */
|
||||
{ int temp = errno; close (fd); errno = temp; }
|
||||
|
||||
if (tt != finfo.st_size)
|
||||
{
|
||||
free (string);
|
||||
|
||||
file_error_exit:
|
||||
file_error (filename);
|
||||
free (filename);
|
||||
|
||||
/* POSIX shells exit if non-interactive and file error. */
|
||||
if (posixly_correct && !interactive_shell)
|
||||
{
|
||||
last_command_exit_value = 1;
|
||||
longjmp (top_level, EXITPROG);
|
||||
}
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (tt > 80)
|
||||
tt = 80;
|
||||
|
||||
if (check_binary_file ((unsigned char *)string, tt))
|
||||
{
|
||||
free (string);
|
||||
builtin_error ("%s: cannot execute binary file", filename);
|
||||
free (filename);
|
||||
return (EX_BINARY_FILE);
|
||||
}
|
||||
|
||||
begin_unwind_frame ("File Sourcing");
|
||||
|
||||
if (list->next)
|
||||
{
|
||||
push_dollar_vars ();
|
||||
add_unwind_protect ((Function *)maybe_pop_dollar_vars, (char *)NULL);
|
||||
remember_args (list->next, 1);
|
||||
}
|
||||
|
||||
unwind_protect_int (return_catch_flag);
|
||||
unwind_protect_jmp_buf (return_catch);
|
||||
unwind_protect_int (interactive);
|
||||
unwind_protect_int (sourcelevel);
|
||||
add_unwind_protect ((Function *)xfree, filename);
|
||||
interactive = 0;
|
||||
sourcelevel++;
|
||||
|
||||
set_dollar_vars_unchanged ();
|
||||
|
||||
return_catch_flag++;
|
||||
return_val = setjmp (return_catch);
|
||||
|
||||
if (return_val)
|
||||
parse_and_execute_cleanup ();
|
||||
else
|
||||
result = parse_and_execute (string, filename, -1);
|
||||
|
||||
run_unwind_frame ("File Sourcing");
|
||||
|
||||
/* If RETURN_VAL is non-zero, then we return the value given
|
||||
to return_builtin (), since that is how we got here. */
|
||||
if (return_val)
|
||||
result = return_catch_value;
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error ("filename argument required");
|
||||
result = EXECUTION_FAILURE;
|
||||
}
|
||||
return (result);
|
||||
}
|
86
builtins/suspend.def
Normal file
86
builtins/suspend.def
Normal file
|
@ -0,0 +1,86 @@
|
|||
This file is suspend.def, from which is created suspend.c.
|
||||
It implements the builtin "suspend" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES suspend.c
|
||||
|
||||
$BUILTIN suspend
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$FUNCTION suspend_builtin
|
||||
$SHORT_DOC suspend [-f]
|
||||
Suspend the execution of this shell until it receives a SIGCONT
|
||||
signal. The `-f' if specified says not to complain about this
|
||||
being a login shell if it is; just suspend anyway.
|
||||
$END
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
|
||||
#if defined (JOB_CONTROL)
|
||||
extern int job_control;
|
||||
|
||||
static SigHandler *old_cont, *old_tstp;
|
||||
|
||||
/* Continue handler. */
|
||||
sighandler
|
||||
suspend_continue (sig)
|
||||
int sig;
|
||||
{
|
||||
set_signal_handler (SIGCONT, old_cont);
|
||||
set_signal_handler (SIGTSTP, old_tstp);
|
||||
#if !defined (VOID_SIGHANDLER)
|
||||
return (0);
|
||||
#endif /* !VOID_SIGHANDLER */
|
||||
}
|
||||
|
||||
/* Suspending the shell. If -f is the arg, then do the suspend
|
||||
no matter what. Otherwise, complain if a login shell. */
|
||||
int
|
||||
suspend_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
if (!job_control)
|
||||
{
|
||||
builtin_error ("Cannot suspend a shell without job control");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
if (list)
|
||||
if (strcmp (list->word->word, "-f") == 0)
|
||||
goto do_suspend;
|
||||
|
||||
no_args (list);
|
||||
|
||||
if (login_shell)
|
||||
{
|
||||
builtin_error ("Can't suspend a login shell");
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
do_suspend:
|
||||
old_cont = (SigHandler *)set_signal_handler (SIGCONT, suspend_continue);
|
||||
old_tstp = (SigHandler *)set_signal_handler (SIGTSTP, SIG_DFL);
|
||||
killpg (shell_pgrp, SIGTSTP);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
#endif /* JOB_CONTROL */
|
144
builtins/test.def
Normal file
144
builtins/test.def
Normal file
|
@ -0,0 +1,144 @@
|
|||
This file is test.def, from which is created test.c.
|
||||
It implements the builtin "test" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES test.c
|
||||
|
||||
$BUILTIN test
|
||||
$FUNCTION test_builtin
|
||||
$SHORT_DOC test [expr]
|
||||
Exits with a status of 0 (trueness) or 1 (falseness) depending on
|
||||
the evaluation of EXPR. Expressions may be unary or binary. Unary
|
||||
expressions are often used to examine the status of a file. There
|
||||
are string operators as well, and numeric comparison operators.
|
||||
|
||||
File operators:
|
||||
|
||||
-b FILE True if file is block special.
|
||||
-c FILE True if file is character special.
|
||||
-d FILE True if file is a directory.
|
||||
-e FILE True if file exists.
|
||||
-f FILE True if file exists and is a regular file.
|
||||
-g FILE True if file is set-group-id.
|
||||
-h FILE True if file is a symbolic link. Use "-L".
|
||||
-L FILE True if file is a symbolic link.
|
||||
-k FILE True if file has its "sticky" bit set.
|
||||
-p FILE True if file is a named pipe.
|
||||
-r FILE True if file is readable by you.
|
||||
-s FILE True if file is not empty.
|
||||
-S FILE True if file is a socket.
|
||||
-t FD True if FD is opened on a terminal.
|
||||
-u FILE True if the file is set-user-id.
|
||||
-w FILE True if the file is writable by you.
|
||||
-x FILE True if the file is executable by you.
|
||||
-O FILE True if the file is effectively owned by you.
|
||||
-G FILE True if the file is effectively owned by your group.
|
||||
|
||||
FILE1 -nt FILE2 True if file1 is newer than (according to
|
||||
modification date) file2.
|
||||
|
||||
FILE1 -ot FILE2 True if file1 is older than file2.
|
||||
|
||||
FILE1 -ef FILE2 True if file1 is a hard link to file2.
|
||||
|
||||
String operators:
|
||||
|
||||
-z STRING True if string is empty.
|
||||
|
||||
-n STRING
|
||||
or STRING True if string is not empty.
|
||||
|
||||
STRING1 = STRING2
|
||||
True if the strings are equal.
|
||||
STRING1 != STRING2
|
||||
True if the strings are not equal.
|
||||
|
||||
Other operators:
|
||||
|
||||
! EXPR True if expr is false.
|
||||
EXPR1 -a EXPR2 True if both expr1 AND expr2 are true.
|
||||
EXPR1 -o EXPR2 True if either expr1 OR expr2 is true.
|
||||
|
||||
arg1 OP arg2 Arithmetic tests. OP is one of -eq, -ne,
|
||||
-lt, -le, -gt, or -ge.
|
||||
|
||||
Arithmetic binary operators return true if ARG1 is equal, not-equal,
|
||||
less-than, less-than-or-equal, greater-than, or greater-than-or-equal
|
||||
than ARG2.
|
||||
$END
|
||||
|
||||
$BUILTIN [
|
||||
$DOCNAME test_bracket
|
||||
$FUNCTION test_builtin
|
||||
$SHORT_DOC [ arg... ]
|
||||
This is a synonym for the "test" shell builtin, excepting that the
|
||||
last argument must be literally `]', to match the `[' which invoked
|
||||
the test.
|
||||
$END
|
||||
|
||||
#if defined (HAVE_STRING_H)
|
||||
# include <string.h>
|
||||
#else /* !HAVE_STRING_H */
|
||||
# include <strings.h>
|
||||
#endif /* !HAVE_STRING_H */
|
||||
|
||||
#include "../shell.h"
|
||||
extern char *this_command_name;
|
||||
|
||||
/* TEST/[ builtin. */
|
||||
int
|
||||
test_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
char **argv;
|
||||
int argc, result;
|
||||
WORD_LIST *t = list;
|
||||
|
||||
/* We let Matthew Bradburn and Kevin Braunsdorf's code do the
|
||||
actual test command. So turn the list of args into an array
|
||||
of strings, since that is what his code wants. */
|
||||
if (!list)
|
||||
{
|
||||
if (this_command_name[0] == '[' && !this_command_name[1])
|
||||
builtin_error ("missing `]'");
|
||||
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/* Get the length of the argument list. */
|
||||
for (argc = 0; t; t = t->next, argc++);
|
||||
|
||||
/* Account for argv[0] being a command name. This makes our life easier. */
|
||||
argc++;
|
||||
argv = (char **)xmalloc ((1 + argc) * sizeof (char *));
|
||||
argv[argc] = (char *)NULL;
|
||||
|
||||
/* this_command_name is the name of the command that invoked this
|
||||
function. So you can't call test_builtin () directly from
|
||||
within this code, there are too many things to worry about. */
|
||||
argv[0] = savestring (this_command_name);
|
||||
|
||||
for (t = list, argc = 1; t; t = t->next, argc++)
|
||||
argv[argc] = savestring (t->word->word);
|
||||
|
||||
result = test_command (argc, argv);
|
||||
free_array (argv);
|
||||
return (result);
|
||||
}
|
89
builtins/times.def
Normal file
89
builtins/times.def
Normal file
|
@ -0,0 +1,89 @@
|
|||
This file is times.def, from which is created times.c.
|
||||
It implements the builtin "times" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES times.c
|
||||
|
||||
$BUILTIN times
|
||||
$FUNCTION times_builtin
|
||||
$SHORT_DOC times
|
||||
Print the accumulated user and system times for processes run from
|
||||
the shell.
|
||||
$END
|
||||
|
||||
#include "../shell.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
#if defined (hpux) || defined (USGr4) || defined (XD88) || defined (USGr3)
|
||||
# undef HAVE_RESOURCE
|
||||
#endif /* hpux || USGr4 || XD88 || USGr3 */
|
||||
|
||||
#if defined (_POSIX_VERSION) || !defined (HAVE_RESOURCE)
|
||||
# include <sys/times.h>
|
||||
#else /* !_POSIX_VERSION && HAVE_RESOURCE */
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#endif /* !_POSIX_VERSION && HAVE_RESOURCE */
|
||||
|
||||
/* Print the totals for system and user time used. The
|
||||
information comes from variables in jobs.c used to keep
|
||||
track of this stuff. */
|
||||
times_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
#if !defined (_POSIX_VERSION) && defined (HAVE_RESOURCE) && defined (RUSAGE_SELF)
|
||||
struct rusage self, kids;
|
||||
|
||||
getrusage (RUSAGE_SELF, &self);
|
||||
getrusage (RUSAGE_CHILDREN, &kids); /* terminated child processes */
|
||||
|
||||
print_timeval (&self.ru_utime);
|
||||
putchar (' ');
|
||||
print_timeval (&self.ru_stime);
|
||||
putchar ('\n');
|
||||
print_timeval (&kids.ru_utime);
|
||||
putchar (' ');
|
||||
print_timeval (&kids.ru_stime);
|
||||
putchar ('\n');
|
||||
|
||||
#else /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */
|
||||
# if !defined (BrainDeath)
|
||||
struct tms t;
|
||||
|
||||
times (&t);
|
||||
|
||||
/* As of System V.3, HP-UX 6.5, and other ATT-like systems, this stuff is
|
||||
returned in terms of clock ticks (HZ from sys/param.h). C'mon, guys.
|
||||
This kind of stupid clock-dependent stuff is exactly the reason 4.2BSD
|
||||
introduced the `timeval' struct. */
|
||||
|
||||
print_time_in_hz (t.tms_utime);
|
||||
putchar (' ');
|
||||
print_time_in_hz (t.tms_stime);
|
||||
putchar ('\n');
|
||||
print_time_in_hz (t.tms_cutime);
|
||||
putchar (' ');
|
||||
print_time_in_hz (t.tms_cstime);
|
||||
putchar ('\n');
|
||||
# endif /* BrainDeath */
|
||||
#endif /* _POSIX_VERSION || !HAVE_RESOURCE || !RUSAGE_SELF */
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
204
builtins/trap.def
Normal file
204
builtins/trap.def
Normal file
|
@ -0,0 +1,204 @@
|
|||
This file is trap.def, from which is created trap.c.
|
||||
It implements the builtin "trap" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES trap.c
|
||||
|
||||
$BUILTIN trap
|
||||
$FUNCTION trap_builtin
|
||||
$SHORT_DOC trap [arg] [signal_spec]
|
||||
The command ARG is to be read and executed when the shell receives
|
||||
signal(s) SIGNAL_SPEC. If ARG is absent all specified signals are
|
||||
reset to their original values. If ARG is the null string this
|
||||
signal is ignored by the shell and by the commands it invokes. If
|
||||
SIGNAL_SPEC is EXIT (0) the command ARG is executed on exit from
|
||||
the shell. The trap command with no arguments prints the list of
|
||||
commands associated with each signal number. SIGNAL_SPEC is either
|
||||
a signal name in <signal.h>, or a signal number. The syntax `trap -l'
|
||||
prints a list of signal names and their corresponding numbers.
|
||||
Note that a signal can be sent to the shell with "kill -signal $$".
|
||||
$END
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include "../shell.h"
|
||||
#include "../trap.h"
|
||||
#include "common.h"
|
||||
|
||||
/* The trap command:
|
||||
|
||||
trap <arg> <signal ...>
|
||||
trap <signal ...>
|
||||
trap -l
|
||||
trap [--]
|
||||
|
||||
Set things up so that ARG is executed when SIGNAL(s) N is recieved.
|
||||
If ARG is the empty string, then ignore the SIGNAL(s). If there is
|
||||
no ARG, then set the trap for SIGNAL(s) to its original value. Just
|
||||
plain "trap" means to print out the list of commands associated with
|
||||
each signal number. Single arg of "-l" means list the signal names. */
|
||||
|
||||
/* Possible operations to perform on the list of signals.*/
|
||||
#define SET 0 /* Set this signal to first_arg. */
|
||||
#define REVERT 1 /* Revert to this signals original value. */
|
||||
#define IGNORE 2 /* Ignore this signal. */
|
||||
|
||||
extern int interactive;
|
||||
|
||||
trap_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
register int i;
|
||||
int list_signal_names = 0;
|
||||
|
||||
while (list)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'l'))
|
||||
{
|
||||
list_signal_names++;
|
||||
list = list->next;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if ((*list->word->word == '-') && list->word->word[1])
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
builtin_error ("usage: trap [-l] [arg] [sigspec]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (list_signal_names)
|
||||
{
|
||||
int column = 0;
|
||||
|
||||
for (i = 0; i < NSIG; i++)
|
||||
{
|
||||
printf ("%2d) %s", i, signal_name (i));
|
||||
if (++column < 4)
|
||||
printf ("\t");
|
||||
else
|
||||
{
|
||||
printf ("\n");
|
||||
column = 0;
|
||||
}
|
||||
}
|
||||
if (column != 0)
|
||||
printf ("\n");
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (list)
|
||||
{
|
||||
char *first_arg = list->word->word;
|
||||
int operation = SET, any_failed = 0;
|
||||
|
||||
if (signal_object_p (first_arg))
|
||||
operation = REVERT;
|
||||
else
|
||||
{
|
||||
list = list->next;
|
||||
if (*first_arg == '\0')
|
||||
operation = IGNORE;
|
||||
else if (first_arg[0] == '-' && !first_arg[1])
|
||||
operation = REVERT;
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
int sig;
|
||||
|
||||
sig = decode_signal (list->word->word);
|
||||
|
||||
if (sig == NO_SIG)
|
||||
{
|
||||
builtin_error ("%s: not a signal specification",
|
||||
list->word->word);
|
||||
any_failed++;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (operation)
|
||||
{
|
||||
case SET:
|
||||
set_signal (sig, first_arg);
|
||||
break;
|
||||
|
||||
case REVERT:
|
||||
restore_default_signal (sig);
|
||||
|
||||
/* Signals that the shell treats specially need special
|
||||
handling. */
|
||||
switch (sig)
|
||||
{
|
||||
case SIGINT:
|
||||
if (interactive)
|
||||
set_signal_handler (SIGINT, sigint_sighandler);
|
||||
else
|
||||
set_signal_handler (SIGINT, termination_unwind_protect);
|
||||
break;
|
||||
|
||||
case SIGQUIT:
|
||||
/* Always ignore SIGQUIT. */
|
||||
set_signal_handler (SIGQUIT, SIG_IGN);
|
||||
break;
|
||||
case SIGTERM:
|
||||
#if defined (JOB_CONTROL)
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
case SIGTSTP:
|
||||
#endif /* JOB_CONTROL */
|
||||
if (interactive)
|
||||
set_signal_handler (sig, SIG_IGN);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case IGNORE:
|
||||
ignore_signal (sig);
|
||||
break;
|
||||
}
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
return ((!any_failed) ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
for (i = 0; i < NSIG; i++)
|
||||
{
|
||||
char *t, *p;
|
||||
|
||||
p = trap_list[i];
|
||||
|
||||
if (p == (char *)DEFAULT_SIG)
|
||||
continue;
|
||||
|
||||
t = (p == (char *)IGNORE_SIG) ? (char *)NULL : single_quote (p);
|
||||
printf ("trap -- %s %s\n", t ? t : "''", signal_name (i));
|
||||
if (t)
|
||||
free (t);
|
||||
}
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
325
builtins/type.def
Normal file
325
builtins/type.def
Normal file
|
@ -0,0 +1,325 @@
|
|||
This file is type.def, from which is created type.c.
|
||||
It implements the builtin "type" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991, 1992 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES type.c
|
||||
|
||||
$BUILTIN type
|
||||
$FUNCTION type_builtin
|
||||
$SHORT_DOC type [-all] [-type | -path] [name ...]
|
||||
For each NAME, indicate how it would be interpreted if used as a
|
||||
command name.
|
||||
|
||||
If the -type flag is used, returns a single word which is one of
|
||||
`alias', `keyword', `function', `builtin', `file' or `', if NAME is an
|
||||
alias, shell reserved word, shell function, shell builtin, disk file,
|
||||
or unfound, respectively.
|
||||
|
||||
If the -path flag is used, either returns the name of the disk file
|
||||
that would be exec'ed, or nothing if -type wouldn't return `file'.
|
||||
|
||||
If the -all flag is used, displays all of the places that contain an
|
||||
executable named `file'. This includes aliases and functions, if and
|
||||
only if the -path flag is not also used.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include "../posixstat.h"
|
||||
#include "../shell.h"
|
||||
#include "../execute_cmd.h"
|
||||
|
||||
#if defined (ALIAS)
|
||||
#include "../alias.h"
|
||||
#endif /* ALIAS */
|
||||
|
||||
#include "common.h"
|
||||
|
||||
extern STRING_INT_ALIST word_token_alist[];
|
||||
|
||||
/* For each word in LIST, find out what the shell is going to do with
|
||||
it as a simple command. i.e., which file would this shell use to
|
||||
execve, or if it is a builtin command, or an alias. Possible flag
|
||||
arguments:
|
||||
-type Returns the "type" of the object, one of
|
||||
`alias', `keyword', `function', `builtin',
|
||||
or `file'.
|
||||
|
||||
-path Returns the pathname of the file if -type is
|
||||
a file.
|
||||
|
||||
-all Returns all occurrences of words, whether they
|
||||
be a filename in the path, alias, function,
|
||||
or builtin.
|
||||
Order of evaluation:
|
||||
alias
|
||||
keyword
|
||||
function
|
||||
builtin
|
||||
file
|
||||
*/
|
||||
type_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int path_only, type_only, all, verbose;
|
||||
int successful_finds;
|
||||
|
||||
path_only = type_only = all = 0;
|
||||
successful_finds = 0;
|
||||
|
||||
if (!list)
|
||||
return (EXECUTION_SUCCESS);
|
||||
|
||||
while (list && *(list->word->word) == '-')
|
||||
{
|
||||
char *flag = &(list->word->word[1]);
|
||||
|
||||
if (flag[0] == 't' && (!flag[1] || strcmp (flag + 1, "ype") == 0))
|
||||
{
|
||||
type_only = 1;
|
||||
path_only = 0;
|
||||
}
|
||||
else if (flag[0] == 'p' && (!flag[1] || strcmp (flag + 1, "ath") == 0))
|
||||
{
|
||||
path_only = 1;
|
||||
type_only = 0;
|
||||
}
|
||||
else if (flag[0] == 'a' && (!flag[1] || strcmp (flag + 1, "ll") == 0))
|
||||
{
|
||||
all = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
bad_option (flag);
|
||||
builtin_error ("usage: type [-all | -path | -type ] name [name ...]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
if (type_only)
|
||||
verbose = 1;
|
||||
else if (!path_only)
|
||||
verbose = 2;
|
||||
else if (path_only)
|
||||
verbose = 3;
|
||||
else
|
||||
verbose = 0;
|
||||
|
||||
while (list)
|
||||
{
|
||||
int found;
|
||||
|
||||
found = describe_command (list->word->word, verbose, all);
|
||||
|
||||
if (!found && !path_only && !type_only)
|
||||
builtin_error ("%s: not found", list->word->word);
|
||||
|
||||
successful_finds += found;
|
||||
list = list->next;
|
||||
}
|
||||
|
||||
fflush (stdout);
|
||||
|
||||
if (successful_finds != 0)
|
||||
return (EXECUTION_SUCCESS);
|
||||
else
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
/*
|
||||
* Describe COMMAND as required by the type builtin.
|
||||
*
|
||||
* If VERBOSE == 0, don't print anything
|
||||
* If VERBOSE == 1, print short description as for `type -t'
|
||||
* If VERBOSE == 2, print long description as for `type' and `command -V'
|
||||
* If VERBOSE == 3, print path name only for disk files
|
||||
* If VERBOSE == 4, print string used to invoke COMMAND, for `command -v'
|
||||
*
|
||||
* ALL says whether or not to look for all occurrences of COMMAND, or
|
||||
* return after finding it once.
|
||||
*/
|
||||
describe_command (command, verbose, all)
|
||||
char *command;
|
||||
int verbose, all;
|
||||
{
|
||||
int found = 0, i, found_file = 0;
|
||||
char *full_path = (char *)NULL;
|
||||
SHELL_VAR *func;
|
||||
|
||||
#if defined (ALIAS)
|
||||
/* Command is an alias? */
|
||||
ASSOC *alias = find_alias (command);
|
||||
|
||||
if (alias)
|
||||
{
|
||||
if (verbose == 1)
|
||||
printf ("alias\n");
|
||||
else if (verbose == 2)
|
||||
printf ("%s is aliased to `%s'\n", command, alias->value);
|
||||
else if (verbose == 4)
|
||||
{
|
||||
char *x = single_quote (alias->value);
|
||||
printf ("alias %s=%s\n", command, x);
|
||||
free (x);
|
||||
}
|
||||
|
||||
found = 1;
|
||||
|
||||
if (!all)
|
||||
return (1);
|
||||
}
|
||||
#endif /* ALIAS */
|
||||
|
||||
/* Command is a shell reserved word? */
|
||||
i = find_reserved_word (command);
|
||||
if (i >= 0)
|
||||
{
|
||||
if (verbose == 1)
|
||||
printf ("keyword\n");
|
||||
else if (verbose == 2)
|
||||
printf ("%s is a shell keyword\n", command);
|
||||
else if (verbose == 4)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (!all)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a function? */
|
||||
func = find_function (command);
|
||||
|
||||
if (func)
|
||||
{
|
||||
if (verbose == 1)
|
||||
printf ("function\n");
|
||||
else if (verbose == 2)
|
||||
{
|
||||
#define PRETTY_PRINT_FUNC 1
|
||||
char *result;
|
||||
|
||||
printf ("%s is a function\n", command);
|
||||
|
||||
/* We're blowing away THE_PRINTED_COMMAND here... */
|
||||
|
||||
result = named_function_string (command,
|
||||
(COMMAND *) function_cell (func),
|
||||
PRETTY_PRINT_FUNC);
|
||||
printf ("%s\n", result);
|
||||
#undef PRETTY_PRINT_FUNC
|
||||
}
|
||||
else if (verbose == 4)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (!all)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a builtin? */
|
||||
if (find_shell_builtin (command))
|
||||
{
|
||||
if (verbose == 1)
|
||||
printf ("builtin\n");
|
||||
else if (verbose == 2)
|
||||
printf ("%s is a shell builtin\n", command);
|
||||
else if (verbose == 4)
|
||||
printf ("%s\n", command);
|
||||
|
||||
found = 1;
|
||||
|
||||
if (!all)
|
||||
return (1);
|
||||
}
|
||||
|
||||
/* Command is a disk file? */
|
||||
/* If the command name given is already an absolute command, just
|
||||
check to see if it is executable. */
|
||||
if (absolute_program (command))
|
||||
{
|
||||
int f = file_status (command);
|
||||
if (f & FS_EXECABLE)
|
||||
{
|
||||
if (verbose == 1)
|
||||
printf ("file\n");
|
||||
else if (verbose == 2)
|
||||
printf ("%s is %s\n", command, command);
|
||||
else if (verbose == 3 || verbose == 4)
|
||||
printf ("%s\n", command);
|
||||
|
||||
/* There's no use looking in the hash table or in $PATH,
|
||||
because they're not consulted when an absolute program
|
||||
name is supplied. */
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* If the user isn't doing "-all", then we might care about
|
||||
whether the file is present in our hash table. */
|
||||
if (!all)
|
||||
{
|
||||
if ((full_path = find_hashed_filename (command)) != (char *)NULL)
|
||||
{
|
||||
if (verbose == 1)
|
||||
printf ("file\n");
|
||||
else if (verbose == 2)
|
||||
printf ("%s is hashed (%s)\n", command, full_path);
|
||||
else if (verbose == 3 || verbose == 4)
|
||||
printf ("%s\n", full_path);
|
||||
|
||||
return (1);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now search through $PATH. */
|
||||
while (1)
|
||||
{
|
||||
if (!all)
|
||||
full_path = find_user_command (command);
|
||||
else
|
||||
full_path =
|
||||
user_command_matches (command, FS_EXEC_ONLY, found_file);
|
||||
/* XXX - should that be FS_EXEC_PREFERRED? */
|
||||
|
||||
if (!full_path)
|
||||
break;
|
||||
|
||||
found_file++;
|
||||
found = 1;
|
||||
|
||||
if (verbose == 1)
|
||||
printf ("file\n");
|
||||
else if (verbose == 2)
|
||||
printf ("%s is %s\n", command, full_path);
|
||||
else if (verbose == 3 || verbose == 4)
|
||||
printf ("%s\n", full_path);
|
||||
|
||||
free (full_path);
|
||||
full_path = (char *)NULL;
|
||||
|
||||
if (!all)
|
||||
break;
|
||||
}
|
||||
|
||||
return (found);
|
||||
}
|
731
builtins/ulimit.def
Normal file
731
builtins/ulimit.def
Normal file
|
@ -0,0 +1,731 @@
|
|||
This file is ulimit.def, from which is created ulimit.c.
|
||||
It implements the builtin "ulimit" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES ulimit.c
|
||||
|
||||
$BUILTIN ulimit
|
||||
$FUNCTION ulimit_builtin
|
||||
$DEPENDS_ON !MINIX
|
||||
$SHORT_DOC ulimit [-SHacdfmstpnuv [limit]]
|
||||
Ulimit provides control over the resources available to processes
|
||||
started by the shell, on systems that allow such control. If an
|
||||
option is given, it is interpreted as follows:
|
||||
|
||||
-S use the `soft' resource limit
|
||||
-H use the `hard' resource limit
|
||||
-a all current limits are reported
|
||||
-c the maximum size of core files created
|
||||
-d the maximum size of a process's data segment
|
||||
-m the maximum resident set size
|
||||
-s the maximum stack size
|
||||
-t the maximum amount of cpu time in seconds
|
||||
-f the maximum size of files created by the shell
|
||||
-p the pipe buffer size
|
||||
-n the maximum number of open file descriptors
|
||||
-u the maximum number of user processes
|
||||
-v the size of virtual memory
|
||||
|
||||
If LIMIT is given, it is the new value of the specified resource.
|
||||
Otherwise, the current value of the specified resource is printed.
|
||||
If no option is given, then -f is assumed. Values are in 1k
|
||||
increments, except for -t, which is in seconds, -p, which is in
|
||||
increments of 512 bytes, and -u, which is an unscaled number of
|
||||
processes.
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/param.h>
|
||||
#include <errno.h>
|
||||
#include "../shell.h"
|
||||
#include "pipesize.h"
|
||||
|
||||
#if !defined (errno)
|
||||
extern int errno;
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
# include <sys/time.h>
|
||||
# include <sys/resource.h>
|
||||
#else
|
||||
# include <sys/times.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_UNISTD_H)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_LIMITS_H)
|
||||
# include <limits.h>
|
||||
#endif
|
||||
|
||||
/* Check for the most basic symbols. If they aren't present, this
|
||||
system's <sys/resource.h> isn't very useful to us. */
|
||||
#if !defined (RLIMIT_FSIZE) || defined (GETRLIMIT_MISSING)
|
||||
# undef HAVE_RESOURCE
|
||||
#endif
|
||||
|
||||
#if !defined (RLIMTYPE)
|
||||
# define RLIMTYPE long
|
||||
# define string_to_rlimtype string_to_long
|
||||
# define print_rlimtype(num, nl) printf ("%ld%s", num, nl ? "\n" : "")
|
||||
#endif
|
||||
|
||||
static void print_long ();
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* Ulimit builtin and Hacks. */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
/* Block size for ulimit operations. */
|
||||
#define ULIMIT_BLOCK_SIZE ((long)1024)
|
||||
|
||||
#define u_FILE_SIZE 0x001
|
||||
#define u_MAX_BREAK_VAL 0x002
|
||||
#define u_PIPE_SIZE 0x004
|
||||
#define u_CORE_FILE_SIZE 0x008
|
||||
#define u_DATA_SEG_SIZE 0x010
|
||||
#define u_PHYS_MEM_SIZE 0x020
|
||||
#define u_CPU_TIME_LIMIT 0x040
|
||||
#define u_STACK_SIZE 0x080
|
||||
#define u_NUM_OPEN_FILES 0x100
|
||||
#define u_MAX_VIRTUAL_MEM 0x200
|
||||
#define u_MAX_USER_PROCS 0x400
|
||||
|
||||
#define u_ALL_LIMITS 0x7ff
|
||||
|
||||
#if !defined (RLIM_INFINITY)
|
||||
# define RLIM_INFINITY 0x7fffffff
|
||||
#endif
|
||||
|
||||
/* Some systems use RLIMIT_NOFILE, others use RLIMIT_OFILE */
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_OFILE) && !defined (RLIMIT_NOFILE)
|
||||
# define RLIMIT_NOFILE RLIMIT_OFILE
|
||||
#endif /* HAVE_RESOURCE && RLIMIT_OFILE && !RLIMIT_NOFILE */
|
||||
|
||||
#define LIMIT_HARD 0x01
|
||||
#define LIMIT_SOFT 0x02
|
||||
|
||||
static RLIMTYPE shell_ulimit ();
|
||||
static RLIMTYPE pipesize ();
|
||||
static RLIMTYPE open_files ();
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
static RLIMTYPE getmaxvm ();
|
||||
#endif /* HAVE_RESOURCE */
|
||||
|
||||
static void print_specific_limits ();
|
||||
static void print_all_limits ();
|
||||
|
||||
static char t[2];
|
||||
|
||||
/* Return 1 if the limit associated with CMD can be raised from CURRENT
|
||||
to NEW. This is for USG systems without HAVE_RESOURCE, most of which
|
||||
do not allow any user other than root to raise limits. There are,
|
||||
however, exceptions. */
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
static int
|
||||
canraise (cmd, current, new)
|
||||
int cmd;
|
||||
RLIMTYPE current, new;
|
||||
{
|
||||
# if defined (HAVE_SETDTABLESIZE)
|
||||
if (cmd == u_NUM_OPEN_FILES)
|
||||
return (1);
|
||||
# endif /* HAVE_SETDTABLSIZE */
|
||||
|
||||
return ((current > new) || (current_user.uid == 0));
|
||||
}
|
||||
#endif /* !HAVE_RESOURCE */
|
||||
|
||||
/* Report or set limits associated with certain per-process resources.
|
||||
See the help documentation in builtins.c for a full description.
|
||||
|
||||
Rewritten by Chet Ramey 6/30/91. */
|
||||
int
|
||||
ulimit_builtin (list)
|
||||
register WORD_LIST *list;
|
||||
{
|
||||
register char *s;
|
||||
int c, setting, cmd, mode, verbose_print, opt_eof;
|
||||
int all_limits, specific_limits;
|
||||
long block_factor;
|
||||
RLIMTYPE current_limit, real_limit, limit;
|
||||
|
||||
c = mode = verbose_print = opt_eof = 0;
|
||||
limit = (RLIMTYPE)-1;
|
||||
|
||||
do
|
||||
{
|
||||
cmd = setting = all_limits = specific_limits = 0;
|
||||
block_factor = ULIMIT_BLOCK_SIZE;
|
||||
|
||||
/* read_options: */
|
||||
if (list && !opt_eof && *list->word->word == '-')
|
||||
{
|
||||
s = &(list->word->word[1]);
|
||||
list = list->next;
|
||||
|
||||
while (*s && (c = *s++))
|
||||
{
|
||||
switch (c)
|
||||
{
|
||||
#define ADD_CMD(x) { if (cmd) specific_limits++; cmd |= (x); }
|
||||
|
||||
case '-': /* ulimit -- */
|
||||
opt_eof++;
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
all_limits++;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
ADD_CMD (u_FILE_SIZE);
|
||||
break;
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
/* -S and -H are modifiers, not real options. */
|
||||
case 'S':
|
||||
mode |= LIMIT_SOFT;
|
||||
break;
|
||||
|
||||
case 'H':
|
||||
mode |= LIMIT_HARD;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
ADD_CMD (u_CORE_FILE_SIZE);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
ADD_CMD (u_DATA_SEG_SIZE);
|
||||
break;
|
||||
|
||||
#if !defined (USGr4)
|
||||
case 'm':
|
||||
ADD_CMD (u_PHYS_MEM_SIZE);
|
||||
break;
|
||||
#endif /* USGr4 */
|
||||
|
||||
case 't':
|
||||
ADD_CMD (u_CPU_TIME_LIMIT);
|
||||
block_factor = 1; /* seconds */
|
||||
break;
|
||||
|
||||
case 's':
|
||||
ADD_CMD (u_STACK_SIZE);
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
ADD_CMD (u_MAX_VIRTUAL_MEM);
|
||||
block_factor = 1;
|
||||
break;
|
||||
|
||||
case 'u':
|
||||
ADD_CMD (u_MAX_USER_PROCS);
|
||||
block_factor = 1;
|
||||
break;
|
||||
|
||||
#endif /* HAVE_RESOURCE */
|
||||
|
||||
case 'p':
|
||||
ADD_CMD (u_PIPE_SIZE);
|
||||
block_factor = 512;
|
||||
break;
|
||||
|
||||
case 'n':
|
||||
ADD_CMD (u_NUM_OPEN_FILES);
|
||||
block_factor = 1;
|
||||
break;
|
||||
|
||||
default: /* error_case: */
|
||||
t[0] = c;
|
||||
t[1] = '\0';
|
||||
bad_option (t);
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
builtin_error("usage: ulimit [-afnp] [new limit]");
|
||||
#else
|
||||
builtin_error("usage: ulimit [-SHacmdstfnpuv] [new limit]");
|
||||
#endif
|
||||
return (EX_USAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (all_limits)
|
||||
{
|
||||
print_all_limits (mode);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
if (specific_limits)
|
||||
{
|
||||
print_specific_limits (cmd, mode);
|
||||
if (list)
|
||||
verbose_print++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cmd == 0)
|
||||
cmd = u_FILE_SIZE;
|
||||
|
||||
/* If an argument was supplied for the command, then we want to
|
||||
set the limit. Note that `ulimit something' means a command
|
||||
of -f with argument `something'. */
|
||||
if (list)
|
||||
{
|
||||
if (opt_eof || (*list->word->word != '-'))
|
||||
{
|
||||
s = list->word->word;
|
||||
list = list->next;
|
||||
|
||||
if (STREQ (s, "unlimited"))
|
||||
limit = RLIM_INFINITY;
|
||||
else if (all_digits (s))
|
||||
limit = string_to_rlimtype (s);
|
||||
else
|
||||
{
|
||||
builtin_error ("bad non-numeric arg `%s'", s);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
setting++;
|
||||
}
|
||||
else if (!opt_eof)
|
||||
verbose_print++;
|
||||
}
|
||||
|
||||
if (limit == RLIM_INFINITY)
|
||||
block_factor = 1;
|
||||
|
||||
real_limit = limit * block_factor;
|
||||
|
||||
/* If more than one option is given, list each in a verbose format,
|
||||
the same that is used for -a. */
|
||||
if (!setting && verbose_print)
|
||||
{
|
||||
print_specific_limits (cmd, mode);
|
||||
continue;
|
||||
}
|
||||
|
||||
current_limit = shell_ulimit (cmd, real_limit, 0, mode);
|
||||
|
||||
if (setting)
|
||||
{
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
/* Most USG systems do not most allow limits to be raised by any
|
||||
user other than root. There are, however, exceptions. */
|
||||
if (canraise (cmd, current_limit, real_limit) == 0)
|
||||
{
|
||||
builtin_error ("cannot raise limit: %s", strerror (EPERM));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
#endif /* !HAVE_RESOURCE */
|
||||
|
||||
if (shell_ulimit (cmd, real_limit, 1, mode) == (RLIMTYPE)-1)
|
||||
{
|
||||
builtin_error ("cannot raise limit: %s", strerror (errno));
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (current_limit < 0)
|
||||
builtin_error ("cannot get limit: %s", strerror (errno));
|
||||
else if (current_limit != RLIM_INFINITY)
|
||||
print_rlimtype ((current_limit / block_factor), 1);
|
||||
else
|
||||
printf ("unlimited\n");
|
||||
}
|
||||
}
|
||||
while (list);
|
||||
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* The ulimit that we call from within Bash.
|
||||
|
||||
WHICH says which limit to twiddle; SETTING is non-zero if NEWLIM
|
||||
contains the desired new limit. Otherwise, the existing limit is
|
||||
returned. If mode & LIMIT_HARD, the hard limit is used; if
|
||||
mode & LIMIT_SOFT, the soft limit. Both may be set by specifying
|
||||
-H and -S; if both are specified, or if neither is specified, the
|
||||
soft limit will be returned.
|
||||
|
||||
Systems without BSD resource limits can specify only u_FILE_SIZE.
|
||||
This includes most USG systems.
|
||||
|
||||
Chet Ramey supplied the BSD resource limit code. */
|
||||
static RLIMTYPE
|
||||
shell_ulimit (which, newlim, setting, mode)
|
||||
int which, setting, mode;
|
||||
RLIMTYPE newlim;
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
struct rlimit limit;
|
||||
int cmd;
|
||||
|
||||
if (mode == 0)
|
||||
mode |= LIMIT_SOFT;
|
||||
#endif
|
||||
|
||||
switch (which)
|
||||
{
|
||||
#if !defined (HAVE_RESOURCE)
|
||||
|
||||
case u_FILE_SIZE:
|
||||
if (!setting)
|
||||
{
|
||||
/* ulimit () returns a number that is in 512 byte blocks, thus we
|
||||
must multiply it by 512 to get back to bytes. This is false
|
||||
only under HP/UX 6.x. */
|
||||
RLIMTYPE result;
|
||||
|
||||
result = ulimit (1, 0L);
|
||||
|
||||
# if defined (hpux) && !defined (_POSIX_VERSION)
|
||||
return (result);
|
||||
# else
|
||||
return (result * 512);
|
||||
# endif /* hpux 6.x */
|
||||
}
|
||||
else
|
||||
return (ulimit (2, newlim / 512L));
|
||||
|
||||
break;
|
||||
|
||||
#else /* defined (HAVE_RESOURCE) */
|
||||
|
||||
case u_FILE_SIZE:
|
||||
cmd = RLIMIT_FSIZE;
|
||||
goto do_ulimit;
|
||||
|
||||
case u_CORE_FILE_SIZE:
|
||||
cmd = RLIMIT_CORE;
|
||||
goto do_ulimit;
|
||||
|
||||
case u_DATA_SEG_SIZE:
|
||||
cmd = RLIMIT_DATA;
|
||||
goto do_ulimit;
|
||||
|
||||
#if !defined (USGr4)
|
||||
case u_PHYS_MEM_SIZE:
|
||||
# if defined (RLIMIT_RSS)
|
||||
cmd = RLIMIT_RSS;
|
||||
# else /* !RLIMIT_RSS */
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
# endif /* !RLIMIT_RSS */
|
||||
|
||||
goto do_ulimit;
|
||||
#endif /* USGr4 */
|
||||
|
||||
case u_CPU_TIME_LIMIT:
|
||||
#if defined (RLIMIT_CPU)
|
||||
cmd = RLIMIT_CPU;
|
||||
goto do_ulimit;
|
||||
#else
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
# endif /* !RLIMIT_CPU */
|
||||
|
||||
|
||||
case u_STACK_SIZE:
|
||||
cmd = RLIMIT_STACK;
|
||||
|
||||
do_ulimit:
|
||||
|
||||
if (getrlimit (cmd, &limit) != 0)
|
||||
return ((RLIMTYPE)-1);
|
||||
|
||||
if (!setting)
|
||||
{
|
||||
if (mode & LIMIT_SOFT)
|
||||
return (limit.rlim_cur);
|
||||
else
|
||||
return (limit.rlim_max);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mode & LIMIT_SOFT)
|
||||
{
|
||||
/* Non-root users are only allowed to raise a limit up to the
|
||||
hard limit, not to infinity. */
|
||||
if (current_user.euid != 0 && newlim == RLIM_INFINITY)
|
||||
limit.rlim_cur = limit.rlim_max;
|
||||
else
|
||||
limit.rlim_cur = newlim;
|
||||
}
|
||||
if (mode & LIMIT_HARD)
|
||||
limit.rlim_max = newlim;
|
||||
|
||||
return (setrlimit (cmd, &limit));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
#endif /* HAVE_RESOURCE */
|
||||
|
||||
/* You can't get or set the pipe size with getrlimit, so we have to
|
||||
cheat. */
|
||||
case u_PIPE_SIZE:
|
||||
if (setting)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
}
|
||||
return (pipesize ());
|
||||
|
||||
case u_NUM_OPEN_FILES:
|
||||
if (setting)
|
||||
{
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_NOFILE)
|
||||
cmd = RLIMIT_NOFILE;
|
||||
goto do_ulimit;
|
||||
#else
|
||||
# if defined (HAVE_SETDTABLESIZE)
|
||||
return (setdtablesize (newlim));
|
||||
# else
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
# endif /* HAVE_SETDTABLESIZE */
|
||||
#endif /* !HAVE_RESOURCE || !RLIMIT_NOFILE */
|
||||
}
|
||||
else
|
||||
return (open_files (mode));
|
||||
|
||||
case u_MAX_VIRTUAL_MEM:
|
||||
if (setting)
|
||||
{
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined (HAVE_RESOURCE)
|
||||
return (getmaxvm (mode));
|
||||
#else /* !HAVE_RESOURCE */
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
#endif /* !HAVE_RESOURCE */
|
||||
}
|
||||
|
||||
case u_MAX_USER_PROCS:
|
||||
#if defined (HAVE_RESOURCE) && defined (RLIMIT_NPROC)
|
||||
cmd = RLIMIT_NPROC;
|
||||
goto do_ulimit;
|
||||
#else /* !HAVE_RESOURCE || !RLIMIT_NPROC */
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
#endif /* !HAVE_RESOURCE || !RLIMIT_NPROC */
|
||||
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
static RLIMTYPE
|
||||
getmaxvm (mode)
|
||||
int mode;
|
||||
{
|
||||
struct rlimit rl;
|
||||
|
||||
#if defined (RLIMIT_VMEM)
|
||||
if (getrlimit (RLIMIT_VMEM, &rl) < 0)
|
||||
return ((RLIMTYPE)-1);
|
||||
else
|
||||
return (((mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max) / 1024L);
|
||||
#else /* !RLIMIT_VMEM */
|
||||
RLIMTYPE maxdata, maxstack;
|
||||
|
||||
if (getrlimit (RLIMIT_DATA, &rl) < 0)
|
||||
return ((RLIMTYPE)-1);
|
||||
else
|
||||
maxdata = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
|
||||
|
||||
if (getrlimit (RLIMIT_STACK, &rl) < 0)
|
||||
return ((RLIMTYPE)-1);
|
||||
else
|
||||
maxstack = (mode & LIMIT_SOFT) ? rl.rlim_cur : rl.rlim_max;
|
||||
|
||||
/* Protect against overflow. */
|
||||
return ((maxdata / 1024L) + (maxstack / 1024L));
|
||||
#endif /* !RLIMIT_VMEM */
|
||||
}
|
||||
#endif /* HAVE_RESOURCE */
|
||||
|
||||
static RLIMTYPE
|
||||
open_files (mode)
|
||||
int mode;
|
||||
{
|
||||
#if !defined (RLIMIT_NOFILE)
|
||||
return ((RLIMTYPE)getdtablesize ());
|
||||
#else
|
||||
struct rlimit rl;
|
||||
|
||||
getrlimit (RLIMIT_NOFILE, &rl);
|
||||
if (mode & LIMIT_SOFT)
|
||||
return (rl.rlim_cur);
|
||||
else
|
||||
return (rl.rlim_max);
|
||||
#endif
|
||||
}
|
||||
|
||||
static RLIMTYPE
|
||||
pipesize ()
|
||||
{
|
||||
#if defined (PIPE_BUF)
|
||||
/* This is defined on Posix systems. */
|
||||
return ((RLIMTYPE) PIPE_BUF);
|
||||
#else
|
||||
# if defined (PIPESIZE)
|
||||
/* This is defined by running a program from the Makefile. */
|
||||
return ((RLIMTYPE) PIPESIZE);
|
||||
# else
|
||||
errno = EINVAL;
|
||||
return ((RLIMTYPE)-1);
|
||||
# endif /* PIPESIZE */
|
||||
#endif /* PIPE_BUF */
|
||||
}
|
||||
|
||||
/* ulimit(2) returns information about file size limits in terms of 512-byte
|
||||
blocks. This is the factor by which to divide to turn it into information
|
||||
in terms of 1024-byte blocks. Except for hpux 6.x, which returns it in
|
||||
terms of bytes. */
|
||||
#if !defined (hpux) || defined (_POSIX_VERSION)
|
||||
# define ULIMIT_DIVISOR 2
|
||||
#else
|
||||
# define ULIMIT_DIVISOR 1024
|
||||
#endif
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
|
||||
typedef struct {
|
||||
int option_cmd; /* The ulimit command for this limit. */
|
||||
int parameter; /* Parameter to pass to getrlimit (). */
|
||||
int block_factor; /* Blocking factor for specific limit. */
|
||||
char *description; /* Descriptive string to output. */
|
||||
} BSD_RESOURCE_LIMITS;
|
||||
|
||||
static BSD_RESOURCE_LIMITS limits[] = {
|
||||
{ u_CORE_FILE_SIZE, RLIMIT_CORE, 1024, "core file size (blocks)" },
|
||||
{ u_DATA_SEG_SIZE, RLIMIT_DATA, 1024, "data seg size (kbytes)" },
|
||||
{ u_FILE_SIZE, RLIMIT_FSIZE, 1024, "file size (blocks)" },
|
||||
#if !defined (USGr4) && defined (RLIMIT_RSS)
|
||||
{ u_PHYS_MEM_SIZE, RLIMIT_RSS, 1024, "max memory size (kbytes)" },
|
||||
#endif /* USGr4 && RLIMIT_RSS */
|
||||
{ u_STACK_SIZE, RLIMIT_STACK, 1024, "stack size (kbytes)" },
|
||||
#if defined (RLIMIT_CPU)
|
||||
{ u_CPU_TIME_LIMIT, RLIMIT_CPU, 1, "cpu time (seconds)" },
|
||||
#endif /* RLIMIT_CPU */
|
||||
#if defined (RLIMIT_NPROC)
|
||||
{ u_MAX_USER_PROCS, RLIMIT_NPROC, 1, "max user processes" },
|
||||
#endif /* RLIMIT_NPROC */
|
||||
{ 0, 0, 0, (char *)NULL }
|
||||
};
|
||||
|
||||
static void
|
||||
print_bsd_limit (i, mode)
|
||||
int i, mode;
|
||||
{
|
||||
struct rlimit rl;
|
||||
RLIMTYPE limit;
|
||||
|
||||
getrlimit (limits[i].parameter, &rl);
|
||||
if (mode & LIMIT_HARD)
|
||||
limit = rl.rlim_max;
|
||||
else
|
||||
limit = rl.rlim_cur;
|
||||
printf ("%-25s", limits[i].description);
|
||||
if (limit == RLIM_INFINITY)
|
||||
printf ("unlimited\n");
|
||||
else
|
||||
print_rlimtype ((limit / limits[i].block_factor), 1);
|
||||
}
|
||||
|
||||
static void
|
||||
print_specific_bsd_limits (cmd, mode)
|
||||
int cmd, mode;
|
||||
{
|
||||
register int i;
|
||||
|
||||
for (i = 0; limits[i].option_cmd; i++)
|
||||
if (cmd & limits[i].option_cmd)
|
||||
print_bsd_limit (i, mode);
|
||||
}
|
||||
#endif /* HAVE_RESOURCE */
|
||||
|
||||
/* Print the limits corresponding to a specific set of resources. This is
|
||||
called when an option string contains more than one character (e.g. -at),
|
||||
because limits may not be specified with that kind of argument. */
|
||||
static void
|
||||
print_specific_limits (cmd, mode)
|
||||
int cmd, mode;
|
||||
{
|
||||
if (mode == 0)
|
||||
mode = LIMIT_SOFT;
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
print_specific_bsd_limits (cmd, mode);
|
||||
#else /* !HAVE_RESOURCE */
|
||||
if (cmd & u_FILE_SIZE)
|
||||
{
|
||||
printf ("%-25s", "file size (blocks)");
|
||||
print_rlimtype ((ulimit (1, 0L) / ULIMIT_DIVISOR), 1);
|
||||
}
|
||||
#endif /* !HAVE_RESOURCE */
|
||||
|
||||
if (cmd & u_PIPE_SIZE)
|
||||
{
|
||||
printf ("%-25s", "pipe size (512 bytes)");
|
||||
print_rlimtype ((pipesize () / 512), 1);
|
||||
}
|
||||
|
||||
if (cmd & u_NUM_OPEN_FILES)
|
||||
{
|
||||
printf ("%-25s", "open files");
|
||||
print_rlimtype (open_files (mode), 1);
|
||||
}
|
||||
|
||||
#if defined (HAVE_RESOURCE)
|
||||
if (cmd & u_MAX_VIRTUAL_MEM)
|
||||
{
|
||||
printf ("%-25s", "virtual memory (kbytes)");
|
||||
print_rlimtype (getmaxvm (mode), 1);
|
||||
}
|
||||
#endif /* HAVE_RESOURCE */
|
||||
}
|
||||
|
||||
static void
|
||||
print_all_limits (mode)
|
||||
int mode;
|
||||
{
|
||||
if (mode == 0)
|
||||
mode |= LIMIT_SOFT;
|
||||
|
||||
print_specific_limits (u_ALL_LIMITS, mode);
|
||||
}
|
288
builtins/umask.def
Normal file
288
builtins/umask.def
Normal file
|
@ -0,0 +1,288 @@
|
|||
This file is umask.def, from which is created umask.c.
|
||||
It implements the builtin "umask" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
$PRODUCES umask.c
|
||||
|
||||
$BUILTIN umask
|
||||
$FUNCTION umask_builtin
|
||||
$SHORT_DOC umask [-S] [mode]
|
||||
The user file-creation mask is set to MODE. If MODE is omitted, or if
|
||||
`-S' is supplied, the current value of the mask is printed. The `-S'
|
||||
option makes the output symbolic; otherwise an octal number is output.
|
||||
If MODE begins with a digit, it is interpreted as an octal number,
|
||||
otherwise it is a symbolic mode string like that accepted by chmod(1).
|
||||
$END
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/file.h>
|
||||
#include "../shell.h"
|
||||
#include "../posixstat.h"
|
||||
#include "common.h"
|
||||
|
||||
/* **************************************************************** */
|
||||
/* */
|
||||
/* UMASK Builtin and Helpers */
|
||||
/* */
|
||||
/* **************************************************************** */
|
||||
|
||||
static void print_symbolic_umask ();
|
||||
static int symbolic_umask ();
|
||||
|
||||
/* Set or display the mask used by the system when creating files. Flag
|
||||
of -S means display the umask in a symbolic mode. */
|
||||
umask_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int print_symbolically = 0;
|
||||
|
||||
while (list)
|
||||
{
|
||||
if (ISOPTION (list->word->word, 'S'))
|
||||
{
|
||||
list = list->next;
|
||||
print_symbolically++;
|
||||
continue;
|
||||
}
|
||||
else if (ISOPTION (list->word->word, '-'))
|
||||
{
|
||||
list = list->next;
|
||||
break;
|
||||
}
|
||||
else if (*(list->word->word) == '-')
|
||||
{
|
||||
bad_option (list->word->word);
|
||||
builtin_error ("usage: umask [-S] [mode]");
|
||||
return (EX_USAGE);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
if (list)
|
||||
{
|
||||
int new_umask;
|
||||
|
||||
if (digit (*list->word->word))
|
||||
{
|
||||
new_umask = read_octal (list->word->word);
|
||||
|
||||
/* Note that other shells just let you set the umask to zero
|
||||
by specifying a number out of range. This is a problem
|
||||
with those shells. We don't change the umask if the input
|
||||
is lousy. */
|
||||
if (new_umask == -1)
|
||||
{
|
||||
builtin_error ("`%s' is not an octal number from 000 to 777",
|
||||
list->word->word);
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new_umask = symbolic_umask (list);
|
||||
if (new_umask == -1)
|
||||
return (EXECUTION_FAILURE);
|
||||
}
|
||||
umask (new_umask);
|
||||
if (print_symbolically)
|
||||
print_symbolic_umask (new_umask);
|
||||
}
|
||||
else /* Display the UMASK for this user. */
|
||||
{
|
||||
int old_umask;
|
||||
|
||||
old_umask = umask (022);
|
||||
umask (old_umask);
|
||||
|
||||
if (print_symbolically)
|
||||
print_symbolic_umask (old_umask);
|
||||
else
|
||||
printf ("%03o\n", old_umask);
|
||||
}
|
||||
fflush (stdout);
|
||||
return (EXECUTION_SUCCESS);
|
||||
}
|
||||
|
||||
/* Print the umask in a symbolic form. In the output, a letter is
|
||||
printed if the corresponding bit is clear in the umask. */
|
||||
static void
|
||||
print_symbolic_umask (um)
|
||||
int um;
|
||||
{
|
||||
char ubits[4], gbits[4], obits[4]; /* u=rwx,g=rwx,o=rwx */
|
||||
int i;
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IRUSR) == 0)
|
||||
ubits[i++] = 'r';
|
||||
if ((um & S_IWUSR) == 0)
|
||||
ubits[i++] = 'w';
|
||||
if ((um & S_IXUSR) == 0)
|
||||
ubits[i++] = 'x';
|
||||
ubits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IRGRP) == 0)
|
||||
gbits[i++] = 'r';
|
||||
if ((um & S_IWGRP) == 0)
|
||||
gbits[i++] = 'w';
|
||||
if ((um & S_IXGRP) == 0)
|
||||
gbits[i++] = 'x';
|
||||
gbits[i] = '\0';
|
||||
|
||||
i = 0;
|
||||
if ((um & S_IROTH) == 0)
|
||||
obits[i++] = 'r';
|
||||
if ((um & S_IWOTH) == 0)
|
||||
obits[i++] = 'w';
|
||||
if ((um & S_IXOTH) == 0)
|
||||
obits[i++] = 'x';
|
||||
obits[i] = '\0';
|
||||
|
||||
printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
|
||||
}
|
||||
|
||||
/* Set the umask from a symbolic mode string similar to that accepted
|
||||
by chmod. If the -S argument is given, then print the umask in a
|
||||
symbolic form. */
|
||||
static int
|
||||
symbolic_umask (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int um, umc, c;
|
||||
int who, op, perm, mask;
|
||||
char *s;
|
||||
|
||||
/* Get the initial umask. Don't change it yet. */
|
||||
um = umask (022);
|
||||
umask (um);
|
||||
|
||||
/* All work below is done with the complement of the umask -- its
|
||||
more intuitive and easier to deal with. It is complemented
|
||||
again before being returned. */
|
||||
umc = ~um;
|
||||
|
||||
s = list->word->word;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
who = op = perm = mask = 0;
|
||||
|
||||
/* Parse the `who' portion of the symbolic mode clause. */
|
||||
while (member (*s, "agou"))
|
||||
{
|
||||
switch (c = *s++)
|
||||
{
|
||||
case 'u':
|
||||
who |= S_IRWXU;
|
||||
continue;
|
||||
case 'g':
|
||||
who |= S_IRWXG;
|
||||
continue;
|
||||
case 'o':
|
||||
who |= S_IRWXO;
|
||||
continue;
|
||||
case 'a':
|
||||
who |= S_IRWXU | S_IRWXG | S_IRWXO;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The operation is now sitting in *s. */
|
||||
op = *s++;
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
case '-':
|
||||
case '=':
|
||||
break;
|
||||
default:
|
||||
builtin_error ("bad symbolic mode operator: %c", op);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* Parse out the `perm' section of the symbolic mode clause. */
|
||||
while (member (*s, "rwx"))
|
||||
{
|
||||
c = *s++;
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 'r':
|
||||
perm |= S_IRUGO;
|
||||
break;
|
||||
|
||||
case 'w':
|
||||
perm |= S_IWUGO;
|
||||
break;
|
||||
|
||||
case 'x':
|
||||
perm |= S_IXUGO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now perform the operation or return an error for a
|
||||
bad permission string. */
|
||||
if (!*s || *s == ',')
|
||||
{
|
||||
if (who)
|
||||
perm &= who;
|
||||
|
||||
switch (op)
|
||||
{
|
||||
case '+':
|
||||
umc |= perm;
|
||||
break;
|
||||
|
||||
case '-':
|
||||
umc &= ~perm;
|
||||
break;
|
||||
|
||||
case '=':
|
||||
umc &= ~who;
|
||||
umc |= perm;
|
||||
break;
|
||||
|
||||
default:
|
||||
builtin_error ("bad operation character: %c", op);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
if (!*s)
|
||||
{
|
||||
um = ~umc & 0777;
|
||||
break;
|
||||
}
|
||||
else
|
||||
s++; /* skip past ',' */
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error ("bad character in symbolic mode: %c", *s);
|
||||
return (-1);
|
||||
}
|
||||
}
|
||||
return (um);
|
||||
}
|
132
builtins/wait.def
Normal file
132
builtins/wait.def
Normal file
|
@ -0,0 +1,132 @@
|
|||
This file is wait.def, from which is created wait.c.
|
||||
It implements the builtin "wait" in Bash.
|
||||
|
||||
Copyright (C) 1987, 1989, 1991 Free Software Foundation, Inc.
|
||||
|
||||
This file is part of GNU Bash, the Bourne Again SHell.
|
||||
|
||||
Bash is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 1, or (at your option) any later
|
||||
version.
|
||||
|
||||
Bash is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along
|
||||
with Bash; see the file COPYING. If not, write to the Free Software
|
||||
Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
|
||||
|
||||
$BUILTIN wait
|
||||
$FUNCTION wait_builtin
|
||||
$DEPENDS_ON JOB_CONTROL
|
||||
$PRODUCES wait.c
|
||||
$SHORT_DOC wait [n]
|
||||
Wait for the specified process and report its termination status. If
|
||||
N is not given, all currently active child processes are waited for,
|
||||
and the return code is zero. N may be a process ID or a job
|
||||
specification; if a job spec is given, all processes in the job's
|
||||
pipeline are waited for.
|
||||
$END
|
||||
|
||||
$BUILTIN wait
|
||||
$FUNCTION wait_builtin
|
||||
$DEPENDS_ON !JOB_CONTROL
|
||||
$SHORT_DOC wait [n]
|
||||
Wait for the specified process and report its termination status. If
|
||||
N is not given, all currently active child processes are waited for,
|
||||
and the return code is zero. N is a process ID; if it is not given,
|
||||
all child processes of the shell are waited for.
|
||||
$END
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include "../shell.h"
|
||||
#include "../jobs.h"
|
||||
|
||||
extern int interrupt_immediately;
|
||||
|
||||
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
|
||||
wait for all of the active background processes of the shell and return
|
||||
0. If a list of pids or job specs are given, return the exit status of
|
||||
the last one waited for. */
|
||||
wait_builtin (list)
|
||||
WORD_LIST *list;
|
||||
{
|
||||
int status = EXECUTION_SUCCESS;
|
||||
|
||||
begin_unwind_frame ("wait_builtin");
|
||||
unwind_protect_int (interrupt_immediately);
|
||||
interrupt_immediately++;
|
||||
|
||||
/* We support jobs or pids.
|
||||
wait <pid-or-job> [pid-or-job ...] */
|
||||
|
||||
/* But wait without any arguments means to wait for all of the shell's
|
||||
currently active background processes. */
|
||||
if (!list)
|
||||
{
|
||||
wait_for_background_pids ();
|
||||
status = EXECUTION_SUCCESS;
|
||||
goto return_status;
|
||||
}
|
||||
|
||||
while (list)
|
||||
{
|
||||
pid_t pid;
|
||||
char *w;
|
||||
|
||||
w = list->word->word;
|
||||
if (digit (*w))
|
||||
{
|
||||
if (all_digits (w + 1))
|
||||
{
|
||||
pid = (pid_t)atoi (w);
|
||||
status = wait_for_single_pid (pid);
|
||||
}
|
||||
else
|
||||
{
|
||||
builtin_error ("`%s' is not a pid or legal job spec", w);
|
||||
status = EXECUTION_FAILURE;
|
||||
goto return_status;
|
||||
}
|
||||
}
|
||||
#if defined (JOB_CONTROL)
|
||||
else if (job_control && *w)
|
||||
/* Must be a job spec. Check it out. */
|
||||
{
|
||||
int job;
|
||||
sigset_t set, oset;
|
||||
|
||||
BLOCK_CHILD (set, oset);
|
||||
job = get_job_spec (list);
|
||||
|
||||
if (job < 0 || job >= job_slots || !jobs[job])
|
||||
{
|
||||
if (job != DUP_JOB)
|
||||
builtin_error ("No such job %s", list->word->word);
|
||||
UNBLOCK_CHILD (oset);
|
||||
status = 127; /* As per Posix.2, section 4.70.2 */
|
||||
list = list->next;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Job spec used. Wait for the last pid in the pipeline. */
|
||||
UNBLOCK_CHILD (oset);
|
||||
status = wait_for_job (job);
|
||||
}
|
||||
#endif /* JOB_CONTROL */
|
||||
else
|
||||
{
|
||||
builtin_error ("`%s' is not a pid or legal job spec", w);
|
||||
status = EXECUTION_FAILURE;
|
||||
}
|
||||
list = list->next;
|
||||
}
|
||||
return_status:
|
||||
run_unwind_frame ("wait_builtin");
|
||||
return (status);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue