aboutsummaryrefslogtreecommitdiffstats
path: root/examples
diff options
context:
space:
mode:
Diffstat (limited to 'examples')
-rw-r--r--examples/functions/autoload.v3125
-rw-r--r--examples/functions/inetaddr18
-rw-r--r--examples/functions/lowercase30
-rw-r--r--examples/functions/repeat312
-rw-r--r--examples/functions/seq237
-rw-r--r--examples/functions/which44
-rw-r--r--examples/loadables/Makefile.in180
-rw-r--r--examples/loadables/README18
-rw-r--r--examples/loadables/dirname.c2
-rw-r--r--examples/loadables/finfo.c11
-rw-r--r--examples/loadables/hello.c9
-rw-r--r--examples/loadables/id.c308
-rw-r--r--examples/loadables/ln.c203
-rw-r--r--examples/loadables/mkdir.c216
-rw-r--r--examples/loadables/necho.c2
-rw-r--r--examples/loadables/pathchk.c9
-rw-r--r--examples/loadables/printenv.c71
-rw-r--r--examples/loadables/pushd.c608
-rw-r--r--examples/loadables/sleep.c17
-rw-r--r--examples/loadables/sync.c32
-rw-r--r--examples/loadables/template.c56
-rw-r--r--examples/loadables/uname.c139
-rw-r--r--examples/loadables/unlink.c52
-rw-r--r--examples/loadables/whoami.c52
-rwxr-xr-xexamples/misc/aliasconv.bash10
-rwxr-xr-xexamples/misc/aliasconv.sh10
-rwxr-xr-xexamples/scripts/adventure.sh8
27 files changed, 1543 insertions, 736 deletions
diff --git a/examples/functions/autoload.v3 b/examples/functions/autoload.v3
new file mode 100644
index 0000000..a82ffe9
--- /dev/null
+++ b/examples/functions/autoload.v3
@@ -0,0 +1,125 @@
+#From: Mark Kennedy <mtk@ny.ubs.com>
+#Message-ID: <35E2B899.63A02DF5@ny.ubs.com>
+#Date: Tue, 25 Aug 1998 09:14:01 -0400
+#To: chet@nike.ins.cwru.edu
+#Subject: a newer version of the ksh-style 'autoload'
+
+#enclosed you'll find 'autoload.v3', a version of the autoloader
+#that emulates the ksh semantics of delaying the resolution (and loading) of the function
+#until its first use. i took the liberty of simplifying the code a bit although it still uses the
+#same functional breakdown. i recently went through the exercise of converting
+#my ksh-based environment to bash (a very, very pleasant experience)
+#and this popped out.
+
+# the psuedo-ksh autoloader.
+
+# The first cut of this was by Bill Trost, trost@reed.bitnet.
+# The second cut came from Chet Ramey, chet@ins.CWRU.Edu
+# The third cut came from Mark Kennedy, mtk@ny.ubs.com. 1998/08/25
+
+unset _AUTOLOADS
+
+_aload()
+{
+ local func
+ for func; do
+ eval $func '()
+ {
+ local f=$(_autoload_resolve '$func')
+ if [[ $f ]]; then
+ . $f
+ '$func' "$@"
+ return $?
+ else
+ return 1
+ fi
+ }'
+ _autoload_addlist $func
+ done
+}
+
+_autoload_addlist()
+{
+ local func
+
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $func = "$1" ]] && return
+ done
+
+ _AUTOLOADS[${#_AUTOLOADS[@]}]=$1
+}
+
+_autoload_dump()
+{
+ local func
+
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $1 ]] && echo -n "autoload "
+ echo $func
+ done
+}
+
+_autoload_remove_one()
+{
+ local func
+ local -a NEW_AUTOLOADS
+
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $func != "$1" ]] && NEW_AUTOLOADS[${#NEW_AUTOLOADS[@]}]=$func
+ done
+
+ _AUTOLOADS=( ${NEW_AUTOLOADS[@]} )
+}
+
+_autoload_remove()
+{
+ local victim func
+
+ for victim; do
+ for func in ${_AUTOLOADS[@]}; do
+ [[ $victim = "$func" ]] && unset -f $func && continue 2
+ done
+ echo "autoload: $func: not an autoloaded function" >&2
+ done
+
+ for func; do
+ _autoload_remove_one $func
+ done
+}
+
+_autoload_resolve()
+{
+ if [[ ! "$FPATH" ]]; then
+ echo "autoload: FPATH not set or null" >&2
+ return
+ fi
+
+ local p
+
+ for p in $( (IFS=':'; set -- ${FPATH}; echo "$@") ); do
+ p=${p:-.}
+ if [ -f $p/$1 ]; then echo $p/$1; return; fi
+ done
+
+ echo "autoload: $1: function source file not found" >&2
+}
+
+autoload()
+{
+ if (( $# == 0 )) ; then _autoload_dump; return; fi
+
+ local opt OPTIND
+
+ while getopts pu opt
+ do
+ case $opt in
+ p) _autoload_dump printable; return;;
+ u) shift $((OPTIND-1)); _autoload_remove "$@"; return;;
+ *) echo "autoload: usage: autoload [-pu] [function ...]" >&2; return;;
+ esac
+ done
+
+ shift $(($OPTIND-1))
+
+ _aload "$@"
+}
diff --git a/examples/functions/inetaddr b/examples/functions/inetaddr
index 776b204..08086ae 100644
--- a/examples/functions/inetaddr
+++ b/examples/functions/inetaddr
@@ -23,6 +23,17 @@ inet2hex ()
hex2inet ()
{
local x1 x2 x3 x4
+ local rev
+
+ OPTIND=1
+ while getopts "r" o
+ do
+ case "$o" in
+ r) rev=true;;
+ *) echo "hex2inet: usage: hex2inet [0x]XXXXXXXX" >&2 ; exit 2;;
+ esac
+ done
+ shift $(( $OPTIND - 1 ))
case "$1" in
0x*) h=${1#??} ;;
@@ -40,5 +51,10 @@ hex2inet ()
x3=$(( 0x${h:4:2} ))
x4=$(( 0x${h:6:2} ))
- printf "%d.%d.%d.%d\n" $x1 $x2 $x3 $x4
+ if [ -z "$rev" ] ; then
+ printf "%d.%d.%d.%d\n" $x1 $x2 $x3 $x4
+ else
+ printf "%d.%d.%d.%d\n" $x4 $x3 $x2 $x1
+ fi
+ return 0
}
diff --git a/examples/functions/lowercase b/examples/functions/lowercase
index 5f4fc9d..a0649f8 100644
--- a/examples/functions/lowercase
+++ b/examples/functions/lowercase
@@ -8,19 +8,19 @@
lowercase()
{
-for file; do
- filename=${file##*/}
- case "$filename" in
- */*) dirname=${file%/*} ;;
- *) dirname=.;;
- esac
- nf=$(echo $filename | tr A-Z a-z)
- newname="${dirname}/${nf}"
- if [ "$nf" != "$filename" ]; then
- mv "$file" "$newname"
- echo "$0: $file -> $newname"
- else
- echo "$0: $file not changed."
- fi
-done
+ for file; do
+ filename=${file##*/}
+ case "$filename" in
+ */*) dirname=${file%/*} ;;
+ *) dirname=.;;
+ esac
+ nf=$(echo $filename | tr A-Z a-z)
+ newname="${dirname}/${nf}"
+ if [ "$nf" != "$filename" ]; then
+ mv "$file" "$newname"
+ echo "lowercase: $file -> $newname"
+ else
+ echo "lowercase: $file not changed."
+ fi
+ done
}
diff --git a/examples/functions/repeat3 b/examples/functions/repeat3
new file mode 100644
index 0000000..65048bf
--- /dev/null
+++ b/examples/functions/repeat3
@@ -0,0 +1,12 @@
+# From psamuels@jake.niar.twsu.edu (Peter Samuelson)
+# posted to usenet, Message-ID: <6rtp8j$2a0$1@jake.niar.twsu.edu>
+
+repeat ()
+{
+ local i max; # note that you can use \$i in the command string
+ max=$1; shift;
+
+ i=1; while ((i <= max)); do
+ eval "$@"; ((i = i + 1));
+ done;
+}
diff --git a/examples/functions/seq2 b/examples/functions/seq2
new file mode 100644
index 0000000..c3ad95c
--- /dev/null
+++ b/examples/functions/seq2
@@ -0,0 +1,37 @@
+# Generate a sequence from m to n, m defaults to 1.
+
+seq ()
+{
+ declare -i lo hi i # makes local
+ local _SEQ INIT COMPARE STEP
+
+ case "$1" in
+ -r) INIT='i=$hi _SEQ=""' COMPARE='let "i >= $lo"' STEP='let i-=1' ; shift ;;
+ *) INIT='i=$lo _SEQ=""' COMPARE='let "i <= $hi"' STEP='let i+=1' ;;
+ esac
+
+ case $# in
+ 1) lo=1 hi="$1" ;;
+ 2) lo=$1 hi=$2 ;;
+ *) echo seq: usage: seq [-r] [low] high 1>&2 ; return 2 ;;
+ esac
+
+ # equivalent to the as-yet-unimplemented
+ # for (( "$INIT" ; "$COMPARE" ; "$STEP" )); do _SEQ="${_SEQ}$i "; done
+ eval "$INIT"
+ while eval "$COMPARE"; do
+ _SEQ="${_SEQ}$i "
+ eval "$STEP"
+ done
+ echo "${_SEQ# }"
+ return 0
+}
+
+# like the APL `iota' function (or at least how I remember it :-)
+iota()
+{
+ case $# in
+ 1) seq 1 "$1"; return $?;;
+ *) echo "iota: usage: iota high" 1>&2; return 2;;
+ esac
+}
diff --git a/examples/functions/which b/examples/functions/which
new file mode 100644
index 0000000..54ace77
--- /dev/null
+++ b/examples/functions/which
@@ -0,0 +1,44 @@
+#
+# which - emulation of `which' as it appears in FreeBSD
+#
+# usage: which [-as] command [command...]
+#
+
+which()
+{
+ local aflag sflag ES a
+
+ OPTIND=1
+ while builtin getopts as opt ; do
+ case "$opt" in
+ a) aflag=-a ;;
+ s) sflag=1 ;;
+ ?) echo "which: usage: which [-as] command [command ...]" >&2
+ exit 2 ;;
+ esac
+ done
+
+ (( $OPTIND > 1 )) && shift $(( $OPTIND - 1 ))
+
+ # without command arguments, exit with status 1
+ ES=1
+
+ # exit status is 0 if all commands are found, 1 if any are not found
+ for command; do
+ # if $command is a function, make sure we add -a so type
+ # will look in $PATH after finding the function
+ a=$aflag
+ case "$(builtin type -t $command)" in
+ "function") a=-a;;
+ esac
+
+ if [ -n "$sflag" ]; then
+ builtin type -p $a $command >/dev/null 2>&1
+ else
+ builtin type -p $a $command
+ fi
+ ES=$?
+ done
+
+ return $ES
+}
diff --git a/examples/loadables/Makefile.in b/examples/loadables/Makefile.in
index 9773144..799b4cf 100644
--- a/examples/loadables/Makefile.in
+++ b/examples/loadables/Makefile.in
@@ -1,8 +1,6 @@
#
# Simple makefile for the sample loadable builtins
#
-# This includes some boilerplate definitions added by configure, but will
-# still need hand-editing
#
# Include some boilerplate Gnu makefile definitions.
prefix = @prefix@
@@ -22,123 +20,148 @@ VPATH = .:@srcdir@
CC = @CC@
RM = rm -f
-SHELL = /bin/sh
-
-# SunOS 4
-#PICFLAG = -pic
-# Some versions of gcc, esp. on NetBSD and FreeBSD
-PICFLAG = -fpic
-# Linux -- could also be -fpic
-#PICFLAG = -fPIC
-# SunOS 5
-#PICFLAG = -K pic
-# SVR4, SVR4.2, Irix
-#PICFLAG = -K PIC
-# BSD/OS 2.1, BSD/OS 3.x
-#PICFLAG =
-# AIX 4.2
-#PICFLAG = -K
-
-# SunOS 4, BSD/OS 2.1, BSD/OS 3.x, SVR4.2, SVR4, Linux, AIX 4.2, etc.
-LD = ld
-# SunOS 5, Linux
-#LD = ${CC}
-
-# SunOS 4
-#LDOPT = -assert pure-text
-# OSF/1, Digital UNIX
-#LDOPT = -shared -soname $@ -expect_unresolved '*'
-# SunOS 5 using sun cc
-#LDOPT = -dy -z text -G -i -h $@
-# SunOS 5 using gcc with Sun ld
-#LDOPT = -shared -Wl,-dy -Wl,-G -Wl,-i
-# SVR4, SVR4.2
-#LDOPT = -dy -z text -G -h $@
-# NetBSD, FreeBSD -- might also need -r
-LDOPT = -x -Bshareable
-# Linux
-#LDOPT = -shared
-# BSD/OS 2.1, BSD/OS 3.x
-#LDOPT = -r
-# AIX 4.2
-#LDOPT = -bdynamic -bnoentry -bexpall -G
-
-# other libraries to link the shared object against
-# BSD/OS 2.1
-#LDLIBS = -lc_s.2.1.0
-# BSD/OS 3.0, BSD/OS 3.1
-#LDLIBS = -lc_s.3.0.0
+SHELL = @MAKE_SHELL@
+host_os = @host_os@
+host_cpu = @host_cpu@
+host_vendor = @host_vendor@
+
+CFLAGS = @CFLAGS@
+
+#
+# These values are generated for configure by ${topdir}/support/shobj-conf.
+# If your system is not supported by that script, but includes facilities for
+# dynamic loading of shared objects, please update the script and send the
+# changes to bash-maintainers@gnu.org.
+#
+SHOBJ_CC = @SHOBJ_CC@
+SHOBJ_CFLAGS = @SHOBJ_CFLAGS@
+SHOBJ_LD = @SHOBJ_LD@
+SHOBJ_LDFLAGS = @SHOBJ_LDFLAGS@
+SHOBJ_XLDFLAGS = @SHOBJ_XLDFLAGS@
+SHOBJ_LIBS = @SHOBJ_LIBS@
+SHOBJ_STATUS = @SHOBJ_STATUS@
INC = -I. -I.. -I$(topdir) -I$(topdir)/lib -I$(topdir)/builtins \
-I$(BUILD_DIR) -I$(BUILD_DIR)/lib -I$(BUILD_DIR)/builtins
.c.o:
- $(CC) $(PICFLAG) $(CFLAGS) $(INC) -c -o $@ $<
+ $(SHOBJ_CC) $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ $<
ALLPROG = print truefalse sleep pushd finfo logname basename dirname \
- tty pathchk tee head rmdir sprintf
+ tty pathchk tee head mkdir rmdir sprintf printenv id whoami \
+ uname sync push ln unlink
OTHERPROG = necho getconf hello cat
-all: $(ALLPROG)
-others: $(OTHERPROG)
+all: $(SHOBJ_STATUS)
+
+supported: $(ALLPROG)
+others: $(OTHERPROG)
+
+unsupported:
+ @echo "Your system (${host_os}) is not supported by the"
+ @echo "${topdir}/support/shobj-conf script."
+ @echo "If your operating system provides facilities for dynamic"
+ @echo "loading of shared objects using the dlopen(3) interface,"
+ @echo "please update the script and re-run configure.
+ @echo "Please send the changes you made to bash-maintainers@gnu.org"
+ @echo "for inclusion in future bash releases."
-everything: all others
+everything: supported others
sprintf: sprintf.o
- $(LD) $(LDOPT) -o $@ sprintf.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sprintf.o $(SHOBJ_LIBS)
print: print.o
- $(LD) $(LDOPT) -o $@ print.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ print.o $(SHOBJ_LIBS)
necho: necho.o
- $(LD) $(LDOPT) -o $@ necho.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ necho.o $(SHOBJ_LIBS)
getconf: getconf.o
- $(LD) $(LDOPT) -o $@ getconf.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ getconf.o $(SHOBJ_LIBS)
hello: hello.o
- $(LD) $(LDOPT) -o $@ hello.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ hello.o $(SHOBJ_LIBS)
truefalse: truefalse.o
- $(LD) $(LDOPT) -o $@ truefalse.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ truefalse.o $(SHOBJ_LIBS)
sleep: sleep.o
- $(LD) $(LDOPT) -o $@ sleep.o $(LDLIBS)
-
-pushd: pushd.o
- $(LD) $(LDOPT) -o $@ pushd.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sleep.o $(SHOBJ_LIBS)
finfo: finfo.o
- $(LD) $(LDOPT) -o $@ finfo.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ finfo.o $(SHOBJ_LIBS)
cat: cat.o
- $(LD) $(LDOPT) -o $@ cat.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ cat.o $(SHOBJ_LIBS)
logname: logname.o
- $(LD) $(LDOPT) -o $@ logname.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ logname.o $(SHOBJ_LIBS)
basename: basename.o
- $(LD) $(LDOPT) -o $@ basename.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ basename.o $(SHOBJ_LIBS)
dirname: dirname.o
- $(LD) $(LDOPT) -o $@ dirname.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ dirname.o $(SHOBJ_LIBS)
tty: tty.o
- $(LD) $(LDOPT) -o $@ tty.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tty.o $(SHOBJ_LIBS)
pathchk: pathchk.o
- $(LD) $(LDOPT) -o $@ pathchk.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pathchk.o $(SHOBJ_LIBS)
tee: tee.o
- $(LD) $(LDOPT) -o $@ tee.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ tee.o $(SHOBJ_LIBS)
+
+mkdir: mkdir.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ mkdir.o $(SHOBJ_LIBS)
rmdir: rmdir.o
- $(LD) $(LDOPT) -o $@ rmdir.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ rmdir.o $(SHOBJ_LIBS)
head: head.o
- $(LD) $(LDOPT) -o $@ head.o $(LDLIBS)
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ head.o $(SHOBJ_LIBS)
+
+printenv: printenv.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ printenv.o $(SHOBJ_LIBS)
+
+id: id.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ id.o $(SHOBJ_LIBS)
+
+whoami: whoami.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ whoami.o $(SHOBJ_LIBS)
+
+uname: uname.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ uname.o $(SHOBJ_LIBS)
+
+sync: sync.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ sync.o $(SHOBJ_LIBS)
+
+push: push.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ push.o $(SHOBJ_LIBS)
+
+ln: ln.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ ln.o $(SHOBJ_LIBS)
+
+unlink: unlink.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ unlink.o $(SHOBJ_LIBS)
+
+
+# pushd is a special case. We use the same source that the builtin version
+# uses, with special compilation options.
+#
+pushd.c: ${topdir}/builtins/pushd.def
+ $(RM) $@
+ ${BUILD_DIR}/builtins/mkbuiltins -D ${topdir}/builtins ${topdir}/builtins/pushd.def
+
+pushd.o: pushd.c
+ $(RM) $@
+ $(SHOBJ_CC) -DPUSHD_AND_POPD -DLOADABLE_BUILTIN $(SHOBJ_CFLAGS) $(CFLAGS) $(INC) -c -o $@ $<
+
+pushd: pushd.o
+ $(SHOBJ_LD) $(SHOBJ_LDFLAGS) $(SHOBJ_XLDFLAGS) -o $@ pushd.o $(SHOBJ_LIBS)
clean:
$(RM) $(ALLPROG) $(OTHERPROG) *.o
@@ -146,12 +169,11 @@ clean:
mostlyclean: clean
distclean maintainer-clean: clean
- $(RM) Makefile
+ $(RM) Makefile pushd.c
print.o: print.c
truefalse.o: truefalse.c
sleep.o: sleep.c
-pushd.o: pushd.c
finfo.o: finfo.c
logname.o: logname.c
basename.o: basename.c
@@ -166,4 +188,10 @@ necho.o: necho.c
getconf.o: getconf.c
hello.o: hello.c
cat.o: cat.c
-
+printenv.o: printenv.c
+id.o: id.c
+whoami.o: whoami.c
+uname.o: uname.c
+sync.o: sync.c
+push.o: push.c
+mkdir.o: mkdir.c
diff --git a/examples/loadables/README b/examples/loadables/README
index 4c02f47..db67860 100644
--- a/examples/loadables/README
+++ b/examples/loadables/README
@@ -10,13 +10,18 @@ of the shell.
All of the new builtins in ksh93 that bash didn't already have
are included here, as is the ksh `print' builtin.
-Compile with cc and whatever pic options you need (look in the
-Makefile for a few common settings)
+The configure script in the top-level source directory uses the
+support/shobj-conf script to set the right values in the Makefile,
+so you should not need to change the Makefile. If your system
+is not supported by support/shobj-conf, and it has the necessary
+facilities for building shared objects and support for the
+dlopen/dlsyn/dlclose/dlerror family of functions, please make
+the necessary changes to support/shobj-conf and send the changes
+to bash-maintainers@gnu.org.
-load with ld and whatever shared object options you need (again,
-look in the Makefile)
+Loadable builtins are loaded into a running shell with
-then enable -f filename builtin-name
+ enable -f filename builtin-name
enable uses a simple reference-counting scheme to avoid unloading a
shared object that implements more than one loadable builtin before
@@ -24,4 +29,5 @@ all loadable builtins implemented in the object are removed.
Many of the details needed by builtin writers are found in hello.c,
the canonical example. There is no real `builtin writers' programming
-guide'.
+guide'. The file template.c provides a template to use for creating
+new loadable builtins.
diff --git a/examples/loadables/dirname.c b/examples/loadables/dirname.c
index e875865..6159560 100644
--- a/examples/loadables/dirname.c
+++ b/examples/loadables/dirname.c
@@ -58,7 +58,7 @@ dirname_builtin (list)
if (string[slen] == '/')
break;
- if (slen >= 0)
+ if (slen < 0)
{
fputs (".\n", stdout);
return (EXECUTION_SUCCESS);
diff --git a/examples/loadables/finfo.c b/examples/loadables/finfo.c
index c0b0365..ab3c9a4 100644
--- a/examples/loadables/finfo.c
+++ b/examples/loadables/finfo.c
@@ -196,6 +196,13 @@ int m;
obits[i++] = 'x';
obits[i] = '\0';
+ if (m & S_ISUID)
+ ubits[2] = (m & S_IXUSR) ? 's' : 'S';
+ if (m & S_ISGID)
+ gbits[2] = (m & S_IXGRP) ? 's' : 'S';
+ if (m & S_ISVTX)
+ obits[2] = (m & S_IXOTH) ? 't' : 'T';
+
printf ("u=%s,g=%s,o=%s", ubits, gbits, obits);
}
@@ -217,6 +224,10 @@ int mode;
printf("S_IFLNK ");
if (S_ISSOCK(mode))
printf("S_IFSOCK ");
+#ifdef S_ISWHT
+ if (S_ISWHT(mode))
+ printf("S_ISWHT ");
+#endif
perms(getperm(mode));
printf("\n");
}
diff --git a/examples/loadables/hello.c b/examples/loadables/hello.c
index 3f371e5..f4b4a8e 100644
--- a/examples/loadables/hello.c
+++ b/examples/loadables/hello.c
@@ -3,19 +3,21 @@
/* See Makefile for compilation details. */
-#include "config.h"
+#include <config.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <stdio.h>
+
#include "builtins.h"
#include "shell.h"
+#include "bashgetopt.h"
/* A builtin `xxx' is normally implemented with an `xxx_builtin' function.
If you're converting a command that uses the normal Unix argc/argv
- calling convention, use argv = word_list_to_argv (list, &argc) and call
+ calling convention, use argv = make_builtin_argv (list, &argc) and call
the original `main' something like `xxx_main'. Look at cat.c for an
example.
@@ -41,7 +43,6 @@ hello_builtin (list)
which is printed by `help xxx'. It must end with a NULL. */
char *hello_doc[] = {
"this is the long doc for the sample hello builtin",
- "which is a bare-bones echo",
(char *)NULL
};
@@ -53,7 +54,7 @@ struct builtin hello_struct = {
hello_builtin, /* function implementing the builtin */
BUILTIN_ENABLED, /* initial flags for builtin */
hello_doc, /* array of long documentation strings. */
- "hello [args]", /* usage synopsis; becomes short_doc */
+ "hello", /* usage synopsis; becomes short_doc */
0 /* reserved for internal use */
};
diff --git a/examples/loadables/id.c b/examples/loadables/id.c
new file mode 100644
index 0000000..945190d
--- /dev/null
+++ b/examples/loadables/id.c
@@ -0,0 +1,308 @@
+/*
+ * id - POSIX.2 user identity
+ *
+ * (INCOMPLETE -- supplementary groups for other users not yet done)
+ *
+ * usage: id [-Ggu] [-nr] [user]
+ *
+ * The default output format looks something like:
+ * uid=xxx(chet) gid=xx groups=aa(aname), bb(bname), cc(cname)
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include "bashtypes.h"
+#include <pwd.h>
+#include <grp.h>
+#include "bashansi.h"
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#else
+# include <sys/param.h>
+#endif
+
+#if !defined (HAVE_GETPW_DECLS)
+extern struct passwd *getpwuid ();
+#endif
+extern struct group *getgrgid ();
+
+#include "shell.h"
+#include "builtins.h"
+#include "stdc.h"
+#include "common.h"
+#include "bashgetopt.h"
+
+#define ID_ALLGROUPS 0x001 /* -G */
+#define ID_GIDONLY 0x002 /* -g */
+#define ID_USENAME 0x004 /* -n */
+#define ID_USEREAL 0x008 /* -r */
+#define ID_USERONLY 0x010 /* -u */
+
+#define ID_FLAGSET(s) ((id_flags & (s)) != 0)
+
+static int id_flags;
+
+static uid_t ruid, euid;
+static gid_t rgid, egid;
+
+static char *id_user;
+
+static int inituser ();
+
+static int id_pruser ();
+static int id_prgrp ();
+static int id_prgroups ();
+static int id_prall ();
+
+int
+id_builtin (list)
+ WORD_LIST *list;
+{
+ int opt;
+ char *user;
+
+ id_flags = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "Ggnru")) != -1)
+ {
+ switch (opt)
+ {
+ case 'G': id_flags |= ID_ALLGROUPS; break;
+ case 'g': id_flags |= ID_GIDONLY; break;
+ case 'n': id_flags |= ID_USENAME; break;
+ case 'r': id_flags |= ID_USEREAL; break;
+ case 'u': id_flags |= ID_USERONLY; break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ user = list ? list->word->word : (char *)NULL;
+
+ /* Check for some invalid option combinations */
+ opt = ID_FLAGSET (ID_ALLGROUPS) + ID_FLAGSET (ID_GIDONLY) + ID_FLAGSET (ID_USERONLY);
+ if (opt > 1 || (opt == 0 && ((id_flags & (ID_USEREAL|ID_USENAME)) != 0)))
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (list && list->next)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (inituser (user) < 0)
+ return (EXECUTION_FAILURE);
+
+ opt = 0;
+ if (id_flags & ID_USERONLY)
+ opt += id_pruser ((id_flags & ID_USEREAL) ? ruid : euid);
+ else if (id_flags & ID_GIDONLY)
+ opt += id_prgrp ((id_flags & ID_USEREAL) ? rgid : egid);
+ else if (id_flags & ID_ALLGROUPS)
+ opt += id_prgroups (user);
+ else
+ opt += id_prall (user);
+ putchar ('\n');
+ fflush (stdout);
+
+ return (opt == 0 ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+}
+
+static int
+inituser (uname)
+ char *uname;
+{
+ struct passwd *pwd;
+
+ if (uname)
+ {
+ pwd = getpwnam (uname);
+ if (pwd == 0)
+ {
+ builtin_error ("%s: no such user", uname);
+ return -1;
+ }
+ ruid = euid = pwd->pw_uid;
+ rgid = egid = pwd->pw_gid;
+ }
+ else
+ {
+ ruid = current_user.uid;
+ euid = current_user.euid;
+ rgid = current_user.gid;
+ egid = current_user.egid;
+ }
+ return 0;
+}
+
+/* Print the name or value of user ID UID. */
+static int
+id_pruser (uid)
+ int uid;
+{
+ struct passwd *pwd = NULL;
+ int r;
+
+ r = 0;
+ if (id_flags & ID_USENAME)
+ {
+ pwd = getpwuid (uid);
+ if (pwd == NULL)
+ r = 1;
+ }
+ if (pwd)
+ printf ("%s", pwd->pw_name);
+ else
+ printf ("%u", (unsigned) uid);
+
+ return r;
+}
+
+/* Print the name or value of group ID GID. */
+
+static int
+id_prgrp (gid)
+ int gid;
+{
+ struct group *grp = NULL;
+ int r;
+
+ r = 0;
+ if (id_flags & ID_USENAME)
+ {
+ grp = getgrgid (gid);
+ if (grp == NULL)
+ r = 1;
+ }
+
+ if (grp)
+ printf ("%s", grp->gr_name);
+ else
+ printf ("%u", (unsigned) gid);
+
+ return r;
+}
+
+static int
+id_prgroups (uname)
+ char *uname;
+{
+ int *glist, ng, i, r;
+
+ r = 0;
+ id_prgrp (rgid);
+ if (egid != rgid)
+ {
+ putchar (' ');
+ id_prgrp (egid);
+ }
+
+ if (uname)
+ {
+ builtin_error ("supplementary groups for other users not yet implemented");
+ glist = (int *)NULL;
+ ng = 0;
+ r = 1;
+ }
+ else
+ glist = get_group_array (&ng);
+
+ for (i = 0; i < ng; i++)
+ if (glist[i] != rgid && glist[i] != egid)
+ {
+ putchar (' ');
+ id_prgrp (glist[i]);
+ }
+
+ return r;
+}
+
+static int
+id_prall (uname)
+ char *uname;
+{
+ int r, i, ng, *glist;
+ struct passwd *pwd;
+ struct group *grp;
+
+ r = 0;
+ printf ("uid=%u", (unsigned) ruid);
+ pwd = getpwuid (ruid);
+ if (pwd == NULL)
+ r = 1;
+ else
+ printf ("(%s)", pwd->pw_name);
+
+ printf (" gid=%u", (unsigned) rgid);
+ grp = getgrgid (rgid);
+ if (grp == NULL)
+ r = 1;
+ else
+ printf ("(%s)", grp->gr_name);
+
+ if (euid != ruid)
+ {
+ printf (" euid=%u", (unsigned) euid);
+ pwd = getpwuid (euid);
+ if (pwd == NULL)
+ r = 1;
+ else
+ printf ("(%s)", pwd->pw_name);
+ }
+
+ if (egid != rgid)
+ {
+ printf (" egid=%u", (unsigned) egid);
+ grp = getgrgid (egid);
+ if (grp == NULL)
+ r = 1;
+ else
+ printf ("(%s)", grp->gr_name);
+ }
+
+ if (uname)
+ {
+ builtin_error ("supplementary groups for other users not yet implemented");
+ glist = (int *)NULL;
+ ng = 0;
+ r = 1;
+ }
+ else
+ glist = get_group_array (&ng);
+
+ if (ng > 0)
+ printf (" groups=");
+ for (i = 0; i < ng; i++)
+ {
+ if (i > 0)
+ printf (", ");
+ printf ("%u", (unsigned) glist[i]);
+ grp = getgrgid (glist[i]);
+ if (grp == NULL)
+ r = 1;
+ else
+ printf ("(%s)", grp->gr_name);
+ }
+
+ return r;
+}
+
+char *id_doc[] = {
+ "return information about user identity",
+ (char *)NULL
+};
+
+struct builtin id_struct = {
+ "id",
+ id_builtin,
+ BUILTIN_ENABLED,
+ id_doc,
+ "id [user]\n\tid -G [-n] [user]\n\tid -g [-nr] [user]\n\tid -u [-nr] [user]",
+ 0
+};
diff --git a/examples/loadables/ln.c b/examples/loadables/ln.c
new file mode 100644
index 0000000..9c4c91b
--- /dev/null
+++ b/examples/loadables/ln.c
@@ -0,0 +1,203 @@
+/* ln - make links */
+
+/* See Makefile for compilation details. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "posixstat.h"
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define LN_SYMLINK 0x01
+#define LN_UNLINK 0x02
+
+static Function *linkfn;
+static int dolink ();
+
+ln_builtin (list)
+ WORD_LIST *list;
+{
+ int rval, opt, flags;
+ WORD_LIST *l;
+ char *sdir;
+ struct stat sb;
+
+ flags = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "fs")) != -1)
+ {
+ switch (opt)
+ {
+ case 'f':
+ flags |= LN_UNLINK;
+ break;
+ case 's':
+ flags |= LN_SYMLINK;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ linkfn = (flags & LN_SYMLINK) ? symlink : link;
+
+ if (list->next == 0) /* ln target, equivalent to ln target . */
+ return (dolink (list->word->word, ".", flags));
+
+ if (list->next->next == 0) /* ln target source */
+ return (dolink (list->word->word, list->next->word->word, flags));
+
+ /* ln target1 target2 ... directory */
+
+ /* find last argument: target directory, and make sure it's an existing
+ directory. */
+ for (l = list; l->next; l = l->next)
+ ;
+ sdir = l->word->word;
+
+ if (stat(sdir, &sb) < 0)
+ {
+ builtin_error ("%s", sdir);
+ return (EXECUTION_FAILURE);
+ }
+
+ if (S_ISDIR (sb.st_mode) == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ for (rval = EXECUTION_SUCCESS; list != l; list = list->next)
+ rval += dolink (list->word->word, sdir, flags);
+
+ return rval;
+}
+
+static char *
+mkdirpath (dir, file)
+ char *dir, *file;
+{
+ int dlen, flen;
+ char *ret;
+
+ dlen = strlen (dir);
+ flen = strlen (file);
+
+ ret = xmalloc (2 + dlen + flen);
+
+ strcpy (ret, dir);
+ if (ret[dlen - 1] != '/')
+ ret[dlen++] = '/';
+ strcpy (ret + dlen, file);
+ return ret;
+}
+
+#if defined (HAVE_LSTAT)
+# define LSTAT lstat
+#else
+# define LSTAT stat
+#endif
+
+static int
+dolink (src, dst, flags)
+ char *src, *dst;
+ int flags;
+{
+ struct stat ssb, dsb;
+ int exists;
+ char *dst_path, *p;
+
+ /* If we're not doing symlinks, the source must exist and not be a
+ directory. */
+ if ((flags & LN_SYMLINK) == 0)
+ {
+ if (stat (src, &ssb) != 0)
+ {
+ builtin_error ("%s: %s", src, strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+ if (S_ISDIR (ssb.st_mode))
+ {
+ errno = EISDIR;
+ builtin_error ("%s: %s", src, strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+ }
+
+ /* If the destination is a directory, create the final filename by appending
+ the basename of the source to the destination. */
+ dst_path = 0;
+ if ((stat (dst, &dsb) == 0) && S_ISDIR (dsb.st_mode))
+ {
+ if ((p = strrchr (src, '/')) == 0)
+ p = src;
+ else
+ p++;
+
+ dst_path = mkdirpath (dst, p);
+ dst = dst_path;
+ }
+
+ exists = LSTAT (dst, &dsb) == 0;
+
+ /* If -f was specified, and the destination exists, unlink it. */
+ if ((flags & LN_UNLINK) && exists && unlink (dst) != 0)
+ {
+ builtin_error ("%s: cannot unlink: %s", dst, strerror (errno));
+ FREE (dst_path);
+ return (EXECUTION_FAILURE);
+ }
+
+ /* Perform the link. */
+ if ((*linkfn) (src, dst) != 0)
+ {
+ builtin_error ("cannot link %s to %s: %s", dst, src, strerror (errno));
+ FREE (dst_path);
+ return (EXECUTION_FAILURE);
+ }
+
+ FREE (dst_path);
+ return (EXECUTION_SUCCESS);
+}
+
+char *ln_doc[] = {
+ "Create a new directory entry with the same modes as the original",
+ "file. The -f option means to unlink any existing file, permitting",
+ "the link to occur. The -s option means to create a symbolic link.",
+ "By default, ln makes hard links.",
+ (char *)NULL
+};
+
+/* The standard structure describing a builtin command. bash keeps an array
+ of these structures. */
+struct builtin ln_struct = {
+ "ln", /* builtin name */
+ ln_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ ln_doc, /* array of long documentation strings. */
+ "ln [-fs] file1 [file2] OR ln [-fs] file ... directory", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/mkdir.c b/examples/loadables/mkdir.c
new file mode 100644
index 0000000..cd6e5f9
--- /dev/null
+++ b/examples/loadables/mkdir.c
@@ -0,0 +1,216 @@
+/* mkdir - make directories */
+
+/* See Makefile for compilation details. */
+
+#include <config.h>
+
+#include "bashtypes.h"
+#include "posixstat.h"
+#include <errno.h>
+#include <stdio.h>
+#include "bashansi.h"
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#define ISOCTAL(c) ((c) >= '0' && (c) <= '7')
+
+extern int parse_symbolic_mode ();
+
+static int make_path ();
+
+static int original_umask;
+
+int
+mkdir_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, pflag, omode, rval, octal, nmode, parent_mode, um;
+ char *mode;
+ WORD_LIST *l;
+
+ reset_internal_getopt ();
+ pflag = 0;
+ mode = (char *)NULL;
+ while ((opt = internal_getopt(list, "m:p")) != -1)
+ switch (opt)
+ {
+ case 'p':
+ pflag = 1;
+ break;
+ case 'm':
+ mode = list_optarg;
+ break;
+ default:
+ builtin_usage();
+ return (EX_USAGE);
+ }
+ list = loptend;
+
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (mode == NULL)
+ omode = S_IRWXU | S_IRWXG | S_IRWXO; /* a=rwx */
+ else if (ISOCTAL (*mode)) /* octal number */
+ {
+ omode = read_octal (mode);
+ if (omode < 0)
+ {
+ builtin_error ("invalid file mode: %s", mode);
+ return (EXECUTION_FAILURE);
+ }
+ octal = 1;
+ }
+ else if (mode)
+ {
+ /* initial bits are a=rwx; the mode argument modifies them */
+ omode = parse_symbolic_mode (mode, S_IRWXU | S_IRWXG | S_IRWXO);
+ if (omode < 0)
+ {
+ builtin_error ("invalid file mode: %s", mode);
+ return (EXECUTION_FAILURE);
+ }
+ octal = 0;
+ }
+
+ /* Make the new mode */
+ original_umask = umask (0);
+ umask (original_umask);
+
+ nmode = (S_IRWXU | S_IRWXG | S_IRWXO) & ~original_umask;
+ parent_mode = nmode | (S_IWRITE|S_IEXEC); /* u+wx */
+
+ /* Adjust new mode based on mode argument */
+ nmode &= omode;
+
+ for (rval = EXECUTION_SUCCESS, l = list; l; l = l->next)
+ {
+ if (pflag && make_path (l->word->word, nmode, parent_mode))
+ {
+ rval = EXECUTION_FAILURE;
+ continue;
+ }
+ else if (pflag == 0 && mkdir (l->word->word, nmode) < 0)
+ {
+ builtin_error ("cannot create directory `%s': %s", l->word->word, strerror (errno));
+ rval = EXECUTION_FAILURE;
+ }
+ }
+ return rval;
+}
+
+/* Make all the directories leading up to PATH, then create PATH. Note that
+ this changes the process's umask; make sure that all paths leading to a
+ return reset it to ORIGINAL_UMASK */
+static int
+make_path (path, nmode, parent_mode)
+ char *path;
+ int nmode, parent_mode;
+{
+ int oumask;
+ struct stat sb;
+ char *p, *npath;
+
+ if (stat (path, &sb) == 0)
+ {
+ if (S_ISDIR (sb.st_mode) == 0)
+ {
+ builtin_error ("`%s': file exists but is not a directory", path);
+ return 1;
+ }
+
+ if (chmod (path, nmode))
+ {
+ builtin_error ("%s: %s", path, strerror (errno));
+ return 1;
+ }
+
+ return 0;
+ }
+
+ oumask = umask (0);
+ npath = savestring (path); /* So we can write to it. */
+
+ /* Check whether or not we need to do anything with intermediate dirs. */
+
+ /* Skip leading slashes. */
+ p = npath;
+ while (*p == '/')
+ p++;
+
+ while (p = strchr (p, '/'))
+ {
+ *p = '\0';
+ if (stat (npath, &sb) != 0)
+ {
+ if (mkdir (npath, parent_mode))
+ {
+ builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
+ umask (original_umask);
+ free (npath);
+ return 1;
+ }
+ }
+ else if (S_ISDIR (sb.st_mode) == 0)
+ {
+ builtin_error ("`%s': file exists but is not a directory", npath);
+ umask (original_umask);
+ free (npath);
+ return 1;
+ }
+
+ *p++ = '/'; /* restore slash */
+ while (*p == '/')
+ p++;
+ }
+
+ /* Create the final directory component. */
+ if (stat (npath, &sb) && mkdir (npath, nmode))
+ {
+ builtin_error ("cannot create directory `%s': %s", npath, strerror (errno));
+ umask (original_umask);
+ free (npath);
+ return 1;
+ }
+
+ umask (original_umask);
+ free (npath);
+ return 0;
+}
+
+char *mkdir_doc[] = {
+ "Make directories. Create the directories named as arguments, in",
+ "the order specified, using mode rwxrwxrwx as modified by the current",
+ "umask (see `help umask'). The -m option causes the file permission",
+ "bits of the final directory to be MODE. The MODE argument may be",
+ "an octal number or a symbolic mode like that used by chmod(1). If",
+ "a symbolic mode is used, the operations are interpreted relative to",
+ "an initial mode of \"a=rwx\". The -p option causes any required",
+ "intermediate directories in PATH to be created. The directories",
+ "are created with permssion bits of rwxrwxrwx as modified by the current",
+ "umask, plus write and search permissions for the owner. mkdir",
+ "returns 0 if the directories are created successfully, and non-zero",
+ "if an error occurs.",
+ (char *)NULL
+};
+
+struct builtin mkdir_struct = {
+ "mkdir",
+ mkdir_builtin,
+ BUILTIN_ENABLED,
+ mkdir_doc,
+ "mkdir [-p] [-m mode] directory [directory ...]",
+ 0
+};
diff --git a/examples/loadables/necho.c b/examples/loadables/necho.c
index 695062a..521ee2c 100644
--- a/examples/loadables/necho.c
+++ b/examples/loadables/necho.c
@@ -22,7 +22,7 @@ char *necho_doc[] = {
(char *)NULL
};
-struct builtin echo_struct = {
+struct builtin necho_struct = {
"echo",
necho_builtin,
BUILTIN_ENABLED,
diff --git a/examples/loadables/pathchk.c b/examples/loadables/pathchk.c
index dc02fce..2e36f8f 100644
--- a/examples/loadables/pathchk.c
+++ b/examples/loadables/pathchk.c
@@ -170,8 +170,7 @@ portable_chars_only (path)
for (p = path; *p; ++p)
if (portable_chars[(const unsigned char) *p] == 0)
{
- error (0, 0, "path `%s' contains nonportable character `%c'",
- path, *p);
+ builtin_error ("path `%s' contains nonportable character `%c'", path, *p);
return 0;
}
return 1;
@@ -212,7 +211,7 @@ dir_ok (path)
if (!S_ISDIR (stats.st_mode))
{
- error (0, 0, "`%s' is not a directory", path);
+ builtin_error ("`%s' is not a directory", path);
return 0;
}
@@ -324,7 +323,7 @@ validate_path (path, portability)
name_max = _POSIX_NAME_MAX;
if (length > name_max)
{
- error (0, 0, "name `%s' has length %d; exceeds limit of %d",
+ builtin_error ("name `%s' has length %d; exceeds limit of %d",
start, length, name_max);
free (parent);
return 1;
@@ -350,7 +349,7 @@ validate_path (path, portability)
free (parent);
if (strlen (path) > path_max)
{
- error (0, 0, "path `%s' has length %d; exceeds limit of %d",
+ builtin_error ("path `%s' has length %d; exceeds limit of %d",
path, strlen (path), path_max);
return 1;
}
diff --git a/examples/loadables/printenv.c b/examples/loadables/printenv.c
new file mode 100644
index 0000000..16f398f
--- /dev/null
+++ b/examples/loadables/printenv.c
@@ -0,0 +1,71 @@
+/*
+ * printenv -- minimal builtin clone of BSD printenv(1).
+ *
+ * usage: printenv [varname]
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+extern char **export_env;
+
+int
+printenv_builtin (list)
+ WORD_LIST *list;
+{
+ register char **envp;
+ int opt;
+ SHELL_VAR *var;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "")) != -1)
+ {
+ switch (opt)
+ {
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ /* printenv */
+ if (list == 0)
+ {
+ maybe_make_export_env (); /* this allows minimal code */
+ for (envp = export_env; *envp; envp++)
+ printf ("%s\n", *envp);
+ return (EXECUTION_SUCCESS);
+ }
+
+ /* printenv varname */
+ var = find_variable (list->word->word);
+ if (var == 0 || (exported_p (var) == 0))
+ return (EXECUTION_FAILURE);
+
+ if (function_p (var))
+ print_var_function (var);
+ else
+ print_var_value (var, 0);
+
+ return (EXECUTION_SUCCESS);
+}
+
+char *printenv_doc[] = {
+ "print values of environment variables",
+ (char *)NULL
+};
+
+struct builtin printenv_struct = {
+ "printenv",
+ printenv_builtin,
+ BUILTIN_ENABLED,
+ printenv_doc,
+ "printenv [varname]",
+ 0
+};
diff --git a/examples/loadables/pushd.c b/examples/loadables/pushd.c
deleted file mode 100644
index 2ecbcbb..0000000
--- a/examples/loadables/pushd.c
+++ /dev/null
@@ -1,608 +0,0 @@
-/* pushd.c, created from pushd.def. */
-#include <config.h>
-
-#include <stdio.h>
-#include <sys/param.h>
-
-#if defined (HAVE_UNISTD_H)
-# include <unistd.h>
-#endif
-
-#include "bashansi.h"
-
-#include <errno.h>
-
-#include <tilde/tilde.h>
-
-#include "shell.h"
-#include "builtins.h"
-#include "maxpath.h"
-#include "common.h"
-
-#if !defined (errno)
-extern int errno;
-#endif /* !errno */
-
-static char *m_badarg = "%s: bad argument";
-
-/* The list of remembered directories. */
-static char **pushd_directory_list = (char **)NULL;
-
-/* Number of existing slots in this list. */
-static int directory_list_size;
-
-/* Offset to the end of the list. */
-static int directory_list_offset;
-
-static void pushd_error ();
-static void clear_directory_stack ();
-static int cd_to_string ();
-static int change_to_temp ();
-static int get_dirstack_index ();
-static void add_dirstack_element ();
-
-#define NOCD 0x01
-#define ROTATE 0x02
-#define LONGFORM 0x04
-#define CLEARSTAK 0x08
-
-int
-pushd_builtin (list)
- WORD_LIST *list;
-{
- char *temp, *current_directory, *top;
- int j, flags;
- long num;
- char direction;
-
- /* If there is no argument list then switch current and
- top of list. */
- if (list == 0)
- {
- if (directory_list_offset == 0)
- {
- builtin_error ("no other directory");
- return (EXECUTION_FAILURE);
- }
-
- current_directory = get_working_directory ("pushd");
- if (current_directory == 0)
- return (EXECUTION_FAILURE);
-
- j = directory_list_offset - 1;
- temp = pushd_directory_list[j];
- pushd_directory_list[j] = current_directory;
- j = change_to_temp (temp);
- free (temp);
- return j;
- }
-
- for (flags = 0; list; list = list->next)
- {
- if (ISOPTION (list->word->word, 'n'))
- {
- flags |= NOCD;
- }
- else if (ISOPTION (list->word->word, '-'))
- {
- list = list->next;
- break;
- }
- else if (list->word->word[0] == '-' && list->word->word[1] == '\0')
- /* Let `pushd -' work like it used to. */
- break;
- else if (((direction = list->word->word[0]) == '+') || direction == '-')
- {
- if (legal_number (list->word->word + 1, &num) == 0)
- {
- builtin_error (m_badarg, list->word->word);
- builtin_usage ();
- return (EXECUTION_FAILURE);
- }
-
- if (direction == '-')
- num = directory_list_offset - num;
-
- if (num > directory_list_offset || num < 0)
- {
- pushd_error (directory_list_offset, list->word->word);
- return (EXECUTION_FAILURE);
- }
- flags |= ROTATE;
- }
- else if (*list->word->word == '-')
- {
- bad_option (list->word->word);
- builtin_usage ();
- return (EXECUTION_FAILURE);
- }
- else
- break;
- }
-
- if (flags & ROTATE)
- {
- /* Rotate the stack num times. Remember, the current
- directory acts like it is part of the stack. */
- temp = get_working_directory ("pushd");
-
- if (num == 0)
- {
- j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
- free (temp);
- return j;
- }
-
- do
- {
- top = pushd_directory_list[directory_list_offset - 1];
-
- for (j = directory_list_offset - 2; j > -1; j--)
- pushd_directory_list[j + 1] = pushd_directory_list[j];
-
- pushd_directory_list[j + 1] = temp;
-
- temp = top;
- num--;
- }
- while (num);
-
- j = ((flags & NOCD) == 0) ? change_to_temp (temp) : EXECUTION_SUCCESS;
- free (temp);
- return j;
- }
-
- if (list == 0)
- return (EXECUTION_SUCCESS);
-
- /* Change to the directory in list->word->word. Save the current
- directory on the top of the stack. */
- current_directory = get_working_directory ("pushd");
- if (current_directory == 0)
- return (EXECUTION_FAILURE);
-
- j = ((flags & NOCD) == 0) ? cd_builtin (list) : EXECUTION_SUCCESS;
- if (j == EXECUTION_SUCCESS)
- {
- add_dirstack_element ((flags & NOCD) ? savestring (list->word->word) : current_directory);
- dirs_builtin ((WORD_LIST *)NULL);
- if (flags & NOCD)
- free (current_directory);
- return (EXECUTION_SUCCESS);
- }
- else
- {
- free (current_directory);
- return (EXECUTION_FAILURE);
- }
-}
-
-/* Pop the directory stack, and then change to the new top of the stack.
- If LIST is non-null it should consist of a word +N or -N, which says
- what element to delete from the stack. The default is the top one. */
-int
-popd_builtin (list)
- WORD_LIST *list;
-{
- register int i;
- long which;
- int flags;
- char direction;
- char *which_word;
-
- which_word = (char *)NULL;
- for (flags = 0, which = 0L, direction = '+'; list; list = list->next)
- {
- if (ISOPTION (list->word->word, 'n'))
- {
- flags |= NOCD;
- }
- else if (ISOPTION (list->word->word, '-'))
- {
- list = list->next;
- break;
- }
- else if (((direction = list->word->word[0]) == '+') || direction == '-')
- {
- if (legal_number (list->word->word + 1, &which) == 0)
- {
- builtin_error (m_badarg, list->word->word);
- builtin_usage ();
- return (EXECUTION_FAILURE);
- }
- which_word = list->word->word;
- }
- else if (*list->word->word == '-')
- {
- bad_option (list->word->word);
- builtin_usage ();
- return (EXECUTION_FAILURE);
- }
- else
- break;
- }
-
- if (which > directory_list_offset || (directory_list_offset == 0 && which == 0))
- {
- pushd_error (directory_list_offset, which_word ? which_word : "");
- return (EXECUTION_FAILURE);
- }
-
- /* Handle case of no specification, or top of stack specification. */
- if ((direction == '+' && which == 0) ||
- (direction == '-' && which == directory_list_offset))
- {
- i = ((flags & NOCD) == 0) ? cd_to_string (pushd_directory_list[directory_list_offset - 1])
- : EXECUTION_SUCCESS;
- if (i != EXECUTION_SUCCESS)
- return (i);
- free (pushd_directory_list[--directory_list_offset]);
- }
- else
- {
- /* Since an offset other than the top directory was specified,
- remove that directory from the list and shift the remainder
- of the list into place. */
- i = (direction == '+') ? directory_list_offset - which : which;
- free (pushd_directory_list[i]);
- directory_list_offset--;
-
- /* Shift the remainder of the list into place. */
- for (; i < directory_list_offset; i++)
- pushd_directory_list[i] = pushd_directory_list[i + 1];
- }
-
- dirs_builtin ((WORD_LIST *)NULL);
- return (EXECUTION_SUCCESS);
-}
-
-/* Print the current list of directories on the directory stack. */
-int
-dirs_builtin (list)
- WORD_LIST *list;
-{
- int flags, desired_index, index_flag, vflag;
- long i;
- char *temp, *w;
-
- for (flags = vflag = index_flag = 0, desired_index = -1, w = ""; list; list = list->next)
- {
- if (ISOPTION (list->word->word, 'l'))
- {
- flags |= LONGFORM;
- }
- else if (ISOPTION (list->word->word, 'c'))
- {
- flags |= CLEARSTAK;
- }
- else if (ISOPTION (list->word->word, 'v'))
- {
- vflag |= 2;
- }
- else if (ISOPTION (list->word->word, 'p'))
- {
- vflag |= 1;
- }
- else if (ISOPTION (list->word->word, '-'))
- {
- list = list->next;
- break;
- }
- else if (*list->word->word == '+' || *list->word->word == '-')
- {
- int sign;
- if (legal_number (w = list->word->word + 1, &i) == 0)
- {
- builtin_error (m_badarg, list->word->word);
- builtin_usage ();
- return (EXECUTION_FAILURE);
- }
- sign = (*list->word->word == '+') ? 1 : -1;
- desired_index = get_dirstack_index (i, sign, &index_flag);
- }
- else
- {
- bad_option (list->word->word);
- builtin_usage ();
- return (EXECUTION_FAILURE);
- }
- }
-
- if (flags & CLEARSTAK)
- {
- clear_directory_stack ();
- return (EXECUTION_SUCCESS);
- }
-
- if (index_flag && (desired_index < 0 || desired_index > directory_list_offset))
- {
- pushd_error (directory_list_offset, w);
- return (EXECUTION_FAILURE);
- }
-
-#define DIRSTACK_FORMAT(temp) \
- (flags & LONGFORM) ? temp : polite_directory_format (temp)
-
- /* The first directory printed is always the current working directory. */
- if (index_flag == 0 || (index_flag == 1 && desired_index == 0))
- {
- temp = get_working_directory ("dirs");
- if (temp == 0)
- temp = savestring ("<no current directory>");
- if (vflag & 2)
- printf ("%2d %s", 0, DIRSTACK_FORMAT (temp));
- else
- printf ("%s", DIRSTACK_FORMAT (temp));
- free (temp);
- if (index_flag)
- {
- putchar ('\n');
- return EXECUTION_SUCCESS;
- }
- }
-
-#define DIRSTACK_ENTRY(i) \
- (flags & LONGFORM) ? pushd_directory_list[i] \
- : polite_directory_format (pushd_directory_list[i])
-
- /* Now print the requested directory stack entries. */
- if (index_flag)
- {
- if (vflag & 2)
- printf ("%2d %s", directory_list_offset - desired_index,
- DIRSTACK_ENTRY (desired_index));
- else
- printf ("%s", DIRSTACK_ENTRY (desired_index));
- }
- else
- for (i = directory_list_offset - 1; i >= 0; i--)
- if (vflag >= 2)
- printf ("\n%2d %s", directory_list_offset - (int)i, DIRSTACK_ENTRY (i));
- else
- printf ("%s%s", (vflag & 1) ? "\n" : " ", DIRSTACK_ENTRY (i));
-
- putchar ('\n');
- fflush (stdout);
- return (EXECUTION_SUCCESS);
-}
-
-static void
-pushd_error (offset, arg)
- int offset;
- char *arg;
-{
- if (offset == 0)
- builtin_error ("directory stack empty");
- else if (arg)
- builtin_error ("%s: bad directory stack index", arg);
- else
- builtin_error ("bad directory stack index");
-}
-
-static void
-clear_directory_stack ()
-{
- register int i;
-
- for (i = 0; i < directory_list_offset; i++)
- free (pushd_directory_list[i]);
- directory_list_offset = 0;
-}
-
-/* Switch to the directory in NAME. This uses the cd_builtin to do the work,
- so if the result is EXECUTION_FAILURE then an error message has already
- been printed. */
-static int
-cd_to_string (name)
- char *name;
-{
- WORD_LIST *tlist;
- int result;
-
- tlist = make_word_list (make_word (name), NULL);
- result = cd_builtin (tlist);
- dispose_words (tlist);
- return (result);
-}
-
-static int
-change_to_temp (temp)
- char *temp;
-{
- int tt;
-
- tt = temp ? cd_to_string (temp) : EXECUTION_FAILURE;
-
- if (tt == EXECUTION_SUCCESS)
- dirs_builtin ((WORD_LIST *)NULL);
-
- return (tt);
-}
-
-static void
-add_dirstack_element (dir)
- char *dir;
-{
- int j;
-
- if (directory_list_offset == directory_list_size)
- {
- j = (directory_list_size += 10) * sizeof (char *);
- pushd_directory_list = (char **)xrealloc (pushd_directory_list, j);
- }
- pushd_directory_list[directory_list_offset++] = dir;
-}
-
-static int
-get_dirstack_index (ind, sign, indexp)
- int ind, sign, *indexp;
-{
- if (indexp)
- *indexp = sign > 0 ? 1 : 2;
-
- /* dirs +0 prints the current working directory. */
- /* dirs -0 prints last element in directory stack */
- if (ind == 0 && sign > 0)
- return 0;
- else if (ind == directory_list_offset)
- {
- if (indexp)
- *indexp = sign > 0 ? 2 : 1;
- return 0;
- }
- else
- return (sign > 0 ? directory_list_offset - ind : ind);
-}
-
-char *
-get_dirstack_element (ind, sign)
- int ind, sign;
-{
- int i;
-
- i = get_dirstack_index (ind, sign, (int *)NULL);
- return (i < 0 || i > directory_list_offset) ? (char *)NULL
- : pushd_directory_list[i];
-}
-
-void
-set_dirstack_element (ind, sign, value)
- int ind, sign;
- char *value;
-{
- int i;
-
- i = get_dirstack_index (ind, sign, (int *)NULL);
- if (ind == 0 || i < 0 || i > directory_list_offset)
- return;
- free (pushd_directory_list[i]);
- pushd_directory_list[i] = savestring (value);
-}
-
-WORD_LIST *
-get_directory_stack ()
-{
- register int i;
- WORD_LIST *ret;
- char *d, *t;
-
- for (ret = (WORD_LIST *)NULL, i = 0; i < directory_list_offset; i++)
- {
- d = polite_directory_format (pushd_directory_list[i]);
- ret = make_word_list (make_word (d), ret);
- }
- /* Now the current directory. */
- d = get_working_directory ("dirstack");
- i = 0; /* sentinel to decide whether or not to free d */
- if (d == 0)
- d = ".";
- else
- {
- t = polite_directory_format (d);
- /* polite_directory_format sometimes returns its argument unchanged.
- If it does not, we can free d right away. If it does, we need to
- mark d to be deleted later. */
- if (t != d)
- {
- free (d);
- d = t;
- }
- else /* t == d, so d is what we want */
- i = 1;
- }
- ret = make_word_list (make_word (d), ret);
- if (i)
- free (d);
- return ret; /* was (REVERSE_LIST (ret, (WORD_LIST *)); */
-}
-
-static char *dirs_doc[] = {
- "Display the list of currently remembered directories. Directories",
- "find their way onto the list with the `pushd' command; you can get",
- "back up through the list with the `popd' command.",
- "",
- "The -l flag specifies that `dirs' should not print shorthand versions",
- "of directories which are relative to your home directory. This means",
- "that `~/bin' might be displayed as `/homes/bfox/bin'. The -v flag",
- "causes `dirs' to print the directory stack with one entry per line,",
- "prepending the directory name with its position in the stack. The -p",
- "flag does the same thing, but the stack position is not prepended.",
- "The -c flag clears the directory stack by deleting all of the elements.",
- "",
- "+N displays the Nth entry counting from the left of the list shown by",
- " dirs when invoked without options, starting with zero.",
- "",
- "-N displays the Nth entry counting from the right of the list shown by",
- " dirs when invoked without options, starting with zero.",
- (char *)NULL
-};
-
-static char *pushd_doc[] = {
- "Adds a directory to the top of the directory stack, or rotates",
- "the stack, making the new top of the stack the current working",
- "directory. With no arguments, exchanges the top two directories.",
- "",
- "+N Rotates the stack so that the Nth directory (counting",
- " from the left of the list shown by `dirs', starting with"
- " zero) is at the top.",
- "",
- "-N Rotates the stack so that the Nth directory (counting",
- " from the right of the list shown by `dirs', starting with"
- " zero) is at the top.",
- "",
- "-n suppress the normal change of directory when adding directories",
- " to the stack, so only the stack is manipulated.",
- "",
- "dir adds DIR to the directory stack at the top, making it the",
- " new current working directory.",
- "",
- "You can see the directory stack with the `dirs' command.",
- (char *)NULL
-};
-
-static char *popd_doc[] = {
- "Removes entries from the directory stack. With no arguments,",
- "removes the top directory from the stack, and cd's to the new",
- "top directory.",
- "",
- "+N removes the Nth entry counting from the left of the list",
- " shown by `dirs', starting with zero. For example: `popd +0'",
- " removes the first directory, `popd +1' the second.",
- "",
- "-N removes the Nth entry counting from the right of the list",
- " shown by `dirs', starting with zero. For example: `popd -0'",
- " removes the last directory, `popd -1' the next to last.",
- "",
- "-n suppress the normal change of directory when removing directories",
- " from the stack, so only the stack is manipulated.",
- "",
- "You can see the directory stack with the `dirs' command.",
- (char *)NULL
-};
-
-struct builtin pushd_struct = {
- "pushd",
- pushd_builtin,
- BUILTIN_ENABLED,
- pushd_doc,
- "pushd [+N | -N] [-n] [dir]",
- 0
-};
-
-struct builtin popd_struct = {
- "popd",
- popd_builtin,
- BUILTIN_ENABLED,
- popd_doc,
- "popd [+N | -N] [-n]",
- 0
-};
-
-struct builtin dirs_struct = {
- "dirs",
- dirs_builtin,
- BUILTIN_ENABLED,
- dirs_doc,
- "dirs [-clpv] [+N] [-N]",
- 0
-};
diff --git a/examples/loadables/sleep.c b/examples/loadables/sleep.c
index 57f2cb6..8ae4bc9 100644
--- a/examples/loadables/sleep.c
+++ b/examples/loadables/sleep.c
@@ -60,6 +60,8 @@ long sec, usec;
/*
* An incredibly simplistic floating point converter.
*/
+static int multiplier[7] = { 1, 100000, 10000, 1000, 100, 10, 1 };
+
static int
convert(s, sp, usp)
char *s;
@@ -95,18 +97,11 @@ long *sp, *usp;
}
/* Now convert to millionths */
- if (n == 1)
- usec *= 100000;
- else if (n == 2)
- usec *= 10000;
- else if (n == 3)
- usec *= 1000;
- else if (n == 4)
- usec *= 100;
- else if (n == 5)
- usec *= 10;
- else if (n == 6 && p[6] && isdigit(p[6]) && p[6] >= '5')
+ usec *= multiplier[n];
+
+ if (n == 6 && p[6] && isdigit(p[6]) && p[6] >= '5')
usec++; /* round up 1 */
+
RETURN(1);
}
diff --git a/examples/loadables/sync.c b/examples/loadables/sync.c
new file mode 100644
index 0000000..44d4e09
--- /dev/null
+++ b/examples/loadables/sync.c
@@ -0,0 +1,32 @@
+/* sync - sync the disks by forcing pending filesystem writes to complete */
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+sync_builtin (list)
+ WORD_LIST *list;
+{
+ sync();
+ return (EXECUTION_SUCCESS);
+}
+
+char *sync_doc[] = {
+ "force completion of pending disk writes",
+ (char *)NULL
+};
+
+struct builtin sync_struct = {
+ "sync", /* builtin name */
+ sync_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ sync_doc, /* array of long documentation strings. */
+ "sync", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/template.c b/examples/loadables/template.c
new file mode 100644
index 0000000..7bb3f9f
--- /dev/null
+++ b/examples/loadables/template.c
@@ -0,0 +1,56 @@
+/* template - example template for loadable builtin */
+
+/* See Makefile for compilation details. */
+
+#include <config.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+#include "bashansi.h"
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+extern char *strerror ();
+
+template_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, rval;
+
+ rval = EXECUTION_SUCCESS;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "")) != -1)
+ {
+ switch (opt)
+ {
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ return (rval);
+}
+
+char *template_doc[] = {
+ (char *)NULL
+};
+
+struct builtin template_struct = {
+ "template", /* builtin name */
+ template_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ template_doc, /* array of long documentation strings. */
+ "template", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/uname.c b/examples/loadables/uname.c
new file mode 100644
index 0000000..9f450cd
--- /dev/null
+++ b/examples/loadables/uname.c
@@ -0,0 +1,139 @@
+/*
+ * uname - print system information
+ *
+ * usage: uname [-amnrsv]
+ *
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "bashtypes.h"
+
+#if defined (HAVE_UNAME)
+# include <sys/utsname.h>
+#else
+struct utsname {
+ char sysname[32];
+ char nodename[32];
+ char release[32];
+ char version[32];
+ char machine[32];
+};
+#endif
+
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+#define FLAG_SYSNAME 0x01 /* -s */
+#define FLAG_NODENAME 0x02 /* -n */
+#define FLAG_RELEASE 0x04 /* -r */
+#define FLAG_VERSION 0x08 /* -v */
+#define FLAG_MACHINE 0x10 /* -m, -p */
+
+#define FLAG_ALL 0x1f
+
+#ifndef errno
+extern int errno;
+#endif
+
+static void uprint();
+
+static int uname_flags;
+
+uname_builtin (list)
+ WORD_LIST *list;
+{
+ int opt, r;
+ struct utsname uninfo;
+
+ uname_flags = 0;
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "amnprsv")) != -1)
+ {
+ switch (opt)
+ {
+ case 'a':
+ uname_flags |= FLAG_ALL;
+ break;
+ case 'm':
+ case 'p':
+ uname_flags |= FLAG_MACHINE;
+ break;
+ case 'n':
+ uname_flags |= FLAG_NODENAME;
+ break;
+ case 'r':
+ uname_flags |= FLAG_RELEASE;
+ break;
+ case 's':
+ uname_flags |= FLAG_SYSNAME;
+ break;
+ case 'v':
+ uname_flags |= FLAG_VERSION;
+ break;
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+
+ if (list)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (uname_flags == 0)
+ uname_flags = FLAG_SYSNAME;
+
+ /* Only ancient systems will not have uname(2). */
+#ifdef HAVE_UNAME
+ if (uname (&uninfo) < 0)
+ {
+ builtin_error ("cannot get system name: %s", strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+#else
+ builtin_error ("cannot get system information: uname(2) not available");
+ return (EXECUTION_FAILURE);
+#endif
+
+ uprint (FLAG_SYSNAME, uninfo.sysname);
+ uprint (FLAG_NODENAME, uninfo.nodename);
+ uprint (FLAG_RELEASE, uninfo.release);
+ uprint (FLAG_VERSION, uninfo.version);
+ uprint (FLAG_MACHINE, uninfo.machine);
+
+ return (EXECUTION_SUCCESS);
+}
+
+static void
+uprint (flag, info)
+ int flag;
+ char *info;
+{
+ if (uname_flags & flag)
+ {
+ uname_flags &= ~flag;
+ printf ("%s%c", info, uname_flags ? ' ' : '\n');
+ }
+}
+
+char *uname_doc[] = {
+ "display information about the system",
+ (char *)NULL
+};
+
+struct builtin uname_struct = {
+ "uname",
+ uname_builtin,
+ BUILTIN_ENABLED,
+ uname_doc,
+ "uname [-amnrsv]",
+ 0
+};
diff --git a/examples/loadables/unlink.c b/examples/loadables/unlink.c
new file mode 100644
index 0000000..8c81ad0
--- /dev/null
+++ b/examples/loadables/unlink.c
@@ -0,0 +1,52 @@
+/* unlink - remove a directory entry */
+
+/* Should only be used to remove directories by a superuser prepared to let
+ fsck clean up the file system. */
+
+#include <config.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+
+#include "builtins.h"
+#include "shell.h"
+
+#ifndef errno
+extern int errno;
+#endif
+
+unlink_builtin (list)
+ WORD_LIST *list;
+{
+ if (list == 0)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (unlink (list->word->word) != 0)
+ {
+ builtin_error ("%s: cannot unlink: %s", list->word->word, strerror (errno));
+ return (EXECUTION_FAILURE);
+ }
+
+ return (EXECUTION_SUCCESS);
+}
+
+char *unlink_doc[] = {
+ "Remove a directory entry.",
+ (char *)NULL
+};
+
+struct builtin unlink_struct = {
+ "unlink", /* builtin name */
+ unlink_builtin, /* function implementing the builtin */
+ BUILTIN_ENABLED, /* initial flags for builtin */
+ unlink_doc, /* array of long documentation strings. */
+ "unlink name", /* usage synopsis; becomes short_doc */
+ 0 /* reserved for internal use */
+};
diff --git a/examples/loadables/whoami.c b/examples/loadables/whoami.c
new file mode 100644
index 0000000..41fd5c4
--- /dev/null
+++ b/examples/loadables/whoami.c
@@ -0,0 +1,52 @@
+/*
+ * whoami - print out username of current user
+ */
+
+#include <config.h>
+#include <stdio.h>
+
+#include "builtins.h"
+#include "shell.h"
+#include "bashgetopt.h"
+
+whoami_builtin (list)
+ WORD_LIST *list;
+{
+ int opt;
+
+ reset_internal_getopt ();
+ while ((opt = internal_getopt (list, "")) != -1)
+ {
+ switch (opt)
+ {
+ default:
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+ }
+ list = loptend;
+ if (list)
+ {
+ builtin_usage ();
+ return (EX_USAGE);
+ }
+
+ if (current_user.user_name == 0)
+ get_current_user_info ();
+ printf ("%s\n", current_user.user_name);
+ return (EXECUTION_SUCCESS);
+}
+
+char *whoami_doc[] = {
+ "display name of current user",
+ (char *)NULL
+};
+
+struct builtin whoami_struct = {
+ "whoami",
+ whoami_builtin,
+ BUILTIN_ENABLED,
+ whoami_doc,
+ "whoami",
+ 0
+};
diff --git a/examples/misc/aliasconv.bash b/examples/misc/aliasconv.bash
index cb92ee0..3fbe877 100755
--- a/examples/misc/aliasconv.bash
+++ b/examples/misc/aliasconv.bash
@@ -1,8 +1,8 @@
#! /bin/bash
#
-# alias-conv.sh - convert csh aliases to bash aliases and functions
+# aliasconv.bash - convert csh aliases to bash aliases and functions
#
-# usage: alias-conv.sh
+# usage: aliasconv.bash
#
# Chet Ramey
# chet@po.cwru.edu
@@ -27,7 +27,11 @@ mkalias ()
}
EOF
-sed "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>/tmp/cb$$.1
+# the first thing we want to do is to protect single quotes in the alias,
+# since they whole thing is going to be surrounded by single quotes when
+# passed to mkalias
+
+sed -e "s:':\\'\\\'\\':" -e "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>/tmp/cb$$.1
$BASH /tmp/cb$$.1 | sed -e 's/\$cwd/\$PWD/g' \
-e 's/\$term/\$TERM/g' \
diff --git a/examples/misc/aliasconv.sh b/examples/misc/aliasconv.sh
index 4cbebfb..29e1ead 100755
--- a/examples/misc/aliasconv.sh
+++ b/examples/misc/aliasconv.sh
@@ -1,8 +1,8 @@
#! /bin/bash
#
-# alias-conv.sh - convert csh aliases to bash aliases and functions
+# aliasconv.sh - convert csh aliases to bash aliases and functions
#
-# usage: alias-conv.sh
+# usage: aliasconv.sh
#
# Chet Ramey
# chet@po.cwru.edu
@@ -27,7 +27,11 @@ mkalias ()
}
EOF
-sed "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>/tmp/cb$$.1
+# the first thing we want to do is to protect single quotes in the alias,
+# since they whole thing is going to be surrounded by single quotes when
+# passed to mkalias
+
+sed -e "s:':\\'\\\'\\':" -e "s/^\([a-zA-Z0-9_-]*\)$T\(.*\)$/mkalias \1 '\2'/" >>/tmp/cb$$.1
sh /tmp/cb$$.1 | sed -e 's/\$cwd/\$PWD/g' \
-e 's/\$term/\$TERM/g' \
diff --git a/examples/scripts/adventure.sh b/examples/scripts/adventure.sh
index a6d2eaa..4e22393 100755
--- a/examples/scripts/adventure.sh
+++ b/examples/scripts/adventure.sh
@@ -90,6 +90,11 @@ ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; }
ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75 -l$[ ( $# + 4 ) / 5 ]; }
ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; }
+# enable history, bang history expansion, and emacs editing
+set -o history
+set -o histexpand
+set -o emacs
+
cd
LIM=.limbo # $HOME/$LIM contains "destroyed" objects
mkdir $LIM >&- 2>&-
@@ -164,8 +169,7 @@ do room=`pwd`
prev=$room
fi
- echo -n '-advsh> ' # prompt
- read verb obj x
+ read -e -p '-advsh> ' verb obj x # prompt is '-advsh> '
if [ $? != 0 ]
then verb=quit # EOF
fi