DFIncludes.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
derived from Dependencies.mesa
Paul Rovner on December 3, 1983 12:52 pm
MBrown on December 17, 1983 4:15 pm
Russ Atkinson on March 11, 1985 9:16:55 pm PST
DIRECTORY
Commander USING [CommandProc, Register, Handle],
CommandTool USING [ArgumentVector, Parse, Failed],
DefaultRemoteNames USING [Get],
DFInternal USING [AbortDF, GetFileInfo, RemoteFileInfo, ReportFSError],
DFUtilities USING [Date, DirectoryItem, FileItem, Filter, IncludeItem, ParseFromStream, ProcessItemProc, RemoveVersionNumber, SyntaxError],
FS USING [Error, StreamOpen],
IO USING [card, int, Close, GetIndex, rope, STREAM, PutF, Put, PutRope],
IOClasses USING [CreateDribbleOutputStream],
List USING [CompareProc, Sort],
Process USING [CheckForAbort],
Rope USING [Compare, Concat, Equal, Find, Flatten, Length, ROPE, Run, Substr];
DFIncludes: CEDAR PROGRAM
IMPORTS Commander, CommandTool, DefaultRemoteNames, DFInternal, DFUtilities, FS, IO, IOClasses, List, Process, Rope = {
ROPE: TYPE = Rope.ROPE;
FileDesc: TYPE = RECORD [
shortName: ROPE,
path: ROPE,
parent: ROPE -- DF file containing defining occurrence of 'shortName'
];
StripPrefix: PROC [path: ROPE, prefix: ROPE] RETURNS [ROPE] = {
len: INT = Rope.Length[prefix];
IF Rope.Run[path, 0, prefix, 0, FALSE] = len THEN RETURN [Rope.Flatten[path, len]];
RETURN [path];
};
Construct: PROC [dfFile: ROPE, cmd: Commander.Handle] RETURNS [errors, warnings, filesActedUpon: INT ← 0] = {
logFileStream: IO.STREAMFS.StreamOpen[fileName: "DFIncludes.log", accessOptions: $create];
log: IO.STREAM ← IOClasses.CreateDribbleOutputStream[cmd.out, logFileStream];
listOfFileDescRefs: LIST OF REF ANYNIL;
currentPrefix: ROPE = DefaultRemoteNames.Get[].current;
Compare: List.CompareProc = {
PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Comparison];
f1: REF FileDesc = NARROW[ref1];
f2: REF FileDesc = NARROW[ref2];
RETURN[f1.shortName.Compare[f2.shortName, FALSE]];
};
ConstructInner: PROC [dfFile: ROPE, date: DFUtilities.Date, filter: DFUtilities.Filter, nestingDepth: NAT] RETURNS [finished: BOOLFALSE] = {
shortDirectoryPath: ROPENIL;
shortDfFile: ROPE ← StripDfPrefix[dfFile];
StripDfPrefix: PROC [path: ROPE] RETURNS [rest: ROPE] = {
RETURN [StripPrefix[StripPrefix[path, currentPrefix], "Top>"]];
};
StripDirPrefix: PROC [path: ROPE] RETURNS [ROPE] = {
RETURN [StripPrefix[path, currentPrefix]];
};
DoOneItem: DFUtilities.ProcessItemProc = {
Process.CheckForAbort[];
WITH item SELECT FROM
directory: REF DFUtilities.DirectoryItem =>
shortDirectoryPath ← StripDirPrefix[directory.path1];
file: REF DFUtilities.FileItem => {
desc: REF FileDesc = NEW[FileDesc ← [
shortName: DFUtilities.RemoveVersionNumber[file.name],
path: shortDirectoryPath,
parent: shortDfFile
]];
listOfFileDescRefs ← CONS[desc, listOfFileDescRefs];
};
include: REF DFUtilities.IncludeItem =>
[] ← ConstructInner[include.path1, include.date, filter, nestingDepth + 1];
ENDCASE => ERROR;
};
dfInfo: REF DFInternal.RemoteFileInfo = NEW[DFInternal.RemoteFileInfo ← [name: dfFile, date: date]];
dfStream: IO.STREAM;
DFInternal.GetFileInfo[info: dfInfo, client: NIL ! FS.Error => {errors ← errors.SUCC; GO TO skip}];
dfStream ← FS.StreamOpen[fileName: dfInfo.name
! FS.Error => {errors ← errors.SUCC; DFInternal.ReportFSError[error, dfInfo, NIL]; GO TO skip}
];
dfInfo.name ← DFUtilities.RemoveVersionNumber[dfInfo.name];
FOR i: NAT IN [1..nestingDepth] DO log.PutRope[" "] ENDLOOP;
log.Put[IO.rope["starting to look at "], IO.rope[dfInfo.name], IO.rope["\n"]];
DFUtilities.ParseFromStream[dfStream, DoOneItem, filter !
DFUtilities.SyntaxError -- [reason: ROPE]-- => {
errors ← errors.SUCC;
log.PutF[
"Error: Syntax error in '%g'[%d]: %g\NProcessing of this DF file aborted.",
IO.rope[dfInfo.name], IO.card[dfStream.GetIndex[]], IO.rope[reason]
];
CONTINUE
};
ABORTED => dfStream.Close[];
];
dfStream.Close[];
RETURN[TRUE];
EXITS skip => NULL;
};
START Construct HERE
{
ENABLE {
ABORTED => {
errors ← errors.SUCC;
log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]];
We would like to RESUME at this point, but until ABORTED is redeclared as a SIGNAL, it won't work.
};
DFInternal.AbortDF => {
errors ← errors.SUCC;
log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]];
CONTINUE
};
};
The following is a terrible cheat, since the date is technically illegal. However, the (desired!) effect is to treat a version number on 'dfFile' as truth (i.e., it won't be stripped off by DFInternal.GetFileInfo.)
IF ConstructInner[dfFile: dfFile, date: [format: $explicit], filter: [filterA: $source, filterC: $defining], nestingDepth: 0] THEN {
The list of FileDesc has now been filled.
PrintFileDesc: PROC [file: REF FileDesc] = {
out.PutF["%-30g %-20g %g\n",
IO.rope[file.shortName], IO.rope[file.parent], IO.rope[file.path]];
};
fPrev, fCurrent: REF FileDesc ← NIL;
nFiles: INT ← 0;
out: IO.STREAM = FS.StreamOpen[fileName: "DFIncludes.txt", accessOptions: $create];
out.PutF["List of DF file inclusion relationships from %g\n\n", IO.rope[dfFile]];
listOfFileDescRefs ← List.Sort[listOfFileDescRefs, Compare];
FOR l: LIST OF REF ANY ← listOfFileDescRefs, l.rest UNTIL l = NIL DO {
fCurrent ← NARROW[l.first];
IF fPrev # NIL AND fPrev.shortName.Equal[fCurrent.shortName, FALSE] THEN {
warnings ← warnings.SUCC;
IF fPrev.parent.Equal[s2: fCurrent.parent, case: FALSE]
THEN {
log.PutF[
"warning: '%g' appears more than once (via '%g')\n",
IO.rope[fPrev.shortName], IO.rope[fPrev.parent]
];
GOTO next;
}
ELSE
log.PutF[
"WARNING: '%g' appears more than once (via '%g' and '%g')\n",
IO.rope[fPrev.shortName], IO.rope[fPrev.parent], IO.rope[fCurrent.parent]
];
};
PrintFileDesc[fCurrent];
nFiles ← nFiles.SUCC;
GOTO next;
EXITS next => fPrev ← fCurrent }
ENDLOOP;
out.PutF["\nEND of list of DF file inclusion relationships from %g\n%g files listed\n",
IO.rope[dfFile], IO.int[nFiles]];
out.Close[];
log.PutF["\n***DF file inclusion relationships from %g written onto DFIncludes.txt",
IO.rope[dfFile]];
IF errors # 0 OR warnings # 0
THEN {
log.PutF["\n*** %g errors and %g warnings written onto DFIncludes.log\n",
IO.int[errors], IO.int[warnings]];
}
ELSE log.PutRope[".\n"];
}; -- end IF ConstructInner[dfFile, [format: $explicit], [], 0] THEN
}; -- ENABLE
logFileStream.Close[];
};
DoDFIncludes: Commander.CommandProc = {
PROC [cmd: Commander.Handle] RETURNS [result: REFNIL, msg: Rope.ROPENIL]
dfFileName: ROPENIL;
length: NAT;
argv: CommandTool.ArgumentVector ← NIL;
argv ← CommandTool.Parse[cmd ! CommandTool.Failed => { msg ← errorMsg; CONTINUE; }];
IF argv = NIL THEN RETURN[$Failure, msg];
IF argv.argc # 2 THEN RETURN[$Failure, "Usage: Dependencies dfFileName\n"];
dfFileName ← argv[1];
length ← dfFileName.Length[];
IF length < 4 OR (Rope.Compare[Rope.Substr[dfFileName, length - 3, 3], ".df", FALSE] # equal
AND Rope.Find[dfFileName, "!", MAX[0, length-5]] = -1)
THEN dfFileName ← Rope.Concat[dfFileName, ".df"];
[] ← Construct[dfFileName, cmd];
};
Commander.Register[
"DFIncludes", DoDFIncludes, "Build a list of df file inclusion relationships from a df file."
];
}.