1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * alarm [-r] [varname [+]when]
23*4887Schin  *
24*4887Schin  *   David Korn
25*4887Schin  *   AT&T Labs
26*4887Schin  *
27*4887Schin  */
28*4887Schin 
29*4887Schin #include	"defs.h"
30*4887Schin #include	<error.h>
31*4887Schin #include	<stak.h>
32*4887Schin #include	"builtins.h"
33*4887Schin #include	"FEATURE/time"
34*4887Schin 
35*4887Schin #define R_FLAG	1
36*4887Schin #define L_FLAG	2
37*4887Schin 
38*4887Schin struct	tevent
39*4887Schin {
40*4887Schin 	Namfun_t	fun;
41*4887Schin 	Namval_t	*node;
42*4887Schin 	Namval_t	*action;
43*4887Schin 	struct tevent	*next;
44*4887Schin 	long		milli;
45*4887Schin 	int		flags;
46*4887Schin 	void            *timeout;
47*4887Schin 	Shell_t		*sh;
48*4887Schin };
49*4887Schin 
50*4887Schin static const char ALARM[] = "alarm";
51*4887Schin 
52*4887Schin static void	trap_timeout(void*);
53*4887Schin 
54*4887Schin /*
55*4887Schin  * insert timeout item on current given list in sorted order
56*4887Schin  */
57*4887Schin static void *time_add(struct tevent *item, void *list)
58*4887Schin {
59*4887Schin 	register struct tevent *tp = (struct tevent*)list;
60*4887Schin 	if(!tp || item->milli < tp->milli)
61*4887Schin 	{
62*4887Schin 		item->next = tp;
63*4887Schin 		list = (void*)item;
64*4887Schin 	}
65*4887Schin 	else
66*4887Schin 	{
67*4887Schin 		while(tp->next && item->milli > tp->next->milli)
68*4887Schin 			tp = tp->next;
69*4887Schin 		item->next = tp->next;
70*4887Schin 		tp->next = item;
71*4887Schin 	}
72*4887Schin 	tp = item;
73*4887Schin 	tp->timeout = (void*)sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,(void*)tp);
74*4887Schin 	return(list);
75*4887Schin }
76*4887Schin 
77*4887Schin /*
78*4887Schin  * delete timeout item from current given list, delete timer
79*4887Schin  */
80*4887Schin static 	void *time_delete(register struct tevent *item, void *list)
81*4887Schin {
82*4887Schin 	register struct tevent *tp = (struct tevent*)list;
83*4887Schin 	if(item==tp)
84*4887Schin 		list = (void*)tp->next;
85*4887Schin 	else
86*4887Schin 	{
87*4887Schin 		while(tp && tp->next != item)
88*4887Schin 			tp = tp->next;
89*4887Schin 		if(tp)
90*4887Schin 			tp->next = item->next;
91*4887Schin 	}
92*4887Schin 	if(item->timeout)
93*4887Schin 		timerdel((void*)item->timeout);
94*4887Schin 	return(list);
95*4887Schin }
96*4887Schin 
97*4887Schin static void	print_alarms(void *list)
98*4887Schin {
99*4887Schin 	register struct tevent *tp = (struct tevent*)list;
100*4887Schin 	while(tp)
101*4887Schin 	{
102*4887Schin 		if(tp->timeout)
103*4887Schin 		{
104*4887Schin 			register char *name = nv_name(tp->node);
105*4887Schin 			if(tp->flags&R_FLAG)
106*4887Schin 			{
107*4887Schin 				double d = tp->milli;
108*4887Schin 				sfprintf(sfstdout,e_alrm1,name,d/1000.);
109*4887Schin 			}
110*4887Schin 			else
111*4887Schin 				sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node));
112*4887Schin 		}
113*4887Schin 		tp = tp->next;
114*4887Schin 	}
115*4887Schin }
116*4887Schin 
117*4887Schin static void	trap_timeout(void* handle)
118*4887Schin {
119*4887Schin 	register struct tevent *tp = (struct tevent*)handle;
120*4887Schin 	tp->sh->trapnote |= SH_SIGALRM;
121*4887Schin 	if(!(tp->flags&R_FLAG))
122*4887Schin 		tp->timeout = 0;
123*4887Schin 	tp->flags |= L_FLAG;
124*4887Schin 	tp->sh->sigflag[SIGALRM] |= SH_SIGALRM;
125*4887Schin 	if(sh_isstate(SH_TTYWAIT))
126*4887Schin 		sh_timetraps();
127*4887Schin }
128*4887Schin 
129*4887Schin void	sh_timetraps(void)
130*4887Schin {
131*4887Schin 	register struct tevent *tp, *tpnext;
132*4887Schin 	register struct tevent *tptop;
133*4887Schin 	while(1)
134*4887Schin 	{
135*4887Schin 		sh.sigflag[SIGALRM] &= ~SH_SIGALRM;
136*4887Schin 		tptop= (struct tevent*)sh.st.timetrap;
137*4887Schin 		for(tp=tptop;tp;tp=tpnext)
138*4887Schin 		{
139*4887Schin 			tpnext = tp->next;
140*4887Schin 			if(tp->flags&L_FLAG)
141*4887Schin 			{
142*4887Schin 				tp->flags &= ~L_FLAG;
143*4887Schin 				if(tp->action)
144*4887Schin 					sh_fun(tp->action,tp->node,(char**)0);
145*4887Schin 				tp->flags &= ~L_FLAG;
146*4887Schin 				if(!tp->flags)
147*4887Schin 				{
148*4887Schin 					nv_unset(tp->node);
149*4887Schin 					nv_close(tp->node);
150*4887Schin 				}
151*4887Schin 			}
152*4887Schin 		}
153*4887Schin 		if(!(sh.sigflag[SIGALRM]&SH_SIGALRM))
154*4887Schin 			break;
155*4887Schin 	}
156*4887Schin }
157*4887Schin 
158*4887Schin 
159*4887Schin /*
160*4887Schin  * This trap function catches "alarm" actions only
161*4887Schin  */
162*4887Schin static char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t
163*4887Schin  *fp)
164*4887Schin {
165*4887Schin         register struct tevent *tp = (struct tevent*)fp;
166*4887Schin 	if(!event)
167*4887Schin 		return(action?"":(char*)ALARM);
168*4887Schin 	if(strcmp(event,ALARM)!=0)
169*4887Schin 	{
170*4887Schin 		/* try the next level */
171*4887Schin 		return(nv_setdisc(np, event, action, fp));
172*4887Schin 	}
173*4887Schin 	if(action==np)
174*4887Schin 		action = tp->action;
175*4887Schin 	else
176*4887Schin 		tp->action = action;
177*4887Schin 	return(action?(char*)action:"");
178*4887Schin }
179*4887Schin 
180*4887Schin /*
181*4887Schin  * catch assignments and set alarm traps
182*4887Schin  */
183*4887Schin static void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp)
184*4887Schin {
185*4887Schin 	register struct tevent *tp;
186*4887Schin 	register double d;
187*4887Schin 	if(val)
188*4887Schin 	{
189*4887Schin 		double now;
190*4887Schin #ifdef timeofday
191*4887Schin 		struct timeval tmp;
192*4887Schin 		timeofday(&tmp);
193*4887Schin 		now = tmp.tv_sec + 1.e-6*tmp.tv_usec;
194*4887Schin #else
195*4887Schin 		now = (double)time(NIL(time_t*));
196*4887Schin #endif /* timeofday */
197*4887Schin 		nv_putv(np,val,flag,fp);
198*4887Schin 		d = nv_getnum(np);
199*4887Schin 		tp = (struct tevent*)fp;
200*4887Schin 		if(*val=='+')
201*4887Schin 		{
202*4887Schin 			double x = d + now;
203*4887Schin 			nv_putv(np,(char*)&x,NV_INTEGER,fp);
204*4887Schin 		}
205*4887Schin 		else
206*4887Schin 			d -= now;
207*4887Schin 		tp->milli = 1000*(d+.0005);
208*4887Schin 		if(tp->timeout)
209*4887Schin 			sh.st.timetrap = time_delete(tp,sh.st.timetrap);
210*4887Schin 		if(tp->milli > 0)
211*4887Schin 			sh.st.timetrap = time_add(tp,sh.st.timetrap);
212*4887Schin 	}
213*4887Schin 	else
214*4887Schin 	{
215*4887Schin 		tp = (struct tevent*)nv_stack(np, (Namfun_t*)0);
216*4887Schin 		sh.st.timetrap = time_delete(tp,sh.st.timetrap);
217*4887Schin 		if(tp->action)
218*4887Schin 			nv_close(tp->action);
219*4887Schin 		nv_unset(np);
220*4887Schin 		free((void*)fp);
221*4887Schin 	}
222*4887Schin }
223*4887Schin 
224*4887Schin static const Namdisc_t alarmdisc =
225*4887Schin {
226*4887Schin 	sizeof(struct tevent),
227*4887Schin 	putval,
228*4887Schin 	0,
229*4887Schin 	0,
230*4887Schin 	setdisc,
231*4887Schin };
232*4887Schin 
233*4887Schin int	b_alarm(int argc,char *argv[],void *extra)
234*4887Schin {
235*4887Schin 	register int n,rflag=0;
236*4887Schin 	register Namval_t *np;
237*4887Schin 	register struct tevent *tp;
238*4887Schin 	register Shell_t *shp = (Shell_t*)extra;
239*4887Schin 	while (n = optget(argv, sh_optalarm)) switch (n)
240*4887Schin 	{
241*4887Schin 	    case 'r':
242*4887Schin 		rflag = R_FLAG;
243*4887Schin 		break;
244*4887Schin 	    case ':':
245*4887Schin 		errormsg(SH_DICT,2, "%s", opt_info.arg);
246*4887Schin 		break;
247*4887Schin 	    case '?':
248*4887Schin 		errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
249*4887Schin 		break;
250*4887Schin 	}
251*4887Schin 	argc -= opt_info.index;
252*4887Schin 	argv += opt_info.index;
253*4887Schin 	if(error_info.errors)
254*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
255*4887Schin 	if(argc==0)
256*4887Schin 	{
257*4887Schin 		print_alarms(shp->st.timetrap);
258*4887Schin 		return(0);
259*4887Schin 	}
260*4887Schin 	if(argc!=2)
261*4887Schin 		errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
262*4887Schin 	np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN);
263*4887Schin 	if(!nv_isnull(np))
264*4887Schin 		nv_unset(np);
265*4887Schin 	nv_setattr(np, NV_INTEGER|NV_DOUBLE);
266*4887Schin 	if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0)))
267*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_nospace);
268*4887Schin 	tp->fun.disc = &alarmdisc;
269*4887Schin 	tp->flags = rflag;
270*4887Schin 	tp->node = np;
271*4887Schin 	tp->sh = shp;
272*4887Schin 	nv_stack(np,(Namfun_t*)tp);
273*4887Schin 	nv_putval(np, argv[1], 0);
274*4887Schin 	return(0);
275*4887Schin }
276*4887Schin 
277