From 9d8085074991d5c0a42d6fc96a2d1a3ee918aad1 Mon Sep 17 00:00:00 2001
From: Daniel Baumann <daniel.baumann@progress-linux.org>
Date: Sat, 27 Apr 2024 08:17:24 +0200
Subject: Adding upstream version 5.1.

Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
---
 examples/functions/array-stuff     | 122 ++++++++
 examples/functions/array-to-string |  15 +
 examples/functions/arrayops.bash   | 146 ++++++++++
 examples/functions/autoload        | 111 ++++++++
 examples/functions/autoload.v2     | 192 +++++++++++++
 examples/functions/autoload.v3     | 125 +++++++++
 examples/functions/autoload.v4     | 556 +++++++++++++++++++++++++++++++++++++
 examples/functions/autoload.v4.t   | 184 ++++++++++++
 examples/functions/basename        |  23 ++
 examples/functions/csh-compat      |  48 ++++
 examples/functions/dirname         |  21 ++
 examples/functions/dirstack        | 160 +++++++++++
 examples/functions/exitstat        |  22 ++
 examples/functions/external        |  50 ++++
 examples/functions/fact            |  13 +
 examples/functions/fstty           |  77 +++++
 examples/functions/func            |  43 +++
 examples/functions/inetaddr        |  79 ++++++
 examples/functions/inpath          |  14 +
 examples/functions/isnum2          |  41 +++
 examples/functions/isvalidip       |  14 +
 examples/functions/ksh-cd          |  54 ++++
 examples/functions/ksh-compat-test |  58 ++++
 examples/functions/kshenv          | 246 ++++++++++++++++
 examples/functions/login           |  11 +
 examples/functions/notify.bash     |  77 +++++
 examples/functions/seq             |  48 ++++
 examples/functions/seq2            |  56 ++++
 examples/functions/shcat           |   7 +
 examples/functions/shcat2          |  19 ++
 examples/functions/sort-pos-params |  69 +++++
 examples/functions/substr          |  97 +++++++
 examples/functions/substr2         |  99 +++++++
 examples/functions/whatis          |  71 +++++
 examples/functions/whence          |  78 ++++++
 examples/functions/which           |  62 +++++
 36 files changed, 3108 insertions(+)
 create mode 100644 examples/functions/array-stuff
 create mode 100644 examples/functions/array-to-string
 create mode 100644 examples/functions/arrayops.bash
 create mode 100644 examples/functions/autoload
 create mode 100644 examples/functions/autoload.v2
 create mode 100644 examples/functions/autoload.v3
 create mode 100644 examples/functions/autoload.v4
 create mode 100644 examples/functions/autoload.v4.t
 create mode 100644 examples/functions/basename
 create mode 100644 examples/functions/csh-compat
 create mode 100644 examples/functions/dirname
 create mode 100644 examples/functions/dirstack
 create mode 100644 examples/functions/exitstat
 create mode 100644 examples/functions/external
 create mode 100644 examples/functions/fact
 create mode 100644 examples/functions/fstty
 create mode 100644 examples/functions/func
 create mode 100644 examples/functions/inetaddr
 create mode 100644 examples/functions/inpath
 create mode 100644 examples/functions/isnum2
 create mode 100644 examples/functions/isvalidip
 create mode 100644 examples/functions/ksh-cd
 create mode 100644 examples/functions/ksh-compat-test
 create mode 100644 examples/functions/kshenv
 create mode 100644 examples/functions/login
 create mode 100644 examples/functions/notify.bash
 create mode 100644 examples/functions/seq
 create mode 100644 examples/functions/seq2
 create mode 100644 examples/functions/shcat
 create mode 100644 examples/functions/shcat2
 create mode 100644 examples/functions/sort-pos-params
 create mode 100644 examples/functions/substr
 create mode 100644 examples/functions/substr2
 create mode 100644 examples/functions/whatis
 create mode 100644 examples/functions/whence
 create mode 100644 examples/functions/which

(limited to 'examples/functions')

