PlotFile.mesa, Copyright (C) 1985 by Xerox Corporation. All rights reserved.
Last Edited by:
Sweetsun Chen, July 22, 1985 6:24:35 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.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 <files>"
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 {
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.
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.";
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.
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
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.
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
writing routines
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 <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.