From: palmerp@math.orst.edu (Paul A Palmer)
Subject: Re: zork shell
Reply-To: Paul Palmer <palmerp@math.orst.edu>
Organization: Dept. of Math, Oregon State University
	<laqbkuINN34i@jethro.Corp.Sun.COM>
	<PALMERP.92Sep11135715@phoebus.math.orst.edu>
	<1992Sep12.231259.13833@Princeton.EDU> <BuHp4G.5L2@news.cso.uiuc.edu>
Date: Mon, 14 Sep 1992 03:40:45 GMT

In article <BuHp4G.5L2@news.cso.uiuc.edu> tinsel@uiuc.edu (Thomas Aaron Insel) writes:

   subbarao@tex.Princeton.EDU (Kartik Subbarao) writes:

   > >When I read the original post, I thought he meant something like the 
   > >Adventure Shell. 

   > Correct -- What the poster wants is 'ash', the Adventure Shell, not zsh,
   > the Z-shell.

   Can anyone tell me where I can find this?  Archie lists a dozen or so
   copies available of "ash", from comp.sources.unix v.19, I think, but
   this is hacked SysV shell, not the adventure shell.

Since I've already seen a cople requests for this, I'll go ahead and post it.
I had to hack a bit to get it running, but it wasn't too hard (I'm using
SunOS 4.x.x).

This is from a mailing I got from someone else. I've removed the header so he
doesn't get hassled. He recommended ignoring the Makefile & compiling things
by hand, which is what I did. It did run under /bin/sh on my Sun, though.

------------------------------------------------------------------------------

Will do.  Here it is...The Makefile is braindead, so what you need
to do is to make the programs ask and opg by hand with make -f xxx.mk.
Don't know why they did it that way, very silly.

Our /bin/sh is too stupid to run ash (which is just a big shell
script) so I needed to hack it up to run under bash.  If you need that
version let me know.  This is the virgin version I got in response to
my query.  

#!/bin/sh
# Self-unpacking archive format.  To unbundle, sh this file.
echo 'Makefile' 1>&2
cat >'Makefile' <<'END OF Makefile'
#	Makefile -- for ash

#	last edit:	84/03/09	D A Gwyn

#	SCCS ID:	@(#)Makefile	1.3

PRODUCT = ash
SHFILE	= ${PRODUCT}.sh
HELP	= ${PRODUCT}.help
INST	= ${PRODUCT}.inst
BINDIR	= /vld/bin
LIBDIR	= /vld/lib
MANDIR	= /usr/5lib/man/local/man1
TESTDIR = .
INS	= cp

.DEFAULT:
	$(GET) $(GFLAGS) -p s.$@ > ${TESTDIR}/$@
	touch $@

all:		${SHFILE} ${HELP} ${INST} ${PRODUCT}.1

print:		${PRODUCT}.1 Makefile ${SHFILE} ${HELP} ${INST}
	( nroff -Tlp -man ${TESTDIR}/${PRODUCT}.1 ; \
	  pr Makefile ${TESTDIR}/${SHFILE} ${TESTDIR}/${HELP} \
		${TESTDIR}/${INST} ${TESTDIR}/${PRODUCT}.1 ) | lpr

compare:	all
	cmp ${BINDIR}/${PRODUCT} ${TESTDIR}/${SHFILE}
	cmp ${LIBDIR}/${HELP} ${TESTDIR}/${HELP}
	cmp ${LIBDIR}/${INST} ${TESTDIR}/${INST}
	cmp ${MANDIR}/${PRODUCT}.1 ${TESTDIR}/${PRODUCT}.1

install:	all
	${INS} ${TESTDIR}/${SHFILE} ${BINDIR}/${PRODUCT}
	chmod 755 ${BINDIR}/${PRODUCT}
	${INS} ${TESTDIR}/${HELP} ${LIBDIR}/${HELP}
	${INS} ${TESTDIR}/${INST} ${LIBDIR}/${INST}
	${INS} ${TESTDIR}/${PRODUCT}.1 ${MANDIR}/${PRODUCT}.1
	chmod 644 ${LIBDIR}/${HELP} ${LIBDIR}/${INST} \
		${MANDIR}/${PRODUCT}.1

clean:

clobber:	clean
	-if vax; then rm -f ${TESTDIR}/${SHFILE} ${TESTDIR}/${HELP} \
		${TESTDIR}/${INST} ${TESTDIR}/${PRODUCT}.1; fi
END OF Makefile
echo 'ash.1' 1>&2
cat >'ash.1' <<'END OF ash.1'
.TH ASH 1V VMB
'\"	last edit:	84/09/28	D A Gwyn
'\"	SCCS ID:	@(#)ash.1	1.4
.SH NAME
ash \- interactive Adventure shell
.hw PDP-11s
.SH SYNOPSIS
.B ash
.SH DESCRIPTION
.I Ash\^
is a ``user friendly'' interactive command interpreter
similar in function to the standard
.SM UNIX
shell
.IR sh\^ (1).
It offers two features that the standard shell does not:
the ability to carry files around with you
as you move around the file system,
and the ability to resurrect a dead (deleted) file.
.P
For operating instructions,
run
.I ash\^
and answer
.B yes
to the question about instructions.
Additional information is available by entering the
.I ash\^
command
.BR help .
.SH RESTRICTIONS
.I ash\^
was developed as a joke
and is not as capable as the standard shell
.IR sh\^ (1).
.SH EXAMPLE
.RS
$ \|\fIash\fP
.br
Welcome to the Adventure shell!  Do you need instructions? \|\fIno\fP
.br
You are in your own home.  This room contains:
.br
junk	       mailbox
.br
There are exits labeled:
.br
bin	       mail	      work
.br
as well as a passage overhead.
.br
\o'\(em>' \|\fIopen junk\fP
.br
Opening the junk reveals:
.br
This is the contents of the file ``junk''.
.br
\o'\(em>' \|\fIkill junk\fP
.br
The junk cannot defend himself; he dies.
.br
\o'\(em>' \|\fIquit\fP
.br
Do you really want to quit now? \|\fIyes\fP
.br
See you later!
.RE
.SH FILES
\s-2$HOME\s0/.knapsack
.br
\s-2$HOME\s0/.limbo
.br
/vld/lib/ash.help
.br
/vld/lib/ash.inst
.SH "SEE ALSO"
ask(1V), opg(1V), sh(1).
.SH DIAGNOSTICS
Error messages are meant to be puzzled out by the user.
.SH AUTHOR
Douglas A Gwyn, BRL/VLD-VMB
.SH BUGS
Due to the implementation of
.I ash\^
as a large shell script
and some inadequacies in the way
.IR sh\^ (1)
handles string variable allocation,
.I ash\^
may abort with an
``out of space''
message on PDP-11s.
.P
.I Ash\^
is too slow.
END OF ash.1
echo 'ash.help' 1>&2
cat >'ash.help' <<'END OF ash.help'
I understand the following commands (synonyms in parentheses):

