<> <> <> <> <> <> DIRECTORY BasicTime USING [FromPupTime], Buttons USING [Button, Create], Containers USING [ChildXBound, ChildYBound, Container, Create], FS USING [Error, Open, OpenFile], GVBasics USING [Timestamp], GVPDefs, IO USING [Flush, PutF, PutFR, PutText, Reset, SP, STREAM, TAB], Labels USING [Create, Set], Loader USING [Error, Start, Instantiate, IRItem], ObjectDirDefs USING [ObjectType], PrincOps USING [ControlModule], Rope USING [Concat, Fetch, FromChar, Length], ViewerIO USING [CreateViewerStreams], ViewerOps USING [CreateViewer, MoveViewer, PaintViewer], ViewerTools USING [GetContents, GetSelectedViewer, GetSelection, MakeNewTextViewer, SelPos, SelPosRec, SetSelection]; GVPEditor: CEDAR MONITOR LOCKS lock IMPORTS BasicTime, Buttons, Containers, FS, GVPDefs, IO, Labels, Loader, Rope, ViewerIO, ViewerOps, ViewerTools EXPORTS GVPDefs SHARES ObjectDirDefs = BEGIN OPEN GVPDefs; <> <> <> <> <> <> index: CARDINAL; bold: ROPE = " fb"; fixed: ROPE = " f"; EditDisplayMode: TYPE = {wordMode, charMode, stringMode}; EditModeSeq: TYPE = RECORD[SEQUENCE length: CARDINAL OF EditDisplayMode]; editModeVec: REF EditModeSeq _ NIL; <> <> <> <> values: REF WordSeq _ NIL; thisPageChanged, pageHere: BOOLEAN _ FALSE; pageWords: REF PageWordVec _ NIL; pageBytes: REF PageByteVec _ NIL; bufferLength, firstMarked: CARDINAL _ 0; editorButtons, editorText, valueInput, editMsg: Viewer; <> <> MakeEditorButtons: PUBLIC PROC[h: GVPRef] = BEGIN SBSize: CARDINAL = 8*char; col5a: CARDINAL = col4+10*char; col6a: CARDINAL = col5a+10*char; col7a: CARDINAL = col6a+10*char; editorText _ ViewerOps.CreateViewer[flavor: $Typescript, info: [parent: h.root, border: TRUE, iconic: FALSE, wy: offScreen]]; h.editorStream _ ViewerIO.CreateViewerStreams[viewer: editorText, name: NIL].out; editorButtons _ Containers.Create[[name: NIL, parent: h.root, wx: 0, wy: offScreen, wh: 4*rowSize, border: FALSE, scrollable: FALSE]]; valueInput _ ViewerTools.MakeNewTextViewer[[parent: editorButtons, wx: col5, wy: row1+2, ww: 40*char, wh: rowHeight, scrollable: FALSE, border: FALSE]]; [] _ Buttons.Create[info: [name: "BROWSER", wx: col1, wy: row3, wh: rowSize+rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: BrowserButton]; [] _ Buttons.Create[info: [name: "SERVER", wx: col1, wy: row1, wh: rowSize+rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: ServerButton]; [] _ Buttons.Create[info: [name: "reset page", wx: col2, wy: row1, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: ResetPageButton]; [] _ Buttons.Create[info: [name: "get next", wx: col2, wy: row2, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: GetNextButton]; [] _ Buttons.Create[info: [name: "get prev", wx: col2, wy: row3, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: GetPrevButton]; [] _ Buttons.Create[info: [name: "get page", wx: col2, wy: row4, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: GetPageButton]; [] _ Buttons.Create[info: [name: "put page", wx: col3, wy: row1, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: PutPageButton]; [] _ Buttons.Create[info: [name: "chars", wx: col3, wy: row2, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: CharsButton]; [] _ Buttons.Create[info: [name: "words", wx: col3, wy: row3, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: WordsButton]; [] _ Buttons.Create[info: [name: "show page", wx: col3, wy: row4, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: ShowPageButton]; [] _ Buttons.Create[info: [name: "Values >", wx: col4, wy: row1, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: NewValueButton]; [] _ Buttons.Create[info: [name: "replace", wx: col4, wy: row2, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: ReplaceButton]; [] _ Buttons.Create[info: [name: "RUN extern", wx: col4, wy: row3, wh: rowHeight, ww: buttonSize, parent: editorButtons], clientData: h, proc: ExternalButton]; [] _ Buttons.Create[info: [name: "Object", wx: col4, wy: row4, wh: rowHeight, ww: SBSize, parent: editorButtons], clientData: h, proc: ObjectButton]; [] _ Buttons.Create[info: [name: "RName", wx: col5a, wy: row4, wh: rowHeight, ww: SBSize, parent: editorButtons], clientData: h, proc: RNameButton]; [] _ Buttons.Create[info: [name: "Time", wx: col6a, wy: row4, wh: rowHeight, ww: SBSize, parent: editorButtons], clientData: h, proc: TimeStampButton]; [] _ Buttons.Create[info: [name: "Size", wx: col7a, wy: row4, wh: rowHeight, ww: SBSize, parent: editorButtons], clientData: h, proc: SizeButton]; editMsg _ Labels.Create[[parent: editorButtons, wx: col5, wy: row3, wh: rowHeight, border: FALSE, ww: 40*char]]; END; <> <> EditorButton: PUBLIC ENTRY ButtonProc = 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: editorButtons, 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: editorText, x:0, y: row6, w: 0, h: 0, paint: FALSE]; Containers.ChildXBound[h.root, editorText]; Containers.ChildXBound[h.root, editorButtons]; Containers.ChildYBound[h.root, editorText]; ViewerOps.PaintViewer[h.root, all]; h.currentButtons _ editorButtons; h.currentText _ editorText END; NewValueButton: ButtonProc = BEGIN -- put selection in input viewer ViewerTools.SetSelection[valueInput] END; <> <> <> <> <last having flashed something suitable.>> SelectIndex: PROC RETURNS[first, last: CARDINAL] = BEGIN editSelPos: ViewerTools.SelPos; first _ 1; last _ 0; IF editorText#ViewerTools.GetSelectedViewer[] THEN {Flash["Wrong viewer"]; RETURN}; IF NOT PageOK[] THEN RETURN; editSelPos _ ViewerTools.GetSelection[editorText]; first _ editSelPos.start; last _ first + editSelPos.length; IF first<9 THEN first _ 9; IF last<9 THEN last _ 9; first _ ((first-9) / 63)*8 + ((first-9) MOD 63)/7; last _ ((last-9) / 63)*8 + ((last-9) MOD 63)/7; IF first>=pageWordSize THEN first _ pageWordSize-1; IF last>=pageWordSize THEN last _ pageWordSize-1; IF first=last THEN Set[IO.PutFR["Selected word is %d", [cardinal[first]]]] ELSE Set[IO.PutFR["Selected words are %d thru %d", [cardinal[first]], [cardinal[last]]]] END; <> <> <> IndexSelect: PROC[first, last: CARDINAL] = BEGIN selection: ViewerTools.SelPos _ NEW[ViewerTools.SelPosRec]; IF first>last THEN RETURN; IF NOT first IN [0..pageWordSize) THEN ERROR; IF NOT last IN [0..pageWordSize) THEN ERROR; selection.start _ 8 + ((first/8)*63) + (first MOD 8)*7; selection.length _ 8 + ((last/8)*63) + (last MOD 8)*7 + 6 - selection.start; ViewerTools.SetSelection[editorText, selection] END; PageOK: PROC RETURNS[ok: BOOLEAN] = BEGIN IF NOT pageHere THEN Flash["Get the page first"]; ok _ pageHere END; <> <> <> <> <> ResetPageButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; IF Failed[ ReadServerPage[h, h.pPage, pageBytes] ] THEN RETURN; NewPage[h] END; GetPageButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; IF Failed[ ReadHeapPage[h, h.pPage, pageBytes] ] THEN RETURN; NewPage[h] END; GetNextButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; IF NOT NextPage[h] THEN {Flash["Couldn't"]; RETURN}; IF Failed[ ReadHeapPage[h, h.pPage, pageBytes] ] THEN {[] _ PrevPage[h]; RETURN}; NewPage[h] END; GetPrevButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; IF NOT PrevPage[h] THEN {Flash["Couldn't"]; RETURN}; IF Failed[ ReadHeapPage[h, h.pPage, pageBytes] ] THEN {[] _ NextPage[h]; RETURN}; NewPage[h] END; <> PutPageButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; IF NOT PageOK[] THEN RETURN; IF NOT thisPageChanged THEN {Flash["Page not changed"]; RETURN}; IF Failed[ WriteLocalPage[h, h.pPage, pageBytes] ] THEN RETURN; h.logStream.PutF["\nEdit buffer copied to local page %d\n", [cardinal[h.pPage]]]; thisPageChanged _ FALSE; EditInfo[h] END; <> <> <> NewPage: PROC[h: GVPRef] = BEGIN FOR i: CARDINAL IN [0..pageWordSize) DO editModeVec[i] _ wordMode ENDLOOP; thisPageChanged _ FALSE; pageHere _ TRUE; firstMarked _ 0; bufferLength _ 0; ShowPageProc[h]; Set[PositionRope[h]] END; ShowPageButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; ShowPageProc[h]; Set[PositionRope[h]] END; <> <> <> <> ObjectButton: ButtonProc = TRUSTED BEGIN first, last: CARDINAL; objH: LONG POINTER TO ObjectHeader; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; objH _ LOOPHOLE[pageWords, LONG POINTER]+first; last _ first+objHdrSize+objH.size; IF first>pageWordSize-objHdrSize THEN Flash["Sorry"] ELSE BEGIN r: ROPE _ IO.PutFR["Size=%d. Page=%bB, Index=%bB, Type=%g, (Fill=%bB).", [cardinal[objH.size]], [cardinal[objH.number.page]], [cardinal[objH.number.index]], [rope[ObjectRope[LOOPHOLE[objH.number.type, CARDINAL], FALSE]]], [cardinal[objH.number.fill]]]; r _ Rope.Concat[r, IO.PutFR[" Words %06bB %06bB %06bB", [cardinal[pageWords[first]]], [cardinal[pageWords[first+1]]], [cardinal[pageWords[first+2]]]]]; Set[r]; last _ IF last < pageWordSize THEN last-1 ELSE pageWordSize-1; IndexSelect[first, last] END END; <> <> TimeStampButton: ButtonProc = TRUSTED BEGIN first, last: CARDINAL; stamp: LONG POINTER TO GVBasics.Timestamp; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; IF first+SIZE[GVBasics.Timestamp]>pageWordSize THEN {Flash["Sorry"]; RETURN}; stamp _ LOOPHOLE[pageWords, LONG POINTER]+first; Set[IO.PutFR["Net address %b#%b#, time %t", [cardinal[stamp.net]], [cardinal[stamp.host]], [time[BasicTime.FromPupTime[stamp.time]]]]]; IndexSelect[first, first+SIZE[GVBasics.Timestamp]-1] END; <> <> <> SizeButton: ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; first, last, pages: CARDINAL _ 0; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; last _ first+pageWords[first]; pages _ last / pageWordSize; last _ IF last>=pageWordSize THEN pageWordSize-1 ELSE last; IF pages=0 THEN Set[IO.PutFR["Last word is word %d on this page", [cardinal[last]]]] ELSE Set["Word is beyond this page"]; IndexSelect[first, last] END; <> <> <> RNameButton: ButtonProc = BEGIN first, last: CARDINAL; len: CARDINAL; nWords: CARDINAL; r: ROPE; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; IF first>pageWordSize-2 THEN {Flash["Sorry"]; RETURN}; len _ pageWords[first]; nWords _ (len+1)/2; r _ IO.PutFR["Len (%g, %g) \"", [cardinal[len]], [cardinal[pageWords[first+1]]]]; editModeVec[first] _ stringMode; editModeVec[first+1] _ wordMode; last _ first+2; FOR i: CARDINAL IN [0..nWords) DO c1, c2: CHAR; IF last >= pageWordSize THEN EXIT; c1 _ LOOPHOLE[pageWords[last]/256]; c2 _ LOOPHOLE[pageWords[last] MOD 256]; editModeVec[last] _ charMode; r _ Rope.Concat[r, Rope.FromChar[c1]]; len _ len - 1; last _ last + 1; IF len=0 THEN EXIT; r _ Rope.Concat[r, Rope.FromChar[c2]]; len _ len - 1 ENDLOOP; Set[Rope.Concat[r, "\""]]; IndexSelect[first, last-1] END; <> <> <> <> ReplaceButton: ENTRY ButtonProc = BEGIN h: GVPRef = NARROW[clientData]; n: CARDINAL = ParseValues[values]; first, last, j: CARDINAL _ 0; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; IF n=lastCard OR n=0 THEN {Flash["Bad data for replace"]; RETURN}; j _ MIN[last-first+1, n]; h.logStream.PutF["\nEdits made on page %d in words [%d..%d] (old_new)\n", [cardinal[h.pPage]], [cardinal[first]], [cardinal[last]]]; FOR i: CARDINAL IN [0..j) DO IF pageWords[first+i]#values[i] THEN h.logStream.PutF["Word %d: %06b_%06b\n", [cardinal[first+i]], [cardinal[pageWords[first+i]]], [cardinal[values[i]]]]; pageWords[first+i] _ values[i]; ENDLOOP; h.logStream.PutText["\n"]; IF j=1 THEN Set[IO.PutFR["Updated word %d", [cardinal[first]]]] ELSE Set[IO.PutFR["Updated words %d thru %d (%d words)", [cardinal[first]], [cardinal[first+j-1]], [cardinal[j]]]]; thisPageChanged _ TRUE; ShowPageProc[h]; IndexSelect[first, first+j-1] END; <> <> CharsButton: ENTRY ButtonProc = BEGIN first, last: CARDINAL; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; FOR i: CARDINAL IN [first..last] DO editModeVec[i] _ charMode ENDLOOP; IndexSelect[first, last] END; WordsButton: ENTRY ButtonProc = BEGIN first, last: CARDINAL; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; FOR i: CARDINAL IN [first..last] DO editModeVec[i] _ wordMode ENDLOOP; IndexSelect[first, last] END; <> <> ExternalButton: ENTRY ButtonProc = TRUSTED BEGIN code: PrincOps.ControlModule; ubi: LIST OF Loader.IRItem; bcd: FS.OpenFile = FS.Open["GVPatchExternal.bcd" ! FS.Error => BEGIN Flash["Unable to open external file GVPatchExternal.bcd"]; GOTO fail END]; [code, ubi] _ Loader.Instantiate[bcd, 1 ! Loader.Error => BEGIN Flash[Rope.Concat["Error while loading bcd - ", message]]; GOTO fail END]; IF ubi # NIL THEN Flash["There are unbound imports"]; Set["Starting"]; Loader.Start[code] EXITS fail => NULL END; <> <> <> GetEditBuffer: PUBLIC PROC RETURNS[buffer: REF WordSeq _ NIL] = BEGIN first, last: CARDINAL; [first, last] _ SelectIndex[]; IF first>last THEN RETURN; firstMarked _ first; bufferLength _ last-first+1; buffer _ NEW[WordSeq[bufferLength]]; FOR i: CARDINAL IN [0..buffer.length) DO buffer[i] _ pageWords[first+i] ENDLOOP END; <> <> <> <> PutEditBuffer: PUBLIC PROC[buffer: REF WordSeq, r: ROPE _ NIL] = BEGIN h: GVPRef = GetHandle[]; last, len: CARDINAL; IF buffer=NIL THEN {Flash["No words changed"]; RETURN}; len _ MIN[buffer.length, bufferLength]; last _ firstMarked+len-1; h.logStream.PutF["\nExternal edits made on page %d in words [%d..%d], (old_new) %g\n", [cardinal[h.pPage]], [cardinal[firstMarked]], [cardinal[last]], [rope[r]]]; FOR i: CARDINAL IN [0..len) DO IF pageWords[firstMarked+i]#buffer[i] THEN h.logStream.PutF["Word %d: %06b_%06b\n", [cardinal[firstMarked+i]], [cardinal[pageWords[firstMarked+i]]], [cardinal[buffer[i]]]]; pageWords[firstMarked+i] _ buffer[i] ENDLOOP; Set[IO.PutFR["External edit, words in [%d..%d] altered", [cardinal[firstMarked]], [cardinal[last]]]]; thisPageChanged _ TRUE; ShowPageProc[h]; IndexSelect[firstMarked, last] END; <> EditInfo: PROC[h: GVPRef] = BEGIN Labels.Set[editMsg, IO.PutFR["Page %d, %g, %g", [cardinal[h.pPage]], [rope[IF thisPageChanged THEN "edits pending" ELSE "no edits"]], [rope[IF GetPageState[h.pPage]=alteredPage THEN "altered" ELSE "unchanged"]]]] END; <> <> <> <> <> <> ShowPageProc: PROC[h: GVPRef] = BEGIN out: IO.STREAM = h.editorStream; IF NOT PageOK[] THEN RETURN; ToFocus[]; out.Reset[]; out.PutText["\n"]; Look[out, fixed]; EditInfo[h]; index _ 0; FOR i: CARDINAL IN [0..pageHdrSize) DO Break[out, index, fixed]; out.PutF["%06b\t", [cardinal[pageWords[index]]]]; index _ index+1 ENDLOOP; WHILE index < pageWordSize DO TRUSTED BEGIN ptr: LONG POINTER TO ObjectHeader = LOOPHOLE[pageBytes, LONG POINTER]+index; limit: CARDINAL; ShowHeader[out, ptr]; limit _ index+ptr.size; IF limit > pageWordSize THEN limit _ pageWordSize; Look[out, fixed]; FOR i: CARDINAL IN [index..limit) DO PutNum[out, pageWords[i], fixed] ENDLOOP; END; ENDLOOP; out.Flush[] END; <> <> ShowHeader: PROC [out: IO.STREAM, ptr: LONG POINTER TO ObjectHeader] = TRUSTED BEGIN bad: BOOLEAN = ptr.number.page>256 OR ptr.number.index>85 OR ptr.number.fill#0 OR ptr.size+index+objHdrSize>pageWordSize; Look[out, bold]; -- do a header IF index > pageWordSize-objHdrSize THEN WHILE index> < to clear looks, "f" for fixed pitch font and "b" for bold.>> Look: PROC[out: IO.STREAM, r: ROPE] = BEGIN out.PutF["%l", [rope[r]]] END; <> <> <> Break: PROC[out: IO.STREAM, i: CARDINAL, oldLook: ROPE] = BEGIN IF i MOD 8 = 0 THEN BEGIN IF oldLook#fixed THEN Look[out, fixed]; out.PutF["\n%4d:\t", [cardinal[i]]]; IF oldLook#fixed THEN Look[out, oldLook] END END; <> <> <<(the length) it prints "RN-xxx" where xxx is the length in octal.>> PutNum: PROC[out: IO.STREAM, number: WORD, look: ROPE] = BEGIN Break[out, index, look]; SELECT editModeVec[index] FROM wordMode => out.PutF["%06b\t", [cardinal[number]]]; stringMode => out.PutF["RN-%03b\t", [cardinal[number MOD 256]]]; charMode => BEGIN c1: CARDINAL = number/256; c2: CARDINAL = number MOD 256; c1c: BOOLEAN = c1>=040B AND c1<=177B; c2c: BOOLEAN = c2>=040B AND c2<=177B; SELECT TRUE FROM c1c AND c2c => out.PutF[" %g %g \t", [character[LOOPHOLE[c1]]], [character[LOOPHOLE[c2]]]]; NOT c1c AND NOT c2c => out.PutF["%06b\t", [cardinal[number]]]; c1c AND NOT c2c => out.PutF[" %g %03b\t", [character[LOOPHOLE[c1]]], [cardinal[c2]]]; NOT c1c AND c2c => out.PutF["%03b %g \t", [cardinal[c1]], [character[LOOPHOLE[c2]]]]; ENDCASE => ERROR END; ENDCASE => ERROR; index _ index + 1; END; <> <> <> <> <> ParseValues: PROC[values: REF WordSeq] RETURNS[number: CARDINAL] = BEGIN r: ROPE = ViewerTools.GetContents[valueInput]; len: CARDINAL = Rope.Length[r]; word: CARDINAL; i: CARDINAL _ 0; number _ 0; WHILE i BEGIN -- octal number word _ 0; WHILE c IN ['0..'7] DO word _ word*8 + c -'0; i _ i+1; IF i=len THEN EXIT; c _ Rope.Fetch[r, i] ENDLOOP; values[number] _ word; number _ number+1 END; c='" => BEGIN i _ i+1; -- char after quote WHILE i i _ i+1; ENDCASE => {number _ lastCard; EXIT} ENDLOOP END; <> <> EditorInit: PUBLIC PROC = BEGIN editModeVec _ NEW[EditModeSeq[pageWordSize]]; values _ NEW[WordSeq[40]]; pageWords _ NEW[PageWordVec]; TRUSTED { pageBytes _ LOOPHOLE[pageWords]; }; pageHere _ FALSE; thisPageChanged _ FALSE; firstMarked _ 0; bufferLength _ 0 END; EditorTidyUp: PUBLIC PROC = BEGIN pageWords _ NIL; pageBytes _ NIL; editModeVec _ NIL; values _ NIL END; END.