Imported from ../bash-1.14.7.tar.gz.
[platform/upstream/bash.git] / examples / scripts / bcsh.sh
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
294 case "`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                 ;;
307 esac
308 history=${history-22}
309 savehist=${savehist-22}
310 histfile=${histfile-$HOME/.bhistory}
311 logoutfile=${logoutfile-$HOME/.blogout}
312 EDITOR=${EDITOR-ed}
313 VISUAL=${VISUAL-vi}
314 PAGER=${PAGER-more}
315
316 aliasfile=${aliasfile-$HOME/.baliases}
317
318 # the alias file may contain 1 blank line, so a test -s will not work
319
320 case "`cat $aliasfile 2> /dev/null`" in
321         "")
322                 doalias=no
323                 ;;
324         *)
325                 doalias=yes
326                 ;;
327 esac
328
329 if test -s "${sourcefile-$HOME/.bcshrc}"
330         then
331         . ${sourcefile-$HOME/.bcshrc}
332 fi
333
334 if test -s "$histfile"
335         then
336         cmdno="`set - \`wc -l $histfile\`;echo $1`"
337         cmdno="`expr \"$cmdno\" + 1`"
338         lastcmd="`tail -1 $histfile`"
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
352 else
353         cat /dev/null > $histfile
354         cmdno=1
355         lastcmd=
356 fi
357
358 # keep track of command number as the default
359
360 inc_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
365 case "$PS1" in
366         "")                                     
367                 PS1="% "
368                 ;;                              
369 esac
370 case "$PS2" in
371         "")                                     
372                 PS2="> "
373                 ;;                              
374 esac
375
376 export histfile savehist history aliasfile EDITOR VISUAL PAGER cmdno PS1 PS2
377
378 case "$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                 ;;
388 esac
389
390 trap ':' 2
391 trap exit 3
392 trap "tail -$savehist $histfile>/tmp/hist$$;uniq /tmp/hist$$ > $histfile;\
393 rm -f /tmp/*$$;exit 0" 15
394
395 getcmd=yes
396 mailcheck=
397 exclaim=
398 echoit=
399 mailprompt=
400
401 while :
402 do
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"
520                 while test "$line" != "done" -a "$line" != "end"
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[\ \  ]*)
534                 while test "$line" != "fi" -a "$line" != "endif"
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/;;\
588 esac/
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]*\(.*\)'`"
662                                         i="`tail -$wanted $histfile | sed -e "1q"`"
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
692                                 i="`grep \"$wanted\" $histfile | tail -1`"
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
711                                 i="`grep \"^$wanted\" $histfile | tail -1`"
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[\ \        ]*)
920                 tail -$savehist $histfile>/tmp/hist$$
921                 uniq /tmp/hist$$ > $histfile
922                 rm -f /tmp/*$$
923                 echo $cmd > /tmp/cmd$$
924                 . /tmp/cmd$$
925                 ;;
926         login[\ \       ]*|newgrp[\ \   ]*)
927                 tail -$savehist $histfile>/tmp/hist$$
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
939                 tail -$savehist $histfile > /tmp/hist$$
940                 uniq /tmp/hist$$ > $histfile
941                 rm -f /tmp/*$$
942                 exit 0
943                 ;;
944         h|history)
945                 grep -n . $histfile | tail -$history | sed -e 's@:@     @' | $PAGER
946                 continue
947                 ;;
948         h[\ \   ]\|*|h[\ \      ]\>*|h\|*|h\>*)
949                 cmd="`echo \"$cmd\" | sed -e \"s@h@grep -n . $histfile | tail -$history | sed -e 's@:@  @'@\"`"
950                 getcmd=no
951                 continue
952                 ;;
953         history[\ \     ]*\|*|history[\ \       ]*\>*)
954                 cmd="`echo \"$cmd\" | sed -e \"s@history@grep -n . $histfile | tail -$history | sed -e 's@:@ @'@\"`"
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
1251 done
1252 exit 0
1253
1254 # Christine Robertson  {linus, ihnp4, decvax}!utzoo!globetek!chris