2 Copyright © 2010, The AROS Development Team. All rights reserved.
5 Desc: Execute a command after a given time
9 /******************************************************************************
17 D=DATE/K,T=TIME/K,YR=YEARS/K/N,MN=MONTHS/K/N,DY=DAYS/K/N,H=HOURS/K/N,
18 M=MINS/K/N,S=SECS/K/N,L=LOOP/K/N,A=ALWAYS/S,V=VERBOSE/S,HELP/S,CMDLINE/F
26 WaitX will wait for a given amount of time and then it
27 will execute the given command.
31 D=DATE -- Waits until DATE has been reached
32 T=TIME -- Waits until TIME has been reached
33 YR=YEARS -- How many years to wait
34 MN=MONTHS -- How many months to wait
35 DY=DAYS -- How many days to wait
36 H=HOURS -- How many hours to wait
37 M=MINS -- How many minutes to wait
38 S=SECS -- How many seconds to wait
39 L=LOOP -- How many times to execute CMDLINE
40 A=ALWAYS -- Execute CMDLINE every set interval/time/date
41 V=VERBOSE -- Print extra info on what waitx is doing
45 $ waitx TIME=12:34:12 echo "this is an example"
46 waitx waits until 12:34:12 is reached and will execute echo
48 $ waitx H=5 M=36 echo "this is an example"
49 waitx will wait 5 hours and 36 minutes and execute echo
51 $ waitx HOURS=2 MINS=12 SECS=59
52 waitx will wait 2 hours, 12 minutes and 59 seconds and then
55 $ waitx DY=1 L=5 echo "this is an example"
56 waitx will wait 1 day and execute echo,
57 then repeat this a total of 5 times
59 $ waitx M=15 ALWAYS echo "this is an example"
60 waitx will execute echo every 15 minutes
62 $ waitx D=12/9 T=16 L=0 echo "this is an example"
63 waitx will wait until September 12th 16:00 and execute echo,
66 $ waitx echo "this is an example"
67 waitx will execute echo immediatly
73 Based on Public Domain WaitX:
74 http://aminet.net/package/util/cli/waitx
75 Programming: Sigbjørn Skjæret <cisc@c2i.net>
76 Idea & Docs: Nicholas Stallard <snowy@netphile.de>
82 Will not return to prompt while waiting. This is intended.
88 ******************************************************************************/
92 #include <proto/dos.h>
93 #include <proto/exec.h>
94 #include <exec/memory.h>
95 #include <proto/timer.h>
96 #include <proto/utility.h>
97 #include <utility/date.h>
108 const char Version
[] = "$VER: WaitX 2.1 (16.04.2008)";
110 int strtoi(STRPTR string
);
112 LONG
MainEntry(struct ExecBase
*SysBase
);
114 __startup
static AROS_PROCH(Start
, argstr
, argsize
, sBase
)
117 return MainEntry(sBase
);
122 LONG
MainEntry(struct ExecBase
*SysBase
)
124 struct DosLibrary
*DOSBase
= NULL
;
125 struct UtilityBase
*UtilityBase
= NULL
;
126 struct Library
*TimerBase
;
128 BYTE TimerDevice
= -1;
129 struct ClockData
*clock
= NULL
;
130 struct Interval
*interval
= NULL
;
131 struct MsgPort
*TimerPort
= NULL
;
132 struct timerequest
*TimerReq
= NULL
;
133 ULONG i
, loop
, step
, unit
, seconds
= 0, signal
= 0, timesig
= 0, usersig
= SIGBREAKF_CTRL_C
| SIGBREAKF_CTRL_D
| SIGBREAKF_CTRL_E
;
135 BPTR StdErr
= BNULL
, StdIn
;
137 struct RDArgs
*rdargs
= NULL
;
138 STRPTR Template
= "D=DATE/K,T=TIME/K,YR=YEARS/K/N,MN=MONTHS/K/N,DY=DAYS/K/N,H=HOURS/K/N,M=MINS/K/N,S=SECS/K/N,L=LOOP/K/N,A=ALWAYS/S,V=VERBOSE/S,HELP/S,CMDLINE/F";
158 IPTR ArgArray
[TEM_NUMARGS
], ret
;
162 ret
= 20; /* Fatal error if something fails here */
163 if (!(DOSBase
= (struct DosLibrary
*)OpenLibrary("dos.library", 36)))
165 if (!(UtilityBase
= (struct UtilityBase
*)OpenLibrary("utility.library", 36)))
167 if (!(StdErr
= Open("CONSOLE:", MODE_NEWFILE
)))
169 ret
= 0; /* Clear return */
171 GetProgramName(ProgName
, sizeof(ProgName
));
172 for (i
=0; i
<TEM_NUMARGS
; ArgArray
[i
++]=0)
174 rdargs
= ReadArgs(Template
, ArgArray
, NULL
);
176 if (ArgArray
[TEM_HELP
] || !rdargs
)
178 FPrintf(StdErr
, "%s\n\n", &Version
[6]);
179 FPrintf(StdErr
, "Usage: %s [DATE=<DD/MM/YYYY>] [TIME=<HH:MM:SS>] <commandline>\n", ProgName
);
180 FPrintf(StdErr
, "Usage: %s [HOURS=<hours>] [MINS=<mins>] [SECS=<secs>] <commandline>\n", ProgName
);
185 if (ArgArray
[TEM_LOOP
])
186 loop
= *((ULONG
*)ArgArray
[TEM_LOOP
]);
188 if (ArgArray
[TEM_ALWAYS
] || loop
== 0)
194 if (ArgArray
[TEM_CMDLINE
])
195 cmdline
= (STRPTR
)ArgArray
[TEM_CMDLINE
];
197 cmdline
= ""; /* Prevented from Execute()ing later */
199 if (ArgArray
[TEM_DATE
] || ArgArray
[TEM_TIME
] || ArgArray
[TEM_YEARS
] || ArgArray
[TEM_MONTHS
])
201 unit
= UNIT_WAITUNTIL
;
202 if (!(clock
= AllocMem(sizeof(struct ClockData
), MEMF_PUBLIC
| MEMF_CLEAR
)))
204 FPrintf(StdErr
, "Unable to allocate needed memory!\n");
208 if (!(interval
= AllocMem(sizeof(struct Interval
), MEMF_PUBLIC
| MEMF_CLEAR
)))
210 FPrintf(StdErr
, "Unable to allocate needed memory!\n");
215 if (ArgArray
[TEM_YEARS
])
216 interval
->years
= *((ULONG
*)ArgArray
[TEM_YEARS
]);
217 if (ArgArray
[TEM_MONTHS
])
218 interval
->months
= *((ULONG
*)ArgArray
[TEM_MONTHS
]);
219 if (ArgArray
[TEM_DAYS
])
220 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_DAYS
]) * 86400;
221 if (ArgArray
[TEM_HOURS
])
222 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_HOURS
]) * 3600;
223 if (ArgArray
[TEM_MINS
])
224 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_MINS
]) * 60;
225 if (ArgArray
[TEM_SECS
])
226 interval
->seconds
+= *((ULONG
*)ArgArray
[TEM_SECS
]);
228 if (interval
->years
|| interval
->months
|| interval
->seconds
)
236 if (ArgArray
[TEM_DAYS
])
237 seconds
+= *((ULONG
*)ArgArray
[TEM_DAYS
]) * 86400;
238 if (ArgArray
[TEM_HOURS
])
239 seconds
+= *((ULONG
*)ArgArray
[TEM_HOURS
]) * 3600;
240 if (ArgArray
[TEM_MINS
])
241 seconds
+= *((ULONG
*)ArgArray
[TEM_MINS
]) * 60;
242 if (ArgArray
[TEM_SECS
])
243 seconds
+= *((ULONG
*)ArgArray
[TEM_SECS
]);
246 if (seconds
> 0 || clock
)
248 if (!(TimerPort
= CreateMsgPort()))
250 FPrintf(StdErr
, "Couldn't create Timer-MsgPort!\n");
254 if (!(TimerReq
= (struct timerequest
*)CreateIORequest(TimerPort
, sizeof(struct timerequest
))))
256 FPrintf(StdErr
, "Couldn't create Timer-IORequest!\n");
260 if ((TimerDevice
= OpenDevice(TIMERNAME
, unit
, (struct IORequest
*)TimerReq
, 0)))
262 FPrintf(StdErr
, "Couldn't open %s!\n", TIMERNAME
);
267 TimerBase
= (struct Library
*)TimerReq
->tr_node
.io_Device
;
268 timesig
= 1L << TimerPort
->mp_SigBit
;
272 GetSysTime(&TimerReq
->tr_time
); /* Get current System Time */
273 Amiga2Date(TimerReq
->tr_time
.tv_secs
, clock
); /* Fill in current date/time as default */
275 if (ArgArray
[TEM_DATE
])
277 tmpptr
= (STRPTR
)ArgArray
[TEM_DATE
];
278 clock
->mday
= strtoi(tmpptr
);
279 if ((tmpptr
= strstr(tmpptr
, "/")))
281 clock
->month
= strtoi(++tmpptr
);
282 if ((tmpptr
= strstr(tmpptr
, "/")))
284 clock
->year
= strtoi(++tmpptr
);
292 else if (!interval
->set
)
294 interval
->months
= 1;
298 if (clock
->year
< 100) /* Be nice to digit-challenged ppl. ;) */
300 if (clock
->year
< 78)
301 clock
->year
+= 2000; /* If less than 78, assume 20xx */
306 else if (!interval
->set
)
308 interval
->seconds
= 86400;
312 if (ArgArray
[TEM_TIME
])
314 tmpptr
= (STRPTR
)ArgArray
[TEM_TIME
];
315 clock
->hour
= strtoi(tmpptr
);
316 clock
->min
= clock
->sec
= 0; /* Clear default time */
317 if ((tmpptr
= strstr(tmpptr
, ":")))
319 clock
->min
= strtoi(++tmpptr
);
320 if ((tmpptr
= strstr(tmpptr
, ":")))
321 clock
->sec
= strtoi(++tmpptr
);
325 if (!(seconds
= CheckDate(clock
)))
327 FPrintf(StdErr
, "Invalid date/time!\n");
331 if (seconds
<= TimerReq
->tr_time
.tv_secs
)
335 for (i
=0; i
<count
; i
+=step
)
337 clock
->year
+= interval
->years
;
338 clock
->month
+= interval
->months
;
340 if (clock
->month
> 12) /* We need some annual magic */
343 clock
->year
+= clock
->month
/ 12;
346 if (!(seconds
= CheckDate(clock
)))
348 clock
->mday
-= 1; /* If date doesn't exist, try previous day */
349 if (!(seconds
= CheckDate(clock
)))
352 if (!(seconds
= CheckDate(clock
)))
355 if (!(seconds
= CheckDate(clock
)))
357 FPrintf(StdErr
, "Invalid date/time!\n");
365 clock
->mday
+= 1; /* Restore day for future reference */
368 if (interval
->seconds
)
370 seconds
+= interval
->seconds
;
371 Amiga2Date(seconds
, clock
);
374 if (loop
> 0 && step
> 0)
376 if (seconds
> TimerReq
->tr_time
.tv_secs
)
380 if (seconds
<= TimerReq
->tr_time
.tv_secs
|| loop
== 0)
382 FPrintf(StdErr
, "Date/time has already passed!\n");
386 else if (ArgArray
[TEM_VERBOSE
])
388 FPrintf(StdErr
, "Note: Schedule has been moved to %02lu/%02lu/%lu %02lu:%02lu:%02lu because the assigned date/time has already passed",
389 (ULONG
)clock
->mday
, (ULONG
)clock
->month
, (ULONG
)clock
->year
, (ULONG
)clock
->hour
, (ULONG
)clock
->min
, (ULONG
)clock
->sec
);
392 FPrintf(StdErr
, ".\n");
394 FPrintf(StdErr
, " (%lu loop(s) left).\n", loop
);
400 if (IsInteractive((StdIn
= Input())))
401 StdIn
= BNULL
; /* Don't use StdIn if it isn't redirected */
403 for (i
=0; i
<loop
; i
+=step
)
407 TimerReq
->tr_time
.tv_secs
= seconds
;
408 TimerReq
->tr_time
.tv_micro
= 0;
409 TimerReq
->tr_node
.io_Command
= TR_ADDREQUEST
;
411 SendIO((struct IORequest
*)TimerReq
);
412 signal
= Wait(timesig
| usersig
);
414 if (signal
& usersig
)
416 AbortIO((struct IORequest
*)TimerReq
);
417 WaitIO((struct IORequest
*)TimerReq
);
418 SetSignal(0L, timesig
| usersig
); /* Clear signalbits since WaitIO most likely preserves them */
420 if (signal
& SIGBREAKF_CTRL_C
)
425 if (cmdline
[0] == '\0')
426 break; /* There's no point in going on */
427 if (!(signal
& SIGBREAKF_CTRL_D
))
429 if (!Execute(cmdline
, StdIn
, Output()))
431 FPrintf(StdErr
, "Unable to execute \"%s\".\n", cmdline
);
437 break; /* Don't go into tight unbreakable loop */
441 clock
->year
+= interval
->years
;
442 clock
->month
+= interval
->months
;
444 if (clock
->month
> 12) /* We need some annual magic */
447 clock
->year
+= clock
->month
/ 12;
450 if (!(seconds
= CheckDate(clock
)))
452 clock
->mday
-= 1; /* If date doesn't exist, try previous day */
453 if (!(seconds
= CheckDate(clock
)))
456 if (!(seconds
= CheckDate(clock
)))
459 if (!(seconds
= CheckDate(clock
)))
461 FPrintf(StdErr
, "Invalid date/time!\n");
469 clock
->mday
+= 1; /* Restore day for future reference */
472 if (interval
->seconds
)
474 seconds
+= interval
->seconds
;
475 Amiga2Date(seconds
, clock
);
479 if (ArgArray
[TEM_VERBOSE
] && (i
+1<loop
|| step
== 0))
481 FPrintf(StdErr
, "Next scheduled execution ");
484 FPrintf(StdErr
, "at %02lu/%02lu/%lu %02lu:%02lu:%02lu", (ULONG
)clock
->mday
, (ULONG
)clock
->month
, (ULONG
)clock
->year
,
485 (ULONG
)clock
->hour
, (ULONG
)clock
->min
, (ULONG
)clock
->sec
);
487 FPrintf(StdErr
, "in %lu hours, %lu minutes and %lu seconds", seconds
/ 3600, (seconds
% 3600) / 60, seconds
% 60);
490 FPrintf(StdErr
, ".\n");
492 FPrintf(StdErr
, " (%lu loop(s) left).\n", loop
-i
-1);
498 FreeMem(clock
, sizeof(struct ClockData
));
500 FreeMem(interval
, sizeof(struct Interval
));
503 CloseDevice((struct IORequest
*)TimerReq
);
505 DeleteIORequest((struct IORequest
*)TimerReq
);
507 DeleteMsgPort(TimerPort
);
514 CloseLibrary((struct Library
*)DOSBase
);
520 /* A simple atoi()-alike function because it does what we need, and no more. */
521 int strtoi(STRPTR string
)
525 for (i
=0,num
=0; string
[i
]>='0' && string
[i
]<='9'; ++i
)
526 num
= 10 * num
+ (string
[i
] - '0');