xref: /titanic_51/usr/src/lib/libshell/common/sh/arith.c (revision 3e14f97f673e8a630f076077de35afdd43dc1587)
1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin *                                                                      *
3da2e3ebdSchin *               This software is part of the ast package               *
4*3e14f97fSRoger A. Faulkner *          Copyright (c) 1982-2010 AT&T Intellectual Property          *
5da2e3ebdSchin *                      and is licensed under the                       *
6da2e3ebdSchin *                  Common Public License, Version 1.0                  *
77c2fbfb3SApril Chin *                    by AT&T Intellectual Property                     *
8da2e3ebdSchin *                                                                      *
9da2e3ebdSchin *                A copy of the License is available at                 *
10da2e3ebdSchin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11da2e3ebdSchin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
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  * Shell arithmetic - uses streval library
23da2e3ebdSchin  *   David Korn
24da2e3ebdSchin  *   AT&T Labs
25da2e3ebdSchin  */
26da2e3ebdSchin 
27da2e3ebdSchin #include	"defs.h"
28da2e3ebdSchin #include	"lexstates.h"
29da2e3ebdSchin #include	"name.h"
30da2e3ebdSchin #include	"streval.h"
31da2e3ebdSchin #include	"variables.h"
32da2e3ebdSchin 
33da2e3ebdSchin #ifndef LLONG_MAX
34da2e3ebdSchin #define LLONG_MAX	LONG_MAX
35da2e3ebdSchin #endif
36da2e3ebdSchin 
377c2fbfb3SApril Chin static Sfdouble_t	NaN, Inf, Fun;
38da2e3ebdSchin static Namval_t Infnod =
39da2e3ebdSchin {
40da2e3ebdSchin 	{ 0 },
41da2e3ebdSchin 	"Inf",
42da2e3ebdSchin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
43da2e3ebdSchin };
44da2e3ebdSchin 
45da2e3ebdSchin static Namval_t NaNnod =
46da2e3ebdSchin {
47da2e3ebdSchin 	{ 0 },
48da2e3ebdSchin 	"NaN",
49da2e3ebdSchin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
50da2e3ebdSchin };
51da2e3ebdSchin 
527c2fbfb3SApril Chin static Namval_t FunNode =
537c2fbfb3SApril Chin {
547c2fbfb3SApril Chin 	{ 0 },
557c2fbfb3SApril Chin 	"?",
567c2fbfb3SApril Chin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
577c2fbfb3SApril Chin };
587c2fbfb3SApril Chin 
scope(Shell_t * shp,register Namval_t * np,register struct lval * lvalue,int assign)597c2fbfb3SApril Chin static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval *lvalue,int assign)
60da2e3ebdSchin {
61da2e3ebdSchin 	register int flag = lvalue->flag;
627c2fbfb3SApril Chin 	register char *sub=0, *cp=(char*)np;
63da2e3ebdSchin 	register Namval_t *mp;
647c2fbfb3SApril Chin 	int	flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET;
65*3e14f97fSRoger A. Faulkner 	int	nosub = lvalue->nosub;
667c2fbfb3SApril Chin 	Dt_t	*sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0);
6734f9b3eeSRoland Mainz 	Dt_t	*root = shp->var_tree;
687c2fbfb3SApril Chin 	assign = assign?NV_ASSIGN:NV_NOASSIGN;
69*3e14f97fSRoger A. Faulkner 	lvalue->nosub = 0;
70da2e3ebdSchin 	if(cp>=lvalue->expr &&  cp < lvalue->expr+lvalue->elen)
71da2e3ebdSchin 	{
727c2fbfb3SApril Chin 		int offset;
737c2fbfb3SApril Chin 		/* do binding to node now */
74da2e3ebdSchin 		int c = cp[flag];
75da2e3ebdSchin 		cp[flag] = 0;
767c2fbfb3SApril Chin 		if((!(np = nv_open(cp,shp->var_tree,assign|NV_VARNAME|NV_NOADD|NV_NOFAIL)) || nv_isnull(np)) && sh_macfun(shp,cp, offset = staktell()))
777c2fbfb3SApril Chin 		{
787c2fbfb3SApril Chin 			Fun = sh_arith(sub=stakptr(offset));
797c2fbfb3SApril Chin 			FunNode.nvalue.ldp = &Fun;
807c2fbfb3SApril Chin 			cp[flag] = c;
817c2fbfb3SApril Chin 			return(&FunNode);
827c2fbfb3SApril Chin 		}
8334f9b3eeSRoland Mainz 		if(!np && assign)
847c2fbfb3SApril Chin 			np = nv_open(cp,shp->var_tree,assign|NV_VARNAME);
8534f9b3eeSRoland Mainz 		if(!np)
8634f9b3eeSRoland Mainz 			return(0);
8734f9b3eeSRoland Mainz 		root = shp->last_root;
88da2e3ebdSchin 		cp[flag] = c;
89da2e3ebdSchin 		if(cp[flag+1]=='[')
90da2e3ebdSchin 			flag++;
91da2e3ebdSchin 		else
92da2e3ebdSchin 			flag = 0;
937c2fbfb3SApril Chin 		cp = (char*)np;
94da2e3ebdSchin 	}
9534f9b3eeSRoland Mainz 	if((lvalue->emode&ARITH_COMP) && dtvnext(root) && ((mp=nv_search(cp,root,flags))||(sdict && (mp=nv_search(cp,sdict,flags)))))
96da2e3ebdSchin 	{
97da2e3ebdSchin 		while(nv_isref(mp))
98da2e3ebdSchin 		{
99da2e3ebdSchin 			sub = nv_refsub(mp);
100da2e3ebdSchin 			mp = nv_refnode(mp);
101da2e3ebdSchin 		}
102da2e3ebdSchin 		np = mp;
103da2e3ebdSchin 	}
104*3e14f97fSRoger A. Faulkner 	if(!nosub && (flag || sub))
105da2e3ebdSchin 	{
106da2e3ebdSchin 		if(!sub)
107da2e3ebdSchin 			sub = (char*)&lvalue->expr[flag];
108da2e3ebdSchin 		nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
109da2e3ebdSchin 	}
110da2e3ebdSchin 	return(np);
111da2e3ebdSchin }
112da2e3ebdSchin 
arith(const char ** ptr,struct lval * lvalue,int type,Sfdouble_t n)113da2e3ebdSchin static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
114da2e3ebdSchin {
1157c2fbfb3SApril Chin 	Shell_t		*shp = &sh;
116da2e3ebdSchin 	register Sfdouble_t r= 0;
117da2e3ebdSchin 	char *str = (char*)*ptr;
1187c2fbfb3SApril Chin 	register char *cp;
119da2e3ebdSchin 	switch(type)
120da2e3ebdSchin 	{
121da2e3ebdSchin 	    case ASSIGN:
122da2e3ebdSchin 	    {
123da2e3ebdSchin 		register Namval_t *np = (Namval_t*)(lvalue->value);
1247c2fbfb3SApril Chin 		np = scope(shp,np,lvalue,1);
125da2e3ebdSchin 		nv_putval(np, (char*)&n, NV_LDOUBLE);
126da2e3ebdSchin 		r=nv_getnum(np);
127*3e14f97fSRoger A. Faulkner 		lvalue->value = (char*)np;
128da2e3ebdSchin 		break;
129da2e3ebdSchin 	    }
130da2e3ebdSchin 	    case LOOKUP:
131da2e3ebdSchin 	    {
132da2e3ebdSchin 		register int c = *str;
133da2e3ebdSchin 		register char *xp=str;
134da2e3ebdSchin 		lvalue->value = (char*)0;
135da2e3ebdSchin 		if(c=='.')
136da2e3ebdSchin 			str++;
137da2e3ebdSchin 		c = mbchar(str);
138da2e3ebdSchin 		if(isaletter(c))
139da2e3ebdSchin 		{
140da2e3ebdSchin 			register Namval_t *np;
141da2e3ebdSchin 			int dot=0;
142da2e3ebdSchin 			while(1)
143da2e3ebdSchin 			{
144da2e3ebdSchin 				while(xp=str, c=mbchar(str), isaname(c));
145da2e3ebdSchin 				str = xp;
1467c2fbfb3SApril Chin 				if(c=='[' && dot==NV_NOADD)
1477c2fbfb3SApril Chin 				{
1487c2fbfb3SApril Chin 					str = nv_endsubscript((Namval_t*)0,str,0);
1497c2fbfb3SApril Chin 					c = *str;
1507c2fbfb3SApril Chin 				}
151da2e3ebdSchin 				if(c!='.')
152da2e3ebdSchin 					break;
1537c2fbfb3SApril Chin 				dot=NV_NOADD;
154da2e3ebdSchin 				if((c = *++str) !='[')
155da2e3ebdSchin 					continue;
156da2e3ebdSchin 				str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
157da2e3ebdSchin 				if(sh_checkid(cp+1,(char*)0))
158da2e3ebdSchin 					str -=2;
159da2e3ebdSchin 			}
160da2e3ebdSchin 			if(c=='(')
161da2e3ebdSchin 			{
162da2e3ebdSchin 				int fsize = str- (char*)(*ptr);
163da2e3ebdSchin 				const struct mathtab *tp;
164da2e3ebdSchin 				c = **ptr;
165da2e3ebdSchin 				lvalue->fun = 0;
166da2e3ebdSchin 				if(fsize<=(sizeof(tp->fname)-2)) for(tp=shtab_math; *tp->fname; tp++)
167da2e3ebdSchin 				{
168da2e3ebdSchin 					if(*tp->fname > c)
169da2e3ebdSchin 						break;
170da2e3ebdSchin 					if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],*ptr,fsize)==0)
171da2e3ebdSchin 					{
172da2e3ebdSchin 						lvalue->fun = tp->fnptr;
173da2e3ebdSchin 						lvalue->nargs = *tp->fname;
174da2e3ebdSchin 						break;
175da2e3ebdSchin 					}
176da2e3ebdSchin 				}
177da2e3ebdSchin 				if(lvalue->fun)
178da2e3ebdSchin 					break;
179da2e3ebdSchin 				lvalue->value = (char*)ERROR_dictionary(e_function);
180da2e3ebdSchin 				return(r);
181da2e3ebdSchin 			}
182da2e3ebdSchin 			if((lvalue->emode&ARITH_COMP) && dot)
183da2e3ebdSchin 			{
184da2e3ebdSchin 				lvalue->value = (char*)*ptr;
185da2e3ebdSchin 				lvalue->flag =  str-lvalue->value;
186da2e3ebdSchin 				break;
187da2e3ebdSchin 			}
188da2e3ebdSchin 			*str = 0;
189da2e3ebdSchin 			if(sh_isoption(SH_NOEXEC))
190da2e3ebdSchin 				np = L_ARGNOD;
191da2e3ebdSchin 			else
192da2e3ebdSchin 			{
193da2e3ebdSchin 				int offset = staktell();
194da2e3ebdSchin 				char *saveptr = stakfreeze(0);
1957c2fbfb3SApril Chin 				Dt_t  *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree;
196da2e3ebdSchin 				*str = c;
197da2e3ebdSchin 				while(c=='[' || c=='.')
198da2e3ebdSchin 				{
199da2e3ebdSchin 					if(c=='[')
200da2e3ebdSchin 					{
201da2e3ebdSchin 						str = nv_endsubscript(np,cp=str,0);
202da2e3ebdSchin 						if((c= *str)!='[' &&  c!='.')
203da2e3ebdSchin 						{
204da2e3ebdSchin 							str = cp;
205da2e3ebdSchin 							c = '[';
206da2e3ebdSchin 							break;
207da2e3ebdSchin 						}
208da2e3ebdSchin 					}
209da2e3ebdSchin 					else
210da2e3ebdSchin 					{
2117c2fbfb3SApril Chin 						dot = NV_NOADD|NV_NOFAIL;
212da2e3ebdSchin 						str++;
213da2e3ebdSchin 						while(xp=str, c=mbchar(str), isaname(c));
214da2e3ebdSchin 						str = xp;
215da2e3ebdSchin 					}
216da2e3ebdSchin 				}
217da2e3ebdSchin 				*str = 0;
2187c2fbfb3SApril Chin 				cp = (char*)*ptr;
2197c2fbfb3SApril Chin 				if ((cp[0] == 'i' || cp[0] == 'I') && (cp[1] == 'n' || cp[1] == 'N') && (cp[2] == 'f' || cp[2] == 'F') && cp[3] == 0)
220da2e3ebdSchin 				{
2217c2fbfb3SApril Chin 					Inf = strtold("Inf", NiL);
222da2e3ebdSchin 					Infnod.nvalue.ldp = &Inf;
223da2e3ebdSchin 					np = &Infnod;
224da2e3ebdSchin 				}
2257c2fbfb3SApril Chin 				else if ((cp[0] == 'n' || cp[0] == 'N') && (cp[1] == 'a' || cp[1] == 'A') && (cp[2] == 'n' || cp[2] == 'N') && cp[3] == 0)
226da2e3ebdSchin 				{
2277c2fbfb3SApril Chin 					NaN = strtold("NaN", NiL);
228da2e3ebdSchin 					NaNnod.nvalue.ldp = &NaN;
229da2e3ebdSchin 					np = &NaNnod;
230da2e3ebdSchin 				}
2317c2fbfb3SApril Chin 				else if(!(np = nv_open(*ptr,root,NV_NOASSIGN|NV_VARNAME|dot)))
2327c2fbfb3SApril Chin 				{
2337c2fbfb3SApril Chin 					lvalue->value = (char*)*ptr;
2347c2fbfb3SApril Chin 					lvalue->flag =  str-lvalue->value;
2357c2fbfb3SApril Chin 				}
236da2e3ebdSchin 				if(saveptr != stakptr(0))
237da2e3ebdSchin 					stakset(saveptr,offset);
238da2e3ebdSchin 				else
239da2e3ebdSchin 					stakseek(offset);
240da2e3ebdSchin 			}
241da2e3ebdSchin 			*str = c;
2427c2fbfb3SApril Chin 			if(!np && lvalue->value)
2437c2fbfb3SApril Chin 				break;
244da2e3ebdSchin 			lvalue->value = (char*)np;
245da2e3ebdSchin 			/* bind subscript later */
24634f9b3eeSRoland Mainz 			if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
24734f9b3eeSRoland Mainz 				lvalue->isfloat=1;
248da2e3ebdSchin 			lvalue->flag = 0;
249da2e3ebdSchin 			if(c=='[')
250da2e3ebdSchin 			{
251da2e3ebdSchin 				lvalue->flag = (str-lvalue->expr);
252da2e3ebdSchin 				do
253da2e3ebdSchin 					str = nv_endsubscript(np,str,0);
254da2e3ebdSchin 				while((c= *str)=='[');
255da2e3ebdSchin 				break;
256da2e3ebdSchin 			}
257da2e3ebdSchin 		}
258da2e3ebdSchin 		else
259da2e3ebdSchin 		{
260da2e3ebdSchin 			char	lastbase=0, *val = xp, oerrno = errno;
261da2e3ebdSchin 			errno = 0;
262da2e3ebdSchin 			r = strtonll(val,&str, &lastbase,-1);
263da2e3ebdSchin 			if(*str=='8' || *str=='9')
264da2e3ebdSchin 			{
265da2e3ebdSchin 				lastbase=10;
266da2e3ebdSchin 				errno = 0;
267da2e3ebdSchin 				r = strtonll(val,&str, &lastbase,-1);
268da2e3ebdSchin 			}
269da2e3ebdSchin 			if(lastbase<=1)
270da2e3ebdSchin 				lastbase=10;
271da2e3ebdSchin 			if(*val=='0')
272da2e3ebdSchin 			{
273da2e3ebdSchin 				while(*val=='0')
274da2e3ebdSchin 					val++;
275da2e3ebdSchin 				if(*val==0 || *val=='.' || *val=='x' || *val=='X')
276da2e3ebdSchin 					val--;
277da2e3ebdSchin 			}
278da2e3ebdSchin 			if(r==LLONG_MAX && errno)
279da2e3ebdSchin 				c='e';
280da2e3ebdSchin 			else
281da2e3ebdSchin 				c = *str;
2827c2fbfb3SApril Chin 			if(c==GETDECIMAL(0) || c=='e' || c == 'E' || lastbase ==
2837c2fbfb3SApril Chin  16 && (c == 'p' || c == 'P'))
284da2e3ebdSchin 			{
285da2e3ebdSchin 				lvalue->isfloat=1;
286da2e3ebdSchin 				r = strtold(val,&str);
287da2e3ebdSchin 			}
288da2e3ebdSchin 			else if(lastbase==10 && val[1])
289da2e3ebdSchin 			{
290da2e3ebdSchin 				if(val[2]=='#')
291da2e3ebdSchin 					val += 3;
292da2e3ebdSchin 				if((str-val)>2*sizeof(Sflong_t))
293da2e3ebdSchin 				{
294da2e3ebdSchin 					Sfdouble_t rr;
295da2e3ebdSchin 					rr = strtold(val,&str);
296da2e3ebdSchin 					if(rr!=r)
297da2e3ebdSchin 					{
298da2e3ebdSchin 						r = rr;
299da2e3ebdSchin 						lvalue->isfloat=1;
300da2e3ebdSchin 					}
301da2e3ebdSchin 				}
302da2e3ebdSchin 			}
303da2e3ebdSchin 			errno = oerrno;
304da2e3ebdSchin 		}
305da2e3ebdSchin 		break;
306da2e3ebdSchin 	    }
307da2e3ebdSchin 	    case VALUE:
308da2e3ebdSchin 	    {
309da2e3ebdSchin 		register Namval_t *np = (Namval_t*)(lvalue->value);
310da2e3ebdSchin 		if(sh_isoption(SH_NOEXEC))
311da2e3ebdSchin 			return(0);
3127c2fbfb3SApril Chin 		np = scope(shp,np,lvalue,0);
31334f9b3eeSRoland Mainz 		if(!np)
31434f9b3eeSRoland Mainz 		{
31534f9b3eeSRoland Mainz 			if(sh_isoption(SH_NOUNSET))
31634f9b3eeSRoland Mainz 			{
31734f9b3eeSRoland Mainz 				*ptr = lvalue->value;
31834f9b3eeSRoland Mainz 				goto skip;
31934f9b3eeSRoland Mainz 			}
32034f9b3eeSRoland Mainz 			return(0);
32134f9b3eeSRoland Mainz 		}
322da2e3ebdSchin 		if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
323da2e3ebdSchin 		{
324da2e3ebdSchin 			*ptr = nv_name(np);
32534f9b3eeSRoland Mainz 		skip:
326da2e3ebdSchin 			lvalue->value = (char*)ERROR_dictionary(e_notset);
327da2e3ebdSchin 			lvalue->emode |= 010;
328da2e3ebdSchin 			return(0);
329da2e3ebdSchin 		}
330da2e3ebdSchin 		r = nv_getnum(np);
331da2e3ebdSchin 		if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
332da2e3ebdSchin 			lvalue->isfloat= (r!=(Sflong_t)r);
3337c2fbfb3SApril Chin 		else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
334da2e3ebdSchin 			lvalue->isfloat=1;
335da2e3ebdSchin 		return(r);
336da2e3ebdSchin 	    }
337da2e3ebdSchin 
338da2e3ebdSchin 	    case MESSAGE:
339da2e3ebdSchin 		sfsync(NIL(Sfio_t*));
340da2e3ebdSchin #if 0
341da2e3ebdSchin 		if(warn)
342da2e3ebdSchin 			errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
343da2e3ebdSchin 		else
344da2e3ebdSchin #endif
345da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
346da2e3ebdSchin 	}
347da2e3ebdSchin 	*ptr = str;
348da2e3ebdSchin 	return(r);
349da2e3ebdSchin }
350da2e3ebdSchin 
351da2e3ebdSchin /*
352da2e3ebdSchin  * convert number defined by string to a Sfdouble_t
353da2e3ebdSchin  * ptr is set to the last character processed
354da2e3ebdSchin  * if mode>0, an error will be fatal with value <mode>
355da2e3ebdSchin  */
356da2e3ebdSchin 
sh_strnum(register const char * str,char ** ptr,int mode)357da2e3ebdSchin Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
358da2e3ebdSchin {
359da2e3ebdSchin 	register Sfdouble_t d;
360da2e3ebdSchin 	char base=0, *last;
361da2e3ebdSchin 	if(*str==0)
362da2e3ebdSchin 	{
363da2e3ebdSchin 		if(ptr)
364da2e3ebdSchin 			*ptr = (char*)str;
365da2e3ebdSchin 		return(0);
366da2e3ebdSchin 	}
367da2e3ebdSchin 	errno = 0;
368da2e3ebdSchin 	d = strtonll(str,&last,&base,-1);
369da2e3ebdSchin 	if(*last || errno)
370da2e3ebdSchin 	{
3717c2fbfb3SApril Chin 		if(!last || *last!='.' || last[1]!='.')
372da2e3ebdSchin 			d = strval(str,&last,arith,mode);
373da2e3ebdSchin 		if(!ptr && *last && mode>0)
374da2e3ebdSchin 			errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
375da2e3ebdSchin 	}
3767c2fbfb3SApril Chin 	else if (!d && *str=='-')
3777c2fbfb3SApril Chin 		d = -0.0;
378da2e3ebdSchin 	if(ptr)
379da2e3ebdSchin 		*ptr = last;
380da2e3ebdSchin 	return(d);
381da2e3ebdSchin }
382da2e3ebdSchin 
sh_arith(register const char * str)383da2e3ebdSchin Sfdouble_t sh_arith(register const char *str)
384da2e3ebdSchin {
385da2e3ebdSchin 	return(sh_strnum(str, (char**)0, 1));
386da2e3ebdSchin }
387da2e3ebdSchin 
sh_arithcomp(register char * str)388da2e3ebdSchin void	*sh_arithcomp(register char *str)
389da2e3ebdSchin {
390da2e3ebdSchin 	const char *ptr = str;
391da2e3ebdSchin 	Arith_t *ep;
392da2e3ebdSchin 	ep = arith_compile(str,(char**)&ptr,arith,ARITH_COMP|1);
393da2e3ebdSchin 	if(*ptr)
394da2e3ebdSchin 		errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
395da2e3ebdSchin 	return((void*)ep);
396da2e3ebdSchin }
397