45
|
1 #include <stdio.h>
|
|
2 #include <signal.h>
|
|
3 #include <fcntl.h> /* FASYNC */
|
|
4 #ifdef USG /* FASYNC for SysV */
|
|
5 #include <sys/file.h>
|
|
6 #endif
|
|
7 #include <sys/time.h> /* itimer */
|
|
8 #include <sys/types.h> /* time_t */
|
|
9
|
|
10 extern int errno;
|
|
11 extern char *sys_errlist[], *malloc();
|
|
12 extern time_t time();
|
|
13
|
|
14 #define MAXEVENTS 256
|
|
15 #define FS 1 /* field seperator for input */
|
|
16
|
|
17 struct event {
|
|
18 char *token;
|
|
19 time_t reply_at;
|
|
20 } *events[MAXEVENTS];
|
|
21
|
|
22 int slot; /* The next open place in the events array */
|
|
23 int mevent = 0; /* 1+ the highest event number */
|
|
24 char *pname; /* programme name for error messages */
|
|
25
|
|
26 /* Accepts a string of two fields seperated by a ';'
|
|
27 * First field is string for getdate, saying when to wake-up.
|
|
28 * Second field is a token to identify the request.
|
|
29 */
|
|
30 struct event *
|
|
31 schedule(str)
|
|
32 char *str;
|
|
33
|
|
34 {
|
|
35 extern time_t getdate();
|
|
36 extern char *strcpy();
|
|
37 time_t now;
|
|
38 register char *p;
|
|
39 static struct event e;
|
|
40
|
|
41 for(p = str; *p && *p != FS; p++);
|
|
42 if (!*p) {
|
|
43 (void)fprintf(stderr, "%s: bad input format: %s", pname, str);
|
|
44 return((struct event *)NULL);
|
|
45 }
|
|
46 *p++ = 0;
|
|
47
|
441
|
48 if ((e.reply_at = get_date(str, NULL)) - time(&now) < 0) {
|
45
|
49 (void)fprintf(stderr, "%s: bad time spec: %s%c%s", pname, str, FS, p);
|
|
50 return((struct event *)NULL);
|
|
51 }
|
|
52
|
|
53 if ((e.token = malloc((unsigned)strlen(p) + 1)) == NULL) {
|
|
54 (void)fprintf(stderr, "%s: malloc %s: %s%c%s",
|
|
55 pname, sys_errlist[errno], str, FS, p);
|
|
56 return((struct event *)NULL);
|
|
57 }
|
|
58 (void)strcpy(e.token,p);
|
|
59
|
|
60 return(&e);
|
|
61 }
|
|
62
|
|
63 void
|
|
64 notify()
|
|
65
|
|
66 {
|
|
67 time_t now, tdiff;
|
|
68 register int i, newmax = 0;
|
|
69 /* I prefer using the interval timer rather than alarm(); the latter
|
|
70 could be substituted if portability requires it. */
|
|
71 struct itimerval itimer;
|
|
72
|
|
73 now = time((time_t *)NULL);
|
|
74 slot = mevent;
|
|
75 itimer.it_interval.tv_sec = itimer.it_interval.tv_usec = 0;
|
|
76 itimer.it_value.tv_usec = 0;
|
|
77 itimer.it_value.tv_sec = -1;
|
|
78
|
|
79 for(i=0; i < mevent; i++) {
|
|
80 while (events[i] && events[i]->reply_at <= now) {
|
|
81 (void)fputs(events[i]->token, stdout);
|
|
82 free(events[i]->token);
|
|
83 free((char *)events[i]);
|
|
84 events[i] = 0;
|
|
85 }
|
|
86
|
|
87 if (events[i]) {
|
|
88 newmax = i+1;
|
|
89 if ((tdiff = events[i]->reply_at - now) < (time_t)itimer.it_value.tv_sec
|
|
90 || itimer.it_value.tv_sec < 0)
|
|
91 /* next timeout */
|
|
92 itimer.it_value.tv_sec = (long)tdiff;
|
|
93 } else {
|
|
94 /* Keep slot as the lowest unused events element */
|
|
95 if (i < slot) slot = i;
|
|
96 }
|
|
97 }
|
|
98 /* if the array is full to mevent, slot should be the next available spot */
|
|
99 if (slot > (mevent = newmax)) slot = mevent;
|
|
100 /* If there's no more events, SIGIO should be next wake-up */
|
|
101 if (mevent) (void)setitimer(ITIMER_REAL, &itimer, (struct itimerval *)NULL);
|
|
102 }
|
|
103
|
|
104 void
|
|
105 getevent()
|
|
106
|
|
107 {
|
621
|
108 extern char *fgets();
|
45
|
109 struct event *ep;
|
|
110 char buf[256];
|
|
111
|
|
112 /* in principle the itimer should be disabled on entry to this function,
|
|
113 but it really doesn't make any important difference if it isn't */
|
|
114
|
|
115 if (fgets(buf, sizeof(buf), stdin) == NULL) exit(0);
|
|
116
|
|
117 if (slot == MAXEVENTS)
|
|
118 (void)fprintf(stderr, "%s: too many events: %s", pname, buf);
|
|
119
|
|
120 else {
|
|
121 if ((events[slot] = (struct event *)malloc((sizeof(struct event))))
|
|
122 == NULL)
|
|
123 (void)fprintf(stderr,"%s: malloc %s: %s", pname, sys_errlist[errno],buf);
|
|
124
|
|
125 else {
|
|
126 if ((ep = schedule(buf)) == NULL)
|
|
127 free((char *)events[slot]), events[slot] = 0;
|
|
128
|
|
129 else {
|
621
|
130 memcpy((char *)events[slot],(char *)ep,sizeof(struct event));
|
45
|
131 if (slot == mevent) mevent++;
|
|
132 } /* schedule */
|
|
133 } /* malloc */
|
|
134 } /* limit events */
|
|
135 /* timing, timing. Who knows what this interrupted, or if it said "now"? */
|
|
136 notify();
|
|
137 }
|
|
138
|
|
139 /*ARGSUSED*/
|
|
140 int
|
|
141 main(argc, argv)
|
|
142 int argc;
|
|
143 char **argv;
|
|
144
|
|
145 {
|
|
146 for (pname = argv[0] + strlen(argv[0]); *pname != '/' && pname != argv[0];
|
|
147 pname--);
|
|
148 if (*pname == '/') pname++;
|
|
149
|
|
150 (void)signal(SIGIO, getevent);
|
|
151 (void)signal(SIGALRM, notify);
|
|
152 (void)fcntl(0, F_SETFL, FASYNC);
|
|
153
|
|
154 while (1) pause();
|
|
155 }
|