<> <> <> <> <<>> DIRECTORY DFClosure, DFUtilities, DFUtilitiesExtras, FS, Rope, RopeHash; DFClosureImpl: CEDAR PROGRAM IMPORTS DFUtilitiesExtras, FS, Rope, RopeHash EXPORTS DFClosure ~ BEGIN OPEN DFClosure; ROPE: TYPE ~ Rope.ROPE; ROPES: TYPE ~ LIST OF ROPE; <> EnumerateClosure: PUBLIC PROC [dfName: ROPE, private: BOOL, file: FileProc, import: ImportProc, error: ErrorProc, message: MessageProc _ NIL, data: REF _ NIL] RETURNS [dfFiles: INT] ~ { EnumerateClosureInternal: PROC [dfName: ROPE, private: BOOL] = { ProcessItem: DFUtilities.ProcessItemProc = { WITH item SELECT FROM dirItem: REF DFUtilities.DirectoryItem => lastDirectory _ dirItem; fileItem: REF DFUtilities.FileItem => { IF (alreadyFetchedPublic AND NOT lastDirectory.exported) OR lastDirectory.exported OR private THEN file[data, fileItem.name, fileItem.date, lastDirectory.path1, lastDirectory.exported]; }; importsItem: REF DFUtilities.ImportsItem => SELECT import[data, importsItem.path1, importsItem.date, importsItem.exported] FROM public => EnumerateClosureInternal[importsItem.path1, FALSE]; all => EnumerateClosureInternal[importsItem.path1, TRUE]; same => EnumerateClosureInternal[importsItem.path1, private]; none => {}; ENDCASE => ERROR; includeItem: REF DFUtilities.IncludeItem => EnumerateClosureInternal[includeItem.path1, private]; ENDCASE => ERROR; }; alreadyFetchedPublic: BOOL _ FALSE; lastDirectory: REF DFUtilities.DirectoryItem _ NIL; fullDFName: ROPE = ShortToFullMapping[shortToFull, dfName ! FS.Error => {errorMsg _ error.explanation; GOTO FSFailed}]; IF Member[IF private THEN fullWithAll ELSE fullWithPublic, fullDFName] THEN RETURN; IF NOT private AND Member[fullWithAll, fullDFName] THEN RETURN; dfFiles _ dfFiles + 1; IF private THEN fullWithAll _ CONS [fullDFName, fullWithAll] ELSE fullWithPublic _ CONS [fullDFName, fullWithPublic]; alreadyFetchedPublic _ private AND Member[fullWithPublic, fullDFName]; IF message#NIL THEN message[data, Rope.Cat["Considering ", fullDFName, IF private THEN IF alreadyFetchedPublic THEN " (private)" ELSE " (all)" ELSE " (public)"]]; DFUtilitiesExtras.ParseFromFile[ fullDFName, ProcessItem, [comments: FALSE, filterA: $all, filterB: IF alreadyFetchedPublic THEN $private ELSE $all, filterC: $all, list: NIL] ! FS.Error => {errorMsg _ error.explanation; GOTO FSFailed}; DFUtilitiesExtras.FileSyntaxError => {errorMsg _ reason; GOTO FileSyntaxError}]; EXITS FSFailed => error[data, notFound, errorMsg]; FileSyntaxError => error[data, syntaxError, errorMsg]; }; errorMsg: ROPE; shortToFull: REF = CreateShortToFullMapping[]; fullWithAll: LIST OF ROPE _ NIL; -- list of all the full df files fetched with recurse=all fullWithPublic: LIST OF ROPE _ NIL; -- list of all the full df files fetched with recurse=public dfFiles _ 0; EnumerateClosureInternal[dfName: dfName, private: private ! ABORTED => {error[data, aborted, "ABORTED\n"]; CONTINUE}]; }; <> Member: PROC [ropes: ROPES, rope: ROPE] RETURNS [BOOL] = { WHILE ropes#NIL DO IF Rope.Equal[ropes.first, rope, FALSE] THEN RETURN [TRUE]; ropes _ ropes.rest; ENDLOOP; RETURN [FALSE]; }; mappingSize: CARDINAL = 61; MappingArray: TYPE = ARRAY [0 .. mappingSize) OF LIST OF MappingPair; MappingPair: TYPE = RECORD [short, full: ROPE]; CreateShortToFullMapping: PUBLIC PROC RETURNS [mapping: REF] = { mapping _ NEW [MappingArray _ ALL [NIL]]; }; ShortToFullMapping: PUBLIC PROC [mapping: REF, short: ROPE] RETURNS [full: ROPE] = { map: REF MappingArray = NARROW [mapping]; hash: CARDINAL = RopeHash.FromRope[short, FALSE] MOD mappingSize; FOR pairs: LIST OF MappingPair _ map[hash], pairs.rest WHILE pairs#NIL DO IF Rope.Equal[pairs.first.short, short, FALSE] THEN RETURN [pairs.first.full]; ENDLOOP; full _ FS.FileInfo[short].fullFName; map[hash] _ CONS [[short: short, full: full], map[hash]]; }; END.