home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #20 / NN_1992_20.iso / spool / comp / unix / shell / 3936 < prev    next >
Encoding:
Text File  |  1992-09-13  |  43.2 KB  |  1,834 lines

  1. Newsgroups: comp.unix.shell
  2. Path: sparky!uunet!spool.mu.edu!umn.edu!news.orst.edu!talon.ucs.orst.edu!palmerp
  3. From: palmerp@math.orst.edu (Paul A Palmer)
  4. Subject: Re: zork shell
  5. In-Reply-To: tinsel@uiuc.edu's message of Sat, 12 Sep 1992 23:55:26 GMT
  6. Message-ID: <PALMERP.92Sep13194045@phoebus.math.orst.edu>
  7. Sender: usenet@news.orst.edu (Usenet News admin)
  8. Nntp-Posting-Host: phoebus.math.orst.edu
  9. Reply-To: Paul Palmer <palmerp@math.orst.edu>
  10. Organization: Dept. of Math, Oregon State University
  11. References: <1992Sep8.093159.2003@drycas.club.cc.cmu.edu>
  12.     <laqbkuINN34i@jethro.Corp.Sun.COM>
  13.     <PALMERP.92Sep11135715@phoebus.math.orst.edu>
  14.     <1992Sep12.231259.13833@Princeton.EDU> <BuHp4G.5L2@news.cso.uiuc.edu>
  15. Date: Mon, 14 Sep 1992 03:40:45 GMT
  16. Lines: 1816
  17.  
  18. In article <BuHp4G.5L2@news.cso.uiuc.edu> tinsel@uiuc.edu (Thomas Aaron Insel) writes:
  19.  
  20.    subbarao@tex.Princeton.EDU (Kartik Subbarao) writes:
  21.  
  22.    > >When I read the original post, I thought he meant something like the 
  23.    > >Adventure Shell. 
  24.  
  25.    > Correct -- What the poster wants is 'ash', the Adventure Shell, not zsh,
  26.    > the Z-shell.
  27.  
  28.    Can anyone tell me where I can find this?  Archie lists a dozen or so
  29.    copies available of "ash", from comp.sources.unix v.19, I think, but
  30.    this is hacked SysV shell, not the adventure shell.
  31.  
  32. Since I've already seen a cople requests for this, I'll go ahead and post it.
  33. I had to hack a bit to get it running, but it wasn't too hard (I'm using
  34. SunOS 4.x.x).
  35.  
  36. This is from a mailing I got from someone else. I've removed the header so he
  37. doesn't get hassled. He recommended ignoring the Makefile & compiling things
  38. by hand, which is what I did. It did run under /bin/sh on my Sun, though.
  39.  
  40. ------------------------------------------------------------------------------
  41.  
  42. Will do.  Here it is...The Makefile is braindead, so what you need
  43. to do is to make the programs ask and opg by hand with make -f xxx.mk.
  44. Don't know why they did it that way, very silly.
  45.  
  46. Our /bin/sh is too stupid to run ash (which is just a big shell
  47. script) so I needed to hack it up to run under bash.  If you need that
  48. version let me know.  This is the virgin version I got in response to
  49. my query.  
  50.  
  51. #!/bin/sh
  52. # Self-unpacking archive format.  To unbundle, sh this file.
  53. echo 'Makefile' 1>&2
  54. cat >'Makefile' <<'END OF Makefile'
  55. #    Makefile -- for ash
  56.  
  57. #    last edit:    84/03/09    D A Gwyn
  58.  
  59. #    SCCS ID:    @(#)Makefile    1.3
  60.  
  61. PRODUCT = ash
  62. SHFILE    = ${PRODUCT}.sh
  63. HELP    = ${PRODUCT}.help
  64. INST    = ${PRODUCT}.inst
  65. BINDIR    = /vld/bin
  66. LIBDIR    = /vld/lib
  67. MANDIR    = /usr/5lib/man/local/man1
  68. TESTDIR = .
  69. INS    = cp
  70.  
  71. .DEFAULT:
  72.     $(GET) $(GFLAGS) -p s.$@ > ${TESTDIR}/$@
  73.     touch $@
  74.  
  75. all:        ${SHFILE} ${HELP} ${INST} ${PRODUCT}.1
  76.  
  77. print:        ${PRODUCT}.1 Makefile ${SHFILE} ${HELP} ${INST}
  78.     ( nroff -Tlp -man ${TESTDIR}/${PRODUCT}.1 ; \
  79.       pr Makefile ${TESTDIR}/${SHFILE} ${TESTDIR}/${HELP} \
  80.         ${TESTDIR}/${INST} ${TESTDIR}/${PRODUCT}.1 ) | lpr
  81.  
  82. compare:    all
  83.     cmp ${BINDIR}/${PRODUCT} ${TESTDIR}/${SHFILE}
  84.     cmp ${LIBDIR}/${HELP} ${TESTDIR}/${HELP}
  85.     cmp ${LIBDIR}/${INST} ${TESTDIR}/${INST}
  86.     cmp ${MANDIR}/${PRODUCT}.1 ${TESTDIR}/${PRODUCT}.1
  87.  
  88. install:    all
  89.     ${INS} ${TESTDIR}/${SHFILE} ${BINDIR}/${PRODUCT}
  90.     chmod 755 ${BINDIR}/${PRODUCT}
  91.     ${INS} ${TESTDIR}/${HELP} ${LIBDIR}/${HELP}
  92.     ${INS} ${TESTDIR}/${INST} ${LIBDIR}/${INST}
  93.     ${INS} ${TESTDIR}/${PRODUCT}.1 ${MANDIR}/${PRODUCT}.1
  94.     chmod 644 ${LIBDIR}/${HELP} ${LIBDIR}/${INST} \
  95.         ${MANDIR}/${PRODUCT}.1
  96.  
  97. clean:
  98.  
  99. clobber:    clean
  100.     -if vax; then rm -f ${TESTDIR}/${SHFILE} ${TESTDIR}/${HELP} \
  101.         ${TESTDIR}/${INST} ${TESTDIR}/${PRODUCT}.1; fi
  102. END OF Makefile
  103. echo 'ash.1' 1>&2
  104. cat >'ash.1' <<'END OF ash.1'
  105. .TH ASH 1V VMB
  106. '\"    last edit:    84/09/28    D A Gwyn
  107. '\"    SCCS ID:    @(#)ash.1    1.4
  108. .SH NAME
  109. ash \- interactive Adventure shell
  110. .hw PDP-11s
  111. .SH SYNOPSIS
  112. .B ash
  113. .SH DESCRIPTION
  114. .I Ash\^
  115. is a ``user friendly'' interactive command interpreter
  116. similar in function to the standard
  117. .SM UNIX
  118. shell
  119. .IR sh\^ (1).
  120. It offers two features that the standard shell does not:
  121. the ability to carry files around with you
  122. as you move around the file system,
  123. and the ability to resurrect a dead (deleted) file.
  124. .P
  125. For operating instructions,
  126. run
  127. .I ash\^
  128. and answer
  129. .B yes
  130. to the question about instructions.
  131. Additional information is available by entering the
  132. .I ash\^
  133. command
  134. .BR help .
  135. .SH RESTRICTIONS
  136. .I ash\^
  137. was developed as a joke
  138. and is not as capable as the standard shell
  139. .IR sh\^ (1).
  140. .SH EXAMPLE
  141. .RS
  142. $ \|\fIash\fP
  143. .br
  144. Welcome to the Adventure shell!  Do you need instructions? \|\fIno\fP
  145. .br
  146. You are in your own home.  This room contains:
  147. .br
  148. junk           mailbox
  149. .br
  150. There are exits labeled:
  151. .br
  152. bin           mail          work
  153. .br
  154. as well as a passage overhead.
  155. .br
  156. \o'\(em>' \|\fIopen junk\fP
  157. .br
  158. Opening the junk reveals:
  159. .br
  160. This is the contents of the file ``junk''.
  161. .br
  162. \o'\(em>' \|\fIkill junk\fP
  163. .br
  164. The junk cannot defend himself; he dies.
  165. .br
  166. \o'\(em>' \|\fIquit\fP
  167. .br
  168. Do you really want to quit now? \|\fIyes\fP
  169. .br
  170. See you later!
  171. .RE
  172. .SH FILES
  173. \s-2$HOME\s0/.knapsack
  174. .br
  175. \s-2$HOME\s0/.limbo
  176. .br
  177. /vld/lib/ash.help
  178. .br
  179. /vld/lib/ash.inst
  180. .SH "SEE ALSO"
  181. ask(1V), opg(1V), sh(1).
  182. .SH DIAGNOSTICS
  183. Error messages are meant to be puzzled out by the user.
  184. .SH AUTHOR
  185. Douglas A Gwyn, BRL/VLD-VMB
  186. .SH BUGS
  187. Due to the implementation of
  188. .I ash\^
  189. as a large shell script
  190. and some inadequacies in the way
  191. .IR sh\^ (1)
  192. handles string variable allocation,
  193. .I ash\^
  194. may abort with an
  195. ``out of space''
  196. message on PDP-11s.
  197. .P
  198. .I Ash\^
  199. is too slow.
  200. END OF ash.1
  201. echo 'ash.help' 1>&2
  202. cat >'ash.help' <<'END OF ash.help'
  203. I understand the following commands (synonyms in parentheses):
  204.  
  205. change OBJECT to NEW_NAME    changes the name of the object
  206. clone OBJECT as NEW_NAME    duplicates the object
  207. drop OBJECTS            leaves the objects in the room
  208. enter (go) PASSAGE        takes the labeled passage
  209. examine OBJECTS            describes the objects in detail
  210. feed OBJECT to MONSTER        stuffs the object into a UNIX monster
  211. get (take) OBJECTS        picks up the specified objects
  212. gripe (bug)            report a problem with the Adventure shell
  213. help                prints this summary
  214. inventory (i)            tells what you are carrying
  215. kill (destroy) OBJECTS        destroys the objects
  216. look (l)            describes the room, including hidden objects
  217. open (read) OBJECT        shows the contents of an object
  218. quit (exit)            leaves the Adventure shell
  219. resurrect OBJECTS        attempts to restore dead objects
  220. steal OBJECT from MONSTER    obtains the object from a UNIX monster
  221. throw OBJECT at daemon        feeds the object to the printer daemon
  222. up                takes the overhead passage
  223. wake MONSTER            awakens a UNIX monster
  224. where (w)            tells you where you are
  225. xyzzy                moves you to your home
  226. END OF ash.help
  227. echo 'ash.inst' 1>&2
  228. cat >'ash.inst' <<'END OF ash.inst'
  229.  
  230.         Instructions for the Adventure shell
  231.  
  232. Welcome to the Adventure shell!  In this exploration of the UNIX file
  233. system, I will act as your eyes and hands.  As you move around, I will
  234. describe whatever is visible and will carry out your commands.  The
  235. general form of a command is
  236.     Verb Object Extra_stuff.
  237. Most commands pay no attention to the "Extra_stuff", and many do not
  238. need an "Object".  A typical command is
  239.     get all
  240. which picks up all files in the current "room" (directory).  You can
  241. find out what you are carrying by typing the command
  242.     inventory
  243. The command "help" results in a full description of all commands that I
  244. understand.  To quit the Adventure shell, type
  245.     quit
  246.  
  247. There are UNIX monsters lurking in the background.  These are also
  248. known as "commands with arguments".
  249.  
  250. Good luck!
  251.  
  252. END OF ash.inst
  253. echo 'ash.sh' 1>&2
  254. cat >'ash.sh' <<'END OF ash.sh'
  255. #!/usr/5bin/sh
  256. #    ash -- "Adventure shell"
  257. #    last edit:    86/04/21    D A Gwyn
  258. #    SCCS ID:    @(#)ash.sh    1.4
  259.  
  260. OPATH=$PATH
  261.  
  262. ASK=/vld/bin/ask
  263. CAT=/vld/bin/opg
  264. HELP=/vld/lib/ash.help
  265. INST=/vld/lib/ash.inst
  266. MAINT=Gwyn@BRL.ARPA
  267. PATH=/usr/5bin:/bin:/usr/bin
  268. export PATH
  269.  
  270. trap 'echo Ouch!' 2 3
  271. trap '' 18            # disable Berkeley job control
  272.  
  273. ash_lk(){ echo " $1 " | fgrep " $2 " >&- 2>&-; }
  274. ash_pr(){ echo $* | tr ' ' '\012' | pr -5 -t -w75; }
  275. ash_rm(){ echo " $1 " | sed -e "s/ $2 / /" -e 's/^ //' -e 's/ $//'; }
  276.  
  277. cd
  278. LIM=.limbo            # $HOME/$LIM contains "destroyed" objects
  279. mkdir $LIM >&- 2>&-
  280. KNAP=.knapsack            # $HOME/$KNAP contains objects being "carried"
  281. if [ ! -d $KNAP ]
  282. then    mkdir $KNAP >&- 2>&-
  283.     if [ $? = 0 ]
  284.     then    echo 'You found a discarded empty knapsack.'
  285.     else    echo 'You have no knapsack to carry things in.'
  286.         exit 1
  287.     fi
  288. else    echo 'One moment while I peek in your old knapsack...'
  289. fi
  290.  
  291. kn=`echo \`ls -a $KNAP | sed -e '/^\.$/d' -e '/^\.\.$/d'\``
  292.  
  293. if $ASK 'Welcome to the Adventure shell!  Do you need instructions?'
  294. then    $CAT < $INST
  295.     echo 'Type a newline to continue: \c'
  296.     read i
  297. fi
  298.  
  299. wiz=false
  300. cha=false
  301. prev=$LIM
  302. while :
  303. do    room=`pwd`
  304.     if [ $room != $prev ]
  305.     then    if [ $room = $HOME ]
  306.         then    echo 'You are in your own home.  \c'
  307.         else    echo "You have entered $room.  \c"
  308.         fi
  309.         exs=
  310.         obs=
  311.         hexs=
  312.         hobs=
  313.         f=false
  314.         for i in `ls -a`
  315.         do    case $i in
  316.             .|..)    ;;
  317.             .*)    if [ -f $i ]
  318.                 then    hobs="$hobs $i"
  319.                 elif [ -d $i ]
  320.                 then    hexs="$hexs $i"
  321.                 else    f=true
  322.                 fi
  323.                 ;;
  324.             *)    if [ -f $i ]
  325.                 then    obs="$obs $i"
  326.                 elif [ -d $i ]
  327.                 then    exs="$exs $i"
  328.                 else    f=true
  329.                 fi
  330.                 ;;
  331.             esac
  332.         done
  333.         if [ "$obs" ]
  334.         then    echo 'This room contains:'
  335.             ash_pr $obs
  336.         else    echo 'The room looks empty.'
  337.         fi
  338.         if [ "$exs" ]
  339.         then    echo 'There are exits labeled:'
  340.             ash_pr $exs
  341.             echo 'as well as a passage overhead.'
  342.         else    echo 'There is a passage overhead.'
  343.         fi
  344.         if sh -c $f
  345.         then    echo 'There are shadowy figures in the corner.'
  346.         fi
  347.         prev=$room
  348.     fi
  349.  
  350.     echo '-\b> \c'            # prompt
  351.     read verb obj x
  352.     if [ $? != 0 ]
  353.     then    verb=quit        # EOF
  354.     fi
  355.  
  356.     case $verb in
  357.     change)        if [ "$obj" ]
  358.             then    if ash_lk "$obs $hobs" "$obj"
  359.                 then    set -- $x
  360.                     case "$1" in
  361.                     to)    if [ "$2" ]
  362.                         then    if [ -f $2 ]
  363.                             then    echo "You must destroy $2 first."
  364.                                 set --
  365.                             fi
  366.                             if [ "$2" ]
  367.                             then    if mv $obj $2 >&- 2>&-
  368.                                 then    echo "The $obj shimmers and turns into $2."
  369.                                     obs=`ash_rm "$2 $obs" "$obj"`
  370.                                 else    echo "There is a cloud of smoke but the $obj is unchanged."
  371.                                 fi
  372.                             fi
  373.                         else    echo 'To what?'
  374.                         fi
  375.                         ;;
  376.                     *)    echo "Change $obj to what?"
  377.                         ;;
  378.                     esac
  379.                 else    if ash_lk "$kn" "$obj"
  380.                     then    echo 'You must drop it first.'
  381.                     else    echo "I see no $obj here."
  382.                     fi
  383.                 fi
  384.             else    echo 'Change what?'
  385.             fi
  386.             ;;
  387.     clone)        if [ "$obj" ]
  388.             then    if ash_lk "$obs $hobs" "$obj"
  389.                 then    if [ ! -r $obj ]
  390.                     then    echo "The $obj does not wish to be cloned."
  391.                     else    set -- $x
  392.                         case "$1" in
  393.                         as)    if [ "$2" ]
  394.                             then    if [ -f $2 ]
  395.                                 then    echo "You must destroy $2 first."
  396.                                 else    if cp $obj $2 >&- 2>&-
  397.                                     then    echo "Poof!  When the smoke clears, you see the new $2."
  398.                                         obs="$obs $2"
  399.                                     else    echo 'You hear a dull thud but no clone appears.'
  400.                                     fi
  401.                                 fi
  402.                             else    echo 'As what?'
  403.                             fi
  404.                             ;;
  405.                         *)    echo "Clone $obj as what?"
  406.                             ;;
  407.                         esac
  408.                     fi
  409.                 else    if ash_lk "$kn" "$obj"
  410.                     then    echo 'You must drop it first.'
  411.                     else    echo "I see no $obj here."
  412.                     fi
  413.                 fi
  414.             else    echo 'Clone what?'
  415.             fi
  416.             ;;
  417.     drop)        if [ "$obj" ]
  418.             then    for it in $obj $x
  419.                 do    if ash_lk "$kn" "$it"
  420.                     then    if [ -w $it ]
  421.                         then    echo "You must destroy $it first."
  422.                         else    if mv $HOME/$KNAP/$it $it >&- 2>&-
  423.                             then    echo "$it: dropped."
  424.                                 kn=`ash_rm "$kn" "$it"`
  425.                                 obs=`echo $it $obs`
  426.                             else    echo "The $it is caught in your knapsack."
  427.                             fi
  428.                         fi
  429.                     else    echo "You're not carrying the $it!"
  430.                     fi
  431.                 done
  432.             else    echo 'Drop what?'
  433.             fi
  434.             ;;
  435.     enter|go)    if [ "$obj" ]
  436.             then    if [ $obj != up ]
  437.                 then    if ash_lk "$exs $hexs" "$obj"
  438.                     then    if [ -x $obj ]
  439.                         then    if cd $obj
  440.                             then    echo 'You squeeze through the passage.'
  441.                             else    echo "You can't go that direction."
  442.                             fi
  443.                         else    echo 'An invisible force blocks your way.'
  444.                         fi
  445.                     else    echo 'I see no such passage.'
  446.                     fi
  447.                 else    if cd ..
  448.                     then    echo 'You struggle upwards.'
  449.                     else    echo "You can't reach that high."
  450.                     fi
  451.                 fi
  452.             else    echo 'Which passage?'
  453.             fi
  454.             ;;
  455.     examine)    if [ "$obj" ]
  456.             then    if [ $obj = all ]
  457.                 then    $obj=`echo $obs $exs`
  458.                     x=
  459.                 fi
  460.                 for it in $obj $x
  461.                 do    if ash_lk "$obs $hobs $exs $hexs" "$it"
  462.                     then    echo "Upon close inspection of the $it, you see:"
  463.                         ls -ld $it 2>&-
  464.                         if [ $? != 0 ]
  465.                         then    echo "-- when you look directly at the $it, it vanishes."
  466.                         fi
  467.                     else    if ash_lk "$kn" "$it"
  468.                         then    echo 'You must drop it first.'
  469.                         else    echo "I see no $it here."
  470.                         fi
  471.                     fi
  472.                 done
  473.             else    echo 'Examine what?'
  474.             fi
  475.             ;;
  476.     feed)        if [ "$obj" ]
  477.             then    if ash_lk "$obs $hobs" "$obj"
  478.                 then    set -- $x
  479.                     case "$1" in
  480.                     to)    if [ "$2" ]
  481.                         then    shift
  482.                             if env PATH=$OPATH $* <$obj 2>&-
  483.                             then    echo "The $1 monster devours your $obj."
  484.                                 if rm -f $obj >&- 2>&-
  485.                                 then    obs=`ash_rm "$obs" "$obj"`
  486.                                 else    echo 'But he spits it back up.'
  487.                                 fi
  488.                             else    echo "The $1 monster holds his nose in disdain."
  489.                             fi
  490.                         else    echo 'To what?'
  491.                         fi
  492.                         ;;
  493.                     *)    echo "Feed $obj to what?"
  494.                         ;;
  495.                     esac
  496.                 else    if ash_lk "$kn" "$obj"
  497.                     then    echo 'You must drop it first.'
  498.                     else    echo "I see no $obj here."
  499.                     fi
  500.                 fi
  501.             else    echo 'Feed what?'
  502.             fi
  503.             ;;
  504.     get|take)    if [ "$obj" ]
  505.             then    if [ $obj = all ]
  506.                 then    obj="$obs"
  507.                     x=
  508.                 fi
  509.                 for it in $obj $x
  510.                 do    if ash_lk "$obs $hobs" "$it"
  511.                     then    if ash_lk "$kn" "$it"
  512.                         then    echo 'You already have one.'
  513.                         else    if mv $it $HOME/$KNAP/$it >&- 2>&-
  514.                             then    echo "$it: taken."
  515.                                 kn="$it $kn"
  516.                                 obs=`ash_rm "$obs" "$it"`
  517.                             else    echo "The $it is too heavy."
  518.                             fi
  519.                         fi
  520.                     else    echo "I see no $it here."
  521.                     fi
  522.                 done
  523.             else    echo 'Get what?'
  524.             fi
  525.             ;;
  526.     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.'
  527.             cat | mail $MAINT -s 'ash bug'
  528.             echo 'Thank you!'
  529.             ;;
  530.     help)        $CAT < $HELP
  531.             ;;
  532.     inventory|i)    if [ "$kn" ]
  533.             then    echo 'Your knapsack contains:'
  534.                 ash_pr $kn
  535.             else    echo 'You are poverty-stricken.'
  536.             fi
  537.             ;;
  538.     kill|destroy)    if [ "$obj" ]
  539.             then    if [ $obj = all ]
  540.                 then    x=
  541.                     if $ASK "Do you really want to attempt to $verb them all?"
  542.                     then    obj=`echo $obs`
  543.                     else    echo 'Chicken!'
  544.                         obj=
  545.                     fi
  546.                 fi
  547.                 for it in $obj $x
  548.                 do    if ash_lk "$obs $hobs" "$it"
  549.                     then    if mv $it $HOME/$LIM <&- >&- 2>&-
  550.                         then    if [ $verb = kill ]
  551.                             then    echo "The $it cannot defend himself; he dies."
  552.                             else    echo "You have destroyed the $it; it vanishes."
  553.                             fi
  554.                             obs=`ash_rm "$obs" "$it"`
  555.                         else    if [ $verb = kill ]
  556.                             then    echo "Your feeble blows are no match for the $it."
  557.                             else    echo "The $it is indestructible."
  558.                             fi
  559.                         fi
  560.                     else    if ash_lk "$kn" "$it"
  561.                         then    echo "You must drop the $it first."
  562.                             found=false
  563.                         else    echo "I see no $it here."
  564.                         fi
  565.                     fi
  566.                 done
  567.             else    echo 'Kill what?'
  568.             fi
  569.             ;;
  570.     look|l)        obs=`echo $obs $hobs`
  571.             hobs=
  572.             if [ "$obs" ]
  573.             then    echo 'The room contains:'
  574.                 ash_pr $obs
  575.             else    echo 'The room is empty.'
  576.             fi
  577.             exs=`echo $exs $hexs`
  578.             hexs=
  579.             if [ "$exs" ]
  580.             then    echo 'There are exits plainly labeled:'
  581.                 ash_pr $exs
  582.                 echo 'and a passage directly overhead.'
  583.             else    echo 'The only exit is directly overhead.'
  584.             fi
  585.             ;;
  586.     magic)        if [ "$obj" = mode ]
  587.             then    if sh -c $cha
  588.                 then    echo 'You had your chance and you blew it.'
  589.                 else    if $ASK 'Are you a wizard?'
  590.                     then    echo 'Prove it!  Say the magic word: \c'
  591.                         read obj
  592.                         if [ "$obj" = armadillo ]
  593.                         then    echo 'Yes, master!!'
  594.                             wiz=true
  595.                         else    echo "Foo, you're nothing but a charlatan!"
  596.                             cha=true
  597.                         fi
  598.                     else    echo "I didn't think so."
  599.                     fi
  600.                 fi
  601.             else    echo 'Nice try.'
  602.             fi
  603.             ;;
  604.     open|read)    if [ "$obj" ]
  605.             then    if ash_lk "$obs $hobs" "$obj"
  606.                 then    if [ -r $obj ]
  607.                     then    if [ -s $obj ]
  608.                         then    echo "Opening the $obj reveals:"
  609.                             $CAT < $obj 2>&-
  610.                             if [ $? != 0 ]
  611.                             then    echo '-- oops, you lost the contents!'
  612.                             fi
  613.                         else    echo "There is nothing inside the $obj."
  614.                         fi
  615.                     else    echo "You do not have the proper tools to open the $obj."
  616.                     fi
  617.                 else    if ash_lk "$kn" "$obj"
  618.                     then    echo 'You must drop it first.'
  619.                         found=false
  620.                     else    echo "I see no $obj here."
  621.                     fi
  622.                 fi
  623.             else    echo 'Open what?'
  624.             fi
  625.             ;;
  626.     quit|exit)    if $ASK 'Do you really want to quit now?'
  627.             then    if [ "$kn" ]
  628.                 then    echo 'The contents of your knapsack will still be there next time.'
  629.                 fi
  630.                 rm -rf $HOME/$LIM
  631.                 echo 'See you later!'
  632.                 exit 0
  633.             fi
  634.             ;;
  635.     resurrect)    if [ "$obj" ]
  636.             then    for it in $obj $x
  637.                 do    if ash_lk "$obs $hobs" "$it"
  638.                     then    echo "The $it is already alive and well."
  639.                     else    if mv $HOME/$LIM/$it $it <&- >&- 2>&-
  640.                         then    echo "The $it staggers to his feet."
  641.                             obs=`echo $it $obs`
  642.                         else    echo "There are sparks but no $it appears."
  643.                         fi
  644.                     fi
  645.                 done
  646.             else    echo 'Resurrect what?'
  647.             fi
  648.             ;;
  649.     steal)        if [ "$obj" ]
  650.             then    if ash_lk "$obs $hobs" "$obj"
  651.                 then    echo 'There is already one here.'
  652.                 else    set -- $x
  653.                     case "$1" in
  654.                     from)    if [ "$2" ]
  655.                         then    shift
  656.                             if env PATH=$OPATH $* >$obj 2>&-
  657.                             then    echo "The $1 monster drops the $obj."
  658.                                 obs=`echo $obj $obs`
  659.                             else    echo "The $1 monster runs away as you approach."
  660.                                 rm -f $obj >&- 2>&-
  661.                             fi
  662.                         else    echo 'From what?'
  663.                         fi
  664.                         ;;
  665.                     *)    echo "Steal $obj from what?"
  666.                         ;;
  667.                     esac
  668.                 fi
  669.             else    echo 'Steal what?'
  670.             fi
  671.             ;;
  672.     throw)        if [ "$obj" ]
  673.             then    if ash_lk "$obs $hobs" "$obj"
  674.                 then    set -- $x
  675.                     case "$1" in
  676.                     at)    case "$2" in
  677.                         daemon)    if sh -c "lpr -r $obj"
  678.                             then    echo "The daemon catches the $obj, turns it into paper,\nand leaves it in the basket."
  679.                                 obs=`ash_rm "$obs" "$obj"`
  680.                             else    echo "The daemon is nowhere to be found."
  681.                             fi
  682.                             ;;
  683.                         *)    echo 'At what?'
  684.                             ;;
  685.                         esac
  686.                         ;;
  687.                     *)    echo "Throw $obj at what?"
  688.                         ;;
  689.                     esac
  690.                 else    if ash_lk "$kn" "$obj"
  691.                     then    echo 'It is in your knapsack.'
  692.                         found=false
  693.                     else    echo "I see no $obj here."
  694.                     fi
  695.                 fi
  696.             else    echo 'Throw what?'
  697.             fi
  698.             ;;
  699.     u|up)        if cd ..
  700.             then    echo 'You pull yourself up a level.'
  701.             else    echo "You can't reach that high."
  702.             fi
  703.             ;;
  704.     wake)        if [ "$obj" ]
  705.             then    echo "You awaken the $obj monster:"
  706.                 env PATH=$OPATH $obj $x
  707.                 echo 'The monster slithers back into the darkness.'
  708.             else    echo 'Wake what?'
  709.             fi
  710.             ;;
  711.     w|where)    echo "You are in $room."
  712.             ;;
  713.     xyzzy)        if cd
  714.             then    echo 'A strange feeling comes over you.'
  715.             else    echo 'Your spell fizzles out.'
  716.             fi
  717.             ;;
  718.     *)        if [ "$verb" ]
  719.             then    if sh -c $wiz
  720.                 then    env PATH=$OPATH $verb $obj $x
  721.                 else    echo "I don't know how to \"$verb\"."
  722.                     echo 'Type "help" for assistance.'
  723.                 fi
  724.             else    echo 'Say something!'
  725.             fi
  726.             ;;
  727.     esac
  728. done
  729. END OF ash.sh
  730. echo 'ask.1' 1>&2
  731. cat >'ask.1' <<'END OF ask.1'
  732. .TH ASK 1V VMB
  733. '\"    last edit:    85/03/05    D A Gwyn
  734. '\"    SCCSID        @(#)ask.1    1.6
  735. .SH NAME
  736. ask \- ask the user a question and exit with appropriate status
  737. .SH SYNOPSIS
  738. .B ask
  739. [
  740. .B \-n
  741. ] [
  742. .B \-y
  743. ] word ...
  744. .SH DESCRIPTION
  745. .I Ask\^
  746. displays the
  747. .IR word\^ s
  748. (which will usually ask a Yes/No question
  749. ending with a question mark)
  750. separated by spaces
  751. as a user query message
  752. on the terminal
  753. and gets a response from
  754. the user.
  755. .P
  756. Valid user responses consist of
  757. optional white space followed by
  758. any word beginning with
  759. an upper- or lower-case
  760. .B N
  761. (taken as ``No'')
  762. or an upper- or lower-case
  763. .B Y
  764. (taken as ``Yes'').
  765. If the optional
  766. .B \-n
  767. or
  768. .B \-y
  769. flag is used,
  770. a null response
  771. (all whitespace, such as just a \s-2NEWLINE\s0)
  772. is taken to mean ``No'' or ``Yes'', respectively.
  773. .SH EXAMPLE
  774. The following shell command
  775. emulates the behavior of
  776. .B "rm\ \|\-i\ \|*"
  777. while giving a somewhat improved user prompt message:
  778. .RS
  779. $ \|\fIfor \|$file \|in \|*\fP
  780. .br
  781. > \|\fIdo    if \|ask \|\-n \|Delete \|$file\\?\fP
  782. .br
  783. >        \fIthen    rm \|\-f \|$file\fP
  784. .br
  785. >        \fIfi\fP
  786. .br
  787. > \|\fIdone\fP
  788. .RE
  789. Notice that the question mark must be protected from
  790. interpretation by the shell.
  791. .SH FILES
  792. /dev/tty
  793. .SH "SEE ALSO"
  794. echo(1), find(1), pick(1V), sh(1).
  795. .SH DIAGNOSTICS
  796. I/O errors cause a default response to be assumed
  797. (``No'' unless the
  798. .B \-y
  799. flag is used).
  800. Invalid user responses cause the query to be repeated
  801. until a valid response is received.
  802. .SH "EXIT CODES"
  803. Exit status 0 is returned for a ``Yes'' response
  804. and 1 for a ``No'' response.
  805. .SH AUTHORS
  806. John S. Quarterman, Geotronics Corporation
  807. .br
  808. Douglas A. Gwyn, BRL/VLD-VMB
  809. END OF ask.1
  810. echo 'ask.c' 1>&2
  811. cat >'ask.c' <<'END OF ask.c'
  812. /*
  813.     ask -- ask the user a question and exit with appropriate status
  814.         (Original version due to JSQ; modified by DAG)
  815.  
  816.     last edit:    83/10/19    D A Gwyn
  817.  
  818. The arguments are echoed as a prompt for a Yes/No response; all I/O is
  819. performed on ctermid().  "ask" does not supply a trailing question mark.
  820.  
  821. Upper or lower case `Y' or `N' as the first non-blank character of the
  822. answer, or a null response when a "-n" or "-y" flag is given, are the
  823. only accepted responses; anything else causes the prompt to be repeated.
  824.  
  825. If the first argument is "-n" or "-y", then a null (blank) response will
  826. be taken to mean "No" or "Yes", respectively; otherwise a null response
  827. is considered invalid and the request is repeated.
  828.  
  829. Exit code 0 indicates Yes, 1 indicates No; errors produce a default
  830. exit code (0 if "-y" flag is given; 1 otherwise).
  831. */
  832. static char    sccsid[] = "@(#)ask.c    1.4";
  833.  
  834. #include    <stdio.h>
  835. #include    <string.h>
  836.  
  837. extern void    exit();
  838. extern char    *malloc();
  839.  
  840. main( argc, argv )            /* "ask" executive */
  841.     int        argc;        /* argument count */
  842.     char        **argv;     /* argument vector */
  843.     {
  844.     int        nullresp;    /* null response semantics:
  845.                         0 => invalid;
  846.                        -1 => "No";
  847.                         1 => "Yes".
  848.                      */
  849.     register FILE    *input, *output;/* terminal i/o streams */
  850.     char        *pname = *argv; /* program invocation name */
  851.  
  852.     /* first argument "-n" or "-y" permits null response */
  853.  
  854.     nullresp = 0;            /* default: null => invalid */
  855.     if ( argc > 1 )
  856.         if ( strcmp( argv[1], "-n" ) == 0 )
  857.             nullresp = -1;    /* null => "No" */
  858.         else if ( strcmp( argv[1], "-y" ) == 0 )
  859.             nullresp = 1;    /* null => "Yes" */
  860.     if ( nullresp != 0 )
  861.         --argc, ++argv;
  862.  
  863.     /* set up terminal i/o */ 
  864.     {
  865.     register char    *tname;     /* filename for terminal */
  866.  
  867.     if ( (tname = ctermid( (char *)NULL )) == NULL )
  868.         {
  869.         (void)fprintf( stderr, "%s: no terminal available\n",
  870.                    pname
  871.                  );
  872.         exit( nullresp > 0 ? 0 : 1 );
  873.         }
  874.  
  875.     if ( (output = fopen( tname, "w" )) == NULL )
  876.         {
  877.         (void)fprintf( stderr, "%s: can't write \"%s\"\n",
  878.                    pname, tname
  879.                  );
  880.         exit( nullresp > 0 ? 0 : 1 );
  881.         }
  882.     setbuf( output, malloc( BUFSIZ ) );
  883.  
  884.     if ( (input = fopen( tname, "r" )) == NULL )
  885.         {
  886.         (void)fprintf( stderr, "%s: can't read \"%s\"\n",
  887.                    pname, tname
  888.                  );
  889.         exit( nullresp > 0 ? 0 : 1 );
  890.         }
  891.     setbuf( input, (char *)NULL );
  892.     }
  893.  
  894.     if ( argc < 2 )
  895.         {
  896.         (void)printf( "\"%s question\" prints the question,\n",
  897.                   pname
  898.                 );
  899.         (void)printf( "waits for a Yes/No response,\n" );
  900.         (void)printf( "and returns the appropriate exit code.\n"
  901.                 );
  902.  
  903.         (void)fprintf( stderr, "%s: no arguments\n", pname );
  904.         exit( nullresp > 0 ? 0 : 1 );
  905.         }
  906.  
  907.     /* keep prompting and getting response until valid */
  908.  
  909.     for ( ; ; )
  910.         {
  911.         char    inbuf[BUFSIZ];    /* user-response input buffer */
  912.         int    narg = argc;    /* argument counter */
  913.         char    **word = argv;    /* argument pointer */
  914.  
  915.         /* print arguments followed by one space each */
  916.  
  917.         for ( --narg, ++word; narg > 0; --narg, ++word )
  918.             if ( fprintf( output, "%s ", *word ) != 
  919.                  strlen( *word ) + 1
  920.                )    {
  921.                 (void)fprintf( stderr,
  922.                            "%s: output error\n",
  923.                            pname
  924.                          );
  925.                 exit( nullresp > 0 ? 0 : 1 );
  926.                 }
  927.         (void)fflush( output );
  928.  
  929.         /* get response */
  930.  
  931.         if ( fgets( inbuf, sizeof inbuf, input ) == NULL )
  932.             {
  933.             (void)fprintf( stderr, "%s: input error\n",
  934.                        pname
  935.                      );
  936.             exit( nullresp > 0 ? 0 : 1 );
  937.             }
  938.  
  939.         /* return appropriate status code */
  940.         {
  941.         register char    *first; /* -> first char of response */
  942.  
  943.         if ( (first = strtok( inbuf, " \t\n" )) == NULL )
  944.             if ( nullresp < 0 )
  945.                 exit( 1 );    /* same as "No" */
  946.             else if ( nullresp > 0 )
  947.                 exit( 0 );    /* same as "Yes" */
  948.             else
  949.                 first = "x";    /* invalid response */
  950.         if ( *first == 'N' || *first == 'n' )
  951.             exit( 1 );
  952.         if ( *first == 'Y' || *first == 'y' )
  953.             exit( 0 );
  954.         }
  955.  
  956.         /* response was invalid; help user respond */
  957.         {
  958.         static char    help[] = "Please answer `Y' or `N'\n";
  959.  
  960.         if ( fprintf( output, help ) != sizeof help - 1 )
  961.             {
  962.             (void)fprintf( stderr, "%s: output error\n",
  963.                        pname
  964.                      );
  965.             exit( nullresp > 0 ? 0 : 1 );
  966.             }
  967.         }
  968.         }
  969.     /*NOTREACHED*/
  970.     }
  971. END OF ask.c
  972. echo 'ask.mk' 1>&2
  973. cat >'ask.mk' <<'END OF ask.mk'
  974. #    ask.mk -- makefile for "ask" utility
  975.  
  976. #    last edit:    86/11/10    D A Gwyn
  977.  
  978. #    SCCS ID:    @(#)ask.mk    1.11
  979.  
  980. PRODUCT = ask
  981. MKFILE    = ${PRODUCT}.mk
  982. CFILES    = ${PRODUCT}.c
  983. OBJS    = ${PRODUCT}.o
  984. LDFLAGS = -n
  985. BINDIR    = /vld/bin
  986. MANDIR    = /usr/5lib/man/local/man1
  987. BINPERM    = 775
  988. MANPERM    = 664
  989. INS    = cp
  990.  
  991. .DEFAULT:
  992.     $(GET) $(GFLAGS) -p s.$@ > $@
  993.     touch $@
  994.  
  995. all:        ${PRODUCT} ${PRODUCT}.1
  996.  
  997. ${PRODUCT}:    ${OBJS}
  998.     $(CC) -o $@ ${LDFLAGS} ${OBJS}
  999.     size $@
  1000.     touch $@
  1001.  
  1002. print:        ${PRODUCT}.1 ${MKFILE} ${CFILES}
  1003.     ( nroff -Tlp -man ${PRODUCT}.1 ; \
  1004.       pr ${MKFILE} ${CFILES} ${PRODUCT}.1 ) | lpr
  1005.  
  1006. lint:        ${CFILES}
  1007.     lint ${CFILES} > ${PRODUCT}.lint
  1008.  
  1009. compare:    all
  1010.     cmp ${BINDIR}/${PRODUCT} ${PRODUCT}
  1011.     cmp ${MANDIR}/${PRODUCT}.1 ${PRODUCT}.1
  1012.  
  1013. install:    all
  1014.     -chmod ${BINPERM} ${PRODUCT}
  1015.     ${INS} ${PRODUCT} ${BINDIR}
  1016.     -chmod ${MANPERM} ${PRODUCT}.1
  1017.     ${INS} ${PRODUCT}.1 ${MANDIR}
  1018.  
  1019. clean:
  1020.     -if vax; then rm -f ${CFILES}; fi
  1021.     -rm -f ${OBJS} ${PRODUCT}.lint
  1022.  
  1023. clobber:    clean
  1024.     -if vax; then rm -f ${PRODUCT}.1; fi
  1025.     -rm -f ${PRODUCT}
  1026. END OF ask.mk
  1027. echo 'opg.1' 1>&2
  1028. cat >'opg.1' <<'END OF opg.1'
  1029. .TH OPG 1V VMB
  1030. '\"    last edit:    85/03/05    D A Gwyn
  1031. '\"    SCCSID        @(#)opg.1    1.9
  1032. .SH NAME
  1033. opg \- paginate files to terminal
  1034. .SH SYNOPSIS
  1035. .B opg
  1036. [
  1037. .B \-e
  1038. ] [
  1039. .B \-h
  1040. screen_height
  1041. ] [
  1042. .B \-T
  1043. terminal
  1044. ] [
  1045. .B \-w
  1046. line_width
  1047. ] [ file ... ]
  1048. .SH DESCRIPTION
  1049. .I Opg\^
  1050. displays the contents of the specified
  1051. .IR file\^ s
  1052. (standard input if not given)
  1053. on the terminal
  1054. attached to its standard output,
  1055. one screenload at a time.
  1056. At the end of each screen,
  1057. .I opg\^
  1058. asks ``More?'' (if reading standard input)
  1059. or ``More\ of\ \fIfile\^\fP?''
  1060. and inputs a single-character response
  1061. >from the user's terminal;
  1062. any response except
  1063. .BR N ,
  1064. .BR n ,
  1065. or EOT
  1066. causes the next screenload to be displayed.
  1067. Similarly,
  1068. .I opg\^
  1069. asks ``Next\ file\ (\fIfile\^\fP)?''
  1070. before every
  1071. .I file\^
  1072. but the first
  1073. and inputs a single-character response
  1074. >from the terminal;
  1075. any response except
  1076. .BR N ,
  1077. .BR n ,
  1078. or EOT
  1079. causes the next
  1080. .I file\^
  1081. to be displayed.
  1082. .P
  1083. The range of lines visible is shown as
  1084. ``[\fIfirst\^\fP\-\fIlast\^\fP]''
  1085. before the ``More?''
  1086. prompt,
  1087. and the name of the just-ended file is shown as
  1088. ``[end\ of\ \fIfile\^\fP]''
  1089. before the ``Next\ file?'' prompt if any.
  1090. .P
  1091. SIGINT aborts the current file;
  1092. SIGQUIT aborts
  1093. .IR opg\^ .
  1094. These are disabled when the
  1095. .B \-e
  1096. flag is specified;
  1097. this may be necessary to
  1098. preserve escape sequence integrity.
  1099. After SIGINT, ``[\fIfile\^\fP\ aborted]'' is shown.
  1100. .P
  1101. Environment variable
  1102. .B \s-2TERM\s0
  1103. is used to determine terminal type;
  1104. the
  1105. .B \-T
  1106. option overrides this.
  1107. Only a few terminal types
  1108. are known to
  1109. .IR opg\^ ;
  1110. an unknown terminal type is scrolled
  1111. rather than painting its screen from the top down.
  1112. A terminal known to use ANSI escape sequences
  1113. has the
  1114. .B \-e
  1115. flag automatically set.
  1116. .P
  1117. The optional
  1118. .I line_width\^
  1119. is the number of characters on a line without the cursor wrapping
  1120. (default 79),
  1121. and the optional
  1122. .I screen_height\^
  1123. is the number of lines visible on the display (default 24).
  1124. If the operating system supports a ``get window size'' feature,
  1125. it will be used to determine the display dimensions.
  1126. .SH WARNING
  1127. This program is essentially superceded by
  1128. the more powerful UNIX System V Release 2 utility
  1129. .IR pg\^ (1).
  1130. It is expected to vanish someday.
  1131. .SH EXAMPLE
  1132. .RS
  1133. $ \|\fIopg \|\-T vt100 \|*.c\fP
  1134. .RE
  1135. .SH FILES
  1136. /dev/tty
  1137. .SH "SEE ALSO"
  1138. cat(1), pg(1).
  1139. .SH DIAGNOSTICS
  1140. If the standard output is not a terminal,
  1141. .I opg\^
  1142. will terminate
  1143. with an error message
  1144. and return non-zero exit status.
  1145. If the terminal type is unknown,
  1146. a warning message is printed
  1147. and scrolling is used instead of screen painting.
  1148. .SH AUTHOR
  1149. Douglas A. Gwyn, BRL/VLD-VMB
  1150. .SH BUGS
  1151. This program should use
  1152. .IR termcap\^ (4)
  1153. or
  1154. .IR terminfo\^ (4)
  1155. rather than a built-in table.
  1156. END OF opg.1
  1157. echo 'opg.c' 1>&2
  1158. cat >'opg.c' <<'END OF opg.c'
  1159. /*
  1160.     opg -- paginate input files (can be used as end of a pipeline)
  1161.  
  1162.     last edit:    87/03/23    D A Gwyn
  1163.  
  1164. Usage:
  1165.     $ opg[ -e][ -h screen_ht][ -T terminal][ -w line_width] file ...
  1166.     or
  1167.     $ program | opg[ -e][ -h screen_ht][ -T terminal][ -w line_width]
  1168.  
  1169.     where `terminal' is a terminal designator (e.g., "vt100"),
  1170.     `line_width' is the number of characters on a line (default 79),
  1171.     `screen_ht' is the number of lines on a screen (default 24).
  1172.     Whitespace before these parameters is optional.
  1173.  
  1174. Method:
  1175.     Copies argument files (or standard input, if no file args) to
  1176.     standard output one screenload at a time.  After each screen,
  1177.     "More of <file>?" (just "More?" if standard input) is asked; any
  1178.     response except "n" or EOT will present the next screen.  "Next
  1179.     file (<file>)?" is asked before each file except the first.
  1180.     The range of lines visible is shown as "[<s>-<e>]" before the
  1181.     "More?" prompt, and the name of the just-ended file is shown as
  1182.     "[end of <file>]", before the "Next File?" prompt if any.
  1183.  
  1184.     SIGINT aborts the current file; SIGQUIT aborts "opg".  These are
  1185.     disabled when the "-e" flag is specified, to preserve escape
  1186.     sequence integrity.  After SIGINT, "[<file> aborted]" is shown.
  1187.  
  1188.     Environment variable "TERM" is used to set up terminal type; the
  1189.     -T option overrides this.  An unknown terminal type is scrolled
  1190.     rather than painting its screen from the top down.
  1191. */
  1192. #ifndef    lint
  1193. static char    sccsid[] = "@(#)opg.c    1.14";
  1194. #endif
  1195.  
  1196. #include    <ctype.h>
  1197. #include    <termio.h>
  1198. #include    <signal.h>
  1199. #include    <stdio.h>
  1200. #include    <string.h>
  1201.  
  1202. #include    <std.h>
  1203.  
  1204. #define    TERMINAL    "/dev/tty"    /* UNIX filename for terminal */
  1205.  
  1206. extern void    exit();
  1207. extern char    *getenv(), *malloc();
  1208. extern int    ioctl();
  1209.  
  1210. static void    clear(), intr(), quit();
  1211. static bool    more(), setterm();
  1212.  
  1213. /* screen-clear code sequences vary: */
  1214. #define    UNK    (-1)
  1215. #define    ANSI    0
  1216. #define    ADM3    1
  1217. #define    VT52    2
  1218. #define    FF    3
  1219. static int    ttype = UNK;        /* screen-clear code type */
  1220.  
  1221. static int    linesize = 79;        /* chars before wrap-around */
  1222. static int    pagesize = 24;        /* # of lines on terminal */
  1223. static int    filnum = 1;        /* file being processed */
  1224. static bool    eflag = false;        /* support escape sequences */
  1225. static bool    neednl = false;     /* newline needed on stdout */
  1226. static bool    typeit = false;     /* turned off by SIGINT */
  1227.  
  1228. static struct termio    tty = { 0 };
  1229. static struct termio    omode = { 0 };    /* original terminal mode */
  1230. static struct termio    rmode = { 0 };    /* raw mode during prompt */
  1231.  
  1232. main( argc, argv )
  1233.     int    argc;
  1234.     char    *argv[];
  1235.     {
  1236.     char    *fname;         /* filename file for prompt */
  1237.  
  1238.     {
  1239.     register char    *tname;     /* terminal name */
  1240.  
  1241.     if ( (tname = getenv( "TERM" )) != NULL )
  1242.         (void)setterm( tname ); /* if possible */
  1243.     }
  1244.  
  1245.     while ( argc > 1 && (*++argv)[0] == '-' )
  1246.         {            /* process option */
  1247.         switch( (int)(*argv)[1] )
  1248.             {
  1249.             register char    *arg;    /* additional param */
  1250.             int        temp;    /* converted value */
  1251.  
  1252.         case 'e':        /* "-e" */
  1253.             eflag = true;
  1254.             break;
  1255.  
  1256.         case 'h':        /* "-h screen_ht" */
  1257.             if ( *(arg = &(*argv)[2]) == '\0' )
  1258.                 {
  1259.                 --argc;
  1260.                 arg = *++argv;
  1261.                 }
  1262.             if ( sscanf( arg, "%d", &temp ) != 1
  1263.               || temp <= 0
  1264.                )
  1265.                 (void)fprintf( stderr,
  1266.                            "opg: bad -h \"%s\"\n",
  1267.                            arg
  1268.                          );
  1269.             else
  1270.                 pagesize = temp;
  1271.             break;
  1272.  
  1273.         case 'T':        /* "-T term" */
  1274.             if ( *(arg = &(*argv)[2]) == '\0' )
  1275.                 {
  1276.                 --argc;
  1277.                 arg = *++argv;
  1278.                 }
  1279.             if ( !setterm( arg ) )
  1280.                 (void)fprintf( stderr,
  1281.                           "opg: unknown -T \"%s\"\n",
  1282.                            arg
  1283.                          );
  1284.             break;
  1285.  
  1286.         case 'w':        /* "-w line_width" */
  1287.             if ( *(arg = &(*argv)[2]) == '\0' )
  1288.                 {
  1289.                 --argc;
  1290.                 arg = *++argv;
  1291.                 }
  1292.             if ( sscanf( arg, "%d", &temp ) != 1
  1293.               || temp <= 0
  1294.                )
  1295.                 (void)fprintf( stderr,
  1296.                            "opg: bad -w \"%s\"\n",
  1297.                            arg
  1298.                          );
  1299.             else
  1300.                 linesize = temp;
  1301.             break;
  1302.  
  1303.         default:
  1304.             (void)fprintf( stderr,
  1305.                        "opg: unknown option \"%s\"\n",
  1306.                        *argv
  1307.                      );
  1308.             break;
  1309.             }
  1310.  
  1311.         --argc;
  1312.         }
  1313.  
  1314.     if ( eflag )
  1315.         {
  1316.         (void)signal( SIGINT, SIG_IGN );
  1317.         (void)signal( SIGQUIT, SIG_IGN );
  1318.         }
  1319.     else    {
  1320.         (void)signal( SIGINT, intr );
  1321.         (void)signal( SIGQUIT, quit );
  1322.         }
  1323.  
  1324.     if ( freopen( TERMINAL, "r", stderr ) == NULL
  1325.       || ioctl( fileno( stderr ), TCGETA, &tty ) != 0
  1326.        )
  1327.         exit( 2 );
  1328.     omode = tty;            /* save for exit */
  1329.     rmode = tty;            /* corresponding raw mode */
  1330.     rmode.c_lflag &= ~(ICANON | ECHO | ECHOE | ECHOK | ECHONL);
  1331.     rmode.c_cc[VMIN] = (unsigned char)1;
  1332.     rmode.c_cc[VTIME] = (unsigned char)0;    /* no timeout */
  1333.     setbuf( stderr, (char *)NULL ); /* for single-char read */
  1334.     /* after this point, cannot write on stderr */
  1335.  
  1336.     fname = argc > 1 ? *argv : NULL;    /* first file, if any */
  1337.  
  1338.     do    {
  1339.         bool        done;
  1340.         register int    c;
  1341.         register int    col = 0, line = 1;
  1342.         int        lastc = '\n';
  1343.         long        lcount = 0L, lstart = 1L;
  1344.  
  1345.         clear();
  1346.  
  1347.         if ( argc > 1 )
  1348.             {
  1349.             if ( freopen( fname, "r", stdin ) == NULL )
  1350.                 (void)printf(
  1351.                     "**** can't open \"%s\" ****\n",
  1352.                           fname
  1353.                         );
  1354.             else
  1355.                 (void)printf( "======== %s ========\n",
  1356.                           fname
  1357.                         );
  1358.  
  1359.             ++line;
  1360.             }
  1361.  
  1362.         done = false;        /* true when tired of file */
  1363.         typeit = true;        /* false when SIGINT caught */
  1364.  
  1365.         while ( typeit && (c = getchar()) != EOF )
  1366.             {
  1367.             if ( line >= pagesize )
  1368.                 {
  1369.                 if ( done = !more( false, fname,
  1370.                            lstart, lcount
  1371.                          )
  1372.                    )
  1373.                     break;    /* next file */
  1374.  
  1375.                 clear();
  1376.                 lstart = lcount + 1;    /* next line */
  1377.                 line = 1;
  1378.                 }
  1379.  
  1380.             switch ( c = toascii( c ) )
  1381.                 {
  1382.             case 0013:    /* VT */
  1383.             case 0014:    /* FF */
  1384.                 line = pagesize;
  1385.                 c = 0012;
  1386.                 /* line count may not agree with "ed" */
  1387.                 /* fall through */
  1388.  
  1389.             case 0012:    /* LF */
  1390.                 ++lcount;
  1391.                 ++line;
  1392.                 /* fall through */
  1393.  
  1394.             case 0015:    /* CR */
  1395.                 col = 0;
  1396.                 break;
  1397.  
  1398.             case 0010:    /* BS */
  1399.                 if ( col > 0 )
  1400.                     --col;
  1401.                 break;
  1402.  
  1403.             case 0011:    /* HT */
  1404.                 col += 8;
  1405.                 col -= col % 8;
  1406.                 break;
  1407.  
  1408.             case 0177:    /* DEL */
  1409.                 (void)ungetc( '/', stdin );
  1410.                 c = toascii( '^' );
  1411.                 ++col;
  1412.                 break;
  1413.  
  1414.             case 0033:    /* ESC */
  1415.                 if ( eflag )
  1416.                     {
  1417.                     c = tohostc( c );
  1418.  
  1419.                     do    {
  1420.                         if ( col < linesize )
  1421.                             (void)putchar( c );
  1422.                         if ( isalpha( c ) )
  1423.                         /* end esc sequence */
  1424.                             break;
  1425.  
  1426.                         if ( (c = getchar())
  1427.                              == EOF
  1428.                            )
  1429.                             typeit = false;
  1430.                         }
  1431.                     while ( typeit && !iscntrl( c )
  1432.                           );
  1433.  
  1434.                     if ( typeit && iscntrl( c ) )
  1435.                         (void)ungetc( c,
  1436.                                   stdin
  1437.                                 );
  1438.  
  1439.                     continue;    /* read next */
  1440.                     }
  1441.                 /* else fall through */
  1442.  
  1443.             default:
  1444.                 if ( c < 0040 ) /* map ctrl char */
  1445.                     {
  1446.                     (void)ungetc( tohostc( c + 0100
  1447.                                  ),
  1448.                               stdin
  1449.                             );
  1450.                     c = toascii( '^' );
  1451.                     }
  1452.  
  1453.                 ++col;
  1454.                 break;
  1455.                 }
  1456.  
  1457.             if ( col < linesize )
  1458.                 (void)putchar( lastc = tohostc( c ) );
  1459.             }
  1460.         /* end of file */
  1461.  
  1462.         if ( !typeit )        /* interrupted */
  1463.             if ( fname == NULL )
  1464.                 (void)fputs( "\n[aborted]", stdout );
  1465.             else
  1466.                 (void)printf( "\n[%s aborted] ", fname
  1467.                         );
  1468.         else
  1469.             if ( !done && fname != NULL )
  1470.                 {
  1471.                 neednl = true;
  1472.                 (void)printf( "[end of %s] ", fname );
  1473.                 }
  1474.  
  1475.         if ( lastc != '\n' )
  1476.             (void)putchar( '\n' );
  1477.  
  1478.         fname = *++argv;
  1479.         }
  1480.     while ( ++filnum < argc && more( true, fname, 0L, 0L ) );
  1481.  
  1482.     if ( neednl )
  1483.         (void)putchar( '\n' );
  1484.  
  1485.     exit( 0 );
  1486.     }
  1487.  
  1488. static bool
  1489. more( file, fname, lstart, lcount )
  1490.     register bool    file;        /* determines prompt type */
  1491.     char        *fname;     /* filename for prompt */
  1492.     long        lstart;     /* first line on screen */
  1493.     long        lcount;     /* last line on screen */
  1494.     {
  1495. /* possible funny characters to take care of in RAW mode: */
  1496. #if    defined(BRL) && defined(pdp11)
  1497. #undef    CINTR
  1498. #undef    CQUIT
  1499. #define    CINTR    0003
  1500. #define    CQUIT    0002
  1501. #endif
  1502.     register int    c;
  1503.  
  1504.     (void)fflush( stdout );
  1505.     (void)signal( SIGTERM, quit );
  1506.     tty = rmode;
  1507.     (void)ioctl( fileno( stderr ), TCSETAW, &tty );
  1508.  
  1509.     if ( file )
  1510.         (void)printf( "Next file (%s)? ", fname );
  1511.     else
  1512.         if ( fname == NULL )
  1513.             (void)printf( "[%ld-%ld] More? ", lstart, lcount
  1514.                     );
  1515.         else
  1516.             (void)printf( "[%ld-%ld] More of %s? ",
  1517.                       lstart, lcount, fname
  1518.                     );
  1519.  
  1520.     (void)fflush( stdout );
  1521.     neednl = true;
  1522.  
  1523.     while ( (c = getc( stderr )) == CINTR && file    /* race */
  1524.          || c == CSTOP || c == CSTART
  1525.           )
  1526.         ;
  1527.  
  1528.     tty = omode;
  1529.     (void)ioctl( fileno( stderr ), TCSETAW, &tty );
  1530.     (void)signal( SIGTERM, SIG_DFL );
  1531.  
  1532.     if ( c == CINTR )
  1533.         return false;        /* (file == false) */
  1534.  
  1535.     if ( c == CQUIT )
  1536.         quit( 3 );
  1537.  
  1538.     return c != EOF && c != CEOF && tolower( c ) != 'n';
  1539.     }
  1540.  
  1541. static bool
  1542. setterm( name )             /* set up terminal type */
  1543.     register char    *name;        /* terminal designator */
  1544.     {
  1545.     /* table of recognized terminal types - add your favorites
  1546.        (synonyms are okay) */
  1547.     static struct term
  1548.         {
  1549.         char    *tname;        /* termcap designator */
  1550.         int    clear;        /* `ttype' screen-clear code */
  1551.         int    rows;        /* lines visible */
  1552.         int    cols;        /* chars without wrap */
  1553.         }    table[] =
  1554.         {
  1555.     "adm12",    ADM3,    24,    79,    /* LSI ADM12 */
  1556.     "adm3a",    ADM3,    24,    79,    /* LSI ADM3A */
  1557.     "apple2e",    FF,    24,    79,    /* Apple //e */
  1558.     "apple2e-p",    FF,    24,    79,    /* Apple //e Pascal */
  1559.     "apple-ae",    FF,    24,    79,    /* ASCII Express */
  1560.     "dmd",        ANSI,    70,    87,    /* Teletype 5620 */
  1561.     "hirez100",    ANSI,    48,    80,    /* Selanar HiREZ-100 */
  1562.     "hp2623a",    VT52,    24,    79,    /* H-P 2623A */
  1563.     "hp2647a",    VT52,    24,    79,    /* H-P 2647A */
  1564.     "matrox",    FF,    24,    79,    /* Matrox MTX-512 */
  1565.     "tek4105",    ANSI,    30,    80,    /* Tektronix 4105 */
  1566.     "tty5620",    ANSI,    70,    87,    /* Teletype 5620 */
  1567.     "tty5620-1",    ANSI,    70,    87,    /* Teletype 5620 */
  1568.     "tty5620-2",    ANSI,    70,    87,    /* Teletype 5620 */
  1569.     "vi200",     VT52,    24,    79,    /* Visual 200 */
  1570.     "vt52",     VT52,    24,    79,    /* DEC VT52 */
  1571.     "vt100",    ANSI,    24,    80,    /* DEC VT100 */
  1572.     "vt220",    ANSI,    24,    80,    /* DEC VT220 */
  1573.     NULL,        UNK,    24,    79    /* must be last entry */
  1574.         };
  1575.     register struct term    *tp;
  1576. #ifdef TIOCGWINSZ
  1577.     struct _winsize        window;
  1578. #endif
  1579.  
  1580.     for ( tp = table; tp->tname != NULL; ++tp )
  1581.         if ( strcmp( name, tp->tname ) == 0 )
  1582.             break;
  1583.  
  1584.     ttype = tp->clear;        /* UNK if not in table */
  1585. #ifdef TIOCGWINSZ
  1586.     if ( ioctl( fileno( stdout ), TIOCGWINSZ, &window ) == 0
  1587.       && window.ws_row != 0 && window.ws_col != 0
  1588.        )    {
  1589.         pagesize = (int)window.ws_row;
  1590.         linesize = (int)window.ws_col - 1;
  1591.         }
  1592.     else    {
  1593. #endif
  1594.         pagesize = tp->rows;
  1595.         linesize = tp->cols;
  1596. #ifdef TIOCGWINSZ
  1597.         }
  1598. #endif
  1599.  
  1600.     if ( ttype == ANSI )
  1601.         eflag = true;        /* support escape sequences */
  1602.  
  1603.     return tp->tname != NULL;
  1604.     }
  1605.  
  1606. static void
  1607. clear()                 /* clear terminal screen */
  1608.     {
  1609.     switch ( ttype )
  1610.         {
  1611.     case ANSI:
  1612.         (void)fputs( "\033[H\033[J", stdout );
  1613.         break;
  1614.  
  1615.     case ADM3:
  1616.         (void)putchar( '\032' );
  1617.         break;
  1618.  
  1619.     case VT52:
  1620.         (void)fputs( "\033H\033J", stdout );
  1621.         break;
  1622.  
  1623.     case FF:
  1624.         (void)putchar( '\f' );
  1625.         break;
  1626.  
  1627.     default:
  1628.         if ( neednl )
  1629.             (void)putchar( '\n' );
  1630.         break;
  1631.         }
  1632.  
  1633.     (void)putchar( '\r' );        /* tty driver lost column */
  1634.     neednl = false;
  1635.     }
  1636.  
  1637. static void
  1638. intr( sig )                /* called on SIGINT */
  1639.     int    sig;            /* signal number */
  1640.     {
  1641.     (void)signal( sig, intr );    /* re-arm immediately */
  1642.  
  1643.     neednl = true;            /* probably garbage on screen */
  1644.     typeit = false;         /* ask for interruption */
  1645.     }
  1646.  
  1647. static void
  1648. quit( sig )    /* also called on SIGQUIT and on SIGTERM in raw mode */
  1649.     int    sig;            /* signal number */
  1650.     {
  1651.     (void)signal( SIGINT, SIG_IGN );/* protect until mode reset */
  1652.     (void)signal( SIGQUIT, SIG_IGN );
  1653.     (void)signal( SIGTERM, SIG_IGN );
  1654.  
  1655.     tty = omode;
  1656.     (void)ioctl( fileno( stderr ), TCSETAW, &tty );
  1657.  
  1658.     neednl = true;            /* probably garbage on screen */
  1659.     clear();
  1660.  
  1661.     exit( sig );
  1662.     }
  1663. END OF opg.c
  1664. echo 'opg.mk' 1>&2
  1665. cat >'opg.mk' <<'END OF opg.mk'
  1666. #    opg.mk -- makefile for "opg" utility
  1667.  
  1668. #    last edit:    86/11/10    D A Gwyn
  1669.  
  1670. #    SCCS ID:    @(#)opg.mk    1.13
  1671.  
  1672. PRODUCT = opg
  1673. MAKEFIL    = ${PRODUCT}.mk
  1674. CFILES    = ${PRODUCT}.c
  1675. OBJS    = ${PRODUCT}.o
  1676. BINDIR    = /vld/bin
  1677. INCDIR    = /vld/include
  1678. MANDIR    = /usr/5lib/man/local/man1
  1679. BINPERM    = 775
  1680. MANPERM    = 664
  1681. CFLAGS    = -I${INCDIR} -O -DBRL
  1682. LDFLAGS = -n
  1683. INS    = cp
  1684.  
  1685. #    Generic SCCS rule:
  1686.  
  1687. .DEFAULT:
  1688.     $(GET) $(GFLAGS) -p s.$@ > $@
  1689.  
  1690. all:        ${PRODUCT} ${PRODUCT}.1
  1691.  
  1692. ${PRODUCT}:    ${OBJS}
  1693.     $(CC) -o $@ ${LDFLAGS} ${OBJS}
  1694.     size $@
  1695.  
  1696. print:        ${PRODUCT}.1 ${MAKEFIL} ${CFILES}
  1697.     ( nroff -Tlp -man ${PRODUCT}.1 ; \
  1698.       pr ${MAKEFIL} ${CFILES} ${PRODUCT}.1 ) | lp
  1699.  
  1700. lint:        ${CFILES}
  1701.     lint -I${INCDIR} -DBRL ${CFILES} > ${PRODUCT}.lint
  1702.  
  1703. flow:        ${CFILES}
  1704.     cflow -I${INCDIR} ${CFILES} > ${PRODUCT}.flow
  1705.  
  1706. xref:        ${CFILES}
  1707.     cxref -c -s -w132 -I${INCDIR} ${CFILES} > ${PRODUCT}.xref
  1708.  
  1709. test:
  1710.     @echo 'Test "opg" by hand.'
  1711.  
  1712. compare:    all
  1713.     cmp ${BINDIR}/${PRODUCT} ${PRODUCT}
  1714.     cmp ${MANDIR}/${PRODUCT}.1 ${PRODUCT}.1
  1715.  
  1716. install:    all
  1717.     -chmod ${BINPERM} ${PRODUCT}
  1718.     @if cmp -s ${BINDIR}/${PRODUCT} ${PRODUCT}; \
  1719.      then    echo ${PRODUCT} unchanged; \
  1720.      else    ${INS} ${PRODUCT} ${BINDIR}; \
  1721.         echo ${PRODUCT} installed; \
  1722.      fi
  1723.     -chmod ${MANPERM} ${PRODUCT}.1
  1724.     @if cmp -s ${MANDIR}/${PRODUCT}.1 ${PRODUCT}.1; \
  1725.      then    echo ${PRODUCT}.1 unchanged; \
  1726.      else    ${INS} ${PRODUCT}.1 ${MANDIR}; \
  1727.         echo ${PRODUCT}.1 installed; \
  1728.      fi
  1729.  
  1730. clean:
  1731.     -if vax; then rm -f ${CFILES}; fi
  1732.     -rm -f ${OBJS} ${PRODUCT}.lint ${PRODUCT}.flow ${PRODUCT}.xref
  1733.  
  1734. clobber:    clean
  1735.     -if vax; then rm -f ${PRODUCT}.1; fi
  1736.     -rm -f ${PRODUCT}
  1737. END OF opg.mk
  1738. echo 'std.h' 1>&2
  1739. cat >'std.h' <<'END OF std.h'
  1740. /*
  1741.     std.h -- Douglas A. Gwyn's standard C programming definitions
  1742.                         (UNIX System V version)
  1743.  
  1744.     Prerequisite:    <math.h> (if you invoke Round())
  1745.  
  1746.     last edit:    86/05/12    D A Gwyn
  1747.  
  1748.     SCCS ID:    @(#)std.h    1.16
  1749.  
  1750.     This file is to be modified by the VMB Software Development Team
  1751.     leader only.  Currently, this is Douglas A. Gwyn <Gwyn@BRL.ARPA>.
  1752. */
  1753.  
  1754. #ifndef    _VLD_STD_H_
  1755. #define    _VLD_STD_H_            /* once-only latch */
  1756.  
  1757. /* Extended data types */
  1758.  
  1759. #ifndef NULL
  1760. #define NULL    0            /* null pointer, all types */
  1761. #endif
  1762.  
  1763. typedef int    bool;            /* Boolean data */
  1764. #define     false    0
  1765. #define     true    1
  1766.  
  1767. typedef unsigned char    u_char;        /* unsigned integer types */
  1768. typedef unsigned short    u_short;
  1769. #ifdef    pdp11
  1770. typedef long        u_long;        /* (not in Ritchie compiler) */
  1771. #else
  1772. typedef unsigned long    u_long;
  1773. #endif
  1774.  
  1775. typedef char    *pointer;        /* generic pointer (void *) */
  1776.  
  1777. #define    const        /* nothing */    /* (undefine for ANSI C) */
  1778. #define    signed        /* nothing */    /* (undefine for ANSI C) */
  1779. #define    volatile    /* nothing */    /* (undefine for ANSI C) */
  1780.  
  1781. /* Universal constants */
  1782.  
  1783. #define DEGRAD    57.2957795130823208767981548141051703324054724665642
  1784.                     /* degrees per radian */
  1785. #define    E    2.71828182845904523536028747135266249775724709369996
  1786.                     /* base of natural logs */
  1787. #define    GAMMA    0.57721566490153286061
  1788.                     /* Euler's constant */
  1789. #define LOG10E    0.43429448190325182765112891891660508229439700580367
  1790.                     /* log of e to the base 10 */
  1791. #define PHI    1.618033988749894848204586834365638117720309180
  1792.                     /* golden ratio */
  1793. #define PI    3.14159265358979323846264338327950288419716939937511
  1794.                     /* ratio of circumf. to diam. */
  1795.  
  1796. /* Useful macros */
  1797.  
  1798. /* arbitrary numerical arguments and value: */
  1799. #define Abs( x )    ((x) < 0 ? -(x) : (x))
  1800. #define Max( a, b )    ((a) > (b) ? (a) : (b))
  1801. #define Min( a, b )    ((a) < (b) ? (a) : (b))
  1802.  
  1803. /* floating-point arguments and value: */
  1804. #define Round( d )    floor( (d) + 0.5 )
  1805.  
  1806. /* arbitrary numerical arguments, integer value: */
  1807. #define    Sgn( x )    ((x) == 0 ? 0 : (x) > 0 ? 1 : -1)
  1808.  
  1809. /* integer (or character) arguments and value: */
  1810. #ifndef    unix
  1811. #define    toascii( c )    ((c) & 0177)    /* map host char set to ASCII */
  1812. #endif
  1813. #define tohostc( c )    (c)        /* map ASCII to host char set */
  1814. #define tonumber( c )    ((c) - '0')    /* convt digit char to number */
  1815. #define todigit( n )    ((n) + '0')    /* convt digit number to char */
  1816.  
  1817. /* other kludges for deficient C implementations etc.: */
  1818. /*#define    strchr    index        /* 7th Edition UNIX, 4.2BSD */
  1819. /*#define    strrchr    rindex        /* 7th Edition UNIX, 4.2BSD */
  1820. /*#define    void    int        /* K&R Appendix A followers */
  1821.  
  1822. #endif    /* _VLD_STD_H_ */
  1823. END OF std.h
  1824.  
  1825.  
  1826.  
  1827.  
  1828.  
  1829. --
  1830. Paul Palmer
  1831. Department of Mathematics         E-mail: palmerp@math.orst.edu
  1832. Kidder Hall 368
  1833. Oregon State University, Corvallis, Oregon 97331-4605
  1834.