DIRECTORY CommDriver USING [GetNetworkChain, Network], Process USING [Pause, SecondsToTicks, Ticks], RefText USING [ObtainScratch, ReleaseScratch], Rope USING [Cat, Concat, Equal, Fetch, FromRefText, Index, Length, ROPE, Substr], XNS USING [Address, broadcastHost, broadcastNet, GetThisHost, Host, Net, unknownAddress, unknownNet, unknownSocket, Socket], XNSName USING[ErrorCode, Format]; XNSNameImpl: CEDAR PROGRAM IMPORTS CommDriver, Process, RefText, Rope, XNS EXPORTS XNSName ~ { ROPE: TYPE ~ Rope.ROPE; Name: TYPE ~ Rope.ROPE; Address: TYPE ~ XNS.Address; Host: TYPE ~ XNS.Host; Net: TYPE ~ XNS.Net; Socket: TYPE ~ XNS.Socket; ErrorCode: TYPE ~ XNSName.ErrorCode; Format: TYPE ~ XNSName.Format; BYTE: TYPE ~ [0..100H); FieldType: TYPE = { default, broadcast, octal, decimal, hex, clearinghouse }; MyAddress: PUBLIC PROC RETURNS [Address] ~ { RETURN [ [net~DefaultNet[], host~XNS.GetThisHost[], socket~XNS.unknownSocket] ] }; MyName: PUBLIC PROC RETURNS [Name] ~ { RETURN [RopeFromAddress[MyAddress[]]] }; MyRope: PUBLIC PROC [format: Format _ octal] RETURNS [ROPE] ~ { RETURN [RopeFromAddress[MyAddress[], format]] }; AddressFromRope: PUBLIC PROC [rope: ROPE, default: Socket _ XNS.unknownSocket] RETURNS [Address] ~ { RETURN [AddressFromName[name~rope, default~default]] }; AddressFromName: PUBLIC PROC [name: Name, default: Socket _ XNS.unknownSocket] RETURNS [Address] ~ { nameLen: INT ~ Rope.Length[name]; answer: Address _ XNS.unknownAddress; netPart, hostPart, socketPart: ROPE _ NIL; netType, hostType, socketType: FieldType _ default; BEGIN firstDot, secondDot: INT; firstDot _ Rope.Index[s1~name, s2~"."]; IF firstDot = nameLen THEN firstDot _ Rope.Index[s1~name, s2~"#"]; IF firstDot = nameLen THEN { hostPart _ name; hostType _ GetType[hostPart]; GOTO DoneSplit }; secondDot _ Rope.Index[s1~name, pos1~firstDot+1, s2~"."]; IF secondDot = nameLen THEN secondDot _ Rope.Index[s1~name, pos1~firstDot+1, s2~"#"]; IF secondDot = nameLen THEN { part1: ROPE ~ Rope.Substr[base~name, len~firstDot]; part2: ROPE ~ Rope.Substr[base~name, start~firstDot+1]; type1: FieldType ~ GetType[part1]; type2: FieldType ~ GetType[part2]; SELECT TRUE FROM (type1 = clearinghouse) AND (type2 # clearinghouse) => { hostPart _ part1; hostType _ type1; socketPart _ part2; socketType _ type2 }; (type1 # clearinghouse) AND (type2 = clearinghouse) => { netPart _ part1; netType _ type1; hostPart _ part2; hostType _ type2 }; ENDCASE => ERROR Error[code~syntax, text~"ambiguous address"]; GOTO DoneSplit }; { netPart _ Rope.Substr[base~name, len~firstDot]; netType _ GetType[netPart]; hostPart _ Rope.Substr[base~name, start~firstDot+1, len~secondDot-firstDot-1]; hostType _ GetType[hostPart]; socketPart _ Rope.Substr[base~name, start~secondDot+1]; socketType _ GetType[socketPart]; GOTO DoneSplit }; EXITS DoneSplit => NULL; END; IF netType = clearinghouse THEN ERROR Error[code~syntax, text~"net syntax"]; IF socketType = clearinghouse THEN ERROR Error[code~syntax, text~"socket syntax"]; SELECT hostType FROM default => ERROR Error[code~syntax, text~"cannot default host"]; broadcast => answer.host _ XNS.broadcastHost; clearinghouse => { IF Rope.Equal[hostPart, "ME"] THEN { answer _ MyAddress[] } ELSE { ERROR Error[code~noResponse, text~"no Clearinghouse access (yet)"] }; }; ENDCASE => answer.host _ CvtHost[hostPart, hostType]; SELECT netType FROM default => IF answer.net = XNS.unknownNet THEN answer.net _ DefaultNet[]; broadcast => answer.net _ XNS.broadcastNet; clearinghouse => ERROR; ENDCASE => answer.net _ CvtNet[netPart, netType]; SELECT socketType FROM default => IF answer.socket = XNS.unknownSocket THEN answer.socket _ default; broadcast => answer.socket _ XNS.unknownSocket; clearinghouse => ERROR; ENDCASE => answer.socket _ CvtSocket[socketPart, socketType]; RETURN [answer]; }; AddressesFromName: PUBLIC PROC [name: Name, default: Socket _ XNS.unknownSocket] RETURNS [LIST OF Address] ~ { RETURN [ LIST [AddressFromName[name, default]] ] }; RopeFromAddress: PUBLIC PROC [address: Address, format: Format _ octal] RETURNS [rope: ROPE] ~ { rope _ Fmt[ [0, 0, address.net.a, address.net.b, address.net.c, address.net.d], format]; rope _ Rope.Cat[rope, ".", Fmt[ [address.host.a, address.host.b, address.host.c, address.host.d, address.host.e, address.host.f], format], "." ]; IF address.socket # XNS.unknownSocket THEN rope _ Rope.Concat[rope, Fmt[ [0, 0, 0, 0, address.socket.a, address.socket.b], format] ]; }; NameFromAddress: PUBLIC PROC [address: Address, ignoreSocket: BOOL _ TRUE] RETURNS [Name] ~ { temp: Address _ address; IF ignoreSocket THEN temp.socket _ XNS.unknownSocket; RETURN [ RopeFromAddress[temp] ]; }; NetFromRope: PUBLIC PROC [rope: ROPE] RETURNS [Net] ~ { type: FieldType ~ GetType[rope]; SELECT type FROM broadcast => RETURN [XNS.broadcastNet]; octal, decimal, hex => RETURN [CvtNet[rope, type]]; ENDCASE => ERROR Error[syntax, "net syntax"]; }; HostFromRope: PUBLIC PROC [rope: ROPE] RETURNS [Host] ~ { type: FieldType ~ GetType[rope]; SELECT type FROM broadcast => RETURN [XNS.broadcastHost]; octal, decimal, hex => RETURN [CvtHost[rope, type]]; clearinghouse => ERROR Error[syntax, "no CH lookup (yet)"]; ENDCASE => ERROR Error[syntax, "host syntax"]; }; SocketFromRope: PUBLIC PROC [rope: ROPE] RETURNS [Socket] ~ { type: FieldType ~ GetType[rope]; SELECT type FROM octal, decimal, hex => RETURN [CvtSocket[rope, type]]; ENDCASE => ERROR Error[syntax, "socket syntax"]; }; RopeFromNet: PUBLIC PROC [net: Net, format: Format _ octal] RETURNS [ROPE] ~ { RETURN[ Fmt[ [0, 0, net.a, net.b, net.c, net.d], format ] ]; }; RopeFromHost: PUBLIC PROC [host: Host, format: Format _ octal] RETURNS [ROPE] ~ { RETURN[ Fmt[ [host.a, host.b, host.c, host.d, host.e, host.f], format ] ]; }; RopeFromSocket: PUBLIC PROC [socket: Socket, format: Format _ octal] RETURNS [ROPE] ~ { RETURN[ Fmt[ [0, 0, 0, 0, socket.a, socket.b], format ] ]; }; DefaultNet: PROC RETURNS [default: Net _ XNS.unknownNet] ~ { netH: CommDriver.Network; oneSecond: Process.Ticks ~ Process.SecondsToTicks[1]; FOR i: NAT IN [1..5] DO IF ((netH _ CommDriver.GetNetworkChain[]) # NIL) AND ((default _ netH.xns.net) # XNS.unknownNet) THEN EXIT; Process.Pause[oneSecond]; ENDLOOP; }; bnSize: NAT ~ 6; BigNum: TYPE ~ ARRAY[0..bnSize) OF CARDINAL; CvtHost: PROC [rope: ROPE, type: FieldType] RETURNS [Host] ~ { n: BigNum ~ Cvt[rope, type]; RETURN [ [a~n[0], b~n[1], c~n[2], d~n[3], e~n[4], f~n[5]] ] }; CvtNet: PROC [rope: ROPE, type: FieldType] RETURNS [Net] ~ { n: BigNum ~ Cvt[rope, type]; RETURN [ [a~n[2], b~n[3], c~n[4], d~n[5]] ] }; CvtSocket: PROC [rope: ROPE, type: FieldType] RETURNS [Socket] ~ { n: BigNum ~ Cvt[rope, type]; RETURN [ [a~n[4], b~n[5]] ] }; Cvt: PROC [rope: ROPE, type: FieldType] RETURNS [BigNum] ~ { n: BigNum _ ALL [0]; base: CARDINAL; len: CARDINAL; c: CHAR; MulAdd: PROC [increment: CARDINAL] ~ { FOR i: CARDINAL DECREASING IN [0..bnSize) DO temp: CARDINAL _ n[i] * base + increment; n[i] _ temp MOD 100H; increment _ temp / 100H; ENDLOOP; }; base _ SELECT type FROM octal => 8, decimal => 10, ENDCASE => 16; IF (len _ Rope.Length[rope]) = 0 THEN ERROR; c _ Rope.Fetch[rope, len-1]; SELECT TRUE FROM (type = octal) AND ((c = 'B) OR (c = 'b)) => len _ len - 1; (type = hex) AND ((c = 'H) OR (c = 'h)) => len _ len - 1; ENDCASE => NULL; FOR i: CARDINAL IN [0..len) DO SELECT (c _ Rope.Fetch[rope,i]) FROM IN ['0..'9] => MulAdd[c - '0]; IN ['A..'F] => MulAdd[(c - 'A) + 10]; IN ['a..'f] => MulAdd[(c - 'a) + 10]; ENDCASE => NULL; ENDLOOP; RETURN [n]; }; GetType: PROC [rope: ROPE] RETURNS [type: FieldType] ~ { limit: CARDINAL; IF (limit _ Rope.Length[rope]) = 0 THEN RETURN [default]; limit _ limit - 1; IF Rope.Equal[rope, "*"] THEN RETURN [broadcast]; type _ (SELECT Rope.Fetch[rope, 0] FROM IN ['0 .. '7] => octal, IN ['8 .. '9] => decimal, ENDCASE => clearinghouse); FOR i: CARDINAL IN [1 .. limit) WHILE type < clearinghouse DO SELECT Rope.Fetch[rope, i] FROM IN ['0 .. '7] => type _ MAX[type, octal]; IN ['8 .. '9] => type _ MAX[type, decimal]; IN ['A .. 'F], IN ['a .. 'f] => type _ MAX[type, hex]; '- => type _ (IF type <= decimal THEN decimal ELSE clearinghouse); ENDCASE => type _ clearinghouse; ENDLOOP; IF limit > 0 THEN SELECT Rope.Fetch[rope, limit] FROM IN ['0 .. '9], 'D, 'd => type _ MAX[type, decimal]; 'B, 'b => type _ MAX[type, octal]; IN ['A .. 'F], IN ['a .. 'f], 'H, 'h => type _ MAX[type, hex]; ENDCASE => type _ clearinghouse; }; maxDigits: NAT ~ 24; repChar: ARRAY [0 .. 16) OF CHAR ~ ['0, '1, '2, '3, '4, '5, '6, '7, '8, '9, 'A, 'B, 'C, 'D, 'E, 'F]; Fmt: PROC [n: BigNum, type: Format] RETURNS [rope: ROPE] ~ { text: REF TEXT; base, rem, i: CARDINAL; isZero: BOOL; DivRem: PROC ~ { temp, carry: CARDINAL; rem _ 0; isZero _ TRUE; FOR j: CARDINAL IN [0 .. bnSize) DO temp _ n[j] + rem*0100H; IF (n[j] _ temp / base) # 0 THEN isZero _ FALSE; rem _ temp MOD base; ENDLOOP; carry _ 0; FOR j: CARDINAL DECREASING IN [0 .. bnSize) DO temp _ n[j] + carry; n[j] _ temp MOD 0100H; carry _ temp / 0100H; ENDLOOP; }; text _ RefText.ObtainScratch[maxDigits]; text.length _ text.maxLength; i _ text.length; SELECT type FROM productSoftware => { untilDash: NAT _ 3; nDashes: NAT _ 0; base _ 10; isZero _ FALSE; WHILE (NOT isZero) OR (nDashes = 0) DO DivRem[]; -- [n, rem, isZero] _ [n/base, n MOD base, (n/base = 0)] IF untilDash = 0 THEN { text[i _ i - 1] _ '-; untilDash _ 3; nDashes _ nDashes + 1 }; text[i _ i - 1] _ repChar[rem]; untilDash _ untilDash - 1; ENDLOOP; }; octal => { base _ 8; text[i _ i - 1] _ 'B; isZero _ FALSE; WHILE NOT isZero DO DivRem[]; -- [n, rem, isZero] _ [n/base, n MOD base, (n/base = 0)] text[i _ i - 1] _ repChar[rem]; ENDLOOP; }; hex => { base _ 16; text[i _ i - 1] _ 'H; isZero _ FALSE; WHILE (NOT isZero) OR (rem >= 10) DO DivRem[]; -- [n, rem, isZero] _ [n/base, n MOD base, (n/base = 0)] text[i _ i - 1] _ repChar[rem]; ENDLOOP; }; ENDCASE => ERROR; rope _ Rope.Substr[base~Rope.FromRefText[text], start~i]; RefText.ReleaseScratch[text]; }; Error: PUBLIC ERROR [code: ErrorCode, text: ROPE] ~ CODE; }. rXNSNameImpl.mesa Copyright c 1986 by Xerox Corporation. All rights reserved. Demers, June 6, 1986 0:08:49 am PDT The order in which these possibilities are specified is important: receiving more information (i.e. looking at more characters of the field) may cause a computed FieldType to increase (e.g. octal->decimal->hex) but cannot cause it to decrease. See GetType[...]. Local name Return best address for this machine. Socket will be unknownSocket. Tries to get a human-readable name for the local machine, e.g "Shark". This is hard to do in the XNS world, so for now it just calls MyRope. Returns a ROPE of the form "3.313.". There are no possible errors. NIL might happen if there are no drivers active. THIS IS PROBABLY BOGUS! Name/Address translation The implementation might use a local cache, so all those sorts of problems can happen. The servers already have a cache, and the Dicentras sometimes don't notice updates as fast as they should, so local caching shouldn't make things much more complicated. Split name into pieces. One-part name. Two-part name. Three-part name. Like AddressFromName, except it returns all the addresses, closest first. DOES THIS MAKE SENSE IN XNS??? Returns a ROPE of the form "1.12.123". Hack: unknownSocket => "1.12." (no trailing 0). This is hard to do in the XNS world. For now it just calls RopeFromAddress. If ignoreSocket is TRUE, then unknownSocket is used in place of address.socket. Private Procedures We define the default net to be the one at the head of the network chain. It may not be a good idea to block the caller of DefaultNet for so long, but it shouldn't happen (in theory). A BigNum a represents sum over i ( a[i] * 256**(5-i) ); that is, it's a base 256 number with the most significant part in a[0] and the least significant in a[5]. WARNING: Call a BigNum "normalized" if all the elements are in the range [0..256). The BigNum multiplication routine, MulAdd, always produces normalized results, but the division routine, DivRem, while mathematically correct, would leave its result unnormalized except for the explicit renormalization code. For legal network numbers, it can be proved that BigNum elements won't exceed LAST[LONG CARDINAL], so to speed thing up you could change the declaration of BigNum and delete the renormalization code. Yecch. [n, rem, isZero] _ [n/base, n MOD base, (n/base = 0)] n _ renormalize[n]: Errors Ê P˜codešœ™Kšœ Ïmœ1™—Kšžœ ˜—K˜˜K™Kšœ/˜/K˜KšœN˜NK˜Kšœ7˜7K˜!Kšžœ ˜—K˜šž˜Kšœ žœ˜—Kšžœ˜—K˜šžœž˜Kšžœ'˜,—šžœž˜"Kšžœ*˜/—K˜šžœ ž˜Kšœ žœ0˜@Kšœžœ˜-šœ˜šžœ˜Kšžœ˜Kšžœžœ@˜L—K˜—Kšžœ.˜5—K˜šžœ ž˜Kšœ žœžœ žœ˜IKšœžœ˜+Kšœžœ˜Kšžœ*˜1—K˜šžœ ž˜Kšœ žœžœžœ˜MKšœžœ˜/Kšœžœ˜Kšžœ6˜=—K˜Kšžœ ˜K˜—K˜šŸœžœžœ žœžœžœžœ ˜nKšœI™IKšžœžœ&˜3Kš žœžœžœžœžœžœ™K˜—š Ÿœžœžœ,žœžœ˜`Kšœ žœ™&K™/KšœX˜Xšœ˜Kšœo˜oK˜—šžœžœž˜*K˜Z—Kšœ˜K™—š Ÿœžœžœ"žœžœžœ ˜]Kšœžœ/™LK™PK˜Kšžœžœžœ˜5Kšžœ˜!K˜K˜—šŸ œž œžœžœ ˜7K˜ šžœž˜Kšœ žœžœ˜'Kšœžœ˜3Kšžœžœ˜-—K˜K˜—šŸ œž œžœžœ ˜9K˜ šžœž˜Kšœ žœžœ˜(Kšœžœ˜4Kšœžœ%˜;Kšžœžœ˜.—K˜K˜—šŸœž œžœžœ ˜=K˜ šžœž˜Kšœžœ˜6Kšžœžœ ˜0—K˜K˜—š Ÿ œžœžœ$žœžœ˜NKšžœ6˜K˜Kšžœ8˜>—K˜šŸœžœžœžœ ˜Kšžœ˜ —K˜K˜—K˜Kšœ žœ žœžœD˜dK˜šŸœžœžœžœ˜