AgentStub.Mesa
Copyright c 1985 by Xerox Corporation. All rights reserved.
Bill Jackson June 25, 1985 3:37:50 am PDT
Bob Hagmann June 24, 1985 4:30:29 pm PDT
BJackson, June 24, 1985 6:40:18 pm PDT
DIRECTORY
CedarNSPrint,
CedarNSPrintRpcControl,
CedarNSPrintUtilsRpcControl,
Commander USING [CommandProc, Register],
CommandTool USING [ArgumentVector, Failed, Parse],
IO USING [PutRope, STREAM],
Process USING [CheckForAbort],
Rope USING [Fetch, Flatten, Length, ROPE],
RPC USING [ImportFailed, ShortROPE],
UserProfile USING [Token];
AgentStub: CEDAR PROGRAM
IMPORTS CedarNSPrint, CedarNSPrintRpcControl, CedarNSPrintUtilsRpcControl, Commander, CommandTool, IO, Process, Rope, RPC, UserProfile =
BEGIN
ROPE: TYPE = Rope.ROPE;
ShortROPE: TYPE = RPC.ShortROPE;
STREAM: TYPE = IO.STREAM;
  Be sure that you've got these guys going...
 Run CedarNSPrintRpcClientImpl.bcd
 Run CedarNSPrintUtilsRpcClientImpl.bcd
  And if you'd rather just so some interpretor based debugging:
 ← CedarNSPrintRpcControl.ImportInterface[[NIL, "Thunderbird"]]
 ← CedarNSPrintUtilsRpcControl.ImportInterface[[NIL, "Thunderbird"]]
 ← &host ← Rope.Flatten["Papermate:PARC:Xerox"]
 ← &addr ← CedarNSPrint.AddressTranslationStringToNetworkAddress[name: LOOPHOLE[&host]]
 ← &file ← Rope.Flatten["[Cherry]<BJackson>Print.scratch$"]
 ← CedarNSPrint.Print[master: LOOPHOLE[&file], printAttributes: NIL, printOptions: NIL, systemElement: LOOPHOLE[&addr]]
