1 /***********************************************************************
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 *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * Shell arithmetic - uses streval library
28 #include "lexstates.h"
31 #include "variables.h"
34 #define LLONG_MAX LONG_MAX
37 static Sfdouble_t NaN
, Inf
, Fun
;
38 static Namval_t Infnod
=
42 NV_NOFREE
|NV_LDOUBLE
,NV_RDONLY
45 static Namval_t NaNnod
=
49 NV_NOFREE
|NV_LDOUBLE
,NV_RDONLY
52 static Namval_t FunNode
=
56 NV_NOFREE
|NV_LDOUBLE
,NV_RDONLY
59 static Namval_t
*scope(Shell_t
*shp
,register Namval_t
*np
,register struct lval
*lvalue
,int assign
)
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
;
70 if(cp
>=lvalue
->expr
&& cp
< lvalue
->expr
+lvalue
->elen
)
73 /* do binding to node now */
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()))
78 Fun
= sh_arith(sub
=stakptr(offset
));
79 FunNode
.nvalue
.ldp
= &Fun
;
84 np
= nv_open(cp
,shp
->var_tree
,assign
|NV_VARNAME
);
87 root
= shp
->last_root
;
95 if((lvalue
->emode
&ARITH_COMP
) && dtvnext(root
) && ((mp
=nv_search(cp
,root
,flags
))||(sdict
&& (mp
=nv_search(cp
,sdict
,flags
)))))
104 if(!nosub
&& (flag
|| sub
))
107 sub
= (char*)&lvalue
->expr
[flag
];
108 nv_endsubscript(np
,sub
,NV_ADD
|NV_SUBQUOTE
);
113 static Sfdouble_t
arith(const char **ptr
, struct lval
*lvalue
, int type
, Sfdouble_t n
)
116 register Sfdouble_t r
= 0;
117 char *str
= (char*)*ptr
;
123 register Namval_t
*np
= (Namval_t
*)(lvalue
->value
);
124 np
= scope(shp
,np
,lvalue
,1);
125 nv_putval(np
, (char*)&n
, NV_LDOUBLE
);
127 lvalue
->value
= (char*)np
;
132 register int c
= *str
;
133 register char *xp
=str
;
134 lvalue
->value
= (char*)0;
140 register Namval_t
*np
;
144 while(xp
=str
, c
=mbchar(str
), isaname(c
));
146 if(c
=='[' && dot
==NV_NOADD
)
148 str
= nv_endsubscript((Namval_t
*)0,str
,0);
154 if((c
= *++str
) !='[')
156 str
= nv_endsubscript((Namval_t
*)0,cp
=str
,NV_SUBQUOTE
)-1;
157 if(sh_checkid(cp
+1,(char*)0))
162 int fsize
= str
- (char*)(*ptr
);
163 const struct mathtab
*tp
;
166 if(fsize
<=(sizeof(tp
->fname
)-2)) for(tp
=shtab_math
; *tp
->fname
; tp
++)
170 if(tp
->fname
[1]==c
&& tp
->fname
[fsize
+1]==0 && strncmp(&tp
->fname
[1],*ptr
,fsize
)==0)
172 lvalue
->fun
= tp
->fnptr
;
173 lvalue
->nargs
= *tp
->fname
;
179 lvalue
->value
= (char*)ERROR_dictionary(e_function
);
182 if((lvalue
->emode
&ARITH_COMP
) && dot
)
184 lvalue
->value
= (char*)*ptr
;
185 lvalue
->flag
= str
-lvalue
->value
;
189 if(sh_isoption(SH_NOEXEC
))
193 int offset
= staktell();
194 char *saveptr
= stakfreeze(0);
195 Dt_t
*root
= (lvalue
->emode
&ARITH_COMP
)?shp
->var_base
:shp
->var_tree
;
197 while(c
=='[' || c
=='.')
201 str
= nv_endsubscript(np
,cp
=str
,0);
202 if((c
= *str
)!='[' && c
!='.')
211 dot
= NV_NOADD
|NV_NOFAIL
;
213 while(xp
=str
, c
=mbchar(str
), isaname(c
));
219 if ((cp
[0] == 'i' || cp
[0] == 'I') && (cp
[1] == 'n' || cp
[1] == 'N') && (cp
[2] == 'f' || cp
[2] == 'F') && cp
[3] == 0)
221 Inf
= strtold("Inf", NiL
);
222 Infnod
.nvalue
.ldp
= &Inf
;
225 else if ((cp
[0] == 'n' || cp
[0] == 'N') && (cp
[1] == 'a' || cp
[1] == 'A') && (cp
[2] == 'n' || cp
[2] == 'N') && cp
[3] == 0)
227 NaN
= strtold("NaN", NiL
);
228 NaNnod
.nvalue
.ldp
= &NaN
;
231 else if(!(np
= nv_open(*ptr
,root
,NV_NOASSIGN
|NV_VARNAME
|dot
)))
233 lvalue
->value
= (char*)*ptr
;
234 lvalue
->flag
= str
-lvalue
->value
;
236 if(saveptr
!= stakptr(0))
237 stakset(saveptr
,offset
);
242 if(!np
&& lvalue
->value
)
244 lvalue
->value
= (char*)np
;
245 /* bind subscript later */
246 if(nv_isattr(np
,NV_DOUBLE
)==NV_DOUBLE
)
251 lvalue
->flag
= (str
-lvalue
->expr
);
253 str
= nv_endsubscript(np
,str
,0);
254 while((c
= *str
)=='[');
260 char lastbase
=0, *val
= xp
, oerrno
= errno
;
262 r
= strtonll(val
,&str
, &lastbase
,-1);
263 if(*str
=='8' || *str
=='9')
267 r
= strtonll(val
,&str
, &lastbase
,-1);
275 if(*val
==0 || *val
=='.' || *val
=='x' || *val
=='X')
278 if(r
==LLONG_MAX
&& errno
)
282 if(c
==GETDECIMAL(0) || c
=='e' || c
== 'E' || lastbase
==
283 16 && (c
== 'p' || c
== 'P'))
286 r
= strtold(val
,&str
);
288 else if(lastbase
==10 && val
[1])
292 if((str
-val
)>2*sizeof(Sflong_t
))
295 rr
= strtold(val
,&str
);
309 register Namval_t
*np
= (Namval_t
*)(lvalue
->value
);
310 if(sh_isoption(SH_NOEXEC
))
312 np
= scope(shp
,np
,lvalue
,0);
315 if(sh_isoption(SH_NOUNSET
))
317 *ptr
= lvalue
->value
;
322 if(((lvalue
->emode
&2) || lvalue
->level
>1 || sh_isoption(SH_NOUNSET
)) && nv_isnull(np
) && !nv_isattr(np
,NV_INTEGER
))
326 lvalue
->value
= (char*)ERROR_dictionary(e_notset
);
327 lvalue
->emode
|= 010;
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
)
339 sfsync(NIL(Sfio_t
*));
342 errormsg(SH_DICT
,ERROR_warn(0),lvalue
->value
,*ptr
);
345 errormsg(SH_DICT
,ERROR_exit((lvalue
->emode
&3)!=0),lvalue
->value
,*ptr
);
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>
357 Sfdouble_t
sh_strnum(register const char *str
, char** ptr
, int mode
)
359 register Sfdouble_t d
;
368 d
= strtonll(str
,&last
,&base
,-1);
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
);
376 else if (!d
&& *str
=='-')
383 Sfdouble_t
sh_arith(register const char *str
)
385 return(sh_strnum(str
, (char**)0, 1));
388 void *sh_arithcomp(register char *str
)
390 const char *ptr
= str
;
392 ep
= arith_compile(str
,(char**)&ptr
,arith
,ARITH_COMP
|1);
394 errormsg(SH_DICT
,ERROR_exit(1),e_lexbadchar
,*ptr
,str
);