Procs
SplitNameOrAddress:
PROC [name:
ROPE]
RETURNS [hostPart:
ROPE ¬
NIL, portPart:
ROPE ¬
NIL] ~ {
portPos, hostLen: INT;
pos: INT ¬ 0;
IF Rope.IsEmpty[name] THEN RETURN;
SELECT
TRUE
FROM
(pos ¬ Rope.FindBackward[name, ":"]) >= 0 => {
portPos ¬ pos+1;
hostLen ¬ pos;
};
(pos ¬ Rope.FindBackward[name, "]"]) >= 0 => {
portPos ¬ pos+1;
hostLen ¬ pos+1;
};
ENDCASE => {
portPos ¬ Rope.Length[name];
hostLen ¬ portPos;
};
portPart ¬ Rope.Substr[name, portPos];
hostPart ¬ Rope.Substr[name, 0, hostLen];
IF (hostLen >= 2) AND (Rope.Fetch[hostPart, 0] = '[) AND (Rope.Fetch[hostPart, hostLen-1] = ']) THEN hostPart ¬ Rope.Substr[hostPart, 1, hostLen-2];
};
ConvertHostLiteral:
PROC [literal:
ROPE]
RETURNS [ok:
BOOL ¬
FALSE, host:
ROPE ¬
NIL] ~ {
ENABLE Convert.Error => CONTINUE;
len: INT;
host ¬ Convert.RopeFromArpaAddress[
IF Rope.IsEmpty[literal]
THEN Arpa.nullAddress
ELSE Convert.ArpaAddressFromRope[literal]
];
len ¬ Rope.Length[host];
IF (len >= 2)
AND (Rope.Fetch[host, 0] = '[)
THEN host ¬ Rope.Substr[host, 1, len-2];
ok ¬ TRUE;
};
LookupHostName:
ENTRY PROC [name:
ROPE]
RETURNS [addr:
ROPE ¬
NIL] ~ {
errorCodes: LIST OF ATOM ¬ NIL;
found: BOOL;
val: REF;
[found, val] ¬ SymTab.Fetch[hostsByName, name];
IF found THEN RETURN[NARROW[val]]
ELSE RETURN WITH ERROR NN.Error[ LIST[$notFound], "EtcHosts lookup error" ];
};
ConvertPortLiteral:
PROC [portLiteral:
ROPE]
RETURNS [ok:
BOOL ¬
FALSE, port:
ROPE ¬
NIL] ~ {
ENABLE Convert.Error => CONTINUE;
n: CARD;
n ¬ IF Rope.IsEmpty[portLiteral] THEN 0 ELSE Convert.CardFromRope[portLiteral];
port ¬ Convert.RopeFromCard[n];
ok ¬ TRUE;
};
AddressFromName:
NN.AddressFromNameProc
-- [r, name, portHint, components] RETURNS [addr] -- ~ {
host, port, hostName, portName: ROPE ¬ NIL;
ok: BOOL;
addr ¬ NIL;
[hostName, portName] ¬ SplitNameOrAddress[name];
SELECT components
FROM
host, hostAndPort => {
[ok, host] ¬ ConvertHostLiteral[hostName];
IF NOT ok THEN host ¬ LookupHostName[hostName]; -- ! NN.Error
};
ENDCASE;
SELECT components
FROM
port, hostAndPort => {
IF Rope.IsEmpty[portName] THEN portName ¬ portHint;
[ok, port] ¬ ConvertPortLiteral[portName];
IF NOT ok THEN NN.Error[ LIST[$notFound], "port name not found"]; -- no symbolic port names from this package.
};
ENDCASE;
addr ¬ host;
IF NOT Rope.IsEmpty[portName] THEN addr ¬ Rope.Cat[addr, ":", port];
};
LookupHost:
ENTRY PROC [host:
ROPE]
RETURNS [hostName:
ROPE ¬
NIL] ~ {
errorCodes: LIST OF ATOM ¬ NIL;
found: BOOL;
val: REF;
[found, val] ¬ SymTab.Fetch[hostsByAddr, host];
IF found THEN RETURN[NARROW[val]]
ELSE RETURN WITH ERROR NN.Error[ LIST[$notFound], "EtcHosts lookup error" ];
};
NameFromAddress:
NN.NameFromAddressProc
-- [r, addr, components] RETURNS [name] -- ~ {
host, port, hostName, portName: ROPE ¬ NIL;
ok: BOOL;
name ¬ NIL;
[host, port] ¬ SplitNameOrAddress[addr];
SELECT components
FROM
host, hostAndPort => {
IF
NOT Rope.IsEmpty[host]
THEN {
[ok, host] ¬ ConvertHostLiteral[host];
IF NOT ok THEN ERROR NN.Error[ LIST[$syntax], "host address syntax"];
hostName ¬ LookupHost[host]; -- ! NN.Error
};
};
ENDCASE;
SELECT components
FROM
port, hostAndPort => {
IF
NOT Rope.IsEmpty[port]
THEN {
[ok, port] ¬ ConvertPortLiteral[port];
IF NOT ok THEN ERROR NN.Error[ LIST[$syntax], "port number syntax"];
portName ¬ port; -- no symbolic port names from this package
};
};
ENDCASE;
SELECT components
FROM
host => RETURN [hostName];
port => RETURN [portName];
hostAndPort => RETURN [Rope.Cat[hostName, ":", portName]];
ENDCASE => ERROR;
};
hostsByName: SymTab.Ref ¬ SymTab.Create[];
hostsByAddr: SymTab.Ref ¬ SymTab.Create[];
nLines: CARD ¬ 0;
GetNLines:
PROC []
RETURNS [
CARD] ~ {
RETURN[nLines];
};
fileName: PFS.PATH ~ PFS.PathFromRope["/etc/hosts"];
CacheFile:
ENTRY PROC []
RETURNS [] ~ {
hosts: IO.STREAM ¬ PFS.StreamOpen[fileName, read ! IO.Error, PFS.Error => GOTO Out];
ReadOneLine:
PROC []
RETURNS [
BOOL ¬
TRUE] ~ {
WhiteSpace: IO.BreakProc ~ {
IF (char = '#)
THEN
comment ¬ TRUE;
RETURN[
SELECT
TRUE
FROM
comment, char IN [IO.NUL .. IO.SP] => sepr,
ENDCASE => other
];
};
comment: BOOL ¬ FALSE; -- WhiteSpace state variable
line: ROPE ¬ IO.GetLineRope[hosts ! IO.EndOfStream, PFS.Error => GOTO none];
addr: ROPE;
firstOne: BOOL ¬ TRUE;
s: IO.STREAM;
IF ( line.Length[] = 0 ) THEN RETURN;
s ¬ IO.RIS[line];
addr ¬ s.GetTokenRope[WhiteSpace ! IO.EndOfStream => GO TO some].token;
DO
name: ROPE ¬ s.GetTokenRope[WhiteSpace ! IO.EndOfStream => GO TO some].token;
[] ¬ hostsByName.Store[name, addr];
IF firstOne THEN [] ¬ hostsByAddr.Store[addr, name];
firstOne ¬ FALSE;
ENDLOOP;
EXITS
none => RETURN[FALSE];
some => RETURN[TRUE];
};
hostsByName.Erase[];
hostsByAddr.Erase[];
{
ENABLE IO.Error, PFS.Error => GOTO Close;
nLines ¬ 0;
WHILE ReadOneLine[] DO nLines ¬ nLines+1 ENDLOOP;
hosts.Close[];
EXITS
Close => {
IO.Close[hosts ! IO.Error, PFS.Error => CONTINUE];
hostsByName.Erase[];
hostsByAddr.Erase[];
};
};
};
RegisterSelf:
PROC ~ {
r: NN.Registration;
RegistrationCallback:
NN.RegistrationCallbackProc
-- [oldRegistration] RETURNS [action, newRegistration] -- ~ {
RETURN [insert, r];
};
r ¬
NEW[
NN.RegistrationObject ¬ [
family~myFamily,
flavor~myFlavor,
addressFromName~AddressFromName,
nameFromAddress~NameFromAddress
]];
NN.Register[myFamily, RegistrationCallback];
CacheFile[];
RegisterSelf[];
}.