RepeatCommandImpl.mesa
Copyright Ó 1986, 1987, 1988, 1990, 1991, 1992 by Xerox Corporation. All rights reserved.
Carl Hauser, February 3, 1987 11:02:30 am PST
Wes Irish, May 25, 1988 11:08:38 am PDT
Willie-s, February 7, 1992 6:25 pm PST
DIRECTORY
BasicTime USING [GMT, Now, Period, Update, nullGMT],
Commander USING [CommandProc, Handle, Register],
CommanderOps USING [DoCommand, ArgumentVector, Failed, Parse],
Convert USING [Error, IntFromRope],
IO USING [PutF, PutRope],
List USING [Assoc],
Process USING [Pause, SecondsToTicks],
ProcessProps USING [GetPropList],
Rope USING [Cat, Concat, ROPE],
RepeatCommand,
Tempus USING [Parse, Unintelligible];
RepeatCommandImpl:
CEDAR
PROGRAM
IMPORTS BasicTime, Commander, CommanderOps, Convert, IO, List, Process, ProcessProps, Rope, Tempus
EXPORTS RepeatCommand
~ BEGIN
OPEN RepeatCommand;
repeatCommandDoc: ROPE = "\"Command line to be performed\" [period [\"Start time interpretable by Tempus\" [nTimes]]] [&]
period defaults to 24*60*60 (one day)
startTime defaults to BasicTime.Now[]
nTimes defaults to LAST[INT]
use the & (as usual) if you want this forked";
atCommandDoc: ROPE = "\"Start time interpretable by Tempus\" \"Command line to be performed\" [&]
use the & (as usual) if you want this forked";
Repeat:
PUBLIC
PROC [cmd:
ROPE, period:
INT ¬ Days, start: BasicTime.
GMT ¬ Immediately, nTimes:
INT ¬ Forever] ~ {
aborting: BOOL ¬ FALSE;
nextTime: BasicTime.GMT ¬ IF start = BasicTime.nullGMT THEN BasicTime.Now[] ELSE start;
parent: Commander.Handle = NARROW[List.Assoc[$CommanderHandle, ProcessProps.GetPropList[]]];
FOR i:
INT
IN [0..nTimes)
WHILE
NOT aborting
DO
parent.out.PutF["-- Waiting until %g to execute: %g\n", [time[nextTime]], [rope[cmd]]];
IF WaitForTime[nextTime]
THEN {
[] ¬ CommanderOps.DoCommand[commandLine: cmd, parent: parent];
nextTime ¬ BasicTime.Update[nextTime, period];
}
ELSE aborting ¬ TRUE;
ENDLOOP;
parent.out.PutRope[IF aborting THEN "... aborting command.\n" ELSE "Done.\n"];
};
WaitForTime:
PROC [time: BasicTime.
GMT]
RETURNS [ok:
BOOL] ~ {
ENABLE {
ABORTED => GOTO AbortRequested;
};
timeLeft: INT;
WHILE (timeLeft ¬ BasicTime.Period[ from: BasicTime.Now[], to: time ]) > 0
DO
Process.Pause[Process.SecondsToTicks[MIN[timeLeft, 1000]]];
ENDLOOP;
RETURN[TRUE];
EXITS
AbortRequested => RETURN[FALSE];
};
RepeatCommandProc: Commander.CommandProc = {
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd
! CommanderOps.Failed => {msg ¬ Rope.Concat[ "usage: ", repeatCommandDoc]; GO TO failed}];
When parsing the command line, be prepared for failure. The error is reported to the user.
argc: NAT ¬ argv.argc;
commandLine: ROPE;
startTime: BasicTime.GMT ¬ BasicTime.nullGMT;
period: INT ¬ Days;
nTimes: INT ¬ LAST[INT];
IF argc < 2 THEN {msg ¬ Rope.Concat[ "usage: ", repeatCommandDoc]; GO TO failed};
commandLine ¬ argv[1];
IF argc >= 3
THEN period ¬ Convert.IntFromRope[argv[2] ! Convert.Error => {
msg ¬ Rope.Cat[ "Can't Parse \"", argv[2], "\" as an INT"]; GO TO failed}];
IF argc >= 4
THEN startTime ¬ Tempus.Parse[argv[3] ! Tempus.Unintelligible => {
msg ¬ Rope.Cat[ "Can't Parse \"", argv[3], "\" as a time"]; GO TO failed}].time;
IF argc >= 5
THEN nTimes ¬ Convert.IntFromRope[argv[4] ! Convert.Error => {
msg ¬ Rope.Cat[ "Can't Parse \"", argv[4], "\" as an INT"]; GO TO failed}];
Repeat[commandLine, period, startTime, nTimes];
EXITS
failed => {result ¬ $Failure};
};
AtCommandProc: Commander.CommandProc = {
[cmd: Commander.Handle] RETURNS [result: REF ANY ← NIL, msg: ROPE ← NIL]
argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd
! CommanderOps.Failed => {msg ¬ Rope.Concat[ "usage: ", atCommandDoc]; GO TO failed}];
When parsing the command line, be prepared for failure. The error is reported to the user.
argc: NAT ¬ argv.argc;
commandLine: ROPE;
startTime: BasicTime.GMT ¬ BasicTime.nullGMT;
IF argc # 3 THEN {msg ¬ Rope.Concat[ "usage: ", atCommandDoc]; GO TO failed};
startTime ¬ Tempus.Parse[argv[1]
! Tempus.Unintelligible => {
msg ¬ Rope.Cat[ "Can't Parse \"", argv[1], "\" as a time"]; GO TO failed};
].time;
commandLine ¬ argv[2];
Repeat[commandLine, 0, startTime, 1];
EXITS
failed => {result ¬ $Failure};
};
Initialization
Commander.Register[
key: "Repeat",
proc: RepeatCommandProc,
doc: repeatCommandDoc,
clientData: NIL,
interpreted: TRUE
];
Commander.Register[
key: "At",
proc: AtCommandProc,
doc: atCommandDoc,
clientData: NIL,
interpreted: TRUE
];
END.
Carl Hauser, February 3, 1987 11:02:02 am PST
Register command in current working directory rather than ///Commands/
Wes Irish, May 19, 1988 11:07:16 pm PDT
Added "At" command
Added the ability to abort pending commands and "Waiting until ..." message