<<>> <> <> <> <> <> <> 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]] ~ { < pfsi.fullFName is valid>> <> < all of pfsi 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, 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 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 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]] ~ { < pfsi.fullFName is valid>> <> < all of pfsi 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 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; < 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 [""]; r ¬ Convert.RopeFromTimeRFC822[gmt !Convert.Error => GOTO Cant]; RETURN; EXITS Cant => r ¬ IO.PutFR1["", [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.