summaryrefslogtreecommitdiff
path: root/Src/Builtins/sched.c
diff options
context:
space:
mode:
authorPeter Stephenson <pws@users.sourceforge.net>2006-09-10 15:24:26 +0000
committerPeter Stephenson <pws@users.sourceforge.net>2006-09-10 15:24:26 +0000
commitb726ead94e911e1ce3e8b582c315b3d6f83a6eb7 (patch)
tree6298d1215ba8a55aa8cac4fd536de3af91bbb4b2 /Src/Builtins/sched.c
parent638b0da9704add12fff91868efdfbb2dd35f0b54 (diff)
downloadzsh-b726ead94e911e1ce3e8b582c315b3d6f83a6eb7.tar.gz
zsh-b726ead94e911e1ce3e8b582c315b3d6f83a6eb7.zip
22676, 22678: extend sched and make it able to run events when waiting for
input
Diffstat (limited to 'Src/Builtins/sched.c')
-rw-r--r--Src/Builtins/sched.c295
1 files changed, 206 insertions, 89 deletions
diff --git a/Src/Builtins/sched.c b/Src/Builtins/sched.c
index 558a00ba6..c32a5f219 100644
--- a/Src/Builtins/sched.c
+++ b/Src/Builtins/sched.c
@@ -34,61 +34,156 @@
typedef struct schedcmd *Schedcmd;
+/* Flags for each scheduled event */
+enum schedflags {
+ /* Trash zle if necessary when event is activated */
+ SCHEDFLAG_TRASH_ZLE = 1
+};
+
struct schedcmd {
struct schedcmd *next;
char *cmd; /* command to run */
time_t time; /* when to run it */
+ int flags; /* flags as above */
};
/* the list of sched jobs pending */
static struct schedcmd *schedcmds;
+/* Check scheduled commands; call this function from time to time. */
+
+/**/
+static void
+checksched(void)
+{
+ time_t t;
+ struct schedcmd *sch;
+
+ if(!schedcmds)
+ return;
+ t = time(NULL);
+ /*
+ * List is ordered, so we only need to consider the
+ * head element.
+ */
+ while (schedcmds && schedcmds->time <= t) {
+ /*
+ * Remove the entry to be executed from the list
+ * before execution: this makes quite sure that
+ * the entry hasn't been monkeyed with when we
+ * free it.
+ */
+ sch = schedcmds;
+ schedcmds = sch->next;
+ /*
+ * Delete from the timed function list now in case
+ * the called code reschedules.
+ */
+ deltimedfn(checksched);
+
+ if ((sch->flags & SCHEDFLAG_TRASH_ZLE) && zleactive)
+ trashzleptr();
+ execstring(sch->cmd, 0, 0);
+ zsfree(sch->cmd);
+ zfree(sch, sizeof(struct schedcmd));
+
+ /*
+ * Fix time for future events.
+ * I had this outside the loop, for a little extra efficiency.
+ * However, it then occurred to me that having the list of
+ * forthcoming entries up to date could be regarded as
+ * a feature, and the inefficiency is negligible.
+ */
+ if (schedcmds) {
+ /*
+ * We need to delete the function from the list again,
+ * in case called code rescheduled. This is almost
+ * as cheap as checking if it's in the list already.
+ */
+ deltimedfn(checksched);
+ DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (1)"); addtimedfn(checksched, schedcmds->time);
+ }
+ }
+}
+
/**/
static int
-bin_sched(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
+bin_sched(char *nam, char **argv, UNUSED(Options ops), UNUSED(int func))
{
- char *s = *argv++;
+ char *s, **argptr;
time_t t;
- long h, m;
+ long h, m, sec;
struct tm *tm;
struct schedcmd *sch, *sch2, *schl;
- int sn;
+ int sn, flags = 0;
/* If the argument begins with a -, remove the specified item from the
schedule. */
- if (s && *s == '-') {
- sn = atoi(s + 1);
+ for (argptr = argv; *argptr && **argptr == '-'; argptr++) {
+ char *arg = *argptr + 1;
+ if (idigit(*arg)) {
+ sn = atoi(arg);
- if (!sn) {
- zwarnnam("sched", "usage for delete: sched -<item#>.");
- return 1;
- }
- for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds, sn--;
- sch && sn; sch = (schl = sch)->next, sn--);
- if (!sch) {
- zwarnnam("sched", "not that many entries");
+ if (!sn) {
+ zwarnnam("sched", "usage for delete: sched -<item#>.");
+ return 1;
+ }
+ for (schl = NULL, sch = schedcmds, sn--;
+ sch && sn; sch = (schl = sch)->next, sn--);
+ if (!sch) {
+ zwarnnam("sched", "not that many entries");
+ return 1;
+ }
+ if (schl)
+ schl->next = sch->next;
+ else {
+ deltimedfn(checksched);
+ schedcmds = sch->next;
+ if (schedcmds) {
+ DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (2)");
+ addtimedfn(checksched, schedcmds->time);
+ }
+ }
+ zsfree(sch->cmd);
+ zfree(sch, sizeof(struct schedcmd));
+
+ return 0;
+ } else if (*arg == '-') {
+ /* end of options */
+ argptr++;
+ break;
+ } else if (!strcmp(arg, "o")) {
+ flags |= SCHEDFLAG_TRASH_ZLE;
+ } else {
+ if (*arg)
+ zwarnnam(nam, "bad option: -%c", *arg);
+ else
+ zwarnnam(nam, "option expected");
return 1;
}
- schl->next = sch->next;
- zsfree(sch->cmd);
- zfree(sch, sizeof(struct schedcmd));
-
- return 0;
}
/* given no arguments, display the schedule list */
- if (!s) {
- char tbuf[40];
+ if (!*argptr) {
+ char tbuf[40], *flagstr, *endstr;
for (sn = 1, sch = schedcmds; sch; sch = sch->next, sn++) {
t = sch->time;
tm = localtime(&t);
ztrftime(tbuf, 20, "%a %b %e %k:%M:%S", tm);
- printf("%3d %s %s\n", sn, tbuf, sch->cmd);
+ if (sch->flags & SCHEDFLAG_TRASH_ZLE)
+ flagstr = "-o ";
+ else
+ flagstr = "";
+ if (*sch->cmd == '-')
+ endstr = "-- ";
+ else
+ endstr = "";
+ printf("%3d %s %s%s%s\n", sn, tbuf, flagstr, endstr, sch->cmd);
}
return 0;
- } else if (!*argv) {
+ } else if (!argptr[1]) {
/* other than the two cases above, sched *
*requires at least two arguments */
zwarnnam("sched", "not enough arguments");
@@ -97,86 +192,108 @@ bin_sched(UNUSED(char *nam), char **argv, UNUSED(Options ops), UNUSED(int func))
/* The first argument specifies the time to schedule the command for. The
remaining arguments form the command. */
+ s = *argptr++;
if (*s == '+') {
- /* + introduces a relative time. The rest of the argument is an
- hour:minute offset from the current time. Once the hour and minute
- numbers have been extracted, and the format verified, the resulting
- offset is simply added to the current time. */
- h = zstrtol(s + 1, &s, 10);
- if (*s != ':') {
+ /*
+ * + introduces a relative time. The rest of the argument may be an
+ * hour:minute offset from the current time. Once the hour and minute
+ * numbers have been extracted, and the format verified, the resulting
+ * offset is simply added to the current time.
+ */
+ zlong zl = zstrtol(s + 1, &s, 10);
+ if (*s == ':') {
+ m = (long)zstrtol(s + 1, &s, 10);
+ if (*s == ':')
+ sec = (long)zstrtol(s + 1, &s, 10);
+ else
+ sec = 0;
+ if (*s) {
+ zwarnnam("sched", "bad time specifier");
+ return 1;
+ }
+ t = time(NULL) + (long)zl * 3600 + m * 60 + sec;
+ } else if (!*s) {
+ /*
+ * Alternatively, it may simply be a number of seconds.
+ * This is here for consistency with absolute times.
+ */
+ t = time(NULL) + (time_t)zl;
+ } else {
zwarnnam("sched", "bad time specifier");
return 1;
}
- m = zstrtol(s + 1, &s, 10);
- if (*s) {
- zwarnnam("sched", "bad time specifier");
- return 1;
- }
- t = time(NULL) + h * 3600 + m * 60;
} else {
- /* If there is no +, an absolute time of day must have been given.
- This is in hour:minute format, optionally followed by a string starting
- with `a' or `p' (for a.m. or p.m.). Characters after the `a' or `p'
- are ignored. */
- h = zstrtol(s, &s, 10);
- if (*s != ':') {
- zwarnnam("sched", "bad time specifier");
- return 1;
- }
- m = zstrtol(s + 1, &s, 10);
- if (*s && *s != 'a' && *s != 'A' && *s != 'p' && *s != 'P') {
+ /*
+ * If there is no +, an absolute time must have been given.
+ * This may be in hour:minute format, optionally followed by a string
+ * starting with `a' or `p' (for a.m. or p.m.). Characters after the
+ * `a' or `p' are ignored.
+ */
+ zlong zl = zstrtol(s, &s, 10);
+ if (*s == ':') {
+ h = (long)zl;
+ m = (long)zstrtol(s + 1, &s, 10);
+ if (*s == ':')
+ sec = (long)zstrtol(s + 1, &s, 10);
+ else
+ sec = 0;
+ if (*s && *s != 'a' && *s != 'A' && *s != 'p' && *s != 'P') {
+ zwarnnam("sched", "bad time specifier");
+ return 1;
+ }
+ t = time(NULL);
+ tm = localtime(&t);
+ t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600;
+ if (*s == 'p' || *s == 'P')
+ h += 12;
+ t += h * 3600 + m * 60 + sec;
+ /*
+ * If the specified time is before the current time, it must refer
+ * to tomorrow.
+ */
+ if (t < time(NULL))
+ t += 3600 * 24;
+ } else if (!*s) {
+ /*
+ * Otherwise, it must be a raw time specifier.
+ */
+ t = (long)zl;
+ } else {
zwarnnam("sched", "bad time specifier");
return 1;
}
- t = time(NULL);
- tm = localtime(&t);
- t -= tm->tm_sec + tm->tm_min * 60 + tm->tm_hour * 3600;
- if (*s == 'p' || *s == 'P')
- h += 12;
- t += h * 3600 + m * 60;
- /* If the specified time is before the current time, it must refer to
- tomorrow. */
- if (t < time(NULL))
- t += 3600 * 24;
}
/* The time has been calculated; now add the new entry to the linked list
of scheduled commands. */
- sch = (struct schedcmd *) zshcalloc(sizeof *sch);
+ sch = (struct schedcmd *) zalloc(sizeof *sch);
sch->time = t;
- sch->cmd = zjoin(argv, ' ', 0);
- sch->next = NULL;
- for (sch2 = (struct schedcmd *)&schedcmds; sch2->next; sch2 = sch2->next);
- sch2->next = sch;
- return 0;
-}
-
-/* Check scheduled commands; call this function from time to time. */
-
-/**/
-static void
-checksched(void)
-{
- time_t t;
- struct schedcmd *sch, *schl;
-
- if(!schedcmds)
- return;
- t = time(NULL);
- for (schl = (struct schedcmd *)&schedcmds, sch = schedcmds; sch;
- sch = (schl = sch)->next) {
- if (sch->time <= t) {
- execstring(sch->cmd, 0, 0);
- schl->next = sch->next;
- zsfree(sch->cmd);
- zfree(sch, sizeof(struct schedcmd));
- sch = schl;
+ sch->cmd = zjoin(argptr, ' ', 0);
+ sch->flags = flags;
+ /* Insert into list in time order */
+ if (schedcmds) {
+ if (sch->time < schedcmds->time) {
+ deltimedfn(checksched);
+ sch->next = schedcmds;
+ schedcmds = sch;
+ DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (3)");
+ addtimedfn(checksched, t);
+ } else {
+ for (sch2 = schedcmds;
+ sch2->next && sch2->next->time < sch->time;
+ sch2 = sch2->next)
+ ;
+ sch->next = sch2->next;
+ sch2->next = sch;
}
+ } else {
+ sch->next = NULL;
+ schedcmds = sch;
+ DPUTS(timedfns && firstnode(timedfns), "BUG: already timed fn (4)");
+ addtimedfn(checksched, t);
}
+ return 0;
}
-static void (*p_checksched) _((void)) = checksched;
-static struct linknode n_checksched = { NULL, NULL, &p_checksched };
-
static struct builtin bintab[] = {
BUILTIN("sched", 0, bin_sched, 0, -1, 0, NULL, NULL),
};
@@ -194,7 +311,7 @@ boot_(Module m)
{
if(!addbuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab)))
return 1;
- uaddlinknode(prepromptfns, &n_checksched);
+ addprepromptfn(&checksched);
return 0;
}
@@ -209,7 +326,7 @@ cleanup_(Module m)
zsfree(sch->cmd);
zfree(sch, sizeof(*sch));
}
- uremnode(prepromptfns, &n_checksched);
+ delprepromptfn(&checksched);
deletebuiltins(m->nam, bintab, sizeof(bintab)/sizeof(*bintab));
return 0;
}