gawk-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[gawk-diffs] [SCM] gawk branch, feature/api-mpfr, created. gawk-4.1.0-23


From: Andrew J. Schorr
Subject: [gawk-diffs] [SCM] gawk branch, feature/api-mpfr, created. gawk-4.1.0-2396-g9ef4372
Date: Fri, 6 Jan 2017 19:50:08 +0000 (UTC)

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".

The branch, feature/api-mpfr has been created
        at  9ef43720d1b2b3125f4367f3ccf2cb7129d1a9ba (commit)

- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=9ef43720d1b2b3125f4367f3ccf2cb7129d1a9ba

commit 9ef43720d1b2b3125f4367f3ccf2cb7129d1a9ba
Author: Andrew J. Schorr <address@hidden>
Date:   Fri Jan 6 14:48:53 2017 -0500

    Enhance API to support extended-precision arithmetic and implement intdiv 
as a demonstration.

diff --git a/ChangeLog b/ChangeLog
index 9d4bcd6..6ec9377 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,45 @@
+2017-01-06         Andrew J. Schorr     <address@hidden>
+
+       Enhance API to support extended-precision arithmetic.
+       * awk.h (enum block_id): Add new values BLOCK_MPFR and BLOCK_MPZ.
+       (make_number_node): New inline function to reduce code duplication
+       for creating numeric nodes.
+       * gawkapi.h (gawk_api_major_version): Bump to 3.
+       (awk_number_t): New typedef to represent numbers with varying internal
+       representations.
+       (awk_value_t): For numbers, replace double with awk_number_t.
+       (num_value): Redefine.
+       (num_type, num_ptr): New defines for awk_number_t union members.
+       (gawk_api_t): Add constants for version checking: gmp_major_version,
+       gmp_minor_version, mpfr_major_version, and mpfr_minor_version.
+       Add functions api_get_mpfr and api_get_mpz to allocate memory for
+       extended-precision numbers to hand to gawk.
+       (get_mpfr_ptr, get_mpz_ptr): Helper macros to warp api_get_mpfr and
+       api_get_mpz.
+       (make_number): Modify to populate awk_number_t correctly.
+       (make_number_mpz, make_number_mpfr): New helper functions to create
+       extended-precision numeric nodes.
+       (check_mpfr_version): New macro to check GMP/MPFR version compatibility
+       in extensions that want to support extended-precision math.
+       * gawkapi.c (getmpfr, freempfr, getmpz, freempz): New macros to
+       allocate and free memory blocks for extended-precision math.
+       (awk_value_to_node): For AWK_NUMBER values, support 3 different kinds
+       of internal numbers: double, mpz_t, and mpfr_t.
+       (assign_number): New helper function to convert a numeric node to
+       an awk_value_t.
+       (node_to_awk_value): Use assign_number in a couple of places to
+       pass numbers properly.
+       (api_get_mpfr): Implement new api_get_mpfr hook.
+       (api_get_mpfz): Implement new api_get_mpz hook.
+       (api_impl): Add GMP & MPFR versions, api_get_mpfr, and api_get_mpz.
+       * node.c (r_make_number): Use new make_number_node inline function
+       to reduce code duplication.
+       (nextfree): Add block allocators for mpfr_t and mpz_t.
+       (more_blocks): Add an assert to protect against cases where the block
+       size is too small to hold our structure.
+       * mpfr.c (mpg_node): Use new make_number_node inline function
+       to reduce code duplication.
+
 2016-12-27         Juergen Kahrs         <address@hidden>
 
        * CMakeLists.txt: Updated after adding support library.
diff --git a/awk.h b/awk.h
index 278f54c..514dfdc 100644
--- a/awk.h
+++ b/awk.h
@@ -1060,6 +1060,8 @@ enum block_id {
        BLOCK_INVALID = 0,      /* not legal */
        BLOCK_NODE,
        BLOCK_BUCKET,
+       BLOCK_MPFR,
+       BLOCK_MPZ,
        BLOCK_MAX       /* count */
 };
 
@@ -1945,3 +1947,18 @@ erealloc_real(void *ptr, size_t count, const char 
*where, const char *var, const
 
        return ret;
 }
+
+static inline NODE *
+make_number_node(unsigned int tp)
+{
+       NODE *r;
+       getnode(r);
+       r->type = Node_val;
+       r->valref = 1;
+       r->flags = (tp|MALLOC|NUMBER|NUMCUR);
+       r->stptr = NULL;
+       r->stlen = 0;
+       r->wstptr = NULL;
+       r->wstlen = 0;
+       return r;
+}
diff --git a/extension/ChangeLog b/extension/ChangeLog
index 20834b0..84f1467 100644
--- a/extension/ChangeLog
+++ b/extension/ChangeLog
@@ -1,3 +1,13 @@
+2017-01-06         Andrew J. Schorr     <address@hidden>
+
+       * intdiv.c: New extension to demonstrate how to implement intdiv
+       using the new extended-precision math API.
+       * Makefile.am (pkgextension_LTLIBRARIES): Add intdiv.la.
+       (intdiv_la_SOURCES, intdiv_la_LDFLAGS, intdiv_la_LIBADD): Add support
+       for new intdiv library.
+       * configure.ac (AC_CHECK_FUNCS): Check for fmod needed by intdiv.
+       (GNUPG_CHECK_MPFR): Add check for MPFR support.
+
 2016-12-22         Arnold D. Robbins     <address@hidden>
 
        * testext.c (valrep2str): Update for new API types.
