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