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

This commit is contained in:
Jari Aalto 1996-12-23 17:02:34 +00:00
commit ccc6cda312
502 changed files with 91988 additions and 69123 deletions

View file

@ -0,0 +1,29 @@
From friedman@cli.com Thu May 25 12:19:06 1995
Flags: 10
Return-Path: friedman@cli.com
Received: from po.cwru.edu (root@po.CWRU.Edu [129.22.4.2]) by odin.INS.CWRU.Edu with ESMTP (8.6.10+cwru/CWRU-2.1-ins)
id MAA08685; Thu, 25 May 1995 12:19:05 -0400 (from friedman@cli.com for <chet@odin.INS.CWRU.Edu>)
Received: from cli.com (cli.com [192.31.85.1]) by po.cwru.edu with SMTP (8.6.10+cwru/CWRU-2.3)
id MAA11299; Thu, 25 May 1995 12:19:00 -0400 (from friedman@cli.com for <chet@po.cwru.edu>)
Received: from tepui.cli.com by cli.com (4.1/SMI-4.1)
id AA27213; Thu, 25 May 95 11:18:25 CDT
Received: by tepui.cli.com (4.1) id AA16031; Thu, 25 May 95 11:18:23 CDT
Message-Id: <9505251618.AA16031@tepui.cli.com>
From: friedman@gnu.ai.mit.edu (Noah Friedman)
To: chet@po.cwru.edu
Subject: Bash scripts
Reply-To: friedman@gnu.ai.mit.edu
In-Reply-To: <chet@odin.ins.cwru.edu> Thu, 25 May 1995 11:19:59 -0400
References: <9505251519.AA06424.SM@odin.INS.CWRU.Edu>
Date: Thu, 25 May 95 11:18:21 CST
>Hi. I snagged some of your bash functions from your home directory on
>the FSF machines (naughty, I know), and I was wondering if you'd let
>me distribute them with bash-2.0. Thanks.
Sure. I think there's a later copy in
~ftp/friedman/shell-inits/init-4.89.tar.gz. There are also some elisp and
es frobs in that file.
It should serve as a pretty good example of how to get carried away. :-)

View file

@ -0,0 +1,24 @@
This collection of scripts was originally written for older versions
of bash by Noah Friedman (friedman@gnu.ai.mit.edu). The conversion
to bash v2 syntax was done by Chet Ramey.
These scripts are as-is; there is no copyright associated with
any of them. They exist simply as examples of bash scripting.
Here's a description of what's in this directory:
aref.bash pseudo-arrays and substring indexing examples
bash.sub.bash library functions used by require.bash
bash_version.bash a function to slice up $BASH_VERSION
meta.bash enable and disable eight-bit readline input
mktmp.bash make a temporary file with a unique name
number.bash a fun hack to translate numerals into english
prompt.bash a way to set PS1 to some predefined strings
remap_keys.bash a front end to `bind' to redo readline bindings
require.bash lisp-like require/provide library functions for bash
send_mail.bash replacement smtp client written in bash
shcat.bash bash replacement for `cat'
source.bash replacement for source that uses current directory
string.bash the string(3) functions at the shell level
stty.bash front-end to stty that changes readline bindings too
y_or_n_p.bash prompt for a yes/no/quit answer

View file

@ -0,0 +1,44 @@
# aref.bash --- pseudo-array manipulating routines
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created 1992-07-01
# Last modified: 1993-02-03
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring aref:
# Usage: aref NAME INDEX
#
# In array NAME, access element INDEX (0-origin)
#:end docstring:
###;;;autoload
function aref ()
{
local name="$1"
local index="$2"
set -- ${!name}
[ $index -ge 1 ] && shift $index
echo $1
}
#:docstring string_aref:
# Usage: aref STRING INDEX
#
# Echo the INDEXth character in STRING (0-origin) on stdout.
#:end docstring:
###;;;autoload
function string_aref ()
{
local stuff=${1:$2}
echo ${stuff:0:1}
}
provide aref
# aref.bash ends here

View file

@ -0,0 +1,28 @@
# bash.sub.bash --- stub for standalone shell scripts using bash library
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-07-13
# Last modified: 1993-09-29
# Public domain
#:docstring bash.sub:
# Standard subroutines for bash scripts wishing to use "require" to load
# libraries.
#
# Usage: In each directory where a bash script that uses this script
# exists, place a copy of this script. Then, at the top of such scripts,
# put the command
#
# source ${0%/*}/bash.sub || exit 1
#
# Then you can use `require' to load packages.
#
#:end docstring:
default_FPATH="~friedman/etc/init/bash/functions/lib"
source "${default_FPATH}/feature"
REQUIRE_FAILURE_FATAL=t
FPATH="${FPATH-${default_FPATH}}"
# bash.sub.bash ends here

