DIRECTORY Atom USING [GetPropFromList], Basics USING [BYTE], BasicTime USING [GMT], Commander USING [CommandProc, Register], CommandTool USING [ParseToList], Convert USING [CardFromRope, Error, RopeFromTime], FileNames USING [CurrentWorkingDirectory], FS USING [EnumerateForNames, NameProc, Error, StreamOpen], Graph USING [CaretIndex, CaretSpec, ColorIndex, Entity, EntityGroup, EntityGroupList, EntityGroupRec, EntityHashSize, EntityList, EntityRec, FontIndex, GRAPH, GraphHandle, GraphProc, HashIndex, LastEntityColor, NestedEntities, NestedEntitiesList, NestedEntitiesRec, NumberOfColors, NumberOfFonts, ROPE, SegmentDataList, TargetSpec, Text, TextRec, Texts, ValueList, Viewer, XY], GraphCleanUp USING [CleanUpEL, CleanUpVL], GraphFileKeys, GraphOps USING [Lock, Unlock], GraphPrivate USING [GraphStreamProc, MakeTable, PaintAll, PaintTails, ReadAsciiFile, RopeList, ShowChart], GraphUtil USING [AppendEGL, AppendEntityList, AppendTexts, HandleNotNil, InitSegAll, InitSegEnd, NewEntityId, NewGroupId, NewTextId, ReverseEntityList, ReverseTexts, ReverseValueList, UseMyColors, UseMyFonts, VanillaHandle], IO USING [Close, EndOf, EndOfStream, Error, GetChar, GetIndex, int, PeekChar, PutFR, rope, STREAM], List USING [DReverse, Kill], RefText USING [New, ObtainScratch, ReleaseScratch], Rope USING [Equal, Fetch, Find, FromRefText, IsEmpty, Length, Substr], ViewerOps USING [DestroyViewer]; GraphRead: CEDAR PROGRAM IMPORTS Atom, Commander, CommandTool, Convert, FileNames, FS, IO, List, GraphCleanUp, GraphOps, GraphPrivate, GraphUtil, RefText, Rope, ViewerOps EXPORTS GraphPrivate = { OPEN Graph, GraphFileKeys, GraphOps, GraphPrivate, GraphUtil; ReadBeyondEOF: PUBLIC SIGNAL[message: ROPE _ NIL] = CODE; SyntaxError: PUBLIC SIGNAL[message: ROPE _ NIL] = CODE; DataError: PUBLIC SIGNAL[message: ROPE _ NIL] = CODE; STREAM: TYPE = IO.STREAM; BYTE: TYPE = Basics.BYTE; CharPair: TYPE = MACHINE DEPENDENT RECORD[high, low: CHAR]; FourChars: TYPE = MACHINE DEPENDENT RECORD[lh, ll, hh, hl: CHAR]; FileFormat: TYPE = {old, binary, ascii, illegal}; -- currently only binary is supported. HandleFromFile: PUBLIC PROC[file: ROPE _ NIL] RETURNS [handle: GraphHandle _ NIL, msg: ROPE _ NIL] = { handle _ VanillaHandle[]; Lock[handle]; handle.userEditAllowed _ FALSE; msg _ GetGraph[handle, file]; handle.userEditAllowed _ TRUE; Unlock[handle]; }; -- HandleFromFile GetGraph: PUBLIC PROC [handle: GraphHandle, file: ROPE] RETURNS [msg: ROPE _ NIL] = { IF file.IsEmpty[] THEN RETURN["No file specified."]; IF HandleNotNil[handle] THEN { s: STREAM _ NIL; s _ FS. StreamOpen[file ! FS.Error => {msg _ error.explanation; CONTINUE} ]; IF msg = NIL THEN { ENABLE { SyntaxError => { msg _ IO.PutFR["Syntax error: %g at [%g].", IO.rope[message], IO.int[s.GetIndex[]] ]; CONTINUE; }; ReadBeyondEOF => { msg _ IO.PutFR["Attempting to read beyond end of file for %g at [%g].", IO.rope[message], IO.int[s.GetIndex[]] ]; CONTINUE; }; DataError => { msg _ IO.PutFR["Error: %g at [%g].", IO.rope[message], IO.int[s.GetIndex[]] ]; CONTINUE; }; IO.EndOfStream => { msg _ "End of file reached"; CONTINUE; }; IO.Error => { msg _ IO.PutFR["%g at [%g].", IO.rope[SELECT ec FROM SyntaxError => "Syntax error", Overflow => "Overflow in input conversion" ENDCASE => IO.PutFR["IO Error # %g", IO.int[LOOPHOLE[ec, CARDINAL]]]], IO.int[s.GetIndex[]] ]; CONTINUE; }; ABORTED => { msg _ "Graph aborted. ... "; CONTINUE; }; }; IF handle.controller # NIL THEN IF handle.controller.table # NIL THEN { ViewerOps.DestroyViewer[handle.controller.table]; handle.controller.table _ NIL; }; handle.userEditAllowed _ FALSE; msg _ SELECT CheckFormat[s] FROM old => ReadPlotFile[handle, s], binary => ReadGraphFile[handle, s], ascii => ReadAsciiFile[handle, s], ENDCASE => "Illegal graph file."; handle.userEditAllowed _ TRUE; IF handle.controller # NIL THEN MakeTable[handle, IF handle.controller.tableVisible THEN 0 ELSE 1000, 0]; }; IF s # NIL THEN s.Close[]; }; }; -- GetGraph ReadPlotFile: PROC[handle: GraphHandle, s: STREAM] RETURNS [msg: ROPE _ NIL] = { OPEN handle; nNamesMax: INT; xEntity: Entity _ NIL; entityGroup: EntityGroup _ NIL; entityList: EntityList _ NIL; v1, v2: ValueList _ NIL; x1, x2: REAL _ 0.0; title: Text _ NEW[TextRec _ [ text: GetRope[s], place: [0.5, 1.1], colorIndex: 15, fontIndex: 2, justifX: center, justifY: bottom, id: NewTextId[handle, 0]]]; time: Text _ NEW[TextRec _ [ text: Convert.RopeFromTime[GetTime[s]], place: [1.0, -0.35], colorIndex: 15, fontIndex: 1, justifX: right, justifY: bottom, id: NewTextId[handle, 1]]]; file: Text _ NEW[TextRec _ [ text: (graph.fileName _ NARROW[Atom.GetPropFromList[s.propList, $Name]]), place: [0, -0.35], colorIndex: 15, fontIndex: 1, justifX: left, justifY: bottom, id: NewTextId[handle, 2]]]; graph.texts _ AppendTexts[graph.texts, CONS[title, CONS[time, CONS[file, NIL]]]]; allTexts _ AppendTexts[allTexts, CONS[title, CONS[time, CONS[file, NIL]]]]; graph.bounds _ [GetReal[s], GetReal[s], GetReal[s], GetReal[s]]; graph.auto[bounds] _ FALSE; nNamesMax _ GetCardinal[s]; xEntity _ NEW[EntityRec _ [name: "X", id: NewEntityId[handle, 0]]]; entityHash[xEntity.id MOD EntityHashSize] _ CONS[xEntity, entityHash[xEntity.id MOD EntityHashSize]]; entityGroup _ NEW[EntityGroupRec _ [ x: xEntity, ys: NEW[NestedEntitiesRec _ []], id: NewGroupId[handle, 0] -- should update length later. ]]; xEntity.group _ entityGroup; entityGroupList _ AppendEGL[entityGroupList, CONS[entityGroup, NIL]]; FOR i: INT IN [1..nNamesMax] DO index: HashIndex _ i MOD EntityHashSize; entity: Entity _ NEW[EntityRec _ [ name: GetRope[s], colorIndex: ((i-1) MOD LastEntityColor) + 1, group: entityGroup, id: NewEntityId[handle, i] ]]; entityHash[index] _ CONS[entity, entityHash[index]]; entityList _ CONS[entity, entityList]; ENDLOOP; entityGroup.ys.entityList _ ReverseEntityList[entityList, FALSE]; graph.entityList _ AppendEntityList[graph.entityList, ReverseEntityList[entityList, FALSE]]; IF chart.viewer = NIL THEN { ShowChart[handle]; -- will unlock handle right before viewer is opened up. No more (11/13/85). } ELSE PaintAll[handle]; entityGroup.length _ GetCardinal[s]; FOR i: INT IN [1..entityGroup.length] DO vl: ValueList; x2 _ GetReal[s]; vl _ CONS[x2, NIL]; IF xEntity.lastValue = NIL THEN xEntity.oldValues _ xEntity.lastValue _ vl ELSE {xEntity.lastValue.rest _ vl; xEntity.lastValue _ vl}; v2 _ NIL; FOR el: EntityList _ ReverseEntityList[entityList, FALSE], el.rest UNTIL el = NIL DO y2: REAL _ GetReal[s]; yEntity: Entity _ el.first; v2 _ CONS[y2, v2]; vl _ CONS[y2, NIL]; IF yEntity.lastValue = NIL THEN yEntity.oldValues _ yEntity.lastValue _ vl ELSE {yEntity.lastValue.rest _ vl; yEntity.lastValue _ vl}; ENDLOOP; IF i > 1 THEN PaintTails[handle, paint, v1, v2, x1, x2]; -- v1 and v2 are in reversed order. v1 _ GraphCleanUp.CleanUpVL[v1]; v1 _ v2; x1 _ x2; ENDLOOP; v1 _ NIL; v2 _ GraphCleanUp.CleanUpVL[v2]; InitSegEnd[xEntity]; FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO InitSegAll[el.first]; ENDLOOP; entityList _ GraphCleanUp.CleanUpEL[entityList, FALSE]; nNamesMax _ nNamesMax MOD LastEntityColor; lastEntityColor _ IF nNamesMax = 0 THEN LastEntityColor ELSE nNamesMax; }; -- ReadPlotFile ReadGraphFile: PROC [handle: GraphHandle, s: STREAM] RETURNS [msg: ROPE _ NIL] = { OPEN handle; graph.fileName _ NARROW[Atom.GetPropFromList[s.propList, $Name]]; WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM NameKey => [] _ GetRope[s]; -- graph.fileName is already initialized above. TextsKey => { allTexts _ GetTexts[s, handle]; graph.texts _ ReverseTexts[allTexts, FALSE]; graph.texts _ ReverseTexts[graph.texts, TRUE]; }; CaretsKey => GetCarets[s, graph]; ShowSlopeKey => graph.showSlope _ GetBool[s]; TargetsKey => GetTargets[s, graph]; GridsKey => GetGrids[s, graph]; DivisionsKey => GetDivisions[s, graph]; BoundsKey => GetBounds[s, graph]; ColorsKey => GetColors[s, graph]; FontsKey => GetFonts[s, graph]; EntityGroupListKey => GetEntityGroupList[s, handle]; EndOfRecordKey => EXIT; -- later we can read more than one graphs at a time. ENDCASE => SIGNAL SyntaxError["Graph"]; ENDLOOP; FOR egltemp: EntityGroupList _ entityGroupList, egltemp.rest UNTIL egltemp = NIL DO InitSegEnd[egltemp.first.x]; ENDLOOP; InitSomeCurves[handle]; IF handle.chart.viewer # NIL THEN { UseMyColors[handle]; UseMyFonts[handle]; PaintAll[handle]; } ELSE { ShowChart[handle]; -- will unlock handle. no more, 11/13/85. }; }; -- ReadGraphFile GetTexts: PROC [s: STREAM, handle: GraphHandle] RETURNS [texts: Texts _ NIL] = { DO SELECT GetByte[s] FROM EndOfListKey => EXIT; TextKey => texts _ CONS[GetText[s, handle], texts]; -- 1 ENDCASE => SIGNAL SyntaxError["Texts"]; ENDLOOP; texts _ ReverseTexts[texts, TRUE]; }; -- GetTexts GetText: PROC [s: STREAM, handle: GraphHandle] RETURNS [text: Text _ NIL] = { text _ NEW[TextRec _ []]; DO SELECT GetByte[s] FROM NameKey => text.text _ GetRope[s]; -- 1 PlaceKey => text.place _ [GetReal[s], GetReal[s]]; -- 2 FontIndexKey => text.fontIndex _ GetByte[s]; -- 3 ColorIndexKey => text.colorIndex _ GetByte[s]; -- 4 RotationKey => text.rotation _ GetReal[s]; -- 5 JustificationsKey => { -- 6 WHILE NOT s.EndOf[] DO byte: BYTE; SELECT GetByte[s] FROM XKey => { -- 1 byte _ GetByte[s]; IF byte IN [LeftKey..RightKey] THEN text.justifX _ SELECT byte FROM -- 1, 2, 3. LeftKey => left, CenterKey => center, ENDCASE => right ELSE SIGNAL SyntaxError["X Justification"]; }; YKey => { -- 2 byte _ GetByte[s]; IF byte IN [TopKey..BottomKey] THEN text.justifY _ SELECT byte FROM -- 1, 2, 3. TopKey => top, CenterKey => center, ENDCASE => bottom ELSE SIGNAL SyntaxError["Y Justification"]; }; EndOfRecordKey => EXIT; ENDCASE => SIGNAL SyntaxError["Justifications"]; ENDLOOP; }; TextIdKey => {text.id _ NewTextId[handle, GetInt[s]]}; -- 7 EndOfRecordKey => EXIT; ENDCASE => SIGNAL SyntaxError["Text"]; ENDLOOP; }; -- GetText GetCarets: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [PrimaryKey..TextCaretKey] => { -- 1, 2, 3. index: CaretIndex _ SELECT byte FROM PrimaryKey => primary, SecondaryKey => secondary, ENDCASE => text; GetCaret[s, graph.caret[index]]; }; ENDCASE => SIGNAL SyntaxError["Carets"]; ENDLOOP; }; -- GetCarets GetCaret: PROC [s: STREAM, spec: CaretSpec] = { WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; PlaceKey => spec.place _ [GetReal[s], GetReal[s]]; -- 2 OnKey => spec.on _ GetBool[s]; -- 12 ENDCASE => SIGNAL SyntaxError["Caret"]; ENDLOOP; }; -- GetCaret GetTargets: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [XKey..YKey] => { -- 1, 2. xy: XY _ IF byte = XKey THEN x ELSE y; GetTarget[s, graph.target[xy]]; }; ENDCASE => SIGNAL SyntaxError["Targets"]; ENDLOOP; }; -- GetTargets GetTarget: PROC [s: STREAM, spec: TargetSpec] = { WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; ValueKey => spec.value _ GetReal[s]; -- 1 WidthKey => spec.width _ GetReal[s]; -- 2 ColorIndexKey => spec.colorIndex _ GetByte[s]; -- 4, need proctection. OnKey => spec.on _ GetBool[s]; -- 12 ENDCASE => SIGNAL SyntaxError["Target"]; ENDLOOP; }; -- GetTarget GetGrids: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [XKey..YKey] => { -- 1, 2 xy: XY _ IF byte = XKey THEN x ELSE y; WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; OnKey => graph.grids[xy] _ GetBool[s]; -- 12 ENDCASE => SIGNAL SyntaxError["Grid"]; ENDLOOP; }; ENDCASE => SIGNAL SyntaxError["Grids"]; ENDLOOP; }; -- GetGrids GetDivisions: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [XKey..YKey] => { -- 1, 2 xy: XY _ IF byte = XKey THEN x ELSE y; WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; AutoKey => graph.auto[divisions] _ GetBool[s]; -- 9 DivisionsKey => graph.division[xy] _ GetByte[s]; -- 7 ENDCASE => SIGNAL SyntaxError["Division"]; ENDLOOP; }; ENDCASE => SIGNAL SyntaxError["Divisions"]; ENDLOOP; }; -- GetDivisions GetBounds: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [XKey..YKey] => { -- 1, 2 xy: XY _ IF byte = XKey THEN x ELSE y; WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; AutoKey => graph.auto[bounds] _ GetBool[s]; -- 9 MaxKey => IF xy = x THEN graph.bounds.xmax _ GetReal[s] -- 1 ELSE graph.bounds.ymax _ GetReal[s]; MinKey => IF xy = x THEN graph.bounds.xmin _ GetReal[s] -- 2 ELSE graph.bounds.ymin _ GetReal[s]; ENDCASE => SIGNAL SyntaxError["Bound"]; ENDLOOP; }; ENDCASE => SIGNAL SyntaxError["Bounds"]; ENDLOOP; }; -- GetBounds GetColors: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [1..NumberOfColors] => { index: ColorIndex _ byte - 1; GetColor[s, graph, index]; }; ENDCASE => SIGNAL SyntaxError["Colors"]; ENDLOOP; }; -- GetColors GetColor: PROC [s: STREAM, graph: GRAPH, index: ColorIndex] = { WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; RKey => graph.color[index].R _ GetReal[s]; -- 1 GKey => graph.color[index].G _ GetReal[s]; -- 2 BKey => graph.color[index].B _ GetReal[s]; -- 3 ENDCASE => SIGNAL SyntaxError["Color"]; ENDLOOP; }; -- GetColor GetFonts: GraphStreamProc = { byte: BYTE; WHILE NOT s.EndOf[] DO SELECT (byte _ GetByte[s]) FROM EndOfRecordKey => EXIT; IN [1..NumberOfFonts] => { index: FontIndex _ byte - 1; GetFont[s, graph, index]; }; ENDCASE => SIGNAL SyntaxError["Fonts"]; ENDLOOP; }; -- GetFonts GetFont: PROC [s: STREAM, graph: GRAPH, index: FontIndex] = { WHILE NOT s.EndOf[] DO SELECT GetByte[s] FROM EndOfRecordKey => EXIT; NameKey => graph.font[index].family _ GetRope[s]; -- 1 BoldKey => graph.font[index].bold _ GetBool[s]; -- 2 ItalicKey => graph.font[index].italic _ GetBool[s]; -- 3 VFontSizeKey => graph.font[index].vFontSize _ GetInt[s]; -- 4 PFontScaleKey => graph.font[index].pFontScale _ GetReal[s]; -- 5 ENDCASE => SIGNAL SyntaxError["Font"]; ENDLOOP; }; -- GetFonts GetEntityGroupList: PROC [s: STREAM, handle: GraphHandle] = { OPEN handle; egl, t1, t2: EntityGroupList _ NIL; DO SELECT GetByte[s] FROM EndOfListKey => EXIT; EntityGroupKey => t1 _ CONS[GetEntityGroup[s, handle], t1]; -- 4 ENDCASE => SIGNAL SyntaxError["EntityGroupList"]; ENDLOOP; FOR t2 _ t1, t2.rest UNTIL t2 = NIL DO egl _ CONS[t2.first, egl]; ENDLOOP; entityGroupList _ AppendEGL[entityGroupList, egl]; TRUSTED {List.Kill[LOOPHOLE[t1]]}; }; -- GetEntityGroupList GetEntityGroup: PROC [s: STREAM, handle: GraphHandle] RETURNS [eg: EntityGroup] = { eg _ NEW[EntityGroupRec _ []]; DO SELECT GetByte[s] FROM EntityKey => eg.x _ GetEntity[s, handle, eg, NIL]; -- 2 NestedEntitiesKey => eg.ys _ GetNestedEntities[s, handle, eg, NIL]; -- 5 GroupIdKey => eg.id _ NewGroupId[handle, GetInt[s]]; -- 6 LengthKey => eg.length _ GetInt[s]; -- 7 CrossSectionsKey => GetCrossSections[s, eg]; EndOfRecordKey => EXIT; ENDCASE => SIGNAL SyntaxError["EntityGroup"]; ENDLOOP; }; -- GetEntityGroup GetEntityList: PROC [s: STREAM, handle: GraphHandle, group: EntityGroup, father: NestedEntities] RETURNS [el: EntityList _ NIL] = { -- without getting the values, for now. DO SELECT GetByte[s] FROM EndOfListKey => EXIT; EntityKey => el _ CONS[GetEntity[s, handle, group, father], el]; -- 2 ENDCASE => SyntaxError["EntityList"]; ENDLOOP; el _ ReverseEntityList[el, TRUE]; -- resume the order. }; -- GetEntityList GetEntity: PROC [s: STREAM, handle: GraphHandle, eg: EntityGroup, father: NestedEntities _ NIL] RETURNS [entity: Entity _ NIL] = { hashIndex: [0..EntityHashSize); entity _ NEW[EntityRec _ [group: eg, parent: father]]; DO SELECT GetByte[s] FROM NameKey => entity.name _ GetRope[s]; -- 1 CommentKey => entity.comment _ GetRope[s]; -- 11 ColorIndexKey => entity.colorIndex _ GetByte[s]; -- 4 MarkKey => { -- 3 byte: BYTE _ GetByte[s]; IF byte IN [NoneKey..PercentKey] THEN -- 1 .. 7 entity.mark _ SELECT byte FROM NoneKey => none, RoundKey => round, SquareKey => square, DiamondKey => diamond, CrossKey => cross, DollarKey => dollar, ENDCASE => percent ELSE SIGNAL SyntaxError["Mark"]; }; WidthKey => entity.width _ GetReal[s]; -- 2 ValuesKey => [entity.oldValues, entity.lastValue] _ GetValueList[s]; -- 5 EntityIdKey => entity.id _ NewEntityId[handle, GetInt[s]]; -- 7 EndOfRecordKey => EXIT; ENDCASE => SIGNAL SyntaxError["Entity"]; ENDLOOP; hashIndex _ entity.id MOD EntityHashSize; handle.entityHash[hashIndex] _ CONS[entity, handle.entityHash[hashIndex]]; }; -- GetEntity GetValueList: PROC [s: STREAM] RETURNS [vl, last: ValueList _ NIL] = { length: INT _ GetInt[s]; FOR i: INT IN [0..length) DO vl _ CONS[GetReal[s], vl]; ENDLOOP; [vl, last] _ ReverseValueList[vl, TRUE]; }; -- GetValueList GetNestedEntitiesList: PROC [s: STREAM, handle: GraphHandle, group: EntityGroup, father: NestedEntities _ NIL] RETURNS [nel: NestedEntitiesList _ NIL] = { tnel: NestedEntitiesList _ NIL; DO SELECT GetByte[s] FROM EndOfListKey => EXIT; NestedEntitiesKey => tnel _ CONS[ -- 5 GetNestedEntities[s, handle, group, father], tnel]; ENDCASE => SyntaxError["NestedEntitiesList"]; ENDLOOP; FOR ttnel: NestedEntitiesList _ tnel, ttnel.rest UNTIL ttnel = NIL DO nel _ CONS[ttnel.first, nel]; ENDLOOP; WHILE tnel # NIL DO next: NestedEntitiesList _ tnel.rest; tnel.first _ NIL; tnel.rest _ NIL; tnel _ next; ENDLOOP; }; -- GetNestedEntitiesList GetNestedEntities: PROC [s: STREAM, handle: GraphHandle, group: EntityGroup, father: NestedEntities _ NIL] RETURNS [ne: NestedEntities] = { ne _ NEW[NestedEntitiesRec _ [parent: father]]; DO SELECT GetByte[s] FROM NameKey => ne.name _ GetRope[s]; -- 1 CommentKey => ne.comment _ GetRope[s]; -- 11 EntityListKey => ne.entityList _ GetEntityList[s, handle, group, father]; -- 3 NELKey => ne.children _ GetNestedEntitiesList[s, handle, group, ne]; -- 4 EndOfRecordKey => EXIT; ENDCASE => SIGNAL SyntaxError["NestedEntities"]; ENDLOOP; }; -- GetNestedEntities GetCrossSections: PROC [s: STREAM, group: EntityGroup] = { AddValuesToEL: PROC [entityList: EntityList] = { FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO vl: ValueList _ CONS[GetReal[s], NIL]; el.first.lastValue.rest _ vl; el.first.lastValue _ vl; ENDLOOP; }; -- AddValuesToEL AddValuesToNEL: PROC [nestedEntityList: NestedEntitiesList] = { FOR nel: NestedEntitiesList _ nestedEntityList, nel.rest UNTIL nel = NIL DO AddValuesToEL[nel.first.entityList]; AddValuesToNEL[nel.first.children]; ENDLOOP; }; -- AddValuesToNEL DO -- error if eof is hit inside the loop; SELECT GetByte[s] FROM EndOfListKey => EXIT; TailsKey => { -- 8 vl: ValueList _ CONS[GetReal[s], NIL]; group.x.lastValue.rest _ vl; group.x.lastValue _ vl; AddValuesToEL[group.ys.entityList]; AddValuesToNEL[group.ys.children]; }; ENDCASE => SyntaxError["CrossSection"]; ENDLOOP; }; -- GetCrossSections InitSomeCurves: GraphProc = { OPEN handle; InitSomeEntity: PROC [ne: NestedEntities, graf: GRAPH, count: INT] RETURNS [newCount: INT] = { newCount _ count; FOR el: EntityList _ ne.entityList, el.rest UNTIL el = NIL OR newCount >= LastEntityColor DO entity: Entity _ el.first; InitSegAll[entity]; graf.entityList _ CONS[entity, graf.entityList]; newCount _ newCount + 1; ENDLOOP; FOR nel: NestedEntitiesList _ ne.children, nel.rest UNTIL nel = NIL OR newCount >= LastEntityColor DO newCount _ InitSomeEntity[nel.first, graf, newCount]; ENDLOOP; }; -- InitSomeEntity curveCount: CARDINAL _ 0; FOR egl: EntityGroupList _ entityGroupList, egl.rest UNTIL egl = NIL OR curveCount >= LastEntityColor DO curveCount _ InitSomeEntity[egl.first.ys, graph, curveCount]; ENDLOOP; graph.entityList _ ReverseEntityList[graph.entityList, TRUE]; }; -- InitSomeCurves CheckFormat: PROC [stream: STREAM] RETURNS[format: FileFormat _ illegal] = { firstChar: CHAR _ stream.PeekChar[]; IF firstChar = 0C THEN { rope: ROPE; rope _ GetRope[stream! ReadBeyondEOF => {rope _ NIL; CONTINUE}]; IF NOT rope.IsEmpty[] THEN SELECT TRUE FROM rope.Equal["* binary"] => format _ old; rope.Equal["binary graph"] => format _ binary; ENDCASE; -- illegal } ELSE format _ ascii; }; -- CheckFormat myScratch: REF TEXT _ RefText.New[256]; GetRope: PROC [stream: STREAM] RETURNS [rope: ROPE] = { length: NAT = GetCardinal[stream]; text: REF TEXT _ IF length > 256 THEN RefText.ObtainScratch[length] ELSE myScratch; FOR i: NAT IN [0..length) DO IF stream.EndOf[] THEN SIGNAL ReadBeyondEOF[ IO.PutFR["%gth character of a rope of length %g.", IO.int[i+1], IO.int[length]]]; text[i] _ stream.GetChar[]; ENDLOOP; text.length _ length; rope _ Rope.FromRefText[text]; IF length > 256 THEN RefText.ReleaseScratch[text]; }; -- GetRope GetTime: PROC [stream: STREAM] RETURNS [BasicTime.GMT] = { RETURN[LOOPHOLE[GetLongWord[stream, " a BasicTime.GMT"], BasicTime.GMT]]; }; -- GetTime GetBool: PROC [stream: STREAM] RETURNS [bool: BOOL _ FALSE] = { SELECT GetByte[stream] FROM TrueKey => bool _ TRUE; FalseKey => bool _ FALSE; ENDCASE => SIGNAL SyntaxError["Boolean"]; }; -- GetBool GetByte: PROC [stream: STREAM] RETURNS [BYTE] = { RETURN[LOOPHOLE[stream.GetChar[], BYTE]]; }; -- GetByte GetInt: PROC [stream: STREAM] RETURNS [INT] = { RETURN[LOOPHOLE[GetLongWord[stream, " an INT"], INT]]; }; -- GetInt GetReal: PROC [stream: STREAM] RETURNS [REAL] = { RETURN[LOOPHOLE[GetLongWord[stream, " a real number"], REAL]]; }; -- GetReal GetCardinal: PROC [stream: STREAM] RETURNS [CARDINAL] = { pair: CharPair; pair.high _ MyGetChar[stream, "1st byte of a cardinal"]; pair.low _ MyGetChar[stream, "2nd byte of a cardinal"]; RETURN[LOOPHOLE[pair, CARDINAL]]; }; -- GetCardinal GetLongWord: PROC [stream: STREAM, info: ROPE] RETURNS [chars: FourChars] = { chars.lh _ MyGetChar[stream, "1st byte of", info]; chars.ll _ MyGetChar[stream, "2nd byte of", info]; chars.hh _ MyGetChar[stream, "3rd byte of", info]; chars.hl _ MyGetChar[stream, "4th byte of", info]; }; -- GetLongWord MyGetChar: PROC [stream: STREAM, info1, info2: ROPE _ NIL] RETURNS [CHAR] = { IF stream.EndOf[] THEN SIGNAL ReadBeyondEOF[ IO.PutFR["%g%g.", IO.rope[info1], IO.rope[info2]]]; RETURN[stream.GetChar[]]; }; -- MyGetChar GraphFiles: Commander.CommandProc = { argList: RopeList; length: NAT; msg _ NIL; [argList, length] _ CommandTool.ParseToList[cmd]; IF length <= 0 THEN msg _ "To review graph files, type: Graph " ELSE { wDir: ROPE _ FileNames.CurrentWorkingDirectory[]; nGraphs: NAT _ 0; maxGraphs: NAT _ 12; allVersions: BOOL _ FALSE; FOR arg: RopeList _ argList, arg.rest UNTIL arg = NIL OR msg # NIL DO IF arg.first.Fetch[0] = '- THEN { IF arg.first.Length[] >= 2 THEN SELECT arg.first.Fetch[1] FROM 'A, 'a => allVersions _ TRUE; 'H, 'h => allVersions _ FALSE; IN ['0..'9] => { max: NAT _ Convert.CardFromRope[arg.first.Substr[1] ! Convert.Error => max _ maxGraphs]; -- don't change it maxGraphs _ max; }; ENDCASE; -- simply ignors illegal switches } ELSE { fileList: RopeList _ FileListFrom[arg.first, wDir, allVersions]; IF fileList = NIL THEN msg _ "No such file." ELSE FOR file: RopeList _ fileList, file.rest UNTIL file = NIL OR msg # NIL DO IF nGraphs >= maxGraphs THEN msg _ IO.PutFR[ "Note: max. %g plots for each command. You may change it by a switch.", IO.int[maxGraphs]] ELSE [, msg] _ HandleFromFile[file: file.first]; nGraphs _ nGraphs + 1; ENDLOOP; }; ENDLOOP; }; IF msg = NIL THEN msg _ "done."; }; -- GraphFiles FileListFrom: PROC [pattern, wDir: ROPE _ NIL, allVersions: BOOL _ FALSE] RETURNS [fileList: RopeList _ NIL] = { root, lastRoot: ROPE _ NIL; LinkIt: FS.NameProc -- PROC [fullFName] RETURNS [continue: BOOL] -- = { excl: INT _ fullFName.Find["!"]; continue _ TRUE; IF fullFName.Substr[excl-6, 6].Equal[".press", FALSE] THEN RETURN; IF ~allVersions THEN { root _ fullFName.Substr[0, excl]; IF root.Equal[lastRoot, FALSE] THEN { fileList.first _ fullFName; RETURN; }; lastRoot _ root; }; fileList _ CONS[fullFName, fileList]; }; -- LinkIt FS.EnumerateForNames[pattern, LinkIt, wDir]; TRUSTED {fileList _ LOOPHOLE[List.DReverse[LOOPHOLE[fileList]]]}; }; -- FileListFrom Commander.Register["Graph", GraphFiles, "Graph , reviews the graphs in the files. See GraphDoc.tioga for more information."]; Commander.Register["Plot", GraphFiles, "Plot , reviews the graphs in the files. See GraphDoc.tioga for more information."]; }. CHANGE LOG. SChen, created at October 9, 1985 6:21:05 pm PDT. ΖGraphRead.mesa, Copyright c 1985 by Xerox Corporation. All rights reserved. Last Edited by: Sweetsun Chen, November 17, 1985 1:03:04 am PST assume handle is already locked. if no problem then return msg=nil. assume handle is already locked. texts: title, time, and file name. bounds, nNamesMax, entityHash, and entityGroupList. allocate EntityRec for each curve, construct the entity list entityGroupList.ys and graph.entityList, and create the graph viewer to show the axes, title and time. Lock[handle]; add tails v2 _ ReverseValueList[v2]; correct order of oldValues for xEntity and each entity on graph.entityList xEntity.oldValues _ ReverseValueList[xEntity.oldValues]; FOR el: EntityList _ graph.entityList, el.rest UNTIL el = NIL DO el.first.oldValues _ ReverseValueList[el.first.oldValues]; ENDLOOP; initialize each segment data lastTextId _ 1; lastEntityId _ nNamesMax; lastEntityGroupId is 0. handle should be unlocked by caller. assume handle is already locked. The format could have been more compact. But it is easier to allow for upward/backward compatibility this way. AutoKey => graph.auto _ [GetBool[s], GetBool[s]]; initialize segments for x entities. draw some of the curves. Lock[handle]; handle should be unlocked by caller of this proc. reads in graph.texts in the reversed order. reverse it. append it cleanup t1 NameKey => eg.name _ GetRope[s]; -- 1 reverse it. clean up. reading routines scratch for GetRope and for historical reasons Κ ˜JšœΟmœ1™Lšœ™Icode™/—J˜šΟk ˜ Jšœžœ˜Jšœžœžœ˜Jšœ žœžœ˜Jšœ žœ˜(Jšœ žœ˜ Jšœžœ%˜2Jšœ žœ˜*Jšžœžœ2˜:Jš œžœžœŒžœHžœ˜ωJšœ žœ˜*J˜Jšœ žœ˜Jšœ žœX˜jJšœ žœΡ˜ΰJšžœžœSžœ˜cJšœžœ˜Jšœžœ&˜3Jšœžœ<˜FJšœ žœ˜ —J˜šœ žœž˜Jšžœ3žœžœQ˜‘Jšžœ˜—J˜Jšžœ9˜=J˜Jš œžœžœ žœžœžœ˜9Jš œ žœžœ žœžœžœ˜7Jš œ žœžœ žœžœžœ˜5J˜Jšžœžœžœžœ˜Jšžœžœ žœ˜Jš œ žœžœž œžœ žœ˜;Jš œ žœžœž œžœžœ˜AJšœ žœ"Οc&˜XJ˜šΟnœžœžœžœžœžœžœžœžœ˜fJšœ˜J˜ Jšœžœ˜Jšœ˜Jšœžœ˜J˜JšœŸ˜J˜—š œžœžœžœžœžœžœ˜UJ™ Jšœ"™"Jšžœžœžœ˜4šžœžœ˜Jšœžœžœ˜Jšœžœžœ$žœ˜Lšžœžœžœ˜šžœ˜˜šœžœ#˜+Jšžœ˜Jšžœ˜Jšœ˜—Jšžœ˜ J˜—šœ˜šœžœ?˜GJšžœ˜Jšžœ˜Jšœ˜—Jšžœ˜ J˜—˜šœžœ˜$Jšžœ˜Jšžœ˜Jšœ˜—Jšžœ˜ J˜—šžœ˜Jšœ˜Jšžœ˜ J˜—šžœ ˜ šœžœ˜šžœžœž˜J˜J˜*Jš žœžœžœžœžœ˜F—Jšžœ˜Jšœ˜—Jšžœ˜ J˜—šžœ˜ Jšœ˜Jšžœ˜ J˜—J˜—š žœžœžœžœžœžœ˜GJšœ1˜1Jšœžœ˜J˜—Jšœžœ˜šœžœž˜ J˜J˜#J˜"Jšžœ˜!—Jšœžœ˜šžœžœžœ˜1Jšžœ žœžœ ˜7—J˜—Jšžœžœžœ ˜J˜—JšœŸ ˜J˜š  œžœžœžœžœžœžœ˜]J™ Jšœ žœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜Jšœžœ˜J™J™"šœžœ ˜Jšœ˜JšœR˜RJšœ˜—šœ žœ ˜Jšœ'˜'JšœS˜SJšœ˜—šœ žœ ˜Jšœžœ+˜IJšœP˜PJšœ˜—Jš œ'žœžœžœžœ˜QJš œ!žœžœžœžœ˜KJ˜Jšœ4™4Jšœ@˜@Jšœžœ˜Jšœ˜Jšœ žœ6˜CJšœžœžœ žœ˜ešœžœ˜$Jšœ ˜ Jšœžœ˜ JšœŸ˜8Jšœ˜—J˜Jšœ-žœžœ˜EJ™Jšœ£™£šžœžœžœž˜Jšœžœ˜(šœžœ˜"Jšœ˜Jšœžœ˜,J˜Jšœ˜Jšœ˜—Jšœžœ˜4Jšœ žœ˜&Jšžœ˜—Jšœ:žœ˜AJšœTžœ˜\šžœžœžœ˜JšœŸK˜^J™ J˜—Jšžœ˜J™Jšœ ™ Jšœ$˜$šžœžœžœž˜(Jšœ˜Jšœ˜Jšœžœžœ˜Jšžœžœžœ+˜JJšžœ7˜;Jšœžœ˜ š žœ0žœ žœžœž˜TJšœžœ˜J˜Jšœžœ ˜Jšœžœžœ˜Jšžœžœžœ+˜JJšžœ7˜;Jšžœ˜—Jšœ™Jšžœžœ,Ÿ#˜\J˜ Jšœ˜Jšœ˜Jšžœ˜—Jšœžœ˜ J˜ ™JšœJ™JJšœ8™8šžœ,žœžœž™@Jšœ:™:Jšžœ™——J˜J™Jšœ˜šžœ&žœžœž˜:Jšœ˜Jšžœ˜—J™J™Jšœ™Jšœ™Jšœ0žœ˜7Jšœžœ˜*Jšœžœžœžœ ˜GJšœ$™$JšœŸ˜J˜—š   œžœžœžœžœžœ˜RJšžœ˜ J™ J™oJšœžœ*˜Ašžœžœ ž˜šžœ ž˜JšœŸ/˜Kšœ ˜ Jšœ˜Jšœ%žœ˜,Jšœ(žœ˜.Jšœ˜—Jšœ!˜!J˜-Jšœ#˜#Jšœ˜J˜'Jšœ!˜!Jšœ1™1Jšœ!˜!Jšœ˜Jšœ4˜4JšœžœŸ4˜LJšžœžœ˜'—Jšžœ˜—J™J™#šžœ:žœ žœž˜SJšœ˜Jšžœ˜—J˜J™Jšœ˜šžœžœžœ˜#J˜J˜Jšœ˜J˜—šžœ˜JšœŸ)˜žœŸ˜HJšœ5Ÿ˜9Jšœ$Ÿ˜(Jšœ,˜,Jšœžœ˜Jšžœžœ˜-—Jšžœ˜—šœŸ˜J˜——š   œžœžœCžœžœŸ'˜«šž˜šžœ ž˜Jšœžœ˜Jšœžœ+Ÿ˜EJšžœ˜%—Jšžœ˜—JšœžœŸ˜6JšœŸ˜J˜š   œžœžœAžœžœžœ˜‚Jšœ˜Jšœ žœ*˜6šž˜šžœ ž˜Jšœ%Ÿ˜)Jšœ+Ÿ˜0Jšœ1Ÿ˜5šœ Ÿ˜Jšœžœ˜šžœžœžœŸ ˜/šœžœž˜Jšœ8˜8Jšœ>˜>Jšžœ ˜——Jšžœžœ˜ J˜—Jšœ'Ÿ˜+JšœEŸ˜IJšœ;Ÿ˜?Jšœžœ˜Jšžœžœ˜(—Jšžœ˜—Jšœžœ˜)Jšœžœ'˜JJšœŸ ˜—J˜š   œžœžœžœžœ˜FJšœžœ ˜šžœžœžœ ž˜Jšœžœ˜Jšžœ˜—Jšœ"žœ˜(šœŸ˜J˜———š  œžœžœDžœžœžœ˜šJšœžœ˜šž˜šžœ ž˜Jšœžœ˜šœžœŸ˜&Jšœ3˜3—Jšžœ&˜-—Jšžœ˜—J™ šžœ.žœ žœž˜EJšœžœ˜Jšžœ˜—J™ šžœžœž˜Jšœ%˜%Jšœ žœ˜Jšœ žœ˜J˜ Jšžœ˜—JšœŸ˜J˜—š  œžœžœDžœžœ˜‹Jšœžœ'˜/šž˜šžœ ž˜Jšœ!Ÿ˜%Jšœ'Ÿ˜,JšœJŸ˜NJšœEŸ˜IJšœžœ˜Jšžœžœ˜0—Jšžœ˜—JšœŸ˜J˜—š œžœžœ˜:š  œžœ˜0šžœ&žœžœž˜:Jšœžœ žœ˜&Jšœ˜J˜Jšžœ˜—JšœŸ˜—š œžœ+˜?šžœ6žœžœž˜KJšœ$˜$Jšœ#˜#Jšžœ˜—JšœŸ˜—šžœŸ'˜*šžœ ž˜Jšœžœ˜šœŸ˜Jšœžœ žœ˜&Jšœ˜J˜Jšœ#˜#Jšœ"˜"J˜—Jšžœ ˜'—Jšžœ˜—JšœŸ˜—J˜—šœžœ˜*š  œžœžœ žœžœ žœ˜^Jšœ˜šžœ(˜+Jšžœžœžœž˜0J˜Jšœ˜Jšœžœ˜0Jšœ˜Jšžœ˜—šžœ0˜3Jšžœžœžœž˜1Jšœ5˜5Jšžœ˜—JšœŸ˜J˜—Jšœ žœ˜šžœ1˜4šžœžœžœž˜3Jšœ=˜=—Jšžœ˜—Jšœ7žœ˜=JšœŸ˜J˜——š  œžœ žœžœ"˜LJšœ žœ˜$šžœžœ˜Jšœž˜ Jšœ0žœžœ˜@š žœžœžœžœžœž˜+Jšœ'˜'Jšœ.˜.JšžœŸ ˜—J˜—Jšžœ˜JšœŸ˜——J˜šœ™J™Jšœ žœžœ˜'J˜š  œžœ žœžœžœ˜7Jšœžœ˜"Jš œžœžœžœžœžœ ˜Sšžœžœžœ ž˜šžœžœžœ˜,Jšžœ1žœ žœ˜Q—Jšœ˜Jšžœ˜—Jšœ˜Jšœ˜Jšžœžœ˜2JšœŸ ˜ J˜—š  œžœ žœžœ žœ˜:Jšžœžœ4žœ˜IJšœŸ ˜ J˜—š  œžœ žœžœžœžœ˜?šžœž˜Jšœžœ˜Jšœžœ˜Jšžœžœ˜)—JšœŸ ˜ J˜—š  œžœ žœžœžœ˜1Jšžœžœžœ˜)JšœŸ ˜ J˜—š  œžœ žœžœžœ˜/Jšžœžœ!žœ˜6JšœŸ ˜ J˜—š  œžœ žœžœžœ˜1Jšžœžœ(žœ˜>JšœŸ ˜ J˜—š   œžœ žœžœžœ˜9J˜Jšœ8˜8Jšœ7˜7Jšžœžœžœ˜!JšœŸ˜J˜—š   œžœ žœžœžœ˜MJšœ2˜2Jšœ2˜2Jšœ2˜2Jšœ2˜2JšœŸ˜J˜—š  œžœ žœžœžœžœžœ˜Mšžœžœžœ˜,Jšžœžœžœ˜3—Jšžœ˜JšœŸ ˜——J˜šΟb œ˜%Jšœ˜Jšœžœ˜ Jšœžœ˜ Jšœ1˜1Jšžœ žœ3˜Fšžœ˜Jšœžœ'˜1Jšœ žœ˜Jšœ žœ˜Jšœ žœžœ˜š žœ#žœžœžœžœž˜Ešžœžœ˜!šžœžœžœž˜>Jšœžœ˜Jšœžœ˜šžœ˜šœžœ+˜3Jšœ%Ÿ˜7—J˜J˜—JšžœŸ!˜*—J˜—šžœ˜Jšœ@˜@Jšžœ žœžœ˜,š žœžœ&žœžœžœžœž˜Nšžœžœžœ˜,JšœG˜GJšžœ˜—Jšžœ,˜0Jšœ˜Jšžœ˜—J˜—Jšžœ˜—J˜Jšžœžœžœ˜ —JšœŸ ˜J˜š  œžœžœžœžœžœžœžœ˜pJšœžœžœ˜š œžœ ŸΠckŸ ’Ÿ ’Ÿœ˜GJšœžœ˜ Jšœ žœ˜Jšžœ-žœžœžœ˜Bšžœžœ˜J˜!šžœžœžœ˜%Jšœ˜Jšžœ˜J˜—Jšœ˜J˜—Jšœ žœ˜%JšœŸœ˜ —J˜Jšžœ*˜,Jšžœ žœžœ˜AJšœŸ˜—J˜—JšœŽ˜ŽJšœ™šœŒ˜ŒJ˜—Jšœ˜J˜šžœžœ˜ Jšœ-žœ˜1——…—^ζ„Θ