<> <> <> DIRECTORY DFUtilities USING [Date], IO USING [STREAM], Rope USING [ROPE]; GenerateDFClosure: CEDAR DEFINITIONS = BEGIN <> <<>> Date: TYPE = DFUtilities.Date; ROPE: TYPE = Rope.ROPE; STREAM: TYPE = IO.STREAM; <> <<>> ActionKind: TYPE = {file, notFound, syntaxError}; <<= file for a file in the closure>> <<= notFound for a DF file that was not found>> <<= syntaxError for a DF file with a syntax error>> ActionProc: TYPE = PROC [data: REF, kind: ActionKind, name: ROPE, date: Date, from: ROPE]; <> <> <> <> <> <> <<>> ClosureInfo: TYPE = RECORD [files: INT, dfFiles: INT, notFound: INT]; <> Options: TYPE = RECORD [ messages: BOOL _ TRUE, <> toFork: NAT _ 0, <> followImports: BOOL _ TRUE, <> serverRetries: NAT _ 10 <> ]; <> <<>> GenerateClosureToProc: PROC [dfName: ROPE, errs: STREAM, action: ActionProc, data: REF, options: Options _ []] RETURNS [info: ClosureInfo]; <<... generates the closure of files mentioned by the given DF file. Files may appear in the closure twice, although this is not frequent for well-structured DF files. For each file in the closure, the caller's action routine is invoked with the file name and other information (see above). The action routine may be invoked from as many as 1+options.toFork processes, so the client may need to be careful about concurrent actions.>> GenerateClosureToStream: PROC [dfName: ROPE, errs: STREAM, out: STREAM, options: Options _ [], verbose: BOOL _ FALSE] RETURNS [info: ClosureInfo]; <<... performs roughly the same actions as GenerateClosureToProc, except that the closure so generated is written to the given output stream (which is left open at the end). If verbose = TRUE, then information about IMPORTS and INCLUDES is also written to the file.>> END.