XNSCHImpl.mesa
Demers, January 1, 1987 9:12:06 pm PST
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: BOOLFALSE]
~ { 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: BOOLFALSE;
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: BOOLFALSE]
~ { 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: BOOLFALSE]
~ { 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: BOOLFALSE]
~ { 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: BOOLFALSE]
~ { 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: BOOLFALSE]
~ { 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: BOOLFALSE]
~ { 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: ROPENIL, defaultOrganization: ROPENIL]
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: CARDINALLAST[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] };
}.