<> <> <<>> DIRECTORY Basics USING [bytesPerHWord, Card16FromH, HFromCard16, HWORD, ShortNumber], CHEntriesP0V0 USING [addressList], CHOpsP2V3 USING [AddGroupProperty, AddItemProperty, AddMember, AddSelf, Authenticator, ChangeItem, CreateAlias, CreateObject, DeleteAlias, DeleteMember, DeleteSelf, DeleteObject, DeleteProperty, IsMember, ItemObject, ListAliases, ListAliasesOf, ListDomains, ListDomainsServed, ListObjects, ListOrganizations, ListProperties, LookupObject, NetworkAddressList, RetrieveAddresses, RetrieveItem, RetrieveMembers], CrRPC USING [BulkDataCheckAbortProc, BulkDataValueProc, BulkDataXferProc, GetRope, Handle, MarshalledRopeHWords, PutRope, ReadBulkDataStream, WriteBulkDataSegment], IO USING [STREAM], RefText USING [AppendChar, ObtainScratch, ReleaseScratch], Rope USING [Cat, FromRefText, Index, InlineFetch, IsEmpty, Length, ROPE, Substr], XNS USING [Address, Host, unknownAddress], XNSAuth USING [Identity], XNSCH USING [Conversation, Element, ElementStreamProc, EnumeratorProc, ErrorCode, InitiateConversation, Item, Name, NameStreamProc, notUsable, Pattern, Properties, PropertyID, TerminateConversation, unspecified, Which], XNSCHPrivate USING [CallRemote, GetAuthenticator, IsGeneric, RemoteProc], XNSRouter USING [GetHops] ; XNSCHImpl: CEDAR PROGRAM IMPORTS Basics, CHOpsP2V3, CrRPC, RefText, Rope, XNSCH, XNSCHPrivate, XNSRouter EXPORTS XNSCH, XNSCHPrivate ~ { OPEN CHEntries: CHEntriesP0V0, CHOps: CHOpsP2V3; ROPE: TYPE ~ Rope.ROPE; Name: TYPE ~ XNSCH.Name; Pattern: TYPE ~ XNSCH.Pattern; Element: TYPE ~ XNSCH.Element; PropertyID: TYPE ~ XNSCH.PropertyID; Properties: TYPE ~ XNSCH.Properties; Item: TYPE ~ XNSCH.Item; Conversation: TYPE ~ XNSCH.Conversation; HWORD: TYPE ~ Basics.HWORD; RemoteProc: TYPE ~ XNSCHPrivate.RemoteProc; BulkDataXferProc: TYPE ~ CrRPC.BulkDataXferProc; BulkDataValueProc: TYPE ~ CrRPC.BulkDataValueProc; shiftInName: ROPE ~ "CHServers"; chServiceName: Name ~ [organization~shiftInName, domain~shiftInName, object~"Clearinghouse Service"]; Error: PUBLIC ERROR [code: XNSCH.ErrorCode, which: XNSCH.Which] ~ CODE; <> Add: PUBLIC PROC [c: Conversation, name: Name] ~ { DoAdd: RemoteProc -- [handle, host] -- ~ { CHOps.CreateObject[handle, name, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAdd, DomainFromElement[name]]; }; Delete: PUBLIC PROC [c: Conversation, name: Name] ~ { DoDelete: RemoteProc -- [handle, host] -- ~ { CHOps.DeleteObject[handle, name, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDelete, DomainFromElement[name]]; }; Lookup: PUBLIC PROC [c: Conversation, pattern: Pattern] RETURNS [distingName: Name] ~ { DoLookup: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.LookupObject[handle, pattern, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoLookup, DomainFromElement[pattern]]; }; AddAlias: PUBLIC PROC [c: Conversation, name, alias: Name] RETURNS [distingName: Name] ~ { DoAddAlias: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.CreateAlias[handle, alias, name, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddAlias, DomainFromElement[alias--????--]]; }; DeleteAlias: PUBLIC PROC [c: Conversation, alias: Name] RETURNS [distingName: Name] ~ { DoDeleteAlias: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.DeleteAlias[handle, alias, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteAlias, DomainFromElement[alias]]; }; ListAliases: PUBLIC PROC [c: Conversation, pattern: Pattern, eachAlias: XNSCH.NameStreamProc] RETURNS [distingName: Name] ~ { ReadStreamOfNames: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachNameInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachAlias[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachNameInStream]]; }; DoListAliases: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.ListAliasesOf[handle, pattern, ReadStreamOfNames, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoListAliases, DomainFromElement[pattern], FALSE]; }; <> GetProperties: PUBLIC PROC [c: Conversation, pattern: Pattern] RETURNS [distingName: Name, properties: Properties] ~ { DoGetProperties: RemoteProc -- [handle, host] -- ~ { [distinguishedObject~distingName, properties~properties] _ CHOps.ListProperties[handle, pattern, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoGetProperties, DomainFromElement[pattern]]; }; DeleteProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID] RETURNS [distingName: Name] ~ { DoDeleteProperty: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.DeleteProperty[handle, name, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteProperty, DomainFromElement[name]]; }; AddItemProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, item: Item] RETURNS [distingName: Name] ~ { DoAddItemProperty: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.AddItemProperty[handle, name, pID, item, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddItemProperty, DomainFromElement[name]]; }; ChangeItemProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, item: Item] RETURNS [distingName: Name] ~ { DoChangeItemProperty: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.ChangeItem[handle, name, pID, item, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoChangeItemProperty, DomainFromElement[name]]; }; LookupItemProperty: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID] RETURNS [distingName: Name, item: Item] ~ { DoLookupItemProperty: RemoteProc -- [handle, host] -- ~ { [distinguishedObject~distingName, value~item] _ CHOps.RetrieveItem[handle, pattern, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoLookupItemProperty, DomainFromElement[pattern]]; }; LookupAddress: PUBLIC PROC [c: Conversation, pattern: Pattern] RETURNS [distingName: Name, address: XNS.Address] ~ { DoLookupAddress: RemoteProc -- [handle, host] -- ~ { item: Item; addresses: LIST OF XNS.Address; [distinguishedObject~distingName, value~item] _ CHOps.RetrieveItem[handle, pattern, CHEntries.addressList, XNSCHPrivate.GetAuthenticator[c, host]]; addresses _ AddressesFromItem[item]; IF addresses # NIL THEN address _ BestAddressInList[addresses] ELSE address _ XNS.unknownAddress; }; XNSCHPrivate.CallRemote[c, DoLookupAddress, DomainFromElement[pattern]]; }; LookupRopeProperty: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID] RETURNS [distingName: Name, ropeProperty: ROPE] ~ { DoLookupRopeProperty: RemoteProc -- [handle, host] -- ~ { item: Item; [distinguishedObject~distingName, value~item] _ CHOps.RetrieveItem[handle, pattern, pID, XNSCHPrivate.GetAuthenticator[c, host]]; ropeProperty _ RopeFromItem[item]; }; XNSCHPrivate.CallRemote[c, DoLookupRopeProperty, DomainFromElement[pattern]]; }; LookupNameProperty: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID] RETURNS [distingName: Name, nameProperty: Name] ~ { DoLookupNameProperty: RemoteProc -- [handle, host] -- ~ { item: Item; [distinguishedObject~distingName, value~item] _ CHOps.RetrieveItem[handle, pattern, pID, XNSCHPrivate.GetAuthenticator[c, host]]; nameProperty _ ElementFromItem[item]; }; XNSCHPrivate.CallRemote[c, DoLookupNameProperty, DomainFromElement[pattern]]; }; HeAborted: ERROR ~ CODE; AddGroupProperty: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, enumerator: XNSCH.EnumeratorProc] RETURNS [distingName: Name] ~ { WriteStreamOfElements: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { heAborted: BOOL _ FALSE; EachElement: PROC [element: Element] ~ { WriteTheElement: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL]>> ~ { PutElement[s, element]; RETURN [FALSE] }; [heAborted~heAborted] _ CrRPC.WriteBulkDataSegment[h, s, checkAbort, WriteTheElement, 1]; IF heAborted THEN ERROR HeAborted[]; }; enumerator[EachElement ! HeAborted => CONTINUE ]; IF NOT heAborted THEN [] _ CrRPC.WriteBulkDataSegment[h, s, NIL, NIL, 0]; RETURN [FALSE] }; DoAddGroupProperty: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.AddGroupProperty[handle, name, pID, WriteStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddGroupProperty, DomainFromElement[name]]; }; AddMember: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, member: Element] RETURNS [distingName: Name] ~ { DoAddMember: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.AddMember[handle, name, pID, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddMember, DomainFromElement[name]]; }; AddSelf: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID] RETURNS [distingName: Name] ~ { DoAddSelf: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.AddSelf[handle, name, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoAddSelf, DomainFromElement[name]]; }; DeleteMember: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID, member: Element] RETURNS [distingName: Name] ~ { DoDeleteMember: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.DeleteMember[handle, name, pID, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteMember, DomainFromElement[name]]; }; DeleteSelf: PUBLIC PROC [c: Conversation, name: Name, pID: PropertyID] RETURNS [distingName: Name] ~ { DoDeleteSelf: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.DeleteSelf[handle, name, pID, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoDeleteSelf, DomainFromElement[name]]; }; ListMembers: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, eachMember: XNSCH.ElementStreamProc] RETURNS [distingName: Name] ~ { ReadStreamOfElements: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachElementInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachMember[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachElementInStream]]; }; DoListMembers: RemoteProc -- [handle, host] -- ~ { distingName _ CHOps.RetrieveMembers[handle, pattern, pID, ReadStreamOfElements, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoListMembers, DomainFromElement[pattern], FALSE]; }; IsMember: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, member: Element] RETURNS [distingName: Name, isMember: BOOL] ~ { DoIsMember: RemoteProc -- [handle, host] -- ~ { [isMember~isMember, distinguishedObject~distingName] _ CHOps.IsMember[handle, pattern, pID, XNSCH.notUsable, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoIsMember, DomainFromElement[pattern]]; }; IsMemberClosure: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, member: Element, pID2: PropertyID] RETURNS [distingName: Name, isMember: BOOL] ~ { DoIsMemberClosure: RemoteProc -- [handle, host] -- ~ { [isMember~isMember, distinguishedObject~distingName] _ CHOps.IsMember[handle, pattern, pID, pID2, member, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF pID2 = XNSCH.unspecified THEN pID2 _ pID; XNSCHPrivate.CallRemote[c, DoIsMemberClosure, DomainFromElement[pattern]]; }; <> Enumerate: PUBLIC PROC [c: Conversation, pattern: Pattern, pID: PropertyID, eachObject: XNSCH.NameStreamProc] ~ { ReadStreamOfNames: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachNameInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachObject[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachNameInStream]]; }; DoEnumerate: RemoteProc -- [handle, host] -- ~ { CHOps.ListObjects[handle, pattern, pID, ReadStreamOfNames, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerate, DomainFromElement[pattern], FALSE]; }; EnumerateAliases: PUBLIC PROC [c: Conversation, pattern: Pattern, eachName: XNSCH.NameStreamProc] ~ { ReadStreamOfNames: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachNameInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachName[GetElement[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachNameInStream]]; }; DoEnumerateAliases: RemoteProc -- [handle, host] -- ~ { CHOps.ListAliases[handle, pattern, ReadStreamOfNames, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerateAliases, DomainFromElement[pattern], FALSE]; }; EnumerateOrganizations: PUBLIC PROC [c: Conversation, pattern: Pattern, eachOrganization: XNSCH.ElementStreamProc] ~ { ReadStreamOfOrganizations: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachOrganizationInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachOrganization[GetOrganization[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachOrganizationInStream]]; }; DoEnumerateOrganizations: RemoteProc -- [handle, host] -- ~ { CHOps.ListOrganizations[handle, pattern.organization, ReadStreamOfOrganizations, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerateOrganizations, NIL, FALSE]; }; EnumerateDomains: PUBLIC PROC [c: Conversation, pattern: Pattern, eachDomain: XNSCH.ElementStreamProc] ~ { ReadStreamOfDomains: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachDomainInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachDomain[GetDomain[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachDomainInStream]]; }; DoEnumerateDomains: RemoteProc -- [handle, host] -- ~ { CHOps.ListDomains[handle, [organization~pattern.organization, domain~pattern.domain], ReadStreamOfDomains, XNSCHPrivate.GetAuthenticator[c, host]]; }; XNSCHPrivate.CallRemote[c, DoEnumerateDomains, NIL, FALSE]; }; <> LookupAddressFromRope: PUBLIC PROC [rope: ROPE] RETURNS [distingName: Name, address: XNS.Address] ~ { c: Conversation ~ XNSCH.InitiateConversation[]; [distingName, address] _ LookupAddress[c, ElementFromRope[rope] ! Error => { distingName _ [NIL,NIL,NIL]; address _ XNS.unknownAddress; CONTINUE }]; XNSCH.TerminateConversation[c] }; <> GetServerAddresses: PUBLIC PROC [c: Conversation] RETURNS [addresses: LIST OF XNS.Address] ~ { list: CHOps.NetworkAddressList; DoGetServerAddresses: RemoteProc -- [handle, host] -- ~ { i: CARDINAL; list _ CHOps.RetrieveAddresses[handle]; i _ list.length; addresses _ NIL; WHILE i > 0 DO i _ i - 1; addresses _ CONS [LOOPHOLE[list.body[i]], addresses]; ENDLOOP; }; IF XNSCHPrivate.IsGeneric[c] THEN ERROR Error[inappropriateConversation, first]; XNSCHPrivate.CallRemote[c, DoGetServerAddresses, NIL]; }; EnumerateDomainsServed: PUBLIC PROC [c: Conversation, eachDomain: XNSCH.ElementStreamProc] ~ { ReadStreamOfDomains: BulkDataXferProc <<[h: Handle, s: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];>> ~ { EachDomainInStream: BulkDataValueProc <<[s: IO.STREAM] RETURNS [abort: BOOL _ FALSE]>> ~ { eachDomain[GetDomain[s]] }; RETURN [CrRPC.ReadBulkDataStream[h, s, checkAbort, EachDomainInStream]]; }; DoEnumerateDomainsServed: RemoteProc -- [handle, host] -- ~ { CHOps.ListDomainsServed[handle, ReadStreamOfDomains, XNSCHPrivate.GetAuthenticator[c, host]]; }; IF XNSCHPrivate.IsGeneric[c] THEN ERROR Error[inappropriateConversation, first]; XNSCHPrivate.CallRemote[c, DoEnumerateDomainsServed, NIL]; }; <> <<(Un)marshalling>> <> adrHWords: CARDINAL ~ BITS[XNS.Address]/BITS[HWORD]; AddressesFromItem: PUBLIC PROC [item: Item] RETURNS [addresses: LIST OF XNS.Address] ~ { buf: ARRAY [0..adrHWords) OF HWORD; cnt: CARD16 _ item.body[0]; index: CARDINAL _ 1; IF item.length < 1+cnt*adrHWords THEN RETURN[NIL]; THROUGH [1..cnt] DO FOR i: CARDINAL IN [0..adrHWords) DO buf[i] _ Basics.HFromCard16[item.body[index]]; index _ index + 1; ENDLOOP; addresses _ CONS[LOOPHOLE[buf], addresses]; ENDLOOP; }; ItemFromAddresses: PUBLIC PROC [addresses: LIST OF XNS.Address] RETURNS [item: Item] ~ { buf: ARRAY [0..adrHWords) OF HWORD; index: CARDINAL; cnt: CARD16 _ 0; FOR temp: LIST OF XNS.Address _ addresses, temp.rest WHILE temp # NIL DO cnt _ cnt + 1; ENDLOOP; item _ NEW[CHOps.ItemObject[1+cnt*adrHWords]]; item.body[0] _ cnt; index _ 1; FOR temp: LIST OF XNS.Address _ addresses, temp.rest WHILE temp # NIL DO buf _ LOOPHOLE[temp.first]; FOR i: CARDINAL IN [0..adrHWords) DO item.body[index] _ Basics.Card16FromH[buf[i]]; index _ index + 1; ENDLOOP; ENDLOOP; }; RopeFromItem: PUBLIC PROC [item: Item] RETURNS [rope: ROPE] ~ { [rope~rope] _ RopeFromItemInner[item,0] }; ElementFromItem: PUBLIC PROC [item: Item] RETURNS [element: Element] ~ { pos: INT; [rope~element.organization, newPos~pos] _ RopeFromItemInner[item, 0]; [rope~element.domain, newPos~pos] _ RopeFromItemInner[item, pos]; [rope~element.object] _ RopeFromItemInner[item, pos]; }; RopeFromItemInner: PROC [item: Item, pos: INT] RETURNS [rope: ROPE, newPos: INT] ~ { buf: Basics.ShortNumber; text: REF TEXT; cnt: CARDINAL; IF item.length <= pos THEN RETURN [NIL, pos]; cnt _ item.body[pos]; IF ((item.length-pos-1)*Basics.bytesPerHWord) < cnt THEN RETURN [NIL, pos]; -- ERROR text _ RefText.ObtainScratch[cnt]; newPos _ pos+1; DO IF cnt = 0 THEN EXIT; buf.sc _ item.body[newPos]; newPos _ newPos+1; text _ RefText.AppendChar[to~text, from~LOOPHOLE[buf.hi]]; cnt _ cnt-1; IF cnt = 0 THEN EXIT; text _ RefText.AppendChar[to~text, from~LOOPHOLE[buf.lo]]; cnt _ cnt-1; ENDLOOP; rope _ Rope.FromRefText[text]; RefText.ReleaseScratch[text]; }; ItemFromRope: PUBLIC PROC [rope: ROPE] RETURNS [item: Item] ~ { itemLen: INT ~ 1 + CrRPC.MarshalledRopeHWords[rope]; item _ NEW[CHOps.ItemObject[itemLen]]; ItemFromRopeInner[rope, item, 0]; }; ItemFromElement: PUBLIC PROC [element: Element] RETURNS [item: Item] ~ { orgLen: INT ~ CrRPC.MarshalledRopeHWords[element.organization]; domLen: INT ~ CrRPC.MarshalledRopeHWords[element.domain]; objLen: INT ~ CrRPC.MarshalledRopeHWords[element.object]; itemLen: INT ~ orgLen + domLen + objLen; item _ NEW[CHOps.ItemObject[itemLen]]; ItemFromRopeInner[element.organization, item, 0]; ItemFromRopeInner[element.domain, item, orgLen]; ItemFromRopeInner[element.object, item, orgLen + domLen] }; ItemFromRopeInner: PROC [rope: ROPE, item: Item, pos: INT] ~ { buf: Basics.ShortNumber; ropeLen: INT ~ Rope.Length[rope]; itemLen: INT ~ 1 + ((ropeLen+Basics.bytesPerHWord-1) / Basics.bytesPerHWord); iFrom: INT _ 0; item.body[pos] _ ropeLen; pos _ pos + 1; DO IF iFrom >= ropeLen THEN EXIT; buf.hi _ ORD[Rope.InlineFetch[rope, iFrom]]; iFrom _ iFrom+1; buf.lo _ IF iFrom < ropeLen THEN ORD[Rope.InlineFetch[rope, iFrom]] ELSE 0; iFrom _ iFrom+1; item.body[pos] _ buf.sc; pos _ pos + 1; ENDLOOP; }; < Rope conversion>> ElementFromRope: PUBLIC PROC [rope: ROPE, defaultDomain: ROPE _ NIL, defaultOrganization: ROPE _ NIL] RETURNS [element: Element] ~ { GetDefaultDomain: PROC RETURNS [ROPE] ~ INLINE { IF Rope.IsEmpty[defaultDomain] THEN defaultDomain _ "PARC"; -- BOGUS RETURN [defaultDomain] }; GetDefaultOrganization: PROC RETURNS [ROPE] ~ INLINE { IF Rope.IsEmpty[defaultOrganization] THEN defaultOrganization _ "Xerox"; -- BOGUS RETURN [defaultOrganization] }; pos1, pos2, len: INT; len _ Rope.Length[rope]; pos1 _ Rope.Index[s1~rope, pos1~0, s2~":"]; pos2 _ Rope.Index[s1~rope, pos1~pos1+1, s2~":"]; element.object _ Rope.Substr[base~rope, start~0, len~pos1]; element.domain _ IF pos1 < len THEN Rope.Substr[base~rope, start~pos1+1, len~pos2-pos1-1] ELSE NIL; IF Rope.IsEmpty[element.domain] THEN element.domain _ GetDefaultDomain[]; element.organization _ IF pos2 < len THEN Rope.Substr[base~rope, start~pos2+1, len~len-pos2-1] ELSE NIL; IF Rope.IsEmpty[element.organization] THEN element.organization _ GetDefaultOrganization[]; }; RopeFromElement: PUBLIC PROC [element: Element] RETURNS [rope: ROPE] ~ { rope _ Rope.Cat[element.object, ":", "element.domain", ":", element.organization]; }; DomainFromElement: PROC [element: Element] RETURNS [rope: ROPE] ~ INLINE { < "Xerox:PARC">> rope _ Rope.Cat[element.organization, ":", element.domain] }; <
> BestAddressInList: PUBLIC PROC [list: LIST OF XNS.Address] RETURNS [bestAddress: XNS.Address] ~ { bestHops: CARDINAL _ LAST[CARDINAL]; WHILE list # NIL DO tempHops: CARDINAL ~ XNSRouter.GetHops[list.first.net]; IF tempHops < bestHops THEN { bestAddress _ list.first; bestHops _ tempHops }; list _ list.rest; ENDLOOP; }; <> GetElement: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ { element.organization _ CrRPC.GetRope[stream]; element.domain _ CrRPC.GetRope[stream]; element.object _ CrRPC.GetRope[stream] }; GetOrganization: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ { element.organization _ CrRPC.GetRope[stream]; element.domain _ NIL; element.object _ NIL }; GetDomain: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ { element.organization _ CrRPC.GetRope[stream]; element.domain _ CrRPC.GetRope[stream]; element.object _ NIL }; PutElement: PUBLIC PROC [stream: IO.STREAM, element: Element] ~ { CrRPC.PutRope[stream, element.organization]; CrRPC.PutRope[stream, element.domain]; CrRPC.PutRope[stream, element.object] }; }.