DIRECTORY Buttons USING [Button, ButtonProc, Create], Commander USING [CommandProc, Register], Containers USING [ChildXBound, ChildYBound, Container, Create], GVPDefs, IO USING [Flush, PutF, time], Labels USING [Create, Set, SetDisplayStyle], Process USING [MsecToTicks, Pause], Rope USING [Fetch, Length], ViewerEvents USING [EventProc, RegisterEventProc], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, MoveViewer, PaintViewer, SaveViewer], ViewerTools USING [GetContents, MakeNewTextViewer, SetSelection]; GVPMain: CEDAR MONITOR LOCKS lock IMPORTS Buttons, Commander, Containers, GVPDefs, IO, Labels, Process, Rope, ViewerEvents, ViewerIO, ViewerOps, ViewerTools EXPORTS GVPDefs = BEGIN OPEN GVPDefs; lock: PUBLIC MONITORLOCK; h: GVPRef _ NIL; message, focus, root: Viewer; serverButtons, logText, serverInput, fileInput, cLineInput, lengthInput: Viewer; MainInit: PROC = BEGIN root _ Containers.Create[[name: "GV-Patch", iconic: FALSE, scrollable: FALSE]]; h.root _ root; -- this is a fudge I don't really understand focus _ ViewerTools.MakeNewTextViewer[[parent: root, wx: 0, wy: row5, ww: char, wh: rowHeight, border: FALSE]]; message _ Labels.Create[[parent: root, wx: col1, wy: row5, ww: 90*char, wh: rowHeight, border: FALSE]]; MakeEditorButtons[h]; MakeBrowserButtons[h]; MakeServerButtons[h]; ViewerOps.MoveViewer[viewer: serverButtons, x: 0, y: 0, w: 0, h: 4*rowSize, paint: FALSE]; ViewerOps.MoveViewer[viewer: logText, x: 0, y: row6, w: 0, h: 0, paint: FALSE]; Containers.ChildXBound[root, serverButtons]; Containers.ChildXBound[root, logText]; Containers.ChildYBound[root, logText]; ViewerOps.PaintViewer[root, all]; ToFocus[]; h.currentButtons _ serverButtons; h.currentText _ logText END; DestroyProc: ViewerEvents.EventProc = TRUSTED BEGIN IF viewer#root THEN RETURN; h.root _ NIL; BrowserTidyUp[]; ProcsTidyUp[]; EditorTidyUp[]; DriverTidyUp[]; h _ NIL END; ToFocus: PUBLIC PROC = {ViewerTools.SetSelection[focus]}; -- selection put in "focus" GetHandle: PUBLIC PROC RETURNS[handle: GVPRef] = {handle _ h}; -- return data record^ Set: PUBLIC PROC[r: ROPE _ NIL] = { Labels.Set[message, r, TRUE] }; Flash: PUBLIC PROC[r: ROPE] = BEGIN Labels.Set[message, r, TRUE]; Labels.SetDisplayStyle[message, $WhiteOnBlack]; Process.Pause[Process.MsecToTicks[750]]; Labels.SetDisplayStyle[message, $BlackOnWhite] END; Failed: PUBLIC PROC[r: ROPE] RETURNS [failed: BOOLEAN] = BEGIN failed _ r#NIL; IF failed THEN Flash[r] ELSE Set[] END; NumFromRope: PUBLIC PROC[octal: BOOLEAN, r: ROPE, start: CARDINAL] RETURNS [num, end: CARDINAL] = BEGIN i: CARDINAL _ start; top: CHAR = IF octal THEN '7 ELSE '9; base: CARDINAL = IF octal THEN 8 ELSE 10; c: CHAR _ ' ; len: CARDINAL = Rope.Length[r]; num _ 0; end _ len; UNTIL c IN ['0..top] OR c='/ DO IF i=len THEN {num _ lastCard; RETURN}; c _ Rope.Fetch[r, i]; i _ i + 1 ENDLOOP; IF c IN ['0..top] THEN BEGIN i _ i - 1; UNTIL i = len OR NOT( c IN ['0..top] ) DO c _ Rope.Fetch[r, i]; IF c IN ['0..top] THEN num _ num * base + c - '0; i _ i + 1 ENDLOOP; IF i#len THEN i _ i-1 END ELSE num _ lastCard; end _ i END; MakeServerButtons: PROC[h: GVPRef] = BEGIN logText _ ViewerOps.CreateViewer[flavor: $Typescript, info: [parent: h.root, file: "GVPatch.log", border: TRUE, iconic: FALSE, wy: offScreen]]; h.logStream _ ViewerIO.CreateViewerStreams[viewer: logText, name: NIL].out; serverButtons _ Containers.Create[[name: NIL, parent: h.root, wx: 0, wy: offScreen, wh: 4*rowSize, border: FALSE, scrollable: FALSE]]; serverInput _ ViewerTools.MakeNewTextViewer[[parent: serverButtons, wx: col5, wy: row1+2, ww: 40*char, wh: rowHeight, scrollable: FALSE, border: FALSE, data: "???"]]; fileInput _ ViewerTools.MakeNewTextViewer[[parent: serverButtons, wx: col5, wy: row2+2, ww: 40*char, wh: rowHeight, scrollable: FALSE, border: FALSE]]; lengthInput _ ViewerTools.MakeNewTextViewer[[parent: serverButtons, wx: col5, wy: row3+2, ww: 40*char, wh: rowHeight, scrollable: FALSE, border: FALSE]]; cLineInput _ ViewerTools.MakeNewTextViewer[[parent: serverButtons, wx: col5, wy: row4+2, ww: 80*char, wh: rowHeight, scrollable: FALSE, border: FALSE, data: "@Server"]]; [] _ Buttons.Create[info: [name: "BROWSER", wx: col1, wy: row3, wh: rowSize+rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: BrowserButton]; [] _ Buttons.Create[info: [name: "EDITOR", wx: col1, wy: row1, wh: rowSize+rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: EditorButton]; [] _ Buttons.Create[info: [name: "server >", wx: col4, wy: row1, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: ServNameButton]; [] _ Buttons.Create[info: [name: "read heap", wx: col2, wy: row1, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, guarded: TRUE, proc: ReadHeapButton]; [] _ Buttons.Create[info: [name: "write heap", wx: col3, wy: row1, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, guarded: TRUE, proc: WriteHeapButton]; [] _ Buttons.Create[info: [name: "read file", wx: col2, wy: row2, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: ReadFileButton]; [] _ Buttons.Create[info: [name: "write file", wx: col3, wy: row2, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: WriteFileButton]; [] _ Buttons.Create[info: [name: "file >", wx: col4, wy: row2, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: FileNameButton]; [] _ Buttons.Create[info: [name: "length >", wx: col4, wy: row3, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: LengthButton]; [] _ Buttons.Create[info: [name: "set local", wx: col2, wy: row3, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: SetLocalButton]; [] _ Buttons.Create[info: [name: "set server", wx: col3, wy: row3, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: SetServerButton]; [] _ Buttons.Create[info: [name: "write log", wx: col2, wy: row4, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: WriteLogButton]; [] _ Buttons.Create[info: [name: "RESTART", wx: col3, wy: row4, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, guarded: TRUE, proc: RestartButton]; [] _ Buttons.Create[info: [name: "command >", wx: col4, wy: row4, wh: rowHeight, ww: buttonSize, parent: serverButtons], clientData: h, proc: CLineButton]; END; ServerButton: PUBLIC ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; ToFocus[]; ViewerOps.MoveViewer[viewer: h.currentButtons, x:0, y: offScreen, w: 0, h: 0, paint: FALSE]; ViewerOps.MoveViewer[viewer: serverButtons, x:0, y: 0, w: 0, h: 4*rowSize, paint: FALSE]; ViewerOps.MoveViewer[viewer: h.currentText, x:0, y: offScreen, w: 0, h: 0, paint: FALSE]; ViewerOps.MoveViewer[viewer: logText, x:0, y: row6, w: 0, h: 0, paint: FALSE]; Containers.ChildXBound[h.root, logText]; Containers.ChildXBound[h.root, serverButtons]; Containers.ChildYBound[h.root, logText]; ViewerOps.PaintViewer[h.root, all]; h.currentButtons _ serverButtons; h.currentText _ logText END; GetServerName: PUBLIC PROC RETURNS[name: ROPE] = BEGIN name _ ViewerTools.GetContents[serverInput] END; ServNameButton: ButtonProc = TRUSTED {ViewerTools.SetSelection[serverInput]}; CLineButton: ButtonProc = TRUSTED {ViewerTools.SetSelection[cLineInput]}; FileNameButton: ButtonProc = TRUSTED {ViewerTools.SetSelection[fileInput]}; LengthButton: ButtonProc = TRUSTED {ViewerTools.SetSelection[lengthInput]}; ReadHeapButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; [] _ Failed[GetHeapFile[h]] END; WriteHeapButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; [] _ Failed[WriteHeap[h]] END; ReadFileButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; [] _ Failed[ReadFile[h, ViewerTools.GetContents[fileInput]]] END; WriteFileButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; [] _ Failed[WriteFile[h, ViewerTools.GetContents[fileInput]]] END; SetLocalButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; pages, bytes: CARDINAL; ok: BOOLEAN; [pages, bytes, ok] _ ParseLength[]; IF NOT ok THEN RETURN; [] _ Failed[SetLocalLength[h, ViewerTools.GetContents[fileInput], pages, bytes]] END; SetServerButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; pages, bytes: CARDINAL; ok: BOOLEAN; [pages, bytes, ok] _ ParseLength[]; IF NOT ok THEN RETURN; [] _ Failed[SetServerLength[h, ViewerTools.GetContents[fileInput], pages, bytes]] END; RestartButton: ENTRY ButtonProc = TRUSTED BEGIN h: GVPRef = NARROW[clientData]; [] _ Failed[RestartServer[h, ViewerTools.GetContents[cLineInput]]] END; WriteLogButton: ENTRY ButtonProc = TRUSTED BEGIN Set["Writing log . . ."]; h.logStream.PutF["\nLog written on %t\n", IO.time[]]; h.logStream.Flush[]; ViewerOps.SaveViewer[logText]; Set["Log written to file GVPatch.log"] END; ParseLength: PROC RETURNS[pages, bytes: CARDINAL, ok: BOOLEAN] = BEGIN r: ROPE = ViewerTools.GetContents[lengthInput]; pos: CARDINAL _ 0; ok _ FALSE; [pages, pos] _ NumFromRope[FALSE, r, 0]; [bytes, pos] _ NumFromRope[FALSE, r, pos]; IF pages=lastCard OR bytes>=bytesPerPage THEN {Flash["Bad file length"]; RETURN}; ok _ TRUE END; DoIt: Commander.CommandProc = TRUSTED {StartPatch[]}; StartPatch: ENTRY PROC = BEGIN IF h#NIL THEN RETURN; h _ NEW[GVPRec]; DriverInit[]; ProcsInit[]; EditorInit[]; MainInit[]; BrowserInit[] END; [] _ ViewerEvents.RegisterEventProc[DestroyProc, destroy]; Commander.Register["GVPatch", DoIt]; StartPatch[] END. €GVPMain.mesa, start module for the GVPatch system HGM, May 23, 1984 10:47:43 pm PDT Steve Temple, September 30, 1982 12:19 pm Schroeder, March 31, 1983 10:03 am This module contains the start code for the GVPatch system and also the server mode viewer code. The monitor lock which is shared with GVPEditor and GVPBrowser is here as is the basic viewer framework. MainInit makes a container for the various viewers which will be created, a label for messages and a small viewer to put the current selection in while the mode is changing. (If a viewer is taken off screen with the selection in it you can't get it (the selection) back) It makes calls to create a viewer for each mode and then puts the server mode viewer on the screen. The fields currentText and currentButtons in the data record (h^) hold the typescript and buttons container for the mode currently on screen. DestroyProc is called whenever a viewer is destroyed (this is set up near the end of this module). We filter out all but destroys of the outermost container (root) and when this occurs free the data record and call each TidyUp procedure. Set and Flash put a message in the message window (the label "message") Flash also blinks the window to signify that this is an error message Failed takes a rope error message, Flashes it if non-NIL and returns a BOOLEAN error flag NumFromRope is a general purpose proc which extracts numbers in base 8 or 10 from a rope. The "start" parameter is the position in the rope from which the first char of the number will be taken. The proc returns the number and "end", the position after the last char of the number or the last char of the rope If the char / is found instead of a digit this counts as the number LAST[CARDINAL], this value is also returned if the end of the rope is reached before a digit is found. Any non-digit chars are valid as separators. Note that overflow is not checked for and the max number obtainable is 65535 MakeServerButtons creates the server mode viewer, this consists of a typescript (which also serves as the system log and so has a backing file) and a container to hold the buttons and the four input viewers. All the buttons FORK their procedures and we rely on all the button procedures being ENTRY procedures to ensure that no conflicts occur. ServerButton will be called by clicking the SERVER button in either Editor or Browser modes. It just moves the current viewer off the screen and puts the server mode viewer up instead. Note that we put the selection in the "focus" viewer before attempting any of this. GetServerName gives the server name to the proc in GVPDriver which opens the server bytestream. The next four procs just put the selection in the appropriate input viewer. ReadHeap uses the proc in GVPDriver to do the work, as do ReadFile and WriteFile. WriteHeap uses a proc in GVPProcs to do its work SetLocal and SetServer both call ParseLength to get the file length (pages and bytes) and then call the appropriate proc in GVPDriver Restart uses the proc in GVPDriver to do its work, a sensible default command line was set up earlier in MakeServerButtons. WriteLog flushes the typescript and puts it in the file GVPatch.log, the old file is lost. ParseLength tries to make a file length from the rope in the length input viewer. A BOOLEAN says that we got something reasonable. A file length is two numbers, the first is the number of completely full pages in the file, the second the number of bytes in the last page of the file. The command that is registered with the Commander only lets one instance of GVPatch be alive at any one time. If the REF to the data record isn't NIL when we invoke the command nothing happens! StartPatch makes a new record and calls each Init proc to get things going The remaining lines are the start code. We make sure DestroyProc is called each time a viewer is destroyed, then register the command with the Commander and finally start the system going. Ê Ñ˜šœ1™1Jšœ!™!Jšœ)™)Jšœ"™"—J˜JšœS™SJšœS™SJšœ!™!J˜J˜šÏk ˜ Jšœœ˜+šœ œ˜(Jšœ œ/˜?—J˜Jšœœ˜Jšœœ ˜,Jšœœ˜#Jšœœ˜—Jšœ œ ˜2Jšœ œ˜%Jšœ œ5˜DJšœ œ0˜AJ˜Jšœ œ˜Jšœ˜ Jš˜Jšœ)œG˜rJšœ ˜Jšœœ ˜J˜Jšœœ œ˜J˜Jšœ œ˜J˜J˜J˜PJ˜J˜JšœV™VJšœW™WJšœ`™`JšœW™WJšœW™WJšœB™BJ˜JšÏnœœ˜˜Jšœ4œœ˜OJšœÏc,˜;J˜˜OJšœœ˜J˜—˜GJšœœ˜J˜—J˜J˜J˜J˜JšœSœ˜ZJšœHœ˜OJ˜J˜,J˜&J˜&J˜J˜!J˜ J˜!J˜Jšœ˜J˜J˜—JšœZ™ZJšœ^™^Jšœ4™4J˜šœ&œ˜3Jšœ œœ˜Jšœ œ˜ J˜J˜J˜J˜Jšœ˜Jšœ˜J˜J˜—Jšžœœœ&Ÿ˜UJ˜Jš ž œœœœ!Ÿ˜UJ˜J˜JšœG™GJšœE™EJ˜Jš žœœœœœœ˜CJ˜š žœœœœ˜#Jšœœ˜J˜/J˜(J˜.Jšœ˜J˜J˜—JšœY™YJ˜š žœœœœœ œ˜>Jšœ œ˜Jšœœ œ˜"Jšœ˜J˜J˜—JšœY™YJšœ^™^JšœX™XJšœ#™#JšœS™SJšœV™VJšœR™RJšœ&™&J˜š ž œœœœœ œ˜BJšœ œ˜$Jšœœ ˜Jš œœœœœ˜%Jš œœœœœ˜)Jšœœ˜ Jšœœ˜J˜J˜ J˜šœœ œ˜Jšœœœ˜(J˜J˜ Jšœ˜J˜—šœœ ˜šœ˜ J˜ š œ œœœ ˜)J˜Jšœœ œ˜1J˜ Jšœ˜Jšœœ˜—Jš˜—Jšœ˜J˜Jšœ˜J˜J˜——Jšœ[™[Jšœ[™[JšœT™TJšœK™KJ˜Jšžœœ˜*˜˜5Jšœ4œ œ˜YJ˜—JšœBœ˜KJ˜šœ)œ'˜SJšœœœ˜2J˜—˜YJšœ(œ œ˜LJ˜—˜WJšœ(œ œ˜?J˜—˜YJšœ(œ œ˜?J˜—˜XJšœ(œ œ˜PJ˜J˜—˜WJ˜LJ˜—˜UJ˜KJ˜—˜RJ˜NJ˜—˜PJ˜7Jšœ œ˜&J˜—˜QJ˜6Jšœ œ˜'J˜—˜PJ˜MJ˜—˜QJ˜OJ˜—˜SJ˜MJ˜—˜QJ˜KJ˜—˜PJ˜MJ˜—˜QJ˜NJ˜—˜PJ˜MJ˜—˜NJ˜6Jšœ œ˜%J˜—˜PJ˜J—Jšœ˜J˜J˜—JšœU™UJšœY™YJšœ\™\J˜šœœœœ˜5Jšœ œ ˜J˜ JšœUœ˜\JšœRœ˜YJšœRœ˜YJšœGœ˜NJ˜J˜(J˜.J˜(J˜#J˜J˜!J˜Jšœ˜J˜J˜—JšœS™SJšœW™WJ˜š ž œœœœœ˜6J˜+Jšœ˜J˜—Jšœœ)˜MJ˜Jšœœ(˜IJ˜Jšœœ'˜KJ˜Jšœœ)˜KJ˜J˜JšœQ™QJšœ0™0J˜šœœœ˜0Jšœ œ ˜J˜Jšœ˜J˜—šœœœ˜1Jšœ œ ˜J˜Jšœ˜J˜—šœœœ˜0Jšœ œ ˜J˜