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; 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 = { argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd ! CommanderOps.Failed => {msg ¬ Rope.Concat[ "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.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 = { argv: CommanderOps.ArgumentVector ¬ CommanderOps.Parse[cmd: cmd ! CommanderOps.Failed => {msg ¬ Rope.Concat[ "usage: ", atCommandDoc]; GO TO failed}]; 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}; }; 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. N 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 [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] When parsing the command line, be prepared for failure. The error is reported to the user. [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL] When parsing the command line, be prepared for failure. The error is reported to the user. Initialization 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 Êñ•NewlineDelimiter –(cedarcode) style™™Icodešœ ÏeœN™ZKšœ*Ïk™-Kšœ'™'K™&J™—šž ˜ Kšœ žœžœ ˜4Kšœ žœ!˜0Kšœ žœ,˜>Kšœžœ˜#Kšžœžœ˜Kšœžœ ˜Kšœžœ˜&Kšœ žœ˜!Kšœžœžœ˜Kšœ˜Kšœžœ˜%K˜—šÏnœžœžœ˜!Kšžœ.žœ+˜bKšžœ˜Kšœžœ˜Kšžœ˜K˜—šžœžœžœ˜K˜—Kšœžœÿ˜•K˜Kšœžœ˜‘K˜šŸœžœžœžœ žœžœžœ˜rKšœ žœžœ˜Kš œžœžœžœžœ˜WKšœžœ;˜\š žœžœžœ žœžœ ž˜/KšœW˜Wšžœžœ˜K˜>K˜.K˜Kšžœ žœ˜—Kšžœ˜—Kšœžœ žœžœ ˜NK˜K˜—š Ðbn œžœžœžœžœ˜>šžœ˜Kšžœžœ˜K˜—Kšœ žœ˜šžœFž˜MKšœ%žœ˜;Kšžœ˜—Kšžœžœ˜ šž˜Kšœžœžœ˜ —K˜K˜—•StartOfExpansionL -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]šŸœ˜,Kš œžœ žœžœžœžœžœ™H–I[cmd: Commander.Handle, starExpand: BOOL _ FALSE, switchChar: CHAR]˜?KšœKžœžœ ˜ZKšœ[™[—Kšœžœ ˜Kšœ žœ˜Kšœžœ˜-Kšœžœ˜Kšœžœžœžœ˜K˜Kšžœ žœ3žœžœ ˜QK˜šžœ žœ:˜KKšœ<žœžœ ˜K—šžœ žœ>˜OKšœ<žœžœ˜P—šžœ žœ:˜KKšœ<žœžœ ˜K—K˜K˜/K˜šž˜K˜—K˜K˜K˜—–L -- [cmd: Commander.Handle] RETURNS [result: REF ANY _ NIL, msg: ROPE _ NIL]šŸ œ˜(Kš œžœ žœžœžœžœžœ™H–I[cmd: Commander.Handle, starExpand: BOOL _ FALSE, switchChar: CHAR]˜?KšœGžœžœ ˜VKšœ[™[—Kšœžœ ˜Kšœ žœ˜Kšœžœ˜-K˜Kšžœ žœ/žœžœ ˜M˜ šœ˜Kšœ<žœžœ ˜J—Kšœ˜—K˜K˜Kšœ%˜%K˜šž˜K˜—K˜K˜K˜—head–x[key: ROPE, proc: Commander.CommandProc, doc: ROPE _ NIL, clientData: REF ANY _ NIL, interpreted: BOOL _ TRUE]™šœ˜Kšœ˜Kšœ˜Kšœ˜Kšœ žœ˜Kšœ ž˜Kšœ˜K˜—šœ˜Kšœ ˜ Kšœ˜Kšœ˜Kšœ žœ˜Kšœ ž˜Kšœ˜K˜——Kšžœ˜šœ*ž™-K™F—K™šœ$ž™'K™K™K—K™—…—`Ÿ