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.