Print: PROCEDURE[agent: ShortROPE, printServer: ROPE, master: ROPE, log: STREAM] =
{
noBind: BOOLEANFALSE;
longStringServerName: ROPE;
interpressMaster: ROPE;
serverNSAddress: CedarNSPrint.SystemElement;
chUsed: BOOLEAN;
printRequestID: CedarNSPrint.RequestID;
CedarNSPrintRpcControl.ImportInterface[[NIL, agent] !
RPC.ImportFailed =>
{
noBind ← TRUE;
IO.PutRope[log, "CedarNSPrintRpcControl.ImportInterface from "];
IO.PutRope[log, agent];
IO.PutRope[log, " failed: "];
SELECT why FROM
communications => IO.PutRope[log, "communications"];
badInstance => IO.PutRope[log, "badInstance"];
badVersion => IO.PutRope[log, "badVersion"];
wrongVersion => IO.PutRope[log, "wrongVersion"];
unbound => IO.PutRope[log, "unbound"];
stubProtocol => IO.PutRope[log, "stubProtocol"];
ENDCASE => IO.PutRope[log, "??"];
IO.PutRope[log, ".\n"];
CONTINUE;
}];
IF noBind THEN RETURN;
CedarNSPrintUtilsRpcControl.ImportInterface[[NIL, agent] !
RPC.ImportFailed =>
{
noBind ← TRUE;
IO.PutRope[log, "CedarNSPrintUtilsRpcControl.ImportInterface from "];
IO.PutRope[log, agent];
IO.PutRope[log, " failed: "];
SELECT why FROM
communications => IO.PutRope[log, "communications"];
badInstance => IO.PutRope[log, "badInstance"];
badVersion => IO.PutRope[log, "badVersion"];
wrongVersion => IO.PutRope[log, "wrongVersion"];
unbound => IO.PutRope[log, "unbound"];
stubProtocol => IO.PutRope[log, "stubProtocol"];
ENDCASE => IO.PutRope[log, "??"];
IO.PutRope[log, ".\n"];
CONTINUE;
}];
IF noBind THEN RETURN;
longStringServerName ← Rope.Flatten[printServer];
interpressMaster ← Rope.Flatten[master];
IO.PutRope[log, "Trying to contact Clearinghouse: "];
TRUSTED{[serverNSAddress, chUsed] ← CedarNSPrint.AddressTranslationStringToNetworkAddress[name: LOOPHOLE[longStringServerName, LONG STRING]]};
IF chUsed THEN
IO.PutRope[log, "went to server.\n"]
ELSE
IO.PutRope[log, "local cache hit.\n"];
IO.PutRope[log, "Trying to Print:"];
TRUSTED{printRequestID ← CedarNSPrint.Print[master: LOOPHOLE[interpressMaster, LONG STRING], printAttributes: NIL, printOptions: NIL, systemElement: serverNSAddress]};
IO.PutRope[log, " all"];
TRUSTED{CedarNSPrintRpcControl.UnimportInterface[]};
TRUSTED{CedarNSPrintUtilsRpcControl.UnimportInterface[]};
IO.PutRope[log, " done.\n"];
};
IPPrintCommandProc: Commander.CommandProc = {
[cmd: Handle] RETURNS [result: REFNIL, msg: ROPENIL]
CommandObject = [in, out, err: STREAM, commandLine, command: ROPE, ...]
out: STREAM = cmd.out;
switches: PACKED ARRAY CHAR['a..'z] OF BOOLALL[FALSE];
agent: ShortROPE ← UserProfile.Token["IPPrint.PrintAgent"];
printServer: ROPE ← UserProfile.Token["IPPrint.PrintServer"];
master: ROPE ← UserProfile.Token["IPPrint.PrintScratch"];
nada: BOOL ← TRUE;
ProcessSwitches: PROC [arg: ROPE] = {
sense: BOOLTRUE;
FOR index: INT IN [0..Rope.Length[arg]) DO
char: CHAR ← Rope.Fetch[arg, index];
SELECT char FROM
'- => LOOP;
'~ => {sense ← NOT sense; LOOP};
IN ['a..'z] => switches[char] ← sense;
IN ['A..'Z] => switches[char + ('a-'A)] ← sense;
ENDCASE;
sense ← TRUE;
ENDLOOP;
};
ProcessArgument: PROC [arg: ROPE] = {
argsProcessed ← argsProcessed + 1;
Process.CheckForAbort[];
It is a good idea to periodically check for a process abort request. This should be done whenever a clean point has been reached and some significant processing (1 second, 1 file or 1 phase) has taken place. It is cheap enough to do fairly often.
IF switches['a] THEN {switches['a] ← FALSE; agent ← arg; RETURN};
IF switches['s] THEN {switches['s] ← FALSE; printServer ← arg; RETURN};
master ← arg;
Print[agent, printServer, master, out];
USAGE: Print[-a: agent, -s: printServer, file1, file2, ..., filen];
};
argsProcessed: NAT ← 0;
# of arguments processed
argv: CommandTool.ArgumentVector ← CommandTool.Parse[cmd: cmd, starExpand: FALSE
! CommandTool.Failed => {msg ← errorMsg; GO TO failed}];
When parsing the command line, be prepared for failure. The error is reported to the user
ProcessSwitches[UserProfile.Token["IPPrint.DefaultSwitches"]];
Allows the user to specify personal defaults for the switches via the user's profile.
FOR i: NAT IN [1..argv.argc) DO
Each argument can either be a switch specification or a genuine argument to be processed. The first argument (argv[0]) is not examined, because by convention it is the name of the command as given by the user.
arg: ROPE = argv[i];
Process.CheckForAbort[];
It is a good idea to periodically check for a process abort request.
IF Rope.Length[arg] = 0 THEN LOOP;
Ignore null arguments (it is not easy to generate them, even).
IF Rope.Fetch[arg, 0] = '- THEN {
This argument sets switches for the remaining patterns. By convention, switches are normally "sticky", in that they stay set until explicitly changed.
ProcessSwitches[arg];
LOOP;
};
ProcessArgument[arg];
Perform whatever processing is necessary for a normal argument.
ENDLOOP;
EXITS
failed => {result ← $Failure};
};
doc: ROPE = "IPPrint -- print an interpress master.\nUSAGE: IPPrint <Interpress Master 1> <Interpress Master 2> ...<Interpress Master n>\nSwitches: -a: <XDE-Agent> -s: <8044 Print Server>";
Commander.Register[
key: "///Commands/IPPrint",
key is the name of the command. Registering the command under the "///Commands/" directory indicates that this command should be globally known and useful. If no directory is given, the command is registered under the current working directory, which is the proper place for more specific commands.
proc: IPPrintCommandProc,
proc is called to execute the command.
doc: doc,
doc gives the brief documentation for the command. This should be as brief as possible to remind the user of the function and options.
clientData: NIL,
clientData is passed to the command through cmd.procData.clientData. This is useful when various commands are registered with the same procedure, since the clientData can be used to tell the invocations apart.
interpreted: TRUE
interpreted indicates whether or not the arguments should be scanned for special characters. The default is TRUE, which implies that I/O redicrection characters should be interpreted by the CommandTool.
];
END...