// EraseDisk.bcpl - Procedures for making a basic OS disk and
//  extending a file system.
// Copyright Xerox Corporation 1979, 1980, 1982
// Last modified March 15, 1982  4:16 PM by Boggs

get "AltoFileSys.d"
get "Disks.d"
get "BFS.d"
get "Streams.d"
get "SysDefs.d"
get "SysInternals.d"
get "AltoDefs.d"
get "BcplFiles.d"

external
[
// outgoing procedures
EraseDisk; ExtendDisk

// incoming procedures
BFSInit; BFSNewDisk; BFSExtendDisk; BFSTryDisk
AssignDiskPage; ReleaseDiskPage; BFSClose
CreateSysDisk; OpenFile
PositionPage; WriteBlock
Gets; Closes; Resets
Ws; Wo; Wss; GetString; YesNo
Idle

// incoming statics
sysZone; sysDisk
sysFont; sysFontSize
SysErr; keys; CursorLink
]

//----------------------------------------------------------------------------
let EraseDisk() be
//----------------------------------------------------------------------------
// First create a virgin Alto file system using BFSNewDisk,
//  then install the Alto OS files.
[
Ws("   Type the name of a host from which I can get Alto programs: ")
let hostName = vec 20; GetString(hostName)
Ws("   Type the name of the directory where Alto programs are kept.")
Ws("*N   If the host is an IFS or Maxc, this should probably be 'Alto'")
Ws("*N   If the host is just another random Alto, type <return>: ")
let directory = vec 20; GetString(directory)

// Ask user about what size disk he'd like to have.
let nDisks, dirLen = 1, 5000
if BFSTryDisk(1, 0) then
   [
   Ws("   Use both of the disks? ")
   if YesNo() then [ nDisks = 2; dirLen = dirLen*2 ]
   ]
let nTracks = 203
if BFSTryDisk(0, 203) then
   [
   Ws("   Use all 406 cylinders of the disk? ")
   if YesNo() then [ nTracks = 406; dirLen = dirLen*2 ]
   ]
let nSectors = BFSmNSectors
if BFSTryDisk(0, 0, 13) then
   [
   Ws("   Use all 14 sectors of the disk? ")
   if YesNo() then nSectors = 14
   ]
if nDisks eq 1 & nTracks eq 203 then
   [
   Ws("   Do you want a big SysDir? ")
   if YesNo() then dirLen = dirLen*2
   ]

// Now give the user time to reconsider and/or change disks.
Ws("   If you wish to change disks, please do so now.*N")
Ws("   When the disk is ready, type OK to proceed, A to abort: ")
   [
   let c = Gets(keys)
   if c eq $A % c eq $a then [ Ws("*n"); return ]
   unless c eq $O % c eq $o then loop
   Ws("O")
   c = Gets(keys)
   if c eq $K % c eq $k then break
   ] repeat
Ws("K")

// EraseDisk (cont'd)

// Assertion: the only way out of here now is out the bottom.
let savedSysErr = SysErr; SysErr = EraseSysErr
let savedIdle = Idle; Idle = EraseIdle
CursorLink = false

// We should handle fail returns here...
BFSNewDisk(sysZone, 0, nDisks, nTracks, dirLen, nSectors)
sysDisk = BFSInit(sysZone, true, 0)

// Make some files at advertised disk addresses
// The -1 is for the leader page: the boot disk address is page 1 of a file.
// Dumper.boot under the "DU" keys
ReleaseDiskPage(sysDisk, AssignDiskPage(sysDisk, 4608-2))
Closes(OpenFile("Dumper.boot"))
// DMT.boot under the "D" key
ReleaseDiskPage(sysDisk, AssignDiskPage(sysDisk, 3072-2))
Closes(OpenFile("DMT.boot"))
ReleaseDiskPage(sysDisk, AssignDiskPage(sysDisk, 0))

// Patch FTP back to remove crock about page count (see Install.bcpl)
ftpOs>>SV.H.length = ftpOs>>SV.H.length-2

// Write the HiddenFTP.run inside the OS onto Executive.run.
// When we finish, "Executive.run" (really HiddenFTP) will be
//  invoked with a command line to go get the real FTP and Exec.
let s = OpenFile("Executive.Run")
PositionPage(s, 135)  //as of 5/5/79 it was 101 pages long
Resets(s)
WriteBlock(s, ftpOs, ftpOs!-1)
Closes(s)

// Write FTP.Run from the copy saved in memory.  This is used to
//  get the Executive and the full function version of FTP.
s = OpenFile("Ftp.Run")
PositionPage(s, 200)  //as of 5/5/79 it was 176 pages long
Resets(s)
WriteBlock(s, ftpOs, ftpOs!-1)  //HiddenFTP
Closes(s)

// Restore FTP to buggered status (see Install.bcpl)
ftpOs>>SV.H.length = ftpOs>>SV.H.length+2

// FTP command line to retrieve the Exec and FTP
s = OpenFile("Com.cm", ksTypeWriteOnly, charItem)
Wss(s, "Ftp.Run "); Wss(s, hostName)
if directory>>STRING.length ne 0 then
   [ Wss(s, " Directory/c "); Wss(s, directory) ]
Wss(s, " Retrieve/c Executive.Run Ftp.run")
Closes(s)

// Make the current font be SysFont.al on the new disk
s = OpenFile("SysFont.Al")
WriteBlock(s, sysFont-2, sysFontSize)
Closes(s)

// Create Swatee.  This is used by Swat, the Mesa Debugger,
// Bravo, Empress, and others who need a large temporary file.
s = OpenFile("Swatee")
PositionPage(s, 375b+3)
Closes(s)

// Flush DiskDescriptor
BFSClose(sysDisk)
SysErr = savedSysErr
Idle = savedIdle
CursorLink = true

Ws("*N*N*N*N*N*N*N*N")
]