change OBJECT to NEW_NAME	changes the name of the object
clone OBJECT as NEW_NAME	duplicates the object
drop OBJECTS			leaves the objects in the room
enter (go) PASSAGE		takes the labeled passage
examine OBJECTS			describes the objects in detail
feed OBJECT to MONSTER		stuffs the object into a UNIX monster
get (take) OBJECTS		picks up the specified objects
gripe (bug)			report a problem with the Adventure shell
help				prints this summary
inventory (i)			tells what you are carrying
kill (destroy) OBJECTS		destroys the objects
look (l)			describes the room, including hidden objects
open (read) OBJECT		shows the contents of an object
quit (exit)			leaves the Adventure shell
resurrect OBJECTS		attempts to restore dead objects
steal OBJECT from MONSTER	obtains the object from a UNIX monster
throw OBJECT at daemon		feeds the object to the printer daemon
up				takes the overhead passage
wake MONSTER			awakens a UNIX monster
where (w)			tells you where you are
xyzzy				moves you to your home
END OF ash.help
echo 'ash.inst' 1>&2
cat >'ash.inst' <<'END OF ash.inst'

		Instructions for the Adventure shell

Welcome to the Adventure shell!  In this exploration of the UNIX file
system, I will act as your eyes and hands.  As you move around, I will
describe whatever is visible and will carry out your commands.  The
general form of a command is
	Verb Object Extra_stuff.
Most commands pay no attention to the "Extra_stuff", and many do not
need an "Object".  A typical command is
	get all
which picks up all files in the current "room" (directory).  You can
find out what you are carrying by typing the command
	inventory
The command "help" results in a full description of all commands that I
understand.  To quit the Adventure shell, type
	quit

There are UNIX monsters lurking in the background.  These are also
known as "commands with arguments".

Good luck!

END OF ash.inst
echo 'ash.sh' 1>&2
cat >'ash.sh' <<'END OF ash.sh'
#!/usr/5bin/sh
#	ash -- "Adventure shell"
#	last edit:	86/04/21	D A Gwyn
#	SCCS ID:	@(#)ash.sh	1.4

OPATH=$PATH

ASK=/vld/bin/ask
CAT=/vld/bin/opg
HELP=/vld/lib/ash.help
INST=/vld/lib/ash.inst
MAINT=Gwyn@BRL.ARPA
PATH=/usr/5bin:/bin:/usr/bin
export PATH

trap 'echo Ouch!' 2 3
trap '' 18			# disable Berkeley job control

ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; }
ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75; }
ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; }

cd
LIM=.limbo			# $HOME/$LIM contains "destroyed" objects
mkdir $LIM >&- 2>&-
KNAP=.knapsack			# $HOME/$KNAP contains objects being "carried"
if [ ! -d $KNAP ]
then	mkdir $KNAP >&- 2>&-
	if [ $? = 0 ]
	then	echo 'You found a discarded empty knapsack.'
	else	echo 'You have no knapsack to carry things in.'
		exit 1
	fi
else	echo 'One moment while I peek in your old knapsack...'
fi

kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\``

if $ASK 'Welcome to the Adventure shell!  Do you need instructions?'
then	$CAT < $INST
	echo 'Type a newline to continue: \c'
	read i
fi

