1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1982-2013 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
12 *                                                                      *
13 *              Information and Software Systems Research               *
14 *                            AT&T Research                             *
15 *                           Florham Park NJ                            *
16 *                                                                      *
17 *                    David Korn <dgkorn@gmail.com>                     *
18 *                                                                      *
19 ***********************************************************************/
20 /*
21  * Shell arithmetic - uses streval library
22  *   David Korn
23  *   AT&T Labs
24  */
25 
26 #include	"defs.h"
27 #include	"lexstates.h"
28 #include	"name.h"
29 #include	"streval.h"
30 #include	"variables.h"
31 #include	"builtins.h"
32 
33 #undef SHOPT_FIXEDARRAY
34 #ifndef LLONG_MAX
35 #define LLONG_MAX	LONG_MAX
36 #endif
37 
38 typedef Sfdouble_t (*Math_f)(Sfdouble_t, ...);
39 
40 extern const Namdisc_t	ENUM_disc;
41 static bool		Varsubscript;
42 static Sfdouble_t	NaN, Inf, Fun;
43 static Namval_t Infnod =
44 {
45 	{ 0 },
46 	"Inf",
47 };
48 
49 static Namval_t NaNnod =
50 {
51 	{ 0 },
52 	"NaN",
53 };
54 
55 static Namval_t FunNode =
56 {
57 	{ 0 },
58 	"?",
59 };
60 
61 struct Mathconst
62 {
63 	char		name[9];
64 	Sfdouble_t  	value;
65 };
66 
67 #ifndef M_1_PIl
68 #   define M_1_PIl	0.3183098861837906715377675267450287L
69 #endif
70 #ifndef M_2_PIl
71 #   define M_2_PIl	0.6366197723675813430755350534900574L
72 #endif
73 #ifndef M_2_SQRTPIl
74 #   define M_2_SQRTPIl	1.1283791670955125738961589031215452L
75 #endif
76 #ifndef M_El
77 #   define M_El		2.7182818284590452353602874713526625L
78 #endif
79 #ifndef M_LOG2El
80 #   define M_LOG2El	1.4426950408889634073599246810018921L
81 #endif
82 #ifndef M_LOG10El
83 #   define M_LOG10El	0.4342944819032518276511289189166051L
84 #endif
85 #ifndef M_LN2l
86 #   define M_LN2l	0.6931471805599453094172321214581766L
87 #endif
88 #ifndef M_LN10l
89 #   define M_LN10l	2.3025850929940456840179914546843642L
90 #endif
91 #ifndef M_PIl
92 #   define M_PIl	3.1415926535897932384626433832795029L
93 #endif
94 #ifndef M_PI_2l
95 #   define M_PI_2l	1.5707963267948966192313216916397514L
96 #endif
97 #ifndef M_PI_4l
98 #   define M_PI_4l	0.7853981633974483096156608458198757L
99 #endif
100 #ifndef M_SQRT2l
101 #   define M_SQRT2l	1.4142135623730950488016887242096981L
102 #endif
103 #ifndef M_SQRT1_2l
104 #   define M_SQRT1_2l	0.7071067811865475244008443621048490L
105 #endif
106 
107 /* The firs three entries cann't be moved or it will break the code */
108 static const struct Mathconst Mtable[]=
109 {
110 	"1_PI",		M_1_PIl,
111 	"2_PI",		M_2_PIl,
112 	"2_SQRTPI",	M_2_SQRTPIl,
113 	"E",		M_El,
114 	"LOG2E",	M_LOG2El,
115 	"LOG10E",	M_LOG10El,
116 	"LN2",		M_LN2l,
117 	"PI",		M_PIl,
118 	"PI_2",		M_PI_2l,
119 	"PI_4",		M_PI_4l,
120 	"SQRT2",	M_SQRT2l,
121 	"SQRT1_2",	M_SQRT1_2l,
122 	0,		0
123 };
124 
125 typedef struct Intconst_s
126 {
127 	const char	name[4];
128 	short		ss;
129 	unsigned short	us;
130 	int		si;
131 	unsigned int	ui;
132 	Sflong_t	sl;
133 	Sfulong_t	ul;
134 } Intconst_t;
135 
136 typedef struct Fltconst_s
137 {
138 	const char	name[12];
139 	float		f;
140 	double		d;
141 	Sfdouble_t	l;
142 } Fltconst_t;
143 
144 static const Intconst_t	intconst[] =
145 {
146 	{
147 		"DIG",
148 		USHRT_DIG,	USHRT_DIG,
149 		UINT_DIG,	UINT_DIG,
150 #ifdef LLONG_DIG
151 		ULLONG_DIG,	ULLONG_DIG,
152 #else
153 		ULONG_DIG,	ULONG_DIG,
154 #endif
155 	},
156 	{
157 		"MAX",
158 		SHRT_MAX,	USHRT_MAX,
159 		INT_MAX,	UINT_MAX,
160 #ifdef LLONG_MAX
161 		LLONG_MAX,	ULLONG_MAX,
162 #else
163 		LONG_MAX,	ULONG_MAX,
164 #endif
165 	},
166 	{
167 		"MIN",
168 		SHRT_MIN,	0,
169 		INT_MIN,	0,
170 #ifdef LLONG_MIN
171 		LLONG_MIN,	0,
172 #else
173 		LONG_MIN,	0,
174 #endif
175 	},
176 };
177 
178 static const Fltconst_t	fltconst[] =
179 {
180 	{
181 		"DIG",
182 		FLT_DIG,
183 		DBL_DIG,
184 #ifdef LDBL_DIG
185 		LDBL_DIG,
186 #else
187 		DBL_DIG,
188 #endif
189 	},
190 	{
191 		"EPSILON",
192 		FLT_EPSILON,
193 		DBL_EPSILON,
194 #ifdef LDBL_EPSILON
195 		LDBL_EPSILON,
196 #else
197 		DBL_EPSILON,
198 #endif
199 	},
200 	{
201 		"INT_MAX",
202 		FLT_INTMAX_MAX,
203 		DBL_INTMAX_MAX,
204 #ifdef LDBL_INTMAX_MAX
205 		LDBL_INTMAX_MAX,
206 #else
207 		DBL_INTMAX_MAX,
208 #endif
209 	},
210 	{
211 		"INT_MIN",
212 		FLT_INTMAX_MIN,
213 		DBL_INTMAX_MIN,
214 #ifdef LDBL_INTMAX_MIN
215 		LDBL_INTMAX_MIN,
216 #else
217 		DBL_INTMAX_MIN,
218 #endif
219 	},
220 	{
221 		"MAX",
222 		FLT_MAX,
223 		DBL_MAX,
224 #ifdef LDBL_MAX
225 		LDBL_MAX,
226 #else
227 		DBL_MAX,
228 #endif
229 	},
230 	{
231 		"MAX_10_EXP",
232 		FLT_MAX_10_EXP,
233 		DBL_MAX_10_EXP,
234 #ifdef LDBL_MAX_10_EXP
235 		LDBL_MAX_10_EXP,
236 #else
237 		DBL_MAX_10_EXP,
238 #endif
239 	},
240 	{
241 		"MAX_EXP",
242 		FLT_MAX_EXP,
243 		DBL_MAX_EXP,
244 #ifdef LDBL_MAX_EXP
245 		LDBL_MAX_EXP,
246 #else
247 		DBL_MAX_EXP,
248 #endif
249 	},
250 	{
251 		"MIN",
252 		FLT_MIN,
253 		DBL_MIN,
254 #ifdef LDBL_MIN
255 		LDBL_MIN,
256 #else
257 		DBL_MIN,
258 #endif
259 	},
260 	{
261 		"MIN_10_EXP",
262 		FLT_MIN_10_EXP,
263 		DBL_MIN_10_EXP,
264 #ifdef LDBL_MIN_10_EXP
265 		LDBL_MIN_10_EXP,
266 #else
267 		DBL_MIN_10_EXP,
268 #endif
269 	},
270 	{
271 		"MIN_EXP",
272 		FLT_MIN_EXP,
273 		DBL_MIN_EXP,
274 #ifdef LDBL_MIN_EXP
275 		LDBL_MIN_EXP,
276 #else
277 		DBL_MIN_EXP,
278 #endif
279 	},
280 	{
281 		"UINT_MAX",
282 		FLT_UINTMAX_MAX,
283 		DBL_UINTMAX_MAX,
284 #ifdef LDBL_UINTMAX_MAX
285 		LDBL_UINTMAX_MAX,
286 #else
287 		DBL_UINTMAX_MAX,
288 #endif
289 	},
290 	{
291 		"UINT_MIN",
292 		0,
293 		0,
294 		0,
295 	},
296 };
297 
check_limits(Shell_t * shp,char * cp)298 static Namval_t	*check_limits(Shell_t *shp, char *cp)
299 {
300 	static Namval_t	node;
301 	static Sfdouble_t dd;
302 	Namval_t	*np;
303 	char		*ep;
304 	int 		n;
305 	if(!(ep=strrchr(cp,'.')))
306 		return(0);
307 	*ep = 0;
308 	np = nv_open(cp, shp->var_tree, NV_VARNAME|NV_NOADD|NV_NOFAIL);
309 	*ep++ = '.';
310 	if(!np || !nv_isattr(np,NV_INTEGER))
311 		return(0);
312 	if(nv_isattr (np,NV_DOUBLE)==NV_DOUBLE)
313 	{
314 		const Fltconst_t *fp = fltconst;
315 		n = sizeof(fltconst)/sizeof(Fltconst_t);
316 		for(; n-->0; fp++)
317 		{
318 			if(strcmp(fp->name,ep)==0)
319 				break;
320 		}
321 		if(n>=0)
322 		{
323 			node = *np;
324 			node.nvalue.ldp = &dd;
325 			if(nv_isattr(np,NV_SHORT))
326 				*node.nvalue.fp = fp->f;
327 			else if(nv_isattr(np,NV_LONG))
328 				*node.nvalue.ldp = fp->l;
329 			else
330 				*node.nvalue.dp = fp->d;
331 			return(&node);
332 		}
333 	}
334 	else
335 	{
336 		const Intconst_t *ip = intconst;
337 		n = sizeof(intconst)/sizeof(Intconst_t);
338 		for(; n-->=0; ip++)
339 		{
340 			if(strcmp(ip->name,ep)==0)
341 				break;
342 		}
343 		if(n>=0)
344 		{
345 			int unsign = nv_isattr(np,NV_LTOU);
346 			node = *np;
347 			node.nvalue.ldp = &dd;
348 			if(nv_isattr(np,NV_SHORT))
349 			{
350 				if(unsign)
351 					node.nvalue.u = ip->us;
352 				else
353 					node.nvalue.s = ip->ss;
354 			}
355 			else if(nv_isattr(np,NV_LONG))
356 			{
357 				if(unsign)
358 					*node.nvalue.llp = ip->ul;
359 				else
360 					*node.nvalue.llp = ip->sl;
361 			}
362 			else
363 			{
364 				if(unsign)
365 					*node.nvalue.ip = ip->ui;
366 				else
367 					*node.nvalue.ip = ip->ul;
368 			}
369 			return(&node);
370 		}
371 	}
372 	return(0);
373 }
374 
scope(register Namval_t * np,register struct lval * lvalue,int assign)375 static Namval_t *scope(register Namval_t *np,register struct lval *lvalue,int assign)
376 {
377 	register int flag = lvalue->flag;
378 	register char *sub=0, *cp=(char*)np;
379 	register Namval_t *mp;
380 	Shell_t		*shp = lvalue->shp;
381 	int	flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET;
382 	int	c=0,nosub = lvalue->nosub;
383 	Dt_t	*sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0);
384 	Dt_t	*nsdict = (shp->namespace?nv_dict(shp->namespace):0);
385 	Dt_t	*root = shp->var_tree;
386 	assign = assign?NV_ASSIGN:NV_NOASSIGN;
387 	lvalue->nosub = 0;
388 	if(nosub<0 && lvalue->ovalue)
389 		return((Namval_t*)lvalue->ovalue);
390 	lvalue->ovalue = 0;
391 	if(cp>=lvalue->expr &&  cp < lvalue->expr+lvalue->elen)
392 	{
393 		int offset;
394 		/* do binding to node now */
395 		int d = cp[flag];
396 		cp[flag] = 0;
397 		if((!(np = nv_open(cp,root,assign|NV_VARNAME|NV_NOADD|NV_NOFAIL)) || nv_isnull(np)) && sh_macfun(shp,cp, offset = stktell(shp->stk)))
398 		{
399 			Fun = sh_arith(shp,sub=stkptr(shp->stk,offset));
400 			FunNode.nvalue.ldp = &Fun;
401 			FunNode.nvshell = shp;
402 			nv_onattr(&FunNode,NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
403 			cp[flag] = d;
404 			return(&FunNode);
405 		}
406 		if(!np)
407 		{
408 			if(assign)
409 				np = nv_open(cp,root,assign|NV_VARNAME);
410 			else
411 				np = check_limits(shp,cp);
412 		}
413 		cp[flag] = d;
414 		if(!np)
415 			return(0);
416 		root = shp->last_root;
417 		if(cp[flag+1]=='[')
418 			flag++;
419 		else
420 			flag = 0;
421 		cp = (char*)np;
422 	}
423 	else if(assign==NV_ASSIGN  && nv_isnull(np) && !nv_isattr(np, ~(NV_MINIMAL|NV_NOFREE)))
424 		flags |= NV_ADD;
425 	if((lvalue->emode&ARITH_COMP) && dtvnext(root) && ((sdict && (mp=nv_search(cp,sdict,flags&~NV_ADD))) || (mp=nv_search(cp,root,flags&~(NV_ADD))) || (nsdict && (mp=nv_search(cp,nsdict,flags&~(NV_ADD|HASH_NOSCOPE)))) ))
426 		np = mp;
427 	while(nv_isref(np))
428 	{
429 #if SHOPT_FIXEDARRAY
430 		int n,dim;
431 		dim = nv_refdimen(np);
432 		n = nv_refindex(np);
433 #endif /* SHOPT_FIXEDARRAY */
434 		sub = nv_refsub(np);
435 		np = nv_refnode(np);
436 #if SHOPT_FIXEDARRAY
437 		if(n)
438 		{
439 			Namarr_t *ap = nv_arrayptr(np);
440 			ap->nelem = dim;
441 			nv_putsub(np,(char*),n,0);
442 		}
443 		else
444 #endif /* SHOPT_FIXEDARRAY */
445 		if(sub)
446 			nv_putsub(np,sub,0,assign==NV_ASSIGN?ARRAY_ADD:0);
447 	}
448 	if(!nosub && flag)
449 	{
450 		int		hasdot = 0;
451 		cp = (char*)&lvalue->expr[flag];
452 		if(sub)
453 		{
454 			goto skip;
455 		}
456 		sub = cp;
457 		while(1)
458 		{
459 			Namarr_t	*ap;
460 			Namval_t	*nq;
461 			cp = nv_endsubscript(np,cp,0,(void*)shp);
462 			if(c || *cp=='.')
463 			{
464 				c = '.';
465 				while(*cp=='.')
466 				{
467 					hasdot=1;
468 					cp++;
469 					while(c=mbchar(cp),isaname(c));
470 				}
471 				if(c=='[')
472 					continue;
473 			}
474 			flag = *cp;
475 			*cp = 0;
476 			if(c || hasdot)
477 			{
478 				sfprintf(shp->strbuf,"%s%s%c",nv_name(np),sub,0);
479 				sub = sfstruse(shp->strbuf);
480 			}
481 			if(strchr(sub,'$'))
482 				sub = sh_mactrim(shp,sub,0);
483 			*cp = flag;
484 			if(c || hasdot)
485 			{
486 				np = nv_open(sub,shp->var_tree,NV_VARNAME|assign);
487 				return(np);
488 			}
489 #if SHOPT_FIXEDARRAY
490 			ap = nv_arrayptr(np);
491 			cp = nv_endsubscript(np,sub,(assign==NV_ASSIGN?NV_ADD:0)|NV_SUBQUOTE|(ap&&ap->fixed?NV_FARRAY:0),np->nvshell);
492 #else
493 			cp = nv_endsubscript(np,sub,(assign==NV_ASSIGN?NV_ADD:0)|NV_SUBQUOTE,np->nvshell);
494 #endif /* SHOPT_FIXEDARRAY */
495 			if(*cp!='[')
496 				break;
497 		skip:
498 			if(nq = nv_opensub(np))
499 				np = nq;
500 			else
501 			{
502 				ap = nv_arrayptr(np);
503 				if(ap && !ap->table)
504 				{
505 					ap->table = dtopen(&_Nvdisc,Dtoset);
506 					dtuserdata(ap->table,shp,1);
507 				}
508 				if(ap && ap->table && (nq=nv_search(nv_getsub(np),ap->table,NV_ADD)))
509 					nq->nvenv = (char*)np;
510 				if(nq && nv_isnull(nq))
511 					np = nv_arraychild(np,nq,0);
512 			}
513 			sub = cp;
514 		}
515 	}
516 	else if(nosub>0)
517 		nv_putsub(np,(char*)0,nosub-1,0);
518 	return(np);
519 }
520 
sh_mathstdfun(const char * fname,size_t fsize,short * nargs)521 Math_f sh_mathstdfun(const char *fname, size_t fsize, short * nargs)
522 {
523 	register const struct mathtab *tp;
524 	register char c = fname[0];
525 	for(tp=shtab_math; *tp->fname; tp++)
526 	{
527 		if(*tp->fname > c)
528 			break;
529 		if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],fname,fsize)==0)
530 		{
531 			if(nargs)
532 				*nargs = *tp->fname;
533 			return(tp->fnptr);
534 		}
535 	}
536 	return(0);
537 }
538 
sh_mathstd(const char * name)539 int	sh_mathstd(const char *name)
540 {
541 	return(sh_mathstdfun(name,strlen(name),NULL)!=0);
542 }
543 
number(const char * s,char ** p,int b,struct lval * lvalue)544 static Sfdouble_t number(const char* s, char** p, int b, struct lval* lvalue)
545 {
546 	Sfdouble_t	r;
547 	char*		t;
548 	int		oerrno;
549 	int		c;
550 	char		base;
551 	struct lval	v;
552 
553 	oerrno = errno;
554 	errno = 0;
555 	base = b;
556 	if (!lvalue)
557 		lvalue = &v;
558 	else if (lvalue->shp->bltindata.bnode==SYSLET && !sh_isoption(lvalue->shp, SH_LETOCTAL))
559 		while (*s=='0' && isdigit(s[1]))
560 			s++;
561 	lvalue->eflag = 0;
562 	lvalue->isfloat = 0;
563 	r = strtonll(s, &t, &base, -1);
564 	if (*t=='8' || *t=='9')
565 	{
566 		base = 10;
567 		errno = 0;
568 		r = strtonll(s, &t, &base, -1);
569 	}
570 	if (base <= 1)
571 		base = 10;
572 	if (*t=='_')
573 	{
574 		if ((r==1||r==2) && strcmp(t,"_PI")==0)
575 		{
576 			t += 3;
577 			r = Mtable[(int)r-1].value;
578 		}
579 		else if (r==2 && strcmp(t,"_SQRTPI")==0)
580 		{
581 			t += 7;
582 			r = Mtable[2].value;
583 		}
584 	}
585 	c = r==LLONG_MAX && errno ? 'e' : *t;
586 	if (c==GETDECIMAL(0) || c=='e' || c == 'E' || base == 16 && (c == 'p' || c == 'P'))
587 	{
588 		r = strtold(s, &t);
589 		lvalue->isfloat = TYPE_LD;
590 	}
591 	if (t > s)
592 	{
593 		if (*t=='f' || *t=='F')
594 		{
595 			t++;
596 			lvalue->isfloat = TYPE_F;
597 			r = (float)r;
598 		}
599 		else if (*t=='l' || *t=='L')
600 		{
601 			t++;
602 			lvalue->isfloat= TYPE_LD;
603 		}
604 		else if (*t=='d' || *t=='D')
605 		{
606 			t++;
607 			lvalue->isfloat= TYPE_LD;
608 			r = (double)r;
609 		}
610 	}
611 	errno = oerrno;
612 	*p = t;
613 	return r;
614 }
615 
arith(const char ** ptr,struct lval * lvalue,int type,Sfdouble_t n)616 static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
617 {
618 	Shell_t		*shp = lvalue->shp;
619 	register Sfdouble_t r= 0;
620 	char *str = (char*)*ptr;
621 	register char *cp;
622 	switch(type)
623 	{
624 	    case ASSIGN:
625 	    {
626 		register Namval_t *np = (Namval_t*)(lvalue->value);
627 		np = scope(np,lvalue,1);
628 		nv_putval(np, (char*)&n, NV_LDOUBLE);
629 		if(lvalue->eflag)
630 			lvalue->ptr = (void*)nv_hasdisc(np,&ENUM_disc);
631 		lvalue->eflag = 0;
632 		r=nv_getnum(np);
633 		lvalue->value = (char*)np;
634 		break;
635 	    }
636 	    case LOOKUP:
637 	    {
638 		register int c = *str;
639 		register char *xp=str;
640 		lvalue->value = (char*)0;
641 		if(c=='.')
642 			str++;
643 		c = mbchar(str);
644 		if(isaletter(c))
645 		{
646 			register Namval_t *np=0;
647 			int dot=0;
648 			while(1)
649 			{
650 				while(xp=str, c=mbchar(str), isaname(c));
651 				str = xp;
652 				while(c=='[' && dot==NV_NOADD)
653 				{
654 					str = nv_endsubscript((Namval_t*)0,str,0,shp);
655 					c = *str;
656 				}
657 				if(c!='.')
658 					break;
659 				dot=NV_NOADD;
660 				if((c = *++str) !='[')
661 					continue;
662 				str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE,shp)-1;
663 				if(sh_checkid(cp+1,(char*)0))
664 					str -=2;
665 			}
666 			if(c=='(')
667 			{
668 				int off=stktell(shp->stk);
669 				int fsize = str- (char*)(*ptr);
670 				const struct mathtab *tp;
671 				Namval_t	*nq;
672 				c = **ptr;
673 				lvalue->fun = 0;
674 				sfprintf(shp->stk,".sh.math.%.*s%c",fsize,*ptr,0);
675 				stkseek(shp->stk,off);
676 				if(nq=nv_search(stkptr(shp->stk,off),shp->fun_tree,0))
677 				{
678 						lvalue->nargs = -nq->nvalue.rp->argc;
679 						lvalue->fun = (Math_f)nq;
680 						break;
681 				}
682 				if(fsize<=(sizeof(tp->fname)-2))
683 					lvalue->fun = (Math_f)sh_mathstdfun(*ptr,fsize,&lvalue->nargs);
684 				if(lvalue->fun)
685 					break;
686 				if(lvalue->emode&ARITH_COMP)
687 					lvalue->value = (char*)e_function;
688 				else
689 					lvalue->value = (char*)ERROR_dictionary(e_function);
690 				return(r);
691 			}
692 			if((lvalue->emode&ARITH_COMP) && dot)
693 			{
694 				lvalue->value = (char*)*ptr;
695 				lvalue->flag =  str-lvalue->value;
696 				break;
697 			}
698 			*str = 0;
699 			if(sh_isoption(shp,SH_NOEXEC))
700 				np = L_ARGNOD;
701 			else
702 			{
703 				int offset = stktell(shp->stk);
704 				char *saveptr = stkfreeze(shp->stk,0);
705 				Dt_t  *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree;
706 				*str = c;
707 				cp = str;
708 				while(c=='[' || c=='.')
709 				{
710 					if(c=='[')
711 					{
712 						str = nv_endsubscript(np,str,0,(void*)shp);
713 						if((c= *str)!='[' &&  c!='.')
714 						{
715 							str = cp;
716 							c = '[';
717 							break;
718 						}
719 					}
720 					else
721 					{
722 						dot = NV_NOADD|NV_NOFAIL;
723 						str++;
724 						while(xp=str, c=mbchar(str), isaname(c));
725 						str = xp;
726 					}
727 				}
728 				*str = 0;
729 				cp = (char*)*ptr;
730 				Varsubscript = false;
731 				if ((cp[0] == 'i' || cp[0] == 'I') && (cp[1] == 'n' || cp[1] == 'N') && (cp[2] == 'f' || cp[2] == 'F') && cp[3] == 0)
732 				{
733 					Inf = strtold("Inf", NiL);
734 					Infnod.nvalue.ldp = &Inf;
735 					np = &Infnod;
736 					np->nvshell = shp;
737 					nv_onattr(np,NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
738 				}
739 				else if ((cp[0] == 'n' || cp[0] == 'N') && (cp[1] == 'a' || cp[1] == 'A') && (cp[2] == 'n' || cp[2] == 'N') && cp[3] == 0)
740 				{
741 					NaN = strtold("NaN", NiL);
742 					NaNnod.nvalue.ldp = &NaN;
743 					np = &NaNnod;
744 					np->nvshell = shp;
745 					nv_onattr(np,NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
746 				}
747 				else
748 				{
749 					const struct Mathconst *mp=0;
750 					np = 0;
751 #if 1
752 					if(strchr("ELPS12",**ptr))
753 					{
754 						for(mp=Mtable; *mp->name; mp++)
755 						{
756 							if(strcmp(mp->name,*ptr)==0)
757 								break;
758 						}
759 					}
760 					if(mp && *mp->name)
761 					{
762 						r = mp->value;
763 						lvalue->isfloat = TYPE_LD;
764 						goto skip2;
765 					}
766 #endif
767 					if(shp->namref_root && !(lvalue->emode&ARITH_COMP))
768 						np = nv_open(*ptr,shp->namref_root,NV_NOREF|NV_NOASSIGN|NV_VARNAME|NV_NOSCOPE|NV_NOADD|dot);
769 					if(!np)
770 						np = nv_open(*ptr,root,NV_NOREF|NV_NOASSIGN|NV_VARNAME|dot);
771 					if(!np || Varsubscript)
772 					{
773 						np = 0;
774 						lvalue->value = (char*)*ptr;
775 						lvalue->flag =  str-lvalue->value;
776 					}
777 				}
778 			skip2:
779 				if(saveptr != stkptr(shp->stk,0))
780 					stkset(shp->stk,saveptr,offset);
781 				else
782 					stkseek(shp->stk,offset);
783 			}
784 			*str = c;
785 #if 1
786 			if(lvalue->isfloat==TYPE_LD)
787 				break;
788 #endif
789 			if(!np && lvalue->value)
790 				break;
791 			lvalue->value = (char*)np;
792 			/* bind subscript later */
793 			if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
794 				lvalue->isfloat=1;
795 			lvalue->flag = 0;
796 			if(c=='[')
797 			{
798 				lvalue->flag = (str-lvalue->expr);
799 				do
800 				{
801 					while(c=='.')
802 					{
803 						str++;
804 						while(xp=str, c=mbchar(str), isaname(c));
805 						c = *(str = xp);
806 					}
807 					if(c=='[')
808 						str = nv_endsubscript(np,str,0,np->nvshell);
809 				}
810 				while((c= *str)=='[' || c=='.');
811 				break;
812 			}
813 		}
814 		else
815 			r = number(xp, &str, 0, lvalue);
816 		break;
817 	    }
818 	    case VALUE:
819 	    {
820 		register Namval_t *np = (Namval_t*)(lvalue->value);
821 		Namarr_t *ap;
822 		if(sh_isoption(shp,SH_NOEXEC))
823 			return(0);
824 		np = scope(np,lvalue,0);
825 		if(!np)
826 		{
827 			if(sh_isoption(shp,SH_NOUNSET))
828 			{
829 				*ptr = lvalue->value;
830 				goto skip;
831 			}
832 			return(0);
833 		}
834 		lvalue->ovalue = (char*)np;
835 		if(lvalue->eflag)
836 			lvalue->ptr = (void*)nv_hasdisc(np,&ENUM_disc);
837 		else if((Namfun_t*)lvalue->ptr && !nv_hasdisc(np,&ENUM_disc) && !nv_isattr(np,NV_INTEGER))
838 		{
839 			Namval_t *mp,node;
840 			mp = ((Namfun_t*)lvalue->ptr)->type;
841 			memset(&node,0,sizeof(node));
842 			nv_clone(mp,&node,0);
843 			nv_offattr(&node,NV_RDONLY|NV_NOFREE);
844 			nv_putval(&node,np->nvname,0);
845 			if(nv_isattr(&node,NV_NOFREE))
846 				return(r=nv_getnum(&node));
847 		}
848 		lvalue->eflag = 0;
849 		if(((lvalue->emode&2) || lvalue->level>1 || (lvalue->nextop!=A_STORE && sh_isoption(shp,SH_NOUNSET))) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
850 		{
851 			*ptr = nv_name(np);
852 		skip:
853 			lvalue->value = (char*)ERROR_dictionary(e_notset);
854 			lvalue->emode |= 010;
855 			return(0);
856 		}
857 		if(lvalue->userfn && (ap=nv_arrayptr(np)) && (ap->flags&ARRAY_UNDEF))
858 		{
859 			r = (Sfdouble_t)integralof(np);
860 			lvalue->isfloat=5;
861 			return(r);
862 		}
863 		r = nv_getnum(np);
864 		if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
865 			lvalue->isfloat= (r!=(Sflong_t)r)?TYPE_LD:0;
866 		else if(nv_isattr(np,(NV_DOUBLE|NV_SHORT))==(NV_DOUBLE|NV_SHORT))
867 		{
868 			lvalue->isfloat = TYPE_F;
869 			r = (float)r;
870 		}
871 		else if(nv_isattr(np,(NV_DOUBLE|NV_LONG))==(NV_DOUBLE|NV_LONG))
872 			lvalue->isfloat = TYPE_LD;
873 		else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
874 		{
875 			lvalue->isfloat = TYPE_D;
876 			r = (double)r;
877 		}
878 		if((lvalue->emode&ARITH_ASSIGNOP) && nv_isarray(np))
879 			lvalue->nosub = nv_aindex(np)+1;
880 		return(r);
881 	    }
882 
883 	    case MESSAGE:
884 		sfsync(NIL(Sfio_t*));
885 #if 0
886 		if(warn)
887 			errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
888 		else
889 #endif
890 		if(lvalue->emode&ARITH_COMP)
891 			return(-1);
892 
893 		errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
894 	}
895 	*ptr = str;
896 	return(r);
897 }
898 
sh_arith(Shell_t * shp,register const char * str)899 Sfdouble_t sh_arith(Shell_t *shp,register const char *str)
900 {
901 	return(sh_strnum(shp, str, (char**)0, 1));
902 }
903 
sh_arithcomp(Shell_t * shp,register char * str)904 void	*sh_arithcomp(Shell_t *shp,register char *str)
905 {
906 	const char *ptr = str;
907 	Arith_t *ep;
908 	ep = arith_compile(shp,str,(char**)&ptr,arith,ARITH_COMP|1);
909 	if(*ptr)
910 		errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
911 	return((void*)ep);
912 }
913 
914 /*
915  * convert number defined by string to a Sfdouble_t
916  * ptr is set to the last character processed
917  * if mode>0, an error will be fatal with value <mode>
918  */
sh_strnum_20120720(Shell_t * shp,register const char * str,char ** ptr,int mode)919 Sfdouble_t sh_strnum_20120720(Shell_t *shp,register const char *str, char** ptr, int mode)
920 {
921 	register Sfdouble_t d;
922 	char *last;
923 	if(*str==0)
924 	{
925 		if(ptr)
926 			*ptr = (char*)str;
927 		return(0);
928 	}
929 	errno = 0;
930 	d = number(str,&last,shp->inarith?0:10,NiL);
931 	if(*last)
932 	{
933 		if(*last!='.' || last[1]!='.')
934 		{
935 			d = strval(shp,str,&last,arith,mode);
936 			Varsubscript = true;
937 		}
938 		if(!ptr && *last && mode>0)
939 			errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
940 	}
941 	else if (!d && *str=='-')
942 		d = -0.0;
943 	if(ptr)
944 		*ptr = last;
945 	return(d);
946 }
947 
948 #undef sh_strnum
sh_strnum(register const char * str,char ** ptr,int mode)949 Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
950 {
951 	return(sh_strnum_20120720(sh_getinterp(),str,ptr,mode));
952 }
953 
954