xref: /onnv-gate/usr/src/lib/libshell/common/sh/arith.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.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	"lexstates.h"
294887Schin #include	"name.h"
304887Schin #include	"streval.h"
314887Schin #include	"variables.h"
324887Schin 
334887Schin #ifndef LLONG_MAX
344887Schin #define LLONG_MAX	LONG_MAX
354887Schin #endif
364887Schin 
378462SApril.Chin@Sun.COM static Sfdouble_t	NaN, Inf, Fun;
384887Schin static Namval_t Infnod =
394887Schin {
404887Schin 	{ 0 },
414887Schin 	"Inf",
424887Schin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
434887Schin };
444887Schin 
454887Schin static Namval_t NaNnod =
464887Schin {
474887Schin 	{ 0 },
484887Schin 	"NaN",
494887Schin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
504887Schin };
514887Schin 
528462SApril.Chin@Sun.COM static Namval_t FunNode =
538462SApril.Chin@Sun.COM {
548462SApril.Chin@Sun.COM 	{ 0 },
558462SApril.Chin@Sun.COM 	"?",
568462SApril.Chin@Sun.COM 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
578462SApril.Chin@Sun.COM };
588462SApril.Chin@Sun.COM 
scope(Shell_t * shp,register Namval_t * np,register struct lval * lvalue,int assign)598462SApril.Chin@Sun.COM static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval *lvalue,int assign)
604887Schin {
614887Schin 	register int flag = lvalue->flag;
628462SApril.Chin@Sun.COM 	register char *sub=0, *cp=(char*)np;
638462SApril.Chin@Sun.COM 	register Namval_t *mp;
648462SApril.Chin@Sun.COM 	int	flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET;
65*12068SRoger.Faulkner@Oracle.COM 	int	nosub = lvalue->nosub;
668462SApril.Chin@Sun.COM 	Dt_t	*sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0);
6710898Sroland.mainz@nrubsig.org 	Dt_t	*root = shp->var_tree;
688462SApril.Chin@Sun.COM 	assign = assign?NV_ASSIGN:NV_NOASSIGN;
69*12068SRoger.Faulkner@Oracle.COM 	lvalue->nosub = 0;
708462SApril.Chin@Sun.COM 	if(cp>=lvalue->expr &&  cp < lvalue->expr+lvalue->elen)
714887Schin 	{
728462SApril.Chin@Sun.COM 		int offset;
738462SApril.Chin@Sun.COM 		/* do binding to node now */
748462SApril.Chin@Sun.COM 		int c = cp[flag];
758462SApril.Chin@Sun.COM 		cp[flag] = 0;
768462SApril.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()))
774887Schin 		{
788462SApril.Chin@Sun.COM 			Fun = sh_arith(sub=stakptr(offset));
798462SApril.Chin@Sun.COM 			FunNode.nvalue.ldp = &Fun;
804887Schin 			cp[flag] = c;
818462SApril.Chin@Sun.COM 			return(&FunNode);
824887Schin 		}
8310898Sroland.mainz@nrubsig.org 		if(!np && assign)
8410898Sroland.mainz@nrubsig.org 			np = nv_open(cp,shp->var_tree,assign|NV_VARNAME);
8510898Sroland.mainz@nrubsig.org 		if(!np)
8610898Sroland.mainz@nrubsig.org 			return(0);
8710898Sroland.mainz@nrubsig.org 		root = shp->last_root;
888462SApril.Chin@Sun.COM 		cp[flag] = c;
898462SApril.Chin@Sun.COM 		if(cp[flag+1]=='[')
908462SApril.Chin@Sun.COM 			flag++;
918462SApril.Chin@Sun.COM 		else
928462SApril.Chin@Sun.COM 			flag = 0;
938462SApril.Chin@Sun.COM 		cp = (char*)np;
948462SApril.Chin@Sun.COM 	}
9510898Sroland.mainz@nrubsig.org 	if((lvalue->emode&ARITH_COMP) && dtvnext(root) && ((mp=nv_search(cp,root,flags))||(sdict && (mp=nv_search(cp,sdict,flags)))))
968462SApril.Chin@Sun.COM 	{
978462SApril.Chin@Sun.COM 		while(nv_isref(mp))
984887Schin 		{
998462SApril.Chin@Sun.COM 			sub = nv_refsub(mp);
1008462SApril.Chin@Sun.COM 			mp = nv_refnode(mp);
1014887Schin 		}
1028462SApril.Chin@Sun.COM 		np = mp;
1034887Schin 	}
104*12068SRoger.Faulkner@Oracle.COM 	if(!nosub && (flag || sub))
1054887Schin 	{
1064887Schin 		if(!sub)
1074887Schin 			sub = (char*)&lvalue->expr[flag];
10810898Sroland.mainz@nrubsig.org 		nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
1094887Schin 	}
1104887Schin 	return(np);
1114887Schin }
1124887Schin 
arith(const char ** ptr,struct lval * lvalue,int type,Sfdouble_t n)1134887Schin static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
1144887Schin {
1158462SApril.Chin@Sun.COM 	Shell_t		*shp = &sh;
1164887Schin 	register Sfdouble_t r= 0;
1174887Schin 	char *str = (char*)*ptr;
1188462SApril.Chin@Sun.COM 	register char *cp;
1194887Schin 	switch(type)
1204887Schin 	{
1214887Schin 	    case ASSIGN:
1224887Schin 	    {
1234887Schin 		register Namval_t *np = (Namval_t*)(lvalue->value);
1248462SApril.Chin@Sun.COM 		np = scope(shp,np,lvalue,1);
1254887Schin 		nv_putval(np, (char*)&n, NV_LDOUBLE);
1264887Schin 		r=nv_getnum(np);
127*12068SRoger.Faulkner@Oracle.COM 		lvalue->value = (char*)np;
1284887Schin 		break;
1294887Schin 	    }
1304887Schin 	    case LOOKUP:
1314887Schin 	    {
1324887Schin 		register int c = *str;
1334887Schin 		register char *xp=str;
1344887Schin 		lvalue->value = (char*)0;
1354887Schin 		if(c=='.')
1364887Schin 			str++;
1374887Schin 		c = mbchar(str);
1384887Schin 		if(isaletter(c))
1394887Schin 		{
1404887Schin 			register Namval_t *np;
1414887Schin 			int dot=0;
1424887Schin 			while(1)
1434887Schin 			{
1444887Schin 				while(xp=str, c=mbchar(str), isaname(c));
1454887Schin 				str = xp;
1468462SApril.Chin@Sun.COM 				if(c=='[' && dot==NV_NOADD)
1478462SApril.Chin@Sun.COM 				{
1488462SApril.Chin@Sun.COM 					str = nv_endsubscript((Namval_t*)0,str,0);
1498462SApril.Chin@Sun.COM 					c = *str;
1508462SApril.Chin@Sun.COM 				}
1514887Schin 				if(c!='.')
1524887Schin 					break;
1538462SApril.Chin@Sun.COM 				dot=NV_NOADD;
1544887Schin 				if((c = *++str) !='[')
1554887Schin 					continue;
1564887Schin 				str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
1574887Schin 				if(sh_checkid(cp+1,(char*)0))
1584887Schin 					str -=2;
1594887Schin 			}
1604887Schin 			if(c=='(')
1614887Schin 			{
1624887Schin 				int fsize = str- (char*)(*ptr);
1634887Schin 				const struct mathtab *tp;
1644887Schin 				c = **ptr;
1654887Schin 				lvalue->fun = 0;
1664887Schin 				if(fsize<=(sizeof(tp->fname)-2)) for(tp=shtab_math; *tp->fname; tp++)
1674887Schin 				{
1684887Schin 					if(*tp->fname > c)
1694887Schin 						break;
1704887Schin 					if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],*ptr,fsize)==0)
1714887Schin 					{
1724887Schin 						lvalue->fun = tp->fnptr;
1734887Schin 						lvalue->nargs = *tp->fname;
1744887Schin 						break;
1754887Schin 					}
1764887Schin 				}
1774887Schin 				if(lvalue->fun)
1784887Schin 					break;
1794887Schin 				lvalue->value = (char*)ERROR_dictionary(e_function);
1804887Schin 				return(r);
1814887Schin 			}
1824887Schin 			if((lvalue->emode&ARITH_COMP) && dot)
1834887Schin 			{
1844887Schin 				lvalue->value = (char*)*ptr;
1854887Schin 				lvalue->flag =  str-lvalue->value;
1864887Schin 				break;
1874887Schin 			}
1884887Schin 			*str = 0;
1894887Schin 			if(sh_isoption(SH_NOEXEC))
1904887Schin 				np = L_ARGNOD;
1914887Schin 			else
1924887Schin 			{
1934887Schin 				int offset = staktell();
1944887Schin 				char *saveptr = stakfreeze(0);
1958462SApril.Chin@Sun.COM 				Dt_t  *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree;
1964887Schin 				*str = c;
1974887Schin 				while(c=='[' || c=='.')
1984887Schin 				{
1994887Schin 					if(c=='[')
2004887Schin 					{
2014887Schin 						str = nv_endsubscript(np,cp=str,0);
2024887Schin 						if((c= *str)!='[' &&  c!='.')
2034887Schin 						{
2044887Schin 							str = cp;
2054887Schin 							c = '[';
2064887Schin 							break;
2074887Schin 						}
2084887Schin 					}
2094887Schin 					else
2104887Schin 					{
2118462SApril.Chin@Sun.COM 						dot = NV_NOADD|NV_NOFAIL;
2124887Schin 						str++;
2134887Schin 						while(xp=str, c=mbchar(str), isaname(c));
2144887Schin 						str = xp;
2154887Schin 					}
2164887Schin 				}
2174887Schin 				*str = 0;
2188462SApril.Chin@Sun.COM 				cp = (char*)*ptr;
2198462SApril.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)
2204887Schin 				{
2218462SApril.Chin@Sun.COM 					Inf = strtold("Inf", NiL);
2224887Schin 					Infnod.nvalue.ldp = &Inf;
2234887Schin 					np = &Infnod;
2244887Schin 				}
2258462SApril.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)
2264887Schin 				{
2278462SApril.Chin@Sun.COM 					NaN = strtold("NaN", NiL);
2284887Schin 					NaNnod.nvalue.ldp = &NaN;
2294887Schin 					np = &NaNnod;
2304887Schin 				}
2318462SApril.Chin@Sun.COM 				else if(!(np = nv_open(*ptr,root,NV_NOASSIGN|NV_VARNAME|dot)))
2328462SApril.Chin@Sun.COM 				{
2338462SApril.Chin@Sun.COM 					lvalue->value = (char*)*ptr;
2348462SApril.Chin@Sun.COM 					lvalue->flag =  str-lvalue->value;
2358462SApril.Chin@Sun.COM 				}
2364887Schin 				if(saveptr != stakptr(0))
2374887Schin 					stakset(saveptr,offset);
2384887Schin 				else
2394887Schin 					stakseek(offset);
2404887Schin 			}
2414887Schin 			*str = c;
2428462SApril.Chin@Sun.COM 			if(!np && lvalue->value)
2438462SApril.Chin@Sun.COM 				break;
2444887Schin 			lvalue->value = (char*)np;
24510898Sroland.mainz@nrubsig.org 			/* bind subscript later */
24610898Sroland.mainz@nrubsig.org 			if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
24710898Sroland.mainz@nrubsig.org 				lvalue->isfloat=1;
24810898Sroland.mainz@nrubsig.org 			lvalue->flag = 0;
24910898Sroland.mainz@nrubsig.org 			if(c=='[')
2504887Schin 			{
25110898Sroland.mainz@nrubsig.org 				lvalue->flag = (str-lvalue->expr);
25210898Sroland.mainz@nrubsig.org 				do
25310898Sroland.mainz@nrubsig.org 					str = nv_endsubscript(np,str,0);
25410898Sroland.mainz@nrubsig.org 				while((c= *str)=='[');
2554887Schin 				break;
2564887Schin 			}
2574887Schin 		}
2584887Schin 		else
2594887Schin 		{
2604887Schin 			char	lastbase=0, *val = xp, oerrno = errno;
2614887Schin 			errno = 0;
2624887Schin 			r = strtonll(val,&str, &lastbase,-1);
2634887Schin 			if(*str=='8' || *str=='9')
2644887Schin 			{
2654887Schin 				lastbase=10;
2664887Schin 				errno = 0;
2674887Schin 				r = strtonll(val,&str, &lastbase,-1);
2684887Schin 			}
2694887Schin 			if(lastbase<=1)
2704887Schin 				lastbase=10;
2714887Schin 			if(*val=='0')
2724887Schin 			{
2734887Schin 				while(*val=='0')
2744887Schin 					val++;
2754887Schin 				if(*val==0 || *val=='.' || *val=='x' || *val=='X')
2764887Schin 					val--;
2774887Schin 			}
2784887Schin 			if(r==LLONG_MAX && errno)
2794887Schin 				c='e';
2804887Schin 			else
2814887Schin 				c = *str;
2828462SApril.Chin@Sun.COM 			if(c==GETDECIMAL(0) || c=='e' || c == 'E' || lastbase ==
2838462SApril.Chin@Sun.COM  16 && (c == 'p' || c == 'P'))
2844887Schin 			{
2854887Schin 				lvalue->isfloat=1;
2864887Schin 				r = strtold(val,&str);
2874887Schin 			}
2884887Schin 			else if(lastbase==10 && val[1])
2894887Schin 			{
2904887Schin 				if(val[2]=='#')
2914887Schin 					val += 3;
2924887Schin 				if((str-val)>2*sizeof(Sflong_t))
2934887Schin 				{
2944887Schin 					Sfdouble_t rr;
2954887Schin 					rr = strtold(val,&str);
2964887Schin 					if(rr!=r)
2974887Schin 					{
2984887Schin 						r = rr;
2994887Schin 						lvalue->isfloat=1;
3004887Schin 					}
3014887Schin 				}
3024887Schin 			}
3034887Schin 			errno = oerrno;
3044887Schin 		}
3054887Schin 		break;
3064887Schin 	    }
3074887Schin 	    case VALUE:
3084887Schin 	    {
3094887Schin 		register Namval_t *np = (Namval_t*)(lvalue->value);
3104887Schin 		if(sh_isoption(SH_NOEXEC))
3114887Schin 			return(0);
3128462SApril.Chin@Sun.COM 		np = scope(shp,np,lvalue,0);
31310898Sroland.mainz@nrubsig.org 		if(!np)
31410898Sroland.mainz@nrubsig.org 		{
31510898Sroland.mainz@nrubsig.org 			if(sh_isoption(SH_NOUNSET))
31610898Sroland.mainz@nrubsig.org 			{
31710898Sroland.mainz@nrubsig.org 				*ptr = lvalue->value;
31810898Sroland.mainz@nrubsig.org 				goto skip;
31910898Sroland.mainz@nrubsig.org 			}
32010898Sroland.mainz@nrubsig.org 			return(0);
32110898Sroland.mainz@nrubsig.org 		}
3224887Schin 		if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
3234887Schin 		{
3244887Schin 			*ptr = nv_name(np);
32510898Sroland.mainz@nrubsig.org 		skip:
3264887Schin 			lvalue->value = (char*)ERROR_dictionary(e_notset);
3274887Schin 			lvalue->emode |= 010;
3284887Schin 			return(0);
3294887Schin 		}
3304887Schin 		r = nv_getnum(np);
3314887Schin 		if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
3324887Schin 			lvalue->isfloat= (r!=(Sflong_t)r);
3338462SApril.Chin@Sun.COM 		else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
3344887Schin 			lvalue->isfloat=1;
3354887Schin 		return(r);
3364887Schin 	    }
3374887Schin 
3384887Schin 	    case MESSAGE:
3394887Schin 		sfsync(NIL(Sfio_t*));
3404887Schin #if 0
3414887Schin 		if(warn)
3424887Schin 			errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
3434887Schin 		else
3444887Schin #endif
3454887Schin 			errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
3464887Schin 	}
3474887Schin 	*ptr = str;
3484887Schin 	return(r);
3494887Schin }
3504887Schin 
3514887Schin /*
3524887Schin  * convert number defined by string to a Sfdouble_t
3534887Schin  * ptr is set to the last character processed
3544887Schin  * if mode>0, an error will be fatal with value <mode>
3554887Schin  */
3564887Schin 
sh_strnum(register const char * str,char ** ptr,int mode)3574887Schin Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
3584887Schin {
3594887Schin 	register Sfdouble_t d;
3604887Schin 	char base=0, *last;
3614887Schin 	if(*str==0)
3624887Schin 	{
3634887Schin 		if(ptr)
3644887Schin 			*ptr = (char*)str;
3654887Schin 		return(0);
3664887Schin 	}
3674887Schin 	errno = 0;
3684887Schin 	d = strtonll(str,&last,&base,-1);
3694887Schin 	if(*last || errno)
3704887Schin 	{
3718462SApril.Chin@Sun.COM 		if(!last || *last!='.' || last[1]!='.')
3728462SApril.Chin@Sun.COM 			d = strval(str,&last,arith,mode);
3734887Schin 		if(!ptr && *last && mode>0)
3744887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
3754887Schin 	}
3768462SApril.Chin@Sun.COM 	else if (!d && *str=='-')
3778462SApril.Chin@Sun.COM 		d = -0.0;
3784887Schin 	if(ptr)
3794887Schin 		*ptr = last;
3804887Schin 	return(d);
3814887Schin }
3824887Schin 
sh_arith(register const char * str)3834887Schin Sfdouble_t sh_arith(register const char *str)
3844887Schin {
3854887Schin 	return(sh_strnum(str, (char**)0, 1));
3864887Schin }
3874887Schin 
sh_arithcomp(register char * str)3884887Schin void	*sh_arithcomp(register char *str)
3894887Schin {
3904887Schin 	const char *ptr = str;
3914887Schin 	Arith_t *ep;
3924887Schin 	ep = arith_compile(str,(char**)&ptr,arith,ARITH_COMP|1);
3934887Schin 	if(*ptr)
3944887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
3954887Schin 	return((void*)ep);
3964887Schin }
397