1da2e3ebdSchin /***********************************************************************
2da2e3ebdSchin * *
3da2e3ebdSchin * This software is part of the ast package *
4*3e14f97fSRoger A. Faulkner * Copyright (c) 1982-2010 AT&T Intellectual Property *
5da2e3ebdSchin * and is licensed under the *
6da2e3ebdSchin * Common Public License, Version 1.0 *
77c2fbfb3SApril Chin * by AT&T Intellectual Property *
8da2e3ebdSchin * *
9da2e3ebdSchin * A copy of the License is available at *
10da2e3ebdSchin * http://www.opensource.org/licenses/cpl1.0.txt *
11da2e3ebdSchin * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12da2e3ebdSchin * *
13da2e3ebdSchin * Information and Software Systems Research *
14da2e3ebdSchin * AT&T Research *
15da2e3ebdSchin * Florham Park NJ *
16da2e3ebdSchin * *
17da2e3ebdSchin * David Korn <dgk@research.att.com> *
18da2e3ebdSchin * *
19da2e3ebdSchin ***********************************************************************/
20da2e3ebdSchin #pragma prototyped
21da2e3ebdSchin /*
22da2e3ebdSchin * Shell arithmetic - uses streval library
23da2e3ebdSchin * David Korn
24da2e3ebdSchin * AT&T Labs
25da2e3ebdSchin */
26da2e3ebdSchin
27da2e3ebdSchin #include "defs.h"
28da2e3ebdSchin #include "lexstates.h"
29da2e3ebdSchin #include "name.h"
30da2e3ebdSchin #include "streval.h"
31da2e3ebdSchin #include "variables.h"
32da2e3ebdSchin
33da2e3ebdSchin #ifndef LLONG_MAX
34da2e3ebdSchin #define LLONG_MAX LONG_MAX
35da2e3ebdSchin #endif
36da2e3ebdSchin
377c2fbfb3SApril Chin static Sfdouble_t NaN, Inf, Fun;
38da2e3ebdSchin static Namval_t Infnod =
39da2e3ebdSchin {
40da2e3ebdSchin { 0 },
41da2e3ebdSchin "Inf",
42da2e3ebdSchin NV_NOFREE|NV_LDOUBLE,NV_RDONLY
43da2e3ebdSchin };
44da2e3ebdSchin
45da2e3ebdSchin static Namval_t NaNnod =
46da2e3ebdSchin {
47da2e3ebdSchin { 0 },
48da2e3ebdSchin "NaN",
49da2e3ebdSchin NV_NOFREE|NV_LDOUBLE,NV_RDONLY
50da2e3ebdSchin };
51da2e3ebdSchin
527c2fbfb3SApril Chin static Namval_t FunNode =
537c2fbfb3SApril Chin {
547c2fbfb3SApril Chin { 0 },
557c2fbfb3SApril Chin "?",
567c2fbfb3SApril Chin NV_NOFREE|NV_LDOUBLE,NV_RDONLY
577c2fbfb3SApril Chin };
587c2fbfb3SApril Chin
scope(Shell_t * shp,register Namval_t * np,register struct lval * lvalue,int assign)597c2fbfb3SApril Chin static Namval_t *scope(Shell_t *shp,register Namval_t *np,register struct lval *lvalue,int assign)
60da2e3ebdSchin {
61da2e3ebdSchin register int flag = lvalue->flag;
627c2fbfb3SApril Chin register char *sub=0, *cp=(char*)np;
63da2e3ebdSchin register Namval_t *mp;
647c2fbfb3SApril Chin int flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET;
65*3e14f97fSRoger A. Faulkner int nosub = lvalue->nosub;
667c2fbfb3SApril Chin Dt_t *sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0);
6734f9b3eeSRoland Mainz Dt_t *root = shp->var_tree;
687c2fbfb3SApril Chin assign = assign?NV_ASSIGN:NV_NOASSIGN;
69*3e14f97fSRoger A. Faulkner lvalue->nosub = 0;
70da2e3ebdSchin if(cp>=lvalue->expr && cp < lvalue->expr+lvalue->elen)
71da2e3ebdSchin {
727c2fbfb3SApril Chin int offset;
737c2fbfb3SApril Chin /* do binding to node now */
74da2e3ebdSchin int c = cp[flag];
75da2e3ebdSchin cp[flag] = 0;
767c2fbfb3SApril Chin if((!(np = nv_open(cp,shp->var_tree,assign|NV_VARNAME|NV_NOADD|NV_NOFAIL)) || nv_isnull(np)) && sh_macfun(shp,cp, offset = staktell()))
777c2fbfb3SApril Chin {
787c2fbfb3SApril Chin Fun = sh_arith(sub=stakptr(offset));
797c2fbfb3SApril Chin FunNode.nvalue.ldp = &Fun;
807c2fbfb3SApril Chin cp[flag] = c;
817c2fbfb3SApril Chin return(&FunNode);
827c2fbfb3SApril Chin }
8334f9b3eeSRoland Mainz if(!np && assign)
847c2fbfb3SApril Chin np = nv_open(cp,shp->var_tree,assign|NV_VARNAME);
8534f9b3eeSRoland Mainz if(!np)
8634f9b3eeSRoland Mainz return(0);
8734f9b3eeSRoland Mainz root = shp->last_root;
88da2e3ebdSchin cp[flag] = c;
89da2e3ebdSchin if(cp[flag+1]=='[')
90da2e3ebdSchin flag++;
91da2e3ebdSchin else
92da2e3ebdSchin flag = 0;
937c2fbfb3SApril Chin cp = (char*)np;
94da2e3ebdSchin }
9534f9b3eeSRoland Mainz if((lvalue->emode&ARITH_COMP) && dtvnext(root) && ((mp=nv_search(cp,root,flags))||(sdict && (mp=nv_search(cp,sdict,flags)))))
96da2e3ebdSchin {
97da2e3ebdSchin while(nv_isref(mp))
98da2e3ebdSchin {
99da2e3ebdSchin sub = nv_refsub(mp);
100da2e3ebdSchin mp = nv_refnode(mp);
101da2e3ebdSchin }
102da2e3ebdSchin np = mp;
103da2e3ebdSchin }
104*3e14f97fSRoger A. Faulkner if(!nosub && (flag || sub))
105da2e3ebdSchin {
106da2e3ebdSchin if(!sub)
107da2e3ebdSchin sub = (char*)&lvalue->expr[flag];
108da2e3ebdSchin nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
109da2e3ebdSchin }
110da2e3ebdSchin return(np);
111da2e3ebdSchin }
112da2e3ebdSchin
arith(const char ** ptr,struct lval * lvalue,int type,Sfdouble_t n)113da2e3ebdSchin static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
114da2e3ebdSchin {
1157c2fbfb3SApril Chin Shell_t *shp = &sh;
116da2e3ebdSchin register Sfdouble_t r= 0;
117da2e3ebdSchin char *str = (char*)*ptr;
1187c2fbfb3SApril Chin register char *cp;
119da2e3ebdSchin switch(type)
120da2e3ebdSchin {
121da2e3ebdSchin case ASSIGN:
122da2e3ebdSchin {
123da2e3ebdSchin register Namval_t *np = (Namval_t*)(lvalue->value);
1247c2fbfb3SApril Chin np = scope(shp,np,lvalue,1);
125da2e3ebdSchin nv_putval(np, (char*)&n, NV_LDOUBLE);
126da2e3ebdSchin r=nv_getnum(np);
127*3e14f97fSRoger A. Faulkner lvalue->value = (char*)np;
128da2e3ebdSchin break;
129da2e3ebdSchin }
130da2e3ebdSchin case LOOKUP:
131da2e3ebdSchin {
132da2e3ebdSchin register int c = *str;
133da2e3ebdSchin register char *xp=str;
134da2e3ebdSchin lvalue->value = (char*)0;
135da2e3ebdSchin if(c=='.')
136da2e3ebdSchin str++;
137da2e3ebdSchin c = mbchar(str);
138da2e3ebdSchin if(isaletter(c))
139da2e3ebdSchin {
140da2e3ebdSchin register Namval_t *np;
141da2e3ebdSchin int dot=0;
142da2e3ebdSchin while(1)
143da2e3ebdSchin {
144da2e3ebdSchin while(xp=str, c=mbchar(str), isaname(c));
145da2e3ebdSchin str = xp;
1467c2fbfb3SApril Chin if(c=='[' && dot==NV_NOADD)
1477c2fbfb3SApril Chin {
1487c2fbfb3SApril Chin str = nv_endsubscript((Namval_t*)0,str,0);
1497c2fbfb3SApril Chin c = *str;
1507c2fbfb3SApril Chin }
151da2e3ebdSchin if(c!='.')
152da2e3ebdSchin break;
1537c2fbfb3SApril Chin dot=NV_NOADD;
154da2e3ebdSchin if((c = *++str) !='[')
155da2e3ebdSchin continue;
156da2e3ebdSchin str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
157da2e3ebdSchin if(sh_checkid(cp+1,(char*)0))
158da2e3ebdSchin str -=2;
159da2e3ebdSchin }
160da2e3ebdSchin if(c=='(')
161da2e3ebdSchin {
162da2e3ebdSchin int fsize = str- (char*)(*ptr);
163da2e3ebdSchin const struct mathtab *tp;
164da2e3ebdSchin c = **ptr;
165da2e3ebdSchin lvalue->fun = 0;
166da2e3ebdSchin if(fsize<=(sizeof(tp->fname)-2)) for(tp=shtab_math; *tp->fname; tp++)
167da2e3ebdSchin {
168da2e3ebdSchin if(*tp->fname > c)
169da2e3ebdSchin break;
170da2e3ebdSchin if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],*ptr,fsize)==0)
171da2e3ebdSchin {
172da2e3ebdSchin lvalue->fun = tp->fnptr;
173da2e3ebdSchin lvalue->nargs = *tp->fname;
174da2e3ebdSchin break;
175da2e3ebdSchin }
176da2e3ebdSchin }
177da2e3ebdSchin if(lvalue->fun)
178da2e3ebdSchin break;
179da2e3ebdSchin lvalue->value = (char*)ERROR_dictionary(e_function);
180da2e3ebdSchin return(r);
181da2e3ebdSchin }
182da2e3ebdSchin if((lvalue->emode&ARITH_COMP) && dot)
183da2e3ebdSchin {
184da2e3ebdSchin lvalue->value = (char*)*ptr;
185da2e3ebdSchin lvalue->flag = str-lvalue->value;
186da2e3ebdSchin break;
187da2e3ebdSchin }
188da2e3ebdSchin *str = 0;
189da2e3ebdSchin if(sh_isoption(SH_NOEXEC))
190da2e3ebdSchin np = L_ARGNOD;
191da2e3ebdSchin else
192da2e3ebdSchin {
193da2e3ebdSchin int offset = staktell();
194da2e3ebdSchin char *saveptr = stakfreeze(0);
1957c2fbfb3SApril Chin Dt_t *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree;
196da2e3ebdSchin *str = c;
197da2e3ebdSchin while(c=='[' || c=='.')
198da2e3ebdSchin {
199da2e3ebdSchin if(c=='[')
200da2e3ebdSchin {
201da2e3ebdSchin str = nv_endsubscript(np,cp=str,0);
202da2e3ebdSchin if((c= *str)!='[' && c!='.')
203da2e3ebdSchin {
204da2e3ebdSchin str = cp;
205da2e3ebdSchin c = '[';
206da2e3ebdSchin break;
207da2e3ebdSchin }
208da2e3ebdSchin }
209da2e3ebdSchin else
210da2e3ebdSchin {
2117c2fbfb3SApril Chin dot = NV_NOADD|NV_NOFAIL;
212da2e3ebdSchin str++;
213da2e3ebdSchin while(xp=str, c=mbchar(str), isaname(c));
214da2e3ebdSchin str = xp;
215da2e3ebdSchin }
216da2e3ebdSchin }
217da2e3ebdSchin *str = 0;
2187c2fbfb3SApril Chin cp = (char*)*ptr;
2197c2fbfb3SApril Chin if ((cp[0] == 'i' || cp[0] == 'I') && (cp[1] == 'n' || cp[1] == 'N') && (cp[2] == 'f' || cp[2] == 'F') && cp[3] == 0)
220da2e3ebdSchin {
2217c2fbfb3SApril Chin Inf = strtold("Inf", NiL);
222da2e3ebdSchin Infnod.nvalue.ldp = &Inf;
223da2e3ebdSchin np = &Infnod;
224da2e3ebdSchin }
2257c2fbfb3SApril Chin else if ((cp[0] == 'n' || cp[0] == 'N') && (cp[1] == 'a' || cp[1] == 'A') && (cp[2] == 'n' || cp[2] == 'N') && cp[3] == 0)
226da2e3ebdSchin {
2277c2fbfb3SApril Chin NaN = strtold("NaN", NiL);
228da2e3ebdSchin NaNnod.nvalue.ldp = &NaN;
229da2e3ebdSchin np = &NaNnod;
230da2e3ebdSchin }
2317c2fbfb3SApril Chin else if(!(np = nv_open(*ptr,root,NV_NOASSIGN|NV_VARNAME|dot)))
2327c2fbfb3SApril Chin {
2337c2fbfb3SApril Chin lvalue->value = (char*)*ptr;
2347c2fbfb3SApril Chin lvalue->flag = str-lvalue->value;
2357c2fbfb3SApril Chin }
236da2e3ebdSchin if(saveptr != stakptr(0))
237da2e3ebdSchin stakset(saveptr,offset);
238da2e3ebdSchin else
239da2e3ebdSchin stakseek(offset);
240da2e3ebdSchin }
241da2e3ebdSchin *str = c;
2427c2fbfb3SApril Chin if(!np && lvalue->value)
2437c2fbfb3SApril Chin break;
244da2e3ebdSchin lvalue->value = (char*)np;
245da2e3ebdSchin /* bind subscript later */
24634f9b3eeSRoland Mainz if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
24734f9b3eeSRoland Mainz lvalue->isfloat=1;
248da2e3ebdSchin lvalue->flag = 0;
249da2e3ebdSchin if(c=='[')
250da2e3ebdSchin {
251da2e3ebdSchin lvalue->flag = (str-lvalue->expr);
252da2e3ebdSchin do
253da2e3ebdSchin str = nv_endsubscript(np,str,0);
254da2e3ebdSchin while((c= *str)=='[');
255da2e3ebdSchin break;
256da2e3ebdSchin }
257da2e3ebdSchin }
258da2e3ebdSchin else
259da2e3ebdSchin {
260da2e3ebdSchin char lastbase=0, *val = xp, oerrno = errno;
261da2e3ebdSchin errno = 0;
262da2e3ebdSchin r = strtonll(val,&str, &lastbase,-1);
263da2e3ebdSchin if(*str=='8' || *str=='9')
264da2e3ebdSchin {
265da2e3ebdSchin lastbase=10;
266da2e3ebdSchin errno = 0;
267da2e3ebdSchin r = strtonll(val,&str, &lastbase,-1);
268da2e3ebdSchin }
269da2e3ebdSchin if(lastbase<=1)
270da2e3ebdSchin lastbase=10;
271da2e3ebdSchin if(*val=='0')
272da2e3ebdSchin {
273da2e3ebdSchin while(*val=='0')
274da2e3ebdSchin val++;
275da2e3ebdSchin if(*val==0 || *val=='.' || *val=='x' || *val=='X')
276da2e3ebdSchin val--;
277da2e3ebdSchin }
278da2e3ebdSchin if(r==LLONG_MAX && errno)
279da2e3ebdSchin c='e';
280da2e3ebdSchin else
281da2e3ebdSchin c = *str;
2827c2fbfb3SApril Chin if(c==GETDECIMAL(0) || c=='e' || c == 'E' || lastbase ==
2837c2fbfb3SApril Chin 16 && (c == 'p' || c == 'P'))
284da2e3ebdSchin {
285da2e3ebdSchin lvalue->isfloat=1;
286da2e3ebdSchin r = strtold(val,&str);
287da2e3ebdSchin }
288da2e3ebdSchin else if(lastbase==10 && val[1])
289da2e3ebdSchin {
290da2e3ebdSchin if(val[2]=='#')
291da2e3ebdSchin val += 3;
292da2e3ebdSchin if((str-val)>2*sizeof(Sflong_t))
293da2e3ebdSchin {
294da2e3ebdSchin Sfdouble_t rr;
295da2e3ebdSchin rr = strtold(val,&str);
296da2e3ebdSchin if(rr!=r)
297da2e3ebdSchin {
298da2e3ebdSchin r = rr;
299da2e3ebdSchin lvalue->isfloat=1;
300da2e3ebdSchin }
301da2e3ebdSchin }
302da2e3ebdSchin }
303da2e3ebdSchin errno = oerrno;
304da2e3ebdSchin }
305da2e3ebdSchin break;
306da2e3ebdSchin }
307da2e3ebdSchin case VALUE:
308da2e3ebdSchin {
309da2e3ebdSchin register Namval_t *np = (Namval_t*)(lvalue->value);
310da2e3ebdSchin if(sh_isoption(SH_NOEXEC))
311da2e3ebdSchin return(0);
3127c2fbfb3SApril Chin np = scope(shp,np,lvalue,0);
31334f9b3eeSRoland Mainz if(!np)
31434f9b3eeSRoland Mainz {
31534f9b3eeSRoland Mainz if(sh_isoption(SH_NOUNSET))
31634f9b3eeSRoland Mainz {
31734f9b3eeSRoland Mainz *ptr = lvalue->value;
31834f9b3eeSRoland Mainz goto skip;
31934f9b3eeSRoland Mainz }
32034f9b3eeSRoland Mainz return(0);
32134f9b3eeSRoland Mainz }
322da2e3ebdSchin if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
323da2e3ebdSchin {
324da2e3ebdSchin *ptr = nv_name(np);
32534f9b3eeSRoland Mainz skip:
326da2e3ebdSchin lvalue->value = (char*)ERROR_dictionary(e_notset);
327da2e3ebdSchin lvalue->emode |= 010;
328da2e3ebdSchin return(0);
329da2e3ebdSchin }
330da2e3ebdSchin r = nv_getnum(np);
331da2e3ebdSchin if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
332da2e3ebdSchin lvalue->isfloat= (r!=(Sflong_t)r);
3337c2fbfb3SApril Chin else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
334da2e3ebdSchin lvalue->isfloat=1;
335da2e3ebdSchin return(r);
336da2e3ebdSchin }
337da2e3ebdSchin
338da2e3ebdSchin case MESSAGE:
339da2e3ebdSchin sfsync(NIL(Sfio_t*));
340da2e3ebdSchin #if 0
341da2e3ebdSchin if(warn)
342da2e3ebdSchin errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
343da2e3ebdSchin else
344da2e3ebdSchin #endif
345da2e3ebdSchin errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
346da2e3ebdSchin }
347da2e3ebdSchin *ptr = str;
348da2e3ebdSchin return(r);
349da2e3ebdSchin }
350da2e3ebdSchin
351da2e3ebdSchin /*
352da2e3ebdSchin * convert number defined by string to a Sfdouble_t
353da2e3ebdSchin * ptr is set to the last character processed
354da2e3ebdSchin * if mode>0, an error will be fatal with value <mode>
355da2e3ebdSchin */
356da2e3ebdSchin
sh_strnum(register const char * str,char ** ptr,int mode)357da2e3ebdSchin Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
358da2e3ebdSchin {
359da2e3ebdSchin register Sfdouble_t d;
360da2e3ebdSchin char base=0, *last;
361da2e3ebdSchin if(*str==0)
362da2e3ebdSchin {
363da2e3ebdSchin if(ptr)
364da2e3ebdSchin *ptr = (char*)str;
365da2e3ebdSchin return(0);
366da2e3ebdSchin }
367da2e3ebdSchin errno = 0;
368da2e3ebdSchin d = strtonll(str,&last,&base,-1);
369da2e3ebdSchin if(*last || errno)
370da2e3ebdSchin {
3717c2fbfb3SApril Chin if(!last || *last!='.' || last[1]!='.')
372da2e3ebdSchin d = strval(str,&last,arith,mode);
373da2e3ebdSchin if(!ptr && *last && mode>0)
374da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
375da2e3ebdSchin }
3767c2fbfb3SApril Chin else if (!d && *str=='-')
3777c2fbfb3SApril Chin d = -0.0;
378da2e3ebdSchin if(ptr)
379da2e3ebdSchin *ptr = last;
380da2e3ebdSchin return(d);
381da2e3ebdSchin }
382da2e3ebdSchin
sh_arith(register const char * str)383da2e3ebdSchin Sfdouble_t sh_arith(register const char *str)
384da2e3ebdSchin {
385da2e3ebdSchin return(sh_strnum(str, (char**)0, 1));
386da2e3ebdSchin }
387da2e3ebdSchin
sh_arithcomp(register char * str)388da2e3ebdSchin void *sh_arithcomp(register char *str)
389da2e3ebdSchin {
390da2e3ebdSchin const char *ptr = str;
391da2e3ebdSchin Arith_t *ep;
392da2e3ebdSchin ep = arith_compile(str,(char**)&ptr,arith,ARITH_COMP|1);
393da2e3ebdSchin if(*ptr)
394da2e3ebdSchin errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
395da2e3ebdSchin return((void*)ep);
396da2e3ebdSchin }
397