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