PlotFile.mesa, Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, August 1, 1985 7:51:39 pm PDT
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, FromRefText, IsEmpty, Length, ROPE, Substr, ToRefText],
ViewerClasses USING [Viewer],
ViewerOps USING [DestroyViewer, PaintViewer];
PlotFile: CEDAR MONITOR
IMPORTS Basics, Commander, CommandTool, Convert, FileNames, FS, IO, List, Plot, PlotOps, RefText, Rope, ViewerOps
EXPORTS Plot = {
OPEN Plot;
ReadBeyondEOF: SIGNAL[message: Rope.ROPENIL];
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 <files>"
ELSE {
wDir: Rope.ROPE ← FileNames.CurrentWorkingDirectory[];
nPlots: NAT ← 0;
maxPlots: NAT ← 12;
allVersions: BOOLFALSE;
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.ROPENIL, viewer: ViewerClasses.Viewer ← NIL, iconic: BOOLTRUE] RETURNS[msg: Rope.ROPENIL] = {
handle: PlotOps.Handle ← NIL;
plotSpec: PlotSpec ← NIL;
s: IO.STREAMNIL;
ok: BOOLTRUE;
format: FileFormat;
nVector: CARDINAL;
c: FS.ComponentPositions;
wDir, fullName: Rope.ROPENIL;
IF viewer # NIL THEN {
IF NOT IsPlotViewer[viewer] THEN RETURN["Not a plot viewer."];
handle ← NARROW[viewer.data];
IF handle # NIL THEN plotSpec ← handle.plotSpec;
};
IF name.IsEmpty[] THEN RETURN["No file name."];
IF plotSpec # NIL THEN {
[wDir, c] ← FS.ExpandName[plotSpec.file];
wDir ← wDir.Substr[0, c.base.start];
};
[fullName, c]← FS.ExpandName[name, wDir];
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 {
set plotSpec
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];
set vectors
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.ROPENIL] RETURNS[msg: Rope.ROPENIL] = {
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.ROPENIL] = {
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.ROPENIL] = {
ok: BOOLTRUE;
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.";
ok ← FALSE;
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;
nVector ← Basics.LowHalf[List.Length[curves]]; (complained by compiler.)
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.ROPENIL, allVersions: BOOLFALSE] RETURNS [fileList: RopeList ← NIL] = {
root, lastRoot: Rope.ROPENIL;
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
reading routines
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[Rope.FromRefText[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.ROPENIL] 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
writing routines
PutRope: PROC [stream: IO.STREAM, rope: Rope.ROPENIL] = {
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 <plot file list>, reviews the plots in the files. See PlotDoc.tioga for more information."];
and for historical reasons
Commander.Register["OpenPlot", PlotFiles, "OpenPlot <plot file list>, reviews the plots in the files. See PlotDoc.tioga for more information."];
}.
CHANGE LOG.
Created by: SChen in Cedar5.
SChen, July 22, 1985 6:22:31 pm PDT, => Cedar6.0.