wiz=false
cha=false
prev=$LIM
while :
do	room=`pwd`
	if [ $room != $prev ]
	then	if [ $room = $HOME ]
		then	echo 'You are in your own home.  \c'
		else	echo "You have entered $room.  \c"
		fi
		exs=
		obs=
		hexs=
		hobs=
		f=false
		for i in `ls -a`
		do	case $i in
			.|..)	;;
			.*)	if [ -f $i ]
				then	hobs="$hobs $i"
				elif [ -d $i ]
				then	hexs="$hexs $i"
				else	f=true
				fi
				;;
			*)	if [ -f $i ]
				then	obs="$obs $i"
				elif [ -d $i ]
				then	exs="$exs $i"
				else	f=true
				fi
				;;
			esac
		done
		if [ "$obs" ]
		then	echo 'This room contains:'
			ash_pr $obs
		else	echo 'The room looks empty.'
		fi
		if [ "$exs" ]
		then	echo 'There are exits labeled:'
			ash_pr $exs
			echo 'as well as a passage overhead.'
		else	echo 'There is a passage overhead.'
		fi
		if sh -c $f
		then	echo 'There are shadowy figures in the corner.'
		fi
		prev=$room
	fi

	echo '-\b> \c'			# prompt
	read verb obj x
	if [ $? != 0 ]
	then	verb=quit		# EOF
	fi

	case $verb in
	change)		if [ "$obj" ]
			then	if ash_lk "$obs $hobs" "$obj"
				then	set -- $x
					case "$1" in
					to)	if [ "$2" ]
						then	if [ -f $2 ]
							then	echo "You must destroy $2 first."
								set --
							fi
							if [ "$2" ]
							then	if mv $obj $2 >&- 2>&-
								then	echo "The $obj shimmers and turns into $2."
									obs=`ash_rm "$2 $obs" "$obj"`
								else	echo "There is a cloud of smoke but the $obj is unchanged."
								fi
							fi
						else	echo 'To what?'
						fi
						;;
					*)	echo "Change $obj to what?"
						;;
					esac
				else	if ash_lk "$kn" "$obj"
					then	echo 'You must drop it first.'
					else	echo "I see no $obj here."
					fi
				fi
			else	echo 'Change what?'
			fi
			;;
	clone)		if [ "$obj" ]
			then	if ash_lk "$obs $hobs" "$obj"
				then	if [ ! -r $obj ]
					then	echo "The $obj does not wish to be cloned."
					else	set -- $x
						case "$1" in
						as)	if [ "$2" ]
							then	if [ -f $2 ]
								then	echo "You must destroy $2 first."
								else	if cp $obj $2 >&- 2>&-
									then	echo "Poof!  When the smoke clears, you see the new $2."
										obs="$obs $2"
									else	echo 'You hear a dull thud but no clone appears.'
									fi
								fi
							else	echo 'As what?'
							fi
							;;
						*)	echo "Clone $obj as what?"
							;;
						esac
					fi
				else	if ash_lk "$kn" "$obj"
					then	echo 'You must drop it first.'
					else	echo "I see no $obj here."
					fi
				fi
			else	echo 'Clone what?'
			fi
			;;
	drop)		if [ "$obj" ]
			then	for it in $obj $x
				do	if ash_lk "$kn" "$it"
					then	if [ -w $it ]
						then	echo "You must destroy $it first."
						else	if mv $HOME/$KNAP/$it $it >&- 2>&-
							then	echo "$it: dropped."
								kn=`ash_rm "$kn" "$it"`
								obs=`echo $it $obs`
							else	echo "The $it is caught in your knapsack."
							fi
						fi
					else	echo "You're not carrying the $it!"
					fi
				done
			else	echo 'Drop what?'
			fi
			;;
	enter|go)	if [ "$obj" ]
			then	if [ $obj != up ]
				then	if ash_lk "$exs $hexs" "$obj"
					then	if [ -x $obj ]
						then	if cd $obj
							then	echo 'You squeeze through the passage.'
							else	echo "You can't go that direction."
							fi
						else	echo 'An invisible force blocks your way.'
						fi
					else	echo 'I see no such passage.'
					fi
				else	if cd ..
					then	echo 'You struggle upwards.'
					else	echo "You can't reach that high."
					fi
				fi
			else	echo 'Which passage?'
			fi
			;;
	examine)	if [ "$obj" ]
			then	if [ $obj = all ]
				then	$obj=`echo $obs $exs`
					x=
				fi
				for it in $obj $x
				do	if ash_lk "$obs $hobs $exs $hexs" "$it"
					then	echo "Upon close inspection of the $it, you see:"
						ls -ld $it 2>&-
						if [ $? != 0 ]
						then	echo "-- when you look directly at the $it, it vanishes."
						fi
					else	if ash_lk "$kn" "$it"
						then	echo 'You must drop it first.'
						else	echo "I see no $it here."
						fi
					fi
				done
			else	echo 'Examine what?'
			fi
			;;
	feed)		if [ "$obj" ]
			then	if ash_lk "$obs $hobs" "$obj"
				then	set -- $x
					case "$1" in
					to)	if [ "$2" ]
						then	shift
							if env PATH=$OPATH $* <$obj 2>&-
							then	echo "The $1 monster devours your $obj."
								if rm -f $obj >&- 2>&-
								then	obs=`ash_rm "$obs" "$obj"`
								else	echo 'But he spits it back up.'
								fi
							else	echo "The $1 monster holds his nose in disdain."
							fi
						else	echo 'To what?'
						fi
						;;
					*)	echo "Feed $obj to what?"
						;;
					esac
				else	if ash_lk "$kn" "$obj"
					then	echo 'You must drop it first.'
					else	echo "I see no $obj here."
					fi
				fi
			else	echo 'Feed what?'
			fi
			;;
	get|take)	if [ "$obj" ]
			then	if [ $obj = all ]
				then	obj="$obs"
					x=
				fi
				for it in $obj $x
				do	if ash_lk "$obs $hobs" "$it"
					then	if ash_lk "$kn" "$it"
						then	echo 'You already have one.'
						else	if mv $it $HOME/$KNAP/$it >&- 2>&-
							then	echo "$it: taken."
								kn="$it $kn"
								obs=`ash_rm "$obs" "$it"`
							else	echo "The $it is too heavy."
							fi
						fi
					else	echo "I see no $it here."
					fi
				done
			else	echo 'Get what?'
			fi
			;;
	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.'
			cat | mail $MAINT -s 'ash bug'
			echo 'Thank you!'
			;;
	help)		$CAT < $HELP
			;;
	inventory|i)	if [ "$kn" ]
			then	echo 'Your knapsack contains:'
				ash_pr $kn
			else	echo 'You are poverty-stricken.'
			fi
			;;
	kill|destroy)	if [ "$obj" ]
			then	if [ $obj = all ]
				then	x=
					if $ASK "Do you really want to attempt to $verb them all?"
					then	obj=`echo $obs`
					else	echo 'Chicken!'
						obj=
					fi
				fi
				for it in $obj $x
				do	if ash_lk "$obs $hobs" "$it"
					then	if mv $it $HOME/$LIM <&- >&- 2>&-
						then	if [ $verb = kill ]
							then	echo "The $it cannot defend himself; he dies."
							else	echo "You have destroyed the $it; it vanishes."
							fi
							obs=`ash_rm "$obs" "$it"`
						else	if [ $verb = kill ]
							then	echo "Your feeble blows are no match for the $it."
							else	echo "The $it is indestructible."
							fi
						fi
					else	if ash_lk "$kn" "$it"
						then	echo "You must drop the $it first."
							found=false
						else	echo "I see no $it here."
						fi
					fi
				done
			else	echo 'Kill what?'
			fi
			;;
	look|l)		obs=`echo $obs $hobs`
			hobs=
			if [ "$obs" ]
			then	echo 'The room contains:'
				ash_pr $obs
			else	echo 'The room is empty.'
			fi
			exs=`echo $exs $hexs`
			hexs=
			if [ "$exs" ]
			then	echo 'There are exits plainly labeled:'
				ash_pr $exs
				echo 'and a passage directly overhead.'
			else	echo 'The only exit is directly overhead.'
			fi
			;;
	magic)		if [ "$obj" = mode ]
			then	if sh -c $cha
				then	echo 'You had your chance and you blew it.'
				else	if $ASK 'Are you a wizard?'
					then	echo 'Prove it!  Say the magic word: \c'
						read obj
						if [ "$obj" = armadillo ]
						then	echo 'Yes, master!!'
							wiz=true
						else	echo "Foo, you're nothing but a charlatan!"
							cha=true
						fi
					else	echo "I didn't think so."
					fi
				fi
			else	echo 'Nice try.'
			fi
			;;
	open|read)	if [ "$obj" ]
			then	if ash_lk "$obs $hobs" "$obj"
				then	if [ -r $obj ]
					then	if [ -s $obj ]
						then	echo "Opening the $obj reveals:"
							$CAT < $obj 2>&-
							if [ $? != 0 ]
							then	echo '-- oops, you lost the contents!'
							fi
						else	echo "There is nothing inside the $obj."
						fi
					else	echo "You do not have the proper tools to open the $obj."
					fi
				else	if ash_lk "$kn" "$obj"
					then	echo 'You must drop it first.'
						found=false
					else	echo "I see no $obj here."
					fi
				fi
			else	echo 'Open what?'
			fi
			;;
	quit|exit)	if $ASK 'Do you really want to quit now?'
			then	if [ "$kn" ]
				then	echo 'The contents of your knapsack will still be there next time.'
				fi
				rm -rf $HOME/$LIM
				echo 'See you later!'
				exit 0
			fi
			;;
	resurrect)	if [ "$obj" ]
			then	for it in $obj $x
				do	if ash_lk "$obs $hobs" "$it"
					then	echo "The $it is already alive and well."
					else	if mv $HOME/$LIM/$it $it <&- >&- 2>&-
						then	echo "The $it staggers to his feet."
							obs=`echo $it $obs`
						else	echo "There are sparks but no $it appears."
						fi
					fi
				done
			else	echo 'Resurrect what?'
			fi
			;;
	steal)		if [ "$obj" ]
			then	if ash_lk "$obs $hobs" "$obj"
				then	echo 'There is already one here.'
				else	set -- $x
					case "$1" in
					from)	if [ "$2" ]
						then	shift
							if env PATH=$OPATH $* >$obj 2>&-
							then	echo "The $1 monster drops the $obj."
								obs=`echo $obj $obs`
							else	echo "The $1 monster runs away as you approach."
								rm -f $obj >&- 2>&-
							fi
						else	echo 'From what?'
						fi
						;;
					*)	echo "Steal $obj from what?"
						;;
					esac
				fi
			else	echo 'Steal what?'
			fi
			;;
	throw)		if [ "$obj" ]
			then	if ash_lk "$obs $hobs" "$obj"
				then	set -- $x
					case "$1" in
					at)	case "$2" in
						daemon)	if sh -c "lpr -r $obj"
							then	echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket."
								obs=`ash_rm "$obs" "$obj"`
							else	echo "The daemon is nowhere to be found."
							fi
							;;
						*)	echo 'At what?'
							;;
						esac
						;;
					*)	echo "Throw $obj at what?"
						;;
					esac
				else	if ash_lk "$kn" "$obj"
					then	echo 'It is in your knapsack.'
						found=false
					else	echo "I see no $obj here."
					fi
				fi
			else	echo 'Throw what?'
			fi
			;;
	u|up)		if cd ..
			then	echo 'You pull yourself up a level.'
			else	echo "You can't reach that high."
			fi
			;;
	wake)		if [ "$obj" ]
			then	echo "You awaken the $obj monster:"
				env PATH=$OPATH $obj $x
				echo 'The monster slithers back into the darkness.'
			else	echo 'Wake what?'
			fi
			;;
	w|where)	echo "You are in $room."
			;;
	xyzzy)		if cd
			then	echo 'A strange feeling comes over you.'
			else	echo 'Your spell fizzles out.'
			fi
			;;
	*)		if [ "$verb" ]
			then	if sh -c $wiz
				then	env PATH=$OPATH $verb $obj $x
				else	echo "I don't know how to \"$verb\"."
					echo 'Type "help" for assistance.'
				fi
			else	echo 'Say something!'
			fi
			;;
	esac
