<> <> DIRECTORY Basics USING [LowHalf], BasicTime USING [GMT, nullGMT], Commander USING [CommandProc, Register], CommandTool USING [ParseToList], Convert USING [CardFromRope, Error], FileNames USING [CurrentWorkingDirectory], FS USING [ComponentPositions, EnumerateForNames, ExpandName, NameProc, Error, StreamOpen], IO USING [Close, EndOf, Error, Flush, GetChar, int, PutBlock, PutChar, PutFR, rope, STREAM], List USING [DReverse], Plot USING [AddVector, CreateViewer, Curves, IsPlotViewer, PlotSpec, PlotSpecRec, RealSequence, RopeSequence, SetSpec, Vector], PlotOps USING [Handle, Lock, Unlock], RefText USING [New], Rope USING [Equal, Fetch, Find, IsEmpty, Length, ROPE, Substr, ToRefText], RopeFrom USING [String], ViewerClasses USING [Viewer], ViewerOps USING [DestroyViewer, PaintViewer]; PlotFile: CEDAR MONITOR IMPORTS Basics, Commander, CommandTool, Convert, FileNames, FS, IO, List, Plot, PlotOps, RefText, Rope, RopeFrom, ViewerOps EXPORTS Plot = { OPEN Plot; ReadBeyondEOF: SIGNAL[message: Rope.ROPE _ NIL]; CharPair: TYPE = MACHINE DEPENDENT RECORD[high, low: CHAR]; FourChars: TYPE = MACHINE DEPENDENT RECORD[lh, ll, hh, hl: CHAR]; FileFormat: TYPE = {binary, text, illegal}; -- currently only binary is supported. RopeList: TYPE = LIST OF Rope.ROPE; formatRope: ARRAY FileFormat OF Rope.ROPE = ["* binary", "* text", ""]; PlotFiles: PUBLIC Commander.CommandProc = { argList: RopeList; length: NAT; [argList, length] _ CommandTool.ParseToList[cmd]; IF length <= 0 THEN msg _ "To review plot files, type: Plot " ELSE { wDir: Rope.ROPE _ FileNames.CurrentWorkingDirectory[]; nPlots: NAT _ 0; maxPlots: 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 _ maxPlots]; -- don't change it maxPlots _ max; }; ENDCASE; -- simply ignors illegal switches } ELSE { fileList: RopeList _ FileListFrom[arg.first, wDir, allVersions]; FOR file: RopeList _ fileList, file.rest UNTIL file = NIL OR msg # NIL DO msg _ IF nPlots >= maxPlots THEN IO.PutFR["Note: max. %g plots for each command. You may change it by a switch.", IO.int[maxPlots]] ELSE ReadPlotFile[ name: file.first, viewer: NIL, iconic: nPlots # 0]; nPlots _ nPlots + 1; ENDLOOP; }; ENDLOOP; }; }; -- PlotFiles ReadPlotFile: PUBLIC PROC [name: Rope.ROPE _ NIL, viewer: ViewerClasses.Viewer _ NIL, iconic: BOOL _ TRUE] RETURNS[msg: Rope.ROPE _ NIL] = { plotSpec: PlotSpec; s: IO.STREAM _ NIL; ok: BOOL _ TRUE; format: FileFormat; nVector: CARDINAL; c: FS.ComponentPositions; fullName: Rope.ROPE; IF name.IsEmpty[] THEN RETURN["No file name."]; [fullName, c]_ FS.ExpandName[name, FileNames.CurrentWorkingDirectory[]]; IF viewer # NIL AND NOT IsPlotViewer[viewer] THEN RETURN["Not a plot viewer."]; s _ FS. StreamOpen[fullName ! FS.Error => {msg _ error.explanation; ok _ FALSE; CONTINUE} ]; IF ok THEN { ENABLE { ReadBeyondEOF => { msg _ IO.PutFR["Attempting to read beyond end of file for the %g.", IO.rope[message]]; CONTINUE; }; IO.Error => { msg _ IO.PutFR["IO Error # %g in ReadPlotFile.", IO.int[LOOPHOLE[ec, CARDINAL]]]; CONTINUE; }; ABORTED => { msg _ "Plot aborted. ... "; IF viewer # NIL THEN ViewerOps.DestroyViewer[viewer]; CONTINUE; }; }; format _ CheckFormat[s]; IF format = illegal THEN msg _ "Illegal plot file." ELSE { <> plotSpec _ NEW[PlotSpecRec _ [ file: fullName, title: GetRope[s], time: GetTime[s], bounds: [GetReal[s], GetReal[s], GetReal[s], GetReal[s]], nCurvesMax: GetCardinal[s] ]]; plotSpec.legendEntries _ NEW[RopeSequence[plotSpec.nCurvesMax]]; FOR i: CARDINAL IN [0..plotSpec.nCurvesMax) DO plotSpec.legendEntries[i] _ GetRope[s]; ENDLOOP; IF viewer = NIL THEN viewer _ CreateViewer[spec: plotSpec, iconic: iconic] ELSE SetSpec[viewer, plotSpec]; <> nVector _ GetCardinal[s]; FOR i: CARDINAL IN [0..nVector) DO vector: Vector _ NEW[RealSequence[plotSpec.nCurvesMax + 1]]; FOR j: CARDINAL IN [0..plotSpec.nCurvesMax] DO vector[j] _ GetReal[s]; ENDLOOP; AddVector[viewer, vector]; ENDLOOP; }; }; IF s # NIL THEN s.Close[]; }; -- ReadPlotFile SavePlot: PUBLIC ENTRY PROC[viewer: ViewerClasses.Viewer, toFile: Rope.ROPE _ NIL] RETURNS[msg: Rope.ROPE _ NIL] = { handle: PlotOps.Handle; IF NOT IsPlotViewer[viewer] THEN RETURN["Not a Plot viewer."]; handle _ NARROW[viewer.data]; IF handle = NIL THEN RETURN["No data."]; IF toFile.IsEmpty[] THEN RETURN["Please select a file name."]; IF toFile.Find["/", 1] > 1 OR toFile.Find["]"] > 1 THEN RETURN["Can not write a remote file."] ELSE { GetHighestVersion: PROC[] RETURNS [n: Rope.ROPE _ NIL] = { Enum: FS.NameProc = {n _ fullFName; continue _ TRUE; }; FS.EnumerateForNames[fileNameRoot, Enum]; }; -- GetNewVersionName excl: INT _ toFile.Find["!"]; fileNameRoot: Rope.ROPE = IF excl < 0 THEN toFile ELSE toFile.Substr[0, excl]; PlotOps.Lock[handle]; msg _ WritePlotFile[fileNameRoot, handle.plotSpec, handle.curves]; viewer.name _ handle.plotSpec.file _ GetHighestVersion[]; PlotOps.Unlock[handle]; ViewerOps.PaintViewer[viewer, caption, FALSE, NIL]; }; }; -- SavePlot WritePlotFile: PROC [file: Rope.ROPE, spec: PlotSpec, curves: Curves] RETURNS[msg: Rope.ROPE _ NIL] = { ok: BOOL _ TRUE; s: IO.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 }; rightOrder: Curves _ NIL; -- it was reversed. PutRope[s, formatRope[binary]]; PutRope[s, spec.title]; PutTime[s, spec.time]; PutReal[s, spec.bounds.xmin]; PutReal[s, spec.bounds.ymin]; PutReal[s, spec.bounds.xmax]; PutReal[s, spec.bounds.ymax]; PutCardinal[s, spec.nCurvesMax]; FOR i: CARDINAL IN [0..spec.nCurvesMax) DO PutRope[s, spec.legendEntries[i]]; ENDLOOP; <> FOR graph: Curves _ curves, graph.rest UNTIL graph = NIL DO rightOrder _ CONS[graph.first, rightOrder]; nVector _ nVector + 1; ENDLOOP; PutCardinal[s, nVector]; FOR graph: Curves _ rightOrder, graph.rest UNTIL graph = NIL DO FOR i: CARDINAL IN [0..spec.nCurvesMax] DO PutReal[s, graph.first[i]]; ENDLOOP; ENDLOOP; IF s # NIL THEN {s.Flush[]; s.Close[]}; }; }; -- WritePlotFile FileListFrom: PROC [pattern, wDir: Rope.ROPE _ NIL, allVersions: BOOL _ FALSE] RETURNS [fileList: RopeList _ NIL] = { root, lastRoot: Rope.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 <> GetRope: PROC [stream: IO.STREAM] RETURNS [Rope.ROPE] = { length: NAT = GetCardinal[stream]; text: REF TEXT _ RefText.New[length]; 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; RETURN[RopeFrom.String[text]]; }; -- GetRope GetTime: PROC [stream: IO.STREAM] RETURNS [BasicTime.GMT] = { RETURN[LOOPHOLE[GetLongWord[stream, " a BasicTime.GMT"], BasicTime.GMT]]; }; -- GetTime GetReal: PROC [stream: IO.STREAM] RETURNS [REAL] = { RETURN[LOOPHOLE[GetLongWord[stream, " a real number"], REAL]]; }; -- GetReal GetCardinal: PROC [stream: IO.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: IO.STREAM, info: Rope.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: IO.STREAM, info1, info2: Rope.ROPE _ NIL] RETURNS [CHAR] = { IF stream.EndOf[] THEN SIGNAL ReadBeyondEOF[ IO.PutFR["%g%g.", IO.rope[info1], IO.rope[info2]]]; RETURN[stream.GetChar[]]; }; -- MyGetChar CheckFormat: PROC [stream: IO.STREAM] RETURNS[format: FileFormat] = { rope: Rope.ROPE _ GetRope[stream]; format _ SELECT TRUE FROM rope.Equal[formatRope[binary]] => binary, rope.Equal[formatRope[text], FALSE] => illegal, -- text format will be legal later ENDCASE => illegal; }; -- CheckFormat <> PutRope: PROC [stream: IO.STREAM, rope: Rope.ROPE _ NIL] = { length: CARDINAL _ Basics.LowHalf[rope.Length[]]; PutCardinal[stream, length]; stream.PutBlock[Rope.ToRefText[rope], 0, length]; }; -- PutRope PutTime: PROC [stream: IO.STREAM, time: BasicTime.GMT _ BasicTime.nullGMT] = { PutLongWord[stream, LOOPHOLE[time, FourChars]]; }; -- PutTime PutReal: PROC [stream: IO.STREAM, real: REAL _ 0] = { PutLongWord[stream, LOOPHOLE[real, FourChars]]; }; -- PutReal PutCardinal: PROC [stream: IO.STREAM, word: CARDINAL _ 0] = { pair: CharPair _ LOOPHOLE[word, CharPair]; stream.PutChar[pair.high]; stream.PutChar[pair.low]; }; -- PutCardinal PutLongWord: PROC [stream: IO.STREAM, long: FourChars] = INLINE { stream.PutChar[long.lh]; stream.PutChar[long.ll]; stream.PutChar[long.hh]; stream.PutChar[long.hl]; }; -- PutLongCard Commander.Register["Plot", PlotFiles, "Plot , reviews the plots in the files. See PlotDoc.tioga for more information."]; <> Commander.Register["OpenPlot", PlotFiles, "OpenPlot , reviews the plots in the files. See PlotDoc.tioga for more information."]; }. CHANGE LOG.