<> <> <> <> DIRECTORY Commander USING [CommandProc, Register], CommandTool USING [ArgumentVector, Failed, Parse], FS, GenerateDFClosure, IO, PriorityQueue, Rope; GenSortedClosure: CEDAR PROGRAM IMPORTS Commander, CommandTool, FS, GenerateDFClosure, IO, PriorityQueue, Rope = BEGIN LORA: TYPE = LIST OF REF ANY; ROPE: TYPE = Rope.ROPE; RopeList: TYPE = LIST OF ROPE; STREAM: TYPE = IO.STREAM; Wombat: Commander.CommandProc = { <<[cmd: Handle] RETURNS [result: REF _ NIL, msg: ROPE _ NIL]>> <> err: STREAM = cmd.err; outName: ROPE _ "[]<>Temp>GenSortedClosure.$"; out: STREAM _ NIL; fx: NAT _ 1; lag: ROPE _ NIL; argv: CommandTool.ArgumentVector _ CommandTool.Parse[cmd: cmd ! CommandTool.Failed => {msg _ errorMsg; GO TO failed}]; GenerateDir: PROC [dirName: ROPE] RETURNS [head: RopeList _ NIL] = { <<... returns a list of names provided by the enumeration of the given pattern (no error handling if the pattern is illegal).>> tail: RopeList _ NIL; eachName: FS.NameProc = { <<[fullFName: ROPE] RETURNS [continue: BOOL]>> new: RopeList _ LIST[fullFName]; continue _ TRUE; IF tail = NIL THEN head _ new ELSE tail.rest _ new; tail _ new; }; IF Rope.SkipTo[dirName, 0, "*"] = Rope.Length[dirName] THEN dirName _ Rope.Concat[dirName, "*"]; FS.EnumerateForNames[dirName, eachName]; }; GenSortedClosure: PROC [dfName: ROPE] RETURNS [head: RopeList _ NIL] = { tail: RopeList _ NIL; pq: PriorityQueue.Ref _ PriorityQueue.Predict[100, SortPred, NIL]; eachData: EachData _ NEW[EachDataRep _ [pq, err]]; [] _ GenerateDFClosure.GenerateClosureToProc[dfName, err, EachFile, eachData, [messages: TRUE, toFork: IF switches['m] THEN 2 ELSE 0, followImports: NOT switches['s]]]; WHILE NOT PriorityQueue.Empty[pq] DO name: ROPE _ NARROW[PriorityQueue.Remove[pq]]; new: RopeList _ LIST[name]; IF tail = NIL THEN head _ new ELSE tail.rest _ new; tail _ new; ENDLOOP; }; DumpList: PROC [list: RopeList, out: STREAM] = { WHILE list # NIL DO IO.PutRope[out, list.first]; IO.PutChar[out, '\n]; list _ list.rest; ENDLOOP; }; RemoveNames: PROC [list: RopeList, subList: RopeList] RETURNS [RopeList] = { <<... destructively removes names from the list that are in the subList. No alteration is made to the subList.>> lag: RopeList _ NIL; current: RopeList _ list; WHILE current # NIL AND subList # NIL DO top: ROPE = subList.first; SELECT Rope.Compare[top, current.first, FALSE] FROM less => { <> subList _ subList.rest; }; equal => { <> subList _ subList.rest; current _ current.rest; lag.rest _ current; }; greater => { <> lag _ current; current _ lag.rest; }; ENDCASE; ENDLOOP; RETURN [list]; }; ProcessSwitches: PROC [arg: ROPE] = { sense: BOOL _ TRUE; FOR index: INT IN [0..Rope.Length[arg]) DO char: CHAR _ Rope.Fetch[arg, index]; SELECT char FROM '- => LOOP; '~ => {sense _ NOT sense; LOOP}; IN ['a..'z] => switches[char] _ sense; IN ['A..'Z] => switches[char + ('a-'A)] _ sense; ENDCASE; sense _ TRUE; ENDLOOP; }; switches: PACKED ARRAY CHAR['a..'z] OF BOOL _ ALL[FALSE]; dfName: ROPE _ NIL; directory: ROPE _ NIL; FOR i: NAT IN [1..argv.argc) DO <> arg: ROPE = argv[i]; IF Rope.Length[arg] = 0 THEN LOOP; <> IF Rope.Fetch[arg, 0] = '- THEN { <> ProcessSwitches[arg]; LOOP; }; SELECT TRUE FROM Rope.Equal[arg, "_"] => {}; i+1 < argv.argc AND Rope.Equal[argv[i+1], "_"] => outName _ arg; dfName = NIL => dfName _ arg; directory = NIL => directory _ arg; ENDCASE => GO TO usage; ENDLOOP; out _ FS.StreamOpen[outName, create ! FS.Error => IF error.group # bug THEN {msg _ error.explanation; GO TO failed} ]; IO.PutRope[err, "Output to "]; IO.PutRope[err, outName]; DumpList[RemoveNames[GenerateDir[directory], GenSortedClosure[dfName]], out]; IO.PutChar[err, '\n]; IO.Close[out]; EXITS usage => { result _ $Failure; msg _ "Usage: GenSortedClosure (output _) dfName dirName\n"}; failed => {result _ $Failure}; }; EachData: TYPE = REF EachDataRep; EachDataRep: TYPE = RECORD [pq: PriorityQueue.Ref, err: STREAM]; EachFile: GenerateDFClosure.ActionProc = TRUSTED { eachData: EachData = NARROW[data]; pq: PriorityQueue.Ref = eachData.pq; IF date.format # explicit OR Rope.SkipTo[name, 0, "!"] = Rope.Length[name] THEN { <> name _ FS.FileInfo[name ! FS.Error => IF error.group # bug THEN { IO.PutRope[eachData.err, "\n"]; IO.PutRope[eachData.err, error.explanation]; GO TO bogus; } ].fullFName; }; PriorityQueue.Insert[pq, name]; EXITS bogus => {}; }; SortPred: PriorityQueue.SortPred = { <<[x: Item, y: Item, data: REF] RETURNS [BOOL]>> xx: ROPE = NARROW[x]; yy: ROPE = NARROW[y]; RETURN [Rope.Compare[xx, yy, FALSE] = less]; }; Commander.Register[key: "///Commands/GenSortedClosure", proc: Wombat, doc: "GenSortedClosure (output _) dfName dirName\n -m: multiple processes (2 helpers)\n -s: shallow (don't follow imports)"]; END. <<>>