-- Copyright (C) 1982 by Xerox Corporation. All rights reserved.
-- NetDirPrinter.Mesa, HGM, 30-Jan-82 18:36:13
DIRECTORY
Ascii USING [FF],
Checksum USING [ComputeChecksum],
Inline USING [LowHalf],
FormSW USING [
ClientItemsProcType, ProcType, AllocateItemDescriptor, newLine, CommandItem],
MFile USING [Error, GetLength, Handle, ReadOnly],
MSegment USING [Address, Create, Delete, Handle],
Put USING [Char, CR, Decimal, Text, Line, LongDecimal, Octal, Number],
Runtime USING [GetBcdTime],
String USING [AppendString],
Time USING [Append, Unpack],
Tool USING [Create, MakeSWsProc, MakeFormSW, MakeFileSW],
UserInput USING [UserAbort],
Window USING [Handle],
PupWireFormat USING [BcplSTRING],
PupDefs USING [PupAddress],
NetDirDefs USING [
Addr, AddrOffset, Entry, EntryOffset, Name, NameOffset, StringOffset,
NameBase, AddrBase, EntryBase, StringBase, Offset, Header, Attribute, last,
maxAddrsPerEntry, maxNamesPerEntry];
NetDirPrinter: PROGRAM
IMPORTS
Checksum, FormSW, Inline, MFile, MSegment, Put, Runtime, String, Time, Tool,
UserInput =
BEGIN OPEN NetDirDefs;
form, log: Window.Handle;
header: LONG POINTER TO Header;
p: LONG POINTER;
nameTable: LONG POINTER TO ARRAY [0..0) OF NameOffset;
numberOfNames: CARDINAL ← 0;
addrTable: LONG POINTER TO ARRAY [0..0) OF AddrOffset;
numberOfAddrs: CARDINAL ← 0;
e: EntryBase;
n: NameBase;
a: AddrBase;
s: StringBase;
nameTableLocation: CARDINAL;
addrTableLocation: CARDINAL;
entryLocation: CARDINAL;
lengthOfEntries: CARDINAL;
BcplString: TYPE = LONG POINTER TO PupWireFormat.BcplSTRING;
PupAddress: TYPE = PupDefs.PupAddress;
PrintHeader: PROCEDURE =
BEGIN
Put.Text[log, "Name lookup table length "];
Put.Octal[log, header.numberOfNames];
Put.Text[log, " ("];
Put.Decimal[log, header.numberOfNames];
Put.Text[log, "), address "];
Put.Octal[log, header.nameLookupTable];
Put.Line[log, "."];
Put.Text[log, "Address lookup table length "];
Put.Octal[log, header.numberOfAddrs];
Put.Text[log, " ("];
Put.Decimal[log, header.numberOfAddrs];
Put.Text[log, "), address "];
Put.Octal[log, header.addrLookupTable];
Put.Line[log, "."];
Put.Text[log, "Entry table length "];
Put.Octal[log, header.lengthOfEntries];
Put.Text[log, " ("];
Put.Decimal[log, header.lengthOfEntries];
Put.Text[log, "), address "];
Put.Octal[log, header.firstEntry];
Put.Line[log, "."];
Put.Text[log, "version = "];
Put.Decimal[log, header.version];
Put.Line[log, "."];
Put.CR[log];
Put.CR[log];
END;
WriteBcplString: PROCEDURE [string: BcplString] =
BEGIN
FOR i: CARDINAL IN [0..string.length) DO
Put.Char[log, string.char[i]]; ENDLOOP;
END;
O6: PROCEDURE [n: UNSPECIFIED] =
BEGIN Put.Number[log, n, [8, FALSE, TRUE, 6]]; END;
O7: PROCEDURE [n: UNSPECIFIED] =
BEGIN Put.Number[log, n, [8, FALSE, TRUE, 7]]; END;
O: PROCEDURE [n: UNSPECIFIED] =
BEGIN Put.Number[log, n, [8, FALSE, TRUE, 0]]; END;
PrintPupAddress: PROCEDURE [a: LONG POINTER TO PupAddress] =
BEGIN
Put.Number[log, a.net, [8, FALSE, TRUE, 0]];
Put.Char[log, '#];
Put.Number[log, a.host, [8, FALSE, TRUE, 0]];
Put.Char[log, '#];
IF a.socket.a # 0 THEN
BEGIN
Put.Number[log, a.socket.a, [8, FALSE, TRUE, 0]];
Put.Char[log, '|];
END;
Put.Number[log, a.socket.b, [8, FALSE, TRUE, 0]];
END;
OutOfBounds: PROCEDURE [x: Offset] RETURNS [BOOLEAN] =
BEGIN y: CARDINAL = x; RETURN[y > length - 1]; END;
NotEven: PROCEDURE [x: Offset] RETURNS [BOOLEAN] =
BEGIN y: CARDINAL = x; RETURN[(x MOD 2) # 0]; END;
Names: FormSW.ProcType =
BEGIN
name: LONG POINTER TO Name;
IF source = NIL THEN
BEGIN
Put.Line[log, "Please get a reasonable Pup-Network.directory."];
RETURN;
END;
Put.Line[log, "Name lookup table:"];
Put.CR[log];
Put.Line[log, " Table Loc Next Entry Text"];
FOR i: CARDINAL IN [0..numberOfNames) DO
IF UserInput.UserAbort[log] THEN EXIT;
O7[i + nameTableLocation];
O7[nameTable[i]];
IF OutOfBounds[nameTable[i]] THEN
BEGIN Put.Line[log, " (out of bounds)"]; LOOP; END;
name ← @n[nameTable[i]];
O7[name.next];
O7[name.entry];
Put.Text[log, " "];
WriteBcplString[@name.string];
IF NotEven[nameTable[i]] THEN Put.Text[log, " ****** (not even)"];
Put.CR[log];
ENDLOOP;
Put.Char[log, Ascii.FF];
Put.CR[log];
END;
Addresses: FormSW.ProcType =
BEGIN
addr: LONG POINTER TO Addr;
IF source = NIL THEN
BEGIN
Put.Line[log, "Please get a reasonable Pup-Network.directory."];
RETURN;
END;
Put.Line[log, "Address lookup table:"];
Put.CR[log];
Put.Line[log, " Table Loc Next Entry Address"];
FOR i: CARDINAL IN [0..numberOfAddrs) DO
IF UserInput.UserAbort[log] THEN EXIT;
O7[i + addrTableLocation];
O7[addrTable[i]];
IF OutOfBounds[addrTable[i]] THEN
BEGIN Put.Line[log, " (out of bounds)"]; LOOP; END;
addr ← @a[addrTable[i]];
O7[addr.next];
O7[addr.entry];
Put.Text[log, " "];
PrintPupAddress[@addr.port];
IF NotEven[addrTable[i]] THEN Put.Text[log, " ****** (not even)"];
Put.CR[log];
ENDLOOP;
Put.Char[log, Ascii.FF];
Put.CR[log];
END;
Entries: FormSW.ProcType =
BEGIN
file: CARDINAL ← entryLocation;
size: CARDINAL;
entry: LONG POINTER TO Entry ← LOOPHOLE[e + entryLocation];
name: NameOffset;
addr: AddrOffset;
attribute: LONG POINTER TO Attribute;
IF source = NIL THEN
BEGIN
Put.Line[log, "Please get a reasonable Pup-Network.directory."];
RETURN;
END;
Put.Line[log, "Entry blocks:"];
Put.CR[log];
Put.Line[log, " Loc Name Addr Atrributes"];
WHILE file < entryLocation + lengthOfEntries DO
IF UserInput.UserAbort[log] THEN EXIT;
O6[file];
Put.Text[log, " Names: "];
name ← entry.name;
FOR i: CARDINAL ← 0, i + 1 UNTIL i > 50 DO
O[name];
Put.Text[log, " "];
IF OutOfBounds[name] THEN
BEGIN Put.Text[log, " (out of bounds)"]; EXIT; END;
WriteBcplString[@n[name].string];
name ← n[name].next;
IF name = last THEN
BEGIN
IF i >= maxNamesPerEntry THEN Put.Line[log, "****** Too many names."];
EXIT;
END;
Put.Text[log, ", "];
REPEAT
FINISHED =>
Put.Line[log, "****** Looks like a loop in the name list."];
ENDLOOP;
Put.CR[log];
Put.Text[log, " Addresses: "];
addr ← entry.addr;
FOR i: CARDINAL ← 0, i + 1 UNTIL i > 50 DO
O[addr];
Put.Text[log, " "];
IF OutOfBounds[addr] THEN
BEGIN Put.Line[log, " (out of bounds)"]; EXIT; END;
PrintPupAddress[@a[addr].port];
addr ← a[addr].next;
IF addr = last THEN
BEGIN
IF i >= maxAddrsPerEntry THEN
Put.Line[log, "****** Too many addresses."];
EXIT;
END;
Put.Text[log, ", "];
REPEAT
FINISHED =>
Put.Line[log, "****** Looks like a loop in the address list."];
ENDLOOP;
FOR i: CARDINAL IN [0..entry.numberOfAttributes) DO
IF UserInput.UserAbort[log] THEN EXIT;
attribute ← @entry.attributes[i];
IF i = 0 THEN
BEGIN
Put.CR[log];
Put.Text[log, " "];
Put.Decimal[log, entry.numberOfAttributes];
Put.Text[log, " Attributes: "];
END
ELSE Put.Text[log, ", "];
Put.Char[log, '(];
O[attribute.name];
Put.Text[log, ") "];
IF OutOfBounds[attribute.name] THEN Put.Text[log, "(out of bounds)"]
ELSE WriteBcplString[@s[attribute.name]];
Put.Text[log, ": ("];
O[attribute.value];
Put.Text[log, ") """];
IF OutOfBounds[attribute.value] THEN Put.Text[log, "(out of bounds)"]
ELSE WriteBcplString[@s[attribute.value]];
Put.Char[log, '"];
ENDLOOP;
size ← SIZE[Entry] + entry.numberOfAttributes*SIZE[Attribute];
IF size > 50 THEN
BEGIN
Put.Line[
log,
" ****** The size of this Entry is huge. The file is probably trash."];
EXIT;
END;
file ← file + size;
entry ← entry + size;
Put.CR[log];
IF file > length THEN BEGIN EXIT; END;
ENDLOOP;
Put.Char[log, Ascii.FF];
Put.CR[log];
END;
source: MSegment.Handle ← NIL;
length: CARDINAL;
RoundUp: PROCEDURE [w: CARDINAL] RETURNS [CARDINAL] =
BEGIN IF (w MOD 2) # 0 THEN w ← w + 1; RETURN[w]; END;
Initialize: FormSW.ProcType = BEGIN CheckFile[]; END;
CheckFile: PROCEDURE =
BEGIN
file: MFile.Handle;
IF source # NIL THEN RETURN;
file ← MFile.ReadOnly[
"Pup-Network.Directory", [] !
MFile.Error =>
BEGIN
Put.Line[log, "Can't read Pup-Network.Directory."];
GOTO NoFile;
END];
BEGIN
eof: LONG CARDINAL ← MFile.GetLength[file];
IF eof < 2*SIZE[Header] THEN
BEGIN Put.Line[log, "The file is way too short."]; GOTO FileTooShort; END;
Put.Text[log, "There are "];
Put.LongDecimal[log, eof];
Put.Line[log, " bytes in the file."];
IF eof > 2*LONG[LAST[CARDINAL]] THEN
BEGIN Put.Line[log, "The file is too big."]; GOTO FileTooBig; END;
length ← Inline.LowHalf[eof/2];
END;
source ← MSegment.Create[file, [], 0];
p ← MSegment.Address[source];
e ← p;
n ← p;
a ← p;
s ← p;
header ← p;
PrintHeader[];
IF (p + length - 1)↑ # Checksum.ComputeChecksum[0, length - 1, p] THEN
Put.Line[log, "******The Checksum is bad."];
numberOfNames ← header.numberOfNames;
nameTableLocation ← LOOPHOLE[header.nameLookupTable];
nameTable ← LOOPHOLE[e + nameTableLocation];
IF NotEven[nameTableLocation] THEN
Put.Line[
log, "****** The Name lookup table does not start on an even word."];
IF nameTableLocation + numberOfNames > length THEN
Put.Line[log, "****** (Part of) The Name table is out of bounds."];
numberOfAddrs ← header.numberOfAddrs;
addrTableLocation ← LOOPHOLE[header.addrLookupTable];
addrTable ← LOOPHOLE[e + addrTableLocation];
IF NotEven[addrTableLocation] THEN
Put.Line[
log, "****** The Address lookup table does not start on an even word."];
IF addrTableLocation + numberOfAddrs > length THEN
Put.Line[log, "****** (Part of) The Address table is out of bounds."];
lengthOfEntries ← header.lengthOfEntries;
entryLocation ← RoundUp[addrTableLocation + numberOfAddrs];
IF entryLocation + lengthOfEntries > length THEN
Put.Line[log, "****** (Some of) The Entry blocks are out of bounds."];
EXITS
NoFile,
FileTooShort,
FileTooBig =>
BEGIN IF source # NIL THEN MSegment.Delete[source]; source ← NIL; END;
END;
MakeSWs: Tool.MakeSWsProc =
BEGIN
form ← Tool.MakeFormSW[window: window, formProc: MakeForm];
log ← Tool.MakeFileSW[window: window, name: "NetDirPrinter.log"];
CheckFile[];
END;
MakeForm: FormSW.ClientItemsProcType =
BEGIN
nParams: CARDINAL = 4;
items ← FormSW.AllocateItemDescriptor[nParams];
items[0] ← FormSW.CommandItem[
tag: "Initialize"L, proc: Initialize, place: FormSW.newLine];
items[1] ← FormSW.CommandItem[tag: "Names"L, proc: Names];
items[2] ← FormSW.CommandItem[tag: "Addresses"L, proc: Addresses];
items[3] ← FormSW.CommandItem[tag: "Entries"L, proc: Entries];
RETURN[items, TRUE];
END;
Init: PROCEDURE =
BEGIN
herald: STRING = [50];
String.AppendString[herald, "NetDirPrinter of "L];
Time.Append[herald, Time.Unpack[Runtime.GetBcdTime[]]];
[] ← Tool.Create[name: herald, makeSWsProc: MakeSWs];
END;
Init[];
END.