26763: fix problem on failed cd -s to relative path
[zsh.git] / Src / Modules / mathfunc.c
blob04483b555512dc4cb6fad5e15def6bf9d2bce4e6
1 /*
2 * mathfunc.c - basic mathematical functions for use in math evaluations
4 * This file is part of zsh, the Z shell.
6 * Copyright (c) 1999 Peter Stephenson
7 * All rights reserved.
9 * Permission is hereby granted, without written agreement and without
10 * license or royalty fees, to use, copy, modify, and distribute this
11 * software and to distribute modified versions of this software for any
12 * purpose, provided that the above copyright notice and the following
13 * two paragraphs appear in all copies of this software.
15 * In no event shall Peter Stephenson or the Zsh Development Group be liable
16 * to any party for direct, indirect, special, incidental, or consequential
17 * damages arising out of the use of this software and its documentation,
18 * even if Peter Stephenson and the Zsh Development Group have been advised of
19 * the possibility of such damage.
21 * Peter Stephenson and the Zsh Development Group specifically disclaim any
22 * warranties, including, but not limited to, the implied warranties of
23 * merchantability and fitness for a particular purpose. The software
24 * provided hereunder is on an "as is" basis, and Peter Stephenson and the
25 * Zsh Development Group have no obligation to provide maintenance,
26 * support, updates, enhancements, or modifications.
30 #include "mathfunc.mdh"
31 #include "mathfunc.pro"
33 #include <math.h>
35 enum {
36 MF_ABS,
37 MF_ACOS,
38 MF_ACOSH,
39 MF_ASIN,
40 MF_ASINH,
41 MF_ATAN,
42 MF_ATANH,
43 MF_CBRT,
44 MF_CEIL,
45 MF_COPYSIGN,
46 MF_COS,
47 MF_COSH,
48 MF_ERF,
49 MF_ERFC,
50 MF_EXP,
51 MF_EXPM1,
52 MF_FABS,
53 MF_FLOAT,
54 MF_FLOOR,
55 MF_FMOD,
56 MF_GAMMA,
57 MF_HYPOT,
58 MF_ILOGB,
59 MF_INT,
60 MF_J0,
61 MF_J1,
62 MF_JN,
63 MF_LDEXP,
64 MF_LGAMMA,
65 MF_LOG,
66 MF_LOG10,
67 MF_LOG1P,
68 MF_LOGB,
69 MF_NEXTAFTER,
70 MF_RINT,
71 MF_SCALB,
72 #ifdef HAVE_SIGNGAM
73 MF_SIGNGAM,
74 #endif
75 MF_SIN,
76 MF_SINH,
77 MF_SQRT,
78 MF_TAN,
79 MF_TANH,
80 MF_Y0,
81 MF_Y1,
82 MF_YN
85 /* also functions taking a string argument */
87 enum {
88 MS_RAND48
92 * also to do, but differently argument or returned: abs (no type
93 * conversion), atan2.
96 /* Flags for bounds. Note these must start at 1, not 0. */
98 enum {
99 BF_POS = 1, /* must be positive */
100 BF_NONNEG = 2, /* must be non-negative */
101 BF_FRAC = 3, /* must be -1 <= x <= 1 */
102 BF_GE1 = 4, /* must be >= 1 */
103 BF_FRACO = 5, /* must be in open range -1 < x < 1 */
104 BF_INTPOS = 6, /* must be non-integer or positive */
105 BF_GTRM1 = 7, /* must be > -1 */
106 BF_NONZ = 8, /* must be nonzero */
107 BF_POS2 = 9 /* second argument must be positive */
110 #define BFLAG(x) ((x) << 8)
113 * Flags for type of function: unlike the above, these must
114 * be individually bit-testable.
117 enum {
118 TF_NOCONV = 1, /* don't convert to float */
119 TF_INT1 = 2, /* first argument is integer */
120 TF_INT2 = 4, /* second argument is integer */
121 TF_NOASS = 8 /* don't assign result as double */
124 #define TFLAG(x) ((x) << 16)
127 static struct mathfunc mftab[] = {
128 NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) |
129 TFLAG(TF_NOCONV|TF_NOASS)),
130 NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)),
131 NUMMATHFUNC("acosh", math_func, 1, 1, MF_ACOSH | BFLAG(BF_GE1)),
132 NUMMATHFUNC("asin", math_func, 1, 1, MF_ASIN | BFLAG(BF_FRAC)),
133 NUMMATHFUNC("asinh", math_func, 1, 1, MF_ASINH),
134 NUMMATHFUNC("atan", math_func, 1, 2, MF_ATAN),
135 NUMMATHFUNC("atanh", math_func, 1, 1, MF_ATANH | BFLAG(BF_FRACO)),
136 NUMMATHFUNC("cbrt", math_func, 1, 1, MF_CBRT),
137 NUMMATHFUNC("ceil", math_func, 1, 1, MF_CEIL),
138 NUMMATHFUNC("copysign", math_func, 2, 2, MF_COPYSIGN),
139 NUMMATHFUNC("cos", math_func, 1, 1, MF_COS),
140 NUMMATHFUNC("cosh", math_func, 1, 1, MF_COSH),
141 NUMMATHFUNC("erf", math_func, 1, 1, MF_ERF),
142 NUMMATHFUNC("erfc", math_func, 1, 1, MF_ERFC),
143 NUMMATHFUNC("exp", math_func, 1, 1, MF_EXP),
144 NUMMATHFUNC("expm1", math_func, 1, 1, MF_EXPM1),
145 NUMMATHFUNC("fabs", math_func, 1, 1, MF_FABS),
146 NUMMATHFUNC("float", math_func, 1, 1, MF_FLOAT),
147 NUMMATHFUNC("floor", math_func, 1, 1, MF_FLOOR),
148 NUMMATHFUNC("fmod", math_func, 2, 2, MF_FMOD),
149 NUMMATHFUNC("gamma", math_func, 1, 1, MF_GAMMA | BFLAG(BF_INTPOS)),
150 NUMMATHFUNC("hypot", math_func, 2, 2, MF_HYPOT),
151 NUMMATHFUNC("ilogb", math_func, 1, 1, MF_ILOGB | BFLAG(BF_NONZ) |
152 TFLAG(TF_NOASS)),
153 NUMMATHFUNC("int", math_func, 1, 1, MF_INT | TFLAG(TF_NOASS)),
154 NUMMATHFUNC("j0", math_func, 1, 1, MF_J0),
155 NUMMATHFUNC("j1", math_func, 1, 1, MF_J1),
156 NUMMATHFUNC("jn", math_func, 2, 2, MF_JN | TFLAG(TF_INT1)),
157 NUMMATHFUNC("ldexp", math_func, 2, 2, MF_LDEXP | TFLAG(TF_INT2)),
158 NUMMATHFUNC("lgamma", math_func, 1, 1, MF_LGAMMA | BFLAG(BF_INTPOS)),
159 NUMMATHFUNC("log", math_func, 1, 1, MF_LOG | BFLAG(BF_POS)),
160 NUMMATHFUNC("log10", math_func, 1, 1, MF_LOG10 | BFLAG(BF_POS)),
161 NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P | BFLAG(BF_GTRM1)),
162 NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB | BFLAG(BF_NONZ)),
163 NUMMATHFUNC("nextafter", math_func, 2, 2, MF_NEXTAFTER),
164 #ifdef HAVE_ERAND48
165 STRMATHFUNC("rand48", math_string, MS_RAND48),
166 #endif
167 NUMMATHFUNC("rint", math_func, 1, 1, MF_RINT),
168 NUMMATHFUNC("scalb", math_func, 2, 2, MF_SCALB | TFLAG(TF_INT2)),
169 #ifdef HAVE_SIGNGAM
170 NUMMATHFUNC("signgam", math_func, 0, 0, MF_SIGNGAM | TFLAG(TF_NOASS)),
171 #endif
172 NUMMATHFUNC("sin", math_func, 1, 1, MF_SIN),
173 NUMMATHFUNC("sinh", math_func, 1, 1, MF_SINH),
174 NUMMATHFUNC("sqrt", math_func, 1, 1, MF_SQRT | BFLAG(BF_NONNEG)),
175 NUMMATHFUNC("tan", math_func, 1, 1, MF_TAN),
176 NUMMATHFUNC("tanh", math_func, 1, 1, MF_TANH),
177 NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0 | BFLAG(BF_POS)),
178 NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1 | BFLAG(BF_POS)),
179 NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1))
182 /**/
183 static mnumber
184 math_func(char *name, int argc, mnumber *argv, int id)
186 mnumber ret;
187 double argd = 0, argd2 = 0, retd = 0;
188 int argi = 0;
190 if (argc && !(id & TFLAG(TF_NOCONV))) {
191 if (id & TFLAG(TF_INT1))
192 argi = (argv->type == MN_FLOAT) ? (zlong)argv->u.d : argv->u.l;
193 else
194 argd = (argv->type == MN_INTEGER) ? (double)argv->u.l : argv->u.d;
195 if (argc > 1) {
196 if (id & TFLAG(TF_INT2))
197 argi = (argv[1].type == MN_FLOAT) ? (zlong)argv[1].u.d :
198 argv[1].u.l;
199 else
200 argd2 = (argv[1].type == MN_INTEGER) ? (double)argv[1].u.l :
201 argv[1].u.d;
205 ret.type = MN_FLOAT;
206 ret.u.d = 0;
208 if (errflag)
209 return ret;
211 if (id & 0xff00) {
212 int rtst = 0;
214 switch ((id >> 8) & 0xff) {
215 case BF_POS:
216 rtst = (argd <= 0.0);
217 break;
219 case BF_NONNEG:
220 rtst = (argd < 0.0);
221 break;
223 case BF_FRAC:
224 rtst = (fabs(argd) > 1.0);
225 break;
227 case BF_GE1:
228 rtst = (argd < 1.0);
229 break;
231 case BF_FRACO:
232 rtst = (fabs(argd) >= 1.0);
233 break;
235 case BF_INTPOS:
236 rtst = (argd <= 0 && (double)(zlong)argd == argd);
237 break;
239 case BF_GTRM1:
240 rtst = (argd <= -1);
241 break;
243 case BF_POS2:
244 rtst = (argd2 <= 0.0);
245 break;
248 if (rtst) {
249 zerr("math: argument to %s out of range", name);
250 return ret;
254 switch (id & 0xff) {
255 case MF_ABS:
256 ret.type = argv->type;
257 if (argv->type == MN_INTEGER)
258 ret.u.l = (argv->u.l < 0) ? - argv->u.l : argv->u.l;
259 else
260 ret.u.d = fabs(argv->u.d);
261 break;
263 case MF_ACOS:
264 retd = acos(argd);
265 break;
267 case MF_ACOSH:
268 retd = acosh(argd);
269 break;
271 case MF_ASIN:
272 retd = asin(argd);
273 break;
275 case MF_ASINH:
276 retd = asinh(argd);
277 break;
279 case MF_ATAN:
280 if (argc == 2)
281 retd = atan2(argd, argd2);
282 else
283 retd = atan(argd);
284 break;
286 case MF_ATANH:
287 retd = atanh(argd);
288 break;
290 case MF_CBRT:
291 retd = cbrt(argd);
292 break;
294 case MF_CEIL:
295 retd = ceil(argd);
296 break;
298 case MF_COPYSIGN:
299 retd = copysign(argd, argd2);
300 break;
302 case MF_COS:
303 retd = cos(argd);
304 break;
306 case MF_COSH:
307 retd = cosh(argd);
308 break;
310 case MF_ERF:
311 retd = erf(argd);
312 break;
314 case MF_ERFC:
315 retd = erfc(argd);
316 break;
318 case MF_EXP:
319 retd = exp(argd);
320 break;
322 case MF_EXPM1:
323 retd = expm1(argd);
324 break;
326 case MF_FABS:
327 retd = fabs(argd);
328 break;
330 case MF_FLOAT:
331 retd = argd;
332 break;
334 case MF_FLOOR:
335 retd = floor(argd);
336 break;
338 case MF_FMOD:
339 retd = fmod(argd, argd2);
340 break;
342 case MF_GAMMA:
343 retd = gamma(argd);
344 break;
346 case MF_HYPOT:
347 retd = hypot(argd, argd2);
348 break;
350 case MF_ILOGB:
351 ret.type = MN_INTEGER;
352 ret.u.l = ilogb(argd);
353 break;
355 case MF_INT:
356 ret.type = MN_INTEGER;
357 ret.u.l = (zlong)argd;
358 break;
360 case MF_J0:
361 retd = j0(argd);
362 break;
364 case MF_J1:
365 retd = j1(argd);
366 break;
368 case MF_JN:
369 retd = jn(argi, argd2);
370 break;
372 case MF_LDEXP:
373 retd = ldexp(argd, argi);
374 break;
376 case MF_LGAMMA:
377 retd = lgamma(argd);
378 break;
380 case MF_LOG:
381 retd = log(argd);
382 break;
384 case MF_LOG10:
385 retd = log10(argd);
386 break;
388 case MF_LOG1P:
389 retd = log1p(argd);
390 break;
392 case MF_LOGB:
393 retd = logb(argd);
394 break;
396 case MF_NEXTAFTER:
397 retd = nextafter(argd, argd2);
398 break;
400 case MF_RINT:
401 retd = rint(argd);
402 break;
404 case MF_SCALB:
405 retd = scalb(argd, argi);
406 break;
408 #ifdef HAVE_SIGNGAM
409 case MF_SIGNGAM:
410 ret.type = MN_INTEGER;
411 ret.u.l = signgam;
412 break;
413 #endif
415 case MF_SIN:
416 retd = sin(argd);
417 break;
419 case MF_SINH:
420 retd = sinh(argd);
421 break;
423 case MF_SQRT:
424 retd = sqrt(argd);
425 break;
427 case MF_TAN:
428 retd = tan(argd);
429 break;
431 case MF_TANH:
432 retd = tanh(argd);
433 break;
435 case MF_Y0:
436 retd = y0(argd);
437 break;
439 case MF_Y1:
440 retd = y1(argd);
441 break;
443 case MF_YN:
444 retd = yn(argi, argd2);
445 break;
447 #ifdef DEBUG
448 default:
449 fprintf(stderr, "BUG: mathfunc type not handled: %d", id);
450 break;
451 #endif
454 if (!(id & TFLAG(TF_NOASS)))
455 ret.u.d = retd;
457 return ret;
460 /**/
461 static mnumber
462 math_string(UNUSED(char *name), char *arg, int id)
464 mnumber ret = zero_mnumber;
465 char *send;
467 * Post-process the string argument, which is just passed verbatim.
468 * Not clear if any other functions that use math_string() will
469 * want this, but assume so for now.
471 while (iblank(*arg))
472 arg++;
473 send = arg + strlen(arg);
474 while (send > arg && iblank(send[-1]))
475 send--;
476 *send = '\0';
478 switch (id)
480 #ifdef HAVE_ERAND48
481 case MS_RAND48:
483 static unsigned short seedbuf[3];
484 static int seedbuf_init;
485 unsigned short tmp_seedbuf[3], *seedbufptr;
486 int do_init = 1;
488 if (*arg) {
489 /* Seed is contained in parameter named by arg */
490 char *seedstr;
491 seedbufptr = tmp_seedbuf;
492 if ((seedstr = getsparam(arg)) && strlen(seedstr) >= 12) {
493 int i, j;
494 do_init = 0;
496 * Decode three sets of four hex digits corresponding
497 * to each unsigned short.
499 for (i = 0; i < 3 && !do_init; i++) {
500 unsigned short *seedptr = seedbufptr + i;
501 *seedptr = 0;
502 for (j = 0; j < 4; j++) {
503 if (idigit(*seedstr))
504 *seedptr += *seedstr - '0';
505 else if (tolower(*seedstr) >= 'a' &&
506 tolower(*seedstr) <= 'f')
507 *seedptr += tolower(*seedstr) - 'a' + 10;
508 else {
509 do_init = 1;
510 break;
512 seedstr++;
513 if (j < 3)
514 *seedptr *= 16;
518 else if (errflag)
519 break;
521 else
523 /* Use default seed: must be initialised. */
524 seedbufptr = seedbuf;
525 if (!seedbuf_init)
526 seedbuf_init = 1;
527 else
528 do_init = 1;
530 if (do_init) {
531 seedbufptr[0] = (unsigned short)rand();
532 seedbufptr[1] = (unsigned short)rand();
533 seedbufptr[2] = (unsigned short)rand();
535 * Some implementations of rand48() need initialization.
536 * This is likely to be harmless elsewhere, since
537 * according to the documentation erand48() normally
538 * doesn't look at the seed set in this way.
540 (void)seed48(seedbufptr);
542 ret.type = MN_FLOAT;
543 ret.u.d = erand48(seedbufptr);
545 if (*arg)
547 char outbuf[13];
548 sprintf(outbuf, "%04x%04x%04x", (int)seedbufptr[0],
549 (int)seedbufptr[1], (int)seedbufptr[2]);
550 setsparam(arg, ztrdup(outbuf));
553 break;
554 #endif
557 return ret;
561 static struct features module_features = {
562 NULL, 0,
563 NULL, 0,
564 mftab, sizeof(mftab)/sizeof(*mftab),
565 NULL, 0,
569 /**/
571 setup_(UNUSED(Module m))
573 return 0;
576 /**/
578 features_(Module m, char ***features)
580 *features = featuresarray(m, &module_features);
581 return 0;
584 /**/
586 enables_(Module m, int **enables)
588 return handlefeatures(m, &module_features, enables);
591 /**/
593 boot_(Module m)
595 return 0;
598 /**/
600 cleanup_(Module m)
602 return setfeatureenables(m, &module_features, NULL);
605 /**/
607 finish_(UNUSED(Module m))
609 return 0;