1#!/bin/bash
2#	ash -- "Adventure shell"
3#	last edit:	86/04/21	D A Gwyn
4#	SCCS ID:	@(#)ash.sh	1.4
5
6OPATH=$PATH
7
8ask()
9{
10	echo -n "$@" '[y/n] '
11	read ans
12
13	case "$ans" in
14	y*|Y*)
15		return 0
16		;;
17	*)
18		return 1
19		;;
20	esac
21}
22	
23CAT=${PAGER:-more}
24
25ash_inst()
26{
27	cat <<- EOF
28
29	                Instructions for the Adventure shell
30
31	Welcome to the Adventure shell!  In this exploration of the UNIX file
32	system, I will act as your eyes and hands.  As you move around, I will
33	describe whatever is visible and will carry out your commands.  The
34	general form of a command is
35	        Verb Object Extra_stuff.
36	Most commands pay no attention to the "Extra_stuff", and many do not
37	need an "Object".  A typical command is
38	        get all
39	which picks up all files in the current "room" (directory).  You can
40	find out what you are carrying by typing the command
41	        inventory
42	The command "help" results in a full description of all commands that I
43	understand.  To quit the Adventure shell, type
44	        quit
45
46	There are UNIX monsters lurking in the background.  These are also
47	known as "commands with arguments".
48
49	Good luck!
50	EOF
51}
52
53ash_help()
54{
55echo "I understand the following commands (synonyms in parentheses):"
56echo ""
57
58echo "change OBJECT to NEW_NAME       changes the name of the object"
59echo "clone OBJECT as NEW_NAME        duplicates the object"
60echo "drop OBJECTS                    leaves the objects in the room"
61echo "enter (go) PASSAGE              takes the labeled passage"
62echo "examine OBJECTS                 describes the objects in detail"
63echo "feed OBJECT to MONSTER          stuffs the object into a UNIX monster"
64echo "get (take) OBJECTS              picks up the specified objects"
65echo "gripe (bug)                     report a problem with the Adventure shell"
66echo "help                            prints this summary"
67echo "inventory (i)                   tells what you are carrying"
68echo "kill (destroy) OBJECTS          destroys the objects"
69echo "look (l)                        describes the room, including hidden objects"
70echo "open (read) OBJECT              shows the contents of an object"
71echo "quit (exit)                     leaves the Adventure shell"
72echo "resurrect OBJECTS               attempts to restore dead objects"
73echo "steal OBJECT from MONSTER       obtains the object from a UNIX monster"
74echo "throw OBJECT at daemon          feeds the object to the printer daemon"
75echo "up                              takes the overhead passage"
76echo "wake MONSTER                    awakens a UNIX monster"
77echo "where (w)                       tells you where you are"
78echo "xyzzy                           moves you to your home"
79}
80	
81MAINT=chet@ins.cwru.edu
82
83PATH=/usr/ucb:/bin:/usr/bin:/usr/local/bin:.
84export PATH
85
86trap 'echo Ouch!' 2 3
87#trap '' 18			# disable Berkeley job control
88
89#ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; }
90ash_lk(){ echo " $1 " | fgrep -q " $2 " >/dev/null 2>&1 ; }
91ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75 -l$[ ( $# + 4 ) / 5 ]; }
92ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; }
93
94# enable history, bang history expansion, and emacs editing
95set -o history
96set -o histexpand
97set -o emacs
98
99cd
100LIM=.limbo			# $HOME/$LIM contains "destroyed" objects
101mkdir $LIM || {
102	echo "ash: cannot mkdir $LIM: exiting"
103	exit 1
104}
105KNAP=.knapsack			# $HOME/$KNAP contains objects being "carried"
106if [ ! -d $KNAP ]
107then	mkdir $KNAP >/dev/null 2>&1
108	if [ $? = 0 ]
109	then	echo 'You found a discarded empty knapsack.'
110	else	echo 'You have no knapsack to carry things in.'
111		exit 1
112	fi
113else	echo 'One moment while I peek in your old knapsack...'
114fi
115
116kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\``
117
118if ask 'Welcome to the Adventure shell!  Do you need instructions?'
119then
120	ash_inst
121	echo -n 'Type a newline to continue: '
122	read
123fi
124
125wiz=false
126cha=false
127prev=$LIM
128while :
129do	room=`pwd`
130	if [ $room != $prev ]
131	then	if [ $room = $HOME ]
132		then	echo 'You are in your own home.'
133		else	echo "You have entered $room."
134		fi
135		exs=
136		obs=
137		hexs=
138		hobs=
139		f=false
140		for i in `ls -a`
141		do	case $i in
142			.|..)	;;
143			.*)	if [ -f $i ]
144				then	hobs="$hobs $i"
145				elif [ -d $i ]
146				then	hexs="$hexs $i"
147				else	f=true
148				fi
149				;;
150			*)	if [ -f $i ]
151				then	obs="$obs $i"
152				elif [ -d $i ]
153				then	exs="$exs $i"
154				else	f=true
155				fi
156				;;
157			esac
158		done
159		if [ "$obs" ]
160		then	echo 'This room contains:'
161			ash_pr $obs
162		else	echo 'The room looks empty.'
163		fi
164		if [ "$exs" ]
165		then	echo 'There are exits labeled:'
166			ash_pr $exs
167			echo 'as well as a passage overhead.'
168		else	echo 'There is a passage overhead.'
169		fi
170		if sh -c $f
171		then	echo 'There are shadowy figures in the corner.'
172		fi
173		prev=$room
174	fi
175
176	read -e -p '-advsh> ' verb obj x	# prompt is '-advsh> '
177	if [ $? != 0 ]
178	then	verb=quit		# EOF
179	fi
180
181	case $verb in
182	change)		if [ "$obj" ]
183			then	if ash_lk "$obs $hobs" "$obj"
184				then	set -- $x
185					case "$1" in
186					to)	if [ "$2" ]
187						then	if [ -f $2 ]
188							then	echo "You must destroy $2 first."
189								set --
190							fi
191							if [ "$2" ]
192							then	if mv $obj $2 # >&- 2>&-
193								then	echo "The $obj shimmers and turns into $2."
194									obs=`ash_rm "$2 $obs" "$obj"`
195								else	echo "There is a cloud of smoke but the $obj is unchanged."
196								fi
197							fi
198						else	echo 'To what?'
199						fi
200						;;
201					*)	echo "Change $obj to what?"
202						;;
203					esac
204				else	if ash_lk "$kn" "$obj"
205					then	echo 'You must drop it first.'
206					else	echo "I see no $obj here."
207					fi
208				fi
209			else	echo 'Change what?'
210			fi
211			;;
212	clone)		if [ "$obj" ]
213			then	if ash_lk "$obs $hobs" "$obj"
214				then	if [ ! -r $obj ]
215					then	echo "The $obj does not wish to be cloned."
216					else	set -- $x
217						case "$1" in
218						as)	if [ "$2" ]
219							then	if [ -f $2 ]
220								then	echo "You must destroy $2 first."
221								else	if cp $obj $2 # >&- 2>&-
222									then	echo "Poof!  When the smoke clears, you see the new $2."
223										obs="$obs $2"
224									else	echo 'You hear a dull thud but no clone appears.'
225									fi
226								fi
227							else	echo 'As what?'
228							fi
229							;;
230						*)	echo "Clone $obj as what?"
231							;;
232						esac
233					fi
234				else	if ash_lk "$kn" "$obj"
235					then	echo 'You must drop it first.'
236					else	echo "I see no $obj here."
237					fi
238				fi
239			else	echo 'Clone what?'
240			fi
241			;;
242	drop)		if [ "$obj" ]
243			then	for it in $obj $x
244				do	if ash_lk "$kn" "$it"
245					then	if [ -w $it ]
246						then	echo "You must destroy $it first."
247						else	if mv $HOME/$KNAP/$it $it # >&- 2>&-
248							then	echo "$it: dropped."
249								kn=`ash_rm "$kn" "$it"`
250								obs=`echo $it $obs`
251							else	echo "The $it is caught in your knapsack."
252							fi
253						fi
254					else	echo "You're not carrying the $it!"
255					fi
256				done
257			else	echo 'Drop what?'
258			fi
259			;;
260	enter|go)	if [ "$obj" ]
261			then	if [ $obj != up ]
262				then	if ash_lk "$exs $hexs" "$obj"
263					then	if [ -x $obj ]
264						then	if cd $obj
265							then	echo 'You squeeze through the passage.'
266							else	echo "You can't go that direction."
267							fi
268						else	echo 'An invisible force blocks your way.'
269						fi
270					else	echo 'I see no such passage.'
271					fi
272				else	if cd ..
273					then	echo 'You struggle upwards.'
274					else	echo "You can't reach that high."
275					fi
276				fi
277			else	echo 'Which passage?'
278			fi
279			;;
280	examine)	if [ "$obj" ]
281			then	if [ $obj = all ]
282				then	$obj=`echo $obs $exs`
283					x=
284				fi
285				for it in $obj $x
286				do	if ash_lk "$obs $hobs $exs $hexs" "$it"
287					then	echo "Upon close inspection of the $it, you see:"
288						ls -ld $it 2>/dev/null
289						if [ $? != 0 ]
290						then	echo "-- when you look directly at the $it, it vanishes."
291						fi
292					else	if ash_lk "$kn" "$it"
293						then	echo 'You must drop it first.'
294						else	echo "I see no $it here."
295						fi
296					fi
297				done
298			else	echo 'Examine what?'
299			fi
300			;;
301	feed)		if [ "$obj" ]
302			then	if ash_lk "$obs $hobs" "$obj"
303				then	set -- $x
304					case "$1" in
305					to)	if [ "$2" ]
306						then	shift
307							if PATH=$OPATH $* <$obj 2>/dev/null
308							then	echo "The $1 monster devours your $obj."
309								if rm -f $obj # >&- 2>&-
310								then	obs=`ash_rm "$obs" "$obj"`
311								else	echo 'But he spits it back up.'
312								fi
313							else	echo "The $1 monster holds his nose in disdain."
314							fi
315						else	echo 'To what?'
316						fi
317						;;
318					*)	echo "Feed $obj to what?"
319						;;
320					esac
321				else	if ash_lk "$kn" "$obj"
322					then	echo 'You must drop it first.'
323					else	echo "I see no $obj here."
324					fi
325				fi
326			else	echo 'Feed what?'
327			fi
328			;;
329	get|take)	if [ "$obj" ]
330			then	if [ $obj = all ]
331				then	obj="$obs"
332					x=
333				fi
334				for it in $obj $x
335				do	if ash_lk "$obs $hobs" "$it"
336					then	if ash_lk "$kn" "$it"
337						then	echo 'You already have one.'
338						else	if mv $it $HOME/$KNAP/$it # >&- 2>&-
339							then	echo "$it: taken."
340								kn="$it $kn"
341								obs=`ash_rm "$obs" "$it"`
342							else	echo "The $it is too heavy."
343							fi
344						fi
345					else	echo "I see no $it here."
346					fi
347				done
348			else	echo 'Get what?'
349			fi
350			;;
351	gripe|bug)	echo 'Please describe the problem and your situation at the time it failed.\nEnd the bug report with a line containing just a Ctrl-D.'
352			cat | mail $MAINT -s 'ash bug'
353			echo 'Thank you!'
354			;;
355	help)		ash_help
356			;;
357	inventory|i)	if [ "$kn" ]
358			then	echo 'Your knapsack contains:'
359				ash_pr $kn
360			else	echo 'You are poverty-stricken.'
361			fi
362			;;
363	kill|destroy)	if [ "$obj" ]
364			then	if [ $obj = all ]
365				then	x=
366					if ask "Do you really want to attempt to $verb them all?"
367					then	obj=`echo $obs`
368					else	echo 'Chicken!'
369						obj=
370					fi
371				fi
372				for it in $obj $x
373				do	if ash_lk "$obs $hobs" "$it"
374					then	if mv $it $HOME/$LIM # <&- >&- 2>&-
375						then	if [ $verb = kill ]
376							then	echo "The $it cannot defend himself; he dies."
377							else	echo "You have destroyed the $it; it vanishes."
378							fi
379							obs=`ash_rm "$obs" "$it"`
380						else	if [ $verb = kill ]
381							then	echo "Your feeble blows are no match for the $it."
382							else	echo "The $it is indestructible."
383							fi
384						fi
385					else	if ash_lk "$kn" "$it"
386						then	echo "You must drop the $it first."
387							found=false
388						else	echo "I see no $it here."
389						fi
390					fi
391				done
392			else	echo 'Kill what?'
393			fi
394			;;
395	look|l)		obs=`echo $obs $hobs`
396			hobs=
397			if [ "$obs" ]
398			then	echo 'The room contains:'
399				ash_pr $obs
400			else	echo 'The room is empty.'
401			fi
402			exs=`echo $exs $hexs`
403			hexs=
404			if [ "$exs" ]
405			then	echo 'There are exits plainly labeled:'
406				ash_pr $exs
407				echo 'and a passage directly overhead.'
408			else	echo 'The only exit is directly overhead.'
409			fi
410			;;
411	magic)		if [ "$obj" = mode ]
412			then	if sh -c $cha
413				then	echo 'You had your chance and you blew it.'
414				else	if ask 'Are you a wizard?'
415					then	echo -n 'Prove it!  Say the magic word: '
416						read obj
417						if [ "$obj" = armadillo ]
418						then	echo 'Yes, master!!'
419							wiz=true
420						else	echo "Homie says: I don't think so"
421							cha=true
422						fi
423					else	echo "I didn't think so."
424					fi
425				fi
426			else	echo 'Nice try.'
427			fi
428			;;
429	open|read)	if [ "$obj" ]
430			then	if ash_lk "$obs $hobs" "$obj"
431				then	if [ -r $obj ]
432					then	if [ -s $obj ]
433						then	echo "Opening the $obj reveals:"
434							$CAT < $obj
435							if [ $? != 0 ]
436							then	echo '-- oops, you lost the contents!'
437							fi
438						else	echo "There is nothing inside the $obj."
439						fi
440					else	echo "You do not have the proper tools to open the $obj."
441					fi
442				else	if ash_lk "$kn" "$obj"
443					then	echo 'You must drop it first.'
444						found=false
445					else	echo "I see no $obj here."
446					fi
447				fi
448			else	echo 'Open what?'
449			fi
450			;;
451	quit|exit)	if ask 'Do you really want to quit now?'
452			then	if [ "$kn" ]
453				then	echo 'The contents of your knapsack will still be there next time.'
454				fi
455				rm -rf $HOME/$LIM
456				echo 'See you later!'
457				exit 0
458			fi
459			;;
460	resurrect)	if [ "$obj" ]
461			then	for it in $obj $x
462				do	if ash_lk "$obs $hobs" "$it"
463					then	echo "The $it is already alive and well."
464					else	if mv $HOME/$LIM/$it $it # <&- >&- 2>&-
465						then	echo "The $it staggers to his feet."
466							obs=`echo $it $obs`
467						else	echo "There are sparks but no $it appears."
468						fi
469					fi
470				done
471			else	echo 'Resurrect what?'
472			fi
473			;;
474	steal)		if [ "$obj" ]
475			then	if ash_lk "$obs $hobs" "$obj"
476				then	echo 'There is already one here.'
477				else	set -- $x
478					case "$1" in
479					from)	if [ "$2" ]
480						then	shift
481							if PATH=$OPATH $* >$obj 2>/dev/null
482							then	echo "The $1 monster drops the $obj."
483								obs=`echo $obj $obs`
484							else	echo "The $1 monster runs away as you approach."
485								rm -f $obj # >&- 2>&-
486							fi
487						else	echo 'From what?'
488						fi
489						;;
490					*)	echo "Steal $obj from what?"
491						;;
492					esac
493				fi
494			else	echo 'Steal what?'
495			fi
496			;;
497	throw)		if [ "$obj" ]
498			then	if ash_lk "$obs $hobs" "$obj"
499				then	set -- $x
500					case "$1" in
501					at)	case "$2" in
502						daemon)	if sh -c "lpr -r $obj"
503							then	echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket."
504								obs=`ash_rm "$obs" "$obj"`
505							else	echo "The daemon is nowhere to be found."
506							fi
507							;;
508						*)	echo 'At what?'
509							;;
510						esac
511						;;
512					*)	echo "Throw $obj at what?"
513						;;
514					esac
515				else	if ash_lk "$kn" "$obj"
516					then	echo 'It is in your knapsack.'
517						found=false
518					else	echo "I see no $obj here."
519					fi
520				fi
521			else	echo 'Throw what?'
522			fi
523			;;
524	u|up)		if cd ..
525			then	echo 'You pull yourself up a level.'
526			else	echo "You can't reach that high."
527			fi
528			;;
529	wake)		if [ "$obj" ]
530			then	echo "You awaken the $obj monster:"
531				PATH=$OPATH $obj $x
532				echo 'The monster slithers back into the darkness.'
533			else	echo 'Wake what?'
534			fi
535			;;
536	w|where)	echo "You are in $room."
537			;;
538	xyzzy)		if cd
539			then	echo 'A strange feeling comes over you.'
540			else	echo 'Your spell fizzles out.'
541			fi
542			;;
543	*)		if [ "$verb" ]
544			then	if sh -c $wiz
545				then	PATH=$OPATH $verb $obj $x
546				else	echo "I don't know how to \"$verb\"."
547					echo 'Type "help" for assistance.'
548				fi
549			else	echo 'Say something!'
550			fi
551			;;
552	esac
553done
554