//----------------------------------------------------------------------------
and ExtendDisk() be
//----------------------------------------------------------------------------
[
CreateSysDisk()
if sysDisk>>BFSDSK.nDisks eq 2 then [ BFSClose(sysDisk); return ]
let nTracks = BFSTryDisk(0, 203)? BFS44NTracks, BFS31NTracks
let nDisks = BFSTryDisk(1, 0)? 2, 1
if nDisks ne sysDisk>>BFSDSK.nDisks then
   [
   Ws("   Use both of the disks? ")
   unless YesNo() do nDisks = 1
   ]
if nTracks ne sysDisk>>BFSDSK.nTracks then
   [
   Ws("   Use all 406 cylinders of the disk? ")
   unless YesNo() do nTracks = BFS31NTracks
   ]

// Give user chance to reconsider...
Ws("   Are you sure?  Type OK to proceed, A to abort: ")
   [
   let c = Gets(keys)
   if c eq $A % c eq $a then
      [ Ws("*n"); BFSClose(sysDisk); return ]
   unless c eq $O % c eq $o then loop
   Ws("O")
   c = Gets(keys)
   if c eq $K % c eq $k then break
   ] repeat
Ws("K...")
let savedSysErr = SysErr; SysErr = EraseSysErr
let savedIdle = Idle; Idle = EraseIdle
CursorLink = false

BFSExtendDisk(sysZone, sysDisk, nDisks, nTracks)

BFSClose(sysDisk)
SysErr = savedSysErr
Idle = savedIdle
CursorLink = true
Ws("Done!*N")
]

//----------------------------------------------------------------------------
and EraseSysErr(p, nil, nil, nil, nil, nil; numargs na) be
//----------------------------------------------------------------------------
[
Ws("*NSysErr during EraseDisk or ExtendDisk")
for i = 1 to na do [ Wo((lv p)!(i-1)); Ws(" ") ]
// To debug, insert a disk with Dumper.boot on it, and DumperBoot
p = Gets(keys) repeatuntil p eq $*n  //"DU" won't proceed it
]

//----------------------------------------------------------------------------
and EraseIdle() be
//----------------------------------------------------------------------------
[
let MulDiv = table
   [
   055001B	// sta 3 savedPC,2
   155000B	// mov 2 3
   111000B	// mov 0 2
   102460B	// mkzero 0 0
   061020B	// mul
   031403B	// lda 2 3 3
   061021B	// div
   077400B	// Swat
   121000B	// mov 1 0
   171000B	// mov 3 2
   035001B	// lda 3 savedPC,2
   001401B	// jmp 1,3
   ]
@cursorX = 200 + 200*diskAddress>>DA.disk
@cursorY = diskAddress>>DA.track ls 0? 0,
 20 + MulDiv(808-40-16, diskAddress>>DA.track, 406)
]