-- RStatsSupportImpl.Mesa, last edit January 3, 1983 5:34 pm
-- Pilot 6.0/ Mesa 7.0
--
-- to compute statistics
--
-- RStats -i Cedar3.1.DF
--
-- then
-- RStats -b for the bcds
-- RStats -d for the DF files
-- RStats -s for the source files
-- RStats -t for totals on # and size of files
-- RStats -x produce DF cross reference on XRef.DFXRef
DIRECTORY
CS: TYPE USING[Flat],
CWF: TYPE USING[SWF2, SWF3],
Date: TYPE USING[StringToPacked],
DFSubr: TYPE USING[DFSeq],
DFUser: TYPE USING[CleanupEnumerate, EnumerateEntries, EnumerateProcType],
Environment: TYPE USING[Comparison],
FileIO: TYPE USING[Open],
FQ: TYPE USING[FileQuery, Result],
IFSFile: TYPE USING[Close, FileHandle, GetTimes, UnableToLogin],
IO: TYPE USING[card, Close, Handle, PutChar, PutF, rope, string],
LeafSubr: TYPE USING[Open],
List: TYPE USING[CompareProc],
RStatsSupport: TYPE USING[BcdDep, DFDep, DFRec, XRef],
Rope: TYPE USING[Compare, Find, Flatten, ROPE, Text],
Stream: TYPE USING[EndOfStream, GetChar, Handle],
Subr: TYPE USING [AbortMyself, FileError, strcpy, TTYProcs],
TypeScript: TYPE USING[TS, UserAbort];
RStatsSupportImpl: PROGRAM
IMPORTS CS, CWF, Date, DFUser, FileIO, FQ, IFSFile, IO, LeafSubr, Rope,
Stream, Subr, TypeScript
EXPORTS RStatsSupport = {
LeafOpenWithCreate: PUBLIC PROC[host, directory, shortname: LONG STRING,
version: CARDINAL, createtime: LONG CARDINAL, out: IO.Handle,
tty: Subr.TTYProcs] RETURNS[fh: IFSFile.FileHandle] =
{
sfn: STRING ← [100];
IF version > 0 -- AND criterion = none -- AND createtime = 0 THEN
CWF.SWF3[sfn, "<%s>%s!%u"L, directory, shortname, @version]
ELSE
CWF.SWF2[sfn, "<%s>%s"L, directory, shortname]; -- this gets !H
fh ← LeafSubr.Open[host, sfn, tty, oldReadOnly
! IFSFile.UnableToLogin =>
IF reason = io THEN {
out.PutF["Unable to analyze - no Leaf server on %s.\n",
IO.string[host]];
GOTO err;
};
];
IF createtime ~= 0 AND IFSFile.GetTimes[fh].create ~= createtime THEN {
fres: FQ.Result;
remoteVersion: CARDINAL;
targetFileName: STRING ← [125];
IFSFile.Close[fh];
[fres: fres, remoteVersion: remoteVersion] ← FQ.FileQuery[host, directory,
shortname, version, createtime, FALSE, tty, targetFileName];
SELECT fres FROM
foundCorrectVersion => {
CWF.SWF3[sfn, "<%s>%s!%u"L, directory, shortname, @remoteVersion];
fh ← LeafSubr.Open[host, sfn, tty, oldReadOnly];
};
foundWrongVersion =>
ERROR Subr.FileError[wrongVersion];
notFound =>
ERROR Subr.FileError[notFound];
ENDCASE => ERROR;
};
EXITS
err => RETURN[NIL];
};
BreakUp: PUBLIC PROC[line: Rope.ROPE] RETURNS[filename: Rope.Text, create: LONG CARDINAL] =
{
pos: INT ← Rope.Find[line, " "];
IF pos < 0 THEN {
filename ← CS.Flat[line];
create ← 0;
}
ELSE {
sd: Rope.Text;
short: STRING ← [100];
filename ← Rope.Flatten[line, 0, pos];
sd ← Rope.Flatten[line, pos+1];
Subr.strcpy[short, LOOPHOLE[sd]];
create ← Date.StringToPacked[short];
};
};
CompareDFRec: PUBLIC List.CompareProc = CHECKED {
da, db: REF RStatsSupport.DFRec;
compare: Environment.Comparison;
da ← NARROW[ref1];
db ← NARROW[ref2];
-- assumes Rope.Compare and List.Comparison use same return values
compare ← Rope.Compare[da.shortname, db.shortname, FALSE];
IF compare = equal THEN
compare ← Rope.Compare[da.directory, db.directory, FALSE];
RETURN[compare];
};
CompareDFDep: PUBLIC List.CompareProc = CHECKED {
da, db: REF RStatsSupport.DFDep;
compare: Environment.Comparison;
da ← NARROW[ref1];
db ← NARROW[ref2];
-- assumes Rope.Compare and List.Comparison use same return values
compare ← Rope.Compare[da.shortname, db.shortname, FALSE];
IF compare = equal THEN {
IF da.createtime ~= 0 THEN
compare ← IF da.createtime < db.createtime THEN less
ELSE IF da.createtime = db.createtime THEN equal
ELSE greater
ELSE compare ← Rope.Compare[da.directory, db.directory, FALSE];
};
RETURN[compare];
};
CompareBcdDep: PUBLIC List.CompareProc = CHECKED {
da, db: REF RStatsSupport.BcdDep;
compare: Environment.Comparison;
da ← NARROW[ref1];
db ← NARROW[ref2];
-- assumes Rope.Compare and List.Comparison use same return values
compare ← CompareDFRec[da.dfrec, db.dfrec];
IF compare = equal THEN
compare ← Rope.Compare[da.bcdName, db.bcdName, FALSE];
RETURN[compare];
};
CompareXRef: PUBLIC List.CompareProc = CHECKED {
da, db: REF RStatsSupport.XRef;
compare: Environment.Comparison;
da ← NARROW[ref1];
db ← NARROW[ref2];
-- assumes Rope.Compare and List.Comparison use same return values
compare ← Rope.Compare[da.shortname, db.shortname, FALSE];
IF compare = equal THEN
compare ← Rope.Compare[da.dfshortname, db.dfshortname, FALSE];
RETURN[compare];
};
-- puts \n at end of line
GetLine: PUBLIC PROC[sh: Stream.Handle, line: LONG STRING, out: IO.Handle]
RETURNS[noteof: BOOL] = {
i: CARDINAL ← 0;
ch: CHAR;
DO
IF i >= line.maxlength THEN EXIT;
ch ← Stream.GetChar[sh
! Stream.EndOfStream => EXIT
];
line[i] ← ch;
IF line[i] = '\000 AND i > 0 AND line[i-1] = '\000 THEN {
-- tioga formatting, ignore rest of document
i ← i - 1;
DO
[] ← Stream.GetChar[sh
! Stream.EndOfStream => EXIT -- from inner loop
];
ENDLOOP;
EXIT; -- from outer loop
};
i ← i + 1;
IF ch = '\n THEN EXIT;
ENDLOOP;
line.length ← i;
IF line.length >= line.maxlength THEN {
line.length ← line.maxlength;
out.PutF["GetLine-- line '%s' is too long.\n", IO.string[line]];
};
RETURN[line.length ~= 0];
};
-- code to read in DF files and produce a list of files
ComputeFileList: PUBLIC PROC[dfFileName: LONG STRING, fileListName: Rope.Text,
typeScript: TypeScript.TS, out: IO.Handle, tty: Subr.TTYProcs] =
{
file: IO.Handle;
OneFile: DFUser.EnumerateProcType =
{
file.PutF["[%s]<%s>%s", IO.string[host], IO.string[directory], IO.string[shortName]];
IF version > 0 THEN file.PutF["!%s", IO.card[version]];
IF createTime > 0 THEN file.PutF[" %t", IO.card[createTime]];
file.PutChar['\n];
IF TypeScript.UserAbort[typeScript] THEN SIGNAL Subr.AbortMyself;
};
file ← FileIO.Open[fileListName, overwrite];
DFUser.EnumerateEntries[dfFileName: dfFileName, procToCall: OneFile,
nEntriesInDFFiles: 8000, confirmBeforeOverwriting: FALSE,
printProgressMessages: TRUE, sortOption: byLongName,
tryDollars: FALSE, in: tty.in, out: tty.out, confirmData: tty.data, Confirm: tty.Confirm
! UNWIND => DFUser.CleanupEnumerate[]];
file.Close[];
out.PutF["List of files written on %s\n", IO.rope[fileListName]];
DFUser.CleanupEnumerate[];
};
-- must be delimited by non-alphabetic chars
SubString: PUBLIC PROC[line, match: LONG STRING] RETURNS[is: BOOL] =
{
is ← FALSE;
FOR i: CARDINAL IN [0 .. line.length) DO
IF line[i] = match[0] AND i + match.length <= line.length THEN
FOR j: CARDINAL IN [0 .. match.length) DO
IF line[i+j] ~= match[j] THEN EXIT;
REPEAT
FINISHED => {
f, l: CARDINAL;
f ← i-1; -- char before
l ← i+match.length; -- char after
IF (i = 0 OR (line[f] NOT IN ['A .. 'Z] AND line[f] NOT IN ['a .. 'z]))
AND
(l >= line.length OR (line[l] NOT IN ['A .. 'Z] AND line[l] NOT IN ['a .. 'z]))
THEN
RETURN[TRUE];
};
ENDLOOP;
ENDLOOP;
};
}.