done
END OF ash.sh
echo 'ask.1' 1>&2
cat >'ask.1' <<'END OF ask.1'
.TH ASK 1V VMB
'\"	last edit:	85/03/05	D A Gwyn
'\"	SCCSID		@(#)ask.1	1.6
.SH NAME
ask \- ask the user a question and exit with appropriate status
.SH SYNOPSIS
.B ask
[
.B \-n
] [
.B \-y
] word ...
.SH DESCRIPTION
.I Ask\^
displays the
.IR word\^ s
(which will usually ask a Yes/No question
ending with a question mark)
separated by spaces
as a user query message
on the terminal
and gets a response from
the user.
.P
Valid user responses consist of
optional white space followed by
any word beginning with
an upper- or lower-case
.B N
(taken as ``No'')
or an upper- or lower-case
.B Y
(taken as ``Yes'').
If the optional
.B \-n
or
.B \-y
flag is used,
a null response
(all whitespace, such as just a \s-2NEWLINE\s0)
is taken to mean ``No'' or ``Yes'', respectively.
.SH EXAMPLE
The following shell command
emulates the behavior of
.B "rm\ \|\-i\ \|*"
while giving a somewhat improved user prompt message:
.RS
$ \|\fIfor \|$file \|in \|*\fP
.br
> \|\fIdo	if \|ask \|\-n \|Delete \|$file\\?\fP
.br
>		\fIthen	rm \|\-f \|$file\fP
.br
>		\fIfi\fP
.br
> \|\fIdone\fP
.RE
Notice that the question mark must be protected from
interpretation by the shell.
.SH FILES
/dev/tty
.SH "SEE ALSO"
echo(1), find(1), pick(1V), sh(1).
.SH DIAGNOSTICS
I/O errors cause a default response to be assumed
(``No'' unless the
.B \-y
flag is used).
Invalid user responses cause the query to be repeated
until a valid response is received.
.SH "EXIT CODES"
Exit status 0 is returned for a ``Yes'' response
and 1 for a ``No'' response.
.SH AUTHORS
John S. Quarterman, Geotronics Corporation
.br
Douglas A. Gwyn, BRL/VLD-VMB
END OF ask.1
echo 'ask.c' 1>&2
cat >'ask.c' <<'END OF ask.c'
/*
	ask -- ask the user a question and exit with appropriate status
		(Original version due to JSQ; modified by DAG)

	last edit:	83/10/19	D A Gwyn

The arguments are echoed as a prompt for a Yes/No response; all I/O is
performed on ctermid().  "ask" does not supply a trailing question mark.

Upper or lower case `Y' or `N' as the first non-blank character of the
answer, or a null response when a "-n" or "-y" flag is given, are the
only accepted responses; anything else causes the prompt to be repeated.

If the first argument is "-n" or "-y", then a null (blank) response will
be taken to mean "No" or "Yes", respectively; otherwise a null response
is considered invalid and the request is repeated.

Exit code 0 indicates Yes, 1 indicates No; errors produce a default
exit code (0 if "-y" flag is given; 1 otherwise).
*/
static char	sccsid[] = "@(#)ask.c	1.4";

#include	<stdio.h>
#include	<string.h>

extern void	exit();
extern char	*malloc();

