1N/A/***********************************************************************
1N/A* *
1N/A* This software is part of the ast package *
1N/A* Copyright (c) 1982-2011 AT&T Intellectual Property *
1N/A* and is licensed under the *
1N/A* Common Public License, Version 1.0 *
1N/A* by AT&T Intellectual Property *
1N/A* *
1N/A* A copy of the License is available at *
1N/A* http://www.opensource.org/licenses/cpl1.0.txt *
1N/A* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
1N/A* *
1N/A* Information and Software Systems Research *
1N/A* AT&T Research *
1N/A* Florham Park NJ *
1N/A* *
1N/A* David Korn <dgk@research.att.com> *
1N/A* *
1N/A***********************************************************************/
1N/A#pragma prototyped
1N/A/*
1N/A * alarm [-r] [varname [+]when]
1N/A *
1N/A * David Korn
1N/A * AT&T Labs
1N/A *
1N/A */
1N/A
1N/A#include "defs.h"
1N/A#include <error.h>
1N/A#include <stak.h>
1N/A#include "builtins.h"
1N/A#include "FEATURE/time"
1N/A
1N/A#define R_FLAG 1
1N/A#define L_FLAG 2
1N/A
1N/Astruct tevent
1N/A{
1N/A Namfun_t fun;
1N/A Namval_t *node;
1N/A Namval_t *action;
1N/A struct tevent *next;
1N/A long milli;
1N/A int flags;
1N/A void *timeout;
1N/A Shell_t *sh;
1N/A};
1N/A
1N/Astatic const char ALARM[] = "alarm";
1N/A
1N/Astatic void trap_timeout(void*);
1N/A
1N/A/*
1N/A * insert timeout item on current given list in sorted order
1N/A */
1N/Astatic void *time_add(struct tevent *item, void *list)
1N/A{
1N/A register struct tevent *tp = (struct tevent*)list;
1N/A if(!tp || item->milli < tp->milli)
1N/A {
1N/A item->next = tp;
1N/A list = (void*)item;
1N/A }
1N/A else
1N/A {
1N/A while(tp->next && item->milli > tp->next->milli)
1N/A tp = tp->next;
1N/A item->next = tp->next;
1N/A tp->next = item;
1N/A }
1N/A tp = item;
1N/A tp->timeout = (void*)sh_timeradd(tp->milli,tp->flags&R_FLAG,trap_timeout,(void*)tp);
1N/A return(list);
1N/A}
1N/A
1N/A/*
1N/A * delete timeout item from current given list, delete timer
1N/A */
1N/Astatic void *time_delete(register struct tevent *item, void *list)
1N/A{
1N/A register struct tevent *tp = (struct tevent*)list;
1N/A if(item==tp)
1N/A list = (void*)tp->next;
1N/A else
1N/A {
1N/A while(tp && tp->next != item)
1N/A tp = tp->next;
1N/A if(tp)
1N/A tp->next = item->next;
1N/A }
1N/A if(item->timeout)
1N/A timerdel((void*)item->timeout);
1N/A return(list);
1N/A}
1N/A
1N/Astatic void print_alarms(void *list)
1N/A{
1N/A register struct tevent *tp = (struct tevent*)list;
1N/A while(tp)
1N/A {
1N/A if(tp->timeout)
1N/A {
1N/A register char *name = nv_name(tp->node);
1N/A if(tp->flags&R_FLAG)
1N/A {
1N/A double d = tp->milli;
1N/A sfprintf(sfstdout,e_alrm1,name,d/1000.);
1N/A }
1N/A else
1N/A sfprintf(sfstdout,e_alrm2,name,nv_getnum(tp->node));
1N/A }
1N/A tp = tp->next;
1N/A }
1N/A}
1N/A
1N/Astatic void trap_timeout(void* handle)
1N/A{
1N/A register struct tevent *tp = (struct tevent*)handle;
1N/A tp->sh->trapnote |= SH_SIGALRM;
1N/A if(!(tp->flags&R_FLAG))
1N/A tp->timeout = 0;
1N/A tp->flags |= L_FLAG;
1N/A tp->sh->sigflag[SIGALRM] |= SH_SIGALRM;
1N/A if(sh_isstate(SH_TTYWAIT))
1N/A sh_timetraps(tp->sh);
1N/A}
1N/A
1N/Avoid sh_timetraps(Shell_t *shp)
1N/A{
1N/A register struct tevent *tp, *tpnext;
1N/A register struct tevent *tptop;
1N/A while(1)
1N/A {
1N/A shp->sigflag[SIGALRM] &= ~SH_SIGALRM;
1N/A tptop= (struct tevent*)shp->st.timetrap;
1N/A for(tp=tptop;tp;tp=tpnext)
1N/A {
1N/A tpnext = tp->next;
1N/A if(tp->flags&L_FLAG)
1N/A {
1N/A tp->flags &= ~L_FLAG;
1N/A if(tp->action)
1N/A sh_fun(tp->action,tp->node,(char**)0);
1N/A tp->flags &= ~L_FLAG;
1N/A if(!tp->flags)
1N/A {
1N/A nv_unset(tp->node);
1N/A nv_close(tp->node);
1N/A }
1N/A }
1N/A }
1N/A if(!(shp->sigflag[SIGALRM]&SH_SIGALRM))
1N/A break;
1N/A }
1N/A}
1N/A
1N/A
1N/A/*
1N/A * This trap function catches "alarm" actions only
1N/A */
1N/Astatic char *setdisc(Namval_t *np, const char *event, Namval_t* action, Namfun_t
1N/A *fp)
1N/A{
1N/A register struct tevent *tp = (struct tevent*)fp;
1N/A if(!event)
1N/A return(action?"":(char*)ALARM);
1N/A if(strcmp(event,ALARM)!=0)
1N/A {
1N/A /* try the next level */
1N/A return(nv_setdisc(np, event, action, fp));
1N/A }
1N/A if(action==np)
1N/A action = tp->action;
1N/A else
1N/A tp->action = action;
1N/A return(action?(char*)action:"");
1N/A}
1N/A
1N/A/*
1N/A * catch assignments and set alarm traps
1N/A */
1N/Astatic void putval(Namval_t* np, const char* val, int flag, Namfun_t* fp)
1N/A{
1N/A register struct tevent *tp = (struct tevent*)fp;
1N/A register double d;
1N/A Shell_t *shp = tp->sh;
1N/A if(val)
1N/A {
1N/A double now;
1N/A#ifdef timeofday
1N/A struct timeval tmp;
1N/A timeofday(&tmp);
1N/A now = tmp.tv_sec + 1.e-6*tmp.tv_usec;
1N/A#else
1N/A now = (double)time(NIL(time_t*));
1N/A#endif /* timeofday */
1N/A nv_putv(np,val,flag,fp);
1N/A d = nv_getnum(np);
1N/A if(*val=='+')
1N/A {
1N/A double x = d + now;
1N/A nv_putv(np,(char*)&x,NV_INTEGER|NV_DOUBLE,fp);
1N/A }
1N/A else
1N/A d -= now;
1N/A tp->milli = 1000*(d+.0005);
1N/A if(tp->timeout)
1N/A shp->st.timetrap = time_delete(tp,shp->st.timetrap);
1N/A if(tp->milli > 0)
1N/A shp->st.timetrap = time_add(tp,shp->st.timetrap);
1N/A }
1N/A else
1N/A {
1N/A tp = (struct tevent*)nv_stack(np, (Namfun_t*)0);
1N/A shp->st.timetrap = time_delete(tp,shp->st.timetrap);
1N/A if(tp->action)
1N/A nv_close(tp->action);
1N/A nv_unset(np);
1N/A free((void*)fp);
1N/A }
1N/A}
1N/A
1N/Astatic const Namdisc_t alarmdisc =
1N/A{
1N/A sizeof(struct tevent),
1N/A putval,
1N/A 0,
1N/A 0,
1N/A setdisc,
1N/A};
1N/A
1N/Aint b_alarm(int argc,char *argv[],void *extra)
1N/A{
1N/A register int n,rflag=0;
1N/A register Namval_t *np;
1N/A register struct tevent *tp;
1N/A register Shell_t *shp = ((Shbltin_t*)extra)->shp;
1N/A while (n = optget(argv, sh_optalarm)) switch (n)
1N/A {
1N/A case 'r':
1N/A rflag = R_FLAG;
1N/A break;
1N/A case ':':
1N/A errormsg(SH_DICT,2, "%s", opt_info.arg);
1N/A break;
1N/A case '?':
1N/A errormsg(SH_DICT,ERROR_usage(2), "%s", opt_info.arg);
1N/A break;
1N/A }
1N/A argc -= opt_info.index;
1N/A argv += opt_info.index;
1N/A if(error_info.errors)
1N/A errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
1N/A if(argc==0)
1N/A {
1N/A print_alarms(shp->st.timetrap);
1N/A return(0);
1N/A }
1N/A if(argc!=2)
1N/A errormsg(SH_DICT,ERROR_usage(2),optusage((char*)0));
1N/A np = nv_open(argv[0],shp->var_tree,NV_NOARRAY|NV_VARNAME|NV_NOASSIGN);
1N/A if(!nv_isnull(np))
1N/A nv_unset(np);
1N/A nv_setattr(np, NV_DOUBLE);
1N/A if(!(tp = newof(NIL(struct tevent*),struct tevent,1,0)))
1N/A errormsg(SH_DICT,ERROR_exit(1),e_nospace);
1N/A tp->fun.disc = &alarmdisc;
1N/A tp->flags = rflag;
1N/A tp->node = np;
1N/A tp->sh = shp;
1N/A nv_stack(np,(Namfun_t*)tp);
1N/A nv_putval(np, argv[1], 0);
1N/A return(0);
1N/A}
1N/A