VersionMapViewsImpl.mesa
Copyright Ó 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Last tweaked by Mike Spreitzer on December 18, 1990 7:22 am PST
Willie-s, March 26, 1992 11:07 am PST
Michael Plass, January 27, 1992 5:07 pm PST
Chauser, March 20, 1992 2:48 pm PST
DIRECTORY Atom, Basics, BasicTime, Convert, IO, PFS, PFSBackdoor, PFSClass, PFSNames, PFSPrefixMap, RedBlackTree, Rope, VersionMap, VersionMapDefaults, VersionMapViews;
VersionMapViewsImpl: CEDAR PROGRAM
IMPORTS Atom, BasicTime, Convert, IO, PFS, PFSBackdoor, PFSClass, PFSNames, PFSPrefixMap, RedBlackTree, Rope, VersionMap, VersionMapDefaults
EXPORTS VersionMapViews
SHARES VersionMap
=
BEGIN OPEN PFSNames, PFSClass;
nullStampArray: PACKED ARRAY [0..BYTES[VersionMap.VersionStamp]) OF BYTE ~ ALL[0];
nullStamp: VersionMap.VersionStamp ~ LOOPHOLE[nullStampArray]; --currently (February 7, 1990) the only D&P sharable way to make a null stamp
OpenMapFile: TYPE ~ REF OpenMapFileRecord;
OpenMapFileRecord: TYPE ~ RECORD [
of: PFS.OpenFile];
FSData: TYPE ~ REF FSDataRecord;
FSDataRecord: TYPE ~ RECORD [
c0: Component,
xfm, all: BOOL];
AllInfo: TYPE ~ RECORD [
stamp: VersionMap.VersionStamp ¬ nullStamp,
pfsi: PFSInfo ¬ [],
base: PATH ¬ NIL,
cl: Component ¬ []];
PFSInfo: TYPE ~ RECORD [
fullFName, attachedTo: PATH ¬ NIL,
uniqueID: UniqueID ¬ PFS.nullUniqueID,
bytes: INT ¬ -1,
mutability: PFS.Mutability ¬ immutable,
fileType: PFS.FileType ¬ PFS.tUnspecified];
VMInfo: TYPE ~ RECORD [
stamp: VersionMap.VersionStamp,
name: ROPE,
created: BasicTime.GMT];
glovar: ATOM ~ $VersionMapViewsImpl;
myKey: ROPE ~ Convert.RopeFromTime[from: BasicTime.Now[], end: seconds];
flavorX: ATOM ~ $VerMapX;
flavorTX: ATOM ~ $VerMapTX;
flavorA: ATOM ~ $VerMapA;
flavorTA: ATOM ~ $VerMapTA;
c0X: Component ~ CC[Rope.Concat["-", Atom.GetPName[flavorX]]];
c0TX: Component ~ CC[Rope.Concat["-", Atom.GetPName[flavorTX]]];
c0A: Component ~ CC[Rope.Concat["-", Atom.GetPName[flavorA]]];
c0TA: Component ~ CC[Rope.Concat["-", Atom.GetPName[flavorTA]]];
fsdX: FSData ~ NEW [FSDataRecord ¬ [c0X, FALSE, FALSE]];
fsdTX: FSData ~ NEW [FSDataRecord ¬ [c0TX, TRUE, FALSE]];
fsdA: FSData ~ NEW [FSDataRecord ¬ [c0A, FALSE, TRUE]];
fsdTA: FSData ~ NEW [FSDataRecord ¬ [c0TA, TRUE, TRUE]];
myMaintenanceProcs: MaintenanceProcs ~ NEW [MaintenanceProcsObject ¬ [
sweep: Sweep,
validate: Validate]];
myFileManipulationProcs: FileManipulationProcs ~ NEW [FileManipulationProcsObject ¬ [
delete: Delete,
enumerateForInfo: EnumerateForInfo,
enumerateForNames: EnumerateForNames,
fileInfo: FileInfo,
lookupName: Lookup,
rename: Rename,
copy: Copy,
setAttributes: SetAttributes,
setByteCountAndUniqueID: SetByteCountAndUniqueID,
setClientProperty: SetClientProperty,
getClientProperty: GetClientProperty,
enumerateClientProperties: EnumerateClientProperties,
read: Read,
write: Write,
open: Open,
close: Close,
store: Store,
retrieve: Retrieve,
attach: Attach,
getInfo: GetInfo]];
GetHandleX: PROC [fs: ROPE, flavorSpecified: BOOL] RETURNS [h: FSHandle, downMsg: ROPE] ~ {
myFSHandle: FSHandle ~ NEW [FSObject ¬ [
flavor: flavorX,
name: fs,
maintenanceProcs: myMaintenanceProcs,
procs: myFileManipulationProcs,
data: fsdX]];
RETURN [myFSHandle, NIL]};
GetHandleTX: PROC [fs: ROPE, flavorSpecified: BOOL] RETURNS [h: FSHandle, downMsg: ROPE] ~ {
myFSHandle: FSHandle ~ NEW [FSObject ¬ [
flavor: flavorTX,
name: fs,
maintenanceProcs: myMaintenanceProcs,
procs: myFileManipulationProcs,
data: fsdTX]];
RETURN [myFSHandle, NIL]};
GetHandleA: PROC [fs: ROPE, flavorSpecified: BOOL] RETURNS [h: FSHandle, downMsg: ROPE] ~ {
myFSHandle: FSHandle ~ NEW [FSObject ¬ [
flavor: flavorA,
name: fs,
maintenanceProcs: myMaintenanceProcs,
procs: myFileManipulationProcs,
data: fsdA]];
RETURN [myFSHandle, NIL]};
GetHandleTA: PROC [fs: ROPE, flavorSpecified: BOOL] RETURNS [h: FSHandle, downMsg: ROPE] ~ {
myFSHandle: FSHandle ~ NEW [FSObject ¬ [
flavor: flavorTA,
name: fs,
maintenanceProcs: myMaintenanceProcs,
procs: myFileManipulationProcs,
data: fsdTA]];
RETURN [myFSHandle, NIL]};
Delete: DeleteProc ~ {
PFSBackdoor.ProduceError[accessDenied, Rope.Concat["Can't mutate ", FmtName[h, file]]]};
EnumerateForInfo: EnumerateForInfoProc ~ {
ReportInfo: PROC [ai: AllInfo] RETURNS [continue: BOOL] ~ {
continue ¬ proc[ai.pfsi.fullFName, ai.pfsi.attachedTo, ai.pfsi.uniqueID, ai.pfsi.bytes, ai.pfsi.mutability, ai.pfsi.fileType];
RETURN};
EnumerateVMInfo[h, TRUE, TRUE, TRUE, FALSE, pattern, lbound, hbound, PFS.nullUniqueID, ReportInfo];
RETURN};
EnumerateForNames: EnumerateForNamesProc ~ {
ReportName: PROC [ai: AllInfo] RETURNS [continue: BOOL] ~ {
continue ¬ proc[ai.pfsi.fullFName];
RETURN};
EnumerateVMInfo[h, TRUE, FALSE, FALSE, FALSE, pattern, lbound, hbound, PFS.nullUniqueID, ReportName];
RETURN};
FileInfo: FileInfoProc ~ {
[[, [, attachedTo, uniqueID, bytes, mutability, fileType], , ]] ¬ Find[h, file, wantedUniqueID, [highest], FALSE, TRUE, TRUE, TRUE];
version ¬ [none];
RETURN};
Lookup: LookupNameProc ~ {
ai: AllInfo ~ Find[h, file, PFS.nullUniqueID, [highest], TRUE, FALSE, FALSE, FALSE];
RETURN [ai.pfsi.fullFName]};
Rename: RenameProc ~ {
PFSBackdoor.ProduceError[accessDenied, Rope.Concat["Can't mutate ", FmtName[h, fromFile]]]};
Copy: CopyProc ~ {
ai: AllInfo ~ Find[h, fromFile, wantedUniqueID, [highest], FALSE, TRUE, FALSE, TRUE];
ConfirmCopy: PROC [fullName: PATH, uniqueID: UniqueID] RETURNS [continue: BOOL ¬ FALSE] ~ {
continue ¬ proc[ai.pfsi.fullFName, uniqueID];
RETURN};
PFS.Copy[ai.base, toFile, ai.pfsi.uniqueID, createOptions, ConfirmCopy];
RETURN};
SetAttributes: SetAttributesProc ~ {PFSBackdoor.ProduceError[accessDenied, "can't mutate a version map file"]};
SetByteCountAndUniqueID: SetByteCountAndUniqueIDProc ~ {PFSBackdoor.ProduceError[accessDenied, "can't mutate a version map file"]};
SetClientProperty: SetClientPropertyProc ~ {PFSBackdoor.ProduceError[accessDenied, "can't mutate a version map file"]};
GetClientProperty: GetClientPropertyProc ~ {
omf: OpenMapFile ~ NARROW[file.data];
RETURN PFS.GetClientProperty[omf.of, propertyName]};
EnumerateClientProperties: EnumerateClientPropertiesProc ~ {
omf: OpenMapFile ~ NARROW[file.data];
PFS.EnumerateClientProperties[omf.of, proc];
RETURN};
Open: OpenProc ~ {
oof: OpenFile ~ NEW [OpenFileObject];
base: PATH;
iof: PFS.OpenFile;
omf: OpenMapFile;
oof.fs ¬ h;
oof.attachedTo ¬ NIL;
IF access#read THEN PFSBackdoor.ProduceError[accessDenied, "version map files may only be opened for read"];
[[, [oof.fullFName, , oof.uniqueID, oof.bytes, oof.mutability, oof.fileType], base,]] ¬ Find[h, file, wantedUniqueID, [highest], TRUE, TRUE, TRUE, TRUE];
iof ¬ PFS.Open[base, access, oof.uniqueID, checkFileType, fileType, createOptions];
omf ¬ NEW [OpenMapFileRecord ¬ [iof]];
oof.state ¬ open;
oof.data ¬ omf;
RETURN [oof]};
Read: UNSAFE PROC [h: FSHandle, file: OpenFile, filePosition, nBytes: CARD, toPtr: LONG POINTER, toStart: CARD] RETURNS [bytesRead: INT] ~ UNCHECKED {
omf: OpenMapFile ~ NARROW[file.data];
RETURN PFS.Read[omf.of, filePosition, nBytes, toPtr, toStart]};
Write: PROC [h: FSHandle, file: OpenFile, filePosition, nBytes: CARD, fromPtr: LONG POINTER, fromStart: CARD] RETURNS [bytesWritten: INT] ~ {
PFSBackdoor.ProduceError[accessDenied, "version map files may only be read"];
RETURN [-1]};
Close: CloseProc ~ {
omf: OpenMapFile ~ NARROW[file.data];
PFS.Close[omf.of]};
Store: StoreProc ~ {
PFSBackdoor.ProduceError[accessDenied, Rope.Concat["Can't mutate ", FmtName[h, file]]]};
Retrieve: RetrieveProc ~ {
ai: AllInfo;
ConfirmRetrieve: PROC[fullFName: PATH, bytes: INT, uniqueID: UniqueID] RETURNS [IO.STREAM] ~ {
RETURN proc[ai.pfsi.fullFName, bytes, uniqueID]};
ai ¬ Find[h, file, wantedUniqueID, [highest], TRUE, TRUE, FALSE, TRUE];
PFS.Retrieve[ai.base, ai.pfsi.uniqueID, ConfirmRetrieve, checkFileType, fileType];
RETURN};
Attach: AttachProc ~ {
PFSBackdoor.ProduceError[accessDenied, Rope.Concat["Can't mutate ", FmtName[h, file]]]};
GetInfo: GetInfoProc ~ {
RETURN [file.fullFName, file.attachedTo, file.uniqueID, file.bytes, file.mutability, file.fileType]};
Find: PROC [h: FSHandle, file: PATH, wantedUniqueID: UniqueID, defaultVersion: Version, mtoo, ctoo, itoo, err: BOOL] RETURNS [ai: AllInfo ¬ []] ~ {
byUID: BOOL ~ wantedUniqueID#PFS.nullUniqueID;
seenOne: BOOL ¬ FALSE;
ncl: Component ¬ file.ShortName[];
CatchInfo: PROC [thisAi: AllInfo] RETURNS [continue: BOOL] ~ {
IF seenOne THEN {
SELECT defaultVersion FROM
[highest] => NULL;
[lowest] => RETURN [TRUE];
ENDCASE => ERROR};
seenOne ¬ TRUE;
ai ¬ thisAi;
RETURN [TRUE]};
IF wantedUniqueID.host # [0, 0] OR wantedUniqueID.egmt.usecs # 0 THEN PFSBackdoor.ProduceError[unknownFile, IO.PutFLR["UID [[%g, %g], [%g, %g]] not in any version maps - only GMT + 0's exist, for %g or any file", LIST [[time[wantedUniqueID.egmt.gmt]], [cardinal[wantedUniqueID.egmt.usecs]], [cardinal[wantedUniqueID.host.a]], [cardinal[wantedUniqueID.host.b]], [rope[FmtName[h, file]]]] ]];
SELECT ncl.version.versionKind FROM
numeric, lowest, highest, next => NULL;
none => file ¬ file.SetVersionNumber[defaultVersion];
all => PFSBackdoor.ProduceError[patternNotAllowed, Rope.Cat["version pattern not allowed (", FmtName[h, file], ")"]];
ENDCASE => ERROR;
EnumerateVMInfo[h, mtoo, ctoo, itoo, TRUE, file, NIL, NIL, wantedUniqueID, CatchInfo];
IF err AND NOT seenOne THEN PFSBackdoor.ProduceError[unknownFile, Rope.Cat["no version map entry for ", FmtName[h, file], IF byUID THEN Rope.Concat[" of ", FmtTime[wantedUniqueID.egmt.gmt]] ELSE NIL]];
RETURN};
GetAiPathKey: PROC [data: REF ANY] RETURNS [REF ANY] ~ {
RETURN [data]};
CompareAiPath: PROC [k, data: REF ANY] RETURNS [c: Basics.Comparison] ~ {
ai1: REF AllInfo ~ NARROW[k];
ai2: REF AllInfo ~ NARROW[data];
c ¬ PathCompare[ai1.base, ai2.base, CompareComponentsModVersion];
RETURN};
GetAiVcKey: PROC [data: REF ANY] RETURNS [REF ANY] ~ {
RETURN [data]};
CompareAiVc: PROC [k, data: REF ANY] RETURNS [Basics.Comparison] ~ {
ai1: REF AllInfo ~ NARROW[k];
ai2: REF AllInfo ~ NARROW[data];
c: Basics.Comparison ~ CompareVersionAndTime[ai1.cl.version, ai2.cl.version, ai1.pfsi.uniqueID.egmt.gmt, ai2.pfsi.uniqueID.egmt.gmt];
RETURN [c]};
RopeAssoc: TYPE ~ REF RopeAssocPrivate;
RopeAssocPrivate: TYPE ~ RECORD [key: ROPE, data: REF ANY];
GetRAKey: PROC [data: REF ANY] RETURNS [REF ANY] ~ {
ra: RopeAssoc ~ NARROW[data];
RETURN [ra.key]};
CompareRA: PROC [k, data: REF ANY] RETURNS [Basics.Comparison] ~ {
r1: ROPE ~ NARROW[k];
ra2: RopeAssoc ~ NARROW[data];
RETURN r1.Compare[ra2.key, FALSE]};
EnumerateVMInfo: PROC [h: FSHandle, mtoo, ctoo, itoo, literal: BOOL, pattern, lbound, hbound: PATH, wantedUID: UniqueID, proc: PROC [AllInfo] RETURNS [continue: BOOL]] ~ {
fsd: FSData ~ NARROW[h.data];
IF fsd.all
THEN EnumerateAInfo[h, fsd, mtoo, ctoo, itoo, literal, pattern, lbound, hbound, wantedUID, proc]
ELSE EnumerateXInfo[h, fsd, mtoo, ctoo, itoo, literal, pattern, lbound, hbound, wantedUID, proc];
RETURN};
EnumerateAInfo: PROC [h: FSHandle, fsd: FSData, mtoo, ctoo, itoo, literal: BOOL, pattern, lbound, hbound: PATH, wantedUID: UniqueID, proc: PROC [AllInfo] RETURNS [continue: BOOL]] ~ {
mtoo => pfsi.fullFName is valid
pfsi.uniqueID is valid
itoo => all of pfsi is valid
stamp is null
byUID: BOOL ~ wantedUID # PFS.nullUniqueID;
which: ATOM;
mapList: VersionMap.MapList;
rl: VersionMap.RangeList;
cl: Component;
patterned, extremely: BOOL ¬ TRUE;
sr, qr: ROPE;
seekLen, pos: INT;
byShort, theByLong, theSorter: RedBlackTree.Table ¬ NIL;
GenFromShort: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
ra: RopeAssoc ~ NARROW[data];
byLong: RedBlackTree.Table ~ NARROW[ra.data];
RETURN [NOT ReallyGenFromShort[byLong]]};
ReallyGenFromShort: PROC [byLong: RedBlackTree.Table] RETURNS [continue: BOOL ¬ TRUE] ~ {
byAns: RedBlackTree.Table;
extremeSeen: BOOL ¬ FALSE;
eai: AllInfo ¬ [];
GenFromLong: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
apat: REF AllInfo ~ NARROW[data];
base: PATH ¬ apat.base;
PassInfo: PROC [fullFName, attachedTo: PATH, uniqueID: UniqueID, bytes: INT, mutability: PFS.Mutability, fileType: PFS.FileType] RETURNS [continue: BOOL ¬ TRUE] --PFS.InfoProc-- ~ {
IF byUID AND wantedUID # uniqueID THEN RETURN;
IF extremely THEN {
thisCl: Component ~ fullFName.ShortName[];
better: BOOL;
IF extremeSeen THEN {
cmp: Basics.Comparison ~ CompareVersionAndTime[thisCl.version, eai.cl.version, uniqueID.egmt.gmt, eai.pfsi.uniqueID.egmt.gmt];
SELECT cl.version.versionKind FROM
lowest => better ¬ cmp<equal;
highest => better ¬ cmp>=equal;
ENDCASE => ERROR}
ELSE better ¬ TRUE;
IF better THEN {
eai ¬ [base: fullFName, cl: fullFName.ShortName[], pfsi: [NIL, NIL, uniqueID, bytes, mutability, fileType], stamp: nullStamp];
extremeSeen ¬ TRUE};
}
ELSE {
rai: REF AllInfo ¬ NEW [AllInfo ¬ [base: fullFName, cl: fullFName.ShortName[], pfsi: [NIL, NIL, uniqueID, bytes, mutability, fileType], stamp: nullStamp]];
byAns.Insert[rai, rai !RedBlackTree.DuplicateKey => CONTINUE];
};
RETURN};
IF byUID AND cl.version.versionKind#all THEN {
[] ¬ APPLY[PassInfo, PFS.FileInfo[apat.base, wantedUID !PFS.Error => GOTO TryEnumerate]];
RETURN;
EXITS TryEnumerate => base ¬ base.SetVersionNumber[[all]]};
PFS.EnumerateForInfo[base, PassInfo];
RETURN};
PassAns: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
rai: REF AllInfo ~ NARROW[data];
stop ¬ PassAi[rai­];
IF stop THEN continue ¬ FALSE;
RETURN};
PassAi: PROC [ai: AllInfo] RETURNS [stop: BOOL ¬ FALSE] ~ {
IF fsd.xfm
THEN {ai.pfsi.fullFName ¬ ai.base; ai.pfsi.attachedTo ¬ NIL}
ELSE {ai.pfsi.fullFName ¬ IF mtoo THEN pattern.ReplaceShortName[ClearVersion[ai.cl]] ELSE NIL; ai.pfsi.attachedTo ¬ ai.base};
stop ¬ NOT proc[ai];
RETURN};
IF NOT extremely THEN byAns ¬ RedBlackTree.Create[GetAiVcKey, CompareAiVc];
byLong.EnumerateIncreasing[GenFromLong];
IF extremely THEN {
IF extremeSeen
THEN continue ¬ NOT PassAi[eai]
ELSE extremeSeen ¬ FALSE}
ELSE byAns.EnumerateIncreasing[PassAns];
RETURN};
IF pattern.ComponentCount[] # 3 THEN RETURN;
which ¬ Atom.MakeAtom[pattern.Fetch[1].ComponentRope[--don't want version--]];
mapList ¬ VersionMapDefaults.GetMapList[which];
IF mapList=NIL THEN RETURN;
cl ¬ pattern.ShortName[];
SELECT cl.version.versionKind FROM
numeric => RETURN;
none, all => extremely ¬ FALSE;
lowest, highest => extremely ¬ TRUE;
next => RETURN;
ENDCASE => ERROR;
sr ¬ cl.ComponentRope[--don't want version--];
seekLen ¬ sr.Length[];
pos ¬ sr.Index[s2: "*"];
patterned ¬ pos<seekLen;
IF patterned THEN {
byShort ¬ RedBlackTree.Create[GetRAKey, CompareRA];
IF literal THEN PFSBackdoor.ProduceError[patternNotAllowed, Rope.Cat["pattern not allowed (", FmtName[h, pattern], ")"]]}
ELSE theByLong ¬ RedBlackTree.Create[GetAiPathKey, CompareAiPath];
qr ¬ sr.Substr[len: pos];
rl ¬ VersionMap.ShortNameToRanges[mapList, qr];
FOR rl ¬ rl, rl.rest WHILE rl#NIL DO
r: VersionMap.Range ¬ rl.first;
FOR si: NAT ¬ r.first, si+1 WHILE si < r.map.shortNameSeq.len DO
long, short: ROPE;
thisAi: AllInfo ¬ [];
thisRa: RopeAssoc;
byLong: RedBlackTree.Table;
rai: REF AllInfo;
[thisAi.stamp, long, thisAi.pfsi.uniqueID.egmt.gmt] ¬ VersionMap.Fetch[r.map, r.map.shortNameSeq[si]];
short ¬ VersionMap.ShortName[long];
IF patterned THEN {
IF short.CompareSubstrs[len1: pos, s2: qr, case: FALSE] > equal THEN EXIT;
IF NOT Rope.Match[sr, short, FALSE] THEN LOOP}
ELSE IF NOT Rope.Equal[sr, short, FALSE] THEN EXIT;
thisAi.base ¬ PFS.PathFromRope[long !PFS.Error => PFSBackdoor.ProduceError[inconsistent, Rope.Cat["Unparseable name ", long, " from ", FmtName[h, pattern]]]];
thisAi.base ¬ thisAi.base.SetVersionNumber[[IF cl.version.versionKind=none THEN none ELSE all]];
thisAi.cl ¬ thisAi.base.ShortName[];
IF patterned THEN {
thisRa ¬ NARROW[byShort.Lookup[short]];
IF thisRa=NIL THEN byShort.Insert[NEW [RopeAssocPrivate ¬ [short, byLong ¬ RedBlackTree.Create[GetAiPathKey, CompareAiPath]]], short]
ELSE byLong ¬ NARROW[thisRa.data];
}
ELSE byLong ¬ theByLong;
rai ¬ NEW [AllInfo ¬ thisAi];
byLong.Insert[rai, rai !RedBlackTree.DuplicateKey => CONTINUE];
ENDLOOP;
ENDLOOP;
IF patterned
THEN byShort.EnumerateIncreasing[GenFromShort]
ELSE [] ¬ ReallyGenFromShort[theByLong];
RETURN};
EnumerateXInfo: PROC [h: FSHandle, fsd: FSData, mtoo, ctoo, itoo, literal: BOOL, pattern, lbound, hbound: PATH, wantedUID: UniqueID, proc: PROC [AllInfo] RETURNS [continue: BOOL]] ~ {
mtoo => pfsi.fullFName is valid
pfsi.uniqueID is valid
itoo => all of pfsi is valid
stamp is valid
byUID: BOOL ~ wantedUID # PFS.nullUniqueID;
which: ATOM;
mapList: VersionMap.MapList;
rl: VersionMap.RangeList;
cl: Component;
patterned, extremely: BOOL ¬ TRUE;
sr, qr: ROPE;
seekLen, pos: INT;
byShort, theSorter: RedBlackTree.Table ¬ NIL;
extremeSeen: BOOL ¬ FALSE;
extremeAi: AllInfo ¬ [];
AddThis: PROC [short: ROPE, thisAi: AllInfo, ok1, ok2: Basics.Comparison] ~ {
IF patterned
THEN IF extremely
THEN {
ra: RopeAssoc ¬ NARROW[byShort.Lookup[short]];
IF ra=NIL
THEN byShort.Insert[NEW [RopeAssocPrivate ¬ [short, NEW [AllInfo ¬ thisAi]]], short]
ELSE {eai: REF AllInfo ~ NARROW[ra.data];
cmp: Basics.Comparison ~ CompareVersionAndTime[thisAi.cl.version, eai.cl.version, thisAi.pfsi.uniqueID.egmt.gmt, eai.pfsi.uniqueID.egmt.gmt];
IF cmp=ok1 OR cmp=ok2 THEN eai­ ¬ thisAi};
}
ELSE {
rai: REF AllInfo ~ NEW [AllInfo ¬ thisAi];
ra: RopeAssoc ¬ NARROW[byShort.Lookup[short]];
sorter: RedBlackTree.Table;
IF ra=NIL
THEN byShort.Insert[NEW [RopeAssocPrivate ¬ [short, sorter ¬ RedBlackTree.Create[GetAiVcKey, CompareAiVc]]], short]
ELSE sorter ¬ NARROW[ra.data];
sorter.Insert[rai, rai !RedBlackTree.DuplicateKey => CONTINUE];
}
ELSE IF extremely
THEN {
IF extremeSeen THEN {
cmp: Basics.Comparison ~ CompareVersionAndTime[thisAi.cl.version, extremeAi.cl.version, thisAi.pfsi.uniqueID.egmt.gmt, extremeAi.pfsi.uniqueID.egmt.gmt];
IF cmp=ok1 OR cmp=ok2 THEN extremeAi ¬ thisAi;
}
ELSE {
extremeSeen ¬ TRUE;
extremeAi ¬ thisAi};
}
ELSE {
rai: REF AllInfo ~ NEW [AllInfo ¬ thisAi];
theSorter.Insert[rai, rai !RedBlackTree.DuplicateKey => CONTINUE];
};
RETURN};
Pass: PROC [ai: AllInfo] RETURNS [continue: BOOL] ~ {
gotUID: UniqueID ¬ ai.pfsi.uniqueID;
IF itoo THEN [, , gotUID, ai.pfsi.bytes, ai.pfsi.mutability, ai.pfsi.fileType] ¬ PFS.FileInfo[ai.base, ai.pfsi.uniqueID !PFS.Error => CONTINUE];
IF fsd.xfm
THEN {ai.pfsi.fullFName ¬ ai.base; ai.pfsi.attachedTo ¬ NIL}
ELSE {ai.pfsi.fullFName ¬ IF mtoo THEN pattern.ReplaceShortName[ClearVersion[ai.cl]] ELSE NIL; ai.pfsi.attachedTo ¬ ai.base};
RETURN proc[ai]};
IF pattern.ComponentCount[] # 3 THEN RETURN;
which ¬ Atom.MakeAtom[pattern.Fetch[1].ComponentRope[--don't want version--]];
mapList ¬ VersionMapDefaults.GetMapList[which];
IF mapList=NIL THEN RETURN;
cl ¬ pattern.ShortName[];
IF byUID THEN cl.version ¬ [all];
SELECT cl.version.versionKind FROM
numeric => RETURN;
none, all => extremely ¬ FALSE;
lowest, highest => extremely ¬ TRUE;
next => RETURN;
ENDCASE => ERROR;
sr ¬ cl.ComponentRope[--don't want version--];
seekLen ¬ sr.Length[];
pos ¬ sr.Index[s2: "*"];
patterned ¬ pos<seekLen;
IF patterned THEN {
byShort ¬ RedBlackTree.Create[GetRAKey, CompareRA];
IF literal THEN PFSBackdoor.ProduceError[patternNotAllowed, Rope.Cat["pattern not allowed (", FmtName[h, pattern], ")"]]}
ELSE IF NOT extremely THEN theSorter ¬ RedBlackTree.Create[GetAiVcKey, CompareAiVc];
qr ¬ sr.Substr[len: pos];
rl ¬ VersionMap.ShortNameToRanges[mapList, qr];
FOR rl ¬ rl, rl.rest WHILE rl#NIL DO
r: VersionMap.Range ¬ rl.first;
FOR si: NAT ¬ r.first, si+1 WHILE si < r.map.shortNameSeq.len DO
long, short: ROPE;
thisAi: AllInfo ¬ [];
[thisAi.stamp, long, thisAi.pfsi.uniqueID.egmt.gmt] ¬ VersionMap.Fetch[r.map, r.map.shortNameSeq[si]];
short ¬ VersionMap.ShortName[long];
IF patterned THEN {
IF short.CompareSubstrs[len1: pos, s2: qr, case: FALSE] > equal THEN EXIT;
IF NOT Rope.Match[sr, short, FALSE] THEN LOOP}
ELSE IF NOT Rope.Equal[sr, short, FALSE] THEN EXIT;
IF byUID AND wantedUID#thisAi.pfsi.uniqueID THEN LOOP;
thisAi.base ¬ PFS.PathFromRope[long !PFS.Error => PFSBackdoor.ProduceError[inconsistent, Rope.Cat["Unparseable name ", long, " from ", FmtName[h, pattern]]]];
thisAi.cl ¬ thisAi.base.ShortName[];
SELECT cl.version.versionKind FROM
none, all => AddThis[short, thisAi, equal, equal];
lowest => AddThis[short, thisAi, less, less];
highest => AddThis[short, thisAi, greater, equal];
numeric => ERROR;
<<numeric => SELECT thisAi.cl.version.versionKind FROM
numeric => IF cl.version.version=thisAi.cl.version.version THEN AddThis[short, thisAi, equal, equal] ELSE NULL;
ENDCASE => NULL;>>
ENDCASE => ERROR;
ENDLOOP;
ENDLOOP;
IF patterned
THEN IF extremely
THEN {
ReportExtreme: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
ra: RopeAssoc ~ NARROW[data];
eai: REF AllInfo ~ NARROW[ra.data];
stop ¬ NOT Pass[eai­];
RETURN};
byShort.EnumerateIncreasing[ReportExtreme];
}
ELSE {
ReportSorter: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
ra: RopeAssoc ~ NARROW[data];
sorter: RedBlackTree.Table ~ NARROW[ra.data];
quit: BOOL ¬ FALSE;
ReportSortee: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
rai: REF AllInfo ~ NARROW[data];
stop ¬ NOT Pass[rai­];
IF stop THEN quit ¬ TRUE;
RETURN};
sorter.EnumerateIncreasing[ReportSortee];
RETURN [quit]};
byShort.EnumerateIncreasing[ReportSorter];
}
ELSE IF extremely
THEN {
IF extremeSeen THEN [] ¬ Pass[extremeAi];
}
ELSE {
ReportSortee: PROC [data: REF ANY] RETURNS [stop: BOOL ¬ FALSE] --RedBlackTree.EachNode-- ~ {
rai: REF AllInfo ~ NARROW[data];
stop ¬ NOT Pass[rai­];
RETURN};
theSorter.EnumerateIncreasing[ReportSortee];
};
RETURN};
Sweep: SweepProc ~ {RETURN};
Validate: ValidateProc ~ {
latest: ROPE ~ NARROW[Atom.GetProp[glovar, $LatestInstance]];
IF latest # myKey THEN RETURN [TRUE, Rope.Cat["I was started ", myKey, ", but latest instance was started ", latest]];
RETURN[FALSE, NIL]};
FmtName: PROC [h: FSHandle, file: PATH] RETURNS [r: ROPE] ~ {
ENABLE PFS.Error => {r ¬ "!err in formatting name!"; CONTINUE};
fsd: FSData ~ NARROW[h.data];
file ¬ file.ReplaceComponent[0, fsd.c0];
r ¬ PFS.RopeFromPath[file];
RETURN};
FmtTime: PROC [gmt: BasicTime.GMT] RETURNS [r: ROPE] ~ {
IF gmt = BasicTime.nullGMT THEN RETURN ["<null GMT>"];
r ¬ Convert.RopeFromTimeRFC822[gmt !Convert.Error => GOTO Cant];
RETURN;
EXITS Cant => r ¬ IO.PutFR1["<unprintable time %xH>", [cardinal[LOOPHOLE[gmt]]]]};
CC: PROC [r: ROPE, v: Version ¬ [none]] RETURNS [Component] ~ {
RETURN [[name: [r, 0, r.Length], version: v]]};
CompareVersionAndTime: PROC [v1, v2: Version, t1, t2: BasicTime.GMT] RETURNS [Basics.Comparison] ~ {
SELECT BasicTime.Period[t1, t2] FROM
>0 => RETURN [less];
=0 => RETURN [equal];
<0 => RETURN [greater];
ENDCASE => ERROR;
};
CompareTime: PROC [t1, t2: BasicTime.GMT] RETURNS [cmp: Basics.Comparison] ~ {
cmp ¬ SELECT BasicTime.Period[t1, t2] FROM
>0 => less,
=0 => equal,
<0 => greater,
ENDCASE => ERROR;
RETURN};
MapViewPathFromPath: PUBLIC PROC [whichMap: ATOM, file: PATH, all: BOOL ¬ TRUE] RETURNS [PATH] ~ {
RETURN PFSNames.ConstructName[components: LIST[IF all THEN c0A ELSE c0X, CC[Atom.GetPName[whichMap]] ], absolute: TRUE].Cat[file]};
MapViewPathFromComponent: PUBLIC PROC [whichMap: ATOM, file: Component, all: BOOL ¬ TRUE] RETURNS [PATH] ~ {
RETURN PFSNames.ConstructName[components: LIST[IF all THEN c0A ELSE c0X, CC[Atom.GetPName[whichMap]], c0X ], absolute: TRUE].ReplaceShortName[file]};
MapViewPathFromRope: PUBLIC PROC [whichMap: ATOM, file: ROPE, all: BOOL ¬ TRUE] RETURNS [PATH] ~ {
fp: PATH ~ PFS.PathFromRope[file];
RETURN MapViewPathFromPath[whichMap, fp, all]};
RopeFindR: PUBLIC PROC [whichMap: ATOM, file: ROPE, all: BOOL ¬ TRUE] RETURNS [map, base: PATH ¬ NIL] ~ {
[map, base] ¬ PFS.FileInfo[MapViewPathFromRope[whichMap, file, all] !PFS.Error => CONTINUE]};
ComponentFindR: PUBLIC PROC [whichMap: ATOM, file: Component, all: BOOL ¬ TRUE] RETURNS [map, base: PATH ¬ NIL] ~ {
[map, base] ¬ PFS.FileInfo[MapViewPathFromComponent[whichMap, file, all] !PFS.Error => CONTINUE]};
PathFindR: PUBLIC PROC [whichMap: ATOM, file: PATH, all: BOOL ¬ TRUE] RETURNS [map, base: PATH ¬ NIL] ~ {
[map, base] ¬ PFS.FileInfo[MapViewPathFromPath[whichMap, file, all] !PFS.Error => CONTINUE]};
Ropifynd: PUBLIC PROC [map, base: PATH] RETURNS [rMap, rBase: ROPE] ~ {
rMap ¬ PFS.RopeFromPath[map];
rBase ¬ PFS.RopeFromPath[base];
RETURN};
PathCompare: PROC [n1, n2: PFS.PATH, Cc: PROC [c1, c2: Component] RETURNS [Basics.Comparison]] RETURNS [Basics.Comparison] ~ {
c: Basics.Comparison;
CompareBools: PROC [b1, b2: BOOL] RETURNS [Basics.Comparison] ~ {
SELECT TRUE FROM
~b1 AND b2 => RETURN[less];
b1 AND ~b2 => RETURN[greater];
ENDCASE => NULL;
RETURN[equal];
};
n1 ¬ n1.NonNIL[];
n2 ¬ n2.NonNIL[];
IF (c ¬ CompareBools[n1.IsAbsolute, n2.IsAbsolute]) # equal THEN RETURN[c];
{count1: NAT ~ n1.ComponentCount[];
count2: NAT ~ n2.ComponentCount[];
FOR p: NAT IN (0..MIN[count1, count2]) DO
IF (c ¬ Cc[n1.Fetch[p-1], n2.Fetch[p-1]]) # equal THEN RETURN[c];
ENDLOOP;
SELECT TRUE FROM
count1 < count2 => RETURN[less];
count1 > count2 => RETURN[greater];
ENDCASE => NULL;
IF count1>0 AND (c ¬ Cc[n1.ShortName[], n2.ShortName[]]) # equal THEN RETURN[c];
RETURN[CompareBools[n1.IsADirectory, n2.IsADirectory]];
}};
CompareComponentsModVersion: PROC [c1, c2: Component] RETURNS [Basics.Comparison] ~ {
SELECT Rope.CompareSubstrs[
c1.name.base, c1.name.start, c1.name.len,
c2.name.base, c2.name.start, c2.name.len, FALSE] FROM
less => RETURN[less];
equal => RETURN[equal];
greater => RETURN[greater];
ENDCASE => ERROR};
ClearVersion: PROC [c: PFSNames.Component] RETURNS [PFSNames.Component]
~ INLINE {c.version ¬ [none]; RETURN [c]};
Start: PROC ~ {
Atom.PutProp[glovar, $LatestInstance, myKey];
PFSClass.Register[flavorX, GetHandleX];
PFSClass.Register[flavorTX, GetHandleTX];
PFSClass.Register[flavorA, GetHandleA];
PFSClass.Register[flavorTA, GetHandleTA];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/p/"], translation: PFSNames.ConstructName[LIST[c0A, CC["PSource"]], TRUE, TRUE]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/px/"], translation: PFSNames.ConstructName[LIST[c0X, CC["PSource"]], TRUE, TRUE]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/r/"], translation: PFSNames.ConstructName[LIST[c0A, CC["Source"]], TRUE, TRUE]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/rx/"], translation: PFSNames.ConstructName[LIST[c0X, CC["Source"]], TRUE, TRUE]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/d/"], translation: PFSNames.ConstructName[LIST[c0A, CC["DSource"]], TRUE, TRUE]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/dx/"], translation: PFSNames.ConstructName[LIST[c0X, CC["DSource"]], TRUE, TRUE]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/VersionMapViewA/"], translation: PFS.PathFromRope["-VerMapA:/"]];
[] ¬ PFSPrefixMap.Insert[prefix: PFS.PathFromRope["/VersionMapViewX/"], translation: PFS.PathFromRope["-VerMapX:/"]];
RETURN};
Start[];
END.