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];
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
NameProc: TYPE = PROC [fullFName: ROPE] RETURNS [continue: BOOLEAN];
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[];
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...