DIRECTORY
BasicTime USING [GetClockPulses, GMT, Pulses, PulsesToMicroseconds],
FS USING [Close, ComponentPositions, Copy, Create, Delete, Error, ErrorDesc, EnumerateForInfo, EnumerateForNames, ExpandName, GetDefaultWDir, InfoProc, NameProc, nullOpenFile, Open, OpenFile, Position, Rename, SetKeep, SetDefaultWDir],
FSBackdoor USING [EntryPtr, Enumerate, EnumerateCacheForNames, Flush, MakeFName, NameProc, ScavengeDirectoryAndCache, SetFreeboard, TextFromTextRep, VolumePages],
IO USING [BreakProc, CharsAvail, CR, CreateEditedStream, Error, GetChar, GetInt, GetToken, LF, PutChar, PutF, PutFR, PutRope, Signal, SP, STREAM, TAB],
List USING [PutAssoc],
ProcessProps USING [AddPropList, GetPropList],
Rope USING [Concat, Equal, Fetch, Find, Flatten, Length, ROPE, Substr, Text],
SimpleTerminal USING [TurnOn];
FSTest:
CEDAR
PROGRAM
IMPORTS BasicTime, FS, FSBackdoor, IO, List, ProcessProps, Rope, SimpleTerminal
= BEGIN
in, out: IO.STREAM;
MyBreakProc:
IO.BreakProc =
BEGIN OPEN IO;
SELECT char
FROM
SP, LF, TAB => RETURN[sepr];
CR => RETURN[break];
ENDCASE => RETURN[other];
END;
Empty:
PROC [] =
BEGIN
WHILE in.CharsAvail[] DO [] ← in.GetChar[] ENDLOOP;
END;
ProcessFSError:
PROC [desc: FS.ErrorDesc]
RETURNS [acceptIt:
BOOLEAN] =
BEGIN
out.PutF[" ... FS.Error[%g]\n", [rope[desc.explanation]]];
acceptIt ← TRUE;
END;
DoIt:
PROC =
BEGIN
uneditedIn: IO.STREAM;
[uneditedIn, out] ← SimpleTerminal.TurnOn["FSTest"];
in ← IO.CreateEditedStream[in: uneditedIn, echoTo: out];
out.PutRope["\n\n"];
Commands[];
DO
ENABLE
BEGIN
IO.Signal => { IF ec = Rubout THEN {out.PutRope["\n"]; RETRY} };
IO.Error => {IF ec = StreamClosed THEN EXIT ELSE {out.PutRope["\n"]; RETRY}};
END;
cmd: Rope.ROPE;
Empty[];
out.PutChar['>];
cmd ← in.GetToken[MyBreakProc];
BEGIN
ENABLE
FS.Error =>
IF ProcessFSError[error]
THEN
CONTINUE;
SELECT
TRUE
FROM
Rope.Equal["attach", cmd, FALSE] => Attach[];
Rope.Equal["bringover", cmd, FALSE] => BringOver[];
Rope.Equal["copy", cmd, FALSE] => Copy[];
Rope.Equal["create", cmd, FALSE] => Create[];
Rope.Equal["debug", cmd, FALSE] => Debug[];
Rope.Equal["delete", cmd, FALSE] => Delete[];
Rope.Equal["flush", cmd, FALSE] => Flush[];
Rope.Equal["getWDir", cmd, FALSE] => GetWDir[];
Rope.Equal["listCache", cmd, FALSE] => ListCache[];
Rope.Equal["listInfo", cmd, FALSE] => ListInfo[];
Rope.Equal["listNames", cmd, FALSE] => ListNames[];
Rope.Equal["load", cmd, FALSE] => Load[];
Rope.Equal["pages", cmd, FALSE] => Pages[];
Rope.Equal["parseName", cmd, FALSE] => ParseName[];
Rope.Equal["rename", cmd, FALSE] => Rename[];
Rope.Equal["scavenge", cmd, FALSE] => Scavenge[];
Rope.Equal["setFreeboard", cmd, FALSE] => SetFreeboard[];
Rope.Equal["setkeep", cmd, FALSE] => SetKeep[];
Rope.Equal["setPDir", cmd, FALSE] => SetPDir[];
Rope.Equal["setWDir", cmd, FALSE] => SetWDir[];
Rope.Equal["times", cmd, FALSE] => Times[];
Rope.Equal["?", cmd, FALSE] => Commands[];
Rope.Equal["\n", cmd, FALSE] => NULL;
ENDCASE => out.PutRope[" ... ?\n"];
END;
ENDLOOP;
END;
Commands:
PROCEDURE =
BEGIN
out.PutRope["Commands are: attach, bringOver, copy, create, debug, delete, flush, getWDir, listCache, listInfo, listNames, load, pages, parseName, rename, scavenge, setFreeboard, setKeep, setPDir, setWDir and times\n"];
END;
Attach:
PROCEDURE =
BEGIN
from: Rope.ROPE = in.GetToken[MyBreakProc];
to: Rope.ROPE = in.GetToken[MyBreakProc];
FS.Copy[from: from, to: to, keep: createKeep, remoteCheck: FALSE, attach: TRUE];
END;
BringOver:
PROCEDURE =
BEGIN
attachIt:
FS.InfoProc =
BEGIN
localName: Rope.ROPE;
lastPoint, bangIndex: INT ← 0;
FOR i:
INT
DECREASING
IN [0 .. Rope.Length[fullFName])
DO
SELECT Rope.Fetch[fullFName, i]
FROM
'! => bangIndex ← i;
'> => {lastPoint ← i; EXIT};
ENDCASE;
ENDLOOP;
IF bangIndex = lastPoint + 1 THEN RETURN[TRUE]; -- skip [..]<..>!1
localName ← Rope.Substr[fullFName, lastPoint+1, bangIndex - lastPoint - 1];
out.PutF[" %g ← %g\n", [rope[localName]], [rope[fullFName]]];
FS.Copy[from: fullFName, to: localName, keep: createKeep, wantedCreatedTime: created, attach: TRUE];
RETURN[TRUE];
END;
pattern: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Length[pattern] = 0
OR
(Rope.Fetch[pattern, 0] = '[ AND Rope.Fetch[pattern,1] = ']) OR
(Rope.Fetch[pattern, 0] = '/ AND Rope.Fetch[pattern, 1] = '/)
THEN out.PutRope[" ... give a remote pattern\n"]
ELSE FS.EnumerateForInfo[pattern, attachIt];
END;
createKeep: CARDINAL ← 2;
Copy:
PROCEDURE =
BEGIN
fromName: Rope.ROPE = in.GetToken[MyBreakProc];
toName: Rope.ROPE = in.GetToken[MyBreakProc];
FS.Copy[from: fromName, to: toName, keep: createKeep];
END;
Create:
PROCEDURE =
BEGIN
name: Rope.ROPE = in.GetToken[MyBreakProc];
FS.Close[FS.Create[name: name, keep: createKeep]];
END;
GoToDebugger: SIGNAL = CODE;
Debug:
PROCEDURE =
{ SIGNAL GoToDebugger };
Delete:
PROCEDURE =
BEGIN
deleteIt:
FS.NameProc =
BEGIN
out.PutF[" deleting %g\n", [rope[fullFName]]];
FS.Delete[fullFName];
RETURN[TRUE];
END;
pattern: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Find[pattern, "*"] = -1
THEN FS.Delete[pattern]
ELSE
BEGIN
IF Rope.Find[pattern, "!"] = -1
THEN pattern ← Rope.Concat[pattern, "!L"];
FS.EnumerateForNames[pattern, deleteIt];
END
END;
Flush:
PROCEDURE =
BEGIN
flushIt: FSBackdoor.NameProc =
BEGIN
out.PutF[" flushing %g", [rope[fullGName]]];
FSBackdoor.Flush[fullGName
! FS.Error => {out.PutF[ " ... FS.Error[%g]", [rope[error.explanation]] ]; CONTINUE}];
out.PutRope["\n"];
RETURN[TRUE];
END;
pattern: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Find[pattern, "*"] = -1
THEN FSBackdoor.Flush[pattern]
ELSE FSBackdoor.EnumerateCacheForNames[flushIt, NIL, pattern];
END;
GetWDir:
PROCEDURE =
BEGIN
out.PutF[" ... default working directory is %g\n", [rope[FS.GetDefaultWDir[]]] ];
END;
ListInfo:
PROCEDURE =
BEGIN
print:
FS.InfoProc =
BEGIN
IF attachedTo = NIL
THEN out.PutF[" %g -- keep = %g, %g bytes, %g\n", [rope[fullFName]], [cardinal[keep]], [integer[bytes]], [time[created]]]
ELSE out.PutF[" %g -- keep = %g\n attached to %g -- %g bytes, %g\n", [rope[fullFName]], [cardinal[keep]], [rope[attachedTo]], [integer[bytes]], [time[created]]];
RETURN[TRUE];
END;
pattern: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Equal[pattern, "\n"] THEN pattern ← "*";
FS.EnumerateForInfo[pattern, print];
END;
ListCache:
PROCEDURE =
BEGIN
print:
UNSAFE
PROC [entry: FSBackdoor.EntryPtr]
RETURNS [accept, stop:
BOOLEAN] =
UNCHECKED
BEGIN
fullGName: Rope.ROPE = FSBackdoor.MakeFName[ FSBackdoor.TextFromTextRep[@entry[entry.nameBody]], entry.version ];
WITH e: entry^
SELECT FROM
cached => out.PutF[" %g -- used at %g\n", [rope[fullGName]], [time[e.used]]];
ENDCASE => ERROR;
RETURN[FALSE, FALSE];
END;
pattern: Rope.Text ← Rope.Flatten[in.GetToken[MyBreakProc]];
IF Rope.Equal[pattern, "\n"] THEN pattern ← "[*";
FSBackdoor.Enumerate[volName: NIL, nameBodyPattern: pattern, localOnly: FALSE, allVersions: TRUE, version: [0], matchProc: print, acceptProc: NIL];
END;
ListNames:
PROCEDURE =
BEGIN
print:
FS.NameProc =
BEGIN
out.PutF[" %g\n", [rope[fullFName]] ];
RETURN[TRUE];
END;
pattern: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Equal[pattern, "\n"] THEN pattern ← "*";
FS.EnumerateForNames[pattern, print];
END;
Load:
PROCEDURE =
BEGIN
fetch:
FS.NameProc =
BEGIN
file: FS.OpenFile ← FS.nullOpenFile;
out.PutF[" loading %g\n", [rope[fullFName]] ];
file ←
FS.Open[fullFName, read
! FS.Error => {out.PutF[ " ... FS.Error[%g] on opening %g\n", [rope[error.explanation]], [rope[fullFName]] ]; CONTINUE}];
IF file # FS.nullOpenFile THEN FS.Close[file];
RETURN[TRUE];
END;
pattern: Rope.ROPE ← in.GetToken[MyBreakProc];
FS.EnumerateForNames[pattern, fetch];
END;
Pages:
PROCEDURE =
BEGIN
volName: Rope.ROPE ← in.GetToken[MyBreakProc];
size, free, freeboard: INT;
IF Rope.Equal[volName, "\n"] THEN volName ← NIL;
[size, free, freeboard] ← FSBackdoor.VolumePages[volName];
out.PutF[" size = %g, free = %g, freeboard = %g\n", [integer[size]], [integer[free]], [integer[freeboard]] ];
END;
ParseName:
PROCEDURE =
BEGIN
MakePrintRope:
PROC [p:
FS.Position]
RETURNS [r: Rope.
ROPE] =
BEGIN
IF p.length = 0
THEN r ← IO.PutFR["[%g, 0]", [cardinal[p.start]]]
ELSE r ← Rope.Substr[fullName, p.start, p.length];
END;
cp: FS.ComponentPositions;
fullName: Rope.ROPE;
name: Rope.ROPE ← in.GetToken[MyBreakProc];
wDir: Rope.ROPE ← NIL;
IF Rope.Equal[name, "\n"]
THEN name ← NIL
ELSE
BEGIN
wDir ← in.GetToken[MyBreakProc];
IF Rope.Equal[wDir, "\n"] THEN wDir ← NIL;
END;
[fullName, cp, ] ← FS.ExpandName[name, wDir];
out.PutF[" %g\n", [rope[fullName]]];
out.PutF[" \"%g\", \"%g\", \"%g\", ",
[rope[MakePrintRope[cp.server]]],
[rope[MakePrintRope[cp.dir]]],
[rope[MakePrintRope[cp.subDirs]]]
];
out.PutF["\"%g\", \"%g\", \"%g\"\n",
[rope[MakePrintRope[cp.base]]],
[rope[MakePrintRope[cp.ext]]],
[rope[MakePrintRope[cp.ver]]]
];
END;
Rename:
PROCEDURE =
BEGIN
fromName: Rope.ROPE = in.GetToken[MyBreakProc];
toName: Rope.ROPE = in.GetToken[MyBreakProc];
FS.Rename[from: fromName, to: toName];
END;
Scavenge:
PROCEDURE =
BEGIN
volName: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Equal[volName, "\n"] THEN volName ← NIL;
FSBackdoor.ScavengeDirectoryAndCache[volName];
END;
SetFreeboard:
PROCEDURE =
BEGIN
FSBackdoor.SetFreeboard[in.GetInt[]];
END;
SetKeep:
PROCEDURE =
BEGIN
name: Rope.ROPE = in.GetToken[MyBreakProc];
FS.SetKeep[name, in.GetInt[]];
END;
SetPDir:
PROCEDURE =
BEGIN
name: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Length[name] <= 1 THEN name ← NIL;
[] ← List.PutAssoc[key: $WorkingDirectory, val: name, aList: ProcessProps.GetPropList[]];
END;
SetWDir:
PROCEDURE =
BEGIN
name: Rope.ROPE ← in.GetToken[MyBreakProc];
IF Rope.Length[name] <= 1 THEN name ← NIL;
FS.SetDefaultWDir[name];
GetWDir[];
END;
Times:
PROCEDURE =
BEGIN
start: BasicTime.Pulses;
period, count: INT;
entryProc:
UNSAFE
PROC [entry: FSBackdoor.EntryPtr]
RETURNS [accept, stop:
BOOLEAN] =
UNCHECKED
{ count ← count + 1; RETURN[FALSE, FALSE] };
nameProc:
FS.NameProc =
{ count ← count + 1; RETURN[TRUE] };
infoProc:
FS.InfoProc =
{ count ← count + 1; RETURN[TRUE] };
openProc:
FS.NameProc =
BEGIN
file: FS.OpenFile ← FS.nullOpenFile;
count ← count + 1;
file ←
FS.Open[fullFName, read
! FS.Error => CONTINUE ];
IF file # FS.nullOpenFile THEN FS.Close[file];
RETURN[TRUE];
END;
pattern: Rope.Text ← Rope.Flatten[in.GetToken[MyBreakProc]];
IF Rope.Equal[pattern, "\n"] THEN pattern ← "*";
count ← 0;
start ← BasicTime.GetClockPulses[];
FSBackdoor.Enumerate[NIL, pattern, TRUE, TRUE, [0], entryProc, NIL];
period ← BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[] - start] / 1000;
out.PutF[" enumerated %g entries in %g milliseconds\n", [integer[count]], [integer[period]]];
count ← 0;
start ← BasicTime.GetClockPulses[];
FS.EnumerateForNames[pattern, nameProc];
period ← BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[] - start] / 1000;
out.PutF[" enumerated %g names in %g milliseconds\n", [integer[count]], [integer[period]]];
count ← 0;
start ← BasicTime.GetClockPulses[];
FS.EnumerateForInfo[pattern, infoProc];
period ← BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[] - start] / 1000;
out.PutF[" enumerated %g infos in %g milliseconds\n", [integer[count]], [integer[period]]];
count ← 0;
start ← BasicTime.GetClockPulses[];
FS.EnumerateForNames[pattern, openProc];
period ← BasicTime.PulsesToMicroseconds[BasicTime.GetClockPulses[] - start] / 1000;
out.PutF[" opened %g different files in %g milliseconds\n", [integer[count]], [integer[period]]];
END;
p: PROCESS = FORK ProcessProps.AddPropList [ List.PutAssoc[key: $WorkingDirectory, val: NIL, aList: NIL], DoIt ];