// PeekSum.bcpl -- Peek.reports summary
// Copyright Xerox Corporation 1979, 1980
// Last modified October 29, 1980  11:15 AM by Boggs

// Bldr PeekSum Template

get "Streams.d"
get "SysDefs.d"

external
[
// Incoming procedures
OpenFile; ReadBlock; FileLength
Ws; Wss; PutTemplate
Endofs; Gets; Resets; Closes
Usc; Zero; MoveBlock; Junta; CallSwat; MyFrame; SysErr
InitializeZone; Allocate; AddToZone

// incoming statics
sysZone
]

manifest stackLimit = 335b

static
[
list1; list2; list3
AltoIITable; hashTab
netNum; hostNum
rpt; sum; dir
token; termChar
]

structure String [ length byte; char↑1,1 byte ]

//----------------------------------------------------------------------------
let PeekSum() be
//----------------------------------------------------------------------------
[
let netDir = OpenFile("PUP-NETWORK.DIRECTORY", ksTypeReadOnly, wordItem)
if netDir ne 0 then
   [
   let length = vec 1; FileLength(netDir, length)
   if length!0 eq 0 then
      [
      length = length!1 rshift 1 +1
      Resets(netDir)
      ReadBlock(netDir, @stackLimit, length)
      dir = @stackLimit; @stackLimit = @stackLimit + length
      ]
   Closes(netDir)
   ]

// set up free storage zone
let freeBegin = @stackLimit
let freeEnd = MyFrame() -2000
if freeEnd - freeBegin ls 0 then freeEnd = freeBegin + 77777b
@stackLimit = freeEnd
sysZone = InitializeZone(freeBegin, freeEnd-freeBegin, SysErr, 0)

// open files
rpt = OpenFile("Peek.Reports", ksTypeReadOnly, charItem, 0, 0, 0, sysZone)
if rpt eq 0 then [ Ws("*NCan't find file Peek.Reports"); finish ] 
sum = OpenFile("PeekSummary.tx", ksTypeWriteOnly, charItem, 0, 0, 0, sysZone)
if sum eq 0 then CallSwat("Can't open PeekSummary.tx")

// dont need OS through levScan any more
Junta(levStreams, AfterJunta)
]

//----------------------------------------------------------------------------
and AfterJunta() be
//----------------------------------------------------------------------------
[
let freeBegin = @stackLimit
let freeEnd = MyFrame() - 1000
@stackLimit = freeEnd
AddToZone(sysZone, freeBegin, freeEnd-freeBegin)

// following three lists are indexed by host number
// hanging off each entry is a linked list of items
list1 = Allocate(sysZone, 256); Zero(list1, 256)  // Error Text
list2 = Allocate(sysZone, 256); Zero(list2, 256)  // Main mem errors
list3 = Allocate(sysZone, 256); Zero(list3, 256)  // Ctrl mem errors

// bit on means this host is an Alto II
AltoIITable = Allocate(sysZone, 16); Zero(AltoIITable, 16)

// error strings are kept in a hash table to detect duplicates.
// List1 items also point to the strings.
hashTab = Allocate(sysZone, 256); Zero(hashTab, 256)

token = Allocate(sysZone, 100)

until Endofs(rpt) do
   [
   ReadToken()	//read network number
   //print lines in Peek.reports that don't start with <netnumber>#
   if termChar ne $# then PutTemplate(sum, "$S*N", token)

   if netNum eq 0 then netNum = StringToNumber(8)
   ReadToken()	//read serial number
   if termChar ne $# then		//line screwed up--discard line
      [
      while termChar ne $*N do ReadToken()
      loop
      ]
   hostNum = StringToNumber(8)

   ReadToken()	//read something, hopefully a number
   if termChar ne $*S then	//if it doesn't end in <space>, discard line
      [
      while termChar ne $*N do ReadToken()
      loop
      ]
   let item = vec 5
   let FN = StringToNumber(10)

   // AfterJunta (cont'd)

   ReadToken()
   switchon termChar into
      [
      case $*N:
         [
         test token!0 gr 5	//at most 5 chars in a number
            ifso		//token is text
               [
               item!0 = HashLookup()	//->error text
               item!1 = FN		//# of errors of this type
               AddToList(list1, item, 2)
               ]
            ifnot		//token is number of RAM chip errors
               [
               item!0 = FN		// chip number
               item!1 = StringToNumber(10)  // # of errors in this chip
               AddToList(list3, item, 2)
               ]
         endcase
         ]

      case $*S:			//line describes bad main mem chip
         [				// AltoI	AltoII
         item!0 = FN			// card		card
         item!1 = StringToNumber(10)	// column	chip
         ReadToken()
         item!2 = StringToNumber(10)	// row		# of errors
         if termChar eq $*N then
            [
            SetAltoIIBit(hostNum)	//this is an Alto II
            AddToList(list2, item, 3)
            loop
            ]
         ReadToken()
         item!3 = StringToNumber(10)	// # of errors
         if termChar ne $*N loop
         AddToList(list2, item, 4)
         endcase
         ]

      default: loop
      ]
   ]

Closes(rpt)

// Generate results
let base, addr = 0, 0
if dir ne 0 then
   [
   base = dir
   addr = base + base!3
   while (@(base + @addr + 2) rshift 8) ne netNum do addr = addr +1
   ]

PutTemplate(sum, "*NNetwork number $O*N*N*N", netNum)

for host = 0 to 255 do
   [
   if list1!host eq 0 loop
   PutTemplate(sum, "$3O--", host)

   if dir ne 0 then
      [
      while (@(base + @addr + 2) & 377b) ls host do addr = addr +1
      test (@(base + @addr + 2) & 377b) eq host
         ifso
            [
            Wss(sum, base + @(base + @(base + @addr + 1) + 6))
            Wss(sum, "  ")
            Wss(sum, base + @(base + @(base + @addr + 1) + 4))
            ]
         ifnot Wss(sum, "not in PUP-NETWORK.DIRECTORY")
      ]

   // print any error strings
   let errors = false
   let link = list1!host
   until link eq 0 do
      [
      if link!2 ne 0 then errors = true
      link = link!0
      ]
   unless errors do
      [
      Wss (sum, " : NO ERRORS*N*N")
      loop
      ]
   link = list1!host
   Wss(sum, " :*N")
   until link eq 0 do
      [
      PutTemplate(sum, "$5D $S*N", link!2, (link!1)+1)
      link = link!0
      ]


   // AfterJunta (cont'd)

   // print main memory chip errors
   link = list2!host
   if link ne 0 then
      [
      Wss(sum, "*NMain memory chips ")
      test IsAltoII(host)
         ifso Wss(sum, "(Alto II):*NCard  Chip  Errors*N")
         ifnot Wss(sum, "(Alto I):*NCard  Col   Row   Errors*N")
      until link eq 0 do
         [
         for j = 1 to (2+(1-IsAltoII(host))) do
            PutTemplate(sum, "$2D    ", link!j)
         PutTemplate(sum, "$5D*N", link!(3+(1-IsAltoII(host))))
         link = link!0
         ]
      ]

   // print control memory chip errors
   link = list3!host
   if link ne 0 then Wss(sum, "*NControl memory chips:*NChip  Errors*N")
   until link eq 0 do
      [
      PutTemplate(sum, "$2D    $5D*N", link!1, link!2)
      link = link!0
      ]
   Wss(sum, "*N*N")
   ]
Closes(sum)
finish  // We Juntaed -- simply returning doesn't work anymore.
]

