<> <> <> <> <> DIRECTORY Atom USING [PropList, GetProp, GetPropFromList, MakeAtom], BasicTime USING [Period, GMT, Now], Containers USING [Container], Convert USING [Error, CardFromRope, IntFromRope], FS USING [ ComponentPositions, Error, EnumerateForNames, ExpandName, NameProc, StreamOpen, StreamOptions, defaultStreamOptions], IO USING [ card, Close, GetBlock, PutBlock, GetTokenRope, IDProc, EndOf, EndOfStream, Error, int, PutF, PutFR, PutRope, RIS, rope, RopeFromROS, ROS, STREAM], Labels USING [Label, Set], List USING [Reverse], Process USING [Pause, SecondsToTicks], Rope USING [Concat, Equal, Find, IsEmpty, Index, Replace, ROPE, Substr], STP USING [Close, Create, CreateRemoteStream, Error, Handle, IsOpen, Login, Open], TapeToolInternal USING [Action, TapeTool, TapeToolOp, WaitForResponse, GetToolParameters], TapeOps USING [BackSpaceFile, CloseDrive, DriveNumber, ForwardSpaceFile, GetStatus, OpenDrive, Rewind, TapeHandle, TapeOpsError, TapeStatus, TapeStatusIndex, Unload], TapeStreams USING [ConversionRecord, ConversionList, Error, StreamOpen, TapeRecordProc], ViewerClasses USING [Viewer], ViewerTools USING [SetContents], UserCredentials USING [Get]; TapeToolOpsImpl: CEDAR PROGRAM IMPORTS Atom, BasicTime, Convert, FS, IO, Labels, List, Process, Rope, STP, TapeOps, TapeToolInternal, TapeStreams, ViewerTools, UserCredentials EXPORTS TapeToolInternal = BEGIN OPEN Tool: TapeToolInternal; ROPE: TYPE ~ Rope.ROPE; STREAM: TYPE ~ IO.STREAM; ExecuteOp: PUBLIC PROC [tool: Tool.TapeTool, op: Tool.Action] = BEGIN ENABLE {ABORTED => tool.typeScript.PutRope["Aborted\n"]; -- ABORTED is terminated by the queue UNWIND => {ViewerTools.SetContents[tool.question, " "]; IF tool.AbortNow THEN tool.AbortNow _ FALSE;}}; tool.params _ Tool.GetToolParameters[]; IF tool.AbortNow THEN BEGIN tool.AbortNow _ FALSE; MyError[tool, NIL]; END; SELECT op.op FROM Open => Open[tool, op]; Close => Close[tool]; Rewind => Rewind[tool]; Unload => Unload[tool]; Status => Status[tool]; Read => ReadFile[tool, op]; Write => WriteFile[tool, op]; FSF => FwdSpFile[tool]; BSF => BkSpFile[tool]; ENDCASE => ERROR; ViewerTools.SetContents[tool.question, " "]; END; myAborted: ERROR = CODE; -- Internal Procs MyError: PROC [tool: Tool.TapeTool, message: ROPE] = BEGIN ENABLE UNWIND => NULL; IF NOT message.IsEmpty[] THEN tool.typeScript.PutRope[message]; ERROR ABORTED; END; Open: PROC [tool: Tool.TapeTool, op: Tool.Action] = BEGIN OPEN TapeOps; ENABLE UNWIND => NULL; tape: TapeHandle _ tool.tapeHandle; dr: INT; tool.serverName _ IF NOT op.serverName.IsEmpty[] THEN op.serverName ELSE tool.params.defaultServer; dr _ Convert.IntFromRope[op.driveNumberRope ! Convert.Error => MyError[tool, "Invalid drive number.\n"]]; tool.typeScript.PutF["Opening to %g ... ", IO.rope[tool.serverName]]; IF dr NOT IN TapeOps.DriveNumber THEN MyError[tool, "Invalid drive number.\n"]; tool.driveNumber _ dr; IF tool.open THEN { tool.typeScript.PutRope["Connection already open.\n"]; RETURN; }; tape _ OpenDrive[tool.serverName, tool.driveNumber, tool.density ! TapeOps.TapeOpsError => {tool.open _ FALSE; MyError[tool, ec.Concat[" .. "]];}]; IF tape # NIL THEN tool.typeScript.PutF["%g\n", IO.rope[tape.versionString]] ELSE { tool.typeScript.PutRope["Did not open.\n"]; RETURN; }; tool.tapeHandle _ tape; tool.open _ TRUE; PrintStatus[tool]; tool.outer.guardDestroy _ TRUE; END; Close: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; tape: TapeHandle; IF tool = NIL THEN RETURN; tape _ tool.tapeHandle; IF NOT OpenCheck[tool] THEN RETURN; tool.fileNumber _ 0; tool.typeScript.PutF["Closing connection with %g\n", IO.rope[tool.serverName]]; tape.CloseDrive[]; -- Won't raise any errors. tool.open _ FALSE; PrintStatus[tool]; tool.tapeHandle _ NIL; tool.outer.guardDestroy _ FALSE; END; ReadFile: PROC [tool: Tool.TapeTool, op: Tool.Action] = BEGIN ENABLE UNWIND => NULL; s, out: STREAM _ NIL; wDir: ROPE _ op.opWDir; list: LIST OF ROPE _ NIL; cp: FS.ComponentPositions; stp: STP.Handle _ STP.Create[]; curServer: ROPE _ NIL; starInUse: BOOL _ FALSE; fileRope, fullFName, starRope: ROPE _ NIL; starFileNumber: CARDINAL _ 0; conversions: TapeStreams.ConversionList _ NIL; CloseAll: PROC [message: ROPE] = BEGIN IF s # NIL THEN {s.Close[ ! TapeStreams.Error => CONTINUE]; s _ NIL }; IF out # NIL THEN {out.Close[ ! STP.Error => CONTINUE; FS.Error => CONTINUE]; out _ NIL }; IF stp # NIL AND stp.IsOpen[] THEN stp.Close[ ! STP.Error => CONTINUE]; PrintStatus[tool]; MyError[tool, (IF message.IsEmpty[] THEN NIL ELSE message.Concat[" .. "])]; END; ReadFile: PROC [fileName: ROPE] RETURNS [BOOL] = BEGIN ENABLE {UNWIND => NULL; TapeStreams.Error => CloseAll[error.explanation]; FS.Error => CloseAll[error.explanation]; STP.Error => CloseAll[error]; IO.Error => SELECT ec FROM NotImplementedForThisStream => CloseAll["Improper conversion chosen!"]; ENDCASE => CloseAll["Unexpected IO error!"]; myAborted => CloseAll[NIL];}; tool.inUseRecordCount _ 0; tool.inUseByteCount _ 0; s _ TapeStreams.StreamOpen[tape: tool.tapeHandle, padding: tool.fillBlock, conversions: conversions, tapeRecordProc: TapeRecordProc, clientData: tool]; tool.fileNumber _ tool.fileNumber + 1; IF s.EndOf[] THEN BEGIN tool.atEndOfTape _ TRUE; tool.typeScript.PutRope["End Of Tape Reached\n"]; RETURN [FALSE]; END; IF cp.server.length = 0 THEN out _ FS.StreamOpen[fileName: fullFName, accessOptions: $create] ELSE { out _ CreateSTPStoreStream[tool, stp, fullFName, curServer]; curServer _ Rope.Substr[fullFName, cp.server.start, cp.server.length]}; TransferTheFile[tool: tool, from: s, to: out]; out.Close[]; s.Close[]; RETURN [TRUE]; END; list _ GetRopeList[op.opFiles]; IF list = NIL THEN {tool.typeScript.PutRope["Please set file name field.\n"]; RETURN;}; conversions _ GetConversions[tool, op ! BadConversions => GOTO Punt ]; IF NOT OpenCheck[tool] THEN RETURN; DO yes: BOOL; fileRope _ list.first; IF EOTCheck[tool] THEN RETURN; IF fileRope.Find["*"] >= 0 THEN {starInUse _ TRUE; starRope _ fileRope;}; IF starInUse THEN BEGIN starFileNumber _ starFileNumber + 1; fileRope _ fileRope.Replace[fileRope.Index[0, "*"], 1, IO.PutFR["%g", IO.card[starFileNumber]]]; END; [fullFName: fullFName, cp: cp] _ FS.ExpandName[fileRope, wDir ! FS.Error => { IF stp # NIL AND stp.IsOpen THEN stp.Close[ ! STP.Error => CONTINUE]; MyError[tool, error.explanation.Concat[" .. "]]}]; IF (NOT tool.params.localDisk) AND (cp.server.length = 0) THEN { tool.typeScript.PutRope["Stores to local files illegal.\n"]; IF stp # NIL AND stp.IsOpen THEN stp.Close[ ! STP.Error => CONTINUE]; RETURN; }; ViewerTools.SetContents[tool.question, IO.PutFR["%g <= tape", IO.rope[fullFName]]]; yes _ Tool.WaitForResponse[tool]; IF yes THEN BEGIN start: BasicTime.GMT _ BasicTime.Now[]; sec: INT _ 0; tool.typeScript.PutF["Starting read into %g ... ", IO.rope[fullFName]]; IF NOT ReadFile[fullFName] THEN EXIT; ViewerTools.SetContents[tool.question, " "]; sec _ BasicTime.Period[start, BasicTime.Now[]]; tool.typeScript.PutF[" Done.\n%g bytes read, in %g records. (%g bits/sec)\n", IO.int[tool.inUseByteCount], IO.int[tool.inUseRecordCount], IO.int[(tool.inUseByteCount*8)/(sec+1)]]; END ELSE RETURN; IF NOT starInUse THEN {list _ list.rest; IF list = NIL THEN EXIT; }; ENDLOOP; IF stp # NIL AND stp.IsOpen THEN stp.Close[ ! STP.Error => CONTINUE]; EXITS Punt => NULL; END; TapeRecordProc: TapeStreams.TapeRecordProc = BEGIN --PROC [clientData: REF ANY _ NIL] ENABLE UNWIND => NULL; tool: Tool.TapeTool _ NARROW[clientData]; tool.inUseRecordCount _ tool.inUseRecordCount + 1; PrintStatus[tool]; Labels.Set[tool.recordCountLabel, IO.PutFR["File number: %5g Records %g: %8g", IO.card[tool.fileNumber], IO.rope[tool.inUseOp], IO.int[tool.inUseRecordCount]]]; IF tool.tapeHandle.status[errSE] THEN IO.PutRope[tool.typeScript, " SE "]; IF tool.AbortNow THEN { tool.AbortNow _ FALSE; ERROR myAborted}; END; TransferTheFile: PROCEDURE [tool: Tool.TapeTool, from, to: IO.STREAM] = BEGIN ENABLE UNWIND => NULL; buffer: REF TEXT = NEW[TEXT[1024]]; buffer.length _ buffer.maxLength; DO nBytes: NAT = from.GetBlock[buffer, 0, buffer.maxLength]; to.PutBlock[buffer, 0, nBytes]; tool.inUseByteCount _ tool.inUseByteCount + nBytes; IF from.EndOf[] THEN EXIT; ENDLOOP; END; WriteFile: PROC [tool: Tool.TapeTool, op: Tool.Action] = BEGIN ENABLE UNWIND => NULL; so: FS.StreamOptions _ FS.defaultStreamOptions; in, s: STREAM; list: LIST OF ROPE _ NIL; fullFNameList, tail: LIST OF ROPE _ NIL; cp: FS.ComponentPositions; blocking: INT; openNew, fileFound: BOOL _ FALSE; headFileList, tailFileList: REF FileList _ NIL; FileList: TYPE ~ RECORD [ next: REF FileList _ NIL, file: ROPE _ NIL ]; stp: STP.Handle _ STP.Create[]; fileRope, wDir, server, currentServer: ROPE _ NIL; conversions: TapeStreams.ConversionList _ NIL; CloseAll: PROC [message: ROPE] = BEGIN IF s # NIL THEN {s.Close[ ! TapeStreams.Error => CONTINUE]; s _ NIL }; IF in # NIL THEN {in.Close[ ! STP.Error => CONTINUE; FS.Error => CONTINUE]; in _ NIL }; IF stp # NIL AND stp.IsOpen[] THEN stp.Close[ ! STP.Error => CONTINUE]; PrintStatus[tool]; MyError[tool, (IF message.IsEmpty[] THEN NIL ELSE message.Concat["\n"])]; END; IF NOT OpenCheck[tool] THEN RETURN; IF EOTCheck[tool] THEN RETURN; list _ GetRopeList[op.opFiles]; IF list = NIL THEN {tool.typeScript.PutRope["Please set file name field.\n"]; RETURN;}; IF tool.params.localDisk THEN so[tiogaRead] _ NOT op.tiogaRead; wDir _ op.opWDir; blocking _ Convert.IntFromRope[op.opBlockingRope ! Convert.Error => MyError[tool, "Invalid blocking factor.\n"]]; IF blocking < 10 THEN BEGIN tool.typeScript.PutF["Blocking factor less than 10: %g\n", IO.rope[op.opBlockingRope]]; RETURN; END; tool.typeScript.PutRope["Enumerating file list ... "]; DO error: BOOL _ FALSE; nameProc: FS.NameProc = BEGIN <> IF tailFileList = NIL THEN headFileList _ tailFileList _ NEW[FileList] ELSE {tailFileList.next _ NEW[FileList]; tailFileList _ tailFileList.next;}; [cp: cp] _ FS.ExpandName[fullFName]; IF (NOT tool.params.localDisk) AND (cp.server.length = 0) THEN BEGIN tool.typeScript.PutRope["Fetch from local files illegal.\n"]; error _ TRUE; RETURN [FALSE]; END; tailFileList.file _ fullFName; fileFound _ TRUE; RETURN [TRUE]; END; fileRope _ list.first; IF fileRope.Find["!"] < 0 THEN fileRope _ fileRope.Concat["!H"]; FS.EnumerateForNames[fileRope, nameProc, wDir ! FS.Error => MyError[tool, error.explanation.Concat["\n"]];]; IF error THEN {tool.typeScript.PutRope[" Done\n"]; RETURN;}; list _ list.rest; IF list = NIL THEN {tool.typeScript.PutRope[" Done\n"]; EXIT;}; ENDLOOP; IF NOT fileFound THEN {tool.typeScript.PutRope["Did not find file(s)!\n"]; RETURN;}; IF (tailFileList _ headFileList) = NIL THEN {tool.typeScript.PutRope["Did not find file(s)!\n"]; RETURN;}; conversions _ GetConversions[tool, op ! BadConversions => GOTO Punt ]; DO yes: BOOL; start: BasicTime.GMT; sec: INT _ 0; fullFName: ROPE _ tailFileList.file; tool.responseNeeded _ TRUE; [cp: cp] _ FS.ExpandName[fullFName]; ViewerTools.SetContents[tool.question, IO.PutFR["tape <-- %g", IO.rope[fullFName]]]; yes _ Tool.WaitForResponse[tool]; IF yes THEN BEGIN ENABLE {UNWIND => NULL; TapeStreams.Error => CloseAll[error.explanation]; FS.Error => CloseAll[error.explanation]; STP.Error => CloseAll[error]; IO.Error => SELECT ec FROM NotImplementedForThisStream => CloseAll["Improper conversion chosen!"]; ENDCASE => CloseAll["Unexpected IO error!"]; myAborted => CloseAll[NIL];}; server _ fullFName.Substr[cp.server.start, cp.server.length]; start _ BasicTime.Now[]; IF NOT server.Equal[currentServer, FALSE] THEN BEGIN currentServer _ server; IF stp # NIL THEN IF stp.IsOpen[] THEN stp.Close[]; openNew _ TRUE; END ELSE openNew _ FALSE; tool.inUseRecordCount _ 0; tool.inUseByteCount _ 0; in _ IF cp.server.length = 0 THEN FS.StreamOpen[fileName: fullFName, streamOptions: so] ELSE CreateSTPRetrieveStream[tool: tool, stp: stp, fullFName: fullFName, openNew: openNew]; s _ TapeStreams.StreamOpen[tape: tool.tapeHandle, access: write, padding: tool.fillBlock, blocking: blocking, conversions: conversions, tapeRecordProc: TapeRecordProc, clientData: tool]; tool.fileNumber _ tool.fileNumber + 1; tool.typeScript.PutF["Starting write from %g ... ", IO.rope[fullFName]]; TransferTheFile[tool: tool, from: in, to: s]; s.Close[]; in.Close[]; sec _ BasicTime.Period[start, BasicTime.Now[]]; tool.typeScript.PutF[" Done.\n%g bytes written (not including padding), in %g records. (%g bits/sec)\n", IO.int[tool.inUseByteCount], IO.int[tool.inUseRecordCount - 1], IO.int[(tool.inUseByteCount*8)/(sec+1)]]; ViewerTools.SetContents[tool.question, " "]; END; IF tailFileList.next = NIL THEN EXIT; tailFileList _ tailFileList.next; ENDLOOP; IF stp # NIL THEN IF stp.IsOpen[] THEN stp.Close[]; EXITS Punt => NULL; END; Status: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; ENABLE { UNWIND => NULL; TapeOpsError => MyError[tool, ec]; }; status: TapeStatus; IF NOT OpenCheck[tool] THEN RETURN; status _ tool.tapeHandle.GetStatus[]; PrintStatus[tool]; RETURN; END; Rewind: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; ENABLE { UNWIND => NULL; TapeOpsError => MyError[tool, ec]; }; status: TapeStatus; IF NOT OpenCheck[tool] THEN RETURN; tool.atEndOfTape _ FALSE; status _ tool.tapeHandle.Rewind[FALSE]; tool.fileNumber _ 0; DO Process.Pause[Process.SecondsToTicks[1]]; status _ tool.tapeHandle.GetStatus[]; PrintStatus[tool]; IF tool.tapeHandle.status[RDY] OR tool.tapeHandle.status[BOT] THEN EXIT; IF tool.AbortNow THEN BEGIN tool.AbortNow _ FALSE; MyError[tool, NIL]; END; ENDLOOP; END; Unload: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; ENABLE { UNWIND => NULL; TapeOpsError => MyError[tool, ec]; }; tape: TapeHandle _ tool.tapeHandle; IF NOT OpenCheck[tool] THEN RETURN; tool.atEndOfTape _ FALSE; [] _ tool.tapeHandle.Unload[]; PrintStatus[tool]; tool.typeScript.PutF["Closing connection with %g\n", IO.rope[tool.serverName]]; tape.CloseDrive[]; Labels.Set[tool.statusLabel, "Connection Closed"]; tool.fileNumber _ 0; Labels.Set[tool.recordCountLabel, IO.PutFR["File number: %5g", IO.card[tool.fileNumber]]]; tool.tapeHandle _ NIL; tool.open _ FALSE; tool.outer.guardDestroy _ FALSE; END; FwdSpFile: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; ENABLE { UNWIND => NULL; TapeOpsError => MyError[tool, ec]; }; tape: TapeHandle _ tool.tapeHandle; IF NOT OpenCheck[tool] THEN RETURN; IF EOTCheck[tool] THEN RETURN; [] _ tool.tapeHandle.ForwardSpaceFile[]; tool.fileNumber _ tool.fileNumber + 1; PrintStatus[tool]; END; BkSpFile: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; ENABLE { UNWIND => NULL; TapeOpsError => MyError[tool, ec]; }; tape: TapeHandle _ tool.tapeHandle; IF NOT OpenCheck[tool] THEN RETURN; tool.atEndOfTape _ FALSE; [] _ tool.tapeHandle.BackSpaceFile[]; IF tool.fileNumber > 0 THEN tool.fileNumber _ tool.fileNumber - 1; PrintStatus[tool]; END; PrintStatus: PROC [tool: Tool.TapeTool] = BEGIN OPEN TapeOps; dont: BOOL _ FALSE; status: TapeStatus _ tool.tapeHandle.status; stat: WORD _ LOOPHOLE[status]; myS: STREAM _ IO.ROS[]; IF NOT tool.open THEN {Labels.Set[tool.statusLabel, "Connection Closed"]; RETURN;}; IF stat = 0 THEN myS.PutRope["Tape not ready"]; IF status[EOT] AND status[BOT] THEN { myS.PutRope["Tape not mounted"]; dont _ TRUE; }; IF NOT dont THEN FOR reason: TapeStatusIndex IN TapeStatusIndex DO IF status[reason] THEN myS.PutRope[tapeExplanation[reason]] ELSE myS.PutRope[" "]; ENDLOOP; Labels.Set[tool.statusLabel, myS.RopeFromROS[]]; Labels.Set[tool.recordCountLabel, IO.PutFR["File number: %5g", IO.card[tool.fileNumber]]]; RETURN; END; CreateSTPRetrieveStream: PROC [tool: Tool.TapeTool, stp: STP.Handle, fullFName: ROPE, openNew: BOOL] RETURNS [outStream: STREAM] = BEGIN ENABLE UNWIND => NULL; user, password, server, file: ROPE _ NIL; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] _ FS.ExpandName[fullFName]; server _ fullFName.Substr[cp.server.start, cp.server.length]; file _ fullFName.Substr[cp.dir.start-1]; [user, password] _ UserCredentials.Get[]; IF stp = NIL THEN stp _ STP.Create[]; stp.Login[user, password]; IF openNew THEN [ ] _ stp.Open[server ! STP.Error => IF code = connectionRejected OR tool.AbortNow THEN RETRY ELSE REJECT]; outStream _ stp.CreateRemoteStream[file: file, access: read]; RETURN [outStream]; END; CreateSTPStoreStream: PROC [tool: Tool.TapeTool, stp: STP.Handle, fullFName: ROPE, curServer: ROPE _ NIL] RETURNS [inStream: STREAM] = BEGIN ENABLE UNWIND => NULL; user, password, server, file: ROPE _ NIL; cp: FS.ComponentPositions; [fullFName: fullFName, cp: cp] _ FS.ExpandName[fullFName]; server _ fullFName.Substr[cp.server.start, cp.server.length]; file _ fullFName.Substr[cp.dir.start-1]; [user, password] _ UserCredentials.Get[]; stp.Login[user, password]; IF NOT Rope.Equal[server, curServer, FALSE] THEN BEGIN IF STP.IsOpen[stp] THEN STP.Close[stp]; [ ] _ stp.Open[server ! STP.Error => IF code = connectionRejected AND NOT tool.AbortNow THEN {tool.typeScript.PutRope["\nConnection rejected; retrying .. "]; Process.Pause[Process.SecondsToTicks[1]]; RETRY} ELSE REJECT]; END; inStream _ stp.CreateRemoteStream[file: file, access: write, fileType: binary, creation: BasicTime.Now[]]; END; OpenCheck: PROC [tool: Tool.TapeTool] RETURNS [b: BOOL _ TRUE] = BEGIN IF NOT tool.open THEN { tool.typeScript.PutRope["Please open connection\n"];RETURN [FALSE]; }; END; EOTCheck: PROC [tool: Tool.TapeTool] RETURNS [b: BOOL _ FALSE] = BEGIN IF tool.atEndOfTape THEN {tool.typeScript.PutRope["At end of tape.\n"]; RETURN [TRUE];}; END; GetRopeList: PROC [r: ROPE] RETURNS [list: LIST OF ROPE _ NIL] = BEGIN s: STREAM _ IO.RIS[r]; tail: LIST OF ROPE _ NIL; DO r: ROPE _ s.GetTokenRope[IO.IDProc ! IO.EndOfStream => EXIT].token; rL: LIST OF ROPE; rL _ CONS[r, NIL]; IF list = NIL THEN list _ rL ELSE tail.rest _ rL; tail _ rL; ENDLOOP; END; GetConversions: PROC [ tool: Tool.TapeTool, op: Tool.Action ] RETURNS [ conversions: TapeStreams.ConversionList _ NIL ] = BEGIN cNames: ROPE = op.opConversions; cns: IO.STREAM = IO.RIS[cNames]; DO c: ATOM = Atom.MakeAtom[cns.GetTokenRope[breakProc: IO.IDProc ! IO.EndOfStream => EXIT].token]; pl: Atom.PropList = NARROW[Atom.GetProp[$TapeTool, $Conversions]]; cr: REF TapeStreams.ConversionRecord _ NARROW[Atom.GetPropFromList[pl, c]]; IF cr = NIL THEN GOTO Punt; IF cr.name = $ToEbcdic THEN BEGIN lc: LONG CARDINAL = Convert.CardFromRope[op.oplreclRope ! Convert.Error => GOTO Bad]; blocking: LONG CARDINAL = Convert.CardFromRope[op.opBlockingRope ! Convert.Error => GOTO Bad1]; IF lc # 0 AND blocking MOD lc # 0 THEN GOTO Bad; cr.clientData _ NEW [CARDINAL _ 0]; NARROW[cr.clientData, REF CARDINAL]^ _ lc; END; conversions _ CONS[cr, conversions]; REPEAT Bad => { tool.typeScript.PutRope["Bad lrecl value!\n"]; ERROR BadConversions}; Bad1 => { tool.typeScript.PutRope["Bad blocking value!\n"]; ERROR BadConversions}; Punt => { tool.typeScript.PutRope["Improper format conversions!\n"]; ERROR BadConversions}; ENDLOOP; TRUSTED { conversions _ LOOPHOLE[List.Reverse[LOOPHOLE[conversions]]]}; END; BadConversions: ERROR = CODE; NilRope: TYPE = Rope.ROPE _ NIL; tapeExplanation: ARRAY TapeOps.TapeStatusIndex OF NilRope = [ RDY: "Rdy ", ONL: "Onl ", RWD: "Rwd ", FPT: "WP ", BOT: "BOT ", EOT: "EOT ", FMK: "FMK ", NRZI: "NRZI ", errHE: "HE ", errSE: "SE ", errDL: "DL ", errRDP: "RDP ", errICL: "ICL ", errHDW: "Hdw ", errWFP: "FP ", errCMD: "Cmd " ]; END...