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