PDPrinterClientImpl.mesa
Michael Plass, April 10, 1984 2:00:07 pm PST
Last Edited by: Pier, November 22, 1983 2:52 pm
DIRECTORY Basics, Commander, Convert, Rope, IO, FS, MessageWindow, PDInterpBasic, PDPrinterRpcControl, PDPrinter, PDPrinterClient, PieViewers, RPC, LupineRuntime, Process, ViewerOps;
PDPrinterClientImpl: CEDAR PROGRAM
IMPORTS Commander, Convert, IO, FS, MessageWindow, PDPrinterRpcControl, PDPrinter, Rope, RPC, LupineRuntime, PieViewers, Process, ViewerOps
EXPORTS PDPrinterClient
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
mess: CARDINAL ← 0;
copiesFieldIndex: NAT ~ 10;
BinaryStreamOptions: PROC RETURNS [s: FS.StreamOptions] ~ {
s ← FS.defaultStreamOptions;
s[tiogaRead] ← FALSE;
};
GetToken: PROC [stream: IO.STREAM] RETURNS [token: ROPENIL] = {
token ← stream.GetTokenRope[Break ! IO.EndOfStream => CONTINUE].token;
};
Break: PROC [char: CHAR] RETURNS [IO.CharClass] = {
IF char = '← OR char = '; THEN RETURN [break];
IF char = ' OR char = '  OR char = ', OR char = '\n THEN RETURN [sepr];
RETURN [other];
};
IsInteger: PROC [rope: ROPE] RETURNS [BOOLEAN] ~ {
IF NOT rope.Length IN [1..3] THEN RETURN [FALSE];
FOR i: INT IN [0..rope.Length) DO
IF rope.Fetch[i] NOT IN ['0..'9] THEN RETURN [FALSE];
ENDLOOP;
RETURN [TRUE];
};
NotAPDFile: PUBLIC ERROR ~ CODE;
CheckPassword: PROC [word0: CARDINAL] ~ {IF word0 # 0AAAAH THEN ERROR NotAPDFile};
Print: PUBLIC PROC [file: Rope.ROPE, server: Rope.ROPE, copies: NAT ← 1, report: IO.STREAMNIL, createFeedbackViewer: BOOLEANTRUE] ~ TRUSTED {
serverRName: Rope.ROPE = server.Concat[".auto"];
interfaceName: RPC.InterfaceName ← [instance: serverRName];
pageNo: INT ← 0;
ReportStatus: SAFE PROC [status: PDInterpBasic.Status, report: IO.STREAMNIL] ~ CHECKED {
stream: IO.STREAMIF report = NIL THEN IO.ROS[] ELSE report;
SELECT status FROM
constructingImage => stream.PutF[" [%g", IO.int[pageNo ← pageNo + 1]];
betweenPages => {IF pageNo > 0 THEN stream.PutChar[']]};
transmissionComplete => stream.PutRope[" done"];
ENDCASE => {stream.PutChar[' ]; stream.Put[IO.refAny[NEW[PDInterpBasic.Status ← status]]]};
IF report = NIL THEN {
MessageWindow.Append[IO.RopeFromROS[stream], mess MOD 4 = 0];
mess ← mess + 1;
};
};
stream: IO.STREAMFS.StreamOpen[fileName: file, streamOptions: BinaryStreamOptions[]
! FS.Error => TRUSTED {
s: IO.STREAMIO.ROS[];
s.PutRope["Unable to open PD file: "];
s.PutRope[error.explanation];
s.PutRope[" ("];
s.Put[IO.rope[file]];
s.PutRope[")"];
IF report = NIL THEN {
MessageWindow.Append[IO.RopeFromROS[s], TRUE];
MessageWindow.Blink[];
}
ELSE {
report.PutRope[IO.RopeFromROS[s]];
};
GOTO Quit;
}
];
response: PDPrinter.Response ← [nextWordIndex: 0, status: betweenPages, currentPage: 0];
dataBlock: PDPrinter.DataBlock;
oldStatus: PDInterpBasic.Status ← transmissionComplete;
bufferPointer: LONG POINTER ← @dataBlock.buffer;
pieViewer: PieViewers.PieViewer ← NIL;
fileSize: INT = stream.GetLength;
PDPrinterRpcControl.ImportInterface[interfaceName
! RPC.ImportFailed => {
s: IO.STREAMIO.ROS[];
s.PutRope["Unable to access PDInterpControl: "];
s.Put[IO.refAny[NEW[RPC.ImportFailure ← why]]];
IF report = NIL THEN {
MessageWindow.Append[IO.RopeFromROS[s], TRUE];
MessageWindow.Blink[];
}
ELSE {
report.PutRope[IO.RopeFromROS[s]];
};
GOTO Quit;
}
];
IF createFeedbackViewer THEN {
pieViewer ← PieViewers.Create[parent: NIL, diameter: 0, total: fileSize];
pieViewer.name ← file.Concat[" to "].Concat[server];
pieViewer.icon ← private;
};
BEGIN ENABLE UNWIND => {PDPrinterRpcControl.UnimportInterface[]; IO.Close[stream]; IF pieViewer # NIL THEN {ViewerOps.DestroyViewer[pieViewer]; pieViewer ← NIL}};
WHILE response.nextWordIndex >= 0 DO
byteIndex: INT ← response.nextWordIndex*2;
bytesRead: INT ← 0;
bytesPerBlock: INT = PDPrinter.maxBlockSize*Basics.bytesPerWord;
stream.SetIndex[byteIndex];
bytesRead ← stream.UnsafeGetBlock[[bufferPointer, 0, bytesPerBlock]];
dataBlock.wordIndex ← response.nextWordIndex;
dataBlock.wordCount ← bytesRead/Basics.bytesPerWord;
IF (copiesFieldIndex-dataBlock.wordIndex) IN [0..dataBlock.wordCount) THEN {
dataBlock.buffer[copiesFieldIndex-dataBlock.wordIndex] ← copies;
};
IF byteIndex = 0 THEN CheckPassword[dataBlock.buffer[0]];
IF pieViewer # NIL THEN PieViewers.Set[pieViewer, fileSize-byteIndex];
response ← PDPrinter.TransmitBlock[dataBlock];
IF response.status # oldStatus THEN {
ReportStatus[response.status, report];
oldStatus ← response.status;
};
ENDLOOP;
END;
IF pieViewer # NIL THEN PieViewers.Set[pieViewer, 0];
PDPrinterRpcControl.UnimportInterface[];
IO.Close[stream];
IF pieViewer # NIL THEN {ViewerOps.DestroyViewer[pieViewer]; pieViewer ← NIL}
EXITS Quit => NULL;
};
PeachCommand: Commander.CommandProc ~ {
cmdStream: IO.STREAMIO.RIS[cmd.commandLine];
server: ROPE ← GetToken[cmdStream];
copies: NAT ← 1;
DO token: ROPE ← GetToken[cmdStream];
IF token.Length = 0 THEN EXIT;
IF IsInteger[token] THEN copies ← Convert.IntFromRope[token]
ELSE {
fileName: ROPE;
cp: FS.ComponentPositions;
[fileName, cp] ← FS.ExpandName[token ! FS.Error => {
IF cmd.out = NIL THEN REJECT ELSE {cmd.out.PutRope[fileName]; cmd.out.PutRope[": "]; cmd.out.PutRope[error.explanation]; CONTINUE}
}];
IF fileName = NIL THEN LOOP;
IF cp.ext.length = 0 THEN {
fileName ← fileName.Replace[cp.ext.start, cp.ext.length, ".pd"];
};
IF cmd.out # NIL THEN {
cmd.out.PutRope["Sending "];
cmd.out.PutRope[fileName];
IF copies # 1 THEN {
cmd.out.PutF[" (%g copies)", IO.int[copies]];
};
cmd.out.PutRope[" to "];
cmd.out.PutRope[server];
cmd.out.PutRope[" . . ."];
};
Print[fileName, server, copies, cmd.out !
LupineRuntime.BindingError => {IF cmd.out # NIL THEN cmd.out.PutRope[" ."]; Process.Pause[Process.MsecToTicks[5000]]; RETRY};
NotAPDFile => {IF cmd.out # NIL THEN cmd.out.PutRope[" not a PD file"]; CONTINUE};
];
IF cmd.out # NIL THEN {
cmd.out.PutRope[";\n"];
};
};
ENDLOOP;
};
Commander.Register["Peach", PeachCommand, "Usage: Peach <Peach server> {[ <copies> ] <PD file name>}, e.g. Peach Melba my 2 foo bar 1 baz sends one copy of my.pd, 2 of foo.pd and bar.pd, and one of baz.pd" ];
END.