]> git.ipfire.org Git - thirdparty/bash.git/blame - examples/scripts/bcsh.sh
Imported from ../bash-3.0.tar.gz.
[thirdparty/bash.git] / examples / scripts / bcsh.sh
CommitLineData
726f6388
JA
1# 1-Feb-86 09:37:35-MST,30567;000000000001
2# Return-Path: <unix-sources-request@BRL.ARPA>
3# Received: from BRL-TGR.ARPA by SIMTEL20.ARPA with TCP; Sat 1 Feb 86 09:36:16-MST
4# Received: from usenet by TGR.BRL.ARPA id a002623; 1 Feb 86 9:33 EST
5# From: chris <chris@globetek.uucp>
6# Newsgroups: net.sources
7# Subject: Improved Bcsh (Bourne Shell Cshell-Emulator)
8# Message-ID: <219@globetek.UUCP>
9# Date: 30 Jan 86 17:34:26 GMT
10# To: unix-sources@BRL-TGR.ARPA
11#
12# This is a new, improved version of my Bourne shell cshell-emulator.
13# The code has been cleaned up quite a bit, and a couple of new features
14# added (now supports 'noclobber' and 'iclobber' variables). A bug with
15# 'eval' that caused "illegal I/O" error messages on vanilla V7 shells has
16# also been fixed.
17
18# I have posted the program in its entirety because a context diff of the
19# old and new versions was longer than the new version...
20
21# --Chris
22# Bcsh -- A Simple Cshell-Like Command Pre-Processor For The Bourne Shell
23#
24# "Copyright (c) Chris Robertson, December 1985"
25#
26# This software may be used for any purpose provided the original
27# copyright notice and this notice are affixed thereto. No warranties of
28# any kind whatsoever are provided with this software, and it is hereby
29# understood that the author is not liable for any damagages arising
30# from the use of this software.
31#
32# Features Which the Cshell Does Not Have:
33# ----------------------------------------
34#
35# + command history persists across bcsh sessions
36# + global last-command editing via 'g^string1^string2^' syntax
37# + edit any command via $EDITOR or $VISUAL editors
38# + history file name, .bcshrc file name, alias file name, and number
39# of commands saved on termination can be set by environment variables
40# + prompt may evaluate commands, such as `pwd`, `date`, etc.
41# + the whole text of interactive 'for' and 'while' loops and 'if'
42# statements goes into the history list and may be re-run or edited
43# + multiple copies of commands and requests to see command history
44# are not added to the history list
45# + the history mechanism actually stores all commands entered in a
46# current session, not just $history of them. This means that you
47# can increase $history on the fly and at once have a larger history.
48#
49#
50# Synonyms:
51# ---------
52#
53# logout, exit, bye write out history file and exit
54# h, history show current history list
55#
56#
57# Aliases:
58# --------
59#
60# alias NAME CMND create an alias called NAME to run CMND
61# unalias NAME remove the alias NAME
62#
63# There are no 'current-session only' aliases -- all alias and unalias
64# commands are permanent, and stored in the $aliasfile.
65#
66# If an alias contains positional variables -- $1, $2, $*, etc. -- any
67# arguments following the alias name are considered to be values for
68# those variables, and the alias is turned into a command of the form
69# 'set - arguments;alias'. Otherwise, a simple substitution is performed
70# for the alias and the rest of the command preserved. The cshell
71# convention of using '\!:n' in an alias to get bits of the current
72# command is mercifully abandoned.
73#
74# Quotes are not necessary around the commands comprising an alias;
75# in fact, any enclosing quotes are stripped when the alias is added
76# to the file.
77#
78# A couple of typical aliases might be:
79#
80# goto cd $1;pwd
81# l ls -F
82#
83# Note that aliasing something to "commands;logout" will not work -- if
84# you want something to happen routinely on logout put it in the file
85# specified by $logoutfile, default = $HOME/.blogout.
86#
87#
88# Command Substitutions:
89# ----------------------
90#
91# !! substitute last command from history list
92# !!:N substitute Nth element of last command from
93# history list -- 0 = command name, 1 = 1st arg
94# !!:$ substitute last element of last command from
95# history list
96# !!:* substitute all arguments to last command
97# from history list
98# !NUMBER substitute command NUMBER from the history list
99# !NUMBER:N as above, but substitute Nth element, where
100# 0 = command name, 1 = 1st arg, etc.
101# !NUMBER:$ as above, but substitute last element
102# !NUMBER:* as above, but substitute all arguments
103# !-NUMBER substitute the command NUMBER lines from the
104# end of the history list; 1 = last command
105# !-NUMBER:N as above, but substitute Nth element, where
106# 0 = command name, 1 = 1st arg, etc.
107# !-NUMBER:$ as above, but substitute last element
108# !-NUMBER:* as above, but substitute all arguments
109# !?STRING substitute most-recent command from history list
110# containing STRING -- STRING must be enclosed in
111# braces if followed by any other characters
112# !?STRING:N as above, but substitute Nth element, where
113# 0 = command name, 1 = 1st arg, etc.
114# !?STRING:$ as above, but substitute last element
115# !?STRING:* as above, but substitute all arguments
116#
117#
118# Command Editing:
119# ----------------
120#
121# CMND~e edit CMND using $EDITOR, where CMND may be found
122# using a history substitution
123# CMND~v edit CMND using $VISUAL, where CMND may be found
124# using a history substitution
125# " ^string1^string2^ substitute string2 for string1 in last command"
126# command and run it
127# " g^string1^string2^ globally substitute string2 for string1 in "
128# last command and run it
129# !NUMBER:s/string1/string2/
130# substitute string2 for string1 in
131# command NUMBER and run it
132# !NUMBER:gs/string1/string2/
133# globally substitute string2 for string1 in
134# command NUMBER and run it
135# !?STRING:s/string1/string2/
136# substitute string2 for string1 in last command
137# containing STRING and run it
138# !?STRING:gs/string1/string2/
139# globally substitute string2 for string1 in last
140# command containing STRING and run it
141#
142# Any command which ends in the string ":p" is treated as a normal
143# command until all substitutions have been completed. The trailing
144# ":p" is then stripped, and the command is simply echoed and added to
145# the history list instead of being executed.
146#
147# None of the other colon extensions of the cshell are supported.
148#
149#
150# Shell Environment Variables:
151# ----------------------------
152#
153# EDITOR editor used by ~e command, default = "ed"
154# VISUAL editor used by ~v command, default = "vi"
155# MAIL your system mailbox
156# PAGER paging program used by history command, default = "more"
157# PS1 primary prompt
158# PS2 secondary prompt
159# history number of commands in history list, default = 22
160# histfile file history list is saved in, default = $HOME/.bhistory
161# savehist number of commands remembered from last bcsh session
162# aliasfile file of aliased commands, default = $HOME/.baliases
163# logoutfile file of commands to be executed before termination
164# inc_cmdno yes/no -- keep track of command numbers or not
165# noclobber if set, existing files are not overwritten by '>'
166# iclobber if both noclobber and iclobber are set, the user is
167# prompted for confirmation before existing files are
168# overwritten by '>'
169#
170# Note: if you are setting either noclobber or iclobber mid-session,
171# set them to 'yes'
172#
173#
174# Regular Shell Variables:
175# ------------------------
176#
177# Shell variables may be set via Bourne or cshell syntax, e.g., both
178# "set foo=bar" and "foo=bar" set a variable called "foo" with the value
179# "bar". However, all variables are automatically set as environment
180# variables, so there is no need to export them. Conversely, there
181# are NO local variables. Sorry, folks.
182#
183# A cshell-style "setenv" command is turned into a regular "set" command.
184#
185#
186# The Prompt:
187# ----------
188#
189# You may, if you wish, have a command executed in your prompt. If
190# the variable PS1 contains a dollar sign or a backquote, it is
191# evaluated and the result used as the prompt, provided the evaluation
192# did not produce a "not found" error message. The two special cases
193# of PS1 consisting solely of "$" or "$ " are handled correctly. For
194# example, to have the prompt contain the current directory followed
195# by a space, enter:
196#
197# PS1=\'echo "`pwd` "\'
198#
199# You need the backslashed single quotes to prevent the command being
200# evaluated by the variable-setting mechanism and the shell before it
201# is assigned to PS1.
202#
203# To include the command number in your prompt, enter the command:
204#
205# PS1=\'echo "$cmdno "\'
206#
207#
208# Shell Control-Flow Syntax:
209# --------------------------
210#
211# 'While', 'for', 'case', and 'if' commands entered in Bourne shell
212# syntax are executed as normal.
213#
214# A valiant attempt is made to convert 'foreach' loops into 'for' loops,
215# cshell-syntax 'while' loops into Bourne shell syntax, and 'switch'
216# statements into 'case' statements. I cannot guarantee to always get it
217# right. If you forget the 'do' in a 'while' or 'for' loop, or finish
218# them with 'end' instead of 'done', this will be corrected.
219#
220# Note that cshell-to-Bourne control flow conversions do not take place
221# if control is nested -- e.g., a 'foreach' inside a 'while' will fail.
222#
223# The simple-case cshell "if (condition) command" is turned into Bourne
224# syntax. Other 'if' statements are left alone apart from making the
225# 'then' a separate statement, because constructing a valid interactive
226# cshell 'if' statement is essentially an exercise in frustration anyway.
227# The cshell and Bourne shell have sufficiently different ideas about
228# conditions that if is probably best to resign yourself to learning
229# the Bourne shell conventions.
230#
231# Note that since most of the testing built-ins of the cshell are
232# not available in the Bourne shell, a complex condition in a 'while'
233# loop or an 'if' statement will probably fail.
234#
235#
236# Bugs, Caveats, etc.:
237# --------------------
238#
239# This is not a super-speedy program. Be patient, especially on startup.
240#
241# To the best of my knowledge this program should work on ANY Bourne
242# shell -- note that if your shell does not understand 'echo -n' you
243# will have to re-set the values of '$n' and '$c'.
244#
245# This program may run out of stack space on a 16-bit machine where
246# /bin/sh is not split-space.
247#
248# Mail checking is done every 10 commands if $MAIL is set in your
249# environment. For anything fancier, you will have to hack the code.
250#
251# Because commands are stuffed in a file before sh is invoked on them,
252# error messages from failed commands are ugly.
253#
254# Failed history substitutions either give nothing at all, or a
255# "not found" style of error message.
256#
257# A command history is kept whether you want it or not. This may be
258# perceived as a bug or a feature, depending on which side of bed you
259# got out on.
260#
261# If you want a real backslash in a command, you will have to type two
262# of them because the shell swallows the first backslash in the initial
263# command pickup. This means that to include a non-history '!' in a
264# command you need '\\!' -- a real wart, especially for net mail,
265# but unavoidable.
266#
267# Commands containing an '@' will break all sorts of things.
268#
269# Very complex history substitutions may fail.
270#
271# File names containing numbers may break numeric history sustitutions.
272#
273# Commands containing bizzare sequences of characters may conflict
274# with internal kludges.
275#
276# Aliasing something to "commands;logout" will not work -- if you
277# want something to happen routinely on logout, put it in the file
278# specified by $logoutfile, default = $HOME/.blogout.
279#
280# Please send all bug reports to ihnp4!utzoo!globetek!chris.
281# Flames will be posted to net.general with 'Reply-to' set to your
282# ' path... :-) '
283#
284#
285#
286# ************* VERY IMPORTANT NOTICE *************
287#
288# If your shell supports # comments, then REPLACE all the colon 'comments'
289# with # comments. If it does not, then REMOVE all the 'comment' lines from the
290# working copy of the file, as it will run MUCH faster -- the shell evaluates
291# lines starting with a colon but does not actually execute them, so you will
292# save the read-and-evaluate time by removing them.
293
294case "`echo -n foo`" in
295 -n*)
296 n=
297 c="\c"
298 ;;
299 foo)
300 n=-n
301 c=
302 ;;
303 *)
304 echo "Your 'echo' command is broken."
305 exit 1
306 ;;
307esac
308history=${history-22}
309savehist=${savehist-22}
310histfile=${histfile-$HOME/.bhistory}
311logoutfile=${logoutfile-$HOME/.blogout}
312EDITOR=${EDITOR-ed}
313VISUAL=${VISUAL-vi}
314PAGER=${PAGER-more}
315
316aliasfile=${aliasfile-$HOME/.baliases}
317
318# the alias file may contain 1 blank line, so a test -s will not work
319
320case "`cat $aliasfile 2> /dev/null`" in
321 "")
322 doalias=no
323 ;;
324 *)
325 doalias=yes
326 ;;
327esac
328
329if test -s "${sourcefile-$HOME/.bcshrc}"
330 then
331 . ${sourcefile-$HOME/.bcshrc}
332fi
333
334if test -s "$histfile"
335 then
336 cmdno="`set - \`wc -l $histfile\`;echo $1`"
337 cmdno="`expr \"$cmdno\" + 1`"
7117c2d2 338 lastcmd="`sed -n '$p' $histfile`"
726f6388
JA
339 copy=false
340 ohist=$histfile
341 while test ! -w "$histfile"
342 do
343 echo "Cannot write to history file '$histfile'."
344 echo $n "Please enter a new history filename: $c"
345 read histfile
346 copy=true
347 done
348 if $copy
349 then
350 cp $ohist $histfile
351 fi
352else
353 cat /dev/null > $histfile
354 cmdno=1
355 lastcmd=
356fi
357
358# keep track of command number as the default
359
360inc_cmdno=${inc_cmdo-yes}
361
362# default prompts -- PS1 and PS2 may be SET but EMPTY, so '${PS1-% }' syntax
363# is not used here
364
365case "$PS1" in
366 "")
367 PS1="% "
368 ;;
369esac
370case "$PS2" in
371 "")
372 PS2="> "
373 ;;
374esac
375
376export histfile savehist history aliasfile EDITOR VISUAL PAGER cmdno PS1 PS2
377
378case "$MAIL" in
379 "")
380 ;;
381 *)
382 if [ -f $MAIL ]; then
383 mailsize=`set - \`wc -c $MAIL\`;echo $1`
384 else
385 mailsize=0
386 fi
387 ;;
388esac
389
390trap ':' 2
391trap exit 3
b80f6443 392trap "tail -n $savehist $histfile>/tmp/hist$$;uniq /tmp/hist$$ > $histfile;\
726f6388
JA
393rm -f /tmp/*$$;exit 0" 15
394
395getcmd=yes
396mailcheck=
397exclaim=
398echoit=
399mailprompt=
400
401while :
402do
403
404 run=yes
405 case "$mailprompt" in
406 "")
407 ;;
408 *)
409 echo "$mailprompt"
410 ;;
411 esac
412 case "$getcmd" in
413 yes)
414 : guess if the prompt should be evaluated or not
415 case "$PS1" in
416 \$|\$\ )
417 echo $n "$PS1$c"
418 ;;
419 *\`*|*\$*)
420 tmp="`(eval $PS1) 2>&1`"
421 case "$tmp" in
422 *not\ found)
423 echo $n "$PS1$c"
424 ;;
425 *)
426 echo $n "$tmp$c"
427 ;;
428 esac
429 ;;
430 *)
431 echo $n "$PS1$c"
432 ;;
433 esac
434
435 read cmd || cmd="exit"
436 ;;
437 *) ;;
438 esac
439
440 case "$MAIL" in
441 "")
442 ;;
443 *)
444 : check for mail every 10 commands
445 case "$mailcheck" in
446 1111111111)
447 mailcheck=
448 if [ -f $MAIL ]; then
449 newsize="`set - \`wc -c $MAIL\`;echo $1`"
450 else
451 newsize=0
452 fi
453 if test "$newsize" -gt "$mailsize"; then
454 mailprompt="You have new mail"
455 else
456 mailprompt=
457 fi
458 mailsize=$newsize
459 ;;
460 *)
461 mailcheck=1$mailcheck
462 ;;
463 esac
464 ;;
465 esac
466 hist=no
467
468 case "$cmd" in
469 "")
470 continue
471 ;;
472 sh)
473 sh
474 run=no
475 ;;
476 !!)
477 cmd=$lastcmd
478 echoit=yes
479 getcmd=no
480 continue
481 ;;
482 *:p)
483 cmd="`expr \"$cmd\" : '\(.*\):p'` +~+p"
484 getcmd=no
485 continue
486 ;;
487 foreach[\ \ ]*)
488 while test "$line" != "end"; do
489 echo $n "$PS2$c"
490 read line
491 cmd="${cmd};$line"
492 done
493 echo "$cmd" > /tmp/bcsh$$
494 ed - /tmp/bcsh$$ << ++++
495 s/end/done/
496 s/foreach[ ]\(.*\)(/for \1 in /
497 s/)//
498 s/;/;do /
499 w
500++++
501 ;;
502 for[\ \ ]*|while[\ \ ]*)
503 # try to catch the most common cshell-to-Bourne-shell
504 # mistakes
505
506 echo $n "$PS2$c"
507 read line
508 case "$line" in
509 *do)
510 line="do :"
511 ;;
512 *do*)
513 ;;
514 *)
515 line="do $line"
516 ;;
517 esac
518
519 cmd="${cmd};$line"
b80f6443 520 while test "$line" != "done" && test "$line" != "end"
726f6388
JA
521 do
522 echo $n "$PS2$c"
523 read line
524 case "$line" in
525 end)
526 line=done
527 ;;
528 esac
529 cmd="${cmd};$line"
530 done
531 echo "$cmd" > /tmp/bcsh$$
532 ;;
533 if[\ \ ]*)
b80f6443 534 while test "$line" != "fi" && test "$line" != "endif"
726f6388
JA
535 do
536 echo $n "$PS2$c"
537 read line
538 case "$line" in
539 *[a-z]*then)
540 line="`expr \"$line\" : '\(.*\)then'`;then"
541 ;;
542 endif)
543 line=fi
544 ;;
545 esac
546 cmd="${cmd};$line"
547 done
548 echo "$cmd" > /tmp/bcsh$$
549 case "`grep then /tmp/bcsh$$`" in
550 "")
551 # fix 'if foo bar' cases
552
553 ed - /tmp/bcsh$$ << ++++
554 s/)/);then/
555 s/.*/;fi/
556 w
557++++
558 ;;
559 esac
560 ;;
561 case[\ \ ]*)
562 while test "$line" != "esac"
563 do
564 echo $n "$PS2$c"
565 read line
566 cmd="${cmd}@$line"
567 done
568 cmd="`echo \"$cmd\" | tr '@' ' '`"
569 echo "$cmd" > /tmp/bcsh$$
570 ;;
571 switch[\ \ ]*)
572 while test "$line" != "endsw"
573 do
574 echo $n "$PS2$c"
575 read line
576 cmd="${cmd}@$line"
577 done
578 echo "$cmd" > /tmp/bcsh$$
579 ed - /tmp/bcsh$$ << '++++'
580 1,$s/@/\
581/g
582 g/switch.*(/s//case "/
583 s/)/" in/
584 1,$s/case[ ]\(.*\):$/;;\
585 \1)/
586 2d
587 1,$s/endsw/;;\
588esac/
589 g/breaksw/s///
590 1,$s/default.*/;;\
591 *)/
592 w
593++++
594 cmd="`cat /tmp/bcsh$$`"
595 ;;
596 *!*)
597 hist=yes
598 ;;
599 esac
600
601 case "$hist" in
602 yes)
603 # deal with genuine exclamation marks, go back and parse again
604
605 case "$cmd" in
606 *\>![\ \ ]*|*\\!*)
607 cmd="`echo \"$cmd\" | sed -e 's@\\!@REALEXCLAMATIONMARK@g'`"
608 exclaim=yes
609 getcmd=no
610 continue
611 ;;
612 esac
613
614 # break command into elements, parse each one
615
616 tmp=
617 for i in $cmd
618 do
619 # find element with !, peel off stuff up to !
620
621 case "$i" in
622 !)
623 # most likely a typo for !!, so fix it
624 front=
625 $i=!!
626 ;;
627 !!*)
628 front=
629 i="`expr \"$i\" : '.*\(!!.*\)'`"
630 ;;
631 *!!*)
632 front="`expr \"$i\" : '\(.*\)!!.*'`"
633 i="`expr \"$i\" : '.*\(!!.*\)'`"
634 ;;
635 !*)
636 front=
637 i="`expr \"$i\" : '.*!\(.*\)'`"
638 ;;
639 *)
640 tmp="$tmp$i "
641 continue
642 ;;
643 esac
644 case "$i" in
645 !!*)
646 # want last command
647
648 rest="`expr \"$i\" : '!!\(.*\)'`"
649 i=$lastcmd
650 ;;
651 -*)
652 # we want to search back through the history list
653
654 case "$i" in
655 -)
656 rest="`expr \"$i\" : '-\(.*\)'`"
657 i=$lastcmd
658 ;;
659 -[0-9]*)
660 wanted="`expr \"$i\" : '-\([0-9][0-9]*\).*'`"
661 rest="`expr \"$i\" : '-[0-9][0-9]*\(.*\)'`"
b80f6443 662 i="`tail -n $wanted $histfile | sed -e "1q"`"
726f6388
JA
663 ;;
664 esac
665 ;;
666 [0-9]*)
667 # find which number command is wanted
668
669 wanted="`expr \"$i\" : '\([0-9][0-9]*\).*'`"
670 rest="`expr \"$i\" : '[0-9][0-9]*\(.*\)'`"
671 i="`grep -n . $histfile | grep \"^$wanted\"`"
672 i="`expr \"$i\" : \"${wanted}.\(.*\)\"`"
673 ;;
674 \?*)
675
676 # find which 'command-contains' match is wanted
677
678 case "$i" in
679 \?{*}*)
680 wanted="`expr \"$i\" : '?{\(.*\)}.*'`"
681 rest="`expr \"$i\" : '?.*}\(.*\)'`"
682 ;;
683 \?*:*)
684 wanted="`expr \"$i\" : '?\(.*\):.*'`"
685 rest="`expr \"$i\" : '?.*\(:.*\)'`"
686 ;;
687 \?*)
688 wanted="`expr \"$i\" : '?\(.*\)'`"
689 rest=
690 ;;
691 esac
7117c2d2 692 i="`grep \"$wanted\" $histfile | sed -n '$p'`"
726f6388
JA
693 ;;
694 *)
695 # find which 'start-of-command' match is wanted
696
697 case "$i" in
698 {*}*)
699 wanted="`expr \"$i\" : '{\(.*\)}.*'`"
700 rest="`expr \"$i\" : '.*}\(.*\)'`"
701 ;;
702 *:*)
703 wanted="`expr \"$i\" : '\(.*\):.*'`"
704 rest="`expr \"$i\" : '.*\(:.*\)'`"
705 ;;
706 *)
707 wanted="$i"
708 rest=
709 ;;
710 esac
7117c2d2 711 i="`grep \"^$wanted\" $histfile | sed -n '$p'`"
726f6388
JA
712 ;;
713 esac
714
715 # see if we actually found anything to substitute
716
717 case "$i" in
718 "")
719 badsub="Event not found"
720 break
721 ;;
722 *)
723 badsub=no
724 ;;
725 esac
726
727 case "$rest" in
728 "")
729 tmp="$front$tmp$i "
730 continue
731 ;;
732 :[0-9]*)
733 # find which element of $i is wanted
734
735 number="`expr \"$rest\" : ':\([0-9][0-9]*\).*'`"
736 rest="`expr \"$rest\" : ':[0-9][0-9]*\(.*\)'`"
737
738 # count through $i till we get to the
739 # right element
740
741 counter=0
742 for element in $i
743 do
744 case "$counter" in
745 $number)
746 break
747 ;;
748 *)
749 counter="`expr \"$counter\" + 1`"
750 # counter=$[ $counter + 1 ]
751 ;;
752 esac
753 done
754 case "$counter" in
755 $number)
756 badsub=no
757 ;;
758 *)
759 badsub="Bad command element"
760 break
761 ;;
762 esac
763 tmp="$tmp$front$element$rest "
764 continue
765 ;;
766 :\$*)
767 # spin through $i till we hit the last element
768
769 rest="`expr \"$rest\" : ':\$\(.*\)'`"
770 for element in $i
771 do
772 :
773 done
774 tmp="$tmp$front$element$rest "
775 continue
776 ;;
777 :\**)
778 # we want all elements except the command itself
779
780 rest="`expr \"$rest\" : ':\*\(.*\)'`"
781 save=$i
782 set - $i
783 shift
784 case "$*" in
785 "")
786 badsub="No arguments to command '$save'"
787 break
788 ;;
789 *)
790 badsub=no
791 ;;
792 esac
793 tmp="$tmp$front$*$rest "
794 continue
795 ;;
796 :s*|:gs*)
797 # we are doing a substitution
798 # put / on end if needed
799
800 case "$rest" in
801 :s/*/*/*|:gs/*/*/*)
802 ;;
803 :s/*/*|:gs/*/*)
804 rest="${rest}/"
805 ;;
806 esac
807
808 # find what substitution is wanted
809
810 first="`expr \"$rest\" : ':*s\/\(.*\)\/.*\/.*'`"
811 second="`expr \"$i\" : ':*s/.*/\(.*\)/.*'`"
812
813 # see if it is a global substitution
814
815 case "$rest" in
816 :gs*)
817 global=g
818 ;;
819 :s*)
820 global=
821 ;;
822 esac
823 rest="`expr \"$rest\" : '.*/.*/.*/\(.*\)'`"
824 i="`echo \"$i\" | sed -e \"s@$first@$second@$global\"`"
825
826 # see if subsitution worked
827
828 case "$i" in
829 "")
830 badsub="Substiution failed"
831 break
832 ;;
833 *)
834 badsub=no
835 ;;
836 esac
837 tmp="$tmp$front$i$rest "
838 continue
839 ;;
840 *)
841 tmp="$tmp$front$i$rest "
842 ;;
843 esac
844 done
845 case "$badsub" in
846 no)
847 ;;
848 *)
849 echo "$badsub"
850 badsub=no
851 continue
852 ;;
853 esac
854 cmd="$tmp"
855 echoit=yes
856 getcmd=no
857 continue
858 ;;
859 *)
860 run=yes
861 ;;
862 esac
863
864 case "$cmd" in
865 *\^*\^*\^*)
866 # see if the substitution is global
867 case "$cmd" in
868 g*)
869 global=g
870 ;;
871 *)
872 global=
873 ;;
874 esac
875
876 # put a '^' on the end if necessary
877 case "$cmd" in
878 *\^)
879 ;;
880 *)
881 cmd="${cmd}^"
882 ;;
883 esac
884
885 # find what substitution is wanted
886
887 first="`expr \"$cmd\" : '*\^\(.*\)\^.*\^.*'`"
888 second="`expr \"$cmd\" : '*\^.*\^\(.*\)\^.*'`"
889 rest="`expr \"$cmd\" : '*\^.*\^.*\^\(.*\)'`"
890 cmd="`echo \"$lastcmd\" | sed -e \"s@$first@$second@$global\"`$rest"
891
892 # see if the substitution worked
893
894 case "$cmd" in
895 "")
896 echo "Substitution failed"
897 continue
898 ;;
899 esac
900 echoit=yes
901 getcmd=no
902 continue
903 ;;
904 *~e)
905 echo "$cmd" | sed -e "s@~e@@" > /tmp/bcsh$$
906 $EDITOR /tmp/bcsh$$
907 cmd="`cat /tmp/bcsh$$`"
908 getcmd=no
909 continue
910 ;;
911 *~v)
912 echo "$cmd" | sed -e "s@~v@@" > /tmp/bcsh$$
913 echo "$lastcmd" > /tmp/bcsh$$
914 $VISUAL /tmp/bcsh$$
915 cmd="`cat /tmp/bcsh$$`"
916 getcmd=no
917 continue
918 ;;
919 exec[\ \ ]*)
b80f6443 920 tail -n $savehist $histfile>/tmp/hist$$
726f6388
JA
921 uniq /tmp/hist$$ > $histfile
922 rm -f /tmp/*$$
923 echo $cmd > /tmp/cmd$$
924 . /tmp/cmd$$
925 ;;
926 login[\ \ ]*|newgrp[\ \ ]*)
b80f6443 927 tail -n $savehist $histfile>/tmp/hist$$
726f6388
JA
928 uniq /tmp/hist$$ > $histfile
929 rm -f /tmp/*$$
930 echo $cmd > /tmp/cmd$$
931 . /tmp/cmd$$
932 ;;
933 logout|exit|bye)
934 if test -s "$logoutfile"
935 then
936 # sh $logoutfile
937 $SHELL $logoutfile
938 fi
b80f6443 939 tail -n $savehist $histfile > /tmp/hist$$
726f6388
JA
940 uniq /tmp/hist$$ > $histfile
941 rm -f /tmp/*$$
942 exit 0
943 ;;
944 h|history)
b80f6443 945 grep -n . $histfile | tail -n $history | sed -e 's@:@ @' | $PAGER
726f6388
JA
946 continue
947 ;;
948 h[\ \ ]\|*|h[\ \ ]\>*|h\|*|h\>*)
b80f6443 949 cmd="`echo \"$cmd\" | sed -e \"s@h@grep -n . $histfile | tail -n $history | sed -e 's@:@ @'@\"`"
726f6388
JA
950 getcmd=no
951 continue
952 ;;
953 history[\ \ ]*\|*|history[\ \ ]*\>*)
b80f6443 954 cmd="`echo \"$cmd\" | sed -e \"s@history@grep -n . $histfile | tail -n $history | sed -e 's@:@ @'@\"`"
726f6388
JA
955 getcmd=no
956 continue
957 ;;
958 source[\ \ ]*)
959 set - $cmd
960 shift
961 echo . $* > /tmp/cmd$$
962 . /tmp/cmd$$
963 run=no
964 ;;
965 wait)
966 wait
967 run=no
968 ;;
969 .[\ \ ]*)
970 echo $cmd > /tmp/cmd$$
971 . /tmp/cmd$$
972 run=no
973 ;;
974 cd|cd[\ \ ]*)
975 # check if it will work first, or else this shell will terminate
976 # if the cd dies. If you have a built-in test, you might want
977 # to replace the try-it-and-see below with a couple of tests,
978 # but it is probably just as fast like this.
979
980 echo $cmd > /tmp/cmd$$
981 if ($SHELL /tmp/cmd$$) ; then
982 . /tmp/cmd$$
983 fi
984 run=no
985 ;;
986 awk[\ \ ]*|dd[\ \ ]*|cc[\ \ ]*|make[\ \ ]*)
987 # these are the only commands I can think of whose syntax
988 # includes an equals sign. Add others as you find them.
989
990 echo "$cmd" > /tmp/bcsh$$
991 ;;
992 setenv*|*=*)
993 # handle setting shell variables, turning cshell syntax to Bourne
994 # syntax -- note all variables must be exported or they will not
995 # be usable in other commands
996
997 echo "$cmd" > /tmp/cmd$$
998 ed - /tmp/cmd$$ << ++++
999 g/^setenv[ ]/s/[ ]/@/
1000 g/^setenv@/s/[ ]/=/
1001 g/^setenv@/s///
1002 g/^set/s///
1003 .t.
1004 \$s/=.*//
1005 s/^/export /
1006 w
1007++++
1008 . /tmp/cmd$$
1009 rm -f /tmp/cmd$$
1010 run=no
1011 ;;
1012 unset[\ \ ]*|umask[\ \ ]*|export[\ \ ]*|set[\ \ ]*)
1013 # handle commands which twiddle current environment
1014
1015 $cmd
1016 run=no
1017 ;;
1018 alias|alias[\ \ ])
1019 if [ -f $aliasfile ]; then
1020 $PAGER $aliasfile
1021 fi
1022 lastcmd=$cmd
1023 run=no
1024 continue
1025 ;;
1026 alias[\ \ ]*)
1027 case "$cmd" in
1028 alias[\ \ ]\|*|alias[\ \ ]\>*)
1029 cmd="`echo \"$cmd\" | sed -e \"s@alias@cat $aliasfile@\"`"
1030 getcmd=no
1031 continue
1032 ;;
1033 alias[\ \ ]*[\ \ ]*)
1034 ;;
1035 *)
1036 echo "Syntax: alias name command"
1037 cmd=
1038 continue
1039 ;;
1040 esac
1041 set - $cmd
1042 shift
1043 cmd="$*"
1044
1045 # make sure there is always 1 blank line in file so
1046 # unaliasing will always work -- ed normally refuses
1047 # to write an empty file
1048 echo "" >> $aliasfile
1049 cat << ++++ >> $aliasfile
1050$cmd
1051++++
1052
1053# ed - $aliasfile << '++++'
1054# g/alias[ ]/s///
1055# g/^['"]\(.*\)['"]$/s//\1/
1056# g/^/s//alias /
1057# w
1058#++++
1059
1060 sort -u -o $aliasfile $aliasfile
1061 doalias=yes
1062 cmd="alias $cmd"
1063 run=no
1064 ;;
1065 unalias[\ \ ]*)
1066 set - $cmd
1067 case "$#" in
1068 2)
1069 cmd=$2
1070 ;;
1071 *)
1072 echo "Syntax: unalias alias_name"
1073 continue
1074 ;;
1075 esac
1076 ed - $aliasfile << ++++
1077 /^$cmd[ ]/d
1078 w
1079++++
1080 case "`set - \`wc -l $aliasfile\`;echo $1`" in
1081 1)
1082 # just removed last alias
1083 doalias=no
1084 ;;
1085 esac
1086 run=no
1087 ;;
1088 *)
1089 case "$doalias" in
1090 yes)
1091 set - $cmd
1092 tmp="`grep \"^$1 \" $aliasfile`"
1093 case "$tmp" in
1094 $1[\ \ ]*)
1095 shift
1096 cmd=$*
1097 set - $tmp
1098 shift
1099 tmp=$*
1100 case "$tmp" in
1101 *\$*)
1102 # uses positional variables
1103
1104 cmd="set - $cmd ; $tmp"
1105 getcmd=no
1106 continue
1107 ;;
1108 *)
1109 cmd="$tmp $cmd"
1110 getcmd=no
1111 continue
1112 ;;
1113 esac
1114 ;;
1115 *)
1116 echo "$cmd" > /tmp/bcsh$$
1117 ;;
1118 esac
1119 ;;
1120 no)
1121 echo "$cmd" > /tmp/bcsh$$
1122 ;;
1123 esac
1124 ;;
1125 esac
1126
1127 case "$cmd" in
1128 *+~+p)
1129 cmd="`expr \"$cmd\" : '\(.*\)+~+p'`"
1130 echoit=yes
1131 run=no
1132 ;;
1133 esac
1134
1135 case "$cmd" in
1136 "")
1137 continue
1138 ;;
1139 *)
1140 case "$exclaim" in
1141 yes)
1142 cmd="`echo \"$cmd\" | sed -e 's@REALEXCLAMATIONMARK@!@g'`"
1143 echo "$cmd" > /tmp/bcsh$$
1144 ;;
1145 esac
1146 case "$echoit" in
1147 yes)
1148 echo $cmd
1149 ;;
1150 esac
1151 case "$run" in
1152 yes)
1153 case "${noclobber+yes}" in
1154 yes)
1155 case "$cmd" in
1156 *\>![\ \ ]*)
1157 ed - /tmp/bcsh$$ << ++++
1158 g/>!/s//>/
1159 w
1160++++
1161 ;;
1162 *\>\>*)
1163 ;;
1164 *\>*)
1165 outfile="`expr \"$cmd\" : '.*>\(.*\)'`"
1166 case "$outfile" in
1167 \&*)
1168 ;;
1169 *)
1170 set - $outfile
1171 outfile="$1"
1172 if test -s "$outfile"
1173 then
1174 case "${iclobber+yes}" in
1175 yes)
1176 echo $n "Overwrite ${outfile}? $c"
1177 read answer
1178 case "$answer" in
1179 y*)
1180 ;;
1181 *)
1182 echo ':' > /tmp/bcsh$$
1183 ;;
1184 esac
1185 ;;
1186 *)
1187 echo "${outfile}: file exists"
1188 echo ':' > /tmp/bcsh$$
1189 ;;
1190 esac
1191 fi
1192 ;;
1193 esac
1194 ;;
1195 esac
1196 ;;
1197 *)
1198 case "$cmd" in
1199 *\>![\ \ ]*)
1200 ed - /tmp/bcsh$$ << ++++
1201 g/>!/s//>/g
1202 w
1203++++
1204 ;;
1205 esac
1206 ;;
1207 esac
1208 (trap 'exit 1' 2 3; $BASH /tmp/bcsh$$)
1209 ;;
1210 esac
1211 case "$cmd" in
1212 $lastcmd)
1213 ;;
1214 *)
1215 case "$exclaim" in
1216 yes)
1217 cmd="`echo \"$cmd\" | sed -e 's@!@\\\\!@g'`"
1218 ;;
1219 esac
1220
1221 cat << ++++ >> $histfile
1222$cmd
1223++++
1224 lastcmd=$cmd
1225
1226 case "$inc_cmdno" in
1227 yes)
1228 cmdno="`expr \"$cmdno\" + 1`"
1229 # cmdno=$[$cmdno + 1]
1230 ;;
1231 esac
1232 ;;
1233 esac
1234 ;;
1235 esac
1236
1237 # The next commented-out line sets the prompt to include the command
1238 # number -- you should only un-comment this if it is the ONLY thing
1239 # you ever want as your prompt, because it will override attempts
1240 # to set PS1 from the command level. If you want the command number
1241 # in your prompt without sacrificing the ability to change the prompt
1242 # later, replace the default setting for PS1 before the beginning of
1243 # the main loop with the following: PS1='echo -n "${cmdno}% "'
1244 # Doing it this way is, however, slower than the simple version below.
1245
1246 PS1="${cmdno}% "
1247
1248 getcmd=yes
1249 echoit=no
1250 exclaim=no
1251done
1252exit 0
1253
1254# Christine Robertson {linus, ihnp4, decvax}!utzoo!globetek!chris