GVPBrowser.mesa
HGM. May 23, 1984 11:01:01 pm PDT
Steve Temple. November 5, 1982 1:34 pm
Schroeder on March 31, 1983 9:51 am
This module implements the browser mode of the GVPatch system. The monitor lock for this
module is in GVPMain. This module contains all the browser mode button procedures and
relies on procedures in GVPProcs for many of its operations. Note that we must SHARE
ObjectDirDefs to get at the internals of object numbers (machine dependent records)
DIRECTORY
Buttons USING [Button, Create, ReLabel, SetDisplayStyle],
Containers USING [ChildXBound, ChildYBound, Container, Create],
GVPDefs,
IO USING [PutF, PutText, SetIndex, STREAM, UnsafeGetBlock],
ObjectDirDefs USING [ObjectNumber],
Rope USING [Concat, Equal, Fetch, Length, Substr],
ViewerIO USING [CreateViewerStreams],
ViewerOps USING [CreateViewer, MoveViewer, PaintViewer],
ViewerTools USING [GetContents, MakeNewTextViewer, SetSelection, SetContents];
GVPBrowser: CEDAR MONITOR
LOCKS lock
IMPORTS Buttons, Containers, GVPDefs, IO, Rope, ViewerIO, ViewerOps, ViewerTools
EXPORTS GVPDefs
SHARES ObjectDirDefs =
BEGIN OPEN GVPDefs;
The viewers here are for the obvious thing. The BOOLs are used to control repeating
operations or the style of printing objects. The buffer "pageBuffer" holds a disk page
while we are printing its contents.
browserButtons, browserText, setInput, repeatInput, patternInput: Viewer;
repeatPending, stopScan, stoppable, autoShow: BOOLEANFALSE;
showFull: BOOLEANTRUE;
pageBuffer: REF PageWordVec ← NIL;
objects: ARRAY objRange OF ROPE = -- used for printing and lookup
["Gap ", "Body ", "SLinp ", "SLpend", "SLfwd ", "RSobj ", "RSmail", "temp ",
"RSname", "MSname", "test-M", "TOC ", "Arch ", "s15 ", "s16 ", "s17 " ];
MakeBrowserButtons makes a container for the browser buttons and (three) input viewers
and also makes a typescript and attaches an output stream to it. See MakeServerButtons in
GVPMain for more details.
MakeBrowserButtons: PUBLIC PROC[h: GVPRef] = BEGIN
browserText ← ViewerOps.CreateViewer[flavor: $Typescript,
info: [parent: h.root, border: TRUE, iconic: FALSE, wy: offScreen]];
h.browserStream ← ViewerIO.CreateViewerStreams[viewer: browserText, name: NIL].out;
browserButtons ← Containers.Create[[name: NIL, parent: h.root, wx: 0, wy: offScreen,
wh: 4*rowSize, border: FALSE, scrollable: FALSE]];
setInput ← ViewerTools.MakeNewTextViewer[[parent: browserButtons, wx: col6,
wy: row1+2, ww: 30*char, wh: rowHeight, scrollable: FALSE, border: FALSE, data: "0"]];
patternInput ← ViewerTools.MakeNewTextViewer[[parent: browserButtons, wx: col6,
wy: row3+2, ww: 30*char, wh: rowHeight, scrollable: FALSE, border: FALSE, data: "/ / /"]];
repeatInput ← ViewerTools.MakeNewTextViewer[[parent: browserButtons, wx: col6,
wy: row2+2, ww: 30*char, wh: rowHeight, scrollable: FALSE, border: FALSE, data: "1"]];
[] ← Buttons.Create[info: [name: "SERVER", wx: col1, wy: row1, wh: rowSize+rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ServerButton];
[] ← Buttons.Create[info: [name: "EDITOR", wx: col1, wy: row3, wh: rowSize+rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: EditorButton];
[] ← Buttons.Create[info: [name: "position #", wx: col3, wy: row1, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: SetLogicalButton];
[] ← Buttons.Create[info: [name: "page #", wx: col2, wy: row1, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: SetPhysicalButton];
[] ← Buttons.Create[info: [name: "number >", wx: col5, wy: row1, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ValueButton];
[] ← Buttons.Create[info: [name: "FULL", wx: col2, wy: row2, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ShowModeButton];
[] ← Buttons.Create[info: [name: "REPEAT", wx: col3, wy: row2, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: RepeatButton];
[] ← Buttons.Create[info: [name: "AUTO", wx: col4, wy: row2, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: AutoShowButton];
[] ← Buttons.Create[info: [name: "next", wx: col2, wy: row3, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: NextButton];
[] ← Buttons.Create[info: [name: "prev", wx: col3, wy: row3, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: PrevButton];
[] ← Buttons.Create[info: [name: "pattern >", wx: col5, wy: row3, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: PatternButton];
[] ← Buttons.Create[info: [name: "scan error", wx: col2, wy: row4, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ScanErrorButton];
[] ← Buttons.Create[info: [name: "scan match", wx: col3, wy: row4, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ScanMatchButton];
[] ← Buttons.Create[info: [name: " ! STOP !", wx: col4, wy: row4, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: StopButton];
[] ← Buttons.Create[info: [name: "show", wx: col4, wy: row3, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ShowButton];
[] ← Buttons.Create[info: [name: "repeat >", wx: col5, wy: row2, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: RptCountButton];
[] ← Buttons.Create[info: [name: "reset", wx: col4, wy: row1, wh: rowHeight,
ww: buttonSize, parent: browserButtons], clientData: h, proc: ResetButton]
END;
BrowserButton is called by clicking the BROWSER button in server or editor modes. It just
shifts the current mode's viewer off the screen and puts up the browser mode viewer.
Note that we call CheckStructure to make the data strucures necessary for browsing. If this
fails we can't get to brower mode.
BrowserButton: PUBLIC ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
r: ROPE = CheckStructure[h];
IF r#NIL THEN {Flash[r]; RETURN};
ToFocus[];
ViewerOps.MoveViewer[viewer: h.currentButtons, x:0, y: offScreen, w: 0, h: 0, paint: FALSE];
ViewerOps.MoveViewer[viewer: browserButtons, 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: browserText, x:0, y: row6, w: 0, h: 0, paint: FALSE];
Containers.ChildXBound[h.root, browserText];
Containers.ChildXBound[h.root, browserButtons];
Containers.ChildYBound[h.root, browserText];
ViewerOps.PaintViewer[h.root, all];
h.currentButtons ← browserButtons;
h.currentText ← browserText
END;
ShowAuto consults the auto display BOOLEAN and if set prints the current page.
It returns the current position as a rope. PlaceRope is the proc which does just that.
ShowAuto: PROC[h: GVPRef] RETURNS[r: ROPE] = BEGIN
IF autoShow THEN ShowItem[h, showFull];
r ← PlaceRope[h]
END;
PlaceRope: PROC[h: GVPRef] RETURNS[r:ROPE] ={r ← Rope.Concat["Current ", PositionRope[h]]};
SetLogicalButton and SetPhysicalButton get a number from the input viewer and attempt
to make that the current position or page. The procs that do the work are in GVPProcs.
If OK then call ShowAuto to show where we are and maybe print the page.
ResetButton is just a special case of SetLogicalButton
SetLogicalButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
a: CARDINAL;
[num: a] ← NumFromRope[octal: FALSE, r: ViewerTools.GetContents[setInput], start: 0];
IF SetLogical[h, a] THEN Set[ShowAuto[h]] ELSE Flash["Couldn't"]
END;
SetPhysicalButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
a: CARDINAL;
[num: a] ← NumFromRope[octal: FALSE, r: ViewerTools.GetContents[setInput], start: 0];
IF SetPhysical[h, a] THEN Set[ShowAuto[h]] ELSE Flash["Couldn't"]
END;
ResetButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
IF SetLogical[h, 0] THEN Set[ShowAuto[h]] ELSE Flash["Couldn't"]
END;
PrevButton and NextButton call the appropriate proc in GVPProcs to work out the new
position. They may both repeat and the auto show facility may be enabled. We must also
check to see if the STOP button has been clicked.
ShowButton just calls ShowItem (this module) with the print mode flag as an argument.
PrevButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
stoppable ← TRUE;
THROUGH [0..GetRepeatCount[]) DO
IF NOT PrevPage[h] THEN {Flash["No more pages"]; EXIT};
[] ← ShowAuto[h];
IF StopRequested[] THEN EXIT
ENDLOOP;
stoppable ← FALSE;
Set[PlaceRope[h]]
END;
NextButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
stoppable ← TRUE;
THROUGH [0..GetRepeatCount[]) DO
IF NOT NextPage[h] THEN {Flash["No more pages"]; EXIT};
[] ← ShowAuto[h];
IF StopRequested[] THEN EXIT
ENDLOOP;
stoppable ← FALSE;
Set[PlaceRope[h]]
END;
ShowButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
ShowItem[h, showFull];
Set[PlaceRope[h]]
END;
ShowModeButton just flips the printing mode flag (showFull) and relabels itself
accordingly. RepeatButton is much the same, the flag is repeatPending and reverse
video is used to show the flag is set. AutoShowButton is similar.
ShowModeButton: ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
me: Viewer = NARROW[parent];
showFull ← NOT showFull;
Buttons.ReLabel[me, IF showFull THEN "FULL" ELSE "BRIEF"]
END;
RepeatButton: ButtonProc = TRUSTED BEGIN
me: Viewer = NARROW[parent];
repeatPending ← NOT repeatPending;
Buttons.SetDisplayStyle[me, IF repeatPending THEN $WhiteOnBlack ELSE $BlackOnWhite]
END;
AutoShowButton: ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
me: Viewer = NARROW[parent];
autoShow ← NOT autoShow;
Buttons.SetDisplayStyle[me, IF autoShow THEN $WhiteOnBlack ELSE $BlackOnWhite]
END;
ScanError and ScanMatch both use the ScanHeap proc (from GVPProcs) to scan thro the
heap. They are both stoppable and the only difference is the BOOLEAN argument which
says whether to scan only for errors or for pattern matches also.
ScanErrorButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
stoppable ← TRUE;
[] ← Failed[ ScanHeap[h, TRUE] ];
stoppable ← FALSE
END;
ScanMatchButton: ENTRY ButtonProc = TRUSTED BEGIN
h: GVPRef = NARROW[clientData];
stoppable ← TRUE;
[] ← Failed[ ScanHeap[h, FALSE] ];
stoppable ← FALSE
END;
StopButton sets a stop flag if the currently running command is stoppable.
StopRequested tests and clears this flag returning its old value.
StopButton: ButtonProc = TRUSTED BEGIN
IF stoppable THEN stopScan ← TRUE
END;
StopRequested: PUBLIC PROC RETURNS[stop: BOOLEAN] = BEGIN
IF stopScan
THEN {stop ← TRUE; stopScan ← FALSE}
ELSE stop ← FALSE
END;
ValueButton, PatternButton and RptCountButton just direct the selection to the right
viewer and may impose a default content while they're about it.
ValueButton: ButtonProc = TRUSTED BEGIN
ViewerTools.SetSelection[setInput]
END;
PatternButton: ButtonProc = TRUSTED BEGIN
ViewerTools.SetContents[patternInput, "/ / /"];
Set["Input page, index(octal) and type(string). '/' means don't care"];
ViewerTools.SetSelection[patternInput]
END;
RptCountButton: ButtonProc = TRUSTED BEGIN
ViewerTools.SetContents[repeatInput, "1"];
ViewerTools.SetSelection[repeatInput]
END;
GetRepeatCount checks the repeat flag and returns 1 if it's not set. Otherwise it reads
the count from the input viewer and returns that. Empty viewer or / means 1.
GetRepeatCount: PROC RETURNS [c: CARDINAL ← 1] = BEGIN
IF NOT repeatPending THEN RETURN;
[num: c] ← NumFromRope[octal: FALSE, r: ViewerTools.GetContents[repeatInput], start: 0];
IF c=lastCard THEN c ← 1;
END;
GetSearchPattern reads 2 numbers (octal) and a string from the input viewer and returns
3 numbers the last being the object type derived from the string.
GetSearchPattern: PUBLIC PROC RETURNS[page, index, type: CARDINAL] = BEGIN
pos: CARDINAL;
rope: ROPE = ViewerTools.GetContents[patternInput];
[num: page, end: pos] ← NumFromRope[octal: TRUE, r: rope, start: 0];
[num: index, end: pos] ← NumFromRope[octal: TRUE, r: rope, start: pos];
type ← ObjectIndex[rope, pos]
END;
ObjectRope and ObjectIndex convert between strings representing object types and numbers.
Valid object type indices are [0..15]. ObjectRope returns a rope when presented with a number
in this range. A BOOLEAN says only give a single char for commonly occurring object types.
ObjectIndex does the reverse operation, starting at a given position in a rope. The char /
returns LAST[CARDINAL] while a bad rope returns 16. Only the first 3 chars are matched.
ObjectRope: PUBLIC PROC[index: CARDINAL, brief: BOOLEAN]
RETURNS[r: ROPENIL] = BEGIN
IF NOT index IN objRange THEN RETURN;
IF brief AND (index IN [firstObj..firstObj+5] OR index IN [firstObj+11..firstObj+12])
THEN r ← Rope.Substr[objects[index], 0, 1]
ELSE r ← objects[index]
END;
ObjectIndex: PROC[r: ROPE, start: CARDINAL] RETURNS[index: CARDINAL] = BEGIN
len: CARDINAL = Rope.Length[r];
chars: CARDINAL;
index ← lastObj+1;
IF start=len THEN RETURN;
WHILE Rope.Fetch[r, start]=' AND start#len DO start ← start+1 ENDLOOP;
chars ← len-start;
IF chars=0 THEN RETURN;
IF Rope.Fetch[r, start]='/ THEN {index ← lastCard; RETURN};
IF chars<3 THEN RETURN;
IF chars>3 THEN chars ← 3;
index ← firstObj;
WHILE index <= lastObj DO
IF Rope.Equal[Rope.Substr[r, start, chars], Rope.Substr[objects[index], 0, chars], FALSE]
THEN EXIT;
index ← index + 1
ENDLOOP;
END;
ShowItem prints the current page according to the print mode flag
ShowItem: PROC[h: GVPRef, full: BOOLEAN] = BEGIN
IF full
THEN PrintPageFull[h]
ELSE PrintPageBrief[h]
END;
PrintPageFull and PrintPageBrief both print the objects on the current page in various levels
of detail. The page in question is read into the buffer (pageBuffer) and the objects are picked
out for printing. Bad object numbers and continuation sub-objects are noted.
PrintPageFull: PROC[h: GVPRef] = TRUSTED BEGIN
out: IO.STREAM = h.browserStream;
page: INT = h.pPage;
byte: INT = page*pageByteSize;
word: [0..256] ← pageHdrSize;
header: LONG POINTER TO PageHeader = LOOPHOLE[pageBuffer];
cont: BOOLEAN;
h.heapStream.SetIndex[byte];
[] ← h.heapStream.UnsafeGetBlock[[LOOPHOLE[pageBuffer], 0, bytesPerPage]];
cont ← header.offset#0;
out.PutText["\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"];
out.PutF["Page at %g\n\n", [rope[PositionRope[h]]]];
DO
objH: LONG POINTER TO ObjectHeader = LOOPHOLE[header + word];
out.PutF["Object Number=[page:%3bB, index:%3bB, %g]",
[cardinal[objH.number.page]],
[cardinal[objH.number.index]],
[rope[ObjectRope[LOOPHOLE[objH.number.type, CARDINAL], FALSE]]] ];
out.PutF[", size=%d, word=%d.",
[cardinal[objH.size]],
[cardinal[word]] ];
IF cont THEN
{out.PutF[" Cont, offset=%d", [cardinal[header.offset]]]; cont ← FALSE };
IF objH.number.page>maxObjNumPage OR
objH.number.index>maxObjNumIndex OR
objH.number.fill#0 THEN out.PutText[" **Illegal**"];
out.PutText["\n"];
word ← word + objHdrSize + objH.size;
IF word + objHdrSize > 255 THEN EXIT
ENDLOOP;
out.PutText["\n"]
END;
PrintPageBrief: PROC[h: GVPRef] = TRUSTED BEGIN
out: IO.STREAM = h.browserStream;
page: INT = h.pPage;
byte: INT = page*pageByteSize;
word: [0..256] ← pageHdrSize;
header: LONG POINTER TO PageHeader = LOOPHOLE[pageBuffer];
cont: BOOLEAN;
h.heapStream.SetIndex[byte];
[] ← h.heapStream.UnsafeGetBlock[[LOOPHOLE[pageBuffer], 0, bytesPerPage]];
cont ← header.offset#0;
IF h.pPage MOD segSize = 0
THEN out.PutF["\n(pos: %d, page: %d) ", [cardinal[h.lPage]], [cardinal[h.pPage]]];
DO
objH: LONG POINTER TO ObjectHeader = LOOPHOLE[header + word];
IF cont
THEN {out.PutText["-"]; cont ← FALSE}
ELSE out.PutF["%g", [rope[ObjectRope[LOOPHOLE[objH.number.type, CARDINAL], TRUE]]]];
IF objH.number.page>maxObjNumPage OR
objH.number.index>maxObjNumIndex OR
objH.number.fill#0 THEN out.PutText["(←**Illegal**)"];
word ← word + objHdrSize + objH.size;
IF word + objHdrSize > 255 THEN EXIT
ENDLOOP;
out.PutText[" "]
END;
BrowserInit just gets storage for the page buffer and sets up all the flags.
BrowserTidyUp frees the page buffer.
BrowserInit: PUBLIC PROC = BEGIN
pageBuffer ← NEW[PageWordVec];
autoShow ← FALSE;
showFull ← TRUE;
repeatPending ← FALSE;
stopScan ← FALSE;
stoppable ← FALSE
END;
BrowserTidyUp: PUBLIC PROC = BEGIN
pageBuffer ← NIL;
END;
END.