XNSCHImpl.mesa
Demers, December 11, 1986 8:27:23 pm PST
To Do: Check whether CrRPCRuntime support catches errors in bulk data i/o procs.
DIRECTORY
Basics USING [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, BulkDataXferProc, Error, Handle, MarshalledROPEHWords],
Endian USING [CardFromH, HWORD, HFromCard],
IO USING [EndOfStream, Error, GetChar, PutChar, 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 [BulkDataValueProc, CallRemote, GetAuthenticator, IsGeneric, RemoteProc],
XNSRouter USING [GetHops],
XNSStream USING [ConnectionClosed]
;
XNSCHImpl: CEDAR PROGRAM
IMPORTS CHOpsP2V3, CrRPC, Endian, IO, RefText, Rope, XNSCH, XNSCHPrivate, XNSRouter, XNSStream
EXPORTS XNSCH, XNSCHPrivate
~ {
OPEN CHEntries: CHEntriesP0V0, CHOps: CHOpsP2V3;
CARD16: TYPE ~ CARDINAL; -- temporary until Mimosa ????
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 ~ Endian.HWORD;
RemoteProc: TYPE ~ XNSCHPrivate.RemoteProc;
BulkDataValueProc: TYPE ~ XNSCHPrivate.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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachNameInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachAlias[ReadElement[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
heAborted: BOOLFALSE;
EachElement: PROC [element: Element] ~ {
WriteTheElement: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOL]
~ { WriteElement[stream, element]; RETURN [FALSE] };
[heAborted~heAborted] ← WriteSegment[h, stream, checkAbort, WriteTheElement, 1];
IF heAborted THEN ERROR HeAborted[];
};
enumerator[EachElement ! HeAborted => CONTINUE ];
IF NOT heAborted THEN [] ← WriteSegment[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachElementInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachMember[ReadElement[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachNameInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachObject[ReadElement[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachNameInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachName[ReadElement[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachOrganizationInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachOrganization[ReadOrganization[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachDomainInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachDomain[ReadDomain[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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: CrRPC.BulkDataXferProc
[h: Handle, stream: IO.STREAM, checkAbort: BulkDataCheckAbortProc] RETURNS [abort: BOOL];
~ {
EachDomainInStream: BulkDataValueProc
[stream: IO.STREAM] RETURNS [abort: BOOLFALSE]
~ { eachDomain[ReadDomain[stream]] };
RETURN [ReadBulkDataStream[h, stream, 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 ~ 6; -- FIX THIS ????
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] ← Endian.HFromCard[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] ← Endian.CardFromH[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)*2 < cnt THEN RETURN [NIL, pos]; -- ERROR
text ← RefText.ObtainScratch[cnt];
newPos ← pos+1;
DO
IF cnt = 0 THEN EXIT;
buf.lc ← 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+1)/2;
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.lc; 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 Procs
ReadBulkDataStream: PUBLIC PROC [h: CrRPC.Handle, stream: IO.STREAM,
checkAbort: CrRPC.BulkDataCheckAbortProc,
readValue: BulkDataValueProc]
RETURNS [abort: BOOL] ~ {
ENABLE IO.EndOfStream, IO.Error, XNSStream.ConnectionClosed =>
ERROR CrRPC.Error[NIL, communicationFailure, "communication failure"];
segmentKind: CARD16;
lastSegment: CARD16 ~ 1;
len: CARD16;
DO
IF checkAbort[h] THEN RETURN[FALSE];
segmentKind ← ReadCard16[stream];
len ← ReadCard16[stream];
THROUGH [1..len] DO
IF checkAbort[h] THEN RETURN[FALSE];
IF readValue[stream].abort THEN RETURN[TRUE];
ENDLOOP;
IF segmentKind = lastSegment THEN EXIT;
ENDLOOP;
RETURN[FALSE];
};
WriteSegment: PUBLIC PROC [h: CrRPC.Handle, stream: IO.STREAM,
checkAbort: CrRPC.BulkDataCheckAbortProc,
writeValue: BulkDataValueProc,
n: CARDINAL]
RETURNS [abort: BOOLFALSE, heAborted: BOOLFALSE] ~ {
ENABLE IO.EndOfStream, IO.Error, XNSStream.ConnectionClosed =>
ERROR CrRPC.Error[NIL, communicationFailure, "communication failure"];
nextSegment: CARD16 ~ 0;
lastSegment: CARD16 ~ 1;
WriteCard16[stream, (IF n > 0 THEN nextSegment ELSE lastSegment)];
WriteCard16[stream, n];
THROUGH [1..n] DO
IF checkAbort[h] THEN { heAborted ← TRUE; RETURN };
IF writeValue[stream].abort THEN { abort ← TRUE; RETURN };
ENDLOOP;
};
ReadCard16: PUBLIC PROC [stream: IO.STREAM] RETURNS [CARD16] ~ {
buf: Basics.ShortNumber;
buf.hi ← ORD[IO.GetChar[stream]];
buf.lo ← ORD[IO.GetChar[stream]];
RETURN [buf.lc] };
ReadRope: PUBLIC PROC [stream: IO.STREAM] RETURNS [rope: ROPE] ~ {
text: REF TEXT;
len: CARD16;
len ← ReadCard16[stream];
text ← RefText.ObtainScratch[len];
FOR i: INT IN [0 .. len) DO
text ← RefText.AppendChar[to~text, from~IO.GetChar[stream]]
ENDLOOP;
IF (len MOD 2) # 0 THEN [] ← IO.GetChar[stream];
rope ← Rope.FromRefText[text];
RefText.ReleaseScratch[text];
};
ReadElement: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ {
element.organization ← ReadRope[stream];
element.domain ← ReadRope[stream];
element.object ← ReadRope[stream] };
ReadOrganization: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ {
element.organization ← ReadRope[stream];
element.domain ← NIL;
element.object ← NIL };
ReadDomain: PUBLIC PROC [stream: IO.STREAM] RETURNS [element: Element] ~ {
element.organization ← ReadRope[stream];
element.domain ← ReadRope[stream];
element.object ← NIL };
WriteCard16: PUBLIC PROC [stream: IO.STREAM, card16: CARD16] ~ {
buf: Basics.ShortNumber;
buf.lc ← card16;
IO.PutChar[stream, VAL[buf.hi]];
IO.PutChar[stream, VAL[buf.lo]] };
WriteRope: PUBLIC PROC [stream: IO.STREAM, rope: ROPE] ~ {
ENABLE IO.Error, XNSStream.ConnectionClosed =>
ERROR CrRPC.Error[NIL, communicationFailure, "communication failure"];
len: INT ~ Rope.Length[rope];
WriteCard16[stream, len];
FOR i: INT IN [0..len) DO
IO.PutChar[stream, Rope.InlineFetch[rope, i]];
ENDLOOP;
IF (len MOD 2) # 0 THEN IO.PutChar[stream, VAL[0]];
};
WriteElement: PUBLIC PROC [stream: IO.STREAM, element: Element] ~ {
WriteRope[stream, element.organization];
WriteRope[stream, element.domain];
WriteRope[stream, element.object] };
}.