View file

@ -0,0 +1,42 @@
# bash_version.bash --- get major and minor components of bash version number
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-01-26
# Last modified: 1993-01-26
# Public domain
# Converted to bash v2 syntax by Chet Ramey
# Commentary:
# Code:
#:docstring bash_version:
# Usage: bash_version {major|minor}
#
# Echo the major or minor number of this version of bash on stdout, or
# just echo $BASH_VERSION if no argument is given.
#:end docstring:
###;;;autoload
function bash_version ()
{
local major minor
case "$1" in
major) echo "${BASH_VERSION/.*/}" ;;
minor) major="${BASH_VERSION/.*/}"
minor="${BASH_VERSION#${major}.}"
echo "${minor%%.*}" ;;
patchlevel) minor="${BASH_VERSION#*.*.}"
echo "${minor%(*}" ;;
version) minor=${BASH_VERSION/#*.*./}
echo ${BASH_VERSION/%.$minor/} ;;
release) echo ${BASH_VERSION%(*} ;;
build) minor="${BASH_VERSION#*.*.*(}"
echo ${minor%)} ;;
*) echo "${BASH_VERSION}" ;;
esac
}
provide bash_version
# bash_version.bash ends here

View file

@ -0,0 +1,37 @@
# meta.bash --- meta key frobnications
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-06-28
# Last modified: 1993-01-26
# Public domain
# Commentary:
# Code:
#:docstring meta:
# Usage: meta [on|off]
#
# An argument of "on" will make bash use the 8th bit of any input from
# a terminal as a "meta" bit, i.e bash will be able to use a real meta
# key.
#
# An argument of "off" causes bash to disregard the 8th bit, which is
# assumed to be used for parity instead.
#:end docstring:
function meta ()
{
case "$1" in
on) bind 'set input-meta On'
bind 'set output-meta on'
bind 'set convert-meta off' ;;
off) bind 'set input-meta Off'
bind 'set output-meta off'
bind 'set convert-meta on' ;;
*) echo "Usage: meta [on|off]" 1>&2 ; return 1 ;;
esac
return 0
}
provide meta
# meta.bash ends here

View file

@ -0,0 +1,66 @@
# mktmp.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-02-03
# Last modified: 1993-02-03
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring mktmp:
# Usage: mktmp [template] {createp}
#
# Generate a unique filename from TEMPLATE by appending a random number to
# the end.
#
# If optional 2nd arg CREATEP is non-null, file will be created atomically
# before returning. This is to avoid the race condition that in between
# the time that the temporary name is returned and the caller uses it,
# someone else creates the file.
#:end docstring:
###;;;autoload
function mktmp ()
{
local template="$1"
local tmpfile="${template}${RANDOM}"
local createp="$2"
local noclobber_status
case "$-" in
*C*) noclobber_status=set;;
esac
if [ "${createp:+set}" = "set" ]; then
# Version which creates file atomically through noclobber test.
set -o noclobber
(> "${tmpfile}") 2> /dev/null
while [ $? -ne 0 ] ; do
# Detect whether file really exists or creation lost because of
# some other permissions problem. If the latter, we don't want
# to loop forever.
if [ ! -e "${tmpfile}" ]; then
# Trying to create file again creates stderr message.
echo -n "mktmp: " 1>&2
> "${tmpfile}"
return 1
fi
tmpfile="${template}${RANDOM}"
(> "${tmpfile}") 2> /dev/null
done
test "${noclobber_status}" != "set" && set +o noclobber
else
# Doesn't create file, so it introduces race condition for caller.
while [ -e "${tmpfile}" ]; do
tmpfile="${template}${RANDOM}"
done
fi
echo "${tmpfile}"
}
provide mktmp
# mktmp.bash ends here

View file

