DirectoryListImpl.mesa
Copyright © 1986 by Xerox Corporation. All rights reserved.
Michael Plass, January 2, 1986 6:15:23 pm PST
DIRECTORY BTree, Commander, DirectoryList, File, FS, FSBackdoor, FSDir, FSFileOps, FSName, IO, PrincOpsUtils, RefText, Rope;
DirectoryListImpl: CEDAR PROGRAM
IMPORTS BTree, Commander, File, FS, FSDir, FSName, IO, PrincOpsUtils, RefText, Rope
EXPORTS DirectoryList
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
Count: PROC [volumeName: ROPE] RETURNS [n: INT ← 0] ~ TRUSTED {
pp: FSName.ParsedFName ~ FSName.ParseCacheName[volumeName, "[]<>", FALSE].pn;
volDesc: FSFileOps.VolumeDesc ~ pp.volDesc;
Proc: UNSAFE PROC [entry: BTree.Entry] RETURNS [continue: BOOLEANTRUE] ~ {
n ← n + 1;
};
[] ← BTree.EnumerateEntries[tree: volDesc.tree, key: NIL, relation: greaterEqual, Proc: Proc]
};
GetText: UNSAFE PROC [textRep: LONG POINTER TO FSBackdoor.TextRep, text: REF TEXT] = UNCHECKED {
text.length ← textRep.length;
[] ← PrincOpsUtils.ByteBlt [
to: [ BASE[DESCRIPTOR[text]], 0, textRep.length ],
from: [ BASE[DESCRIPTOR[textRep]], 0, textRep.length ]
];
};
zzz: ROPE ~ "\377";
aaa: ROPE ~ "\000";
CommonPrefixLength: PROC [path: ROPE, sub: BOOL] RETURNS [i: NAT] ~ {
i ← Rope.Size[path];
WHILE i > 0 AND Rope.Fetch[path, i-1] # '> DO i ← i-1 ENDLOOP;
IF NOT sub THEN {
IF i>0 THEN i ← i-1;
WHILE i > 0 AND Rope.Fetch[path, i-1] # '> DO i ← i-1 ENDLOOP;
};
};
GetNextDirectory: PUBLIC PROC [path: ROPE, sub: BOOLFALSE] RETURNS [next: ROPENIL] ~ TRUSTED {
Returns next sibling if sub = FALSE
Returns first child if sub = TRUE
fullFName: ROPE;
cp: FS.ComponentPositions;
[fullFName, cp] ← FS.ExpandName[Rope.Concat[path, "*"]];
IF sub OR cp.subDirs.length # 0 THEN {
text: REF TEXT ← RefText.ObtainScratch[512];
pp: FSName.ParsedFName ~ FSName.ParseCacheName[Rope.Substr[fullFName, cp.dir.start, cp.dir.length], path, FALSE].pn;
volDesc: FSFileOps.VolumeDesc ~ pp.volDesc;
key: ROPE ← Rope.Concat[Rope.Substr[fullFName, cp.subDirs.start, cp.subDirs.length+1], IF sub THEN aaa ELSE zzz];
commonPrefixLength: NAT ← CommonPrefixLength[key, sub];
matchProc: UNSAFE PROC [entry: FSBackdoor.EntryPtr] RETURNS [accept, stop: BOOLEANFALSE] ~ {
name: LONG POINTER TO FSBackdoor.TextRep = @entry[entry.nameBody];
IF name.length > text.length THEN text ← NEW[TEXT[name.length]];
GetText[name, text];
IF text.length > 0 AND text[0] = '[ THEN {text.length ← 0; stop ← TRUE; RETURN};
IF text.length <= commonPrefixLength OR Rope.Run[s1: LOOPHOLE[text], s2: key, case: FALSE] < commonPrefixLength THEN {text.length ← 0; stop ← TRUE; RETURN};
stop ← Rope.Find[s1: LOOPHOLE[text], s2: ">", pos1: commonPrefixLength] >= 0;
};
newLength: NAT;
FSDir.EnumerateEntries[vDesc: volDesc, start: Rope.Flatten[key], versions: bangLOnly, matchProc: matchProc, acceptProc: NIL];
newLength ← MIN[commonPrefixLength, text.length];
WHILE newLength < text.length AND text[newLength] # '> DO newLength ← newLength+1 ENDLOOP;
IF newLength < text.length THEN newLength ← newLength+1;
text.length ← newLength;
WHILE text.length > 0 AND text[text.length-1] # '> DO text.length ← text.length - 1 ENDLOOP;
IF text.length <= commonPrefixLength OR Rope.Run[s1: LOOPHOLE[text], pos1: 0, s2: fullFName, pos2: cp.subDirs.start, case: FALSE] < commonPrefixLength THEN text.length ← 0;
IF text.length = Rope.Size[key]-1 AND Rope.Run[s1: LOOPHOLE[text], s2: key, case: FALSE] = text.length THEN text.length ← 0;
IF text.length > 0 THEN {
next ← Rope.Concat[Rope.Substr[fullFName, 0, cp.dir.start + cp.dir.length+1], Rope.FromRefText[text]];
};
RefText.ReleaseScratch[text];
};
};
RemoveSubDir: PUBLIC PROC [path: ROPE] RETURNS [ROPE] ~ {
FOR i: INT DECREASING IN [0..Rope.Size[path]-1) DO
IF Rope.Fetch[path, i] = '> THEN RETURN [Rope.Substr[path, 0, i+1]];
ENDLOOP;
RETURN [NIL];
};
Levels: PROC [dir: ROPE] RETURNS [levels: NAT ← 0] ~ {
FOR i: INT IN [0..Rope.Size[dir]) DO
IF Rope.Fetch[dir, i] = '> THEN levels ← levels + 1;
ENDLOOP;
};
GetNext: PUBLIC PROC [path: ROPE, levelClip: NATNAT.LAST] RETURNS [next: ROPENIL] ~ {
level: NAT ← Levels[path];
IF levelClip >= level THEN {
next ← GetNextDirectory[path, TRUE];
}
ELSE {
WHILE levelClip+1 < level DO
path ← RemoveSubDir[path];
level ← level - 1;
ENDLOOP;
};
WHILE Rope.Size[next] = 0 AND Rope.Size[path] # 0 DO
next ← GetNextDirectory[path, FALSE];
IF next = NIL THEN path ← RemoveSubDir[path];
ENDLOOP;
};
DirCommand: Commander.CommandProc ~ {
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
n: NATLAST[NAT];
system: File.Volume ~ File.SystemVolume[];
n ← MIN[MAX[IO.GetInt[stream: IO.RIS[cmd.commandLine] ! IO.EndOfStream, IO.Error => CONTINUE], 0], n];
FOR volume: File.Volume ← File.NextVolume[NIL, FALSE], File.NextVolume[volume, FALSE] UNTIL volume = NIL DO
dir: ROPE ← Rope.Cat["[]<", IF volume # system THEN File.LogicalInfo[volume].name ELSE NIL, ">"];
WHILE Rope.Size[dir] # 0 DO
IO.PutRope[cmd.out, dir];
IO.PutChar[cmd.out, '\n];
dir ← GetNext[dir, n];
ENDLOOP;
ENDLOOP;
};
SubDirCommand: Commander.CommandProc ~ {
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
n: INTEGER ← 9999;
dir, wd: ROPENIL;
dir ← FS.ExpandName["*"].fullFName;
dir ← Rope.Substr[dir, 0, Rope.Size[dir]-1];
n ← MIN[MAX[IO.GetInt[stream: IO.RIS[cmd.commandLine] ! IO.EndOfStream, IO.Error => CONTINUE], -n], n];
IF n < 0 THEN {
THROUGH [0..-n) WHILE Levels[dir] > 1 DO dir ← RemoveSubDir[dir] ENDLOOP;
n ← 1;
};
n ← MAX[n + Levels[dir] - 1, 0];
wd ← dir;
WHILE Rope.Run[s1: dir, s2: wd, case: FALSE] = Rope.Size[wd] DO
IO.PutRope[cmd.out, dir];
IO.PutChar[cmd.out, '\n];
dir ← GetNext[dir, n];
ENDLOOP;
};
Commander.Register[key: "Dir", proc: DirCommand, doc: "List local directories and subdirectories, to the depth indicated"];
Commander.Register[key: "SubDir", proc: SubDirCommand, doc: "List local sub-directories of the current working directory, to the relative depth indicated"];
END.