main( argc, argv )			/* "ask" executive */
	int		argc;		/* argument count */
	char		**argv; 	/* argument vector */
	{
	int		nullresp;	/* null response semantics:
					    0 => invalid;
					   -1 => "No";
					    1 => "Yes".
					 */
	register FILE	*input, *output;/* terminal i/o streams */
	char		*pname = *argv; /* program invocation name */

	/* first argument "-n" or "-y" permits null response */

	nullresp = 0;			/* default: null => invalid */
	if ( argc > 1 )
		if ( strcmp( argv[1], "-n" ) == 0 )
			nullresp = -1;	/* null => "No" */
		else if ( strcmp( argv[1], "-y" ) == 0 )
			nullresp = 1;	/* null => "Yes" */
	if ( nullresp != 0 )
		--argc, ++argv;

	/* set up terminal i/o */ 
	{
	register char	*tname; 	/* filename for terminal */

	if ( (tname = ctermid( (char *)NULL )) == NULL )
		{
		(void)fprintf( stderr, "%s: no terminal available\n",
			       pname
			     );
		exit( nullresp > 0 ? 0 : 1 );
		}

	if ( (output = fopen( tname, "w" )) == NULL )
		{
		(void)fprintf( stderr, "%s: can't write \"%s\"\n",
			       pname, tname
			     );
		exit( nullresp > 0 ? 0 : 1 );
		}
	setbuf( output, malloc( BUFSIZ ) );

	if ( (input = fopen( tname, "r" )) == NULL )
		{
		(void)fprintf( stderr, "%s: can't read \"%s\"\n",
			       pname, tname
			     );
		exit( nullresp > 0 ? 0 : 1 );
		}
	setbuf( input, (char *)NULL );
	}

	if ( argc < 2 )
		{
		(void)printf( "\"%s question\" prints the question,\n",
			      pname
			    );
		(void)printf( "waits for a Yes/No response,\n" );
		(void)printf( "and returns the appropriate exit code.\n"
			    );

		(void)fprintf( stderr, "%s: no arguments\n", pname );
		exit( nullresp > 0 ? 0 : 1 );
		}

	/* keep prompting and getting response until valid */

	for ( ; ; )
		{
		char	inbuf[BUFSIZ];	/* user-response input buffer */
		int	narg = argc;	/* argument counter */
		char	**word = argv;	/* argument pointer */

		/* print arguments followed by one space each */

		for ( --narg, ++word; narg > 0; --narg, ++word )
			if ( fprintf( output, "%s ", *word ) != 
			     strlen( *word ) + 1
			   )	{
				(void)fprintf( stderr,
					       "%s: output error\n",
					       pname
					     );
				exit( nullresp > 0 ? 0 : 1 );
				}
		(void)fflush( output );

		/* get response */

		if ( fgets( inbuf, sizeof inbuf, input ) == NULL )
			{
			(void)fprintf( stderr, "%s: input error\n",
				       pname
				     );
			exit( nullresp > 0 ? 0 : 1 );
			}

		/* return appropriate status code */
		{
		register char	*first; /* -> first char of response */

		if ( (first = strtok( inbuf, " \t\n" )) == NULL )
			if ( nullresp < 0 )
				exit( 1 );	/* same as "No" */
			else if ( nullresp > 0 )
				exit( 0 );	/* same as "Yes" */
			else
				first = "x";	/* invalid response */
		if ( *first == 'N' || *first == 'n' )
			exit( 1 );
		if ( *first == 'Y' || *first == 'y' )
			exit( 0 );
		}

		/* response was invalid; help user respond */
		{
		static char	help[] = "Please answer `Y' or `N'\n";

		if ( fprintf( output, help ) != sizeof help - 1 )
			{
			(void)fprintf( stderr, "%s: output error\n",
				       pname
				     );
			exit( nullresp > 0 ? 0 : 1 );
			}
		}
		}
	/*NOTREACHED*/
	}
END OF ask.c
echo 'ask.mk' 1>&2
cat >'ask.mk' <<'END OF ask.mk'
#	ask.mk -- makefile for "ask" utility

#	last edit:	86/11/10	D A Gwyn

#	SCCS ID:	@(#)ask.mk	1.11

PRODUCT = ask
MKFILE	= ${PRODUCT}.mk
CFILES	= ${PRODUCT}.c
OBJS	= ${PRODUCT}.o
LDFLAGS = -n
BINDIR	= /vld/bin
MANDIR	= /usr/5lib/man/local/man1
BINPERM	= 775
MANPERM	= 664
INS	= cp

.DEFAULT:
	$(GET) $(GFLAGS) -p s.$@ > $@
	touch $@

all:		${PRODUCT} ${PRODUCT}.1

${PRODUCT}:	${OBJS}
	$(CC) -o $@ ${LDFLAGS} ${OBJS}
	size $@
	touch $@

print:		${PRODUCT}.1 ${MKFILE} ${CFILES}
	( nroff -Tlp -man ${PRODUCT}.1 ; \
	  pr ${MKFILE} ${CFILES} ${PRODUCT}.1 ) | lpr

lint:		${CFILES}
	lint ${CFILES} > ${PRODUCT}.lint

compare:	all
	cmp ${BINDIR}/${PRODUCT} ${PRODUCT}
	cmp ${MANDIR}/${PRODUCT}.1 ${PRODUCT}.1

install:	all
	-chmod ${BINPERM} ${PRODUCT}
	${INS} ${PRODUCT} ${BINDIR}
	-chmod ${MANPERM} ${PRODUCT}.1
	${INS} ${PRODUCT}.1 ${MANDIR}

clean:
	-if vax; then rm -f ${CFILES}; fi
	-rm -f ${OBJS} ${PRODUCT}.lint

clobber:	clean
	-if vax; then rm -f ${PRODUCT}.1; fi
	-rm -f ${PRODUCT}
END OF ask.mk
echo 'opg.1' 1>&2
cat >'opg.1' <<'END OF opg.1'
.TH OPG 1V VMB
'\"	last edit:	85/03/05	D A Gwyn
'\"	SCCSID		@(#)opg.1	1.9
.SH NAME
opg \- paginate files to terminal
.SH SYNOPSIS
.B opg
[
.B \-e
] [
.B \-h
screen_height
] [
.B \-T
terminal
] [
.B \-w
line_width
] [ file ... ]
.SH DESCRIPTION
.I Opg\^
displays the contents of the specified
.IR file\^ s
(standard input if not given)
on the terminal
attached to its standard output,
one screenload at a time.
At the end of each screen,
.I opg\^
asks ``More?'' (if reading standard input)
or ``More\ of\ \fIfile\^\fP?''
and inputs a single-character response
>from the user's terminal;
any response except
.BR N ,
.BR n ,
or EOT
causes the next screenload to be displayed.
Similarly,
.I opg\^
asks ``Next\ file\ (\fIfile\^\fP)?''
before every
.I file\^
but the first
and inputs a single-character response
>from the terminal;
any response except
.BR N ,
.BR n ,
or EOT
causes the next
.I file\^
to be displayed.
.P
The range of lines visible is shown as
``[\fIfirst\^\fP\-\fIlast\^\fP]''
before the ``More?''
prompt,
and the name of the just-ended file is shown as
``[end\ of\ \fIfile\^\fP]''
before the ``Next\ file?'' prompt if any.
.P
SIGINT aborts the current file;
SIGQUIT aborts
.IR opg\^ .
These are disabled when the
.B \-e
flag is specified;
this may be necessary to
preserve escape sequence integrity.
After SIGINT, ``[\fIfile\^\fP\ aborted]'' is shown.
.P
Environment variable
.B \s-2TERM\s0
is used to determine terminal type;
the
.B \-T
option overrides this.
Only a few terminal types
are known to
.IR opg\^ ;
an unknown terminal type is scrolled
rather than painting its screen from the top down.
A terminal known to use ANSI escape sequences
has the
.B \-e
flag automatically set.
.P
The optional
.I line_width\^
is the number of characters on a line without the cursor wrapping
(default 79),
and the optional
.I screen_height\^
is the number of lines visible on the display (default 24).
If the operating system supports a ``get window size'' feature,
it will be used to determine the display dimensions.
.SH WARNING
This program is essentially superceded by
the more powerful UNIX System V Release 2 utility
.IR pg\^ (1).
It is expected to vanish someday.
.SH EXAMPLE
.RS
$ \|\fIopg \|\-T vt100 \|*.c\fP
.RE
.SH FILES
/dev/tty
.SH "SEE ALSO"
cat(1), pg(1).
.SH DIAGNOSTICS
If the standard output is not a terminal,
.I opg\^
will terminate
with an error message
and return non-zero exit status.
If the terminal type is unknown,
a warning message is printed
and scrolling is used instead of screen painting.
.SH AUTHOR
Douglas A. Gwyn, BRL/VLD-VMB
.SH BUGS
This program should use
.IR termcap\^ (4)
or
.IR terminfo\^ (4)
rather than a built-in table.
END OF opg.1
echo 'opg.c' 1>&2
cat >'opg.c' <<'END OF opg.c'
/*
	opg -- paginate input files (can be used as end of a pipeline)

	last edit:	87/03/23	D A Gwyn

Usage:
	$ opg[ -e][ -h screen_ht][ -T terminal][ -w line_width] file ...
    or
	$ program | opg[ -e][ -h screen_ht][ -T terminal][ -w line_width]

	where `terminal' is a terminal designator (e.g., "vt100"),
	`line_width' is the number of characters on a line (default 79),
	`screen_ht' is the number of lines on a screen (default 24).
	Whitespace before these parameters is optional.

Method:
	Copies argument files (or standard input, if no file args) to
	standard output one screenload at a time.  After each screen,
	"More of <file>?" (just "More?" if standard input) is asked; any
	response except "n" or EOT will present the next screen.  "Next
	file (<file>)?" is asked before each file except the first.
	The range of lines visible is shown as "[
-<e>]" before the
	"More?" prompt, and the name of the just-ended file is shown as
	"[end of <file>]", before the "Next File?" prompt if any.

	SIGINT aborts the current file; SIGQUIT aborts "opg".  These are
	disabled when the "-e" flag is specified, to preserve escape
	sequence integrity.  After SIGINT, "[<file> aborted]" is shown.

	Environment variable "TERM" is used to set up terminal type; the
	-T option overrides this.  An unknown terminal type is scrolled
	rather than painting its screen from the top down.
*/
#ifndef	lint
static char	sccsid[] = "@(#)opg.c	1.14";
#endif