@ -0,0 +1,185 @@
# number.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-02-22
# Last modified: 1993-04-01
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring number:
# Usage: number [number]
#
# Converts decimal integers to english notation. Spaces and commas are
# optional. Numbers 67 digits and larger will overflow this script.
#
# E.g: number 99,000,000,000,000,454
# => ninety-nine quadrillion four hundred fifty-four
#
#:end docstring:
function number ()
{
local result
local val1
local val2
local val3
local d1
local d2
local d3
case "$*" in
*[!0-9,.]* )
echo "number: invalid character in argument." 1>&2
return 1
;;
*.* )
echo "number: fractions not supported (yet)." 1>&2
return 1
;;
esac
result=''
eval set - "`echo ${1+\"$@\"} | sed -n -e '
s/[, ]//g;s/^00*/0/g;s/\(.\)\(.\)\(.\)$/\"\1 \2 \3\"/;
:l
/[0-9][0-9][0-9]/{
s/\([^\" ][^\" ]*\)\([^\" ]\)\([^\" ]\)\([^\" ]\)/\1\"\2 \3 \4\"/g;
t l
}
/^[0-9][0-9][0-9]/s/\([^\" ]\)\([^\" ]\)\([^\" ]\)/\"\1 \2 \3\"/;
/^[0-9][0-9]/s/\([^\" ]\)\([^\" ]\)/\"\1 \2\"/;
/^[0-9]/s/^\([^\" ][^\" ]*\)/\"\1\"/g;s/\"\"/\" \"/g;p;'`"
while test $# -ne 0 ; do
eval `set - $1;
d3='' d2='' d1=''
case $# in
1 ) d1=$1 ;;
2 ) d2=$1 d1=$2 ;;
3 ) d3=$1 d2=$2 d1=$3 ;;
esac
echo "d3=\"${d3}\" d2=\"${d2}\" d1=\"${d1}\""`
val1='' val2='' val3=''
case "${d3}" in
'1' ) val3='one' ;;
'2' ) val3='two' ;;
'3' ) val3='three' ;;
'4' ) val3='four' ;;
'5' ) val3='five' ;;
'6' ) val3='six' ;;
'7' ) val3='seven' ;;
'8' ) val3='eight' ;;
'9' ) val3='nine' ;;
esac
case "${d2}" in
'1' ) val2='teen' ;;
'2' ) val2='twenty' ;;
'3' ) val2='thirty' ;;
'4' ) val2='forty' ;;
'5' ) val2='fifty' ;;
'6' ) val2='sixty' ;;
'7' ) val2='seventy' ;;
'8' ) val2='eighty' ;;
'9' ) val2='ninety' ;;
esac
case "${val2}" in
'teen')
val2=''
case "${d1}" in
'0') val1='ten' ;;
'1') val1='eleven' ;;
'2') val1='twelve' ;;
'3') val1='thirteen' ;;
'4') val1='fourteen' ;;
'5') val1='fifteen' ;;
'6') val1='sixteen' ;;
'7') val1='seventeen' ;;
'8') val1='eighteen' ;;
'9') val1='nineteen' ;;
esac
;;
0 ) : ;;
* )
if test ".${val2}" != '.' -a ".${d1}" != '.0' ; then
val2="${val2}-"
fi
case "${d1}" in
'0') val2="${val2} " ;;
'1') val1='one' ;;
'2') val1='two' ;;
'3') val1='three' ;;
'4') val1='four' ;;
'5') val1='five' ;;
'6') val1='six' ;;
'7') val1='seven' ;;
'8') val1='eight' ;;
'9') val1='nine' ;;
esac
;;
esac
if test ".${val3}" != '.' ; then
result="${result}${val3} hundred "
fi
if test ".${val2}" != '.' ; then
result="${result}${val2}"
fi
if test ".${val1}" != '.' ; then
result="${result}${val1} "
fi
if test ".${d1}${d2}${d3}" != '.000' ; then
case $# in
0 | 1 ) ;;
2 ) result="${result}thousand " ;;
3 ) result="${result}million " ;;
4 ) result="${result}billion " ;;
5 ) result="${result}trillion " ;;
6 ) result="${result}quadrillion " ;;
7 ) result="${result}quintillion " ;;
8 ) result="${result}sextillion " ;;
9 ) result="${result}septillion " ;;
10 ) result="${result}octillion " ;;
11 ) result="${result}nonillion " ;;
12 ) result="${result}decillion " ;;
13 ) result="${result}undecillion " ;;
14 ) result="${result}duodecillion " ;;
15 ) result="${result}tredecillion " ;;
16 ) result="${result}quattuordecillion " ;;
17 ) result="${result}quindecillion " ;;
18 ) result="${result}sexdecillion " ;;
19 ) result="${result}septendecillion " ;;
20 ) result="${result}octodecillion " ;;
21 ) result="${result}novemdecillion " ;;
22 ) result="${result}vigintillion " ;;
* )
echo "Error: number too large (66 digits max)." 1>&2
return 1
;;
esac
fi
shift
done
set - ${result}
case "$*" in
'') set - 'zero' ;;
esac
echo ${1+"$@"}
}
provide number
# number.bash ends here

