// IfsScavDEdit.bcpl -- a simple disk editor
// Copyright Xerox Corporation 1979
// Last modified December 22, 1979 3:14 PM by Boggs
get "AltoFileSys.d"
get "Streams.d"
get "Disks.d"
get "Tfs.d"
external
[
// outgoing procedures
DiskEditor
// incoming procedures
OpenDisk; CloseDisk; VirtualDiskDA
InitializeDiskCBZ; GetDiskCb; DoDiskCommand
Allocate; Free; Resets; Puts; Gets; Closes
Ws; PutTemplate; EraseBits; CharWidth
ShowDisplayStream; CreateDisplayStream
ScavConfirm; UnsnarfBuffer
PrintDiskError; SysErr
// incoming statics
dsp; keys; sysZone; sysFont; pass
]
static
[
editDisk; label; data; number; address
numberTyped; pageOpen; cellOpen; pageDirty
]
//----------------------------------------------------------------------------
let DiskEditor(buffPtr, numBuffs) be
//----------------------------------------------------------------------------
[
pass = 0
editDisk = OpenDisk("*NWhat disk would you like to edit? ", 0, true, false)
if editDisk eq 0 then
[
for i = 0 to numBuffs-1 do UnsnarfBuffer(buffPtr+i*256)
return
]
// replace the normal tiny display with a giant display
let normalDsp = dsp>>ST.par1
ShowDisplayStream(normalDsp, DSdelete)
dsp>>ST.par1 = CreateDisplayStream(800/((sysFont!-2) & -2),
buffPtr, 256*numBuffs)
ShowDisplayStream(dsp>>ST.par1, DSalone)
let lenData = 1 lshift editDisk>>DSK.lnPageSize
label = Allocate(sysZone, 10)
data = Allocate(sysZone, lenData)
pageOpen = false
address, number = 0, 0
Puts(dsp, $*N)
switchon GetNumber() into
[
case $/:
[
address = number
ExaminePage(not numberTyped)
endcase
]
case $*L:
[
test numberTyped
ifso Oop()
ifnot
[
address = address +1
ExaminePage(true)
]
endcase
]
case $↑:
[
test numberTyped
ifso Oop()
ifnot
[
address = address -1
ExaminePage(true)
]
endcase
]
case $\:
[
test numberTyped % not pageOpen
ifso Oop()
ifnot
[
address = VirtualDiskDA(editDisk, lv label>>DL.previous)
ExaminePage(true)
]
endcase
]
// DiskEditor (cont'd)
case $L: case $l:
[
test numberTyped % not pageOpen
ifso Oop()
ifnot EditPage(label, 10)
endcase
]
case $D: case $d:
[
test numberTyped % not pageOpen
ifso Oop()
ifnot EditPage(data, lenData)
endcase
]
case $Q: case $q:
[
if ScavConfirm("*NQuit Disk editor") break
endcase
]
case $*N:
[
Puts(dsp, $*N)
pageOpen = false
endcase
]
case $*177: [ Ws(" XXX"); endcase ]
default: [ Oop(); endcase ]
] repeat
Free(sysZone, label)
Free(sysZone, data)
CloseDisk(editDisk)
Closes(dsp>>ST.par1)
dsp>>ST.par1 = normalDsp
ShowDisplayStream(dsp>>ST.par1, DSalone)
Puts(dsp, $*N)
for i = 0 to numBuffs-1 do UnsnarfBuffer(buffPtr+i*256)
]
//----------------------------------------------------------------------------
and GetNumber() = valof //returns terminating character
//----------------------------------------------------------------------------
[
manifest maxStringChars = 7 //6 octal digits + minus sign
let string = vec maxStringChars //1 char per word
let count = 0 //chars in string
let char = nil
[
char = Gets(keys)
switchon char into
[
case $0 to $7:
case $-:
[
if (char eq $-) ? (count eq 0), (count ls maxStringChars) then
[
Puts(dsp, char)
count = count +1
string!count = char
]
endcase
]
case $*001: case $*010: //↑A, BS
[
if count ne 0 then
[
EraseBits(dsp>>ST.par1, -CharWidth(dsp>>ST.par1, string!count))
count = count -1
]
endcase
]
case $*027: //↑W
[
for i = count to 1 by -1 do
EraseBits(dsp>>ST.par1, -CharWidth(dsp>>ST.par1, string!i))
count = 0
endcase
]
case $*177: 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 char
]
//----------------------------------------------------------------------------
and Oop() be [ Ws(" ?"); Resets(keys) ]
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
and ExaminePage(displayAddress) be
//----------------------------------------------------------------------------
[
if displayAddress then PutTemplate(dsp, "*N$UO", address)
Ws("/*T")
if DETransferPage(DCreadLD) then
[
PutTemplate(dsp, "FID $EUO;$UO, page number $UO, num chars $UO ",
lv label>>DL.fileId, label!2, label>>DL.pageNumber, label>>DL.numChars)
let previous = VirtualDiskDA(editDisk, lv label>>DL.previous)
let next = VirtualDiskDA(editDisk, lv label>>DL.next)
PutTemplate(dsp, "previous vda $UO, next vda $UO", previous, next)
number = next
pageOpen = true
]
]
//----------------------------------------------------------------------------
and DETransferPage(action) = valof
//----------------------------------------------------------------------------
[
if address eq eofDA then
[
Oop()
pageOpen = false
resultis false
]
let cbz = Allocate(sysZone, CBzoneLength)
InitializeDiskCBZ(editDisk, cbz, 0, CBzoneLength,
TransferRetry, lv TransferError)
TransferRetry:
let cb = GetDiskCb(editDisk, cbz)
cb>>CB.AddrL = label
DoDiskCommand(editDisk, cb, data, address, lv label>>DL.fileId,
label>>DL.pageNumber, action)
while @cbz>>CBZ.queueHead ne 0 do GetDiskCb(editDisk, cbz)
Free(sysZone, cbz)
pageOpen = action eq DCreadLD
resultis true
]
//----------------------------------------------------------------------------
and TransferError(nil, cb, errorCode) be
//----------------------------------------------------------------------------
test errorCode eq ecUnRecovDiskError
ifso PrintDiskError(cb)
ifnot SysErr(0, errorCode, cb)
//----------------------------------------------------------------------------
and EditPage(buffer, length) be
//----------------------------------------------------------------------------
[
PutTemplate(dsp, "*NEdit $S*N", buffer eq label? "label","data")
let diskAddress = address; address = 0
let diskNumber = number; number = 0
pageDirty = false
cellOpen = false
switchon GetNumber() into
[
case $/:
[
address = number
ExamineCell(buffer, length, not numberTyped)
endcase
]
case $*N:
[
DepositCell(buffer)
Puts(dsp, $*N)
endcase
]
case $*L:
[
if DepositCell(buffer) then
[
address = address +1
ExamineCell(buffer, length, true)
]
endcase
]
case $↑:
[
if DepositCell(buffer) then
[
address = address -1
ExamineCell(buffer, length, true)
]
endcase
]
case $Q: case $q:
[
if ScavConfirm("*NQuit page editor") break
endcase
]
case $*177: [ Ws(" XXX"); endcase ]
default: [ Oop(); endcase ]
] repeat
number = diskNumber
address = diskAddress
if pageDirty then
if ScavConfirm("*NRewrite page?") then
DETransferPage(DCwriteLD)
Puts(dsp, $*N)
]
//----------------------------------------------------------------------------
and ExamineCell(buffer, length, printAddress) = valof
//----------------------------------------------------------------------------
[
if printAddress then PutTemplate(dsp, "*N$UO", address)
if buffer eq label then
Ws(selecton address into
[
case 0: " = SN1 "
case 1: " = SN2 "
case 2: " = VN "
case 3: " = PackID "
case 4: " = numChars "
case 5: " = PN "
case 6: " = Prev cyl "
case 7: " = Prev hd, sec "
case 8: " = Next cyl "
case 9: " = Next hd, sec "
default: ""
])
Ws("/*T")
if address ge length % address ls 0 then
[
Oop()
cellOpen = false
resultis false
]
PutTemplate(dsp, "$6UO*T", buffer!address)
if buffer eq data then //also display as characters
[
let left = buffer!address rshift 8
let right = buffer!address & 377b
PutTemplate(dsp, "$3UO $3UO*T", left, right)
PrintChar(left)
PrintChar(right)
]
number = buffer!address
cellOpen = true
resultis 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
//----------------------------------------------------------------------------
//Does nothing if no number was typed
[
if numberTyped test cellOpen
ifso
[
buffer!address = number
pageDirty = true
]
ifnot
[
Oop()
resultis false
]
cellOpen = false
resultis true
]