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