about summary refs log tree commit diff
diff options
context:
space:
mode:
authorTanaka Akira <akr@users.sourceforge.net>1999-09-22 13:33:14 +0000
committerTanaka Akira <akr@users.sourceforge.net>1999-09-22 13:33:14 +0000
commite7384c33a4e3abecf6dc1b521376e99878147911 (patch)
treedad14a25e7372368385d0f7d0e036cd264580ca7
parent3d74a2f6896f34e155169310331dda1b66e6c14e (diff)
downloadzsh-e7384c33a4e3abecf6dc1b521376e99878147911.tar.gz
zsh-e7384c33a4e3abecf6dc1b521376e99878147911.tar.xz
zsh-e7384c33a4e3abecf6dc1b521376e99878147911.zip
Initial revision
-rw-r--r--Completion/Base/_combination95
-rw-r--r--Doc/Zsh/mod_mathfunc.yo52
-rw-r--r--Src/Modules/mathfunc.c482
-rw-r--r--Src/Modules/mathfunc.mdd3
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"