// TFUutils.bcpl
// Copyright Xerox Corporation 1979
// Last modified November 22, 1980 12:40 PM by Taft
get "AltoFileSys.d"
get "Streams.d"
external
[
//TFU -- export
ReadToken
BackToken
Disambiguate
ReadFile
ReadDrive
StrEq
ReadNumber
Switch
Error
RunEther
PrintEther
InitLog
CloseLog
BigDisplay
SmallDisplay
ReportDebugStats
//TFU -- import
InitDisk
//GP
SetupReadParam
ReadParam
//Template
PutTemplate
//OS
MoveBlock; SetBlock
DoubleAdd
Wss; Wns
Ws; Gets; Puts; Resets; keys; dsp
StartIO
DefaultArgs
MyFrame; Usc; Allocate; SysErr
OpenFile; TruncateDiskStream; Closes
CreateDisplayStream; ShowDisplayStream
//INTERRUPT
FindInterruptMask
InitializeInterrupt
// incoming statics
defaultDrive
sysDisk
str
sw
noConfirm
sysZone
// outgoing static
lastToken
]
static
[
lastToken
backUpToken
EtherCount
sysDsp; myDsp; log; lenBigDisplay; displayLineCount; save335
parsing = false
]
// ReadToken() returns value
// token values:
// 1 = eof on command line
// 2 = command terminator (|)
// 3 = number
// 4 = "Erase"
// 5 = ... remaining commands -- see Disambiguate, below
// 1000 = ambiguous command
//----------------------------------------------------------------------------
let ReadToken() = valof
//----------------------------------------------------------------------------
[
let backedUp = backUpToken
lastToken = valof
[
let a=backUpToken
if a then
[
unless a eq 1 then backUpToken=0
resultis a
]
let ans=ReadParam($P,0,0,0,true)
if ans eq -1 then
[
backUpToken=1
resultis 1
]
resultis Disambiguate(str)
]
unless backedUp do
switchon lastToken into
[
case 1: case 2:
parsing = false; Ws("*n~~~~~~~~~~*n")
endcase
default:
unless parsing do Ws("*n~~~~~~~~~~*n")
parsing = false
Ws(str)
if sw!0 ne 0 then PutTemplate(dsp, "/$US", sw)
Puts(dsp, $*s)
parsing = true
endcase
]
resultis lastToken
]
//----------------------------------------------------------------------------
and BackToken() be backUpToken = lastToken
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
and Disambiguate(str) = valof
//----------------------------------------------------------------------------
// Given a string, disambiguate it from several commands, and return one.
// returns 1000 if cannot make sense of it
[
if str>>STRING.length eq 0 then resultis false
let c=str>>STRING.char↑1
if c eq $| then resultis 2 //vertical bar -- like end of file
if c ge $0 & c le $9 then resultis 3 //Number
let len=str>>STRING.length
let matchNo=nil
let matchCnt=0
for i=4 to 100 do
[
let s=selecton i into
[
case 4: "Erase"
case 5: "Copy"
case 6: "Delete"
case 7: "CreateFile"
case 8: "Directory"
case 9: "Addresses"
case 10: "Certify"
case 11: "Drive"
case 12: "Exercise"
case 13: "Convert"
case 14: "BadSpots"
case 15: "ResetBadSpots"
case 16: "Rename"
default: 1000
]
if s eq 1000 then break //Done
if len gr s>>STRING.length then loop
let match=true
for j=1 to len do
if ((str>>STRING.char↑j xor s>>STRING.char↑j)&(not #40)) ne 0 then
match=false
if match then
[
matchCnt=matchCnt+1
matchNo=i
]
]
if matchCnt eq 1 then resultis matchNo
resultis 1000
]
//----------------------------------------------------------------------------
and ReadFile(nam) = valof
//----------------------------------------------------------------------------
// Read and parse a file name for the disk name first (s: t: tn:) and
// return a pointer to the relevant "disk" object.
// Also update the name to omit the disk tag.
[
let a=ReadToken()
if a le 2 then resultis 0 //End of command ....
let colonfound=0
let len=str>>STRING.length
for i=1 to len do if str>>STRING.char↑i eq $: then colonfound=i
for i=colonfound+1 to len do
nam>>STRING.char↑(i-colonfound)=str>>STRING.char↑i
nam>>STRING.length=len-colonfound
if colonfound le 1 then resultis InitDisk(defaultDrive)
str>>STRING.length=colonfound-1
let drive = ReadDrive(str)
resultis selecton drive into
[
case -1: sysDisk
case -2: Error("Illegal drive -- ", str)
default: InitDisk(drive)
]
]
//----------------------------------------------------------------------------
and ReadDrive(str) = valof
//----------------------------------------------------------------------------
// Interprets string of the form "TPn" or "DPn".
// Returns drive number for TPn, -1 for DP0, and -2 for anything else.
[
let number = 0
let lastNonDigit = 0
for i = 1 to str>>STRING.length do
[
let char = str>>STRING.char↑i
test char ge $0 & char le $7
ifso number = 8*number + (char-$0)
ifnot [ lastNonDigit = i; number = 0 ]
]
str>>STRING.length = lastNonDigit
if StrEq(str, "TP") % StrEq(str, "T") then resultis number
if (StrEq(str, "DP") % StrEq(str, "S")) & number eq 0 then resultis -1
resultis -2
]
//----------------------------------------------------------------------------
and StrEq(a,b) = valof
//----------------------------------------------------------------------------
[
let len=a>>STRING.length
if len ne b>>STRING.length then resultis false
for i=1 to len do
[
let c=a>>STRING.char↑i
let d=b>>STRING.char↑i
if c gr $a & c le $z then c=c-$a+$A
if d gr $a & d le $z then d=d-$a+$A
if c ne d then resultis false
]
resultis true
]
//----------------------------------------------------------------------------
and ReadNumber(str, radix; numargs na) = valof
//----------------------------------------------------------------------------
[
DefaultArgs(lv na, -1, 10)
let n=0
for i=1 to str>>STRING.length do
[
let c=(str>>STRING.char↑i)-$0
if c ls 0 % c ge radix then break
n=n*radix+c
]
resultis n
]
// Returns true if switch ch is in switch vector sw.
//----------------------------------------------------------------------------
and Switch(ch) = valof
//----------------------------------------------------------------------------
[
let swnum=sw!0
for i=1 to swnum do
[
let c=sw!i
if c ge $a & c le $z then c=c-$a+$A
if c eq ch then resultis true
]
resultis false
]
//----------------------------------------------------------------------------
and Error(a,b; numargs n) be
//----------------------------------------------------------------------------
[
Ws("Error -- ")
Ws(a)
if n ne 1 then Ws(b)
Ws("*n")
finish
]
//Stuff to run the EtherNet when disking.
//----------------------------------------------------------------------------
and RunEther() be
//----------------------------------------------------------------------------
[
static eBuf
let EtherRead() be //Interrupt routine
[
@#604=300
@#605=eBuf
StartIO(2) //Restart input
EtherCount=EtherCount+1
]
eBuf=@#335
@#335=eBuf+400
let mask=FindInterruptMask(1)
InitializeInterrupt(eBuf+300, 100, mask, EtherRead)
@#610=0 //Promiscuous reader
@#601=mask //Interrupt mask
]
//----------------------------------------------------------------------------
and PrintEther(s) be if @#601 ne 0 then
//----------------------------------------------------------------------------
[
if EtherCount gr 1 then
[
PutTemplate(s, "[read $UD packets]", EtherCount-1)
EtherCount=0
]
StartIO(3)
]
//----------------------------------------------------------------------------
and ReportDebugStats() be
//----------------------------------------------------------------------------
[
let p = @#645
let s = p!3
if p ne 0 then while s ne p!4 do
[
if s!0 eq -1 break
if s eq p!3 then [ BigDisplay(); Ws("*nTFS debug statistics:") ]
PutTemplate(dsp, "*n status: $6UO, count: $6ED", s!0, s+1)
s = s+3
]
SmallDisplay()
]
//----------------------------------------------------------------------------
and InitLog() be
//----------------------------------------------------------------------------
[
lenBigDisplay = MyFrame()-@#335-5000
if Usc(lenBigDisplay, 10000) gr 0 then lenBigDisplay = 10000
sysDsp = dsp
myDsp = dsp
dsp = Allocate(sysZone, lST)
SetBlock(dsp, SysErr, lST)
dsp>>ST.puts = DisplayPuts
dsp>>ST.reset = DisplayReset
log = OpenFile("TFU.log", ksTypeWriteOnly, charItem)
TruncateDiskStream(log)
]
//----------------------------------------------------------------------------
and CloseLog() be
//----------------------------------------------------------------------------
[
SmallDisplay()
Closes(log)
]
//----------------------------------------------------------------------------
and BigDisplay() be
//----------------------------------------------------------------------------
[
if myDsp eq sysDsp then
[
myDsp = CreateDisplayStream(25, @#335, lenBigDisplay)
save335 = @#335
@#335 = @#335 + lenBigDisplay
ShowDisplayStream(myDsp)
displayLineCount = 0
Wss(log, "*n*n")
]
]
//----------------------------------------------------------------------------
and SmallDisplay() be
//----------------------------------------------------------------------------
[
if myDsp ne sysDsp then
[
unless noConfirm do
[ Wss(myDsp, " (continue?...)"); Gets(keys) ]
Closes(myDsp)
@#335 = save335
myDsp = sysDsp
Wss(log, "*n*n")
]
]
//----------------------------------------------------------------------------
and DisplayPuts(nil, char) be
//----------------------------------------------------------------------------
[
if parsing then
[ parsing = false; Ws("*n~~~~~~~~~~*n") ]
if myDsp ne sysDsp & not noConfirm do
if char eq $*n then
[
displayLineCount = displayLineCount+1
if displayLineCount eq 25 then
[
Wss(myDsp, " (continue?...)"); Gets(keys)
displayLineCount = 0
]
]
Puts(myDsp, char)
Puts(log, char)
]
//----------------------------------------------------------------------------
and DisplayReset(nil) be Resets(myDsp)
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
and Ws(string) be Wss(dsp, string)
//----------------------------------------------------------------------------