SimpleGraph.mesa
Last Edited by: SChen, June 15, 1985 7:37:41 pm PDT
Sweetsun Chen, November 7, 1985 0:19:13 am PST
DIRECTORY
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, EndOfStream, Error, GetInt, GetReal, GetRopeLiteral, int, PutF, PutFR, STREAM],
List USING [DReverse, Kill],
Graph USING [ValueList],
GraphOps USING [AddCurve, AddText, CreateGraph, SetXValues],
GraphPrivate USING [GraphHandle],
Real USING [LargestNumber],
Rope USING [Cat, Equal, Fetch, Find, IsEmpty, Length, ROPE, Substr];
SimpleGraph: CEDAR PROGRAM
IMPORTS Commander, CommandTool, Convert, FileNames, FS, GraphOps, IO, List, Rope = {
OPEN IO, Graph, GraphPrivate;
RopeList: TYPE = LIST OF Rope.ROPE;
DataError: SIGNAL[reason: Rope.ROPENIL] = CODE;
SGraph: Commander.CommandProc = {
argList: RopeList;
length: NAT;
[argList, length] ← CommandTool.ParseToList[cmd];
IF length <= 0 THEN msg ← "To plot data in files, type: SGraph <files>"
ELSE {
wDir: Rope.ROPE ← FileNames.CurrentWorkingDirectory[];
nGraphs: NAT ← 0;
maxGraphs: 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 ← maxGraphs]; -- don't change it
maxGraphs ← 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 nGraphs >= maxGraphs THEN
IO.PutFR["Note: max. %g plots for each command.", IO.int[maxGraphs]]
ELSE SimpleGraph[file.first];
nGraphs ← nGraphs + 1;
ENDLOOP;
};
ENDLOOP;
};
}; -- SGraph
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
SimpleGraph: PROC[file: Rope.ROPENIL] RETURNS[msg: Rope.ROPENIL] = {
s: IO.STREAMNIL;
buffer: REF TEXT ← RefText.Scratch[512];
tokenKind: IO.TokenKind ← tokenROPE;
token: REF TEXT;
charsSkipped: INT;
error: TokenError;
ok: BOOLTRUE;
fullName, status: Rope.ROPENIL;
nNames: INT ← 0;
names, lastName: LIST OF Rope.ROPENIL;
xList: ValueList ← NIL;
lvl, tlvl: LIST OF ValueList ← NIL;
r: REAL;
handle: GraphHandle ← NIL;
int: INT ← 0;
xmin, xmax, ymin, ymax: REAL;
IF file.IsEmpty[] THEN RETURN["No file name."];
s ← FS. StreamOpen[file ! FS.Error => {status ← error.explanation; ok ← FALSE; CONTINUE} ];
IF ok THEN {
ENABLE {
DataError => {
msg ← reason;
ok ← FALSE;
CONTINUE;
};
IO.EndOfStream => {
msg ← Rope.Cat["End of file reached", status];
ok ← FALSE;
CONTINUE;
};
IO.Error => {
msg ← Rope.Cat[
SELECT ec FROM
SyntaxError => "Syntax error",
Overflow => "Overflow in input conversion"
ENDCASE => IO.PutFR["IO Error # %g", IO.int[LOOPHOLE[ec, CARDINAL]]],
status];
ok ← FALSE;
CONTINUE;
};
ABORTED => {
msg ← "SGraph aborted. ... ";
ok ← FALSE;
CONTINUE;
};
};
DO
[tokenKind, token, charsSkipped, error] ← s.GetCedarToken[buffer];
IF error = none THEN {
IF tokenKind = tokenROPE OR tokenKind = tokenID THEN {
nl: LIST OF ROPECONS[Rope.FromRefText[token], NIL];
IF lastName = NIL THEN lastName ← names ← nl
ELSE lastName.rest ← nl;
nNames ← nNames + 1;
}
ELSE IF tokenKind = tokenCHAR OR tokenKind = tokenCOMMENT THEN LOOP
ELSE EXIT;
}
ELSE SIGNAL DataError[IO.PutFR["Error after the %g-th name.", IO.int[nNames]]];
ENDLOOP;
IF nNames = 0 THEN DataError["Can't find any names of curves."];
xmin ← ymin ← Real.LargestNumber;
xmax ← ymax ← -xmin;
FOR j: INT IN [0..nNames) DO lvl ← CONS[NIL, lvl]; ENDLOOP;
UNTIL s.EndOf[] DO
first: BOOLTRUE;
tlvl ← lvl;
FOR j: INT IN [0..nCurves] DO
ENABLE {
IO.Error => {
msg ← Rope.Cat[
SELECT ec FROM
SyntaxError => "Syntax error",
Overflow => "Overflow"
ENDCASE => IO.PutFR["IO Error # %g", IO.int[LOOPHOLE[ec, CARDINAL]]],
IO.PutFR[" in getting the %g-th number on the %g-th row in the table.",
IO.int[j+1], IO.int[i+1]]];
GOTO mistake;
};
IO.EndOfStream => {
IF j = 0 THEN GOTO finished
ELSE {
msg ← Rope.Cat[
"End of file reached",
IO.PutFR[" in getting the %g-th number on the %g-th row in the table.",
IO.int[j+1], IO.int[i+1]]];
GOTO mistake;
};
};
};
r ← s.GetReal[];
IF j = 0 THEN {
xList ← CONS[r, xList];
IF first THEN {xmin ← r; first ← FALSE}
ELSE xmax ← r;
}
ELSE {
tlvl.first ← CONS[r, tlvl.first];
ymax ← MAX[ymax, r];
ymin ← MIN[ymin, r];
tlvl ← tlvl.rest;
};
ENDLOOP;
out.PutF["."];
REPEAT
mistake => ok ← FALSE;
finished => NULL;
ENDLOOP;
};
IF ok THEN {
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]; };
};
out.PutF[" creating graph ... "];
handle ← GraphOps.CreateGraph[
bounds: [xmin, ymin, xmax, ymax],
fileName: fullName
];
[] ← GraphOps.AddText[handle: handle,
id: 0, rope: title, place: [0.5, 1.1], fontIndex: 2, justifX: center];
[] ← GraphOps.SetXValues[handle, xList];
int ← nCurves;
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, int, tlvl.first, lastName.first, int];
int ← int - 1;
tlvl ← tlvl.rest;
ENDLOOP;
TRUSTED {
List.Kill[LOOPHOLE[lvl]];
List.Kill[LOOPHOLE[names]];
};
out.PutF["done.\n"];
};
IF s # NIL THEN s.Close[];
}; -- SimpleGraph
Commander.Register[
"SGraph", SGraph,
"SGraph <data files>, use a simple minded plot routine to plot data in the data files that have the following special format:

-- comment nodes are ignored.
-- carriage returns are treated the same as spaces.
<title> -- a text string enclosed by double quotes.
<xmin> <ymin> <xmax> <ymax> -- four real numbers.
<number of curves> -- Curves are functions of x.
<names of the curves> -- Each name is a text string enclosed by double quotes.
<number of rows>
-- Each row in the table below has a leading x value followed by the corresponding y values.
-- If there are n curves then the table for m different x values will be an m x n+1 matrix as follows.
x1 y1(x1) y2(x1) y3(x1) ... yn(x1)
x2 y1(x2) y2(x2) y3(x2) ... yn(x2)
... ... ... ... ... ... ... ... ... ... ... ... ... ...
xm y1(xm) y2(xm) y3(xm) ... yn(xm)
"];
}.