DIRECTORY
Atom USING [ MakeAtom ],
Commander USING [ Register, CommandProc ],
CommanderOps USING [ GetProp, NextArgument ],
IO,
LoganBerry USING [ Error, LogInfo, IndexInfo, SchemaInfo, Describe, nullDB, OpenDB, Open ],
Rope USING [ Concat, Equal, Fetch, Find, Length, ROPE, Substr ],
PFS USING [ ErrorGroup, Error, PATH, PathFromRope, FileInfo, RopeFromPath, StreamOpen ],
PFSNames USING [ ComponentRope, Directory, ShortName ],
SymTab USING [ Create, Erase, Fetch, Ref, Store ],
UserProfile USING [ Token ],
WalnutOps USING [ ValidOpsHandle ],
WalnutWindow USING [ WalnutHandle, GetHandleList, Shutdown, StartUp ]
;
WalnutUtilsImpl:
CEDAR
PROGRAM
IMPORTS Atom, Commander, CommanderOps,
IO, LoganBerry, Rope,
PFS, PFSNames, SymTab, UserProfile, WalnutWindow, WalnutOps ~ {
OPEN IO;
ROPE: TYPE ~ Rope.ROPE;
WalnutFileInfo: TYPE ~ REF WalnutFileInfoBody;
WalnutFileInfoBody:
TYPE ~
RECORD [
rootFileName: ROPE,
logFileName: ROPE,
dbName: ROPE,
lbLogFileName: ROPE,
indexNames: LIST OF IndexInfo
];
IndexInfo: TYPE ~ REF IndexInfoBody;
IndexInfoBody:
TYPE ~
RECORD [
key: ATOM,
fileName: ROPE
];
wfis: SymTab.Ref;
FileExists:
PROC[name: Rope.
ROPE]
RETURNS [exists:
BOOL¬
TRUE] ~ {
gotName: BOOL¬FALSE;
[] ¬
PFS.FileInfo[name:
PFS.PathFromRope[name]!
PFS.Error =>
IF error.group=$user
AND error.code=$unknownFile
THEN
{
exists¬FALSE; CONTINUE}];
};
GetTwiddleFile:
PROC[name: Rope.
ROPE]
RETURNS [baseExists: BOOL¬TRUE, twiddleName: Rope.ROPE] ~ {
IF ~FileExists[name] THEN RETURN[FALSE, NIL];
twiddleName ¬ name;
WHILE
TRUE
DO
twiddleName ¬ twiddleName.Concat["~"];
IF ~FileExists[twiddleName] THEN RETURN;
ENDLOOP;
};
FindTemp: Commander.CommandProc ~ {
baseExists: BOOL;
res: Rope.ROPE;
base: Rope.ROPE;
[baseExists, res] ¬ GetTwiddleFile[CommanderOps.NextArgument[cmd]];
IF baseExists
THEN {
result ¬ res;
IO.PutRope[cmd.out, res];
}
ELSE {
result ¬ $Failure;
msg ¬ "No such file"
}
};
Wait: Commander.CommandProc ~ {
[] ¬ WalnutOps.ValidOpsHandle[NIL];
};
CloseAll: Commander.CommandProc ~ {
hl: LIST OF WalnutWindow.WalnutHandle ¬ WalnutWindow.GetHandleList[];
FOR l:
LIST
OF WalnutWindow.WalnutHandle ¬ hl, l.rest
WHILE l#
NIL
DO
WalnutWindow.Shutdown[l.first];
ENDLOOP;
};
DirectoryOf: Commander.CommandProc ~ {
fileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
filePath: PFS.PATH ¬ PFS.FileInfo[PFS.PathFromRope[fileName]].fullFName;
IO.PutRope[cmd.out, PFS.RopeFromPath[PFSNames.Directory[filePath]]];
};
DirectoryIfGiven: Commander.CommandProc ~ {
fileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
filePath: PFS.PATH ¬ PFS.PathFromRope[fileName];
fileName ¬ PFS.RopeFromPath[PFSNames.Directory[filePath]];
IF fileName = NIL OR fileName.Length[] = 0 THEN fileName ¬ "./";
IO.PutRope[cmd.out, fileName];
};
DefaultDirectory: Commander.CommandProc ~ {
fileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
filePath: PFS.PATH;
defaultDirectory: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
IF fileName=
NIL
OR defaultDirectory=
NIL
THEN
RETURN[$Failure, "Usage: DefaultDirectory <fileName> <defaultDirectory>"];
filePath ¬ PFS.PathFromRope[fileName];
fileName ¬ PFS.RopeFromPath[PFSNames.Directory[filePath]];
IF fileName = NIL OR fileName.Length[] = 0 THEN fileName ¬ defaultDirectory;
IO.PutRope[cmd.out, fileName];
};
ShortNameOf: Commander.CommandProc ~ {
filePath: PFS.PATH ¬ PFS.PathFromRope[CommanderOps.NextArgument[cmd]];
shortName: Rope.ROPE ¬ PFSNames.ComponentRope[PFSNames.ShortName[filePath]];
IO.PutRope[cmd.out, shortName];
};
DefaultExtension: Commander.CommandProc ~ {
fileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
defaultExtension: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
index: INT;
IF fileName=
NIL
OR defaultExtension=
NIL
THEN
RETURN[$Failure, "Usage: DefaultExtension <fileName> <defaultExtension>"];
index ¬ Rope.Find[fileName, "."];
IF index=-1 THEN fileName ¬ IO.PutFR["%g.%g", rope[fileName], rope[defaultExtension]]
ELSE IF index=fileName.Length[]-1 THEN fileName ¬ fileName.Concat[defaultExtension];
IO.PutRope[cmd.out, fileName];
};
BaseName: Commander.CommandProc ~ {
index: INT;
shortName: Rope.ROPE;
filePath: PFS.PATH;
fileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
IF fileName=
NIL
THEN
RETURN[$Failure, "Usage: BaseName <fileName>"];
filePath ¬ PFS.PathFromRope[fileName];
shortName ¬ PFSNames.ComponentRope[PFSNames.ShortName[filePath]];
index ¬ Rope.Find[shortName, "."];
IF index#-1 THEN shortName ¬ shortName.Substr[len: index];
IO.PutRope[cmd.out, shortName];
};
ScriptDefault: Commander.CommandProc ~ {
default: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
userSupplied: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
IF userSupplied=NIL OR userSupplied.Length[]=0 OR userSupplied.Equal["."] OR
userSupplied.Fetch[0] = '$ THEN userSupplied ¬ default;
IO.PutRope[cmd.out, userSupplied];
};
MakeEmptyLBLog: Commander.CommandProc ~ {
fileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
s: IO.STREAM;
IF fileName=
NIL
THEN
RETURN[$Failure, "Usage: MakeEmptyLBLog <fileName>"];
s ¬ PFS.StreamOpen[PFS.PathFromRope[fileName], $create];
s.PutChar['\377];
s.Close[];
};
WalnutFile: Commander.CommandProc ~
TRUSTED {
spec: Rope.ROPE;
resultFile: Rope.ROPE;
rootRqst: BOOL;
wfi: WalnutFileInfo;
rootFileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
IF rootFileName.Equal["."]
OR rootFileName=
NIL
THEN
rootFileName ¬ UserProfile.Token["Walnut.WalnutRootFile"];
IF rootFileName=NIL THEN { result¬$Failure; msg ¬ "no root file name"; RETURN; };
spec ¬ CommanderOps.NextArgument[cmd];
IF spec=NIL THEN spec ¬ "rootFile";
rootRqst ¬ spec.Equal["rootFile", FALSE];
IF spec.Equal["clear",
FALSE]
THEN {
IF wfis#NIL THEN SymTab.Erase[wfis]; msg ¬ "Walnut Info Cleared"; RETURN; };
IF ~rootRqst THEN wfi ¬ GetWFI[rootFileName];
IF ~rootRqst
AND wfi=
NIL
THEN {
result ¬ $Failure; msg ¬ "Walnut db file information not available; check root file and ancillary LoganBerry databases."; RETURN; };
SELECT
TRUE
FROM
rootRqst => resultFile ¬ rootFileName;
spec.Equal["lblog", FALSE]=> resultFile ¬ wfi.lbLogFileName;
spec.Equal["db", FALSE]=> resultFile ¬ wfi.dbName;
spec.Equal["log", FALSE]=> resultFile ¬ wfi.logFileName;
spec.Equal["index",
FALSE]=> {
indexKey: ATOM ¬ Atom.MakeAtom[CommanderOps.NextArgument[cmd]];
IF indexKey=NIL THEN { result ¬ $Failure; msg ¬ usage; };
FOR iList:
LIST
OF IndexInfo ¬ wfi.indexNames, iList.rest
WHILE iList#
NIL
DO
IF iList.first.key#indexKey THEN LOOP;
resultFile ¬ iList.first.fileName;
EXIT;
ENDLOOP;
};
ENDCASE => { result ¬ $Failure; msg ¬ usage; };
IF resultFile=NIL THEN { result ¬ $Failure; RETURN; };
resultFile ← PFS.RopeFromPath[PFS.FileInfo[PFS.PathFromRope[resultFile]].fullFName];
IO.PutRope[cmd.out, resultFile];
};
GetWFI:
PROC[rootFileName:
ROPE]
RETURNS [wfi: WalnutFileInfo] ~
TRUSTED {
s: IO.STREAM;
IF wfis=NIL THEN wfis ¬ SymTab.Create[case: TRUE];
wfi ¬ NARROW[SymTab.Fetch[wfis, rootFileName].val];
IF wfi#NIL THEN RETURN;
wfi ¬ NEW[WalnutFileInfoBody];
wfi.rootFileName ¬ rootFileName;
s ¬ PFS.StreamOpen[PFS.PathFromRope[rootFileName]];
WHILE ~s.EndOf[]
DO
lineBuf: REF TEXT;
key: ROPE;
lineBuf ¬ s.GetLine[lineBuf];
key ¬ LOOPHOLE[lineBuf];
SELECT
TRUE
FROM
key.Equal["Database",
FALSE] => {
db: LoganBerry.OpenDB ¬ LoganBerry.nullDB;
si: LoganBerry.SchemaInfo;
wfi.dbName ¬ s.GetLineRope[];
db ¬ LoganBerry.Open[dbName: wfi.dbName!LoganBerry.Error => CONTINUE];
IF db#LoganBerry.nullDB
THEN {
si ¬ LoganBerry.Describe[db: db];
wfi.lbLogFileName ¬ si.logs.first.file;
FOR ii:
LIST
OF LoganBerry.IndexInfo ¬ si.indices, ii.rest
WHILE ii#
NIL
DO
iInfo: IndexInfo ¬ NEW[IndexInfoBody ¬ [ii.first.key, ii.first.file]];
wfi.indexNames ¬ CONS[iInfo, wfi.indexNames];
ENDLOOP;
};
};
key.Equal["LogInfo",
FALSE] => {
logFileName: ROPE ¬ s.GetLineRope[];
lineBuf ¬ s.GetLine[lineBuf];
lineBuf ¬ s.GetLine[lineBuf];
key ¬ LOOPHOLE[lineBuf];
IF key.Fetch[0] = '0 THEN wfi.logFileName ¬ logFileName;
};
ENDCASE;
ENDLOOP;
IF wfi.dbName=NIL OR wfi.logFileName=NIL THEN RETURN[NIL];
[] ¬ wfis.Store[rootFileName, wfi];
};
StartWalnutReadOnly: Commander.CommandProc ~ {
Doesn't work at the moment because the TRUE argument to StartUp is ignored!
rootFileName: Rope.ROPE ¬ CommanderOps.NextArgument[cmd];
[]¬WalnutWindow.StartUp[rootFileName, TRUE];
};
IFFailed: Commander.CommandProc ~ {
result ¬ CommanderOps.GetProp[cmd, $Result];
IF result = $Failure THEN result ¬ NIL ELSE result ¬ $Failure;
};
usage: Rope.ROPE ¬ "Usage: WalnutFile <spec>
etc. etc. etc.";
Commander.Register["Waitt", Wait, "Wait for scavenge or whatever to finish."];
Commander.Register["CloseAll", CloseAll, "Close all Walnut windows."];
Commander.Register["WalnutRO", StartWalnutReadOnly, "Start Walnut Read Only."];
Commander.Register["FindTemp", FindTemp, "Find unused temp file name by appending ~'s to base file name."];
Commander.Register["MakeEmptyLBLog", MakeEmptyLBLog, "Create empty log file (with valid termination character in it)
Usage: MakeEmptyLBLog <filename>"];
Commander.Register["WalnutFile", WalnutFile, "Obtain specified Walnut implementation file
Usage: WalnutFile <spec>
etc. etc. etc."];
Generic functions. Should not be part of Walnut.
Commander.Register["BaseName", BaseName, "/a/b/c/d/e/f.g => f"];
Commander.Register["DefaultExtension", DefaultExtension, "Produce file name given file name and default extension, using default extension if none was supplied."];
Commander.Register["DefaultDirectory", DefaultDirectory, "Produce directory name given file name and default directory, using default directory if none was supplied."];
Commander.Register["DirectoryOf", DirectoryOf, "Produce prefix given path name"];
Commander.Register["DirectoryIfGiven", DirectoryIfGiven, "Produce prefix, if any, given path name"];
Commander.Register["ShortNameOf", ShortNameOf, "Produce short file name given path name"];
Commander.Register["ScriptDefault", ScriptDefault, "ScriptDefault <default> <supplied>; provide the <default> value if the user-<supplied> value is in one way or another null"];
Null values: NIL, "", ".", "$anything".
Commander.Register["IFFailed", IFFailed, "Fail iff previous command did not."];
}.