//----------------------------------------------------------------------------
and AddToList(list, item, len) be
//----------------------------------------------------------------------------
[
let listItem = list!hostNum
while listItem ne 0 do
   [
   let found = true
   for i = 1 to len-1 do
      if item!(i-1) ne listItem!i then [ found = false; break ] 
   if found then
      [
      //only smash current count with bigger count
      //so restart of DMT doesn't destroy record of previous errors
      //rshifts force ignorance of sign bit, with loss of bottom bit
      if Usc(listItem!len, item!(len-1)) ls 0 then
         listItem!len = item!(len-1)
      return
      ] 
   listItem = listItem!0
   ]

// Not on list.  Add it
let t = Allocate(sysZone, len+1)
MoveBlock(t+1, item, len)
t!0 = list!hostNum; list!hostNum = t
]

//----------------------------------------------------------------------------
and HashLookup() = valof
//----------------------------------------------------------------------------
[ 
let probe = 0
for i = 1 to token>>String.length do
   probe = probe + token>>String.char↑i
probe = probe & 377b

let entry = hashTab!probe
let found = false
until entry eq 0 % found do
   [ 
   found = true
   for i = 1 to token>>String.length do
      if token>>String.char↑i ne (entry+1)>>String.char↑i then
         [ found = false; break ]
   unless found do entry = entry!0
   ]

if found resultis entry

let wordLen = token>>String.length rshift 1 +1
let t = Allocate(sysZone, wordLen +1)
MoveBlock(t+1, token, wordLen)
t!0 = hashTab!probe; hashTab!probe = t
resultis t
]

//----------------------------------------------------------------------------
and ReadToken() be
//----------------------------------------------------------------------------
[
let number = false
let first = true
token>>String.length = 0
   [
   if Endofs(rpt) return
   termChar = Gets(rpt)
   switchon termChar into
      [
      case $0 to $9:
         [
         if first then number = true
         docase -1
         ]
      case $*N: return
      case $*S: case $*T:
         [
         if first loop
         if number return
         ]
      default: if number return  // otherwise fall into case -1
      case -1:
         [
         first = false
         token>>String.length = token>>String.length+1
         token>>String.char↑(token>>String.length) = termChar
         endcase
         ]
      ]
   ] repeat
]

//----------------------------------------------------------------------------
and StringToNumber(base) = valof
//----------------------------------------------------------------------------
[
let number = 0
for i = 1 to token>>String.length do
   number = number * base + (token>>String.char↑i - $0)
resultis number
]

//----------------------------------------------------------------------------
and SetAltoIIBit(host) be
//----------------------------------------------------------------------------
   AltoIITable!(host rshift 4) = (AltoIITable!(host rshift 4)) %
    (#100000 rshift (host & #17))

//----------------------------------------------------------------------------
and IsAltoII(host) =
   ((AltoIITable!(host rshift 4)) & (#100000 rshift (host & #17))) eq 0? 0, 1
//----------------------------------------------------------------------------