//MFTP.bcpl // Mag Tape Utility // for ethernet use // April 28, 1980 12:58 PM // Last modified by Tim Diebert, June 9, 1980 10:46 AM get "Pup.decl" get "TSP.decl" get "Tapes.d" external [ InitPupLevel1; OpenLevel1Socket; CloseLevel1Socket; SetAllocation OpenRTPSocket; CreateBSPStream; GetPartner BSPForceOutput; BSPGetMark; BSPPutMark; BSPWriteBlock InitializeContext; CallContextList; Block; Enqueue; Unqueue InitializeZone; CreateDisplayStream; ShowDisplayStream Gets; Puts; Closes; Endofs; Ws; Wss; Wo; Wos; EraseBits; CharWidth keys; dsp; OpenFile; WriteBlock; ReadBlock; CallSwat ] static [ myDsp; bspSoc; bspStr; ctxQ; tspBuffer; file; blk; status; error ] let Mftp() be // initialization [ Ws("*n MFTP, Magtape File Transfer Program, version 1.2, June 9, 1980") let myZone = vec 10000; InitializeZone(myZone, 10000) let q = vec 1; ctxQ = q; ctxQ!0 = 0 InitPupLevel1(myZone,ctxQ,5) let v = vec 300 blk = v let v = vec 1040 tspBuffer = v let v = vec 9000 myDsp = CreateDisplayStream(40, v, 9000) ShowDisplayStream(myDsp) let v = vec 3000 Enqueue(ctxQ, InitializeContext(v, 3000, TopLevel)) CallContextList(ctxQ!0) repeat ] and TopLevel() be // top-level process [ Wss(myDsp,"*nConnect to (CR to exit program): ") let name = vec 127; GetString(name) if name>>String.length eq 0 then finish let frnPort = vec lenPort unless GetPartner(name, dsp, frnPort, 0, tapeSocket) do loop let v = vec lenBSPSoc; bspSoc = v OpenLevel1Socket(bspSoc, 0, frnPort) unless OpenRTPSocket(bspSoc, ctxQ) do [ Wss(myDsp,"*nFailed to connect") CloseLevel1Socket(bspSoc) loop ] Wss(myDsp,"*nOpen!") bspStr = CreateBSPStream(bspSoc) let keysToNetCtx = vec 2000 Enqueue(ctxQ, InitializeContext(keysToNetCtx, 2000, KeysToNet)) Block () repeatuntil bspSoc>>BSPSoc.state ne stateOpen % @#177035 eq #177775 //second blank key pressed Unqueue(ctxQ, keysToNetCtx) Closes(bspStr) Wss(myDsp,"*nConnection Closed!") ] repeat and KeysToNet() be [ //Establish connection, open drive, then // wait for key, r VersionCommand(); GetReply() OpenCommand(); GetReply() let fname = vec 127 while true do [ error = false Wss(myDsp,"*nCommand (? for help): "); let char = GetKeys() switchon char into [ case $c: [ Wss(myDsp," Close Connection") CloseConnection() endcase ] case $r: [ Wss(myDsp," Read file, filename? ") Block() GetString(fname) file = OpenFile(fname) unless file do [ Wss(myDsp," file system error ") endcase ] let done = false let recordCount = 0 until done % error do [ //get and print blocks until eof or error ReadRecordCommand() done = ReadReply() recordCount = recordCount + 1 ] test error ifso Wss(myDsp,"Read error") ifnot [ Wss(myDsp," ") Wos(myDsp,recordCount-1) Wss(myDsp, " records read") ] Closes(file); endcase ] case $w: [ Wss(myDsp," Write file, filename? ") Block() GetString(fname) file = OpenFile(fname,ksTypeReadOnly,wordItem) unless file do [ Wss(myDsp," file does not exist") endcase ] Wss(myDsp,"*nRecord size in bytes (1024) ") let rsize = GetNumber() if rsize eq 0 then [ Wss(myDsp, " used 1024") rsize = 1024 ] if rsize gr 2048 then [ Wss(myDsp, " used 2048") rsize = 2048 ] let recordCount = 0 until Endofs(file) % error do [ //get and print blocks until eof or error WriteRecordCommand(file,rsize) WriteReply() recordCount = recordCount + 1 ] test error ifso [ Wss(myDsp,"Error on Write") ] ifnot [ EOFCommand(); WriteReply() Wos(myDsp,recordCount) Wss(myDsp, " records written") ] Closes(file); endcase ] case $f: [ Wss(myDsp," Fwd skip file, how many: ") let n = GetNumber(); if n eq 0 then [ Wss(myDsp, "1") n = 1 ] status = 0 until (n eq 0) % error % status<<Status.EOT do [ n = n-1 FileFwdCommand() GetYesNo() if error then [ test status<<Status.EOT ifso Wss(myDsp, "can't skip past EOT") ifnot Wss(myDsp, "error in skip") ] ] endcase ] case $b: [ Wss(myDsp," Back skip file, how many: ") let n = GetNumber(); if n eq 0 then [ Wss(myDsp, "1") n = 1 ] status = 0 until (n eq 0) % error % status<<Status.BOT do [ n = n-1 FileBackCommand() GetYesNo() if error then Wss(myDsp, "error in skip") if status<<Status.BOT then Wss(myDsp, " At beginning of tape") ] endcase ] case $u: [ Wss(myDsp," Rewind") RewindCommand() GetReply() endcase ] case $?: [ Wss(myDsp,"*nc=Close, r=Read file, w=Write file, f=Fwd skip file, b=Back skip file, u=Rewind") endcase ] default: [ Wss(myDsp," Bad command") endcase ] ] ] ] and GetReply() be [ //get block let b = 0; let hi = GetFromBsp() lshift 8 let len = hi + GetFromBsp() tspBuffer!0 = len for b = 1 to len-1 do [ hi = GetFromBsp() lshift 8 tspBuffer!b = hi + GetFromBsp() ] ] and GetFromBsp() = valof [ let c = -1 until c ge 0 do [ Block() c = Gets(bspStr) ] resultis c ] and ReadReply() = valof [ //get block and if not error or eof, print data GetReply() //fill block status = tspBuffer>>HereIsRecord.endingStatus let i = status & #374 //error bits if i then error = true //error if status<<Status.EOF then resultis true //EOF if status<<Status.EOT then error = true //EOT unless status<<Status.RDY then error = true //not ready unless status<<Status.ONL then error = true //not on line let len = tspBuffer>>HereIsRecord.recordLength WriteBlock(file,lv tspBuffer>>HereIsRecord.record,(len+1)/2) resultis false //not done ] and WriteReply() = valof [ //get block and if not error or eof, return false //result=done GetReply() //fill block status = tspBuffer>>YesNo.code let i = status & #374 //error bits if i then error = true //error if status<<Status.EOF then error = true //EOF if status<<Status.EOT then error = true //EOT unless status<<Status.RDY then error = true //not ready unless status<<Status.ONL then error = true //not on line resultis false //not done ] and GetYesNo() be [ GetReply() //only check error, not EOF, EOT, or BOT status = tspBuffer>>YesNo.code let i = status & #374 //error bits if i then error = true //error unless status<<Status.RDY then error = true //not ready unless status<<Status.ONL then error = true //not on line ] and VersionCommand() be [ //send [Version] block blk>>Version.type = cmdVersion //type field blk>>Version.versno = 0 //version numeric let str = "Version 1.0 Tape Server Protocol" let len = 3 + ((str>>String.length + 2) / 2) blk>>Version.length = len let i = 0 for i = 0 to len-4 do [ (lv blk>>Version.verstext)!i = str!i //add text in ] BSPWriteBlock(bspStr,blk,0,2*len) //send this block BSPForceOutput(bspSoc) //now ] and OpenCommand() be [ //send [OpenDrive] block blk>>OpenDrive.type = cmdOpenDrive //type field blk>>OpenDrive.driveNumber = 0 //drive 0 let str = "Glenn" let len = 3 + ((str>>String.length + 2) / 2) blk>>OpenDrive.length = len let i = 0 for i = 0 to len-4 do [ (lv blk>>OpenDrive.userID)!i = str!i //add text in ] BSPWriteBlock(bspStr,blk,0,2*len) //send this block BSPForceOutput(bspSoc) //now ] and CloseCommand() be [ //send [CloseDrive] block blk>>CloseDrive.type = cmdCloseDrive //type field blk>>CloseDrive.length = 2 //this is whole message BSPWriteBlock(bspStr,blk,0,4) //send this block BSPForceOutput(bspSoc) //now ] and EOFCommand() be [ //send [WriteEOF] block blk>>WriteEndOfFile.type = cmdWriteEOF //type field blk>>WriteEndOfFile.length = 2 //this is whole message BSPWriteBlock(bspStr,blk,0,4) //send this block BSPForceOutput(bspSoc) //now ] and RewindCommand() be [ //send [Rewind] block blk>>Rewind.type = cmdRewind //type field blk>>Rewind.length = 2 //this is whole message BSPWriteBlock(bspStr,blk,0,4) //send this block BSPForceOutput(bspSoc) //now ] and ReadRecordCommand() be [ //send [ReadRecord] block Wss(myDsp, ".") blk>>ReadRecord.type = cmdReadRecord //type field blk>>ReadRecord.length = 2 //this is whole message BSPWriteBlock(bspStr,blk,0,4) //send this block BSPForceOutput(bspSoc) //now ] and WriteRecordCommand(file,rsize) be [ //send [WriteRecord] block Wss(myDsp, ".") tspBuffer>>WriteRecord.type = cmdWriteRecord //type field let len = ReadBlock(file, lv tspBuffer>>WriteRecord.record,rsize/2) tspBuffer>>WriteRecord.length = len+3 tspBuffer>>WriteRecord.recordLength = 2*len BSPWriteBlock(bspStr,tspBuffer,0,6+2*len) //send this block BSPForceOutput(bspSoc) //now ] and FileFwdCommand() be [ //send [FwdSpaceFile] block blk>>FwdSpaceFile.type = cmdFwdSpaceFile //type field blk>>FwdSpaceFile.length = 2 //this is whole message BSPWriteBlock(bspStr,blk,0,4) //send this block BSPForceOutput(bspSoc) //now ] and FileBackCommand() be [ //send [BackSpaceFile] block blk>>BackSpaceFile.type = cmdBackSpaceFile //type field blk>>BackSpaceFile.length = 2 //this is whole message BSPWriteBlock(bspStr,blk,0,4) //send this block BSPForceOutput(bspSoc) //now ] and CloseConnection() be [ Closes(bspStr) ] and GetKeys() = valof [ while Endofs(keys) do Block() resultis Gets(keys) ] and GetString(string) be [ let i = 1 while i le 255 do [ let char = GetKeys() switchon char into [ case 127: [ i = 1 Wss(myDsp,"XXX*n") endcase //del ] case $*n: [ string>>String.length = i-1 return endcase //cr ] case 8: [ if i gr 1 then //backspace [ i = i - 1 EraseBits(myDsp, -CharWidth(myDsp, string>>String.char↑i)) ] endcase ] default: [ string>>String.char↑i = char Puts(myDsp, char) i = i + 1 endcase ] ] ] ] and GetNumber() = valof [ let s = vec 127 //string let d = 0 //digit let n = -1 while n ls 0 do [ n = 0 GetString(s) let i = 0 while (i ls s>>String.length) & (n ge 0) do [ i = i+1 n = n * 10 //new digit d = (s>>String.char↑i) - 48 n = n + d if (d ls 0) % (d gr 9) then n = -1 ] if n ls 0 then [ Wss(myDsp," Bad number*n") n = 0 ] ] resultis n ]