#include	<ctype.h>
#include	<termio.h>
#include	<signal.h>
#include	<stdio.h>
#include	<string.h>

#include	<std.h>

#define	TERMINAL	"/dev/tty"	/* UNIX filename for terminal */

extern void	exit();
extern char	*getenv(), *malloc();
extern int	ioctl();

static void	clear(), intr(), quit();
static bool	more(), setterm();

/* screen-clear code sequences vary: */
#define	UNK	(-1)
#define	ANSI	0
#define	ADM3	1
#define	VT52	2
#define	FF	3
static int	ttype = UNK;		/* screen-clear code type */

static int	linesize = 79;		/* chars before wrap-around */
static int	pagesize = 24;		/* # of lines on terminal */
static int	filnum = 1;		/* file being processed */
static bool	eflag = false;		/* support escape sequences */
static bool	neednl = false; 	/* newline needed on stdout */
static bool	typeit = false; 	/* turned off by SIGINT */

static struct termio	tty = { 0 };
static struct termio	omode = { 0 };	/* original terminal mode */
static struct termio	rmode = { 0 };	/* raw mode during prompt */

main( argc, argv )
	int	argc;
	char	*argv[];
	{
	char	*fname; 		/* filename file for prompt */

	{
	register char	*tname; 	/* terminal name */

	if ( (tname = getenv( "TERM" )) != NULL )
		(void)setterm( tname ); /* if possible */
	}

	while ( argc > 1 && (*++argv)[0] == '-' )
		{			/* process option */
		switch( (int)(*argv)[1] )
			{
			register char	*arg;	/* additional param */
			int		temp;	/* converted value */

		case 'e':		/* "-e" */
			eflag = true;
			break;

		case 'h':		/* "-h screen_ht" */
			if ( *(arg = &(*argv)[2]) == '\0' )
				{
				--argc;
				arg = *++argv;
				}
			if ( sscanf( arg, "%d", &temp ) != 1
			  || temp <= 0
			   )
				(void)fprintf( stderr,
					       "opg: bad -h \"%s\"\n",
					       arg
					     );
			else
				pagesize = temp;
			break;

		case 'T':		/* "-T term" */
			if ( *(arg = &(*argv)[2]) == '\0' )
				{
				--argc;
				arg = *++argv;
				}
			if ( !setterm( arg ) )
				(void)fprintf( stderr,
					      "opg: unknown -T \"%s\"\n",
					       arg
					     );
			break;

		case 'w':		/* "-w line_width" */
			if ( *(arg = &(*argv)[2]) == '\0' )
				{
				--argc;
				arg = *++argv;
				}
			if ( sscanf( arg, "%d", &temp ) != 1
			  || temp <= 0
			   )
				(void)fprintf( stderr,
					       "opg: bad -w \"%s\"\n",
					       arg
					     );
			else
				linesize = temp;
			break;

		default:
			(void)fprintf( stderr,
				       "opg: unknown option \"%s\"\n",
				       *argv
				     );
			break;
			}

		--argc;
		}

	if ( eflag )
		{
		(void)signal( SIGINT, SIG_IGN );
		(void)signal( SIGQUIT, SIG_IGN );
		}
	else	{
		(void)signal( SIGINT, intr );
		(void)signal( SIGQUIT, quit );
		}

	if ( freopen( TERMINAL, "r", stderr ) == NULL
	  || ioctl( fileno( stderr ), TCGETA, &tty ) != 0
	   )
		exit( 2 );
	omode = tty;			/* save for exit */
	rmode = tty;			/* corresponding raw mode */
	rmode.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
	rmode.c_cc[VMIN] = (unsigned char)1;
	rmode.c_cc[VTIME] = (unsigned char)0;	/* no timeout */
	setbuf( stderr, (char *)NULL ); /* for single-char read */
	/* after this point, cannot write on stderr */

	fname = argc > 1 ? *argv : NULL;	/* first file, if any */

	do	{
		bool		done;
		register int	c;
		register int	col = 0, line = 1;
		int		lastc = '\n';
		long		lcount = 0L, lstart = 1L;

		clear();

		if ( argc > 1 )
			{
			if ( freopen( fname, "r", stdin ) == NULL )
				(void)printf(
					"**** can't open \"%s\" ****\n",
					      fname
					    );
			else
				(void)printf( "======== %s ========\n",
					      fname
					    );

			++line;
			}

		done = false;		/* true when tired of file */
		typeit = true;		/* false when SIGINT caught */

		while ( typeit && (c = getchar()) != EOF )
			{
			if ( line >= pagesize )
				{
				if ( done = !more( false, fname,
						   lstart, lcount
						 )
				   )
					break;	/* next file */

				clear();
				lstart = lcount + 1;	/* next line */
				line = 1;
				}

			switch ( c = toascii( c ) )
				{
			case 0013:	/* VT */
			case 0014:	/* FF */
				line = pagesize;
				c = 0012;
				/* line count may not agree with "ed" */
				/* fall through */

			case 0012:	/* LF */
				++lcount;
				++line;
				/* fall through */

			case 0015:	/* CR */
				col = 0;
				break;

			case 0010:	/* BS */
				if ( col > 0 )
					--col;
				break;

			case 0011:	/* HT */
				col += 8;
				col -= col % 8;
				break;

			case 0177:	/* DEL */
				(void)ungetc( '/', stdin );
				c = toascii( '^' );
				++col;
				break;

			case 0033:	/* ESC */
				if ( eflag )
					{
					c = tohostc( c );

					do	{
						if ( col < linesize )
							(void)putchar( c );
						if ( isalpha( c ) )
						/* end esc sequence */
							break;

						if ( (c = getchar())
						     == EOF
						   )
							typeit = false;
						}
					while ( typeit && !iscntrl( c )
					      );

					if ( typeit && iscntrl( c ) )
						(void)ungetc( c,
							      stdin
							    );

					continue;	/* read next */
					}
				/* else fall through */

			default:
				if ( c < 0040 ) /* map ctrl char */
					{
					(void)ungetc( tohostc( c + 0100
							     ),
						      stdin
						    );
					c = toascii( '^' );
					}

				++col;
				break;
				}

			if ( col < linesize )
				(void)putchar( lastc = tohostc( c ) );
			}
		/* end of file */

		if ( !typeit )		/* interrupted */
			if ( fname == NULL )
				(void)fputs( "\n[aborted]", stdout );
			else
				(void)printf( "\n[%s aborted] ", fname
					    );
		else
			if ( !done && fname != NULL )
				{
				neednl = true;
				(void)printf( "[end of %s] ", fname );
				}

		if ( lastc != '\n' )
			(void)putchar( '\n' );

		fname = *++argv;
		}
	while ( ++filnum < argc && more( true, fname, 0L, 0L ) );

	if ( neednl )
		(void)putchar( '\n' );

	exit( 0 );
	}