diff --git a/extension/Makefile.am b/extension/Makefile.am
index 59c5cb8..398ca81 100644
--- a/extension/Makefile.am
+++ b/extension/Makefile.am
@@ -39,6 +39,7 @@ pkgextension_LTLIBRARIES =    \
        fnmatch.la      \
        fork.la         \
        inplace.la      \
+       intdiv.la       \
        ordchr.la       \
        readdir.la      \
        readfile.la     \
@@ -69,6 +70,10 @@ inplace_la_SOURCES    = inplace.c
 inplace_la_LDFLAGS    = $(MY_MODULE_FLAGS)
 inplace_la_LIBADD     = $(MY_LIBS)
 
+intdiv_la_SOURCES     = intdiv.c
+intdiv_la_LDFLAGS     = $(MY_MODULE_FLAGS)
+intdiv_la_LIBADD      = $(MY_LIBS)
+
 ordchr_la_SOURCES     = ordchr.c
 ordchr_la_LDFLAGS     = $(MY_MODULE_FLAGS)
 ordchr_la_LIBADD      = $(MY_LIBS)
diff --git a/extension/Makefile.in b/extension/Makefile.in
index 23bb5cf..9ec585a 100644
--- a/extension/Makefile.in
+++ b/extension/Makefile.in
@@ -114,10 +114,10 @@ host_triplet = @host@
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/../m4/arch.m4 \
-       $(top_srcdir)/m4/dirfd.m4 $(top_srcdir)/m4/libtool.m4 \
-       $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
-       $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
-       $(top_srcdir)/configure.ac
+       $(top_srcdir)/../m4/mpfr.m4 $(top_srcdir)/m4/dirfd.m4 \
+       $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
+       $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
+       $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 DIST_COMMON = $(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -187,6 +187,12 @@ inplace_la_OBJECTS = $(am_inplace_la_OBJECTS)
 inplace_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
        $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
        $(inplace_la_LDFLAGS) $(LDFLAGS) -o $@
+intdiv_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_intdiv_la_OBJECTS = intdiv.lo
+intdiv_la_OBJECTS = $(am_intdiv_la_OBJECTS)
+intdiv_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+       $(intdiv_la_LDFLAGS) $(LDFLAGS) -o $@
 ordchr_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
 am_ordchr_la_OBJECTS = ordchr.lo
 ordchr_la_OBJECTS = $(am_ordchr_la_OBJECTS)
@@ -270,15 +276,17 @@ am__v_CCLD_ = $(address@hidden@)
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \
-       $(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \
-       $(readdir_la_SOURCES) $(readfile_la_SOURCES) \
-       $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \
-       $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES)
+       $(fork_la_SOURCES) $(inplace_la_SOURCES) $(intdiv_la_SOURCES) \
+       $(ordchr_la_SOURCES) $(readdir_la_SOURCES) \
+       $(readfile_la_SOURCES) $(revoutput_la_SOURCES) \
+       $(revtwoway_la_SOURCES) $(rwarray_la_SOURCES) \
+       $(testext_la_SOURCES) $(time_la_SOURCES)
 DIST_SOURCES = $(filefuncs_la_SOURCES) $(fnmatch_la_SOURCES) \
-       $(fork_la_SOURCES) $(inplace_la_SOURCES) $(ordchr_la_SOURCES) \
-       $(readdir_la_SOURCES) $(readfile_la_SOURCES) \
-       $(revoutput_la_SOURCES) $(revtwoway_la_SOURCES) \
-       $(rwarray_la_SOURCES) $(testext_la_SOURCES) $(time_la_SOURCES)
+       $(fork_la_SOURCES) $(inplace_la_SOURCES) $(intdiv_la_SOURCES) \
+       $(ordchr_la_SOURCES) $(readdir_la_SOURCES) \
+       $(readfile_la_SOURCES) $(revoutput_la_SOURCES) \
+       $(revtwoway_la_SOURCES) $(rwarray_la_SOURCES) \
+       $(testext_la_SOURCES) $(time_la_SOURCES)
 RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
        ctags-recursive dvi-recursive html-recursive info-recursive \
        install-data-recursive install-dvi-recursive \
@@ -413,6 +421,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
+LIBMPFR = @LIBMPFR@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
@@ -511,6 +520,7 @@ pkgextension_LTLIBRARIES = \
        fnmatch.la      \
        fork.la         \
        inplace.la      \
+       intdiv.la       \
        ordchr.la       \
        readdir.la      \
        readfile.la     \
@@ -537,6 +547,9 @@ fork_la_LIBADD = $(MY_LIBS)
 inplace_la_SOURCES = inplace.c
 inplace_la_LDFLAGS = $(MY_MODULE_FLAGS)
 inplace_la_LIBADD = $(MY_LIBS)
+intdiv_la_SOURCES = intdiv.c
+intdiv_la_LDFLAGS = $(MY_MODULE_FLAGS)
+intdiv_la_LIBADD = $(MY_LIBS)
 ordchr_la_SOURCES = ordchr.c
 ordchr_la_LDFLAGS = $(MY_MODULE_FLAGS)
 ordchr_la_LIBADD = $(MY_LIBS)
@@ -679,6 +692,9 @@ fork.la: $(fork_la_OBJECTS) $(fork_la_DEPENDENCIES) 
$(EXTRA_fork_la_DEPENDENCIES
 inplace.la: $(inplace_la_OBJECTS) $(inplace_la_DEPENDENCIES) 
$(EXTRA_inplace_la_DEPENDENCIES) 
        $(AM_V_CCLD)$(inplace_la_LINK) -rpath $(pkgextensiondir) 
$(inplace_la_OBJECTS) $(inplace_la_LIBADD) $(LIBS)
 
+intdiv.la: $(intdiv_la_OBJECTS) $(intdiv_la_DEPENDENCIES) 
$(EXTRA_intdiv_la_DEPENDENCIES) 
+       $(AM_V_CCLD)$(intdiv_la_LINK) -rpath $(pkgextensiondir) 
$(intdiv_la_OBJECTS) $(intdiv_la_LIBADD) $(LIBS)
+
 ordchr.la: $(ordchr_la_OBJECTS) $(ordchr_la_DEPENDENCIES) 
$(EXTRA_ordchr_la_DEPENDENCIES) 
        $(AM_V_CCLD)$(ordchr_la_LINK) -rpath $(pkgextensiondir) 
$(ordchr_la_OBJECTS) $(ordchr_la_LIBADD) $(LIBS)
 
@@ -714,6 +730,7 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
 @AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
diff --git a/extension/aclocal.m4 b/extension/aclocal.m4
index 5665d48..1e7a343 100644
--- a/extension/aclocal.m4
+++ b/extension/aclocal.m4
@@ -1211,6 +1211,7 @@ AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
 m4_include([../m4/arch.m4])
+m4_include([../m4/mpfr.m4])
 m4_include([m4/dirfd.m4])
 m4_include([m4/libtool.m4])
 m4_include([m4/ltoptions.m4])
diff --git a/extension/configh.in b/extension/configh.in
index d3a226a..9d3d991 100644
--- a/extension/configh.in
+++ b/extension/configh.in
@@ -27,6 +27,9 @@
 /* Define to 1 if you have the `fdopendir' function. */
 #undef HAVE_FDOPENDIR
 
+/* Define to 1 if you have the `fmod' function. */
+#undef HAVE_FMOD
+
 /* Define to 1 if you have the `fnmatch' function. */
 #undef HAVE_FNMATCH
 
@@ -51,6 +54,9 @@
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define to 1 if you have fully functional mpfr and gmp libraries. */
+#undef HAVE_MPFR
+
 /* Define to 1 if you have the `nanosleep' function. */
 #undef HAVE_NANOSLEEP
 
diff --git a/extension/configure b/extension/configure
index 4060155..580cc15 100755
--- a/extension/configure
+++ b/extension/configure
@@ -635,6 +635,7 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+LIBMPFR
 pkgextensiondir
 LT_SYS_LIBRARY_PATH
 OTOOL64
@@ -763,6 +764,7 @@ with_aix_soname
 with_gnu_ld
 with_sysroot
 enable_libtool_lock
+with_mpfr
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1416,6 +1418,7 @@ Optional Packages:
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
   --with-sysroot[=DIR]    Search for dependent libraries within DIR (or the
                           compiler's sysroot if not specified).
+  --with-mpfr=DIR         look for the mpfr and gmp libraries in DIR
 
 Some influential environment variables:
   CC          C compiler command
@@ -12859,7 +12862,88 @@ $as_echo "#define TIME_WITH_SYS_TIME 1" >>confdefs.h
 fi
 
 
-for ac_func in fdopendir fnmatch gettimeofday \
+case `uname -m` in
+*'Power Macintosh'*)
+       : ;;
+*)
+
+
+# Check whether --with-mpfr was given.
+if test "${with_mpfr+set}" = set; then :
+  withval=$with_mpfr; _do_mpfr=$withval
+else
+  _do_mpfr=yes
+fi
+
+
+  if test "$_do_mpfr" != "no" ; then
+     if test -d "$withval" ; then
+        CPPFLAGS="${CPPFLAGS} -I$withval/include"
+        LDFLAGS="${LDFLAGS} -L$withval/lib"
+     fi
+
+        _mpfr_save_libs=$LIBS
+        _combo="-lmpfr -lgmp"
+        LIBS="$LIBS $_combo"
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mpfr via 
\"$_combo\" is present and usable" >&5
+$as_echo_n "checking whether mpfr via \"$_combo\" is present and usable... " 
>&6; }
+
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+
+#include <stdio.h>
+#include <mpfr.h>
+#include <gmp.h>
+
+int
+main ()
+{
+
+mpfr_t p;
+mpz_t z;
+mpfr_init(p);
+mpz_init(z);
+mpfr_printf("%Rf%Zd", p, z);
+mpfr_clear(p);
+mpz_clear(z);
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  _found_mpfr=yes
+else
+  _found_mpfr=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_found_mpfr" >&5
+$as_echo "$_found_mpfr" >&6; }
+
+        LIBS=$_mpfr_save_libs
+
+        if test $_found_mpfr = yes ; then
+
+$as_echo "#define HAVE_MPFR 1" >>confdefs.h
+
+           LIBMPFR=$_combo
+
+           break
+        fi
+
+     unset _mpfr_save_libs
+     unset _combo
+     unset _found_mpfr
+  fi
+
+       ;;
+esac
+
+for ac_func in fdopendir fnmatch gettimeofday fmod \
                getdtablesize nanosleep select statvfs GetSystemTimeAsFileTime
 do :
   as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
