14887Schin /*********************************************************************** 24887Schin * * 34887Schin * This software is part of the ast package * 4*8462SApril.Chin@Sun.COM * Copyright (c) 1982-2008 AT&T Intellectual Property * 54887Schin * and is licensed under the * 64887Schin * Common Public License, Version 1.0 * 7*8462SApril.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 <ctype.h> 294887Schin #include "lexstates.h" 304887Schin #include "name.h" 314887Schin #include "streval.h" 324887Schin #include "variables.h" 334887Schin 344887Schin #ifndef LLONG_MAX 354887Schin #define LLONG_MAX LONG_MAX 364887Schin #endif 374887Schin 38*8462SApril.Chin@Sun.COM static Sfdouble_t NaN, Inf, Fun; 394887Schin static Namval_t Infnod = 404887Schin { 414887Schin { 0 }, 424887Schin "Inf", 434887Schin NV_NOFREE|NV_LDOUBLE,NV_RDONLY 444887Schin }; 454887Schin 464887Schin static Namval_t NaNnod = 474887Schin { 484887Schin { 0 }, 494887Schin "NaN", 504887Schin NV_NOFREE|NV_LDOUBLE,NV_RDONLY 514887Schin }; 524887Schin 53*8462SApril.Chin@Sun.COM static Namval_t FunNode = 54*8462SApril.Chin@Sun.COM { 55*8462SApril.Chin@Sun.COM { 0 }, 56*8462SApril.Chin@Sun.COM "?", 57*8462SApril.Chin@Sun.COM NV_NOFREE|NV_LDOUBLE,NV_RDONLY 58*8462SApril.Chin@Sun.COM }; 59*8462SApril.Chin@Sun.COM 60*8462SApril.Chin@Sun.COM static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval *lvalue,int assign) 614887Schin { 624887Schin register Namarr_t *ap; 634887Schin register int flag = lvalue->flag; 64*8462SApril.Chin@Sun.COM register char *sub=0, *cp=(char*)np; 65*8462SApril.Chin@Sun.COM register Namval_t *mp; 66*8462SApril.Chin@Sun.COM int flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET; 67*8462SApril.Chin@Sun.COM Dt_t *sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0); 68*8462SApril.Chin@Sun.COM assign = assign?NV_ASSIGN:NV_NOASSIGN; 69*8462SApril.Chin@Sun.COM if(cp>=lvalue->expr && cp < lvalue->expr+lvalue->elen) 704887Schin { 71*8462SApril.Chin@Sun.COM int offset; 72*8462SApril.Chin@Sun.COM /* do binding to node now */ 73*8462SApril.Chin@Sun.COM int c = cp[flag]; 74*8462SApril.Chin@Sun.COM cp[flag] = 0; 75*8462SApril.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())) 764887Schin { 77*8462SApril.Chin@Sun.COM Fun = sh_arith(sub=stakptr(offset)); 78*8462SApril.Chin@Sun.COM FunNode.nvalue.ldp = &Fun; 794887Schin cp[flag] = c; 80*8462SApril.Chin@Sun.COM return(&FunNode); 814887Schin } 82*8462SApril.Chin@Sun.COM np = nv_open(cp,shp->var_tree,assign|NV_VARNAME); 83*8462SApril.Chin@Sun.COM cp[flag] = c; 84*8462SApril.Chin@Sun.COM if(cp[flag+1]=='[') 85*8462SApril.Chin@Sun.COM flag++; 86*8462SApril.Chin@Sun.COM else 87*8462SApril.Chin@Sun.COM flag = 0; 88*8462SApril.Chin@Sun.COM cp = (char*)np; 89*8462SApril.Chin@Sun.COM } 90*8462SApril.Chin@Sun.COM if((lvalue->emode&ARITH_COMP) && dtvnext(shp->var_tree) && ((mp=nv_search(cp,shp->var_tree,flags))||(sdict && (mp=nv_search(cp,sdict,flags))))) 91*8462SApril.Chin@Sun.COM { 92*8462SApril.Chin@Sun.COM while(nv_isref(mp)) 934887Schin { 94*8462SApril.Chin@Sun.COM sub = nv_refsub(mp); 95*8462SApril.Chin@Sun.COM mp = nv_refnode(mp); 964887Schin } 97*8462SApril.Chin@Sun.COM np = mp; 984887Schin } 994887Schin if(flag || sub) 1004887Schin { 1014887Schin if(!sub) 1024887Schin sub = (char*)&lvalue->expr[flag]; 1034887Schin if(((ap=nv_arrayptr(np)) && array_assoc(ap)) || (lvalue->emode&ARITH_COMP)) 1044887Schin nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE); 1054887Schin else 1064887Schin nv_putsub(np, NIL(char*),flag); 1074887Schin } 1084887Schin return(np); 1094887Schin } 1104887Schin 1114887Schin static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n) 1124887Schin { 113*8462SApril.Chin@Sun.COM Shell_t *shp = &sh; 1144887Schin register Sfdouble_t r= 0; 1154887Schin char *str = (char*)*ptr; 116*8462SApril.Chin@Sun.COM register char *cp; 1174887Schin switch(type) 1184887Schin { 1194887Schin case ASSIGN: 1204887Schin { 1214887Schin register Namval_t *np = (Namval_t*)(lvalue->value); 122*8462SApril.Chin@Sun.COM np = scope(shp,np,lvalue,1); 1234887Schin nv_putval(np, (char*)&n, NV_LDOUBLE); 1244887Schin r=nv_getnum(np); 1254887Schin break; 1264887Schin } 1274887Schin case LOOKUP: 1284887Schin { 1294887Schin register int c = *str; 1304887Schin register char *xp=str; 1314887Schin lvalue->value = (char*)0; 1324887Schin if(c=='.') 1334887Schin str++; 1344887Schin c = mbchar(str); 1354887Schin if(isaletter(c)) 1364887Schin { 1374887Schin register Namval_t *np; 1384887Schin int dot=0; 1394887Schin while(1) 1404887Schin { 1414887Schin while(xp=str, c=mbchar(str), isaname(c)); 1424887Schin str = xp; 143*8462SApril.Chin@Sun.COM if(c=='[' && dot==NV_NOADD) 144*8462SApril.Chin@Sun.COM { 145*8462SApril.Chin@Sun.COM str = nv_endsubscript((Namval_t*)0,str,0); 146*8462SApril.Chin@Sun.COM c = *str; 147*8462SApril.Chin@Sun.COM } 1484887Schin if(c!='.') 1494887Schin break; 150*8462SApril.Chin@Sun.COM dot=NV_NOADD; 1514887Schin if((c = *++str) !='[') 1524887Schin continue; 1534887Schin str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1; 1544887Schin if(sh_checkid(cp+1,(char*)0)) 1554887Schin str -=2; 1564887Schin } 1574887Schin if(c=='(') 1584887Schin { 1594887Schin int fsize = str- (char*)(*ptr); 1604887Schin const struct mathtab *tp; 1614887Schin c = **ptr; 1624887Schin lvalue->fun = 0; 1634887Schin if(fsize<=(sizeof(tp->fname)-2)) for(tp=shtab_math; *tp->fname; tp++) 1644887Schin { 1654887Schin if(*tp->fname > c) 1664887Schin break; 1674887Schin if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],*ptr,fsize)==0) 1684887Schin { 1694887Schin lvalue->fun = tp->fnptr; 1704887Schin lvalue->nargs = *tp->fname; 1714887Schin break; 1724887Schin } 1734887Schin } 1744887Schin if(lvalue->fun) 1754887Schin break; 1764887Schin lvalue->value = (char*)ERROR_dictionary(e_function); 1774887Schin return(r); 1784887Schin } 1794887Schin if((lvalue->emode&ARITH_COMP) && dot) 1804887Schin { 1814887Schin lvalue->value = (char*)*ptr; 1824887Schin lvalue->flag = str-lvalue->value; 1834887Schin break; 1844887Schin } 1854887Schin *str = 0; 1864887Schin if(sh_isoption(SH_NOEXEC)) 1874887Schin np = L_ARGNOD; 1884887Schin else 1894887Schin { 1904887Schin int offset = staktell(); 1914887Schin char *saveptr = stakfreeze(0); 192*8462SApril.Chin@Sun.COM Dt_t *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree; 1934887Schin *str = c; 1944887Schin while(c=='[' || c=='.') 1954887Schin { 1964887Schin if(c=='[') 1974887Schin { 1984887Schin str = nv_endsubscript(np,cp=str,0); 1994887Schin if((c= *str)!='[' && c!='.') 2004887Schin { 2014887Schin str = cp; 2024887Schin c = '['; 2034887Schin break; 2044887Schin } 2054887Schin } 2064887Schin else 2074887Schin { 208*8462SApril.Chin@Sun.COM dot = NV_NOADD|NV_NOFAIL; 2094887Schin str++; 2104887Schin while(xp=str, c=mbchar(str), isaname(c)); 2114887Schin str = xp; 2124887Schin } 2134887Schin } 2144887Schin *str = 0; 215*8462SApril.Chin@Sun.COM cp = (char*)*ptr; 216*8462SApril.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) 2174887Schin { 218*8462SApril.Chin@Sun.COM Inf = strtold("Inf", NiL); 2194887Schin Infnod.nvalue.ldp = &Inf; 2204887Schin np = &Infnod; 2214887Schin } 222*8462SApril.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) 2234887Schin { 224*8462SApril.Chin@Sun.COM NaN = strtold("NaN", NiL); 2254887Schin NaNnod.nvalue.ldp = &NaN; 2264887Schin np = &NaNnod; 2274887Schin } 228*8462SApril.Chin@Sun.COM else if(!(np = nv_open(*ptr,root,NV_NOASSIGN|NV_VARNAME|dot))) 229*8462SApril.Chin@Sun.COM { 230*8462SApril.Chin@Sun.COM lvalue->value = (char*)*ptr; 231*8462SApril.Chin@Sun.COM lvalue->flag = str-lvalue->value; 232*8462SApril.Chin@Sun.COM } 2334887Schin if(saveptr != stakptr(0)) 2344887Schin stakset(saveptr,offset); 2354887Schin else 2364887Schin stakseek(offset); 2374887Schin } 2384887Schin *str = c; 239*8462SApril.Chin@Sun.COM if(!np && lvalue->value) 240*8462SApril.Chin@Sun.COM break; 2414887Schin lvalue->value = (char*)np; 2424887Schin if((lvalue->emode&ARITH_COMP) || (nv_isarray(np) && nv_aindex(np)<0)) 2434887Schin { 2444887Schin /* bind subscript later */ 2454887Schin lvalue->flag = 0; 2464887Schin if(c=='[') 2474887Schin { 2484887Schin lvalue->flag = (str-lvalue->expr); 2494887Schin do 2504887Schin str = nv_endsubscript(np,str,0); 2514887Schin while((c= *str)=='['); 2524887Schin } 2534887Schin break; 2544887Schin } 2554887Schin if(c=='[') 2564887Schin { 2574887Schin do 2584887Schin str = nv_endsubscript(np,str,NV_ADD|NV_SUBQUOTE); 2594887Schin while((c=*str)=='['); 2604887Schin } 261*8462SApril.Chin@Sun.COM if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE) 2624887Schin lvalue->isfloat=1; 2634887Schin lvalue->flag = nv_aindex(np); 2644887Schin } 2654887Schin else 2664887Schin { 2674887Schin char lastbase=0, *val = xp, oerrno = errno; 2684887Schin errno = 0; 2694887Schin r = strtonll(val,&str, &lastbase,-1); 2704887Schin if(*str=='8' || *str=='9') 2714887Schin { 2724887Schin lastbase=10; 2734887Schin errno = 0; 2744887Schin r = strtonll(val,&str, &lastbase,-1); 2754887Schin } 2764887Schin if(lastbase<=1) 2774887Schin lastbase=10; 2784887Schin if(*val=='0') 2794887Schin { 2804887Schin while(*val=='0') 2814887Schin val++; 2824887Schin if(*val==0 || *val=='.' || *val=='x' || *val=='X') 2834887Schin val--; 2844887Schin } 2854887Schin if(r==LLONG_MAX && errno) 2864887Schin c='e'; 2874887Schin else 2884887Schin c = *str; 289*8462SApril.Chin@Sun.COM if(c==GETDECIMAL(0) || c=='e' || c == 'E' || lastbase == 290*8462SApril.Chin@Sun.COM 16 && (c == 'p' || c == 'P')) 2914887Schin { 2924887Schin lvalue->isfloat=1; 2934887Schin r = strtold(val,&str); 2944887Schin } 2954887Schin else if(lastbase==10 && val[1]) 2964887Schin { 2974887Schin if(val[2]=='#') 2984887Schin val += 3; 2994887Schin if((str-val)>2*sizeof(Sflong_t)) 3004887Schin { 3014887Schin Sfdouble_t rr; 3024887Schin rr = strtold(val,&str); 3034887Schin if(rr!=r) 3044887Schin { 3054887Schin r = rr; 3064887Schin lvalue->isfloat=1; 3074887Schin } 3084887Schin } 3094887Schin } 3104887Schin errno = oerrno; 3114887Schin } 3124887Schin break; 3134887Schin } 3144887Schin case VALUE: 3154887Schin { 3164887Schin register Namval_t *np = (Namval_t*)(lvalue->value); 3174887Schin if(sh_isoption(SH_NOEXEC)) 3184887Schin return(0); 319*8462SApril.Chin@Sun.COM np = scope(shp,np,lvalue,0); 3204887Schin if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER)) 3214887Schin { 3224887Schin *ptr = nv_name(np); 3234887Schin lvalue->value = (char*)ERROR_dictionary(e_notset); 3244887Schin lvalue->emode |= 010; 3254887Schin return(0); 3264887Schin } 3274887Schin r = nv_getnum(np); 3284887Schin if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY)) 3294887Schin lvalue->isfloat= (r!=(Sflong_t)r); 330*8462SApril.Chin@Sun.COM else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE) 3314887Schin lvalue->isfloat=1; 3324887Schin return(r); 3334887Schin } 3344887Schin 3354887Schin case MESSAGE: 3364887Schin sfsync(NIL(Sfio_t*)); 3374887Schin #if 0 3384887Schin if(warn) 3394887Schin errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr); 3404887Schin else 3414887Schin #endif 3424887Schin errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr); 3434887Schin } 3444887Schin *ptr = str; 3454887Schin return(r); 3464887Schin } 3474887Schin 3484887Schin /* 3494887Schin * convert number defined by string to a Sfdouble_t 3504887Schin * ptr is set to the last character processed 3514887Schin * if mode>0, an error will be fatal with value <mode> 3524887Schin */ 3534887Schin 3544887Schin Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode) 3554887Schin { 3564887Schin register Sfdouble_t d; 3574887Schin char base=0, *last; 3584887Schin if(*str==0) 3594887Schin { 3604887Schin if(ptr) 3614887Schin *ptr = (char*)str; 3624887Schin return(0); 3634887Schin } 3644887Schin errno = 0; 3654887Schin d = strtonll(str,&last,&base,-1); 3664887Schin if(*last || errno) 3674887Schin { 368*8462SApril.Chin@Sun.COM if(!last || *last!='.' || last[1]!='.') 369*8462SApril.Chin@Sun.COM d = strval(str,&last,arith,mode); 3704887Schin if(!ptr && *last && mode>0) 3714887Schin errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str); 3724887Schin } 373*8462SApril.Chin@Sun.COM else if (!d && *str=='-') 374*8462SApril.Chin@Sun.COM d = -0.0; 3754887Schin if(ptr) 3764887Schin *ptr = last; 3774887Schin return(d); 3784887Schin } 3794887Schin 3804887Schin Sfdouble_t sh_arith(register const char *str) 3814887Schin { 3824887Schin return(sh_strnum(str, (char**)0, 1)); 3834887Schin } 3844887Schin 3854887Schin void *sh_arithcomp(register char *str) 3864887Schin { 3874887Schin const char *ptr = str; 3884887Schin Arith_t *ep; 3894887Schin ep = arith_compile(str,(char**)&ptr,arith,ARITH_COMP|1); 3904887Schin if(*ptr) 3914887Schin errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str); 3924887Schin return((void*)ep); 3934887Schin } 394