xref: /freebsd/contrib/tcsh/tc.sched.c (revision 9122aeeaa60ee2a1381ea935d749194b32940e7a)
1c80476e4SDavid E. O'Brien /*
2c80476e4SDavid E. O'Brien  * tc.sched.c: Scheduled command execution
3c80476e4SDavid E. O'Brien  *
4c80476e4SDavid E. O'Brien  * Karl Kleinpaste: Computer Consoles Inc. 1984
5c80476e4SDavid E. O'Brien  */
6c80476e4SDavid E. O'Brien /*-
7c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
8c80476e4SDavid E. O'Brien  * All rights reserved.
9c80476e4SDavid E. O'Brien  *
10c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
11c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
12c80476e4SDavid E. O'Brien  * are met:
13c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
14c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
15c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
16c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
17c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
1829301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
19c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
20c80476e4SDavid E. O'Brien  *    without specific prior written permission.
21c80476e4SDavid E. O'Brien  *
22c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
33c80476e4SDavid E. O'Brien  */
34c80476e4SDavid E. O'Brien #include "sh.h"
35c80476e4SDavid E. O'Brien #include "ed.h"
3629301572SMark Peek #include "tw.h"
37c80476e4SDavid E. O'Brien #include "tc.h"
38c80476e4SDavid E. O'Brien 
39c80476e4SDavid E. O'Brien extern int just_signaled;
40c80476e4SDavid E. O'Brien 
41c80476e4SDavid E. O'Brien struct sched_event {
42c80476e4SDavid E. O'Brien     struct sched_event *t_next;
43c80476e4SDavid E. O'Brien     time_t t_when;
44c80476e4SDavid E. O'Brien     Char  **t_lex;
45c80476e4SDavid E. O'Brien };
46c80476e4SDavid E. O'Brien static struct sched_event *sched_ptr = NULL;
47c80476e4SDavid E. O'Brien 
48c80476e4SDavid E. O'Brien 
49c80476e4SDavid E. O'Brien time_t
sched_next(void)5045e5710bSMark Peek sched_next(void)
51c80476e4SDavid E. O'Brien {
52c80476e4SDavid E. O'Brien     if (sched_ptr)
53c80476e4SDavid E. O'Brien 	return (sched_ptr->t_when);
54c80476e4SDavid E. O'Brien     return ((time_t) - 1);
55c80476e4SDavid E. O'Brien }
56c80476e4SDavid E. O'Brien 
57c80476e4SDavid E. O'Brien /*ARGSUSED*/
58c80476e4SDavid E. O'Brien void
dosched(Char ** v,struct command * c)5945e5710bSMark Peek dosched(Char **v, struct command *c)
60c80476e4SDavid E. O'Brien {
6145e5710bSMark Peek     struct sched_event *tp, **pp;
62c80476e4SDavid E. O'Brien     time_t  cur_time;
63c80476e4SDavid E. O'Brien     int     count, hours, minutes, dif_hour, dif_min;
64c80476e4SDavid E. O'Brien     Char   *cp;
6523338178SMark Peek     int    relative;		/* time specified as +hh:mm */
66c80476e4SDavid E. O'Brien     struct tm *ltp;
67c80476e4SDavid E. O'Brien 
68c80476e4SDavid E. O'Brien     USE(c);
69c80476e4SDavid E. O'Brien /* This is a major kludge because of a gcc linker  */
70c80476e4SDavid E. O'Brien /* Problem.  It may or may not be needed for you   */
713b6eaa7bSAndrey A. Chernov #if defined(_MINIX) && !defined(_MINIX_VMD)
72c80476e4SDavid E. O'Brien     char kludge[10];
73c80476e4SDavid E. O'Brien     extern char *sprintf();
74c80476e4SDavid E. O'Brien     sprintf(kludge, CGETS(24, 1, "kludge"));
753b6eaa7bSAndrey A. Chernov #endif /* _MINIX && !_MINIX_VMD */
76c80476e4SDavid E. O'Brien 
77c80476e4SDavid E. O'Brien     v++;
78c80476e4SDavid E. O'Brien     cp = *v++;
79c80476e4SDavid E. O'Brien     if (cp == NULL) {
8045e5710bSMark Peek 	const Char *fmt;
81c80476e4SDavid E. O'Brien 	if ((fmt = varval(STRsched)) == STRNULL)
82c80476e4SDavid E. O'Brien 	    fmt = str2short("%h\t%T\t%R\n");
83c80476e4SDavid E. O'Brien 	/* print list of scheduled events */
84c80476e4SDavid E. O'Brien 	for (count = 1, tp = sched_ptr; tp; count++, tp = tp->t_next) {
8545e5710bSMark Peek 	    Char *buf, *str;
8645e5710bSMark Peek 
8745e5710bSMark Peek 	    buf = blkexpand(tp->t_lex);
8845e5710bSMark Peek 	    cleanup_push(buf, xfree);
8945e5710bSMark Peek 	    str = tprintf(FMT_SCHED, fmt, short2str(buf), tp->t_when, &count);
9045e5710bSMark Peek 	    cleanup_until(buf);
9145e5710bSMark Peek 	    cleanup_push(str, xfree);
9245e5710bSMark Peek 	    for (cp = str; *cp;)
9323338178SMark Peek 		xputwchar(*cp++);
9445e5710bSMark Peek 	    cleanup_until(str);
95c80476e4SDavid E. O'Brien 	}
96c80476e4SDavid E. O'Brien 	return;
97c80476e4SDavid E. O'Brien     }
98c80476e4SDavid E. O'Brien 
99c80476e4SDavid E. O'Brien     if (*cp == '-') {
100c80476e4SDavid E. O'Brien 	/* remove item from list */
101c80476e4SDavid E. O'Brien 	if (!sched_ptr)
102c80476e4SDavid E. O'Brien 	    stderror(ERR_NOSCHED);
103c80476e4SDavid E. O'Brien 	if (*v)
104c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDUSAGE);
105c80476e4SDavid E. O'Brien 	count = atoi(short2str(++cp));
106c80476e4SDavid E. O'Brien 	if (count <= 0)
107c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDUSAGE);
10845e5710bSMark Peek 	pp = &sched_ptr;
109c80476e4SDavid E. O'Brien 	tp = sched_ptr;
110c80476e4SDavid E. O'Brien 	while (--count) {
111c80476e4SDavid E. O'Brien 	    if (tp->t_next == 0)
112c80476e4SDavid E. O'Brien 		break;
113c80476e4SDavid E. O'Brien 	    else {
11445e5710bSMark Peek 		pp = &tp->t_next;
115c80476e4SDavid E. O'Brien 		tp = tp->t_next;
116c80476e4SDavid E. O'Brien 	    }
117c80476e4SDavid E. O'Brien 	}
118c80476e4SDavid E. O'Brien 	if (count)
119c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDEV);
12045e5710bSMark Peek 	*pp = tp->t_next;
121c80476e4SDavid E. O'Brien 	blkfree(tp->t_lex);
12245e5710bSMark Peek 	xfree(tp);
123c80476e4SDavid E. O'Brien 	return;
124c80476e4SDavid E. O'Brien     }
125c80476e4SDavid E. O'Brien 
126c80476e4SDavid E. O'Brien     /* else, add an item to the list */
127c80476e4SDavid E. O'Brien     if (!*v)
128c80476e4SDavid E. O'Brien 	stderror(ERR_SCHEDCOM);
129c80476e4SDavid E. O'Brien     relative = 0;
130c80476e4SDavid E. O'Brien     if (!Isdigit(*cp)) {	/* not abs. time */
131c80476e4SDavid E. O'Brien 	if (*cp != '+')
132c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDUSAGE);
133c80476e4SDavid E. O'Brien 	cp++, relative++;
134c80476e4SDavid E. O'Brien     }
135c80476e4SDavid E. O'Brien     minutes = 0;
136c80476e4SDavid E. O'Brien     hours = atoi(short2str(cp));
137c80476e4SDavid E. O'Brien     while (*cp && *cp != ':' && *cp != 'a' && *cp != 'p')
138c80476e4SDavid E. O'Brien 	cp++;
139c80476e4SDavid E. O'Brien     if (*cp && *cp == ':')
140c80476e4SDavid E. O'Brien 	minutes = atoi(short2str(++cp));
141c80476e4SDavid E. O'Brien     if ((hours < 0) || (minutes < 0) ||
142c80476e4SDavid E. O'Brien 	(hours > 23) || (minutes > 59))
143c80476e4SDavid E. O'Brien 	stderror(ERR_SCHEDTIME);
144c80476e4SDavid E. O'Brien     while (*cp && *cp != 'p' && *cp != 'a')
145c80476e4SDavid E. O'Brien 	cp++;
146c80476e4SDavid E. O'Brien     if (*cp && relative)
147c80476e4SDavid E. O'Brien 	stderror(ERR_SCHEDREL);
148c80476e4SDavid E. O'Brien     if (*cp == 'p')
149c80476e4SDavid E. O'Brien 	hours += 12;
150c80476e4SDavid E. O'Brien     (void) time(&cur_time);
151c80476e4SDavid E. O'Brien     ltp = localtime(&cur_time);
152c80476e4SDavid E. O'Brien     if (relative) {
153c80476e4SDavid E. O'Brien 	dif_hour = hours;
154c80476e4SDavid E. O'Brien 	dif_min = minutes;
155c80476e4SDavid E. O'Brien     }
156c80476e4SDavid E. O'Brien     else {
157c80476e4SDavid E. O'Brien 	if ((dif_hour = hours - ltp->tm_hour) < 0)
158c80476e4SDavid E. O'Brien 	    dif_hour += 24;
159c80476e4SDavid E. O'Brien 	if ((dif_min = minutes - ltp->tm_min) < 0) {
160c80476e4SDavid E. O'Brien 	    dif_min += 60;
161c80476e4SDavid E. O'Brien 	    if ((--dif_hour) < 0)
162c80476e4SDavid E. O'Brien 		dif_hour = 23;
163c80476e4SDavid E. O'Brien 	}
164c80476e4SDavid E. O'Brien     }
16545e5710bSMark Peek     tp = xcalloc(1, sizeof *tp);
166c80476e4SDavid E. O'Brien #ifdef _SX
167c80476e4SDavid E. O'Brien     tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600 + dif_min * 60;
168c80476e4SDavid E. O'Brien #else	/* _SX */
169c80476e4SDavid E. O'Brien     tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600L + dif_min * 60L;
170c80476e4SDavid E. O'Brien #endif /* _SX */
171c80476e4SDavid E. O'Brien     /* use of tm_sec: get to beginning of minute. */
17245e5710bSMark Peek     for (pp = &sched_ptr; *pp != NULL && tp->t_when >= (*pp)->t_when;
17345e5710bSMark Peek 	 pp = &(*pp)->t_next)
17445e5710bSMark Peek 	;
17545e5710bSMark Peek     tp->t_next = *pp;
17645e5710bSMark Peek     *pp = tp;
177c80476e4SDavid E. O'Brien     tp->t_lex = saveblk(v);
178c80476e4SDavid E. O'Brien }
179c80476e4SDavid E. O'Brien 
180c80476e4SDavid E. O'Brien /*
181c80476e4SDavid E. O'Brien  * Execute scheduled events
182c80476e4SDavid E. O'Brien  */
183c80476e4SDavid E. O'Brien void
sched_run(void)18445e5710bSMark Peek sched_run(void)
185c80476e4SDavid E. O'Brien {
186c80476e4SDavid E. O'Brien     time_t   cur_time;
18745e5710bSMark Peek     struct sched_event *tp;
188c80476e4SDavid E. O'Brien     struct wordent cmd, *nextword, *lastword;
189c80476e4SDavid E. O'Brien     struct command *t;
190c80476e4SDavid E. O'Brien     Char  **v, *cp;
191c80476e4SDavid E. O'Brien 
19245e5710bSMark Peek     pintr_disabled++;
19345e5710bSMark Peek     cleanup_push(&pintr_disabled, disabled_cleanup);
194c80476e4SDavid E. O'Brien 
195c80476e4SDavid E. O'Brien     (void) time(&cur_time);
196c80476e4SDavid E. O'Brien 
197c80476e4SDavid E. O'Brien     /* bugfix by: Justin Bur at Universite de Montreal */
198c80476e4SDavid E. O'Brien     /*
199c80476e4SDavid E. O'Brien      * this test wouldn't be necessary if this routine were not called before
200c80476e4SDavid E. O'Brien      * each prompt (in sh.c).  But it is, to catch missed alarms.  Someone
201c80476e4SDavid E. O'Brien      * ought to fix it all up.  -jbb
202c80476e4SDavid E. O'Brien      */
20345e5710bSMark Peek     if (!(sched_ptr && sched_ptr->t_when < cur_time)) {
20445e5710bSMark Peek 	cleanup_until(&pintr_disabled);
205c80476e4SDavid E. O'Brien 	return;
206c80476e4SDavid E. O'Brien     }
207c80476e4SDavid E. O'Brien 
208c80476e4SDavid E. O'Brien     if (GettingInput)
209c80476e4SDavid E. O'Brien 	(void) Cookedmode();
210c80476e4SDavid E. O'Brien 
21145e5710bSMark Peek     while ((tp = sched_ptr) != NULL && tp->t_when < cur_time) {
212c80476e4SDavid E. O'Brien 	if (seterr) {
21345e5710bSMark Peek 	    xfree(seterr);
214c80476e4SDavid E. O'Brien 	    seterr = NULL;
215c80476e4SDavid E. O'Brien 	}
216c80476e4SDavid E. O'Brien 	cmd.word = STRNULL;
217c80476e4SDavid E. O'Brien 	lastword = &cmd;
218c80476e4SDavid E. O'Brien 	v = tp->t_lex;
219c80476e4SDavid E. O'Brien 	for (cp = *v; cp; cp = *++v) {
22045e5710bSMark Peek 	    nextword = xcalloc(1, sizeof cmd);
221c80476e4SDavid E. O'Brien 	    nextword->word = Strsave(cp);
222c80476e4SDavid E. O'Brien 	    lastword->next = nextword;
223c80476e4SDavid E. O'Brien 	    nextword->prev = lastword;
224c80476e4SDavid E. O'Brien 	    lastword = nextword;
225c80476e4SDavid E. O'Brien 	}
226c80476e4SDavid E. O'Brien 	lastword->next = &cmd;
227c80476e4SDavid E. O'Brien 	cmd.prev = lastword;
22845e5710bSMark Peek 	sched_ptr = tp->t_next;	/* looping termination cond: */
22945e5710bSMark Peek 	blkfree(tp->t_lex);	/* straighten out in case of */
23045e5710bSMark Peek 	xfree(tp);		/* command blow-up. */
231c80476e4SDavid E. O'Brien 
23245e5710bSMark Peek 	cleanup_push(&cmd, lex_cleanup);
233c80476e4SDavid E. O'Brien 	/* expand aliases like process() does. */
234c80476e4SDavid E. O'Brien 	alias(&cmd);
235c80476e4SDavid E. O'Brien 	/* build a syntax tree for the command. */
236c80476e4SDavid E. O'Brien 	t = syntax(cmd.next, &cmd, 0);
23745e5710bSMark Peek 	cleanup_push(t, syntax_cleanup);
238c80476e4SDavid E. O'Brien 	if (seterr)
239c80476e4SDavid E. O'Brien 	    stderror(ERR_OLD);
240c80476e4SDavid E. O'Brien 	/* execute the parse tree. */
24129301572SMark Peek 	execute(t, -1, NULL, NULL, TRUE);
242c80476e4SDavid E. O'Brien 	/* done. free the lex list and parse tree. */
24345e5710bSMark Peek 	cleanup_until(&cmd);
244c80476e4SDavid E. O'Brien     }
245c80476e4SDavid E. O'Brien     if (GettingInput && !just_signaled) {	/* PWP */
246c80476e4SDavid E. O'Brien 	(void) Rawmode();
247c80476e4SDavid E. O'Brien 	ClearLines();		/* do a real refresh since something may */
248c80476e4SDavid E. O'Brien 	ClearDisp();		/* have printed to the screen */
249c80476e4SDavid E. O'Brien 	Refresh();
250c80476e4SDavid E. O'Brien     }
251c80476e4SDavid E. O'Brien     just_signaled = 0;
252c80476e4SDavid E. O'Brien 
25345e5710bSMark Peek     cleanup_until(&pintr_disabled);
254c80476e4SDavid E. O'Brien }
255