View file

@ -0,0 +1,40 @@
# prompt.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-01-15
# Public domain
# $Id: prompt.bash,v 1.2 1994/10/18 16:34:35 friedman Exp $
# Commentary:
# Code:
#:docstring prompt:
# Usage: prompt [chars]
#
# Various preformatted prompt strings selected by argument. For a
# list of available arguments and corresponding formats, do
# `type prompt'.
#:end docstring:
###;;;autoload
function prompt ()
{
case "$1" in
d) PS1='$(dirs) \$ ' ;;
n) PS1='\$ ' ;;
hsw) PS1='\h[$SHLVL]: \w \$ ' ;;
hw) PS1='\h: \w \$ ' ;;
sh) PS1='[$SHLVL] \h\$ ' ;;
sw) PS1='[$SHLVL] \w \$ ' ;;
uh) PS1='\u@\h\$ ' ;;
uhsHw) PS1='\u@\h[$SHLVL]:\#: \w \$ ' ;;
uhsw) PS1='\u@\h[$SHLVL]: \w \$ ' ;;
uhw) PS1='\u@\h: \w \$ ' ;;
uw) PS1='(\u) \w \$ ' ;;
w) PS1='\w \$ ' ;;
esac
}
provide prompt
# prompt.bash ends here

View file

@ -0,0 +1,71 @@
# remap_keybindings.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-01-11
# Last modified: 1993-02-03
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring remap_keybindings:
# Usage: remap_keybindings old_function new_function
#
# Clear all readline keybindings associated with OLD_FUNCTION (a Readline
# function) rebinding them to NEW_FUNCTION (`self-insert' by default)
#
# This requires bash version 1.10 or newer, since previous versions did not
# implement the `bind' builtin.
#:end docstring:
###;;;autoload
function remap_keybindings ()
{
local unbind_function="$1"
local bind_function="${2:-'self-insert'}"
local bind_output
local arg
# If they're the same thing, the work has already been done. :-)
if [ "${unbind_function}" = "${bind_function}" ]; then
return 0
fi
while : ; do
bind_output="$(bind -q ${unbind_function} 2> /dev/null)"
case "${bind_output}" in
"${unbind_function} can be invoked via"* ) ;;
"" ) return 1 ;; # probably bad argument to bind
*) return 0 ;; # unbound
esac
# Format of bind_output is like:
# 'quoted-insert can be invoked via "\C-q", "\C-v".'
# 'self-insert can be invoked via " ", "!", """, "$", "%", ...'
set -- ${bind_output}
shift 5
for arg in "$@" ; do
# strip off trailing `.' or `,'
arg=${arg%.};
arg=${arg%,};
case ${arg} in
..)
# bind -q didn't provide whole list of key bindings; jump
# to top loop to get more
continue 2 ;
;;
*)
bind "${arg}: ${bind_function}"
;;
esac
done
done
}
provide remap_keybindings
# remap_keybindings.bash ends here

View file