static bool
more( file, fname, lstart, lcount )
	register bool	file;		/* determines prompt type */
	char		*fname; 	/* filename for prompt */
	long		lstart; 	/* first line on screen */
	long		lcount; 	/* last line on screen */
	{
/* possible funny characters to take care of in RAW mode: */
#if	defined(BRL) && defined(pdp11)
#undef	CINTR
#undef	CQUIT
#define	CINTR	0003
#define	CQUIT	0002
#endif
	register int	c;

	(void)fflush( stdout );
	(void)signal( SIGTERM, quit );
	tty = rmode;
	(void)ioctl( fileno( stderr ), TCSETAW, &tty );

	if ( file )
		(void)printf( "Next file (%s)? ", fname );
	else
		if ( fname == NULL )
			(void)printf( "[%ld-%ld] More? ", lstart, lcount
				    );
		else
			(void)printf( "[%ld-%ld] More of %s? ",
				      lstart, lcount, fname
				    );

	(void)fflush( stdout );
	neednl = true;

	while ( (c = getc( stderr )) == CINTR && file	/* race */
	     || c == CSTOP || c == CSTART
	      )
		;

	tty = omode;
	(void)ioctl( fileno( stderr ), TCSETAW, &tty );
	(void)signal( SIGTERM, SIG_DFL );

	if ( c == CINTR )
		return false;		/* (file == false) */

	if ( c == CQUIT )
		quit( 3 );

	return c != EOF && c != CEOF && tolower( c ) != 'n';
	}

static bool
setterm( name ) 			/* set up terminal type */
	register char	*name;		/* terminal designator */
	{
	/* table of recognized terminal types - add your favorites
	   (synonyms are okay) */
	static struct term
		{
		char	*tname;		/* termcap designator */
		int	clear;		/* `ttype' screen-clear code */
		int	rows;		/* lines visible */
		int	cols;		/* chars without wrap */
		}	table[] =
		{
	"adm12",	ADM3,	24,	79,	/* LSI ADM12 */
	"adm3a",	ADM3,	24,	79,	/* LSI ADM3A */
	"apple2e",	FF,	24,	79,	/* Apple //e */
	"apple2e-p",	FF,	24,	79,	/* Apple //e Pascal */
	"apple-ae",	FF,	24,	79,	/* ASCII Express */
	"dmd",		ANSI,	70,	87,	/* Teletype 5620 */
	"hirez100",	ANSI,	48,	80,	/* Selanar HiREZ-100 */
	"hp2623a",	VT52,	24,	79,	/* H-P 2623A */
	"hp2647a",	VT52,	24,	79,	/* H-P 2647A */
	"matrox",	FF,	24,	79,	/* Matrox MTX-512 */
	"tek4105",	ANSI,	30,	80,	/* Tektronix 4105 */
	"tty5620",	ANSI,	70,	87,	/* Teletype 5620 */
	"tty5620-1",	ANSI,	70,	87,	/* Teletype 5620 */
	"tty5620-2",	ANSI,	70,	87,	/* Teletype 5620 */
	"vi200", 	VT52,	24,	79,	/* Visual 200 */
	"vt52", 	VT52,	24,	79,	/* DEC VT52 */
	"vt100",	ANSI,	24,	80,	/* DEC VT100 */
	"vt220",	ANSI,	24,	80,	/* DEC VT220 */
	NULL,		UNK,	24,	79	/* must be last entry */
		};
	register struct term	*tp;
#ifdef TIOCGWINSZ
	struct _winsize		window;
#endif

	for ( tp = table; tp->tname != NULL; ++tp )
		if ( strcmp( name, tp->tname ) == 0 )
			break;

	ttype = tp->clear;		/* UNK if not in table */
#ifdef TIOCGWINSZ
	if ( ioctl( fileno( stdout ), TIOCGWINSZ, &window ) == 0
	  && window.ws_row != 0 && window.ws_col != 0
	   )	{
		pagesize = (int)window.ws_row;
		linesize = (int)window.ws_col - 1;
		}
	else	{
#endif
	    pagesize = tp->rows;
	    linesize = tp->cols;
#ifdef TIOCGWINSZ
		}
#endif

	if ( ttype == ANSI )
		eflag = true;		/* support escape sequences */

	return tp->tname != NULL;
	}

static void
clear() 				/* clear terminal screen */
	{
	switch ( ttype )
		{
	case ANSI:
		(void)fputs( "\033[H\033[J", stdout );
		break;

	case ADM3:
		(void)putchar( '\032' );
		break;

	case VT52:
		(void)fputs( "\033H\033J", stdout );
		break;

	case FF:
		(void)putchar( '\f' );
		break;

	default:
		if ( neednl )
			(void)putchar( '\n' );
		break;
		}

	(void)putchar( '\r' );		/* tty driver lost column */
	neednl = false;
	}

