DFIncludes.mesa
derived from Dependencies.mesa
Paul Rovner on December 3, 1983 12:52 pm
MBrown on December 17, 1983 4:15 pm
Russ Atkinson on February 23, 1984 3:45:33 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],
ProcessExtras 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, ProcessExtras, Rope
= BEGIN OPEN Int: DFInternal, Utils: DFUtilities;
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.STREAM ← FS.StreamOpen[fileName: "DFIncludes.log", accessOptions: $create];
log: IO.STREAM ← IOClasses.CreateDribbleOutputStream[cmd.out, logFileStream];
listOfFileDescRefs: LIST OF REF ANY ← NIL;
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: Utils.Date, filter: Utils.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: Utils.ProcessItemProc = {
ProcessExtras.CheckForAbort[];
WITH item
SELECT
FROM
directory:
REF Utils.DirectoryItem =>
shortDirectoryPath ← StripDirPrefix[directory.path1];
file:
REF Utils.FileItem => {
desc:
REF FileDesc =
NEW[FileDesc ← [
shortName: Utils.RemoveVersionNumber[file.name],
path: shortDirectoryPath,
parent: shortDfFile
]];
listOfFileDescRefs ← CONS[desc, listOfFileDescRefs];
};
include:
REF Utils.IncludeItem =>
[] ← ConstructInner[include.path1, include.date, filter, nestingDepth + 1];
ENDCASE => ERROR;
};
dfInfo: REF Int.RemoteFileInfo = NEW[Int.RemoteFileInfo ← [name: dfFile, date: date]];
dfStream: IO.STREAM;
Int.GetFileInfo[info: dfInfo, client: NIL ! FS.Error => {errors ← errors.SUCC; GO TO skip}];
dfStream ←
FS.StreamOpen[fileName: dfInfo.name
! FS.Error => {errors ← errors.SUCC; Int.ReportFSError[error, dfInfo, NIL]; GO TO skip}
];
dfInfo.name ← Utils.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"]];
Utils.ParseFromStream[dfStream, DoOneItem, filter !
Utils.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];
}; -- end ConstructInner
START Construct HERE
BEGIN
ENABLE
BEGIN
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.
};
Int.AbortDF => {
errors ← errors.SUCC;
log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]];
CONTINUE
};
END;
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 Int.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
END; -- ENABLE
logFileStream.Close[];
}; -- end Construct
DoDFIncludes: Commander.CommandProc = {
PROC [cmd: Commander.Handle] RETURNS [result: REF ← NIL, msg: Rope.ROPE ← NIL]
dfFileName: ROPE ← NIL;
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."
];
END.