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
commitd6b6dd078d560dba1d72350427035bdbf08f5e20 (patch)
tree45de47f27e5c05653934c03431f67ed5acc318e9
parent5b061d74c20e153e166086f5c22ea62ef4f5a475 (diff)
downloadzsh-d6b6dd078d560dba1d72350427035bdbf08f5e20.tar.gz
zsh-d6b6dd078d560dba1d72350427035bdbf08f5e20.tar.xz
zsh-d6b6dd078d560dba1d72350427035bdbf08f5e20.zip
zsh-workers/7999
-rw-r--r--Completion/Base/_combination95
-rw-r--r--Doc/Makefile.in6
-rw-r--r--Doc/Zsh/guide.yo4
-rw-r--r--Doc/Zsh/mod_mapfile.yo2
-rw-r--r--Doc/Zsh/mod_mathfunc.yo52
-rw-r--r--Doc/Zsh/modules.yo5
-rw-r--r--Src/Modules/mathfunc.c482
-rw-r--r--Src/Modules/mathfunc.mdd3
-rw-r--r--Src/math.c52
9 files changed, 673 insertions, 28 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/Makefile.in b/Doc/Makefile.in
index 6c6367526..d7673d0a1 100644
--- a/Doc/Makefile.in
+++ b/Doc/Makefile.in
@@ -59,7 +59,7 @@ Zsh/index.yo Zsh/intro.yo Zsh/invoke.yo Zsh/jobs.yo Zsh/metafaq.yo \
 Zsh/modules.yo Zsh/mod_cap.yo \
 Zsh/mod_clone.yo Zsh/mod_comp1.yo Zsh/mod_compctl.yo Zsh/mod_complist.yo \
 Zsh/mod_deltochar.yo Zsh/mod_example.yo Zsh/mod_files.yo \
-Zsh/mod_mapfile.yo Zsh/mod_parameter.yo Zsh/mod_sched.yo \
+Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_parameter.yo Zsh/mod_sched.yo \
 Zsh/mod_stat.yo Zsh/mod_zftp.yo Zsh/mod_zle.yo Zsh/options.yo \
 Zsh/params.yo Zsh/prompt.yo Zsh/redirect.yo Zsh/restricted.yo \
 Zsh/seealso.yo Zsh/zftpsys.yo Zsh/zle.yo
@@ -135,8 +135,8 @@ zshmisc.1: Zsh/grammar.yo Zsh/redirect.yo Zsh/exec.yo Zsh/func.yo \
 zshmodules.1: Zsh/modules.yo Zsh/mod_cap.yo Zsh/mod_clone.yo \
               Zsh/mod_comp1.yo Zsh/mod_complist.yo Zsh/mod_compctl.yo \
               Zsh/mod_deltochar.yo Zsh/mod_example.yo Zsh/mod_files.yo \
-              Zsh/mod_mapfile.yo Zsh/mod_sched.yo Zsh/mod_stat.yo \
-              Zsh/mod_zftp.yo Zsh/mod_zle.yo
+              Zsh/mod_mapfile.yo Zsh/mod_mathfunc.yo Zsh/mod_sched.yo \
+              Zsh/mod_stat.yo Zsh/mod_zftp.yo Zsh/mod_zle.yo
 
 zshoptions.1: Zsh/options.yo
 
diff --git a/Doc/Zsh/guide.yo b/Doc/Zsh/guide.yo
index cc8fe0f7d..c9f97fad9 100644
--- a/Doc/Zsh/guide.yo
+++ b/Doc/Zsh/guide.yo
@@ -119,9 +119,13 @@ menu(The cap Module)
 menu(The clone Module)
 menu(The comp1 Module)
 menu(The compctl Module)
+menu(The complist Module)
 menu(The deltochar Module)
 menu(The example Module)
 menu(The files Module)
+menu(The mapfile Module)
+menu(The mathfunc Module)
+menu(The parameter Module)
 menu(The sched Module)
 menu(The stat Module)
 menu(The zftp Module)