diff --git a/extension/configure.ac b/extension/configure.ac
index b5b27d0..58935b6 100644
--- a/extension/configure.ac
+++ b/extension/configure.ac
@@ -69,7 +69,16 @@ AC_HEADER_DIRENT
 AC_HEADER_MAJOR
 AC_HEADER_TIME
 
-AC_CHECK_FUNCS(fdopendir fnmatch gettimeofday \
+dnl check for mpfr support
+case `uname -m` in
+*'Power Macintosh'*)
+       : ;;
+*)
+       GNUPG_CHECK_MPFR
+       ;;
+esac
+
+AC_CHECK_FUNCS(fdopendir fnmatch gettimeofday fmod \
                getdtablesize nanosleep select statvfs GetSystemTimeAsFileTime)
 
 GAWK_FUNC_DIRFD
diff --git a/extension/intdiv.c b/extension/intdiv.c
new file mode 100644
index 0000000..2f446c4
--- /dev/null
+++ b/extension/intdiv.c
@@ -0,0 +1,206 @@
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <math.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "gawkapi.h"
+
+#ifdef HAVE_MPFR
+#include <gmp.h>
+#include <mpfr.h>
+#endif
+
+#include "gettext.h"
+#define _(msgid)  gettext(msgid)
+#define N_(msgid) msgid
+
+static const gawk_api_t *api;  /* for convenience macros to work */
+static awk_ext_id_t *ext_id;
+static const char *ext_version = "intdiv extension: version 1.0";
+
+int plugin_is_GPL_compatible;
+
+static double
+double_to_int(double d)
+{
+       if (d >= 0)
+               d = floor(d);
+       else
+               d = ceil(d);
+       return d;
+}
+
+static void
+array_set_number(awk_array_t array, const char *sub, size_t sublen, double num)
+{
+       awk_value_t index, tmp;
+
+       set_array_element(array, make_const_string(sub, sublen, & index), 
make_number(num, & tmp));
+}
+
+#ifdef HAVE_MPFR
+
+static mpz_ptr
+mpz_conv(const awk_value_t *arg, mpz_ptr tmp)
+{
+       switch (arg->num_type) {
+       case AWK_NUMBER_TYPE_MPZ:
+               return arg->num_ptr;
+       case AWK_NUMBER_TYPE_MPFR:
+               if (! mpfr_number_p(arg->num_ptr))
+                       return NULL;
+               mpz_init(tmp);
+               mpfr_get_z(tmp, arg->num_ptr, MPFR_RNDZ);
+               return tmp;
+       case AWK_NUMBER_TYPE_DOUBLE:    /* can this happen? */
+               mpz_init(tmp);
+               mpz_set_d(tmp, double_to_int(arg->num_value));
+               return tmp;
+       default:        /* should never happen */
+               fatal(ext_id, _("intdiv: invalid numeric type `%d'"), 
arg->num_type);
+               return NULL;
+       }
+}
+
+static void
+array_set_mpz(awk_array_t array, const char *sub, size_t sublen, mpz_ptr num)
+{
+       awk_value_t index, tmp;
+
+       set_array_element(array, make_const_string(sub, sublen, & index), 
make_number_mpz(num, & tmp));
+}
+
+#endif
+
+/* do_intdiv --- do integer division, return quotient and remainder in dest 
array */
+
+/*
+ * We define the semantics as:
+ *     numerator = int(numerator)
+ *     denominator = int(denonmator)
+ *     quotient = int(numerator / denomator)
+ *     remainder = int(numerator % denomator)
+ */
+
+static awk_value_t *
+do_intdiv(int nargs, awk_value_t *result, struct awk_ext_func *unused)
+{
+       awk_value_t nv, dv, array_param;
+       awk_array_t array;
+
+       if (! get_argument(0, AWK_NUMBER, & nv)) {
+               warning(ext_id, _("intdiv: first argument must be numeric"));
+               return make_number(-1, result);
+       }
+       if (! get_argument(1, AWK_NUMBER, & dv)) {
+               warning(ext_id, _("intdiv: second argument must be numeric"));
+               return make_number(-1, result);
+       }
+       if (! get_argument(2, AWK_ARRAY, & array_param)) {
+               warning(ext_id, _("intdiv: third argument must be an array"));
+               return make_number(-1, result);
+       }
+       array = array_param.array_cookie;
+       clear_array(array);
+
+#ifdef HAVE_MPFR
+       if (nv.num_type == AWK_NUMBER_TYPE_DOUBLE && dv.num_type == 
AWK_NUMBER_TYPE_DOUBLE) {
+#endif
+               /* regular precision */
+               double num, denom, quotient, remainder;
+
+               num = double_to_int(nv.num_value);
+               denom = double_to_int(dv.num_value);
+
+               if (denom == 0.0)
+                       fatal(ext_id, _("intdiv: division by zero attempted"));
+
+               quotient = double_to_int(num / denom);
+#ifdef HAVE_FMOD
+               remainder = fmod(num, denom);
+#else  /* ! HAVE_FMOD */
+               (void) modf(num / denom, & remainder);
+               remainder = num - remainder * denom;
+#endif /* ! HAVE_FMOD */
+               remainder = double_to_int(remainder);
+
+               array_set_number(array, "quotient", 8, quotient);
+               array_set_number(array, "remainder", 9, remainder);
+#ifdef HAVE_MPFR
+       }
+       else {
+               /* extended precision */
+               mpz_ptr numer, denom;
+               mpz_t numer_tmp, denom_tmp;
+               mpz_ptr quotient, remainder;
+
+               /* convert numerator and denominator to integer */
+               if (!(numer = mpz_conv(&nv, numer_tmp))) {
+                       warning(ext_id, _("intdiv: numerator is not finite"));
+                       return make_number(-1, result);
+               }
+               if (!(denom = mpz_conv(&dv, denom_tmp))) {
+                       warning(ext_id, _("intdiv: denominator is not finite"));
+                       if (numer == numer_tmp)
+                               mpz_clear(numer);
+                       return make_number(-1, result);
+               }
+               if (mpz_sgn(denom) == 0) {
+                       warning(ext_id, _("intdiv: division by zero 
attempted"));
+                       if (numer == numer_tmp)
+                               mpz_clear(numer);
+                       if (denom == denom_tmp)
+                               mpz_clear(denom);
+                       return make_number(-1, result);
+               }
+
+               /* ask gawk to allocate return values for us */
+               quotient = get_mpz_ptr();
+               remainder = get_mpz_ptr();
+
+               /* do the division */
+               mpz_tdiv_qr(quotient, remainder, numer, denom);
+
+               array_set_mpz(array, "quotient", 8, quotient);
+               array_set_mpz(array, "remainder", 9, remainder);
+
+               /* release temporary variables */
+               if (numer == numer_tmp)
+                       mpz_clear(numer);
+               if (denom == denom_tmp)
+                       mpz_clear(denom);
+       }
+#endif
+
+       return make_number(0, result);
+}
+
+static awk_ext_func_t func_table[] = {
+       { "api_intdiv", do_intdiv, 3, 3, awk_false, NULL },
+};
+
+/* init_intdiv --- initialization routine */
+
+static awk_bool_t
+init_intdiv(void)
+{
+#ifdef HAVE_MPFR
+       check_mpfr_version(intdiv)
+#endif
+       return awk_true;
+}
+
+static awk_bool_t (*init_func)(void) = init_intdiv;
+
+/* define the dl_load function using the boilerplate macro */
+
+dl_load_func(func_table, intdiv, "")
diff --git a/gawkapi.c b/gawkapi.c
index 4c6a2f8..914d4fe 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -25,6 +25,14 @@
 
 #include "awk.h"
 
+#ifdef HAVE_MPFR
+#define getmpfr(n)     getblock(n, BLOCK_MPFR, mpfr_ptr)
+#define freempfr(n)    freeblock(n, BLOCK_MPFR)
+
+#define getmpz(n)      getblock(n, BLOCK_MPZ, mpz_ptr)
+#define freempz(n)     freeblock(n, BLOCK_MPZ)
+#endif
+
 /* Declare some globals used by api_get_file: */
 extern IOBUF *curfile;
 extern INSTRUCTION *main_beginfile;
@@ -159,7 +167,36 @@ awk_value_to_node(const awk_value_t *retval)
                ext_ret_val = dupnode(Nnull_string);
                break;
        case AWK_NUMBER:
-               ext_ret_val = make_number(retval->num_value);
+               switch (retval->num_type) {
+               case AWK_NUMBER_TYPE_DOUBLE:
+                       ext_ret_val = make_number(retval->num_value);
+                       break;
+               case AWK_NUMBER_TYPE_MPFR:
+#ifdef HAVE_MPFR
+                       if (! do_mpfr)
+                               fatal(_("awk_value_to_node: not in MPFR mode"));
+                       ext_ret_val = make_number_node(MPFN);
+                       memcpy(&ext_ret_val->mpg_numbr, retval->num_ptr, 
sizeof(ext_ret_val->mpg_numbr));
+                       freempfr(retval->num_ptr);
+#else
+                       fatal(_("awk_value_to_node: MPFR not supported"));
+#endif
+                       break;
+               case AWK_NUMBER_TYPE_MPZ:
+#ifdef HAVE_MPFR
+                       if (! do_mpfr)
+                               fatal(_("awk_value_to_node: not in MPFR mode"));
+                       ext_ret_val = make_number_node(MPZN);
+                       memcpy(&ext_ret_val->mpg_i, retval->num_ptr, 
sizeof(ext_ret_val->mpg_i));
+                       freempz(retval->num_ptr);
+#else
+                       fatal(_("awk_value_to_node: MPFR not supported"));
+#endif
+                       break;
+               default:
+                       fatal(_("awk_value_to_node: invalid number type `%d'"), 
retval->num_type);
+                       break;
+               }
                break;
        case AWK_STRING:
                ext_ret_val = make_str_node(retval->str_value.str,
@@ -450,6 +487,34 @@ assign_string(NODE *node, awk_value_t *val, awk_valtype_t 
val_type)
        val->str_value.len = node->stlen;
 }
 
+/* assign_number -- return a number node */
+
+static inline void
+assign_number(NODE *node, awk_value_t *val)
+{
+       val->val_type = AWK_NUMBER;
+       switch (node->flags & (MPFN|MPZN)) {
+       case 0:
+               val->num_value = node->numbr;
+               val->num_type = AWK_NUMBER_TYPE_DOUBLE;
+               val->num_ptr = NULL;
+               break;
+       case MPFN:
+               val->num_value = mpfr_get_d(node->mpg_numbr, ROUND_MODE);
+               val->num_type = AWK_NUMBER_TYPE_MPFR;
+               val->num_ptr = &node->mpg_numbr;
+               break;
+       case MPZN:
+               val->num_value = mpz_get_d(node->mpg_i);
+               val->num_type = AWK_NUMBER_TYPE_MPZ;
+               val->num_ptr = &node->mpg_i;
+               break;
+       default:
+               fatal(_("node_to_awk_value: detected invalid numeric flags 
combination `%s'; please file a bug report."), flags2str(node->flags));
+               break;
+       }
+}
+
 /* assign_regex --- return a regex node */
 
 static inline void
@@ -502,9 +567,8 @@ node_to_awk_value(NODE *node, awk_value_t *val, 
awk_valtype_t wanted)
                        if (node->flags & REGEX)
                                val->val_type = AWK_REGEX;
                        else {
-                               val->val_type = AWK_NUMBER;
                                (void) force_number(node);
-                               val->num_value = get_number_d(node);
+                               assign_number(node, val);
                                ret = awk_true;
                        }
                        break;
@@ -606,8 +670,7 @@ node_to_awk_value(NODE *node, awk_value_t *val, 
awk_valtype_t wanted)
                                ret = awk_true;
                                break;
                        case NUMBER:
-                               val->val_type = AWK_NUMBER;
-                               val->num_value = get_number_d(node);
+                               assign_number(node, val);
                                ret = awk_true;
                                break;
                        case NUMBER|USER_INPUT:
@@ -1220,6 +1283,36 @@ api_release_value(awk_ext_id_t id, awk_value_cookie_t 
value)
        return awk_true;
 }
 
+/* api_get_mpfr --- allocate an mpfr_ptr */
+
+static void *
+api_get_mpfr(awk_ext_id_t id)
+{
+#ifdef HAVE_MPFR
+       mpfr_ptr p;
+       getmpfr(p);
+       mpfr_init(p);
+       return p;
+#else
+       fatal(_("api_get_mpfr: MPFR not supported"));
+#endif
+}
+
+/* api_get_mpz --- allocate an mpz_ptr */
+
+static void *
+api_get_mpz(awk_ext_id_t id)
+{
+#ifdef HAVE_MPFR
+       mpz_ptr p;
+       getmpz(p);
+       mpz_init(p);
+       return p;
+#else
+       fatal(_("api_get_mpfr: MPFR not supported"));
+#endif
+}
+
 /* api_get_file --- return a handle to an existing or newly opened file */
 
 static awk_bool_t
@@ -1347,6 +1440,16 @@ gawk_api_t api_impl = {
        /* data */
        GAWK_API_MAJOR_VERSION, /* major and minor versions */
        GAWK_API_MINOR_VERSION,
+
+#ifdef HAVE_MPFR
+       __GNU_MP_VERSION,
+       __GNU_MP_VERSION_MINOR,
+       MPFR_VERSION_MAJOR,
+       MPFR_VERSION_MINOR,
+#else
+       0, 0, 0, 0,
+#endif
+
        { 0 },                  /* do_flags */
 
        /* registration functions */
@@ -1399,6 +1502,8 @@ gawk_api_t api_impl = {
        calloc,
        realloc,
        free,
+       api_get_mpfr,
+       api_get_mpz,
 
        /* Find/open a file */
        api_get_file,
diff --git a/gawkapi.h b/gawkapi.h
index 5071adc..5323bce 100644
--- a/gawkapi.h
+++ b/gawkapi.h
@@ -260,7 +260,7 @@ typedef struct awk_two_way_processor {
        awk_const struct awk_two_way_processor *awk_const next;  /* for use by 
gawk */
 } awk_two_way_processor_t;
 
-#define gawk_api_major_version 2
+#define gawk_api_major_version 3
 #define gawk_api_minor_version 0
 
 /* Current version of the API. */
@@ -286,6 +286,16 @@ typedef struct awk_string {
        size_t len;     /* length thereof, in chars */
 } awk_string_t;
 
+typedef struct awk_number {
+       double d;       /* always populated in data received from gawk */
+       enum AWK_NUMBER_TYPE {
+               AWK_NUMBER_TYPE_DOUBLE,
+               AWK_NUMBER_TYPE_MPFR,
+               AWK_NUMBER_TYPE_MPZ
+       } type;
+       void *ptr;      /* either NULL or mpfr_ptr or mpz_ptr */
+} awk_number_t;
+
 /* Arrays are represented as an opaque type. */
 typedef void *awk_array_t;
 
@@ -321,7 +331,7 @@ typedef struct awk_value {
        awk_valtype_t   val_type;
        union {
                awk_string_t    s;
-               double          d;
+               awk_number_t    n;
                awk_array_t     a;
                awk_scalar_t    scl;
                awk_value_cookie_t vc;
@@ -329,7 +339,9 @@ typedef struct awk_value {
 #define str_value      u.s
 #define strnum_value   str_value
 #define regex_value    str_value
-#define num_value      u.d
+#define num_value      u.n.d
+#define num_type       u.n.type
+#define num_ptr                u.n.ptr
 #define array_cookie   u.a
 #define scalar_cookie  u.scl
 #define value_cookie   u.vc
@@ -415,6 +427,12 @@ typedef struct gawk_api {
        awk_const int major_version;
        awk_const int minor_version;
 
+       /* GMP/MPFR versions, if extended-precision is available */
+       awk_const int gmp_major_version;
+       awk_const int gmp_minor_version;
+       awk_const int mpfr_major_version;
+       awk_const int mpfr_minor_version;
+
        /*
         * These can change on the fly as things happen within gawk.
         * Currently only do_lint is prone to change, but we reserve
@@ -711,6 +729,20 @@ typedef struct gawk_api {
        void *(*api_realloc)(void *ptr, size_t size);
        void (*api_free)(void *ptr);
 
+       /*
+        * A function that returns mpfr data should call this function
+        * to allocate and initialize an mpfr_ptr for use in an
+        * awk_value_t structure that will be handed to gawk.
+        */
+       void *(*api_get_mpfr)(awk_ext_id_t id);
+
+       /*
+        * A function that returns mpz data should call this function
+        * to allocate and initialize an mpz_ptr for use in an
+        * awk_value_t structure that will be handed to gawk.
+        */
+       void *(*api_get_mpz)(awk_ext_id_t id);
+
         /*
         * Look up a file.  If the name is NULL or name_len is 0, it returns
         * data for the currently open input file corresponding to FILENAME
@@ -743,7 +775,6 @@ typedef struct gawk_api {
                         */
                        const awk_input_buf_t **ibufp,
                        const awk_output_buf_t **obufp);
-
 } gawk_api_t;
 
 #ifndef GAWK   /* these are not for the gawk code itself! */
@@ -833,6 +864,9 @@ typedef struct gawk_api {
 #define get_file(name, namelen, filetype, fd, ibuf, obuf) \
        (api->api_get_file(ext_id, name, namelen, filetype, fd, ibuf, obuf))
 
+#define get_mpfr_ptr() (api->api_get_mpfr(ext_id))
+#define get_mpz_ptr() (api->api_get_mpz(ext_id))
+
 #define register_ext_version(version) \
        (api->api_register_ext_version(ext_id, version))
 
@@ -923,11 +957,39 @@ make_null_string(awk_value_t *result)
 static inline awk_value_t *
 make_number(double num, awk_value_t *result)
 {
-       memset(result, 0, sizeof(*result));
-
        result->val_type = AWK_NUMBER;
        result->num_value = num;
+       result->num_type = AWK_NUMBER_TYPE_DOUBLE;
+       return result;
+}
+
+/*
+ * make_number_mpz --- make an mpz number value in result.
+ * The mpz_ptr must be from a call to get_mpz_ptr. Gawk will now
+ * take ownership of this memory.
+ */
 
+static inline awk_value_t *
+make_number_mpz(void *mpz_ptr, awk_value_t *result)
+{
+       result->val_type = AWK_NUMBER;
+       result->num_type = AWK_NUMBER_TYPE_MPZ;
+       result->num_ptr = mpz_ptr;
+       return result;
+}
+
+/*
+ * make_number_mpfr --- make an mpfr number value in result.
+ * The mpfr_ptr must be from a call to get_mpfr_ptr. Gawk will now
+ * take ownership of this memory.
+ */
+
+static inline awk_value_t *
+make_number_mpfr(void *mpfr_ptr, awk_value_t *result)
+{
+       result->val_type = AWK_NUMBER;
+       result->num_type = AWK_NUMBER_TYPE_MPFR;
+       result->num_ptr = mpfr_ptr;
        return result;
 }
 
@@ -1020,6 +1082,29 @@ int dl_load(const gawk_api_t *const api_p, awk_ext_id_t 
id)  \
        return (errors == 0); \
 }
 
+/*
+ * If you are using extended-precision calculations in your library, please
+ * call this macro from your init_func.
+ */
+#define check_mpfr_version(extension) { \
+       if (api->gmp_major_version != __GNU_MP_VERSION \
+           || api->gmp_minor_version < __GNU_MP_VERSION_MINOR) { \
+               fprintf(stderr, #extension ": GMP version mismatch with 
gawk!\n"); \
+               fprintf(stderr, "\tmy version (%d, %d), gawk version (%d, 
%d)\n", \
+                       __GNU_MP_VERSION, __GNU_MP_VERSION_MINOR, \
+                       api->gmp_major_version, api->gmp_minor_version); \
+               exit(1); \
+       } \
+       if (api->mpfr_major_version != MPFR_VERSION_MAJOR \
+           || api->mpfr_minor_version < MPFR_VERSION_MINOR) { \
+               fprintf(stderr, #extension ": MPFR version mismatch with 
gawk!\n"); \
+               fprintf(stderr, "\tmy version (%d, %d), gawk version (%d, 
%d)\n", \
+                       MPFR_VERSION_MAJOR, MPFR_VERSION_MINOR, \
+                       api->mpfr_major_version, api->mpfr_minor_version); \
+               exit(1); \
+       } \
+}
+
 #endif /* GAWK */
 
 #ifdef __cplusplus
diff --git a/mpfr.c b/mpfr.c
index c0f1ff0..4b87566 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -105,26 +105,14 @@ cleanup_mpfr(void)
 NODE *
 mpg_node(unsigned int tp)
 {
-       NODE *r;
-       getnode(r);
-       r->type = Node_val;
+       NODE *r = make_number_node(tp);
 
-       if (tp == MPFN) {
+       if (tp == MPFN)
                /* Initialize, set precision to the default precision, and 
value to NaN */
                mpfr_init(r->mpg_numbr);
-               r->flags = MPFN;
-       } else {
+       else
                /* Initialize and set value to 0 */
                mpz_init(r->mpg_i);
-               r->flags = MPZN;
-       }
-
-       r->valref = 1;
-       r->flags |= MALLOC|NUMBER|NUMCUR;
-       r->stptr = NULL;
-       r->stlen = 0;
-       r->wstptr = NULL;
-       r->wstlen = 0;
        return r;
 }
 
diff --git a/node.c b/node.c
index 97f65fa..b83d2ac 100644
--- a/node.c
+++ b/node.c
@@ -332,16 +332,8 @@ r_dupnode(NODE *n)
 static NODE *
 r_make_number(double x)
 {
-       NODE *r;
-       getnode(r);
-       r->type = Node_val;
+       NODE *r = make_number_node(0);
        r->numbr = x;
-       r->flags = MALLOC|NUMBER|NUMCUR;
-       r->valref = 1;
-       r->stptr = NULL;
-       r->stlen = 0;
-       r->wstptr = NULL;
-       r->wstlen = 0;
        return r;
 }
 
@@ -1005,6 +997,10 @@ BLOCK nextfree[BLOCK_MAX] = {
        { 0, NULL},     /* invalid */
        { sizeof(NODE), NULL },
        { sizeof(BUCKET), NULL },
+#ifdef HAVE_MPFR
+       { sizeof(mpfr_t), NULL },
+       { sizeof(mpz_t), NULL },
+#endif
 };
 
 
@@ -1021,6 +1017,7 @@ more_blocks(int id)
 
        size = nextfree[id].size;
 
+       assert(size >= sizeof(BLOCK));
        emalloc(freep, BLOCK *, BLOCKCHUNK * size, "more_blocks");
        p = (char *) freep;
        endp = p + BLOCKCHUNK * size;

-----------------------------------------------------------------------


hooks/post-receive
-- 
gawk



reply via email to

[Prev in Thread] Current Thread [Next in Thread]