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