xref: /freebsd/contrib/tcsh/tc.sched.c (revision 45e5710bbb3676c9d945e9df78019b2c58930a59)
145e5710bSMark Peek /* $Header: /p/tcsh/cvsroot/tcsh/tc.sched.c,v 3.25 2006/03/02 18:46:45 christos Exp $ */
2c80476e4SDavid E. O'Brien /*
3c80476e4SDavid E. O'Brien  * tc.sched.c: Scheduled command execution
4c80476e4SDavid E. O'Brien  *
5c80476e4SDavid E. O'Brien  * Karl Kleinpaste: Computer Consoles Inc. 1984
6c80476e4SDavid E. O'Brien  */
7c80476e4SDavid E. O'Brien /*-
8c80476e4SDavid E. O'Brien  * Copyright (c) 1980, 1991 The Regents of the University of California.
9c80476e4SDavid E. O'Brien  * All rights reserved.
10c80476e4SDavid E. O'Brien  *
11c80476e4SDavid E. O'Brien  * Redistribution and use in source and binary forms, with or without
12c80476e4SDavid E. O'Brien  * modification, are permitted provided that the following conditions
13c80476e4SDavid E. O'Brien  * are met:
14c80476e4SDavid E. O'Brien  * 1. Redistributions of source code must retain the above copyright
15c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer.
16c80476e4SDavid E. O'Brien  * 2. Redistributions in binary form must reproduce the above copyright
17c80476e4SDavid E. O'Brien  *    notice, this list of conditions and the following disclaimer in the
18c80476e4SDavid E. O'Brien  *    documentation and/or other materials provided with the distribution.
1929301572SMark Peek  * 3. Neither the name of the University nor the names of its contributors
20c80476e4SDavid E. O'Brien  *    may be used to endorse or promote products derived from this software
21c80476e4SDavid E. O'Brien  *    without specific prior written permission.
22c80476e4SDavid E. O'Brien  *
23c80476e4SDavid E. O'Brien  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24c80476e4SDavid E. O'Brien  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25c80476e4SDavid E. O'Brien  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26c80476e4SDavid E. O'Brien  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27c80476e4SDavid E. O'Brien  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28c80476e4SDavid E. O'Brien  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29c80476e4SDavid E. O'Brien  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30c80476e4SDavid E. O'Brien  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31c80476e4SDavid E. O'Brien  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32c80476e4SDavid E. O'Brien  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33c80476e4SDavid E. O'Brien  * SUCH DAMAGE.
34c80476e4SDavid E. O'Brien  */
35c80476e4SDavid E. O'Brien #include "sh.h"
36c80476e4SDavid E. O'Brien 
3745e5710bSMark Peek RCSID("$tcsh: tc.sched.c,v 3.25 2006/03/02 18:46:45 christos Exp $")
38c80476e4SDavid E. O'Brien 
39c80476e4SDavid E. O'Brien #include "ed.h"
4029301572SMark Peek #include "tw.h"
41c80476e4SDavid E. O'Brien #include "tc.h"
42c80476e4SDavid E. O'Brien 
43c80476e4SDavid E. O'Brien extern int just_signaled;
44c80476e4SDavid E. O'Brien 
45c80476e4SDavid E. O'Brien struct sched_event {
46c80476e4SDavid E. O'Brien     struct sched_event *t_next;
47c80476e4SDavid E. O'Brien     time_t t_when;
48c80476e4SDavid E. O'Brien     Char  **t_lex;
49c80476e4SDavid E. O'Brien };
50c80476e4SDavid E. O'Brien static struct sched_event *sched_ptr = NULL;
51c80476e4SDavid E. O'Brien 
52c80476e4SDavid E. O'Brien 
53c80476e4SDavid E. O'Brien time_t
5445e5710bSMark Peek sched_next(void)
55c80476e4SDavid E. O'Brien {
56c80476e4SDavid E. O'Brien     if (sched_ptr)
57c80476e4SDavid E. O'Brien 	return (sched_ptr->t_when);
58c80476e4SDavid E. O'Brien     return ((time_t) - 1);
59c80476e4SDavid E. O'Brien }
60c80476e4SDavid E. O'Brien 
61c80476e4SDavid E. O'Brien /*ARGSUSED*/
62c80476e4SDavid E. O'Brien void
6345e5710bSMark Peek dosched(Char **v, struct command *c)
64c80476e4SDavid E. O'Brien {
6545e5710bSMark Peek     struct sched_event *tp, **pp;
66c80476e4SDavid E. O'Brien     time_t  cur_time;
67c80476e4SDavid E. O'Brien     int     count, hours, minutes, dif_hour, dif_min;
68c80476e4SDavid E. O'Brien     Char   *cp;
6923338178SMark Peek     int    relative;		/* time specified as +hh:mm */
70c80476e4SDavid E. O'Brien     struct tm *ltp;
71c80476e4SDavid E. O'Brien 
72c80476e4SDavid E. O'Brien     USE(c);
73c80476e4SDavid E. O'Brien /* This is a major kludge because of a gcc linker  */
74c80476e4SDavid E. O'Brien /* Problem.  It may or may not be needed for you   */
753b6eaa7bSAndrey A. Chernov #if defined(_MINIX) && !defined(_MINIX_VMD)
76c80476e4SDavid E. O'Brien     char kludge[10];
77c80476e4SDavid E. O'Brien     extern char *sprintf();
78c80476e4SDavid E. O'Brien     sprintf(kludge, CGETS(24, 1, "kludge"));
793b6eaa7bSAndrey A. Chernov #endif /* _MINIX && !_MINIX_VMD */
80c80476e4SDavid E. O'Brien 
81c80476e4SDavid E. O'Brien     v++;
82c80476e4SDavid E. O'Brien     cp = *v++;
83c80476e4SDavid E. O'Brien     if (cp == NULL) {
8445e5710bSMark Peek 	const Char *fmt;
85c80476e4SDavid E. O'Brien 	if ((fmt = varval(STRsched)) == STRNULL)
86c80476e4SDavid E. O'Brien 	    fmt = str2short("%h\t%T\t%R\n");
87c80476e4SDavid E. O'Brien 	/* print list of scheduled events */
88c80476e4SDavid E. O'Brien 	for (count = 1, tp = sched_ptr; tp; count++, tp = tp->t_next) {
8945e5710bSMark Peek 	    Char *buf, *str;
9045e5710bSMark Peek 
9145e5710bSMark Peek 	    buf = blkexpand(tp->t_lex);
9245e5710bSMark Peek 	    cleanup_push(buf, xfree);
9345e5710bSMark Peek 	    str = tprintf(FMT_SCHED, fmt, short2str(buf), tp->t_when, &count);
9445e5710bSMark Peek 	    cleanup_until(buf);
9545e5710bSMark Peek 	    cleanup_push(str, xfree);
9645e5710bSMark Peek 	    for (cp = str; *cp;)
9723338178SMark Peek 		xputwchar(*cp++);
9845e5710bSMark Peek 	    cleanup_until(str);
99c80476e4SDavid E. O'Brien 	}
100c80476e4SDavid E. O'Brien 	return;
101c80476e4SDavid E. O'Brien     }
102c80476e4SDavid E. O'Brien 
103c80476e4SDavid E. O'Brien     if (*cp == '-') {
104c80476e4SDavid E. O'Brien 	/* remove item from list */
105c80476e4SDavid E. O'Brien 	if (!sched_ptr)
106c80476e4SDavid E. O'Brien 	    stderror(ERR_NOSCHED);
107c80476e4SDavid E. O'Brien 	if (*v)
108c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDUSAGE);
109c80476e4SDavid E. O'Brien 	count = atoi(short2str(++cp));
110c80476e4SDavid E. O'Brien 	if (count <= 0)
111c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDUSAGE);
11245e5710bSMark Peek 	pp = &sched_ptr;
113c80476e4SDavid E. O'Brien 	tp = sched_ptr;
114c80476e4SDavid E. O'Brien 	while (--count) {
115c80476e4SDavid E. O'Brien 	    if (tp->t_next == 0)
116c80476e4SDavid E. O'Brien 		break;
117c80476e4SDavid E. O'Brien 	    else {
11845e5710bSMark Peek 		pp = &tp->t_next;
119c80476e4SDavid E. O'Brien 		tp = tp->t_next;
120c80476e4SDavid E. O'Brien 	    }
121c80476e4SDavid E. O'Brien 	}
122c80476e4SDavid E. O'Brien 	if (count)
123c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDEV);
12445e5710bSMark Peek 	*pp = tp->t_next;
125c80476e4SDavid E. O'Brien 	blkfree(tp->t_lex);
12645e5710bSMark Peek 	xfree(tp);
127c80476e4SDavid E. O'Brien 	return;
128c80476e4SDavid E. O'Brien     }
129c80476e4SDavid E. O'Brien 
130c80476e4SDavid E. O'Brien     /* else, add an item to the list */
131c80476e4SDavid E. O'Brien     if (!*v)
132c80476e4SDavid E. O'Brien 	stderror(ERR_SCHEDCOM);
133c80476e4SDavid E. O'Brien     relative = 0;
134c80476e4SDavid E. O'Brien     if (!Isdigit(*cp)) {	/* not abs. time */
135c80476e4SDavid E. O'Brien 	if (*cp != '+')
136c80476e4SDavid E. O'Brien 	    stderror(ERR_SCHEDUSAGE);
137c80476e4SDavid E. O'Brien 	cp++, relative++;
138c80476e4SDavid E. O'Brien     }
139c80476e4SDavid E. O'Brien     minutes = 0;
140c80476e4SDavid E. O'Brien     hours = atoi(short2str(cp));
141c80476e4SDavid E. O'Brien     while (*cp && *cp != ':' && *cp != 'a' && *cp != 'p')
142c80476e4SDavid E. O'Brien 	cp++;
143c80476e4SDavid E. O'Brien     if (*cp && *cp == ':')
144c80476e4SDavid E. O'Brien 	minutes = atoi(short2str(++cp));
145c80476e4SDavid E. O'Brien     if ((hours < 0) || (minutes < 0) ||
146c80476e4SDavid E. O'Brien 	(hours > 23) || (minutes > 59))
147c80476e4SDavid E. O'Brien 	stderror(ERR_SCHEDTIME);
148c80476e4SDavid E. O'Brien     while (*cp && *cp != 'p' && *cp != 'a')
149c80476e4SDavid E. O'Brien 	cp++;
150c80476e4SDavid E. O'Brien     if (*cp && relative)
151c80476e4SDavid E. O'Brien 	stderror(ERR_SCHEDREL);
152c80476e4SDavid E. O'Brien     if (*cp == 'p')
153c80476e4SDavid E. O'Brien 	hours += 12;
154c80476e4SDavid E. O'Brien     (void) time(&cur_time);
155c80476e4SDavid E. O'Brien     ltp = localtime(&cur_time);
156c80476e4SDavid E. O'Brien     if (relative) {
157c80476e4SDavid E. O'Brien 	dif_hour = hours;
158c80476e4SDavid E. O'Brien 	dif_min = minutes;
159c80476e4SDavid E. O'Brien     }
160c80476e4SDavid E. O'Brien     else {
161c80476e4SDavid E. O'Brien 	if ((dif_hour = hours - ltp->tm_hour) < 0)
162c80476e4SDavid E. O'Brien 	    dif_hour += 24;
163c80476e4SDavid E. O'Brien 	if ((dif_min = minutes - ltp->tm_min) < 0) {
164c80476e4SDavid E. O'Brien 	    dif_min += 60;
165c80476e4SDavid E. O'Brien 	    if ((--dif_hour) < 0)
166c80476e4SDavid E. O'Brien 		dif_hour = 23;
167c80476e4SDavid E. O'Brien 	}
168c80476e4SDavid E. O'Brien     }
16945e5710bSMark Peek     tp = xcalloc(1, sizeof *tp);
170c80476e4SDavid E. O'Brien #ifdef _SX
171c80476e4SDavid E. O'Brien     tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600 + dif_min * 60;
172c80476e4SDavid E. O'Brien #else	/* _SX */
173c80476e4SDavid E. O'Brien     tp->t_when = cur_time - ltp->tm_sec + dif_hour * 3600L + dif_min * 60L;
174c80476e4SDavid E. O'Brien #endif /* _SX */
175c80476e4SDavid E. O'Brien     /* use of tm_sec: get to beginning of minute. */
17645e5710bSMark Peek     for (pp = &sched_ptr; *pp != NULL && tp->t_when >= (*pp)->t_when;
17745e5710bSMark Peek 	 pp = &(*pp)->t_next)
17845e5710bSMark Peek 	;
17945e5710bSMark Peek     tp->t_next = *pp;
18045e5710bSMark Peek     *pp = tp;
181c80476e4SDavid E. O'Brien     tp->t_lex = saveblk(v);
182c80476e4SDavid E. O'Brien }
183c80476e4SDavid E. O'Brien 
184c80476e4SDavid E. O'Brien /*
185c80476e4SDavid E. O'Brien  * Execute scheduled events
186c80476e4SDavid E. O'Brien  */
187c80476e4SDavid E. O'Brien void
18845e5710bSMark Peek sched_run(void)
189c80476e4SDavid E. O'Brien {
190c80476e4SDavid E. O'Brien     time_t   cur_time;
19145e5710bSMark Peek     struct sched_event *tp;
192c80476e4SDavid E. O'Brien     struct wordent cmd, *nextword, *lastword;
193c80476e4SDavid E. O'Brien     struct command *t;
194c80476e4SDavid E. O'Brien     Char  **v, *cp;
195c80476e4SDavid E. O'Brien 
19645e5710bSMark Peek     pintr_disabled++;
19745e5710bSMark Peek     cleanup_push(&pintr_disabled, disabled_cleanup);
198c80476e4SDavid E. O'Brien 
199c80476e4SDavid E. O'Brien     (void) time(&cur_time);
200c80476e4SDavid E. O'Brien 
201c80476e4SDavid E. O'Brien     /* bugfix by: Justin Bur at Universite de Montreal */
202c80476e4SDavid E. O'Brien     /*
203c80476e4SDavid E. O'Brien      * this test wouldn't be necessary if this routine were not called before
204c80476e4SDavid E. O'Brien      * each prompt (in sh.c).  But it is, to catch missed alarms.  Someone
205c80476e4SDavid E. O'Brien      * ought to fix it all up.  -jbb
206c80476e4SDavid E. O'Brien      */
20745e5710bSMark Peek     if (!(sched_ptr && sched_ptr->t_when < cur_time)) {
20845e5710bSMark Peek 	cleanup_until(&pintr_disabled);
209c80476e4SDavid E. O'Brien 	return;
210c80476e4SDavid E. O'Brien     }
211c80476e4SDavid E. O'Brien 
212c80476e4SDavid E. O'Brien     if (GettingInput)
213c80476e4SDavid E. O'Brien 	(void) Cookedmode();
214c80476e4SDavid E. O'Brien 
21545e5710bSMark Peek     while ((tp = sched_ptr) != NULL && tp->t_when < cur_time) {
216c80476e4SDavid E. O'Brien 	if (seterr) {
21745e5710bSMark Peek 	    xfree(seterr);
218c80476e4SDavid E. O'Brien 	    seterr = NULL;
219c80476e4SDavid E. O'Brien 	}
220c80476e4SDavid E. O'Brien 	cmd.word = STRNULL;
221c80476e4SDavid E. O'Brien 	lastword = &cmd;
222c80476e4SDavid E. O'Brien 	v = tp->t_lex;
223c80476e4SDavid E. O'Brien 	for (cp = *v; cp; cp = *++v) {
22445e5710bSMark Peek 	    nextword = xcalloc(1, sizeof cmd);
225c80476e4SDavid E. O'Brien 	    nextword->word = Strsave(cp);
226c80476e4SDavid E. O'Brien 	    lastword->next = nextword;
227c80476e4SDavid E. O'Brien 	    nextword->prev = lastword;
228c80476e4SDavid E. O'Brien 	    lastword = nextword;
229c80476e4SDavid E. O'Brien 	}
230c80476e4SDavid E. O'Brien 	lastword->next = &cmd;
231c80476e4SDavid E. O'Brien 	cmd.prev = lastword;
23245e5710bSMark Peek 	sched_ptr = tp->t_next;	/* looping termination cond: */
23345e5710bSMark Peek 	blkfree(tp->t_lex);	/* straighten out in case of */
23445e5710bSMark Peek 	xfree(tp);		/* command blow-up. */
235c80476e4SDavid E. O'Brien 
23645e5710bSMark Peek 	cleanup_push(&cmd, lex_cleanup);
237c80476e4SDavid E. O'Brien 	/* expand aliases like process() does. */
238c80476e4SDavid E. O'Brien 	alias(&cmd);
239c80476e4SDavid E. O'Brien 	/* build a syntax tree for the command. */
240c80476e4SDavid E. O'Brien 	t = syntax(cmd.next, &cmd, 0);
24145e5710bSMark Peek 	cleanup_push(t, syntax_cleanup);
242c80476e4SDavid E. O'Brien 	if (seterr)
243c80476e4SDavid E. O'Brien 	    stderror(ERR_OLD);
244c80476e4SDavid E. O'Brien 	/* execute the parse tree. */
24529301572SMark Peek 	execute(t, -1, NULL, NULL, TRUE);
246c80476e4SDavid E. O'Brien 	/* done. free the lex list and parse tree. */
24745e5710bSMark Peek 	cleanup_until(&cmd);
248c80476e4SDavid E. O'Brien     }
249c80476e4SDavid E. O'Brien     if (GettingInput && !just_signaled) {	/* PWP */
250c80476e4SDavid E. O'Brien 	(void) Rawmode();
251c80476e4SDavid E. O'Brien 	ClearLines();		/* do a real refresh since something may */
252c80476e4SDavid E. O'Brien 	ClearDisp();		/* have printed to the screen */
253c80476e4SDavid E. O'Brien 	Refresh();
254c80476e4SDavid E. O'Brien     }
255c80476e4SDavid E. O'Brien     just_signaled = 0;
256c80476e4SDavid E. O'Brien 
25745e5710bSMark Peek     cleanup_until(&pintr_disabled);
258c80476e4SDavid E. O'Brien }
259