GenSortedClosure.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Russ Atkinson, July 9, 1984 11:21:52 pm PDT
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: REFNIL, msg: ROPENIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
err: STREAM = cmd.err;
outName: ROPE ← "[]<>Temp>GenSortedClosure.$";
out: STREAMNIL;
fx: NAT ← 1;
lag: ROPENIL;
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, [1]];
WHILE NOT PriorityQueue.Empty[pq] DO
name: ROPENARROW[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 => {
The name from the subList is less than the current name from the list, so just remove the name from the subList. The list should not be touched.
subList ← subList.rest;
};
equal => {
The name from the subList is equal to the name from the list, so splice out the current element from the list. Also advance to the next element in the subList.
subList ← subList.rest;
current ← current.rest;
lag.rest ← current;
};
greater => {
The name from the subList is greater than the name from the list, so just leave the name from the list as it is, and advance to the next list element.
lag ← current;
current ← lag.rest;
};
ENDCASE;
ENDLOOP;
RETURN [list];
};
IF argv.argc >= 3 AND Rope.Equal["←", argv[2]] THEN {
fx ← 3;
outName ← argv[1];
};
out ← FS.StreamOpen[outName, create
! FS.Error => IF error.group # bug THEN {msg ← error.explanation; GO TO failed}
];
IF fx+1 >= argv.argc THEN GO TO usage;
IO.PutRope[err, "Output to "];
IO.PutRope[err, outName];
DumpList[RemoveNames[GenerateDir[argv[fx+1]], GenSortedClosure[argv[fx]]], 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 {
Full name not present so get it from the server (if possible)
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"];
END.