diff options
-rw-r--r-- | Completion/Base/_combination | 95 | ||||
-rw-r--r-- | Doc/Zsh/mod_mathfunc.yo | 52 | ||||
-rw-r--r-- | Src/Modules/mathfunc.c | 482 | ||||
-rw-r--r-- | Src/Modules/mathfunc.mdd | 3 |
4 files changed, 632 insertions, 0 deletions
diff --git a/Completion/Base/_combination b/Completion/Base/_combination new file mode 100644 index 000000000..631547311 --- /dev/null +++ b/Completion/Base/_combination @@ -0,0 +1,95 @@ +#autoload + +# Usage: +# _combination [-s S] V[:K1:...] Ki1[:Ni1]=Pi1 Ki2[:Ni2]=Pi2 ... Kim[:Nim]=Pim Kj[:Nj] EXPL... +# +# It is assumed that V is formed as PRE_K1_..._Kn if `:K1:...' is not specified. +# +# Example: telnet +# +# Assume an user sets the variable `telnet_hosts_ports_users' as: +# +# telnet_hosts_ports_users=( +# host0:: host1::user1 host2::user2 +# mail-server:{smtp,pop3}: +# news-server:nntp: +# proxy-server:8000: +# ) +# +# `_telnet completes' hosts as: +# +# _combination telnet_hosts_ports_users \ +# ${options[-l]:+users=${options[-l]:q}} \ +# hosts "$expl[@]" +# +# This completes `host1', `host2', `mail-server', `news-server' and +# `proxy-server' according to the user given with `-l' if it is exists. +# And if it is failed, `_hosts' is called. +# +# `_telnet' completes ports as: +# +# _combination telnet_hosts_ports_users \ +# ${options[-l]:+users=${options[-l]:q}} \ +# hosts="${line[2]:q}" \ +# ports "$expl[@]" +# +# This completes `smtp', `pop3', `nntp' and `8000' according to the +# host argument --- $line[2] and the user option argument if it is +# exists. And if it is failed, `_ports' is called. +# +# `_telnet' completes users for an argument of option `-l' as: +# +# _combination telnet_hosts_ports_users \ +# ${line[2]:+hosts="${line[2]:q}"} \ +# ${line[3]:+ports="${line[3]:q}"} \ +# users "$expl[@]" +# +# This completes `user1' and `user2' according to the host argument and +# the port argument if they are exist. And if it is failed, `_users' is +# called. + +local sep var keys pats key num tmp + +if [[ "$1" = -s ]]; then + sep="$2" + shift 2 +else + sep=: +fi + +var=$1 +shift + +if [[ $var = *:* ]]; then + keys=( ${(s/:/)var} ) + shift keys + var="${var%%:*}" +else + keys=( "${(@s:_:)${var#*_}}" ) +fi +pats=( "${(@)keys/*/*}" ) + +while [[ "$1" = *=* ]]; do + tmp="${1%%\=*}" + key="${tmp%:*}" + num="${${tmp##*:}:-1}" + pats[$keys[(in:num:)$key]]="${1#*\=}" + shift +done + +key="${1%:*}" +num="${${1##*:}:-1}" +shift + +if (( ${(P)+${var}} )); then + eval "tmp=( \"\${(@M)${var}:#\${(j($sep))~pats}}\" )" + if (( keys[(in:num:)$key] != 1 )); then + eval "tmp=( \${tmp#\${(j(${sep}))~\${(@)\${(@)keys[2,(rn:num:)\$key]}/*/*}}$sep} )" + fi + tmp=( ${tmp%%$sep*} ) + + compadd "$@" - $tmp || { builtin functions _$key >&- && _$key "$@" } +else + builtin functions _$key >&- && _$key "$@" +fi + diff --git a/Doc/Zsh/mod_mathfunc.yo b/Doc/Zsh/mod_mathfunc.yo new file mode 100644 index 000000000..bc69d2b20 --- /dev/null +++ b/Doc/Zsh/mod_mathfunc.yo @@ -0,0 +1,52 @@ +texinode(The mathfunc Module)(The parameter Module)(The mapfile Module)(Zsh Modules) +sect(The mathfunc Module) +cindex(functions, mathematical) +cindex(mathematical functions) +The tt(mathfunc) module provides standard mathematical functions for use when +evaluating mathematical formulae. The syntax agrees with normal C and +FORTRAN conventions, for example, + +example((( f = sin(0.3) ))) + +assigns the sine of 0.3 to the parameter f. + +Most functions take floating point arguments and return a floating point +value. However, any necessary conversions from or to integer type will be +performed automatically by the shell. Apart from tt(atan) with a second +argument and the tt(abs), tt(int) and tt(float) functions, all functions +behave as noted in the manual page for the corresponding C function, +except that any arguments out of range for the function in question will be +detected by the shell and an error reported. + +The following functions take a single floating point argument: tt(acos), +tt(acosh), tt(asin), tt(asinh), tt(atan), tt(atanh), tt(cbrt), tt(ceil), +tt(cos), tt(cosh), tt(erf), tt(erfc), tt(exp), tt(expm1), tt(fabs), +tt(floor), tt(gamma), tt(j0), tt(j1), tt(lgamma), tt(log), tt(log10), +tt(log1p), tt(logb), tt(sin), tt(sinh), tt(sqrt), tt(tan), tt(tanh), +tt(y0), tt(y1). The tt(atan) function can optionally take a second +argument, in which case it behaves like the C function tt(atan2). +The tt(ilogb) function takes a single floating point argument, but +returns an integer. + +The function tt(signgam) takes no arguments, and returns an integer, which +is the C variable of the same name, as described in manref(gamma)(3). Note +that it is therefore only useful immediately after a call to tt(gamma) or +tt(lgamma). Note also that `tt(signgam())' and `tt(signgam)' are distinct +expresssions. + +The following functions take two floating point arguments: tt(copysign), +tt(drem), tt(fmod), tt(hypot), tt(nextafter). + +The following take an integer first argument and a floating point second +argument: tt(jn), tt(yn). + +The following take a floating point first argument and an integer second +argument: tt(ldexp), tt(scalb). + +The function tt(abs) does not convert the type of its single argument; it +returns the absolute value of either a floating point number or an +integer. The functions tt(float) and tt(int) convert their arguments into +a floating point or integer value (by truncation) respectively. + +Note that the C tt(pow) function is available in ordinary math evaluation +as the `tt(**)' operator and is not provided here. diff --git a/Src/Modules/mathfunc.c b/Src/Modules/mathfunc.c new file mode 100644 index 000000000..770894ce8 --- /dev/null +++ b/Src/Modules/mathfunc.c @@ -0,0 +1,482 @@ +/* + * mathfunc.c - basic mathematical functions for use in math evaluations + * + * This file is part of zsh, the Z shell. + * + * Copyright (c) 1999 Peter Stephenson + * All rights reserved. + * + * Permission is hereby granted, without written agreement and without + * license or royalty fees, to use, copy, modify, and distribute this + * software and to distribute modified versions of this software for any + * purpose, provided that the above copyright notice and the following + * two paragraphs appear in all copies of this software. + * + * In no event shall Peter Stephenson or the Zsh Development Group be liable + * to any party for direct, indirect, special, incidental, or consequential + * damages arising out of the use of this software and its documentation, + * even if Peter Stephenson and the Zsh Development Group have been advised of + * the possibility of such damage. + * + * Peter Stephenson and the Zsh Development Group specifically disclaim any + * warranties, including, but not limited to, the implied warranties of + * merchantability and fitness for a particular purpose. The software + * provided hereunder is on an "as is" basis, and Peter Stephenson and the + * Zsh Development Group have no obligation to provide maintenance, + * support, updates, enhancements, or modifications. + * + */ + +#include "mathfunc.mdh" +#include "mathfunc.pro" + +#include <math.h> + +enum { +MF_ABS, +MF_ACOS, +MF_ACOSH, +MF_ASIN, +MF_ASINH, +MF_ATAN, +MF_ATANH, +MF_CBRT, +MF_CEIL, +MF_COPYSIGN, +MF_COS, +MF_COSH, +MF_DREM, +MF_ERF, +MF_ERFC, +MF_EXP, +MF_EXPM1, +MF_FABS, +MF_FLOAT, +MF_FLOOR, +MF_FMOD, +MF_GAMMA, +MF_HYPOT, +MF_ILOGB, +MF_INT, +MF_J0, +MF_J1, +MF_JN, +MF_LDEXP, +MF_LGAMMA, +MF_LOG, +MF_LOG10, +MF_LOG1P, +MF_LOGB, +MF_NEXTAFTER, +MF_RINT, +MF_SCALB, +MF_SIGNGAM, +MF_SIN, +MF_SINH, +MF_SQRT, +MF_TAN, +MF_TANH, +MF_Y0, +MF_Y1, +MF_YN, +}; + +/* + * also to do, but differently argument or returned: abs (no type + * conversion), atan2. + */ + +/* Flags for bounds. Note these must start at 1, not 0. */ + +enum { + BF_POS = 1, /* must be positive */ + BF_NONNEG = 2, /* must be non-negative */ + BF_FRAC = 3, /* must be -1 <= x <= 1 */ + BF_GE1 = 4, /* must be >= 1 */ + BF_FRACO = 5, /* must be in open range -1 < x < 1 */ + BF_INTPOS = 6, /* must be non-integer or positive */ + BF_GTRM1 = 7, /* must be > -1 */ + BF_NONZ = 8, /* must be nonzero */ + BF_POS2 = 9 /* second argument must be positive */ +}; + +#define BFLAG(x) ((x) << 8) + +/* + * Flags for type of function: unlike the above, these must + * be individually bit-testable. + */ + +enum { + TF_NOCONV = 1, /* don't convert to float */ + TF_INT1 = 2, /* first argument is integer */ + TF_INT2 = 4, /* second argument is integer */ + TF_NOASS = 8 /* don't assign result as double */ +}; + +#define TFLAG(x) ((x) << 16) + + +static struct mathfunc mftab[] = { + NUMMATHFUNC("abs", math_func, 1, 1, MF_ABS | BFLAG(BF_FRAC) | + TFLAG(TF_NOCONV|TF_NOASS)), + NUMMATHFUNC("acos", math_func, 1, 1, MF_ACOS | BFLAG(BF_FRAC)), + NUMMATHFUNC("acosh", math_func, 1, 1, MF_ACOSH | BFLAG(BF_GE1)), + NUMMATHFUNC("asin", math_func, 1, 1, MF_ASIN | BFLAG(BF_FRAC)), + NUMMATHFUNC("asinh", math_func, 1, 1, MF_ASINH), + NUMMATHFUNC("atan", math_func, 1, 2, MF_ATAN), + NUMMATHFUNC("atanh", math_func, 1, 1, MF_ATANH | BFLAG(BF_FRACO)), + NUMMATHFUNC("cbrt", math_func, 1, 1, MF_CBRT), + NUMMATHFUNC("ceil", math_func, 1, 1, MF_CEIL), + NUMMATHFUNC("copysign", math_func, 2, 2, MF_COPYSIGN), + NUMMATHFUNC("cos", math_func, 1, 1, MF_COS), + NUMMATHFUNC("cosh", math_func, 1, 1, MF_COSH), + NUMMATHFUNC("drem", math_func, 2, 2, MF_DREM), + NUMMATHFUNC("erf", math_func, 1, 1, MF_ERF), + NUMMATHFUNC("erfc", math_func, 1, 1, MF_ERFC), + NUMMATHFUNC("exp", math_func, 1, 1, MF_EXP), + NUMMATHFUNC("expm1", math_func, 1, 1, MF_EXPM1), + NUMMATHFUNC("fabs", math_func, 1, 1, MF_FABS), + NUMMATHFUNC("float", math_func, 1, 1, MF_FLOAT), + NUMMATHFUNC("floor", math_func, 1, 1, MF_FLOOR), + NUMMATHFUNC("fmod", math_func, 2, 2, MF_FMOD), + NUMMATHFUNC("gamma", math_func, 1, 1, MF_GAMMA | BFLAG(BF_INTPOS)), + NUMMATHFUNC("hypot", math_func, 2, 2, MF_HYPOT), + NUMMATHFUNC("ilogb", math_func, 1, 1, MF_ILOGB | BFLAG(BF_NONZ) | + TFLAG(TF_NOASS)), + NUMMATHFUNC("int", math_func, 1, 1, MF_INT | TFLAG(TF_NOASS)), + NUMMATHFUNC("j0", math_func, 1, 1, MF_J0), + NUMMATHFUNC("j1", math_func, 1, 1, MF_J1), + NUMMATHFUNC("jn", math_func, 2, 2, MF_JN | TFLAG(TF_INT1)), + NUMMATHFUNC("ldexp", math_func, 2, 2, MF_LDEXP | TFLAG(TF_INT2)), + NUMMATHFUNC("lgamma", math_func, 1, 1, MF_LGAMMA | BFLAG(BF_INTPOS)), + NUMMATHFUNC("log", math_func, 1, 1, MF_LOG | BFLAG(BF_POS)), + NUMMATHFUNC("log10", math_func, 1, 1, MF_LOG10 | BFLAG(BF_POS)), + NUMMATHFUNC("log1p", math_func, 1, 1, MF_LOG1P | BFLAG(BF_GTRM1)), + NUMMATHFUNC("logb", math_func, 1, 1, MF_LOGB | BFLAG(BF_NONZ)), + NUMMATHFUNC("nextafter", math_func, 2, 2, MF_NEXTAFTER), + NUMMATHFUNC("rint", math_func, 1, 1, MF_RINT), + NUMMATHFUNC("scalb", math_func, 2, 2, MF_SCALB | TFLAG(TF_INT2)), + NUMMATHFUNC("signgam", math_func, 0, 0, MF_SIGNGAM | TFLAG(TF_NOASS)), + NUMMATHFUNC("sin", math_func, 1, 1, MF_SIN), + NUMMATHFUNC("sinh", math_func, 1, 1, MF_SINH), + NUMMATHFUNC("sqrt", math_func, 1, 1, MF_SQRT | BFLAG(BF_NONNEG)), + NUMMATHFUNC("tan", math_func, 1, 1, MF_TAN), + NUMMATHFUNC("tanh", math_func, 1, 1, MF_TANH), + NUMMATHFUNC("y0", math_func, 1, 1, MF_Y0 | BFLAG(BF_POS)), + NUMMATHFUNC("y1", math_func, 1, 1, MF_Y1 | BFLAG(BF_POS)), + NUMMATHFUNC("yn", math_func, 2, 2, MF_YN | BFLAG(BF_POS2) | TFLAG(TF_INT1)) +}; + +/**/ +static mnumber +math_func(char *name, int argc, mnumber *argv, int id) +{ + mnumber ret; + double argd = 0, argd2 = 0, retd = 0; + int argi = 0; + + if (argc && !(id & TFLAG(TF_NOCONV))) { + if (id & TFLAG(TF_INT1)) + argi = (argv->type == MN_FLOAT) ? (zlong)argv->u.d : argv->u.l; + else + argd = (argv->type == MN_INTEGER) ? (double)argv->u.l : argv->u.d; + if (argc > 1) { + if (id & TFLAG(TF_INT2)) + argi = (argv[1].type == MN_FLOAT) ? (zlong)argv[1].u.d : + argv[1].u.l; + else + argd2 = (argv[1].type == MN_INTEGER) ? (double)argv[1].u.l : + argv[1].u.d; + } + } + + ret.type = MN_FLOAT; + ret.u.d = 0; + + if (errflag) + return ret; + + if (id & 0xff00) { + int rtst = 0; + + switch ((id >> 8) & 0xff) { + case BF_POS: + rtst = (argd <= 0.0); + break; + + case BF_NONNEG: + rtst = (argd < 0.0); + break; + + case BF_FRAC: + rtst = (fabs(argd) > 1.0); + break; + + case BF_GE1: + rtst = (argd < 1.0); + break; + + case BF_FRACO: + rtst = (fabs(argd) >= 1.0); + break; + + case BF_INTPOS: + rtst = (argd <= 0 && (double)(zlong)argd == argd); + break; + + case BF_GTRM1: + rtst = (argd <= -1); + break; + + case BF_POS2: + rtst = (argd2 <= 0.0); + break; + } + + if (rtst) { + zerr("math: argument to %s out of range", name, 0); + return ret; + } + } + + switch (id & 0xff) { + case MF_ABS: + ret.type = argv->type; + if (argv->type == MN_INTEGER) + ret.u.l = (argv->u.l < 0) ? - argv->u.l : argv->u.l; + else + ret.u.d = fabs(argv->u.d); + break; + + case MF_ACOS: + retd = acos(argd); + break; + + case MF_ACOSH: + retd = acosh(argd); + break; + + case MF_ASIN: + retd = asin(argd); + break; + + case MF_ASINH: + retd = asinh(argd); + break; + + case MF_ATAN: + if (argc == 2) + retd = atan2(argd, argd2); + else + retd = atan(argd); + break; + + case MF_ATANH: + retd = atanh(argd); + break; + + case MF_CBRT: + retd = cbrt(argd); + break; + + case MF_CEIL: + retd = ceil(argd); + break; + + case MF_COPYSIGN: + retd = copysign(argd, argd2); + break; + + case MF_COS: + retd = cos(argd); + break; + + case MF_COSH: + retd = cosh(argd); + break; + + case MF_DREM: + retd = drem(argd, argd2); + break; + + case MF_ERF: + retd = erf(argd); + break; + + case MF_ERFC: + retd = erfc(argd); + break; + + case MF_EXP: + retd = exp(argd); + break; + + case MF_EXPM1: + retd = expm1(argd); + break; + + case MF_FABS: + retd = fabs(argd); + break; + + case MF_FLOAT: + retd = argd; + break; + + case MF_FLOOR: + retd = floor(argd); + break; + + case MF_FMOD: + retd = fmod(argd, argd2); + break; + + case MF_GAMMA: + retd = gamma(argd); + break; + + case MF_HYPOT: + retd = hypot(argd, argd2); + break; + + case MF_ILOGB: + ret.type = MN_INTEGER; + ret.u.l = ilogb(argd); + break; + + case MF_INT: + ret.type = MN_INTEGER; + ret.u.l = (zlong)argd; + break; + + case MF_J0: + retd = j0(argd); + break; + + case MF_J1: + retd = j1(argd); + break; + + case MF_JN: + retd = jn(argi, argd2); + break; + + case MF_LDEXP: + retd = ldexp(argd, argi); + break; + + case MF_LGAMMA: + retd = lgamma(argd); + break; + + case MF_LOG: + retd = log(argd); + break; + + case MF_LOG10: + retd = log10(argd); + break; + + case MF_LOG1P: + retd = log1p(argd); + break; + + case MF_LOGB: + retd = logb(argd); + break; + + case MF_NEXTAFTER: + retd = nextafter(argd, argd2); + break; + + case MF_RINT: + retd = rint(argd); + break; + + case MF_SCALB: + retd = scalb(argd, argi); + break; + + case MF_SIGNGAM: + ret.type = MN_INTEGER; + ret.u.l = signgam; + break; + + case MF_SIN: + retd = sin(argd); + break; + + case MF_SINH: + retd = sinh(argd); + break; + + case MF_SQRT: + retd = sqrt(argd); + break; + + case MF_TAN: + retd = tan(argd); + break; + + case MF_TANH: + retd = tanh(argd); + break; + + case MF_Y0: + retd = y0(argd); + break; + + case MF_Y1: + retd = y1(argd); + break; + + case MF_YN: + retd = yn(argi, argd2); + break; + +#ifdef DEBUG + default: + fprintf(stderr, "BUG: mathfunc type not handled: %d", id); + break; +#endif + } + + if (!(id & TFLAG(TF_NOASS))) + ret.u.d = retd; + + return ret; +} + +/**/ +int +setup_mathfunc(Module m) +{ + return 0; +} + +/**/ +int +boot_mathfunc(Module m) +{ + return !addmathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); +} + +#ifdef MODULE + +/**/ +int +cleanup_mathfunc(Module m) +{ + deletemathfuncs(m->nam, mftab, sizeof(mftab)/sizeof(*mftab)); + return 0; +} + +/**/ +int +finish_mathfunc(Module m) +{ + return 0; +} + +#endif diff --git a/Src/Modules/mathfunc.mdd b/Src/Modules/mathfunc.mdd new file mode 100644 index 000000000..33a861f77 --- /dev/null +++ b/Src/Modules/mathfunc.mdd @@ -0,0 +1,3 @@ +autobins="mathfunc" + +objects="mathfunc.o" |