diff --git a/Doc/Zsh/mod_mapfile.yo b/Doc/Zsh/mod_mapfile.yo
index e6c388823..ad8497027 100644
--- a/Doc/Zsh/mod_mapfile.yo
+++ b/Doc/Zsh/mod_mapfile.yo
@@ -1,4 +1,4 @@
-texinode(The mapfile Module)(The parameter Module)(The files Module)(Zsh Modules)
+texinode(The mapfile Module)(The mathfunc Module)(The files Module)(Zsh Modules)
 sect(The mapfile Module)
 cindex(parameter, file access via)
 The tt(mapfile) module provides one special associative array parameter of
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/Doc/Zsh/modules.yo b/Doc/Zsh/modules.yo
index 12066b773..3f443b073 100644
--- a/Doc/Zsh/modules.yo
+++ b/Doc/Zsh/modules.yo
@@ -37,6 +37,9 @@ Some basic file manipulation commands as builtins.
 item(tt(mapfile))(
 Access to external files via a special associative array.
 )
+item(tt(mathfunc))(
+Standard scientific functions for use in mathematical evaluations.
+)
 item(tt(parameter))(
 Access to internal hash tables via special associative arrays.
 )
@@ -63,6 +66,7 @@ menu(The deltochar Module)
 menu(The example Module)
 menu(The files Module)
 menu(The mapfile Module)
+menu(The mathfunc Module)
 menu(The parameter Module)
 menu(The sched Module)
 menu(The stat Module)
@@ -78,6 +82,7 @@ includefile(Zsh/mod_deltochar.yo)
 includefile(Zsh/mod_example.yo)
 includefile(Zsh/mod_files.yo)
 includefile(Zsh/mod_mapfile.yo)
+includefile(Zsh/mod_mathfunc.yo)
 includefile(Zsh/mod_parameter.yo)
 includefile(Zsh/mod_sched.yo)
 includefile(Zsh/mod_stat.yo)
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"
diff --git a/Src/math.c b/Src/math.c
index 836e0c671..9edfeb651 100644
--- a/Src/math.c
+++ b/Src/math.c
@@ -161,7 +161,7 @@ static int prec[TOKCOUNT] =
      0,  16, 0
 };
 
-#define TOPPREC 16
+#define TOPPREC 17
 #define ARGPREC (TOPPREC-1)
 
 static int type[TOKCOUNT] =
@@ -498,31 +498,35 @@ callmathfunc(char *o)
 	    mnumber *argv = NULL, *q;
 	    LinkList l = newlinklist();
 	    LinkNode node;
-	    char *p;
-
-	    if (*a) {
-		for (p = a; *a; a++) {
-		    if (*a == '\\' && a[1])
-			a++;
-		    else if (*a == ',') {
-			*a = '\0';
-			addlinknode(l, p);
-			argc++;
-			p = a + 1;
-		    }
+
+	    while (iblank(*a))
+		a++;
+	    while (*a) {
+		if (*a) {
+		    argc++;
+ 		    q = (mnumber *)zhalloc(sizeof(mnumber));
+		    *q = mathevall(a, ARGPREC, &a);
+		    addlinknode(l, q);
+		    if (errflag || mtok != COMMA)
+			break;
+		    a++;
 		}
-		addlinknode(l, p);
-		argc++;
 	    }
-	    if (argc >= f->minargs && (f->maxargs < 0 || argc <= f->maxargs)) {
-		if (argc) {
-		    q = argv = (mnumber *) zhalloc(argc * sizeof(mnumber));
-		    for (node = firstnode(l); node; incnode(node))
-			*q++ = matheval((char *) getdata(node));
-		}
-		return f->nfunc(n, argc, argv, f->funcid);
-	    } else
-		zerr("wrong number of argument: %s", o, 0);
+	    if (*a && !errflag)
+		zerr("bad math expression: illegal character: %c",
+		     NULL, *a);
+	    if (!errflag) {
+		if (argc >= f->minargs && (f->maxargs < 0 ||
+					   argc <= f->maxargs)) {
+		    if (argc) {
+			q = argv = (mnumber *)zhalloc(argc * sizeof(mnumber));
+			for (node = firstnode(l); node; incnode(node))
+			    *q++ = *(mnumber *)getdata(node);
+		    }
+		    return f->nfunc(n, argc, argv, f->funcid);
+		} else
+		    zerr("wrong number of arguments: %s", o, 0);
+	    }
 	}
     } else
 	zerr("unknown function: %s", n, 0);