[comp.sources.sun] v01i065: hype - a SunView object-oriented window builder, Part05/11

mcgrew@dartagnan.rutgers.edu (Charles Mcgrew) (09/15/89)

Submitted-by: apctrc!zmls04@uunet.uu.net (Martin L. Smith)
Posting-number: Volume 1, Issue 65
Archive-name: hype/part05

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	Tutorial
#	archives
# This archive created: Thu Sep 14 20:53:16 1989
export PATH; PATH=/bin:$PATH
if test ! -d 'Tutorial'
then
	echo shar: creating directory "'Tutorial'"
	mkdir 'Tutorial'
fi
echo shar: entering directory "'Tutorial'"
cd 'Tutorial'
echo shar: extracting "'introduction'" '(597 characters)'
if test -f 'introduction'
then
	echo shar: will not over-write existing file "'introduction'"
else
sed 's/^	X//' << \SHAR_EOF > 'introduction'
	X.bp 1
	X.ds CF -%-
	X.SH
	X.LG
	XGetting Started
	X.NL
	X.PP
	XThis document is a brief,
	Xself-contained, tutorial introduction to \fBhype\fR.
	XThe tutorial takes you, step by step,
	Xthrough the construction of a simple, but complete,
	X.B hype
	Xapplication
	X(or \fImachine\fR).
	XAll you will require is this tutorial,
	Xa Sun workstation,
	Xaccess to the program
	X.B hype ,
	Xand the ability to use the
	X.B vi
	Xeditor.
	X.PP
	XThis tutorial is not a complete description of
	X.B hype .
	XMany of the script language features and functions
	Xare not discussed.
	XA more thorough exposition is available in
	X.B "Hype: A Programmer's Guide" .
SHAR_EOF
if test 597 -ne "`wc -c < 'introduction'`"
then
	echo shar: error transmitting "'introduction'" '(should have been 597 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'jumpstart'" '(5671 characters)'
if test -f 'jumpstart'
then
	echo shar: will not over-write existing file "'jumpstart'"
