// ScavEdit -- Disk editor
// Copyright Xerox Corporation 1979, 1980, 1981, 1982
// Last modified May 2, 1982  2:25 PM by Boggs

get "AltoFileSys.d"
get "Disks.d"
get "BFS.d"

external
[
// outgoing procedures
EditDisk

// incoming procedures
Confirm; Ws; XferPage
PutTemplate; VirtualDiskDA
Puts; Gets; Resets
SimpleDspEraseBits; SimpleDspCharWidth

// incoming statics
sysZone; sysDisk; keys; dsp
label; data; logFlag
]

static
[
address; number; numberTyped; termChar
pageOpen; cellOpen; pageDirty
]

//-----------------------------------------------------------------------------------------
let EditDisk() be
//-----------------------------------------------------------------------------------------
[
logFlag = true  //write log
Ws("*NDisk editor here.  If you don't know what I am type 'Q<cr>' NOW!*N")
ExaminePage(true)

switchon GetNumber() into
   [
   case $/:
      address = number
      ExaminePage(not numberTyped)
      endcase
   case $↑: case $*L:
      test numberTyped
         ifso Ws(" ?")
         ifnot
            [
            address = address + (termChar eq $*L? 1, -1)
            ExaminePage(true)
            ]
      endcase
   case $\:
      test numberTyped % not pageOpen
         ifso Ws(" ?")
         ifnot
            [
            address = VirtualDiskDA(sysDisk, lv label>>DL.previous)
            ExaminePage(true)
            ]
      endcase
   case $L: case $l:
      EditPage(label, 8)
      endcase
   case $D: case $d:
      EditPage(data, 256)
      endcase
   case $Q: case $q:
      if Confirm("*NQuit disk editor [confirm]") break
      endcase
   case $*N:
      Puts(dsp, $*N)
      pageOpen = false
      endcase
   case $*177: endcase
   default: Ws(" ?"); endcase
   ] repeat
]

//-----------------------------------------------------------------------------------------
and EditPage(buffer, length) be
//-----------------------------------------------------------------------------------------
[
if numberTyped % not pageOpen then [ Ws(" ?"); return ]
let diskAddress = address; address = 0
let diskNumber = number; number = 0
pageDirty = false
PutTemplate(dsp, "*NEditing $S record*N", buffer eq label? "label", "data")
ExamineCell(buffer, length, true)

switchon GetNumber() into
   [
   case $/:
      address = number
      ExamineCell(buffer, length, not numberTyped)
      endcase
   case $↑: case $*L:
      if DepositCell(buffer) then
         [
         address = address + (termChar eq $*L? 1, -1)
         ExamineCell(buffer, length, true)
         ]
      endcase
   case $Q: case $q:
      if Confirm("*NQuit page editor [confirm]") break
      endcase
   case $*N:
      Puts(dsp, $*N)
      DepositCell(buffer)
      endcase
   case $*177: endcase
   default: Ws(" ?"); endcase
   ] repeat

number = diskNumber
address = diskAddress
if pageDirty then XferPage(DCwriteLD, address)
ExaminePage(true)
]

//-----------------------------------------------------------------------------------------
and ExaminePage(printAddress) be
//-----------------------------------------------------------------------------------------
[
if address eq eofDA then [ Ws(" ?"); pageOpen = false; return ]
if printAddress then PutTemplate(dsp, "*N$U6Ob", address)
Ws("/   ")

XferPage(DCreadLD, address)
number = VirtualDiskDA(sysDisk, lv label>>DL.next)
PutTemplate(dsp, "SN $EUOb, PN $UD, NC $UD, backP $UOb, nextP $UOb ",
 lv label>>DL.fileId.serialNumber, label>>DL.pageNumber, label>>DL.numChars,
 VirtualDiskDA(sysDisk, lv label>>DL.previous), number)

pageOpen = true
]

//-----------------------------------------------------------------------------------------
and ExamineCell(buffer, length, printAddress) be
//-----------------------------------------------------------------------------------------
[
if address uge length then
   [ if termChar ne $*L then Ws(" ?"); cellOpen = false; return ]
if printAddress then PutTemplate(dsp, "*N$UOb", address)
if buffer eq label then Ws(selecton address into
   [
   case 0: " = next "
   case 1: " = back "
   case 2: " = 0    "
   case 3: " = NC   "
   case 4: " = PN   "
   case 5: " = VN   "
   case 6: " = SN1  "
   case 7: " = SN2  "
   ])
Ws("/   ")

PutTemplate(dsp, "$6UOb   ", buffer!address)
if buffer eq data then  //also display as characters
   [
   let left = buffer!address rshift 8
   let right = buffer!address & 377b
   PutTemplate(dsp, "$3UOb $3UOb   ", left, right)
   PrintChar(left)
   PrintChar(right)
   ]

number = buffer!address
cellOpen = true
]

//-----------------------------------------------------------------------------------------
and PrintChar(char) be
//-----------------------------------------------------------------------------------------
[
if char ls 40b then PutTemplate(dsp, "↑$C", char+100b)
if char ge 40b & char ls 176b then Puts(dsp, char)
]

//-----------------------------------------------------------------------------------------
and DepositCell(buffer) = valof
//-----------------------------------------------------------------------------------------
[
if numberTyped test cellOpen
   ifso
      [
      buffer!address = number
      pageDirty = true
      ]
   ifnot
      [
      Ws(" ?")
      resultis false
      ]
cellOpen = false
resultis true
]

//-----------------------------------------------------------------------------------------
and GetNumber() = valof
//-----------------------------------------------------------------------------------------
[
manifest maxStringChars = 7  //6 octal digits + minus sign
let string = vec maxStringChars  //1 char per word
let count = 0  //chars in string
   [
   termChar = Gets(keys)
   switchon termChar into
      [
      case $0 to $7: case $-:
         if (termChar eq $-) ? (count eq 0), (count ls maxStringChars) then
            [
            Puts(dsp, termChar)
            count = count +1
            string!count = termChar
            ]
         endcase
      case $*001: case $*010:  //↑A, BS
         if count ne 0 then
            [
            SimpleDspEraseBits(dsp, -SimpleDspCharWidth(dsp, string!count))
            count = count -1
            ]
         endcase
      case $*027:  //↑W
         for i = count to 1 by -1 do
            SimpleDspEraseBits(dsp, -SimpleDspCharWidth(dsp, string!i))
         count = 0
         endcase
      case $*177: Ws(" XXX"); count = 0  //falls through
      default: break
      ]
   ] repeat
numberTyped = count ne 0
if numberTyped then
   [
   number = 0
   let minus = false
   if string!1 eq $- then minus = true
   for i = (minus? 2, 1) to count do
      number = number lshift 3 + (string!i & 7)
   if minus then number = -number
   ]
resultis termChar
]