diff --git a/examples/functions/array-stuff b/examples/functions/array-stuff
new file mode 100644
index 0000000..e6316c7
--- /dev/null
+++ b/examples/functions/array-stuff
@@ -0,0 +1,122 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1999 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# usage: reverse arrayname
+reverse()
+{
+	local -a R
+	local -i i
+	local rlen temp
+
+	# make r a copy of the array whose name is passed as an arg
+	eval R=\( \"\$\{$1\[@\]\}\" \)
+
+	# reverse R
+	rlen=${#R[@]}
+
+	for ((i=0; i < rlen/2; i++ ))
+	do
+		temp=${R[i]}
+		R[i]=${R[rlen-i-1]}
+		R[rlen-i-1]=$temp
+	done
+
+	# and assign R back to array whose name is passed as an arg
+	eval $1=\( \"\$\{R\[@\]\}\" \)
+}
+
+A=(1 2 3 4 5 6 7)
+echo "${A[@]}"
+reverse A
+echo "${A[@]}"
+reverse A
+echo "${A[@]}"
+
+# unset last element of A
+alen=${#A[@]}
+unset A[$alen-1]
+echo "${A[@]}"
+
+# ashift -- like shift, but for arrays
+
+ashift()
+{
+	local -a R
+	local n
+
+	case $# in
+	1)	n=1 ;;
+	2)	n=$2 ;;
+	*)	echo "$FUNCNAME: usage: $FUNCNAME array [count]" >&2
+		exit 2;;
+	esac
+
+	# make r a copy of the array whose name is passed as an arg
+	eval R=\( \"\$\{$1\[@\]\}\" \)
+
+	# shift R
+	R=( "${R[@]:$n}" )
+
+	# and assign R back to array whose name is passed as an arg
+	eval $1=\( \"\$\{R\[@\]\}\" \)
+}
+
+ashift A 2
+echo "${A[@]}"
+
+ashift A
+echo "${A[@]}"
+
+ashift A 7
+echo "${A[@]}"
+
+# Sort the members of the array whose name is passed as the first non-option
+# arg.  If -u is the first arg, remove duplicate array members.
+array_sort()
+{
+	local -a R
+	local u
+
+	case "$1" in
+	-u)	u=-u ; shift ;;
+	esac
+
+	if [ $# -eq 0 ]; then
+		echo "array_sort: argument expected" >&2
+		return 1
+	fi
+
+	# make r a copy of the array whose name is passed as an arg
+	eval R=\( \"\$\{$1\[@\]\}\" \)
+
+	# sort R
+	R=( $( printf "%s\n" "${A[@]}" | sort $u) )
+
+	# and assign R back to array whose name is passed as an arg
+	eval $1=\( \"\$\{R\[@\]\}\" \)
+	return 0
+}
+
+A=(3 1 4 1 5 9 2 6 5 3 2)
+array_sort A
+echo "${A[@]}"
+
+A=(3 1 4 1 5 9 2 6 5 3 2)
+array_sort -u A
+echo "${A[@]}"
diff --git a/examples/functions/array-to-string b/examples/functions/array-to-string
new file mode 100644
index 0000000..0d2fbe5
--- /dev/null
+++ b/examples/functions/array-to-string
@@ -0,0 +1,15 @@
+#! /bin/bash
+
+# Format: array_to_string vname_of_array vname_of_string separator
+array_to_string()
+{
+	(( ($# < 2) || ($# > 3) )) && {
+		 "$FUNCNAME: usage: $FUNCNAME arrayname stringname [separator]"
+		return 2
+	}
+
+	local array=$1 string=$2
+	((3==$#)) && [[ $3 = ? ]] && local IFS="${3}${IFS}"
+	eval $string="\"\${$array[*]}\""
+	return 0
+}
diff --git a/examples/functions/arrayops.bash b/examples/functions/arrayops.bash
new file mode 100644
index 0000000..d34353a
--- /dev/null
+++ b/examples/functions/arrayops.bash
@@ -0,0 +1,146 @@
+# arrayops.bash --- hide some of the nasty syntax for manipulating bash arrays
+# Author: Noah Friedman <friedman@splode.com>
+# Created: 2016-07-08
+# Public domain
+
+# $Id: arrayops.bash,v 1.3 2016/07/28 15:38:55 friedman Exp $
+
+# Commentary:
+
+# These functions try to tame the syntactic nightmare that is bash array
+# syntax, which makes perl's almost look reasonable.
+#
+# For example the apush function below lets you write:
+#
+#	apush arrayvar newval
+#
+# instead of
+#
+#	${arrayvar[${#arrayvar[@]}]}=newval
+#
+# Because seriously, you've got to be kidding me.
+
+# These functions avoid the use of local variables as much as possible
+# (especially wherever modification occurs) because those variable names
+# might shadow the array name passed in.  Dynamic scope!
+
+# Code:
+
+#:docstring apush:
+# Usage: apush arrayname val1 {val2 {...}}
+#
+# Appends VAL1 and any remaining arguments to the end of the array
+# ARRAYNAME as new elements.
+#:end docstring:
+apush()
+{
+    eval "$1=(\"\${$1[@]}\" \"\${@:2}\")"
+}
+
+#:docstring apop:
+# Usage: apop arrayname {n}
+#
+# Removes the last element from ARRAYNAME.
+# Optional argument N means remove the last N elements.
+#:end docstring:
+apop()
+{
+    eval "$1=(\"\${$1[@]:0:\${#$1[@]}-${2-1}}\")"
+}
+
+#:docstring aunshift:
+# Usage: aunshift arrayname val1 {val2 {...}}
+#
+# Prepends VAL1 and any remaining arguments to the beginning of the array
+# ARRAYNAME as new elements.  The new elements will appear in the same order
+# as given to this function, rather than inserting them one at a time.
+#
+# For example:
+#
+#	foo=(a b c)
+#	aunshift foo 1 2 3
+#       => foo is now (1 2 3 a b c)
+# but
+#
+#	foo=(a b c)
+#	aunshift foo 1
+#       aunshift foo 2
+#       aunshift foo 3
+#       => foo is now (3 2 1 a b c)
+#
+#:end docstring:
+aunshift()
+{
+    eval "$1=(\"\${@:2}\" \"\${$1[@]}\")"
+}
+
+#:docstring ashift:
+# Usage: ashift arrayname {n}
+#
+# Removes the first element from ARRAYNAME.
+# Optional argument N means remove the first N elements.
+#:end docstring:
+ashift()
+{
+    eval "$1=(\"\${$1[@]: -\${#$1[@]}+${2-1}}\")"
+}
+
+#:docstring aset:
+# Usage: aset arrayname idx newval
+#
+# Assigns ARRAYNAME[IDX]=NEWVAL
+#:end docstring:
+aset()
+{
+    eval "$1[\$2]=${@:3}"
+}
+
+#:docstring aref:
+# Usage: aref arrayname idx {idx2 {...}}
+#
+# Echoes the value of ARRAYNAME at index IDX to stdout.
+# If more than one IDX is specified, each one is echoed.
+#
+# Unfortunately bash functions cannot return arbitrary values in the usual way.
+#:end docstring:
+aref()
+{
+    eval local "v=(\"\${$1[@]}\")"
+    local x
+    for x in ${@:2} ; do echo "${v[$x]}"; done
+}
+
+#:docstring aref:
+# Usage: alen arrayname
+#
+# Echoes the length of the number of elements in ARRAYNAME.
+#
+# It also returns number as a numeric value, but return values are limited
+# by a maximum of 255 so don't rely on this unless you know your arrays are
+# relatively small.
+#:end docstring:
+alen()
+{
+    eval echo   "\${#$1[@]}"
+    eval return "\${#$1[@]}"
+}
+
+#:docstring anreverse:
+# Usage: anreverse arrayname
+#
+# Reverse the order of the elements in ARRAYNAME.
+# The array variable is altered by this operation.
+#:end docstring:
+anreverse()
+{
+    eval set $1 "\"\${$1[@]}\""
+    eval unset $1
+    while [ $# -gt 1 ]; do
+        eval "$1=(\"$2\" \"\${$1[@]}\")"
+        set $1 "${@:3}"
+    done
+}
+
+#provide arrayops
+
+# arrayops.bash ends here
diff --git a/examples/functions/autoload b/examples/functions/autoload
new file mode 100644
index 0000000..cb3a673
--- /dev/null
+++ b/examples/functions/autoload
@@ -0,0 +1,111 @@
+#
+# An almost ksh-compatible `autoload'.  A function declared as `autoload' will
+# be read in from a file the same name as the function found by searching the
+# $FPATH (which works the same as $PATH), then that definition will be run.
+#
+# To do this without source support, we define a dummy function that, when
+# executed, will load the file (thereby re-defining the function), then 
+# execute that newly-redefined function with the original arguments.
+#
+# It's not identical to ksh because ksh apparently does lazy evaluation
+# and looks for the file to load from only when the function is referenced.
+# This one requires that the file exist when the function is declared as
+# `autoload'.
+#
+# usage: autoload func [func...]
+#
+# The first cut of this was by Bill Trost, trost@reed.bitnet
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+
+#
+# Declare a function ($1) to be autoloaded from a file ($2) when it is first
+# called.  This defines a `temporary' function that will `.' the file 
+# containing the real function definition, then execute that new definition with
+# the arguments given to this `fake' function.  The autoload function defined
+# by the file and the file itself *must* be named identically.
+#
+
+aload()
+{
+	eval $1 '() {  . '$2' ; '$1' "$@" ; return $? ; }'
+}
+
+#
+# Search $FPATH for a file the same name as the function given as $1, and
+# autoload the function from that file.  There is no default $FPATH.
+#
+
+autoload()
+{
+	#
+	# Save the list of functions; we're going to blow away the arguments
+	# in a second.  If any of the names contain white space, TFB.
+	#
+
+	local args="$*"
+
+	#
+	# This should, I think, list the functions marked as autoload and not
+	# yet defined, but we don't have enough information to do that here.
+	#
+	if [ $# -eq 0 ] ; then
+		echo "usage: autoload function [function...]" >&2
+		return 1
+	fi
+
+	#
+	# If there is no $FPATH, there is no work to be done
+	#
+
+	if [ -z "$FPATH" ] ; then
+		echo autoload: FPATH not set or null >&2
+		return 1
+	fi
+
+	#
+	# This treats FPATH exactly like PATH: a null field anywhere in the
+	# FPATH is treated the same as the current directory.
+	#
+	# The path splitting command is taken from Kernighan and Pike
+	#
+
+#	fp=$(echo $FPATH | sed 's/^:/.:/
+#				s/::/:.:/g
+#				s/:$/:./
+#				s/:/ /g')
+
+	# replaced with builtin mechanisms 2001 Oct 10
+
+	fp=${FPATH/#:/.:}
+	fp=${fp//::/:.:}
+	fp=${fp/%:/:.}
+	fp=${fp//:/ }
+
+	for FUNC in $args ; do
+		#
+		# We're blowing away the arguments to autoload here...
+		# We have to; there are no arrays (well, there are, but
+		# this doesn't use them yet).
+		#
+		set -- $fp
+
+		while [ $# -ne 0 ] ; do
+			if [ -f $1/$FUNC ] ; then
+				break			# found it! 
+			fi
+			shift
+		done
+
+		if [ $# -eq 0 ] ; then
+			echo "$FUNC: autoload function not found" >&2
+			continue
+		fi
+
+#		echo auto-loading $FUNC from $1/$FUNC
+		aload $FUNC $1/$FUNC
+	done
+
+	return 0
+}
diff --git a/examples/functions/autoload.v2 b/examples/functions/autoload.v2
new file mode 100644
index 0000000..e29c695
--- /dev/null
+++ b/examples/functions/autoload.v2
@@ -0,0 +1,192 @@
+#
+# An almost ksh-compatible `autoload'.  A function declared as `autoload' will
+# be read in from a file the same name as the function found by searching the
+# $FPATH (which works the same as $PATH), then that definition will be run.
+#
+# To do this without source support, we define a dummy function that, when
+# executed, will load the file (thereby re-defining the function), then 
+# execute that newly-redefined function with the original arguments.
+#
+# It's not identical to ksh because ksh apparently does lazy evaluation
+# and looks for the file to load from only when the function is referenced.
+# This one requires that the file exist when the function is declared as
+# `autoload'.
+#
+# usage: autoload [-pu] [func ...]
+#
+# options:
+#	-p	print in a format that can be reused as input
+#	-u	unset each function and remove it from the autoload list
+#
+# The first cut of this was by Bill Trost, trost@reed.edu
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+
+unset _AUTOLOADS
+_aindex=0
+
+#
+# Declare a function ($1) to be autoloaded from a file ($2) when it is first
+# called.  This defines a `temporary' function that will `.' the file 
+# containing the real function definition, then execute that new definition with
+# the arguments given to this `fake' function.  The autoload function defined
+# by the file and the file itself *must* be named identically.
+#
+
+_aload()
+{
+	eval $1 '() {  . '$2' ; '$1' "$@" ; return $? ; }'
+	_autoload_addlist "$1"
+}
+
+_autoload_addlist()
+{
+	local i=0
+
+	while (( i < $_aindex )); do
+		case "${_AUTOLOADS[i]}" in
+		"$1")	return 1 ;;
+		esac
+		(( i += 1 ))
+	done
+	_AUTOLOADS[_aindex]="$1"
+	(( _aindex += 1 ))
+	return 0
+}
+
+_autoload_dump()
+{
+	local func
+
+	for func in ${_AUTOLOADS[@]}; do
+		[ -n "$1" ] && echo -n "autoload "
+		echo "$func"
+	done
+}
+
+# Remove $1 from the list of autoloaded functions
+_autoload_remove_one()
+{
+	local i=0 nnl=0
+	local -a nlist
+
+	while (( i < _aindex )); do
+		case "${_AUTOLOADS[i]}" in
+		"$1")	;;
+		*)	nlist[nnl]="${_AUTOLOADS[i]}" ; (( nnl += 1 ));;
+		esac
+		(( i += 1 ))
+	done
+	unset _AUTOLOADS _aindex
+	eval _AUTOLOADS=( ${nlist[@]} )
+	_aindex=$nnl
+}
+
+# Remove all function arguments from the list of autoloaded functions
+_autoload_remove()
+{
+	local func i es=0
+	
+	# first unset the autoloaded functions
+	for func; do
+		i=0
+		while (( i < _aindex )); do
+			case "${_AUTOLOADS[i]}" in
+			"$func")	unset -f $func ; break ;;
+			esac
+			(( i += 1 ))
+		done
+		if (( i == _aindex )); then
+			echo "autoload: $func: not an autoloaded function" >&2
+			es=1
+		fi
+	done
+
+	# then rebuild the list of autoloaded functions
+	for func ; do
+		_autoload_remove_one "$func"
+	done
+
+	return $es
+}
+
+#
+# Search $FPATH for a file the same name as the function given as $1, and
+# autoload the function from that file.  There is no default $FPATH.
+#
+
+autoload()
+{
+	local -a fp
+	local _autoload_unset nfp i
+
+	if (( $# == 0 )) ; then
+		_autoload_dump
+		return 0
+	fi
+
+	OPTIND=1
+	while getopts pu opt
+	do
+		case "$opt" in
+		p)	_autoload_dump printable; return 0;;
+		u)	_autoload_unset=y ;;
+		*)	echo "autoload: usage: autoload [-pu] [function ...]" >&2
+			return 1 ;;
+		esac
+	done
+
+	shift $(( $OPTIND - 1 ))
+
+	if [ -n "$_autoload_unset" ]; then
+		_autoload_remove "$@"
+		return $?
+	fi
+
+	#
+	# If there is no $FPATH, there is no work to be done
+	#
+
+	if [ -z "$FPATH" ] ; then
+		echo "autoload: FPATH not set or null" >&2
+		return 1
+	fi
+
+	#
+	# This treats FPATH exactly like PATH: a null field anywhere in the
+	# FPATH is treated the same as the current directory.
+	#
+	# This turns $FPATH into an array, substituting `.' for `'
+	#
+	eval fp=( $(
+			IFS=':'
+			set -- ${FPATH}
+			for p in "$@" ; do echo -n "${p:-.} "; done
+		   )
+		)
+
+	nfp=${#fp[@]}
+
+	for FUNC ; do
+		i=0;
+		while (( i < nfp )) ; do
+			if [ -f ${fp[i]}/$FUNC ] ; then
+				break			# found it! 
+			fi
+			(( i += 1 ))
+		done
+
+		if (( i == nfp )) ; then
+			echo "autoload: $FUNC: autoload function not found" >&2
+			es=1
+			continue
+		fi
+
+#		echo auto-loading $FUNC from ${fp[i]}/$FUNC
+		_aload $FUNC ${fp[i]}/$FUNC
+		es=0
+	done
+
+	return $es
+}
diff --git a/examples/functions/autoload.v3 b/examples/functions/autoload.v3
new file mode 100644
index 0000000..b1e5dfe
--- /dev/null
+++ b/examples/functions/autoload.v3
@@ -0,0 +1,125 @@
+#From: Mark Kennedy <mark.t.kennedy@gmail.com> (<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/autoload.v4 b/examples/functions/autoload.v4
new file mode 100644
index 0000000..7f60563
--- /dev/null
+++ b/examples/functions/autoload.v4
@@ -0,0 +1,556 @@
+## -*- sh -*-
+
+# The psuedo-ksh autoloader.
+
+# How to use:
+# o One function per file.
+# o File and function name match exactly.
+# o File is located in a directory that is in FPATH.
+# o This script (autoload) must be sourced in as early as possible. This
+#   implies that any code in this script should NOT rely on any library of local
+#   or self-defined functions having already been loaded.
+# o autoload must be called for each function before the function can be used. If
+#   autoloads are in directories where there are nothing but autoloads, then
+#   'autoload /path/to/files/*' suffices (but see options -a and -f).
+# o The call must be made in the current environment, not a subshell.
+# o The command line suffices as "current environment". If you have autoload
+#   calls in a script, that script must be dotted into the process.
+
+# 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
+# The fourth cut came from Matthew Persico, matthew.persico@gmail.com 2017/August
+
+autoload_calc_shimsize ()
+{
+    echo $((AUTOLOAD_SHIM_OVERHEAD + 3 * ${#1}))
+}
+
+_autoload_split_fpath ()
+{
+    (IFS=':'; set -- ${FPATH}; echo "$@")
+}
+
+_aload()
+{
+    local opt OPTIND
+    local doexport=0
+    local doreload=0
+    local doverbose=0
+    local doevalshim=0
+    local loadthese
+    local optimize=0
+    local loaded=0
+    local exported=0
+    local optimized=0
+    local summary=0
+    local dofpath=0
+    while getopts xrvla:oyf opt; do
+        case $opt in
+            x) doexport=1;;
+            r) doreload=1;;
+            v) doverbose=1;;
+            l) doevalshim=1;;
+            a) loadthese=$(find $OPTARG -maxdepth 1 -type f -printf '%f ');;
+            o) optimize=1;;
+            y) summary=1;;
+            f) loadthese=$(find $(_autoload_split_fpath) -maxdepth 1 -type f -printf '%f ');;
+            *) echo "_aload: usage: _aload [-xrvlyf] [-a dir] [function ...]" >&2; return;;
+        esac
+    done
+
+    shift $(($OPTIND-1))
+
+    [ -z "$loadthese" ] && loadthese="$@"
+
+    local func
+    for func in $loadthese; do
+        local exists_fn
+        exists_fn=$(declare -F $func)
+        if [ -n "$exists_fn" ] && ((doreload==0)) && ((doevalshim==0))
+        then
+            if ((doverbose))
+            then
+                echo "autoload: function '$func' already exists"
+            fi
+        else
+            local andevaled=''
+            local andexported=''
+            local evalstat=0
+            local doshim=1
+            local funcfile
+            funcfile=$(_autoload_resolve $func)
+            if [[ $funcfile ]] ; then
+                ## The file was found for $func. Process it.
+
+                if ((optimize)); then
+                    ## For the first function loaded, we will not know
+                    ## AUTOLOAD_SHIM_OVERHEAD. We can only calculate it after
+                    ## we have loaded one function.
+                    if [[ $AUTOLOAD_SHIM_OVERHEAD ]]; then
+                        local size=$(wc -c $funcfile| sed 's/ .*//')
+                        local shimsize=$(autoload_calc_shimsize $func)
+                        if (( size <= shimsize)); then
+                            doshim=0
+                            andevaled=', optimized'
+                            ((optimized+=1))
+                        fi
+                    fi
+                fi
+
+                if ((doevalshim)); then
+                    doshim=0
+                    andevaled=', evaled'
+                fi
+
+                ## 'brand' as in branding a cow with a mark. We add a local
+                ## variable to each function we autoload so that we can tell
+                ## later on it is an autoloaded function without having to
+                ## maintain some bash array or hash that cannot be passed to
+                ## and used by subshells.
+                local brandtext
+                brandtext="eval \"\$(type $func | sed -e 1d -e 4ilocal\\ AUTOLOADED=\'$func\')\""
+                if ((doshim)); then
+                    ## Don't bother trying to save space by shoving all the
+                    ## eval text below onto one unreadable line; new lines will
+                    ## be added at your semicolons and any indentation below
+                    ## seems to be ignored anyway if you export the function;
+                    ## look at its BASH_FUNCTION representation.
+                    eval $func '()
+                    {
+                    local IS_SHIM="$func"
+                    local file=$(_autoload_resolve '$func')
+                    if [[ $file ]]
+                    then
+                        . $file
+                        '$brandtext'
+                        '$func' "$@"
+                        return $?
+                    else
+                        return 1;
+                    fi
+                    }'
+                else
+                    . $funcfile
+                    eval "$brandtext"
+                fi
+                evalstat=$?
+                if((evalstat==0))
+                then
+                    ((loaded+=1))
+                    ((doexport)) && export -f $func && andexported=', exported' && ((exported+=1))
+                    ((doverbose)) && echo "$func autoloaded${andexported}${andevaled}"
+                    if [[ ! $AUTOLOAD_SHIM_OVERHEAD ]] && ((doshim)); then
+                        ## ...we have just loaded the first function shim into
+                        ## memory. Let's calc the AUTOLOAD_SHIM_OVERHEAD size
+                        ## to use going forward. In theory, we could check
+                        ## again here to see if we should optimize and source
+                        ## in this function, now that we now the
+                        ## AUTOLOAD_SHIM_OVERHEAD. In practice, it's not worth
+                        ## duping that code or creating a function to do so for
+                        ## one function.
+                        AUTOLOAD_SHIM_OVERHEAD=$(type $func | grep -v -E "^$1 is a function" | sed "s/$func//g"| wc -c)
+                        export AUTOLOAD_SHIM_OVERHEAD
+                    fi
+                else
+                    echo "$func failed to load" >&2
+                fi
+            fi
+        fi
+    done
+    ((summary)) && echo "autoload: loaded:$loaded exported:$exported optimized:$optimized overhead:$AUTOLOAD_SHIM_OVERHEAD bytes"
+}
+
+_autoload_dump()
+{
+    local opt OPTIND
+    local opt_p=''
+    local opt_s=''
+    while getopts ps opt
+    do
+        case $opt in
+            p ) opt_p=1;;
+            s ) opt_s=1;;
+        esac
+    done
+
+    shift $(($OPTIND-1))
+
+    local exported=''
+    local executed=''
+    local func
+    for func in $(declare | grep -E 'local\\{0,1} AUTOLOADED' | sed -e "s/.*AUTOLOADED=//" -e 's/\\//g' -e 's/[");]//g' -e "s/'//g")
+    do
+        if [ -n "$opt_p" ]; then echo -n "autoload "; fi
+        if [ -n "$opt_s" ]
+        then
+            exported=$(declare -F | grep -E "${func}$" | sed 's/declare -f\(x\{0,1\}\).*/\1/')
+            [ "$exported" = 'x' ] && exported=' exported' || exported=' not exported'
+            executed=$(type $func | grep 'local IS_SHIM')
+            [ -z "$executed" ] && executed=' executed' || executed=' not executed'
+        fi
+        echo "${func}${exported}${executed}"
+    done
+}
+
+_autoload_resolve()
+{
+    if [[ ! "$FPATH" ]]; then
+        echo "autoload: FPATH not set or null" >&2
+        return
+    fi
+
+    local p # for 'path'. The $() commands in the for loop split the FPATH
+            # string into its constituents so that each one may be processed.
+
+    for p in $( _autoload_split_fpath ); do
+        p=${p:-.}
+        if [ -f $p/$1 ]; then echo $p/$1; return; fi
+    done
+
+    echo "autoload: $1: function source file not found" >&2
+}
+
+_autoload_edit()
+{
+    [ -z "$EDITOR" ] && echo "Error: no EDITOR defined" && return 1
+    local toedit
+    local func
+    for func in "$@"
+    do
+        local file=$(_autoload_resolve $func)
+        if [[ $file ]]
+        then
+            toedit="$toedit $file"
+        else
+            echo "$funcname not found in FPATH funcfile. Skipping."
+        fi
+    done
+
+    [ -z "$toedit" ] && return 1
+
+    local timemarker=$(mktemp)
+
+    $EDITOR $toedit
+
+    local i
+    for i in $toedit
+    do
+        if [ $i -nt $timemarker ]
+        then
+            local f=$(basename $i)
+            echo Reloading $f
+            autoload -r $f
+        fi
+    done
+}
+
+_autoload_page()
+{
+    [ -z "$PAGER" ] && echo "Error: no PAGER defined" && return 1
+    local topage
+    local func
+    for func in "$@"
+    do
+        local file=$(_autoload_resolve $func)
+        if [[ $file ]]
+        then
+            topage="$topage $file"
+        else
+            echo "$funcname not found in FPATH funcfile. Skipping."
+        fi
+    done
+
+    [ -z "$topage" ] && return 1
+
+    $PAGER $topage
+}
+
+_autoload_remove()
+{
+    unset -f "$@"
+}
+
+_autoload_help()
+{
+    cat <<EOH
+NAME
+        autoload
+
+SYNOPSIS
+        autoload [-ps]
+        autoload [-xuremloyv] [function ...]
+        autoload -a directory [-oyv]
+        autoload -f [-oyv]
+        autoload [-h]
+
+        autoreload [function ...]
+
+DESCRIPTION
+
+        An implementation of the 'autoload' functionality built into other
+        shells, of which 'ksh' is the most prominent.  It allows for a keeping
+        the process environment small by loading small 'shim' functions into
+        memory that will, on first call, load the full text of the given
+        function and run it. Subsequent calls to the function just run the
+        function.
+
+        'autoreload' is a synonym for 'autoload -r'. See below.
+
+USAGE
+
+        o Each function to be autoloaded should be defined in a single file,
+          named exactly the same as the function.
+
+        o In order to avoid side effects, do NOT put code other than the
+          function definition in the file. Unless of course you want to do some
+          one-time initialization. But beware that if you reload the function
+          for any reason, you will rerun the initialization code. Make sure
+          your initialization is re-entrant. Or, better yet,
+
+          *** do NOT put code other than the function definition in the file ***
+
+        o These function definition files should be placed in a directory that
+          is in the FPATH environment variable. Subdirectories are NOT scanned.
+
+        o The autoload script should be sourced into the current process as
+          early as possible in process start up. See NOTES below for
+          suggestions.
+
+        o The calls to the autoload function must be made in the current
+          process. If your calls are in their own script, that script must be
+          sourced in. Command line invocations are also sufficient. (But see
+          '-l' below.)
+
+        o The first time the function is called, the shim function that was
+          created by the 'autoload' call is what is executed. This function
+          then goes and finds the appropriate file in FPATH, sources it in and
+          then calls the actual function with any arguments you just passed in
+          to the shim function. Subsequent calls just run the function.
+
+OPTIONS
+
+        -a Autoload (a)ll the functions found in the given directory.
+
+        -f Autoload all the functions found in all the directories on the
+           FPATH.
+
+        -p Print all the autoloaded functions.
+
+        -s Print all the autoloaded functions and add their export status.
+
+        -x Export the specified functions to the environment for use in
+           subshells.
+
+        -u Unset the function, so it can be reloaded.
+
+        -r Reload the shims of the specified functions, even if the functions
+           have been already been executed.  This will allow you to modify the
+           functions' source and have the new version executed next time the
+           function is called.
+
+           It would be very easy to modify a function's script, run the
+           function and scratch your head for a long time trying to figure out
+           why your changes are not being executed. That's why we provide the
+           '-e' flag described below for modifications.
+
+           Reloads, of course, only apply in the context of the current session
+           and any future subshell you start from the current session. Existing
+           sessions will need to have the same 'autoload -r' command run in
+           them.
+
+        -e Find the scripts in which the specified functions are defined and
+           start up \$EDITOR on those scripts. Reload the ones that were
+           modified when you exit \$EDITOR. (Note: If you use 'autoload -e foo'
+           to edit function 'foo', and then in your editor you separately load
+           up function 'bar', 'autoload' has no way of knowing that you edited
+           'bar' and will NOT reload 'bar' for you.)
+
+           Reloads, of course, only apply in the context of the current session
+           and any future subshell you start from the current session. Existing
+           sessions will need to have the same 'autoload -r' command run in
+           them.
+
+        -m Find the scripts in which the specified functions are defined and
+           run \$PAGER on them ('m' is for 'more', because 'p' (page) and 'l'
+           (load) are already used as options in 'autoload').
+
+        -l When autoloading a function, eval the shim immediately in order to
+           load the true function code. See "Using '-l'" in the NOTES below for
+           details.
+
+        -o Optimize. When autoloading, take the time to execute
+
+               'theCharCount=\$(wc -c \$theFuncFile)'
+
+           for each function and
+
+                if \$theCharCount < \$AUTOLOAD_SHIM_OVERHEAD
+
+           don't shim it, just eval directly.
+
+        -y Summar(y). Print the number of loaded, exported and optimized
+           functions.
+
+        -v Turns up the chattiness.
+
+NOTES
+
+        o Calling 'autoload' on a function that already exists (either shimmed
+          or expanded) silently ignores the request to load the shim unless it
+          has been previously removed (-u) or you force the reload (-r).
+
+        o Changing and reloading a function that has been exported does not
+          require it be re-exported; the modifications will appear in
+          subsequent subshells.
+
+        o Using '-1'
+
+          If you are running under set -x and/or set -v, you may see that the
+          shim does not appear to "work"; instead of seeing the shim first and
+          the real code subsequently, you may see the shim evaluated multiple
+          times.
+
+          This may not be an error; review your code. What is most likely
+          happening is that you are calling the function in subshells via
+          backticks or $(), or in a script that is not being sourced into the
+          current environment. If you have not previously called the function
+          in question at your command line or in a script that was sourced into
+          the current environment, then the various subshells are going to
+          encounter the shim and replace with the real code before executing.
+
+          Remember, however, that environment modifications that occur in a
+          subshell are NOT propagated back to the calling shell or over to any
+          sibling shells. So, if you call an autoloaded function in a very
+          tight loop of very many subshells, you may want to make an 'autoload
+          -l' call before you start your loop. '-l' will instruct 'autoload' to
+          bypass the shim creation and just source in the function's file
+          directly. For a few calls, the overhead of repeatedly running the
+          shim is not expensive, but in a tight loop, it might be. Caveat
+          Programer.
+
+        o Although the number of functions in the environment does not change
+          by using 'autoload', the amount of memory they take up can be greatly
+          reduced, depending on the size of your functions. If you have a lot
+          of small functions, then it is possible that the shim text will be
+          larger than your actual functions, rendering the memory savings moot.
+
+          'small' in this case can be determined by calling the function
+          'autoload_calc_shimsize' with the name of the function to determine
+          its shim size.
+
+        o In order to support the -p and -s options, we need a way to determine
+          if a function 'func' has been autoloaded or if it was loaded
+          diredctly. In order to do that, we modify the function's code by
+          adding the text
+
+              local  AUTOLOADED='func';
+
+          to the shim and to the actual function text, just after the opening
+          brace. Then supporting -p and -s is just a matter of grepping through
+          all the function text in memory. Even though grepping through the
+          environment may not be the most efficient way to support this, it is
+          the simplest to implement for -p and -s operations that are not
+          heavily used.
+
+          As a consquence of this (and other reasons), the AUTOLOAD* namespace
+          is reserved for autoloading. Make sure you check any functions that
+          you bring under autoload for use of variables or functions that start
+          with AUTOLOAD and change them.
+
+        o The easiest way to load shims for all functions on the FPATH is to run
+
+               autoload -f -x
+
+          in the profile that gets run for login shells.
+
+          When called in the profile of a login shell where no definitions
+          exist, -f will load all functions it can find on FPATH and -x will
+          export all of those functions to be available in subshells when this
+          is called in a login shell. Using this option will relieve you of the
+          need to call 'autoload' after Every Single Function Definition, nor
+          will you need to call it in subshells.
+
+          The only thing left to do is to load up the autoload function itself
+          and its helper functions. That needs to happen in your profile:
+
+            export FPATH=~/functions       # or wherever you stash them
+            if [ -z $(declare -F autoload) ]
+            then
+              . ~/bin/autoload             # or wherever you've put it
+            fi
+
+          The 'if' statement is used to make sure we don't reload autoload
+          needlessly. Sourcing in the autoload script loads the 'autoload'
+          function and all of its support functions. Additionally, we export
+          all of these functions so that they are available in subshells; you
+          do not have to re-source the autoload file in '.bashrc'.
+
+        o Even with all of these shenanigans, you will find cases where no
+          matter how hard you try, your autoloaded functions will be
+          unavailable to you, even if you run 'autoload -x -f'. The typical
+          condition for this is starting up not a subshell, but a brand new
+          DIFFERENT shell. And the typical example of this is git extensions.
+
+          At the time of this writing, git extensions work by taking a command
+          'git foo' and looking for a file 'git-foo' on the path. 'git' then
+          executes 'git-foo' in a new shell - it executes your command in
+          /bin/sh. That's not a subshell of your process. It will not get your
+          exported shell functions. Ballgame over.
+
+          If you find that you want your functions to be available in such
+          circumstances, convert them back to plain old scripts, make sure they
+          are 'sh' compliant and take the read/parse hit every time they are
+          run.
+
+EOH
+}
+
+autoload()
+{
+    if (( $# == 0 )) ; then _autoload_dump; return; fi
+
+    local opt OPTIND OPTARG
+    local passthru
+    local dumpopt
+    while getopts psuema:yxrvlohf opt
+    do
+        case $opt in
+            p|s) dumpopt="$dumpopt -${opt}";;
+            u) shift $((OPTIND-1)); _autoload_remove "$@"; return;;
+            e) shift $((OPTIND-1)); _autoload_edit "$@"; return;;
+            m) shift $((OPTIND-1)); _autoload_page "$@"; return;;
+            x|r|v|l|y|f|o) passthru="$passthru -$opt";;
+            a) passthru="$passthru -$opt $OPTARG";;
+            h) _autoload_help; return;;
+            *) echo "autoload: usage: autoload [-puUx] [function ...]" >&2; return;;
+        esac
+    done
+
+    shift $(($OPTIND-1))
+    if [ -n "$dumpopt" ]
+    then
+        _autoload_dump $dumpopt
+    else
+        _aload $passthru "$@"
+    fi
+}
+
+autoreload ()
+{
+    autoload -r "$@"
+}
+
+## When we source in autoload, we export (but NOT autoload) the autoload
+## functions so that they are available in subshells and you don't have to
+## source in the autoload file in subshells.
+export -f _aload \
+       _autoload_dump \
+       _autoload_edit \
+       _autoload_help \
+       _autoload_page \
+       _autoload_resolve \
+       _autoload_split_fpath \
+       autoload \
+       autoload_calc_shimsize \
+       autoreload
diff --git a/examples/functions/autoload.v4.t b/examples/functions/autoload.v4.t
new file mode 100644
index 0000000..6d35d14
--- /dev/null
+++ b/examples/functions/autoload.v4.t
@@ -0,0 +1,184 @@
+#!/bin/bash
+
+workdir=$(mktemp -d)
+
+cp autoload $workdir
+
+cd $workdir
+pwd
+
+. ./autoload
+
+funclist='ALTEST_func1 ALTEST_funcexport ALTEST_funcu'
+for funcname in $funclist; do
+    cat <<EOFFUNC > $funcname
+$funcname ()
+{
+echo this is $funcname
+
+}
+EOFFUNC
+
+done
+
+export FPATH=$workdir
+
+autoload ALTEST_func1 ALTEST_funcu
+autoload -x ALTEST_funcexport
+
+ok=0
+failed=0
+
+for funcname in $funclist; do
+
+    testname="$funcname loaded"
+    got=$(type $funcname 2>&1)
+    if [[ $got =~ "$funcname: not found" ]]; then
+        echo "## Failed $testname"
+        ((failed+=1))
+    else
+        echo "ok - $testname"
+        ((ok+=1))
+
+        testname="$funcname is a shim"
+        if [[ ! $got =~ "IS_SHIM" ]]; then
+            echo "## Failed $testname"
+            ((failed+=1))
+        else
+            echo "ok - $testname"
+            ((ok+=1))
+
+            testname="$funcname shim executed"
+            $funcname > /dev/null
+            got=$(type $funcname 2>&1)
+            if [[ $got =~ "IS_SHIM" ]]; then
+                echo "## Failed $testname"
+                ((failed+=1))
+            else
+                echo "ok - $testname"
+                ((ok+=1))
+            fi
+        fi
+    fi
+done
+
+funcname=ALTEST_func1
+testname="$funcname shim reloaded"
+autoload -r $funcname
+got=$(type $funcname 2>&1)
+if [[ ! $got =~ "IS_SHIM" ]]; then
+    echo "## Failed $testname"
+    ((failed+=1))
+else
+    echo "ok - $testname"
+    ((ok+=1))
+fi
+
+funcname=ALTEST_funcu
+testname="$funcname shim unloaded"
+autoload -u $funcname
+got=$(type $funcname 2>&1)
+if [[ ! $got =~ "$funcname: not found" ]]; then
+    echo "## Failed $testname"
+    ((failed+=1))
+else
+    echo "ok - $testname"
+    ((ok+=1))
+fi
+
+testname="autoload -p"
+got=$(autoload -p | grep ALTEST)
+if [[ ! $got =~ "autoload ALTEST_func1" ]] || \
+       [[ ! $got =~ "autoload ALTEST_funcexport" ]] ; then
+echo "## Failed $testname"
+    ((failed+=1))
+else
+    echo "ok - $testname"
+    ((ok+=1))
+fi
+
+testname="autoload -s"
+echo "Executing $testname, could take a long time..."
+got=$(autoload -s | grep ALTEST)
+if [[ ! $got =~ "ALTEST_func1 not exported not executed" ]] || \
+       [[ ! $got =~ "ALTEST_funcexport exported executed" ]] ; then
+    echo "## Failed $testname"
+    echo "##    got: $got"
+    ((failed+=1))
+else
+    echo "ok - $testname"
+    ((ok+=1))
+fi
+
+testname="autoload -r -a $FPATH"
+autoload -r -a $FPATH
+localfailed=0
+localok=0
+for funcname in $funclist; do
+    got=$(type $funcname 2>&1)
+    if [[ $got =~ "$funcname: not found" ]]; then
+        echo "## Failed $testname - $funcname"
+        ((localfailed+=1))
+    else
+        ((localok+=1))
+        if [[ ! $got =~ "IS_SHIM" ]]; then
+            ((localfailed+=1))
+        else
+            ((localok+=1))
+        fi
+    fi
+done
+if ((localfailed==0)); then
+    echo "ok - $testname"
+    ((ok+=1))
+else
+    ((failed+=1))
+fi
+
+testname="autoload -u $funclist"
+autoload -u $funclist
+localfailed=0
+localok=0
+for funcname in $funclist; do
+    got=$(type $funcname 2>&1)
+    if [[ ! $got =~ "$funcname: not found" ]]; then
+        echo "## Failed $testname - $funcname"
+        ((localfailed+=1))
+    else
+        ((localok+=1))
+    fi
+done
+if ((localfailed==0)); then
+    echo "ok - $testname"
+    ((ok+=1))
+else
+    ((failed+=1))
+fi
+
+testname="autoload -r -f"
+autoload -r -f
+localfailed=0
+localok=0
+for funcname in $funclist; do
+    got=$(type $funcname 2>&1)
+    if [[ $got =~ "$funcname: not found" ]]; then
+        echo "## Failed $testname - $funcname"
+        ((localfailed+=1))
+    else
+        ((localok+=1))
+        if [[ ! $got =~ "IS_SHIM" ]]; then
+            ((localfailed+=1))
+        else
+            ((localok+=1))
+        fi
+    fi
+done
+if ((localfailed==0)); then
+    echo "ok - $testname"
+    ((ok+=1))
+else
+    ((failed+=1))
+fi
+
+echo $ok passed, $failed failed
+exit $failed
diff --git a/examples/functions/basename b/examples/functions/basename
new file mode 100644
index 0000000..a541349
--- /dev/null
+++ b/examples/functions/basename
@@ -0,0 +1,23 @@
+# Date: Fri, 11 Oct 91 11:22:36 edt
+# From: friedman@gnu.ai.mit.edu
+# To: bfox@gnu.ai.mit.edu
+
+# A replacement for basename(1).  Not all the systems I use have this
+# program.  Usage: basename [path] {extension}
+function basename ()
+{
+ local path="$1"
+ local suffix="$2"
+ local tpath="${path%/}"
+
+    # Strip trailing '/' characters from path (unusual that this should
+    # ever occur, but basename(1) seems to deal with it.)
+    while [ "${tpath}" != "${path}" ]; do
+       tpath="${path}"
+       path="${tpath%/}"
+    done
+
+    path="${path##*/}"       # Strip off pathname
+    echo ${path%${suffix}}   # Also strip off extension, if any.
+}
+
diff --git a/examples/functions/csh-compat b/examples/functions/csh-compat
new file mode 100644
index 0000000..54c8488
--- /dev/null
+++ b/examples/functions/csh-compat
@@ -0,0 +1,48 @@
+# C-shell compatibilty package.
+# setenv VAR VALUE
+function setenv ()
+{
+  export $1="$2"
+}
+
+function unsetenv ()
+{
+  unset $1
+}
+
+# Can't write foreach yet.  Need pattern matching, and a few extras.
+function foreach () {
+echo 'Can'\''t do `foreach'\'' yet.  Type "help for".'
+}
+
+# Make this work like csh's.  Special case "term" and "path".
+#set () {
+#}
+
+chdir ()
+{
+  builtin cd "$@"
+}
+
+# alias - convert csh alias commands to bash functions
+# from Mohit Aron <aron@cs.rice.edu>
+# posted to usenet as <4i5p17$bnu@larry.rice.edu>
+function alias ()
+{
+	if [ "x$2" = "x" ] 
+	then
+		declare -f $1
+	else
+		case $2 in
+		*[#\!]*)
+			comm=$(echo $2 | sed  's/\\!\*/\"$\@\"/g
+					       s/\\!:\([1-9]\)/\"$\1\"/g
+				               s/#/\\#/g')
+			;;
+		*)
+			comm="$2 \"\$@\"" ;;
+		esac
+
+		eval function $1 \(\) "{" command "$comm"  "; }"
+	fi
+}
diff --git a/examples/functions/dirname b/examples/functions/dirname
new file mode 100644
index 0000000..ccb8c84
--- /dev/null
+++ b/examples/functions/dirname
@@ -0,0 +1,21 @@
+# Date: Fri, 11 Oct 91 11:22:36 edt
+# From: friedman@gnu.ai.mit.edu
+# To: bfox@gnu.ai.mit.edu
+
+# A replacement for dirname(1).  This one appears less often on some
+# systems I use than basename(1), and I really depend on it for some
+# things.  Usage: dirname [path]
+function dirname ()
+{
+ local dir="$1"
+ local tdir="${dir%/}"
+
+    # Strip trailing '/' characters from dir (unusual that this should
+    # ever occur, but dirname(1) seems to deal with it.)
+    while [ "${tdir}" != "${dir}" ]; do
+       tdir="${dir}"
+       dir="${tdir%/}"
+    done
+
+    echo "${dir%/*}"
+}
diff --git a/examples/functions/dirstack b/examples/functions/dirstack
new file mode 100644
index 0000000..d68e619
--- /dev/null
+++ b/examples/functions/dirstack
@@ -0,0 +1,160 @@
+#!/bin/bash 
+#	@(#)	dirstack
+
+###
+# Another implementation of the directory manipulation functions
+# published in the Bolsky & Korn book : "The new Korn shell" :
+# 	cd, to change current directory
+#	d,  to display the stack content
+# Eric Sanchis (eric.sanchis@iut-rodez.fr), 2012
+#
+#   This program is free software: you can redistribute it and/or modify
+#   it under the terms of the GNU General Public License as published by
+#   the Free Software Foundation, either version 3 of the License, or
+#   (at your option) any later version.
+#
+#   This program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+###
+
+
+shopt -s expand_aliases
+shopt -s extglob
+shopt -s cdable_vars
+
+alias integer='declare -i'
+
+integer	MAX=32
+integer INDMAX=MAX-1
+integer	INDTOP=0
+
+unalias cd 2>/dev/null
+alias cd=cdir
+
+unset tab
+tab[INDTOP]="$(pwd)"
+
+
+function cdir      
+{
+	local -i ind 
+	local    dir
+
+dir="${1:-$HOME}"
+case "$dir" in
+ - )			# cd -  => equivalent to : cd -1
+		ind=INDTOP-1
+ 		cd_by_number  $ind
+		  ;;
+ -+([[:digit:]]) )	# cd -n
+		ind=$INDTOP-${dir#-}
+		cd_by_number  $ind 
+		  ;;
+ *)			# cd ~   or    cd dir_name
+		cd_by_name  "$dir"
+esac
+}
+
+
+function  cd_by_number
+{
+	local -i  k=$1
+	local -i  j 
+	local     dirtmp
+
+if (( k < 0 ))
+ then 		
+   echo Impossible to change directory >&2
+   return 1
+ else
+   dirtmp="${tab[k]}"
+   j=k+1 
+   while (( j <= INDTOP ))
+    do
+      tab[j-1]="${tab[j]}"
+      j=j+1
+    done
+   tab[INDTOP]="$dirtmp"
+   \cd "${tab[INDTOP]}"
+fi
+}
+
+
+function cd_by_name
+{
+ 	local -i  i
+	local     rep
+
+rep=$( \cd "$1" &>/dev/null && pwd)
+if [[ -z "$rep" ]]
+  then 
+    echo cd : "$1" unknown >&2
+    return 1
+fi
+
+	i=$INDTOP 
+	while (( i >= 0 ))
+  	 do
+	   if [[ "${tab[i]}" == "$rep" ]]
+	     then  break
+	   fi
+	   i=i-1
+	 done
+
+if (( i == INDTOP ))
+  then	#  cd -0	=> we do nothing !
+     return 0	
+  elif (( i == -1 ))
+     then	# the directory isn't in the stack
+       if (( INDTOP == INDMAX ))
+         then 	# the stack is FULL
+		# the oldest directory is removed
+            local -i  m
+       
+          m=1
+	  while (( m <= INDMAX ))
+	   do
+	     tab[m-1]="${tab[m]}"
+	     m=m+1
+           done
+        else 	# the new directory is added to the top of the stack
+	  INDTOP=INDTOP+1
+      fi
+      tab[INDTOP]="$rep"
+      \cd "${tab[INDTOP]}"
+      return 0
+  
+     else # the directory is already in the stack 
+	# $i gives its index
+       cd_by_number $i
+fi
+}
+
+
+function d	# display the directory stack
+{
+	local -i  i 
+	local     rep
+
+i=0
+while (( $i <= $INDTOP ))
+ do
+   rep="${tab[INDTOP-i]#$HOME/}"
+   case "$rep" in
+    $HOME)  rep="~" ;;
+    /*   )   :  ;;
+    *    )  rep="~/$rep"
+   esac
+   
+   echo "$i )		$rep"
+   i=i+1
+ done
+}
+
+
diff --git a/examples/functions/exitstat b/examples/functions/exitstat
new file mode 100644
index 0000000..f49ebf5
--- /dev/null
+++ b/examples/functions/exitstat
@@ -0,0 +1,22 @@
+# Contributed by Noah Friedman and Roland McGrath.
+
+# To be run by the PROMPT_COMMAND variable, so that one can see what
+# the exit status of processes are.
+
+function check_exit_status ()
+{
+ local status="$?"
+ local signal=""
+
+    if [ ${status} -ne 0 ] && [ ${status} != 128 ]; then
+       # If process exited by a signal, determine name of signal.
+       if [ ${status} -gt 128 ]; then
+          signal="$(builtin kill -l $((${status} - 128)) 2>/dev/null)"
+	  if [ "$signal" ]; then signal="($signal)"; fi
+       fi
+       echo "[Exit ${status} ${signal}]" 1>&2
+    fi
+    return 0
+}
+
+PROMPT_COMMAND=check_exit_status
diff --git a/examples/functions/external b/examples/functions/external
new file mode 100644
index 0000000..c2e52cd
--- /dev/null
+++ b/examples/functions/external
@@ -0,0 +1,50 @@
+# Contributed by Noah Friedman.
+
+# To avoid using a function in bash, you can use the `builtin' or
+# `command' builtins, but neither guarantees that you use an external
+# program instead of a bash builtin if there's a builtin by that name.  So
+# this function can be used like `command' except that it guarantees the
+# program is external by first disabling any builtin by that name.  After
+# the command is done executing, the state of the builtin is restored. 
+function external ()
+{
+ local state=""
+ local exit_status
+  
+    if builtin_p "$1"; then
+       state="builtin"
+       enable -n "$1"
+    fi
+
+    command "$@"
+    exit_status=$?
+
+    if [ "$state" = "builtin" ]; then
+       enable "$1"
+    fi
+
+    return ${exit_status}
+}
+
+# What is does is tell you if a particular keyword is currently enabled as
+# a shell builtin.  It does NOT tell you if invoking that keyword will
+# necessarily run the builtin.  For that, do something like
+#
+#       test "$(builtin type -type [keyword])" = "builtin"
+#
+# Note also, that disabling a builtin with "enable -n" will make builtin_p
+# return false, since the builtin is no longer available.
+function builtin_p ()
+{
+ local word
+
+    set $(builtin type -all -type "$1")
+
+    for word in "$@" ; do
+       if [ "${word}" = "builtin" ]; then
+          return 0
+       fi
+    done
+
+    return 1
+}
diff --git a/examples/functions/fact b/examples/functions/fact
new file mode 100644
index 0000000..97efd49
--- /dev/null
+++ b/examples/functions/fact
@@ -0,0 +1,13 @@
+# Who said shells can't use recursion?  Here is a factorial function.
+# You call it with a number as an argument, and it returns the factorial
+# of that number.
+
+fact ()
+{
+    local num=$1;
+    if [ "$num" = 1 ] ; then
+        echo 1
+        return ;
+    fi;
+    echo $(( $num * $(fact $(( $num - 1 )) ) ))
+}
diff --git a/examples/functions/fstty b/examples/functions/fstty
new file mode 100644
index 0000000..5ed594f
--- /dev/null
+++ b/examples/functions/fstty
@@ -0,0 +1,77 @@
+#
+# A function that works as a front end for both stty and the `bind'
+# builtin, so the tty driver and readline see the same changes
+#
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 2011 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#
+# Convert between the stty ^H control character form and the readline \C-H
+# form
+#
+cvt()
+{
+	echo "$@" | cat -v | sed 's/\^/\\C-/'
+}
+
+#
+# stty front-end.  Parses the argument list and creates two command strings,
+# one for stty, another for bind.
+#
+fstty()
+{
+	local	cmd="" bargs=""
+	local	e
+
+	while [ $# -gt 0 ]
+	do
+		case "$1" in
+		-a)	cmd="$cmd everything"
+			;;
+		erase)	shift;
+			e=$(cvt "$1")
+			cmd="$cmd erase $1"
+			bargs="$bargs '\"$e\": backward-delete-char'"
+			;;
+		kill)	shift
+			e=$(cvt "$1")
+			cmd="$cmd kill $1"
+			bargs="$bargs '\"$e\": unix-line-discard'"
+			;;
+		werase)	shift;
+			e=$(cvt "$1")
+			cmd="$cmd erase $1"
+			bargs="$bargs '\"$e\": backward-kill-word'"
+			;;
+		lnext)	shift;
+			e=$(cvt "$1")
+			cmd="$cmd erase $1"
+			bargs="$bargs '\"$e\": quoted-insert'"
+			;;
+		*)	cmd="$cmd $1"
+			;;
+		esac
+		shift
+	done
+
+	command stty $cmd
+	if [ -n "$bargs" ]; then
+		builtin bind $bargs
+	fi
+}
diff --git a/examples/functions/func b/examples/functions/func
new file mode 100644
index 0000000..e7696f7
--- /dev/null
+++ b/examples/functions/func
@@ -0,0 +1,43 @@
+#
+# func -- print out definitions for functions named by arguments
+#
+# usage: func name [name ...]
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1991 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+func()
+{
+	local status=0
+
+	if [ $# -eq 0 ] ; then
+		echo "usage: func name [name...]" 1>&2
+		return 1
+	fi
+
+	for f
+	do
+		if [ "$(builtin type -type $f)" != "function" ] ; then
+			echo "func: $f: not a function" 1>&2
+			status=1	# one failed
+			continue
+		fi
+		builtin type $f | sed 1d
+	done
+	return $status
+}
diff --git a/examples/functions/inetaddr b/examples/functions/inetaddr
new file mode 100644
index 0000000..9e72613
--- /dev/null
+++ b/examples/functions/inetaddr
@@ -0,0 +1,79 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 2002 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#
+# inet2hex - Internet address conversion, dotted-decimal to hex
+#
+inet2hex ()
+{
+	local IFS
+
+	IFS=.
+	set -- $1
+
+	if (( $# != 4 )); then
+		echo "inet2hex: incorrect input format: $1" >&2
+		echo "inet2hex: usage: inet2hex XX.XX.XX.XX" >&2
+		return 2
+	fi
+  
+	printf "0x%02x%02x%02x%02x\n" $1 $2 $3 $4
+}
+
+#
+# hex2inet - Internet address conversion, hex to dotted-decimal
+#
+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 [-r] [0x]XXXXXXXX" >&2 ; exit 2;;
+		esac
+	done
+	shift $(( $OPTIND - 1 ))
+
+	case "$1" in
+	0x*)	h=${1#??} ;;
+	*)	h=$1 ;;
+	esac
+
+	if (( ${#h} != 8 )); then
+		echo "hex2inet: $h not in inet format" >&2
+		echo "hex2inet: usage: hex2inet [0x]XXXXXXXX" >&2
+		return 2
+	fi
+
+	x1=$(( 0x${h:0:2} ))
+	x2=$(( 0x${h:2:2} ))
+	x3=$(( 0x${h:4:2} ))
+	x4=$(( 0x${h:6:2} ))
+
+	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/inpath b/examples/functions/inpath
new file mode 100644
index 0000000..cb4c93d
--- /dev/null
+++ b/examples/functions/inpath
@@ -0,0 +1,14 @@
+inpath()
+{
+	local PROG
+	path=$(echo $PATH | sed 's/^:/.:/
+				s/::/:.:/g
+				s/:$/:./
+				s/:/ /g')
+
+	for x in $path
+	do
+		[ -x $x/$1 ] && { PROG=$x/$1; break; }
+	done
+	[ -n "$PROG" ]
+}
diff --git a/examples/functions/isnum2 b/examples/functions/isnum2
new file mode 100644
index 0000000..b21974d
--- /dev/null
+++ b/examples/functions/isnum2
@@ -0,0 +1,41 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1998 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+isnum2()
+{
+	case "$1" in
+	[-+] | '')	return 1;;	# empty or bare `-' or `+'
+	[-+]*[!0-9]*)	return 1;;	# non-digit with leading sign
+	[-+]*)		return 0;;	# OK
+	*[!0-9]*)	return 1;;	# non-digit
+	*)		return 0;;	# OK
+	esac
+}
+
+# this one handles floating point
+isnum3()
+{
+	case "$1" in
+	'')		return 1;;	# empty
+	*[!0-9.+-]*)	return 1;;	# non-digit, +, -, or .
+	*?[-+]*)	return 1;;	# sign as second or later char
+	*.*.*)		return 1;;	# multiple decimal points
+	*)		return 0;;	# OK
+	esac
+}
diff --git a/examples/functions/isvalidip b/examples/functions/isvalidip
new file mode 100644
index 0000000..0b2dafe
--- /dev/null
+++ b/examples/functions/isvalidip
@@ -0,0 +1,14 @@
+# Thanks to Chris F. A. Johnson <c.f.a.johnson@rogers.com> for this one
+is_validip()
+{
+	case "$*" in
+	""|*[!0-9.]*|*[!0-9]) return 1 ;;
+	esac
+
+	local IFS=.
+	set -- $*
+
+        [ $# -eq 4 ] &&
+	    [ ${1:-666} -le 255 ] && [ ${2:-666} -le 255 ] &&
+	    [ ${3:-666} -le 255 ] && [ ${4:-666} -le 254 ]
+}
diff --git a/examples/functions/ksh-cd b/examples/functions/ksh-cd
new file mode 100644
index 0000000..26b00a9
--- /dev/null
+++ b/examples/functions/ksh-cd
@@ -0,0 +1,54 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 2001 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#
+# ksh-like `cd': cd [-LP] [dir [change]]
+#
+cd()
+{
+	OPTIND=1
+	while getopts "LP" opt
+	do
+		case $opt in
+		L|P)	CDOPTS="$CDOPTS -$opt" ;;
+		*)	echo "$FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+			return 2;;
+		esac
+	done
+
+	shift $(( $OPTIND - 1 ))
+
+	case $# in
+	0)	builtin cd $CDOPTS "$HOME" ;;
+	1) 	builtin cd $CDOPTS "$@" ;;
+	2)	old="$1" new="$2"
+		case "$PWD" in
+		*$old*)	;;
+		*)	 echo "${0##*/}: $FUNCNAME: bad substitution" >&2 ; return 1 ;;
+		esac
+
+		dir=${PWD//$old/$new}
+
+		builtin cd $CDOPTS "$dir" && echo "$PWD"
+
+		;;
+	*)	echo "${0##*/}: $FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+		return 2 ;;
+	esac
+}
diff --git a/examples/functions/ksh-compat-test b/examples/functions/ksh-compat-test
new file mode 100644
index 0000000..919d82b
--- /dev/null
+++ b/examples/functions/ksh-compat-test
@@ -0,0 +1,58 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1999 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# replacements for test/[ that do arithmetic expansion on the operands to
+# the arithmetic operators, like ksh.
+#
+function test()
+{
+        local -i n1 n3
+        case "$#" in
+        3)      case "$2" in
+                -lt|-gt|-eq|-ne|-le|-ge)        n1=$(( $1 ))
+                                                n3=$(( $3 ))
+                                                builtin test "$n1" $2 "$n3"
+                                                return $?;;
+                *)      builtin test "$@" ;;
+                esac;;                                                          
+        *)      builtin test "$@" ;;
+        esac
+}
+
+function [()
+{
+        local -i n1 n3
+        case "$#" in
+        4)      case "$2" in
+                -lt|-gt|-eq|-ne|-le|-ge)        n1=$(( $1 ))
+                                                n3=$(( $3 ))
+                                                builtin [ "$n1" $2 "$n3" ]
+                                                return $?;;
+                *)      builtin [ "$@" ;;
+                esac;;                                                          
+        *)      builtin [ "$@" ;;
+        esac
+}
+
+q=7
+
+[ q -lt 10 ]
+echo $?
+[ $q -lt 10 ]
+echo $?
diff --git a/examples/functions/kshenv b/examples/functions/kshenv
new file mode 100644
index 0000000..9faba08
--- /dev/null
+++ b/examples/functions/kshenv
@@ -0,0 +1,246 @@
+#
+# .kshenv -- functions and aliases to provide the beginnings of a ksh 
+#	     environment for bash.
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+#
+
+#
+#  Copyright 2002 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+#
+# These are definitions for the ksh compiled-in `exported aliases'.  There
+# are others, but we already have substitutes for them: "history", "type",
+# and "hash".
+#
+alias r="fc -s"
+alias functions="typeset -f"
+alias integer="typeset -i"
+alias nohup="nohup "
+alias command="command "
+alias stop="kill -s STOP"
+alias redirect="command exec"
+alias hist="fc"
+
+#
+# An almost-ksh compatible `whence' command.  This is as hairy as it is 
+# because of the desire to exactly mimic ksh (whose behavior was determined
+# empirically).
+# 
+# This depends somewhat on knowing the format of the output of the bash
+# `builtin type' command.
+#
+
+whence()
+{
+	local vflag pflag fflag defarg c
+	local path
+
+	vflag= aflag= pflag= fflag=
+	path=
+	if [ "$#" = "0" ] ; then
+		echo "whence: usage: whence [-afpv] name..." >&2
+		return 2
+	fi
+
+	OPTIND=1
+	while getopts "avfp" c
+	do
+		case "$c" in
+		a) defarg=-a ;;
+		f) fflag=1 ;;	# no-op
+		p) pflag=1 ;;
+		v) vflag=1 ;;
+		?) echo "whence: $1: unknown option" >&2
+		   echo "whence: usage: whence [-afpv] name..." >&2
+		   return 2 ;;
+		esac
+	done
+
+	shift $(( $OPTIND - 1 ))
+
+	if [ "$#" = "0" ] ; then
+		echo "whence: usage: whence [-afpv] name..." >&2
+		return 2
+	fi
+
+	for cmd
+	do
+		if [ "$vflag" ]	 ; then
+			if [ -z "$defarg" ]; then
+				builtin type $cmd | sed 1q
+			else
+				if builtin type $defarg -t $cmd | grep 'function$' >/dev/null 2>&1; then
+					# HAIRY awk script to suppress
+					# printing of function body -- could
+					# do it with sed, but I don't have
+					# that kind of time
+					builtin type $defarg $cmd | awk '
+BEGIN {printit = 1;}
+$1 == "'$cmd'" && $2 == "()" {printit=0; next; }
+/^}$/ { if (printit == 0) printit=1 ; else print $0; next ; }
+/.*/ { if (printit) print $0; }'
+				else
+					builtin type $defarg $cmd
+				fi
+			fi
+		else
+			path=$(builtin type $defarg -p $cmd)
+			if [ "$path" ] ; then
+				echo $path
+			else
+				case "$cmd" in
+				/*) echo "" ;;
+				 *) case "$(builtin type -t $cmd)" in
+				    "") echo "" ;;
+				    *) echo "$cmd" ;;
+				    esac
+				    ;;
+				esac
+			fi
+		fi
+	done
+	return 0
+}
+
+#
+# For real ksh homeboy fanatics, redefine the `type' builtin with a ksh
+# version.
+#
+#type()
+#{
+#	whence -v "$*"
+#}
+
+#
+# ksh-like `cd': cd [-LP] [dir [change]]
+#
+cd()
+{
+	OPTIND=1
+	while getopts "LP" opt
+	do
+		case $opt in
+		L|P)	CDOPTS="$CDOPTS -$opt" ;;
+		*)	echo "$FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+			return 2;;
+		esac
+	done
+
+	shift $(( $OPTIND - 1 ))
+
+	case $# in
+	0)	builtin cd $CDOPTS "$HOME" ;;
+	1) 	builtin cd $CDOPTS "$@" ;;
+	2)	old="$1" new="$2"
+		case "$PWD" in
+		*$old*)	;;
+		*)	 echo "${0##*/}: $FUNCNAME: bad substitution" >&2 ; return 1 ;;
+		esac
+
+		dir=${PWD//$old/$new}
+
+		builtin cd $CDOPTS "$dir" && echo "$PWD"
+
+		;;
+	*)	echo "${0##*/}: $FUNCNAME: usage: $FUNCNAME [-LP] [dir] [change]" >&2
+		return 2 ;;
+	esac
+}
+
+#
+# ksh print emulation
+#
+#	print [-Rnprsu[n]] [-f format] [arg ...]
+#
+#	-	end of options
+#	-R	BSD-style -- only accept -n, no escapes
+#	-n	do not add trailing newline
+#	-p	no-op (no coprocesses)
+#	-r	no escapes
+#	-s	print to the history file
+#	-u n	redirect output to fd n
+#	-f format	printf "$format" "$@"
+#
+
+print()
+{
+	local eflag=-e
+	local nflag= fflag= c
+	local fd=1
+
+	OPTIND=1
+	while getopts "fRnprsu:" c
+	do
+		case $c in
+		R)	eflag= ;;
+		r)	eflag= ;;
+		n)	nflag=-n ;;
+		s)	sflag=y ;;
+		f)	fflag=y ;;
+		u)	fd=$OPTARG ;;
+		p)	;;
+		esac
+	done
+	shift $(( $OPTIND - 1 ))
+
+	if [ -n "$fflag" ]; then
+		builtin printf "$@" >&$fd
+		return
+	fi
+
+	case "$sflag" in
+	y)	builtin history -s "$*" ;;
+	*)	builtin echo $eflag $nflag "$@" >&$fd
+	esac
+}
+
+# substring function
+# this function should be equivalent to the substring built-in which was
+# eliminated after the 06/29/84 version
+substring ()
+{
+	local lpat flag str	#local variables
+	set -f
+	case $1 in
+	-l|-L)
+		flag=$1
+		lpat=$2
+		shift 2
+		;;
+	esac
+	# test for too few or too many arguments
+	if [ x"$1" = x ] || [ $# -gt 2 ]; then
+		print -u2 'substring: bad argument count'
+		return 1
+	fi
+	str=$1
+	if [ x"$flag" = x-l ]; then		#substring -l lpat
+		str=${str#$lpat}
+	elif [ x"$flag" = x-L ]; then
+		str=${str##$lpat}		#substring -L lpat
+	fi
+
+	if [ x"$2" != x ]; then
+		echo ${str%$2}
+	else
+		echo $str
+	fi
+
+	return 0
+}
diff --git a/examples/functions/login b/examples/functions/login
new file mode 100644
index 0000000..3d59683
--- /dev/null
+++ b/examples/functions/login
@@ -0,0 +1,11 @@
+# replace the `login' and `newgrp' builtins in old bourne shells
+
+login()
+{
+	exec login "$@"
+}
+
+newgrp()
+{
+	exec newgrp "$@"
+}
diff --git a/examples/functions/notify.bash b/examples/functions/notify.bash
new file mode 100644
index 0000000..ed4377c
--- /dev/null
+++ b/examples/functions/notify.bash
@@ -0,0 +1,77 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1992 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+trap _notify CHLD
+NOTIFY_ALL=false
+unset NOTIFY_LIST
+unalias false
+
+false()
+{
+	return 1
+}
+
+_notify ()
+{
+	local i j
+	local newlist=
+
+	if $NOTIFY_ALL
+	then
+		return		# let bash take care of this itself
+	elif [ -z "$NOTIFY_LIST" ]; then
+		return
+	else
+		set -- $NOTIFY_LIST
+		for i in "$@"
+		do
+			j=$(jobs -n %$i)
+			if [ -n "$j" ]; then
+				echo "$j"
+				jobs -n %$i >/dev/null
+			else
+				newlist="newlist $i"
+			fi
+		done
+		NOTIFY_LIST="$newlist"
+	fi
+}
+
+notify ()
+{
+	local i j
+
+	if [ $# -eq 0 ]; then
+		NOTIFY_ALL=:
+		set -b
+		return
+	else
+		for i in "$@"
+		do
+			# turn a valid job spec into a job number
+			j=$(jobs $i)
+			case "$j" in
+			[*)	j=${j%%]*}
+				j=${j#[}
+				NOTIFY_LIST="$NOTIFY_LIST $j"
+				;;
+			esac
+		done
+	fi
+}
diff --git a/examples/functions/seq b/examples/functions/seq
new file mode 100644
index 0000000..c1953ee
--- /dev/null
+++ b/examples/functions/seq
@@ -0,0 +1,48 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1995 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Generate a sequence from m to n, m defaults to 1.
+
+seq ()
+{
+	declare -i lo hi i	# makes local
+	local _SEQ
+
+	case $# in
+	1) seq 1 "$1" ; return $? ;;
+	2) lo=$1 hi=$2
+	   i=$lo _SEQ=""
+	   while let "i <= hi"; do
+		_SEQ="${_SEQ}$i "
+		let i+=1
+	   done
+	   echo "${_SEQ# }"
+	   return 0 ;;
+	*) echo seq: usage: seq [low] high 1>&2 ; return 2 ;;
+	esac
+}
+
+# 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/seq2 b/examples/functions/seq2
new file mode 100644
index 0000000..4a54498
--- /dev/null
+++ b/examples/functions/seq2
@@ -0,0 +1,56 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1998 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# 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/shcat b/examples/functions/shcat
new file mode 100644
index 0000000..84f0391
--- /dev/null
+++ b/examples/functions/shcat
@@ -0,0 +1,7 @@
+shcat()
+{
+	while IFS= read -r line
+	do
+		echo "$line"
+	done
+}
diff --git a/examples/functions/shcat2 b/examples/functions/shcat2
new file mode 100644
index 0000000..8ceff33
--- /dev/null
+++ b/examples/functions/shcat2
@@ -0,0 +1,19 @@
+shcat()
+{
+	while read -r
+	do
+		echo "$REPLY"
+	done
+}
+
+shcat2()
+{
+	while [ $# -ge 1 ]; do
+		case "$1" in
+		-)	shcat ;;
+		*)	shcat < "$1" ;;
+		esac
+		shift
+	done
+	exit 0
+}
diff --git a/examples/functions/sort-pos-params b/examples/functions/sort-pos-params
new file mode 100644
index 0000000..95acd85
--- /dev/null
+++ b/examples/functions/sort-pos-params
@@ -0,0 +1,69 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 2001 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+# Sort the positional parameters.
+# Make sure the positional parameters are passed as arguments to the function.
+# If -u is the first arg, remove duplicate array members.
+sort_posparams()
+{
+	local -a R
+	local u
+
+	case "$1" in
+	-u)	u=-u ; shift ;;
+	esac
+
+	# if you want the case of no positional parameters to return success,
+	# remove the error message and return 0
+	if [ $# -eq 0 ]; then
+		echo "$FUNCNAME: argument expected" >&2
+		return 1
+	fi
+
+	# make R a copy of the positional parameters
+	R=( "${@}" )
+
+	# sort R.
+	R=( $( printf "%s\n" "${R[@]}" | sort $u) )
+
+	printf "%s\n" "${R[@]}"
+	return 0
+}
+
+# will print everything on separate lines
+set -- 3 1 4 1 5 9 2 6 5 3 2
+sort_posparams "$@"
+
+# sets without preserving quoted parameters
+set -- $( sort_posparams "$@" )
+echo "$@"
+echo $#
+
+# sets preserving quoted parameters, beware pos params with embedded newlines
+set -- 'a b' 'a c' 'x z'
+
+oifs=$IFS
+IFS=$'\n'
+set -- $( sort_posparams "$@" )
+IFS="$oifs"
+
+echo "$@"
+echo $#
+
+sort_posparams
diff --git a/examples/functions/substr b/examples/functions/substr
new file mode 100644
index 0000000..f19f5d7
--- /dev/null
+++ b/examples/functions/substr
@@ -0,0 +1,97 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 2002 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# substr -- a function to emulate the ancient ksh builtin
+#
+
+#
+# -l == shortest from left
+# -L == longest from left
+# -r == shortest from right (the default)
+# -R == longest from right
+
+substr()
+{
+	local flag pat str
+	local usage="usage: substr -lLrR pat string or substr string pat"
+
+	case "$1" in
+	-l | -L | -r | -R)
+		flag="$1"
+		pat="$2"
+		shift 2
+		;;
+	-*)
+		echo "substr: unknown option: $1"
+		echo "$usage"
+		return 1
+		;;
+	*)
+		flag="-r"
+		pat="$2"
+		;;
+	esac
+
+	if [ "$#" -eq 0 ] || [ "$#" -gt 2 ] ; then
+		echo "substr: bad argument count"
+		return 2
+	fi
+
+	str="$1"
+
+	#
+	# We don't want -f, but we don't want to turn it back on if
+	# we didn't have it already
+	#
+	case "$-" in
+	"*f*")
+		;;
+	*)
+		fng=1
+		set -f
+		;;
+	esac
+
+	case "$flag" in
+	-l)
+		str="${str#$pat}"		# substr -l pat string
+		;;
+	-L)
+		str="${str##$pat}"		# substr -L pat string
+		;;
+	-r)
+		str="${str%$pat}"		# substr -r pat string
+		;;
+	-R)
+		str="${str%%$pat}"		# substr -R pat string
+		;;
+	*)
+		str="${str%$2}"			# substr string pat
+		;;
+	esac
+
+	echo "$str"
+
+	#
+	# If we had file name generation when we started, re-enable it
+	#
+	if [ "$fng" = "1" ] ; then
+		set +f
+	fi
+}
diff --git a/examples/functions/substr2 b/examples/functions/substr2
new file mode 100644
index 0000000..fc21b98
--- /dev/null
+++ b/examples/functions/substr2
@@ -0,0 +1,99 @@
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 2002 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# substr -- a function to emulate the ancient ksh builtin
+#
+
+# -l == remove shortest from left
+# -L == remove longest from left
+# -r == remove shortest from right (the default)
+# -R == remove longest from right
+
+substr()
+{
+	local flag pat str
+	local usage="usage: substr -lLrR pat string or substr string pat"
+	local options="l:L:r:R:"
+
+	OPTIND=1
+	while getopts "$options" c
+	do
+		case "$c" in
+		l | L | r | R)
+			flag="-$c"
+			pat="$OPTARG"
+			;;
+		'?')
+			echo "$usage"
+			return 1
+			;;
+		esac
+	done
+
+	if [ "$OPTIND" -gt 1 ] ; then
+		shift $(( $OPTIND -1 ))
+	fi
+
+	if [ "$#" -eq 0 ] || [ "$#" -gt 2 ] ; then
+		echo "substr: bad argument count"
+		return 2
+	fi
+
+	str="$1"
+
+        #
+        # We don't want -f, but we don't want to turn it back on if
+        # we didn't have it already
+        #
+        case "$-" in
+        "*f*")
+                ;;
+        *)
+                fng=1
+                set -f
+		;;
+        esac
+
+	case "$flag" in
+	-l)
+		str="${str#$pat}"		# substr -l pat string
+		;;
+	-L)
+		str="${str##$pat}"		# substr -L pat string
+		;;
+	-r)
+		str="${str%$pat}"		# substr -r pat string
+		;;
+	-R)
+		str="${str%%$pat}"		# substr -R pat string
+		;;
+	*)
+		str="${str%$2}"			# substr string pat
+		;;
+	esac
+
+	echo "$str"
+
+        #
+        # If we had file name generation when we started, re-enable it
+        #
+        if [ "$fng" = "1" ] ; then
+                set +f
+        fi
+}
diff --git a/examples/functions/whatis b/examples/functions/whatis
new file mode 100644
index 0000000..570c585
--- /dev/null
+++ b/examples/functions/whatis
@@ -0,0 +1,71 @@
+#
+# whatis -- and implementation of the 10th Edition Unix sh builtin `whatis'
+#	    command.
+#
+# usage: whatis arg [...]
+#
+# For each argument, whatis prints the associated value as a parameter,
+# builtin, function, alias, or executable file as appropriate.  In each
+# case, the value is printed in a form which would yield the same value
+# if typed as input to the shell itself.
+#
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1994 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+
+whatis()
+{
+	local wusage='usage: whatis arg [arg...]'
+	local fail=0
+
+	if [ $# -eq 0 ] ; then
+		echo "$wusage"
+		return 1
+	fi
+
+	for arg
+	do
+		case $(builtin type -type $arg 2>/dev/null) in
+		"alias")
+			builtin alias "$arg"
+			;;
+		"function")
+			builtin type "$arg" | sed 1d
+			;;
+		"builtin")
+			echo builtin "$arg"
+			;;
+		"file")
+			builtin type -path "$arg"
+			;;
+		*)
+			# OK, we could have a variable, or we could have nada
+			if [ "$(eval echo \${$arg+set})" = "set" ] ; then
+				# It is a variable, and it is set
+				echo -n "$arg="
+				eval echo '\"'\$$arg'\"'
+			else
+				echo whatis: $arg: not found
+				fail=1
+			fi
+			;;
+		esac
+	done
+	return $fail
+}
diff --git a/examples/functions/whence b/examples/functions/whence
new file mode 100644
index 0000000..ba27b00
--- /dev/null
+++ b/examples/functions/whence
@@ -0,0 +1,78 @@
+#
+# An almost-ksh compatible `whence' command.  This is as hairy as it is 
+# because of the desire to exactly mimic ksh.
+# 
+# This depends somewhat on knowing the format of the output of the bash
+# `builtin type' command.
+#
+# Chet Ramey
+# chet@ins.CWRU.Edu
+#
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1994 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+whence()
+{
+	local vflag= path=
+
+	if [ "$#" = "0" ] ; then
+		echo "whence: argument expected"
+		return 1
+	fi
+	case "$1" in
+		-v) vflag=1
+		    shift 1
+		    ;;
+		-*) echo "whence: bad option: $1"
+		    return 1
+		    ;;
+		 *) ;;
+	esac
+
+	if [ "$#" = "0" ] ; then
+		echo "whence: bad argument count"
+		return 1
+	fi
+
+	for cmd
+	do
+		if [ "$vflag" ]	 ; then
+			echo $(builtin type $cmd | sed 1q)
+		else
+			path=$(builtin type -path $cmd)
+			if [ "$path" ] ; then
+				echo $path
+			else
+				case "$cmd" in
+					/*) if [ -x "$cmd" ]; then
+						echo "$cmd"
+					    fi
+					    ;;
+					 *) case "$(builtin type -type $cmd)" in
+						"") ;;
+						 *) echo "$cmd"
+						    ;;
+					    esac
+					    ;;
+				esac
+			fi
+		fi
+	done
+	return 0
+}
diff --git a/examples/functions/which b/examples/functions/which
new file mode 100644
index 0000000..f0db290
--- /dev/null
+++ b/examples/functions/which
@@ -0,0 +1,62 @@
+#
+# which - emulation of `which' as it appears in FreeBSD
+#
+# usage: which [-as] command [command...]
+#
+#
+#  Chet Ramey <chet.ramey@case.edu>
+#
+#  Copyright 1999 Chester Ramey
+#
+#   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.
+#
+#   TThis program is distributed in the hope that it will be useful,
+#   but WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#   GNU General Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License
+#   along with this program; if not, write to the Free Software Foundation,
+#   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+which()
+{
+	local aflag sflag ES a opt
+
+	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
+}
-- 
cgit v1.2.3