-- 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; }; }.