<> <> <> DIRECTORY Atom USING [GetPropFromList], Basics USING [BYTE, LowHalf], BasicTime USING [GMT, nullGMT], 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, EntityGroupRec, EntityList, EntityRec, FontIndex, GRAPH, LastEntityColor, NestedEntities, NestedEntitiesList, NestedEntitiesRec, NumberOfColors, NumberOfFonts, ROPE, SegmentDataList, TargetSpec, Text, TextRec, Texts, ValueList, Viewer, XY], GraphCleanUp USING [CleanUpVL], GraphFileKeys, GraphOps USING [AddCurve, CreateGraph, SetXValues]; GraphPrivate USING [EntityGroupList, EntityHashSize, GraphHandle, GraphProc, Lock, MakeTable, PaintAll, PaintTails, ShowChart, Unlock], GraphUtil USING [FullName, HandleFromViewer, HandleNotNil, InitSegAll, InitSegEnd, LengthOfSDL, LengthOfVL, ReverseEntityList, ReverseTexts, ReverseValueList, UseMyColors, UseMyFonts, VanillaHandle], IO USING [Close, EndOf, Error, Flush, GetChar, GetIndex, int, PutBlock, PutChar, PutFR, rope, STREAM], List USING [DReverse, Kill], RefText USING [New, ObtainScratch, ReleaseScratch], Rope USING [Equal, Fetch, Find, FromRefText, IsEmpty, Length, Substr, ToRefText], ViewerClasses USING [Viewer], ViewerOps USING [DestroyViewer, PaintViewer]; GraphFile: CEDAR PROGRAM IMPORTS Atom, Basics, Commander, CommandTool, Convert, FileNames, FS, IO, List, GraphCleanUp, GraphOps, GraphPrivate, GraphUtil, RefText, Rope, ViewerOps EXPORTS GraphPrivate = { OPEN Graph, GraphFileKeys, GraphPrivate, GraphUtil; ReadBeyondEOF: SIGNAL[message: ROPE _ NIL]; SyntaxError: SIGNAL[message: ROPE _ NIL]; DataError: SIGNAL[message: ROPE _ NIL]; 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, text, illegal}; -- currently only binary is supported. RopeList: TYPE = LIST OF ROPE; <> myScratch: REF TEXT _ RefText.New[256]; 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 HandleFromFile: PUBLIC PROC[file: ROPE _ NIL] RETURNS [handle: GraphHandle _ NIL, msg: ROPE _ NIL] = { handle _ VanillaHandle[]; Lock[handle]; handle.userEditAllowed _ FALSE; msg _ GetGraph[handle, file, FALSE]; handle.userEditAllowed _ TRUE; Unlock[handle]; }; -- HandleFromFile GetGraph: PUBLIC PROC [handle: GraphHandle _ NIL, file: ROPE _ NIL] RETURNS [msg: ROPE _ NIL] = { <> <> IF HandleNotNil[handle] THEN { s: STREAM _ NIL; ok: BOOL _ TRUE; IF file.IsEmpty[] THEN RETURN["No file specified."]; s _ FS. StreamOpen[file ! FS.Error => {msg _ error.explanation; ok _ FALSE; CONTINUE} ]; IF ok THEN { ENABLE { SyntaxError => { msg _ IO.PutFR["Syntax error: %g at [%g].", IO.rope[message], IO.int[s.GetIndex[]] ]; }; ReadBeyondEOF => { msg _ IO.PutFR["Attempting to read beyond end of file for %g at [%g].", IO.rope[message], IO.int[s.GetIndex[]] ]; }; DataError => { msg _ IO.PutFR["Error: %g at [%g].", IO.rope[message], IO.int[s.GetIndex[]] ]; }; IO.EndOfStream => { msg _ End of file reached; }; 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[]] ]; }; ABORTED => { msg _ "Graph aborted. ... "; }; CONTINUE; }; IF handle.controller # NIL THEN IF handle.controller.table # NIL THEN ViewerOps.DestroyViewer[handle.controller.table]; handle.userEditAllowed _ FALSE; msg _ SELECT CheckFormat[s] FROM old => ReadPlotFile[handle, s], binary => ReadGraphFile[handle, s], text => ProcessesTextFile[handle, s], ENDCASE => "Illegal graph file."; handle.userEditAllowed _ TRUE; IF handle.controller # NIL THEN MakeTable[handle]; }; 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, FALSE]]]; 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, FALSE]]]; 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, FALSE]]]; AppendTexts[graph.texts, CONS[title, CONS[time, CONS[file, NIL]]]]; AppendTexts[allTexts, CONS[title, CONS[time, CONS[file, NIL]]]]; <> graph.bounds _ [GetReal[s], GetReal[s], GetReal[s], GetReal[s]]; nNamesMax _ GetCardinal[s]; xEntity _ NEW[EntityRec _ [name: "X", id: NewEntityId[handle, 0, FALSE]]]; entityHash[xEntity.id MOD EntityHashSize] _ CONS[xEntity, entityHash[xEntity.id MOD EntityHashSize]]; entityGroup _ NEW[EntityGroupRec _ [ x: xEntity, ys: NEW[NestedEntitiesRec _ []], id: NewGroupId[handle, 0, FALSE] -- should update length later. ]]; xEntity.group _ entityGroup; 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, FALSE] ]]; entityHash[index] _ CONS[entity, entityHash[index]]; entityList _ CONS[entity, entityList]; ENDLOOP; entityGroup.ys.entityList _ ReverseEntityList[entityList, FALSE]; AppendEntityList[graph.entityList, ReverseEntityList[entityList, FALSE]]; IF chart.viewer = NIL THEN { ShowChart[handle]; -- will unlock handle right before viewer is opened up. Lock[handle]; } ELSE PaintAll[handle]; <<>> <> entityGroup.length _ GetCardinal[s]; FOR i: INT IN [1..entityGroup.length] DO x2 _ GetReal[s]; vl: ValueList _ 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; <<>> <> <> <> 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]; -- graph.fileName is already initialized above. TextsKey => { allTexts _ GetTexts[s]; 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]; < graph.auto _ [GetBool[s], GetBool[s]];>> 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. Lock[handle]; }; <> }; -- ReadGraphFile GraphFileProc: TYPE = PROC [s: STREAM, graph: GRAPH]; 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], FALSE]}; -- 7 EndOfRecordKey => EXIT; ENDCASE => SIGNAL SyntaxError["Text"]; ENDLOOP; }; -- GetText GetCarets: GraphFileProc = { 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: GraphFileProc = { 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: GraphFileProc = { 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: GraphFileProc = { 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: GraphFileProc = { 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: GraphFileProc = { 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: GraphFileProc = { 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; <<>> <> IF handle.entityGroupList = NIL THEN handle.entityGroupList _ egl ELSE FOR t2 _ handle.entityGroupList, t2.rest UNTIL t2 = NIL DO IF t2.rest = NIL THEN t2.rest _ egl; ENDLOOP; <<>> <> List.Kill[LOOPHOLE[t1]]; }; -- GetEntityGroupList GetEntityGroup: PROC [s: STREAM, handle: GraphHandle] RETURNS [eg: EntityGroup] = { eg _ NEW[EntityGroupRec _ []]; DO SELECT GetByte[s] FROM NameKey => eg.name _ GetRope[s]; -- 1 EntityKey => eg.x _ GetEntity[s, handle, eg, NIL]; -- 2 NestedEntitiesKey => eg.ys _ GetNestedEntities[s, handle, eg, NIL]; -- 5 GroupIdKey => eg.id _ NewGroupId[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], FALSE]; -- 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[valueList, 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 ProcessesTextFile: PROC [handle: GraphHandle, s: STREAM] RETURNS [msg: ROPE _ NIL] = { key: ROPE _ s.GetID[ ! IO.EndOfStream => SIGNAL ReadBeyondEOF["first id in text file"]]; IF key.Equal["graph", FALSE] THEN ReadTextFile[handle, s] ELSE { s.SetIndex[0]; ReadSimpleTextFile[handle, s]; }; }; -- ReadTextFile ReadTextFile: PROC [handle: GraphHandle, s: STREAM] RETURNS [msg: ROPE _ NIL] = { <> msg _ "Not implemented yet." }; -- ReadGraphData ReadSimpleTextFile: PROC [handle: GraphHandle, s: STREAM] RETURNS [msg: ROPE _ NIL] = { buffer: REF TEXT _ RefText.Scratch[512]; tokenKind: IO.TokenKind _ tokenROPE; token: REF TEXT; charsSkipped: INT; error: TokenError; get, ok: BOOL _ TRUE; key: ROPE _ NIL; nNames, specifiedN: INT _ 0; nNamesSpeicified: BOOL _ FALSE; names, lastName: LIST OF ROPE _ NIL; xList: ValueList _ NIL; lvl, tlvl: LIST OF ValueList _ NIL; r: REAL; int: INT _ 0; keyRope, tokenRope: ROPE; key: {namesKey, nNamesKey, dataKey, noneKey} _ noneKey; xmin, xmax, ymin, ymax: REAL; iRow, iCol: INT _ 0; -- last row/col read so far. InitData: PROC [] = { <> IF nNamesSpeicified THEN { IF names = NIL THEN { FOR i: INT IN [0..nNamesSpeicified) DO names _ CONS[NIL, names]; ENDLOOP; nNames _ specifiedN; }; ELSE IF nNames # specifiedN THEN SIGNAL DataError[ IO.PutFR["%g names are specified but %g names are listed", IO.int[specifiedN], IO.int[nNames] ]]; } ELSE { IF nNames = 0 THEN SIGNAL DataError[ "Number of curves unknown before reading data"]; }; xmin _ ymin _ Real.LargestNumber; xmax _ ymax _ -xmin; FOR j: INT IN [0..nNames) DO lvl _ CONS[NIL, lvl]; ENDLOOP; tlvl _ lvl; }; -- InitData UNTIL key = dataKey DO <> IF get THEN { [token, ] _ s.GetToken[buffer: buffer]; tokenRope _ Rope.FromRefText[token]; }; get _ TRUE; key _ SELECT TRUE FROM tokenRope.Equal["nNames", FALSE] => nNamesKey, tokenRope.Equal["data", FALSE] => dataKey, tokenRope.Equal["names", FALSE] => namesKey, ENDCASE => SIGNAL SyntaxError["unknown key word"]; <<>> IF key = dataKey THEN InitData[]; DO [tokenKind, token, charsSkipped, error] _ s.GetCedarToken[buffer]; IF tokenKind = tokenEOF OR error # none THEN { status: ROPE; IF key = dataKey AND iCol = nNames THEN EXIT; status _ SELECT key FROM dataKey => IO.PutFR[ "after getting the %g-th number on the %g-th row in the table.", IO.int[iCol], IO.int[iRow+1]], namesKey => "getting names", ENDCASE => "getting the number of names"; IF tokenKind = tokenEOF THEN SIGNAL ReadBeyondEOF[status] ELSE SIGNAL DataError[Rope.Concat["token error in ", status]]; }; tokenRope _ Rope.FromRefText[token]; IF tokenKind = tokenCHAR THEN LOOP ELSE IF tokenKind = tokenID THEN {get _ FALSE; EXIT}; ELSE SELECT key FROM namesKey => IF tokenKind = tokenROPE THEN { nl: LIST OF ROPE _ CONS[tokenRope, NIL]; IF lastName = NIL THEN lastName _ names _ nl ELSE {lastName.rest _ nl; lastName _ nl}; nNames _ nNames + 1; IF nNamesSpeicified AND nNames > specifiedN THEN SIGNAL DataError[ IO.PutFR["%g names are specified but %g names are listed", IO.int[specifiedN], IO.int[nNames] ]; } ELSE SIGNAL SyntaxError [IO.PutFR["after getting the %g-th name", IO.int[nNames]]; }; nNamesKey => { ENABLE Convert.Error => SIGNAL DataError["number of names"]; base: [2..36] _ SELECT tokenKind FROM tokenDECIMAL => 10, tokenOCTAL => 8, tokenHEX => 16, ENDCASE => 2; number: INT _ Convert.IntFromRope[tokenRope, base]; IF names # NIL AND nNames # number THEN SIGNAL DataError[ IO.PutFR["%g names are specified but %g names are listed", IO.int[number], IO.int[nNames] ]; specifiedN _ number; nNamesSpecified _ TRUE; EXIT; }; ENDCASE => { -- dataKey ENABLE Convert.Error => SIGNAL DataError[IO.PutFR[ "parsing the %g-th number on the %g-th row", IO.int[iCol], IO.int[iRow+1]]; IF iCol = nNames THEN {iCol _ 1; iRow _ iRow + 1} ELSE iCol _ iCol + 1; r _ Convert.RealFromRope[tokenRope]; IF iCol = 1 THEN { xList _ CONS[r, xList]; IF iRow = 0 THEN xmin _ r ELSE xmax _ r; } ELSE { tlvl.first _ CONS[r, tlvl.first]; ymax _ MAX[ymax, r]; ymin _ MIN[ymin, r]; tlvl _ tlvl.rest; }; }; ENDLOOP; ENDLOOP; IF ymax = ymin THEN { IF ymax = 0.0 THEN { ymax _ 1.0; ymin _ -1.0 } ELSE { ymax _ ymax + ABS[ymax]; ymin _ ymin - ABS[ymin]; }; }; IF xmax = xmin THEN { IF xmax = 0.0 THEN { xmax _ 1.0; xmin _ -1.0 } ELSE { xmax _ xmax + ABS[xmax]; xmin _ xmin - ABS[xmin]; }; }; handle _ GraphOps.CreateGraph[ bounds: [xmin, ymin, xmax, ymax], fileName: fullName ]; <<[] _ GraphOps.AddText[handle: handle,>> <> [] _ GraphOps.SetXValues[handle, xList]; iCurve _ nNames; TRUSTED { lvl _ LOOPHOLE[List.DReverse[LOOPHOLE[lvl]]]; names _ LOOPHOLE[List.DReverse[LOOPHOLE[names]]]; }; tlvl _ lvl; FOR lastName _ names, lastName.rest UNTIL lastName = NIL DO [] _ GraphOps.AddCurve[handle, iCurve, tlvl.first, lastName.first, iCurve]; iCurve _ iCurve - 1; tlvl _ tlvl.rest; ENDLOOP; TRUSTED { List.Kill[LOOPHOLE[lvl]]; List.Kill[LOOPHOLE[names]]; }; out.PutF["done.\n"]; }; -- ReadSimpleGraphData SaveGraph: PUBLIC PROC[viewer: Viewer, file: ROPE _ NIL, plottedOnly: BOOL _ TRUE] RETURNS [msg: ROPE _ NIL] = { IF file.IsEmpty[] THEN msg _ "Please select a file name." ELSE IF file.Find["/", 1] > 1 OR file.Find["]"] > 1 THEN msg _ "Can not write a remote file." ELSE { handle: GraphHandle _ HandleFromViewer[viewer]; newName: ROPE; [msg, newName] _ WriteGraphFile[handle, file, plottedOnly]; IF plottedOnly THEN IF msg = NIL AND handle.chart.viewer # NIL THEN { handle.chart.viewer.name _ newName; ViewerOps.PaintViewer[handle.chart.viewer, caption, FALSE, NIL]; }; }; }; -- SaveGraph WriteGraphFile: PUBLIC PROC [handle: GraphHandle _ NIL, file: ROPE _ NIL, plottedOnly: BOOL _ TRUE] RETURNS[msg, newName: ROPE _ NIL] = { IF handle = NIL THEN RETURN["handle = NIL IN WriteGraphFile"] ELSE IF file.IsEmpty THEN RETURN ["No file name"] ELSE { OPEN handle; ok: BOOL _ TRUE; s: STREAM; nVector: CARDINAL _ 0; s _ FS. StreamOpen[fileName: file, accessOptions: $create, keep: 99 ! FS.Error => {msg _ error.explanation; ok _ FALSE; CONTINUE} ]; IF ok THEN { ENABLE IO.Error => { msg _ "Write Error."; <> CONTINUE }; PutRope[s, "binary graph"]; -- format id PutTexts[s, IF plottedOnly THEN graph.texts ELSE handle.allTexts]; PutCarets[s, graph]; PutByte[s, ShowSlopeKey]; PutBool[s, graph.showSlope]; PutTargets[s, graph]; PutGrids[s, graph]; PutDivisions[s, graph]; PutBounds[s, graph]; PutColors[s, graph]; PutFonts[s, graph]; PutEntityGroupList[s, handle, plottedOnly]; PutByte[s, EndOfRecordKey]; }; IF s # NIL THEN { s.Flush[]; s.Close[]; newName _ NARROW[Atom.GetPropFromList[s.propList, $Name]] }; }; }; -- WriteGraphFile PutTexts: PROC [s: STREAM, texts: Texts] = { PutByte[s, TextsKey]; FOR ts: Texts _ texts, ts.rest UNTIL ts = NIL DO text: Text _ ts.first; PutByte[s, TextKey]; PutByte[s, NameKey]; PutRope[s, text.text]; PutByte[s, PlaceKey]; PutReal[s, text.place.x]; PutReal[s, text.place.y]; PutByte[s, FontIndexKey]; PutByte[s, text.fontIndex]; PutByte[s, ColorIndexKey]; PutByte[s, text.colorIndex]; PutByte[s, RotationKey]; PutReal[s, text.rotation]; PutByte[s, JustificationsKey]; PutByte[s, XKey]; PutByte[s, SELECT text.justifX FROM left => 1, center => 2, ENDCASE => 3]; PutByte[s, YKey]; PutByte[s, SELECT text.justifY FROM top => 1, center => 2, ENDCASE => 3]; PutByte[s, EndOfRecordKey]; PutByte[s, TextIdKey]; PutInt[s, text.id]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutTexts PutCarets: GraphFileProc = { PutByte[s, CaretsKey]; FOR index: CaretIndex IN CaretIndex DO PutByte[s, SELECT index FROM primary => PrimaryKey, secondary => SecondaryKey, ENDCASE => TextCaretKey]; PutByte[s, PlaceKey]; PutReal[s, graph.caret[index].place.x]; PutReal[s, graph.caret[index].place.y]; PutByte[s, OnKey]; PutBool[s, graph.caret[index].on]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutCarets PutTargets: GraphFileProc = { PutByte[s, TargetsKey]; FOR xy: XY IN XY DO OPEN graph.target[xy]; PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, ValueKey]; PutReal[s, value]; PutByte[s, WidthKey]; PutReal[s, width]; PutByte[s, ColorIndexKey]; PutByte[s, colorIndex]; PutByte[s, OnKey]; PutBool[s, on]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutTargets PutGrids: GraphFileProc = { PutByte[s, GridsKey]; FOR xy: XY IN XY DO PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, OnKey]; PutBool[s, graph.grids[xy]]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutGrids PutDivisions: GraphFileProc = { PutByte[s, DivisionsKey]; FOR xy: XY IN XY DO PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, AutoKey]; PutBool[s, graph.auto[divisions]]; PutByte[s, DivisionsKey]; PutByte[s, graph.division[xy]]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutDivisions PutBounds: GraphFileProc = { PutByte[s, BoundsKey]; FOR xy: XY IN XY DO OPEN graph.bounds; PutByte[s, IF xy = x THEN XKey ELSE YKey]; PutByte[s, AutoKey]; PutBool[s, graph.auto[bounds]]; PutByte[s, MaxKey]; PutReal[s, IF xy = x THEN xmax ELSE ymax]; PutByte[s, MinKey]; PutReal[s, IF xy = x THEN xmin ELSE ymin]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutBounds PutColors: GraphFileProc = { PutByte[s, ColorsKey]; FOR i: ColorIndex IN ColorIndex DO OPEN graph.color[i]; PutByte[s, i+1]; PutByte[s, RKey]; PutReal[s, R]; PutByte[s, GKey]; PutReal[s, G]; PutByte[s, BKey]; PutReal[s, B]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutColors PutFonts: GraphFileProc = { PutByte[s, FontsKey]; FOR i: FontIndex IN FontIndex DO OPEN graph.font[i]; PutByte[s, i+1]; PutByte[s, NameKey]; PutRope[s, family]; PutByte[s, BoldKey]; PutBool[s, bold]; PutByte[s, ItalicKey]; PutBool[s, italic]; PutByte[s, VFontSizeKey]; PutInt[s, vFontSize]; PutByte[s, PFontScaleKey]; PutReal[s, pFontScale]; PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfRecordKey]; }; -- PutFonts PutEntityGroupList: PROC [s: STREAM, handle: GraphHandle, plottedOnly: BOOL _ TRUE] = { PutByte[s, EntityGroupListKey]; FOR egl: EntityGroupList _ handle.entityGroupList, egl.rest UNTIL egl = NIL DO eg: EntityGroup _ egl.first; PutByte[s, EntityGroupKey]; PutByte[s, NameKey]; PutRope[s, eg.name]; PutEntity[s, eg.x, plottedOnly]; IF plottedOnly THEN PutPlottedNE[s, handle.graph.entityList, eg] ELSE PutAllNE[s, eg.ys]; PutByte[s, GroupIdKey]; PutInt[s, eg.id]; PutByte[s, LengthKey]; PutInt[s, eg.length]; <> PutByte[s, EndOfRecordKey]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutEntityGroupList PutEntity: PROC [s: STREAM, entity: Entity, plottedOnly: BOOL _ TRUE] = { PutByte[s, EntityKey]; PutByte[s, NameKey]; PutRope[s, IF plottedOnly THEN FullName[entity] ELSE entity.name]; PutByte[s, CommentKey]; PutRope[s, IF plottedOnly THEN "" ELSE entity.comment]; PutByte[s, ColorIndexKey]; PutByte[s, entity.colorIndex]; PutByte[s, MarkKey]; PutByte[s, SELECT entity.mark FROM none => NoneKey, round => RoundKey, square => SquareKey, diamond => DiamondKey, cross => CrossKey, dollar => DollarKey, ENDCASE => PercentKey]; PutByte[s, WidthKey]; PutReal[s, entity.width]; IF plottedOnly THEN PutValuesForSDL[s, entity.segments] ELSE PutValuesForVL[s, entity.oldValues]; PutByte[s, EntityIdKey]; PutInt[s, entity.id]; PutByte[s, EndOfRecordKey]; }; -- PutEntity PutAllEL: PROC [s: STREAM, entityList: EntityList] = { PutByte[s, EntityListKey]; FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO PutEntity[s, el.first, FALSE]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutAllEL PutPlottedEL: PROC [s: STREAM, el: EntityList, group: EntityGroup] = { PutByte[s, EntityListKey]; FOR el: EntityList _ entityList, el.rest UNTIL el = NIL DO IF el.first.group = group THEN PutEntity[s, el.first, plottedOnly]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutPlottedEL PutPlottedNE: PROC [s: STREAM, plottedEL: EntityList, group: EntityGroup] = { PutByte[s, NestedEntitiesKey]; PutByte[s, NameKey]; PutRope[s, ne.name]; PutByte[s, CommentKey]; PutRope[s, ne.comment]; PutPlottedEL[s, plottedEL, group]; PutNEL[s, NIL]; PutByte[s, EndOfRecordKey]; }; -- PutPlottedNE PutAllNE: PROC [s: STREAM, ne: NestedEntities] = { PutByte[s, NestedEntitiesKey]; PutByte[s, NameKey]; PutRope[s, ne.name]; PutByte[s, CommentKey]; PutRope[s, ne.comment]; PutAllEL[s, ne.entityList]; PutNEL[s, ne.children]; PutByte[s, EndOfRecordKey]; }; -- PutAllNE PutNEL: PROC [s: STREAM, nestedEL: NestedEntitiesList] = { PutByte[s, NELKey]; FOR nel: NestedEntitiesList _ nestedEL, nel.rest UNTIL nel = NIL DO PutAllNE[s, nel.first]; ENDLOOP; PutByte[s, EndOfListKey]; }; -- PutNEL PutValuesForVL: PROC [s: STREAM, valueList: ValueList] = { PutByte[s, ValuesKey]; PutInt[s, LengthOfVL[valueList]]; FOR vl: ValueList _ valueList, vl.rest UNTIL vl = NIL DO PutReal[s, vl.first]; ENDLOOP; }; -- PutValuesForVL PutValuesForSDL: PROC [s: STREAM, segmentDataList: SegmentDataList] = { PutByte[s, ValuesKey]; PutInt[s, LengthOfSDL[segmentDataList]]; FOR sdl: SegmentDataList _ segmentDataList, sdl.rest UNTIL sdl = NIL DO PutReal[s, sdl.first.end]; ENDLOOP; }; -- PutValuesForSDL PutCrossSections: PROC [s: STREAM, eg: EntityGroup] = { VLL: TYPE = LIST OF ValueList; vllR, vll, tvll: VLL _ NIL; GetVLfromSDL: PROC [segmentDataList: SegmentDataList] RETURNS [vl: ValueList _ NIL] = { FOR sdl: SegmentDataList _ segmentDataList, sdl.rest UNTIL sdl = NIL DO vl _ CONS[sdl.first.end]; ENDLOOP; [vl, ] _ ReverseValueList[vl]; }; -- GetVLfromSDL GetVLsFromNE: PROC [ne: NestedEntities, old: VLL] RETURNS [new: VLL _ NIL] = { <> new _ old; FOR el: EntityList _ ne.entityList, el.rest UNTIL el = NIL DO new _ CONS[ IF el.first.segments = NIL THEN el.first.oldValues ELSE GetVLfromSDL[el.first.segments], new] ENDLOOP; new _ GetVLsFromNEL[ne.children, new]; }; -- GetVLsFromNE GetVLsFromNEL: PROC [nestedEntitiesList: NestedEntitiesList, old: VLL] RETURNS [new: VLL _ NIL] = { -- result is in reverse order !! new _ old; FOR nel: NestedEntitiesList _ nestedEntitiesList, nel.rest UNTIL nel = NIL DO new _ GetVLsFromNE[nel.first, new]; ENDLOOP; }; -- GetVLsFromNEL CleanUpVLL: PROC [old: VLL] RETURNS [VLL] = { WHILE old # NIL DO next: VLL _ old.rest; old.first _ NIL; old.rest _ NIL; old _ next; ENDLOOP; RETURN[NIL]; }; -- CleanUpVLL vllR _ CONS[GetVLfromSDL[eg.x.segments], NIL]; -- list of vl in reverse order. vllR _ GetVLsFromNE[eg.ys, vllR]; <> FOR tvll _ vllR, tvll.rest UNTIL tvll = NIL DO vll _ CONS[tvll.first, vll]; ENDLOOP; <<>> <> vllR _ CleanUpVLL[vllR]; <> PutByte[s, CrossSectionsKey]; WHILE vll # NIL DO IF vll.first = NIL THEN EXIT; PutByte[s, TailsKey]; -- keyword before each set of tails FOR tvll _ vll, tvll.rest UNTIL tvll = NIL DO vl: ValueList _ tvll.first; PutReal[s, vl.first]; tvll.first _ vl.rest; ENDLOOP; ENDLOOP; PutByte[s, EndOfListKey]; <<>> <> vll _ CleanUpVLL[vll]; }; -- PutCrossSections WriteDataFile: PUBLIC PROC [graph: GRAPH _ NIL, file: ROPE _ NIL] RETURNS [msg: ROPE _ NIL] = { <> }; -- WriteDataFile CheckFormat: PROC [stream: STREAM] RETURNS[format: FileFormat _ illegal] = { rope: ROPE; firstChar: CHAR _ stream.PeekChar[]; IF firstChar = 0C THEN { 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 _ text; }; -- CheckFormat <> 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 <> PutRope: PROC [stream: STREAM, rope: ROPE _ NIL] = { length: CARDINAL _ Basics.LowHalf[rope.Length[]]; PutCardinal[stream, length]; stream.PutBlock[Rope.ToRefText[rope], 0, length]; }; -- PutRope PutTime: PROC [stream: STREAM, time: BasicTime.GMT _ BasicTime.nullGMT] = { PutLongWord[stream, LOOPHOLE[time, FourChars]]; }; -- PutTime PutBool: PROC[stream: STREAM, bool: BOOL _ TRUE] = { PutByte[stream, IF bool THEN TrueKey ELSE FalseKey]; }; -- PutBool PutByte: PROC [stream: STREAM, byte: BYTE _ 0] = { stream.PutChar[LOOPHOLE[byte, CHAR]]; }; -- PutByte PutInt: PROC [stream: STREAM, int: INT _ 0] = { PutLongWord[stream, LOOPHOLE[int, FourChars]]; }; -- PutInt PutReal: PROC [stream: STREAM, real: REAL _ 0] = { PutLongWord[stream, LOOPHOLE[real, FourChars]]; }; -- PutReal PutCardinal: PROC [stream: STREAM, word: CARDINAL _ 0] = { pair: CharPair _ LOOPHOLE[word, CharPair]; stream.PutChar[pair.high]; stream.PutChar[pair.low]; }; -- PutCardinal PutLongWord: PROC [stream: STREAM, long: FourChars] = INLINE { stream.PutChar[long.lh]; stream.PutChar[long.ll]; stream.PutChar[long.hh]; stream.PutChar[long.hl]; }; -- PutLongCard 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.