<> <> <> <<>> 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], XNSAddressParsing USING[ErrorCode, Format]; XNSAddressParsingImpl: CEDAR PROGRAM IMPORTS CommDriver, Process, RefText, Rope, XNS EXPORTS XNSAddressParsing ~ { 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 ~ XNSAddressParsing.ErrorCode; Format: TYPE ~ XNSAddressParsing.Format; BYTE: TYPE ~ [0..100H); FieldType: TYPE = { default, broadcast, octal, decimal, hex, notANumber }; <decimal->hex) but cannot cause it to decrease. See GetType[...].>> <> MyAddress: PUBLIC PROC RETURNS [Address] ~ { <> <> RETURN [ [net~DefaultNet[], host~XNS.GetThisHost[], socket~XNS.unknownSocket] ] }; <<>> myRopes: ARRAY Format OF ROPE; MyRope: PUBLIC PROC [format: Format] RETURNS [ROPE] ~ { IF myRopes[format] = NIL THEN myRopes[format] _ RopeFromAddress[MyAddress[], format]; RETURN [myRopes[format]] }; <> AddressFromRope: PUBLIC PROC [rope: ROPE, default: Socket] RETURNS [Address] ~ { nameLen: INT ~ Rope.Length[rope]; answer: Address _ XNS.unknownAddress; netPart, hostPart, socketPart: ROPE _ NIL; netType, hostType, socketType: FieldType _ default; <> BEGIN firstDot, secondDot: INT; firstDot _ Rope.Index[s1~rope, s2~"."]; IF firstDot = nameLen THEN firstDot _ Rope.Index[s1~rope, s2~"#"]; IF firstDot = nameLen THEN { <> hostPart _ rope; hostType _ GetType[hostPart]; GOTO DoneSplit }; secondDot _ Rope.Index[s1~rope, pos1~firstDot+1, s2~"."]; IF secondDot = nameLen THEN secondDot _ Rope.Index[s1~rope, pos1~firstDot+1, s2~"#"]; IF secondDot = nameLen THEN { <> part1: ROPE ~ Rope.Substr[base~rope, len~firstDot]; part2: ROPE ~ Rope.Substr[base~rope, start~firstDot+1]; type1: FieldType ~ GetType[part1]; type2: FieldType ~ GetType[part2]; SELECT TRUE FROM (type1 = notANumber) AND (type2 # notANumber) => { hostPart _ part1; hostType _ type1; socketPart _ part2; socketType _ type2 }; (type1 # notANumber) AND (type2 = notANumber) => { netPart _ part1; netType _ type1; hostPart _ part2; hostType _ type2 }; ENDCASE => ERROR Error[code~syntax, text~"ambiguous address"]; GOTO DoneSplit }; { <> netPart _ Rope.Substr[base~rope, len~firstDot]; netType _ GetType[netPart]; hostPart _ Rope.Substr[base~rope, start~firstDot+1, len~secondDot-firstDot-1]; hostType _ GetType[hostPart]; socketPart _ Rope.Substr[base~rope, start~secondDot+1]; socketType _ GetType[socketPart]; GOTO DoneSplit }; EXITS DoneSplit => NULL; END; SELECT hostType FROM default => ERROR Error[code~syntax, text~"cannot default host"]; broadcast => answer.host _ XNS.broadcastHost; notANumber => { IF Rope.Equal[hostPart, "ME"] THEN { answer _ MyAddress[] } ELSE { ERROR Error[code~syntax, text~"host syntax"] }; }; ENDCASE => answer.host _ CvtHost[hostPart, hostType]; SELECT netType FROM default => IF answer.net = XNS.unknownNet THEN answer.net _ DefaultNet[]; broadcast => answer.net _ XNS.broadcastNet; notANumber => ERROR Error[code~syntax, text~"net syntax"]; ENDCASE => answer.net _ CvtNet[netPart, netType]; SELECT socketType FROM default => IF answer.socket = XNS.unknownSocket THEN answer.socket _ default; broadcast => answer.socket _ XNS.unknownSocket; notANumber => ERROR Error[code~syntax, text~"socket syntax"]; ENDCASE => answer.socket _ CvtSocket[socketPart, socketType]; RETURN [answer]; }; 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] ]; }; <<>> 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]]; notANumber => ERROR Error[syntax, "host syntax"]; 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 => notANumber); FOR i: CARDINAL IN [1 .. limit) WHILE type < notANumber 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 notANumber); ENDCASE => type _ notANumber; 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 _ notANumber; }; 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 ~ { <<[n, rem, isZero] _ [n/base, n MOD base, (n/base = 0)]>> 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; }.