<> <> <> <<>> <<>> <> <<>> DIRECTORY Rope USING [Equal, Find, InlineFetch, Length, ROPE], PBasics USING [ByteBlt], YggDID USING [DID, EqualDIDs, ValidateDID], YggDIDMap USING [AddRootDID, CreateNewDID, DestroyDID, GetRootDIDs, RemoveRootDID], YggDIDPrivate USING [DIDRep], YggEnvironment USING [nullDID, nullTransID, Outcome, TransID], YggFixedNames USING [], YggIndex USING [], YggIndexMaint USING [AddOrRemoveIndexPattern], YggNav USING [ErrorDesc, LinkList], YggRep USING [AccurateGMT, AccurateGMTRep, Attribute, AttributeValue, Bits, BitsRep, BytesFromBits, BytesToBits, date, did, DocType, float, int, lastReservedDocType, LatchVDoc, linkMod, metaAttributeMod, noValue, rope, shortRope, SetSizeOfBits, SizeOfBits, symbolicLink, TypedPrimitiveElement, UnlatchVDoc, uninterpretedBytes, VDoc, VolatizeFromDID], YggTransaction USING [Check, CreateTrans, Finish, GetDefaultContainer, NotePossibleDocumentUpdate, SetDefaultContainer]; YggNavImpl: CEDAR MONITOR IMPORTS PBasics, Rope, YggDID, YggDIDMap, YggIndexMaint, YggRep, YggTransaction EXPORTS YggDID, YggFixedNames, YggNav ~ BEGIN <> ROPE: TYPE = Rope.ROPE; Error: PUBLIC ERROR [error: YggNav.ErrorDesc] = CODE; DID: PUBLIC TYPE ~ REF DIDRep; DIDRep: PUBLIC TYPE ~ YggDIDPrivate.DIDRep; NoBytes: YggRep.Bits; <> Contents: PUBLIC Rope.ROPE _ "$contents"; Inlinks: PUBLIC Rope.ROPE _ "$inlinks"; Outlinks: PUBLIC Rope.ROPE _ "$outlinks"; Parents: PUBLIC Rope.ROPE _ "$parents"; Children: PUBLIC Rope.ROPE _ "$children"; ParentContainers: PUBLIC Rope.ROPE _ "$parent-containers"; ChildContainers: PUBLIC Rope.ROPE _ "$child-containers"; AutoIndices: PUBLIC Rope.ROPE _ "$auto-indices"; <> IndexPrefix: PUBLIC Rope.ROPE _ "$index-"; IndexPrefixSize: PUBLIC INT _ Rope.Length[IndexPrefix]; <> DirectoryContents: PUBLIC Rope.ROPE _ "$directoryContents"; <> NFSPropertyName: PUBLIC Rope.ROPE _ "$NFSProperites"; -- NFS (UNIX) properties <> StartTransaction: PUBLIC PROC [parentTrans: YggEnvironment.TransID] RETURNS [trans: YggEnvironment.TransID] ~ { <> trans _ YggTransaction.CreateTrans[parentTrans]; }; <<>> EndTransaction: PUBLIC PROC [trans: YggEnvironment.TransID, commit: BOOL] RETURNS [ok: BOOL _ TRUE] ~ { <> outcome: YggEnvironment.Outcome; [outcome: outcome] _ YggTransaction.Finish[transID: trans, requestedOutcome: IF commit THEN commit ELSE abort]; IF outcome = commit THEN RETURN [TRUE] ELSE RETURN [FALSE]; }; <<>> CheckTransaction: PUBLIC PROC [trans: YggEnvironment.TransID] RETURNS [found: BOOL _ FALSE, active: BOOL _ FALSE, committed: BOOL _ FALSE] ~ { <> outcome: YggEnvironment.Outcome; [outcome: outcome] _ YggTransaction.Check[transID: trans]; SELECT outcome FROM active => RETURN [TRUE, TRUE, FALSE]; abort => RETURN [TRUE, FALSE, FALSE]; commit => RETURN [TRUE, FALSE, TRUE]; unknown => RETURN [FALSE, FALSE, FALSE]; suspended => RETURN [TRUE, FALSE, FALSE]; ENDCASE => ERROR; }; <> <> <<>> GetRoots: PUBLIC PROC RETURNS [roots: LIST OF DID] ~ { <> roots _ YggDIDMap.GetRootDIDs[]; }; <<>> AddRoot: PUBLIC PROC [did: DID] RETURNS [ok: BOOL _ FALSE] ~ { <> IF ~YggDID.ValidateDID[did] THEN RETURN [FALSE]; ok _ YggDIDMap.AddRootDID[did]; }; <<>> RemoveRoot: PUBLIC PROC [did: DID] RETURNS [ok: BOOL _ TRUE] ~ { <> IF ~YggDID.ValidateDID[did] THEN RETURN [FALSE]; ok _ YggDIDMap.RemoveRootDID[did]; }; <> GetTypeOfContents: PUBLIC PROC [trans: YggEnvironment.TransID, did: YggDID.DID] RETURNS [YggRep.DocType] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did]; RETURN[document.contents.docType]; }; <<>> IsDocTypeUninterpretedOK: PROC [docType: YggRep.DocType] RETURNS [ok: BOOL] ~ { IF docType # YggRep.uninterpretedBytes AND docType # YggRep.symbolicLink AND docType <= YggRep.lastReservedDocType THEN RETURN [TRUE] ELSE RETURN [FALSE]; }; GetUninterpretedContents: PUBLIC UNSAFE PROC [trans: YggEnvironment.TransID, did: DID, firstByte: CARD, byteCount: CARD, to: LONG POINTER] RETURNS [bytesMoved: CARD] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did]; [] _ YggRep.LatchVDoc[document]; IF IsDocTypeUninterpretedOK[document.contents.docType] THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; ERROR Error[[$invalidReservedType, "Attempt to access a TypedPrimitiveElement with reserved type as uninterpreted"]]; }; YggRep.BytesFromBits[bits: document.contents.bits, startByte: firstByte, block: [base: LOOPHOLE[to], startIndex: 0, count: byteCount]]; bytesMoved _ byteCount; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> GetContents: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [contents: YggRep.TypedPrimitiveElement] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did]; [] _ YggRep.LatchVDoc[document]; contents _ document.contents; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> SetUninterpretedContents: PUBLIC UNSAFE PROC [trans: YggEnvironment.TransID, did: YggDID.DID, setDocType: BOOL, docType: YggRep.DocType, firstByte: CARD, byteCount: CARD, from: LONG POINTER] RETURNS [bytesMoved: CARD] ~ { <> <> document: YggRep.VDoc; newRef: BOOL; newBits: YggRep.Bits; oldContentsBits: YggRep.Bits; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[document]; IF setDocType THEN { IF IsDocTypeUninterpretedOK[docType] THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]]; }; document.contents.docType _ docType; oldContentsBits _ NoBytes; } ELSE { IF IsDocTypeUninterpretedOK[document.contents.docType] THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]]; }; oldContentsBits _ document.contents.bits; }; [newRef: newRef, newBits: newBits] _ YggRep.BytesToBits[bits: oldContentsBits, startByte: firstByte, block: [base: LOOPHOLE[from], startIndex: 0, count: byteCount]]; IF newRef THEN document.contents.bits _ newBits; document.contentsChanged _ TRUE; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; RETURN[byteCount]; }; <<>> SetContents: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, contents: YggRep.TypedPrimitiveElement] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[document]; document.contents _ contents; document.contentsChanged _ TRUE; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> GetSize: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [size: CARD] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[document]; IF IsDocTypeUninterpretedOK[document.contents.docType] THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; ERROR Error[[$invalidReservedType, "Attempt to get the size of a TypedPrimitiveElement with reserved type as uninterpreted"]]; }; size _ YggRep.SizeOfBits[bits: document.contents.bits]; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> SetSize: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, size: CARD] ~ { <> <> document: YggRep.VDoc; newRef: BOOL; newBits: YggRep.Bits; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[document]; IF IsDocTypeUninterpretedOK[document.contents.docType] THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; ERROR Error[[$invalidReservedType, "Attempt to set a TypedPrimitiveElement with reserved type as uninterpreted"]]; }; IF YggRep.SizeOfBits[bits: document.contents.bits] # size THEN { [newRef: newRef, newBits: newBits] _ YggRep.SetSizeOfBits[bits: document.contents.bits, size: size]; IF newRef THEN document.contents.bits _ newBits; document.contentsChanged _ TRUE; }; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> <> GetProperty: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, propertyName: ROPE] RETURNS [propertyExists: BOOL _ FALSE, property: LIST OF YggRep.Attribute _ NIL] ~ { <> <> document: YggRep.VDoc; metaAttributesOnly: BOOL _ FALSE; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; IF Rope.Length[propertyName] > 0 THEN { IF Rope.InlineFetch[propertyName, 0] = '$ THEN metaAttributesOnly _ TRUE; }; document _ YggRep.VolatizeFromDID[transID: trans, did: did, metaAttributesOnly: metaAttributesOnly]; [] _ YggRep.LatchVDoc[document]; FOR aL: LIST OF YggRep.Attribute _ document.attributes, aL.rest UNTIL aL = NIL DO IF Rope.Equal[aL.first.attributeName, propertyName] THEN { property _ CONS[aL.first, property]; propertyExists _ TRUE; }; ENDLOOP; FOR aL: LIST OF YggRep.Attribute _ document.metaAttributes, aL.rest UNTIL aL = NIL DO IF Rope.Equal[aL.first.attributeName, propertyName] THEN { property _ CONS[aL.first, property]; propertyExists _ TRUE; }; ENDLOOP; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> GetAllProperties: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [properties: LIST OF YggRep.Attribute] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did]; RETURN[document.attributes]; }; <<>> ListAllProperties: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [propertyNames: LIST OF ROPE _ NIL] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did]; [] _ YggRep.LatchVDoc[document]; FOR aL: LIST OF YggRep.Attribute _ document.attributes, aL.rest UNTIL aL = NIL DO FOR pN: LIST OF ROPE _ propertyNames, pN.rest UNTIL pN = NIL DO IF Rope.Equal[aL.first.attributeName, pN.first] THEN EXIT; REPEAT FINISHED => { propertyNames _ CONS[aL.first.attributeName, propertyNames]; }; ENDLOOP; ENDLOOP; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> SetProperty: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, propertyName: ROPE, property: YggRep.Attribute, appendProperty: BOOL] ~ { <> <> document: YggRep.VDoc; somethingChanged: BOOL _ FALSE; prev: LIST OF YggRep.Attribute _ NIL; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[document]; SELECT TRUE FROM appendProperty AND property.value = NIL => NULL; -- nothing to do appendProperty AND property.value # NIL => { -- add prop to end of list somethingChanged _ TRUE; IF document.attributes = NIL THEN document.attributes _ LIST[property] ELSE { FOR aL: LIST OF YggRep.Attribute _ document.attributes, aL.rest UNTIL aL = NIL DO IF aL.rest = NIL THEN {aL.rest _ LIST[property]; EXIT}; ENDLOOP; }; }; ~appendProperty AND property.value = NIL => { -- delete all props of this name IF document.attributes = NIL THEN RETURN -- nothing to do ELSE { FOR aL: LIST OF YggRep.Attribute _ document.attributes, aL.rest UNTIL aL = NIL DO IF Rope.Equal[aL.first.attributeName, propertyName] THEN { somethingChanged _ TRUE; IF prev = NIL THEN document.attributes _ aL.rest ELSE prev.rest _ aL.rest; LOOP; }; prev _ aL; ENDLOOP; }; }; ~appendProperty AND property.value # NIL => { -- delete all props of this name and add this one somethingChanged _ TRUE; IF document.attributes = NIL THEN document.attributes _ LIST[property] ELSE { FOR aL: LIST OF YggRep.Attribute _ document.attributes, aL.rest UNTIL aL = NIL DO IF Rope.Equal[aL.first.attributeName, propertyName] THEN { somethingChanged _ TRUE; IF prev = NIL THEN document.attributes _ aL.rest ELSE prev.rest _ aL.rest; LOOP; }; prev _ aL; ENDLOOP; IF prev = NIL THEN document.attributes _ LIST[property] ELSE prev.rest _ LIST[property]; }; }; ENDCASE; IF somethingChanged THEN { FOR aC: LIST OF ROPE _ document.namesOfAttributesChanged, aC.rest UNTIL aC = NIL DO IF Rope.Equal[aC.first, propertyName] THEN EXIT; REPEAT FINISHED => { document.namesOfAttributesChanged _ CONS[propertyName, document.namesOfAttributesChanged]; }; ENDLOOP; }; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> <> <> <<>> ConstructIntTPE: PUBLIC PROC [int: INT32] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { <> <> ri: REF INT32; ri _ NEW[INT32 _ int]; property _ [YggRep.int, ri]; }; <<>> ConstructFloatTPE: PUBLIC PROC [float: REAL32] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { <> rReal: REF REAL32; rReal _ NEW[REAL32 _ float]; property _ [YggRep.float, rReal]; }; <<>> ConstructDateTPE: PUBLIC PROC [date: YggRep.AccurateGMTRep] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { <> rAccurateGMT: YggRep.AccurateGMT; rAccurateGMT _ NEW[YggRep.AccurateGMTRep _ date]; property _ [YggRep.date, rAccurateGMT]; }; <<>> ConstructShortRopeTPE: PUBLIC PROC [rope: ROPE] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { <> <> IF Rope.Find[rope, "\000"] = -1 THEN { property _ [YggRep.shortRope, rope]; } ELSE ERROR Error[[$shortRopeWithNulls, "Rope has nulls"]]; }; <<>> ConstructRopeTPE: PUBLIC PROC [rope: ROPE] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { <> property _ [YggRep.rope, rope]; }; <<>> ConstructUninterpretedBytesTPE: PUBLIC PROC [docType: YggRep.DocType, bytes: LONG POINTER, size: CARD] RETURNS [property: YggRep.TypedPrimitiveElement] ~ { <> <> nBytes: CARD; rBits: REF YggRep.BitsRep; IF IsDocTypeUninterpretedOK[docType] THEN ERROR Error[[$invalidReservedType, "Attempt to create a TypedPrimitiveElement with reserved type"]]; rBits _ NEW[YggRep.BitsRep[size]]; rBits.validBytes _ size; TRUSTED {nBytes _ PBasics.ByteBlt[ from: [blockPointer: bytes, startIndex: 0, stopIndexPlusOne: size], to: [blockPointer: LOOPHOLE[rBits, LONG POINTER] + SIZE[YggRep.BitsRep[0]], startIndex: 0, stopIndexPlusOne: size]]; }; IF nBytes # size THEN ERROR; property _ [docType, rBits]; }; <> getTypedLinks: PROC [links: LIST OF YggRep.AttributeValue, linksChanged: LIST OF YggRep.linkMod, linkType: ROPE] RETURNS [dids: LIST OF DID _ NIL] ~ { lastDIDs: LIST OF DID _ NIL; FOR linkList: LIST OF YggRep.AttributeValue _ links, linkList.rest UNTIL linkList = NIL DO IF linkType = NIL OR Rope.Equal[linkType, linkList.first.fieldName, FALSE] THEN { FOR lotpe: LIST OF YggRep.TypedPrimitiveElement _ linkList.first.valueSet, lotpe.rest UNTIL lotpe = NIL DO linkDID: DID; IF lotpe.first.docType # YggRep.did THEN ERROR; linkDID _ NARROW[lotpe.first.bits]; IF dids = NIL THEN lastDIDs _ (dids _ LIST[linkDID]) ELSE lastDIDs.rest _ LIST[linkDID]; ENDLOOP; }; ENDLOOP; FOR lolm: LIST OF YggRep.linkMod _ linksChanged, lolm.rest UNTIL lolm = NIL DO IF linkType = NIL AND ~Rope.Equal[lolm.first.linkName, linkType, FALSE] THEN LOOP; IF lolm.first.add THEN { IF lastDIDs = NIL THEN lastDIDs _ (dids _ LIST[lolm.first.linkValue]) ELSE lastDIDs.rest _ LIST[lolm.first.linkValue]; } ELSE { prevLod: LIST OF DID _ NIL; FOR lod: LIST OF DID _ dids, lod.rest UNTIL lod = NIL DO IF YggDID.EqualDIDs[lod.first, lolm.first.linkValue] THEN { IF prevLod = NIL THEN dids _ dids.rest ELSE prevLod.rest _ lod.rest; IF lastDIDs = lod THEN lastDIDs _ prevLod; EXIT; }; prevLod _ lod; ENDLOOP; }; ENDLOOP; }; getLinks: PROC [links: LIST OF YggRep.AttributeValue, linksChanged: LIST OF YggRep.linkMod] RETURNS [currentLinks: LIST OF YggNav.LinkList _ NIL] ~ { lastCurrentLinks: LIST OF YggNav.LinkList _ NIL; FOR linkList: LIST OF YggRep.AttributeValue _ links, linkList.rest UNTIL linkList = NIL DO dids: LIST OF DID _ NIL; lastDIDs: LIST OF DID _ NIL; FOR lotpe: LIST OF YggRep.TypedPrimitiveElement _ linkList.first.valueSet, lotpe.rest UNTIL lotpe = NIL DO linkDID: DID; IF lotpe.first.docType # YggRep.did THEN ERROR; linkDID _ NARROW[lotpe.first.bits]; IF dids = NIL THEN lastDIDs _ (dids _ LIST[linkDID]) ELSE lastDIDs.rest _ LIST[linkDID]; ENDLOOP; IF currentLinks = NIL THEN currentLinks _ lastCurrentLinks _ LIST[[linkList.first.fieldName, dids]] ELSE lastCurrentLinks.rest _ LIST[[linkList.first.fieldName, dids]]; ENDLOOP; FOR lolm: LIST OF YggRep.linkMod _ linksChanged, lolm.rest UNTIL lolm = NIL DO FOR curLnk: LIST OF YggNav.LinkList _ currentLinks, curLnk.rest UNTIL curLnk = NIL DO IF ~Rope.Equal[curLnk.first.linkName, lolm.first.linkName, FALSE] THEN LOOP; IF lolm.first.add THEN { curLnk.first.dids _ CONS[lolm.first.linkValue, curLnk.first.dids]; } ELSE { prevLod: LIST OF DID _ NIL; FOR lod: LIST OF DID _ curLnk.first.dids, lod.rest UNTIL lod = NIL DO IF YggDID.EqualDIDs[lod.first, lolm.first.linkValue] THEN { IF prevLod = NIL THEN curLnk.first.dids _ curLnk.first.dids.rest ELSE prevLod.rest _ lod.rest; EXIT; }; prevLod _ lod; ENDLOOP; }; REPEAT FINISHED => IF lolm.first.add THEN { IF currentLinks = NIL THEN currentLinks _ lastCurrentLinks _ LIST[[lolm.first.linkName, LIST [lolm.first.linkValue]]] ELSE lastCurrentLinks.rest _ LIST[[lolm.first.linkName, LIST [lolm.first.linkValue]]]; }; ENDLOOP; ENDLOOP; }; GetTypedOutlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, linkType: ROPE] RETURNS [outlinks: LIST OF DID _ NIL] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]]; [] _ YggRep.LatchVDoc[document]; outlinks _ getTypedLinks[document.outlinks, document.outlinksChanged, linkType]; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> GetAllOutlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [outlinks: LIST OF YggNav.LinkList _ NIL] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]]; [] _ YggRep.LatchVDoc[document]; outlinks _ getLinks[document.outlinks, document.outlinksChanged]; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> GetTypedInlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, linkType: ROPE] RETURNS [inlinks: LIST OF DID _ NIL] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]]; [] _ YggRep.LatchVDoc[document]; inlinks _ getTypedLinks[document.inlinks, document.inlinksChanged, linkType]; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> GetAllInlinks: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] RETURNS [inlinks: LIST OF YggNav.LinkList _ NIL] ~ { <> <> document: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readOnly, [read, wait]]; [] _ YggRep.LatchVDoc[document]; inlinks _ getLinks[document.inlinks, document.inlinksChanged]; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> SnapLink: PUBLIC PROC [trans: YggEnvironment.TransID, fromDID: DID, toDID: DID, linkType: ROPE] RETURNS [linkDID: DID _ NIL] ~ { <> <> lastLinkMod: LIST OF YggRep.linkMod _ NIL; newLinkMod: LIST OF YggRep.linkMod _ NIL; fromVDoc: YggRep.VDoc; toVDoc: YggRep.VDoc; linkVDoc: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; fromVDoc _ YggRep.VolatizeFromDID[trans, fromDID, readWrite, [write, wait]]; toVDoc _ YggRep.VolatizeFromDID[trans, toDID, readOnly, [read, wait]]; [] _ YggRep.LatchVDoc[fromVDoc]; FOR lolm: LIST OF YggRep.linkMod _ fromVDoc.outlinksChanged, lolm.rest UNTIL lolm = NIL DO lastLinkMod _ lolm; ENDLOOP; linkDID _ YggDIDMap.CreateNewDID[trans]; linkVDoc _ YggRep.VolatizeFromDID[trans, linkDID, readWrite, [write, wait]]; linkVDoc.fromDID _ fromDID; linkVDoc.toDID _ toDID; linkVDoc.linkType _ linkType; linkVDoc.contents.docType _ YggRep.noValue; linkVDoc.linkChanged _ TRUE; newLinkMod _ LIST[[TRUE, linkType, linkDID]]; IF lastLinkMod = NIL THEN fromVDoc.outlinksChanged _ newLinkMod ELSE lastLinkMod.rest _ newLinkMod; IF ~YggRep.UnlatchVDoc[fromVDoc] THEN ERROR; [] _ YggRep.LatchVDoc[toVDoc]; lastLinkMod _ NIL; FOR lolm: LIST OF YggRep.linkMod _ toVDoc.inlinksChanged, lolm.rest UNTIL lolm = NIL DO lastLinkMod _ lolm; ENDLOOP; newLinkMod _ LIST[[TRUE, linkType, linkDID]]; IF lastLinkMod = NIL THEN toVDoc.inlinksChanged _ newLinkMod ELSE lastLinkMod.rest _ newLinkMod; YggTransaction.NotePossibleDocumentUpdate[trans, toVDoc]; IF ~YggRep.UnlatchVDoc[toVDoc] THEN ERROR; }; RemoveLink: PUBLIC PROC [trans: YggEnvironment.TransID, linkDID: YggDID.DID] ~ { <> <> lastLinkMod: LIST OF YggRep.linkMod _ NIL; newLinkMod: LIST OF YggRep.linkMod _ NIL; fromVDoc: YggRep.VDoc; toVDoc: YggRep.VDoc; linkVDoc: YggRep.VDoc; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; linkVDoc _ YggRep.VolatizeFromDID[trans, linkDID, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[linkVDoc]; fromVDoc _ YggRep.VolatizeFromDID[trans, linkVDoc.fromDID, readWrite, [write, wait]]; toVDoc _ YggRep.VolatizeFromDID[trans, linkVDoc.toDID, readOnly, [read, wait], TRUE]; YggDIDMap.DestroyDID[trans, linkDID]; IF ~YggRep.UnlatchVDoc[linkVDoc] THEN ERROR; [] _ YggRep.LatchVDoc[fromVDoc]; FOR lolm: LIST OF YggRep.linkMod _ fromVDoc.outlinksChanged, lolm.rest UNTIL lolm = NIL DO lastLinkMod _ lolm; ENDLOOP; newLinkMod _ LIST[[FALSE, linkVDoc.linkType, linkDID]]; IF lastLinkMod = NIL THEN fromVDoc.outlinksChanged _ newLinkMod ELSE lastLinkMod.rest _ newLinkMod; IF ~YggRep.UnlatchVDoc[fromVDoc] THEN ERROR; [] _ YggRep.LatchVDoc[toVDoc]; lastLinkMod _ NIL; FOR lolm: LIST OF YggRep.linkMod _ toVDoc.inlinksChanged, lolm.rest UNTIL lolm = NIL DO lastLinkMod _ lolm; ENDLOOP; newLinkMod _ LIST[[FALSE, linkVDoc.linkType, linkDID]]; IF lastLinkMod = NIL THEN toVDoc.inlinksChanged _ newLinkMod ELSE lastLinkMod.rest _ newLinkMod; YggTransaction.NotePossibleDocumentUpdate[trans, toVDoc]; IF ~YggRep.UnlatchVDoc[toVDoc] THEN ERROR; }; <> GetDefaultContainer: PUBLIC PROC [trans: YggEnvironment.TransID] RETURNS [did: DID _ NIL] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; did _ YggTransaction.GetDefaultContainer[trans]; }; <<>> SetDefaultContainer: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; YggTransaction.SetDefaultContainer[trans, did]; }; <<>> AddToContainer: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, containerDID: DID] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; addOrRemoveContainer[trans, did, containerDID, TRUE, Parents, Children]; }; <<>> RemoveFromContainer: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, containerDID: DID] RETURNS [ok: BOOL _ TRUE] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; addOrRemoveContainer[trans, did, containerDID, FALSE, Parents, Children]; }; <<>> GetObjectsInContainer: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, dontWait: BOOL] RETURNS [dids: LIST OF DID, success: BOOL] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; [dids, success] _ listContainer [trans, containerDID, Children, dontWait]; }; <<>> GetParents: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID, dontWait: BOOL] RETURNS [dids: LIST OF DID _ NIL, success: BOOL] ~ { <> <> [dids, success] _ listContainer [trans, did, Parents, dontWait]; }; <<>> AddContainerToContainer: PUBLIC PROC [trans: YggEnvironment.TransID, subcontainerDID: DID, containerDID: DID] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; addOrRemoveContainer[trans, subcontainerDID, containerDID, TRUE, ParentContainers, ChildContainers]; }; <<>> RemoveContainerFromContainer: PUBLIC PROC [trans: YggEnvironment.TransID, subcontainerDID: DID, containerDID: DID] RETURNS [ok: BOOL _ TRUE] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; addOrRemoveContainer[trans, subcontainerDID, containerDID, FALSE, ParentContainers, ChildContainers]; }; <<>> GetContainersInContainer: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, dontWait: BOOL] RETURNS [dids: LIST OF DID _ NIL, success: BOOL] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; [dids, success] _ listContainer [trans, containerDID, ChildContainers, dontWait]; }; GetSuperContainers: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, dontWait: BOOL] RETURNS [dids: LIST OF DID _ NIL, success: BOOL] ~ { <> <> IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; [dids, success] _ listContainer [trans, containerDID, ParentContainers, dontWait]; }; addOrRemoveContainer: PROC [trans: YggEnvironment.TransID, did: DID, containerDID: DID, add: BOOL, pAN: ROPE, cN: ROPE, dontLatchDoc: BOOL _ FALSE] ~ { <> <> document: YggRep.VDoc; containerDocument: YggRep.VDoc; newCVal: LIST OF YggRep.metaAttributeMod; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; IF ~dontLatchDoc THEN { [] _ YggRep.LatchVDoc[document]; }; newCVal _ LIST [[attributeName: pAN, add: add, didValue: containerDID, stringValue: NIL]]; IF document.metaAttributesChanged = NIL THEN document.metaAttributesChanged _ newCVal ELSE { prev: LIST OF YggRep.metaAttributeMod _ NIL; FOR macl: LIST OF YggRep.metaAttributeMod _ document.metaAttributesChanged, macl.rest UNTIL macl = NIL DO prev _ macl; ENDLOOP; prev.rest _ newCVal; }; IF ~dontLatchDoc THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; containerDocument _ YggRep.VolatizeFromDID[trans, containerDID, readWrite, [write, wait]]; [] _ YggRep.LatchVDoc[containerDocument]; newCVal _ LIST [[attributeName: cN, add: add, didValue: did, stringValue: NIL]]; IF containerDocument.metaAttributesChanged = NIL THEN containerDocument.metaAttributesChanged _ newCVal ELSE { prev: LIST OF YggRep.metaAttributeMod _ NIL; FOR macl: LIST OF YggRep.metaAttributeMod _ containerDocument.metaAttributesChanged, macl.rest UNTIL macl = NIL DO prev _ macl; ENDLOOP; prev.rest _ newCVal; }; [] _ YggRep.UnlatchVDoc[containerDocument]; }; listContainer: PROC [trans: YggEnvironment.TransID, did: DID, pAN: ROPE, dontWait: BOOL, dontLatch: BOOL _ FALSE] RETURNS[didList: LIST OF DID _ NIL, success: BOOL _ TRUE] ~ { <> <> document: YggRep.VDoc; lastDidList: LIST OF DID _ NIL; didCountItem: TYPE = RECORD [ count: INT _ 0, did: DID ]; modifiedDIDs: LIST OF didCountItem _ NIL; stdValues: LIST OF YggRep.TypedPrimitiveElement _ NIL; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; document _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, IF dontWait THEN fail ELSE wait]]; IF ~dontLatch THEN { IF ~YggRep.LatchVDoc[document, ~dontWait] THEN RETURN[NIL, FALSE]; }; <> FOR loa: LIST OF YggRep.Attribute _ document.metaAttributes, loa.rest UNTIL loa = NIL DO IF Rope.Equal[loa.first.attributeName, pAN] THEN {stdValues _ loa.first.value.first.valueSet; EXIT}; ENDLOOP; <> FOR lotpe: LIST OF YggRep.TypedPrimitiveElement _ stdValues, lotpe.rest UNTIL lotpe = NIL DO tpe: YggRep.TypedPrimitiveElement _ lotpe.first; forgetIt: BOOL _ FALSE; didOnList: DID; didl2add: LIST OF DID _ NIL; IF tpe.docType # YggRep.did THEN ERROR; didOnList _ NARROW[tpe.bits]; FOR macl: LIST OF YggRep.metaAttributeMod _ document.metaAttributesChanged, macl.rest UNTIL macl = NIL DO IF ~Rope.Equal[pAN, macl.first.attributeName] THEN LOOP; IF ~YggDID.EqualDIDs[macl.first.didValue, didOnList] THEN LOOP; forgetIt _ TRUE; FOR mdlist: LIST OF didCountItem _ modifiedDIDs, mdlist.rest UNTIL mdlist = NIL DO IF YggDID.EqualDIDs[mdlist.first.did, didOnList] THEN { mdlist.first.count _ mdlist.first.count + 1; EXIT; }; REPEAT FINISHED => modifiedDIDs _ CONS[[1, didOnList], modifiedDIDs]; ENDLOOP; EXIT; ENDLOOP; IF forgetIt THEN LOOP; didl2add _ LIST[didOnList]; IF didList = NIL THEN lastDidList _ didList _ didl2add ELSE lastDidList _ (lastDidList.rest _ didl2add); ENDLOOP; <> FOR macl: LIST OF YggRep.metaAttributeMod _ document.metaAttributesChanged, macl.rest UNTIL macl = NIL DO IF ~Rope.Equal[pAN, macl.first.attributeName] THEN LOOP; FOR mdlist: LIST OF didCountItem _ modifiedDIDs, mdlist.rest UNTIL mdlist = NIL DO IF YggDID.EqualDIDs[mdlist.first.did, macl.first.didValue] THEN { IF macl.first.add THEN mdlist.first.count _ mdlist.first.count + 1 ELSE mdlist.first.count _ mdlist.first.count - 1; EXIT; }; REPEAT FINISHED => ERROR; ENDLOOP; ENDLOOP; <> FOR mdlist: LIST OF didCountItem _ modifiedDIDs, mdlist.rest UNTIL mdlist = NIL DO IF mdlist.first.count > 0 THEN { FOR i: INT IN [1..mdlist.first.count] DO didl2add: LIST OF DID _ NIL; didl2add _ LIST[mdlist.first.did]; IF didList = NIL THEN lastDidList _ didList _ didl2add ELSE lastDidList _ (lastDidList.rest _ didl2add); ENDLOOP; }; ENDLOOP; IF ~dontLatch THEN { IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; }; <> AddIndexPatternToContainer: PUBLIC PROC [containerDID: YggDID.DID, pattern: ROPE] RETURNS [patternOK: BOOL] ~ { <> <> patternOK _ YggIndexMaint.AddOrRemoveIndexPattern[containerDID: containerDID, pattern: pattern, add: TRUE] }; <<>> RemoveIndexPatternFromContainer: PUBLIC PROC [containerDID: YggDID.DID, pattern: ROPE] RETURNS [ok: BOOL] ~ { <> <> ok _ YggIndexMaint.AddOrRemoveIndexPattern[containerDID: containerDID, pattern: pattern, add: FALSE] }; GetPatternsInContainer: PUBLIC PROC [containerDID: YggDID.DID, dontWait: BOOL] RETURNS [patterns: LIST OF ROPE _ NIL, success: BOOL _ TRUE] ~ { <> <> document: YggRep.VDoc; lastPattern: LIST OF ROPE _ NIL; stdValues: LIST OF YggRep.AttributeValue _ NIL; document _ YggRep.VolatizeFromDID[YggEnvironment.nullTransID, containerDID, readOnly, [read, IF dontWait THEN fail ELSE wait], TRUE]; IF ~YggRep.LatchVDoc[document, ~dontWait] THEN RETURN[NIL, FALSE]; <> FOR loa: LIST OF YggRep.Attribute _ document.metaAttributes, loa.rest UNTIL loa = NIL DO IF Rope.Equal[loa.first.attributeName, AutoIndices] THEN {stdValues _ loa.first.value; EXIT}; ENDLOOP; <> FOR loav: LIST OF YggRep.AttributeValue _ stdValues, loav.rest UNTIL loav = NIL DO indexPattern: ROPE _ NIL; tpe: YggRep.TypedPrimitiveElement _ loav.first.valueSet.first; SELECT tpe.docType FROM YggRep.rope, YggRep.shortRope => { indexPattern _ NARROW[tpe.bits]; }; ENDCASE => ERROR; IF lastPattern = NIL THEN patterns _ LIST[indexPattern] ELSE lastPattern _ (lastPattern.rest _ LIST[indexPattern]); ENDLOOP; IF ~YggRep.UnlatchVDoc[document] THEN ERROR; }; <<>> <> CreateObject: PUBLIC PROC [trans: YggEnvironment.TransID, containerDID: DID, makeRoot: BOOL] RETURNS [did: DID _ NIL] ~ { <> <> foundTrans: BOOL _ FALSE; activeTrans: BOOL _ FALSE; ok: BOOL _ FALSE; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; IF containerDID = NIL OR YggDID.EqualDIDs[containerDID, YggEnvironment.nullDID] THEN containerDID _ GetDefaultContainer[trans]; IF (containerDID = NIL OR YggDID.EqualDIDs[containerDID, YggEnvironment.nullDID]) AND ~makeRoot THEN ERROR Error[error: [code: $invalidDID, explanation: "default container and the containerDID specified are both null; a object must have a container"]]; did _ YggDIDMap.CreateNewDID[trans]; IF containerDID # NIL THEN AddToContainer[trans, did, containerDID]; IF makeRoot THEN ok _ YggDIDMap.AddRootDID[did]; }; <<>> RemoveObject: PUBLIC PROC [trans: YggEnvironment.TransID, did: DID] ~ { <> <> vDoc: YggRep.VDoc; kidDIDs: LIST OF DID; superDIDs: LIST OF DID; subDIDs: LIST OF DID; parentDIDs: LIST OF DID; success: BOOL _ TRUE; IF YggTransaction.Check[transID: trans] # active THEN ERROR Error [ [$invalidTrans, "transaction not active"]]; vDoc _ YggRep.VolatizeFromDID[trans, did, readWrite, [write, wait]]; IF vDoc.outlinks # NIL OR vDoc.inlinks # NIL OR vDoc.outlinksChanged # NIL OR vDoc.inlinksChanged # NIL THEN ERROR; -- doesn't handle recursive delete yet [] _ YggRep.LatchVDoc[vDoc]; [didList: kidDIDs, success: success] _ listContainer[trans: trans, did: did, pAN: Children, dontWait: FALSE, dontLatch: TRUE]; IF kidDIDs # NIL THEN { IF ~YggRep.UnlatchVDoc[vDoc] THEN ERROR; ERROR Error[error: [code: $containerMustBeEmpty, explanation: "attempt to remove an object that is the root of a container that has objects in it"]]; }; [didList: subDIDs, success: success] _ listContainer[trans: trans, did: did, pAN: ChildContainers, dontWait: FALSE, dontLatch: TRUE]; IF subDIDs # NIL THEN { IF ~YggRep.UnlatchVDoc[vDoc] THEN ERROR; ERROR Error[error: [code: $containerMustBeEmpty, explanation: "attempt to remove an object that is the root of a container that has containers in it"]]; }; [didList: parentDIDs, success: success] _ listContainer[trans: trans, did: did, pAN: Parents, dontWait: FALSE, dontLatch: TRUE]; [didList: superDIDs, success: success] _ listContainer[trans: trans, did: did, pAN: ParentContainers, dontWait: FALSE, dontLatch: TRUE]; FOR lopd: LIST OF DID _ parentDIDs, lopd.rest UNTIL lopd = NIL DO addOrRemoveContainer[trans: trans, did: did, containerDID: lopd.first, add: FALSE, pAN: Parents, cN: Children, dontLatchDoc: TRUE]; ENDLOOP; FOR lopd: LIST OF DID _ superDIDs, lopd.rest UNTIL lopd = NIL DO addOrRemoveContainer[trans: trans, did: did, containerDID: lopd.first, add: FALSE, pAN: ParentContainers, cN: ChildContainers, dontLatchDoc: TRUE]; ENDLOOP; vDoc.destroyed _ TRUE; YggDIDMap.DestroyDID[trans, did]; IF ~YggRep.UnlatchVDoc[vDoc] THEN ERROR; }; <<>> <> NoBytes _ NEW[YggRep.BitsRep[0]]; END.