static void
intr( sig )				/* called on SIGINT */
	int	sig;			/* signal number */
	{
	(void)signal( sig, intr );	/* re-arm immediately */

	neednl = true;			/* probably garbage on screen */
	typeit = false; 		/* ask for interruption */
	}

static void
quit( sig )	/* also called on SIGQUIT and on SIGTERM in raw mode */
	int	sig;			/* signal number */
	{
	(void)signal( SIGINT, SIG_IGN );/* protect until mode reset */
	(void)signal( SIGQUIT, SIG_IGN );
	(void)signal( SIGTERM, SIG_IGN );

	tty = omode;
	(void)ioctl( fileno( stderr ), TCSETAW, &tty );

	neednl = true;			/* probably garbage on screen */
	clear();

	exit( sig );
	}
END OF opg.c
echo 'opg.mk' 1>&2
cat >'opg.mk' <<'END OF opg.mk'
#	opg.mk -- makefile for "opg" utility

#	last edit:	86/11/10	D A Gwyn

#	SCCS ID:	@(#)opg.mk	1.13

PRODUCT = opg
MAKEFIL	= ${PRODUCT}.mk
CFILES	= ${PRODUCT}.c
OBJS	= ${PRODUCT}.o
BINDIR	= /vld/bin
INCDIR	= /vld/include
MANDIR	= /usr/5lib/man/local/man1
BINPERM	= 775
MANPERM	= 664
CFLAGS	= -I${INCDIR} -O -DBRL
LDFLAGS = -n
INS	= cp

#	Generic SCCS rule:

.DEFAULT:
	$(GET) $(GFLAGS) -p s.$@ > $@

all:		${PRODUCT} ${PRODUCT}.1

${PRODUCT}:	${OBJS}
	$(CC) -o $@ ${LDFLAGS} ${OBJS}
	size $@

print:		${PRODUCT}.1 ${MAKEFIL} ${CFILES}
	( nroff -Tlp -man ${PRODUCT}.1 ; \
	  pr ${MAKEFIL} ${CFILES} ${PRODUCT}.1 ) | lp

lint:		${CFILES}
	lint -I${INCDIR} -DBRL ${CFILES} > ${PRODUCT}.lint

flow:		${CFILES}
	cflow -I${INCDIR} ${CFILES} > ${PRODUCT}.flow

xref:		${CFILES}
	cxref -c -s -w132 -I${INCDIR} ${CFILES} > ${PRODUCT}.xref

test:
	@echo 'Test "opg" by hand.'

compare:	all
	cmp ${BINDIR}/${PRODUCT} ${PRODUCT}
	cmp ${MANDIR}/${PRODUCT}.1 ${PRODUCT}.1

install:	all
	-chmod ${BINPERM} ${PRODUCT}
	@if cmp -s ${BINDIR}/${PRODUCT} ${PRODUCT}; \
	 then	echo ${PRODUCT} unchanged; \
	 else	${INS} ${PRODUCT} ${BINDIR}; \
		echo ${PRODUCT} installed; \
	 fi
	-chmod ${MANPERM} ${PRODUCT}.1
	@if cmp -s ${MANDIR}/${PRODUCT}.1 ${PRODUCT}.1; \
	 then	echo ${PRODUCT}.1 unchanged; \
	 else	${INS} ${PRODUCT}.1 ${MANDIR}; \
		echo ${PRODUCT}.1 installed; \
	 fi

clean:
	-if vax; then rm -f ${CFILES}; fi
	-rm -f ${OBJS} ${PRODUCT}.lint ${PRODUCT}.flow ${PRODUCT}.xref

clobber:	clean
	-if vax; then rm -f ${PRODUCT}.1; fi
	-rm -f ${PRODUCT}
END OF opg.mk
echo 'std.h' 1>&2
cat >'std.h' <<'END OF std.h'
/*
	std.h -- Douglas A. Gwyn's standard C programming definitions
						(UNIX System V version)

	Prerequisite:	<math.h> (if you invoke Round())

	last edit:	86/05/12	D A Gwyn

	SCCS ID:	@(#)std.h	1.16

	This file is to be modified by the VMB Software Development Team
	leader only.  Currently, this is Douglas A. Gwyn <Gwyn@BRL.ARPA>.
*/

#ifndef	_VLD_STD_H_
#define	_VLD_STD_H_			/* once-only latch */

/* Extended data types */

#ifndef NULL
#define NULL	0			/* null pointer, all types */
#endif

typedef int	bool;			/* Boolean data */
#define 	false	0
#define 	true	1

typedef unsigned char	u_char;		/* unsigned integer types */
typedef unsigned short	u_short;
#ifdef	pdp11
typedef long		u_long;		/* (not in Ritchie compiler) */
#else
typedef unsigned long	u_long;
#endif

typedef char	*pointer;		/* generic pointer (void *) */

#define	const		/* nothing */	/* (undefine for ANSI C) */
#define	signed		/* nothing */	/* (undefine for ANSI C) */
#define	volatile	/* nothing */	/* (undefine for ANSI C) */

/* Universal constants */

#define DEGRAD	57.2957795130823208767981548141051703324054724665642
					/* degrees per radian */
#define	E	2.71828182845904523536028747135266249775724709369996
					/* base of natural logs */
#define	GAMMA	0.57721566490153286061
					/* Euler's constant */
#define LOG10E	0.43429448190325182765112891891660508229439700580367
					/* log of e to the base 10 */
#define PHI	1.618033988749894848204586834365638117720309180
					/* golden ratio */
#define PI	3.14159265358979323846264338327950288419716939937511
					/* ratio of circumf. to diam. */

/* Useful macros */

/* arbitrary numerical arguments and value: */
#define Abs( x )	((x) < 0 ? -(x) : (x))
#define Max( a, b )	((a) > (b) ? (a) : (b))
#define Min( a, b )	((a) < (b) ? (a) : (b))

/* floating-point arguments and value: */
#define Round( d )	floor( (d) + 0.5 )

/* arbitrary numerical arguments, integer value: */
#define	Sgn( x )	((x) == 0 ? 0 : (x) > 0 ? 1 : -1)

/* integer (or character) arguments and value: */
#ifndef	unix
#define	toascii( c )	((c) & 0177)	/* map host char set to ASCII */
#endif
#define tohostc( c )	(c)		/* map ASCII to host char set */
#define tonumber( c )	((c) - '0')	/* convt digit char to number */
#define todigit( n )	((n) + '0')	/* convt digit number to char */

/* other kludges for deficient C implementations etc.: */
/*#define	strchr	index		/* 7th Edition UNIX, 4.2BSD */
/*#define	strrchr	rindex		/* 7th Edition UNIX, 4.2BSD */
/*#define	void	int		/* K&R Appendix A followers */

#endif	/* _VLD_STD_H_ */
END OF std.h





--
Paul Palmer
Department of Mathematics     	E-mail: palmerp@math.orst.edu
Kidder Hall 368
Oregon State University, Corvallis, Oregon 97331-4605