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 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 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 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 3834887Schin Sfdouble_t sh_arith(register const char *str) 3844887Schin { 3854887Schin return(sh_strnum(str, (char**)0, 1)); 3864887Schin } 3874887Schin 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