Imported from ../bash-1.14.7.tar.gz.

This commit is contained in:
Jari Aalto 1996-08-26 18:22:31 +00:00
commit 726f63884d
402 changed files with 150297 additions and 0 deletions

0
builtins/ChangeLog Normal file
View file

267
builtins/Makefile Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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

File diff suppressed because it is too large Load diff

63
builtins/psize.c Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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);
}