else
sed 's/^	X//' << \SHAR_EOF > 'jumpstart'
	X.bp
	X.SH
	X.LG
	XI.  Jump-starting Hype: Making a State File
	X.NL
	X.PP
	X.B Hype
	Xsupports a tree-structured hierarchy of
	X.I objects.
	XAn object contains zero or more
	X.I panes.
	XA pane is a visual sub-region of an object and may contain one or more
	X.I items
	X(widgets), through which a user may interact with
	X.B hype.
	XA
	X.I template
	Xis a pattern on which widgets are arranged;
	Xwhen a template is added to an object for
	Xdisplay it becomes a pane.
	XThe class of objects, panes, items, and templates are
	X.B hype 's
	X.I entities .
	X(For more on entities, see
	X.B "Hype: A Programmer's Guide" .)
	X.PP
	X.B Hype
	Xnormally begins life by reading a \fIstate \fIfile\fR.
	XThe state file contains a complete description of the entities,
	Xattributes, values, and scripts
	Xwhich cause
	X.B hype
	Xto assume the personality programmed into it
	X(and also the entity values and screen positions in use
	Xthe last time
	X.B hype 's
	Xstate was saved).
	XIn this section 
	Xwe will create a new state file,
	Xone with a single object in it.
	X.RS
	X.IP \(em
	XFrom within 
	X.B suntools
	Xor
	X.B sunview ,
	Xstart
	X.B hype
	Xby typing the command
	X.I "hype -s"
	X.RE
	X.LP
	X(The \fB-s\fR tells
	X.B hype
	Xnot to look for a state file.)
	XThis command causes a large,
	Xnauseous-yellow window to open in the middle of the screen.
	XThe window label will be (something like)
	X.DS C
	X\fB/MASTER\fR
	X.DE
	X.RS
	X.IP \(em
	XOpen the object's border menu
	X(click the right mouse button on the frame or title bar of the yellow window).
	X.IP \(em
	XWalk through the
	X.B Object\(rh
	Xsub-menu,
	Xand then select
	X.B "Object Info" .
	X(In the future we will refer to menu actions in this style:
	X``from the object's border menu select \fBObject\fR\(rh\fBObject Info\fR''.)
	X.RE
	X.LP
	XThis will open an
	X.I "object info box"
	Xsomewhere on the screen.
	XIt has labeled fields for several of an object's
	Xattributes and it shows the object's current attributes
	Xin those fields.
	XSome fields are read-only
	Xand consist of ``field name = number''.
	XThe fields that are changeable consist of
	X``field name: changeable contents''.
	XPressing the return key or the tab key moves
	Xthe cursor forward through the changeable fields.
	XPressing shift-tab moves the cursor
	Xbackwards through the changeable fields.
	X.PP
	XWe wish to change the name,
	Xlabel,
	Xand (especially) the color of
	X.B MASTER
	X(which is the root object of your new
	X.B hype
	Xtree).
	XTo do this,
	Xperform the following steps:
	X.RS
	X.IP \(em
	XDelete \fBMASTER\fR from the \fBObject Name\fR
	Xfield and type in \fITutorial\fR.
	X.IP \(em
	XInto the
	X.B Label
	Xfield type \fIMy Tutorial Root\fR.
	X.IP \(em
	XInto the
	X.B Color
	Xfield type ``\fI214 183 27\fR''
	X(without the quotes, but with the spaces);
	Xthis is an earthy looking color that's easier to read
	X(with some background colors) than the original.
	XYou can type any legal \fIrgb\fR combination into this field.
	X.IP \(em
	XClick the left mouse button on the
	X.B OK
	Xbutton.
	X.RE
	X.LP
	XNote that the label bar changes to the new label.
	XThe color may not change
	X(\fBhype\fR has a small problem here);
	Xif it remains yellow,
	Xclick the left mouse button on the object's frame.
	XThis will cause the object to refresh its display
	Xand it will assume its new color.
	X.PP
	XNow save
	X.B hype 's
	Xcurrent state to a file:
	X.RS
	X.IP \(em
	XFrom the border menu select
	X\fBFile\fR\(rh\fBFile\ State\fR.
	X.IP \(em
	X.B Hype
	Xwill prompt for a file name for the state file.
	XType in
	X\fItut.hyp\fR
	Xand click left on
	X.B OK .
	X(By convention,
	X.B hype
	Xstate files end in ``\fI.hyp\fR''.)
	X.IP \(em
	XFrom the border menu select
	X\fBFile\fR\(rh\fBQuit,\ No Save\fR
	Xand respond to the pop-up by clicking left on
	X.B YES .
	X.RE
	X.LP
	X.B Hype
	Xexits and leaves us back in the shell.
	XThere should be a small file named \fBtut.hyp\fR
	Xin the current directory.
	X.PP
	XFor the rest of the tutorial use the command
	X.DS C
	X\fBhype -Stut.hyp\fR
	X.DE
	Xto start 
	X.B hype .
	XThis will cause it to read
	X.B tut.hyp
	Xat start-up and to write its current state back to the same file
	Xon a ``normal'' exit.
	X(A normal exit is \fBFile\(rhSave\ &\ Quit\fR
	Xfrom any object's border menu.)
	X.SH
	XSome Things to Note
	X.PP
	XObject info boxes have a field for the object color.
	XYou will want to use
	X.B colortool
	Xto decide what
	X.I rgb
	Xinteger combination to use.
	XWhen a menu or an info box is on the screen, however,
	Xyou can't do anything except interact with it;
	Xeverything else on the screen is frozen
	X(even the clock is stopped).
	XOne consequence of this is that you cannot
	Xinvoke \fBcolortool\fR while an info box is open.
	XThe simplest way to handle this is to play with
	X.B colortool
	Xto find a zippy color selection
	X.I before
	Xyou open the appropriate info box.
	X.PP
	XIt is not necessary to name the desired state file
	Xon
	X.B hype 's
	Xcommand line;
	Xthere are environment variables which will
	Xprovide defaults for all command line options.
	XThey are discussed in
	X.B "Hype: A Programmer's Guide" .
	XWe do not use them here for simplicity.
	X.PP
	X.B Hype
	Xoffers facilities
	X(all available under the
	X.B File\(rh
	Xsub-menu from any object's border menu)
	Xfor
	X.RS
	X.IP \(bu
	Xupdating the state file without exiting:
	X\fBFile\(rh\fBSave\ State\fR.
	XYou should use this fairly often since
	X.B hype
	Xoccasionally crashes.
	XYou may do this any time you can get to 
	Xan object border menu.
	X.IP \(bu
	Xupdating the state file and exiting:
	X\fBFile\(rh\fBSave\ &\ Quit\fR.
	XThis is a normal quit.
	X.IP \(bu
	Xexiting \fIwithout\fR updating the state file:
	X\fBFile\(rh\fBQuit,\ No\ Save\fR.
	XUse this if you've really screwed up.
	X.RE
	X.LP
	XThe state file is the \fIonly\fR
	Xrecord of your programming effort.
	XIt is source code as surely as any
	X.SM
	XFORTRAN
	X.NL
	Xor C file
	Xand you should treat it with reverence and paranoia.
	XMaking backup copies is appropriate.
	X(This is known as
	X.I "Do As I Say, Not As I Do" ,
	Xand is the only fun part about writing tutorials.)
SHAR_EOF
if test 5671 -ne "`wc -c < 'jumpstart'`"
then
	echo shar: error transmitting "'jumpstart'" '(should have been 5671 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'lookingback'" '(4524 characters)'
if test -f 'lookingback'
then
	echo shar: will not over-write existing file "'lookingback'"
else
sed 's/^	X//' << \SHAR_EOF > 'lookingback'
	X.bp
	X.LP
	XReplace this page with figure V. Looking Back.
	X.bp
	X.PP
	XLet's dissect the message-passing behavior
	Xthat we programmed into the thermometer bars
	Xand into the object (\fBThermometer\fR)
	Xwhich owns them.
	XWe assume that the object is open.
	X(Refer to the figure a few pages after this one.)
	X.PP
	XIf the cursor is over any part of the slider portion of
	X.B "DegF" ,
	Xand the left button is pressed,
	Xthe message
	X.B mouseDown
	X(which we don't intercept) is sent to the item
	Xand then the slider
	Xis set to the value indicated by the cursor.
	XWhen the left button is released,
	Xthe message
	X.B mouseUp
	Xis sent to the item.
	XNote that if the cursor is moved off the slider bar
	Xwhile the left mouse button is still depressed,
	Xthe bar jumps back to its previous position
	Xand (though you cannot tell from watching)
	X.B mouseUp
	Xis not sent.
	X.PP
	XUsing
	X.B mouseUp
	Xinstead of
	X.B mouseDown
	Xoffers two advantages:
	XFirst,
	Xwhen we read the item's value from inside of a script,
	Xwe get the new value.
	XSecond,
	Xwe can retract our change by moving the cursor off of the
	Xitem before releasing the button.
	X.PP
	XThe alternative choice,
	X.B mouseDown ,
	Xhas the advantage that the button you have activated
	X(assuming you've clicked on an item of type button)
	Xremains darkened while the script invoked is still active.
	XThis is a useful way of telling the user that
	X.B hype
	Xis busy fulfilling some request and will not yet respond to new input.
	XAt present, however,
	X.B hype
	Xsometimes gets confused about handling the display of active items.
	XIf you wish to use
	X.B mouseDown ,
	Xyou should be prepared to do some experimentation to make
	Xsure that it performs properly.
	X(We will try to fix this soon.)
	X.PP
	XIf you click left on the label portion of the slider bar,
	Xthe same messages are sent but the slider's value is not changed.
	XObserve that doing so makes the bars flicker as they are redrawn
	Xbut their values don't change.
	X.PP
	XWhen
	X.B DegF
	Xintercepts
	X.B mouseUp ,
	Xthe script snippet which handles that message is executed.
	XThis snippet reads its item's own value and
	Xconverts the value (presumed to be in Fahrenheit)
	Xto centigrade (Celsius).
	XThe script snippet then sends the message
	X.B degreesC
	Xto its owning object (\fBThermometer\fR),
	Xreferred to as \fB"."\fR in the script,
	Xwith the centigrade temperature as the message's parameter.
	X.PP
	XNote that we could instead have sent the message
	Xto \fBself()\fR,
	Xwhich in this case would have been the item
	X.B DegF .
	XIf we had written the script that way,
	Xthe message would have passed \fIthrough\fR
	X.B DegF
	Xand its owning pane
	X.B Mercury ,
	Xsince neither of these provides a handler for
	Xthe message
	X.B degreesC .
	XIt then would have been passed to the object
	X.B Thermometer ,
	Xwhose script would intercept the message.
	X.PP
	XWhen
	X.B Thermometer
	Xreceives
	X.B degreesC ,
	Xits script is executed.
	XThat script sends the message
	X.B changeTo ,
	Xwith the centigrade temperature as its parameter,
	Xto every item in every pane owned by the object.
	XWe did it that way to avoid having to program pane and item
	Xnames into the script but, as you can see,
	Xthe resultant script is kludgy.
	XWe will probably provide a smoother mechanism in the future,
	Xbut the one we show works
	X(and will do so in the future).
	X.PP
	XEach of the items to which
	X.B changeTo
	Xis sent either ignores the message
	X(as the button \fBC\fR does)
	Xor responds to it
	X(as the slider bars do by changing their values).
	X.PP
	XWhen
	X.B Thermometer 's
	Xscript is finished,
	Xit returns to its caller, the
	X.B DegF 
	Xscript.
	XAt this time,
	Xthe
	X.B mouseUp
	Xhandler in
	X.B DegF
	Xis finished and it exits.
	X.PP
	XAt one time,
	X.B DegF
	Xhad two handlers active.
	XThis occurred because
	X.B DegF
	Xsent a message that was intercepted by
	X.B Thermometer
	Xwhich in turn sent a message that was intercepted by
	X.B DegF .
	XA script snippet remains active until execution
	Xhas encountered an explicit
	X.B return
	Xor has run off the end of the script.
	XIt is legal for a script to invoke itself recursively
	X(it can even send standard messages such as
	X.B mouseUp ).
	X.PP
	XAll messages return a value to the entity that sent them.
	XMessages which are not caught return an empty string to the sender.
	XMessages which are caught may return anything specified by the catcher
	Xin a \fBreturn\fR statement
	X(although we haven't used that feature here).
	XIf the intercepting script does not have an explicit
	X.B return ,
	Xthe empty string is returned.
	XThe returned value of a message is available as the return value
	Xof the
	X.B send
	Xfunction which created the message.
	X.bp
	X.LP
	XReplace this page with figure Message-passing in the Tutorial.
SHAR_EOF
if test 4524 -ne "`wc -c < 'lookingback'`"
then
	echo shar: error transmitting "'lookingback'" '(should have been 4524 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'macros'" '(20 characters)'
if test -f 'macros'
then
	echo shar: will not over-write existing file "'macros'"
else
sed 's/^	X//' << \SHAR_EOF > 'macros'
	X.nr PS 11
	X.nr VS 13
SHAR_EOF
if test 20 -ne "`wc -c < 'macros'`"
then
	echo shar: error transmitting "'macros'" '(should have been 20 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'maketree'" '(3058 characters)'
if test -f 'maketree'
then
	echo shar: will not over-write existing file "'maketree'"
else
sed 's/^	X//' << \SHAR_EOF > 'maketree'
	X.bp
	X.SH
	X.LG
	XII.  Building a Tree
	X.NL
	X.PP
	X.B Hype
	Xprogramming has two distinct aspects.
	XOne is \fIentity \fIcreation\fR,
	Xduring which we add to the
	X.B hype
	Xtree the entities
	X(objects, panes, and items)
	Xwhich the final state will need.
	XThe other is \fIentity \fIprogramming\fR,
	Xduring which we assign
	X.I behavior
	Xto entities by writing scripts which define
	Xthe response of each entity to various messages.
	XBuilding a
	X.B hype
	Xmachine is usually a process of alternating
	Xbetween these two activities and incrementally
	Xcreating a structure which does whatever we needed to do.
	X.PP
	XIn this section
	Xwe are going to extend our
	X.B hype
	Xmachine by adding
	Xa child subobject to our root object.
	X.RS
	X.IP \(em
	XStart
	X.B hype
	Xwith \fIhype\ \ \fI-Stut.hyp\fR
	X(We're not going to tell you how anymore.)
	XThe root object will appear on the screen
	Xin the position it had when the state file
	Xwas last saved.
	X(Sometimes 
	X.B hype
	Xforgets its last position.
	XDon't be alarmed if the next time you start
	X.B hype
	Xit has forgotten the positions of your entities on the screen.)
	X.IP \(em
	XFrom its border menu use
	X.B Window\(rhMove
	Xand
	X.B Window\(rhResize
	Xto make this object
	Xa manageable size and to put it into a convenient position.
	X.IP \(em
	XNow use
	X.B "File\(rhSave\ State"
	Xto update the state file
	X.B tut.hyp
	Xwith these new positions and sizes.
	X.RE
	X.LP
	XNow, to create a new object:
	X.RS
	X.IP \(em
	XFrom the root's border menu select
	X.B "Object\(rhCreate\ Child" .
	XThis will create a large, yellow child
	Xobject with a peculiar name.
	X.IP \(em
	XFrom the child's border menu select
	X.B "Object\(rhObject\ Info" .
	X.IP \(em
	XChange
	X.B "Object Name"
	Xto
	X.I Thermometer .
	X.IP \(em
	XInto
	X.B "Object Label"
	Xtype
	X.I Thermometer .
	X.IP \(em
	XInto
	X.B "Object Color"
	Xtype
	X(without the quotes)
	X``\fI143 134 214\fR''
	X(or any \fIrgb\fR combination you prefer).
	X.IP \(em
	XClick left on
	X.B OK .
	X.IP \(em
	XClick left in
	X.B Thermometer 's
	Xborder to get the object to refresh, thus updating the color.
	X.IP \(em
	XMove and resize the object,
	Xfrom its border menu,
	Xto make it livable.
	XIt would be best if it didn't overlap
	Xthe root object.
	X.IP \(em
	X.I "Save your state" .
	X(Use
	X.B "File\(rhSave State" .)
	X.RE
	X.RE
	X.LP
	XYour
	X.B hype
	Xtree now has two objects.
	XThe tree's root is named
	X.B Tutorial
	Xand the root's single child object is named
	X.B Thermometer .
	XThis
	X.B hype
	X``machine'' does not yet do anything useful.
	X.RS
	X.IP \(em
	XNow leave
	X.B hype
	Xnormally,
	Xby selecting
	X.B "File\(rhSave\ &\ Quit"
	Xfrom
	X.I either
	Xobject's border menu.
	XThis method of quitting causes the state file
	Xto be updated automatically.
	X.IP \(em
	XResume
	X.B hype .
	XOnly the root object appears on the screen,
	Xalthough it
	X.I should
	Xbe where you last saw it.
	X.IP \(em
	XTo open
	X.B Thermometer ,
	Xselect
	X.B "Object\(rhOpen\ Child\(rhThermometer" .
	X.RE
	X.LP
	XIn this process,
	X.B hype
	Xallowed you to conveniently open
	Xany of the root's children.
	XMenu-based navigation like this is really intended
	Xonly for programming
	X.B hype .
	XFor the casual user,
	Xwe will
	Xprovide a button
	X(in the next section)
	Xthat achieves the same effect.
	X.RS
	X.IP \(em
	XExit
	X.B hype
	Xnormally.
	X.RE
SHAR_EOF
if test 3058 -ne "`wc -c < 'maketree'`"
then
	echo shar: error transmitting "'maketree'" '(should have been 3058 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'onward'" '(2926 characters)'
if test -f 'onward'
then
	echo shar: will not over-write existing file "'onward'"
else
sed 's/^	X//' << \SHAR_EOF > 'onward'
	X.bp
	X.SH
	X.LG
	XVI.  Additional Features
	X.NL
	X.PP
	XThis section discusses some additional features
	Xyou can add to your machine.
	XWe strongly suggest you pursue these.
	XThe suggestions illustrate new features of
	X.B hype ,
	Xand the experience is worthwhile.
	X.NH 0
	XExit
	X.PP
	XYour machine currently has no way to exit
	X.B hype
	Xwithout using an object border menu.
	XA finished
	X.B hype
	Xapplication should be entirely item-driven;
	Xthe user should not have to use the menu system for anything.
	XOur first suggestion, then, is that you add an
	X.B Exit
	Xbutton to the root object.
	XThe button's script should look like this:
	X.RS
	X.DS
	X\fBmouseUp:
	X{
	X	exit();
	X}.\fR
	X.DE
	X.RE
	X(Don't forget the trailing period.)
	XThe
	X.B exit()
	Xcall saves your state before quitting.
	X.PP
	XThere is a certain amount of dexterity involved
	Xin adding items to small panes and objects.
	XWe suggest you proceed like this:
	X.RS
	X.IP \(em
	XDelete the current pane from the object.
	X(Look for the
	X.B Pane\(rh
	Xmenu.)
	XThis does \fBnot\fR delete the template.
	X.IP \(em
	XOpen the appropriate template,
	Xmake it larger,
	Xand add the new item.
	X.IP \(em
	XSet the new item's info and script as appropriate.
	X.IP \(em
	XAlter the template to the desired final size.
	X.IP \(em
	XMake the host object bigger than the new template requires.
	X.IP \(em
	XAdd the template as a pane.
	X.IP \(em
	XSize the object as desired.
	X.RE
	X.NH
	XinitHype
	X.PP
	XAt startup time,
	X.B hype
	Xbroadcasts the message
	X.B initHype
	Xto every object in its tree.
	X(Note that
	X.B broadcast
	Xmessages only go to objects,
	Xnot to panes or items.)
	XThe parameter of this message,
	Xif any,
	Xis the last unrecognized option on
	X.B hype 's
	Xcommand line.
	XIf
	X.B hype
	Xis invoked with
	X.DS C
	X\fBhype\ \ \-\Stut.hyp thermometer\fR
	X.DE
	Xthe parameter of
	X.B initHype
	Xwill be
	X.B thermometer .
	X.PP
	XWe can use this feature to cause
	X.B hype
	Xto begin with selected windows open.
	XTo use this,
	Xopen an editor on the script of the
	X.I object
	X.B Thermometer
	Xand
	X.I add
	Xthe following to its current script
	X(look for
	X.B "Object\(rhObj\ Script\(rhEdit\ Script" ):
	X.RS
	X.DS
	X\fBinitHype:
	X{
	X	if(param() == "thermometer")
	X		open(self());
	X}.\fR
	X.DE
	X.RE
	X.LP
	Xand then try starting
	X.B hype
	Xwith
	X.DS C
	X\fBhype\ \ \-\Stut.hyp thermometer\fR
	X.DE
	X.NH
	Xstderr()
	X.PP
	X.B Hype 's
	Xscript supports the function
	X.DS C
	X\fBstderr(\fIstring\fB)\fR
	X.DE
	Xwhich prints its argument, followed by a newline,
	Xto
	X.B hype 's
	X.I "standard error" .
	XThe latter is usually directed to the shelltool from which
	X.B hype
	Xwas started.
	X.PP
	X.B Stderr()
	Xis very useful for debugging scripts.
	XTry adding calls to this function
	Xin some of the scripts.
	XFor example,
	Xin the object script for
	X.B Thermometer ,
	Xwithin the script for
	X.B degreesC
	Ximmediately after the
	X.B send()
	Xcall and before the next ``}'',
	Xadd the line
	X.DS C
	X\fBstderr(self() $$ " sent changeTo with " $$ newtemp $$ " to " $$ item);\fR
	X.DE
	Xand then see what shows up on the shelltool when you click on a slider.
	X(The ``$$'' is
	X.B hype 's
	Xstring concatenation operator.)
SHAR_EOF
if test 2926 -ne "`wc -c < 'onward'`"
then
	echo shar: error transmitting "'onward'" '(should have been 2926 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'title'" '(181 characters)'
if test -f 'title'
then
	echo shar: will not over-write existing file "'title'"
else
sed 's/^	X//' << \SHAR_EOF > 'title'
	X.TL
	X.LG
	X.LG
	X.LG
	XHype: A Tutorial
	X.NL
	X.sp 2
	X.AU
	X.LG
	X.LG
	XMartin Smith
	XKim Dill
	XTerri Fischer
	XRob Read
	X
	XJanuary 10, 1989
	X.NL
	X.DA
	X.ds CH Hype: A Tutorial \(em Version 1.2
	X.ds CF
	X.PP
	X
	X
	X
SHAR_EOF
if test 181 -ne "`wc -c < 'title'`"
then
	echo shar: error transmitting "'title'" '(should have been 181 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'usemessages'" '(7807 characters)'
if test -f 'usemessages'
then
	echo shar: will not over-write existing file "'usemessages'"
else
sed 's/^	X//' << \SHAR_EOF > 'usemessages'
	X.bp
	X.SH
	X.LG
	XIV.  Using Messages
	X.NL
	X.PP
	XIn this section
	Xwe will add a simple temperature conversion
	Xsystem to thermometer.
	XWe will dispense with most of the step-by-step
	Xinstructions.
	XRemember to save your current state frequently.
	X.PP
	X.RS
	X.IP \(em
	XStart
	X.B hype
	Xand click left on the
	X.I button
	Xlabeled
	X.B "Open Thermometer"
	Xto open the
	X.I object
	Xnamed
	X.B Thermometer .
	X.IP \(em
	XAdd a template to the object
	X.B Thermometer
	Xand name it
	X.B Mercury .
	X.IP \(em
	X.I "Save your state" .
	X(Pretend that every item in this list ends with
	X"\fISave Your State\fR".)
	X.IP \(em
	XMove
	X.B Mercury
	Xso it doesn't overlap any object and resize it
	Xto make it a bit bigger.
	XThen add the following three items,
	Xpositioning them tastefully in the template:
	X.RS
	X.IP \(em
	XA button
	X.B named
	Xand
	X.B labeled
	X.I C ,
	Xfor close .
	X.IP \(em
	XAn item of
	X.B Type
	X.I Slider ,
	X.B named
	X.I DegF ,
	X.B labeled
	X.I "Deg F" ,
	Xrunning from a
	X.B Min
	Xof
	X.I 32
	Xto a
	X.B Max
	Xof
	X.I 212
	Xwith a
	X.B "Display Length"
	Xof
	X.I 180 .
	X(A good practice is to give the item a name
	Xwhich is identical to its label with all the spaces removed.)
	XNote that you click on an item in the
	X.B Type
	Xlist to change an item's type into something other than a button.
	X.IP \(em
	XAn item of
	X.B Type
	X.I Slider ,
	X.B named
	X.I DegC ,
	X.B labeled
	X.I "Deg C" ,
	Xrunning from a
	X.B Min
	Xof
	X.I 0
	Xto a
	X.B Max
	Xof
	X.I 100
	Xwith a
	X.B "Display Length"
	Xof
	X.I 180 .
	X.RE
	X.IP \(em
	XShrink-wrap the template
	X.B Mercury
	Xusing
	X.B "Window\(rhFit\ Window"
	Xfrom the template's border menu.
	X.IP \(em
	XResize the object
	X.B Thermometer
	Xso it's large enough to hold the new template.
	X.IP \(em
	XAdd the template
	X.B Mercury
	Xto the object
	X.B Thermometer 
	Xas a pane.
	X(Hint:
	Xlook for a
	X.B Pane\(rh
	Xmenu item in
	X.B Thermometer 's
	Xborder menu.)
	X.IP \(em
	XClick left on the slider bars in the pane
	X(in the
	X.I pane,
	Xnot in the
	X.I template);
	Xnote that they respond and alter their values.
	X.RE
	X.PP
	XThe bars' values,
	Xas well as the values of all other items,
	Xare saved in the state file;
	Xso if you set
	X.B "Deg C"
	Xto 27 degrees and exit
	X.B hype
	Xnormally, then the next time you run
	X.B hype
	Xwith this state file, the value in
	X.B "Deg C"
	Xwill be 27 degrees.
	XAlso note that clicking on the bars in the \fItemplate\fR
	Xhas no effect;
	Xthose values may only be changed by altering the item's
	X\fBDefault\fR value through its info box.
	X.PP
	XWe now have a system of two objects,
	Xeach of which has a pane and some items.
	XThe only item that does anything besides change its value
	Xis the button in the root object.
	XNow we'll add some behavior to the
	X.B C
	Xbutton in
	X.B Thermometer :
	Xwe'll program the button to close its owning object,
	X.B Thermometer .
	X.RS
	X.IP \(em
	XGive the
	X.B C
	Xbutton this script (hint: look in the template contents menu):
	X.RS
	X.DS
	X\fBmouseUp:
	X{
	X	close("."); # "." refers to the current object
	X}.
	X.DE
	X.RE
	X(Everything after a "#" in a script is a comment.)
	X.IP \(em
	XClick left on
	X.B C
	X(in the \fIpane\fR, not the \fItemplate\fR) and observe that
	X.B Thermometer
	Xcloses.
	X.IP \(em
	XReopen it by using the button in the root object.
	X.RE
	X.PP
	XItem-driven support for opening and closing objects
	X(navigation)
	Xis important if we want to spare the final user
	Xthe effort of using
	X.B hype 's
	Xprogramming menus.
	X(By the way, have you remembered to
	X.I "save your state" ?)
	X.PP
	XThe last and most complicated piece of programming
	Xis to synchronize the thermometers so that whenever
	Xwe change one,
	Xthe other changes to reflect the equivalent temperature.
	XThat is,
	Xif we click 
	X.B "Deg F"
	Xto 70,
	X.B "Deg C"
	Xshould change itself to show 21.
	XWe will do this in a slightly roundabout way
	Xin which we allow entities in
	X.B Thermometer
	Xto communicate only through message-passing;
	Xwe will not let any entity access another entity's value directly.
	X.PP
	XThe scheme is this:
	XWhenever either of the slider bars receives a
	X.B mouseUp
	Xmessage,
	Xit will read its own value,
	Xconvert that to centigrade (if needed),
	Xand send the message
	X.B degreesC
	Xfollowed by the current centigrade temperature as a parameter
	Xto
	X.B Thermometer ,
	Xthe owning object.
	X.B Thermometer
	Xwill intercept the new temperature message,
	X.B degreesC ,
	Xand will send message
	X.B changeTo
	Xfollowed by the new temperature,
	Xto every item it owns.
	XThe message will be ignored by
	X.B C ,
	Xthe button,
	Xand it will be used by the thermometer bars
	Xto set a new value.
	X(See the figure
	X.B "Message-passing in the Tutorial"
	Xnear the end of the tutorial.)
	XAs you will see in the scripts,
	Xwe are able to do this without having to program
	Xany entity's name into any other entity;
	Xall we have to know is the message-passing convention.
	X.KS
	X.PP
	XFirst we'll add the script for
	X.B Thermometer ,
	Xthe object.
	X.RS
	X.IP \(em
	XFrom 
	X.B Thermometer 's
	Xobject border menu, select
	X.B "Object\(rhObj Script\(rhEdit Script" .
	X.IP \(em
	XInsert this script:
	X.RS
	X.DS
	X#	Everything between a "#" and the end of the line is a comment.
	X#	You don't have to type comments into the script.
	X#	param() returns the received message's parameters.
	X#	self() returns the current entity's name, sometimes
	X#		called the "current context" in hyplish.
	X#	The funny looking stuff on the line starting with
	X#		pane = ...
	X#	is an alternate syntax for describing the members of
	X#	the set of entities owned by another entity,
	X#	where "$$" is hype's string concatenation operator.
	X#	See Hype: A Programmer's Guide for much more on all of this.
	X\fBdegreesC:
	X{
	X	newtemp = param();	# Comments can go here too.
	X	for(i = 0; i < numpanes(self()); i++) {
	X		pane = self() $$ "!" $$ i;
	X		for(j = 0; j < numitems(pane); j++) {
	X			item = getnthitem(pane, j);
	X			send("changeTo", item, newtemp);
	X		}
	X	}
	X}.\fR
	X.DE
	X.RE
	X.RE
	X.LP
	XThis script loops over all of the items of all of the panes
	Xin this object.
	XIt sends the same message to each,
	Xwithout worrying about whether each particular item
	Xwill respond to the message.
	X.KE
	X.KS
	X.PP
	XThe script for each of the slider bars has two message handlers
	Xin it.
	XOne must respond to the
	X.B mouseUp
	Xmessage that is sent by
	X.B hype
	Xitself on a left mouse button event.
	XThe second handler must respond to the
	X.B changeTo
	Xmessage that comes from
	X.B Thermometer
	Xwhenever a new temperature is registered.
	X.RS
	X.IP \(em
	XGive
	X.B "Deg F"
	Xthis script (hint: look in
	X.B Mercury 's
	Xtemplate contents menu.):
	X.RS
	X.DS
	X\fBmouseUp:
	X{
	X	value = getitemval(self());
	X	centigrade = 5.0 * ( value - 32 ) / 9.0;
	X	send("degreesC", ".", centigrade);
	X}.
	XchangeTo:
	X{
	X	fahrenheit = (9.0 * param() / 5.0) + 32;
	X	setitemval(self(), fahrenheit);
	X}.\fR
	X.DE
	X.RE
	X.IP \(em
	Xand give
	X.B "Deg C"
	Xthis script:
	X.RS
	X.DS
	X\fBmouseUp:
	X{
	X	value = getitemval(self());
	X	send("degreesC", ".", value);
	X}.
	XchangeTo:
	X{
	X	setitemval(self(), param());
	X}.\fR
	X.DE
	X.RE
	X.IP \(em
	XYou should now be able to click left on either of the slider bars in
	X.B Thermometer
	Xand have the change reflected in the other bar.
	XIf the slider you
	X.I "didn't"
	Xclick on
	X.I "doesn't"
	Xchange,
	Xcheck your typing
	X.I very
	Xcarefully in all the scripts you've created.
	XAlso, don't forget to
	X.I "save your state" 
	Xonce it works.
	XYou may also
	X.B "Quit Template"
	Xfrom
	X.B Mercury 's
	Xborder menu now (if you're scripts are working).
	X.RE
	X.KE
	X.SH
	XSome Things to Note
	X.PP
	XBoth slider bars currently have the same length.
	XThere is no reason that this has to be so.
	XTry changing
	X.B "Deg C"
	Xso that its length is 100.
	XNote that after you change the item's info,
	Xthe template changes immediately.
	XTo make the pane reflect the new length,
	Xcause the entire object to refresh by clicking
	Xleft on the object's border.
	X.PP
	XCurrently, error handling is very poor.
	XTry deliberately omitting the final period in a script
	Xor mistyping part of a script
	Xso you can see what
	X.B hype
	Xwill (or will not) do.
	X.PP
	XYou may shrink-wrap an object around its panes by using
	X.B "Window\(rhFit Window"
	Xfrom an object's border menu.
	XWe didn't mention it before so that you would be able to clearly
	Xdistinguish between the object border and the pane border.
SHAR_EOF
if test 7807 -ne "`wc -c < 'usemessages'`"
then
	echo shar: error transmitting "'usemessages'" '(should have been 7807 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'Tutorial'"
cd ..
if test ! -d 'archives'
then
	echo shar: creating directory "'archives'"
	mkdir 'archives'
fi
echo shar: entering directory "'archives'"
cd 'archives'
if test ! -d 'container'
then
	echo shar: creating directory "'container'"
	mkdir 'container'
fi
echo shar: entering directory "'container'"
cd 'container'
echo shar: extracting "'Makefile'" '(157 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	XCFLAGS = -g
	Xcontainer.a: container.o
	X	ar rcv container.a container.o
	X	ranlib container.a
	X
	Xctest:	ctest.o 
	X	cc -o ctest ctest.o ../mfile/mfile.a container.a
	X
SHAR_EOF
if test 157 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 157 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'container.c'" '(4713 characters)'
if test -f 'container.c'
then
	echo shar: will not over-write existing file "'container.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'container.c'
	X#include "../mfile/mfile.h"
	X#include <stdio.h>
	X
	Xtypedef MFILE	*Container;
	X
	XContainer cnew_con()
	X{
	X    return mfopen();
	X}
	XContainer cnew_constring(str)
	Xchar *str;
	X{
	X    Container temp;
	X    void cins_cur_chars();
	X    void crewind();
	X    temp = cnew_con();
	X    cins_cur_chars(temp,str,strlen(str));
	X    crewind(temp);
	X    return temp;
	X}
	Xchar *cflatten(cont)
	XContainer cont;
	X{
	X    long n;
	X    char *temp;
	X    n = clength(cont);
	X    temp = (char *) malloc(sizeof(char) * n+1);
	X    crewind(cont);
	X    mfread(cont,temp,n);
	X    temp[n] = '\0';
	X    return temp;
	X}
	Xvoid cdestroy(cont)
	XContainer cont;
	X{
	X    mfclose(cont);
	X}
	Xvoid ctrunc(cont)
	XContainer cont;
	X{
	X    mftrunc(cont);
	X}
	Xvoid crewind(cont)
	XContainer cont;
	X{
	X    mfseek(cont,0,0);
	X}
	XContainer ccpy_con(old)
	XContainer old;
	X{
	X    long size;
	X    long curspot;
	X    Container new;
	X    char *buff,*cget_cur_chars();
	X    void cins_cur_chars();
	X    new = cnew_con();
	X    crewind(old);
	X    buff = cget_cur_chars(old,clength(old));
	X    cins_cur_chars(new,buff,clength(old));
	X    crewind(new);
	X    return new;    
	X}
	Xlong clength(cont)
	XContainer cont;
	X{
	X    return mflength(cont);
	X}
	X
	Xchar *cget_nth_line(cont,n)
	XContainer cont;
	Xint n;
	X{
	X    char c;
	X    char *str;
	X    int m = 0;
	X    int	i;
	X    mfseek(cont,0,0);
	X    
	X    while (n >= 0) {
	X	m = 0;
	X	c = mfgetc(cont);
	X	while ((c != EOF) && (c != '\n')) {
	X	    c = mfgetc(cont);
	X	    m++;
	X	}
	X	if (c == EOF) {
	X	    break;
	X	}
	X	n--;
	X    }
	X    mfseek(cont,-(m+1),1);
	X    str = (char *) malloc(sizeof(char) * (m + 1));
	X    for (i = 0; i < m; i++) {
	X	str[i] = mfgetc(cont);
	X    }
	X    str[m] = '\0';
	X    return str;
	X}
	Xint cfind_nth_line(cont,n)
	XContainer cont;
	Xint n;
	X{
	X    char c;
	X    char *str;
	X    int m = 0;
	X    int	i;
	X    
	X    while (n >= 0) {
	X	m = 0;
	X	c = mfgetc(cont);
	X	while ((c != EOF) && (c != '\n')) {
	X	    c = mfgetc(cont);
	X	    m++;
	X	}
	X	if (c == EOF) {
	X	    break;
	X	}
	X	n--;
	X    }
	X    mfseek(cont,-(m+1),1);
	X    return m;
	X}
	X
	Xint cfind_nth_item(cont,n)
	XContainer cont;
	Xint n;
	X{
	X    char c;
	X    char *str;
	X    int m = 0;
	X    int	i;
	X    
	X    while (n >= 0) {
	X	m = 0;
	X	c = mfgetc(cont);
	X	while ((c != EOF) && (c != ',')) {
	X	    c = mfgetc(cont);
	X	    m++;
	X	}
	X	if (c == EOF) {
	X	    mfseek(cont,-m,1);
	X	    return m;
	X	    break;
	X	}
	X	n--;
	X    }
	X    if (n == 0) {
	X	return 0;
	X    }
	X    mfseek(cont,-(m+1),1);
	X    return m;
	X}
	X
	X#define WHITE_SPACE(x) ((c == ' ') || (c == '\n') || (c == '\t'))
	X
	Xint cfind_nth_word(cont,n)
	XContainer cont;
	Xint	    n;
	X{
	X    char c;
	X    char *str;
	X    int m = 0;
	X    int	i;
	X    
	X    while (n >= 0) {
	X	m = 0;
	X	c = mfgetc(cont);
	X	while (WHITE_SPACE(c)) {
	X	    c = mfgetc(cont);
	X	}
	X	while (!WHITE_SPACE(c)) {
	X	    if (c == EOF) {
	X		if (n != 0) {
	X		    return NULL;
	X		}
	X		mfseek(cont,-(m),1);
	X		return m;    
	X		break;
	X	    }
	X
	X	    c = mfgetc(cont);
	X	    m++;
	X	}
	X	n--;
	X    }
	X    mfseek(cont,-(m+1),1);
	X    return m;    
	X}
	X
	Xchar *cget_nth_word(cont,n)
	XContainer cont;
	Xint n;
	X{
	X    int length;
	X    char *temp;
	X    crewind(cont);
	X    length = cfind_nth_word(cont,n);
	X    temp = (char *) malloc(sizeof(char) * (length + 1));
	X    mfread(cont,temp,length);
	X    temp[length] = '\0';
	X    return temp;
	X}
	Xchar *cget_nth_item(cont,n)
	Xint n;
	XContainer cont;
	X{
	X    int length;
	X    char *temp;
	X    length = cfind_nth_item(cont,n);
	X    temp = (char *) malloc(sizeof(char) * (length + 1));
	X    mfread(cont,temp,length);
	X    temp[length] = '\0';
	X    return temp;
	X}
	Xchar *cget_cur_chars(cont,length)
	XContainer cont;
	Xint length;
	X{
	X    char *temp;
	X    temp = (char *) malloc(sizeof(char) * (length + 1));
	X    mfread(cont,temp,length);
	X    return temp;
	X}
	Xint cget_numwords(cont)
	XContainer cont;
	X{
	X    int len;
	X    char c;
	X    int n;
	X    char *str;
	X    int m = 0;
	X    int	i;
	X    c = 'a';
	X    mfseek(cont,0,0);
	X    n = 0;
	X    while (c != EOF) {
	X	m = 0;
	X	c = mfgetc(cont);
	X	while (WHITE_SPACE(c)) {
	X	    c = mfgetc(cont);
	X	}
	X	while (!WHITE_SPACE(c)) {
	X	    if (c == EOF)
	X		break;
	X	    c = mfgetc(cont);
	X	    m++;
	X	}
	X	n++;
	X    }
	X    if (m == 0) {
	X	return n - 1;
	X    } else {
	X	return n;
	X    }
	X}
	Xint cget_numlines(cont)
	XContainer cont;
	X{
	X    char c,l;
	X    int n;
	X    char *str;
	X    mfseek(cont,0,0);
	X    n = 0;
	X    c = '!';
	X    l = '\n';
	X    while (c != EOF) {
	X	l = c;
	X	c = mfgetc(cont);
	X	if (c == '\n') {
	X	    n++;
	X	}
	X    }
	X    if (l == '\n') {
	X	return n;
	X    }
	X    return n+1;
	X}
	Xint cget_numitems(cont)
	XContainer cont;
	X{
	X    char c,l;
	X    int n;
	X    char *str;
	X    mfseek(cont,0,0);
	X    n = 0;
	X    c = '!';
	X    l = ',';
	X    while (c != EOF) {
	X	l = c;
	X	c = mfgetc(cont);
	X	if (c == ',') {
	X	    n++;
	X	}
	X    }
	X    if (l == ',') {
	X	return n;
	X    }
	X    return n+1;
	X}
	X
	Xvoid cdel_cur_chars(cont,n)
	XContainer cont;
	Xint n;
	X{
	X    mfdelete(cont,n);
	X}
	X
	Xvoid cins_cur_chars(cont,ptr,n)
	XContainer cont;
	Xchar *ptr;
	Xint n;
	X{
	X    mfinsert(cont,ptr,n);
	X}
SHAR_EOF
if test 4713 -ne "`wc -c < 'container.c'`"
then
	echo shar: error transmitting "'container.c'" '(should have been 4713 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'container.h'" '(728 characters)'
if test -f 'container.h'
then
	echo shar: will not over-write existing file "'container.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'container.h'
	X
	X
	X
	Xtypedef	    void    *Container;
	X
	XContainer   cnew_con();
	XContainer   ccpy_con();
	XContainer   cnew_constring();
	Xchar	    *cflatten();
	X
	Xvoid	    cdestroy();
	Xchar	    *cget_nth_line();
	Xchar	    *cget_nth_word();
	Xchar	    *cget_nth_char();
	Xchar	    *cget_nth_item();
	X
	Xvoid	    crewind();
	Xint	    cfind_nth_line();
	Xint	    cfind_nth_word();
	Xint	    cfind_nth_char();
	Xint	    cfind_nth_item();
	X
	Xchar	    *cget_cur_chars();
	Xvoid	    cdel_cur_chars();
	Xvoid	    cins_cur_chars();
	X
	Xvoid	    cdel_nth_line();
	Xvoid	    cdel_nth_word();
	Xvoid	    cdel_nth_char();
	Xvoid	    cdel_nth_item();
	X
	Xvoid	    cins_nth_line();
	Xvoid	    cins_nth_word();
	Xvoid	    cins_nth_char();
	Xvoid	    cins_nth_item();
	X
	Xcseek();
	Xcread();
	Xcwrite();
	Xvoid ctrunc();
SHAR_EOF
if test 728 -ne "`wc -c < 'container.h'`"
then
	echo shar: error transmitting "'container.h'" '(should have been 728 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'ctest.c'" '(573 characters)'
if test -f 'ctest.c'
then
	echo shar: will not over-write existing file "'ctest.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'ctest.c'
	X#include "container.h"
	X#include <stdio.h>
	X
	Xmain ()
	X{
	X    char buff[1000];
	X    int i;
	X    Container cont;
	X    cont = cnew_con();
	X    for(i = 0; i < 1000; i++ ) {
	X	buff[i] = getchar();
	X    }
	X	
	X    mfwrite(cont,buff,1000);
	X    for (i = 0; i < 10; i++) {
	X	crewind(cont);
	X	fprintf(stdout,"%s\n",cget_nth_line(cont,i));
	X	crewind(cont);
	X	fprintf(stdout,"%s\n",cget_cur_chars(cont,cfind_nth_line(cont,i)));
	X	crewind(cont);
	X	cfind_nth_line(cont,4);
	X	cins_cur_chars(cont,"holy lamb\n",10);
	X	crewind(cont);
	X	fprintf(stdout,"%s\n",cget_cur_chars(cont,cfind_nth_word(cont,0)));
	X    }
	X}
SHAR_EOF
if test 573 -ne "`wc -c < 'ctest.c'`"
then
	echo shar: error transmitting "'ctest.c'" '(should have been 573 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'container'"
cd ..
if test ! -d 'hash'
then
	echo shar: creating directory "'hash'"
	mkdir 'hash'
fi
echo shar: entering directory "'hash'"
cd 'hash'
echo shar: extracting "'Makefile'" '(170 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	XCFLAGS = -g
	X
	X.SUFFIXES: .f .c .o .ln
	X
	X.c.ln:
	X	csh -c "lint -xu -i $<"
	X
	X
	X
	Xhash.a: hash.o shash.o
	X	ar rcv hash.a hash.o shash.o
	X	ranlib hash.a
	X
	Xwc: 
	X	wc *.c *.h Makefile
	X	
SHAR_EOF
if test 170 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 170 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hash.c'" '(2978 characters)'
if test -f 'hash.c'
then
	echo shar: will not over-write existing file "'hash.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'hash.c'
	X/*  hash.c -- hype requires many a fine young hash table so that it can have */
	X/*  roughly constant time lookups for most of it's stuff.  This file is an   */
	X/*  attempt at a general hash table maintenance module.			     */
	X
	X
	X#include "../../src/util.h"
	X
	Xtypedef struct hnode {
	X	struct hnode	    *next;
	X	void 		    *key;
	X	char		    *ptr;
	X} Hnode,*HnodePtr;
	X
	Xtypedef struct hash {
	X	int		    size;
	X	HnodePtr	    *entry;
	X} HashT,*HashTPtr;
	X
	XHashTPtr make_hash()
	X{
	X    HashTPtr temp;
	X    temp = (HashTPtr) malloc(sizeof(HashT) * 1);
	X    temp->entry = NULL;
	X    temp->size = 0;
	X    return temp;
	X}
	Xvoid	unmake_hnode_list(ptr)
	XHnodePtr ptr;
	X{
	X    if (ptr != NULL) {
	X	unmake_hnode_list(ptr->next);
	X	free(ptr);
	X    }
	X}
	Xvoid	unmake_hash(hash)
	XHashTPtr hash;
	X{   
	X    int i;
	X    for (i = 0; i < hash->size; i++) {
	X        unmake_hnode_list(hash->entry[i]);
	X    }
	X    free(hash->entry);
	X    free(hash);
	X}
	X
	XHnodePtr make_hnode()
	X{
	X    HnodePtr temp;
	X    temp = (HnodePtr) malloc(sizeof(Hnode) * 1);
	X    temp->key = 0;
	X    temp->next = NULL;
	X    temp->ptr  = NULL;
	X    return temp;
	X}
	Xvoid init_hash( size, hash)
	Xint size;
	XHashTPtr hash;
	X{
	X    int i;
	X    hash->size = size;
	X    hash->entry = (HnodePtr *) malloc(sizeof(HnodePtr) * size);
	X    for ( i = 0; i < size; i++) {
	X	hash->entry[i] = NULL;
	X    }
	X}
	X
	Xint hashval( x, size)
	Xint x;
	Xint size;
	X{
	X    int f;
	X    f = x & 0x000f;
	X    f *= ((x & 0x0f00) >> 16);
	X    f += ((x & 0x00f0) >> 8);
	X    f += ((x & 0xf000) >> 24) * 3;
	X    return abs(f) % size;
	X}
	X
	Xdelete_from_hash(key, hash)
	Xvoid *key;
	XHashTPtr hash;
	X{
	X    int fval;
	X    HnodePtr temp,cur;
	X    fval = hashval(key,hash->size);
	X    cur = hash->entry[fval];
	X    if (cur == NULL) {
	X	mywarning("hash.c: tried to delete non-existent element from hash table\n");
	X    }
	X    if (cur->key == key) {
	X	hash->entry[fval] = cur->next;
	X	free(cur);
	X	return;
	X    }
	X    while ((cur->next != NULL) && ((cur->next->key != key))) {
	X	cur = cur->next;
	X    }
	X    if (cur->next == NULL) {
	X	return;
	X/*	mywarning("hash.c: element to delete not found\n"); */
	X    } else {
	X	temp = cur->next;
	X	cur->next = cur->next->next;
	X	free(temp);
	X    }
	X}
	X
	Xchar *hlookup(key,hash)
	XHashTPtr hash;
	Xvoid *key;
	X{
	X    int fval;
	X    HnodePtr cur;
	X    fval = hashval(key,hash->size);
	X    cur = hash->entry[fval];
	X    if (cur == NULL) {
	X	return NULL;
	X    }
	X    if (cur->key == key) {
	X	return cur->ptr;
	X    }
	X    while (cur != NULL) {
	X	if (cur->key == key) {
	X	    return cur->ptr;
	X	} else {
	X	    cur = cur->next;
	X	}
	X    }
	X    return NULL;
	X}
	Xadd_to_hash(key, hash, ptr)
	Xvoid *key;
	Xchar *ptr;
	XHashTPtr hash;
	X{
	X    HnodePtr temp,cur;
	X    int fval;
	X    if (hlookup(key,hash) != NULL) {
	X	mywarning("duplicate hash key attempted\n");
	X	return NULL;
	X    }
	X	
	X    temp = make_hnode();
	X    temp->key = key;
	X    temp->next = NULL;
	X    temp->ptr = ptr;
	X    fval = hashval(key,hash->size);
	X    cur = hash->entry[fval];
	X
	X    if (cur == NULL) {
	X	hash->entry[fval] = temp;
	X    } else {
	X	temp->next = hash->entry[fval];
	X	hash->entry[fval] = temp;
	X    }
	X}
SHAR_EOF
if test 2978 -ne "`wc -c < 'hash.c'`"
then
	echo shar: error transmitting "'hash.c'" '(should have been 2978 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'hash.h'" '(288 characters)'
if test -f 'hash.h'
then
	echo shar: will not over-write existing file "'hash.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'hash.h'
	X/*  hash.h  -- this file is the header file for a hopefully general hash */
	X/*  table module.							 */
	X
	Xtypedef void	    *HashTPtr;
	X
	XHashTPtr    make_hash();
	X    
	Xvoid	    unmake_hash();
	X
	Xvoid	    init_hash();
	X
	Xvoid	    add_to_hash();
	X
	Xvoid	    delete_from_hash();
	X
	Xvoid	    *hlookup();
SHAR_EOF
if test 288 -ne "`wc -c < 'hash.h'`"
then
	echo shar: error transmitting "'hash.h'" '(should have been 288 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'shash.c'" '(3885 characters)'
if test -f 'shash.c'
then
	echo shar: will not over-write existing file "'shash.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'shash.c'
	X/*  hash.c -- hype requires many a fine young hash table so that it can have */ 
	X/*  roughly constant time lookups for most of it's stuff.  This file is an   */
	X/*  attempt at a general hash table maintenance module.			     */
	X
	X
	X#include "../../src/util.h"
	X   
	Xtypedef struct shnode {
	X	struct shnode	    *next;
	X	char		    *key;
	X	void		    *id;
	X} SHnode,*SHnodePtr;
	X
	Xtypedef struct shash {
	X	int		    size;
	X	SHnodePtr	    *entry;
	X} SHashT,*SHashTPtr;
	X
	Xvoid *slookup();
	X
	XSHashTPtr smake_hash()
	X{
	X    SHashTPtr temp;
	X    temp = (SHashTPtr) malloc(sizeof(SHashT) * 1);
	X    temp->entry = NULL;
	X    temp->size = 0;
	X    return temp;
	X}
	XSHnodePtr smake_hnode()
	X{
	X    SHnodePtr temp;
	X    temp = (SHnodePtr) malloc(sizeof(SHnode) * 1);
	X    temp->key = "";
	X    temp->next = NULL;
	X    temp->id = 0;
	X    return temp;
	X}
	X
	Xchar *shash_get_nth(hash,n)
	XSHashTPtr hash;
	Xint n;
	X{
	X    SHnodePtr s;
	X    int i = 0;
	X    int j = 0;
	X    s = hash->entry[j];
	X	while(s == NULL) {
	X	    j++;
	X	    if (j >= hash->size) {
	X		return NULL;
	X	    }
	X	    s = hash->entry[j];
	X	}	
	X    while (1) {
	X	if (i == n)
	X	    return s->key;
	X	i++;
	X	s = s->next;
	X	while(s == NULL) {
	X	    j++;
	X	    if (j >= hash->size) {
	X		return NULL;
	X	    }
	X	    s = hash->entry[j];
	X	}	
	X    }
	X}
	Xvoid	Sinit_hash( size, hash)
	Xint size;
	XSHashTPtr hash;
	X{
	X    int i;
	X    hash->size = size;
	X    hash->entry = (SHnodePtr *) malloc(sizeof(SHnodePtr) * size);
	X    for (i = 0; i < size; i++) {
	X	hash->entry[i] = NULL;
	X    }
	X}
	X
	Xvoid	sunmake_hnode_list(ptr)
	XSHnodePtr ptr;
	X{
	X    if (ptr != NULL) {
	X	sunmake_hnode_list(ptr->next);
	X	free(ptr->key);
	X	free(ptr);
	X    }
	X}
	Xvoid	sunmake_hash(hash)
	XSHashTPtr hash;
	X{   
	X    int i;
	X    for (i = 0; i < hash->size; i++) {
	X        sunmake_hnode_list(hash->entry[i]);
	X    }
	X    free(hash->entry);
	X    free(hash);
	X}
	Xint	shashval( x, size)
	Xchar *x;
	Xint size;
	X{
	X    int l,n,i;
	X    l = strlen(x);
	X	n = l;
	X    if( l - 1 > 0) {
	X	n = n * x[l-1];
	X    }
	X    if (l - 4 > 0) {
	X	n = n * x[l-1];
	X    }
	X    for (i = 0;i < l;i++) {
	X	n += x[i];
	X    }
	X    n = n % size;
	X    return n;
	X}
	X
	Xint	sadd_to_hash(key, hash, id)
	Xchar *key;
	XSHashTPtr hash;
	Xvoid *id;
	X{
	X    SHnodePtr temp,cur;
	X    int fval;
	X/*    if (slookup(key,hash) != NULL) {
	X	mywarning("duplicate hash key attempted\n");
	X	return NULL;	
	X    }
	X*/
	X    if (strlen(key) == 0) {
	X	mywarning("Major Error: Zero hash key attempted\n");
	X	return 0;
	X    }
	X    temp = smake_hnode();
	X    temp->key = mystrcpy(key);
	X    temp->id = id;
	X    temp->next = NULL;
	X
	X    fval = shashval(temp->key,hash->size);
	X    cur = hash->entry[fval];
	X    if (cur == NULL) {
	X	hash->entry[fval] = temp;
	X    } else {
	X	temp->next = hash->entry[fval];
	X	hash->entry[fval] = temp;
	X    }
	X}
	Xint	sdelete_from_hash(key, hash, id)
	Xchar *key;
	XSHashTPtr hash;
	Xvoid *id;
	X{
	X    int fval;
	X    SHnodePtr temp,cur;
	X    if (strlen(key) == 0) {
	X	return 0;
	X    }
	X    fval = shashval(key,hash->size);
	X    
	X    cur = hash->entry[fval];
	X    if (cur == NULL) {
	X	mywarning("hash.c: tried to delete non-existent element from hash table\n");
	X    }
	X    if (!strcmp(cur->key,key) && (id == cur->id)) {
	X	hash->entry[fval] = cur->next;
	X	free(cur->key);
	X	free(cur);
	X	return;
	X    }
	X    while ((cur->next != NULL) && 
	X    (strcmp(cur->next->key,key) || (id != cur->next->id ))) {
	X	cur = cur->next;
	X    }
	X    if (cur->next == NULL) {
	X	mywarning("hash.c: tried to delete non-existent element from hash table\n");
	X    } else {
	X	temp = cur->next;
	X	cur->next = cur->next->next;
	X	free(temp->key);
	X	free(temp);
	X    }
	X}
	X
	Xvoid *slookup(key,hash)
	XSHashTPtr hash;
	Xchar *key;
	X{
	X    int fval;
	X    SHnodePtr cur;
	X    if (strlen(key) == 0) {
	X	return NULL;
	X    }
	X    fval = shashval(key,hash->size);
	X    cur = hash->entry[fval];
	X    if (cur == NULL) {
	X	return NULL;
	X    }
	X    if (strcmp(cur->key,key) == 0) {
	X	return cur->id;
	X    }
	X    while (cur != NULL) {
	X	if (strcmp(cur->key,key) == 0) {
	X	    return cur->id;
	X	} else {
	X	    cur = cur->next;
	X	}
	X    }
	X    return NULL;
	X}
SHAR_EOF
if test 3885 -ne "`wc -c < 'shash.c'`"
then
	echo shar: error transmitting "'shash.c'" '(should have been 3885 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'shash.h'" '(244 characters)'
if test -f 'shash.h'
then
	echo shar: will not over-write existing file "'shash.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'shash.h'
	X/*  hash.h  -- this file is the header file for a hopefully general hash */
	X/*  table module.							 */
	X
	Xtypedef	void	*SHashTPtr;
	X
	XSHashTPtr smake_hash();
	X
	Xvoid	sunmake_hash();
	Xvoid	sinit_hash();
	X
	Xint	sadd_to_hash();
	X
	Xint	sdelete_from_hash();
	X
SHAR_EOF
if test 244 -ne "`wc -c < 'shash.h'`"
then
	echo shar: error transmitting "'shash.h'" '(should have been 244 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'hash'"
cd ..
if test ! -d 'mfile'
then
	echo shar: creating directory "'mfile'"
	mkdir 'mfile'
fi
echo shar: entering directory "'mfile'"
cd 'mfile'
echo shar: extracting "'Makefile'" '(165 characters)'
if test -f 'Makefile'
then
	echo shar: will not over-write existing file "'Makefile'"
else
sed 's/^	X//' << \SHAR_EOF > 'Makefile'
	XCFLAGS = -g
	X
	Xmfile.a: mfile.o
	X	ar rcv mfile.a mfile.o
	X	ranlib mfile.a
	X
	Xmftest:	mftest.o mfile.o mfile.h
	X	cc -o mftest mftest.o mfile.o
	X
	Xmftest.o: mftest.c mfile.h
	X
	X
SHAR_EOF
if test 165 -ne "`wc -c < 'Makefile'`"
then
	echo shar: error transmitting "'Makefile'" '(should have been 165 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mfile.c'" '(5680 characters)'
if test -f 'mfile.c'
then
	echo shar: will not over-write existing file "'mfile.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'mfile.c'
	X#include    <stdio.h>
	X#include    "../../src/util.h"
	X#define	    MAGIC   327
	X#define	    BUFFSIZE 32
	X#define	    CHECK_MAGIC(x) if (x->magic != MAGIC) { \
	X   	char *y; \
	X	y = (char *) 57; \
	X	fprintf(stderr,"Bad magic number to mfile.\n"); \
	X	fprintf(stderr,"%s\n",y); \
	X}
	X
	Xtypedef struct blk {
	X    char	contents[BUFFSIZE];
	X    struct blk	*next;    
	X} Block,*BlockPtr;
	X
	Xtypedef	struct mfile {
	X    int		magic;
	X    long	length;
	X    long	curr;
	X    BlockPtr	firstbloc;
	X    BlockPtr	curbloc;
	X    BlockPtr	lastbloc;
	X} MFILE;
	X
	X
	XBlockPtr new_bloc()
	X{
	X    BlockPtr temp;
	X    temp = (BlockPtr) malloc(sizeof(Block) * 1);
	X    if (temp == NULL) {
	X	fprintf(stderr,"Out of memory for memory file.\n");
	X    }
	X    temp->next = NULL;
	X    return temp;
	X}
	X
	XMFILE *mfopen()
	X{
	X    MFILE *temp;
	X    temp = (MFILE *) malloc(sizeof(MFILE) * 1);
	X    if (temp == NULL) {
	X	fprintf(stderr,"Out of memory for memory file.\n");
	X    }
	X    temp->length = 0;
	X    temp->magic	 = MAGIC;
	X    temp->curr	 = 0;
	X    temp->firstbloc = NULL;
	X    temp->curbloc= NULL;
	X    temp->lastbloc= NULL;
	X    return temp;
	X}
	Xlong	mflength(file)
	XMFILE *file;
	X{
	X    CHECK_MAGIC(file);
	X    return file->length;
	X}
	Xstatic void dealloc_blocs(bloc)
	XBlockPtr bloc;
	X{
	X    if (bloc == NULL) {
	X	return;
	X    } else {
	X	dealloc_blocs(bloc->next);
	X	free(bloc);
	X    }
	X}
	Xvoid mfclose(file)
	XMFILE *file;
	X{
	X    CHECK_MAGIC(file);
	X    dealloc_blocs(file->firstbloc);
	X    free(file);
	X}
	X
	Xint mfgetc(file)
	XMFILE	*file;
	X{
	X    int c;
	X    CHECK_MAGIC(file);
	X    if (file->curr == file->length) {
	X	return EOF;
	X    }
	X    c = file->curbloc->contents[file->curr % BUFFSIZE];
	X    file->curr++;
	X    if (file->curr % BUFFSIZE == 0) {
	X	file->curbloc = file->curbloc->next;
	X    }
	X    return c;
	X}
	Xint mfungetc(file)
	XMFILE *file;
	X{
	X    mfseek(file,-1,1);
	X}
	Xint mfputc(file,c)
	XMFILE *file;
	Xchar c;
	X{
	X    CHECK_MAGIC(file);
	X    if (file->lastbloc == NULL) {
	X	file->firstbloc = new_bloc();
	X	file->lastbloc  = file->firstbloc;
	X	file->curbloc	= file->firstbloc;
	X    }
	X    if (file->curbloc == NULL) {
	X	file->lastbloc->next = new_bloc();
	X	file->lastbloc = file->lastbloc->next;
	X	file->curbloc  = file->lastbloc;
	X    }
	X    file->curbloc->contents[file->curr % BUFFSIZE] = (char) c;
	X    file->curr++;
	X    if ((file->curr % BUFFSIZE) == 0) {
	X	file->curbloc = file->curbloc->next;
	X    }
	X    if (file->curr > file->length) {
	X	file->length = file->curr;
	X    }
	X    return c;
	X}
	Xint mfinsert(file,ptr,bytes)
	XMFILE	*file;
	Xchar	*ptr;
	Xint	bytes;
	X{
	X    char *temp;
	X    long buffsize;
	X    long curspot;
	X    CHECK_MAGIC(file);
	X    curspot = mfseek(file,0,1);
	X    buffsize = mfseek(file,0,2) - curspot;
	X    temp = (char *) malloc(sizeof(char) * buffsize);
	X    mfseek(file,curspot,0);
	X    mfread(file,temp,buffsize);
	X    mfseek(file,curspot,0);
	X    mfwrite(file,ptr,bytes);
	X    mfwrite(file,temp,buffsize);
	X    free(temp);
	X    return bytes;
	X}
	Xvoid mftrunc(file)
	XMFILE *file;
	X{
	X    CHECK_MAGIC(file);
	X    if (file->curbloc == NULL) {
	X	return;
	X    }
	X    dealloc_blocs(file->curbloc->next);
	X    file->curbloc->next = NULL;
	X    file->lastbloc = file->curbloc;
	X    file->length = file->curr;
	X}
	Xint mfdelete(file,bytes)
	XMFILE	*file;
	Xint	bytes;
	X{
	X    char *temp;
	X    long buffsize;
	X    long curspot;
	X    CHECK_MAGIC(file);
	X    curspot = mfseek(file,0,1);
	X    buffsize = mfseek(file,0,2) - curspot - bytes;
	X    temp = (char *) malloc(sizeof(char) * buffsize);
	X    mfseek(file,curspot+bytes,0);
	X    mfread(file,temp,buffsize);
	X    mfseek(file,curspot,0);
	X    mfwrite(file,temp,buffsize);
	X    mfseek(file,curspot+buffsize,0);
	X    mftrunc(file); 
	X    return bytes;
	X}
	Xint mfwrite(file,ptr,bytes)
	XMFILE	*file;
	Xchar	*ptr;
	Xint	bytes;
	X{
	X    int written;
	X    CHECK_MAGIC(file);
	X    written = 0;
	X    if (bytes <= 0) {
	X	return 0;
	X    }
	X    if (file->lastbloc == NULL) {
	X	file->firstbloc = new_bloc();
	X	file->lastbloc  = file->firstbloc;
	X	file->curbloc	= file->firstbloc;
	X	file->curbloc->contents[file->curr++] = ptr[written++];
	X    }
	X    while (written != bytes) {
	X	if (file->curbloc == NULL) {
	X	    file->lastbloc->next = new_bloc();
	X	    file->lastbloc = file->lastbloc->next;
	X	    file->curbloc  = file->lastbloc;
	X	}
	X	file->curbloc->contents[file->curr % BUFFSIZE] = ptr[written++];
	X	file->curr++;
	X	if (file->curr % BUFFSIZE == 0) {
	X	    file->curbloc = file->curbloc->next;
	X	}
	X    }
	X    if (file->length < file->curr) {
	X	file->length = file->curr;
	X    }
	X    return written;
	X}
	X
	Xint mfread(file,ptr,bytes)
	XMFILE	*file;
	Xchar	*ptr;
	Xint	bytes;
	X{
	X    int read = 0;
	X    CHECK_MAGIC(file);
	X    if (bytes <= 0) {
	X	return read;
	X    }
	X    while (read != bytes) {
	X	if ((file->curbloc == NULL) || (file->curr == file->length)){
	X	    return read;
	X	}
	X	ptr[read++] = file->curbloc->contents[file->curr % BUFFSIZE];
	X	file->curr++;
	X	if ((file->curr % BUFFSIZE) == 0) {
	X	    file->curbloc = file->curbloc->next;
	X	}
	X    }
	X    return read;
	X}
	X
	X
	Xlong mfseek(file,offset,origin)
	XMFILE *file;
	Xlong offset;
	Xint origin;
	X{
	X    long newval;
	X    int i;
	X    CHECK_MAGIC(file);
	X    switch (origin) {
	X	case 0:
	X	    file->curr = offset;
	X	break;
	X	case 1:
	X	    file->curr = file->curr + offset;
	X	break;
	X	case 2:
	X	    file->curr = file->length + offset;
	X	break;
	X    }
	X    if (file->curr < 0) {
	X	file->curr = 0;
	X    }
	X    file->curbloc = file->firstbloc;
	X    if (file->lastbloc == NULL) {
	X	file->firstbloc = new_bloc();
	X	file->lastbloc  = file->firstbloc;
	X	file->curbloc	= file->firstbloc;
	X    }
	X    for (i = 0; i < (file->curr / BUFFSIZE); i++) {
	X	if (file->curbloc == NULL) {
	X	    file->lastbloc->next = new_bloc();
	X	    file->curbloc = file->lastbloc->next;
	X	    file->lastbloc = file->lastbloc->next; 
	X	}
	X	file->curbloc = file->curbloc->next;
	X    }
	X    if (file->curr > file->length) {
	X	file->length = file->curr;
	X    }
	X    return file->curr;
	X}
SHAR_EOF
if test 5680 -ne "`wc -c < 'mfile.c'`"
then
	echo shar: error transmitting "'mfile.c'" '(should have been 5680 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mfile.h'" '(72 characters)'
if test -f 'mfile.h'
then
	echo shar: will not over-write existing file "'mfile.h'"
else
sed 's/^	X//' << \SHAR_EOF > 'mfile.h'
	X
	X
	X
	Xtypedef void	*MFILE;
	X
	X
	XMFILE	*mfopen();
	Xint	mfwrite();
	Xint	mfread();
SHAR_EOF
if test 72 -ne "`wc -c < 'mfile.h'`"
then
	echo shar: error transmitting "'mfile.h'" '(should have been 72 characters)'
fi
fi # end of overwriting check
echo shar: extracting "'mftest.c'" '(804 characters)'
if test -f 'mftest.c'
then
	echo shar: will not over-write existing file "'mftest.c'"
else
sed 's/^	X//' << \SHAR_EOF > 'mftest.c'
	X#include <stdio.h>
	X#include "mfile.h"
	X
	Xmain()
	X{
	X    int i,j;
	X    char c;
	X    MFILE *mf;
	X    FILE *fd;
	X    char bigbuf[6000];
	X    fd = fopen("mfile.c","r");
	X    for (i = 0; i < 1; i++) {
	X	lseek(fd,0,0);
	X	mf = mfopen();
	X	j = 0;
	X	while ((c = getc(fd)) != EOF) {
	X	    bigbuf[j++] = c;
	X	    mfputc(mf,c);
	X	}
	X	mfseek(mf,0,0);
	X	    mfbogus(mf);
	X    	mfseek(mf,5000,0);
	X	    mfbogus(mf);
	X	mfseek(mf,-5000,2);
	X	mfwrite(mf,bigbuf,5000);
	X	    mfbogus(mf);
	X	mfseek(mf,0,0);
	X	    mfbogus(mf);
	X	mfread(mf,bigbuf,5000);
	X	    mfbogus(mf);
	X	mfseek(mf,0,0);
	X	mfdelete(mf,4000); 
	X    	mfseek(mf,0,0);
	X	    mfbogus(mf);
	X	    bigbuf[1] = '\0';
	X/*	    j = mfread(mf,bigbuf,10);*/
	X	    bigbuf[0] = mfgetc(mf);
	X	while (bigbuf[0] != EOF ) {
	X	    fprintf(stdout,"%s",bigbuf);
	X	    bigbuf[0] = mfgetc(mf);
	X	}
	X	mfclose(mf);
	X    }
	X}
SHAR_EOF
if test 804 -ne "`wc -c < 'mftest.c'`"
then
	echo shar: error transmitting "'mftest.c'" '(should have been 804 characters)'
fi
fi # end of overwriting check
echo shar: done with directory "'mfile'"
cd ..
echo shar: done with directory "'archives'"
cd ..
#	End of shell archive
exit 0