<<>> <> <> <> <> <> <> <> <> <<>> 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 = { <> 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; }; <> { ENABLE { ABORTED => { errors ¬ errors.SUCC; log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]]; <> }; DFInternal.AbortDF => { errors ¬ errors.SUCC; log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]]; CONTINUE }; }; <> IF ConstructInner[dfFile: dfFile, date: [format: $explicit], filter: [filterA: $source, filterC: $defining], nestingDepth: 0] THEN { <> 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 = { <> 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." ]; }.