<<>> <> <> <> <> <> <<>> 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: 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.Cat[ "usage: ", repeatCommandDoc]; GO TO failed}]; <> argc: NAT _ argv.argc; commandLine: ROPE; startTime: BasicTime.GMT _ BasicTime.nullGMT; period: INT _ Days; nTimes: INT _ LAST[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 ANY _ NIL, msg: ROPE _ NIL]>> argv: CommanderOps.ArgumentVector _ CommanderOps.Parse[cmd: cmd ! CommanderOps.Failed => {msg _ Rope.Cat[ "usage: ", atCommandDoc]; GO TO failed}]; <> 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}; }; <> 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. <> <> <<>> <> <> <> <<>>