Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/cmd/ksh93/sh/arith.c
1810 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1982-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* David Korn <[email protected]> *
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
#include "builtins.h"
33
34
#ifndef LLONG_MAX
35
#define LLONG_MAX LONG_MAX
36
#endif
37
38
typedef Sfdouble_t (*Math_f)(Sfdouble_t, ...);
39
40
extern const Namdisc_t ENUM_disc;
41
static Sfdouble_t NaN, Inf, Fun;
42
static Namval_t Infnod =
43
{
44
{ 0 },
45
"Inf",
46
};
47
48
static Namval_t NaNnod =
49
{
50
{ 0 },
51
"NaN",
52
};
53
54
static Namval_t FunNode =
55
{
56
{ 0 },
57
"?",
58
};
59
60
static Namval_t *scope(register Namval_t *np,register struct lval *lvalue,int assign)
61
{
62
register int flag = lvalue->flag;
63
register char *sub=0, *cp=(char*)np;
64
register Namval_t *mp;
65
Shell_t *shp = lvalue->shp;
66
int flags = HASH_NOSCOPE|HASH_SCOPE|HASH_BUCKET;
67
int c=0,nosub = lvalue->nosub;
68
Dt_t *sdict = (shp->st.real_fun? shp->st.real_fun->sdict:0);
69
Dt_t *nsdict = (shp->namespace?nv_dict(shp->namespace):0);
70
Dt_t *root = shp->var_tree;
71
assign = assign?NV_ASSIGN:NV_NOASSIGN;
72
lvalue->nosub = 0;
73
if(nosub<0 && lvalue->ovalue)
74
return((Namval_t*)lvalue->ovalue);
75
lvalue->ovalue = 0;
76
if(cp>=lvalue->expr && cp < lvalue->expr+lvalue->elen)
77
{
78
int offset;
79
/* do binding to node now */
80
int c = cp[flag];
81
cp[flag] = 0;
82
if((!(np = nv_open(cp,shp->var_tree,assign|NV_VARNAME|NV_NOADD|NV_NOFAIL)) || nv_isnull(np)) && sh_macfun(shp,cp, offset = staktell()))
83
{
84
Fun = sh_arith(shp,sub=stakptr(offset));
85
FunNode.nvalue.ldp = &Fun;
86
nv_onattr(&FunNode,NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
87
cp[flag] = c;
88
return(&FunNode);
89
}
90
if(!np && assign)
91
np = nv_open(cp,shp->var_tree,assign|NV_VARNAME);
92
cp[flag] = c;
93
if(!np)
94
return(0);
95
root = shp->last_root;
96
if(cp[flag+1]=='[')
97
flag++;
98
else
99
flag = 0;
100
cp = (char*)np;
101
}
102
else if(assign==NV_ASSIGN && nv_isnull(np) && !nv_isattr(np, ~(NV_MINIMAL|NV_NOFREE)))
103
flags |= NV_ADD;
104
if((lvalue->emode&ARITH_COMP) && dtvnext(root) && ((sdict && (mp=nv_search(cp,sdict,flags&~NV_ADD))) || (mp=nv_search(cp,root,flags&~(NV_ADD))) || (nsdict && (mp=nv_search(cp,nsdict,flags&~(NV_ADD|HASH_NOSCOPE)))) ))
105
np = mp;
106
while(nv_isref(np))
107
{
108
#if SHOPT_FIXEDARRAY
109
int n,dim;
110
dim = nv_refdimen(np);
111
n = nv_refindex(np);
112
#endif /* SHOPT_FIXEDARRAY */
113
sub = nv_refsub(np);
114
np = nv_refnode(np);
115
#if SHOPT_FIXEDARRAY
116
if(n)
117
{
118
Namarr_t *ap = nv_arrayptr(np);
119
ap->nelem = dim;
120
nv_putsub(np,(char*)0,n);
121
}
122
else
123
#endif /* SHOPT_FIXEDARRAY */
124
if(sub)
125
nv_putsub(np,sub,assign==NV_ASSIGN?ARRAY_ADD:0);
126
}
127
if(!nosub && flag)
128
{
129
int hasdot = 0;
130
cp = (char*)&lvalue->expr[flag];
131
if(sub)
132
{
133
goto skip;
134
}
135
sub = cp;
136
while(1)
137
{
138
Namarr_t *ap;
139
Namval_t *nq;
140
cp = nv_endsubscript(np,cp,0);
141
if(c || *cp=='.')
142
{
143
c = '.';
144
while(*cp=='.')
145
{
146
hasdot=1;
147
cp++;
148
while(c=mbchar(cp),isaname(c));
149
}
150
if(c=='[')
151
continue;
152
}
153
flag = *cp;
154
*cp = 0;
155
if(c || hasdot)
156
{
157
sfprintf(shp->strbuf,"%s%s%c",nv_name(np),sub,0);
158
sub = sfstruse(shp->strbuf);
159
}
160
if(strchr(sub,'$'))
161
sub = sh_mactrim(shp,sub,0);
162
*cp = flag;
163
if(c || hasdot)
164
{
165
np = nv_open(sub,shp->var_tree,NV_VARNAME|assign);
166
return(np);
167
}
168
#if SHOPT_FIXEDARRAY
169
ap = nv_arrayptr(np);
170
cp = nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE|(ap&&ap->fixed?NV_FARRAY:0));
171
#else
172
cp = nv_endsubscript(np,sub,NV_ADD|NV_SUBQUOTE);
173
#endif /* SHOPT_FIXEDARRAY */
174
if(*cp!='[')
175
break;
176
skip:
177
if(nq = nv_opensub(np))
178
np = nq;
179
else
180
{
181
ap = nv_arrayptr(np);
182
if(ap && !ap->table)
183
ap->table = dtopen(&_Nvdisc,Dtoset);
184
if(ap && ap->table && (nq=nv_search(nv_getsub(np),ap->table,NV_ADD)))
185
nq->nvenv = (char*)np;
186
if(nq && nv_isnull(nq))
187
np = nv_arraychild(np,nq,0);
188
}
189
sub = cp;
190
}
191
}
192
else if(nosub>0)
193
nv_putsub(np,(char*)0,nosub-1);
194
return(np);
195
}
196
197
static Math_f sh_mathstdfun(const char *fname, size_t fsize, short * nargs)
198
{
199
register const struct mathtab *tp;
200
register char c = fname[0];
201
for(tp=shtab_math; *tp->fname; tp++)
202
{
203
if(*tp->fname > c)
204
break;
205
if(tp->fname[1]==c && tp->fname[fsize+1]==0 && strncmp(&tp->fname[1],fname,fsize)==0)
206
{
207
if(nargs)
208
*nargs = *tp->fname;
209
return(tp->fnptr);
210
}
211
}
212
return(0);
213
}
214
215
int sh_mathstd(const char *name)
216
{
217
return(sh_mathstdfun(name,strlen(name),NULL)!=0);
218
}
219
220
static Sfdouble_t arith(const char **ptr, struct lval *lvalue, int type, Sfdouble_t n)
221
{
222
Shell_t *shp = lvalue->shp;
223
register Sfdouble_t r= 0;
224
char *str = (char*)*ptr;
225
register char *cp;
226
switch(type)
227
{
228
case ASSIGN:
229
{
230
register Namval_t *np = (Namval_t*)(lvalue->value);
231
np = scope(np,lvalue,1);
232
nv_putval(np, (char*)&n, NV_LDOUBLE);
233
if(lvalue->eflag)
234
lvalue->ptr = (void*)nv_hasdisc(np,&ENUM_disc);
235
lvalue->eflag = 0;
236
r=nv_getnum(np);
237
lvalue->value = (char*)np;
238
break;
239
}
240
case LOOKUP:
241
{
242
register int c = *str;
243
register char *xp=str;
244
lvalue->value = (char*)0;
245
if(c=='.')
246
str++;
247
c = mbchar(str);
248
if(isaletter(c))
249
{
250
register Namval_t *np;
251
int dot=0;
252
while(1)
253
{
254
while(xp=str, c=mbchar(str), isaname(c));
255
str = xp;
256
while(c=='[' && dot==NV_NOADD)
257
{
258
str = nv_endsubscript((Namval_t*)0,str,0);
259
c = *str;
260
}
261
if(c!='.')
262
break;
263
dot=NV_NOADD;
264
if((c = *++str) !='[')
265
continue;
266
str = nv_endsubscript((Namval_t*)0,cp=str,NV_SUBQUOTE)-1;
267
if(sh_checkid(cp+1,(char*)0))
268
str -=2;
269
}
270
if(c=='(')
271
{
272
int off=stktell(shp->stk);
273
int fsize = str- (char*)(*ptr);
274
const struct mathtab *tp;
275
Namval_t *np;
276
c = **ptr;
277
lvalue->fun = 0;
278
sfprintf(shp->stk,".sh.math.%.*s%c",fsize,*ptr,0);
279
stkseek(shp->stk,off);
280
if(np=nv_search(stkptr(shp->stk,off),shp->fun_tree,0))
281
{
282
lvalue->nargs = -np->nvalue.rp->argc;
283
lvalue->fun = (Math_f)np;
284
break;
285
}
286
if(fsize<=(sizeof(tp->fname)-2))
287
lvalue->fun = (Math_f)sh_mathstdfun(*ptr,fsize,&lvalue->nargs);
288
if(lvalue->fun)
289
break;
290
if(lvalue->emode&ARITH_COMP)
291
lvalue->value = (char*)e_function;
292
else
293
lvalue->value = (char*)ERROR_dictionary(e_function);
294
return(r);
295
}
296
if((lvalue->emode&ARITH_COMP) && dot)
297
{
298
lvalue->value = (char*)*ptr;
299
lvalue->flag = str-lvalue->value;
300
break;
301
}
302
*str = 0;
303
if(sh_isoption(SH_NOEXEC))
304
np = L_ARGNOD;
305
else
306
{
307
int offset = staktell();
308
char *saveptr = stakfreeze(0);
309
Dt_t *root = (lvalue->emode&ARITH_COMP)?shp->var_base:shp->var_tree;
310
*str = c;
311
cp = str;
312
while(c=='[' || c=='.')
313
{
314
if(c=='[')
315
{
316
str = nv_endsubscript(np,str,0);
317
if((c= *str)!='[' && c!='.')
318
{
319
str = cp;
320
c = '[';
321
break;
322
}
323
}
324
else
325
{
326
dot = NV_NOADD|NV_NOFAIL;
327
str++;
328
while(xp=str, c=mbchar(str), isaname(c));
329
str = xp;
330
}
331
}
332
*str = 0;
333
cp = (char*)*ptr;
334
if ((cp[0] == 'i' || cp[0] == 'I') && (cp[1] == 'n' || cp[1] == 'N') && (cp[2] == 'f' || cp[2] == 'F') && cp[3] == 0)
335
{
336
Inf = strtold("Inf", NiL);
337
Infnod.nvalue.ldp = &Inf;
338
np = &Infnod;
339
nv_onattr(np,NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
340
}
341
else if ((cp[0] == 'n' || cp[0] == 'N') && (cp[1] == 'a' || cp[1] == 'A') && (cp[2] == 'n' || cp[2] == 'N') && cp[3] == 0)
342
{
343
NaN = strtold("NaN", NiL);
344
NaNnod.nvalue.ldp = &NaN;
345
np = &NaNnod;
346
nv_onattr(np,NV_NOFREE|NV_LDOUBLE|NV_RDONLY);
347
}
348
else if(!(np = nv_open(*ptr,root,NV_NOREF|NV_NOASSIGN|NV_VARNAME|dot)))
349
{
350
lvalue->value = (char*)*ptr;
351
lvalue->flag = str-lvalue->value;
352
}
353
if(saveptr != stakptr(0))
354
stakset(saveptr,offset);
355
else
356
stakseek(offset);
357
}
358
*str = c;
359
if(!np && lvalue->value)
360
break;
361
lvalue->value = (char*)np;
362
/* bind subscript later */
363
if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
364
lvalue->isfloat=1;
365
lvalue->flag = 0;
366
if(c=='[')
367
{
368
lvalue->flag = (str-lvalue->expr);
369
do
370
{
371
while(c=='.')
372
{
373
str++;
374
while(xp=str, c=mbchar(str), isaname(c));
375
c = *(str = xp);
376
}
377
if(c=='[')
378
str = nv_endsubscript(np,str,0);
379
}
380
while((c= *str)=='[' || c=='.');
381
break;
382
}
383
}
384
else
385
{
386
char lastbase=0, *val = xp, oerrno = errno;
387
lvalue->eflag = 0;
388
errno = 0;
389
if(shp->bltindata.bnode==SYSLET && !sh_isoption(SH_LETOCTAL))
390
{
391
while(*val=='0' && isdigit(val[1]))
392
val++;
393
}
394
r = strtonll(val,&str, &lastbase,-1);
395
if(*str=='8' || *str=='9')
396
{
397
lastbase=10;
398
errno = 0;
399
r = strtonll(val,&str, &lastbase,-1);
400
}
401
if(lastbase<=1)
402
lastbase=10;
403
if(*val=='0')
404
{
405
while(*val=='0')
406
val++;
407
if(*val==0 || *val=='.' || *val=='x' || *val=='X')
408
val--;
409
}
410
if(r==LLONG_MAX && errno)
411
c='e';
412
else
413
c = *str;
414
if(c==GETDECIMAL(0) || c=='e' || c == 'E' || lastbase ==
415
16 && (c == 'p' || c == 'P'))
416
{
417
lvalue->isfloat=1;
418
r = strtold(val,&str);
419
}
420
else if(lastbase==10 && val[1])
421
{
422
if(val[2]=='#')
423
val += 3;
424
if((str-val)>2*sizeof(Sflong_t))
425
{
426
Sfdouble_t rr;
427
rr = strtold(val,&str);
428
if(rr!=r)
429
{
430
r = rr;
431
lvalue->isfloat=1;
432
}
433
}
434
}
435
errno = oerrno;
436
}
437
break;
438
}
439
case VALUE:
440
{
441
register Namval_t *np = (Namval_t*)(lvalue->value);
442
if(sh_isoption(SH_NOEXEC))
443
return(0);
444
np = scope(np,lvalue,0);
445
if(!np)
446
{
447
if(sh_isoption(SH_NOUNSET))
448
{
449
*ptr = lvalue->value;
450
goto skip;
451
}
452
return(0);
453
}
454
lvalue->ovalue = (char*)np;
455
if(lvalue->eflag)
456
lvalue->ptr = (void*)nv_hasdisc(np,&ENUM_disc);
457
else if((Namfun_t*)lvalue->ptr && !nv_hasdisc(np,&ENUM_disc) && !nv_isattr(np,NV_INTEGER))
458
{
459
Namval_t *mp,node;
460
mp = ((Namfun_t*)lvalue->ptr)->type;
461
memset(&node,0,sizeof(node));
462
nv_clone(mp,&node,0);
463
nv_offattr(&node,NV_RDONLY|NV_NOFREE);
464
nv_putval(&node,np->nvname,0);
465
if(nv_isattr(&node,NV_NOFREE))
466
return(r=nv_getnum(&node));
467
}
468
lvalue->eflag = 0;
469
if(((lvalue->emode&2) || lvalue->level>1 || sh_isoption(SH_NOUNSET)) && nv_isnull(np) && !nv_isattr(np,NV_INTEGER))
470
{
471
*ptr = nv_name(np);
472
skip:
473
lvalue->value = (char*)ERROR_dictionary(e_notset);
474
lvalue->emode |= 010;
475
return(0);
476
}
477
r = nv_getnum(np);
478
if(nv_isattr(np,NV_INTEGER|NV_BINARY)==(NV_INTEGER|NV_BINARY))
479
lvalue->isfloat= (r!=(Sflong_t)r);
480
else if(nv_isattr(np,NV_DOUBLE)==NV_DOUBLE)
481
lvalue->isfloat=1;
482
if((lvalue->emode&ARITH_ASSIGNOP) && nv_isarray(np))
483
lvalue->nosub = nv_aindex(np)+1;
484
return(r);
485
}
486
487
case MESSAGE:
488
sfsync(NIL(Sfio_t*));
489
#if 0
490
if(warn)
491
errormsg(SH_DICT,ERROR_warn(0),lvalue->value,*ptr);
492
else
493
#endif
494
if(lvalue->emode&ARITH_COMP)
495
return(-1);
496
497
errormsg(SH_DICT,ERROR_exit((lvalue->emode&3)!=0),lvalue->value,*ptr);
498
}
499
*ptr = str;
500
return(r);
501
}
502
503
/*
504
* convert number defined by string to a Sfdouble_t
505
* ptr is set to the last character processed
506
* if mode>0, an error will be fatal with value <mode>
507
*/
508
509
Sfdouble_t sh_strnum(register const char *str, char** ptr, int mode)
510
{
511
Shell_t *shp = sh_getinterp();
512
register Sfdouble_t d;
513
char base=(shp->inarith?0:10), *last;
514
if(*str==0)
515
{
516
if(ptr)
517
*ptr = (char*)str;
518
return(0);
519
}
520
errno = 0;
521
d = strtonll(str,&last,&base,-1);
522
if(*last || errno)
523
{
524
if(!last || *last!='.' || last[1]!='.')
525
d = strval(shp,str,&last,arith,mode);
526
if(!ptr && *last && mode>0)
527
errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*last,str);
528
}
529
else if (!d && *str=='-')
530
d = -0.0;
531
if(ptr)
532
*ptr = last;
533
return(d);
534
}
535
536
Sfdouble_t sh_arith(Shell_t *shp,register const char *str)
537
{
538
return(sh_strnum(str, (char**)0, 1));
539
}
540
541
void *sh_arithcomp(Shell_t *shp,register char *str)
542
{
543
const char *ptr = str;
544
Arith_t *ep;
545
ep = arith_compile(shp,str,(char**)&ptr,arith,ARITH_COMP|1);
546
if(*ptr)
547
errormsg(SH_DICT,ERROR_exit(1),e_lexbadchar,*ptr,str);
548
return((void*)ep);
549
}
550
551