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