RepeatCommandImpl.mesa
Copyright © 1986, 1987, 1988, 1990, 1991 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 21, 1991 9:26 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, 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;
ROPE: TYPE = Rope.ROPE;
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: BOOLFALSE;
nextTime: BasicTime.GMTIF 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 ANYNIL, msg: ROPENIL]
argv: CommanderOps.ArgumentVector ← CommanderOps.Parse[cmd: cmd
! CommanderOps.Failed => {msg ← Rope.Cat[ "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: INTLAST[INT];
IF argc < 2 THEN {msg ← Rope.Cat[ "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 ANYNIL, msg: ROPENIL]
argv: CommanderOps.ArgumentVector ← CommanderOps.Parse[cmd: cmd
! CommanderOps.Failed => {msg ← Rope.Cat[ "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.Cat[ "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