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 = { 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]; EXITS skip => NULL; }; -- end ConstructInner BEGIN ENABLE BEGIN ABORTED => { errors _ errors.SUCC; log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]]; }; Int.AbortDF => { errors _ errors.SUCC; log.Put[IO.rope["Error: ABORT looking at "], IO.rope[dfFile], IO.rope["\n"]]; CONTINUE }; END; 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.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 = { 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. °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 PROC[ref1: REF ANY, ref2: REF ANY] RETURNS [Comparison]; START Construct HERE We would like to RESUME at this point, but until ABORTED is redeclared as a SIGNAL, it won't work. 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.) The list of FileDesc has now been filled. PROC [cmd: Commander.Handle] RETURNS [result: REF _ NIL, msg: Rope.ROPE _ NIL] Κ,˜šœ™Jšœ™Jšœ(™(Jšœ#™#Jšœ1™1—unitšΟk ˜ Jšœ œ!˜0Jšœ œ!˜2Jšœœ˜šœ œ˜Jšœ5˜5—šœ œ˜Jšœx˜x—Jšœœ˜Jšœœ$œ˜HJšœ œ˜,Jšœœ˜Jšœœ˜$Jšœœ1œ˜N—šœ œ˜š˜JšœEœœ&˜q—Kšœ œ%˜1Jšœœœ˜šœ œœ˜Jšœ œ˜Jšœœ˜ JšœœΟc8˜FJ˜—J˜—š Οn œœœ œœœ˜?Jšœœ˜Jšœœœœ˜SJšœ˜J˜J˜—šŸ œœ œ˜5Jšœ$œ ˜7Jšœœœœ@˜]Jšœœœ?˜MJš œœœœœœ˜*Jšœœ$˜7šΟbœ˜Jš œœœœœœ™8Jšœœ œ˜ Jšœœ œ˜ Jšœ$œ˜2Jšœ˜—šŸœœ œ8œ˜^Jšœ œœ˜$Jšœœœ˜Jšœ œ˜*š Πbn œœœœœ˜9Jšœ9˜?Jšœ˜—š ‘œœœœœ˜4Jšœ$˜*Jšœ˜—š  œ˜$Jšœ˜šœœœ˜šœ œ˜%Jšœ5˜5—šœœ˜šœœ œ ˜%Jšœ0˜0Jšœ˜Jšœ˜J˜—Jšœœ˜4J˜—šœ œ˜!JšœK˜K—Jšœœ˜—Jšœ˜—Kšœœœ2˜VJšœ œœ˜Jš œ&œœœœœ˜\šœ œ!˜.Jš œœœ)œœ˜WJ˜—Jšœ5˜5Jš œœœœœ˜=JšœN˜Nšœ3˜3šœžœ˜*Jšœœ˜šœ ˜ šœK˜KJšœœœ ˜C—Jšœ˜—Jš˜J˜—Jšœ˜Jšœ˜—J˜Jšœœ˜ š˜Jšœœ˜ —Jšœž˜—J˜J™J˜Jš˜šœ˜Jš˜šœ˜ Jšœœ˜JšœM˜MJšœœœœ™bJšœ˜—šœ˜Jšœœ˜JšœM˜MJš˜Jšœ˜—Jšœ˜—JšœΠ™Πšœ:˜šœ ˜ Jšœ4˜4Jšœœ˜/J˜—Jšœ˜ J˜—š˜šœ ˜ Jšœ=˜=Jšœœœ˜IJ˜——J˜—Jšœ˜Jšœœ˜Jšœ˜ Jšœ˜ Jšœ˜—šœW˜WJšœœ˜!—J˜ šœT˜TJšœ˜—šœ œ ˜šœ˜šœI˜IJšœœ˜"—Jšœ˜—Jšœ˜—JšœžA˜E—Jšœž ˜Jšœ˜Jšœž˜—šŸ œ˜'Jš œœ œœ œœ™NJšœ œœ˜Jšœœ˜ Jšœ#œ˜'J˜JšœHœ˜UJšœœœœ˜)Jšœœœ/˜KJ˜Jšœ˜Jšœ˜šœ œ>œ ˜\Jšœœ˜6Jšœ-˜1—J˜Jšœ ˜ Jšœ˜—šœ˜Jšœ]˜]Jšœ˜—Kšœ˜J˜—…—τ#Π