1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * Shell arithmetic - uses streval library
23*4887Schin  *   David Korn
24*4887Schin  *   AT&T Labs
25*4887Schin  */
26*4887Schin 
27*4887Schin #include	"defs.h"
28*4887Schin #include	<ctype.h>
29*4887Schin #include	"lexstates.h"
30*4887Schin #include	"name.h"
31*4887Schin #include	"streval.h"
32*4887Schin #include	"variables.h"
33*4887Schin 
34*4887Schin #ifndef LLONG_MAX
35*4887Schin #define LLONG_MAX	LONG_MAX
36*4887Schin #endif
37*4887Schin 
38*4887Schin static Sfdouble_t	Zero, NaN, Inf;
39*4887Schin static Namval_t Infnod =
40*4887Schin {
41*4887Schin 	{ 0 },
42*4887Schin 	"Inf",
43*4887Schin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
44*4887Schin };
45*4887Schin 
46*4887Schin static Namval_t NaNnod =
47*4887Schin {
48*4887Schin 	{ 0 },
49*4887Schin 	"NaN",
50*4887Schin 	NV_NOFREE|NV_LDOUBLE,NV_RDONLY
51*4887Schin };
52*4887Schin 
53*4887Schin static Namval_t *scope(register Namval_t *np,register struct lval *lvalue,int assign)
54*4887Schin {
55*4887Schin 	register Namarr_t *ap;
56*4887Schin 	register int flag = lvalue->flag;
57*4887Schin 	register char *sub=0;
58*4887Schin 	if(lvalue->emode&ARITH_COMP)
59*4887Schin 	{
60*4887Schin 		char *cp = (char*)np;
61*4887Schin 		register Namval_t *mp;
62*4887Schin 		if(cp>=lvalue->expr &&  cp < lvalue->expr+lvalue->elen)
63*4887Schin 		{
64*4887Schin 			/* do bindiing to node now */
65*4887Schin 			int c = cp[flag];
66*4887Schin 			cp[flag] = 0;
67*4887Schin 			np = nv_open(cp,sh.var_tree,NV_NOASSIGN|NV_VARNAME);
68*4887Schin 			cp[flag] = c;
69*4887Schin 			if(cp[flag+1]=='[')
70*4887Schin 				flag++;
71*4887Schin 			else
72*4887Schin 				flag = 0;
73*4887Schin 		}
74*4887Schin 		else if(dtvnext(sh.var_tree) && (mp=nv_search((char*)np,sh.var_tree,HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET)))
75*4887Schin 		{
76*4887Schin 			while(nv_isref(mp))
77*4887Schin 			{
78*4887Schin 				sub = nv_refsub(mp);
79*4887Schin 				mp = nv_refnode(mp);
80*4887Schin 			}
81*4887Schin 			np = mp;
82*4887Schin 		}
83*4887Schin 	}
84*4887Schin 	if(flag || sub)
85*4887Schin 	{
86*4887Schin 		if(!sub)
87*4887Schin 			sub = (char*)&lvalue->expr[flag];
88*4887Schin 		if(((ap=nv_arrayptr(np)) && array_assoc(ap)) || (lvalue->emode&ARITH_COMP))
89*4887Schin 			nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
90*4887Schin 		else
91*4887Schin 			nv_putsub(np, NIL(char*),flag);
92*4887Schin 	}
93*4887Schin 	return(np);
94*4887Schin }
95*4887Schin 
96*4887Schin static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
97*4887Schin {
98*4887Schin 	register Sfdouble_t r= 0;
99*4887Schin 	char *str = (char*)*ptr;
100*4887Schin 	switch(type)
101*4887Schin 	{
102*4887Schin 	    case ASSIGN:
103*4887Schin 	    {
104*4887Schin 		register Namval_t *np = (Namval_t*)(lvalue->value);
105*4887Schin 		np = scope(np,lvalue,1);
106*4887Schin 		nv_putval(np, (char*)&n, NV_LDOUBLE);
107*4887Schin 		r=nv_getnum(np);
108*4887Schin 		break;
109*4887Schin 	    }
110*4887Schin 	    case LOOKUP:
111*4887Schin 	    {
112*4887Schin 		register int c = *str;
113*4887Schin 		register char *xp=str;
114*4887Schin 		lvalue->value = (char*)0;
115*4887Schin 		if(c=='.')
116*4887Schin 			str++;
117*4887Schin 		c = mbchar(str);
118*4887Schin 		if(isaletter(c))
119*4887Schin 		{
120*4887Schin 			register Namval_t *np;
121*4887Schin 			int dot=0;
122*4887Schin 			char *cp;
123*4887Schin 			while(1)
124*4887Schin 			{
125*4887Schin 				while(xp=str, c=mbchar(str), isaname(c));
126*4887Schin 				str = xp;
127*4887Schin 				if(c!='.')
128*4887Schin 					break;
129*4887Schin 				dot=1;
130*4887Schin 				if((c = *++str) !='[')
131*4887Schin 					continue;
132*4887Schin 				str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
133*4887Schin 				if(sh_checkid(cp+1,(char*)0))
134*4887Schin 					str -=2;
135*4887Schin 			}
136*4887Schin 			if(c=='(')
137*4887Schin 			{
138*4887Schin 				int fsize = str- (char*)(*ptr);
139*4887Schin 				const struct mathtab *tp;
140*4887Schin 				c = **ptr;
141*4887Schin 				lvalue->fun = 0;
142*4887Schin 				if(fsize<=(sizeof(tp->fname)-2)) for(tp=shtab_math; *tp->fname; tp++)
143*4887Schin 				{
144*4887Schin 					if(*tp->fname > c)
145*4887Schin 						break;
146*4887Schin 					if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],*ptr,fsize)==0)
147*4887Schin 					{
148*4887Schin 						lvalue->fun = tp->fnptr;
149*4887Schin 						lvalue->nargs = *tp->fname;
150*4887Schin 						break;
151*4887Schin 					}
152*4887Schin 				}
153*4887Schin 				if(lvalue->fun)
154*4887Schin 					break;
155*4887Schin 				lvalue->value = (char*)ERROR_dictionary(e_function);
156*4887Schin 				return(r);
157*4887Schin 			}
158*4887Schin 			if((lvalue->emode&ARITH_COMP) && dot)
159*4887Schin 			{
160*4887Schin 				lvalue->value = (char*)*ptr;
161*4887Schin 				lvalue->flag =  str-lvalue->value;
162*4887Schin 				break;
163*4887Schin 			}
164*4887Schin 			*str = 0;
165*4887Schin 			if(sh_isoption(SH_NOEXEC))
166*4887Schin 				np = L_ARGNOD;
167*4887Schin 			else
168*4887Schin 			{
169*4887Schin 				int offset = staktell();
170*4887Schin 				char *saveptr = stakfreeze(0);
171*4887Schin 				Dt_t  *root = (lvalue->emode&ARITH_COMP)?sh.var_base:sh.var_tree;
172*4887Schin 				*str = c;
173*4887Schin 				while(c=='[' || c=='.')
174*4887Schin 				{
175*4887Schin 					if(c=='[')
176*4887Schin 					{
177*4887Schin 						str = nv_endsubscript(np,cp=str,0);
178*4887Schin 						if((c= *str)!='[' &&  c!='.')
179*4887Schin 						{
180*4887Schin 							str = cp;
181*4887Schin 							c = '[';
182*4887Schin 							break;
183*4887Schin 						}
184*4887Schin 					}
185*4887Schin 					else
186*4887Schin 					{
187*4887Schin 						str++;
188*4887Schin 						while(xp=str, c=mbchar(str), isaname(c));
189*4887Schin 						str = xp;
190*4887Schin 					}
191*4887Schin 				}
192*4887Schin 				*str = 0;
193*4887Schin 				if(strcasecmp(*ptr,"Inf")==0)
194*4887Schin 				{
195*4887Schin 					Inf = 1.0/Zero;
196*4887Schin 					Infnod.nvalue.ldp = &Inf;
197*4887Schin 					np = &Infnod;
198*4887Schin 				}
199*4887Schin 				else if(strcasecmp(*ptr,"NaN")==0)
200*4887Schin 				{
201*4887Schin 					NaN = 0.0/Zero;
202*4887Schin 					NaNnod.nvalue.ldp = &NaN;
203*4887Schin 					np = &NaNnod;
204*4887Schin 				}
205*4887Schin 				else
206*4887Schin 					np = nv_open(*ptr,root,NV_NOASSIGN|NV_VARNAME);
207*4887Schin 				if(saveptr != stakptr(0))
208*4887Schin 					stakset(saveptr,offset);
209*4887Schin 				else
210*4887Schin 					stakseek(offset);
211*4887Schin 			}
212*4887Schin 			*str = c;
213*4887Schin 			lvalue->value = (char*)np;
214*4887Schin 			if((lvalue->emode&ARITH_COMP) || (nv_isarray(np) && nv_aindex(np)<0))
215*4887Schin 			{
216*4887Schin 				/* bind subscript later */
217*4887Schin 				lvalue->flag = 0;
218*4887Schin 				if(c=='[')
219*4887Schin 				{
220*4887Schin 					lvalue->flag = (str-lvalue->expr);
221*4887Schin 					do
222*4887Schin 						str = nv_endsubscript(np,str,0);
223*4887Schin 					while((c= *str)=='[');
224*4887Schin 				}
225*4887Schin 				break;
226*4887Schin 			}
227*4887Schin 			if(c=='[')
228*4887Schin 			{
229*4887Schin 				do
230*4887Schin 					str = nv_endsubscript(np,str,NV_ADD|NV_SUBQUOTE);
231*4887Schin 				while((c=*str)=='[');
232*4887Schin 			}
233*4887Schin 			else if(nv_isarray(np))
234*4887Schin 				nv_putsub(np,NIL(char*),ARRAY_UNDEF);
235*4887Schin 			if(nv_isattr(np,NV_INTEGER|NV_DOUBLE)==(NV_INTEGER|NV_DOUBLE))
236*4887Schin 				lvalue->isfloat=1;
237*4887Schin 			lvalue->flag = nv_aindex(np);
238*4887Schin 		}
239*4887Schin 		else
240*4887Schin 		{
241*4887Schin 			char	lastbase=0, *val = xp, oerrno = errno;
242*4887Schin 			errno = 0;
243*4887Schin 			r = strtonll(val,&str, &lastbase,-1);
244*4887Schin 			if(*str=='8' || *str=='9')
245*4887Schin 			{
246*4887Schin 				lastbase=10;
247*4887Schin 				errno = 0;
248*4887Schin 				r = strtonll(val,&str, &lastbase,-1);
249*4887Schin 			}
250*4887Schin 			if(lastbase<=1)
251*4887Schin 				lastbase=10;
252*4887Schin 			if(*val=='0')
253*4887Schin 			{
254*4887Schin 				while(*val=='0')
255*4887Schin 					val++;
256*4887Schin 				if(*val==0 || *val=='.' || *val=='x' || *val=='X')
257*4887Schin 					val--;
258*4887Schin 			}
259*4887Schin 			if(r==LLONG_MAX && errno)
260*4887Schin 				c='e';
261*4887Schin 			else
262*4887Schin 				c = *str;
263*4887Schin 			if(c==GETDECIMAL(0) || c=='e' || c == 'E')
264*4887Schin 			{
265*4887Schin 				lvalue->isfloat=1;
266*4887Schin 				r = strtold(val,&str);
267*4887Schin 			}
268*4887Schin 			else if(lastbase==10 && val[1])
269*4887Schin 			{
270*4887Schin 				if(val[2]=='#')
271*4887Schin 					val += 3;
272*4887Schin 				if((str-val)>2*sizeof(Sflong_t))
273*4887Schin 				{
274*4887Schin 					Sfdouble_t rr;
275*4887Schin 					rr = strtold(val,&str);
276*4887Schin 					if(rr!=r)
277*4887Schin 					{
278*4887Schin 						r = rr;
279*4887Schin 						lvalue->isfloat=1;
280*4887Schin 					}
281*4887Schin 				}
282*4887Schin 			}
283*4887Schin 			errno = oerrno;
284*4887Schin 		}
285*4887Schin 		break;
286*4887Schin 	    }
287*4887Schin 	    case VALUE:
288*4887Schin 	    {
289*4887Schin 		register Namval_t *np = (Namval_t*)(lvalue->value);
290*4887Schin 		if(sh_isoption(SH_NOEXEC))
291*4887Schin 			return(0);
292*4887Schin 		np = scope(np,lvalue,0);
293*4887Schin 		if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
294*4887Schin 		{
295*4887Schin 			*ptr = nv_name(np);
296*4887Schin 			lvalue->value = (char*)ERROR_dictionary(e_notset);
297*4887Schin 			lvalue->emode |= 010;
298*4887Schin 			return(0);
299*4887Schin 		}
300*4887Schin 		r = nv_getnum(np);
301*4887Schin 		if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
302*4887Schin 			lvalue->isfloat= (r!=(Sflong_t)r);
303*4887Schin 		else if(nv_isattr(np,NV_INTEGER|NV_DOUBLE)==(NV_INTEGER|NV_DOUBLE))
304*4887Schin 			lvalue->isfloat=1;
305*4887Schin 		return(r);
306*4887Schin 	    }
307*4887Schin 
308*4887Schin 	    case MESSAGE:
309*4887Schin 		sfsync(NIL(Sfio_t*));
310*4887Schin #if 0
311*4887Schin 		if(warn)
312*4887Schin 			errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
313*4887Schin 		else
314*4887Schin #endif
315*4887Schin 			errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
316*4887Schin 	}
317*4887Schin 	*ptr = str;
318*4887Schin 	return(r);
319*4887Schin }
320*4887Schin 
321*4887Schin /*
322*4887Schin  * convert number defined by string to a Sfdouble_t
323*4887Schin  * ptr is set to the last character processed
324*4887Schin  * if mode>0, an error will be fatal with value <mode>
325*4887Schin  */
326*4887Schin 
327*4887Schin Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
328*4887Schin {
329*4887Schin 	register Sfdouble_t d;
330*4887Schin 	char base=0, *last;
331*4887Schin 	if(*str==0)
332*4887Schin 	{
333*4887Schin 		if(ptr)
334*4887Schin 			*ptr = (char*)str;
335*4887Schin 		return(0);
336*4887Schin 	}
337*4887Schin 	errno = 0;
338*4887Schin 	d = strtonll(str,&last,&base,-1);
339*4887Schin 	if(*last || errno)
340*4887Schin 	{
341*4887Schin 		d = strval(str,&last,arith,mode);
342*4887Schin 		if(!ptr && *last && mode>0)
343*4887Schin 			errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
344*4887Schin 	}
345*4887Schin 	if(ptr)
346*4887Schin 		*ptr = last;
347*4887Schin 	return(d);
348*4887Schin }
349*4887Schin 
350*4887Schin Sfdouble_t sh_arith(register const char *str)
351*4887Schin {
352*4887Schin 	return(sh_strnum(str, (char**)0, 1));
353*4887Schin }
354*4887Schin 
355*4887Schin void	*sh_arithcomp(register char *str)
356*4887Schin {
357*4887Schin 	const char *ptr = str;
358*4887Schin 	Arith_t *ep;
359*4887Schin 	ep = arith_compile(str,(char**)&ptr,arith,ARITH_COMP|1);
360*4887Schin 	if(*ptr)
361*4887Schin 		errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
362*4887Schin 	return((void*)ep);
363*4887Schin }
364