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;
Operations on Objects
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];
};
Operations on Properties
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]];
};
Enumeration operations
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];
};
Common Lookups
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] };
Server-Specific Queries
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];
};
Utilities
(Un)marshalling
These are strange because the Items have already been byte-swapped to internal representation, which can mess up objects like XNS.Addresses that are stored inside them.
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;
};
Element <-> 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 {
e.g. ["Xerox", "PARC", "*"] -> "Xerox:PARC"
rope ← Rope.Cat[element.organization, ":", element.domain] };
Address List Manipulation
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;
};
Bulk Data Stream / Marshalling Procs
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] };
}.