The GVPatch Implementation Manual Steve Temple, November 2, 1982 File [Indigo]Tools>GVPImpl.tioga Introduction This document describes the way in which the GVPatch system is implemented and is intended to be useful should the need to alter the program arise. The programs are commented also and should be consulted in addition to this document. System Structure The GVPatch system has two parts, the part which runs on the Grapevine server which is being patched is a single module called GVPServer and is described in a later part of this document. The driver program is a multi-module configuration named GVPatch which will be described shortly. Source Files All sources are currently kept in the directory [Indigo]Tools>, the files in this directory are as follows: GVPServer.mesa the server program source GVPServer.bcd the server program BCD (Alto-Mesa code) GVPServer.df a DF describing GVPServer (for reference only) GVPatch.bcd the driver program code GVPatch.df DF file for GVPatch driver GVPatch.config binder configuration file GVPDefs.mesa Defs file for GVPatch driver GVPDefs.bcd BCD for above GVPBrowser.mesa, bcd implements browser mode viewer GVPMain.mesa, .bcd start code and server mode viewer code GVPEditor.mesa, .bcd editor mode viewer code GVPDriver.mesa, .bcd implements the bytestream interface to GVPServer GVPProcs.mesa, .bcd mostly heap manipulation procedures GVPatch.tioga GVPatch User Manual GVPImpl.tioga this manual GVPExternal.mesa a sample external patching procedure GVPatch - the driver program This configuration runs in the Cedar environment and provides a viewer based user interface. Five program modules are used, together with the Defs file GVPDefs. Thus all modules must be recompiled if GVPDefs but otherwise there are no compilation order requirements.. Overall approach The are a number of styles which are adopted throughout all the modules in the GVPatch driver. Any global state is held in one of two places, if it needs to be freely passed around it is in a record of type GVPRec, a pointer to which is an argument to many procedures. If the state is useful only within one module then it is kept in the global frame of that module. Only one instance of the GVPatch viewer is allowed, this restriction is implemented in GVPMain. In order to keep the data in global frames valid between program incarnations, each module other than GVPMain has two procedures ModuleInit and ModuleTidyUp. These are called at the start and end of each incarnation and their job is to take or give back storage and keep other state in the global frame consistent. Many procedures which have a notion of success or failure communicate this by returning a ROPE with either NIL or some useful message in it. The message can then be placed on the screen or passed up to a higher level. The layout of each module is such that all global frame declarations appear first in the source (Mesa) file, followed by procedure declarations, then the Init and TidyUp procedures. Module GVPDefs This module consists of useful system wide declarations of types and record structures and declarations of procedures which are called across module boundaries. Funnies in here include a fudge of heap object type from an enumerated type to CARDINAL and the declaration of the number of pages in a heap segment which may change from time to time. Otherwise it's all fairly straightforward and descriptions of the procedures defined in here appear in the appropriate module documentation. Module GVPMain This module contains the start code for the system and is also concerned with implementing the server interface. All the procedures invoked when buttons are clicked are to be found here, in GVPEditor or in GVPBrowser. These three modules are a MONITOR and many of the button procedures are ENTRY procedures The lock is kept in GVPMain and the purpose of the monitor is to prevent certain pairs buttons being active at once. The unprotected buttons are either harmless or used to stop an already running button. The viewer itself is a container containing a label as a message window, a small viewer, and six other viewers, two for each display mode. Each mode has a container containing the buttons and data input viewers for that mode, and a typescript for text output. The viewers for the two modes not in use are kept off the screen and juggled around when the mode changes. The procedure MainInit builds the viewer by creating a container and the calling procedures to make viewers for each of the modes. A small viewer called focus is a fudge and used to hold the current selection while the mode is changing (gets round a viewers bug). When the main viewer is destroyed the procedure DestroyProc is called to tidy up, it calls each of the TidyUp procedures and destroys the global data record. Procedure descritions for most PROCs now follow MainInit, DestroyProc see above ToFocus put the selection in focus while moving viewers Set, Flash, Failed, Fail put various things in the message window GetHandle returns the REF to the main data record, only used once NumFromRope reads octal or decimal # from given place in a rope. Returns number and end position. (/ or empty rope returns last CARDINAL) MakeServerButtons called from MainInit to make buttons, note passing of data record also note that logText has the backing file GVPatch.log ServerButton juggle the screen to put server mode viewer up other server buttons mostly just call procedures from other modules or put selection ParseLength get file length supplied, BOOL to say if OK ResetEdit clears editor typescript, moves current selection out first! DoIt the registered command, does nothing if viewer already up. StartPatch makes new record, calls each Init procedure * the start code say we want to know if user hits destroy, register command and start the whole thing up. Module GVPEditor This module implements the page editing functions of GVPatch. The main data structure is the edit buffer, a 256 word MDS zone which holds a page while it is being edited. It is referenced by pointers pageWords and pageBytes. A 256 word SEQUENCE editModeVec contains the associated display mode for each word in the edit buffer. The SEQUENCE values holds replacement words when editing is being made (maximum 40 words). BOOLs are used to say if the buffer contains a valid page and if so, if it has been changed. MakeEditorButtons much the same as its server counterpart PageOK called by many routines to check that buffer holds a valid page SelectIndex returns indices of first and last word touched by the current selection. Some fairly dodgy arithmetic here. Returns first>last if selection in wrong viewer or no page in buffer. Results always in [0..255] IndexSelect places selection over words [first..last], ERROR if args bad. Again wierd arithmetic (bound to change with every Cedar release). Page handling buttons - all use the page read/write facilities in GVProcs ResetPageButton gets current page from server, resets display mode and various BOOLs GetPageButton gets current page from local if possible else from server, then as above GetNextButton calls NextItem (GVPProcs) then as GetPageButton GetPrevButton calls PrevItem then as above NewPage resets things when new page in buffer, prints it ShowPageButton buffer must be valid, then call ShowPageProc Data structure display buttons - all check for valid page and selection in editor typescript ObjectButton must be enough room for header, 5 values is max PutFR can handle TimeStampButton check that it fits, don't attempt a partial print SizeButton Only sensible for the current page, lots more work to span pages RNameButton proceed if at least 2 words on page ReplaceButton call ParseValues to get numbers, then be careful about whether to proceed CharsButton, WordsButton easy ExternalButton Get capability for the bcd and try to load and start it GetEditBuffer If selection is good make a SEQUENCE of the words and return REF PutEditBuffer If REF#NIL make edits and log changes made EditInfo put what we know about the current page in our label ShowPageProc long but straightforward. Calls to ShowHeader, Break, Look and PutNum made from here. index used to index the buffer Look change the look of subsequent chars sent to the typescript ShowHeader set bold look and then print 3 items calling Break between each Break if called with index on a line break then put a newline and word count out in the standard look. Note pointer comparison to decide on look changes. PutNum only called for "data" words, use editModeVec to decide how to print ParseValues tricky PROC reads octal nums or strings from a rope. Spaces or tabs allowed between items, last string OK without closing quote. Returns number of words needed or last CARDINAL if it didn't like something. EditorInit get the storage we need, no checks made if anything fouls up here EditorTidyUp just free the store Module GVPBrowser. This module provides the browser mode viewer. There is a 256 word MDS zone referenced by pageBuffer used here. MakeBrowserButtons same as others BrowserButton same as others ShowAuto print the current page if autoShow flag is on PlaceRope return a rope with the current page in it SetLogicalButton SetPhysicalButton Reset these 3 all call procedures in GVPProcs NextButton PrevButton these 2 may repeat and may do a page print when invoked ShowButton use ShowAuto to print current page ShowModeButton RepeatButton AutoShowButton these 3 just flip BOOLs and change their contents ScanErrorButton ScanMatchButton mark us stoppable and call the scan routine in GVPProcs StopButton StopRequested one sets, the other tests and clears the stop flag ValueButton RepeatCountButton PatternButton just put selection in the right viewer GetRepeatCount if repeat flag set return the count else return 1 GetSearchPattern complex. Get two nums and string, return LAST CARDINAL if / ObjectRope given object type [0..15] return name as rope, can ask for full or brief ObjectIndex given rope object type return [0..15], only first 3 chars count, return 16 if something wrong or LAST CARDINAL if rope was / ShowItem print page according to mode flag PrintPageFull print current page in max detail PrintPageBrief quick summary of page contents, print position if multiple of segSize Module GVPProcs This module holds a set of procedures which manipulate the local copy of the heap. The code is somewhat tricky in places. Global frame data includes a page buffer (pageBuffer) and various SEQUENCES for tables of data. BitMap is such a SEQUENCE and is used when scanning to detect duplicate object numbers, the procedure SetBitFromObj sets a bit in this map and returns the old bit value. The bits are indexed via an object number. LList and PList are SEQUENCES of SegmentPtrs which detail the correspondence between physical segments in the heap file and their corresponding "logical" segments. LList is always indexed by a logical segment number and returns the corresponding physical segment. PList is indexed by a physical segment and does the reverse mapping. These structures are derived from the file Heap.Segments by the procedure GetChain. map is a SEQUENCE of CHARs which says whether a given heap page exists in full in the local heap and if so if it has been altered. This structure is copied to the file Heap.Map between sessions of GVPatch. The possible chars are "." (empty), "f" (full, unchanged) and "a" (full, altered). GetChain does the initialisation of the systems data structures opening the heap STREAM and making the SEQUENCEs LList, PList and map. It uses several MDS zones while doing this but gives them back when it finishes. Other procedures are detailed below SetLogical SetPhysical given a number, make that the current position or page. NextPage make the next position current PrevPage make the previous position current ResetCurrent current _ position zero PositionRope return current position for someone to read ReadHeapPage put a page into callers buffer, get from local if possible else server ReadLocalPage put local page into callers buffer WriteLocalPage write callers buffer to local heap WriteHeap write all altered pages back to servers heap ScanHeap long and moderately simple proc runs thro heap from current place until stopped or at end. Notes possible errors and looks for search pattern if asked GetPageState returns map contents for given page SetPageState sets map contents for given page to given state CheckStructure return if GetChain already called this session else call it ProcsInit get store for page buffer and bitmap ProcsTidyUp write the map file if necessary, close heap stream and release store Module GVPDriver. This module provides the byte stream interface to the server. Its only global data is the bytestream itself. The bytestream is closed whenever a server command fails and is reopened automatically when the next server command is attempted. Operations with the server are started by sending a command byte and then any additional data for the particular command. The server is expected to respond with either an error code (and a message) saying the command could not be performed or with the command byte and any data returned by the command. Procedures are KillByteStream if the stream shows signs of life kill it CheckByteStream if the stream appears dead open it, called by all basic routines which need to talk to the server ConnectToServer open a bytestream to a server and send users name and password RestartServer wrap up the command line into rem.cm, send that to the server and then the restart command. ServerError when a command has been sent wait for error code or the command byte to be returned. If error return the message GetHeapFile read the file Heap.Segments from the server and then the heap structure. Make local heap.data (error if no room) from the structure. OpenFile open named file on the server, specify if it must be old Return length and error message (if any). File is always opened for WRITE SetFileLength set the length of (already open) file on the server ReadPage read given page from server's open file WritePage write given page to server's open file ReadFile copy a server file to local with same name WriteFile obvious SetServerLength open given file on the server (old only) and set its length SetLocalLength set length of a local file ReadServerPage open server's heap and read given page WriteServerPage open server's heap and write given page DriverInit DriverTidyUp start and stop the Pup package Program GVPServer This program is written in Alto-Mesa and runs on the Grapevine server to be patched. It creates a byte stream listener on the GVPatch socket (047B) and waits for commands. A command is a byte followed by data for that command. The data is all received before anything is sent out in reply. If the command can be performed successfully the command byte is sent back to the user followed by any results. If the command fails an error code byte is sent along with a message string. When a stream is opened the first thing to be received must be the login command byte and the name and password of the user. If nobody is currently logged in to the GVPatch server this user is authenticated (must be temple.pa or in the group transport.ms) and if OK made the current user. The server now waits for commands from the use's machine. Only one session is allowed and so if another stream is opened by another user it is immediately closed. If another stream is opened by the same user then that is OK (we assume that his other session died at the other end and will go away soon). Global data is used to hold the name of the current user and info on the currently open file. Only one file may be open at once and opening a file closes the currently open one. Repeatedly opening the same file is handled efficiently. The program is fairly straightforward and the source should provide adequate documentation for any modifications to it. ÊؘJšOœÐbx!œOÏb œóžœ‚ž œmžœ#ž œ×Ðblœ‘žœ£ žœëžœþžœƒžœ‚žœž œã žœUžœËž œž œž œUžœÂžœàžœ\ž œ° žœ¨ž œ.žœ`žœcžœžœž œìžœžœãžœ žœžœžœš žœ¦ž œŸžœ— ˜Ú‘—…—HÜIº