summaryrefslogtreecommitdiff
path: root/examples/scripts/bcsh.sh
diff options
context:
space:
mode:
Diffstat (limited to 'examples/scripts/bcsh.sh')
-rwxr-xr-xexamples/scripts/bcsh.sh1254
1 files changed, 1254 insertions, 0 deletions
diff --git a/examples/scripts/bcsh.sh b/examples/scripts/bcsh.sh
new file mode 100755
index 0000000..b810cab
--- /dev/null
+++ b/examples/scripts/bcsh.sh
@@ -0,0 +1,1254 @@
+# 1-Feb-86 09:37:35-MST,30567;000000000001
+# Return-Path: <unix-sources-request@BRL.ARPA>
+# Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Sat 1 Feb 86 09:36:16-MST
+# Received: from usenet by TGR.BRL.ARPA id a002623; 1 Feb 86 9:33 EST
+# From: chris <chris@globetek.uucp>
+# Newsgroups: net.sources
+# Subject: Improved Bcsh (Bourne Shell Cshell-Emulator)
+# Message-ID: <219@globetek.UUCP>
+# Date: 30 Jan 86 17:34:26 GMT
+# To: unix-sources@BRL-TGR.ARPA
+#
+# This is a new, improved version of my Bourne shell cshell-emulator.
+# The code has been cleaned up quite a bit, and a couple of new features
+# added (now supports 'noclobber' and 'iclobber' variables). A bug with
+# 'eval' that caused "illegal I/O" error messages on vanilla V7 shells has
+# also been fixed.
+
+# I have posted the program in its entirety because a context diff of the
+# old and new versions was longer than the new version...
+
+# --Chris
+# Bcsh -- A Simple Cshell-Like Command Pre-Processor For The Bourne Shell
+#
+# "Copyright (c) Chris Robertson, December 1985"
+#
+# This software may be used for any purpose provided the original
+# copyright notice and this notice are affixed thereto. No warranties of
+# any kind whatsoever are provided with this software, and it is hereby
+# understood that the author is not liable for any damagages arising
+# from the use of this software.
+#
+# Features Which the Cshell Does Not Have:
+# ----------------------------------------
+#
+# + command history persists across bcsh sessions
+# + global last-command editing via 'g^string1^string2^' syntax
+# + edit any command via $EDITOR or $VISUAL editors
+# + history file name, .bcshrc file name, alias file name, and number
+# of commands saved on termination can be set by environment variables
+# + prompt may evaluate commands, such as `pwd`, `date`, etc.
+# + the whole text of interactive 'for' and 'while' loops and 'if'
+# statements goes into the history list and may be re-run or edited
+# + multiple copies of commands and requests to see command history
+# are not added to the history list
+# + the history mechanism actually stores all commands entered in a
+# current session, not just $history of them. This means that you
+# can increase $history on the fly and at once have a larger history.
+#
+#
+# Synonyms:
+# ---------
+#
+# logout, exit, bye write out history file and exit
+# h, history show current history list
+#
+#
+# Aliases:
+# --------
+#
+# alias NAME CMND create an alias called NAME to run CMND
+# unalias NAME remove the alias NAME
+#
+# There are no 'current-session only' aliases -- all alias and unalias
+# commands are permanent, and stored in the $aliasfile.
+#
+# If an alias contains positional variables -- $1, $2, $*, etc. -- any
+# arguments following the alias name are considered to be values for
+# those variables, and the alias is turned into a command of the form
+# 'set - arguments;alias'. Otherwise, a simple substitution is performed
+# for the alias and the rest of the command preserved. The cshell
+# convention of using '\!:n' in an alias to get bits of the current
+# command is mercifully abandoned.
+#
+# Quotes are not necessary around the commands comprising an alias;
+# in fact, any enclosing quotes are stripped when the alias is added
+# to the file.
+#
+# A couple of typical aliases might be:
+#
+# goto cd $1;pwd
+# l ls -F
+#
+# Note that aliasing something to "commands;logout" will not work -- if
+# you want something to happen routinely on logout put it in the file
+# specified by $logoutfile, default = $HOME/.blogout.
+#
+#
+# Command Substitutions:
+# ----------------------
+#
+# !! substitute last command from history list
+# !!:N substitute Nth element of last command from
+# history list -- 0 = command name, 1 = 1st arg
+# !!:$ substitute last element of last command from
+# history list
+# !!:* substitute all arguments to last command
+# from history list
+# !NUMBER substitute command NUMBER from the history list
+# !NUMBER:N as above, but substitute Nth element, where
+# 0 = command name, 1 = 1st arg, etc.
+# !NUMBER:$ as above, but substitute last element
+# !NUMBER:* as above, but substitute all arguments
+# !-NUMBER substitute the command NUMBER lines from the
+# end of the history list; 1 = last command
+# !-NUMBER:N as above, but substitute Nth element, where
+# 0 = command name, 1 = 1st arg, etc.
+# !-NUMBER:$ as above, but substitute last element
+# !-NUMBER:* as above, but substitute all arguments
+# !?STRING substitute most-recent command from history list
+# containing STRING -- STRING must be enclosed in
+# braces if followed by any other characters
+# !?STRING:N as above, but substitute Nth element, where
+# 0 = command name, 1 = 1st arg, etc.
+# !?STRING:$ as above, but substitute last element
+# !?STRING:* as above, but substitute all arguments
+#
+#
+# Command Editing:
+# ----------------
+#
+# CMND~e edit CMND using $EDITOR, where CMND may be found
+# using a history substitution
+# CMND~v edit CMND using $VISUAL, where CMND may be found
+# using a history substitution
+# " ^string1^string2^ substitute string2 for string1 in last command"
+# command and run it
+# " g^string1^string2^ globally substitute string2 for string1 in "
+# last command and run it
+# !NUMBER:s/string1/string2/
+# substitute string2 for string1 in
+# command NUMBER and run it
+# !NUMBER:gs/string1/string2/
+# globally substitute string2 for string1 in
+# command NUMBER and run it
+# !?STRING:s/string1/string2/
+# substitute string2 for string1 in last command
+# containing STRING and run it
+# !?STRING:gs/string1/string2/
+# globally substitute string2 for string1 in last
+# command containing STRING and run it
+#
+# Any command which ends in the string ":p" is treated as a normal
+# command until all substitutions have been completed. The trailing
+# ":p" is then stripped, and the command is simply echoed and added to
+# the history list instead of being executed.
+#
+# None of the other colon extensions of the cshell are supported.
+#
+#
+# Shell Environment Variables:
+# ----------------------------
+#
+# EDITOR editor used by ~e command, default = "ed"
+# VISUAL editor used by ~v command, default = "vi"
+# MAIL your system mailbox
+# PAGER paging program used by history command, default = "more"
+# PS1 primary prompt
+# PS2 secondary prompt
+# history number of commands in history list, default = 22
+# histfile file history list is saved in, default = $HOME/.bhistory
+# savehist number of commands remembered from last bcsh session
+# aliasfile file of aliased commands, default = $HOME/.baliases
+# logoutfile file of commands to be executed before termination
+# inc_cmdno yes/no -- keep track of command numbers or not
+# noclobber if set, existing files are not overwritten by '>'
+# iclobber if both noclobber and iclobber are set, the user is
+# prompted for confirmation before existing files are
+# overwritten by '>'
+#
+# Note: if you are setting either noclobber or iclobber mid-session,
+# set them to 'yes'
+#
+#
+# Regular Shell Variables:
+# ------------------------
+#
+# Shell variables may be set via Bourne or cshell syntax, e.g., both
+# "set foo=bar" and "foo=bar" set a variable called "foo" with the value
+# "bar". However, all variables are automatically set as environment
+# variables, so there is no need to export them. Conversely, there
+# are NO local variables. Sorry, folks.
+#
+# A cshell-style "setenv" command is turned into a regular "set" command.
+#
+#
+# The Prompt:
+# ----------
+#
+# You may, if you wish, have a command executed in your prompt. If
+# the variable PS1 contains a dollar sign or a backquote, it is
+# evaluated and the result used as the prompt, provided the evaluation
+# did not produce a "not found" error message. The two special cases
+# of PS1 consisting solely of "$" or "$ " are handled correctly. For
+# example, to have the prompt contain the current directory followed
+# by a space, enter:
+#
+# PS1=\'echo "`pwd` "\'
+#
+# You need the backslashed single quotes to prevent the command being
+# evaluated by the variable-setting mechanism and the shell before it
+# is assigned to PS1.
+#
+# To include the command number in your prompt, enter the command:
+#
+# PS1=\'echo "$cmdno "\'
+#
+#
+# Shell Control-Flow Syntax:
+# --------------------------
+#
+# 'While', 'for', 'case', and 'if' commands entered in Bourne shell
+# syntax are executed as normal.
+#
+# A valiant attempt is made to convert 'foreach' loops into 'for' loops,
+# cshell-syntax 'while' loops into Bourne shell syntax, and 'switch'
+# statements into 'case' statements. I cannot guarantee to always get it
+# right. If you forget the 'do' in a 'while' or 'for' loop, or finish
+# them with 'end' instead of 'done', this will be corrected.
+#
+# Note that cshell-to-Bourne control flow conversions do not take place
+# if control is nested -- e.g., a 'foreach' inside a 'while' will fail.
+#
+# The simple-case cshell "if (condition) command" is turned into Bourne
+# syntax. Other 'if' statements are left alone apart from making the
+# 'then' a separate statement, because constructing a valid interactive
+# cshell 'if' statement is essentially an exercise in frustration anyway.
+# The cshell and Bourne shell have sufficiently different ideas about
+# conditions that if is probably best to resign yourself to learning
+# the Bourne shell conventions.
+#
+# Note that since most of the testing built-ins of the cshell are
+# not available in the Bourne shell, a complex condition in a 'while'
+# loop or an 'if' statement will probably fail.
+#
+#
+# Bugs, Caveats, etc.:
+# --------------------
+#
+# This is not a super-speedy program. Be patient, especially on startup.
+#
+# To the best of my knowledge this program should work on ANY Bourne
+# shell -- note that if your shell does not understand 'echo -n' you
+# will have to re-set the values of '$n' and '$c'.
+#
+# This program may run out of stack space on a 16-bit machine where
+# /bin/sh is not split-space.
+#
+# Mail checking is done every 10 commands if $MAIL is set in your
+# environment. For anything fancier, you will have to hack the code.
+#
+# Because commands are stuffed in a file before sh is invoked on them,
+# error messages from failed commands are ugly.
+#
+# Failed history substitutions either give nothing at all, or a
+# "not found" style of error message.
+#
+# A command history is kept whether you want it or not. This may be
+# perceived as a bug or a feature, depending on which side of bed you
+# got out on.
+#
+# If you want a real backslash in a command, you will have to type two
+# of them because the shell swallows the first backslash in the initial
+# command pickup. This means that to include a non-history '!' in a
+# command you need '\\!' -- a real wart, especially for net mail,
+# but unavoidable.
+#
+# Commands containing an '@' will break all sorts of things.
+#
+# Very complex history substitutions may fail.
+#
+# File names containing numbers may break numeric history sustitutions.
+#
+# Commands containing bizzare sequences of characters may conflict
+# with internal kludges.
+#
+# Aliasing something to "commands;logout" will not work -- if you
+# want something to happen routinely on logout, put it in the file
+# specified by $logoutfile, default = $HOME/.blogout.
+#
+# Please send all bug reports to ihnp4!utzoo!globetek!chris.
+# Flames will be posted to net.general with 'Reply-to' set to your
+# ' path... :-) '
+#
+#
+#
+# ************* VERY IMPORTANT NOTICE *************
+#
+# If your shell supports # comments, then REPLACE all the colon 'comments'
+# with # comments. If it does not, then REMOVE all the 'comment' lines from the
+# working copy of the file, as it will run MUCH faster -- the shell evaluates
+# lines starting with a colon but does not actually execute them, so you will
+# save the read-and-evaluate time by removing them.
+
+case "`echo -n foo`" in
+ -n*)
+ n=
+ c="\c"
+ ;;
+ foo)
+ n=-n
+ c=
+ ;;
+ *)
+ echo "Your 'echo' command is broken."
+ exit 1
+ ;;
+esac
+history=${history-22}
+savehist=${savehist-22}
+histfile=${histfile-$HOME/.bhistory}
+logoutfile=${logoutfile-$HOME/.blogout}
+EDITOR=${EDITOR-ed}
+VISUAL=${VISUAL-vi}
+PAGER=${PAGER-more}
+
+aliasfile=${aliasfile-$HOME/.baliases}
+
+# the alias file may contain 1 blank line, so a test -s will not work
+
+case "`cat $aliasfile 2> /dev/null`" in
+ "")
+ doalias=no
+ ;;
+ *)
+ doalias=yes
+ ;;
+esac
+
+if test -s "${sourcefile-$HOME/.bcshrc}"
+ then
+ . ${sourcefile-$HOME/.bcshrc}
+fi
+
+if test -s "$histfile"
+ then
+ cmdno="`set - \`wc -l $histfile\`;echo $1`"
+ cmdno="`expr \"$cmdno\" + 1`"
+ lastcmd="`sed -n '$p' $histfile`"
+ copy=false
+ ohist=$histfile
+ while test ! -w "$histfile"
+ do
+ echo "Cannot write to history file '$histfile'."
+ echo $n "Please enter a new history filename: $c"
+ read histfile
+ copy=true
+ done
+ if $copy
+ then
+ cp $ohist $histfile
+ fi
+else
+ cat /dev/null > $histfile
+ cmdno=1
+ lastcmd=
+fi
+
+# keep track of command number as the default
+
+inc_cmdno=${inc_cmdo-yes}
+
+# default prompts -- PS1 and PS2 may be SET but EMPTY, so '${PS1-% }' syntax
+# is not used here
+
+case "$PS1" in
+ "")
+ PS1="% "
+ ;;
+esac
+case "$PS2" in
+ "")
+ PS2="> "
+ ;;
+esac
+
+export histfile savehist history aliasfile EDITOR VISUAL PAGER cmdno PS1 PS2
+
+case "$MAIL" in
+ "")
+ ;;
+ *)
+ if [ -f $MAIL ]; then
+ mailsize=`set - \`wc -c $MAIL\`;echo $1`
+ else
+ mailsize=0
+ fi
+ ;;
+esac
+
+trap ':' 2
+trap exit 3
+trap "tail -n $savehist $histfile>/tmp/hist$$;uniq /tmp/hist$$ > $histfile;\
+rm -f /tmp/*$$;exit 0" 15
+
+getcmd=yes
+mailcheck=
+exclaim=
+echoit=
+mailprompt=
+
+while :
+do
+
+ run=yes
+ case "$mailprompt" in
+ "")
+ ;;
+ *)
+ echo "$mailprompt"
+ ;;
+ esac
+ case "$getcmd" in
+ yes)
+ : guess if the prompt should be evaluated or not
+ case "$PS1" in
+ \$|\$\ )
+ echo $n "$PS1$c"
+ ;;
+ *\`*|*\$*)
+ tmp="`(eval $PS1) 2>&1`"
+ case "$tmp" in
+ *not\ found)
+ echo $n "$PS1$c"
+ ;;
+ *)
+ echo $n "$tmp$c"
+ ;;
+ esac
+ ;;
+ *)
+ echo $n "$PS1$c"
+ ;;
+ esac
+
+ read cmd || cmd="exit"
+ ;;
+ *) ;;
+ esac
+
+ case "$MAIL" in
+ "")
+ ;;
+ *)
+ : check for mail every 10 commands
+ case "$mailcheck" in
+ 1111111111)
+ mailcheck=
+ if [ -f $MAIL ]; then
+ newsize="`set - \`wc -c $MAIL\`;echo $1`"
+ else
+ newsize=0
+ fi
+ if test "$newsize" -gt "$mailsize"; then
+ mailprompt="You have new mail"
+ else
+ mailprompt=
+ fi
+ mailsize=$newsize
+ ;;
+ *)
+ mailcheck=1$mailcheck
+ ;;
+ esac
+ ;;
+ esac
+ hist=no
+
+ case "$cmd" in
+ "")
+ continue
+ ;;
+ sh)
+ sh
+ run=no
+ ;;
+ !!)
+ cmd=$lastcmd
+ echoit=yes
+ getcmd=no
+ continue
+ ;;
+ *:p)
+ cmd="`expr \"$cmd\" : '\(.*\):p'` +~+p"
+ getcmd=no
+ continue
+ ;;
+ foreach[\ \ ]*)
+ while test "$line" != "end"; do
+ echo $n "$PS2$c"
+ read line
+ cmd="${cmd};$line"
+ done
+ echo "$cmd" > /tmp/bcsh$$
+ ed - /tmp/bcsh$$ << ++++
+ s/end/done/
+ s/foreach[ ]\(.*\)(/for \1 in /
+ s/)//
+ s/;/;do /
+ w
+++++
+ ;;
+ for[\ \ ]*|while[\ \ ]*)
+ # try to catch the most common cshell-to-Bourne-shell
+ # mistakes
+
+ echo $n "$PS2$c"
+ read line
+ case "$line" in
+ *do)
+ line="do :"
+ ;;
+ *do*)
+ ;;
+ *)
+ line="do $line"
+ ;;
+ esac
+
+ cmd="${cmd};$line"
+ while test "$line" != "done" && test "$line" != "end"
+ do
+ echo $n "$PS2$c"
+ read line
+ case "$line" in
+ end)
+ line=done
+ ;;
+ esac
+ cmd="${cmd};$line"
+ done
+ echo "$cmd" > /tmp/bcsh$$
+ ;;
+ if[\ \ ]*)
+ while test "$line" != "fi" && test "$line" != "endif"
+ do
+ echo $n "$PS2$c"
+ read line
+ case "$line" in
+ *[a-z]*then)
+ line="`expr \"$line\" : '\(.*\)then'`;then"
+ ;;
+ endif)
+ line=fi
+ ;;
+ esac
+ cmd="${cmd};$line"
+ done
+ echo "$cmd" > /tmp/bcsh$$
+ case "`grep then /tmp/bcsh$$`" in
+ "")
+ # fix 'if foo bar' cases
+
+ ed - /tmp/bcsh$$ << ++++
+ s/)/);then/
+ s/.*/;fi/
+ w
+++++
+ ;;
+ esac
+ ;;
+ case[\ \ ]*)
+ while test "$line" != "esac"
+ do
+ echo $n "$PS2$c"
+ read line
+ cmd="${cmd}@$line"
+ done
+ cmd="`echo \"$cmd\" | tr '@' ' '`"
+ echo "$cmd" > /tmp/bcsh$$
+ ;;
+ switch[\ \ ]*)
+ while test "$line" != "endsw"
+ do
+ echo $n "$PS2$c"
+ read line
+ cmd="${cmd}@$line"
+ done
+ echo "$cmd" > /tmp/bcsh$$
+ ed - /tmp/bcsh$$ << '++++'
+ 1,$s/@/\
+/g
+ g/switch.*(/s//case "/
+ s/)/" in/
+ 1,$s/case[ ]\(.*\):$/;;\
+ \1)/
+ 2d
+ 1,$s/endsw/;;\
+esac/
+ g/breaksw/s///
+ 1,$s/default.*/;;\
+ *)/
+ w
+++++
+ cmd="`cat /tmp/bcsh$$`"
+ ;;
+ *!*)
+ hist=yes
+ ;;
+ esac
+
+ case "$hist" in
+ yes)
+ # deal with genuine exclamation marks, go back and parse again
+
+ case "$cmd" in
+ *\>![\ \ ]*|*\\!*)
+ cmd="`echo \"$cmd\" | sed -e 's@\\!@REALEXCLAMATIONMARK@g'`"
+ exclaim=yes
+ getcmd=no
+ continue
+ ;;
+ esac
+
+ # break command into elements, parse each one
+
+ tmp=
+ for i in $cmd
+ do
+ # find element with !, peel off stuff up to !
+
+ case "$i" in
+ !)
+ # most likely a typo for !!, so fix it
+ front=
+ $i=!!
+ ;;
+ !!*)
+ front=
+ i="`expr \"$i\" : '.*\(!!.*\)'`"
+ ;;
+ *!!*)
+ front="`expr \"$i\" : '\(.*\)!!.*'`"
+ i="`expr \"$i\" : '.*\(!!.*\)'`"
+ ;;
+ !*)
+ front=
+ i="`expr \"$i\" : '.*!\(.*\)'`"
+ ;;
+ *)
+ tmp="$tmp$i "
+ continue
+ ;;
+ esac
+ case "$i" in
+ !!*)
+ # want last command
+
+ rest="`expr \"$i\" : '!!\(.*\)'`"
+ i=$lastcmd
+ ;;
+ -*)
+ # we want to search back through the history list
+
+ case "$i" in
+ -)
+ rest="`expr \"$i\" : '-\(.*\)'`"
+ i=$lastcmd
+ ;;
+ -[0-9]*)
+ wanted="`expr \"$i\" : '-\([0-9][0-9]*\).*'`"
+ rest="`expr \"$i\" : '-[0-9][0-9]*\(.*\)'`"
+ i="`tail -n $wanted $histfile | sed -e "1q"`"
+ ;;
+ esac
+ ;;
+ [0-9]*)
+ # find which number command is wanted
+
+ wanted="`expr \"$i\" : '\([0-9][0-9]*\).*'`"
+ rest="`expr \"$i\" : '[0-9][0-9]*\(.*\)'`"
+ i="`grep -n . $histfile | grep \"^$wanted\"`"
+ i="`expr \"$i\" : \"${wanted}.\(.*\)\"`"
+ ;;
+ \?*)
+
+ # find which 'command-contains' match is wanted
+
+ case "$i" in
+ \?{*}*)
+ wanted="`expr \"$i\" : '?{\(.*\)}.*'`"
+ rest="`expr \"$i\" : '?.*}\(.*\)'`"
+ ;;
+ \?*:*)
+ wanted="`expr \"$i\" : '?\(.*\):.*'`"
+ rest="`expr \"$i\" : '?.*\(:.*\)'`"
+ ;;
+ \?*)
+ wanted="`expr \"$i\" : '?\(.*\)'`"
+ rest=
+ ;;
+ esac
+ i="`grep \"$wanted\" $histfile | sed -n '$p'`"
+ ;;
+ *)
+ # find which 'start-of-command' match is wanted
+
+ case "$i" in
+ {*}*)
+ wanted="`expr \"$i\" : '{\(.*\)}.*'`"
+ rest="`expr \"$i\" : '.*}\(.*\)'`"
+ ;;
+ *:*)
+ wanted="`expr \"$i\" : '\(.*\):.*'`"
+ rest="`expr \"$i\" : '.*\(:.*\)'`"
+ ;;
+ *)
+ wanted="$i"
+ rest=
+ ;;
+ esac
+ i="`grep \"^$wanted\" $histfile | sed -n '$p'`"
+ ;;
+ esac
+
+ # see if we actually found anything to substitute
+
+ case "$i" in
+ "")
+ badsub="Event not found"
+ break
+ ;;
+ *)
+ badsub=no
+ ;;
+ esac
+
+ case "$rest" in
+ "")
+ tmp="$front$tmp$i "
+ continue
+ ;;
+ :[0-9]*)
+ # find which element of $i is wanted
+
+ number="`expr \"$rest\" : ':\([0-9][0-9]*\).*'`"
+ rest="`expr \"$rest\" : ':[0-9][0-9]*\(.*\)'`"
+
+ # count through $i till we get to the
+ # right element
+
+ counter=0
+ for element in $i
+ do
+ case "$counter" in
+ $number)
+ break
+ ;;
+ *)
+ counter="`expr \"$counter\" + 1`"
+ # counter=$[ $counter + 1 ]
+ ;;
+ esac
+ done
+ case "$counter" in
+ $number)
+ badsub=no
+ ;;
+ *)
+ badsub="Bad command element"
+ break
+ ;;
+ esac
+ tmp="$tmp$front$element$rest "
+ continue
+ ;;
+ :\$*)
+ # spin through $i till we hit the last element
+
+ rest="`expr \"$rest\" : ':\$\(.*\)'`"
+ for element in $i
+ do
+ :
+ done
+ tmp="$tmp$front$element$rest "
+ continue
+ ;;
+ :\**)
+ # we want all elements except the command itself
+
+ rest="`expr \"$rest\" : ':\*\(.*\)'`"
+ save=$i
+ set - $i
+ shift
+ case "$*" in
+ "")
+ badsub="No arguments to command '$save'"
+ break
+ ;;
+ *)
+ badsub=no
+ ;;
+ esac
+ tmp="$tmp$front$*$rest "
+ continue
+ ;;
+ :s*|:gs*)
+ # we are doing a substitution
+ # put / on end if needed
+
+ case "$rest" in
+ :s/*/*/*|:gs/*/*/*)
+ ;;
+ :s/*/*|:gs/*/*)
+ rest="${rest}/"
+ ;;
+ esac
+
+ # find what substitution is wanted
+
+ first="`expr \"$rest\" : ':*s\/\(.*\)\/.*\/.*'`"
+ second="`expr \"$i\" : ':*s/.*/\(.*\)/.*'`"
+
+ # see if it is a global substitution
+
+ case "$rest" in
+ :gs*)
+ global=g
+ ;;
+ :s*)
+ global=
+ ;;
+ esac
+ rest="`expr \"$rest\" : '.*/.*/.*/\(.*\)'`"
+ i="`echo \"$i\" | sed -e \"s@$first@$second@$global\"`"
+
+ # see if subsitution worked
+
+ case "$i" in
+ "")
+ badsub="Substiution failed"
+ break
+ ;;
+ *)
+ badsub=no
+ ;;
+ esac
+ tmp="$tmp$front$i$rest "
+ continue
+ ;;
+ *)
+ tmp="$tmp$front$i$rest "
+ ;;
+ esac
+ done
+ case "$badsub" in
+ no)
+ ;;
+ *)
+ echo "$badsub"
+ badsub=no
+ continue
+ ;;
+ esac
+ cmd="$tmp"
+ echoit=yes
+ getcmd=no
+ continue
+ ;;
+ *)
+ run=yes
+ ;;
+ esac
+
+ case "$cmd" in
+ *\^*\^*\^*)
+ # see if the substitution is global
+ case "$cmd" in
+ g*)
+ global=g
+ ;;
+ *)
+ global=
+ ;;
+ esac
+
+ # put a '^' on the end if necessary
+ case "$cmd" in
+ *\^)
+ ;;
+ *)
+ cmd="${cmd}^"
+ ;;
+ esac
+
+ # find what substitution is wanted
+
+ first="`expr \"$cmd\" : '*\^\(.*\)\^.*\^.*'`"
+ second="`expr \"$cmd\" : '*\^.*\^\(.*\)\^.*'`"
+ rest="`expr \"$cmd\" : '*\^.*\^.*\^\(.*\)'`"
+ cmd="`echo \"$lastcmd\" | sed -e \"s@$first@$second@$global\"`$rest"
+
+ # see if the substitution worked
+
+ case "$cmd" in
+ "")
+ echo "Substitution failed"
+ continue
+ ;;
+ esac
+ echoit=yes
+ getcmd=no
+ continue
+ ;;
+ *~e)
+ echo "$cmd" | sed -e "s@~e@@" > /tmp/bcsh$$
+ $EDITOR /tmp/bcsh$$
+ cmd="`cat /tmp/bcsh$$`"
+ getcmd=no
+ continue
+ ;;
+ *~v)
+ echo "$cmd" | sed -e "s@~v@@" > /tmp/bcsh$$
+ echo "$lastcmd" > /tmp/bcsh$$
+ $VISUAL /tmp/bcsh$$
+ cmd="`cat /tmp/bcsh$$`"
+ getcmd=no
+ continue
+ ;;
+ exec[\ \ ]*)
+ tail -n $savehist $histfile>/tmp/hist$$
+ uniq /tmp/hist$$ > $histfile
+ rm -f /tmp/*$$
+ echo $cmd > /tmp/cmd$$
+ . /tmp/cmd$$
+ ;;
+ login[\ \ ]*|newgrp[\ \ ]*)
+ tail -n $savehist $histfile>/tmp/hist$$
+ uniq /tmp/hist$$ > $histfile
+ rm -f /tmp/*$$
+ echo $cmd > /tmp/cmd$$
+ . /tmp/cmd$$
+ ;;
+ logout|exit|bye)
+ if test -s "$logoutfile"
+ then
+ # sh $logoutfile
+ $SHELL $logoutfile
+ fi
+ tail -n $savehist $histfile > /tmp/hist$$
+ uniq /tmp/hist$$ > $histfile
+ rm -f /tmp/*$$
+ exit 0
+ ;;
+ h|history)
+ grep -n . $histfile | tail -n $history | sed -e 's@:@ @' | $PAGER
+ continue
+ ;;
+ h[\ \ ]\|*|h[\ \ ]\>*|h\|*|h\>*)
+ cmd="`echo \"$cmd\" | sed -e \"s@h@grep -n . $histfile | tail -n $history | sed -e 's@:@ @'@\"`"
+ getcmd=no
+ continue
+ ;;
+ history[\ \ ]*\|*|history[\ \ ]*\>*)
+ cmd="`echo \"$cmd\" | sed -e \"s@history@grep -n . $histfile | tail -n $history | sed -e 's@:@ @'@\"`"
+ getcmd=no
+ continue
+ ;;
+ source[\ \ ]*)
+ set - $cmd
+ shift
+ echo . $* > /tmp/cmd$$
+ . /tmp/cmd$$
+ run=no
+ ;;
+ wait)
+ wait
+ run=no
+ ;;
+ .[\ \ ]*)
+ echo $cmd > /tmp/cmd$$
+ . /tmp/cmd$$
+ run=no
+ ;;
+ cd|cd[\ \ ]*)
+ # check if it will work first, or else this shell will terminate
+ # if the cd dies. If you have a built-in test, you might want
+ # to replace the try-it-and-see below with a couple of tests,
+ # but it is probably just as fast like this.
+
+ echo $cmd > /tmp/cmd$$
+ if ($SHELL /tmp/cmd$$) ; then
+ . /tmp/cmd$$
+ fi
+ run=no
+ ;;
+ awk[\ \ ]*|dd[\ \ ]*|cc[\ \ ]*|make[\ \ ]*)
+ # these are the only commands I can think of whose syntax
+ # includes an equals sign. Add others as you find them.
+
+ echo "$cmd" > /tmp/bcsh$$
+ ;;
+ setenv*|*=*)
+ # handle setting shell variables, turning cshell syntax to Bourne
+ # syntax -- note all variables must be exported or they will not
+ # be usable in other commands
+
+ echo "$cmd" > /tmp/cmd$$
+ ed - /tmp/cmd$$ << ++++
+ g/^setenv[ ]/s/[ ]/@/
+ g/^setenv@/s/[ ]/=/
+ g/^setenv@/s///
+ g/^set/s///
+ .t.
+ \$s/=.*//
+ s/^/export /
+ w
+++++
+ . /tmp/cmd$$
+ rm -f /tmp/cmd$$
+ run=no
+ ;;
+ unset[\ \ ]*|umask[\ \ ]*|export[\ \ ]*|set[\ \ ]*)
+ # handle commands which twiddle current environment
+
+ $cmd
+ run=no
+ ;;
+ alias|alias[\ \ ])
+ if [ -f $aliasfile ]; then
+ $PAGER $aliasfile
+ fi
+ lastcmd=$cmd
+ run=no
+ continue
+ ;;
+ alias[\ \ ]*)
+ case "$cmd" in
+ alias[\ \ ]\|*|alias[\ \ ]\>*)
+ cmd="`echo \"$cmd\" | sed -e \"s@alias@cat $aliasfile@\"`"
+ getcmd=no
+ continue
+ ;;
+ alias[\ \ ]*[\ \ ]*)
+ ;;
+ *)
+ echo "Syntax: alias name command"
+ cmd=
+ continue
+ ;;
+ esac
+ set - $cmd
+ shift
+ cmd="$*"
+
+ # make sure there is always 1 blank line in file so
+ # unaliasing will always work -- ed normally refuses
+ # to write an empty file
+ echo "" >> $aliasfile
+ cat << ++++ >> $aliasfile
+$cmd
+++++
+
+# ed - $aliasfile << '++++'
+# g/alias[ ]/s///
+# g/^['"]\(.*\)['"]$/s//\1/
+# g/^/s//alias /
+# w
+#++++
+
+ sort -u -o $aliasfile $aliasfile
+ doalias=yes
+ cmd="alias $cmd"
+ run=no
+ ;;
+ unalias[\ \ ]*)
+ set - $cmd
+ case "$#" in
+ 2)
+ cmd=$2
+ ;;
+ *)
+ echo "Syntax: unalias alias_name"
+ continue
+ ;;
+ esac
+ ed - $aliasfile << ++++
+ /^$cmd[ ]/d
+ w
+++++
+ case "`set - \`wc -l $aliasfile\`;echo $1`" in
+ 1)
+ # just removed last alias
+ doalias=no
+ ;;
+ esac
+ run=no
+ ;;
+ *)
+ case "$doalias" in
+ yes)
+ set - $cmd
+ tmp="`grep \"^$1 \" $aliasfile`"
+ case "$tmp" in
+ $1[\ \ ]*)
+ shift
+ cmd=$*
+ set - $tmp
+ shift
+ tmp=$*
+ case "$tmp" in
+ *\$*)
+ # uses positional variables
+
+ cmd="set - $cmd ; $tmp"
+ getcmd=no
+ continue
+ ;;
+ *)
+ cmd="$tmp $cmd"
+ getcmd=no
+ continue
+ ;;
+ esac
+ ;;
+ *)
+ echo "$cmd" > /tmp/bcsh$$
+ ;;
+ esac
+ ;;
+ no)
+ echo "$cmd" > /tmp/bcsh$$
+ ;;
+ esac
+ ;;
+ esac
+
+ case "$cmd" in
+ *+~+p)
+ cmd="`expr \"$cmd\" : '\(.*\)+~+p'`"
+ echoit=yes
+ run=no
+ ;;
+ esac
+
+ case "$cmd" in
+ "")
+ continue
+ ;;
+ *)
+ case "$exclaim" in
+ yes)
+ cmd="`echo \"$cmd\" | sed -e 's@REALEXCLAMATIONMARK@!@g'`"
+ echo "$cmd" > /tmp/bcsh$$
+ ;;
+ esac
+ case "$echoit" in
+ yes)
+ echo $cmd
+ ;;
+ esac
+ case "$run" in
+ yes)
+ case "${noclobber+yes}" in
+ yes)
+ case "$cmd" in
+ *\>![\ \ ]*)
+ ed - /tmp/bcsh$$ << ++++
+ g/>!/s//>/
+ w
+++++
+ ;;
+ *\>\>*)
+ ;;
+ *\>*)
+ outfile="`expr \"$cmd\" : '.*>\(.*\)'`"
+ case "$outfile" in
+ \&*)
+ ;;
+ *)
+ set - $outfile
+ outfile="$1"
+ if test -s "$outfile"
+ then
+ case "${iclobber+yes}" in
+ yes)
+ echo $n "Overwrite ${outfile}? $c"
+ read answer
+ case "$answer" in
+ y*)
+ ;;
+ *)
+ echo ':' > /tmp/bcsh$$
+ ;;
+ esac
+ ;;
+ *)
+ echo "${outfile}: file exists"
+ echo ':' > /tmp/bcsh$$
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ *)
+ case "$cmd" in
+ *\>![\ \ ]*)
+ ed - /tmp/bcsh$$ << ++++
+ g/>!/s//>/g
+ w
+++++
+ ;;
+ esac
+ ;;
+ esac
+ (trap 'exit 1' 2 3; $BASH /tmp/bcsh$$)
+ ;;
+ esac
+ case "$cmd" in
+ $lastcmd)
+ ;;
+ *)
+ case "$exclaim" in
+ yes)
+ cmd="`echo \"$cmd\" | sed -e 's@!@\\\\!@g'`"
+ ;;
+ esac
+
+ cat << ++++ >> $histfile
+$cmd
+++++
+ lastcmd=$cmd
+
+ case "$inc_cmdno" in
+ yes)
+ cmdno="`expr \"$cmdno\" + 1`"
+ # cmdno=$[$cmdno + 1]
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+
+ # The next commented-out line sets the prompt to include the command
+ # number -- you should only un-comment this if it is the ONLY thing
+ # you ever want as your prompt, because it will override attempts
+ # to set PS1 from the command level. If you want the command number
+ # in your prompt without sacrificing the ability to change the prompt
+ # later, replace the default setting for PS1 before the beginning of
+ # the main loop with the following: PS1='echo -n "${cmdno}% "'
+ # Doing it this way is, however, slower than the simple version below.
+
+ PS1="${cmdno}% "
+
+ getcmd=yes
+ echoit=no
+ exclaim=no
+done
+exit 0
+
+# Christine Robertson {linus, ihnp4, decvax}!utzoo!globetek!chris