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