<> <> <> <> DIRECTORY Atom USING [GetPropFromList], 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], GraphFileKeys, GraphOps USING [AddCurve, AddText, AppendValues, Lock, NewGraph, Unlock], GraphPrivate USING [CharPair, FourChars, GraphStreamProc, MakeTable, PaintAll, ReadAsciiFile, RopeList, ShowChart, STREAM], GraphUtil USING [AppendEGL, AppendEntityList, AppendTexts, HandleNotNil, InitSegAll, InitSegEnd, NewEntityId, NewGroupId, NewTextId, ReverseEntityList, ReplaceFileExt, ReverseTexts, ReverseValueList, UseMyColors, UseMyFonts, VanillaHandle], IO USING [Close, EndOf, EndOfStream, Error, GetChar, GetIndex, int, PeekChar, PutFR, rope], 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, 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; FileFormat: TYPE = {old, binary, ascii, illegal}; 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 errorat [%g], %g.", IO.int[s.GetIndex[]], IO.rope[message]]; CONTINUE; }; ReadBeyondEOF => { msg _ IO.PutFR["End of file at [%g], reading %g.", IO.int[s.GetIndex[]], IO.rope[message]]; CONTINUE; }; DataError => { msg _ IO.PutFR["Error at [%g], %g.", IO.int[s.GetIndex[]], IO.rope[message]]; 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 { IF file.Find["/", 1] > 1 OR file.Find["]"] > 1 THEN file _ "///Graph"; IF handle.controller.table = NIL THEN MakeTable[handle, ReplaceFileExt[file, "table"], 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; <> groupId, valuesLength, nCurves: INT; <<>> <> title: ROPE _ GetRope[s]; time: ROPE _ Convert.RopeFromTime[GetTime[s]]; file: ROPE _ NARROW[Atom.GetPropFromList[s.propList, $Name]]; <> [handle, groupId] _ NewGraph[ fileName: file, groupName: NIL, comment: file, xName: "X", autoBounds: TRUE, bounds: [GetReal[s], GetReal[s], GetReal[s], GetReal[s]], oldGraph: handle ]; <> [] _ AddText[handle: handle, rope: title, place: [0.5, 1.1], fontIndex: 2, justifX: center, justifY: bottom]; [] _ AddText[handle: handle, rope: time, place: [1.0, -0.35], fontIndex: 1, justifX: right, justifY: bottom]; [] _ AddText[handle: handle, rope: file, place: [0, -0.35], fontIndex: 1, justifX: left, justifY: bottom]; <> nCurves _ GetCardinal[s]; FOR i: INT IN [1..nCurves] DO [] _ AddCurve[handle: handle, groupId: groupId, name: GetRope[s], colorIndex: ((i-1) MOD LastEntityColor) + 1]; ENDLOOP; <<>> <> valuesLength _ GetCardinal[s]; FOR i: INT IN [1..valuesLength] DO x: REAL _ GetReal[s]; yvalues: ValueList _ NIL; FOR j: INT IN [1..nCurves] DO yvalues _ CONS[GetReal[s], yvalues]; ENDLOOP; AppendValues[handle, groupId, x, yvalues]; ENDLOOP; }; -- 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 => GetTexts[s, handle]; 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; <<>> <> IF handle.chart.viewer = NIL THEN ShowChart[handle] ELSE { UseMyColors[handle]; UseMyFonts[handle]; PaintAll[handle, TRUE, TRUE, TRUE]; }; <> }; -- ReadGraphFile GetTexts: PROC [s: STREAM, handle: GraphHandle] = { <> texts: Texts _ NIL; DO SELECT GetByte[s] FROM EndOfListKey => EXIT; TextKey => texts _ CONS[GetText[s, handle], texts]; -- 1 ENDCASE => SIGNAL SyntaxError["Texts"]; ENDLOOP; handle.allTexts _ AppendTexts[handle.allTexts, ReverseTexts[texts, FALSE]]; handle.graph.texts _ AppendTexts[handle.graph.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; <<>> InitSomeCurves[handle, egl]; -- init up to six curves in this graph file to be displayed. entityGroupList _ AppendEGL[entityGroupList, egl]; -- append egl. <<>> <> TRUSTED {List.Kill[LOOPHOLE[t1]]}; }; -- GetEntityGroupList GetEntityGroup: PROC [s: STREAM, handle: GraphHandle] RETURNS [eg: EntityGroup] = { eg _ NEW[EntityGroupRec _ []]; DO SELECT GetByte[s] FROM < 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[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: PROC [handle: GraphHandle, newEgl: EntityGroupList] = { OPEN handle; newEL: EntityList _ NIL; InitSomeEntity: PROC [ne: NestedEntities, count: INT] RETURNS [newCount: INT] = { newCount _ count; FOR el: EntityList _ ne.entityList, el.rest UNTIL el = NIL OR newCount >= LastEntityColor/2 DO entity: Entity _ el.first; InitSegAll[entity]; newEL _ CONS[entity, newEL]; newCount _ newCount + 1; ENDLOOP; FOR nel: NestedEntitiesList _ ne.children, nel.rest UNTIL nel = NIL OR newCount >= LastEntityColor/2 DO newCount _ InitSomeEntity[nel.first, newCount]; ENDLOOP; }; -- InitSomeEntity curveCount: CARDINAL _ 0; FOR egl: EntityGroupList _ newEgl, egl.rest UNTIL egl = NIL OR curveCount >= LastEntityColor/2 DO InitSegEnd[egl.first.x]; curveCount _ InitSomeEntity[egl.first.ys, curveCount]; ENDLOOP; graph.entityList _ AppendEntityList[graph.entityList, ReverseEntityList[newEL, 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.