@ -0,0 +1,182 @@
# require.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-07-08
# Last modified: 1993-09-29
# Public domain
# Commentary:
# These functions provide an interface based on the lisp implementation for
# loading libraries when they are needed and eliminating redundant loading.
# The basic idea is that each "package" (or set of routines, even if it is
# only one function) registers itself with a symbol that marks a "feature"
# as being "provided". If later you "require" a given feature, you save
# yourself the trouble of explicitly loading it again.
#
# At the bottom of each package, put a "provide foobar", so when another
# package has a "require foobar", it gets loaded and registered as a
# "feature" that won't need to get loaded again. (See warning below for
# reasons why provide should be put at the end.)
#
# The list of provided features are kept in the `FEATURES' variable, which
# is not exported. Care should be taken not to munge this in the shell.
# The search path comes from a colon-separated `FPATH' variable. It has no
# default value and must be set by the user.
#
# Require uses `fpath_search', which works by scanning all of FPATH for a
# file named the same as the required symbol but with a `.bash' appended to
# the name. If that is found, it is loaded. If it is not, FPATH is
# searched again for a file name the same as the feature (i.e. without any
# extension). Fpath_search may be useful for doing library filename
# lookups in other functions (such as a `load' or `autoload' function).
#
# Warning: Because require ultimately uses the builtin `source' command to
# read in files, it has no way of undoing the commands contained in the
# file if there is an error or if no provide statement appeared (this
# differs from the lisp implementation of require, which normally undoes
# most of the forms that were loaded if the require fails). Therefore, to
# minize the number of problems caused by requiring a faulty package (such
# as syntax errors in the source file) it is better to put the provide at
# the end of the file, rather than at the beginning.
# Code:
# Exporting this variable would cause considerable lossage, since none of
# the functions are exported (or at least, they're not guaranteed to be)
export -n FEATURES
#:docstring :
# Null function. Provided only so that one can put page breaks in source
# files without any ill effects.
#:end docstring:
#
# (\\014 == C-l)
eval "function $(echo -e \\014) () { : }"
#:docstring featurep:
# Usage: featurep argument
#
# Returns 0 (true) if argument is a provided feature. Returns 1 (false)
# otherwise.
#:end docstring:
###;;;autoload
function featurep ()
{
local feature="$1"
case " ${FEATURES} " in
*" ${feature} "* ) return 0 ;;
esac
return 1
}
#:docstring provide:
# Usage: provide symbol ...
#
# Register a list of symbols as provided features
#:end docstring:
###;;;autoload
function provide ()
{
local feature
for feature in "$@" ; do
if ! featurep "${feature}" ; then
FEATURES="${FEATURES} ${feature}"
fi
done
return 0
}
#:docstring require:
# Usage: require feature {file}
#
# Load FEATURE if it is not already provided. Note that require does not
# call `provide' to register features. The loaded file must do that
# itself. If the package does not explicitly do a `provide' after being
# loaded, require will complain about the feature not being provided on
# stderr.
#
# Optional argument FILE means to try to load FEATURE from FILE. If no
# file argument is given, require searches through FPATH (see fpath_search)
# for the appropriate file.
#
# If the variable REQUIRE_FAILURE_FATAL is set, require will cause the
# current shell invocation to exit, rather than merely return. This may be
# useful for a shell script that vitally depends on a package.
#
#:end docstring:
###;;;autoload
function require ()
{
local feature="$1"
local path="$2"
local file
if ! featurep "${feature}" ; then
file=$(fpath_search "${feature}" "${path}") && source "${file}"
if ! featurep "${feature}" ; then
echo "require: ${feature}: feature was not provided." 1>&2
if [ "${REQUIRE_FAILURE_FATAL+set}" = "set" ]; then
exit 1
fi
return 1
fi
fi
return 0
}
#:docstring fpath_search:
# Usage: fpath_search filename {path ...}
#
# Search $FPATH for `filename' or, if `path' (a list) is specified, search
# those directories instead of $FPATH. First the path is searched for an
# occurrence of `filename.bash, then a second search is made for just
# `filename'.
#:end docstring:
###;;;autoload
function fpath_search ()
{
local name="$1"
local path="$2"
local suffix=".bash"
local file
if [ -z "${path}" ]; then path="${FPATH}"; fi
for file in "${name}${suffix}" "${name}" ; do
set -- $(IFS=':'
set -- ${path}
for p in "$@" ; do
echo -n "${p:-.} "
done)
while [ $# -ne 0 ]; do
test -f "${1}/${file}" && { file="${1}/${file}"; break 2 }
shift
done
done
if [ $# -eq 0 ]; then
echo "fpath_search: ${name}: file not found in fpath" 1>&2
return 1
fi
echo "${file}"
return 0
}
provide require
# require.bash ends here

View file

@ -0,0 +1,140 @@
# send_mail.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-07-02
# Public domain
# Commentary:
# TODO: implement Fcc headers (see emacs manual)
# Code:
#:docstring send_mail:
# Usage: send_mail
#
# This function serves as a simple replacement for sendmail as a client
# interface on those systems where it is not available. It does assume
# that one can talk to an SMTP mailer on port 25 either on the local host
# or on the host specified by the MAILHOST environment variable. If you
# have access to sendmail, it's better to use 'sendmail -t' instead of this
# script (which probably isn't as robust).
#
# Message is read from stdin, and headers are parsed to determine
# recipients.
#:end docstring:
###;;;autoload
function send_mail ()
{
# Need gawk, since several extensions are taken advantage of (like
# IGNORECASE for regexps).
local awk="${GAWK_LOCATION:-gawk}"
local DefaultFrom="${USER:-${LOGNAME}}"
local From
local To
local Cc
local Bcc
local tmpfile="/tmp/send_mail$$"
while [ -e "${tmpfile}" ]; do
tmpfile="/tmp/send_mail${RANDOM}"
done
# Lines consisting only of dots need one more dot appended. SMTP
# servers eat one of the dots (and if only 1 dot appears, it signifies
# the end of the message).
sed '/^\.\.*/s/^\(\.\.*\)$/\1./' > "${tmpfile}"
# Parse mail headers in message to extract recipients list.
# This doesn't affect what the user sees---it's only used to generate
# the rcpt-to lines for SMTP.
eval $(${awk} -f - "${tmpfile}" <<- '__EOF__'
# Try to extract email address from amidst random data
function parse_address (data)
{
# From: "real name" <foobar@host>
# From: "" <foobar@host>
if (match(data, /^\"[^\"]*\"[ \t]*<.*>/)) {
data_idx = match(data, /^\"[^\"]*\"[ \t]*</)
data = substr(data, RSTART + RLENGTH);
if (data_idx = match(data, ">.*"))
data = substr(data, 1, RSTART - 1);
return data
}
# From: real name <foobar@host>
if (match(data, /<.*>/)) {
data_idx = match(data, /</)
data = substr(data, RSTART + RLENGTH);
if (data_idx = match(data, ">"))
data = substr(data, 1, RSTART - 1);
return data
}
# From: foobar@host (real name)
if (match(data, /\(.*\)/)) {
data_idx = match(data, /\(/);
data = substr(data, 1, RSTART - 1);
return data
}
# (hopefully) From: foobar@host
return data
}
BEGIN { IGNORECASE = 1; }
# Blank line signifies end of headers, so we can stop looking.
/^$/ { exit(0) }
/^from:|^to:|^cc:|^bcc:/ {
header_idx = match($0, /^[^:]*:/)
if (header_idx) {
# Capitalize header name
header_firstchar = toupper(substr($0, RSTART, 1));
header_rest = tolower(substr($0, RSTART + 1, RLENGTH - 2));
header = header_firstchar header_rest
$0 = substr($0, RSTART + RLENGTH + 1);
addresses = ""
# parse addresses
while ($0) {
# Strip leading whitespace
if (idx = match($0, /[ \t]*/))
$0 = substr($0, RSTART + RLENGTH);
# Find everything up to a nonquoted comma
# FIXME: doesnt handle quoting yet
if (idx = match($0, /,/)) {
data = substr($0, 1, RSTART);
$0 = substr($0, RSTART + 1);
} else {
data = $0
$0 = ""
}
addresses = addresses " " parse_address(data)
}
printf("%s='%s'\n", header, addresses);
}
}
__EOF__)
# Not sure if an address is *required* after the HELO.. every sendmail
# I tried talking to didn't seem to care. Some sendmails don't care
# if there's a HELO at all.
cat <<- __EOF__ | telnet ${MAILHOST:-localhost} 25 > /dev/null 2>&1
HELO
mail from: ${From:-${DefaultFrom}}
$(for name in ${To} ${Cc} ${Bcc} ; do
echo "rcpt to: ${name}"
done)
data
$(cat "${tmpfile}")
.
quit
__EOF__
rm -f "${tmpfile}"
}
provide send_mail
# send_mail.bash ends here

View file

@ -0,0 +1,49 @@
# shcat.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-07-17
# Last modified: 1993-09-29
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring shcat:
# Usage: shcat {file1} {file2} {...}
#
# Like `cat', only this is all inline bash.
#:end docstring:
###;;;autoload
function shcat ()
{
local IFS=""
local line
local file
local exitstat=0
if [ $# -eq 0 ]; then
while read -r line; do
echo "${line}"
done
return 0
else
for file in "$@" ; do
if [ -r "${file}" ]; then
while read -r line; do
echo "${line}"
done < "${file}"
else
# This will cause the error to be printed on stderr
< "${file}"
exitstat=1
fi
done
return ${exitstat}
fi
}
provide shcat
# shcat.bash ends here

View file

@ -0,0 +1,63 @@
# source.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-05-17
# Last modified: 1993-09-29
# Public domain
# Commentary:
# Code:
#:docstring source:
# Usage: source file ...
#
# Source forces file arguments to be considered in the current directory
# only, unless there is an absolute path starting with `/'. I think it's
# bad that the builtin "source" searches PATH, because PATH normally
# contains directories with binary files that aren't useful for bash to
# read and most people don't put "." first in their path.
#
# This "source" is capable of reading more than one file at a time. Return
# value is number of failed source attempts.
#:end docstring:
# This function is not hygienic, but there's not much we can do about
# variable name conflicts here.
###;;;autoload
function source ()
{
local -i _source_failure_count=0
local _source_file
for _source_file ; do
# Check first part of each filename. If it's not `/', `./', or
# `../' then prepend "./" to the path to force the builtin `source'
# not to go searching through PATH to find the file.
case "${_source_file}" in
/*|./*|../* ) ;;
* ) _source_file="./${_source_file}" ;;
esac
builtin source "${_source_file}" ||
_source_failure_count="_source_failure_count + 1"
done
return ${_source_failure_count}
}
#:docstring .:
# See "source"
#:end docstring:
# So that `.' will call function definition of `source' instead of builtin
###;;;autoload
function . ()
{
source "$@"
}
provide source
# source.bash ends here

View file

@ -0,0 +1,226 @@
# string.bash --- bash emulation of string(3) library routines
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-07-01
# Last modified: 1993-09-29
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring strcat:
# Usage: strcat s1 s2
#
# Strcat appends the value of variable s2 to variable s1.
#
# Example:
# a="foo"
# b="bar"
# strcat a b
# echo $a
# => foobar
#
#:end docstring:
###;;;autoload
function strcat ()
{
local s1_val s2_val
s1_val=${!1} # indirect variable expansion
s2_val=${!2}
eval "$1"=\'"${s1_val}${s2_val}"\'
}
#:docstring strncat:
# Usage: strncat s1 s2 $n
#
# Line strcat, but strncat appends a maximum of n characters from the value
# of variable s2. It copies fewer if the value of variabl s2 is shorter
# than n characters. Echoes result on stdout.
#
# Example:
# a=foo
# b=barbaz
# strncat a b 3
# echo $a
# => foobar
#
#:end docstring:
###;;;autoload
function strncat ()
{
local s1="$1"
local s2="$2"
local -i n="$3"
local s1_val s2_val
s1_val=${!s1} # indirect variable expansion
s2_val=${!s2}
if [ ${#s2_val} -gt ${n} ]; then
s2_val=${s2_val:0:$n} # substring extraction
fi
eval "$s1"=\'"${s1_val}${s2_val}"\'
}
#:docstring strcmp:
# Usage: strcmp $s1 $s2
#
# Strcmp compares its arguments and returns an integer less than, equal to,
# or greater than zero, depending on whether string s1 is lexicographically
# less than, equal to, or greater than string s2.
#:end docstring:
###;;;autoload
function strcmp ()
{
[ "$1" = "$2" ] && return 0
[ "${1}" '<' "${2}" ] > /dev/null && return -1
return 1
}
#:docstring strncmp:
# Usage: strncmp $s1 $s2 $n
#
# Like strcmp, but makes the comparison by examining a maximum of n
# characters (n less than or equal to zero yields equality).
#:end docstring:
###;;;autoload
function strncmp ()
{
if [ -z "${3}" -o "${3}" -le "0" ]; then
return 0
fi
if [ ${3} -ge ${#1} -a ${3} -ge ${#2} ]; then
strcmp "$1" "$2"
return $?
else
s1=${1:0:$3}
s2=${2:0:$3}
strcmp $s1 $s2
return $?
fi
}
#:docstring strlen:
# Usage: strlen s
#
# Strlen returns the number of characters in string literal s.
#:end docstring:
###;;;autoload
function strlen ()
{
eval echo "\${#${1}}"
}
#:docstring strspn:
# Usage: strspn $s1 $s2
#
# Strspn returns the length of the maximum initial segment of string s1,
# which consists entirely of characters from string s2.
#:end docstring:
###;;;autoload
function strspn ()
{
# Unsetting IFS allows whitespace to be handled as normal chars.
local IFS=
local result="${1%%[!${2}]*}"
echo ${#result}
}
#:docstring strcspn:
# Usage: strcspn $s1 $s2
#
# Strcspn returns the length of the maximum initial segment of string s1,
# which consists entirely of characters not from string s2.
#:end docstring:
###;;;autoload
function strcspn ()
{
# Unsetting IFS allows whitspace to be handled as normal chars.
local IFS=
local result="${1%%[${2}]*}"
echo ${#result}
}
#:docstring strstr:
# Usage: strstr s1 s2
#
# Strstr echoes a substring starting at the first occurrence of string s2 in
# string s1, or nothing if s2 does not occur in the string. If s2 points to
# a string of zero length, strstr echoes s1.
#:end docstring:
###;;;autoload
function strstr ()
{
# if s2 points to a string of zero length, strstr echoes s1
[ ${#2} -eq 0 ] && { echo "$1" ; return 0; }
# strstr echoes nothing if s2 does not occur in s1
case "$1" in
*$2*) ;;
*) return 1;;
esac
# use the pattern matching code to strip off the match and everything
# following it
first=${1/$2*/}
# then strip off the first unmatched portion of the string
echo "${1##$first}"
}
#:docstring strtok:
# Usage: strtok s1 s2
#
# Strtok considers the string s1 to consist of a sequence of zero or more
# text tokens separated by spans of one or more characters from the
# separator string s2. The first call (with a non-empty string s1
# specified) echoes a string consisting of the first token on stdout. The
# function keeps track of its position in the string s1 between separate
# calls, so that subsequent calls made with the first argument an empty
# string will work through the string immediately following that token. In
# this way subsequent calls will work through the string s1 until no tokens
# remain. The separator string s2 may be different from call to call.
# When no token remains in s1, an empty value is echoed on stdout.
#:end docstring:
###;;;autoload
function strtok ()
{
:
}
#:docstring strtrunc:
# Usage: strtrunc $n $s1 {$s2} {$...}
#
# Used by many functions like strncmp to truncate arguments for comparison.
# Echoes the first n characters of each string s1 s2 ... on stdout.
#:end docstring:
###;;;autoload
function strtrunc ()
{
n=$1 ; shift
for z; do
echo "${z:0:$n}"
done
}
provide string
# string.bash ends here

View file

@ -0,0 +1,64 @@
# stty.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-01-11
# Last modified: 1993-09-29
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
require remap_keybindings
#:docstring stty:
# Track changes to certain keybindings with stty, and make those changes
# reflect in bash's readline bindings as well.
#
# This requires bash version 1.10 or newer, since previous versions did not
# implement the `bind' builtin.
#:end docstring:
###;;;autoload
function stty ()
{
local erase="backward-delete-char"
local kill="unix-line-discard"
local werase="backward-kill-word"
local lnext="quoted-insert"
local readline_function=""
local key=""
local stty_command=""
while [ $# -gt 0 ]; do
case "$1" in
erase | kill | werase | lnext )
key=$(echo "${2}" | cat -v | sed 's/\^/\\C-/')
readline_function=$(eval echo \$${1})
# Get rid of any current bindings; the whole point of this
# function is to make the distinction between readline
# bindings and particular cbreak characters transparent; old
# readline keybindings shouldn't hang around.
# could use bind -r here instead of binding to self-insert
remap_keybindings "${readline_function}" "self-insert"
# Bind new key to appropriate readline function
bind "\"${key}\": ${readline_function}"
stty_command="${stty_command} ${1} ${2}"
shift 2
;;
*)
stty_command="${stty_command} ${1}"
shift
;;
esac
done
command stty ${stty_command}
}
provide stty
# stty.bash ends here

View file

@ -0,0 +1,78 @@
# y_or_n_p.bash
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1992-06-18
# Last modified: 1993-03-01
# Public domain
# Conversion to bash v2 syntax done by Chet Ramey
# Commentary:
# Code:
#:docstring y_or_n_p:
# Usage: y_or_n_p QUERY
#
# Print QUERY on stderr, then read stdin for a y-or-n response. Actually,
# user may type anything they like, but first character must be a `y', `n',
# `q', or `!', otherwise the question is repeated until such an answer is
# obtained.
#
# If user typed `y', y_or_n_p returns 0.
#
# If user typed `n', y_or_n_p returns 1.
#
# If user typed `!', y_or_n_p returns 2. This is an indication to the
# caller that no more queries should be made. Assume `y' for all the rest.
#
# If user typed `q', y_or_n_p returns 3. This is an indication to the
# caller that no more queries should be made. Assume `n' for all the rest.
#
#:end docstring:
###;;;autoload
function y_or_n_p ()
{
local ans
[ ! -t 0 ] && return 1
while read -p "$*" -e ans ; do
case "${ans}" in
y* | Y* ) return 0 ;;
n* | N* ) return 1 ;;
\! ) return 2 ;;
q* | Q* ) return 3 ;;
*) echo "Please answer one of \`y', \`n', \`q', or \`"\!"'" 1>&2 ;;
esac
done
}
#:docstring yes_or_no_p:
# Usage: yes_or_no_p QUERY
#
# Like y_or_n_p, but require a full `yes', `no', `yes!', or `quit' response.
#:end docstring:
###;;;autoload
function yes_or_no_p ()
{
local ans
[ ! -t 0 ] && return 3
while read -p "$*" -e ans; do
ans="$(echo ${ans} | tr '[A-Z]' '[a-z]')"
case "${ans}" in
yes ) return 0 ;;
no ) return 1 ;;
yes\! ) return 2 ;;
quit ) return 3 ;;
*) echo "Please answer \`yes', \`no', \`yes"\!"', or \`quit'" 1>&2 ;;
esac
done
}
provide y_or_n_p
# y_or_n_p.bash ends here