14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * Shell arithmetic - uses streval library
234887Schin  *   David Korn
244887Schin  *   AT&T Labs
254887Schin  */
264887Schin 
274887Schin #include	"defs.h"
284887Schin #include	<ctype.h>
294887Schin #include	"lexstates.h"
304887Schin #include	"name.h"
314887Schin #include	"streval.h"
324887Schin #include	"variables.h"
334887Schin 
344887Schin #ifndef LLONG_MAX
354887Schin #define LLONG_MAX	LONG_MAX
364887Schin #endif
374887Schin 
38*8462SApril.Chin@Sun.COM static Sfdouble_t	NaN, Inf, Fun;
394887Schin static Namval_t Infnod =
404887Schin {
414887Schin 	{ 0 },
424887Schin 	"Inf",
434887Schin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
444887Schin };
454887Schin 
464887Schin static Namval_t NaNnod =
474887Schin {
484887Schin 	{ 0 },
494887Schin 	"NaN",
504887Schin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
514887Schin };
524887Schin 
53*8462SApril.Chin@Sun.COM static Namval_t FunNode =
54*8462SApril.Chin@Sun.COM {
55*8462SApril.Chin@Sun.COM 	{ 0 },
56*8462SApril.Chin@Sun.COM 	"?",
57*8462SApril.Chin@Sun.COM 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
58*8462SApril.Chin@Sun.COM };
59*8462SApril.Chin@Sun.COM 
60*8462SApril.Chin@Sun.COM static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval *lvalue,int assign)
614887Schin {
624887Schin 	register Namarr_t *ap;
634887Schin 	register int flag = lvalue->flag;
64*8462SApril.Chin@Sun.COM 	register char *sub=0, *cp=(char*)np;
65*8462SApril.Chin@Sun.COM 	register Namval_t *mp;
66*8462SApril.Chin@Sun.COM 	int	flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET;
67*8462SApril.Chin@Sun.COM 	Dt_t	*sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0);
68*8462SApril.Chin@Sun.COM 	assign = assign?NV_ASSIGN:NV_NOASSIGN;
69*8462SApril.Chin@Sun.COM 	if(cp>=lvalue->expr &&  cp < lvalue->expr+lvalue->elen)
704887Schin 	{
71*8462SApril.Chin@Sun.COM 		int offset;
72*8462SApril.Chin@Sun.COM 		/* do binding to node now */
73*8462SApril.Chin@Sun.COM 		int c = cp[flag];
74*8462SApril.Chin@Sun.COM 		cp[flag] = 0;
75*8462SApril.Chin@Sun.COM 		if((!(np = nv_open(cp,shp->var_tree,assign|NV_VARNAME|NV_NOADD|NV_NOFAIL)) || nv_isnull(np)) && sh_macfun(shp,cp, offset = staktell()))
764887Schin 		{
77*8462SApril.Chin@Sun.COM 			Fun = sh_arith(sub=stakptr(offset));
78*8462SApril.Chin@Sun.COM 			FunNode.nvalue.ldp = &Fun;
794887Schin 			cp[flag] = c;
80*8462SApril.Chin@Sun.COM 			return(&FunNode);
814887Schin 		}
82*8462SApril.Chin@Sun.COM 		np = nv_open(cp,shp->var_tree,assign|NV_VARNAME);
83*8462SApril.Chin@Sun.COM 		cp[flag] = c;
84*8462SApril.Chin@Sun.COM 		if(cp[flag+1]=='[')
85*8462SApril.Chin@Sun.COM 			flag++;
86*8462SApril.Chin@Sun.COM 		else
87*8462SApril.Chin@Sun.COM 			flag = 0;
88*8462SApril.Chin@Sun.COM 		cp = (char*)np;
89*8462SApril.Chin@Sun.COM 	}
90*8462SApril.Chin@Sun.COM 	if((lvalue->emode&ARITH_COMP) && dtvnext(shp->var_tree) && ((mp=nv_search(cp,shp->var_tree,flags))||(sdict && (mp=nv_search(cp,sdict,flags)))))
91*8462SApril.Chin@Sun.COM 	{
92*8462SApril.Chin@Sun.COM 		while(nv_isref(mp))
934887Schin 		{
94*8462SApril.Chin@Sun.COM 			sub = nv_refsub(mp);
95*8462SApril.Chin@Sun.COM 			mp = nv_refnode(mp);
964887Schin 		}
97*8462SApril.Chin@Sun.COM 		np = mp;
984887Schin 	}
994887Schin 	if(flag || sub)
1004887Schin 	{
1014887Schin 		if(!sub)
1024887Schin 			sub = (char*)&lvalue->expr[flag];
1034887Schin 		if(((ap=nv_arrayptr(np)) && array_assoc(ap)) || (lvalue->emode&ARITH_COMP))
1044887Schin 			nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
1054887Schin 		else
1064887Schin 			nv_putsub(np, NIL(char*),flag);
1074887Schin 	}
1084887Schin 	return(np);
1094887Schin }
1104887Schin 
1114887Schin static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
1124887Schin {
113*8462SApril.Chin@Sun.COM 	Shell_t		*shp = &sh;
1144887Schin 	register Sfdouble_t r= 0;
1154887Schin 	char *str = (char*)*ptr;
116*8462SApril.Chin@Sun.COM 	register char *cp;
1174887Schin 	switch(type)
1184887Schin 	{
1194887Schin 	    case ASSIGN:
1204887Schin 	    {
1214887Schin 		register Namval_t *np = (Namval_t*)(lvalue->value);
122*8462SApril.Chin@Sun.COM 		np = scope(shp,np,lvalue,1);
1234887Schin 		nv_putval(np, (char*)&n, NV_LDOUBLE);
1244887Schin 		r=nv_getnum(np);
1254887Schin 		break;
1264887Schin 	    }
1274887Schin 	    case LOOKUP:
1284887Schin 	    {
1294887Schin 		register int c = *str;
1304887Schin 		register char *xp=str;
1314887Schin 		lvalue->value = (char*)0;
1324887Schin 		if(c=='.')
1334887Schin 			str++;
1344887Schin 		c = mbchar(str);
1354887Schin 		if(isaletter(c))
1364887Schin 		{
1374887Schin 			register Namval_t *np;
1384887Schin 			int dot=0;
1394887Schin 			while(1)
1404887Schin 			{
1414887Schin 				while(xp=str, c=mbchar(str), isaname(c));
1424887Schin 				str = xp;
143*8462SApril.Chin@Sun.COM 				if(c=='[' && dot==NV_NOADD)
144*8462SApril.Chin@Sun.COM 				{
145*8462SApril.Chin@Sun.COM 					str = nv_endsubscript((Namval_t*)0,str,0);
146*8462SApril.Chin@Sun.COM 					c = *str;
147*8462SApril.Chin@Sun.COM 				}
1484887Schin 				if(c!='.')
1494887Schin 					break;
150*8462SApril.Chin@Sun.COM 				dot=NV_NOADD;
1514887Schin 				if((c = *++str) !='[')
1524887Schin 					continue;
1534887Schin 				str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
1544887Schin 				if(sh_checkid(cp+1,(char*)0))
1554887Schin 					str -=2;
1564887Schin 			}
1574887Schin 			if(c=='(')
1584887Schin 			{
1594887Schin 				int fsize = str- (char*)(*ptr);
1604887Schin 				const struct mathtab *tp;
1614887Schin 				c = **ptr;
1624887Schin 				lvalue->fun = 0;
1634887Schin 				if(fsize<=(sizeof(tp->fname)-2)) for(tp=shtab_math; *tp->fname; tp++)
1644887Schin 				{
1654887Schin 					if(*tp->fname > c)
1664887Schin 						break;
1674887Schin 					if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],*ptr,fsize)==0)
1684887Schin 					{
1694887Schin 						lvalue->fun = tp->fnptr;
1704887Schin 						lvalue->nargs = *tp->fname;
1714887Schin 						break;
1724887Schin 					}
1734887Schin 				}
1744887Schin 				if(lvalue->fun)
1754887Schin 					break;
1764887Schin 				lvalue->value = (char*)ERROR_dictionary(e_function);
1774887Schin 				return(r);
1784887Schin 			}
1794887Schin 			if((lvalue->emode&ARITH_COMP) && dot)
1804887Schin 			{
1814887Schin 				lvalue->value = (char*)*ptr;
1824887Schin 				lvalue->flag =  str-lvalue->value;
1834887Schin 				break;
1844887Schin 			}
1854887Schin 			*str = 0;
1864887Schin 			if(sh_isoption(SH_NOEXEC))
1874887Schin 				np = L_ARGNOD;
1884887Schin 			else
1894887Schin 			{
1904887Schin 				int offset = staktell();
1914887Schin 				char *saveptr = stakfreeze(0);
192*8462SApril.Chin@Sun.COM 				Dt_t  *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree;
1934887Schin 				*str = c;
1944887Schin 				while(c=='[' || c=='.')
1954887Schin 				{
1964887Schin 					if(c=='[')
1974887Schin 					{
1984887Schin 						str = nv_endsubscript(np,cp=str,0);
1994887Schin 						if((c= *str)!='[' &&  c!='.')
2004887Schin 						{
2014887Schin 							str = cp;
2024887Schin 							c = '[';
2034887Schin 							break;
2044887Schin 						}
2054887Schin 					}
2064887Schin 					else
2074887Schin 					{
208*8462SApril.Chin@Sun.COM 						dot = NV_NOADD|NV_NOFAIL;
2094887Schin 						str++;
2104887Schin 						while(xp=str, c=mbchar(str), isaname(c));
2114887Schin 						str = xp;
2124887Schin 					}
2134887Schin 				}
2144887Schin 				*str = 0;
215*8462SApril.Chin@Sun.COM 				cp = (char*)*ptr;
216*8462SApril.Chin@Sun.COM 				if ((cp[0] == 'i' || cp[0] == 'I') && (cp[1] == 'n' || cp[1] == 'N') && (cp[2] == 'f' || cp[2] == 'F') && cp[3] == 0)
2174887Schin 				{
218*8462SApril.Chin@Sun.COM 					Inf = strtold("Inf", NiL);
2194887Schin 					Infnod.nvalue.ldp = &Inf;
2204887Schin 					np = &Infnod;
2214887Schin 				}
222*8462SApril.Chin@Sun.COM 				else if ((cp[0] == 'n' || cp[0] == 'N') && (cp[1] == 'a' || cp[1] == 'A') && (cp[2] == 'n' || cp[2] == 'N') && cp[3] == 0)
2234887Schin 				{
224*8462SApril.Chin@Sun.COM 					NaN = strtold("NaN", NiL);
2254887Schin 					NaNnod.nvalue.ldp = &NaN;
2264887Schin 					np = &NaNnod;
2274887Schin 				}
228*8462SApril.Chin@Sun.COM 				else if(!(np = nv_open(*ptr,root,NV_NOASSIGN|NV_VARNAME|dot)))
229*8462SApril.Chin@Sun.COM 				{
230*8462SApril.Chin@Sun.COM 					lvalue->value = (char*)*ptr;
231*8462SApril.Chin@Sun.COM 					lvalue->flag =  str-lvalue->value;
232*8462SApril.Chin@Sun.COM 				}
2334887Schin 				if(saveptr != stakptr(0))
2344887Schin 					stakset(saveptr,offset);
2354887Schin 				else
2364887Schin 					stakseek(offset);
2374887Schin 			}
2384887Schin 			*str = c;
239*8462SApril.Chin@Sun.COM 			if(!np && lvalue->value)
240*8462SApril.Chin@Sun.COM 				break;
2414887Schin 			lvalue->value = (char*)np;
2424887Schin 			if((lvalue->emode&ARITH_COMP) || (nv_isarray(np) && nv_aindex(np)<0))
2434887Schin 			{
2444887Schin 				/* bind subscript later */
2454887Schin 				lvalue->flag = 0;
2464887Schin 				if(c=='[')
2474887Schin 				{
2484887Schin 					lvalue->flag = (str-lvalue->expr);
2494887Schin 					do
2504887Schin 						str = nv_endsubscript(np,str,0);
2514887Schin 					while((c= *str)=='[');
2524887Schin 				}
2534887Schin 				break;
2544887Schin 			}
2554887Schin 			if(c=='[')
2564887Schin 			{
2574887Schin 				do
2584887Schin 					str = nv_endsubscript(np,str,NV_ADD|NV_SUBQUOTE);
2594887Schin 				while((c=*str)=='[');
2604887Schin 			}
261*8462SApril.Chin@Sun.COM 			if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
2624887Schin 				lvalue->isfloat=1;
2634887Schin 			lvalue->flag = nv_aindex(np);
2644887Schin 		}
2654887Schin 		else
2664887Schin 		{
2674887Schin 			char	lastbase=0, *val = xp, oerrno = errno;
2684887Schin 			errno = 0;
2694887Schin 			r = strtonll(val,&str, &lastbase,-1);
2704887Schin 			if(*str=='8' || *str=='9')
2714887Schin 			{
2724887Schin 				lastbase=10;
2734887Schin 				errno = 0;
2744887Schin 				r = strtonll(val,&str, &lastbase,-1);
2754887Schin 			}
2764887Schin 			if(lastbase<=1)
2774887Schin 				lastbase=10;
2784887Schin 			if(*val=='0')
2794887Schin 			{
2804887Schin 				while(*val=='0')
2814887Schin 					val++;
2824887Schin 				if(*val==0 || *val=='.' || *val=='x' || *val=='X')
2834887Schin 					val--;
2844887Schin 			}
2854887Schin 			if(r==LLONG_MAX && errno)
2864887Schin 				c='e';
2874887Schin 			else
2884887Schin 				c = *str;
289*8462SApril.Chin@Sun.COM 			if(c==GETDECIMAL(0) || c=='e' || c == 'E' || lastbase ==
290*8462SApril.Chin@Sun.COM  16 && (c == 'p' || c == 'P'))
2914887Schin 			{
2924887Schin 				lvalue->isfloat=1;
2934887Schin 				r = strtold(val,&str);
2944887Schin 			}
2954887Schin 			else if(lastbase==10 && val[1])
2964887Schin 			{
2974887Schin 				if(val[2]=='#')
2984887Schin 					val += 3;
2994887Schin 				if((str-val)>2*sizeof(Sflong_t))
3004887Schin 				{
3014887Schin 					Sfdouble_t rr;
3024887Schin 					rr = strtold(val,&str);
3034887Schin 					if(rr!=r)
3044887Schin 					{
3054887Schin 						r = rr;
3064887Schin 						lvalue->isfloat=1;
3074887Schin 					}
3084887Schin 				}
3094887Schin 			}
3104887Schin 			errno = oerrno;
3114887Schin 		}
3124887Schin 		break;
3134887Schin 	    }
3144887Schin 	    case VALUE:
3154887Schin 	    {
3164887Schin 		register Namval_t *np = (Namval_t*)(lvalue->value);
3174887Schin 		if(sh_isoption(SH_NOEXEC))
3184887Schin 			return(0);
319*8462SApril.Chin@Sun.COM 		np = scope(shp,np,lvalue,0);
3204887Schin 		if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
3214887Schin 		{
3224887Schin 			*ptr = nv_name(np);
3234887Schin 			lvalue->value = (char*)ERROR_dictionary(e_notset);
3244887Schin 			lvalue->emode |= 010;
3254887Schin 			return(0);
3264887Schin 		}
3274887Schin 		r = nv_getnum(np);
3284887Schin 		if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
3294887Schin 			lvalue->isfloat= (r!=(Sflong_t)r);
330*8462SApril.Chin@Sun.COM 		else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
3314887Schin 			lvalue->isfloat=1;
3324887Schin 		return(r);
3334887Schin 	    }
3344887Schin 
3354887Schin 	    case MESSAGE:
3364887Schin 		sfsync(NIL(Sfio_t*));
3374887Schin #if 0
3384887Schin 		if(warn)
3394887Schin 			errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
3404887Schin 		else
3414887Schin #endif
3424887Schin 			errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
3434887Schin 	}
3444887Schin 	*ptr = str;
3454887Schin 	return(r);
3464887Schin }
3474887Schin 
3484887Schin /*
3494887Schin  * convert number defined by string to a Sfdouble_t
3504887Schin  * ptr is set to the last character processed
3514887Schin  * if mode>0, an error will be fatal with value <mode>
3524887Schin  */
3534887Schin 
3544887Schin Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
3554887Schin {
3564887Schin 	register Sfdouble_t d;
3574887Schin 	char base=0, *last;
3584887Schin 	if(*str==0)
3594887Schin 	{
3604887Schin 		if(ptr)
3614887Schin 			*ptr = (char*)str;
3624887Schin 		return(0);
3634887Schin 	}
3644887Schin 	errno = 0;
3654887Schin 	d = strtonll(str,&last,&base,-1);
3664887Schin 	if(*last || errno)
3674887Schin 	{
368*8462SApril.Chin@Sun.COM 		if(!last || *last!='.' || last[1]!='.')
369*8462SApril.Chin@Sun.COM 			d = strval(str,&last,arith,mode);
3704887Schin 		if(!ptr && *last && mode>0)
3714887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
3724887Schin 	}
373*8462SApril.Chin@Sun.COM 	else if (!d && *str=='-')
374*8462SApril.Chin@Sun.COM 		d = -0.0;
3754887Schin 	if(ptr)
3764887Schin 		*ptr = last;
3774887Schin 	return(d);
3784887Schin }
3794887Schin 
3804887Schin Sfdouble_t sh_arith(register const char *str)
3814887Schin {
3824887Schin 	return(sh_strnum(str, (char**)0, 1));
3834887Schin }
3844887Schin 
3854887Schin void	*sh_arithcomp(register char *str)
3864887Schin {
3874887Schin 	const char *ptr = str;
3884887Schin 	Arith_t *ep;
3894887Schin 	ep = arith_compile(str,(char**)&ptr,arith,ARITH_COMP|1);
3904887Schin 	if(*ptr)
3914887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
3924887Schin 	return((void*)ep);
3934887Schin }
394