DFIncludes.mesa
Copyright Ó 1985, 1987, 1992 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
Doug Wyatt, January 30, 1987 6:04:10 pm PST
Willie-s, January 22, 1992 6:46 pm PST
DIRECTORY
Commander USING [CommandProc, Register, Handle],
CommanderOps USING [ArgumentVector, Parse, Failed],
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, PutF1, Put, PutRope],
IOClasses USING [CreateDribbleOutputStream],
List USING [CompareProc, Sort],
Process USING [CheckForAbort],
Rope USING [Compare, Concat, Equal, Find, Flatten, Length, ROPE, Run, Substr],
SystemNames USING [CedarDir];
DFIncludes: CEDAR PROGRAM
IMPORTS Commander, CommanderOps, DFInternal, DFUtilities, FS, IO, IOClasses, List, Process, Rope, SystemNames = {
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, outFile: ROPE, cmd: Commander.Handle]
RETURNS [errors, warnings, filesActedUpon: INT ¬ 0] = {
logFileStream: IO.STREAM ¬ FS.StreamOpen[fileName: outFile, accessOptions: $create];
log: IO.STREAM ¬ IOClasses.CreateDribbleOutputStream[cmd.out, logFileStream];
listOfFileDescRefs: LIST OF REF ANY ¬ NIL;
currentPrefix: ROPE = SystemNames.CedarDir[];
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: BOOL ¬ FALSE] = {
shortDirectoryPath: ROPE ¬ NIL;
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.PutF1["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.PutF1["\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: ROPE ¬ NIL;
length: NAT;
argv: CommanderOps.ArgumentVector ¬ NIL;
outFile: ROPE;
argv ¬ CommanderOps.Parse[cmd ! CommanderOps.Failed => { msg ¬ errorMsg; CONTINUE; }];
IF argv = NIL THEN RETURN[$Failure, msg];
IF argv.argc > 3 THEN RETURN[$Failure, "Usage: Dependencies dfFileName {outFile}\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"];
IF argv.argc = 2 THEN outFile ¬ "DFIncludes.log" ELSE outFile ¬ argv[2];
[] ¬ Construct[dfFileName, outFile, cmd];
};
Commander.Register[
"DFIncludes", DoDFIncludes, "Build a list of df file inclusion relationships from a df file."
];
}.