gawk-diffs
[Top][All Lists]
Advanced

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

[gawk-diffs] [SCM] gawk branch, long-double, created. 3963bf23516aa77888


From: Arnold Robbins
Subject: [gawk-diffs] [SCM] gawk branch, long-double, created. 3963bf23516aa778881f22ac785352e74fcf6c6f
Date: Fri, 01 Mar 2013 11:19:26 +0000

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, long-double has been created
        at  3963bf23516aa778881f22ac785352e74fcf6c6f (commit)

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

commit 3963bf23516aa778881f22ac785352e74fcf6c6f
Merge: cd119ad a274f1c
Author: John Haque <address@hidden>
Date:   Sun Feb 10 09:58:22 2013 -0600

    Merge branch 'num-handler' into long-double

diff --cc ChangeLog
index d271e22,1dcc301..208f3c1
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,41 -1,96 +1,135 @@@
 +2013-02-09         John Haque      <address@hidden>
 +
 +      * main.c (main): Added GAWK_FLOAT env. variable.
 +      * long_double.c: Remove all use of math functions for C-double as the 
fallback.
 +      Use ours in misc/gawk_math.c instead.
 +
+ 2013-02-06         Arnold D. Robbins     <address@hidden>
+ 
+       * builtin.c (printf_common): Move nargs > 0 check into assert.
+       (do_sprintf): Add nargs check and fatal message to here.
+ 
+ 2013-02-04         Arnold D. Robbins     <address@hidden>
+ 
+       * main.c (main): Remove undocumented -m option which was for
+       compatibility with BWK awk. His awk dropped it back in 2007.
+ 
+ 2013-02-03         Arnold D. Robbins     <address@hidden>
+ 
+       * configure.ac: Add Automake test for cross compiling.
+ 
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * regcomp.c, regex.c, regex_internal.c, regexec.c: Update
+       copyright years to sync with GLIBC.
+ 
+       From: http://www.sourceware.org/ml/libc-alpha/2013-01/msg00967.html,
+       by Andreas Schwab <address@hidden>:
+ 
+       * regexec.c (extend_buffers): Add parameter min_len.
+       (check_matching): Pass minimum needed length.
+       (clean_state_log_if_needed): Likewise.
+       (get_subexp): Likewise.`
+ 
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * dfa.c: Include "dfa.h" which includes regex.h after limits.h
+       so that RE_DUP_MAX gets the correct value. Especially needed on
+       OpenVMS. Thanks to Anders Wallin.
+ 
+       * main.c (version): Print out API version numbers if DYNAMIC.
+       Helpful also for knowing if to run the shlib tests.
+ 
+       * configure: Regenerated after change in m4/readline.m4.
+ 
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * PROBLEMS: Removed. It is no longer needed.
+       * Makefile.am (EXTRA_DIST): Remove PROBLEMS from list.
+ 
+ 2013-01-31         Andrew J. Schorr     <address@hidden>
+ 
+       * configure.ac: Remove TEST_MPFR conditional added in last patch.
+       We will instead test for MPFR capability by looking at the output
+       from gawk --version.
+ 
 +2013-01-27         John Haque      <address@hidden>
 +
 +      * long_double.c (GAWK_FORMAT_INT): New define.
 +      (format_float_1, format_uint_1, double_to_int): Move definitions here
 +      from long_double.h.
 +      * long_double.h (format_float_1, format_uint_1, double_to_int): Adjust.
 +
+ 2013-01-27         Andrew J. Schorr     <address@hidden>
+ 
+       * configure.ac: Add MPFR test for use in test/Makefile.am.
+ 
+ 2013-01-25         Arnold D. Robbins     <address@hidden>
+ 
+       * awkgram.y (parms_shadow): Change int param to bool.
+       * cmd.h (output_is_tty): Sync type with rest of code (is bool).
+       * dfa.c (MALLOC): Undef first, for Irix.
+       * Makefile.am (LDADD): Use LIBREADLINE and LIBMPFR instead of
+       automake substitutions.
+       * configure.ac (AC_INIT): Version bump.
+       (GAWK_CHECK_READLINE): Renamed from GNUPG_CHECK_READLINE.
+ 
 +2013-01-23         John Haque      <address@hidden>
 +
 +      * long_double.c (format_uint_1): New inline routines to format integers.
 +      * long_double.h (format_float_1): Remove integer formatting code.
 +      (format_awkldbl_printf): Use format_uint_1() to format integers.
 +      
++
+ 2013-01-23         Arnold D. Robbins     <address@hidden>
+ 
+       * awk.h (list_functions): Change parameter to bool.
+       * symbol.c (list_functions): Ditto.
+       (get_symbols): Change sort parameter to bool. Additional
+       code cleanup.
+ 
+ 2013-01-22         Arnold D. Robbins     <address@hidden>
+ 
+       * symbol.c (get_symbols): Reset count after each loop to only
+       sort the actual items retrieved. Thanks to Hermann Peifer (by
+       way of Andrew Schorr) for reporting the bug.  Also add some
+       commentary and fix function name in emalloc calls.
+ 
+ 2013-01-20         Arnold D. Robbins     <address@hidden>
+ 
+       * re.c (regexflags2str): New routine.
+       (resetup): If do_intervals, also turn on RE_NO_BK_BRACES.
+       Thanks to Yan Lei <address@hidden> for the
+       bug report.
+ 
 +2013-01-19         John Haque      <address@hidden>
 +
 +      For C long double and without "%Lf" in printf, provide "%.0Lf" to
 +      format 64-bit wide (and wider with a 128-bit long double) integers
 +      correctly; "%Lf" format support in printf is now optional. 
 +
 +      * awk.h (gawk_int_t, gawk_uint_t): New types.
 +      * long_double.c: Restructured. Swap code with long_double.h. 
 +      * long_double.h: Move all header includes and defines to long_double.c;
 +      It is a template to be included in a *.c file.
 +      (gawk_floorl_finite_p, format_uint_finite_p,
 +      format_float_1, init_pow2d_table): New routines.
 +      (double_to_int): Provide replacement routine definition.  
 +
 +      Unrelated:
 +
 +      * long_double.h (make_integer): Remove call to adjust_uint().
 +      Install similar code suitable for a long double.
 +
+ 2013-01-18         Arnold D. Robbins     <address@hidden>
+ 
+       Fix a problem with include ordering to get ptrdiff_t definition,
+       showed up on Debian Lenny. Reported by Manuel Collado.
+       Fix brought over from grep.
+ 
+       * dfa.h: Include regex.h and stddef.h directly.
+       * dfa.c: Adjust includes.
+ 
  2013-01-12         John Haque      <address@hidden>
  
        * format.c: New file.
@@@ -77,27 -161,27 +200,43 @@@
        New routines.
        (mpfp_format_nodes): Removed.
  
+ 2013-01-01         Arnold D. Robbins     <address@hidden>
+ 
+       Sync with GLIBC regex files.
+ 
+       * regex_internal.h (struct re_dfa_t): Remove ifdefs around
+       __libc_lock_define since it's already defined to empty in non-LIBC
+       case.
+       * regexec.c (check_node_accept_bytes): Restore decl with use from
+       GLIBC code since this is LIBC case.
+ 
 +2012-12-29         John Haque      <address@hidden>
 +
 +      Add support for long double numbers.
 +      
 +      * awk.h (awkldbl_hndlr): Declare.
 +      (enum block_id): Add BLOCK_LDBL.
 +      * gawkapi.c (api_sym_update_scalar): Update NODE flag
 +      after freeing number.
 +      * long_double.h: New file.
 +      * long_double.c: New file.
 +      * main.c (main): Added temporary option 'B' to select long double.
 +      (print_numbr_hndlr_versions(): New entry for awkldbl_hndlr.
 +      * node.c (BLOCK nextfree): New entry for long double.
 +      * configure.ac: Added GAWK_USE_LONG_DOUBLE.
 +      * Makefile.am: Added long_double.h and long_double.c.
 +
  2012-12-28         John Haque      <address@hidden>
  
        * double.c: Use make_awknum everywhere instead of make_number
 -      in case a routine is called using not the current handler
 +      in case a routine is called not using the current handler
        or before initialization.
+ 
+ 2012-12-27         Arnold D. Robbins     <address@hidden>
+ 
+       * builtin.c (do_print, do_printf): Use output_fp as default
+       output for print/printf only if running under the debugger.
+       Otherwise use stdout as Brian, Peter, and Al intended.
   
  2012-12-27         John Haque      <address@hidden>
  
diff --cc Makefile.am
index 5aec821,771e333..041d424
--- a/Makefile.am
+++ b/Makefile.am
@@@ -139,10 -131,8 +138,10 @@@ base_sources = 
  
  gawk_SOURCES = $(base_sources)
  
 +EXTRA_LIBS = misc/libmisc.a
 +
  # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
- LDADD = $(EXTRA_LIBS) $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ 
@LIBMPFR@
 -LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR)
++LDADD = $(EXTRA_LIBS) $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) 
$(LIBMPFR)
  
  # Directory for gawk's data files. Automake supplies datadir.
  pkgdatadir = $(datadir)/awk
diff --cc Makefile.in
index 007f0fa,67037c4..83725a8
--- a/Makefile.in
+++ b/Makefile.in
@@@ -119,8 -117,9 +119,9 @@@ am_gawk_OBJECTS = $(am__objects_1
  gawk_OBJECTS = $(am_gawk_OBJECTS)
  gawk_LDADD = $(LDADD)
  am__DEPENDENCIES_1 =
 -gawk_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 +gawk_DEPENDENCIES = $(EXTRA_LIBS) $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
 -      $(am__DEPENDENCIES_1)
 +      $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
  DEFAULT_INCLUDES = address@hidden@
  depcomp = $(SHELL) $(top_srcdir)/depcomp
  am__depfiles_maybe = depfiles
@@@ -468,10 -460,9 +468,10 @@@ base_sources = 
        xalloc.h
  
  gawk_SOURCES = $(base_sources)
 +EXTRA_LIBS = misc/libmisc.a
  
  # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
- LDADD = $(EXTRA_LIBS) $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ 
@LIBMPFR@
 -LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) $(LIBMPFR)
++LDADD = $(EXTRA_LIBS) $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) $(LIBREADLINE) 
$(LIBMPFR)
  
  # stuff for compiling gawk/pgawk
  DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"'
diff --cc m4/ChangeLog
index 5754845,418cf04..0ee0017
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@@ -1,15 -1,14 +1,26 @@@
 +2013-02-09         John Haque      <address@hidden>
 +
 +      * long_double.m4: Reworked.
 +
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * readline.m4: Add cross-compiling action.
+ 
+ 2013-01-25         Arnold D. Robbins     <address@hidden>
+ 
+       * readline.m4 (GAWK_CHECK_READLINE): Renamed from GNUPG_CHECK_READLINE.
+       Test program changed and test changed to try to run the built program
+       since some systems don't notice a link dependency between libreadline
+       and other libs until runtime. Isn't that fun?
+ 
 +2013-01-19         John Haque      <address@hidden>
 +
 +      * long_double.m4: Make "%Lf" support in printf optional.
 +
 +2012-12-29         John Haque      <address@hidden>
 +
 +      * long_double.m4: New file.
 +
  2012-12-24         Arnold D. Robbins     <address@hidden>
  
        * 4.0.2: Release tar ball made.
@@@ -24,10 -23,10 +35,6 @@@
        Remove files related to libtool support.  Libtool usage has been
        pushed down into the extension directory.
  
--2012-04-01         John Haque      <address@hidden>
--
--      * mpfr.m4: New file.
--
  2012-04-27         Arnold D. Robbins     <address@hidden>
  
        Update to autoconf 2.69, automake 1.12.
diff --cc main.c
index 04c9314,8331055..d89d7e8
--- a/main.c
+++ b/main.c
@@@ -206,7 -204,7 +206,7 @@@ main(int argc, char **argv
        /*
         * The + on the front tells GNU getopt not to rearrange argv.
         */
-       const char *optlist = 
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::B::MPrStVY";
 -      const char *optlist = "+F:f:v:W;bcCd::D::e:E:gh:i:l:L:nNo::Op::MPrStVY";
++      const char *optlist = 
"+F:f:v:W;bcCd::D::e:E:gh:i:l:L:nNo::Op::B::MPrStVY";
        bool stopped_early = false;
        int old_optind;
        int i;

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=a274f1cd5ddbfc3137f5342b601b1fbee913e879

commit a274f1cd5ddbfc3137f5342b601b1fbee913e879
Merge: 21e6675 a9b8d46
Author: John Haque <address@hidden>
Date:   Sun Feb 10 09:44:52 2013 -0600

    Merge branch 'master' into num-handler

diff --cc ChangeLog
index 64e2601,887f857..1dcc301
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,59 -1,145 +1,197 @@@
+ 2013-02-06         Arnold D. Robbins     <address@hidden>
+ 
+       * builtin.c (printf_common): Move nargs > 0 check into assert.
+       (do_sprintf): Add nargs check and fatal message to here.
+ 
+ 2013-02-04         Arnold D. Robbins     <address@hidden>
+ 
+       * main.c (main): Remove undocumented -m option which was for
+       compatibility with BWK awk. His awk dropped it back in 2007.
+ 
++2013-02-03         Arnold D. Robbins     <address@hidden>
++
++      * configure.ac: Add Automake test for cross compiling.
++
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * regcomp.c, regex.c, regex_internal.c, regexec.c: Update
+       copyright years to sync with GLIBC.
+ 
+       From: http://www.sourceware.org/ml/libc-alpha/2013-01/msg00967.html,
+       by Andreas Schwab <address@hidden>:
+ 
+       * regexec.c (extend_buffers): Add parameter min_len.
+       (check_matching): Pass minimum needed length.
+       (clean_state_log_if_needed): Likewise.
+       (get_subexp): Likewise.`
+ 
 -<<<<<<< HEAD
 -2013-02-03         Arnold D. Robbins     <address@hidden>
 -
 -      * configure.ac: Add Automake test for cross compiling.
 -
 -=======
 ->>>>>>> gawk-4.0-stable
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * dfa.c: Include "dfa.h" which includes regex.h after limits.h
+       so that RE_DUP_MAX gets the correct value. Especially needed on
+       OpenVMS. Thanks to Anders Wallin.
 -<<<<<<< HEAD
++
+       * main.c (version): Print out API version numbers if DYNAMIC.
+       Helpful also for knowing if to run the shlib tests.
+ 
+       * configure: Regenerated after change in m4/readline.m4.
 -=======
 ->>>>>>> gawk-4.0-stable
+ 
+ 2013-01-31         Arnold D. Robbins     <address@hidden>
+ 
+       * PROBLEMS: Removed. It is no longer needed.
+       * Makefile.am (EXTRA_DIST): Remove PROBLEMS from list.
+ 
+ 2013-01-31         Andrew J. Schorr     <address@hidden>
+ 
+       * configure.ac: Remove TEST_MPFR conditional added in last patch.
+       We will instead test for MPFR capability by looking at the output
+       from gawk --version.
+ 
+ 2013-01-27         Andrew J. Schorr     <address@hidden>
+ 
+       * configure.ac: Add MPFR test for use in test/Makefile.am.
+ 
+ 2013-01-25         Arnold D. Robbins     <address@hidden>
+ 
+       * awkgram.y (parms_shadow): Change int param to bool.
+       * cmd.h (output_is_tty): Sync type with rest of code (is bool).
+       * dfa.c (MALLOC): Undef first, for Irix.
+       * Makefile.am (LDADD): Use LIBREADLINE and LIBMPFR instead of
+       automake substitutions.
+       * configure.ac (AC_INIT): Version bump.
+       (GAWK_CHECK_READLINE): Renamed from GNUPG_CHECK_READLINE.
+ 
+ 2013-01-23         Arnold D. Robbins     <address@hidden>
+ 
+       * awk.h (list_functions): Change parameter to bool.
+       * symbol.c (list_functions): Ditto.
+       (get_symbols): Change sort parameter to bool. Additional
+       code cleanup.
+ 
+ 2013-01-22         Arnold D. Robbins     <address@hidden>
+ 
+       * symbol.c (get_symbols): Reset count after each loop to only
+       sort the actual items retrieved. Thanks to Hermann Peifer (by
+       way of Andrew Schorr) for reporting the bug.  Also add some
+       commentary and fix function name in emalloc calls.
+ 
+ 2013-01-20         Arnold D. Robbins     <address@hidden>
+ 
+       * re.c (regexflags2str): New routine.
+       (resetup): If do_intervals, also turn on RE_NO_BK_BRACES.
+       Thanks to Yan Lei <address@hidden> for the
+       bug report.
+ 
+ 2013-01-18         Arnold D. Robbins     <address@hidden>
+ 
+       Fix a problem with include ordering to get ptrdiff_t definition,
+       showed up on Debian Lenny. Reported by Manuel Collado.
+       Fix brought over from grep.
+ 
+       * dfa.h: Include regex.h and stddef.h directly.
+       * dfa.c: Adjust includes.
+ 
 +2013-01-12         John Haque      <address@hidden>
 +
 +      * format.c: New file.
 +      * Makefile.am: Add format.c to the list of files.
 +      * builtin.c (format_tree, format_nondecimal, fmt_parse,
 +      get_fmt_buf, mbc_byte_count, mbc_char_count): Move to format.c.
 +
 +2013-01-11         John Haque      <address@hidden>
 +
 +      Finish format_tree() refactoring.
 +
 +      * awk.h (struct fmt_list_item): New definition.
 +      * builtin.c (fmt_parse): New routine to parse a single format code.
 +      (format_tree): Adjusted.
 +      * eval.c (fmt_index): (Pre-)compile and store format codes.
 +      * double.c (format_awknum_val): Reworked to use compiled
 +      format codes.
 +      * mpfr.c (mpfp_format_val): Ditto.
 +
+ 2013-01-11         John Haque            <address@hidden>
+ 
+       * awk.h (do_mpfr_rshift): Renamed from do_mpfr_rhift.
+       * awkgram.y (do_mpfr_rshift): Renamed from do_mpfr_rhift.
+       * mpfr.c (_tz1, _tz2, _mpz1, _mpz2, mpz1, mpz2, get_bit_ops,
+       free_bit_ops): Removed.
+       (init_mpfr): Remove calls to mpz_init.
+       (get_intval, free_intval): New functions.
+       (do_mpfr_rshift, do_mpfr_lshift): Rework code.
+       (do_mpfr_and, do_mpfr_or, do_mpfr_xor): Accept two or more arguments
+       to match regular functions.
+ 
+ 2013-01-11         Arnold D. Robbins     <address@hidden>
+ 
+       * bisonfix.awk: Adjust ARGV / ARGC to force reading of standard
+       input; apparently needed for Mac OS X. Thanks to Akim Demaille
+       for the report.
+ 
+ 2013-01-06         Arnold D. Robbins     <address@hidden>
+ 
+       * io.c (redirect, two_way_open): Set the name field in the
+       awk_input_buf_t and awk_output_buf_t structures, as needed.
+       Thanks to Manuel Collado for the report.
+ 
+ 2013-01-05         Arnold D. Robbins     <address@hidden>
+ 
+       * regex_internal.h (struct re_dfa_t): Restore ifdefs around
+       __libc_lock_define, they really were needed. Bleah.
+ 
 +2013-01-03         John Haque      <address@hidden>
 +
 +      Refactor format_tree() to seperate number formatting code.
 +
 +      * format.h: New file.
 +      (format_spec, print_fmt_buf): Definitions.
 +      (chksize, bchunk, bchunk_one, buf_adjust, buf2node,
 +      tmpbuf_prepend, pr_fill, pr_num_tail, free_print_fmt_buf):
 +      Inline routines.
 +      * awk.h (num_handler_t): New fields gawk_format_printf,
 +      gawk_isnan, gawk_isinf. Removed field gawk_format_nodes.
 +      * builtin.c (chksize__internal, cpbuf_chksize__internal,
 +      get_fmt_buf, format_nondecimal): New routines.
 +      (format_tree): Restore function format_tree(). Adjusted to call
 +      the current number formatting routine.
 +      * double.c (awknum_isnan, awknum_isinf, format_awknum_printf):
 +      New routines.
 +      (format_nodes_awknum): Removed.
 +      * mpfr.c (mpfp_isnan, mpfp_isinf, mpfp_format_printf):
 +      New routines.
 +      (mpfp_format_nodes): Removed.
 +
+ 2013-01-01         Arnold D. Robbins     <address@hidden>
+ 
+       Sync with GLIBC regex files.
+ 
+       * regex_internal.h (struct re_dfa_t): Remove ifdefs around
+       __libc_lock_define since it's already defined to empty in non-LIBC
+       case.
+       * regexec.c (check_node_accept_bytes): Restore decl with use from
+       GLIBC code since this is LIBC case.
+ 
 +2012-12-28         John Haque      <address@hidden>
 +
 +      * double.c: Use make_awknum everywhere instead of make_number
 +      in case a routine is called using not the current handler
 +      or before initialization.
++
+ 2012-12-27         Arnold D. Robbins     <address@hidden>
+ 
+       * builtin.c (do_print, do_printf): Use output_fp as default
+       output for print/printf only if running under the debugger.
+       Otherwise use stdout as Brian, Peter, and Al intended.
 + 
 +2012-12-27         John Haque      <address@hidden>
 +
 +      Number handling interface.
 +      
 +      * awk.h (numbr_handler_t, bltin_t): New definitions.
 +      * double.c: New file for C double numbers.
 +      * mpfr.c: Reworked.
 +
 +      Lots of other changes.
  
  2012-12-25         Arnold D. Robbins     <address@hidden>
  
diff --cc awklib/ChangeLog
index 178ce8b,e286a46..07274f9
--- a/awklib/ChangeLog
+++ b/awklib/ChangeLog
@@@ -1,7 -1,12 +1,16 @@@
+ 2013-02-03         Arnold D. Robbins     <address@hidden>
+ 
+       * Makefile.am (AWKPROG): Add definition and conditional for
+       cross compiling. Thanks to Juergen Kahrs.
+ 
+ 2013-01-08         Andrew J. Schorr     <address@hidden>
+ 
+       * eg/lib/inplace.awk: Add new file generated from doc/gawk.texi.
+ 
 +2013-01-06         John Haque            <address@hidden>
 +
 +      * eg/lib/repl_math.awk: New file.
 +
  2012-12-24         Arnold D. Robbins     <address@hidden>
  
        * 4.0.2: Release tar ball made.
diff --cc main.c
index c7e9a89,785935e..8331055
--- a/main.c
+++ b/main.c
@@@ -1417,7 -1412,12 +1403,10 @@@ static voi
  version()
  {
        printf("%s", version_string);
+ #ifdef DYNAMIC
+       printf(", API: %d.%d", GAWK_API_MAJOR_VERSION, GAWK_API_MINOR_VERSION);
+ #endif
 -#ifdef HAVE_MPFR
 -      printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
 -#endif
 +      print_numbr_hndlr_versions();
        printf("\n"); 
        print_ext_versions();
  

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=cd119adb52dac187fcbc7b225fb0ded8d8e5a293

commit cd119adb52dac187fcbc7b225fb0ded8d8e5a293
Author: John Haque <address@hidden>
Date:   Sat Feb 9 22:03:30 2013 -0600

    Add README.LONG_DOUBLE, made other changes for `make check' to use long 
double.

diff --git a/ChangeLog b/ChangeLog
index 4caad77..d271e22 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-02-09         John Haque      <address@hidden>
+
+       * main.c (main): Added GAWK_FLOAT env. variable.
+       * long_double.c: Remove all use of math functions for C-double as the 
fallback.
+       Use ours in misc/gawk_math.c instead.
+
 2013-01-27         John Haque      <address@hidden>
 
        * long_double.c (GAWK_FORMAT_INT): New define.
diff --git a/README.LONG_DOUBLE b/README.LONG_DOUBLE
new file mode 100644
index 0000000..880a1b1
--- /dev/null
+++ b/README.LONG_DOUBLE
@@ -0,0 +1,241 @@
+Compiling and running the tests in `test' directory
+===================================================
+
+$ ./configure
+$ grep USE_LONG_DOUBLE config.h
+#define USE_LONG_DOUBLE 1
+
+Usable long double found!
+
+$ make
+
+A single invocation of `make check' will run the test suite
+using long double first, and then double:
+
+$ make check
+ ...
+ ...
+double tests: ALL TESTS PASSED
+long double tests: ALL TESTS PASSED
+
+The Makefile etc. used for the long double tests are in the
+misc/ldbl_tests directory. The _foo files for any failed tests
+using long double numbers will also be in that directory.
+Currently, `make diffout' does not work for the long double tests.
+
+There are no additional tests for long doubles (yet).
+
+Running scripts
+===============
+
+1) Using command line option:
+$ ./gawk -B -f xx.awk
+$ ./gawk -B '...'
+
+2) Using environment variable GAWK_FLOAT.
+
+$ export GAWK_FLOAT=LDBL
+
+All scripts can then use long double for numbers without
+needing the -B option:
+
+$ ./gawk -f xx.awk
+$ ./gawk '...'
+
+unset GAWK_FLOAT to use the C-double type.
+
+
+Informational
+=============
+
+[1] Requirements for usable long double type (see m4/long_double.m4):
+
+     USE_LONG_DOUBLE = false
+     if have_long_double
+          if LDBL_MANT_DIG > DBL_MANT_DIG
+                  && LDBL_MAX_EXP >= DBL_MAX_EXP
+                  && LDBL_MIN_EXP <= DBL_MIN_EXP
+               USE_LONG_DOUBLE = true
+          end if
+     end if
+
+     if USE_LONG_DOUBLE = true
+          * check for %Lf support in printf; if not present format
+           integers ourself, and use %f for floats.
+          * check for strtold; if not found, use strtod.
+          * if not found ANY of cosl, sinl, atan2l, logl, expl, powl, sqrtl,
+            use our math functions, and NOT the double versions in libm.
+          * check for fmodl seperately; if not found, use our's and NOT fmod.
+          * check for floorl and ceill; if not found, use our integer
+            formatting code to provide equivalent functionalities.
+     end if
+
+In addition to providing a precision more than that for a double, we
+require support for the four basic math operators +, -, * and /
+for the range of floats acceptable for gawk. This minimum requirement
+may or may not be met by some double-double implementations like the
+ones found in various versions of AIX.
+
+[2] Failed tests or unexpected results can be either due to bugs in
+gawk code or somewhere else. Bug(s) in glibc 2.11.1 causes the test
+ofmta.awk to fail:
+
+$ ./gawk -B -vOFMT=%.3f 'BEGIN { x=1.2345; print x }'
+1.235
+
+The expected result is 1.234.
+
+---------------------------------------------------------------------
+From: "Nelson H. F. Beebe"
+
+You commented on this autoconf fragment:
+
+  AC_REQUIRE([AC_TYPE_LONG_DOUBLE])
+  if test $ac_cv_type_long_double = yes; then
+    AC_CACHE_CHECK([whether long double and double are the same],
+     [gl_cv_long_double_equals_double],
+     [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM([[#include <float.h>]],
+         [[typedef int check[sizeof (long double) == sizeof (double)
+                           && LDBL_MANT_DIG == DBL_MANT_DIG
+                           && LDBL_MAX_EXP == DBL_MAX_EXP
+                           && LDBL_MIN_EXP == DBL_MIN_EXP
+                              ? 1 : -1];
+         ]])],
+       [gl_cv_long_double_equals_double=yes],
+       [gl_cv_long_double_equals_double=no])
+     ])
+
+...
+
+Indeed, the code is gcc-dependent, but it is on the right track.  The
+problem is that, while long double has been widely implemented on many
+systems for a long time (even pre-1990), on others it is badly
+botched.  Apple gets a failing grade for NEVER EVER having provided a
+Fortran compiler on Mac OS (now almost 30 years old), and for never
+providing long double support, even on processors like x86 that have
+had it in hardware since 1980.  The BSD people are also guilty; none
+of {Free,Mir,Net,Open}BSD have ever provided long double, and worse,
+some of them have the long double parameters in their header files,
+like <float.h>, but the compilers don't support the data type.
+
+The autoconf code could be rewritten to use a run-time, rather than
+compile-timne, test, reporting whether any of the four equalities fail
+to hold. 
+
+Here is what I wrote in hoc's configure.in script (feel free to
+re-use, and revise as needed for your gawk work; no credits or
+licenses are necessary):
+
+dnl Old: (checks that long double recognized by compiler, even if synonym for 
double)
+dnl AC_CHECK_TYPES(long double)
+dnl New and improved: (checks that long double has greater range and precision)
+dnl The autoconf-2.59 (and earlier) AC_C_LONG_DOUBLE produces a
+dnl nonstandard C program that fails to compile on most systems: bug
+dnl reported on [02-Jun-2004].  Redefine it with my proposed replacement:
+
+AC_DEFUN([AC_C_LONG_DOUBLE],
+       [AC_CACHE_CHECK(for usable long double,
+               ac_cv_c_long_double,
+               [AC_RUN_IFELSE(
+[
+#include <stdio.h>
+#include <float.h>
+
+int
+main()
+{
+#if defined(__NetBSD__)
+       return (1);     /* hack for NetBSD, which has compiler support, but no 
long double library support */
+#endif
+    return (!((DBL_MAX < LDBL_MAX) &&
+             (DBL_MAX > 0.5 * DBL_MAX) &&
+             (LDBL_MAX > 0.5L * LDBL_MAX) &&
+             (LDBL_EPSILON < DBL_EPSILON) &&
+             (LDBL_MIN < DBL_MIN) &&
+             (DBL_MIN > 0.0) &&
+             (LDBL_MIN > 0.0L) &&
+             (DBL_MAX_EXP < LDBL_MAX_EXP) &&
+             (DBL_MANT_DIG < LDBL_MANT_DIG)));
+}
+],
+               ac_cv_c_long_double=yes,
+               ac_cv_c_long_double=no,
+               ac_cv_c_long_double=no)])
+       if test ${ac_cv_c_long_double} = yes
+       then
+               AC_DEFINE(HAVE_LONG_DOUBLE, 1, [Define if the `long double' 
type works.])
+       fi
+       ]) # end AC_C_LONG_DOUBLE
+
+AC_C_LONG_DOUBLE
+
+if test -n "$HAVE_FP_T_QUADRUPLE"
+then
+       if test ${ac_cv_c_long_double} = "no"
+       then
+               AC_MSG_WARN(**************************************************)
+               AC_MSG_WARN(reverting to --with-double on this system       **)
+               AC_MSG_WARN(because long double is a synonym for double, or **)
+               AC_MSG_WARN(is unsupported by the selected compiler         **)
+               AC_MSG_WARN(**************************************************)
+               AC_DEFINE(HAVE_FP_T_DOUBLE)
+               HAVE_FP_T_DOUBLE=1
+               unset HAVE_FP_T_QUADRUPLE
+               HOCSUFFIX=64
+               TESTFP=test64
+       else
+               case "`uname -m || true`" in
+               i386 | i486 | i586 | i686 | i86pc | ia64 | x86_64)
+                       AC_DEFINE(HAVE_FP_T_QUADRUPLE)
+                       HAVE_FP_T_QUADRUPLE=1
+                       HOCSUFFIX=80
+                       TESTFP=test80
+                       ;;
+               ppc | ppc64 )
+                       
AC_MSG_WARN(**************************************************)
+                       AC_MSG_WARN(reverting to --with-double on this system   
    **)
+                       AC_MSG_WARN(because long double is a synonym for double 
    **)
+                       
AC_MSG_WARN(**************************************************)
+                       AC_DEFINE(HAVE_FP_T_DOUBLE)
+                       HAVE_FP_T_DOUBLE=1
+                       unset HAVE_FP_T_QUADRUPLE
+                       HOCSUFFIX=64
+                       TESTFP=test64
+                       ;;
+               *)      case "`uname -s || true`" in
+                       AIX | IRIX* )
+                               
AC_MSG_WARN(**************************************************)
+                               AC_MSG_WARN(reverting to --with-double on this 
system       **)
+                               AC_MSG_WARN(because long double is a broken 
implementation  **)
+                               AC_MSG_WARN(using paired doubles                
            **)
+                               
AC_MSG_WARN(**************************************************)
+                               AC_DEFINE(HAVE_FP_T_DOUBLE)
+                               HAVE_FP_T_DOUBLE=1
+                               unset HAVE_FP_T_QUADRUPLE
+                               HOCSUFFIX=64
+                               TESTFP=test64
+                               ;;
+                       Darwin* | Rhapsody* )
+                               
AC_MSG_WARN(**************************************************)
+                               AC_MSG_WARN(reverting to --with-double on this 
system       **)
+                               AC_MSG_WARN(because long double is a synonym 
for double, or **)
+                               AC_MSG_WARN(is unsupported by the selected 
compiler         **)
+                               
AC_MSG_WARN(**************************************************)
+                               AC_DEFINE(HAVE_FP_T_DOUBLE)
+                               HAVE_FP_T_DOUBLE=1
+                               unset HAVE_FP_T_QUADRUPLE
+                               HOCSUFFIX=64
+                               TESTFP=test64
+                               ;;
+                       *)
+                               AC_DEFINE(HAVE_FP_T_QUADRUPLE)
+                               HAVE_FP_T_QUADRUPLE=1
+                               HOCSUFFIX=128
+                               TESTFP=test128
+                               ;;
+                       esac
+                       ;;
+               esac
+       fi
+fi
diff --git a/TODO.LDBL b/TODO.LDBL
deleted file mode 100644
index 61f073a..0000000
--- a/TODO.LDBL
+++ /dev/null
@@ -1,27 +0,0 @@
-* Replacement math routines. - DONE.
-   Update awk version fp_math.awk for the changes in C code ?
-   FUTURE: Improvemnet/Optimization.
-     [1] Use truncated Taylor series and/or approximating polynomials.
-         It would require at least two versions (80-bit and 128-bit).
-     [2] Horner's rule to evaluate truncated series.
-     [3] Payne and Hanek Reduction Algorithm to provide more sig digs
-         for sin and cos with large arguments. It most likely involves more
-         than just extending the PI table to few thousand entries.
-         Pay particular attention to the case when x is almost an integer
-         multiple of PI/2. For a clean-room implementation, consider the
-         feasibility of using (64-bit) integer arithmetic.
-         References:
-         * Elementary Functions: Algorithms and Implementation. Jean-Michel 
Muller,
-           Birkhäuser Boston.
-        * Handbook of Floating-Point Arithmetic. Jean-Michel Muller et. el.,
-           Birkhäuser Boston.
-         * Argument Reduction for Huge Arguments: Good to the Last Bit. K. C. 
Ng,
-           SunPro, Sun Microsystems, Inc. Business.
-           Original fdmlib implementation copied by most libm.
-       
-*  Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM.
-   What is the point of floor() and ceil() wrappers? Don't have a clue.
-   - DONE. Not sure if it is necessary for any long double and uintmax_t
-          combination found in the wild. Looks like ceil() and floor()
-           wrappers are for VMS; One probably should update comments
-           in floatcomp.c.
diff --git a/configh.in b/configh.in
index 66511a9..eab487c 100644
--- a/configh.in
+++ b/configh.in
@@ -20,9 +20,6 @@
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #undef HAVE_ARPA_INET_H
 
-/* Define to 1 if you have 'atan2l' function. */
-#undef HAVE_ATAN2L
-
 /* Define to 1 if you have the `atexit' function. */
 #undef HAVE_ATEXIT
 
@@ -40,9 +37,6 @@
    the CoreFoundation framework. */
 #undef HAVE_CFPREFERENCESCOPYAPPVALUE
 
-/* Define to 1 if you have 'cosl' function. */
-#undef HAVE_COSL
-
 /* Define if the GNU dcgettext() function is already present or preinstalled.
    */
 #undef HAVE_DCGETTEXT
@@ -54,9 +48,6 @@
 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
 #undef HAVE_DOPRNT
 
-/* Define to 1 if you have 'expl' function. */
-#undef HAVE_EXPL
-
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
@@ -129,9 +120,6 @@
 /* Define to 1 if you have the <locale.h> header file. */
 #undef HAVE_LOCALE_H
 
-/* Define to 1 if you have 'logl' function. */
-#undef HAVE_LOGL
-
 /* Define to 1 if the system has the type `long double'. */
 #undef HAVE_LONG_DOUBLE
 
@@ -186,9 +174,6 @@
 /* Define to 1 if you have the `posix_openpt' function. */
 #undef HAVE_POSIX_OPENPT
 
-/* Define to 1 if you have 'powl' function. */
-#undef HAVE_POWL
-
 /* Define to 1 if you have the `setenv' function. */
 #undef HAVE_SETENV
 
@@ -198,9 +183,6 @@
 /* Define to 1 if you have the `setsid' function. */
 #undef HAVE_SETSID
 
-/* Define to 1 if you have 'sinl' function. */
-#undef HAVE_SINL
-
 /* Define to 1 if you have the `snprintf' function. */
 #undef HAVE_SNPRINTF
 
@@ -210,9 +192,6 @@
 /* we have sockets on this system */
 #undef HAVE_SOCKETS
 
-/* Define to 1 if you have 'sqrtl' function. */
-#undef HAVE_SQRTL
-
 /* Define to 1 if you have the <stdarg.h> header file. */
 #undef HAVE_STDARG_H
 
@@ -411,6 +390,9 @@
 /* Define to 1 if your <sys/time.h> declares `struct tm'. */
 #undef TM_IN_SYS_TIME
 
+/* Define to 1 if you need our math functions. */
+#undef USE_INCLUDED_MATH_FUNCS
+
 /* force use of our version of strftime */
 #undef USE_INCLUDED_STRFTIME
 
diff --git a/configure b/configure
index 2896259..96eaccb 100755
--- a/configure
+++ b/configure
@@ -10238,36 +10238,44 @@ $as_echo "$has_f_format" >&6; }
   if test $ac_cv_type_long_double = yes; then
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether long double and 
double are the same" >&5
 $as_echo_n "checking whether long double and double are the same... " >&6; }
-if ${gl_cv_long_double_equals_double+:} false; then :
+if ${gawk_cv_long_double_equals_double+:} false; then :
   $as_echo_n "(cached) " >&6
 else
+  if test "$cross_compiling" = yes; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 #include <float.h>
 int
 main ()
 {
-typedef int check[sizeof (long double) == sizeof (double)
-                           && LDBL_MANT_DIG == DBL_MANT_DIG
-                           && LDBL_MAX_EXP == DBL_MAX_EXP
-                           && LDBL_MIN_EXP == DBL_MIN_EXP
-                              ? 1 : -1];
+
+            return ! (LDBL_MANT_DIG > DBL_MANT_DIG
+                       && LDBL_MAX_EXP >= DBL_MAX_EXP
+                       && LDBL_MIN_EXP <= DBL_MIN_EXP);
 
   ;
   return 0;
 }
 _ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  gl_cv_long_double_equals_double=yes
+if ac_fn_c_try_run "$LINENO"; then :
+  gawk_cv_long_double_equals_double=no
 else
-  gl_cv_long_double_equals_double=no
+  gawk_cv_long_double_equals_double=yes
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$gl_cv_long_double_equals_double" >&5
-$as_echo "$gl_cv_long_double_equals_double" >&6; }
-    if test $gl_cv_long_double_equals_double = no; then
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$gawk_cv_long_double_equals_double" >&5
+$as_echo "$gawk_cv_long_double_equals_double" >&6; }
+    if test $gawk_cv_long_double_equals_double = no; then
       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether printf 
supports %Lf" >&5
 $as_echo_n "checking whether printf supports %Lf... " >&6; }
 if ${gawk_cv_has_L_format+:} false; then :
@@ -10333,6 +10341,8 @@ $as_echo "#define HAVE_STRTOLD 1" >>confdefs.h
 
     fi
 
+    LONG_DOUBLE_SAVE_LIBS=$LIBS
+    gawk_use_included_math=no
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sinl in -lm" >&5
 $as_echo_n "checking for sinl in -lm... " >&6; }
 if ${ac_cv_lib_m_sinl+:} false; then :
@@ -10378,11 +10388,6 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_sinl = yes; then
-
-$as_echo "#define HAVE_SINL 1" >>confdefs.h
-
-    fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cosl in -lm" >&5
 $as_echo_n "checking for cosl in -lm... " >&6; }
 if ${ac_cv_lib_m_cosl+:} false; then :
@@ -10428,11 +10433,6 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_cosl = yes; then
-
-$as_echo "#define HAVE_COSL 1" >>confdefs.h
-
-    fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l in -lm" >&5
 $as_echo_n "checking for atan2l in -lm... " >&6; }
 if ${ac_cv_lib_m_atan2l+:} false; then :
@@ -10478,11 +10478,6 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_atan2l = yes; then
-
-$as_echo "#define HAVE_ATAN2L 1" >>confdefs.h
-
-    fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl in -lm" >&5
 $as_echo_n "checking for logl in -lm... " >&6; }
 if ${ac_cv_lib_m_logl+:} false; then :
@@ -10528,11 +10523,6 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_logl = yes; then
-
-$as_echo "#define HAVE_LOGL 1" >>confdefs.h
-
-    fi
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl in -lm" >&5
 $as_echo_n "checking for expl in -lm... " >&6; }
 if ${ac_cv_lib_m_expl+:} false; then :
@@ -10578,14 +10568,9 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_expl = yes; then
-
-$as_echo "#define HAVE_EXPL 1" >>confdefs.h
-
-    fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl in -lm" >&5
-$as_echo_n "checking for fmodl in -lm... " >&6; }
-if ${ac_cv_lib_m_fmodl+:} false; then :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl in -lm" >&5
+$as_echo_n "checking for powl in -lm... " >&6; }
+if ${ac_cv_lib_m_powl+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
@@ -10599,27 +10584,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char fmodl ();
+char powl ();
 int
 main ()
 {
-return fmodl ();
+return powl ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_m_fmodl=yes
+  ac_cv_lib_m_powl=yes
 else
-  ac_cv_lib_m_fmodl=no
+  ac_cv_lib_m_powl=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_fmodl" >&5
-$as_echo "$ac_cv_lib_m_fmodl" >&6; }
-if test "x$ac_cv_lib_m_fmodl" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_powl" >&5
+$as_echo "$ac_cv_lib_m_powl" >&6; }
+if test "x$ac_cv_lib_m_powl" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
 _ACEOF
@@ -10628,14 +10613,9 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_fmodl = yes; then
-
-$as_echo "#define HAVE_FMODL 1" >>confdefs.h
-
-    fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for floorl in -lm" >&5
-$as_echo_n "checking for floorl in -lm... " >&6; }
-if ${ac_cv_lib_m_floorl+:} false; then :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl in -lm" >&5
+$as_echo_n "checking for sqrtl in -lm... " >&6; }
+if ${ac_cv_lib_m_sqrtl+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
@@ -10649,27 +10629,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char floorl ();
+char sqrtl ();
 int
 main ()
 {
-return floorl ();
+return sqrtl ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_m_floorl=yes
+  ac_cv_lib_m_sqrtl=yes
 else
-  ac_cv_lib_m_floorl=no
+  ac_cv_lib_m_sqrtl=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floorl" >&5
-$as_echo "$ac_cv_lib_m_floorl" >&6; }
-if test "x$ac_cv_lib_m_floorl" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrtl" >&5
+$as_echo "$ac_cv_lib_m_sqrtl" >&6; }
+if test "x$ac_cv_lib_m_sqrtl" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
 _ACEOF
@@ -10678,14 +10658,19 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_floorl = yes; then
+    if test $ac_cv_lib_m_sinl = no || test $ac_cv_lib_m_cosl = no \
+          || test $ac_cv_lib_m_atan2l = no ||  test $ac_cv_lib_m_logl = no \
+         || test $ac_cv_lib_m_expl = no ||  test $ac_cv_lib_m_powl = no \
+         || test $ac_cv_lib_m_sqrtl = no; then
+       gawk_use_included_math=yes
 
-$as_echo "#define HAVE_FLOORL 1" >>confdefs.h
+$as_echo "#define USE_INCLUDED_MATH_FUNCS 1" >>confdefs.h
 
     fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ceill in -lm" >&5
-$as_echo_n "checking for ceill in -lm... " >&6; }
-if ${ac_cv_lib_m_ceill+:} false; then :
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl in -lm" >&5
+$as_echo_n "checking for fmodl in -lm... " >&6; }
+if ${ac_cv_lib_m_fmodl+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
@@ -10699,27 +10684,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char ceill ();
+char fmodl ();
 int
 main ()
 {
-return ceill ();
+return fmodl ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_m_ceill=yes
+  ac_cv_lib_m_fmodl=yes
 else
-  ac_cv_lib_m_ceill=no
+  ac_cv_lib_m_fmodl=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_ceill" >&5
-$as_echo "$ac_cv_lib_m_ceill" >&6; }
-if test "x$ac_cv_lib_m_ceill" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_fmodl" >&5
+$as_echo "$ac_cv_lib_m_fmodl" >&6; }
+if test "x$ac_cv_lib_m_fmodl" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
 _ACEOF
@@ -10728,14 +10713,14 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_ceill = yes; then
+    if test $ac_cv_lib_m_fmodl = yes; then
 
-$as_echo "#define HAVE_CEILL 1" >>confdefs.h
+$as_echo "#define HAVE_FMODL 1" >>confdefs.h
 
     fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl in -lm" >&5
-$as_echo_n "checking for powl in -lm... " >&6; }
-if ${ac_cv_lib_m_powl+:} false; then :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for floorl in -lm" >&5
+$as_echo_n "checking for floorl in -lm... " >&6; }
+if ${ac_cv_lib_m_floorl+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
@@ -10749,27 +10734,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char powl ();
+char floorl ();
 int
 main ()
 {
-return powl ();
+return floorl ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_m_powl=yes
+  ac_cv_lib_m_floorl=yes
 else
-  ac_cv_lib_m_powl=no
+  ac_cv_lib_m_floorl=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_powl" >&5
-$as_echo "$ac_cv_lib_m_powl" >&6; }
-if test "x$ac_cv_lib_m_powl" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floorl" >&5
+$as_echo "$ac_cv_lib_m_floorl" >&6; }
+if test "x$ac_cv_lib_m_floorl" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
 _ACEOF
@@ -10778,14 +10763,14 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_powl = yes; then
+    if test $ac_cv_lib_m_floorl = yes; then
 
-$as_echo "#define HAVE_POWL 1" >>confdefs.h
+$as_echo "#define HAVE_FLOORL 1" >>confdefs.h
 
     fi
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl in -lm" >&5
-$as_echo_n "checking for sqrtl in -lm... " >&6; }
-if ${ac_cv_lib_m_sqrtl+:} false; then :
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ceill in -lm" >&5
+$as_echo_n "checking for ceill in -lm... " >&6; }
+if ${ac_cv_lib_m_ceill+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
@@ -10799,27 +10784,27 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char sqrtl ();
+char ceill ();
 int
 main ()
 {
-return sqrtl ();
+return ceill ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_m_sqrtl=yes
+  ac_cv_lib_m_ceill=yes
 else
-  ac_cv_lib_m_sqrtl=no
+  ac_cv_lib_m_ceill=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrtl" >&5
-$as_echo "$ac_cv_lib_m_sqrtl" >&6; }
-if test "x$ac_cv_lib_m_sqrtl" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_ceill" >&5
+$as_echo "$ac_cv_lib_m_ceill" >&6; }
+if test "x$ac_cv_lib_m_ceill" = xyes; then :
   cat >>confdefs.h <<_ACEOF
 #define HAVE_LIBM 1
 _ACEOF
@@ -10828,11 +10813,17 @@ _ACEOF
 
 fi
 
-    if test $ac_cv_lib_m_sqrtl = yes; then
+    if test $ac_cv_lib_m_ceill = yes; then
 
-$as_echo "#define HAVE_SQRTL 1" >>confdefs.h
+$as_echo "#define HAVE_CEILL 1" >>confdefs.h
 
     fi
+    if test $ac_cv_lib_m_fmodl = yes || test $ac_cv_lib_m_floorl = yes \
+          || test $ac_cv_lib_m_ceill = yes || test $gawk_use_included_math = 
no; then
+       LIBS="$LONG_DOUBLE_SAVE_LIBS -lm"
+    else
+       LIBS="$LONG_DOUBLE_SAVE_LIBS"
+    fi
   fi
 
 
@@ -11532,7 +11523,7 @@ dylib)  GAWKLIBEXT=so ;;        # MacOS uses .dylib for 
shared libraries, but libtool us
 esac
 
 
-ac_config_files="$ac_config_files Makefile awklib/Makefile doc/Makefile 
po/Makefile.in test/Makefile"
+ac_config_files="$ac_config_files Makefile awklib/Makefile doc/Makefile 
po/Makefile.in test/Makefile misc/ldbl_tests/Makefile"
 
 
 
@@ -12284,6 +12275,7 @@ do
     "doc/Makefile") CONFIG_FILES="$CONFIG_FILES doc/Makefile" ;;
     "po/Makefile.in") CONFIG_FILES="$CONFIG_FILES po/Makefile.in" ;;
     "test/Makefile") CONFIG_FILES="$CONFIG_FILES test/Makefile" ;;
+    "misc/ldbl_tests/Makefile") CONFIG_FILES="$CONFIG_FILES 
misc/ldbl_tests/Makefile" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
diff --git a/configure.ac b/configure.ac
index 8d1e9b0..54efa88 100644
--- a/configure.ac
+++ b/configure.ac
@@ -390,6 +390,7 @@ AC_CONFIG_FILES(Makefile
        awklib/Makefile
        doc/Makefile
        po/Makefile.in
-       test/Makefile)
+       test/Makefile
+       misc/ldbl_tests/Makefile)
 AC_CONFIG_SUBDIRS(extension)
 AC_OUTPUT
diff --git a/long_double.c b/long_double.c
index d604893..08fb807 100644
--- a/long_double.c
+++ b/long_double.c
@@ -67,64 +67,22 @@
 #define get_long_double(d)     getblock(d, BLOCK_LDBL, AWKLDBL *)
 #define free_long_double(d)    freeblock(d, BLOCK_LDBL)
 
-#ifdef HAVE_SINL
-#define gawk_sinl      sinl
+#ifdef USE_INCLUDED_MATH_FUNCS
+#include "misc/gawk_math.h"
 #else
-static inline AWKLDBL
-gawk_sinl(AWKLDBL x)
-{
-       return sin( (double) x);
-}
-#endif
-
-#ifdef HAVE_COSL 
+#define gawk_sinl      sinl
 #define gawk_cosl      cosl
-#else
-static inline AWKLDBL
-gawk_cosl(AWKLDBL x)
-{
-       return cos( (double) x);
-}
-#endif
-
-#ifdef HAVE_ATAN2L
 #define gawk_atan2l    atan2l
-#else
-static inline AWKLDBL
-gawk_atan2l(AWKLDBL y, AWKLDBL x)
-{
-       return atan2( (double) y, (double) x);
-}
-#endif
-
-#ifdef HAVE_LOGL
 #define gawk_logl      logl
-#else
-static inline AWKLDBL
-gawk_logl(AWKLDBL x)
-{
-       return log( (double) x);
-}
-#endif
-
-#ifdef HAVE_EXPL
 #define gawk_expl      expl
-#else
-static inline AWKLDBL
-gawk_expl(AWKLDBL x)
-{
-       return exp( (double) x);
-}
+#define gawk_powl      powl
+#define gawk_sqrtl     sqrtl
 #endif
 
 #ifdef HAVE_FMODL
 #define gawk_fmodl     fmodl
 #else
-static inline AWKLDBL
-gawk_fmodl(AWKLDBL x, AWKLDBL y)
-{
-       return fmod( (double) x, (double) y);
-}
+static AWKLDBL gawk_fmodl(AWKLDBL x, AWKLDBL y);
 #endif
 
 #ifdef HAVE_STRTOLD
@@ -137,27 +95,16 @@ gawk_strtold(const char *str, char **endptr)
 }
 #endif
 
-#ifdef HAVE_POWL
-#define gawk_powl      powl
+#if defined(USE_INCLUDED_MATH_FUNCS) || ! defined(HAVE_FMODL) 
+#define GAWK_INFINITY  HUGE_VALL
+#define GAWK_NAN       (LDC(0.0) / LDC(0.0))
+#if GAWK_LDBL_FRAC_BITS > 64 
+#define REL_ERROR      LDC(1.0e-35)
 #else
-static inline AWKLDBL
-gawk_powl(AWKLDBL x, AWKLDBL y)
-{
-       return pow( (double) x, (double) y);
-}
+#define REL_ERROR      LDC(1.0e-20)
 #endif
-
-#ifdef HAVE_SQRTL
-#define gawk_sqrtl     sqrtl
-#else
-static inline AWKLDBL
-gawk_sqrtl(AWKLDBL x)
-{
-       return sqrt( (double) x);
-}
 #endif
 
-
 /* N.B: if floorl() or ceill() or "%Lf" is missing format integers ourself */
 
 #if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL) && 
defined(PRINTF_HAS_LF_FORMAT)) 
@@ -262,6 +209,7 @@ double_to_int(AWKLDBL x)
 
 
 #include "long_double.h"
+#include "misc/gawk_math.c"
 
 #else  /* ! USE_LONG_DOUBLE */
 
@@ -295,6 +243,5 @@ get_ldbl_handler(char *arg)
        if (arg != NULL && arg[0] == '0')
                return & float80_hndlr;
 #endif
-
        return  & awkldbl_hndlr;
 }
diff --git a/m4/ChangeLog b/m4/ChangeLog
index ea46ed3..5754845 100644
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,7 @@
+2013-02-09         John Haque      <address@hidden>
+
+       * long_double.m4: Reworked.
+
 2013-01-19         John Haque      <address@hidden>
 
        * long_double.m4: Make "%Lf" support in printf optional.
diff --git a/m4/long_double.m4 b/m4/long_double.m4
index 5cac44d..f435dc6 100644
--- a/m4/long_double.m4
+++ b/m4/long_double.m4
@@ -4,14 +4,6 @@ dnl This file is free software; the Free Software Foundation
 dnl gives unlimited permission to copy and/or distribute it,
 dnl with or without modifications, as long as this notice is preserved.
 
-dnl size comparison copied from gnulib math_h.m4 serial 114
-dnl gl_LONG_DOUBLE_VS_DOUBLE
-dnl determines whether 'long double' and 'double' have the same representation.
-dnl Sets variable HAVE_SAME_LONG_DOUBLE_AS_DOUBLE to 0 or 1, and defines
-dnl HAVE_SAME_LONG_DOUBLE_AS_DOUBLE accordingly.
-dnl The currently known platforms where this is the case are:
-dnl Linux/HPPA, Minix 3.1.8, AIX 5, AIX 6 and 7 with xlc, MSVC 9.
-
 dnl Defines USE_LONG_DOUBLE to 1 if long double is found and usable.
 dnl Also checks for math functions with long double arguments.
 
@@ -23,19 +15,18 @@ AC_DEFUN([GAWK_USE_LONG_DOUBLE],
   AC_REQUIRE([AC_TYPE_LONG_DOUBLE])
   if test $ac_cv_type_long_double = yes; then
     AC_CACHE_CHECK([whether long double and double are the same],
-     [gl_cv_long_double_equals_double],
-     [AC_COMPILE_IFELSE(
+     [gawk_cv_long_double_equals_double],
+     [AC_RUN_IFELSE(
        [AC_LANG_PROGRAM([[#include <float.h>]],
-         [[typedef int check[sizeof (long double) == sizeof (double)
-                           && LDBL_MANT_DIG == DBL_MANT_DIG
-                           && LDBL_MAX_EXP == DBL_MAX_EXP
-                           && LDBL_MIN_EXP == DBL_MIN_EXP
-                              ? 1 : -1];
-         ]])],
-       [gl_cv_long_double_equals_double=yes],
-       [gl_cv_long_double_equals_double=no])
+         [[
+            return ! (LDBL_MANT_DIG > DBL_MANT_DIG
+                       && LDBL_MAX_EXP >= DBL_MAX_EXP
+                       && LDBL_MIN_EXP <= DBL_MIN_EXP);        
+          ]])],
+       [gawk_cv_long_double_equals_double=no],
+       [gawk_cv_long_double_equals_double=yes])
      ])
-    if test $gl_cv_long_double_equals_double = no; then
+    if test $gawk_cv_long_double_equals_double = no; then
       AC_CACHE_CHECK([whether printf supports %Lf],
        [gawk_cv_has_L_format],
        [AC_RUN_IFELSE(
@@ -66,26 +57,23 @@ AC_DEFUN([GAWK_USE_LONG_DOUBLE],
       AC_DEFINE([HAVE_STRTOLD], 1, [Define to 1 if you have 'strtold' 
function.])
     fi
 
+    LONG_DOUBLE_SAVE_LIBS=$LIBS
+    gawk_use_included_math=no
     AC_CHECK_LIB(m, sinl)
-    if test $ac_cv_lib_m_sinl = yes; then
-      AC_DEFINE([HAVE_SINL], 1,        [Define to 1 if you have 'sinl' 
function.])
-    fi
     AC_CHECK_LIB(m, cosl)
-    if test $ac_cv_lib_m_cosl = yes; then
-      AC_DEFINE([HAVE_COSL], 1,        [Define to 1 if you have 'cosl' 
function.])
-    fi
     AC_CHECK_LIB(m, atan2l)
-    if test $ac_cv_lib_m_atan2l = yes; then
-      AC_DEFINE([HAVE_ATAN2L], 1, [Define to 1 if you have 'atan2l' function.])
-    fi
     AC_CHECK_LIB(m, logl)
-    if test $ac_cv_lib_m_logl = yes; then
-      AC_DEFINE([HAVE_LOGL], 1,        [Define to 1 if you have 'logl' 
function.])
-    fi
     AC_CHECK_LIB(m, expl)
-    if test $ac_cv_lib_m_expl = yes; then
-      AC_DEFINE([HAVE_EXPL], 1,        [Define to 1 if you have 'expl' 
function.])
+    AC_CHECK_LIB(m, powl)
+    AC_CHECK_LIB(m, sqrtl)
+    if test $ac_cv_lib_m_sinl = no || test $ac_cv_lib_m_cosl = no \
+          || test $ac_cv_lib_m_atan2l = no ||  test $ac_cv_lib_m_logl = no \
+         || test $ac_cv_lib_m_expl = no ||  test $ac_cv_lib_m_powl = no \
+         || test $ac_cv_lib_m_sqrtl = no; then
+       gawk_use_included_math=yes
+       AC_DEFINE([USE_INCLUDED_MATH_FUNCS], 1, [Define to 1 if you need our 
math functions.])
     fi
+
     AC_CHECK_LIB(m, fmodl)
     if test $ac_cv_lib_m_fmodl = yes; then
       AC_DEFINE([HAVE_FMODL], 1, [Define to 1 if you have 'fmodl' function.])
@@ -98,13 +86,11 @@ AC_DEFUN([GAWK_USE_LONG_DOUBLE],
     if test $ac_cv_lib_m_ceill = yes; then
       AC_DEFINE([HAVE_CEILL], 1, [Define to 1 if you have 'ceill' function.])
     fi
-    AC_CHECK_LIB(m, powl)
-    if test $ac_cv_lib_m_powl = yes; then
-      AC_DEFINE([HAVE_POWL], 1,        [Define to 1 if you have 'powl' 
function.])
-    fi
-    AC_CHECK_LIB(m, sqrtl)
-    if test $ac_cv_lib_m_sqrtl = yes; then
-      AC_DEFINE([HAVE_SQRTL], 1, [Define to 1 if you have 'sqrtl' function.])
+    if test $ac_cv_lib_m_fmodl = yes || test $ac_cv_lib_m_floorl = yes \
+          || test $ac_cv_lib_m_ceill = yes || test $gawk_use_included_math = 
no; then
+       LIBS="$LONG_DOUBLE_SAVE_LIBS -lm"
+    else
+       LIBS="$LONG_DOUBLE_SAVE_LIBS"
     fi
   fi
 
diff --git a/main.c b/main.c
index 7857c42..04c9314 100644
--- a/main.c
+++ b/main.c
@@ -216,9 +216,21 @@ main(int argc, char **argv)
        int have_srcfile = 0;
        SRCFILE *s;
        bltin_t *numbr_bltins;
+       const char *float_type;
 
        /* default number handler */
        numbr_hndlr = & awknum_hndlr;
+       if ((float_type = getenv("GAWK_FLOAT")) != NULL) {
+               /*
+                * XXX: This is needed to run the test suite.
+                * Should be ifdef'ed out, but not on NUMEBUG or GAWKDEBUG.
+                */
+
+               if (strcmp(float_type, "LDBL") == 0)
+                       numbr_hndlr = & awkldbl_hndlr;
+               else if (strcmp(float_type, "MPFR") == 0)
+                       numbr_hndlr = & mpfp_hndlr;
+       }
 
        /* do these checks early */
        if (getenv("TIDYMEM") != NULL)
diff --git a/misc/ChangeLog b/misc/ChangeLog
index 0e38871..c0fb388 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,4 +1,10 @@
-013-02-08         John Haque            <address@hidden>
+2013-02-09         John Haque            <address@hidden>
+
+       * ldbl-tests: Renamed directory to gawk_libm_tests.
+       * ldbl_tests/(Makefile.am, Makefile.in, Gentests, Maketests): New files.
+       * Makefile: Updated.
+
+2013-02-08         John Haque            <address@hidden>
 
        * gawk_math.c (gawk_fmodl): Add new routine.
        (gawk_sinl, gawk_cosl): Update to handle huge arguments.
diff --git a/misc/Makefile b/misc/Makefile
index e2a1bb1..3ff1556 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -1,5 +1,3 @@
-LIBSTATIC = libmisc.a
-
 CC = gcc
 LD = gcc
 AR = ar
@@ -7,9 +5,13 @@ CMP = cmp
 
 srcdir = .
 top_srcdir = ..
+top_builddir = ..
 
 AWKPROG = $(top_srcdir)/gawk
 AWK = LC_ALL=C LANG=C $(AWKPROG)
+LIBM_DIR = gawk_libm_tests
+
+LIBSTATIC = libmisc.a
 
 ALL_CFLAGS = $(CFLAGS) -fPIC -DGAWK -DHAVE_CONFIG_H -c -I.. -I.
 
@@ -30,10 +32,17 @@ float80.o: float80.c $(top_srcdir)/awk.h 
$(top_srcdir)/long_double.h $(srcdir)/g
 
 clean:
        rm -f $(OBJS) $(LIBSTATIC)
+       cd $(LIBM_DIR) && rm -f core core.* _*
+       cd ldbl_tests && $(MAKE) clean
 
 distclean: clean
 
 check:
+       @if grep 'USE_LONG_DOUBLE 1' $(top_builddir)/config.h > /dev/null ; 
then \
+          cd ldbl_tests && $(MAKE) check GAWK_FLOAT=LDBL ; \
+       else \
+          echo long double is not supported on this system ; \
+       fi ;
 
 LDBL_TESTS = \
        ldblint64 \
@@ -55,7 +64,7 @@ LDBL_TESTS = \
        fmod64 \
        fmod113
 
-INFILE = ldbl-tests/data.in
+INFILE = $(LIBM_DIR)/data.in
 
 # An attempt to print something that can be grepped for in build logs
 pass-fail:
@@ -65,8 +74,8 @@ pass-fail:
        else    echo $$COUNT TESTS FAILED ; \
        fi
 
-ldbl-tests: $(LDBL_TESTS)
-       @$(MAKE) pass-fail TESTDIR=ldbl-tests
+libm-tests: $(LDBL_TESTS)
+       @$(MAKE) pass-fail TESTDIR=$(LIBM_DIR)
 
 
 $(INFILE):
@@ -74,107 +83,107 @@ $(INFILE):
 
 ldblint64:
        @echo $@
-       @$(AWK) -B0 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
-       @-$(CMP) ldbl-tests/address@hidden ldbl-tests/_$@ && rm -f 
ldbl-tests/_$@
+       @$(AWK) -B0 -f $(LIBM_DIR)/address@hidden > $(LIBM_DIR)/_$@ 2>&1
+       @-$(CMP) $(LIBM_DIR)/address@hidden $(LIBM_DIR)/_$@ && rm -f 
$(LIBM_DIR)/_$@
 
 ldblint128:
        @echo $@
-       @$(AWK) -B1 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
-       @-$(CMP) ldbl-tests/address@hidden ldbl-tests/_$@ && rm -f 
ldbl-tests/_$@
+       @$(AWK) -B1 -f $(LIBM_DIR)/address@hidden > $(LIBM_DIR)/_$@ 2>&1
+       @-$(CMP) $(LIBM_DIR)/address@hidden $(LIBM_DIR)/_$@ && rm -f 
$(LIBM_DIR)/_$@
 
 sqrt64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sqrt.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sqrt.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/sqrt.awk $(INFILE) > 
$(LIBM_DIR)/_$@ 2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/sqrt.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 sqrt113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sqrt.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sqrt.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/sqrt.awk $(INFILE) > 
$(LIBM_DIR)/_$@ 2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/sqrt.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 log64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/log.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/log.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/log.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/log.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 log113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/log.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/log.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/log.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/log.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 exp64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/exp.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/exp.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/exp.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/exp.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 exp113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/exp.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/exp.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/exp.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/exp.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 pow64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/pow.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/pow.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -vTOL=10 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/pow.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/pow.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -vTOL=10 -f floatcmp.awk $(LIBM_DIR)/_$@ 
$(LIBM_DIR)/address@hidden && rm $(LIBM_DIR)/_$@
 
 pow113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/pow.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/pow.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -vTOL=20 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/pow.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/pow.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -vTOL=20 -f floatcmp.awk $(LIBM_DIR)/_$@ 
$(LIBM_DIR)/address@hidden && rm $(LIBM_DIR)/_$@
 
 sin64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sin.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sin.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/sin.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/sin.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 sin113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sin.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sin.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/sin.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/sin.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 cos64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/cos.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/cos.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/cos.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/cos.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 cos113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/cos.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/cos.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/cos.awk $(INFILE) > $(LIBM_DIR)/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/cos.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 atan64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/atan2.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/atan2.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/atan2.awk $(INFILE) > 
$(LIBM_DIR)/_$@ 2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/atan2.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 atan113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/atan2.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/atan2.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/atan2.awk $(INFILE) > 
$(LIBM_DIR)/_$@ 2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/atan2.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 fmod64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/fmod.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/fmod.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B0 -vDIG=17 -f $(LIBM_DIR)/fmod.awk $(INFILE) > 
$(LIBM_DIR)/_$@ 2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f $(LIBM_DIR)/fmod.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
 
 fmod113: $(INFILE)
        @echo $@
        @echo 'This may take a while.'
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/fmod.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/fmod.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
-       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f $(LIBM_DIR)/fmod.awk $(INFILE) > 
$(LIBM_DIR)/_$@ 2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f $(LIBM_DIR)/fmod.awk $(INFILE) > 
$(LIBM_DIR)/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk $(LIBM_DIR)/_$@ $(LIBM_DIR)/address@hidden 
&& rm $(LIBM_DIR)/_$@
diff --git a/misc/TODO.LDBL b/misc/TODO.LDBL
new file mode 100644
index 0000000..c43383a
--- /dev/null
+++ b/misc/TODO.LDBL
@@ -0,0 +1,48 @@
+* Replacement math routines. - DONE.
+   Update awk version fp_math.awk for the changes in C code ?
+   FUTURE: Improvements/Optimizations.
+     [1] Use truncated Taylor series and/or approximating polynomials.
+         It would require at least two versions (80-bit and 128-bit).
+     [2] Horner's rule to evaluate truncated series.
+     [3] Payne and Hanek Reduction Algorithm to provide more sig digs
+         for sin and cos with large arguments. It most likely involves more
+         than just extending the 2/PI table to few thousand entries.
+         Pay particular attention to the case when x is almost an integer
+         multiple of PI/2. For a clean-room implementation, consider the
+         feasibility of using (64-bit) integer arithmetic.
+
+        Also, will need to incorporate the "tail" part of an argument in
+        series approxmations: 
+              sin(x + dx) ~ sin(x) + cos(x) * dx
+                          ~ sin(x) + (1 - x * x/2) * dx
+         Similarly,
+              cos(x + dx) ~ cos(x) - sin(x)* dx
+                           ~ cos(x) - x * dx
+
+        Actual implementation may involve rearrangements of the terms, e.g.
+        combining the low part of the series expansion with the contribution
+         from the tail part of the argument.
+
+        This is mostly an academic exercise; One can often get the few extra
+        digits for free on the platform with 80-bit long doubles.
+
+         References:
+         * Elementary Functions: Algorithms and Implementation. Jean-Michel 
Muller,
+           Birkhäuser Boston.
+         * Handbook of Floating-Point Arithmetic. Jean-Michel Muller et. el.,
+           Birkhäuser Boston.
+         * Argument Reduction for Huge Arguments: Good to the Last Bit. K. C. 
Ng,
+           SunPro, Sun Microsystems, Inc. Business.
+           Original fdmlib implementation copied by most libm.
+
+     [4] fmod computation with 128-bit floats is currently very slow.
+       
+*  Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM.
+          - DONE. Not sure if it is necessary for any long double and uintmax_t
+          combination found in the wild. Looks like ceil() and floor()
+           wrappers are for VMS; One probably should update comments
+           in floatcomp.c.
+
+* NUMINT flag not used in the long double (and also arbitrary-precision float)
+code? The (future) changes needed to use integer-indexed awk arrays may
+have some implications?
diff --git a/misc/float128.c b/misc/float128.c
index d5fefab..0b57f40 100644
--- a/misc/float128.c
+++ b/misc/float128.c
@@ -150,6 +150,14 @@ numbr_handler_t float128_hndlr;
 
 #define awkldbl_hndlr float128_hndlr
 
+#ifndef USE_INCLUDED_MATH_FUNCS
+#define USE_INCLUDED_MATH_FUNCS
+#endif
+#ifdef HAVE_FMODL
+#undef HAVE_FMODL
+static AWKLDBL gawk_fmodl(AWKLDBL x, AWKLDBL y);
+#endif
+
 #include "misc/gawk_math.h"
 #include "long_double.h"
 #include "misc/gawk_math.c"
diff --git a/misc/float80.c b/misc/float80.c
index 263b6a6..6b331a4 100644
--- a/misc/float80.c
+++ b/misc/float80.c
@@ -86,6 +86,14 @@ numbr_handler_t float80_hndlr;
 
 #define awkldbl_hndlr float80_hndlr
 
+#ifndef USE_INCLUDED_MATH_FUNCS
+#define USE_INCLUDED_MATH_FUNCS
+#endif
+#ifdef HAVE_FMODL
+#undef HAVE_FMODL
+static AWKLDBL gawk_fmodl(AWKLDBL x, AWKLDBL y);
+#endif
+
 #include "misc/gawk_math.h"
 #include "long_double.h"
 #include "misc/gawk_math.c"
diff --git a/misc/ldbl-tests/atan2.awk b/misc/gawk_libm_tests/atan2.awk
similarity index 100%
rename from misc/ldbl-tests/atan2.awk
rename to misc/gawk_libm_tests/atan2.awk
diff --git a/misc/ldbl-tests/cos.awk b/misc/gawk_libm_tests/cos.awk
similarity index 100%
rename from misc/ldbl-tests/cos.awk
rename to misc/gawk_libm_tests/cos.awk
diff --git a/misc/ldbl-tests/exp.awk b/misc/gawk_libm_tests/exp.awk
similarity index 100%
rename from misc/ldbl-tests/exp.awk
rename to misc/gawk_libm_tests/exp.awk
diff --git a/misc/ldbl-tests/fmod.awk b/misc/gawk_libm_tests/fmod.awk
similarity index 100%
rename from misc/ldbl-tests/fmod.awk
rename to misc/gawk_libm_tests/fmod.awk
diff --git a/misc/ldbl-tests/ldblint128.awk 
b/misc/gawk_libm_tests/ldblint128.awk
similarity index 100%
rename from misc/ldbl-tests/ldblint128.awk
rename to misc/gawk_libm_tests/ldblint128.awk
diff --git a/misc/ldbl-tests/ldblint128.ok b/misc/gawk_libm_tests/ldblint128.ok
similarity index 100%
rename from misc/ldbl-tests/ldblint128.ok
rename to misc/gawk_libm_tests/ldblint128.ok
diff --git a/misc/ldbl-tests/ldblint64.awk b/misc/gawk_libm_tests/ldblint64.awk
similarity index 100%
rename from misc/ldbl-tests/ldblint64.awk
rename to misc/gawk_libm_tests/ldblint64.awk
diff --git a/misc/ldbl-tests/ldblint64.ok b/misc/gawk_libm_tests/ldblint64.ok
similarity index 100%
rename from misc/ldbl-tests/ldblint64.ok
rename to misc/gawk_libm_tests/ldblint64.ok
diff --git a/misc/ldbl-tests/log.awk b/misc/gawk_libm_tests/log.awk
similarity index 100%
rename from misc/ldbl-tests/log.awk
rename to misc/gawk_libm_tests/log.awk
diff --git a/misc/ldbl-tests/pow.awk b/misc/gawk_libm_tests/pow.awk
similarity index 100%
rename from misc/ldbl-tests/pow.awk
rename to misc/gawk_libm_tests/pow.awk
diff --git a/misc/ldbl-tests/sin.awk b/misc/gawk_libm_tests/sin.awk
similarity index 100%
rename from misc/ldbl-tests/sin.awk
rename to misc/gawk_libm_tests/sin.awk
diff --git a/misc/ldbl-tests/sqrt.awk b/misc/gawk_libm_tests/sqrt.awk
similarity index 100%
rename from misc/ldbl-tests/sqrt.awk
rename to misc/gawk_libm_tests/sqrt.awk
diff --git a/misc/gawk_math.c b/misc/gawk_math.c
index bafe833..1e6448e 100644
--- a/misc/gawk_math.c
+++ b/misc/gawk_math.c
@@ -48,14 +48,145 @@
 #define        GAWK_PI_4_MED   LDC(2.632161460363116600724708860070677474e-10) 
/* 32-bit 2nd part */
 #define        GAWK_PI_4_LOW   LDC(1.500889318411548350422246024296643642e-19) 
/* variable precision 3rd part */
 
+
+#if ! defined(HAVE_FMODL) || defined(USE_INCLUDED_MATH_FUNCS) 
+/*
+ * gawk_frexpl --- split the number x into a normalized fraction and an 
exponent.
+ *     The fraction is in the range [1, 2) (and NOT [0.5, 1)).
+ */
+
+static AWKLDBL
+gawk_frexpl(AWKLDBL x, int *exponent)
+{
+       AWKLDBL y;
+       unsigned low, high, mid;
+
+       /* (isnormal(x) && x > 0) is assumed to be true */
+
+       assert(exponent != NULL);
+       *exponent = 0;
+
+       low = 0;
+       if (x > _2L) {
+               high = GAWK_LDBL_MAX_EXP - 1;
+               while (low <= high) {
+                       mid = (low + high) / 2;
+                       y = x / pow2ld(mid);
+                       if (y > _2L)
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
+               }
+               x /= pow2ld(low);
+               *exponent = low;
+       } else if (x < _1L) {
+               high = GAWK_LDBL_MAX_EXP - 1;   /* could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP */
+               while (low <= high) {
+                       mid = (low + high) / 2;
+                       y =  x * pow2ld(mid);
+                       if (y < _1L)
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
+               }
+               x *= pow2ld(low);
+               *exponent = -low;
+       }
+       if (x == _2L) {
+               x = _1L;
+               ++*exponent;
+       }
+       return x;
+}
+#endif
+
+#ifndef HAVE_FMODL
+/*
+ * gawk_fmodl --- Compute the floating-point remainder of dividing x by y
+ *     Method: shift and subtract.
+ */
+
+static AWKLDBL
+gawk_fmodl(AWKLDBL x, AWKLDBL y)
+{
+       AWKLDBL zx, zy, q;
+       int ex, ey, exy;
+       int signx = 1;
+       unsigned low, high, mid;
+
+       if (isnan(x) || isnan(y) 
+               || isinf(x) || y == _0L         /* XXX: set errno = EDOM ? */
+       )
+               return GAWK_NAN;
+
+       if (x == _0L)
+               return x;       /* +0 or -0 */
+       if (isinf(y))
+               return x;
+       
+       if (x < _0L) {
+               signx = -1;
+               x = -x;
+       }
+       if (y < _0L)
+               y = -y;
+
+       /* x > 0, y > 0 */
+       zy = gawk_frexpl(y, & ey);
+       zx = gawk_frexpl(x, & ex);
+       exy = ex - ey;
+       while (exy > 1) {
+               if (zx == _0L)
+                       return signx * _0L;
+
+               while (zx < zy && exy > 0) {
+                       zx *= 2;
+                       exy--;
+               }
+               if (exy < 0)
+                       break;
+
+               zx -= zy;
+
+#define        GAWK_LDBL_MAX_10_EXP    ((GAWK_LDBL_MAX_EXP + 1) / 4)
+               if (exy >= GAWK_LDBL_MAX_10_EXP) {
+                       /* Avoid possible overflow in 2^n computation */
+ 
+                       AWKLDBL tmp_exy, tmp_y;
+                       tmp_exy = exy;
+                       tmp_y = y;
+                       while (tmp_exy >= GAWK_LDBL_MAX_10_EXP) {
+                               tmp_y *= pow2ld(GAWK_LDBL_MAX_10_EXP);
+                               tmp_exy -= GAWK_LDBL_MAX_10_EXP;
+                       }
+                       x -= pow2ld(tmp_exy) * tmp_y;
+               } else
+                       x -= pow2ld(exy) * y;
+       }
+#undef GAWK_LDBL_MAX_10_EXP
+
+       while (x >= y)
+               x -= y;
+       if (signx > 0) {
+               if (x < _0L)
+                       x += y;
+       } else {
+               x = -x;
+               if (x > _0L)
+                       x -= y;
+       }
+       return x;
+}
+#endif
+
+
+#ifdef USE_INCLUDED_MATH_FUNCS
 static AWKLDBL taylor_exp(AWKLDBL x);
 static AWKLDBL taylor_cos(AWKLDBL x);
 static AWKLDBL taylor_sin(AWKLDBL x);
 static AWKLDBL arctan__p(AWKLDBL y, AWKLDBL x);
-static AWKLDBL gawk_frexpl(AWKLDBL x, int *exponent);
 static int gawk_rem_pio2l(AWKLDBL x, AWKLDBL *y);
 
-
 /* gawk_sinl --- Compute sin(x) */
 
 static AWKLDBL
@@ -639,133 +770,6 @@ gawk_sqrtl(AWKLDBL x)
        return yn;
 }
 
-/*
- * gawk_fmodl --- Compute the floating-point remainder of dividing x by y
- *     Method: shift and subtract.
- */
-
-static AWKLDBL
-gawk_fmodl(AWKLDBL x, AWKLDBL y)
-{
-       AWKLDBL zx, zy, q;
-       int ex, ey, exy;
-       int signx = 1;
-       unsigned low, high, mid;
-
-       if (isnan(x) || isnan(y) 
-               || isinf(x) || y == _0L         /* XXX: set errno = EDOM ? */
-       )
-               return GAWK_NAN;
-
-       if (x == _0L)
-               return x;       /* +0 or -0 */
-       if (isinf(y))
-               return x;
-       
-       if (x < _0L) {
-               signx = -1;
-               x = -x;
-       }
-       if (y < _0L)
-               y = -y;
-
-       /* x > 0, y > 0 */
-       zy = gawk_frexpl(y, & ey);
-       zx = gawk_frexpl(x, & ex);
-       exy = ex - ey;
-       while (exy > 1) {
-               if (zx == _0L)
-                       return signx * _0L;
-
-               while (zx < zy && exy > 0) {
-                       zx *= 2;
-                       exy--;
-               }
-               if (exy < 0)
-                       break;
-
-               zx -= zy;
-
-#define        GAWK_LDBL_MAX_10_EXP    ((GAWK_LDBL_MAX_EXP + 1) / 4)
-               if (exy >= GAWK_LDBL_MAX_10_EXP) {
-                       /* Avoid possible overflow in 2^n computation */
- 
-                       AWKLDBL tmp_exy, tmp_y;
-                       tmp_exy = exy;
-                       tmp_y = y;
-                       while (tmp_exy >= GAWK_LDBL_MAX_10_EXP) {
-                               tmp_y *= pow2ld(GAWK_LDBL_MAX_10_EXP);
-                               tmp_exy -= GAWK_LDBL_MAX_10_EXP;
-                       }
-                       x -= pow2ld(tmp_exy) * tmp_y;
-               } else
-                       x -= pow2ld(exy) * y;
-       }
-#undef GAWK_LDBL_MAX_10_EXP
-
-       while (x >= y)
-               x -= y;
-       if (signx > 0) {
-               if (x < _0L)
-                       x += y;
-       } else {
-               x = -x;
-               if (x > _0L)
-                       x -= y;
-       }
-       return x;
-}
-
-
-/*
- * gawk_frexpl --- split the number x into a normalized fraction and an 
exponent.
- *     The fraction is in the range [1, 2) (and NOT [0.5, 1)).
- */
-
-static AWKLDBL
-gawk_frexpl(AWKLDBL x, int *exponent)
-{
-       AWKLDBL y;
-       unsigned low, high, mid;
-
-       /* (isnormal(x) && x > 0) is assumed to be true */
-
-       assert(exponent != NULL);
-       *exponent = 0;
-
-       low = 0;
-       if (x > _2L) {
-               high = GAWK_LDBL_MAX_EXP - 1;
-               while (low <= high) {
-                       mid = (low + high) / 2;
-                       y = x / pow2ld(mid);
-                       if (y > _2L)
-                               low = mid + 1;
-                       else
-                               high = mid - 1;
-               }
-               x /= pow2ld(low);
-               *exponent = low;
-       } else if (x < _1L) {
-               high = GAWK_LDBL_MAX_EXP - 1;   /* could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP */
-               while (low <= high) {
-                       mid = (low + high) / 2;
-                       y =  x * pow2ld(mid);
-                       if (y < _1L)
-                               low = mid + 1;
-                       else
-                               high = mid - 1;
-               }
-               x *= pow2ld(low);
-               *exponent = -low;
-       }
-       if (x == _2L) {
-               x = _1L;
-               ++*exponent;
-       }
-       return x;
-}
-
 /* taylor_exp --- Compute exp(x) using Taylor series and modified squaring 
reduction */
 
 static AWKLDBL
@@ -983,7 +987,7 @@ arctan__p(AWKLDBL y, AWKLDBL x)
                sign = -1;
                z = -z;
        }
-       assert(z > _1L);
+       assert(z >= _1L);
 
        if (z <= LDC(20.0)) {
                /* For y / x  >= 0.05, Euler atan is slow! */
@@ -1076,3 +1080,4 @@ gawk_rem_pio2l(AWKLDBL x, AWKLDBL *y)
        y[1] = t - (y[0] - w);
        return n;
 }
+#endif /* USE_INCLUDED_MATH_FUNCS */
diff --git a/misc/gawk_math.h b/misc/gawk_math.h
index 5109d55..b96fb92 100644
--- a/misc/gawk_math.h
+++ b/misc/gawk_math.h
@@ -28,7 +28,5 @@ static AWKLDBL gawk_cosl(AWKLDBL x);
 static AWKLDBL gawk_atan2l(AWKLDBL y, AWKLDBL x);
 static AWKLDBL gawk_logl(AWKLDBL x);
 static AWKLDBL gawk_expl(AWKLDBL x);
-static AWKLDBL gawk_fmodl(AWKLDBL x, AWKLDBL y);
 static AWKLDBL gawk_powl(AWKLDBL x, AWKLDBL y);
 static AWKLDBL gawk_sqrtl(AWKLDBL x);
-
diff --git a/misc/ldbl_tests/Gentests b/misc/ldbl_tests/Gentests
new file mode 100755
index 0000000..8924f6a
--- /dev/null
+++ b/misc/ldbl_tests/Gentests
@@ -0,0 +1,114 @@
+#!/usr/bin/gawk -f
+
+# This program should generate Maketests
+
+BEGIN {
+       if (VMSTESTS) vmsargvfixup()
+
+       # read the list of files
+       for (i = 2; i < ARGC; i++)
+               files[ARGV[i]]
+
+       # throw it away
+       ARGC = 2
+
+       ntests = 0
+}
+
+# process the file Makefile.am:
+
+/^[[:upper:]_]*_TESTS *=/,/[^\\]$/ {
+       gsub(/(^[[:upper:]_]*_TESTS *=|\\$)/,"")
+       for (i = 1; i <= NF; i++)
+               tests[++ntests] = $i
+       next
+}
+
+/^NEED_LINT *=/,/[^\\]$/ {
+       gsub(/(^NEED_LINT *=|\\$)/,"")
+       for (i = 1; i <= NF; i++)
+               lint[$i]
+       next
+}
+
+/^NEED_LINT_OLD *=/,/[^\\]$/ {
+       gsub(/(^NEED_LINT_OLD *=|\\$)/,"")
+       for (i = 1; i <= NF; i++)
+               lint_old[$i]
+       next
+}
+
+/^GENTESTS_UNUSED *=/,/[^\\]$/ {
+       gsub(/(^GENTESTS_UNUSED *=|\\$)/,"")
+       for (i = 1; i <= NF; i++)
+               unused[$i]
+       next
+}
+
+/^CHECK_MPFR *=/,/[^\\]$/ {
+       gsub(/(^CHECK_MPFR *=|\\$)/,"")
+       for (i = 1; i <= NF; i++)
+               mpfr[$i]
+       next
+}
+
+/^[[:alpha:]_][[:alnum:]_]*:/ {
+       # remember all targets from Makefile.am
+       sub(/:.*/,"")
+       targets[$0]
+}
+
+# Now write the output file:
+END {
+       # this line tells automake to keep the comment with the rules:
+       print "Gt-dummy:"
+       print "# file Maketests, generated from Makefile.am by the Gentests 
program"
+
+       for (i = 1; i <= ntests; i++) {
+               x = tests[i]
+               if (!(x in targets))
+                       generate(x)
+       }
+
+       print "# end of file Maketests"
+}
+
+function generate(x,   s)
+{
+       if (!(x".awk" in files))
+               printf "WARNING: file `%s.awk' not found.\n", x > "/dev/stderr"
+       else
+               delete files[x".awk"]
+
+       if (VMSTESTS) return vmsgenerate(x)
+
+       print x ":"
+
+       s = ""
+       if (x in lint) {
+               s = s " --lint"
+               delete lint[x]
+       }
+       if (x in lint_old) {
+               s = s " --lint-old"
+               delete lint_old[x]
+       }
+       if (x".in" in files) {
+               s = s " < $(TESTDIR)/address@hidden"
+               delete files[x".in"]
+       }
+
+       printf "address@hidden address@hidden"
+       printf "address@hidden(TESTDIR) $(AWK) -f address@hidden %s >_$@ 2>&1 
|| echo EXIT CODE: $$? >>address@hidden", s
+
+       if (x in mpfr) {
+               delete mpfr[x]
+               printf "address@hidden test -z \"$$AWKFLAGS\" ; then $(CMP) 
$(TESTDIR)/address@hidden _$@ && rm -f _$@ ; else \\\n"
+               printf "\t$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@ ; 
\\\n"
+               printf "\tfi\n\n"
+       } else {
+               printf "address@hidden(CMP) $(TESTDIR)/address@hidden _$@ && rm 
-f address@hidden"
+       }
+}
+# VMSTESTS: generate test template in vms format
+# gawk -v "VMSTESTS=1" -f Gentests -f Gentests.vms Makefile.am *.awk *.in 
>Maketests.vms
diff --git a/test/Makefile.am b/misc/ldbl_tests/Makefile.am
similarity index 66%
copy from test/Makefile.am
copy to misc/ldbl_tests/Makefile.am
index da67b05..16c9dd4 100644
--- a/test/Makefile.am
+++ b/misc/ldbl_tests/Makefile.am
@@ -283,8 +283,6 @@ EXTRA_DIST = \
        functab2.ok \
        functab3.awk \
        functab3.ok \
-       functab4.awk \
-       functab4.ok \
        funlen.awk \
        funlen.in \
        funlen.ok \
@@ -820,8 +818,6 @@ EXTRA_DIST = \
        synerr2.awk \
        synerr2.ok \
        testext.ok \
-       time.awk \
-       time.ok \
        tradanch.awk \
        tradanch.in \
        tradanch.ok \
@@ -869,6 +865,7 @@ EXTRA_DIST = \
        zeroflag.awk \
        zeroflag.ok
 
+TESTDIR = ../../test
 
 TESTS_WE_ARE_NOT_DOING_YET_FIXME_ONE_DAY = longdbl
 
@@ -918,12 +915,16 @@ UNIX_TESTS = \
        fflush getlnhd localenl pid pipeio1 pipeio2 poundbang rtlen rtlen01 \
        space strftlng
 
+# Tests not run with long double: dumpvars, symtab1, symtab6 --- symbol table 
dumps.
+# Different entries in table, not worth the hassle and who wants to constantly
+# update the *.ok files?
+
 GAWK_EXT_TESTS = \
        aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \
-       backw badargs beginfile1 beginfile2 binmode1 charasbytes \
-       clos1way delsub devfd devfd1 devfd2 dumpvars exit \
+       backw badargs beginfile1 binmode1 charasbytes \
+       clos1way delsub devfd devfd1 devfd2 exit \
        fieldwdth fpat1 fpat2 fpat3  fpatnull fsfwfs funlen \
-       functab1 functab2 functab3 functab4 \
+       functab1 functab2 functab3 \
        fwtest fwtest2 fwtest3 \
        gensub gensub2 getlndir gnuops2 gnuops3 gnureops \
        icasefs icasers id igncdym igncfs ignrcas2 ignrcase \
@@ -937,8 +938,8 @@ GAWK_EXT_TESTS = \
        rebuf regx8bit reint reint2 rsstart1 \
        rsstart2 rsstart3 rstest6 shadow sortfor sortu splitarg4 strftime \
        strtonum switch2 \
-       symtab1 symtab2 symtab3 symtab4 symtab5 symtab6 symtab7 \
-       symtab8 symtab9
+       symtab2 symtab3 symtab4 symtab5 symtab7 \
+       symtab9
 
 EXTRA_TESTS = inftest regtest
 
@@ -948,13 +949,16 @@ MACHINE_TESTS = double1 double2 fmtspcl intformat
 
 MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint
 
+# Tests not run with long double: fnraydel, fnparydl --- index ordering issue. 
+#      Not really useful for the purpose.
+
 LOCALE_CHARSET_TESTS = \
-       asort asorti fmttest fnarydel fnparydl jarebug lc_num1 mbfw1 \
+       asort asorti fmttest jarebug lc_num1 mbfw1 \
        mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc
 
 SHLIB_TESTS = \
        fnmatch filefuncs fork fork2 fts ordchr ordchr2 \
-       readdir readfile revout revtwoway rwarray testext time
+       readdir readfile revout revtwoway rwarray testext
 
 # List of the tests which should be run with --lint option:
 NEED_LINT = \
@@ -976,7 +980,7 @@ CHECK_MPFR = \
 GENTESTS_UNUSED = Makefile.in gtlnbufv.awk printfloat.awk inclib.awk hello.awk
 
 CMP = cmp
-AWKPROG = ../gawk$(EXEEXT)
+AWKPROG = ../../gawk$(EXEEXT)
 
 # Default for VALGRIND is empty unless overridden by a command-line argument.
 # This protects against cruft in the environment.
@@ -990,7 +994,7 @@ VALGRIND =
 
 #
 # And we set AWKLIBPATH to find the extension libraries we built.
-AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} 
AWKLIBPATH=../extension/.libs $(VALGRIND) $(AWKPROG)
+AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG)
 
 # Message stuff is to make it a little easier to follow.
 # Make the pass-fail last and dependent on others to avoid
@@ -1001,43 +1005,38 @@ check:  msg \
        unix-msg-start   unix-tests      unix-msg-end \
        extend-msg-start gawk-extensions extend-msg-end \
        machine-msg-start machine-tests machine-msg-end \
-       charset-msg-start charset-tests charset-msg-end \
-       shlib-msg-start  shlib-tests     shlib-msg-end
-       @$(MAKE) pass-fail
+       charset-msg-start charset-tests charset-msg-end
 
-basic: $(BASIC_TESTS)
+basic:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-basic-tests ; fi
 
-unix-tests: $(UNIX_TESTS)
+ldbl-basic-tests: $(BASIC_TESTS)
 
-gawk-extensions: $(GAWK_EXT_TESTS)
+unix-tests:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-unix-tests ; fi
 
-charset-tests: $(LOCALE_CHARSET_TESTS)
+ldbl-unix-tests: $(UNIX_TESTS)
 
-extra: $(EXTRA_TESTS) inet
+gawk-extensions:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-gawk-extensions ; fi
 
-inet:  inetmesg $(INET_TESTS)
+ldbl-gawk-extensions: $(GAWK_EXT_TESTS)
 
-machine-tests: $(MACHINE_TESTS)
+charset-tests:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-charset-tests ; fi
 
-mpfr-tests: $(MPFR_TESTS)
+ldbl-charset-tests: $(LOCALE_CHARSET_TESTS)
 
-shlib-tests:
-       @if grep 'DYNAMIC 1' $(top_builddir)/config.h > /dev/null ; then \
-       $(MAKE) shlib-real-tests ; \
-       else echo shlib tests not supported on this system ; \
-       fi
+machine-tests:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-machine-tests ; fi
 
-shlib-real-tests: $(SHLIB_TESTS)
+ldbl-machine-tests: $(MACHINE_TESTS)
 
 msg::
-       @echo ''
-       @echo 'Any output from "cmp" is bad news, although some differences'
-       @echo 'in floating point values are probably benign -- in particular,'
-       @echo 'some systems may omit a leading zero and the floating point'
-       @echo 'precision may lead to slightly different output in a few cases.'
+       @echo 'Running tests using LONG DOUBLE numbers'
 
 printlang::
-       @$(AWK) -f $(srcdir)/printlang.awk
+       @$(AWK) -f $(TESTDIR)/printlang.awk
 
 basic-msg-start:
        @echo "======== Starting basic tests ========"
@@ -1069,18 +1068,12 @@ charset-msg-start:
 charset-msg-end:
        @echo "======== Done with tests that can vary based on character set or 
locale support ========"
 
-shlib-msg-start:
-       @echo "======== Starting shared library tests ========"
-
-shlib-msg-end:
-       @echo "======== Done with shared library tests ========"
-
 
 lc_num1:
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 
 # This test is a PITA because increasingly, /tmp is getting
@@ -1090,86 +1083,86 @@ lc_num1:
 # so this can still fail
 poundbang::
        @echo $@
-       @sed "s;/tmp/gawk;`pwd`/$(AWKPROG);" < $(srcdir)/poundbang.awk > 
./_pbd.awk
+       @sed "s;/tmp/gawk;`pwd`/$(AWKPROG);" < $(TESTDIR)/poundbang.awk > 
./_pbd.awk
        @chmod +x ./_pbd.awk
-       @if ./_pbd.awk $(srcdir)/poundbang.awk > _`basename address@hidden ; \
+       @if ./_pbd.awk $(TESTDIR)/poundbang.awk > _`basename address@hidden ; \
        then : ; \
        else \
-               sed "s;/tmp/gawk;../$(AWKPROG);" < $(srcdir)/poundbang.awk > 
./_pbd.awk ; \
+               sed "s;/tmp/gawk;../$(AWKPROG);" < $(TESTDIR)/poundbang.awk > 
./_pbd.awk ; \
                chmod +x ./_pbd.awk ; \
-               LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} ./_pbd.awk 
$(srcdir)/poundbang.awk > _`basename address@hidden;  \
+               LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} ./_pbd.awk 
$(TESTDIR)/poundbang.awk > _`basename address@hidden;  \
        fi
-       @-$(CMP) $(srcdir)/poundbang.awk _`basename address@hidden && rm -f 
_`basename address@hidden _pbd.awk
+       @-$(CMP) $(TESTDIR)/poundbang.awk _`basename address@hidden && rm -f 
_`basename address@hidden _pbd.awk
 
 messages::
        @echo $@
-       @$(AWK) -f $(srcdir)/messages.awk >_out2 2>_out3
-       @-$(CMP) $(srcdir)/out1.ok _out1 && $(CMP) $(srcdir)/out2.ok _out2 && 
$(CMP) $(srcdir)/out3.ok _out3 && rm -f _out1 _out2 _out3
+       @$(AWK) -f $(TESTDIR)/messages.awk >_out2 2>_out3
+       @-$(CMP) $(TESTDIR)/out1.ok _out1 && $(CMP) $(TESTDIR)/out2.ok _out2 && 
$(CMP) $(TESTDIR)/out3.ok _out3 && rm -f _out1 _out2 _out3
 
 argarray::
        @echo $@
-       @case $(srcdir) in \
+       @case $(TESTDIR) in \
        .)      : ;; \
-       *)      cp $(srcdir)/argarray.in . ;; \
+       *)      cp $(TESTDIR)/argarray.in . ;; \
        esac
-       @TEST=test echo just a test | $(AWK) -f $(srcdir)/argarray.awk 
./argarray.in - >_$@
-       @case $(srcdir) in \
+       @TEST=test echo just a test | $(AWK) -f $(TESTDIR)/argarray.awk 
./argarray.in - >_$@
+       @case $(TESTDIR) in \
        .)      : ;; \
        *)      rm -f ./argarray.in ;; \
        esac
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 regtest::
        @echo 'Some of the output from regtest is very system specific, do not'
        @echo 'be distressed if your output differs from that distributed.'
        @echo 'Manual inspection is called for.'
-       AWK=$(AWKPROG) $(srcdir)/regtest.sh
+       AWK=$(AWKPROG) $(TESTDIR)/regtest.sh
 
 manyfiles::
        @echo manyfiles
        @rm -rf junk
        @mkdir junk
        @$(AWK) 'BEGIN { for (i = 1; i <= 1030; i++) print i, i}' >_$@
-       @$(AWK) -f $(srcdir)/manyfiles.awk _$@ _$@
+       @$(AWK) -f $(TESTDIR)/manyfiles.awk _$@ _$@
        @wc -l junk/* | $(AWK) '$$1 != 2' | wc -l | sed "s/  *//g" > _$@
        @rm -rf junk
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 compare::
        @echo $@
-       @$(AWK) -f $(srcdir)/compare.awk 0 1 $(srcdir)/compare.in >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/compare.awk 0 1 $(TESTDIR)/compare.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 inftest::
        @echo $@
        @echo This test is very machine specific...
-       @$(AWK) -f $(srcdir)/inftest.awk | sed "s/inf/Inf/g" >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/inftest.awk | sed "s/inf/Inf/g" >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 getline2::
        @echo $@
-       @$(AWK) -f $(srcdir)/getline2.awk $(srcdir)/getline2.awk 
$(srcdir)/getline2.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/getline2.awk $(TESTDIR)/getline2.awk 
$(TESTDIR)/getline2.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 awkpath::
        @echo $@
-       @AWKPATH="$(srcdir)$(PATH_SEPARATOR)$(srcdir)/lib" $(AWK) -f 
awkpath.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH="$(TESTDIR)$(PATH_SEPARATOR)$(TESTDIR)/lib" $(AWK) -f 
awkpath.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 argtest::
        @echo $@
-       @$(AWK) -f $(srcdir)/argtest.awk -x -y abc >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/argtest.awk -x -y abc >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 badargs::
        @echo $@
        @-$(AWK) -f 2>&1 | grep -v patchlevel >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 nonl::
        @echo $@
-       @-AWKPATH=$(srcdir) $(AWK) --lint -f nonl.awk /dev/null >_$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWKPATH=$(TESTDIR) $(AWK) --lint -f nonl.awk /dev/null >_$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 strftime::
        @echo This test could fail on slow machines or on a minute boundary,
@@ -1177,102 +1170,102 @@ strftime::
        @echo $@
        @GAWKLOCALE=C; export GAWKLOCALE; \
        TZ=GMT0; export TZ; \
-       (LC_ALL=C date) | $(AWK) -v OUTPUT=_$@ -f $(srcdir)/strftime.awk
+       (LC_ALL=C date) | $(AWK) -v OUTPUT=_$@ -f $(TESTDIR)/strftime.awk
        @-$(CMP) strftime.ok _$@ && rm -f _$@ strftime.ok || exit 0
 
 litoct::
        @echo $@
-       @echo ab | $(AWK) --traditional -f $(srcdir)/litoct.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @echo ab | $(AWK) --traditional -f $(TESTDIR)/litoct.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 devfd::
        @echo $@
-       @$(AWK) 1 /dev/fd/4 /dev/fd/5 4<$(srcdir)/devfd.in4 
5<$(srcdir)/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) 1 /dev/fd/4 /dev/fd/5 4<$(TESTDIR)/devfd.in4 
5<$(TESTDIR)/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 fflush::
        @echo $@
-       @$(srcdir)/fflush.sh >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 tweakfld::
        @echo $@
-       @$(AWK) -f $(srcdir)/tweakfld.awk $(srcdir)/tweakfld.in >_$@
+       @$(AWK) -f $(TESTDIR)/tweakfld.awk $(TESTDIR)/tweakfld.in >_$@
        @rm -f errors.cleanup
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mmap8k::
        @echo $@
-       @$(AWK) '{ print }' $(srcdir)/mmap8k.in >_$@
-       @-$(CMP) $(srcdir)/mmap8k.in _$@ && rm -f _$@
+       @$(AWK) '{ print }' $(TESTDIR)/mmap8k.in >_$@
+       @-$(CMP) $(TESTDIR)/mmap8k.in _$@ && rm -f _$@
 
 tradanch::
        @echo $@
-       @$(AWK) --traditional -f $(srcdir)/tradanch.awk $(srcdir)/tradanch.in 
>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --traditional -f $(TESTDIR)/tradanch.awk $(TESTDIR)/tradanch.in 
>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 # AIX /bin/sh exec's the last command in a list, therefore issue a ":"
 # command so that pid.sh is fork'ed as a child before being exec'ed.
 pid::
        @echo pid
-       @AWKPATH=$(srcdir) AWK=$(AWKPROG) $(SHELL) $(srcdir)/pid.sh $$$$ > 
_`basename address@hidden ; :
-       @-$(CMP) $(srcdir)/pid.ok _`basename address@hidden && rm -f _`basename 
address@hidden
+       @AWKPATH=$(TESTDIR) AWK=$(AWKPROG) $(SHELL) $(TESTDIR)/pid.sh $$$$ > 
_`basename address@hidden ; :
+       @-$(CMP) $(TESTDIR)/pid.ok _`basename address@hidden && rm -f 
_`basename address@hidden
 
 strftlng::
        @echo $@
-       @TZ=UTC; export TZ; $(AWK) -f $(srcdir)/strftlng.awk >_$@
-       @if $(CMP) $(srcdir)/strftlng.ok _$@ >/dev/null 2>&1 ; then : ; else \
-       TZ=UTC0; export TZ; $(AWK) -f $(srcdir)/strftlng.awk >_$@ ; \
+       @TZ=UTC; export TZ; $(AWK) -f $(TESTDIR)/strftlng.awk >_$@
+       @if $(CMP) $(TESTDIR)/strftlng.ok _$@ >/dev/null 2>&1 ; then : ; else \
+       TZ=UTC0; export TZ; $(AWK) -f $(TESTDIR)/strftlng.awk >_$@ ; \
        fi
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 nors::
        @echo $@
-       @echo A B C D E | tr -d '\12\15' | $(AWK) '{ print $$NF }' - 
$(srcdir)/nors.in > _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @echo A B C D E | tr -d '\12\15' | $(AWK) '{ print $$NF }' - 
$(TESTDIR)/nors.in > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
-fmtspcl.ok: fmtspcl.tok Makefile
-       @$(AWK) -v "sd=$(srcdir)" 'BEGIN {pnan = sprintf("%g",sqrt(-1)); nnan = 
sprintf("%g",-sqrt(-1)); pinf = sprintf("%g",-log(0)); ninf = 
sprintf("%g",log(0))} {sub(/positive_nan/,pnan); sub(/negative_nan/,nnan); 
sub(/positive_infinity/,pinf); sub(/negative_infinity/,ninf); 
sub(/fmtspcl/,(sd"/fmtspcl")); print}' < $(srcdir)/fmtspcl.tok > $@ 2>/dev/null
+fmtspcl.ok: $(TESTDIR)/fmtspcl.tok Makefile
+       @$(AWK) -v "sd=$(TESTDIR)" 'BEGIN {pnan = sprintf("%g",sqrt(-1)); nnan 
= sprintf("%g",-sqrt(-1)); pinf = sprintf("%g",-log(0)); ninf = 
sprintf("%g",log(0))} {sub(/positive_nan/,pnan); sub(/negative_nan/,nnan); 
sub(/positive_infinity/,pinf); sub(/negative_infinity/,ninf); 
sub(/fmtspcl/,(sd"/fmtspcl")); print}' < $(TESTDIR)/fmtspcl.tok > $@ 2>/dev/null
 
 fmtspcl: fmtspcl.ok
        @echo $@
-       @$(AWK) -f $(srcdir)/fmtspcl.awk  --lint >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
+       @$(AWK) -f $(TESTDIR)/fmtspcl.awk  --lint >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
        @-if test -z "$$AWKFLAGS" ; then $(CMP) address@hidden _$@ && rm -f _$@ 
; else \
-       $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ ; \
+       $(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@ ; \
        fi
 
 reint::
        @echo $@
-       @$(AWK) --re-interval -f $(srcdir)/reint.awk $(srcdir)/reint.in >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --re-interval -f $(TESTDIR)/reint.awk $(TESTDIR)/reint.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 pipeio1::
        @echo $@
-       @$(AWK) -f $(srcdir)/pipeio1.awk >_$@
+       @$(AWK) -f $(TESTDIR)/pipeio1.awk >_$@
        @rm -f test1 test2
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 pipeio2::
        @echo $@
-       @$(AWK) -v SRCDIR=$(srcdir) -f $(srcdir)/pipeio2.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -v SRCDIR=$(TESTDIR) -f $(TESTDIR)/pipeio2.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 clobber::
        @echo $@
-       @$(AWK) -f $(srcdir)/clobber.awk >_$@
-       @-$(CMP) $(srcdir)/clobber.ok seq && $(CMP) $(srcdir)/clobber.ok _$@ && 
rm -f _$@
+       @$(AWK) -f $(TESTDIR)/clobber.awk >_$@
+       @-$(CMP) $(TESTDIR)/clobber.ok seq && $(CMP) $(TESTDIR)/clobber.ok _$@ 
&& rm -f _$@
        @rm -f seq
 
 arynocls::
        @echo $@
-       @-AWKPATH=$(srcdir) $(AWK) -v INPUT=$(srcdir)/arynocls.in -f 
arynocls.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWKPATH=$(TESTDIR) $(AWK) -v INPUT=$(TESTDIR)/arynocls.in -f 
arynocls.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 getlnbuf::
        @echo $@
-       @-AWKPATH=$(srcdir) $(AWK) -f getlnbuf.awk $(srcdir)/getlnbuf.in > _$@
-       @-AWKPATH=$(srcdir) $(AWK) -f gtlnbufv.awk $(srcdir)/getlnbuf.in > _2$@
-       @-$(CMP) $(srcdir)/getlnbuf.ok _$@ && $(CMP) $(srcdir)/getlnbuf.ok _2$@ 
&& rm -f _$@ _2$@
+       @-AWKPATH=$(TESTDIR) $(AWK) -f getlnbuf.awk $(TESTDIR)/getlnbuf.in > _$@
+       @-AWKPATH=$(TESTDIR) $(AWK) -f gtlnbufv.awk $(TESTDIR)/getlnbuf.in > 
_2$@
+       @-$(CMP) $(TESTDIR)/getlnbuf.ok _$@ && $(CMP) $(TESTDIR)/getlnbuf.ok 
_2$@ && rm -f _$@ _2$@
 
 inetmesg::
        @echo These tests only work if your system supports the services
@@ -1299,28 +1292,28 @@ inetdayt::
 
 redfilnm::
        @echo $@
-       @$(AWK) -f $(srcdir)/redfilnm.awk srcdir=$(srcdir) 
$(srcdir)/redfilnm.in >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/redfilnm.awk srcdir=$(TESTDIR) 
$(TESTDIR)/redfilnm.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 leaddig::
        @echo $@
-       @$(AWK) -v x=2E  -f $(srcdir)/leaddig.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -v x=2E  -f $(TESTDIR)/leaddig.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 gsubtst3::
        @echo $@
-       @$(AWK) --re-interval -f $(srcdir)/address@hidden 
$(srcdir)/address@hidden >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --re-interval -f $(TESTDIR)/address@hidden 
$(TESTDIR)/address@hidden >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 space::
        @echo $@
-       @$(AWK) -f ' ' $(srcdir)/space.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f ' ' $(TESTDIR)/space.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 printf0::
        @echo $@
-       @$(AWK) --posix -f $(srcdir)/address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --posix -f $(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rsnulbig::
        @echo $@
@@ -1328,7 +1321,7 @@ rsnulbig::
        @$(AWK) 'BEGIN { for (i = 1; i <= 128*64+1; i++) print 
"abcdefgh123456\n" }' 2>&1 | \
        $(AWK) 'BEGIN { RS = ""; ORS = "\n\n" }; { print }' 2>&1 | \
        $(AWK) '/^[^a]/; END{ print NR }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rsnulbig2::
        @echo $@
@@ -1336,298 +1329,293 @@ rsnulbig2::
                for (i = 1; i <= 128; i++) print n; print "abc\n" }' 2>&1 | \
                $(AWK) 'BEGIN { RS = ""; ORS = "\n\n" };{ print }' 2>&1 | \
                $(AWK) '/^[^a]/; END { print NR }' >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 wideidx::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 wideidx2::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 widesub::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 widesub2::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 widesub3::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 widesub4::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 ignrcas2::
        @echo $@
        @GAWKLOCALE=en_US ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >> 
_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >> 
_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 subamp::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden $(srcdir)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 # This test makes sure gawk exits with a zero code.
 # Thus, unconditionally generate the exit code.
 exitval1::
        @echo $@
-       @$(AWK) -f $(srcdir)/exitval1.awk >_$@ 2>&1; echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/exitval1.awk >_$@ 2>&1; echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 fsspcoln::
        @echo $@
-       @$(AWK) -f $(srcdir)/address@hidden 'FS=[ :]+' $(srcdir)/address@hidden 
>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/address@hidden 'FS=[ :]+' 
$(TESTDIR)/address@hidden >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rsstart1::
        @echo $@
-       @$(AWK) -f $(srcdir)/address@hidden $(srcdir)/rsstart1.in >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/rsstart1.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rsstart2::
        @echo $@
-       @$(AWK) -f $(srcdir)/address@hidden $(srcdir)/rsstart1.in >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/rsstart1.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rsstart3::
        @echo $@
-       @head $(srcdir)/rsstart1.in | $(AWK) -f $(srcdir)/rsstart2.awk >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @head $(TESTDIR)/rsstart1.in | $(AWK) -f $(TESTDIR)/rsstart2.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rtlen::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden >_$@ || echo EXIT CODE: 
$$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rtlen01::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden >_$@ || echo EXIT CODE: 
$$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rtlenmb::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(srcdir)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/rtlen.ok _$@ && rm -f _$@
+       AWK=$(AWKPROG) $(TESTDIR)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/rtlen.ok _$@ && rm -f _$@
 
 nondec2::
        @echo $@
-       @$(AWK) --non-decimal-data -v a=0x1 -f $(srcdir)/address@hidden >_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --non-decimal-data -v a=0x1 -f $(TESTDIR)/address@hidden >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 nofile::
        @echo $@
        @$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 binmode1::
        @echo $@
        @$(AWK) -v BINMODE=3 'BEGIN { print BINMODE }' >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 subi18n::
        @echo $@
-       @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f $(srcdir)/address@hidden > _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f $(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 concat4::
        @echo $@
-       @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f $(srcdir)/address@hidden 
$(srcdir)/address@hidden > _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f $(TESTDIR)/address@hidden 
$(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 devfd1::
        @echo $@
-       @$(AWK) -f $(srcdir)/address@hidden 4< $(srcdir)/devfd.in1 5< 
$(srcdir)/devfd.in2 >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -f $(TESTDIR)/address@hidden 4< $(TESTDIR)/devfd.in1 5< 
$(TESTDIR)/devfd.in2 >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 # The program text is the '1' which will print each record. How compact can 
you get?
 devfd2::
        @echo $@
-       @$(AWK) 1 /dev/fd/4 /dev/fd/5 4< $(srcdir)/devfd.in1 5< 
$(srcdir)/devfd.in2 >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) 1 /dev/fd/4 /dev/fd/5 4< $(TESTDIR)/devfd.in1 5< 
$(TESTDIR)/devfd.in2 >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mixed1::
        @echo $@
        @$(AWK) -f /dev/null --source 'BEGIN {return junk}' >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mtchi18n::
        @echo $@
        @GAWKLOCALE=ru_RU.UTF-8 ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden $(srcdir)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 reint2::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) --re-interval -f address@hidden 
$(srcdir)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) --re-interval -f address@hidden 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 localenl::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ 2>/dev/null
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden >_$@ 2>/dev/null
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mbprintf1::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden $(srcdir)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mbprintf2::
        @echo $@
        @GAWKLOCALE=ja_JP.UTF-8 ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >> 
_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >> 
_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mbprintf3::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden $(srcdir)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mbfw1::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(AWK) -f $(srcdir)/address@hidden $(srcdir)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 gsubtst6::
        @echo $@
-       @GAWKLOCALE=C ; $(AWK) -f $(srcdir)/address@hidden > _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @GAWKLOCALE=C ; $(AWK) -f $(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mbstr1::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
-printfbad2: printfbad2.ok
+printfbad2: $(TESTDIR)/printfbad2.ok
        @echo $@
-       @$(AWK) --lint -f $(srcdir)/address@hidden $(srcdir)/address@hidden 
2>&1 | sed 's;\$(srcdir)/;;g' >_$@ || echo EXIT CODE: $$?  >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --lint -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden 
2>&1 | sed 's;\$(TESTDIR)/;;g' >_$@ || echo EXIT CODE: $$?  >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 beginfile1::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) -f address@hidden $(srcdir)/address@hidden . 
./no/such/file Makefile  >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
-
-beginfile2:
-       @echo $@
-       @-( cd $(srcdir) && LC_ALL=C AWK="$(abs_builddir)/$(AWKPROG)" 
$(abs_srcdir)/address@hidden $(abs_srcdir)/address@hidden ) > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden $(TESTDIR)/address@hidden 
. ./no/such/file Makefile  >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 dumpvars::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --dump-variables 1 < $(srcdir)/address@hidden 
>/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@
+       @AWKPATH=$(TESTDIR) $(AWK) --dump-variables 1 < 
$(TESTDIR)/address@hidden >/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@
        @mv awkvars.out _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 profile1:
        @echo $@
-       @$(AWK) address@hidden -f $(srcdir)/xref.awk $(srcdir)/dtdgport.awk > 
address@hidden
-       @$(AWK) -f address@hidden $(srcdir)/dtdgport.awk > address@hidden ; rm 
address@hidden
+       @$(AWK) address@hidden -f $(TESTDIR)/xref.awk $(TESTDIR)/dtdgport.awk > 
address@hidden
+       @$(AWK) -f address@hidden $(TESTDIR)/dtdgport.awk > address@hidden ; rm 
address@hidden
        @cmp address@hidden address@hidden && rm address@hidden || echo EXIT 
CODE: $$? >>_$@
 
 profile2:
        @echo $@
-       @$(AWK) address@hidden -v sortcmd=sort -f $(srcdir)/xref.awk 
$(srcdir)/dtdgport.awk > /dev/null
+       @$(AWK) address@hidden -v sortcmd=sort -f $(TESTDIR)/xref.awk 
$(TESTDIR)/dtdgport.awk > /dev/null
        @sed 1,2d < address@hidden > _$@; rm address@hidden
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 profile3:
        @echo $@
-       @$(AWK) address@hidden -f $(srcdir)/address@hidden > /dev/null
+       @$(AWK) address@hidden -f $(TESTDIR)/address@hidden > /dev/null
        @sed 1,2d < address@hidden > _$@; rm address@hidden
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 posix2008sub:
        @echo $@
-       @$(AWK) --posix -f $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) --posix -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 next:
        @echo $@
-       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden > _$@ 2>&1
-       @-LC_ALL=C $(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-LC_ALL=C $(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 exit:
        @echo $@
-       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rri1::
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 rand:
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/address@hidden _$@ && 
rm -f _$@ ; else \
-       ($(CMP) $(srcdir)/address@hidden _$@ || $(CMP) $(srcdir)/address@hidden 
_$@) && rm -f _$@ ; \
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-if test -z "$$AWKFLAGS" ; then $(CMP) $(TESTDIR)/address@hidden _$@ 
&& rm -f _$@ ; else \
+       ($(CMP) $(TESTDIR)/address@hidden _$@ || $(CMP) 
$(TESTDIR)/address@hidden _$@) && rm -f _$@ ; \
        fi
 
 mpfrieee:
        @echo $@
-       @$(AWK) -M -vPREC=double -f $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -M -vPREC=double -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mpfrexprange:
        @echo $@
-       @$(AWK) -M -vPREC=53 -f $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -M -vPREC=53 -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mpfrrnd:
        @echo $@
-       @$(AWK) -M -vPREC=53 -f $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -M -vPREC=53 -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mpfrnr:
        @echo $@
-       @$(AWK) -M -vPREC=113 -f $(srcdir)/address@hidden 
$(srcdir)/address@hidden > _$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -M -vPREC=113 -f $(TESTDIR)/address@hidden 
$(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mpfrsort:
        @echo $@
-       @$(AWK) -M -vPREC=53 -f $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -M -vPREC=53 -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 mpfrbigint:
        @echo $@
-       @$(AWK) -M -f $(srcdir)/address@hidden > _$@ 2>&1
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(AWK) -M -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 jarebug::
        @echo $@
-       @$(srcdir)/address@hidden "$(AWKPROG)" "$(srcdir)/address@hidden" 
"$(srcdir)/address@hidden" "_$@"
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @$(TESTDIR)/address@hidden "$(AWKPROG)" "$(TESTDIR)/address@hidden" 
"$(TESTDIR)/address@hidden" "_$@"
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 ordchr2::
        @echo $@
        @$(AWK) -l ordchr 'BEGIN {print chr(ord("z"))}' >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 # N.B. If the test fails, create readfile.ok so that "make diffout" will work
 readfile::
@@ -1637,86 +1625,80 @@ readfile::
 
 include2::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) -i inclib 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) -i inclib 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print 
sandwich("a", "b", "c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print 
sandwich("a", "b", "c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe2::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe3::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe4::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -f hello -i hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f hello -i hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe5::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -i hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -i hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe6::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -i inchello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -i inchello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 incdupe7::
        @echo $@
-       @AWKPATH=$(srcdir) $(AWK) --lint -f hello -i inchello >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f hello -i inchello >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 testext::
        @echo $@
        @$(AWK) '/^(@load|BEGIN)/,/^}/' $(top_srcdir)/extension/testext.c > 
testext.awk
        @$(AWK) -f testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@ testext.awk
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@ testext.awk
 
 readdir:
        @echo This test can fail on some filesystems.
        @echo $@
-       @ls -fli $(top_srcdir) | sed 1d | $(AWK) -f $(srcdir)/readdir0.awk > 
address@hidden
-       @$(AWK) -f $(srcdir)/readdir.awk $(top_srcdir) > _$@
+       @ls -fli $(top_srcdir) | sed 1d | $(AWK) -f $(TESTDIR)/readdir0.awk > 
address@hidden
+       @$(AWK) -f $(TESTDIR)/readdir.awk $(top_srcdir) > _$@
        @-$(CMP) address@hidden _$@ && rm -f address@hidden _$@
 
 fts:
        @echo $@
-       @$(AWK) -f $(srcdir)/fts.awk
+       @$(AWK) -f $(TESTDIR)/fts.awk
        @-$(CMP) address@hidden _$@ && rm -f address@hidden _$@
 
 charasbytes:
        @echo $@
        @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
-       AWKPATH=$(srcdir) $(AWK) -b -f address@hidden $(srcdir)/address@hidden 
| \
+       AWKPATH=$(TESTDIR) $(AWK) -b -f address@hidden 
$(TESTDIR)/address@hidden | \
        od -c -t x1 | sed -e 's/  */ /g' -e 's/ *$$//' >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 symtab6:
        @echo $@
-       @$(AWK) -d__$@ -f $(srcdir)/address@hidden
+       @$(AWK) -d__$@ -f $(TESTDIR)/address@hidden
        @grep -v '^ENVIRON' __$@ | grep -v '^PROCINFO' > _$@ ; rm __$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
-
-symtab8:
-       @echo $@
-       @$(AWK) -d__$@ -f $(srcdir)/address@hidden $(srcdir)/address@hidden >_$@
-       @grep -v '^ENVIRON' __$@ | grep -v '^PROCINFO' >> _$@ ; rm __$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
 
 # Targets generated for other tests:
 include Maketests
 
 $(srcdir)/Maketests: $(srcdir)/Makefile.am $(srcdir)/Gentests
-       files=`cd "$(srcdir)" && echo *.awk *.in`; \
+       files=`cd "$(TESTDIR)" && echo *.awk *.in`; \
        $(AWK) -f $(srcdir)/Gentests "$(srcdir)/Makefile.am" $$files > 
$(srcdir)/Maketests
 
 clean:
diff --git a/misc/ldbl_tests/Makefile.in b/misc/ldbl_tests/Makefile.in
new file mode 100644
index 0000000..4294e79
--- /dev/null
+++ b/misc/ldbl_tests/Makefile.in
@@ -0,0 +1,3439 @@
+# Makefile.in generated by automake 1.12.6 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2012 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
address@hidden@
+
+#
+# test/Makefile.am --- automake input file for gawk
+#
+# Copyright (C) 1988-2012 the Free Software Foundation, Inc.
+#
+# This file is part of GAWK, the GNU implementation of the
+# AWK Programming Language.
+#
+# GAWK is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# GAWK is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+#
+VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+       $(srcdir)/Maketests $(top_srcdir)/mkinstalldirs
+subdir = misc/ldbl_tests
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
+       $(top_srcdir)/m4/codeset.m4 $(top_srcdir)/m4/gettext.m4 \
+       $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \
+       $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
+       $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+       $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
+       $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+       $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+       $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+       $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+       $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+       $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+
+# This business forces the locale to be C for running the tests,
+# unless we override it to something else for testing.
+#
+# This can also be done in individual tests where we wish to
+# check things specifically not in the C locale.
+
+#
+# And we set AWKLIBPATH to find the extension libraries we built.
+AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG)
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+GAWKLIBEXT = @GAWKLIBEXT@
+GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GREP = @GREP@
+HAVE_LIBSIGSEGV = @HAVE_LIBSIGSEGV@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LDFLAGS = @LDFLAGS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBMPFR = @LIBMPFR@
+LIBOBJS = @LIBOBJS@
+LIBREADLINE = @LIBREADLINE@
+LIBS = @LIBS@
+LIBSIGSEGV = @LIBSIGSEGV@
+LIBSIGSEGV_PREFIX = @LIBSIGSEGV_PREFIX@
+LN_S = @LN_S@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBSIGSEGV = @LTLIBSIGSEGV@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+OBJEXT = @OBJEXT@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSUB = @POSUB@
+PRINTF_HAS_LF_FORMAT = @PRINTF_HAS_LF_FORMAT@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@
+YACC = @YACC@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+acl_shlibext = @acl_shlibext@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgextensiondir = @pkgextensiondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = \
+       reg \
+       lib \
+       ChangeLog.0 \
+       Gentests \
+       Gentests.vms \
+       Maketests \
+       README \
+       aadelete1.awk \
+       aadelete1.ok \
+       aadelete2.awk \
+       aadelete2.ok \
+       aarray1.awk \
+       aarray1.ok \
+       aasort.awk \
+       aasort.ok \
+       aasorti.awk \
+       aasorti.ok \
+       addcomma.awk \
+       addcomma.in \
+       addcomma.ok \
+       anchgsub.awk \
+       anchgsub.in \
+       anchgsub.ok \
+       argarray.awk \
+       argarray.in \
+       argarray.ok \
+       argtest.awk \
+       argtest.ok \
+       arrayparm.awk \
+       arrayparm.ok \
+       arrayprm2.awk \
+       arrayprm2.ok \
+       arrayprm3.awk \
+       arrayprm3.ok \
+       arrayref.awk \
+       arrayref.ok \
+       arraysort.awk \
+       arraysort.ok \
+       arrymem1.awk \
+       arrymem1.ok \
+       arryref2.awk \
+       arryref2.ok \
+       arryref3.awk \
+       arryref3.ok \
+       arryref4.awk \
+       arryref4.ok \
+       arryref5.awk \
+       arryref5.ok \
+       arynasty.awk \
+       arynasty.ok \
+       arynocls.awk \
+       arynocls.in \
+       arynocls.ok \
+       aryprm1.awk \
+       aryprm1.ok \
+       aryprm2.awk \
+       aryprm2.ok \
+       aryprm3.awk \
+       aryprm3.ok \
+       aryprm4.awk \
+       aryprm4.ok \
+       aryprm5.awk \
+       aryprm5.ok \
+       aryprm6.awk \
+       aryprm6.ok \
+       aryprm7.awk \
+       aryprm7.ok \
+       aryprm8.awk \
+       aryprm8.ok \
+       arysubnm.awk \
+       arysubnm.ok \
+       asgext.awk \
+       asgext.in \
+       asgext.ok \
+       asort.awk \
+       asort.ok \
+       asorti.awk \
+       asorti.ok \
+       awkpath.ok \
+       back89.awk \
+       back89.in \
+       back89.ok \
+       backgsub.awk \
+       backgsub.in \
+       backgsub.ok \
+       backw.awk \
+       backw.in \
+       backw.ok \
+       badargs.ok \
+       beginfile1.awk \
+       beginfile1.ok \
+       beginfile2.in \
+       beginfile2.ok \
+       beginfile2.sh \
+       binmode1.ok \
+       charasbytes.awk \
+       charasbytes.in \
+       charasbytes.ok \
+       childin.awk \
+       childin.in \
+       childin.ok \
+       clobber.awk \
+       clobber.ok \
+       clos1way.awk \
+       clos1way.ok \
+       closebad.awk \
+       closebad.ok \
+       clsflnam.awk \
+       clsflnam.in \
+       clsflnam.ok \
+       compare.awk \
+       compare.in \
+       compare.ok \
+       compare2.awk \
+       compare2.ok \
+       concat1.awk \
+       concat1.in \
+       concat1.ok \
+       concat2.awk \
+       concat2.ok \
+       concat3.awk \
+       concat3.ok \
+       concat4.awk \
+       concat4.in \
+       concat4.ok \
+       convfmt.awk \
+       convfmt.ok \
+       datanonl.awk \
+       datanonl.in \
+       datanonl.ok \
+       defref.awk \
+       defref.ok \
+       delargv.awk \
+       delargv.ok \
+       delarpm2.awk \
+       delarpm2.ok \
+       delarprm.awk \
+       delarprm.ok \
+       delfunc.awk \
+       delfunc.ok \
+       delsub.awk \
+       delsub.ok \
+       devfd.in1 \
+       devfd.in2 \
+       devfd.in4 \
+       devfd.in5 \
+       devfd.ok \
+       devfd1.awk \
+       devfd1.ok \
+       devfd2.ok \
+       dfastress.awk \
+       dfastress.ok \
+       double1.awk \
+       double1.ok \
+       double2.awk \
+       double2.ok \
+       dtdgport.awk \
+       dumpvars.in \
+       dumpvars.ok \
+       dynlj.awk \
+       dynlj.ok \
+       eofsplit.awk \
+       eofsplit.ok \
+       exit.ok \
+       exit.sh \
+       exitval1.awk \
+       exitval1.ok \
+       exitval2.awk \
+       exitval2.ok \
+       exitval2.w32 \
+       fcall_exit.awk \
+       fcall_exit.ok \
+       fcall_exit2.awk \
+       fcall_exit2.in \
+       fcall_exit2.ok \
+       fflush.ok \
+       fflush.sh \
+       fieldwdth.awk \
+       fieldwdth.in \
+       fieldwdth.ok \
+       filefuncs.awk \
+       filefuncs.ok \
+       fldchg.awk \
+       fldchg.in \
+       fldchg.ok \
+       fldchgnf.awk \
+       fldchgnf.in \
+       fldchgnf.ok \
+       fmtspcl-mpfr.ok \
+       fmtspcl.awk \
+       fmtspcl.tok \
+       fmttest.awk \
+       fmttest.ok \
+       fnamedat.awk \
+       fnamedat.in \
+       fnamedat.ok \
+       fnarray.awk \
+       fnarray.ok \
+       fnarray2.awk \
+       fnarray2.in \
+       fnarray2.ok \
+       fnarydel-mpfr.ok \
+       fnarydel.awk \
+       fnarydel.ok \
+       fnaryscl.awk \
+       fnaryscl.ok \
+       fnasgnm.awk \
+       fnasgnm.in \
+       fnasgnm.ok \
+       fnmatch.awk \
+       fnmatch.ok \
+       fnmisc.awk \
+       fnmisc.ok \
+       fnparydl-mpfr.ok \
+       fnparydl.awk \
+       fnparydl.ok \
+       fordel.awk \
+       fordel.ok \
+       fork.awk \
+       fork.ok \
+       fork2.awk \
+       fork2.ok \
+       forref.awk \
+       forref.ok \
+       forsimp.awk \
+       forsimp.ok \
+       fpat1.awk \
+       fpat1.in \
+       fpat1.ok \
+       fpat2.awk \
+       fpat2.ok \
+       fpat3.awk \
+       fpat3.in \
+       fpat3.ok \
+       fpatnull.awk \
+       fpatnull.in \
+       fpatnull.ok \
+       fsbs.awk \
+       fsbs.in \
+       fsbs.ok \
+       fsfwfs.awk \
+       fsfwfs.in \
+       fsfwfs.ok \
+       fsrs.awk \
+       fsrs.in \
+       fsrs.ok \
+       fsspcoln.awk \
+       fsspcoln.in \
+       fsspcoln.ok \
+       fstabplus.awk \
+       fstabplus.in \
+       fstabplus.ok \
+       fts.awk \
+       functab1.awk \
+       functab1.ok \
+       functab2.awk \
+       functab2.ok \
+       functab3.awk \
+       functab3.ok \
+       funlen.awk \
+       funlen.in \
+       funlen.ok \
+       funsemnl.awk \
+       funsemnl.ok \
+       funsmnam.awk \
+       funsmnam.ok \
+       funstack.awk \
+       funstack.in \
+       funstack.ok \
+       fwtest.awk \
+       fwtest.in \
+       fwtest.ok \
+       fwtest2.awk \
+       fwtest2.in \
+       fwtest2.ok \
+       fwtest3.awk \
+       fwtest3.in \
+       fwtest3.ok \
+       gensub.awk \
+       gensub.in \
+       gensub.ok \
+       gensub2.awk \
+       gensub2.ok \
+       getline.awk \
+       getline.in \
+       getline.ok \
+       getline2.awk \
+       getline2.ok \
+       getline3.awk \
+       getline3.ok \
+       getline4.awk \
+       getline4.in \
+       getline4.ok \
+       getline5.awk \
+       getline5.ok \
+       getlnbuf.awk \
+       getlnbuf.in \
+       getlnbuf.ok \
+       getlndir.awk \
+       getlndir.ok \
+       getlnhd.awk \
+       getlnhd.ok \
+       getnr2tb.awk \
+       getnr2tb.in \
+       getnr2tb.ok \
+       getnr2tm.awk \
+       getnr2tm.in \
+       getnr2tm.ok \
+       gnuops2.awk \
+       gnuops2.ok \
+       gnuops3.awk \
+       gnuops3.ok \
+       gnureops.awk \
+       gnureops.ok \
+       gsubasgn.awk \
+       gsubasgn.ok \
+       gsubtest.awk \
+       gsubtest.ok \
+       gsubtst2.awk \
+       gsubtst2.ok \
+       gsubtst3.awk \
+       gsubtst3.in \
+       gsubtst3.ok \
+       gsubtst4.awk \
+       gsubtst4.ok \
+       gsubtst5.awk \
+       gsubtst5.in \
+       gsubtst5.ok \
+       gsubtst6.awk \
+       gsubtst6.ok \
+       gsubtst7.awk \
+       gsubtst7.in \
+       gsubtst7.ok \
+       gsubtst8.awk \
+       gsubtst8.in \
+       gsubtst8.ok \
+       gtlnbufv.awk \
+       hello.awk \
+       hex.awk \
+       hex.ok \
+       hsprint.awk \
+       hsprint.ok \
+       icasefs.awk \
+       icasefs.ok \
+       icasers.awk \
+       icasers.in \
+       icasers.ok \
+       id.awk \
+       id.ok \
+       igncdym.awk \
+       igncdym.in \
+       igncdym.ok \
+       igncfs.awk \
+       igncfs.in \
+       igncfs.ok \
+       ignrcas2.awk \
+       ignrcas2.ok \
+       ignrcase.awk \
+       ignrcase.in \
+       ignrcase.ok \
+       incdupe.ok \
+       incdupe2.ok \
+       incdupe3.ok \
+       incdupe4.ok \
+       incdupe5.ok \
+       incdupe6.ok \
+       incdupe7.ok \
+       inchello.awk \
+       inclib.awk \
+       include.awk \
+       include.ok \
+       include2.ok \
+       indirectcall.awk \
+       indirectcall.in \
+       indirectcall.ok \
+       inftest.awk \
+       inftest.ok \
+       inputred.awk \
+       inputred.ok \
+       intest.awk \
+       intest.ok \
+       intformat.awk \
+       intformat.ok \
+       intprec.awk \
+       intprec.ok \
+       iobug1.awk \
+       iobug1.ok \
+       jarebug.awk \
+       jarebug.in \
+       jarebug.ok \
+       jarebug.sh \
+       lc_num1.awk \
+       lc_num1.ok \
+       leaddig.awk \
+       leaddig.ok \
+       leadnl.awk \
+       leadnl.in \
+       leadnl.ok \
+       lint.awk \
+       lint.ok \
+       lintold.awk \
+       lintold.in \
+       lintold.ok \
+       lintwarn.awk \
+       lintwarn.ok \
+       litoct.awk \
+       litoct.ok \
+       localenl.ok \
+       localenl.sh \
+       longdbl.awk \
+       longdbl.in \
+       longdbl.ok \
+       longsub.awk \
+       longsub.in \
+       longsub.ok \
+       longwrds.awk \
+       longwrds.in \
+       longwrds.ok \
+       manglprm.awk \
+       manglprm.in \
+       manglprm.ok \
+       manyfiles.awk \
+       manyfiles.ok \
+       match1.awk \
+       match1.ok \
+       match2.awk \
+       match2.ok \
+       match3.awk \
+       match3.in \
+       match3.ok \
+       math.awk \
+       math.ok \
+       mbfw1.awk \
+       mbfw1.in \
+       mbfw1.ok \
+       mbprintf1.awk \
+       mbprintf1.in \
+       mbprintf1.ok \
+       mbprintf2.awk \
+       mbprintf2.ok \
+       mbprintf3.awk \
+       mbprintf3.in \
+       mbprintf3.ok \
+       mbstr1.awk \
+       mbstr1.ok \
+       membug1.awk \
+       membug1.in \
+       membug1.ok \
+       messages.awk \
+       minusstr.awk \
+       minusstr.ok \
+       mixed1.ok \
+       mmap8k.in \
+       mtchi18n.awk \
+       mtchi18n.in \
+       mtchi18n.ok \
+       nasty.awk \
+       nasty.ok \
+       nasty2.awk \
+       nasty2.ok \
+       nastyparm.awk \
+       nastyparm.ok \
+       negexp.awk \
+       negexp.ok \
+       negrange.awk \
+       negrange.ok \
+       nested.awk \
+       nested.in \
+       nested.ok \
+       next.ok \
+       next.sh \
+       nfldstr.awk \
+       nfldstr.in \
+       nfldstr.ok \
+       nfneg.awk \
+       nfneg.ok \
+       nfset.awk \
+       nfset.in \
+       nfset.ok \
+       nlfldsep.awk \
+       nlfldsep.in \
+       nlfldsep.ok \
+       nlinstr.awk \
+       nlinstr.in \
+       nlinstr.ok \
+       nlstrina.awk \
+       nlstrina.ok \
+       noeffect.awk \
+       noeffect.ok \
+       nofile.ok \
+       nofmtch.awk \
+       nofmtch.ok \
+       noloop1.awk \
+       noloop1.in \
+       noloop1.ok \
+       noloop2.awk \
+       noloop2.in \
+       noloop2.ok \
+       nondec.awk \
+       nondec.ok \
+       nondec2.awk \
+       nondec2.ok \
+       nonl.awk \
+       nonl.ok \
+       noparms.awk \
+       noparms.ok \
+       nors.in \
+       nors.ok \
+       nulrsend.awk \
+       nulrsend.in \
+       nulrsend.ok \
+       numindex.awk \
+       numindex.in \
+       numindex.ok \
+       numsubstr.awk \
+       numsubstr.in \
+       numsubstr.ok \
+       octsub.awk \
+       octsub.ok \
+       ofmt.awk \
+       ofmt.in \
+       ofmt.ok \
+       ofmta.awk \
+       ofmta.ok \
+       ofmtbig.awk \
+       ofmtbig.in \
+       ofmtbig.ok \
+       ofmtfidl.awk \
+       ofmtfidl.in \
+       ofmtfidl.ok \
+       ofmts.awk \
+       ofmts.in \
+       ofmts.ok \
+       ofs1.awk \
+       ofs1.in \
+       ofs1.ok \
+       onlynl.awk \
+       onlynl.in \
+       onlynl.ok \
+       opasnidx.awk \
+       opasnidx.ok \
+       opasnslf.awk \
+       opasnslf.ok \
+       ordchr.awk \
+       ordchr.ok \
+       ordchr2.ok \
+       out1.ok \
+       out2.ok \
+       out3.ok \
+       paramdup.awk \
+       paramdup.ok \
+       paramres.awk \
+       paramres.ok \
+       paramtyp.awk \
+       paramtyp.ok \
+       paramuninitglobal.awk \
+       paramuninitglobal.ok \
+       parse1.awk \
+       parse1.in \
+       parse1.ok \
+       parsefld.awk \
+       parsefld.in \
+       parsefld.ok \
+       parseme.awk \
+       parseme.ok \
+       patsplit.awk \
+       patsplit.ok \
+       pcntplus.awk \
+       pcntplus.ok \
+       pid.awk \
+       pid.ok \
+       pid.sh \
+       pipeio1.awk \
+       pipeio1.ok \
+       pipeio2.awk \
+       pipeio2.in \
+       pipeio2.ok \
+       posix.awk \
+       posix.in \
+       posix.ok \
+       posix2008sub.awk \
+       posix2008sub.ok \
+       poundbang.awk \
+       prdupval.awk \
+       prdupval.in \
+       prdupval.ok \
+       prec.awk \
+       prec.ok \
+       printf0.awk \
+       printf0.ok \
+       printf1.awk \
+       printf1.ok \
+       printfbad1.awk \
+       printfbad1.ok \
+       printfbad2.awk \
+       printfbad2.in \
+       printfbad2.ok \
+       printfbad3.awk \
+       printfbad3.ok \
+       printfloat.awk \
+       printlang.awk \
+       prmarscl.awk \
+       prmarscl.ok \
+       prmreuse.awk \
+       prmreuse.ok \
+       procinfs.awk \
+       procinfs.ok \
+       profile2.ok \
+       profile3.awk \
+       profile3.ok \
+       prt1eval.awk \
+       prt1eval.ok \
+       prtoeval.awk \
+       prtoeval.ok \
+       pty1.awk \
+       pty1.ok \
+       rand-mpfr.ok \
+       rand.awk \
+       rand.ok \
+       range1.awk \
+       range1.in \
+       range1.ok \
+       readdir.awk \
+       readdir0.awk \
+       rebt8b1.awk \
+       rebt8b1.ok \
+       rebt8b2.awk \
+       rebt8b2.ok \
+       rebuf.awk \
+       rebuf.in \
+       rebuf.ok \
+       redfilnm.awk \
+       redfilnm.in \
+       redfilnm.ok \
+       regeq.awk \
+       regeq.in \
+       regeq.ok \
+       regexprange.awk \
+       regexprange.ok \
+       regrange.awk \
+       regrange.ok \
+       regtest.sh \
+       regx8bit.awk \
+       regx8bit.ok \
+       reindops.awk \
+       reindops.in \
+       reindops.ok \
+       reint.awk \
+       reint.in \
+       reint.ok \
+       reint2.awk \
+       reint2.in \
+       reint2.ok \
+       reparse.awk \
+       reparse.in \
+       reparse.ok \
+       resplit.awk \
+       resplit.in \
+       resplit.ok \
+       revout.awk \
+       revout.ok \
+       revtwoway.awk \
+       revtwoway.ok \
+       rri1.awk \
+       rri1.in \
+       rri1.ok \
+       rs.awk \
+       rs.in \
+       rs.ok \
+       rsnul1nl.awk \
+       rsnul1nl.in \
+       rsnul1nl.ok \
+       rsnulbig.ok \
+       rsnulbig2.ok \
+       rsstart1.awk \
+       rsstart1.in \
+       rsstart1.ok \
+       rsstart2.awk \
+       rsstart2.ok \
+       rsstart3.ok \
+       rstest1.awk \
+       rstest1.ok \
+       rstest2.awk \
+       rstest2.ok \
+       rstest3.awk \
+       rstest3.ok \
+       rstest4.awk \
+       rstest4.ok \
+       rstest5.awk \
+       rstest5.ok \
+       rstest6.awk \
+       rstest6.in \
+       rstest6.ok \
+       rswhite.awk \
+       rswhite.in \
+       rswhite.ok \
+       rtlen.ok \
+       rtlen.sh \
+       rtlen01.ok \
+       rtlen01.sh \
+       rwarray.awk \
+       rwarray.in \
+       rwarray.ok \
+       scalar.awk \
+       scalar.ok \
+       sclforin.awk \
+       sclforin.ok \
+       sclifin.awk \
+       sclifin.ok \
+       shadow.awk \
+       shadow.ok \
+       sort1.awk \
+       sort1.ok \
+       sortempty.awk \
+       sortempty.ok \
+       sortfor.awk \
+       sortfor.in \
+       sortfor.ok \
+       sortu.awk \
+       sortu.ok \
+       space.ok \
+       splitarg4.awk \
+       splitarg4.in \
+       splitarg4.ok \
+       splitargv.awk \
+       splitargv.in \
+       splitargv.ok \
+       splitarr.awk \
+       splitarr.ok \
+       splitdef.awk \
+       splitdef.ok \
+       splitvar.awk \
+       splitvar.in \
+       splitvar.ok \
+       splitwht.awk \
+       splitwht.ok \
+       sprintfc.awk \
+       sprintfc.in \
+       sprintfc.ok \
+       strcat1.awk \
+       strcat1.ok \
+       strftime.awk \
+       strftlng.awk \
+       strftlng.ok \
+       strnum1.awk \
+       strnum1.ok \
+       strtod.awk \
+       strtod.in \
+       strtod.ok \
+       strtonum.awk \
+       strtonum.ok \
+       subamp.awk \
+       subamp.in \
+       subamp.ok \
+       subi18n.awk \
+       subi18n.ok \
+       subsepnm.awk \
+       subsepnm.ok \
+       subslash.awk \
+       subslash.ok \
+       substr.awk \
+       substr.ok \
+       swaplns.awk \
+       swaplns.in \
+       swaplns.ok \
+       switch2.awk \
+       switch2.ok \
+       symtab1.awk \
+       symtab1.ok \
+       symtab2.awk \
+       symtab2.ok \
+       symtab3.awk \
+       symtab3.ok \
+       symtab4.awk \
+       symtab4.in \
+       symtab4.ok \
+       symtab5.awk \
+       symtab5.in \
+       symtab5.ok \
+       symtab6.awk \
+       symtab6.ok \
+       symtab7.awk \
+       symtab7.in \
+       symtab7.ok \
+       symtab8.awk \
+       symtab8.in \
+       symtab8.ok \
+       symtab9.awk \
+       symtab9.ok \
+       synerr1.awk \
+       synerr1.ok \
+       synerr2.awk \
+       synerr2.ok \
+       testext.ok \
+       tradanch.awk \
+       tradanch.in \
+       tradanch.ok \
+       tweakfld.awk \
+       tweakfld.in \
+       tweakfld.ok \
+       uninit2.awk \
+       uninit2.ok \
+       uninit3.awk \
+       uninit3.ok \
+       uninit4.awk \
+       uninit4.ok \
+       uninit5.awk \
+       uninit5.ok \
+       uninitialized.awk \
+       uninitialized.ok \
+       unterm.awk \
+       unterm.ok \
+       uparrfs.awk \
+       uparrfs.in \
+       uparrfs.ok \
+       wideidx.awk \
+       wideidx.in \
+       wideidx.ok \
+       wideidx2.awk \
+       wideidx2.ok \
+       widesub.awk \
+       widesub.ok \
+       widesub2.awk \
+       widesub2.ok \
+       widesub3.awk \
+       widesub3.in \
+       widesub3.ok \
+       widesub4.awk \
+       widesub4.ok \
+       wjposer1.awk \
+       wjposer1.in \
+       wjposer1.ok \
+       xref.awk \
+       xref.original \
+       zero2.awk \
+       zero2.ok \
+       zeroe0.awk \
+       zeroe0.ok \
+       zeroflag.awk \
+       zeroflag.ok
+
+TESTDIR = ../../test
+TESTS_WE_ARE_NOT_DOING_YET_FIXME_ONE_DAY = longdbl
+
+# Get rid of core files when cleaning and generated .ok file
+CLEANFILES = core core.* fmtspcl.ok
+
+# try to keep these sorted. each letter starts a new line
+BASIC_TESTS = \
+       addcomma anchgsub argarray arrayparm arrayprm2 arrayprm3 \
+       arrayref arrymem1 arryref2 arryref3 arryref4 arryref5 arynasty \
+       arynocls aryprm1 aryprm2 aryprm3 aryprm4 aryprm5 aryprm6 aryprm7 \
+       aryprm8 arysubnm asgext awkpath \
+       back89 backgsub \
+       childin clobber closebad clsflnam compare compare2 concat1 concat2 \
+       concat3 concat4 convfmt \
+       datanonl defref delargv delarpm2 delarprm delfunc dfastress dynlj \
+       eofsplit exitval1 exitval2 \
+       fcall_exit fcall_exit2 fldchg fldchgnf fnamedat fnarray fnarray2 \
+       fnaryscl fnasgnm fnmisc fordel forref forsimp fsbs fsrs fsspcoln \
+       fstabplus funsemnl funsmnam funstack \
+       getline getline2 getline3 getline4 getline5 getlnbuf getnr2tb getnr2tm \
+       gsubasgn gsubtest gsubtst2 gsubtst3 gsubtst4 gsubtst5 gsubtst6 \
+       gsubtst7 gsubtst8 \
+       hex hsprint \
+       inputred intest intprec iobug1 \
+       leaddig leadnl litoct longsub longwrds \
+       manglprm math membug1 messages minusstr mmap8k mtchi18n \
+       nasty nasty2 negexp negrange nested nfldstr nfneg nfset nlfldsep \
+       nlinstr nlstrina noeffect nofile nofmtch noloop1 noloop2 nonl \
+       noparms nors nulrsend numindex numsubstr \
+       octsub ofmt ofmta ofmtbig ofmtfidl ofmts ofs1 onlynl opasnidx opasnslf \
+       paramdup paramres paramtyp paramuninitglobal parse1 parsefld parseme \
+       pcntplus posix2008sub prdupval prec printf0 printf1 prmarscl prmreuse \
+       prt1eval prtoeval \
+       rand range1 rebt8b1 redfilnm regeq regexprange regrange \
+       reindops reparse \
+       resplit rri1 rs rsnul1nl rsnulbig rsnulbig2 rstest1 rstest2 \
+       rstest3 rstest4 rstest5 rswhite \
+       scalar sclforin sclifin sortempty splitargv splitarr splitdef \
+       splitvar splitwht strcat1 strnum1 strtod subamp subi18n \
+       subsepnm subslash substr swaplns synerr1 synerr2 tradanch tweakfld \
+       uninit2 uninit3 uninit4 uninit5 uninitialized unterm uparrfs \
+       wideidx wideidx2 widesub widesub2 widesub3 widesub4 wjposer1 \
+       zero2 zeroe0 zeroflag
+
+UNIX_TESTS = \
+       fflush getlnhd localenl pid pipeio1 pipeio2 poundbang rtlen rtlen01 \
+       space strftlng
+
+
+# Tests not run with long double: dumpvars, symtab1, symtab6 --- symbol table 
dumps.
+# Different entries in table, not worth the hassle and who wants to constantly
+# update the *.ok files?
+GAWK_EXT_TESTS = \
+       aadelete1 aadelete2 aarray1 aasort aasorti argtest arraysort \
+       backw badargs beginfile1 binmode1 charasbytes \
+       clos1way delsub devfd devfd1 devfd2 exit \
+       fieldwdth fpat1 fpat2 fpat3  fpatnull fsfwfs funlen \
+       functab1 functab2 functab3 \
+       fwtest fwtest2 fwtest3 \
+       gensub gensub2 getlndir gnuops2 gnuops3 gnureops \
+       icasefs icasers id igncdym igncfs ignrcas2 ignrcase \
+       incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
+       include include2 indirectcall \
+       lint  lintold lintwarn \
+       manyfiles match1 match2 match3 mbstr1 \
+       nastyparm  next nondec nondec2 \
+       patsplit posix printfbad1 printfbad2 printfbad3 procinfs \
+       profile1 profile2 profile3 pty1 \
+       rebuf regx8bit reint reint2 rsstart1 \
+       rsstart2 rsstart3 rstest6 shadow sortfor sortu splitarg4 strftime \
+       strtonum switch2 \
+       symtab2 symtab3 symtab4 symtab5 symtab7 \
+       symtab9
+
+EXTRA_TESTS = inftest regtest
+INET_TESTS = inetdayu inetdayt inetechu inetecht
+MACHINE_TESTS = double1 double2 fmtspcl intformat
+MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint
+
+# Tests not run with long double: fnraydel, fnparydl --- index ordering issue. 
+#      Not really useful for the purpose.
+LOCALE_CHARSET_TESTS = \
+       asort asorti fmttest jarebug lc_num1 mbfw1 \
+       mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc
+
+SHLIB_TESTS = \
+       fnmatch filefuncs fork fork2 fts ordchr ordchr2 \
+       readdir readfile revout revtwoway rwarray testext
+
+
+# List of the tests which should be run with --lint option:
+NEED_LINT = \
+       defref fmtspcl lintwarn noeffect nofmtch shadow \
+       uninit2 uninit3 uninit4 uninit5 uninitialized
+
+
+# List of the tests which should be run with --lint-old option:
+NEED_LINT_OLD = lintold
+
+# List of the tests which fail with EXIT CODE 1
+FAIL_CODE1 = \
+       fnarray2 fnmisc gsubasgn mixed1 noparms paramdup synerr1 synerr2 unterm
+
+
+# List of files which have .ok versions for MPFR
+CHECK_MPFR = \
+       rand fnarydel fnparydl
+
+
+# List of the files that appear in manual tests or are for reserve testing:
+GENTESTS_UNUSED = Makefile.in gtlnbufv.awk printfloat.awk inclib.awk hello.awk
+CMP = cmp
+AWKPROG = ../../gawk$(EXEEXT)
+
+# Default for VALGRIND is empty unless overridden by a command-line argument.
+# This protects against cruft in the environment.
+VALGRIND = 
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in:  $(srcdir)/Makefile.am $(srcdir)/Maketests 
$(am__configure_deps)
+       @for dep in $?; do \
+         case '$(am__configure_deps)' in \
+           *$$dep*) \
+             ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+               && { if test -f $@; then exit 0; else break; fi; }; \
+             exit 1;; \
+         esac; \
+       done; \
+       echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu misc/ldbl_tests/Makefile'; 
\
+       $(am__cd) $(top_srcdir) && \
+         $(AUTOMAKE) --gnu misc/ldbl_tests/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+       @case '$?' in \
+         *config.status*) \
+           cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+         *) \
+           echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ 
$(am__depfiles_maybe)'; \
+           cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ 
$(am__depfiles_maybe);; \
+       esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure 
$(CONFIG_STATUS_DEPENDENCIES)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure:  $(am__configure_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4):  $(am__aclocal_m4_deps)
+       cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+tags: TAGS
+TAGS:
+
+ctags: CTAGS
+CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+       @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+       list='$(DISTFILES)'; \
+         dist_files=`for file in $$list; do echo $$file; done | \
+         sed -e "s|^$$srcdirstrip/||;t" \
+             -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+       case $$dist_files in \
+         */*) $(MKDIR_P) `echo "$$dist_files" | \
+                          sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+                          sort -u` ;; \
+       esac; \
+       for file in $$dist_files; do \
+         if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+         if test -d $$d/$$file; then \
+           dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+           if test -d "$(distdir)/$$file"; then \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx 
{} \;; \
+           fi; \
+           if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+             cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+             find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx 
{} \;; \
+           fi; \
+           cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+         else \
+           test -f "$(distdir)/$$file" \
+           || cp -p $$d/$$file "$(distdir)/$$file" \
+           || exit 1; \
+         fi; \
+       done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+       @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+       if test -z '$(STRIP)'; then \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s 
\
+             install; \
+       else \
+         $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+           install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s 
\
+           "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+       fi
+mostlyclean-generic:
+
+clean-generic:
+       -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+       -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+       -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f 
$(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+       @echo "This command is intended for maintainers to use"
+       @echo "it deletes files that may require special tools to rebuild."
+clean-am: clean-generic mostlyclean-am
+
+distclean: distclean-am
+       -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+       -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic distclean \
+       distclean-generic distdir dvi dvi-am html html-am info info-am \
+       install install-am install-data install-data-am install-dvi \
+       install-dvi-am install-exec install-exec-am install-html \
+       install-html-am install-info install-info-am install-man \
+       install-pdf install-pdf-am install-ps install-ps-am \
+       install-strip installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-generic pdf pdf-am ps ps-am uninstall uninstall-am
+
+
+# Message stuff is to make it a little easier to follow.
+# Make the pass-fail last and dependent on others to avoid
+# spurious errors if `make -j' in effect.
+check: msg \
+       printlang \
+       basic-msg-start  basic           basic-msg-end \
+       unix-msg-start   unix-tests      unix-msg-end \
+       extend-msg-start gawk-extensions extend-msg-end \
+       machine-msg-start machine-tests machine-msg-end \
+       charset-msg-start charset-tests charset-msg-end
+
+basic:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-basic-tests ; fi
+
+ldbl-basic-tests: $(BASIC_TESTS)
+
+unix-tests:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-unix-tests ; fi
+
+ldbl-unix-tests: $(UNIX_TESTS)
+
+gawk-extensions:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-gawk-extensions ; fi
+
+ldbl-gawk-extensions: $(GAWK_EXT_TESTS)
+
+charset-tests:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-charset-tests ; fi
+
+ldbl-charset-tests: $(LOCALE_CHARSET_TESTS)
+
+machine-tests:
+       @if test -n "$$GAWK_FLOAT"; then $(MAKE) ldbl-machine-tests ; fi
+
+ldbl-machine-tests: $(MACHINE_TESTS)
+
+msg::
+       @echo 'Running tests using LONG DOUBLE numbers'
+
+printlang::
+       @$(AWK) -f $(TESTDIR)/printlang.awk
+
+basic-msg-start:
+       @echo "======== Starting basic tests ========"
+
+basic-msg-end:
+       @echo "======== Done with basic tests ========"
+
+unix-msg-start:
+       @echo "======== Starting Unix tests ========"
+
+unix-msg-end:
+       @echo "======== Done with Unix tests ========"
+
+extend-msg-start:
+       @echo "======== Starting gawk extension tests ========"
+
+extend-msg-end:
+       @echo "======== Done with gawk extension tests ========"
+
+machine-msg-start:
+       @echo "======== Starting machine-specific tests ========"
+
+machine-msg-end:
+       @echo "======== Done with machine-specific tests ========"
+
+charset-msg-start:
+       @echo "======== Starting tests that can vary based on character set or 
locale support ========"
+
+charset-msg-end:
+       @echo "======== Done with tests that can vary based on character set or 
locale support ========"
+
+lc_num1:
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# This test is a PITA because increasingly, /tmp is getting
+# mounted noexec.  So, we'll test it locally.  Sigh.
+#
+# More PITA; some systems have medium short limits on #! paths,
+# so this can still fail
+poundbang::
+       @echo $@
+       @sed "s;/tmp/gawk;`pwd`/$(AWKPROG);" < $(TESTDIR)/poundbang.awk > 
./_pbd.awk
+       @chmod +x ./_pbd.awk
+       @if ./_pbd.awk $(TESTDIR)/poundbang.awk > _`basename address@hidden ; \
+       then : ; \
+       else \
+               sed "s;/tmp/gawk;../$(AWKPROG);" < $(TESTDIR)/poundbang.awk > 
./_pbd.awk ; \
+               chmod +x ./_pbd.awk ; \
+               LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} ./_pbd.awk 
$(TESTDIR)/poundbang.awk > _`basename address@hidden;  \
+       fi
+       @-$(CMP) $(TESTDIR)/poundbang.awk _`basename address@hidden && rm -f 
_`basename address@hidden _pbd.awk
+
+messages::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/messages.awk >_out2 2>_out3
+       @-$(CMP) $(TESTDIR)/out1.ok _out1 && $(CMP) $(TESTDIR)/out2.ok _out2 && 
$(CMP) $(TESTDIR)/out3.ok _out3 && rm -f _out1 _out2 _out3
+
+argarray::
+       @echo $@
+       @case $(TESTDIR) in \
+       .)      : ;; \
+       *)      cp $(TESTDIR)/argarray.in . ;; \
+       esac
+       @TEST=test echo just a test | $(AWK) -f $(TESTDIR)/argarray.awk 
./argarray.in - >_$@
+       @case $(TESTDIR) in \
+       .)      : ;; \
+       *)      rm -f ./argarray.in ;; \
+       esac
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regtest::
+       @echo 'Some of the output from regtest is very system specific, do not'
+       @echo 'be distressed if your output differs from that distributed.'
+       @echo 'Manual inspection is called for.'
+       AWK=$(AWKPROG) $(TESTDIR)/regtest.sh
+
+manyfiles::
+       @echo manyfiles
+       @rm -rf junk
+       @mkdir junk
+       @$(AWK) 'BEGIN { for (i = 1; i <= 1030; i++) print i, i}' >_$@
+       @$(AWK) -f $(TESTDIR)/manyfiles.awk _$@ _$@
+       @wc -l junk/* | $(AWK) '$$1 != 2' | wc -l | sed "s/  *//g" > _$@
+       @rm -rf junk
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+compare::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/compare.awk 0 1 $(TESTDIR)/compare.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+inftest::
+       @echo $@
+       @echo This test is very machine specific...
+       @$(AWK) -f $(TESTDIR)/inftest.awk | sed "s/inf/Inf/g" >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline2::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/getline2.awk $(TESTDIR)/getline2.awk 
$(TESTDIR)/getline2.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+awkpath::
+       @echo $@
+       @AWKPATH="$(TESTDIR)$(PATH_SEPARATOR)$(TESTDIR)/lib" $(AWK) -f 
awkpath.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+argtest::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/argtest.awk -x -y abc >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+badargs::
+       @echo $@
+       @-$(AWK) -f 2>&1 | grep -v patchlevel >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nonl::
+       @echo $@
+       @-AWKPATH=$(TESTDIR) $(AWK) --lint -f nonl.awk /dev/null >_$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strftime::
+       @echo This test could fail on slow machines or on a minute boundary,
+       @echo so if it does, double check the actual results:
+       @echo $@
+       @GAWKLOCALE=C; export GAWKLOCALE; \
+       TZ=GMT0; export TZ; \
+       (LC_ALL=C date) | $(AWK) -v OUTPUT=_$@ -f $(TESTDIR)/strftime.awk
+       @-$(CMP) strftime.ok _$@ && rm -f _$@ strftime.ok || exit 0
+
+litoct::
+       @echo $@
+       @echo ab | $(AWK) --traditional -f $(TESTDIR)/litoct.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+devfd::
+       @echo $@
+       @$(AWK) 1 /dev/fd/4 /dev/fd/5 4<$(TESTDIR)/devfd.in4 
5<$(TESTDIR)/devfd.in5 >_$@ 2>&1 || echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fflush::
+       @echo $@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+tweakfld::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/tweakfld.awk $(TESTDIR)/tweakfld.in >_$@
+       @rm -f errors.cleanup
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mmap8k::
+       @echo $@
+       @$(AWK) '{ print }' $(TESTDIR)/mmap8k.in >_$@
+       @-$(CMP) $(TESTDIR)/mmap8k.in _$@ && rm -f _$@
+
+tradanch::
+       @echo $@
+       @$(AWK) --traditional -f $(TESTDIR)/tradanch.awk $(TESTDIR)/tradanch.in 
>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# AIX /bin/sh exec's the last command in a list, therefore issue a ":"
+# command so that pid.sh is fork'ed as a child before being exec'ed.
+pid::
+       @echo pid
+       @AWKPATH=$(TESTDIR) AWK=$(AWKPROG) $(SHELL) $(TESTDIR)/pid.sh $$$$ > 
_`basename address@hidden ; :
+       @-$(CMP) $(TESTDIR)/pid.ok _`basename address@hidden && rm -f 
_`basename address@hidden
+
+strftlng::
+       @echo $@
+       @TZ=UTC; export TZ; $(AWK) -f $(TESTDIR)/strftlng.awk >_$@
+       @if $(CMP) $(TESTDIR)/strftlng.ok _$@ >/dev/null 2>&1 ; then : ; else \
+       TZ=UTC0; export TZ; $(AWK) -f $(TESTDIR)/strftlng.awk >_$@ ; \
+       fi
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nors::
+       @echo $@
+       @echo A B C D E | tr -d '\12\15' | $(AWK) '{ print $$NF }' - 
$(TESTDIR)/nors.in > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fmtspcl.ok: $(TESTDIR)/fmtspcl.tok Makefile
+       @$(AWK) -v "sd=$(TESTDIR)" 'BEGIN {pnan = sprintf("%g",sqrt(-1)); nnan 
= sprintf("%g",-sqrt(-1)); pinf = sprintf("%g",-log(0)); ninf = 
sprintf("%g",log(0))} {sub(/positive_nan/,pnan); sub(/negative_nan/,nnan); 
sub(/positive_infinity/,pinf); sub(/negative_infinity/,ninf); 
sub(/fmtspcl/,(sd"/fmtspcl")); print}' < $(TESTDIR)/fmtspcl.tok > $@ 2>/dev/null
+
+fmtspcl: fmtspcl.ok
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/fmtspcl.awk  --lint >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
+       @-if test -z "$$AWKFLAGS" ; then $(CMP) address@hidden _$@ && rm -f _$@ 
; else \
+       $(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@ ; \
+       fi
+
+reint::
+       @echo $@
+       @$(AWK) --re-interval -f $(TESTDIR)/reint.awk $(TESTDIR)/reint.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+pipeio1::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/pipeio1.awk >_$@
+       @rm -f test1 test2
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+pipeio2::
+       @echo $@
+       @$(AWK) -v SRCDIR=$(TESTDIR) -f $(TESTDIR)/pipeio2.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+clobber::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/clobber.awk >_$@
+       @-$(CMP) $(TESTDIR)/clobber.ok seq && $(CMP) $(TESTDIR)/clobber.ok _$@ 
&& rm -f _$@
+       @rm -f seq
+
+arynocls::
+       @echo $@
+       @-AWKPATH=$(TESTDIR) $(AWK) -v INPUT=$(TESTDIR)/arynocls.in -f 
arynocls.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getlnbuf::
+       @echo $@
+       @-AWKPATH=$(TESTDIR) $(AWK) -f getlnbuf.awk $(TESTDIR)/getlnbuf.in > _$@
+       @-AWKPATH=$(TESTDIR) $(AWK) -f gtlnbufv.awk $(TESTDIR)/getlnbuf.in > 
_2$@
+       @-$(CMP) $(TESTDIR)/getlnbuf.ok _$@ && $(CMP) $(TESTDIR)/getlnbuf.ok 
_2$@ && rm -f _$@ _2$@
+
+inetmesg::
+       @echo These tests only work if your system supports the services
+       @echo "'discard'" at port 9 and "'daytimed'" at port 13. Check your
+       @echo file /etc/services and do "'netstat -a'".
+
+inetechu::
+       @echo This test is for establishing UDP connections
+       @$(AWK) 'BEGIN {print "" |& "/inet/udp/0/127.0.0.1/9"}'
+
+inetecht::
+       @echo This test is for establishing TCP connections
+       @$(AWK) 'BEGIN {print "" |& "/inet/tcp/0/127.0.0.1/9"}'
+
+inetdayu::
+       @echo This test is for bidirectional UDP transmission
+       @$(AWK) 'BEGIN { print "" |& "/inet/udp/0/127.0.0.1/13"; \
+       "/inet/udp/0/127.0.0.1/13" |& getline; print $0}'
+
+inetdayt::
+       @echo This test is for bidirectional TCP transmission
+       @$(AWK) 'BEGIN { print "" |& "/inet/tcp/0/127.0.0.1/13"; \
+       "/inet/tcp/0/127.0.0.1/13" |& getline; print $0}'
+
+redfilnm::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/redfilnm.awk srcdir=$(TESTDIR) 
$(TESTDIR)/redfilnm.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+leaddig::
+       @echo $@
+       @$(AWK) -v x=2E  -f $(TESTDIR)/leaddig.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst3::
+       @echo $@
+       @$(AWK) --re-interval -f $(TESTDIR)/address@hidden 
$(TESTDIR)/address@hidden >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+space::
+       @echo $@
+       @$(AWK) -f ' ' $(TESTDIR)/space.awk >_$@ 2>&1 || echo EXIT CODE: $$? 
>>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printf0::
+       @echo $@
+       @$(AWK) --posix -f $(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsnulbig::
+       @echo $@
+       @ : Suppose that block size for pipe is at most 128kB:
+       @$(AWK) 'BEGIN { for (i = 1; i <= 128*64+1; i++) print 
"abcdefgh123456\n" }' 2>&1 | \
+       $(AWK) 'BEGIN { RS = ""; ORS = "\n\n" }; { print }' 2>&1 | \
+       $(AWK) '/^[^a]/; END{ print NR }' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsnulbig2::
+       @echo $@
+       @$(AWK) 'BEGIN { ORS = ""; n = "\n"; for (i = 1; i <= 10; i++) n = (n 
n); \
+               for (i = 1; i <= 128; i++) print n; print "abc\n" }' 2>&1 | \
+               $(AWK) 'BEGIN { RS = ""; ORS = "\n\n" };{ print }' 2>&1 | \
+               $(AWK) '/^[^a]/; END { print NR }' >_$@ 2>&1 || echo EXIT CODE: 
$$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+wideidx::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+wideidx2::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+widesub::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+widesub2::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+widesub3::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+widesub4::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ignrcas2::
+       @echo $@
+       @GAWKLOCALE=en_US ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >> 
_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+subamp::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# This test makes sure gawk exits with a zero code.
+# Thus, unconditionally generate the exit code.
+exitval1::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/exitval1.awk >_$@ 2>&1; echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsspcoln::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/address@hidden 'FS=[ :]+' 
$(TESTDIR)/address@hidden >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsstart1::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/rsstart1.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsstart2::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/rsstart1.in >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsstart3::
+       @echo $@
+       @head $(TESTDIR)/rsstart1.in | $(AWK) -f $(TESTDIR)/rsstart2.awk >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rtlen::
+       @echo $@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden >_$@ || echo EXIT CODE: 
$$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rtlen01::
+       @echo $@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden >_$@ || echo EXIT CODE: 
$$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rtlenmb::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+       AWK=$(AWKPROG) $(TESTDIR)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/rtlen.ok _$@ && rm -f _$@
+
+nondec2::
+       @echo $@
+       @$(AWK) --non-decimal-data -v a=0x1 -f $(TESTDIR)/address@hidden >_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nofile::
+       @echo $@
+       @$(AWK) '{}' no/such/file >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+binmode1::
+       @echo $@
+       @$(AWK) -v BINMODE=3 'BEGIN { print BINMODE }' >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+subi18n::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f $(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat4::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; $(AWK) -f $(TESTDIR)/address@hidden 
$(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+devfd1::
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/address@hidden 4< $(TESTDIR)/devfd.in1 5< 
$(TESTDIR)/devfd.in2 >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# The program text is the '1' which will print each record. How compact can 
you get?
+devfd2::
+       @echo $@
+       @$(AWK) 1 /dev/fd/4 /dev/fd/5 4< $(TESTDIR)/devfd.in1 5< 
$(TESTDIR)/devfd.in2 >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mixed1::
+       @echo $@
+       @$(AWK) -f /dev/null --source 'BEGIN {return junk}' >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mtchi18n::
+       @echo $@
+       @GAWKLOCALE=ru_RU.UTF-8 ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+reint2::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) --re-interval -f address@hidden 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+localenl::
+       @echo $@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden >_$@ 2>/dev/null
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mbprintf1::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mbprintf2::
+       @echo $@
+       @GAWKLOCALE=ja_JP.UTF-8 ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >> 
_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mbprintf3::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mbfw1::
+       @echo $@
+       @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
+       $(AWK) -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden >_$@ 2>&1 
|| echo EXIT CODE: $$? >> _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst6::
+       @echo $@
+       @GAWKLOCALE=C ; $(AWK) -f $(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mbstr1::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printfbad2: $(TESTDIR)/printfbad2.ok
+       @echo $@
+       @$(AWK) --lint -f $(TESTDIR)/address@hidden $(TESTDIR)/address@hidden 
2>&1 | sed 's;\$(TESTDIR)/;;g' >_$@ || echo EXIT CODE: $$?  >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+beginfile1::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden $(TESTDIR)/address@hidden 
. ./no/such/file Makefile  >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+dumpvars::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --dump-variables 1 < 
$(TESTDIR)/address@hidden >/dev/null 2>&1 || echo EXIT CODE: $$? >>_$@
+       @mv awkvars.out _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+profile1:
+       @echo $@
+       @$(AWK) address@hidden -f $(TESTDIR)/xref.awk $(TESTDIR)/dtdgport.awk > 
address@hidden
+       @$(AWK) -f address@hidden $(TESTDIR)/dtdgport.awk > address@hidden ; rm 
address@hidden
+       @cmp address@hidden address@hidden && rm address@hidden || echo EXIT 
CODE: $$? >>_$@
+
+profile2:
+       @echo $@
+       @$(AWK) address@hidden -v sortcmd=sort -f $(TESTDIR)/xref.awk 
$(TESTDIR)/dtdgport.awk > /dev/null
+       @sed 1,2d < address@hidden > _$@; rm address@hidden
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+profile3:
+       @echo $@
+       @$(AWK) address@hidden -f $(TESTDIR)/address@hidden > /dev/null
+       @sed 1,2d < address@hidden > _$@; rm address@hidden
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+posix2008sub:
+       @echo $@
+       @$(AWK) --posix -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+next:
+       @echo $@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-LC_ALL=C $(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+exit:
+       @echo $@
+       @-AWK="$(AWKPROG)" $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rri1::
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rand:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-if test -z "$$AWKFLAGS" ; then $(CMP) $(TESTDIR)/address@hidden _$@ 
&& rm -f _$@ ; else \
+       ($(CMP) $(TESTDIR)/address@hidden _$@ || $(CMP) 
$(TESTDIR)/address@hidden _$@) && rm -f _$@ ; \
+       fi
+
+mpfrieee:
+       @echo $@
+       @$(AWK) -M -vPREC=double -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mpfrexprange:
+       @echo $@
+       @$(AWK) -M -vPREC=53 -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mpfrrnd:
+       @echo $@
+       @$(AWK) -M -vPREC=53 -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mpfrnr:
+       @echo $@
+       @$(AWK) -M -vPREC=113 -f $(TESTDIR)/address@hidden 
$(TESTDIR)/address@hidden > _$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mpfrsort:
+       @echo $@
+       @$(AWK) -M -vPREC=53 -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+mpfrbigint:
+       @echo $@
+       @$(AWK) -M -f $(TESTDIR)/address@hidden > _$@ 2>&1
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+jarebug::
+       @echo $@
+       @$(TESTDIR)/address@hidden "$(AWKPROG)" "$(TESTDIR)/address@hidden" 
"$(TESTDIR)/address@hidden" "_$@"
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ordchr2::
+       @echo $@
+       @$(AWK) -l ordchr 'BEGIN {print chr(ord("z"))}' >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# N.B. If the test fails, create readfile.ok so that "make diffout" will work
+readfile::
+       @echo $@
+       @$(AWK) -l readfile 'BEGIN {printf "%s", readfile("Makefile")}' >_$@ 
2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) Makefile _$@ && rm -f _$@ || cp -p Makefile address@hidden
+
+include2::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -i inclib 'BEGIN {print sandwich("a", "b", 
"c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -i inclib -i inclib.awk 'BEGIN {print 
sandwich("a", "b", "c")}' >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe2::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f inclib -f inclib.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe3::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe4::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f hello -i hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe5::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -i hello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe6::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -i inchello -f hello.awk >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+incdupe7::
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) --lint -f hello -i inchello >_$@ 2>&1 || 
echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+testext::
+       @echo $@
+       @$(AWK) '/^(@load|BEGIN)/,/^}/' $(top_srcdir)/extension/testext.c > 
testext.awk
+       @$(AWK) -f testext.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@ testext.awk
+
+readdir:
+       @echo This test can fail on some filesystems.
+       @echo $@
+       @ls -fli $(top_srcdir) | sed 1d | $(AWK) -f $(TESTDIR)/readdir0.awk > 
address@hidden
+       @$(AWK) -f $(TESTDIR)/readdir.awk $(top_srcdir) > _$@
+       @-$(CMP) address@hidden _$@ && rm -f address@hidden _$@
+
+fts:
+       @echo $@
+       @$(AWK) -f $(TESTDIR)/fts.awk
+       @-$(CMP) address@hidden _$@ && rm -f address@hidden _$@
+
+charasbytes:
+       @echo $@
+       @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \
+       AWKPATH=$(TESTDIR) $(AWK) -b -f address@hidden 
$(TESTDIR)/address@hidden | \
+       od -c -t x1 | sed -e 's/  */ /g' -e 's/ *$$//' >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab6:
+       @echo $@
+       @$(AWK) -d__$@ -f $(TESTDIR)/address@hidden
+       @grep -v '^ENVIRON' __$@ | grep -v '^PROCINFO' > _$@ ; rm __$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+Gt-dummy:
+# file Maketests, generated from Makefile.am by the Gentests program
+addcomma:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+anchgsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayparm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayprm2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayprm3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayref:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrymem1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arynasty:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm6:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm7:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm8:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arysubnm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+asgext:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+back89:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+backgsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+childin:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+closebad:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+clsflnam:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+compare2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+convfmt:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+datanonl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+defref:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delargv:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delarpm2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delarprm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delfunc:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+dfastress:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+dynlj:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+eofsplit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+exitval2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fcall_exit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fcall_exit2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fldchg:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fldchgnf:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnamedat:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnarray:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnarray2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnaryscl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnasgnm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnmisc:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fordel:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+forref:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+forsimp:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsbs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsrs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fstabplus:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funsemnl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funsmnam:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funstack:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getnr2tb:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getnr2tm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubasgn:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst7:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst8:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+hex:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+hsprint:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+inputred:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+intest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+intprec:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+iobug1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+leadnl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+longsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+longwrds:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+manglprm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+math:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+membug1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+minusstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nasty:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nasty2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+negexp:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+negrange:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nested:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nfldstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nfneg:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nfset:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nlfldsep:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nlinstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nlstrina:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noeffect:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nofmtch:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noloop1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noloop2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noparms:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nulrsend:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+numindex:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+numsubstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+octsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmt:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmta:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmtbig:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmtfidl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmts:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofs1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+onlynl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+opasnidx:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+opasnslf:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramdup:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramres:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramtyp:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramuninitglobal:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+parse1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+parsefld:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+parseme:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+pcntplus:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prdupval:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prec:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printf1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prmarscl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prmreuse:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prt1eval:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prtoeval:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+range1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rebt8b1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regeq:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regexprange:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regrange:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+reindops:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+reparse:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+resplit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsnul1nl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rswhite:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+scalar:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sclforin:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sclifin:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sortempty:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitargv:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitarr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitdef:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitvar:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitwht:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strcat1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strnum1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strtod:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+subsepnm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+subslash:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+substr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+swaplns:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+synerr1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+synerr2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninitialized:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+unterm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uparrfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+wjposer1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+zero2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+zeroe0:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+zeroflag:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getlnhd:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aadelete1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aadelete2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aarray1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aasort:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aasorti:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arraysort:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+backw:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+clos1way:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fieldwdth:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpat1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpat2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpat3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpatnull:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsfwfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funlen:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+functab1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+functab2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+functab3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fwtest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fwtest2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fwtest3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gensub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gensub2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getlndir:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gnuops2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gnuops3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gnureops:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+icasefs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+icasers:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+id:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+igncdym:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+igncfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ignrcase:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+include:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+indirectcall:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+lint:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+lintold:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint-old < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+lintwarn:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+match1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+match2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+match3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nastyparm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nondec:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+patsplit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+posix:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printfbad1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printfbad3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+procinfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+pty1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rebuf:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regx8bit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest6:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+shadow:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sortfor:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sortu:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitarg4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strtonum:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+switch2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab7:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab9:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+double1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+double2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+intformat:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+asort:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+asorti:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fmttest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rebt8b2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sort1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sprintfc:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnmatch:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+filefuncs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fork:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fork2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ordchr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+revout:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+revtwoway:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rwarray:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# end of file Maketests
+
+# Targets generated for other tests:
+
+$(srcdir)/Maketests: $(srcdir)/Makefile.am $(srcdir)/Gentests
+       files=`cd "$(TESTDIR)" && echo *.awk *.in`; \
+       $(AWK) -f $(srcdir)/Gentests "$(srcdir)/Makefile.am" $$files > 
$(srcdir)/Maketests
+
+clean:
+       rm -fr _* core core.* fmtspcl.ok junk strftime.ok test1 test2 seq *~ 
readfile.ok fork.tmp.* testext.awk fts.ok readdir.ok
+
+# An attempt to print something that can be grepped for in build logs
+pass-fail:
+       @COUNT=`ls _* 2>/dev/null | wc -l` ; \
+       if test $$COUNT = 0 ; \
+       then    echo ALL TESTS PASSED ; \
+       else    echo $$COUNT TESTS FAILED ; \
+       fi
+
+# This target for my convenience to look at all the results
+diffout:
+       for i in _* ; \
+       do  \
+               if [ "$$i" != "_*" ]; then \
+               echo ============== $$i ============= ; \
+               if [ -r $${i#_}.ok ]; then \
+               diff -c $${i#_}.ok $$i ; \
+               else \
+               diff -c $(srcdir)/$${i#_}.ok  $$i ; \
+               fi ; \
+               fi ; \
+       done | more
+
+# convenient way to scan valgrind results for errors
+valgrind-scan:
+       @echo "Scanning valgrind log files for problems:"
+       @$(AWK) '\
+       function show() {if (cmd) {printf "%s: %s\n",FILENAME,cmd; cmd = ""}; \
+         printf "\t%s\n",$$0}; \
+       {$$1 = ""}; \
+       $$2 == "Command:" {incmd = 1; $$2 = ""; cmd = $$0; next}; \
+       incmd {if (/Parent PID:/) incmd = 0; else {cmd = (cmd $$0); next}}; \
+       /ERROR SUMMARY:/ && !/: 0 errors from 0 contexts/ {show()}; \
+       /definitely lost:/ && !/: 0 bytes in 0 blocks/ {show()}; \
+       /possibly lost:/ && !/: 0 bytes in 0 blocks/ {show()}; \
+       / suppressed:/ && !/: 0 bytes in 0 blocks/ {show()}; \
+       ' log.[0-9]*
+
+# This target is for testing with electric fence.
+efence:
+       for i in $$(ls _* | sed 's;_\(.*\);\1;') ; \
+       do \
+               bad=$$(wc -l < _$$i) \
+               ok=$$(wc -l < $$i.ok) ; \
+               if (( $$bad == $$ok + 2 )) ; \
+               then \
+                       rm _$$i ; \
+               fi ; \
+       done
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/misc/ldbl_tests/Maketests b/misc/ldbl_tests/Maketests
new file mode 100644
index 0000000..d723560
--- /dev/null
+++ b/misc/ldbl_tests/Maketests
@@ -0,0 +1,1298 @@
+Gt-dummy:
+# file Maketests, generated from Makefile.am by the Gentests program
+addcomma:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+anchgsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayparm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayprm2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayprm3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrayref:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arrymem1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arryref5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arynasty:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm6:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm7:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aryprm8:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arysubnm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+asgext:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+back89:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+backgsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+childin:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+closebad:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+clsflnam:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+compare2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+concat3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+convfmt:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+datanonl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+defref:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delargv:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delarpm2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delarprm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delfunc:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+dfastress:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+dynlj:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+eofsplit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+exitval2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fcall_exit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fcall_exit2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fldchg:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fldchgnf:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnamedat:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnarray:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnarray2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnaryscl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnasgnm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnmisc:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fordel:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+forref:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+forsimp:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsbs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsrs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fstabplus:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funsemnl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funsmnam:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funstack:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getline5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getnr2tb:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getnr2tm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubasgn:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst7:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gsubtst8:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+hex:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+hsprint:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+inputred:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+intest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+intprec:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+iobug1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+leadnl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+longsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+longwrds:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+manglprm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+math:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+membug1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+minusstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nasty:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nasty2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+negexp:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+negrange:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nested:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nfldstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nfneg:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nfset:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nlfldsep:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nlinstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nlstrina:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noeffect:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nofmtch:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noloop1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noloop2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+noparms:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nulrsend:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+numindex:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+numsubstr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+octsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmt:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmta:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmtbig:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmtfidl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofmts:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ofs1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+onlynl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+opasnidx:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+opasnslf:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramdup:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramres:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramtyp:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+paramuninitglobal:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+parse1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+parsefld:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+parseme:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+pcntplus:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prdupval:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prec:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printf1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prmarscl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prmreuse:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prt1eval:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+prtoeval:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+range1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rebt8b1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regeq:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regexprange:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regrange:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+reindops:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+reparse:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+resplit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rsnul1nl:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rswhite:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+scalar:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sclforin:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sclifin:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sortempty:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitargv:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitarr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitdef:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitvar:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitwht:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strcat1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strnum1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strtod:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+subsepnm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+subslash:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+substr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+swaplns:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+synerr1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+synerr2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninit5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uninitialized:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+unterm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+uparrfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+wjposer1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+zero2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+zeroe0:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+zeroflag:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getlnhd:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aadelete1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aadelete2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aarray1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aasort:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+aasorti:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+arraysort:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+backw:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+clos1way:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+delsub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fieldwdth:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpat1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpat2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpat3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fpatnull:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fsfwfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+funlen:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+functab1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+functab2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+functab3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fwtest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fwtest2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fwtest3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gensub:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gensub2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+getlndir:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gnuops2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gnuops3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+gnureops:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+icasefs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+icasers:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+id:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+igncdym:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+igncfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ignrcase:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+include:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+indirectcall:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+lint:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+lintold:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint-old < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+lintwarn:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+match1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+match2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+match3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nastyparm:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+nondec:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+patsplit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+posix:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printfbad1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+printfbad3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+procinfs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+pty1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rebuf:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+regx8bit:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rstest6:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+shadow:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  --lint >_$@ 2>&1 || echo 
EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sortfor:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sortu:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+splitarg4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+strtonum:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+switch2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab3:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab4:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab5:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab7:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+symtab9:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+double1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+double2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+intformat:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+asort:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+asorti:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fmttest:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rebt8b2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sort1:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+sprintfc:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fnmatch:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+filefuncs:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fork:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+fork2:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+ordchr:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+revout:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+revtwoway:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+rwarray:
+       @echo $@
+       @AWKPATH=$(TESTDIR) $(AWK) -f address@hidden  < 
$(TESTDIR)/address@hidden >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
+       @-$(CMP) $(TESTDIR)/address@hidden _$@ && rm -f _$@
+
+# end of file Maketests
diff --git a/test/Makefile.am b/test/Makefile.am
index da67b05..667f26e 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -820,8 +820,6 @@ EXTRA_DIST = \
        synerr2.awk \
        synerr2.ok \
        testext.ok \
-       time.awk \
-       time.ok \
        tradanch.awk \
        tradanch.in \
        tradanch.ok \
@@ -954,7 +952,7 @@ LOCALE_CHARSET_TESTS = \
 
 SHLIB_TESTS = \
        fnmatch filefuncs fork fork2 fts ordchr ordchr2 \
-       readdir readfile revout revtwoway rwarray testext time
+       readdir readfile revout revtwoway rwarray testext
 
 # List of the tests which should be run with --lint option:
 NEED_LINT = \
@@ -992,6 +990,7 @@ VALGRIND =
 # And we set AWKLIBPATH to find the extension libraries we built.
 AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} 
AWKLIBPATH=../extension/.libs $(VALGRIND) $(AWKPROG)
 
+
 # Message stuff is to make it a little easier to follow.
 # Make the pass-fail last and dependent on others to avoid
 # spurious errors if `make -j' in effect.
@@ -1002,7 +1001,10 @@ check:   msg \
        extend-msg-start gawk-extensions extend-msg-end \
        machine-msg-start machine-tests machine-msg-end \
        charset-msg-start charset-tests charset-msg-end \
-       shlib-msg-start  shlib-tests     shlib-msg-end
+       shlib-msg-start  shlib-tests     shlib-msg-end \
+       pass-fail-all
+
+pass-fail-all:
        @$(MAKE) pass-fail
 
 basic: $(BASIC_TESTS)
@@ -1192,7 +1194,7 @@ devfd::
 
 fflush::
        @echo $@
-       @$(srcdir)/fflush.sh >_$@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden > _$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 tweakfld::
@@ -1415,18 +1417,18 @@ rsstart3::
 
 rtlen::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? >>_$@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? 
>>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 rtlen01::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? >>_$@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? 
>>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 rtlenmb::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(srcdir)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
+       AWK=$(AWKPROG) $(srcdir)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/rtlen.ok _$@ && rm -f _$@
 
 nondec2::
@@ -1484,7 +1486,7 @@ reint2::
 
 localenl::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ 2>/dev/null
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden >_$@ 2>/dev/null
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 mbprintf1::
@@ -1726,9 +1728,18 @@ clean:
 pass-fail:
        @COUNT=`ls _* 2>/dev/null | wc -l` ; \
        if test $$COUNT = 0 ; \
-       then    echo ALL TESTS PASSED ; \
-       else    echo $$COUNT TESTS FAILED ; \
-       fi
+       then    echo double tests: ALL TESTS PASSED ; \
+       else    echo double tests: $$COUNT TESTS FAILED ; \
+       fi ; \
+       if grep 'USE_LONG_DOUBLE 1' $(top_builddir)/config.h > /dev/null ; then 
\
+          COUNT_LDBL=`ls ../misc/ldbl_tests/_* 2>/dev/null | wc -l` ; \
+          if test $$COUNT_LDBL = 0 ; \
+             then echo long double tests: ALL TESTS PASSED ; \
+          else echo long double tests: $$COUNT_LDBL TESTS FAILED ; \
+          fi ; \
+       else echo long double is not supported on this system ; \
+       fi ;
+
 
 # This target for my convenience to look at all the results
 diffout:
diff --git a/test/Makefile.in b/test/Makefile.in
index 8ee67d2..e64dbb1 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -1035,8 +1035,6 @@ EXTRA_DIST = \
        synerr2.awk \
        synerr2.ok \
        testext.ok \
-       time.awk \
-       time.ok \
        tradanch.awk \
        tradanch.in \
        tradanch.ok \
@@ -1164,7 +1162,7 @@ LOCALE_CHARSET_TESTS = \
 
 SHLIB_TESTS = \
        fnmatch filefuncs fork fork2 fts ordchr ordchr2 \
-       readdir readfile revout revtwoway rwarray testext time
+       readdir readfile revout revtwoway rwarray testext
 
 
 # List of the tests which should be run with --lint option:
@@ -1388,7 +1386,10 @@ check:   msg \
        extend-msg-start gawk-extensions extend-msg-end \
        machine-msg-start machine-tests machine-msg-end \
        charset-msg-start charset-tests charset-msg-end \
-       shlib-msg-start  shlib-tests     shlib-msg-end
+       shlib-msg-start  shlib-tests     shlib-msg-end \
+       pass-fail-all
+
+pass-fail-all:
        @$(MAKE) pass-fail
 
 basic: $(BASIC_TESTS)
@@ -1576,7 +1577,7 @@ devfd::
 
 fflush::
        @echo $@
-       @$(srcdir)/fflush.sh >_$@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden > _$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 tweakfld::
@@ -1799,18 +1800,18 @@ rsstart3::
 
 rtlen::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? >>_$@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? 
>>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 rtlen01::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? >>_$@
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden >_$@ || echo EXIT CODE: $$? 
>>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 rtlenmb::
        @echo $@
        @GAWKLOCALE=en_US.UTF-8 ; export GAWKLOCALE ; \
-       $(srcdir)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
+       AWK=$(AWKPROG) $(srcdir)/rtlen.sh >_$@ || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/rtlen.ok _$@ && rm -f _$@
 
 nondec2::
@@ -1868,7 +1869,7 @@ reint2::
 
 localenl::
        @echo $@
-       @$(srcdir)/address@hidden >_$@ 2>/dev/null
+       @-AWK="$(AWKPROG)" $(srcdir)/address@hidden >_$@ 2>/dev/null
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
 mbprintf1::
@@ -3416,11 +3417,6 @@ rwarray:
        @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
-time:
-       @echo $@
-       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
-
 # end of file Maketests
 
 # Targets generated for other tests:
@@ -3436,9 +3432,17 @@ clean:
 pass-fail:
        @COUNT=`ls _* 2>/dev/null | wc -l` ; \
        if test $$COUNT = 0 ; \
-       then    echo ALL TESTS PASSED ; \
-       else    echo $$COUNT TESTS FAILED ; \
-       fi
+       then    echo double tests: ALL TESTS PASSED ; \
+       else    echo double tests: $$COUNT TESTS FAILED ; \
+       fi ; \
+       if grep 'USE_LONG_DOUBLE 1' $(top_builddir)/config.h > /dev/null ; then 
\
+          COUNT_LDBL=`ls ../misc/ldbl_tests/_* 2>/dev/null | wc -l` ; \
+          if test $$COUNT_LDBL = 0 ; \
+             then echo long double tests: ALL TESTS PASSED ; \
+          else echo long double tests: $$COUNT_LDBL TESTS FAILED ; \
+          fi ; \
+       else echo long double is not supported on this system ; \
+       fi ;
 
 # This target for my convenience to look at all the results
 diffout:
diff --git a/test/Maketests b/test/Maketests
index be8b53b..7ab8405 100644
--- a/test/Maketests
+++ b/test/Maketests
@@ -1319,9 +1319,4 @@ rwarray:
        @AWKPATH=$(srcdir) $(AWK) -f address@hidden  < $(srcdir)/address@hidden 
>_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
        @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
 
-time:
-       @echo $@
-       @AWKPATH=$(srcdir) $(AWK) -f address@hidden  >_$@ 2>&1 || echo EXIT 
CODE: $$? >>_$@
-       @-$(CMP) $(srcdir)/address@hidden _$@ && rm -f _$@
-
 # end of file Maketests
diff --git a/test/fflush.sh b/test/fflush.sh
index 42d624c..f079cb0 100755
--- a/test/fflush.sh
+++ b/test/fflush.sh
@@ -1,16 +1,23 @@
 #! /bin/sh
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print "2nd"|"cat"}'
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print "2nd"|"cat"}'|cat
+if [ "$AWK" = "" ]
+then
+       echo $0: You must set AWK >&2
+       exit 1
+fi
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");close("/dev/stdout");print 
"2nd"|"cat"}'|cat
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print "2nd"|"cat"}'
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"cat";close("cat")}'|cat
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print "2nd"|"cat"}'|cat
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"cat";close("cat")}'|cat
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");close("/dev/stdout");print 
"2nd"|"cat"}'|cat
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"cat";close("cat")}'|cat
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"cat";close("cat")}'|cat
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print "2nd"|"sort"}'|cat
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"cat";close("cat")}'|cat
 
-../gawk 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"sort";close("sort")}'|cat
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"cat";close("cat")}'|cat
+
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print "2nd"|"sort"}'|cat
+
+$AWK 'BEGIN{print "1st";fflush("/dev/stdout");print 
"2nd"|"sort";close("sort")}'|cat
diff --git a/test/localenl.sh b/test/localenl.sh
index ca3ee64..cd15bba 100755
--- a/test/localenl.sh
+++ b/test/localenl.sh
@@ -33,7 +33,11 @@
 # 
 #! /bin/sh
 
-AWK=${AWK:-../gawk}
+if [ "$AWK" = "" ]
+then
+       echo $0: You must set AWK >&2
+       exit 1
+fi
 
 # April 2010: Remove UNKNOWN, causes spurious failures on some systems
 for LC_ALL in C POSIX en_US.ISO-8859-1 en_US.UTF-8 #UNKNOWN 
diff --git a/test/rtlen.sh b/test/rtlen.sh
index 4a74045..85ad9c9 100755
--- a/test/rtlen.sh
+++ b/test/rtlen.sh
@@ -1,5 +1,9 @@
 #! /bin/sh
 
-AWK=${AWK:-../gawk}
+if [ "$AWK" = "" ]
+then
+       echo $0: You must set AWK >&2
+       exit 1
+fi
 
 $AWK 'BEGIN {printf "0\n\n\n1\n\n\n\n\n2\n\n"; exit}' | $AWK 'BEGIN {RS=""}; 
{print length(RT)}'
diff --git a/test/rtlen01.sh b/test/rtlen01.sh
index 72156d9..e7ee063 100755
--- a/test/rtlen01.sh
+++ b/test/rtlen01.sh
@@ -1,6 +1,10 @@
 #! /bin/sh
 
-AWK=${AWK:-../gawk}
+if [ "$AWK" = "" ]
+then
+       echo $0: You must set AWK >&2
+       exit 1
+fi
 
 $AWK 'BEGIN {printf "0"; exit}' | $AWK 'BEGIN {RS=""}; {print length(RT)}'
 $AWK 'BEGIN {printf "0\n"; exit}' | $AWK 'BEGIN {RS=""}; {print length(RT)}'

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=3a4e6e9c74d0ba859b56ba066850dbba3b15eb22

commit 3a4e6e9c74d0ba859b56ba066850dbba3b15eb22
Author: John Haque <address@hidden>
Date:   Fri Feb 8 18:54:16 2013 -0600

    Added fmodl replacement, updated sinl and cosl to handle huge arguments.

diff --git a/TODO.LDBL b/TODO.LDBL
index f0bf2c9..61f073a 100644
--- a/TODO.LDBL
+++ b/TODO.LDBL
@@ -1,17 +1,27 @@
-* Don't trust compiler with type promotion:
-       **** If an operation involves two operands, and one of them is of type 
long double,
-       **** the other one is converted to long double. 
-The latest version of GCC I have (4.4.3) seems to have different ideas. Start 
using cast
-to long double even when it seems unnecessary address@hidden@#
-
-Also, append suffix L to all long double constants.
-
-* Convert gawk math routines to C for platforms lacking any. Without ceil() 
and floor()
-for long doubles, these can't even get 64 bit integers!
-       -- finish fp_fmod() in misc/fp_math.awk.
-
-* Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM. What 
is the point
-of floor() and ceil() wrappers? Don't have a clue.
-       -- DONE. Not sure if it is necessary for any long double and uintmax_t
-       combination found in the wild. Looks like ceil() and floor() wrappers
-       are for VMS; one probably should update comments in floatcomp.c.
+* Replacement math routines. - DONE.
+   Update awk version fp_math.awk for the changes in C code ?
+   FUTURE: Improvemnet/Optimization.
+     [1] Use truncated Taylor series and/or approximating polynomials.
+         It would require at least two versions (80-bit and 128-bit).
+     [2] Horner's rule to evaluate truncated series.
+     [3] Payne and Hanek Reduction Algorithm to provide more sig digs
+         for sin and cos with large arguments. It most likely involves more
+         than just extending the PI table to few thousand entries.
+         Pay particular attention to the case when x is almost an integer
+         multiple of PI/2. For a clean-room implementation, consider the
+         feasibility of using (64-bit) integer arithmetic.
+         References:
+         * Elementary Functions: Algorithms and Implementation. Jean-Michel 
Muller,
+           Birkhäuser Boston.
+        * Handbook of Floating-Point Arithmetic. Jean-Michel Muller et. el.,
+           Birkhäuser Boston.
+         * Argument Reduction for Huge Arguments: Good to the Last Bit. K. C. 
Ng,
+           SunPro, Sun Microsystems, Inc. Business.
+           Original fdmlib implementation copied by most libm.
+       
+*  Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM.
+   What is the point of floor() and ceil() wrappers? Don't have a clue.
+   - DONE. Not sure if it is necessary for any long double and uintmax_t
+          combination found in the wild. Looks like ceil() and floor()
+           wrappers are for VMS; One probably should update comments
+           in floatcomp.c.
diff --git a/long_double.c b/long_double.c
index 190efba..d604893 100644
--- a/long_double.c
+++ b/long_double.c
@@ -44,22 +44,24 @@
  * XXX: LDBL_MANT_DIG is defined if we are here. Assume FLT_RADIX = 2 or 16.
  */
 #if FLT_RADIX == 2
-#define LDBL_FRAC_BITS LDBL_MANT_DIG
+#define GAWK_LDBL_FRAC_BITS    LDBL_MANT_DIG
 #else
-#define LDBL_FRAC_BITS (4 * LDBL_MANT_DIG)
+#define GAWK_LDBL_FRAC_BITS    (4 * LDBL_MANT_DIG)
 #endif
 
+#define GAWK_LDBL_MAX_EXP      LDBL_MAX_EXP
+
 /*
  * N.B: If printf does not have "%Lf" format and the long double type is 
capable of
  * supporting integers wider than 64 bits, must have 64-bit long type.
  *
- * We actually use a maximum of 113 bits when LDBL_INT_BITS is 128.
+ * We actually use a maximum of 113 bits when GAWK_LDBL_INT_BITS is 128.
  */
 
-#if SIZEOF_GAWK_INT == 8 && LDBL_FRAC_BITS > 64
-#define        LDBL_INT_BITS   128
+#if SIZEOF_GAWK_INT == 8 && GAWK_LDBL_FRAC_BITS > 64
+#define        GAWK_LDBL_INT_BITS      128
 #else
-#define        LDBL_INT_BITS   64
+#define        GAWK_LDBL_INT_BITS      64
 #endif
 
 #define get_long_double(d)     getblock(d, BLOCK_LDBL, AWKLDBL *)
diff --git a/long_double.h b/long_double.h
index 2b8e22d..a509c15 100644
--- a/long_double.h
+++ b/long_double.h
@@ -397,7 +397,7 @@ static void
 awkldbl_init_vars()
 {
        unref(PREC_node->var_value);
-        PREC_node->var_value = make_awknum(LDBL_FRAC_BITS);
+        PREC_node->var_value = make_awknum(GAWK_LDBL_FRAC_BITS);
        PREC_node->var_value->flags |= NUMINT;
         unref(ROUNDMODE_node->var_value);
         ROUNDMODE_node->var_value = make_string("N", 1);
@@ -468,8 +468,8 @@ make_integer(uintmax_t n)
 
        /* XXX: is this really needed in this case ??? */
        
-       if (LDBL_FRAC_BITS < CHAR_BIT * sizeof (n)) {
-               int i = CHAR_BIT * sizeof (n) - LDBL_FRAC_BITS;
+       if (GAWK_LDBL_FRAC_BITS < CHAR_BIT * sizeof (n)) {
+               int i = CHAR_BIT * sizeof (n) - GAWK_LDBL_FRAC_BITS;
 
                /* strip leading `i' bits */
 
@@ -802,7 +802,7 @@ do_rand(int nargs ATTRIBUTE_UNUSED)
         *
         *      0 <= n < 1
         */
-       return make_awkldbl((random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+       return make_awkldbl((AWKLDBL) (random() % GAWK_RANDOM_MAX) / 
GAWK_RANDOM_MAX);
 }
 
 /* do_srand --- seed the random number generator */
@@ -1663,7 +1663,7 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
        int high, low, mid;
        AWKLDBL intval = LDC(0.0);
 
-#if    LDBL_INT_BITS == 128
+#if    GAWK_LDBL_INT_BITS == 128
        if (x >= pow2ld(113))
 #else
        if (x >= pow2ld(64))
@@ -1674,7 +1674,7 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
                memset(chunk, '\0', 4 * sizeof (gawk_uint_t));
 
        /* binary search */
-       high = LDBL_INT_BITS - 1;
+       high = GAWK_LDBL_INT_BITS - 1;
        while (x >= LDC(2.0)) {
                low = 0;
                while (low <= high) {
@@ -1696,7 +1696,7 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
                                 *      |<------- x (64/128 bits) ----->|
                                 */
 
-#if    LDBL_INT_BITS == 128
+#if    GAWK_LDBL_INT_BITS == 128
                                if (low <= 32) chunk[0] += (gawk_uint_t) 
pow2ld(low - 1);
                                else if (low <= 64) chunk[1] += (gawk_uint_t) 
pow2ld(low - 33);
                                else if (low <= 96) chunk[2] += (gawk_uint_t) 
pow2ld(low - 65);
@@ -1741,10 +1741,10 @@ format_uint_finite_p(char *str, size_t size, AWKLDBL x)
         *  URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
         */
 
-#if    LDBL_INT_BITS == 128
+#if    GAWK_LDBL_INT_BITS == 128
        static gawk_uint_t coeff[] = { 
                1, 4967296, 9551616,
-#if defined(TEST_NUMBR) && TEST_NUMBR == 1
+#ifdef GAWK_INT_IS_LONG_LONG
                3585223950336ULL,
 #else
                3585223950336UL,
diff --git a/misc/ChangeLog b/misc/ChangeLog
index d668726..0e38871 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,3 +1,10 @@
+013-02-08         John Haque            <address@hidden>
+
+       * gawk_math.c (gawk_fmodl): Add new routine.
+       (gawk_sinl, gawk_cosl): Update to handle huge arguments.
+       * rem_pio2.c: New file.
+       * ldbl-tests/atan2.awk, ldbl-tests/fmod.awk: New tests for the math 
functions.
+
 2013-02-04         John Haque            <address@hidden>
 
        * gawk_math.c (gawk_sinl, gawk_cosl, gawk_atan2l):
diff --git a/misc/Makefile b/misc/Makefile
index 2a07457..e2a1bb1 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -3,10 +3,13 @@ LIBSTATIC = libmisc.a
 CC = gcc
 LD = gcc
 AR = ar
-AWKPROG = ../gawk
 CMP = cmp
 
-AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG)
+srcdir = .
+top_srcdir = ..
+
+AWKPROG = $(top_srcdir)/gawk
+AWK = LC_ALL=C LANG=C $(AWKPROG)
 
 ALL_CFLAGS = $(CFLAGS) -fPIC -DGAWK -DHAVE_CONFIG_H -c -I.. -I.
 
@@ -18,9 +21,9 @@ $(LIBSTATIC): $(OBJS)
        $(AR) rc $(LIBSTATIC) $(OBJS)
        ranlib $(LIBSTATIC)
 
-float128.o: float128.c ../awk.h ../long_double.h ./gawk_math.h ./gawk_math.c
+float128.o: float128.c $(top_srcdir)/awk.h $(top_srcdir)/long_double.h 
$(srcdir)/gawk_math.h $(srcdir)/gawk_math.c $(srcdir)/rem_pio2.c
 
-float80.o: float80.c ../awk.h ../long_double.h ./gawk_math.h ./gawk_math.c
+float80.o: float80.c $(top_srcdir)/awk.h $(top_srcdir)/long_double.h 
$(srcdir)/gawk_math.h $(srcdir)/gawk_math.c $(srcdir)/rem_pio2.c
 
 .c.o:
        $(CC) $(ALL_CFLAGS) $< -o $@
@@ -46,10 +49,13 @@ LDBL_TESTS = \
        sin64 \
        sin113 \
        cos64 \
-       cos113
+       cos113 \
+       atan64 \
+       atan113 \
+       fmod64 \
+       fmod113
 
 INFILE = ldbl-tests/data.in
-INFILE32 = ldbl-tests/sincos.in
 
 # An attempt to print something that can be grepped for in build logs
 pass-fail:
@@ -66,10 +72,6 @@ ldbl-tests: $(LDBL_TESTS)
 $(INFILE):
        @$(AWK) -M -vPREC=quad -f ldblin.awk > $(INFILE) 2>&1
 
-$(INFILE32): $(INFILE)
-       @$(AWK) -M -vPREC=quad -f ldblin.awk | \
-$(AWK) -M -vPREC=quad '($$1 > -2^32 && $$1 < 2^32){ print $$0 }' > $(INFILE32) 
2>&1
-
 ldblint64:
        @echo $@
        @$(AWK) -B0 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
@@ -128,26 +130,51 @@ pow113: $(INFILE)
        @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/pow.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -vTOL=20 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
 
-sin64:
+sin64: $(INFILE)
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sin.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sin.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+sin113: $(INFILE)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sin.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sin.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+cos64: $(INFILE)
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/cos.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/cos.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+cos113: $(INFILE)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/cos.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/cos.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+atan64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sin.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sin.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/atan2.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/atan2.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
-sin113: $(INFILE32)
+atan113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sin.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sin.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/atan2.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/atan2.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
-cos64:
+fmod64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/cos.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/cos.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/fmod.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/fmod.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
-cos113: $(INFILE32)
+fmod113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/cos.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/cos.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @echo 'This may take a while.'
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/fmod.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/fmod.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
diff --git a/misc/float128.c b/misc/float128.c
index ac66520..d5fefab 100644
--- a/misc/float128.c
+++ b/misc/float128.c
@@ -51,53 +51,55 @@
  *     https://github.com/mirrors/gcc/blob/master/libquadmath/quadmath.h
  */
 
-#define FLT128_MAX 1.18973149535723176508575932662800702e4932Q
-#define FLT128_MIN 3.36210314311209350626267781732175260e-4932Q
-#define FLT128_EPSILON 1.92592994438723585305597794258492732e-34Q
-#define FLT128_DENORM_MIN 6.475175119438025110924438958227646552e-4966Q
-#define FLT128_MANT_DIG 113
-#define FLT128_MIN_EXP (-16381)
-#define FLT128_MAX_EXP 16384
-#define FLT128_DIG 33
-#define FLT128_MIN_10_EXP (-4931)
-#define FLT128_MAX_10_EXP 4932
+#define        FLT128_MAX      1.18973149535723176508575932662800702e4932Q
+#define        FLT128_MIN      3.36210314311209350626267781732175260e-4932Q
+#define        FLT128_EPSILON  1.92592994438723585305597794258492732e-34Q
+#define        FLT128_DENORM_MIN       
6.475175119438025110924438958227646552e-4966Q
+#define        FLT128_MANT_DIG 113
+#define        FLT128_MIN_EXP  (-16381)
+#define        FLT128_MAX_EXP  16384
+#define        FLT128_DIG      33
+#define        FLT128_MIN_10_EXP       (-4931)
+#define        FLT128_MAX_10_EXP       4932
 
 /* #define HUGE_VALQ __builtin_huge_valq() */
 /* The following alternative is valid, but brings the warning:
    (floating constant exceeds range of ‘__float128’)  */
-#define HUGE_VALQ (__extension__ 0x1.0p32767Q)
+#define        HUGE_VALQ (__extension__ 0x1.0p32767Q)
 
-#define IEEE_FLOAT128_BIAS 0x3fff
+#define        IEEE_FLOAT128_BIAS 0x3fff
 
 /* end of Macros from quadmath.h */
 
 
-#define LDBL_FRAC_BITS FLT128_MANT_DIG
-#define        LDBL_INT_BITS   128
+#define        GAWK_LDBL_FRAC_BITS     FLT128_MANT_DIG
+#define        GAWK_LDBL_MAX_EXP       FLT128_MAX_EXP
+#define        GAWK_LDBL_INT_BITS      128
 
 #define AWKLDBL        __float128
-#define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
-#define LDC(x)         x##Q
+#define        LDBL_VAL(n)     (*((AWKLDBL *) (n)->qnumbr))
+#define        LDC(x)          x##Q
 
-#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float128")
-#define free_long_double(d)    efree(d)
+#define        get_long_double(d)      emalloc(d, void *, sizeof(AWKLDBL), 
"float128")
+#define        free_long_double(d)     efree(d)
 
 /* we want to format integers ourself */
-#define GAWK_FMT_INT 1
-
-#define gawk_int_t long long
-#define gawk_uint_t unsigned long long
-#ifdef SIZEOF_GAWK_INT
-#undef SIZEOF_GAWK_INT
-#undef GAWK_INT_MAX
-#undef GAWK_INT_MIN
-#undef GAWK_UINT_MAX
+#define        GAWK_FMT_INT 1
+
+#define        gawk_int_t long long
+#define        gawk_uint_t unsigned long long
+#ifdef SIZEOF_GAWK_INT
+#undef SIZEOF_GAWK_INT
+#undef GAWK_INT_MAX
+#undef GAWK_INT_MIN
+#undef GAWK_UINT_MAX
 #endif
 
 #define SIZEOF_GAWK_INT        8
 #define        GAWK_INT_MAX    LLONG_MAX
 #define        GAWK_INT_MIN    LLONG_MIN
 #define        GAWK_UINT_MAX   ULLONG_MAX
+#define GAWK_INT_IS_LONG_LONG  1
 
 static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
 static AWKLDBL gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk);
@@ -148,8 +150,6 @@ numbr_handler_t float128_hndlr;
 
 #define awkldbl_hndlr float128_hndlr
 
-#define TEST_NUMBR 1
-
 #include "misc/gawk_math.h"
 #include "long_double.h"
 #include "misc/gawk_math.c"
@@ -344,10 +344,8 @@ float128_to_hex(__float128 x)
        return buf;
 }
 
-/*
- * format_float_1 --- format a single AWKLDBL value according to FORMAT.
- *     The value must be finite.
- */
+
+/* format_float_1 --- format a single AWKLDBL value according to FORMAT. */
 
 static int
 format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
diff --git a/misc/float80.c b/misc/float80.c
index 8d2a808..263b6a6 100644
--- a/misc/float80.c
+++ b/misc/float80.c
@@ -40,8 +40,9 @@
 #define FLT_RADIX 2
 #endif
 
-#define LDBL_FRAC_BITS LDBL_MANT_DIG
-#define        LDBL_INT_BITS   64
+#define GAWK_LDBL_FRAC_BITS    LDBL_MANT_DIG
+#define GAWK_LDBL_MAX_EXP      LDBL_MAX_EXP
+#define        GAWK_LDBL_INT_BITS      64
 
 #define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float80")
 #define free_long_double(d)    efree(d)
diff --git a/misc/fp_math.awk b/misc/fp_math.awk
index 60048b1..1c3bfa5 100644
--- a/misc/fp_math.awk
+++ b/misc/fp_math.awk
@@ -1,8 +1,7 @@
 # fp_math.awk --- finite precision math functions
 
 #
-#      TODO:   * finish fmod().
-#              * replace all usages of %, and int() or any other math builtin; 
and() is ok!.
+#      TODO:   * replace all usages of %, and int() or any other math builtin; 
and() is ok!.
 #                implement double_to_int() and remove floor/ceil.
 #
 
@@ -409,7 +408,7 @@ function frexpl(x, e, \
 
        low = 0
        if (x > 2) {
-               high = LDBL_MAX_EXP - 1         # XXX: should be 4 * 
LDBL_MAX_EXP - 1 if FLT_RADIX = 16
+               high = LDBL_MAX_EXP - 1
                while (low <= high) {
                        mid = int ((low + high) / 2)
                        y = x / pow2(mid)
@@ -421,7 +420,7 @@ function frexpl(x, e, \
                x /= pow2(low)
                e[0] = low
        } else if (x < 1) {
-               high = LDBL_MAX_EXP - 1         # could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP
+               high = LDBL_MAX_EXP - 1
                while (low <= high) {
                        mid = int ((low + high) / 2)
                        y =  x * pow2(mid)
@@ -443,18 +442,6 @@ function frexpl(x, e, \
 }
 
 
-#
-# $ ./gawk 'BEGIN { printf("%.18e\n", log(7.12111e900))}'
-# inf
-# $ ./gawk -B 'BEGIN { printf("%.18e\n", log(7.12111e900))}'           # with 
logl(), without it inf
-# 2.074289647306790437e+03
-# $ ./gawk -B -f misc/fp_math.awk -e 'BEGIN { printf("%.18e\n", 
fp_log(7.12111e900))}'
-# 2.074289647306790437e+03
-# $ ./gawk -M -vPREC=quad 'BEGIN { printf("%.18e\n", log(7.12111e900))}'
-# 2.074289647306790438e+03
-#
-
-
 function fp_log(x,     \
                e, exponent, i, ypow2, ypow_odd, sum, err, term, sign)
 {
@@ -713,60 +700,8 @@ function fp_ceil(x,        d)
        return d + 1
 }
 
-#
-#      Calculating fmod with correctly rounded output isn't easy:
-#
-# BEGIN {
-#      POW2[0] = 1
-#      for (i = 1; i <= 64; i++) {
-#              POW2[i] = POW2[i - 1] * 2
-#      }
-#      x = 343.4341
-#      y = 1.324355
-#      printf("builtin: %0.18f\n", x % y)
-#
-#      q = int(x / y)  # floor
-#      printf("simple : %0.18f\n", x - q * y)
-#
-#      r = calc_fmod(x, y)
-#      printf("pow2   : %0.18f\n", r)
-# }
-#
-# function calc_fmod(x, y,     q, j)
-# {
-#      # x > 0, y > 0
-#      q = int(x / y)  # floor, q < 2^64
-#      while (q > 2) {
-#              # XXX: use binary search?
-#              for (j = 1; j <= 64; j++) {
-#                      if (q <= POW2[j]) {
-#                              x -= POW2[j - 1] * y
-#                              q -= POW2[j - 1]
-#                              break
-#                      }
-#              }
-#      }
-#      x -= q * y
-#      return x
-# }
-#
-# We can only get correctly rounded 16 digits (with 80 bit long double),
-# using math library or not:
-#
-# $ ./gawk -B -f fmod.awk 
-# builtin: 0.426155000000000019
-# simple : 0.426155000000000006
-# pow2   : 0.426155000000000019
-#
-# For comparison, MPFR quad precision output:
-#
-# $ ./gawk -M -vPREC=quad 'BEGIN { printf("%0.18f\n",  343.4341 % 1.324355) }'
-# 0.426155000000000000
-#
-
-
 function fp_fmod(x, y, \
-               z, sign)
+               zx, ex, zy, ey, exy, signx, txy, ty)
 {
        x = +x
        y = +y
@@ -778,24 +713,62 @@ function fp_fmod(x, y, \
        if (isinf(y))
                return x
 
-       sign = 1
+       signx = 1
        if (x < 0) {
-               sign = -1
+               signx = -1
                x = -x
        }
+
        if (y < 0)
                y = -y
 
-       if (x < y) # nothing to do
-               return sign * x
+       # x > 0, y > 0
+
+       zy = frexpl(y, e)
+       ey = e[0]
+
+       zx = frexpl(x, e)
+       ex = e[0]
+
+       exy = ex - ey
+       while (exy > 1) {
+               while (zx < z1 && exy > 0) {
+                       zx *= 2;
+                       ex--;
+               }
+               if (exy < 0)
+                       break
+               zx -=  zy
+
+               if (exy >= 1024) {
+                       # avoid overflow in 2^n computation
+                       txy = exy
+                       ty = y  
+                       while (txy >= 1024) {
+                               ty *= pow2ld(1024)
+                               txy -= 1024
+                       }
+                       x -= pow2ld(txy) * ty
+               } else  
+                       x -= pow2ld(exy) * y
+       }
 
-       q = fp_floor(x / y)
+       while (x > y)
+               x -= y
 
-       # FIXME -- see above, and also consider integer overflow (q >= 
2^LDBL_MANT_DIG)
-       return sign * (x - q * y)
+       if (signx > 0) {
+               if (x < 0)
+                       x += y
+       } else {
+               x = -x
+               if (x > 0)
+                       x -= y
+       }
+       return x
 }
 
 
+
 # fixprec -- fixes "0.18e" output
 
 function fixprec(str, numdigs, \
diff --git a/misc/gawk_math.c b/misc/gawk_math.c
index 27ca215..bafe833 100644
--- a/misc/gawk_math.c
+++ b/misc/gawk_math.c
@@ -51,8 +51,10 @@
 static AWKLDBL taylor_exp(AWKLDBL x);
 static AWKLDBL taylor_cos(AWKLDBL x);
 static AWKLDBL taylor_sin(AWKLDBL x);
-static AWKLDBL euler_atan_1(AWKLDBL x);
+static AWKLDBL arctan__p(AWKLDBL y, AWKLDBL x);
 static AWKLDBL gawk_frexpl(AWKLDBL x, int *exponent);
+static int gawk_rem_pio2l(AWKLDBL x, AWKLDBL *y);
+
 
 /* gawk_sinl --- Compute sin(x) */
 
@@ -110,12 +112,35 @@ gawk_sinl(AWKLDBL x)
                        sinval = taylor_sin(-x);
                        break;
                default:
-                       break;
+                       cant_happen();
                }
        } else {
-               /* FIXME -- Payne and Hanek Reduction Algorithm ? */
+               AWKLDBL y[2];
+               int n;
+
+               /* Payne and Hanek Reduction Algorithm */
+
+               n = gawk_rem_pio2l(x, y);
+               assert(n >= 0);
+
+               /* We have no use for the tail part y[1]; Expect about 15-16 
sig digs of precision. */
 
-               sinval = (AWKLDBL) sin( (double) x);
+               switch (n & 3) {
+               case 0:
+                       sinval = taylor_sin(y[0]);
+                       break;
+               case 1:
+                       sinval = taylor_cos(y[0]);
+                       break;
+               case 2:
+                       sinval = -taylor_sin(y[0]);
+                       break;
+               case 3:
+                       sinval = -taylor_cos(y[0]);
+                       break;
+               default:
+                       cant_happen();
+               }
        }
 
        return sign > 0 ? sinval : -sinval;
@@ -174,12 +199,34 @@ gawk_cosl(AWKLDBL x)
                        cosval = -taylor_cos(-x);
                        break;
                default:
-                       break;
+                       cant_happen();
                }
        } else {
-               /* FIXME Payne and Hanek Reduction Algorithm ? */
+               /* Payne and Hanek Reduction Algorithm */
+               AWKLDBL y[2];
+               int n;
+
+               n = gawk_rem_pio2l(x, y);
+               assert(n >= 0);
 
-               cosval = (AWKLDBL) cos( (double) x);
+               /* We have no use for the tail part y[1]; Expect about 15-16 
sig digs of precision. */
+
+               switch (n & 3) {
+               case 0:
+                       cosval = taylor_cos(y[0]);
+                       break;
+               case 1:
+                       cosval = -taylor_sin(y[0]);
+                       break;
+               case 2:
+                       cosval = -taylor_cos(y[0]);
+                       break;
+               case 3:
+                       cosval = taylor_sin(y[0]);
+                       break;
+               default:
+                       cant_happen();
+               }
        }
 
        return sign > 0 ? cosval : -cosval;
@@ -229,8 +276,10 @@ gawk_atan2l(AWKLDBL y, AWKLDBL x)
                        y = -y;
                }
                if (y > x)
-                       return sign * (GAWK_PI_2 - euler_atan_1(y / x));
-               return sign * euler_atan_1(x / y);
+                       return sign * (GAWK_PI_2 - arctan__p(x, y));
+
+               /* for y/x <= 1.0e-20, use atan2(y, x) ~ y/x */
+               return y <= LDC(1.0e-20) * x ? sign * y / x : sign * 
arctan__p(y, x);
        }
 
        if (x < _0L) {
@@ -241,13 +290,19 @@ gawk_atan2l(AWKLDBL y, AWKLDBL x)
                if (y < _0L) {
                        y = -y;
                        if (y > x)
-                               return -GAWK_PI_2 - euler_atan_1(y / x);
-                       return euler_atan_1(x / y) - GAWK_PI;
+                               return -GAWK_PI_2 - arctan__p(x, y);
+                       /*
+                        * XXX: for small y/x, single term approximation ?
+                        *      (y / x - GAWK_PI_LOW) - GAWK_PI_HIGH
+                        */ 
+                       return arctan__p(y, x) - GAWK_PI;
                }
                /* y > 0 */
                if (y > x)
-                       return GAWK_PI_2 + euler_atan_1(y / x);
-               return - euler_atan_1(x / y) + GAWK_PI;
+                       return GAWK_PI_2 + arctan__p(x, y);
+
+               /* XXX: for small y/x, single term approximation ? */ 
+               return -arctan__p(y, x) + GAWK_PI;
        }
 
        /*
@@ -300,7 +355,6 @@ gawk_logl(AWKLDBL x)
        frac = gawk_frexpl(x, & iexp);  /* frac in [1, 2) */
        exponent = (AWKLDBL) iexp;
 
-
        /*
         * arctanh(x) series has faster convergence when x is close to 1.
         * Perform a range reduction so that 1 / sqrt(2) <= x <= sqrt(2).
@@ -357,7 +411,7 @@ gawk_expl(AWKLDBL x)
                return _0L;
        if (x == _0L)
                return _1L;
-       if (x >= (AWKLDBL) LDBL_MAX_EXP * GAWK_LOG2)    /* overflow */
+       if (x >= (AWKLDBL) GAWK_LDBL_MAX_EXP * GAWK_LOG2)       /* overflow */
                return GAWK_INFINITY;
        if (x <= (AWKLDBL) (LDBL_MIN_EXP - LDBL_MANT_DIG - 1) * GAWK_LOG2)      
/* underflow */
                return _0L;
@@ -379,7 +433,7 @@ gawk_expl(AWKLDBL x)
 
                AWKLDBL y;
 
-               /* High precision calculation using limited precision float */
+               /* Extra precision calculation using limited precision float */
                /*
                 * We need to calculate x - k * log2 with extra precision. If k 
is not a power
                 * of 2, it would require more than LDBL_MANT_DIG bits for the 
product
@@ -400,33 +454,27 @@ gawk_expl(AWKLDBL x)
        return sign < 0 ? (_1L / expval) : expval;
 }
 
-static AWKLDBL
-gawk_fmodl(AWKLDBL x, AWKLDBL y)
-{
-       return fmod( (double) x, (double) y);
-}
-
 
-#define        GAWK_LDBL_INTEGER       1
-#define        GAWK_LDBL_EVEN_INTEGER  2
-#define        GAWK_LDBL_ODD_INTEGER   4
+#define        GAWK_LDBL_INTEGER       0x01
+#define        GAWK_LDBL_EVEN_INTEGER  0x02
+#define        GAWK_LDBL_ODD_INTEGER   0x04
 
-/* gawk_is_integer__p --- is x an (even or odd) integer ? */
+/* gawk_integer__p --- is x an (even or odd) integer ? */
 
 static unsigned int
-gawk_is_integer__p(AWKLDBL x)
+gawk_integer__p(AWKLDBL x)
 {
        AWKLDBL ival;
        unsigned ret = 0;
 
        if (isnan(x) || isinf(x))
-               return (unsigned int) false;
+               return 0;
        if (x < _0L)
                x = -x;
        if (x < _1L)
-               return (unsigned int) false;
+               return 0;
        if ((ival = double_to_int(x)) != x)
-               return (unsigned int) false;
+               return 0;
        ret = GAWK_LDBL_INTEGER;
        if (ival >= pow2ld(LDBL_MANT_DIG))
                ret |= GAWK_LDBL_EVEN_INTEGER;
@@ -440,8 +488,8 @@ gawk_is_integer__p(AWKLDBL x)
        return ret;
 }
 
-#define gawk_is_integer(x)     ((gawk_is_integer__p(x) & GAWK_LDBL_INTEGER) != 
0)
-#define gawk_is_odd_integer(x) ((gawk_is_integer__p(x) & 
GAWK_LDBL_ODD_INTEGER) != 0)
+#define gawk_is_integer(x)     ((gawk_integer__p(x) & GAWK_LDBL_INTEGER) != 0)
+#define gawk_is_odd_integer(x) ((gawk_integer__p(x) & GAWK_LDBL_ODD_INTEGER) 
!= 0)
 
 /* gawk_powl --- Compute x^y */
 
@@ -537,11 +585,12 @@ gawk_powl(AWKLDBL x, AWKLDBL y)
                }
                expval *= gawk_expl(frac * gawk_logl(x));
        } else
-               expval = gawk_expl(y * gawk_logl(x));   /* XXX: likely infinity 
or zero */ 
+               expval = gawk_expl(y * gawk_logl(x));   /* XXX: most likely 
infinity ? */ 
 
        return sign > 0 ? expval : (_1L / expval);
 }
 
+
 /* gawk_sqrtl --- Compute sqrt(x) using Newton's method */
 
 static AWKLDBL
@@ -587,10 +636,86 @@ gawk_sqrtl(AWKLDBL x)
        yn = (yn + x / yn) / _2L;
        yn = (yn + x / yn) / _2L;
        yn = (yn + x / yn) / _2L;
-
        return yn;
 }
 
+/*
+ * gawk_fmodl --- Compute the floating-point remainder of dividing x by y
+ *     Method: shift and subtract.
+ */
+
+static AWKLDBL
+gawk_fmodl(AWKLDBL x, AWKLDBL y)
+{
+       AWKLDBL zx, zy, q;
+       int ex, ey, exy;
+       int signx = 1;
+       unsigned low, high, mid;
+
+       if (isnan(x) || isnan(y) 
+               || isinf(x) || y == _0L         /* XXX: set errno = EDOM ? */
+       )
+               return GAWK_NAN;
+
+       if (x == _0L)
+               return x;       /* +0 or -0 */
+       if (isinf(y))
+               return x;
+       
+       if (x < _0L) {
+               signx = -1;
+               x = -x;
+       }
+       if (y < _0L)
+               y = -y;
+
+       /* x > 0, y > 0 */
+       zy = gawk_frexpl(y, & ey);
+       zx = gawk_frexpl(x, & ex);
+       exy = ex - ey;
+       while (exy > 1) {
+               if (zx == _0L)
+                       return signx * _0L;
+
+               while (zx < zy && exy > 0) {
+                       zx *= 2;
+                       exy--;
+               }
+               if (exy < 0)
+                       break;
+
+               zx -= zy;
+
+#define        GAWK_LDBL_MAX_10_EXP    ((GAWK_LDBL_MAX_EXP + 1) / 4)
+               if (exy >= GAWK_LDBL_MAX_10_EXP) {
+                       /* Avoid possible overflow in 2^n computation */
+ 
+                       AWKLDBL tmp_exy, tmp_y;
+                       tmp_exy = exy;
+                       tmp_y = y;
+                       while (tmp_exy >= GAWK_LDBL_MAX_10_EXP) {
+                               tmp_y *= pow2ld(GAWK_LDBL_MAX_10_EXP);
+                               tmp_exy -= GAWK_LDBL_MAX_10_EXP;
+                       }
+                       x -= pow2ld(tmp_exy) * tmp_y;
+               } else
+                       x -= pow2ld(exy) * y;
+       }
+#undef GAWK_LDBL_MAX_10_EXP
+
+       while (x >= y)
+               x -= y;
+       if (signx > 0) {
+               if (x < _0L)
+                       x += y;
+       } else {
+               x = -x;
+               if (x > _0L)
+                       x -= y;
+       }
+       return x;
+}
+
 
 /*
  * gawk_frexpl --- split the number x into a normalized fraction and an 
exponent.
@@ -610,7 +735,7 @@ gawk_frexpl(AWKLDBL x, int *exponent)
 
        low = 0;
        if (x > _2L) {
-               high = LDBL_MAX_EXP - 1;        /* XXX: should be 4 * 
LDBL_MAX_EXP - 1 if FLT_RADIX = 16 ? */
+               high = GAWK_LDBL_MAX_EXP - 1;
                while (low <= high) {
                        mid = (low + high) / 2;
                        y = x / pow2ld(mid);
@@ -622,7 +747,7 @@ gawk_frexpl(AWKLDBL x, int *exponent)
                x /= pow2ld(low);
                *exponent = low;
        } else if (x < _1L) {
-               high = LDBL_MAX_EXP - 1;        /* could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP */
+               high = GAWK_LDBL_MAX_EXP - 1;   /* could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP */
                while (low <= high) {
                        mid = (low + high) / 2;
                        y =  x * pow2ld(mid);
@@ -670,8 +795,7 @@ taylor_exp(AWKLDBL x)
 
        k = 1;
        while (x > LDC(0.001)) {
-               /* XXX: For x <= 0.001, max(k) = 10, and max # of terms 6 
(80-bit) / 10 (128-bit) */
-               
+               /* XXX: For x <= 0.001, max(k) = 10, and max # of terms 6 
(80-bit) / 10 (128-bit) */    
                x /= _2L; 
                k++;
        }
@@ -693,7 +817,10 @@ taylor_exp(AWKLDBL x)
        return y + _1L;
 }
 
-/* taylor_sin --- Compute sin(x) using Taylor series */
+/*
+ * taylor_sin --- Compute sin(x) using Taylor series
+ *     sin(x) = (x - x^3/3!) + (x^5/5! - x^7/7!) + ...
+ */
 
 static AWKLDBL
 taylor_sin(AWKLDBL x)
@@ -701,12 +828,15 @@ taylor_sin(AWKLDBL x)
        AWKLDBL xpow, xpow_odd, sinval;
        AWKLDBL err, term, fact;
        unsigned int i;
-
-       assert(x >= _0L);
+       int sign = 1;
 
        if (x == _0L)
                return x;
-
+       if (x < _0L) {
+               sign = -1;
+               x = -x;
+       }
+       
        i = 3;
        fact = LDC(6.0);        /* 3! */
        xpow = x * x;
@@ -727,10 +857,13 @@ taylor_sin(AWKLDBL x)
                sinval += term;
                err = term / sinval;
        } while (err > REL_ERROR);
-       return sinval;
+       return sign > 0 ? sinval : -sinval;
 }
 
-/* taylor_cos --- Compute cos(x) using Taylor series */
+/*
+ * taylor_cos --- Compute cos(x) using Taylor series
+ *     cos(x) = (1 - x^2/2!) + (x^4/4! - x^6/6!)...
+ */
 
 static AWKLDBL
 taylor_cos(AWKLDBL x)
@@ -741,6 +874,8 @@ taylor_cos(AWKLDBL x)
 
        if (x == _0L)
                return _1L;
+       if (x < _0L)
+               x = -x;
 
        i = 2;
        fact = _2L;     /* 2! */
@@ -765,12 +900,69 @@ taylor_cos(AWKLDBL x)
        return cosval;
 }
 
-/* euler_atan_1 --- Compute Euler arctan(1/x) approximation */ 
+
+/*
+ * taylor_atan --- Compute arctan(x) using Taylor series
+ *     arctan(x) = (x - x^3/3) + (x^5/5 - x^7/7) + ...
+ */
 
 static AWKLDBL
-euler_atan_1(AWKLDBL x)
+taylor_atan(AWKLDBL x)
 {
-       AWKLDBL xpow2_plus_one, term, sum, err;
+       AWKLDBL xpow, xpow_odd, atanval;
+       AWKLDBL err, term;
+       unsigned int i;
+       int inverse = 0, mult = 1;
+       
+       /* x >= 0.1 */
+
+       assert(x > _0L);
+       if (x > _1L) {
+               /* arctan(x) = pi / 2 - aractan(1 / x), x > 0 */
+               inverse = 1;
+               x = _1L / x;
+       }
+
+       /* x <= 1.0 */
+
+       /* range reduction --- arctan(x) = 2 arctan(x / (1 + sqrt(1 + x^2))) */
+       while (x > LDC(0.05)) {
+               mult *= 2;
+               x = x / (_1L + gawk_sqrtl(_1L + x * x));
+       } 
+
+       /* maximum ~14 terms for 128-bit and ~8 for 80-bit */
+       
+       i = 3;
+       xpow = x * x;
+       xpow_odd = xpow * x;
+       atanval = x - xpow_odd / ((AWKLDBL) i);
+
+       do {
+               i += 2;
+               xpow_odd *= xpow;
+               term = xpow_odd / ((AWKLDBL) i);
+
+               i += 2;
+               xpow_odd *= xpow;
+               term -= xpow_odd / ((AWKLDBL) i);
+
+               atanval += term;
+               err = term / atanval;
+       } while (err > REL_ERROR);
+
+       if (inverse)
+               return GAWK_PI_2 - atanval * ((AWKLDBL) mult);
+       return atanval * ((AWKLDBL) mult);
+}
+
+
+/* arctan__p --- Compute arctan(y / x) */ 
+
+static AWKLDBL
+arctan__p(AWKLDBL y, AWKLDBL x)
+{
+       AWKLDBL z, xpow2_plus_one, term, atanval, err;
        int sign = 1;
        unsigned int i;
 
@@ -781,28 +973,106 @@ euler_atan_1(AWKLDBL x)
         *      y = (x^2) / (1 + x^2) and -1 <= x <= 1
         *
         * Substituting x = 1/x, for x >= 1
-        *      atan(1/x) = (x / (1 + x^2))    + (2/3) * (x / (1 + x^2)^2)
-        *                                     + (2*4/(3*5)) * (x / (1 + x^2)^3)
-        *                                     + (2*4*6/(3*5*7)) * (x / (1 + 
x^2)^4) + ...
+        *      atan(1/x) = (x / (1 + x^2))  + (2/3) * (x / (1 + x^2)^2)
+        *                               + (2*4/(3*5)) * (x / (1 + x^2)^3)
+        *                               + (2*4*6/(3*5*7)) * (x / (1 + x^2)^4) 
+ ...
         */
 
-       if (x < _0L) {
+       z = x / y;
+       if (z < _0L) {
                sign = -1;
-               x = -x;
+               z = -z;
        }
+       assert(z > _1L);
 
-       xpow2_plus_one = x * x + _1L;
-       term = x / xpow2_plus_one;
-       sum = term;
+       if (z <= LDC(20.0)) {
+               /* For y / x  >= 0.05, Euler atan is slow! */
+               atanval = taylor_atan(_1L / z);
+               return sign > 0 ? atanval : -atanval;
+       }
+
+       /* maximum ~14 terms for 128-bit and ~8 for 80-bit */
+
+       xpow2_plus_one = z * z + _1L;
+       term = z / xpow2_plus_one;
+       atanval = term;
        i = 0;
 
        do {
                term *= (AWKLDBL) (i + 2);
                term /= ((AWKLDBL) (i + 3)) * xpow2_plus_one;
                i += 2;
-               sum += term;
-               err = term / sum;
+               atanval += term;
+               err = term / atanval;
        } while (err > REL_ERROR);
 
-       return sign > 0 ? sum : -sum;
+       return sign > 0 ? atanval : -atanval;
+}
+
+
+/* gawk_scalbn --- return X * 2^E */
+
+static inline double
+gawk_scalbn(double x, int e)
+{
+       if (e >= 0)
+               return x * ((double) pow2ld(e));
+       return x / ((double) pow2ld(-e));
+}
+
+#define scalbn gawk_scalbn
+#include "rem_pio2.c"
+
+
+/* gawk_rem_pio2l --- return the x remainder pi/2 in y[0], y[1] */
+
+static int
+gawk_rem_pio2l(AWKLDBL x, AWKLDBL *y)
+{
+       AWKLDBL t, w;
+       int e0;
+       int n, i;
+#if    (GAWK_LDBL_FRAC_BITS == 113 && GAWK_LDBL_MAX_EXP == 16384) 
+       double tx[5];
+       double ty[3];
+       int nx = 5;
+       int prec = 3;
+#else
+       double tx[3];
+       double ty[2];
+       int nx = 3;
+       int prec = 2;
+#endif
+
+       (void) gawk_frexpl(x, & e0);
+       e0 -=  23;
+       if (e0 > 0)
+               x /= pow2ld(e0);
+       else
+               x *= pow2ld(-e0);
+
+       for (i = 0; i < nx - 1; i++) {
+               tx[i] = floor(x);
+               x -= (AWKLDBL) tx[i];
+               x *= pow2ld(24);
+       }
+       tx[nx - 1] = x;
+
+       while (nx > 0 && tx[nx - 1] == _0L)     /* skip zero terms */
+                nx--;
+
+       n = __kernel_rem_pio2(tx, ty, e0, nx, prec);
+
+       /* The result is in 3 or 2 C-doubles, convert into AWKLDBLs. */
+
+#if    (GAWK_LDBL_FRAC_BITS == 113 && GAWK_LDBL_MAX_EXP == 16384)
+       t = (AWKLDBL) ty[2] + (AWKLDBL) ty[1];
+#else
+       t = (AWKLDBL) ty[1];
+#endif
+       w = (AWKLDBL) ty[0];
+
+       y[0] = w + t;
+       y[1] = t - (y[0] - w);
+       return n;
 }
diff --git a/misc/ldbl-tests/atan2.awk b/misc/ldbl-tests/atan2.awk
new file mode 100644
index 0000000..e4ebb05
--- /dev/null
+++ b/misc/ldbl-tests/atan2.awk
@@ -0,0 +1,45 @@
+BEGIN {
+       x1 = 0.1
+       x2 = 131.4321211
+       x3 = 1.1234567e100
+}
+{
+       r1 = atan2(x1, $1)
+       rm1 = atan2(-x1, $1)
+       t1 = atan2($1, x1)
+       tm1 = atan2($1, -x1)
+       r2 = atan2(x2, $1)
+       rm2 = atan2(-x2, $1)
+       t2 = atan2($1, x2)
+       tm2 = atan2($1, -x2)
+       r3 = atan2(x3, $1)
+       rm3 = atan2(-x3, $1)
+       t3 = atan2($1, x3)
+       tm3 = atan2($1, -x3)
+
+       # don't have -M IEEE emulation for 64-bit binary
+       # need to replace huge values with infinities.
+       # "quad" and 64-bit long double has same exponent range.
+       # This does not effect the binary formats B0, B1
+
+       save_PREC = PREC
+       PREC = "quad"
+       r1 += 0; r2 += 0; r3 += 0
+       t1 += 0; t2 += 0; t3 += 0
+       rm1 += 0; rm2 += 0; rm3 += 0
+       tm1 += 0; tm2 += 0; tm3 += 0
+
+       printf("%*.*e\n", 0, DIG, r1)
+       printf("%*.*e\n", 0, DIG, rm1)
+       printf("%*.*e\n", 0, DIG, t1)
+       printf("%*.*e\n", 0, DIG, tm1)
+       printf("%*.*e\n", 0, DIG, r2)
+       printf("%*.*e\n", 0, DIG, rm2)
+       printf("%*.*e\n", 0, DIG, t2)
+       printf("%*.*e\n", 0, DIG, tm2)
+       printf("%*.*e\n", 0, DIG, r3)
+       printf("%*.*e\n", 0, DIG, rm3)
+       printf("%*.*e\n", 0, DIG, t3)
+       printf("%*.*e\n", 0, DIG, tm3)
+       PREC = save_PREC
+}
diff --git a/misc/ldbl-tests/cos.awk b/misc/ldbl-tests/cos.awk
new file mode 100644
index 0000000..048ef91
--- /dev/null
+++ b/misc/ldbl-tests/cos.awk
@@ -0,0 +1,11 @@
+$1 >= 0x100000000 {
+       #
+       # The code in rem_pio2.c (Payne and Hanek Reduction Algorithm)
+       # provides only C-double precision.
+       #
+       printf("%0.15e\n", cos($1))
+       next
+}
+{
+       printf("%*.*e\n", 0, DIG, cos($1))
+}
diff --git a/misc/ldbl-tests/fmod.awk b/misc/ldbl-tests/fmod.awk
new file mode 100644
index 0000000..eb742a3
--- /dev/null
+++ b/misc/ldbl-tests/fmod.awk
@@ -0,0 +1,52 @@
+BEGIN {
+       x1 = 0.1
+       x2 = 131.4321211
+       x3 = 1.1234567e100
+}
+{
+       r1 = x1 % $1
+       rm1 = -x1 % $1
+       t1 = $1 % x1
+       tm1 = $1 % -x1
+       r2 = x2 % $1
+       rm2 = -x2 % $1
+       t2 = $1 % x2
+       tm2 = $1 % -x2
+       r3 = x3 % $1
+       rm3 = -x3 % $1
+       t3 = $1 % x3
+       tm3 = $1 % -x3
+
+       # don't have -M IEEE emulation for 64-bit binary
+       # need to replace huge values with infinities.
+       # "quad" and 64-bit long double has same exponent range.
+       # This does not effect the binary formats B0, B1
+
+#      save_PREC = PREC
+#      PREC = "quad"
+#      r1 += 0; r2 += 0; r3 += 0
+#      t1 += 0; t2 += 0; t3 += 0
+#      rm1 += 0; rm2 += 0; rm3 += 0
+#      tm1 += 0; tm2 += 0; tm3 += 0
+
+       printf("%*.*e\n", 0, DIG, r1)
+       printf("%*.*e\n", 0, DIG, rm1)
+       printf("%*.*e\n", 0, DIG, t1)
+       printf("%*.*e\n", 0, DIG, tm1)
+       printf("%*.*e\n", 0, DIG, r2)
+       printf("%*.*e\n", 0, DIG, rm2)
+       printf("%*.*e\n", 0, DIG, t2)
+       printf("%*.*e\n", 0, DIG, tm2)
+       printf("%*.*e\n", 0, DIG, r3)
+       printf("%*.*e\n", 0, DIG, rm3)
+       printf("%*.*e\n", 0, DIG, t3)
+       printf("%*.*e\n", 0, DIG, tm3)
+#      PREC = save_PREC
+}
+
+END {
+       printf("%*.*e\n", 0, DIG, 8 % 4)
+       printf("%*.*e\n", 0, DIG, -8 % 4)
+       printf("%*.*e\n", 0, DIG, 8 % -4)
+       printf("%*.*e\n", 0, DIG, -8 % -4)
+}
diff --git a/misc/ldbl-tests/sin.awk b/misc/ldbl-tests/sin.awk
new file mode 100644
index 0000000..f79dc72
--- /dev/null
+++ b/misc/ldbl-tests/sin.awk
@@ -0,0 +1,11 @@
+$1 >= 0x100000000 {
+       #
+       # The code in rem_pio2.c (Payne and Hanek Reduction Algorithm)       
+       # provides only C-double precision.        
+       #
+       printf("%0.15e\n", sin($1))
+       next
+}
+{
+       printf("%*.*e\n", 0, DIG, sin($1))
+}
diff --git a/misc/rem_pio2.c b/misc/rem_pio2.c
new file mode 100644
index 0000000..8d8621f
--- /dev/null
+++ b/misc/rem_pio2.c
@@ -0,0 +1,467 @@
+/* Source: freebsd/master/lib/msun/src/k_rem_pio2.c */
+
+/* @(#)k_rem_pio2.c 1.3 95/01/18 */
+/*
+ * ====================================================
+ * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+ *
+ * Developed at SunSoft, a Sun Microsystems, Inc. business.
+ * Permission to use, copy, modify, and distribute this
+ * software is freely granted, provided that this notice 
+ * is preserved.
+ * ====================================================
+ */
+#if 0
+#ifdef FLT_EVAL_METHOD
+/*
+* Attempt to get strict C99 semantics for assignment with non-C99 compilers.
+*/
+#if FLT_EVAL_METHOD == 0 || __GNUC__ == 0
+#define STRICT_ASSIGN(type, lval, rval) ((lval) = (rval))
+#else
+#define STRICT_ASSIGN(type, lval, rval) do { \
+volatile type __lval; \
+\
+if (sizeof(type) >= sizeof(long double)) \
+(lval) = (rval); \
+else { \
+__lval = (rval); \
+(lval) = __lval; \
+} \
+} while (0)
+#endif
+#endif /* FLT_EVAL_METHOD */
+#endif
+
+
+/* loose extra precision */
+#define STRICT_ASSIGN(type, lval, rval) do { \
+volatile type __lval; \
+__lval = (rval); \
+(lval) = __lval; \
+} while (0)
+
+
+/*
+ * __kernel_rem_pio2(x,y,e0,nx,prec)
+ * double x[],y[]; int e0,nx,prec;
+ * 
+ * __kernel_rem_pio2 return the last three digits of N with 
+ *             y = x - N*pi/2
+ * so that |y| < pi/2.
+ *
+ * The method is to compute the integer (mod 8) and fraction parts of 
+ * (2/pi)*x without doing the full multiplication. In general we
+ * skip the part of the product that are known to be a huge integer (
+ * more accurately, = 0 mod 8 ). Thus the number of operations are
+ * independent of the exponent of the input.
+ *
+ * (2/pi) is represented by an array of 24-bit integers in ipio2[].
+ *
+ * Input parameters:
+ *     x[]     The input value (must be positive) is broken into nx 
+ *             pieces of 24-bit integers in double precision format.
+ *             x[i] will be the i-th 24 bit of x. The scaled exponent 
+ *             of x[0] is given in input parameter e0 (i.e., x[0]*2^e0 
+ *             match x's up to 24 bits.
+ *
+ *             Example of breaking a double positive z into x[0]+x[1]+x[2]:
+ *                     e0 = ilogb(z)-23
+ *                     z  = scalbn(z,-e0)
+ *             for i = 0,1,2
+ *                     x[i] = floor(z)
+ *                     z    = (z-x[i])*2**24
+ *
+ *
+ *     y[]     output result in an array of double precision numbers.
+ *             The dimension of y[] is:
+ *                     24-bit  precision       1
+ *                     53-bit  precision       2
+ *                     64-bit  precision       2
+ *                     113-bit precision       3
+ *             The actual value is the sum of them. Thus for 113-bit
+ *             precison, one may have to do something like:
+ *
+ *             long double t,w,r_head, r_tail;
+ *             t = (long double)y[2] + (long double)y[1];
+ *             w = (long double)y[0];
+ *             r_head = t + w;
+ *             r_tail = w - (r_head - t);
+ *
+ *     e0      The exponent of x[0]. Must be <= 16360 or you need to
+ *              expand the ipio2 table.
+ *
+ *     nx      dimension of x[]
+ *
+ *     prec    an integer indicating the precision:
+ *                     0       24  bits (single)
+ *                     1       53  bits (double)
+ *                     2       64  bits (extended)
+ *                     3       113 bits (quad)
+ *
+ * External function:
+ *     double scalbn(), floor();
+ *
+ *
+ * Here is the description of some local variables:
+ *
+ *     jk      jk+1 is the initial number of terms of ipio2[] needed
+ *             in the computation. The minimum and recommended value
+ *             for jk is 3,4,4,6 for single, double, extended, and quad.
+ *             jk+1 must be 2 larger than you might expect so that our
+ *             recomputation test works. (Up to 24 bits in the integer
+ *             part (the 24 bits of it that we compute) and 23 bits in
+ *             the fraction part may be lost to cancelation before we
+ *             recompute.)
+ *
+ *     jz      local integer variable indicating the number of 
+ *             terms of ipio2[] used. 
+ *
+ *     jx      nx - 1
+ *
+ *     jv      index for pointing to the suitable ipio2[] for the
+ *             computation. In general, we want
+ *                     ( 2^e0*x[0] * ipio2[jv-1]*2^(-24jv) )/8
+ *             is an integer. Thus
+ *                     e0-3-24*jv >= 0 or (e0-3)/24 >= jv
+ *             Hence jv = max(0,(e0-3)/24).
+ *
+ *     jp      jp+1 is the number of terms in PIo2[] needed, jp = jk.
+ *
+ *     q[]     double array with integral value, representing the
+ *             24-bits chunk of the product of x and 2/pi.
+ *
+ *     q0      the corresponding exponent of q[0]. Note that the
+ *             exponent for q[i] would be q0-24*i.
+ *
+ *     PIo2[]  double precision array, obtained by cutting pi/2
+ *             into 24 bits chunks. 
+ *
+ *     f[]     ipio2[] in floating point 
+ *
+ *     iq[]    integer array by breaking up q[] in 24-bits chunk.
+ *
+ *     fq[]    final product of x*(2/pi) in fq[0],..,fq[jk]
+ *
+ *     ih      integer. If >0 it indicates q[] is >= 0.5, hence
+ *             it also indicates the *sign* of the result.
+ *
+ */
+
+
+/*
+ * Constants:
+ * The hexadecimal values are the intended ones for the following 
+ * constants. The decimal values may be used, provided that the 
+ * compiler will convert from decimal to binary accurately enough 
+ * to produce the hexadecimal values shown.
+ */
+
+static const int init_jk[] = {3,4,4,6}; /* initial value for jk */
+
+/*
+ * Table of constants for 2/pi, 396 Hex digits (476 decimal) of 2/pi
+ *
+ *             integer array, contains the (24*i)-th to (24*i+23)-th 
+ *             bit of 2/pi after binary point. The corresponding 
+ *             floating value is
+ *
+ *                     ipio2[i] * 2^(-24(i+1)).
+ *
+ * NB: This table must have at least (e0-3)/24 + jk terms.
+ *     For quad precision (e0 <= 16360, jk = 6), this is 686.
+ */
+static const int32_t ipio2[] = {
+0xA2F983, 0x6E4E44, 0x1529FC, 0x2757D1, 0xF534DD, 0xC0DB62, 
+0x95993C, 0x439041, 0xFE5163, 0xABDEBB, 0xC561B7, 0x246E3A, 
+0x424DD2, 0xE00649, 0x2EEA09, 0xD1921C, 0xFE1DEB, 0x1CB129, 
+0xA73EE8, 0x8235F5, 0x2EBB44, 0x84E99C, 0x7026B4, 0x5F7E41, 
+0x3991D6, 0x398353, 0x39F49C, 0x845F8B, 0xBDF928, 0x3B1FF8, 
+0x97FFDE, 0x05980F, 0xEF2F11, 0x8B5A0A, 0x6D1F6D, 0x367ECF, 
+0x27CB09, 0xB74F46, 0x3F669E, 0x5FEA2D, 0x7527BA, 0xC7EBE5, 
+0xF17B3D, 0x0739F7, 0x8A5292, 0xEA6BFB, 0x5FB11F, 0x8D5D08, 
+0x560330, 0x46FC7B, 0x6BABF0, 0xCFBC20, 0x9AF436, 0x1DA9E3, 
+0x91615E, 0xE61B08, 0x659985, 0x5F14A0, 0x68408D, 0xFFD880, 
+0x4D7327, 0x310606, 0x1556CA, 0x73A8C9, 0x60E27B, 0xC08C6B, 
+
+#if LDBL_MAX_EXP > 1024
+#if LDBL_MAX_EXP > 16384
+#error "ipio2 table needs to be expanded"
+#endif
+0x47C419, 0xC367CD, 0xDCE809, 0x2A8359, 0xC4768B, 0x961CA6,
+0xDDAF44, 0xD15719, 0x053EA5, 0xFF0705, 0x3F7E33, 0xE832C2,
+0xDE4F98, 0x327DBB, 0xC33D26, 0xEF6B1E, 0x5EF89F, 0x3A1F35,
+0xCAF27F, 0x1D87F1, 0x21907C, 0x7C246A, 0xFA6ED5, 0x772D30,
+0x433B15, 0xC614B5, 0x9D19C3, 0xC2C4AD, 0x414D2C, 0x5D000C,
+0x467D86, 0x2D71E3, 0x9AC69B, 0x006233, 0x7CD2B4, 0x97A7B4,
+0xD55537, 0xF63ED7, 0x1810A3, 0xFC764D, 0x2A9D64, 0xABD770,
+0xF87C63, 0x57B07A, 0xE71517, 0x5649C0, 0xD9D63B, 0x3884A7,
+0xCB2324, 0x778AD6, 0x23545A, 0xB91F00, 0x1B0AF1, 0xDFCE19,
+0xFF319F, 0x6A1E66, 0x615799, 0x47FBAC, 0xD87F7E, 0xB76522,
+0x89E832, 0x60BFE6, 0xCDC4EF, 0x09366C, 0xD43F5D, 0xD7DE16,
+0xDE3B58, 0x929BDE, 0x2822D2, 0xE88628, 0x4D58E2, 0x32CAC6,
+0x16E308, 0xCB7DE0, 0x50C017, 0xA71DF3, 0x5BE018, 0x34132E,
+0x621283, 0x014883, 0x5B8EF5, 0x7FB0AD, 0xF2E91E, 0x434A48,
+0xD36710, 0xD8DDAA, 0x425FAE, 0xCE616A, 0xA4280A, 0xB499D3,
+0xF2A606, 0x7F775C, 0x83C2A3, 0x883C61, 0x78738A, 0x5A8CAF,
+0xBDD76F, 0x63A62D, 0xCBBFF4, 0xEF818D, 0x67C126, 0x45CA55,
+0x36D9CA, 0xD2A828, 0x8D61C2, 0x77C912, 0x142604, 0x9B4612,
+0xC459C4, 0x44C5C8, 0x91B24D, 0xF31700, 0xAD43D4, 0xE54929,
+0x10D5FD, 0xFCBE00, 0xCC941E, 0xEECE70, 0xF53E13, 0x80F1EC,
+0xC3E7B3, 0x28F8C7, 0x940593, 0x3E71C1, 0xB3092E, 0xF3450B,
+0x9C1288, 0x7B20AB, 0x9FB52E, 0xC29247, 0x2F327B, 0x6D550C,
+0x90A772, 0x1FE76B, 0x96CB31, 0x4A1679, 0xE27941, 0x89DFF4,
+0x9794E8, 0x84E6E2, 0x973199, 0x6BED88, 0x365F5F, 0x0EFDBB,
+0xB49A48, 0x6CA467, 0x427271, 0x325D8D, 0xB8159F, 0x09E5BC,
+0x25318D, 0x3974F7, 0x1C0530, 0x010C0D, 0x68084B, 0x58EE2C,
+0x90AA47, 0x02E774, 0x24D6BD, 0xA67DF7, 0x72486E, 0xEF169F,
+0xA6948E, 0xF691B4, 0x5153D1, 0xF20ACF, 0x339820, 0x7E4BF5,
+0x6863B2, 0x5F3EDD, 0x035D40, 0x7F8985, 0x295255, 0xC06437,
+0x10D86D, 0x324832, 0x754C5B, 0xD4714E, 0x6E5445, 0xC1090B,
+0x69F52A, 0xD56614, 0x9D0727, 0x50045D, 0xDB3BB4, 0xC576EA,
+0x17F987, 0x7D6B49, 0xBA271D, 0x296996, 0xACCCC6, 0x5414AD,
+0x6AE290, 0x89D988, 0x50722C, 0xBEA404, 0x940777, 0x7030F3,
+0x27FC00, 0xA871EA, 0x49C266, 0x3DE064, 0x83DD97, 0x973FA3,
+0xFD9443, 0x8C860D, 0xDE4131, 0x9D3992, 0x8C70DD, 0xE7B717,
+0x3BDF08, 0x2B3715, 0xA0805C, 0x93805A, 0x921110, 0xD8E80F,
+0xAF806C, 0x4BFFDB, 0x0F9038, 0x761859, 0x15A562, 0xBBCB61,
+0xB989C7, 0xBD4010, 0x04F2D2, 0x277549, 0xF6B6EB, 0xBB22DB,
+0xAA140A, 0x2F2689, 0x768364, 0x333B09, 0x1A940E, 0xAA3A51,
+0xC2A31D, 0xAEEDAF, 0x12265C, 0x4DC26D, 0x9C7A2D, 0x9756C0,
+0x833F03, 0xF6F009, 0x8C402B, 0x99316D, 0x07B439, 0x15200C,
+0x5BC3D8, 0xC492F5, 0x4BADC6, 0xA5CA4E, 0xCD37A7, 0x36A9E6,
+0x9492AB, 0x6842DD, 0xDE6319, 0xEF8C76, 0x528B68, 0x37DBFC,
+0xABA1AE, 0x3115DF, 0xA1AE00, 0xDAFB0C, 0x664D64, 0xB705ED,
+0x306529, 0xBF5657, 0x3AFF47, 0xB9F96A, 0xF3BE75, 0xDF9328,
+0x3080AB, 0xF68C66, 0x15CB04, 0x0622FA, 0x1DE4D9, 0xA4B33D,
+0x8F1B57, 0x09CD36, 0xE9424E, 0xA4BE13, 0xB52333, 0x1AAAF0,
+0xA8654F, 0xA5C1D2, 0x0F3F0B, 0xCD785B, 0x76F923, 0x048B7B,
+0x721789, 0x53A6C6, 0xE26E6F, 0x00EBEF, 0x584A9B, 0xB7DAC4,
+0xBA66AA, 0xCFCF76, 0x1D02D1, 0x2DF1B1, 0xC1998C, 0x77ADC3,
+0xDA4886, 0xA05DF7, 0xF480C6, 0x2FF0AC, 0x9AECDD, 0xBC5C3F,
+0x6DDED0, 0x1FC790, 0xB6DB2A, 0x3A25A3, 0x9AAF00, 0x9353AD,
+0x0457B6, 0xB42D29, 0x7E804B, 0xA707DA, 0x0EAA76, 0xA1597B,
+0x2A1216, 0x2DB7DC, 0xFDE5FA, 0xFEDB89, 0xFDBE89, 0x6C76E4,
+0xFCA906, 0x70803E, 0x156E85, 0xFF87FD, 0x073E28, 0x336761,
+0x86182A, 0xEABD4D, 0xAFE7B3, 0x6E6D8F, 0x396795, 0x5BBF31,
+0x48D784, 0x16DF30, 0x432DC7, 0x356125, 0xCE70C9, 0xB8CB30,
+0xFD6CBF, 0xA200A4, 0xE46C05, 0xA0DD5A, 0x476F21, 0xD21262,
+0x845CB9, 0x496170, 0xE0566B, 0x015299, 0x375550, 0xB7D51E,
+0xC4F133, 0x5F6E13, 0xE4305D, 0xA92E85, 0xC3B21D, 0x3632A1,
+0xA4B708, 0xD4B1EA, 0x21F716, 0xE4698F, 0x77FF27, 0x80030C,
+0x2D408D, 0xA0CD4F, 0x99A520, 0xD3A2B3, 0x0A5D2F, 0x42F9B4,
+0xCBDA11, 0xD0BE7D, 0xC1DB9B, 0xBD17AB, 0x81A2CA, 0x5C6A08,
+0x17552E, 0x550027, 0xF0147F, 0x8607E1, 0x640B14, 0x8D4196,
+0xDEBE87, 0x2AFDDA, 0xB6256B, 0x34897B, 0xFEF305, 0x9EBFB9,
+0x4F6A68, 0xA82A4A, 0x5AC44F, 0xBCF82D, 0x985AD7, 0x95C7F4,
+0x8D4D0D, 0xA63A20, 0x5F57A4, 0xB13F14, 0x953880, 0x0120CC,
+0x86DD71, 0xB6DEC9, 0xF560BF, 0x11654D, 0x6B0701, 0xACB08C,
+0xD0C0B2, 0x485551, 0x0EFB1E, 0xC37295, 0x3B06A3, 0x3540C0,
+0x7BDC06, 0xCC45E0, 0xFA294E, 0xC8CAD6, 0x41F3E8, 0xDE647C,
+0xD8649B, 0x31BED9, 0xC397A4, 0xD45877, 0xC5E369, 0x13DAF0,
+0x3C3ABA, 0x461846, 0x5F7555, 0xF5BDD2, 0xC6926E, 0x5D2EAC,
+0xED440E, 0x423E1C, 0x87C461, 0xE9FD29, 0xF3D6E7, 0xCA7C22,
+0x35916F, 0xC5E008, 0x8DD7FF, 0xE26A6E, 0xC6FDB0, 0xC10893,
+0x745D7C, 0xB2AD6B, 0x9D6ECD, 0x7B723E, 0x6A11C6, 0xA9CFF7,
+0xDF7329, 0xBAC9B5, 0x5100B7, 0x0DB2E2, 0x24BA74, 0x607DE5,
+0x8AD874, 0x2C150D, 0x0C1881, 0x94667E, 0x162901, 0x767A9F,
+0xBEFDFD, 0xEF4556, 0x367ED9, 0x13D9EC, 0xB9BA8B, 0xFC97C4,
+0x27A831, 0xC36EF1, 0x36C594, 0x56A8D8, 0xB5A8B4, 0x0ECCCF,
+0x2D8912, 0x34576F, 0x89562C, 0xE3CE99, 0xB920D6, 0xAA5E6B,
+0x9C2A3E, 0xCC5F11, 0x4A0BFD, 0xFBF4E1, 0x6D3B8E, 0x2C86E2,
+0x84D4E9, 0xA9B4FC, 0xD1EEEF, 0xC9352E, 0x61392F, 0x442138,
+0xC8D91B, 0x0AFC81, 0x6A4AFB, 0xD81C2F, 0x84B453, 0x8C994E,
+0xCC2254, 0xDC552A, 0xD6C6C0, 0x96190B, 0xB8701A, 0x649569,
+0x605A26, 0xEE523F, 0x0F117F, 0x11B5F4, 0xF5CBFC, 0x2DBC34,
+0xEEBC34, 0xCC5DE8, 0x605EDD, 0x9B8E67, 0xEF3392, 0xB817C9,
+0x9B5861, 0xBC57E1, 0xC68351, 0x103ED8, 0x4871DD, 0xDD1C2D,
+0xA118AF, 0x462C21, 0xD7F359, 0x987AD9, 0xC0549E, 0xFA864F,
+0xFC0656, 0xAE79E5, 0x362289, 0x22AD38, 0xDC9367, 0xAAE855,
+0x382682, 0x9BE7CA, 0xA40D51, 0xB13399, 0x0ED7A9, 0x480569,
+0xF0B265, 0xA7887F, 0x974C88, 0x36D1F9, 0xB39221, 0x4A827B,
+0x21CF98, 0xDC9F40, 0x5547DC, 0x3A74E1, 0x42EB67, 0xDF9DFE,
+0x5FD45E, 0xA4677B, 0x7AACBA, 0xA2F655, 0x23882B, 0x55BA41,
+0x086E59, 0x862A21, 0x834739, 0xE6E389, 0xD49EE5, 0x40FB49,
+0xE956FF, 0xCA0F1C, 0x8A59C5, 0x2BFA94, 0xC5C1D3, 0xCFC50F,
+0xAE5ADB, 0x86C547, 0x624385, 0x3B8621, 0x94792C, 0x876110,
+0x7B4C2A, 0x1A2C80, 0x12BF43, 0x902688, 0x893C78, 0xE4C4A8,
+0x7BDBE5, 0xC23AC4, 0xEAF426, 0x8A67F7, 0xBF920D, 0x2BA365,
+0xB1933D, 0x0B7CBD, 0xDC51A4, 0x63DD27, 0xDDE169, 0x19949A,
+0x9529A8, 0x28CE68, 0xB4ED09, 0x209F44, 0xCA984E, 0x638270,
+0x237C7E, 0x32B90F, 0x8EF5A7, 0xE75614, 0x08F121, 0x2A9DB5,
+0x4D7E6F, 0x5119A5, 0xABF9B5, 0xD6DF82, 0x61DD96, 0x023616,
+0x9F3AC4, 0xA1A283, 0x6DED72, 0x7A8D39, 0xA9B882, 0x5C326B,
+0x5B2746, 0xED3400, 0x7700D2, 0x55F4FC, 0x4D5901, 0x8071E0,
+#endif
+
+};
+
+static const double PIo2[] = {
+  1.57079625129699707031e+00, /* 0x3FF921FB, 0x40000000 */
+  7.54978941586159635335e-08, /* 0x3E74442D, 0x00000000 */
+  5.39030252995776476554e-15, /* 0x3CF84698, 0x80000000 */
+  3.28200341580791294123e-22, /* 0x3B78CC51, 0x60000000 */
+  1.27065575308067607349e-29, /* 0x39F01B83, 0x80000000 */
+  1.22933308981111328932e-36, /* 0x387A2520, 0x40000000 */
+  2.73370053816464559624e-44, /* 0x36E38222, 0x80000000 */
+  2.16741683877804819444e-51, /* 0x3569F31D, 0x00000000 */
+};
+
+static const double                    
+zero   = 0.0,
+one    = 1.0,
+two24   =  1.67772160000000000000e+07, /* 0x41700000, 0x00000000 */
+twon24  =  5.96046447753906250000e-08; /* 0x3E700000, 0x00000000 */
+
+static int
+__kernel_rem_pio2(double *x, double *y, int e0, int nx, int prec)
+{
+       int32_t jz,jx,jv,jp,jk,carry,n,iq[20],i,j,k,m,q0,ih;
+       double z,fw,f[20],fq[20],q[20];
+
+    /* initialize jk*/
+       jk = init_jk[prec];
+       jp = jk;
+
+    /* determine jx,jv,q0, note that 3>q0 */
+       jx =  nx-1;
+       jv = (e0-3)/24; if(jv<0) jv=0;
+       q0 =  e0-24*(jv+1);
+
+    /* set up f[0] to f[jx+jk] where f[jx+jk] = ipio2[jv+jk] */
+       j = jv-jx; m = jx+jk;
+       for(i=0;i<=m;i++,j++) f[i] = (j<0)? zero : (double) ipio2[j];
+
+    /* compute q[0],q[1],...q[jk] */
+       for (i=0;i<=jk;i++) {
+           for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j]; q[i] = fw;
+       }
+
+       jz = jk;
+recompute:
+    /* distill q[] into iq[] reversingly */
+       for(i=0,j=jz,z=q[jz];j>0;i++,j--) {
+           fw    =  (double)((int32_t)(twon24* z));
+           iq[i] =  (int32_t)(z-two24*fw);
+           z     =  q[j-1]+fw;
+       }
+
+    /* compute n */
+       z  = scalbn(z,q0);              /* actual value of z */
+       z -= 8.0*floor(z*0.125);                /* trim off integer >= 8 */
+       n  = (int32_t) z;
+       z -= (double)n;
+       ih = 0;
+       if(q0>0) {      /* need iq[jz-1] to determine n */
+           i  = (iq[jz-1]>>(24-q0)); n += i;
+           iq[jz-1] -= i<<(24-q0);
+           ih = iq[jz-1]>>(23-q0);
+       } 
+       else if(q0==0) ih = iq[jz-1]>>23;
+       else if(z>=0.5) ih=2;
+
+       if(ih>0) {      /* q > 0.5 */
+           n += 1; carry = 0;
+           for(i=0;i<jz ;i++) {        /* compute 1-q */
+               j = iq[i];
+               if(carry==0) {
+                   if(j!=0) {
+                       carry = 1; iq[i] = 0x1000000- j;
+                   }
+               } else  iq[i] = 0xffffff - j;
+           }
+           if(q0>0) {          /* rare case: chance is 1 in 12 */
+               switch(q0) {
+               case 1:
+                  iq[jz-1] &= 0x7fffff; break;
+               case 2:
+                  iq[jz-1] &= 0x3fffff; break;
+               }
+           }
+           if(ih==2) {
+               z = one - z;
+               if(carry!=0) z -= scalbn(one,q0);
+           }
+       }
+
+    /* check if recomputation is needed */
+       if(z==zero) {
+           j = 0;
+           for (i=jz-1;i>=jk;i--) j |= iq[i];
+           if(j==0) { /* need recomputation */
+               for(k=1;iq[jk-k]==0;k++);   /* k = no. of terms needed */
+
+               for(i=jz+1;i<=jz+k;i++) {   /* add q[jz+1] to q[jz+k] */
+                   f[jx+i] = (double) ipio2[jv+i];
+                   for(j=0,fw=0.0;j<=jx;j++) fw += x[j]*f[jx+i-j];
+                   q[i] = fw;
+               }
+               jz += k;
+               goto recompute;
+           }
+       }
+
+    /* chop off zero terms */
+       if(z==0.0) {
+           jz -= 1; q0 -= 24;
+           while(iq[jz]==0) { jz--; q0-=24;}
+       } else { /* break z into 24-bit if necessary */
+           z = scalbn(z,-q0);
+           if(z>=two24) { 
+               fw = (double)((int32_t)(twon24*z));
+               iq[jz] = (int32_t)(z-two24*fw);
+               jz += 1; q0 += 24;
+               iq[jz] = (int32_t) fw;
+           } else iq[jz] = (int32_t) z ;
+       }
+
+    /* convert integer "bit" chunk to floating-point value */
+       fw = scalbn(one,q0);
+       for(i=jz;i>=0;i--) {
+           q[i] = fw*(double)iq[i]; fw*=twon24;
+       }
+
+    /* compute PIo2[0,...,jp]*q[jz,...,0] */
+       for(i=jz;i>=0;i--) {
+           for(fw=0.0,k=0;k<=jp&&k<=jz-i;k++) fw += PIo2[k]*q[i+k];
+           fq[jz-i] = fw;
+       }
+
+    /* compress fq[] into y[] */
+       switch(prec) {
+           case 0:
+               fw = 0.0;
+               for (i=jz;i>=0;i--) fw += fq[i];
+               y[0] = (ih==0)? fw: -fw; 
+               break;
+           case 1:
+           case 2:
+               fw = 0.0;
+               for (i=jz;i>=0;i--) fw += fq[i]; 
+               STRICT_ASSIGN(double,fw,fw);
+               y[0] = (ih==0)? fw: -fw;
+               fw = fq[0]-fw;
+               for (i=1;i<=jz;i++) fw += fq[i];
+               y[1] = (ih==0)? fw: -fw; 
+               break;
+           case 3:     /* painful */
+               for (i=jz;i>0;i--) {
+                   fw      = fq[i-1]+fq[i]; 
+                   fq[i]  += fq[i-1]-fw;
+                   fq[i-1] = fw;
+               }
+               for (i=jz;i>1;i--) {
+                   fw      = fq[i-1]+fq[i]; 
+                   fq[i]  += fq[i-1]-fw;
+                   fq[i-1] = fw;
+               }
+               for (fw=0.0,i=jz;i>=2;i--) fw += fq[i]; 
+               if(ih==0) {
+                   y[0] =  fq[0]; y[1] =  fq[1]; y[2] =  fw;
+               } else {
+                   y[0] = -fq[0]; y[1] = -fq[1]; y[2] = -fw;
+               }
+       }
+       return n&7;
+}
+

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=3e6f4db8c8724164a52b12216746c6bb3e050b69

commit 3e6f4db8c8724164a52b12216746c6bb3e050b69
Author: John Haque <address@hidden>
Date:   Mon Feb 4 06:17:09 2013 -0600

    Added replacement trig functions for long double.

diff --git a/misc/ChangeLog b/misc/ChangeLog
index 4dd9c3f..d668726 100644
--- a/misc/ChangeLog
+++ b/misc/ChangeLog
@@ -1,3 +1,10 @@
+2013-02-04         John Haque            <address@hidden>
+
+       * gawk_math.c (gawk_sinl, gawk_cosl, gawk_atan2l):
+       Replacement long double math functions.
+       * ldbl-tests/*.awk: Tests for the math functions.
+       * floatcmp.awk: Added diff mode.
+
 2013-02-02         John Haque            <address@hidden>
 
        * float80.c: New file. Provides 80-bit long-double support
diff --git a/misc/Makefile b/misc/Makefile
index bafec60..2a07457 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -42,9 +42,14 @@ LDBL_TESTS = \
        exp64 \
        exp113 \
        pow64 \
-       pow113
+       pow113 \
+       sin64 \
+       sin113 \
+       cos64 \
+       cos113
 
 INFILE = ldbl-tests/data.in
+INFILE32 = ldbl-tests/sincos.in
 
 # An attempt to print something that can be grepped for in build logs
 pass-fail:
@@ -61,6 +66,10 @@ ldbl-tests: $(LDBL_TESTS)
 $(INFILE):
        @$(AWK) -M -vPREC=quad -f ldblin.awk > $(INFILE) 2>&1
 
+$(INFILE32): $(INFILE)
+       @$(AWK) -M -vPREC=quad -f ldblin.awk | \
+$(AWK) -M -vPREC=quad '($$1 > -2^32 && $$1 < 2^32){ print $$0 }' > $(INFILE32) 
2>&1
+
 ldblint64:
        @echo $@
        @$(AWK) -B0 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
@@ -73,48 +82,72 @@ ldblint128:
 
 sqrt64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sqrt.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sqrt.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sqrt.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sqrt.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
 sqrt113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sqrt.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sqrt.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sqrt.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sqrt.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
 log64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/log.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/log.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/log.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/log.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
 log113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/log.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/log.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/log.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/log.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
 exp64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/exp.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/exp.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/exp.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/exp.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
 exp113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/exp.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/exp.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/exp.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/exp.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
 
 pow64: $(INFILE)
        @echo $@
-       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/pow.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/pow.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/pow.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/pow.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
        @-$(AWK) -M -vTOL=10 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
 
 pow113: $(INFILE)
        @echo $@
-       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/pow.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
-       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/pow.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
-       @-$(AWK) -M -vTOL=10 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/pow.awk $(INFILE) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/pow.awk $(INFILE) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -vTOL=20 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
+
+sin64:
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sin.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sin.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+sin113: $(INFILE32)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sin.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sin.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+cos64:
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/cos.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/cos.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+cos113: $(INFILE32)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/cos.awk $(INFILE32) > ldbl-tests/_$@ 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/cos.awk $(INFILE32) > 
ldbl-tests/address@hidden 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
diff --git a/misc/floatcmp.awk b/misc/floatcmp.awk
index 87c8ea2..ac2a08e 100644
--- a/misc/floatcmp.awk
+++ b/misc/floatcmp.awk
@@ -1,9 +1,14 @@
-# floatcmp.awk --- check floating-point numbers for differences in
-#       sig digs.
+# floatcmp.awk --- check floating-point numbers for differences in sig digs.
+#      -vMODE=[diff|plot] -- diff mode or output data suitable fro plotting
+#      -vTOL=tol       -- ignore sig dig difference <= tol
 
 BEGIN {
+       if (! ("mpfr_version" in PROCINFO)) {
+               print "floatcmp.awk: requires -M option" > "/dev/stderr"
+               exit(1)
+       } 
        if (ARGC < 3) {
-               printf("Usage: gawk -M [-vTOL=1] -f floatcmp.awk file1 file2\n")
+               print "Usage: gawk -M [-vTOL=tol] [-vMODE=diff|plot] -f 
floatcmp.awk file1 file2" > "/dev/stderr"
                exit(1)
        }
 
@@ -20,10 +25,11 @@ BEGIN {
                ret1 = (getline v1 < file1) 
                ret2 = (getline v2 < file2) 
 
+               f1 = v1; f2 = v2;       # save originals for diff mode
                if (ret1 > 0 && ret2 > 0) {
                        line++
                        if ((v1 "") == (v2 ""))
-                               continue;
+                               continue
                        e1 = index(v1, "e")
                        e2 = index(v2, "e")
                        if (e1 > 0 && e2 > 0 &&         # exclude nans and 
infinities
@@ -41,8 +47,17 @@ BEGIN {
                                        continue
                        }
 
-                       printf("%s %s differ: byte ?, line %d\n", file1, file2, 
line)
-                       exit(1)
+                       if (! MODE) {
+                               printf("%s %s differ: byte ?, line %d\n", 
file1, file2, line)
+                               exit(1)
+                       }
+                       if (MODE == "plot")
+                               printf("%d\t%d\n", line, diff)
+                       else {
+                               dig = length(v1)
+                               printf("%-*.*s %-*.*s %+*.*d\n", dig+7, dig+7, 
f1, dig+7, dig+7, f2, dig, dig, diff)
+                       }
+                               continue
                }
 
                if (ret1 == 0 && ret2 == 0)
diff --git a/misc/fp_math.awk b/misc/fp_math.awk
index e2847e6..60048b1 100644
--- a/misc/fp_math.awk
+++ b/misc/fp_math.awk
@@ -39,7 +39,7 @@ function euler_atan_one_over(x,       \
 
        do {
                term *= (i + 2) / (i + 3)
-               err = term /= xpow2_plus_one
+               term /= xpow2_plus_one
                i += 2
                sum += term
                err = term / sum
diff --git a/misc/gawk_math.c b/misc/gawk_math.c
index 6981725..27ca215 100644
--- a/misc/gawk_math.c
+++ b/misc/gawk_math.c
@@ -27,40 +27,250 @@
 #define _0L    LDC(0.0)
 #define _1L    LDC(1.0)
 #define _2L    LDC(2.0)
+#define _3L    LDC(3.0)
+#define _4L    LDC(4.0)
 
 /*
  * Constants for computation using long doubles with enough digits for the 
128-bit quad.
  */
 
-#define GAWK_LOG2      LDC(0.693147180559945309417232121458176568)  /* log 2 
(base e) */
+#define        GAWK_LOG2       LDC(0.693147180559945309417232121458176568)  /* 
log 2 (base e) */
 #define        GAWK_LOG2_HIGH  LDC(0.6931471801362931728363037109375)       /* 
high 32 bits (exact representation) */
-#define GAWK_LOG2_LOW  LDC(4.236521365809284105206765680755001344e-10) /* 
variable precision low bits */
+#define        GAWK_LOG2_LOW   LDC(4.236521365809284105206765680755001344e-10) 
/* variable precision low bits */
 
-#define GAWK_SQRT2     LDC(1.414213562373095048801688724209698079)     /* 
sqrt(2) */
-#define GAWK_SQRT1_2   LDC(0.707106781186547524400844362104849039)     /* 
1/sqrt(2) */
+#define        GAWK_SQRT2      LDC(1.414213562373095048801688724209698079)     
/* sqrt(2) */
+#define        GAWK_SQRT1_2    LDC(0.707106781186547524400844362104849039)     
/* 1/sqrt(2) */
 
+#define        GAWK_PI         LDC(3.141592653589793238462643383279502884)     
/* pi */
+#define        GAWK_PI_2       LDC(1.570796326794896619231321691639751442)     
/* pi/2 */
+#define        GAWK_PI_4       LDC(0.785398163397448309615660845819875721)     
/* pi/4 */
+#define        GAWK_PI_4_HIGH  LDC(0.78539816313423216342926025390625)         
/* 32-bit 1st part */
+#define        GAWK_PI_4_MED   LDC(2.632161460363116600724708860070677474e-10) 
/* 32-bit 2nd part */
+#define        GAWK_PI_4_LOW   LDC(1.500889318411548350422246024296643642e-19) 
/* variable precision 3rd part */
 
 static AWKLDBL taylor_exp(AWKLDBL x);
+static AWKLDBL taylor_cos(AWKLDBL x);
+static AWKLDBL taylor_sin(AWKLDBL x);
+static AWKLDBL euler_atan_1(AWKLDBL x);
 static AWKLDBL gawk_frexpl(AWKLDBL x, int *exponent);
 
+/* gawk_sinl --- Compute sin(x) */
+
 static AWKLDBL
 gawk_sinl(AWKLDBL x)
 {
-       return sin( (double) x);
+       AWKLDBL sinval, dq;
+       int sign = 1;
+
+       if (isinf(x) || isnan(x))
+               return GAWK_NAN;
+
+       if (x == _0L)   /* XXX: sin(-0.0) = -0.0 */
+               return x;
+
+       if (x < _0L) {
+               /* sin(-x) = - sin(x) */
+               sign = -1;
+               x = -x;
+       }
+
+       /* range reduction -- 0 <= x < pi / 4 */
+
+       dq = double_to_int(x / GAWK_PI_4);
+
+       if (dq < pow2ld(32)) {
+               gawk_uint_t q = (gawk_uint_t) dq; 
+
+               sign *= ( (q / 4) % 2 ? -1 : 1 );
+               switch (q % 4) {
+               case 0:
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       sinval = taylor_sin(x);
+                       break;
+               case 1:
+                       q++;
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       sinval = taylor_cos(-x);
+                       break;
+               case 2:
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       sinval = taylor_cos(x);
+                       break;
+               case 3:
+                       q++;
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       sinval = taylor_sin(-x);
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               /* FIXME -- Payne and Hanek Reduction Algorithm ? */
+
+               sinval = (AWKLDBL) sin( (double) x);
+       }
+
+       return sign > 0 ? sinval : -sinval;
 }
 
+/* gawk_cosl --- Compute cos(x) */
+
 static AWKLDBL
 gawk_cosl(AWKLDBL x)
 {
-       return cos( (double) x);
+       AWKLDBL cosval, dq;
+       int sign = 1;
+
+       if (isinf(x) || isnan(x))
+               return GAWK_NAN;
+       if (x < _0L) {
+               /* cos(-x) = cos(x) */
+               x = -x;
+       }
+       if (x == _0L)
+               return _1L;
+
+       /* range reduction -- 0 <= x < pi / 4 */
+
+       dq = double_to_int(x / GAWK_PI_4);
+
+       if (dq < pow2ld(32)) {
+               gawk_uint_t q = (gawk_uint_t) dq; 
+
+               sign *= ( (q / 4) % 2 ? -1 : 1 );
+               switch (q % 4) {
+               case 0:
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       cosval = taylor_cos(x);
+                       break;
+               case 1:
+                       q++;
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       cosval = taylor_sin(-x);
+                       break;
+               case 2:
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       cosval = -taylor_sin(x);
+                       break;
+               case 3:
+                       q++;
+                       x -= q * GAWK_PI_4_HIGH;
+                       x -= q * GAWK_PI_4_MED;
+                       x -= q * GAWK_PI_4_LOW;
+                       cosval = -taylor_cos(-x);
+                       break;
+               default:
+                       break;
+               }
+       } else {
+               /* FIXME Payne and Hanek Reduction Algorithm ? */
+
+               cosval = (AWKLDBL) cos( (double) x);
+       }
+
+       return sign > 0 ? cosval : -cosval;
 }
 
+
+/* gawk_atan2l(x) --- Compute atan2(y, x) */
+
 static AWKLDBL
 gawk_atan2l(AWKLDBL y, AWKLDBL x)
 {
-       return atan2( (double) y, (double) x);
+       int sign;
+
+       /*
+        * Using Euler atan(1/x) and the identity:
+        *      atan(x) = - pi / 2 - atan(1/x),         x < 0
+        *              = pi / 2 - atan(1/x),           x > 0
+        */
+
+       if (isnan(x) || isnan(y))
+               return GAWK_NAN;
+
+       if (isinf(y)) {
+               if (y > _0L) {
+                       if (isinf(x))
+                               return x < _0L ? _3L * GAWK_PI_4 : GAWK_PI_4;
+                       return GAWK_PI_2;
+               }
+               if (isinf(x))
+                       return x < _0L ? -_3L * GAWK_PI_4 : -GAWK_PI_4;
+               return -GAWK_PI_2;
+       }
+
+       if (isinf(x)) {
+               if (x > _0L)
+                       return y < _0L ? -_0L : _0L;
+               /* x = -Infinity */
+               return (y >= _0L) ? GAWK_PI : -GAWK_PI;
+       }
+
+       if (x > _0L) {
+               if (y == _0L)
+                       return y;       /* +0 or -0 */
+               sign = 1;
+               if (y < _0L) {
+                       sign = -1;
+                       y = -y;
+               }
+               if (y > x)
+                       return sign * (GAWK_PI_2 - euler_atan_1(y / x));
+               return sign * euler_atan_1(x / y);
+       }
+
+       if (x < _0L) {
+               if (y == _0L)
+                       return atan2( (double) y, -_1L) < 0.0 ? -GAWK_PI : 
GAWK_PI;
+
+               x = -x;
+               if (y < _0L) {
+                       y = -y;
+                       if (y > x)
+                               return -GAWK_PI_2 - euler_atan_1(y / x);
+                       return euler_atan_1(x / y) - GAWK_PI;
+               }
+               /* y > 0 */
+               if (y > x)
+                       return GAWK_PI_2 + euler_atan_1(y / x);
+               return - euler_atan_1(x / y) + GAWK_PI;
+       }
+
+       /*
+        * XXX -- using atan2 instead of trying to detect +0 or -0. No need for 
signbit(x)!
+        * We need to make sure the value of y is in the double range;
+        * Replace positive (negative) y with 1 (-1), the actual value isn't 
important.
+        */
+
+       if ( y > _0L)
+               y = _1L;
+       else if (y < _0L)
+               y = -_1L;
+
+       /* x = +0 or -0 */
+       if (atan2( (double) y, (double) x) < 0.0)
+               return -GAWK_PI;
+       if (atan2( (double) y, (double) x) > 0.0)
+               return GAWK_PI;
+       /* x = +0 and y = +0 or -0 */
+       return _0L;
 }
 
+
 /* gawk_logl --- Compute log(x) */
 
 static AWKLDBL
@@ -459,7 +669,7 @@ taylor_exp(AWKLDBL x)
                return _1L;
 
        k = 1;
-       while (x > 0.001) {
+       while (x > LDC(0.001)) {
                /* XXX: For x <= 0.001, max(k) = 10, and max # of terms 6 
(80-bit) / 10 (128-bit) */
                
                x /= _2L; 
@@ -482,3 +692,117 @@ taylor_exp(AWKLDBL x)
                y = 2 * y + y * y;
        return y + _1L;
 }
+
+/* taylor_sin --- Compute sin(x) using Taylor series */
+
+static AWKLDBL
+taylor_sin(AWKLDBL x)
+{
+       AWKLDBL xpow, xpow_odd, sinval;
+       AWKLDBL err, term, fact;
+       unsigned int i;
+
+       assert(x >= _0L);
+
+       if (x == _0L)
+               return x;
+
+       i = 3;
+       fact = LDC(6.0);        /* 3! */
+       xpow = x * x;
+       xpow_odd = xpow * x;
+       sinval = x - xpow_odd / fact;
+
+       do {
+               fact *= (AWKLDBL) ((i + 1) * (i + 2));
+               i += 2;
+               xpow_odd *= xpow;
+               term = xpow_odd / fact;
+
+               fact *= (AWKLDBL) ((i + 1) * (i + 2));
+               i += 2;
+               xpow_odd *= xpow;
+               term -= xpow_odd / fact;
+
+               sinval += term;
+               err = term / sinval;
+       } while (err > REL_ERROR);
+       return sinval;
+}
+
+/* taylor_cos --- Compute cos(x) using Taylor series */
+
+static AWKLDBL
+taylor_cos(AWKLDBL x)
+{
+       AWKLDBL xpow, xpow_even, cosval;
+       AWKLDBL err, term, fact;
+       unsigned int i;
+
+       if (x == _0L)
+               return _1L;
+
+       i = 2;
+       fact = _2L;     /* 2! */
+       xpow = x * x;
+       xpow_even = xpow;
+       cosval = _1L - xpow / fact;
+
+       do {
+               fact *= (AWKLDBL) ((i + 1) * (i + 2));
+               i += 2;
+               xpow_even *= xpow;
+               term = xpow_even / fact;
+
+               fact *= (AWKLDBL) ((i + 1) * (i + 2));
+               i += 2;
+               xpow_even *= xpow;
+               term -= xpow_even / fact;
+
+               cosval += term;
+               err = term / cosval;
+       } while (err > REL_ERROR);
+       return cosval;
+}
+
+/* euler_atan_1 --- Compute Euler arctan(1/x) approximation */ 
+
+static AWKLDBL
+euler_atan_1(AWKLDBL x)
+{
+       AWKLDBL xpow2_plus_one, term, sum, err;
+       int sign = 1;
+       unsigned int i;
+
+       /*
+        * Euler atan formula 
(http://mathworld.wolfram.com/InverseTangent.html):
+        *      atan(x) = (y/x) (1 + 2/3 y + (2·4)/(3·5) y^2 + 
(2·4·6)/(3·5·7) y^3 + ...)
+        *  where
+        *      y = (x^2) / (1 + x^2) and -1 <= x <= 1
+        *
+        * Substituting x = 1/x, for x >= 1
+        *      atan(1/x) = (x / (1 + x^2))    + (2/3) * (x / (1 + x^2)^2)
+        *                                     + (2*4/(3*5)) * (x / (1 + x^2)^3)
+        *                                     + (2*4*6/(3*5*7)) * (x / (1 + 
x^2)^4) + ...
+        */
+
+       if (x < _0L) {
+               sign = -1;
+               x = -x;
+       }
+
+       xpow2_plus_one = x * x + _1L;
+       term = x / xpow2_plus_one;
+       sum = term;
+       i = 0;
+
+       do {
+               term *= (AWKLDBL) (i + 2);
+               term /= ((AWKLDBL) (i + 3)) * xpow2_plus_one;
+               i += 2;
+               sum += term;
+               err = term / sum;
+       } while (err > REL_ERROR);
+
+       return sign > 0 ? sum : -sum;
+}
diff --git a/misc/ldbl-tests/pow.awk b/misc/ldbl-tests/pow.awk
index 0e75b56..73cf492 100644
--- a/misc/ldbl-tests/pow.awk
+++ b/misc/ldbl-tests/pow.awk
@@ -16,14 +16,8 @@ BEGIN {
        PREC = "quad"
        y1 += 0; y2 += 0; y3 += 0
 
-       if (y1 <= 1.0e750) {
-               printf("%*.*e\n", 0, DIG, y1)
-       }
-       if (y2 <= 1.0e750) {
-               printf("%*.*e\n", 0, DIG, y2)
-       }
-       if (y3 <= 1.0e750) {
-               printf("%*.*e\n", 0, DIG, y3)
-       }
+       printf("%*.*e\n", 0, DIG, y1)
+       printf("%*.*e\n", 0, DIG, y2)
+       printf("%*.*e\n", 0, DIG, y3)
        PREC = save_PREC
 }

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=fddb32fc890cabd6175ab022302ca3d852a4731d

commit fddb32fc890cabd6175ab022302ca3d852a4731d
Author: John Haque <address@hidden>
Date:   Sat Feb 2 04:18:59 2013 -0600

    PREC and ROUNDMODE, missing math function replacements for long double.

diff --git a/awkgram.c b/awkgram.c
index 3156184..a3e421e 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -99,6 +99,9 @@ static int load_library(INSTRUCTION *file);
 static void next_sourcefile(void);
 static char *tokexpand(void);
 static bool is_deferred_variable(const char *name);
+#ifdef NUMDEBUG
+static NODE *do_default(int nargs);
+#endif
 
 #define instruction(t) bcalloc(t, 1, 0)
 
@@ -198,7 +201,7 @@ extern double fmod(double x, double y);
 #define is_identchar(c)                (isalnum(c) || (c) == '_')
 
 /* Line 371 of yacc.c  */
-#line 202 "awkgram.c"
+#line 205 "awkgram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -367,7 +370,7 @@ int yyparse ();
 /* Copy the second part of user declarations.  */
 
 /* Line 390 of yacc.c  */
-#line 371 "awkgram.c"
+#line 374 "awkgram.c"
 
 #ifdef short
 # undef short
@@ -731,25 +734,25 @@ static const yytype_int16 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   199,   199,   201,   206,   207,   213,   225,   229,   240,
-     246,   251,   259,   267,   269,   274,   282,   284,   290,   291,
-     293,   319,   330,   341,   347,   356,   366,   368,   370,   376,
-     381,   382,   386,   405,   404,   438,   440,   445,   446,   459,
-     464,   465,   469,   471,   473,   480,   570,   612,   654,   767,
-     774,   781,   791,   800,   809,   818,   829,   845,   844,   868,
-     880,   880,   978,   978,  1011,  1041,  1047,  1048,  1054,  1055,
-    1062,  1067,  1079,  1093,  1095,  1103,  1108,  1110,  1118,  1120,
-    1129,  1130,  1138,  1143,  1143,  1154,  1158,  1166,  1167,  1170,
-    1172,  1177,  1178,  1187,  1188,  1193,  1198,  1204,  1206,  1208,
-    1215,  1216,  1222,  1223,  1228,  1230,  1235,  1237,  1239,  1241,
-    1247,  1254,  1256,  1258,  1274,  1284,  1291,  1293,  1298,  1300,
-    1302,  1310,  1312,  1317,  1319,  1324,  1326,  1328,  1378,  1380,
-    1382,  1384,  1386,  1388,  1390,  1392,  1415,  1420,  1425,  1450,
-    1456,  1458,  1460,  1462,  1464,  1466,  1471,  1475,  1489,  1491,
-    1497,  1503,  1516,  1517,  1518,  1523,  1528,  1532,  1536,  1551,
-    1563,  1568,  1604,  1622,  1623,  1629,  1630,  1635,  1637,  1644,
-    1661,  1678,  1680,  1687,  1692,  1700,  1710,  1722,  1731,  1735,
-    1739,  1743,  1747,  1751,  1754,  1756,  1760,  1764,  1768
+       0,   202,   202,   204,   209,   210,   216,   228,   232,   243,
+     249,   254,   262,   270,   272,   277,   285,   287,   293,   294,
+     296,   322,   333,   344,   350,   359,   369,   371,   373,   379,
+     384,   385,   389,   408,   407,   441,   443,   448,   449,   462,
+     467,   468,   472,   474,   476,   483,   573,   615,   657,   770,
+     777,   784,   794,   803,   812,   821,   832,   848,   847,   871,
+     883,   883,   981,   981,  1014,  1044,  1050,  1051,  1057,  1058,
+    1065,  1070,  1082,  1096,  1098,  1106,  1111,  1113,  1121,  1123,
+    1132,  1133,  1141,  1146,  1146,  1157,  1161,  1169,  1170,  1173,
+    1175,  1180,  1181,  1190,  1191,  1196,  1201,  1207,  1209,  1211,
+    1218,  1219,  1225,  1226,  1231,  1233,  1238,  1240,  1242,  1244,
+    1250,  1257,  1259,  1261,  1277,  1287,  1294,  1296,  1301,  1303,
+    1305,  1313,  1315,  1320,  1322,  1327,  1329,  1331,  1381,  1383,
+    1385,  1387,  1389,  1391,  1393,  1395,  1418,  1423,  1428,  1453,
+    1459,  1461,  1463,  1465,  1467,  1469,  1474,  1478,  1492,  1494,
+    1500,  1506,  1519,  1520,  1521,  1526,  1531,  1535,  1539,  1554,
+    1566,  1571,  1607,  1625,  1626,  1632,  1633,  1638,  1640,  1647,
+    1664,  1681,  1683,  1690,  1695,  1703,  1713,  1725,  1734,  1738,
+    1742,  1746,  1750,  1754,  1757,  1759,  1763,  1767,  1771
 };
 #endif
 
@@ -2036,7 +2039,7 @@ yyreduce:
     {
         case 3:
 /* Line 1792 of yacc.c  */
-#line 202 "awkgram.y"
+#line 205 "awkgram.y"
     {
                rule = 0;
                yyerrok;
@@ -2045,7 +2048,7 @@ yyreduce:
 
   case 5:
 /* Line 1792 of yacc.c  */
-#line 208 "awkgram.y"
+#line 211 "awkgram.y"
     {
                next_sourcefile();
                if (sourcefile == srcfiles)
@@ -2055,7 +2058,7 @@ yyreduce:
 
   case 6:
 /* Line 1792 of yacc.c  */
-#line 214 "awkgram.y"
+#line 217 "awkgram.y"
     {
                rule = 0;
                /*
@@ -2068,7 +2071,7 @@ yyreduce:
 
   case 7:
 /* Line 1792 of yacc.c  */
-#line 226 "awkgram.y"
+#line 229 "awkgram.y"
     {
                (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -2076,7 +2079,7 @@ yyreduce:
 
   case 8:
 /* Line 1792 of yacc.c  */
-#line 230 "awkgram.y"
+#line 233 "awkgram.y"
     {
                if (rule != Rule) {
                        msg(_("%s blocks must have an action part"), 
ruletab[rule]);
@@ -2091,7 +2094,7 @@ yyreduce:
 
   case 9:
 /* Line 1792 of yacc.c  */
-#line 241 "awkgram.y"
+#line 244 "awkgram.y"
     {
                in_function = NULL;
                (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
@@ -2101,7 +2104,7 @@ yyreduce:
 
   case 10:
 /* Line 1792 of yacc.c  */
-#line 247 "awkgram.y"
+#line 250 "awkgram.y"
     {
                want_source = false;
                yyerrok;
@@ -2110,7 +2113,7 @@ yyreduce:
 
   case 11:
 /* Line 1792 of yacc.c  */
-#line 252 "awkgram.y"
+#line 255 "awkgram.y"
     {
                want_source = false;
                yyerrok;
@@ -2119,7 +2122,7 @@ yyreduce:
 
   case 12:
 /* Line 1792 of yacc.c  */
-#line 260 "awkgram.y"
+#line 263 "awkgram.y"
     {
                if (include_source((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2131,19 +2134,19 @@ yyreduce:
 
   case 13:
 /* Line 1792 of yacc.c  */
-#line 268 "awkgram.y"
+#line 271 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 14:
 /* Line 1792 of yacc.c  */
-#line 270 "awkgram.y"
+#line 273 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 15:
 /* Line 1792 of yacc.c  */
-#line 275 "awkgram.y"
+#line 278 "awkgram.y"
     {
                if (load_library((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2155,31 +2158,31 @@ yyreduce:
 
   case 16:
 /* Line 1792 of yacc.c  */
-#line 283 "awkgram.y"
+#line 286 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 17:
 /* Line 1792 of yacc.c  */
-#line 285 "awkgram.y"
+#line 288 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 18:
 /* Line 1792 of yacc.c  */
-#line 290 "awkgram.y"
+#line 293 "awkgram.y"
     {  (yyval) = NULL; rule = Rule; }
     break;
 
   case 19:
 /* Line 1792 of yacc.c  */
-#line 292 "awkgram.y"
+#line 295 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
     break;
 
   case 20:
 /* Line 1792 of yacc.c  */
-#line 294 "awkgram.y"
+#line 297 "awkgram.y"
     {
                INSTRUCTION *tp;
 
@@ -2209,7 +2212,7 @@ yyreduce:
 
   case 21:
 /* Line 1792 of yacc.c  */
-#line 320 "awkgram.y"
+#line 323 "awkgram.y"
     {
                static int begin_seen = 0;
                if (do_lint_old && ++begin_seen == 2)
@@ -2224,7 +2227,7 @@ yyreduce:
 
   case 22:
 /* Line 1792 of yacc.c  */
-#line 331 "awkgram.y"
+#line 334 "awkgram.y"
     {
                static int end_seen = 0;
                if (do_lint_old && ++end_seen == 2)
@@ -2239,7 +2242,7 @@ yyreduce:
 
   case 23:
 /* Line 1792 of yacc.c  */
-#line 342 "awkgram.y"
+#line 345 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2249,7 +2252,7 @@ yyreduce:
 
   case 24:
 /* Line 1792 of yacc.c  */
-#line 348 "awkgram.y"
+#line 351 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2259,7 +2262,7 @@ yyreduce:
 
   case 25:
 /* Line 1792 of yacc.c  */
-#line 357 "awkgram.y"
+#line 360 "awkgram.y"
     {
                if ((yyvsp[(2) - (5)]) == NULL)
                        (yyval) = list_create(instruction(Op_no_op));
@@ -2270,19 +2273,19 @@ yyreduce:
 
   case 26:
 /* Line 1792 of yacc.c  */
-#line 367 "awkgram.y"
+#line 370 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 27:
 /* Line 1792 of yacc.c  */
-#line 369 "awkgram.y"
+#line 372 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 28:
 /* Line 1792 of yacc.c  */
-#line 371 "awkgram.y"
+#line 374 "awkgram.y"
     {
                yyerror(_("`%s' is a built-in function, it cannot be 
redefined"),
                                        tokstart);
@@ -2292,13 +2295,13 @@ yyreduce:
 
   case 29:
 /* Line 1792 of yacc.c  */
-#line 377 "awkgram.y"
+#line 380 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 32:
 /* Line 1792 of yacc.c  */
-#line 387 "awkgram.y"
+#line 390 "awkgram.y"
     {
                (yyvsp[(1) - (6)])->source_file = source;
                if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
@@ -2313,13 +2316,13 @@ yyreduce:
 
   case 33:
 /* Line 1792 of yacc.c  */
-#line 405 "awkgram.y"
+#line 408 "awkgram.y"
     { want_regexp = true; }
     break;
 
   case 34:
 /* Line 1792 of yacc.c  */
-#line 407 "awkgram.y"
+#line 410 "awkgram.y"
     {
                  NODE *n, *exp;
                  char *re;
@@ -2352,19 +2355,19 @@ yyreduce:
 
   case 35:
 /* Line 1792 of yacc.c  */
-#line 439 "awkgram.y"
+#line 442 "awkgram.y"
     { bcfree((yyvsp[(1) - (1)])); }
     break;
 
   case 37:
 /* Line 1792 of yacc.c  */
-#line 445 "awkgram.y"
+#line 448 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
   case 38:
 /* Line 1792 of yacc.c  */
-#line 447 "awkgram.y"
+#line 450 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)]) == NULL)
                        (yyval) = (yyvsp[(1) - (2)]);
@@ -2381,25 +2384,25 @@ yyreduce:
 
   case 39:
 /* Line 1792 of yacc.c  */
-#line 460 "awkgram.y"
+#line 463 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
   case 42:
 /* Line 1792 of yacc.c  */
-#line 470 "awkgram.y"
+#line 473 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 43:
 /* Line 1792 of yacc.c  */
-#line 472 "awkgram.y"
+#line 475 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 44:
 /* Line 1792 of yacc.c  */
-#line 474 "awkgram.y"
+#line 477 "awkgram.y"
     {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2410,7 +2413,7 @@ yyreduce:
 
   case 45:
 /* Line 1792 of yacc.c  */
-#line 481 "awkgram.y"
+#line 484 "awkgram.y"
     {
                INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
                INSTRUCTION *ip, *nextc, *tbreak;
@@ -2504,7 +2507,7 @@ yyreduce:
 
   case 46:
 /* Line 1792 of yacc.c  */
-#line 571 "awkgram.y"
+#line 574 "awkgram.y"
     { 
                /*
                 *    -----------------
@@ -2550,7 +2553,7 @@ yyreduce:
 
   case 47:
 /* Line 1792 of yacc.c  */
-#line 613 "awkgram.y"
+#line 616 "awkgram.y"
     {
                /*
                 *    -----------------
@@ -2596,7 +2599,7 @@ yyreduce:
 
   case 48:
 /* Line 1792 of yacc.c  */
-#line 655 "awkgram.y"
+#line 658 "awkgram.y"
     {
                INSTRUCTION *ip;
                char *var_name = (yyvsp[(3) - (8)])->lextok;
@@ -2713,7 +2716,7 @@ regular_loop:
 
   case 49:
 /* Line 1792 of yacc.c  */
-#line 768 "awkgram.y"
+#line 771 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), 
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
 
@@ -2724,7 +2727,7 @@ regular_loop:
 
   case 50:
 /* Line 1792 of yacc.c  */
-#line 775 "awkgram.y"
+#line 778 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), 
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
 
@@ -2735,7 +2738,7 @@ regular_loop:
 
   case 51:
 /* Line 1792 of yacc.c  */
-#line 782 "awkgram.y"
+#line 785 "awkgram.y"
     {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2746,7 +2749,7 @@ regular_loop:
 
   case 52:
 /* Line 1792 of yacc.c  */
-#line 792 "awkgram.y"
+#line 795 "awkgram.y"
     { 
                if (! break_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2759,7 +2762,7 @@ regular_loop:
 
   case 53:
 /* Line 1792 of yacc.c  */
-#line 801 "awkgram.y"
+#line 804 "awkgram.y"
     {
                if (! continue_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2772,7 +2775,7 @@ regular_loop:
 
   case 54:
 /* Line 1792 of yacc.c  */
-#line 810 "awkgram.y"
+#line 813 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule && rule != Rule)
@@ -2785,7 +2788,7 @@ regular_loop:
 
   case 55:
 /* Line 1792 of yacc.c  */
-#line 819 "awkgram.y"
+#line 822 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule == BEGIN || rule == END || rule == ENDFILE)
@@ -2800,7 +2803,7 @@ regular_loop:
 
   case 56:
 /* Line 1792 of yacc.c  */
-#line 830 "awkgram.y"
+#line 833 "awkgram.y"
     {
                /* Initialize the two possible jump targets, the actual target
                 * is resolved at run-time. 
@@ -2819,7 +2822,7 @@ regular_loop:
 
   case 57:
 /* Line 1792 of yacc.c  */
-#line 845 "awkgram.y"
+#line 848 "awkgram.y"
     {
                if (! in_function)
                        yyerror(_("`return' used outside function context"));
@@ -2828,7 +2831,7 @@ regular_loop:
 
   case 58:
 /* Line 1792 of yacc.c  */
-#line 848 "awkgram.y"
+#line 851 "awkgram.y"
     {
                if ((yyvsp[(3) - (4)]) == NULL) {
                        (yyval) = list_create((yyvsp[(1) - (4)]));
@@ -2853,13 +2856,13 @@ regular_loop:
 
   case 60:
 /* Line 1792 of yacc.c  */
-#line 880 "awkgram.y"
+#line 883 "awkgram.y"
     { in_print = true; in_parens = 0; }
     break;
 
   case 61:
 /* Line 1792 of yacc.c  */
-#line 881 "awkgram.y"
+#line 884 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2960,13 +2963,13 @@ regular_print:
 
   case 62:
 /* Line 1792 of yacc.c  */
-#line 978 "awkgram.y"
+#line 981 "awkgram.y"
     { sub_counter = 0; }
     break;
 
   case 63:
 /* Line 1792 of yacc.c  */
-#line 979 "awkgram.y"
+#line 982 "awkgram.y"
     {
                char *arr = (yyvsp[(2) - (4)])->lextok;
 
@@ -3003,7 +3006,7 @@ regular_print:
 
   case 64:
 /* Line 1792 of yacc.c  */
-#line 1016 "awkgram.y"
+#line 1019 "awkgram.y"
     {
                static bool warned = false;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3033,31 +3036,31 @@ regular_print:
 
   case 65:
 /* Line 1792 of yacc.c  */
-#line 1042 "awkgram.y"
+#line 1045 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
   case 66:
 /* Line 1792 of yacc.c  */
-#line 1047 "awkgram.y"
+#line 1050 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 67:
 /* Line 1792 of yacc.c  */
-#line 1049 "awkgram.y"
+#line 1052 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 68:
 /* Line 1792 of yacc.c  */
-#line 1054 "awkgram.y"
+#line 1057 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 69:
 /* Line 1792 of yacc.c  */
-#line 1056 "awkgram.y"
+#line 1059 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3068,13 +3071,13 @@ regular_print:
 
   case 70:
 /* Line 1792 of yacc.c  */
-#line 1063 "awkgram.y"
+#line 1066 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 71:
 /* Line 1792 of yacc.c  */
-#line 1068 "awkgram.y"
+#line 1071 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3090,7 +3093,7 @@ regular_print:
 
   case 72:
 /* Line 1792 of yacc.c  */
-#line 1080 "awkgram.y"
+#line 1083 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3105,13 +3108,13 @@ regular_print:
 
   case 73:
 /* Line 1792 of yacc.c  */
-#line 1094 "awkgram.y"
+#line 1097 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 74:
 /* Line 1792 of yacc.c  */
-#line 1096 "awkgram.y"
+#line 1099 "awkgram.y"
     { 
                NODE *n = (yyvsp[(2) - (2)])->memory;
                (void) force_number(n);
@@ -3123,7 +3126,7 @@ regular_print:
 
   case 75:
 /* Line 1792 of yacc.c  */
-#line 1104 "awkgram.y"
+#line 1107 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3132,13 +3135,13 @@ regular_print:
 
   case 76:
 /* Line 1792 of yacc.c  */
-#line 1109 "awkgram.y"
+#line 1112 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 77:
 /* Line 1792 of yacc.c  */
-#line 1111 "awkgram.y"
+#line 1114 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3147,19 +3150,19 @@ regular_print:
 
   case 78:
 /* Line 1792 of yacc.c  */
-#line 1119 "awkgram.y"
+#line 1122 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 79:
 /* Line 1792 of yacc.c  */
-#line 1121 "awkgram.y"
+#line 1124 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 81:
 /* Line 1792 of yacc.c  */
-#line 1131 "awkgram.y"
+#line 1134 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
@@ -3167,7 +3170,7 @@ regular_print:
 
   case 82:
 /* Line 1792 of yacc.c  */
-#line 1138 "awkgram.y"
+#line 1141 "awkgram.y"
     {
                in_print = false;
                in_parens = 0;
@@ -3177,13 +3180,13 @@ regular_print:
 
   case 83:
 /* Line 1792 of yacc.c  */
-#line 1143 "awkgram.y"
+#line 1146 "awkgram.y"
     { in_print = false; in_parens = 0; }
     break;
 
   case 84:
 /* Line 1792 of yacc.c  */
-#line 1144 "awkgram.y"
+#line 1147 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3195,7 +3198,7 @@ regular_print:
 
   case 85:
 /* Line 1792 of yacc.c  */
-#line 1155 "awkgram.y"
+#line 1158 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
@@ -3203,7 +3206,7 @@ regular_print:
 
   case 86:
 /* Line 1792 of yacc.c  */
-#line 1160 "awkgram.y"
+#line 1163 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
@@ -3211,13 +3214,13 @@ regular_print:
 
   case 91:
 /* Line 1792 of yacc.c  */
-#line 1177 "awkgram.y"
+#line 1180 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 92:
 /* Line 1792 of yacc.c  */
-#line 1179 "awkgram.y"
+#line 1182 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3226,19 +3229,19 @@ regular_print:
 
   case 93:
 /* Line 1792 of yacc.c  */
-#line 1187 "awkgram.y"
+#line 1190 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 94:
 /* Line 1792 of yacc.c  */
-#line 1189 "awkgram.y"
+#line 1192 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]) ; }
     break;
 
   case 95:
 /* Line 1792 of yacc.c  */
-#line 1194 "awkgram.y"
+#line 1197 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->param_count = 0;
                (yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3247,7 +3250,7 @@ regular_print:
 
   case 96:
 /* Line 1792 of yacc.c  */
-#line 1199 "awkgram.y"
+#line 1202 "awkgram.y"
     {
                (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
                (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3257,55 +3260,55 @@ regular_print:
 
   case 97:
 /* Line 1792 of yacc.c  */
-#line 1205 "awkgram.y"
+#line 1208 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 98:
 /* Line 1792 of yacc.c  */
-#line 1207 "awkgram.y"
+#line 1210 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 99:
 /* Line 1792 of yacc.c  */
-#line 1209 "awkgram.y"
+#line 1212 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
   case 100:
 /* Line 1792 of yacc.c  */
-#line 1215 "awkgram.y"
+#line 1218 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 101:
 /* Line 1792 of yacc.c  */
-#line 1217 "awkgram.y"
+#line 1220 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 102:
 /* Line 1792 of yacc.c  */
-#line 1222 "awkgram.y"
+#line 1225 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 103:
 /* Line 1792 of yacc.c  */
-#line 1224 "awkgram.y"
+#line 1227 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 104:
 /* Line 1792 of yacc.c  */
-#line 1229 "awkgram.y"
+#line 1232 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
   case 105:
 /* Line 1792 of yacc.c  */
-#line 1231 "awkgram.y"
+#line 1234 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
@@ -3314,31 +3317,31 @@ regular_print:
 
   case 106:
 /* Line 1792 of yacc.c  */
-#line 1236 "awkgram.y"
+#line 1239 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 107:
 /* Line 1792 of yacc.c  */
-#line 1238 "awkgram.y"
+#line 1241 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 108:
 /* Line 1792 of yacc.c  */
-#line 1240 "awkgram.y"
+#line 1243 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 109:
 /* Line 1792 of yacc.c  */
-#line 1242 "awkgram.y"
+#line 1245 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 110:
 /* Line 1792 of yacc.c  */
-#line 1248 "awkgram.y"
+#line 1251 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3349,19 +3352,19 @@ regular_print:
 
   case 111:
 /* Line 1792 of yacc.c  */
-#line 1255 "awkgram.y"
+#line 1258 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 112:
 /* Line 1792 of yacc.c  */
-#line 1257 "awkgram.y"
+#line 1260 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 113:
 /* Line 1792 of yacc.c  */
-#line 1259 "awkgram.y"
+#line 1262 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3381,7 +3384,7 @@ regular_print:
 
   case 114:
 /* Line 1792 of yacc.c  */
-#line 1275 "awkgram.y"
+#line 1278 "awkgram.y"
     {
                if (do_lint_old)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3395,7 +3398,7 @@ regular_print:
 
   case 115:
 /* Line 1792 of yacc.c  */
-#line 1285 "awkgram.y"
+#line 1288 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3406,31 +3409,31 @@ regular_print:
 
   case 116:
 /* Line 1792 of yacc.c  */
-#line 1292 "awkgram.y"
+#line 1295 "awkgram.y"
     { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
     break;
 
   case 117:
 /* Line 1792 of yacc.c  */
-#line 1294 "awkgram.y"
+#line 1297 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 118:
 /* Line 1792 of yacc.c  */
-#line 1299 "awkgram.y"
+#line 1302 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 /* Line 1792 of yacc.c  */
-#line 1301 "awkgram.y"
+#line 1304 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 /* Line 1792 of yacc.c  */
-#line 1303 "awkgram.y"
+#line 1306 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3439,43 +3442,43 @@ regular_print:
 
   case 121:
 /* Line 1792 of yacc.c  */
-#line 1311 "awkgram.y"
+#line 1314 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 /* Line 1792 of yacc.c  */
-#line 1313 "awkgram.y"
+#line 1316 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 /* Line 1792 of yacc.c  */
-#line 1318 "awkgram.y"
+#line 1321 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 124:
 /* Line 1792 of yacc.c  */
-#line 1320 "awkgram.y"
+#line 1323 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 125:
 /* Line 1792 of yacc.c  */
-#line 1325 "awkgram.y"
+#line 1328 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 126:
 /* Line 1792 of yacc.c  */
-#line 1327 "awkgram.y"
+#line 1330 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 127:
 /* Line 1792 of yacc.c  */
-#line 1329 "awkgram.y"
+#line 1332 "awkgram.y"
     {
                int count = 2;
                bool is_simple_var = false;
@@ -3526,43 +3529,43 @@ regular_print:
 
   case 129:
 /* Line 1792 of yacc.c  */
-#line 1381 "awkgram.y"
+#line 1384 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 130:
 /* Line 1792 of yacc.c  */
-#line 1383 "awkgram.y"
+#line 1386 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 131:
 /* Line 1792 of yacc.c  */
-#line 1385 "awkgram.y"
+#line 1388 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 132:
 /* Line 1792 of yacc.c  */
-#line 1387 "awkgram.y"
+#line 1390 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 133:
 /* Line 1792 of yacc.c  */
-#line 1389 "awkgram.y"
+#line 1392 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 134:
 /* Line 1792 of yacc.c  */
-#line 1391 "awkgram.y"
+#line 1394 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 135:
 /* Line 1792 of yacc.c  */
-#line 1393 "awkgram.y"
+#line 1396 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3589,7 +3592,7 @@ regular_print:
 
   case 136:
 /* Line 1792 of yacc.c  */
-#line 1416 "awkgram.y"
+#line 1419 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3598,7 +3601,7 @@ regular_print:
 
   case 137:
 /* Line 1792 of yacc.c  */
-#line 1421 "awkgram.y"
+#line 1424 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3607,7 +3610,7 @@ regular_print:
 
   case 138:
 /* Line 1792 of yacc.c  */
-#line 1426 "awkgram.y"
+#line 1429 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3631,7 +3634,7 @@ regular_print:
 
   case 139:
 /* Line 1792 of yacc.c  */
-#line 1451 "awkgram.y"
+#line 1454 "awkgram.y"
     {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
@@ -3640,43 +3643,43 @@ regular_print:
 
   case 140:
 /* Line 1792 of yacc.c  */
-#line 1457 "awkgram.y"
+#line 1460 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 141:
 /* Line 1792 of yacc.c  */
-#line 1459 "awkgram.y"
+#line 1462 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 142:
 /* Line 1792 of yacc.c  */
-#line 1461 "awkgram.y"
+#line 1464 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 143:
 /* Line 1792 of yacc.c  */
-#line 1463 "awkgram.y"
+#line 1466 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 144:
 /* Line 1792 of yacc.c  */
-#line 1465 "awkgram.y"
+#line 1468 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 145:
 /* Line 1792 of yacc.c  */
-#line 1467 "awkgram.y"
+#line 1470 "awkgram.y"
     {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 146:
 /* Line 1792 of yacc.c  */
-#line 1472 "awkgram.y"
+#line 1475 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3684,7 +3687,7 @@ regular_print:
 
   case 147:
 /* Line 1792 of yacc.c  */
-#line 1476 "awkgram.y"
+#line 1479 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3702,13 +3705,13 @@ regular_print:
 
   case 148:
 /* Line 1792 of yacc.c  */
-#line 1490 "awkgram.y"
+#line 1493 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 149:
 /* Line 1792 of yacc.c  */
-#line 1492 "awkgram.y"
+#line 1495 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3718,7 +3721,7 @@ regular_print:
 
   case 150:
 /* Line 1792 of yacc.c  */
-#line 1498 "awkgram.y"
+#line 1501 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3728,7 +3731,7 @@ regular_print:
 
   case 151:
 /* Line 1792 of yacc.c  */
-#line 1504 "awkgram.y"
+#line 1507 "awkgram.y"
     {
                static bool warned = false;
 
@@ -3745,7 +3748,7 @@ regular_print:
 
   case 154:
 /* Line 1792 of yacc.c  */
-#line 1519 "awkgram.y"
+#line 1522 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3754,7 +3757,7 @@ regular_print:
 
   case 155:
 /* Line 1792 of yacc.c  */
-#line 1524 "awkgram.y"
+#line 1527 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3763,7 +3766,7 @@ regular_print:
 
   case 156:
 /* Line 1792 of yacc.c  */
-#line 1529 "awkgram.y"
+#line 1532 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3771,7 +3774,7 @@ regular_print:
 
   case 157:
 /* Line 1792 of yacc.c  */
-#line 1533 "awkgram.y"
+#line 1536 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3779,7 +3782,7 @@ regular_print:
 
   case 158:
 /* Line 1792 of yacc.c  */
-#line 1537 "awkgram.y"
+#line 1540 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
@@ -3798,7 +3801,7 @@ regular_print:
 
   case 159:
 /* Line 1792 of yacc.c  */
-#line 1552 "awkgram.y"
+#line 1555 "awkgram.y"
     {
            /*
             * was: $$ = $2
@@ -3811,7 +3814,7 @@ regular_print:
 
   case 160:
 /* Line 1792 of yacc.c  */
-#line 1564 "awkgram.y"
+#line 1567 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3820,7 +3823,7 @@ regular_print:
 
   case 161:
 /* Line 1792 of yacc.c  */
-#line 1569 "awkgram.y"
+#line 1572 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3857,7 +3860,7 @@ regular_print:
 
   case 162:
 /* Line 1792 of yacc.c  */
-#line 1605 "awkgram.y"
+#line 1608 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3875,37 +3878,37 @@ regular_print:
 
   case 163:
 /* Line 1792 of yacc.c  */
-#line 1622 "awkgram.y"
+#line 1625 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 164:
 /* Line 1792 of yacc.c  */
-#line 1624 "awkgram.y"
+#line 1627 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 165:
 /* Line 1792 of yacc.c  */
-#line 1629 "awkgram.y"
+#line 1632 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 166:
 /* Line 1792 of yacc.c  */
-#line 1631 "awkgram.y"
+#line 1634 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 167:
 /* Line 1792 of yacc.c  */
-#line 1636 "awkgram.y"
+#line 1639 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 168:
 /* Line 1792 of yacc.c  */
-#line 1638 "awkgram.y"
+#line 1641 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3913,7 +3916,7 @@ regular_print:
 
   case 169:
 /* Line 1792 of yacc.c  */
-#line 1645 "awkgram.y"
+#line 1648 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -3931,7 +3934,7 @@ regular_print:
 
   case 170:
 /* Line 1792 of yacc.c  */
-#line 1662 "awkgram.y"
+#line 1665 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -3949,13 +3952,13 @@ regular_print:
 
   case 171:
 /* Line 1792 of yacc.c  */
-#line 1679 "awkgram.y"
+#line 1682 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 172:
 /* Line 1792 of yacc.c  */
-#line 1681 "awkgram.y"
+#line 1684 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3963,13 +3966,13 @@ regular_print:
 
   case 173:
 /* Line 1792 of yacc.c  */
-#line 1688 "awkgram.y"
+#line 1691 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 174:
 /* Line 1792 of yacc.c  */
-#line 1693 "awkgram.y"
+#line 1696 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
@@ -3981,7 +3984,7 @@ regular_print:
 
   case 175:
 /* Line 1792 of yacc.c  */
-#line 1701 "awkgram.y"
+#line 1704 "awkgram.y"
     {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@ -3992,7 +3995,7 @@ regular_print:
 
   case 176:
 /* Line 1792 of yacc.c  */
-#line 1711 "awkgram.y"
+#line 1714 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@ -4008,7 +4011,7 @@ regular_print:
 
   case 177:
 /* Line 1792 of yacc.c  */
-#line 1723 "awkgram.y"
+#line 1726 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@ -4018,7 +4021,7 @@ regular_print:
 
   case 178:
 /* Line 1792 of yacc.c  */
-#line 1732 "awkgram.y"
+#line 1735 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@ -4026,7 +4029,7 @@ regular_print:
 
   case 179:
 /* Line 1792 of yacc.c  */
-#line 1736 "awkgram.y"
+#line 1739 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@ -4034,43 +4037,43 @@ regular_print:
 
   case 180:
 /* Line 1792 of yacc.c  */
-#line 1739 "awkgram.y"
+#line 1742 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 182:
 /* Line 1792 of yacc.c  */
-#line 1747 "awkgram.y"
+#line 1750 "awkgram.y"
     { yyerrok; }
     break;
 
   case 183:
 /* Line 1792 of yacc.c  */
-#line 1751 "awkgram.y"
+#line 1754 "awkgram.y"
     { yyerrok; }
     break;
 
   case 186:
 /* Line 1792 of yacc.c  */
-#line 1760 "awkgram.y"
+#line 1763 "awkgram.y"
     { yyerrok; }
     break;
 
   case 187:
 /* Line 1792 of yacc.c  */
-#line 1764 "awkgram.y"
+#line 1767 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
   case 188:
 /* Line 1792 of yacc.c  */
-#line 1768 "awkgram.y"
+#line 1771 "awkgram.y"
     { yyerrok; }
     break;
 
 
 /* Line 1792 of yacc.c  */
-#line 4086 "awkgram.c"
+#line 4089 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4302,7 +4305,7 @@ yyreturn:
 
 
 /* Line 2055 of yacc.c  */
-#line 1770 "awkgram.y"
+#line 1773 "awkgram.y"
 
 
 struct token {
@@ -4395,6 +4398,9 @@ static struct token tokentab[] = {
 {"match",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_match },
 {"mktime",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_mktime },
 {"next",       Op_K_next,       LEX_NEXT,      0,              0 },
+#ifdef NUMDEBUG
+{"next_down",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_default },
+#endif
 {"nextfile",   Op_K_nextfile, LEX_NEXTFILE,    0,              0 },
 {"or",         Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
 {"patsplit",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(2)|A(3)|A(4), 
do_patsplit },
@@ -7981,4 +7987,11 @@ one_line_close(int fd)
        return ret;
 }
 
-
+#ifdef NUMDEBUG
+static NODE *
+do_default(int nargs)
+{
+       fatal(_("not implemented"));
+       return NULL;
+}
+#endif
diff --git a/awkgram.y b/awkgram.y
index 6112414..65acd50 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -58,6 +58,9 @@ static int load_library(INSTRUCTION *file);
 static void next_sourcefile(void);
 static char *tokexpand(void);
 static bool is_deferred_variable(const char *name);
+#ifdef NUMDEBUG
+static NODE *do_default(int nargs);
+#endif
 
 #define instruction(t) bcalloc(t, 1, 0)
 
@@ -1859,6 +1862,9 @@ static struct token tokentab[] = {
 {"match",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_match },
 {"mktime",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_mktime },
 {"next",       Op_K_next,       LEX_NEXT,      0,              0 },
+#ifdef NUMDEBUG
+{"next_down",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_default },
+#endif
 {"nextfile",   Op_K_nextfile, LEX_NEXTFILE,    0,              0 },
 {"or",         Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
 {"patsplit",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(2)|A(3)|A(4), 
do_patsplit },
@@ -5445,4 +5451,11 @@ one_line_close(int fd)
        return ret;
 }
 
-
+#ifdef NUMDEBUG
+static NODE *
+do_default(int nargs)
+{
+       fatal(_("not implemented"));
+       return NULL;
+}
+#endif
diff --git a/configure b/configure
index e3b43ce..2896259 100755
--- a/configure
+++ b/configure
@@ -5557,7 +5557,7 @@ else
 $as_echo "no" >&6; }
        if test -f $srcdir/.dev
        then
-               CFLAGS="$CFLAGS -DLDBLTEST=1"   # DO NOT TURN OFF ASSERTIONS
+               CFLAGS="$CFLAGS -DNUMDEBUG"     # DO NOT TURN OFF ASSERTIONS
        else
                CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
        fi
diff --git a/configure.ac b/configure.ac
index 98e3c94..8d1e9b0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,7 +97,7 @@ else
        AC_MSG_RESULT([no])
        if test -f $srcdir/.dev
        then
-               CFLAGS="$CFLAGS -DLDBLTEST=1"   # DO NOT TURN OFF ASSERTIONS
+               CFLAGS="$CFLAGS -DNUMDEBUG"     # DO NOT TURN OFF ASSERTIONS
        else
                CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
        fi
diff --git a/format.c b/format.c
index ba95201..779faa9 100644
--- a/format.c
+++ b/format.c
@@ -723,7 +723,14 @@ out2:
 
                        s0 = s1;
                        break;
-
+#ifdef NUMDEBUG
+               case 'a':       /* hexadecimal */
+               case 'b':       /* MPFR binary format */
+                       if (numbr_hndlr ==  & awknum_hndlr || numbr_hndlr == & 
awkldbl_hndlr)
+                               ;       /* fall through -- make sure the stupid 
test will pass */
+                       else
+                               goto fmt1;
+#endif
                default:
                        if (isalpha(cs1)) {
                                if (do_lint)
diff --git a/long_double.c b/long_double.c
index c2a5c58..190efba 100644
--- a/long_double.c
+++ b/long_double.c
@@ -232,8 +232,11 @@ double_to_int(AWKLDBL x)
                x = -x;
        }
        if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0)) {
-               /* outside range, use floor() for C double */
+#ifdef HAVE_FLOORL
+               intval = floorl(x);
+#else
                intval = (AWKLDBL) Floor((double) x);
+#endif
        }
        return intval * ((AWKLDBL) sign);
 }
@@ -282,10 +285,14 @@ awkldbl_init(bltin_t **bltins)
 numbr_handler_t *
 get_ldbl_handler(char *arg)
 {
-#if defined(LDBLTEST) && LDBLTEST == 1
+#ifdef NUMDEBUG
        extern numbr_handler_t float128_hndlr;
+       extern numbr_handler_t float80_hndlr;
        if (arg != NULL && arg[0] == '1')
                return & float128_hndlr;
+       if (arg != NULL && arg[0] == '0')
+               return & float80_hndlr;
 #endif
+
        return  & awkldbl_hndlr;
 }
diff --git a/long_double.h b/long_double.h
index 203e04b..2b8e22d 100644
--- a/long_double.h
+++ b/long_double.h
@@ -349,7 +349,7 @@ awkldbl_update_var(NODE *var)
 }
 
 /*
- * awkldbl_set_vars --- update internal variables for assignment
+ * awkldbl_set_var --- update internal variables for assignment
  *     to a special variable.
  */
 
@@ -358,16 +358,21 @@ awkldbl_set_var(const NODE *var)
 {
        NODE *val = var->var_value;
        AWKLDBL d;
-
-       d = LDBL_VAL(val);
+       
        if (var == NR_node) {
+               d = LDBL_VAL(val);
                MNR = d / LONG_MAX;
                NR = d - ((AWKLDBL) MNR) * LONG_MAX;
        } else if (var == FNR_node) {
+               d = LDBL_VAL(val);
                MFNR = d / LONG_MAX;
                FNR = d - ((AWKLDBL) MFNR) * LONG_MAX;
+       } else {
+               /* PREC and ROUNMODE */
+               if (do_lint)
+                       lintwarn(_("setting `%s' has no effect"),
+                               var == PREC_node ? "PREC" : "ROUNDMODE");
        }
-       /* N.B: PREC and ROUNMODE -- not relevant */
 }
 
 /* awkldbl_increment_var --- increment NR or FNR */
@@ -391,7 +396,11 @@ awkldbl_increment_var(const NODE *var, long nr)
 static void
 awkldbl_init_vars()
 {
-       /* dummy function */
+       unref(PREC_node->var_value);
+        PREC_node->var_value = make_awknum(LDBL_FRAC_BITS);
+       PREC_node->var_value->flags |= NUMINT;
+        unref(ROUNDMODE_node->var_value);
+        ROUNDMODE_node->var_value = make_string("N", 1);
 }
 
 /*
@@ -1561,6 +1570,10 @@ out_of_range:
        case 'e':
        case 'f':
        case 'E':
+#ifdef NUMDEBUG
+       case 'a':       /* hexadecimal */
+       case 'b':       /* MPFR binary format */
+#endif
 fmt1:
                if (! spec->have_prec)
                        spec->prec = DEFAULT_G_PRECISION;
diff --git a/misc/ChangeLog b/misc/ChangeLog
new file mode 100644
index 0000000..4dd9c3f
--- /dev/null
+++ b/misc/ChangeLog
@@ -0,0 +1,11 @@
+2013-02-02         John Haque            <address@hidden>
+
+       * float80.c: New file. Provides 80-bit long-double support
+       without any math routines etc. for tests.
+       * floatcmp.awk: New file. Alternative to cmp for floating-point numbers.
+       * gawk_math.c (gawk_sqrtl, gawk_logl, gawk_expl, gawk_powl):
+       Replacement long double math functions.
+       * ldbl-tests/*.awk: Tests for the math functions.
+       * ldblin.awk: Generate input for the tests.
+       * splitlog2.awk: Split log2 into high and low parts.
+       * splitpi4.awk: Split pi/4 into 3 parts.
diff --git a/misc/Makefile b/misc/Makefile
index 8aef648..bafec60 100644
--- a/misc/Makefile
+++ b/misc/Makefile
@@ -12,7 +12,7 @@ ALL_CFLAGS = $(CFLAGS) -fPIC -DGAWK -DHAVE_CONFIG_H -c -I.. 
-I.
 
 all: $(LIBSTATIC)
 
-OBJS := float128.o
+OBJS := float128.o float80.o
 
 $(LIBSTATIC): $(OBJS)
        $(AR) rc $(LIBSTATIC) $(OBJS)
@@ -20,6 +20,8 @@ $(LIBSTATIC): $(OBJS)
 
 float128.o: float128.c ../awk.h ../long_double.h ./gawk_math.h ./gawk_math.c
 
+float80.o: float80.c ../awk.h ../long_double.h ./gawk_math.h ./gawk_math.c
+
 .c.o:
        $(CC) $(ALL_CFLAGS) $< -o $@
 
@@ -32,7 +34,17 @@ check:
 
 LDBL_TESTS = \
        ldblint64 \
-       ldblint128
+       ldblint128 \
+       sqrt64 \
+       sqrt113 \
+       log64 \
+       log113 \
+       exp64 \
+       exp113 \
+       pow64 \
+       pow113
+
+INFILE = ldbl-tests/data.in
 
 # An attempt to print something that can be grepped for in build logs
 pass-fail:
@@ -45,12 +57,64 @@ pass-fail:
 ldbl-tests: $(LDBL_TESTS)
        @$(MAKE) pass-fail TESTDIR=ldbl-tests
 
+
+$(INFILE):
+       @$(AWK) -M -vPREC=quad -f ldblin.awk > $(INFILE) 2>&1
+
 ldblint64:
        @echo $@
-       @$(AWK) -B -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
+       @$(AWK) -B0 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
        @-$(CMP) ldbl-tests/address@hidden ldbl-tests/_$@ && rm -f 
ldbl-tests/_$@
 
 ldblint128:
        @echo $@
        @$(AWK) -B1 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
        @-$(CMP) ldbl-tests/address@hidden ldbl-tests/_$@ && rm -f 
ldbl-tests/_$@
+
+sqrt64: $(INFILE)
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/sqrt.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/sqrt.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+sqrt113: $(INFILE)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/sqrt.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/sqrt.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+log64: $(INFILE)
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/log.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/log.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+log113: $(INFILE)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/log.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/log.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+exp64: $(INFILE)
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/exp.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/exp.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+exp113: $(INFILE)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/exp.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/exp.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -f floatcmp.awk ldbl-tests/_$@ ldbl-tests/address@hidden && 
rm ldbl-tests/_$@
+
+pow64: $(INFILE)
+       @echo $@
+       @$(AWK) -B0 -vDIG=17 -f ldbl-tests/pow.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=17 -vPREC=64 -f ldbl-tests/pow.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -vTOL=10 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
+
+pow113: $(INFILE)
+       @echo $@
+       @$(AWK) -B1 -vDIG=32 -f ldbl-tests/pow.awk > ldbl-tests/_$@ $(INFILE) 
2>&1
+       @$(AWK) -M -vDIG=32 -vPREC=113 -f ldbl-tests/pow.awk > 
ldbl-tests/address@hidden $(INFILE) 2>&1
+       @-$(AWK) -M -vTOL=10 -f floatcmp.awk ldbl-tests/_$@ 
ldbl-tests/address@hidden && rm ldbl-tests/_$@
diff --git a/misc/float128.c b/misc/float128.c
index 3f6ae12..ac66520 100644
--- a/misc/float128.c
+++ b/misc/float128.c
@@ -25,7 +25,7 @@
 
 #include "awk.h"
 
-#if defined(LDBLTEST) && LDBLTEST == 1
+#ifdef NUMDEBUG
 #include <math.h>
 #include "random.h"
 #if 0
@@ -135,6 +135,15 @@ static inline int isinf_awkldbl(AWKLDBL x) { return 
isnan(x - x); }
 #endif
 #define isinf isinf_awkldbl
 
+/*
+ * The relative error need to be less than 5 X 10^-k for rounding to
+ * k significant digits. Note tht FLT128_DIG is 33. If we add 2 extra
+ * digits for rounding error, the allowable maximum relative error
+ * is 5.0e-35.
+ */
+
+#define        REL_ERROR       LDC(5.0e-35)
+
 numbr_handler_t float128_hndlr;
 
 #define awkldbl_hndlr float128_hndlr
@@ -415,11 +424,28 @@ double_to_int(AWKLDBL x)
                sign = -1;
                x = -x;
        }
+
        if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0)) {
-               /* outside range */
-               /* FIXME -- use format_float_1 with "%.0Lf" (MPFR) */
+#if 0
                intval = (AWKLDBL) floorl((long double) x);
+#endif
+               const char *str1;
+               char str2[64];
+               mpfr_t ap_floatval, ap_intval;
+
+               str1 = float128_to_hex(x);
+               mpfr_init2(ap_floatval, 113);
+               mpfr_init2(ap_intval, 113);
+               mpfr_set_str(ap_floatval, str1, 16, MPFR_RNDN);
+               mpfr_trunc(ap_intval, ap_floatval);
+
+               /* get back a hexadecimal string representation */
+               (void) mpfr_snprintf(str2, 64, "%RNa", ap_intval);
+               mpfr_clear(ap_floatval);
+               mpfr_clear(ap_intval);
+               intval = hex_to_float128(str2);
        }
+
        return intval * ((AWKLDBL) sign);
 }
 
@@ -444,4 +470,4 @@ strtofloat128(const char *str, char **endptr)
        return hex_to_float128(hexstr); 
 }
 
-#endif /* LDBLTEST == 1 */
+#endif /* NUMDEBUG */
diff --git a/misc/float80.c b/misc/float80.c
new file mode 100644
index 0000000..8d2a808
--- /dev/null
+++ b/misc/float80.c
@@ -0,0 +1,138 @@
+/*
+ * float80.c - 80-bit float without any math routine.
+ */
+
+/* 
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+#include "awk.h"
+
+#ifdef NUMDEBUG
+
+#include <math.h>
+#include "random.h"
+#include "floatmagic.h"        /* definition of isnan */
+
+#include "format.h"
+
+#define AWKLDBL        long double
+#define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
+#define LDC(x)         x##L
+
+#ifndef FLT_RADIX
+#define FLT_RADIX 2
+#endif
+
+#define LDBL_FRAC_BITS LDBL_MANT_DIG
+#define        LDBL_INT_BITS   64
+
+#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float80")
+#define free_long_double(d)    efree(d)
+
+/* we want to format integers ourself */
+#define GAWK_FMT_INT 1
+
+#define gawk_int_t long
+#define gawk_uint_t unsigned long
+#ifdef SIZEOF_GAWK_INT
+#undef SIZEOF_GAWK_INT
+#undef GAWK_INT_MAX
+#undef GAWK_INT_MIN
+#undef GAWK_UINT_MAX
+#endif
+
+#define SIZEOF_GAWK_INT        4
+#define        GAWK_INT_MAX    LONG_MAX
+#define        GAWK_INT_MIN    LONG_MIN
+#define        GAWK_UINT_MAX   ULONG_MAX
+
+static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+static AWKLDBL gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk);
+static int format_float_1(char *str, size_t size, const char *format, int fw, 
int prec, AWKLDBL x);
+static int format_uint_1(char *str, size_t size, AWKLDBL x);
+static AWKLDBL double_to_int(AWKLDBL x);
+
+#define gawk_strtold strtold
+
+#define GAWK_INFINITY  HUGE_VALL
+#define GAWK_NAN       (LDC(0.0) / LDC(0.0))
+
+/*
+ * The relative error need to be less than 5 X 10^-k for rounding to
+ * k significant digits.
+ */
+
+#define        REL_ERROR       LDC(5.0e-20)
+
+numbr_handler_t float80_hndlr;
+
+#define awkldbl_hndlr float80_hndlr
+
+#include "misc/gawk_math.h"
+#include "long_double.h"
+#include "misc/gawk_math.c"
+
+/*
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ *     The value must be finite.       
+ */
+
+static int
+format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
+{
+       return snprintf(str, size, format, fw, prec, x);
+}
+
+/*
+ * format_uint_1 --- format a long double as an unsigned integer. The double 
value
+ *     must be finite and >= 0.
+ */
+
+static int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+       int ret;
+       if ((ret = format_uint_finite_p(str, size, x)) < 0)
+               return snprintf(str, size, "%.0Lf", x);
+       return ret;
+}
+
+/* double_to_int --- convert double to int, used in several places */
+
+static AWKLDBL
+double_to_int(AWKLDBL x)
+{
+       AWKLDBL intval;
+       int sign = 1;
+
+       if (isnan(x) || isinf(x) || x == LDC(0.0))
+               return x;
+       if (x < LDC(0.0)) {
+               sign = -1;
+               x = -x;
+       }
+       if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0)) {
+               /* outside range, use floorl() */
+               intval = (AWKLDBL) floorl((long double) x);
+       }
+       return intval * ((AWKLDBL) sign);
+}
+
+#endif /* NUMDEBUG */
diff --git a/misc/floatcmp.awk b/misc/floatcmp.awk
new file mode 100644
index 0000000..87c8ea2
--- /dev/null
+++ b/misc/floatcmp.awk
@@ -0,0 +1,57 @@
+# floatcmp.awk --- check floating-point numbers for differences in
+#       sig digs.
+
+BEGIN {
+       if (ARGC < 3) {
+               printf("Usage: gawk -M [-vTOL=1] -f floatcmp.awk file1 file2\n")
+               exit(1)
+       }
+
+       PREC = 200
+
+       # TOL -- allowable difference in significant digits 
+       if (! TOL)
+               TOL = 1
+
+       file1 = ARGV[1]
+       file2 = ARGV[2]
+       line = 0
+       while (1) {
+               ret1 = (getline v1 < file1) 
+               ret2 = (getline v2 < file2) 
+
+               if (ret1 > 0 && ret2 > 0) {
+                       line++
+                       if ((v1 "") == (v2 ""))
+                               continue;
+                       e1 = index(v1, "e")
+                       e2 = index(v2, "e")
+                       if (e1 > 0 && e2 > 0 &&         # exclude nans and 
infinities
+                                       substr(v1, e1) == substr(v2, e2)) { # 
same exponents
+                               sub(/e.*$/, "", v1)
+                               sub(/e.*$/, "", v2)
+                               sub(/\./, "", v1)
+                               sub(/\./, "", v2)
+
+                               # the following test requires arbitrary 
precision math.
+                               # PREC must be large enough to represent 
33-digit (or more)
+                               # integers precisely.
+                               diff = v2 - v1
+                               if (diff <= TOL && diff >= -TOL) 
+                                       continue
+                       }
+
+                       printf("%s %s differ: byte ?, line %d\n", file1, file2, 
line)
+                       exit(1)
+               }
+
+               if (ret1 == 0 && ret2 == 0)
+                       exit(0)
+               if (ret1 < 0 || ret2 < 0) {
+                       printf("cmp: %s: %s\n", ret1 < 0 ? file1 : file2, ERRNO)
+                       exit(1)
+               }
+               printf("EOF on %s\n", ret1 == 0 ? file1 : file2)
+               exit(1)
+       }
+}
diff --git a/misc/gawk_math.c b/misc/gawk_math.c
index 3e8e6ef..6981725 100644
--- a/misc/gawk_math.c
+++ b/misc/gawk_math.c
@@ -23,6 +23,26 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
+
+#define _0L    LDC(0.0)
+#define _1L    LDC(1.0)
+#define _2L    LDC(2.0)
+
+/*
+ * Constants for computation using long doubles with enough digits for the 
128-bit quad.
+ */
+
+#define GAWK_LOG2      LDC(0.693147180559945309417232121458176568)  /* log 2 
(base e) */
+#define        GAWK_LOG2_HIGH  LDC(0.6931471801362931728363037109375)       /* 
high 32 bits (exact representation) */
+#define GAWK_LOG2_LOW  LDC(4.236521365809284105206765680755001344e-10) /* 
variable precision low bits */
+
+#define GAWK_SQRT2     LDC(1.414213562373095048801688724209698079)     /* 
sqrt(2) */
+#define GAWK_SQRT1_2   LDC(0.707106781186547524400844362104849039)     /* 
1/sqrt(2) */
+
+
+static AWKLDBL taylor_exp(AWKLDBL x);
+static AWKLDBL gawk_frexpl(AWKLDBL x, int *exponent);
+
 static AWKLDBL
 gawk_sinl(AWKLDBL x)
 {
@@ -41,16 +61,133 @@ gawk_atan2l(AWKLDBL y, AWKLDBL x)
        return atan2( (double) y, (double) x);
 }
 
+/* gawk_logl --- Compute log(x) */
+
 static AWKLDBL
 gawk_logl(AWKLDBL x)
 {
-       return log( (double) x);
+       AWKLDBL frac, exponent;
+       AWKLDBL y, ypow2, ypow_odd, sum, term, err;
+       int iexp, sign, i;
+       
+       /*
+        *      ln(x) = 2 * arctanh(y)
+        *            = 2 * (y + y^3 / 3 + y^5 / 5 + ..) where y = (x - 1) / (x 
+ 1) 
+        */
+
+       if (isnan(x) || (isinf(x) && x > _0L))
+               return x;
+       if (x < _0L)            /* XXX: not setting errno = EDOM */
+               return GAWK_NAN;
+       if (x == _0L)           /* XXX: not setting errno = ERANGE */
+               return -GAWK_INFINITY;
+       
+       if (x == _1L)   /* special case */
+               return _0L;
+       if (x == _2L)   /* special case */
+               return GAWK_LOG2;
+
+       frac = gawk_frexpl(x, & iexp);  /* frac in [1, 2) */
+       exponent = (AWKLDBL) iexp;
+
+
+       /*
+        * arctanh(x) series has faster convergence when x is close to 1.
+        * Perform a range reduction so that 1 / sqrt(2) <= x <= sqrt(2).
+        */
+
+       if (frac > GAWK_SQRT2 || frac < GAWK_SQRT1_2) {
+               /*
+                * Instead of frac = frac / sqrt(2), compute y directly:
+                *      y = (f /sqrt(2) - 1) / (f / sqrt(2) + 1)
+                *        = (f - sqrt(2)) / (f + sqrt(2))
+                */
+
+               y = (frac - GAWK_SQRT2) / (frac + GAWK_SQRT2);
+               exponent += LDC(0.5);
+       } else
+               y = (frac - _1L) / (frac + _1L);
+
+       if (y == _0L)   /* tricky special case */
+               return exponent * GAWK_LOG2;
+
+       sign = 1;
+       if (y < _0L) {
+               sign = -1;
+               y = -y;
+       }
+
+       i = 1;
+       ypow2 = y * y;
+       ypow_odd = y;
+       sum = y;
+       do {
+               ypow_odd *= ypow2;
+               i += 2;
+               term = ypow_odd / ((AWKLDBL) i);
+               sum += term;
+               err = term / sum;
+       } while (err > REL_ERROR);
+       sum = LDC(2.0) * sum + exponent * GAWK_LOG2;
+
+       return (sign > 0 ? sum : -sum);
 }
 
+/* gawk_expl --- Compute exp(x) */
+
 static AWKLDBL
 gawk_expl(AWKLDBL x)
 {
-       return exp( (double) x);
+       AWKLDBL expval, k = _0L;
+       int sign;
+
+       if (isnan(x) || (isinf(x) && x > _0L))
+               return x;
+       if (isinf(x))   /* -inf */
+               return _0L;
+       if (x == _0L)
+               return _1L;
+       if (x >= (AWKLDBL) LDBL_MAX_EXP * GAWK_LOG2)    /* overflow */
+               return GAWK_INFINITY;
+       if (x <= (AWKLDBL) (LDBL_MIN_EXP - LDBL_MANT_DIG - 1) * GAWK_LOG2)      
/* underflow */
+               return _0L;
+
+       sign = 1;
+       if (x < _0L) {
+               sign = -1;
+               x = -x;
+       }
+
+       /* XXX: Outside overflow and underflow range k has at most 14 bits. */
+       if (x >= GAWK_LOG2)
+               k = double_to_int(x / GAWK_LOG2);  
+
+       if (k == _0L)
+               expval = taylor_exp(x);
+       else {
+               /* range reduction -- 0 < x < log(2) (0.693...) */
+
+               AWKLDBL y;
+
+               /* High precision calculation using limited precision float */
+               /*
+                * We need to calculate x - k * log2 with extra precision. If k 
is not a power
+                * of 2, it would require more than LDBL_MANT_DIG bits for the 
product
+                * to be precise to LDBL_MANT_DIG bits.
+                */
+
+               y = x - k * GAWK_LOG2_HIGH;
+               y -= k * GAWK_LOG2_LOW;
+
+#if 0
+               if (y > GAWK_LOG2 || y < _0L)   /* kludge */
+                       return sign > 0 ? GAWK_INFINITY : _0L;
+#endif
+               expval = taylor_exp(y);
+               expval *= pow2ld((unsigned int) k);
+       }
+
+       return sign < 0 ? (_1L / expval) : expval;
 }
 
 static AWKLDBL
@@ -59,14 +196,289 @@ gawk_fmodl(AWKLDBL x, AWKLDBL y)
        return fmod( (double) x, (double) y);
 }
 
+
+#define        GAWK_LDBL_INTEGER       1
+#define        GAWK_LDBL_EVEN_INTEGER  2
+#define        GAWK_LDBL_ODD_INTEGER   4
+
+/* gawk_is_integer__p --- is x an (even or odd) integer ? */
+
+static unsigned int
+gawk_is_integer__p(AWKLDBL x)
+{
+       AWKLDBL ival;
+       unsigned ret = 0;
+
+       if (isnan(x) || isinf(x))
+               return (unsigned int) false;
+       if (x < _0L)
+               x = -x;
+       if (x < _1L)
+               return (unsigned int) false;
+       if ((ival = double_to_int(x)) != x)
+               return (unsigned int) false;
+       ret = GAWK_LDBL_INTEGER;
+       if (ival >= pow2ld(LDBL_MANT_DIG))
+               ret |= GAWK_LDBL_EVEN_INTEGER;
+       else {
+               ival /= _2L;
+               if (ival == double_to_int(ival))
+                       ret |= GAWK_LDBL_EVEN_INTEGER;
+               else
+                       ret |= GAWK_LDBL_ODD_INTEGER;
+       }
+       return ret;
+}
+
+#define gawk_is_integer(x)     ((gawk_is_integer__p(x) & GAWK_LDBL_INTEGER) != 
0)
+#define gawk_is_odd_integer(x) ((gawk_is_integer__p(x) & 
GAWK_LDBL_ODD_INTEGER) != 0)
+
+/* gawk_powl --- Compute x^y */
+
 static AWKLDBL
 gawk_powl(AWKLDBL x, AWKLDBL y)
 {
-       return pow( (double) x, (double) y);
+       AWKLDBL expval;
+       int sign;
+
+       if ((! isnan(x) && x == _1L) || (! isnan(y) && y == _0L))
+               return _1L;
+       if (isnan(x) || isnan(y))
+               return GAWK_NAN;
+
+       /* Neither x or y is NaN and y isn't 0 */
+       if (isinf(x)) {
+               if (x > _0L)
+                       return y < _0L ? _0L : GAWK_INFINITY;
+
+               /* x == -inf */
+               if (y < _0L)
+                       return (! isinf(y) && gawk_is_odd_integer(y)) ? -_0L : 
_0L;
+               if (y > _0L)
+                       return (! isinf(y) && gawk_is_odd_integer(y)) ? 
-GAWK_INFINITY : GAWK_INFINITY;
+
+       } else {
+               /* x isn't infinity */
+               if (x < _0L && ! isinf(y) && ! gawk_is_integer(y)) 
+                       return GAWK_NAN;
+
+               if (isinf(y)) {
+                       if (x == -_1L)
+                               return _1L;
+                       /* x == +1 handled above */
+                       if (x > -_1L && x < _1L)
+                               return (y == -GAWK_INFINITY) ? GAWK_INFINITY : 
_0L;
+                       /* abs(x) > 1 */
+                       return (y < _0L) ? _0L : GAWK_INFINITY;
+               }
+
+               /* y isn't infinity */
+               if (x == _0L && y > _0L)
+                       return gawk_is_odd_integer(y) ? x : _0L;
+
+               if (x == _0L && y < _0L) {
+                       if (gawk_is_odd_integer(y))     /* HUGE_VALL with same 
sign as x */
+                               return (AWKLDBL) pow((double) x, (double) y);
+                       /* + HUGE_VALL */
+                       return GAWK_INFINITY;
+               }
+       }
+
+       sign = 1;
+       if (y < _0L) {
+               sign = -1;
+               y = -y;
+       }
+
+       if (x < _0L) {
+               AWKLDBL result, d;
+
+               /* y is integer and != 0 */
+
+               result = x;
+               for (d = _1L; d < y; d += _1L)
+                       result *= x;
+               return sign > 0 ? result : _1L / result;
+       }
+
+       /* x^y =  exp(y * log(x)), x > 0 */
+
+       if (y <= (AWKLDBL) GAWK_UINT_MAX) {
+               AWKLDBL frac;
+               gawk_uint_t intpart;
+
+               /*
+                * divide y into integral and fractional parts, use "repeated 
squaring"
+                * to compute x^integer and exp(fraction * log(x)) for the 
fractional power.
+                */
+
+               intpart = (gawk_uint_t) double_to_int(y);
+               frac = y - (AWKLDBL) intpart;
+               expval = _1L;
+               if (intpart > 0) {
+                       AWKLDBL z = x;
+                       while (intpart > 1) {
+                               if ((intpart % 2) == 1)
+                                       expval *= z;
+                               z *= z;
+                               intpart /= 2;
+                       }
+                       expval *= z;
+               }
+               expval *= gawk_expl(frac * gawk_logl(x));
+       } else
+               expval = gawk_expl(y * gawk_logl(x));   /* XXX: likely infinity 
or zero */ 
+
+       return sign > 0 ? expval : (_1L / expval);
 }
 
+/* gawk_sqrtl --- Compute sqrt(x) using Newton's method */
+
 static AWKLDBL
 gawk_sqrtl(AWKLDBL x)
 {
-       return sqrt( (double) x);
+       AWKLDBL yn;
+
+       if (isnan(x) || (isinf(x) && x > _0L))  /* NaN or +inf */
+               return x;
+       if (isinf(x) || x < _0L)        /* -inf or negative */
+               return GAWK_NAN;        /* XXX: not setting errno = EDOM */
+       if (x == _0L)
+               return x;       /* return +0 or -0 */
+
+       if (x <= DBL_MAX && x >= DBL_MIN) {
+               /* use double-precision sqrt value as the initial guess. */
+
+               yn = sqrt( (double) x);
+       } else {
+               /*
+                * outside of the range of C double, we have to compute
+                * the initial guess differently.
+                */
+
+               AWKLDBL frac;
+               int iexp;
+
+               frac = gawk_frexpl(x, & iexp);  /* frac is in [1, 2) */
+               if ((iexp % 2) != 0) {
+                       /* force the exponent to be an even integer */ 
+                       frac /= _2L;
+                       iexp++;
+               }
+               yn = sqrt( (double) frac);
+               iexp /= 2;
+               if (iexp >= 0)
+                       yn *= pow2ld(iexp);
+               else
+                       yn /= pow2ld(-iexp);
+       }
+
+       /* XXX: Exactly 3 iterations. 2 maybe enough ? */
+       yn = (yn + x / yn) / _2L;
+       yn = (yn + x / yn) / _2L;
+       yn = (yn + x / yn) / _2L;
+
+       return yn;
+}
+
+
+/*
+ * gawk_frexpl --- split the number x into a normalized fraction and an 
exponent.
+ *     The fraction is in the range [1, 2) (and NOT [0.5, 1)).
+ */
+
+static AWKLDBL
+gawk_frexpl(AWKLDBL x, int *exponent)
+{
+       AWKLDBL y;
+       unsigned low, high, mid;
+
+       /* (isnormal(x) && x > 0) is assumed to be true */
+
+       assert(exponent != NULL);
+       *exponent = 0;
+
+       low = 0;
+       if (x > _2L) {
+               high = LDBL_MAX_EXP - 1;        /* XXX: should be 4 * 
LDBL_MAX_EXP - 1 if FLT_RADIX = 16 ? */
+               while (low <= high) {
+                       mid = (low + high) / 2;
+                       y = x / pow2ld(mid);
+                       if (y > _2L)
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
+               }
+               x /= pow2ld(low);
+               *exponent = low;
+       } else if (x < _1L) {
+               high = LDBL_MAX_EXP - 1;        /* could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP */
+               while (low <= high) {
+                       mid = (low + high) / 2;
+                       y =  x * pow2ld(mid);
+                       if (y < _1L)
+                               low = mid + 1;
+                       else
+                               high = mid - 1;
+               }
+               x *= pow2ld(low);
+               *exponent = -low;
+       }
+       if (x == _2L) {
+               x = _1L;
+               ++*exponent;
+       }
+       return x;
+}
+
+/* taylor_exp --- Compute exp(x) using Taylor series and modified squaring 
reduction */
+
+static AWKLDBL
+taylor_exp(AWKLDBL x)
+{
+       AWKLDBL xpow, expval;
+       AWKLDBL err, term, y, fact;
+       unsigned int i;
+       int k;
+
+       /*
+        * Method: Taylor series and squaring for large x.
+        *      exp(x) = 1 + x + x ^ 2 / 2! + x ^ 3 / 3! + ..., x < 1 
+        *
+        *      A modification of the squaring reduction allows to 
significantly reduce the
+        *      round-off error [*]. Instead of exp(x) = exp(x/2)^2, we use the 
identity
+        *              exp(x) - 1 = (exp(x/2) - 1)*(exp(x/2) + 1)
+        *      and reduce exp(x) - 1 directly to exp(x/2) - 1. If y = exp(x/2) 
- 1, then
+        *              exp(x) - 1 = 2*y + y^2.
+        *
+        *      [*] R. P. Brent, A Fortran Multiple-Precision Arithmetic 
Package,
+        *      ACM Transactions on Mathematical Software 4, no. 1 (1978), p. 
57. 
+        */
+
+       if (x == _0L)
+               return _1L;
+
+       k = 1;
+       while (x > 0.001) {
+               /* XXX: For x <= 0.001, max(k) = 10, and max # of terms 6 
(80-bit) / 10 (128-bit) */
+               
+               x /= _2L; 
+               k++;
+       }
+
+       y = xpow = x;
+       fact = _1L;
+       i = 1;
+       do {
+               fact *= (AWKLDBL) ++i;
+               xpow *= x;
+               term = xpow / fact;
+               y += term;
+               err = term / y;
+       } while (err > REL_ERROR);
+
+       /* squaring reduction */
+       while (--k > 0)
+               y = 2 * y + y * y;
+       return y + _1L;
 }
diff --git a/misc/ldbl-tests/exp.awk b/misc/ldbl-tests/exp.awk
new file mode 100644
index 0000000..f74a1e8
--- /dev/null
+++ b/misc/ldbl-tests/exp.awk
@@ -0,0 +1,14 @@
+{
+       y = exp($1);
+
+       # don't have -M IEEE emulation for 64-bit binary
+       # need to replace huge values with infinities.
+       # "quad" and 64-bit long double has same exponent range.
+       # This does not effect the binary formats B0, B1
+
+       save_PREC = PREC
+       PREC = "quad"
+       y += 0
+       printf("%*.*e\n", 0, DIG, y)
+       PREC = save_PREC
+}
diff --git a/misc/ldbl-tests/log.awk b/misc/ldbl-tests/log.awk
new file mode 100644
index 0000000..6035be1
--- /dev/null
+++ b/misc/ldbl-tests/log.awk
@@ -0,0 +1,3 @@
+{
+       printf("%*.*e\n", 0, DIG, log($1))
+}
diff --git a/misc/ldbl-tests/pow.awk b/misc/ldbl-tests/pow.awk
new file mode 100644
index 0000000..0e75b56
--- /dev/null
+++ b/misc/ldbl-tests/pow.awk
@@ -0,0 +1,29 @@
+BEGIN {
+       x1 = 0.1
+       x2 = 131.4321211
+       x3 = 1.1234567e100
+}
+{
+       y1 = x1^$1
+       y2 = x2^$1
+       y3 = x3^$1
+       # don't have -M IEEE emulation for 64-bit binary
+       # need to replace huge values with infinities.
+       # "quad" and 64-bit long double has same exponent range.
+       # This does not effect the binary formats B0, B1
+
+       save_PREC = PREC
+       PREC = "quad"
+       y1 += 0; y2 += 0; y3 += 0
+
+       if (y1 <= 1.0e750) {
+               printf("%*.*e\n", 0, DIG, y1)
+       }
+       if (y2 <= 1.0e750) {
+               printf("%*.*e\n", 0, DIG, y2)
+       }
+       if (y3 <= 1.0e750) {
+               printf("%*.*e\n", 0, DIG, y3)
+       }
+       PREC = save_PREC
+}
diff --git a/misc/ldbl-tests/sqrt.awk b/misc/ldbl-tests/sqrt.awk
new file mode 100644
index 0000000..68cd48b
--- /dev/null
+++ b/misc/ldbl-tests/sqrt.awk
@@ -0,0 +1,3 @@
+{
+       printf("%*.*e\n", 0, DIG, sqrt($1))
+}
diff --git a/misc/ldblin.awk b/misc/ldblin.awk
new file mode 100644
index 0000000..be6b832
--- /dev/null
+++ b/misc/ldblin.awk
@@ -0,0 +1,26 @@
+# generate input data for tests
+# gawk -M -vPREC=quad -f .. 
+
+BEGIN {
+       # 16000 almost LDBL_MAX_EXP or -LDBL_MIN_EXP
+
+       for (i = -16000; i < -1000; i += 255.5)
+               printf("%0.17e\n", 1.0*2^i)
+       for (i = -1000; i < -100; i += 25.5)
+               printf("%0.17e\n", 1.0*2^i)
+       for (i = -100; i < -10; i += 2.5)
+               printf("%0.17e\n", 1.0*2^i)
+       for (i = -10; i < -1; i += 0.75)
+               printf("%0.17e\n", 1.0*2^i)
+       for (i = -1; i < 2.0; i += 0.1)
+               printf("%0.17e\n", 2^i)
+       for (i = 1; i < 10; i += 0.75)
+               printf("%0.17e\n", 1.0 * 2^i)
+       for (i = 10; i < 100; i += 2.5)
+               printf("%0.17e\n", 1.0 * 2^i)
+       for (i = 100; i < 1000; i += 25.5)
+               printf("%0.17e\n", 1.0 * 2^i)
+       for (i = 1000; i < 16000; i += 255.5)
+               printf("%0.17e\n", 1.0 * 2^i)
+}
+
diff --git a/misc/splitlog2.awk b/misc/splitlog2.awk
new file mode 100644
index 0000000..16db883
--- /dev/null
+++ b/misc/splitlog2.awk
@@ -0,0 +1,49 @@
+# Split log2 into two parts -- a high part which is exactly representable
+#      with less than the float-precision and a variable precision low part.
+#              log2 = log2_high + log2_low
+#
+#      Extra precision calculation with limited precision float:
+#              r = x - q * log2,       q is an integer
+#                = (x - q * log2_high) - q * log2_low
+#      if the high part has M bits, the integer q should have less than
+#      (float_prec - M) non-zero leading bits.
+
+# Usage: $ gawk -M -f splitlog2.awk
+
+BEGIN {
+       PREC = 300      # at least 64 + 113 (+ few more) 
+
+       y = log(2)
+       printf("log2       = %0.36f\n", y)
+
+       PREC = 32
+       log2_high = next_down(y)        # exactly representable with 32 bits
+
+       PREC = 300
+       log2_low = (y - log2_high)
+
+       printf("log2_high  = %0.36f\n", log2_high)
+       printf("log2_low   = %0.36e\n", log2_low)
+
+       # test case with 128-bit long double
+       print "--- test calculation: r = x - q * log2 ---"
+       PREC = 113
+       ROUND_MODE = "N"
+
+       log2_high += 0  # float precision 
+       log2_low += 0   # Ditto
+
+       x = "501.0"
+       x += 0
+       q = int(x / log(2.0))
+
+       # calculate with float precision
+       printf("regular math   : %0.32e\n", x - q * log(2)) 
+
+       # calculate with more precision
+       printf("high-prec math : %0.32e\n", (x - q * log2_high) - q * log2_low)
+
+       # extra precision with ap float
+       PREC = 300
+       printf("ap math        : %0.32e\n", x - q * log(2))
+}
diff --git a/misc/splitpi4.awk b/misc/splitpi4.awk
new file mode 100644
index 0000000..75b001a
--- /dev/null
+++ b/misc/splitpi4.awk
@@ -0,0 +1,116 @@
+# Split pi/4 into two parts
+#      pi_4 = pi_4_high (exact 32-bit)+ pi_4_med (exact 32-bit) +  pi_4_low
+#
+
+# $ gawk -M -f splitpi4.awk
+
+BEGIN {
+       PREC = 500 
+
+       y = atan2(1, 0) / 2;    # N.B.: integer constants not floats e.g 1.0
+
+       PREC = 32
+       pi_4_high = next_down(y)        # exactly representable with 32 bits
+
+       PREC = 500
+       y1 = (y - pi_4_high) / 2^32
+       PREC = 32
+       pi_4_med = next_down(y1)
+
+       PREC = 500
+       pi_4_low = (y1 - pi_4_med) / 2^32
+
+       pi_4_med *= 2^32
+       pi_4_low *= 2^64
+
+       pi = pi_4_high + pi_4_med + pi_4_low
+
+       printf("pi_4    = %0.112b\n", y)
+       printf("pi_4(3) = %0.112b\n", pi)
+       printf("pi_4_h  = %0.31b\n", pi_4_high)
+       printf("pi_4_m  = %0.31b\n", pi_4_med)
+       printf("pi_4_l  = %0.112b\n", pi_4_low)
+
+       printf("pi_4_high  = %0.36f\n", pi_4_high)
+       printf("pi_4_med   = %0.36e\n", pi_4_med)
+       printf("pi_4_low   = %0.36e\n", pi_4_low)
+}
+
+BEGIN {
+       # test
+
+       z[0] = "501"
+       z[1] = "1.11121e+04"
+       z[2] = "1.2172831e+07"
+       z[3] = "1.13131311113e+09"
+       z[4] = "3.373e+09"
+       z[5] = "8.0e+09"
+       z[6] = "9.1314152e21"
+
+       print "--- test (PREC=113): r = x - q * (pi/4) ---"
+       PREC = 113
+       ROUND_MODE = "N"
+       pi_h = pi_4_high + 0.0
+       pi_m = pi_4_med + 0.0
+       pi_l = pi_4_low + 0.0
+
+       for (ii = 0; ii < length(z); ii++) {
+               PREC = 113
+               x = z[ii];
+               x += 0.0
+               pi_4 = atan2(1, 0) / 2
+               q = int(x / pi_4)
+
+               printf("x = %0.10e, q = %d\n", x, q)
+
+               # calculate with float precision
+               printf("regular math   : %0.32e\n", x - q * pi_4) 
+
+               # calculate with more precision
+               r = x - q * pi_h
+               r -= q * pi_m
+               r -= q * pi_l
+               printf("high-prec math : %0.32e\n", r)
+
+               # extra precision with ap float
+               PREC = 500
+               pi_4 = atan2(1, 0) / 2 
+               r = x - q * pi_4
+               printf("ap math        : %0.32e\n", r)
+       }
+}
+
+BEGIN {
+       print "--- test (PREC=64): r = x - q * (pi/4) ---"
+       PREC = 64
+       ROUND_MODE = "N"
+       pi_h = pi_4_high + 0
+       pi_m = pi_4_med + 0
+       pi_l = pi_4_low + 0
+
+       for (ii = 0; ii < length(z); ii++) {
+               PREC = 64
+               x = z[ii];
+               x += 0.0
+
+               pi_4 = atan2(1, 0) / 2
+               q = int(x / pi_4)
+               printf("x = %0.10e, q = %d\n", x, q)
+
+               r = x - q * pi_4
+               # calculate with float precision
+               printf("regular math   : %0.17e\n", r) 
+
+               # calculate with more precision
+               r = x - q * pi_h
+               r -= q * pi_m
+               r -= q * pi_l
+               printf("high-prec math : %0.17e\n", r)
+
+               # extra precision with ap float
+               PREC = 500
+               pi_4 = atan2(1, 0) / 2 
+               r = x - q * pi_4
+               printf("ap math        : %0.17e\n", r)
+       }
+}
diff --git a/mpfr.c b/mpfr.c
index adcd0d8..faa7f04 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -96,6 +96,9 @@ static NODE *do_mpfp_sqrt(int);
 static NODE *do_mpfp_srand(int);
 static NODE *do_mpfp_strtonum(int);
 static NODE *do_mpfp_xor(int);
+#ifdef NUMDEBUG
+static NODE *do_mpfp_next_down(int);
+#endif
 
 /* internal functions */
 static NODE *mpfp_make_node(unsigned int type);
@@ -207,12 +210,15 @@ mpfp_init(bltin_t **numbr_bltins)
                { "srand",      do_mpfp_srand },
                { "strtonum",   do_mpfp_strtonum },
                { "xor",        do_mpfp_xor },
+#ifdef NUMDEBUG
+               { "next_down",  do_mpfp_next_down },
+#endif
                { NULL, NULL },
        };
        const char *rndmode = DEFAULT_ROUNDMODE;
 
        mpfr_set_default_prec(DEFAULT_PREC);
-       ROUND_MODE = mpfp_get_rounding_mode(rndmode[0]); 
+       ROUND_MODE = mpfp_get_rounding_mode(rndmode[0]);
        mpfr_set_default_rounding_mode(ROUND_MODE);
 
        mpz_init(MNR);
@@ -1503,6 +1509,44 @@ do_mpfp_srand(int nargs)
 }
 
 
+#ifdef NUMDEBUG
+
+/* do_mpfp_next_down --- return the greatest representable float that’s 
strictly less than x. */
+
+static NODE *
+do_mpfp_next_down(int nargs)
+{
+       NODE *tmp, *r;
+
+       tmp = POP_SCALAR();
+       tmp = force_number(tmp);
+
+       if (is_mpfp_integer(tmp)) {
+               /* XXX: have no use. */  
+               fatal(_("next_down: not implemented for an integer"));
+       } else {
+               if (mpfr_nan_p(MPFR_T(tmp->qnumbr)))    /* NaN */
+                       return tmp;
+
+               /*
+                * apply current precision (which can be different from the 
precision of the
+                * input number if changed with an assignment to PREC prior to 
the call),
+                * and round toward minus infinity.
+                */
+               r = mpfp_float();
+               (void) mpfr_set(r->qnumbr, MPFR_T(tmp->qnumbr), MPFR_RNDD);
+
+               /* representable float that’s strictly less than x */
+               mpfr_nextbelow(MPFR_T(r->qnumbr));
+       }
+
+       DEREF(tmp);
+       return r;
+}
+
+#endif
+
+
 /* mpfp_add --- add arbitrary-precision numbers */ 
 
 static NODE *
@@ -1925,6 +1969,10 @@ out_of_range:
        case 'e':
        case 'f':
        case 'E':
+#ifdef NUMDEBUG
+       case 'a':       /* hexadecimal */
+       case 'b':       /* MPFR binary format */
+#endif
                if (is_mpfp_float(arg)) {
                        mf = arg->qnumbr;
                        mpfmt_spec = MP_FLOAT;

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=5f5c0c02c84012a4cb7f418ddb0ca2ec1b5db747

commit 5f5c0c02c84012a4cb7f418ddb0ca2ec1b5db747
Merge: a37db77 21e6675
Author: John Haque <address@hidden>
Date:   Thu Jan 31 13:28:43 2013 -0600

    Merge branch 'num-handler' into long-double


http://git.sv.gnu.org/cgit/gawk.git/commit/?id=21e6675c65899a92c85c59da0711ec5375162dc7

commit 21e6675c65899a92c85c59da0711ec5375162dc7
Author: John Haque <address@hidden>
Date:   Thu Jan 31 13:27:59 2013 -0600

    Set PREC and ROUNDMOE for double.

diff --git a/double.c b/double.c
index c75b07c..d777cfc 100644
--- a/double.c
+++ b/double.c
@@ -331,8 +331,12 @@ awknum_set_var(const NODE *var)
                NR = val->numbr;
        else if (var == FNR_node)
                FNR = val->numbr;
-
-       /* N.B: PREC and ROUNMODE -- not relevant */
+       else {
+               /* PREC and ROUNMODE */
+               if (do_lint)
+                       lintwarn(_("setting `%s' has no effect"),
+                               var == PREC_node ? "PREC" : "ROUNDMODE");
+       }
 }
 
 /* awknum_increment_var --- increment NR or FNR */
@@ -349,7 +353,11 @@ awknum_increment_var(const NODE *var ATTRIBUTE_UNUSED, 
long nr)
 static void
 awknum_init_vars()
 {
-       /* dummy function */
+       unref(PREC_node->var_value);
+        PREC_node->var_value = make_awknum(DBL_MANT_DIG);
+       PREC_node->var_value->flags |= NUMINT;
+        unref(ROUNDMODE_node->var_value);
+        ROUNDMODE_node->var_value = make_string("N", 1);
 }
 
 /* make_awknum --- allocate a node with defined number */
diff --git a/test/dumpvars.ok b/test/dumpvars.ok
index 3670b7b..73d3d30 100644
--- a/test/dumpvars.ok
+++ b/test/dumpvars.ok
@@ -16,9 +16,9 @@ NR: 3
 OFMT: "%.6g"
 OFS: " "
 ORS: "\n"
-PREC: 0
+PREC: 53
 RLENGTH: 0
-ROUNDMODE: ""
+ROUNDMODE: "N"
 RS: "\n"
 RSTART: 0
 RT: "\n"
diff --git a/test/symtab1.ok b/test/symtab1.ok
index dc6a1b7..04709e0 100644
--- a/test/symtab1.ok
+++ b/test/symtab1.ok
@@ -1,6 +1,6 @@
 ARGV[0] = gawk
 SYMTAB["i"] = "i"
-SYMTAB["ROUNDMODE"] = ""
+SYMTAB["ROUNDMODE"] = "N"
 SYMTAB["ORS"] = "
 "
 SYMTAB["OFS"] = " "
@@ -18,7 +18,7 @@ SYMTAB["ARGC"] = "1"
 SYMTAB["FIELDWIDTHS"] = ""
 SYMTAB["CONVFMT"] = "%.6g"
 SYMTAB["SUBSEP"] = ""
-SYMTAB["PREC"] = "0"
+SYMTAB["PREC"] = "53"
 SYMTAB["RS"] = "
 "
 SYMTAB["FPAT"] = "[^[:space:]]+"
diff --git a/test/symtab6.ok b/test/symtab6.ok
index a1fcfb9..91f27e7 100644
--- a/test/symtab6.ok
+++ b/test/symtab6.ok
@@ -16,9 +16,9 @@ NR: 0
 OFMT: "%.6g"
 OFS: " "
 ORS: "\n"
-PREC: 0
+PREC: 53
 RLENGTH: 0
-ROUNDMODE: ""
+ROUNDMODE: "N"
 RS: "\n"
 RSTART: 0
 RT: ""
diff --git a/test/symtab8.ok b/test/symtab8.ok
index f0adb1a..8560c75 100644
--- a/test/symtab8.ok
+++ b/test/symtab8.ok
@@ -17,9 +17,9 @@ NR: 1
 OFMT: "%.6g"
 OFS: " "
 ORS: "\n"
-PREC: 0
+PREC: 53
 RLENGTH: 0
-ROUNDMODE: ""
+ROUNDMODE: "N"
 RS: "\n"
 RSTART: 0
 RT: "\n"

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=a37db774455e596fa9c964a2e0f0fe73af47e221

commit a37db774455e596fa9c964a2e0f0fe73af47e221
Author: John Haque <address@hidden>
Date:   Sun Jan 27 04:53:25 2013 -0600

    Formatting and strtold emulation for __float128, organize misc dir.

diff --git a/ChangeLog b/ChangeLog
index d0daef3..4caad77 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-01-27         John Haque      <address@hidden>
+
+       * long_double.c (GAWK_FORMAT_INT): New define.
+       (format_float_1, format_uint_1, double_to_int): Move definitions here
+       from long_double.h.
+       * long_double.h (format_float_1, format_uint_1, double_to_int): Adjust.
+
 2013-01-23         John Haque      <address@hidden>
 
        * long_double.c (format_uint_1): New inline routines to format integers.
diff --git a/Makefile.am b/Makefile.am
index 00d1b2c..5aec821 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -68,7 +68,10 @@ distcleancheck_listfiles = \
 # The order to do things in.
 # Build explicitly in "." in order to build gawk first, so
 # that `make check' without a prior `make' works.
-SUBDIRS = \
+
+EXTRADIRS = misc
+
+BASEDIRS = \
        . \
        awklib \
        doc \
@@ -76,6 +79,8 @@ SUBDIRS = \
        extension \
        test
 
+SUBDIRS = $(EXTRADIRS) $(BASEDIRS)
+
 # what to make and install
 bin_PROGRAMS = gawk
 include_HEADERS = gawkapi.h
@@ -132,10 +137,12 @@ base_sources = \
        version.c \
        xalloc.h
 
-gawk_SOURCES = $(base_sources) float128.c
+gawk_SOURCES = $(base_sources)
+
+EXTRA_LIBS = misc/libmisc.a
 
 # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
-LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@
+LDADD = $(EXTRA_LIBS) $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ 
@LIBMPFR@
 
 # Directory for gawk's data files. Automake supplies datadir.
 pkgdatadir = $(datadir)/awk
diff --git a/Makefile.in b/Makefile.in
index 243af73..007f0fa 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -115,12 +115,12 @@ am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) 
builtin.$(OBJEXT) \
        random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
        replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
        version.$(OBJEXT)
-am_gawk_OBJECTS = $(am__objects_1) float128.$(OBJEXT)
+am_gawk_OBJECTS = $(am__objects_1)
 gawk_OBJECTS = $(am_gawk_OBJECTS)
 gawk_LDADD = $(LDADD)
 am__DEPENDENCIES_1 =
-gawk_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
-       $(am__DEPENDENCIES_1)
+gawk_DEPENDENCIES = $(EXTRA_LIBS) $(am__DEPENDENCIES_1) \
+       $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
 DEFAULT_INCLUDES = address@hidden@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
@@ -403,7 +403,8 @@ distcleancheck_listfiles = \
 # The order to do things in.
 # Build explicitly in "." in order to build gawk first, so
 # that `make check' without a prior `make' works.
-SUBDIRS = \
+EXTRADIRS = misc
+BASEDIRS = \
        . \
        awklib \
        doc \
@@ -411,6 +412,7 @@ SUBDIRS = \
        extension \
        test
 
+SUBDIRS = $(EXTRADIRS) $(BASEDIRS)
 include_HEADERS = gawkapi.h
 
 # sources for both gawk and dgawk
@@ -465,10 +467,11 @@ base_sources = \
        version.c \
        xalloc.h
 
-gawk_SOURCES = $(base_sources) float128.c
+gawk_SOURCES = $(base_sources)
+EXTRA_LIBS = misc/libmisc.a
 
 # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
-LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@
+LDADD = $(EXTRA_LIBS) $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ 
@LIBMPFR@
 
 # stuff for compiling gawk/pgawk
 DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"'
@@ -598,7 +601,6 @@ 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/configure b/configure
index 3d80b0d..e3b43ce 100755
--- a/configure
+++ b/configure
@@ -5558,8 +5558,6 @@ $as_echo "no" >&6; }
        if test -f $srcdir/.dev
        then
                CFLAGS="$CFLAGS -DLDBLTEST=1"   # DO NOT TURN OFF ASSERTIONS
-#              cp $srcdir/misc/float128.c $srcdir/
-#              sed -i 's/^gawk_SOURCES = $(base_sources)$/& float128.c/' 
$srcdir/Makefile.am
        else
                CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
        fi
diff --git a/configure.ac b/configure.ac
index 2a13506..98e3c94 100644
--- a/configure.ac
+++ b/configure.ac
@@ -98,8 +98,6 @@ else
        if test -f $srcdir/.dev
        then
                CFLAGS="$CFLAGS -DLDBLTEST=1"   # DO NOT TURN OFF ASSERTIONS
-#              cp $srcdir/misc/float128.c $srcdir/
-#              sed -i 's/^gawk_SOURCES = $(base_sources)$/& float128.c/' 
$srcdir/Makefile.am
        else
                CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
        fi
diff --git a/float128.c b/float128.c
deleted file mode 100644
index 15582b8..0000000
--- a/float128.c
+++ /dev/null
@@ -1,128 +0,0 @@
-#include "awk.h"
-
-#if defined(LDBLTEST) && LDBLTEST == 1
-#include <math.h>
-#include "random.h"
-#if 0
-#include "floatmagic.h"        /* definition of isnan -- XXX: only for float 
or double or long double */
-#endif
-
-#include "format.h"
-
-/* XXX: No libquadmath, and don't want or need it anyway. */
-
-/*
- * Macros copied from quadmath.h
- *     https://github.com/mirrors/gcc/blob/master/libquadmath/quadmath.h
- */
-
-#define FLT128_MAX 1.18973149535723176508575932662800702e4932Q
-#define FLT128_MIN 3.36210314311209350626267781732175260e-4932Q
-#define FLT128_EPSILON 1.92592994438723585305597794258492732e-34Q
-#define FLT128_DENORM_MIN 6.475175119438025110924438958227646552e-4966Q
-#define FLT128_MANT_DIG 113
-#define FLT128_MIN_EXP (-16381)
-#define FLT128_MAX_EXP 16384
-#define FLT128_DIG 33
-#define FLT128_MIN_10_EXP (-4931)
-#define FLT128_MAX_10_EXP 4932
-
-/* #define HUGE_VALQ __builtin_huge_valq() */
-/* The following alternative is valid, but brings the warning:
-   (floating constant exceeds range of ‘__float128’)  */
-#define HUGE_VALQ (__extension__ 0x1.0p32767Q)
-
-/* end of Macros from quadmath.h */
-
-
-#define LDBL_FRAC_BITS FLT128_MANT_DIG
-#define        LDBL_INT_BITS   128
-
-#define AWKLDBL        __float128
-#define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
-#define LDC(x)         x##Q
-
-#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float128")
-#define free_long_double(d)    efree(d)
-
-static int format_float_1(char *str, size_t size, const char *format, int fw, 
int prec, AWKLDBL x);
-static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
-
-/*
- * format_uint_1 --- format a AWKLDBL as an unsigned integer. The double value
- *     must be finite and >= 0.
- */
-
-static inline int
-format_uint_1(char *str, size_t size, AWKLDBL x)
-{
-       int ret;
-       if ((ret = format_uint_finite_p(str, size, x)) < 0)
-               return snprintf(str, size, "%.0f", (double) x);
-       return ret;
-}
-
-static AWKLDBL double_to_int(AWKLDBL);
-
-/* if have __float128, also have strtold. No ? */
-
-static inline AWKLDBL
-gawk_strtold(const char *str, char **endptr)
-{
-       return strtold(str, endptr);
-}
-
-/* Define isnan() and isinf() before including the two files */
-
-static inline int isnan_awkldbl(AWKLDBL x) { return x != x; }
-#ifdef isnan
-#undef isnan
-#endif
-#define isnan isnan_awkldbl
-
-static inline int isinf_awkldbl(AWKLDBL x) { return isnan(x - x); }
-#ifdef isinf
-#undef isinf
-#endif
-#define isinf isinf_awkldbl
-
-#define GAWK_INFINITY  HUGE_VALQ
-#define GAWK_NAN       (LDC(0.0) / LDC(0.0))
-
-
-/* XXX: Don't want floorl() or ceill() */ 
-
-#ifdef HAVE_FLOORL
-#undef HAVE_FLOORL
-#endif
-#ifdef HAVE_CEILL
-#undef HAVE_CEILL
-#endif
-#ifdef PRINTF_HAS_LF_FORMAT
-#undef PRINTF_HAS_LF_FORMAT
-#endif
-
-numbr_handler_t float128_hndlr;
-
-#define awkldbl_hndlr float128_hndlr
-
-#define gawk_int_t long long
-#define gawk_uint_t unsigned long long
-#ifdef SIZEOF_GAWK_INT
-#undef SIZEOF_GAWK_INT
-#undef GAWK_INT_MAX
-#undef GAWK_INT_MIN
-#undef GAWK_UINT_MAX
-#endif
-
-#define SIZEOF_GAWK_INT        8
-#define        GAWK_INT_MAX    LLONG_MAX
-#define        GAWK_INT_MIN    LLONG_MIN
-#define        GAWK_UINT_MAX   ULLONG_MAX
-
-#define TEST_NUMBR 1
-
-#include "misc/gawk_math.h"
-#include "long_double.h"
-
-#endif /* LDBLTEST == 1 */
diff --git a/long_double.c b/long_double.c
index 593cd97..c2a5c58 100644
--- a/long_double.c
+++ b/long_double.c
@@ -156,36 +156,53 @@ gawk_sqrtl(AWKLDBL x)
 #endif
 
 
-#if ! defined(PRINTF_HAS_LF_FORMAT)
-#ifdef HAVE_FLOORL
-#undef HAVE_FLOORL
-#endif
-#ifdef HAVE_CEILL
-#undef HAVE_CEILL
+/* N.B: if floorl() or ceill() or "%Lf" is missing format integers ourself */
+
+#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL) && 
defined(PRINTF_HAS_LF_FORMAT)) 
+#define GAWK_FMT_INT 1
 #endif
-#else  /* PRINTF_HAS_LF_FORMAT */
+
+
+#if ! defined(PRINTF_HAS_LF_FORMAT)
 
 /*
- * XXX: have "%Lf" but no floorl() and/or ceill(). ceill() (or ceil() for
- * double) isn't really needed.
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ *     The value must be finite.       
  */
 
-#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
-#ifdef HAVE_FLOORL
-#undef HAVE_FLOORL
-#endif
-#ifdef HAVE_CEILL
-#undef HAVE_CEILL
+static int
+format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
+{
+       char alt_format[16];
+       size_t len;
+
+       len = strlen(format);
+
+       /* expect %Lf, %LF, %Le, %LE, %Lg or %LG */
+       assert(len >= 2 && format[len - 2] == 'L');
+
+       memcpy(alt_format, format, len - 2);
+       alt_format[len - 2] = format[len - 1];  /* skip the `L' */ 
+       alt_format[len - 1] = '\0';
+       return snprintf(str, size, alt_format, fw, prec, (double) x);
+}
+#else
+
+static inline int
+format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
+{
+       return snprintf(str, size, format, fw, prec, x);
+}
 #endif
-#endif /* ! (HAVE_FLOORL && HAVE_CEILL) */ 
-#endif /* PRINTF_HAS_LF_FORMAT */
 
-#if ! defined(PRINTF_HAS_LF_FORMAT)
-static int format_float_1(char *str, size_t size, const char *format, int fw, 
int prec, AWKLDBL x);
+
+#if    defined(GAWK_FMT_INT)
+
 static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+static AWKLDBL gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk);
 
 /*
- * format_uint_finite_p --- format a long double as an unsigned integer. The 
double value
+ * format_uint_1 --- format a long double as an unsigned integer. The double 
value
  *     must be finite and >= 0.
  */
 
@@ -193,33 +210,41 @@ static inline int
 format_uint_1(char *str, size_t size, AWKLDBL x)
 {
        int ret;
-       if ((ret = format_uint_finite_p(str, size, x)) < 0)
+       if ((ret = format_uint_finite_p(str, size, x)) < 0) {
+               /* outside useful range */
                return snprintf(str, size, "%.0f", (double) x);
+       }
        return ret;
 }
-#else
 
-/*
- * format_float_1 --- format a single AWKLDBL value according to FORMAT.
- *     The value must be finite.       
- */
+/* double_to_int --- convert double to int, used in several places */
 
-static inline int
-format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
+static AWKLDBL
+double_to_int(AWKLDBL x)
 {
-       return snprintf(str, size, format, fw, prec, x);
+       AWKLDBL intval;
+       int sign = 1;
+
+       if (isnan(x) || isinf(x) || x == LDC(0.0))
+               return x;
+       if (x < LDC(0.0)) {
+               sign = -1;
+               x = -x;
+       }
+       if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0)) {
+               /* outside range, use floor() for C double */
+               intval = (AWKLDBL) Floor((double) x);
+       }
+       return intval * ((AWKLDBL) sign);
 }
 
+#else
+
 static inline int
 format_uint_1(char *str, size_t size, AWKLDBL x)
 {
        return snprintf(str, size, "%.0Lf", x);
 }
-#endif
-
-#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
-static AWKLDBL double_to_int(AWKLDBL);
-#else
 
 /* double_to_int --- convert double to int, used in several places */
 
@@ -230,6 +255,7 @@ double_to_int(AWKLDBL x)
 }
 #endif
 
+
 #include "long_double.h"
 
 #else  /* ! USE_LONG_DOUBLE */
diff --git a/long_double.h b/long_double.h
index 023ece1..203e04b 100644
--- a/long_double.h
+++ b/long_double.h
@@ -30,11 +30,15 @@
  */
 
 
-static AWKLDBL *pow2d_table;   /* 2^n table for 0 <= n <= LDBL_INT_BITS */
-static AWKLDBL init_pow2d_table(unsigned int);
-
-#define POW2LD(n)      (pow2d_table != NULL ? pow2d_table[n] : 
init_pow2d_table(n))
+static AWKLDBL *pow2d_table;   /* 2^n table for 0 <= n <= 128 */
+static void init_pow2d_table(void);
+static AWKLDBL pow2ld__p(int n);
 
+static inline AWKLDBL
+pow2ld(unsigned int n)
+{
+       return n <= 128 ? pow2d_table[n] : pow2ld__p(n);
+}
 
 /* Can declare these, since we always use the random shipped with gawk */
 extern char *initstate(unsigned long seed, char *state, long n);
@@ -177,6 +181,8 @@ awkldbl_init(bltin_t **numbr_bltins)
        false_node->flags |= NUMINT;
        true_node->flags |= NUMINT;
 
+       init_pow2d_table();     /* FIXME -- initialize only if needed ? */
+
        *numbr_bltins = awkldbl_bltins;
        return true;
 }
@@ -1609,19 +1615,28 @@ fmt1:
 
 /* init_pow2d_table --- populate powers of 2 table */
 
-static AWKLDBL
-init_pow2d_table(unsigned int n)
+static void
+init_pow2d_table()
 {
        unsigned i;
        emalloc(pow2d_table, AWKLDBL *, 129 * sizeof (AWKLDBL), 
"init_pow2d_table");
        pow2d_table[0] = LDC(1.0);
        for (i = 1; i <= 128; i++)
                pow2d_table[i] = pow2d_table[i - 1] * LDC(2.0);
-       return pow2d_table[n];
 }
 
+/* pow2ld__p --- return 2^n for some integer n >= 0 */
+
+static inline AWKLDBL
+pow2ld__p(int n)
+{
+       AWKLDBL dval = LDC(1.0);
+        for (; n > 128; n -= 128)
+               dval *= pow2d_table[128];
+        return dval * pow2d_table[n];
+}
 
-#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL) && 
defined(PRINTF_HAS_LF_FORMAT))
+#if defined(GAWK_FMT_INT)
 
 /*
  * gawk_floorl_finite_p --- provide floor() for long double. The double value
@@ -1636,9 +1651,9 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
        AWKLDBL intval = LDC(0.0);
 
 #if    LDBL_INT_BITS == 128
-       if (x >= POW2LD(113))
+       if (x >= pow2ld(113))
 #else
-       if (x >= POW2LD(64))
+       if (x >= pow2ld(64))
 #endif
                return -LDC(1.0);
 
@@ -1651,15 +1666,15 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
                low = 0;
                while (low <= high) {
                        mid = (low + high) / 2;
-                       if (x < POW2LD(mid))
+                       if (x < pow2ld(mid))
                                high = mid - 1;
                        else
                                low = mid + 1;
                }
 
-               if (x < POW2LD(low)) {
-                       x -= POW2LD(low - 1);
-                       intval += POW2LD(low - 1);
+               if (x < pow2ld(low)) {
+                       x -= pow2ld(low - 1);
+                       intval += pow2ld(low - 1);
 
                        if (chunk != NULL) {
                                /*
@@ -1669,15 +1684,15 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
                                 */
 
 #if    LDBL_INT_BITS == 128
-                               if (low <= 32) chunk[0] += (gawk_uint_t) 
POW2LD(low - 1);
-                               else if (low <= 64) chunk[1] += (gawk_uint_t) 
POW2LD(low - 33);
-                               else if (low <= 96) chunk[2] += (gawk_uint_t) 
POW2LD(low - 65);
-                               else chunk[3] += (gawk_uint_t) POW2LD(low - 97);
+                               if (low <= 32) chunk[0] += (gawk_uint_t) 
pow2ld(low - 1);
+                               else if (low <= 64) chunk[1] += (gawk_uint_t) 
pow2ld(low - 33);
+                               else if (low <= 96) chunk[2] += (gawk_uint_t) 
pow2ld(low - 65);
+                               else chunk[3] += (gawk_uint_t) pow2ld(low - 97);
 #else
-                               if (low <= 16) chunk[0] += (gawk_uint_t) 
POW2LD(low - 1);
-                               else if (low <= 32) chunk[1] += (gawk_uint_t) 
POW2LD(low - 17);
-                               else if (low <= 48) chunk[2] += (gawk_uint_t) 
POW2LD(low - 33);
-                               else chunk[3] += (gawk_uint_t) POW2LD(low - 49);
+                               if (low <= 16) chunk[0] += (gawk_uint_t) 
pow2ld(low - 1);
+                               else if (low <= 32) chunk[1] += (gawk_uint_t) 
pow2ld(low - 17);
+                               else if (low <= 48) chunk[2] += (gawk_uint_t) 
pow2ld(low - 33);
+                               else chunk[3] += (gawk_uint_t) pow2ld(low - 49);
 #endif
                        }
                }
@@ -1693,36 +1708,6 @@ gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
        }
        return intval;  /* >= 0.0 */
 }
-#endif
-
-
-#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
-
-/* double_to_int --- convert double to int, used in several places */
-
-static AWKLDBL
-double_to_int(AWKLDBL x)
-{
-       AWKLDBL intval;
-       int sign = 1;
-
-       if (isnan(x) || isinf(x) || x == LDC(0.0))
-               return x;
-
-       if (x < LDC(0.0)) {
-               sign = -1;
-               x = -x;
-       }
-
-       if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0))
-               intval = (AWKLDBL) Floor((double) x);   /* outside range, use 
floor() for C double */
-       return intval * ((AWKLDBL) sign);
-}
-
-#endif
-
-
-#if ! defined(PRINTF_HAS_LF_FORMAT)
 
 /*
  * format_uint_finite_p --- format a AWKLDBL as an unsigned integer. The 
AWKLDBL value
@@ -1810,25 +1795,4 @@ format_uint_finite_p(char *str, size_t size, AWKLDBL x)
        return len;
 }
 
-/*
- * format_float_1 --- format a single AWKLDBL value according to FORMAT.
- *     The value must be finite.       
- */
-
-static int
-format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
-{
-       char alt_format[16];
-       size_t len;
-
-       len = strlen(format);
-
-       /* expect %Lf, %LF, %Le, %LE, %Lg or %LG */
-       assert(len >= 2 && format[len - 2] == 'L');
-
-       memcpy(alt_format, format, len - 2);
-       alt_format[len - 2] = format[len - 1];  /* skip the `L' */ 
-       alt_format[len - 1] = '\0';
-       return snprintf(str, size, alt_format, fw, prec, (double) x);
-}
 #endif
diff --git a/misc/.gitignore b/misc/.gitignore
new file mode 100644
index 0000000..2460008
--- /dev/null
+++ b/misc/.gitignore
@@ -0,0 +1 @@
+!Makefile
diff --git a/misc/Makefile b/misc/Makefile
new file mode 100644
index 0000000..8aef648
--- /dev/null
+++ b/misc/Makefile
@@ -0,0 +1,56 @@
+LIBSTATIC = libmisc.a
+
+CC = gcc
+LD = gcc
+AR = ar
+AWKPROG = ../gawk
+CMP = cmp
+
+AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG)
+
+ALL_CFLAGS = $(CFLAGS) -fPIC -DGAWK -DHAVE_CONFIG_H -c -I.. -I.
+
+all: $(LIBSTATIC)
+
+OBJS := float128.o
+
+$(LIBSTATIC): $(OBJS)
+       $(AR) rc $(LIBSTATIC) $(OBJS)
+       ranlib $(LIBSTATIC)
+
+float128.o: float128.c ../awk.h ../long_double.h ./gawk_math.h ./gawk_math.c
+
+.c.o:
+       $(CC) $(ALL_CFLAGS) $< -o $@
+
+clean:
+       rm -f $(OBJS) $(LIBSTATIC)
+
+distclean: clean
+
+check:
+
+LDBL_TESTS = \
+       ldblint64 \
+       ldblint128
+
+# An attempt to print something that can be grepped for in build logs
+pass-fail:
+       @COUNT=`ls "$(TESTDIR)"/_* 2>/dev/null | wc -l` ; \
+       if test $$COUNT = 0 ; \
+       then    echo ALL TESTS PASSED ; \
+       else    echo $$COUNT TESTS FAILED ; \
+       fi
+
+ldbl-tests: $(LDBL_TESTS)
+       @$(MAKE) pass-fail TESTDIR=ldbl-tests
+
+ldblint64:
+       @echo $@
+       @$(AWK) -B -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
+       @-$(CMP) ldbl-tests/address@hidden ldbl-tests/_$@ && rm -f 
ldbl-tests/_$@
+
+ldblint128:
+       @echo $@
+       @$(AWK) -B1 -f ldbl-tests/address@hidden > ldbl-tests/_$@ 2>&1
+       @-$(CMP) ldbl-tests/address@hidden ldbl-tests/_$@ && rm -f 
ldbl-tests/_$@
diff --git a/misc/float128.c b/misc/float128.c
new file mode 100644
index 0000000..3f6ae12
--- /dev/null
+++ b/misc/float128.c
@@ -0,0 +1,447 @@
+/*
+ * float128.c - routines for a quad-precision (binary 128) floating-point.
+ */
+
+/* 
+ * Copyright (C) 2013 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+
+#if defined(LDBLTEST) && LDBLTEST == 1
+#include <math.h>
+#include "random.h"
+#if 0
+#include "floatmagic.h"        /* definition of isnan -- XXX: only for float 
or double or long double */
+#endif
+
+#include "format.h"
+
+#include <gmp.h>
+#include <mpfr.h>
+#ifndef MPFR_RNDN
+/* for compatibility with MPFR 2.X */
+#define MPFR_RNDN GMP_RNDN
+#define MPFR_RNDZ GMP_RNDZ
+#define MPFR_RNDU GMP_RNDU
+#define MPFR_RNDD GMP_RNDD
+#endif
+
+/* XXX: No libquadmath, and don't want or need it anyway. */
+
+/*
+ * Macros copied from quadmath.h
+ *     https://github.com/mirrors/gcc/blob/master/libquadmath/quadmath.h
+ */
+
+#define FLT128_MAX 1.18973149535723176508575932662800702e4932Q
+#define FLT128_MIN 3.36210314311209350626267781732175260e-4932Q
+#define FLT128_EPSILON 1.92592994438723585305597794258492732e-34Q
+#define FLT128_DENORM_MIN 6.475175119438025110924438958227646552e-4966Q
+#define FLT128_MANT_DIG 113
+#define FLT128_MIN_EXP (-16381)
+#define FLT128_MAX_EXP 16384
+#define FLT128_DIG 33
+#define FLT128_MIN_10_EXP (-4931)
+#define FLT128_MAX_10_EXP 4932
+
+/* #define HUGE_VALQ __builtin_huge_valq() */
+/* The following alternative is valid, but brings the warning:
+   (floating constant exceeds range of ‘__float128’)  */
+#define HUGE_VALQ (__extension__ 0x1.0p32767Q)
+
+#define IEEE_FLOAT128_BIAS 0x3fff
+
+/* end of Macros from quadmath.h */
+
+
+#define LDBL_FRAC_BITS FLT128_MANT_DIG
+#define        LDBL_INT_BITS   128
+
+#define AWKLDBL        __float128
+#define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
+#define LDC(x)         x##Q
+
+#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float128")
+#define free_long_double(d)    efree(d)
+
+/* we want to format integers ourself */
+#define GAWK_FMT_INT 1
+
+#define gawk_int_t long long
+#define gawk_uint_t unsigned long long
+#ifdef SIZEOF_GAWK_INT
+#undef SIZEOF_GAWK_INT
+#undef GAWK_INT_MAX
+#undef GAWK_INT_MIN
+#undef GAWK_UINT_MAX
+#endif
+
+#define SIZEOF_GAWK_INT        8
+#define        GAWK_INT_MAX    LLONG_MAX
+#define        GAWK_INT_MIN    LLONG_MIN
+#define        GAWK_UINT_MAX   ULLONG_MAX
+
+static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+static AWKLDBL gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk);
+static int format_float_1(char *str, size_t size, const char *format, int fw, 
int prec, AWKLDBL x);
+static inline int format_uint_1(char *str, size_t size, AWKLDBL x);
+static AWKLDBL double_to_int(AWKLDBL x);
+
+static __float128 strtofloat128(const char *str, char **endptr);
+#define gawk_strtold strtofloat128
+
+#if 0
+/* if have __float128, also have strtold. No ? */
+
+static inline AWKLDBL
+gawk_strtold(const char *str, char **endptr)
+{
+       return strtold(str, endptr);
+}
+#endif
+
+#define GAWK_INFINITY  HUGE_VALQ
+#define GAWK_NAN       (LDC(0.0) / LDC(0.0))
+
+/* Define isnan() and isinf() before including the two .h files */
+
+static inline int isnan_awkldbl(AWKLDBL x) { return x != x; }
+#ifdef isnan
+#undef isnan
+#endif
+#define isnan isnan_awkldbl
+
+static inline int isinf_awkldbl(AWKLDBL x) { return isnan(x - x); }
+#ifdef isinf
+#undef isinf
+#endif
+#define isinf isinf_awkldbl
+
+numbr_handler_t float128_hndlr;
+
+#define awkldbl_hndlr float128_hndlr
+
+#define TEST_NUMBR 1
+
+#include "misc/gawk_math.h"
+#include "long_double.h"
+#include "misc/gawk_math.c"
+
+
+/* XXX: This is for little-endian architecture only */
+typedef union {
+       __float128  val;
+
+       /* 64 mantissa LSBs */
+       /* 48 mantissa MSBs */
+       /* 15 exponent bits */
+       /* 1 sign bit */
+
+       struct {
+               uint8_t si[14];
+               uint16_t se;
+       } w1;
+       struct {
+               uint64_t low;
+               uint64_t high;
+       } w2;
+} gfloat128_t;
+
+
+/* hex_to_float128 --- hexadecimal string to __float128 conversion */
+
+static __float128
+hex_to_float128(const char *hexstr)
+{
+       int sign, leading_bit, exp_sign;
+       char *p;
+       uint8_t ch, leading_hex;
+       int exponent;
+       int i, k;
+       gfloat128_t fv;
+
+       memset(& fv, '\0', sizeof (gfloat128_t));
+       
+       p = (char *) hexstr;
+       /* optional sign */
+       sign = 0;
+       if (*p == '-') {
+               sign = 1;
+               p++;
+       } else if (*p == '+')
+               p++;
+
+#define XX (('a' - '0') - 10)
+
+       /* optional "0x" prefix */
+       if (*p == '0' && *(p + 1) == 'x')
+               p += 2;
+
+       leading_bit = 0;
+       k = 0;
+       if (*p != '0') {
+               /* normalized number */
+               leading_hex = ch = (uint8_t)((*p - '0') % XX);
+               while (ch >= 2) {
+                       ch /= 2;
+                       k++;
+               }               
+               leading_bit = 1;
+       }
+       p++;
+
+       if (*p == '.')  /* may not have a decimal point: 0xfp+0 */
+               *p++;
+
+       /* maximum of 28 hex digits */
+       for (i = 13; i >= 0; i--) {
+               if (*p == 'p')
+                       break;
+               ch = (uint8_t) ((*p++ - '0') % XX) ;
+               fv.w1.si[i] |= (ch << 4);
+               if (*p == 'p')
+                       break;
+               ch = (uint8_t) ((*p++ - '0') % XX);
+               fv.w1.si[i] |= ch;
+       }
+
+       if (k > 0) {
+               /* normalized number leading digit not 1; 1 <= k <= 3 */
+               /* shift mantissa to right by k; adjust 4 MSBs */
+               fv.w2.low = fv.w2.low >> k;     /* drop k LSBs from low part */
+               fv.w2.low |= (fv.w2.high << (64 - k));  /* move k LSBs from low 
to MSBs of high */
+               fv.w2.high = fv.w2.high >> k;   /* drop k LSBs from high */
+               fv.w1.si[13] |= leading_hex << (8 - k); /* move k LSBs from 
leading hex digit ... */
+               fv.w1.se = 0;   /* clear sign + exponent part */
+       }
+
+       *p++;   /* skip `p' */
+
+       /* sign of exponent */
+       exp_sign = 0;
+       if (*p == '-') {
+               exp_sign = 1;
+               p++;
+       } else if (*p == '+')
+               p++;
+       exponent = (int) strtol(p, NULL, 10);
+
+       /* adjust exponent for 1 <= significand < 2 */
+       if (exp_sign == 0)
+               exponent += k;
+       else if (exponent > k)
+               exponent -= k;
+       else {
+               exponent = k - exponent;
+               exp_sign = 0;
+       }
+       assert(exponent >= 0);
+
+       /* calculate biased exponent */
+       if (exponent == IEEE_FLOAT128_BIAS - 1 && exp_sign && ! leading_bit)    
/* de-normal number */
+               exponent = 0;
+       else if (leading_bit) {
+               if (exp_sign)
+                       exponent = IEEE_FLOAT128_BIAS - exponent;
+               else
+                       exponent += IEEE_FLOAT128_BIAS;
+       }
+#if 0
+       fprintf(stderr, "======= hex2float=======\n%s\n", hexstr);
+       fprintf(stderr, "exponent (biased) = %d\n", exponent);
+       fprintf(stderr, "sign = %d\n", sign);
+       fprintf(stderr, "significand = %012llx %016llx\n", fv.w2.high, 
fv.w2.low);
+       fprintf(stderr, "========================\n");
+#endif
+       /* set exponent */
+       fv.w1.se |= (uint16_t) exponent;
+       /* set sign */
+       fv.w1.se |= (uint16_t) (sign << 15);
+       return fv.val;
+}
+
+
+/* float128_to_hex --- __float128 to hexadecimal string conversion */
+
+static const char *
+float128_to_hex(__float128 x)
+{
+       static char buf[64];
+       char *p; 
+       int i, exponent, sign, exp_sign;
+       int extra_bit;
+       gfloat128_t fv;
+
+       /* XXX: we don't need to handle infinity and nan here. */
+
+       fv.val = x;
+       p = buf;
+
+       sign = (fv.w1.se & (1 << 15)) != 0;
+       exponent = (fv.w1.se & ((1 << 15) - 1));
+       extra_bit = 1;
+       exp_sign = 0;
+
+       /* calculate unbiased exponent */
+       if (exponent == 0) {
+               int nonzero_significand = ((fv.w2.high & ((1ULL << 48) - 1)) | 
fv.w2.low) != 0;
+
+               extra_bit = 0;
+               if (nonzero_significand) {
+                       exp_sign = 1;
+                       exponent = IEEE_FLOAT128_BIAS - 1;
+               }
+       } else if (exponent >= IEEE_FLOAT128_BIAS)
+               exponent -= IEEE_FLOAT128_BIAS;
+       else {
+               exp_sign = 1;
+               exponent = -(exponent - IEEE_FLOAT128_BIAS);    
+       }
+
+       if (sign)
+               *p++ = '-';
+       *p++ = extra_bit ? '1' : '0';
+       *p++ = '.';
+
+       /* all 28 hex digits -- XXX: quit early if last 64-bits all 0s ? */
+       for (i = 13; i >= 0; i--) {
+               *p++ = lchbuf[(fv.w1.si[i] & 0xF0) >> 4];
+               *p++ = lchbuf[(fv.w1.si[i] & 0x0F)];
+       }
+
+       *p++ = 'p';
+       *p++ = exp_sign ? '-' : '+';
+       sprintf(p, "%d", exponent);     /* decimal exponent */
+
+       /* assert(hex_to_float128(buf) == x); */
+       return buf;
+}
+
+/*
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ *     The value must be finite.
+ */
+
+static int
+format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
+{
+       char alt_format[32];
+       size_t len;
+       int ret = -1;
+       const char *hexstr;
+       mpfr_t ap_float;
+
+       if (isnan(x) || isinf(x)) {
+               /* FIXME: ignoring sign */
+               if (size < 4)
+                       return 3;
+               strcpy(str, isnan(x) ? "nan" : "inf");
+               return 3;
+       }
+
+       len = strlen(format);
+
+       /* expect %Lf, %LF, %Le, %LE, %Lg or %LG */
+       assert(len >= 2 && format[len - 2] == 'L');
+       
+       memcpy(alt_format, format, len + 1);
+       alt_format[len - 2] = 'R';      /* replace `L' with `R' */ 
+       alt_format[len] = alt_format[len - 1];
+       alt_format[len - 1] = 'N';      /* rounding mode = MPFR_RNDN */
+       alt_format[len + 1] = '\0';
+
+       /* loss-less conversion to hexadecimal string */
+       hexstr = float128_to_hex(x);
+
+       /* fprintf(stderr, "hexfloat = %s\n", hexstr); */
+
+       mpfr_init2(ap_float, 113);
+       if (mpfr_set_str(ap_float, hexstr, 16, MPFR_RNDN) < 0) {
+               /* XXX: Invalid string? can it be? */
+               return -1;
+       }
+
+       ret = mpfr_snprintf(str, size, alt_format, fw, prec, ap_float);
+       mpfr_clear(ap_float);
+       return ret;
+}
+
+/*
+ * format_uint_1 --- format a long double as an unsigned integer. The double 
value
+ *     must be finite and >= 0.
+ */
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+       int ret;
+       if ((ret = format_uint_finite_p(str, size, x)) < 0) {
+               /* outside useful range */
+               /* FIXME -- use format_float_1 (MPFR) */
+               return snprintf(str, size, "%.0Lf", (long double) x);
+       }
+       return ret;
+}
+
+/* double_to_int --- convert double to int, used in several places */
+
+static AWKLDBL
+double_to_int(AWKLDBL x)
+{
+       AWKLDBL intval;
+       int sign = 1;
+
+       if (isnan(x) || isinf(x) || x == LDC(0.0))
+               return x;
+       if (x < LDC(0.0)) {
+               sign = -1;
+               x = -x;
+       }
+       if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0)) {
+               /* outside range */
+               /* FIXME -- use format_float_1 with "%.0Lf" (MPFR) */
+               intval = (AWKLDBL) floorl((long double) x);
+       }
+       return intval * ((AWKLDBL) sign);
+}
+
+/* strtofloat128 --- convert string to __float128 */
+
+static __float128
+strtofloat128(const char *str, char **endptr)
+{
+       static char hexstr[64];
+       mpfr_t ap_float;
+
+       /* store as MPFR number */
+       mpfr_init2(ap_float, 113);
+       (void) mpfr_strtofr(ap_float, str, endptr, 10, MPFR_RNDN);
+
+       /* get back a hexadecimal string representation */
+       (void) mpfr_snprintf(hexstr, 64, "%RNa", ap_float);
+       mpfr_clear(ap_float);
+
+       /* fprintf(stderr, "hexfloat (mpfr): %s\n", hexstr); */
+
+       return hex_to_float128(hexstr); 
+}
+
+#endif /* LDBLTEST == 1 */
diff --git a/misc/fp_math.awk b/misc/fp_math.awk
index 80fe7d8..e2847e6 100644
--- a/misc/fp_math.awk
+++ b/misc/fp_math.awk
@@ -4,7 +4,6 @@
 #      TODO:   * finish fmod().
 #              * replace all usages of %, and int() or any other math builtin; 
and() is ok!.
 #                implement double_to_int() and remove floor/ceil.
-#              * fix sqrt(x) for x > DBL_MAX or x < -DBL_MIN.
 #
 
 
@@ -337,19 +336,37 @@ function fp_sqrt(x,       \
        if (x == 0)
                return x        # return +0 or -0
 
-       yn = sqrt(x)    # double-precision sqrt
+       if (x >= DBL_MIN && x <= DBL_MAX)
+               yn = sqrt(x)    # double-precision sqrt
+       else {
+               frac = frexpl(x, e);    # in [1, 2)
+               exponent = e[0]
+               if (and(exponent, 1) != 0) {
+                       frac /= 2
+                       exponent++
+               }
+               yn = sqrt(frac)
+               exponent /= 2
+               if (exponent >= 0)
+                       yn *= pow2(exponent)
+               else
+                       yn /= pow2(-exponent)
+       }
+
        do {
                last = yn
                yn = (yn + x / yn) \
                                / 2
                err = (yn - last) / yn
+               if (err < 0)
+                       err = -err
        } while (err > __REL_ERROR__)
        return yn
 }
 
-# __log2 -- compute log(2)
+# klog2 -- compute k * log2 without loss of precision 
 
-function __log2( \
+function klog2(k, \
                i, three_pow, sum, err, term)
 {
        #
@@ -360,18 +377,18 @@ function __log2( \
        # y = (x - 1) / (x + 1) => y = 1 / 3
        i = 1
        three_pow = 3
-       sum = 1 / 3
-
+       sum = (2 * k) / 3
        do {
                three_pow *= 9
                i += 2
-               term = 1 / (three_pow * i)
+               term = (2 * k) / (three_pow * i)
                sum += term
                err = term / sum
        } while (err > __REL_ERROR__)
-       return 2 * sum
+       return sum
 }
 
+
 function pow2(n, k)
 {
        if (n <= 64)
@@ -381,28 +398,17 @@ function pow2(n, k)
        return k * __POW2__[n]
 }
 
-function fp_log(x,     \
-               k, i, y, ypow2, ypow_odd, sum, err, term, sign, high, low, mid)
+
+# the returned fraction is normalized in [1, 2) and NOT [0.5, 1)  
+# exponent is in e[0]
+
+function frexpl(x, e, \
+               y, low, high, mid)
 {
-       #
-       #       ln(x) = 2 * arctanh(y)
-       #             = 2 * (y + y^3 / 3 + y^5 /5 + ..) where y = (x - 1) / (x 
+ 1) 
-       #
-       x = +x
-       if (isnan(x) || x == __PLUS_INF__)
-               return x
-       if (x == __MINUS_INF__ || x < 0)        # errno EDOM ?
-               return __PLUS_NAN__
-       if (x == 0)     # errno ERANGE ?
-               return __MINUS_INF__
-       
-       if (x == 1)     # special case
-               return 0
-       if (x == 2)     # special case
-               return __LOG2__
-       k = 0
+       # XXX -- (isnormal(x) && x > 0) is assumed to be true
+
+       low = 0
        if (x > 2) {
-               low = 0
                high = LDBL_MAX_EXP - 1         # XXX: should be 4 * 
LDBL_MAX_EXP - 1 if FLT_RADIX = 16
                while (low <= high) {
                        mid = int ((low + high) / 2)
@@ -413,11 +419,8 @@ function fp_log(x, \
                                high = mid - 1
                }
                x /= pow2(low)
-               k = low
-#              printf("x = %0.18e, k = %d\n", x / pow2(low), low)
-
+               e[0] = low
        } else if (x < 1) {
-               low = 0
                high = LDBL_MAX_EXP - 1         # could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP
                while (low <= high) {
                        mid = int ((low + high) / 2)
@@ -428,17 +431,64 @@ function fp_log(x,        \
                                high = mid - 1
                }
                x *= pow2(low)
-               k = -low
+               e[0] = -low
+       } else
+               e[0] = 0
+
+       if (x == 2) {
+               x = 1
+               e[0]++
        }
+       return x        # x in [1, 2)
+}
+
+
+#
+# $ ./gawk 'BEGIN { printf("%.18e\n", log(7.12111e900))}'
+# inf
+# $ ./gawk -B 'BEGIN { printf("%.18e\n", log(7.12111e900))}'           # with 
logl(), without it inf
+# 2.074289647306790437e+03
+# $ ./gawk -B -f misc/fp_math.awk -e 'BEGIN { printf("%.18e\n", 
fp_log(7.12111e900))}'
+# 2.074289647306790437e+03
+# $ ./gawk -M -vPREC=quad 'BEGIN { printf("%.18e\n", log(7.12111e900))}'
+# 2.074289647306790438e+03
+#
+
+
+function fp_log(x,     \
+               e, exponent, i, ypow2, ypow_odd, sum, err, term, sign)
+{
+       #
+       #       ln(x) = 2 * arctanh(y)
+       #             = 2 * (y + y^3 / 3 + y^5 /5 + ..) where y = (x - 1) / (x 
+ 1) 
+       #
+       x = +x
+       if (isnan(x) || x == __PLUS_INF__)
+               return x
+       if (x == __MINUS_INF__ || x < 0)        # errno EDOM ?
+               return __PLUS_NAN__
+       if (x == 0)     # errno ERANGE ?
+               return __MINUS_INF__
+       
+       if (x == 1)     # special case
+               return 0
+       if (x == 2)     # special case
+               return __LOG2__
+
+       x = frexpl(x, e)
+       exponent = e[0]
 
        # arctanh(x) series has faster convergence when x is close to 1
        # range reduction -- 1/sqrt(2) <= x <= sqrt(2)
        if (x > __SQRT_2__ || x < __1_OVER_SQRT_2__) {
                x *= __1_OVER_SQRT_2__
-               k += 0.5
+               exponent += 0.5
        }
 
        y = (x - 1) / (x + 1)
+       if (y == 0)     # tricky special case 
+               return exponent * __LOG2__;
+
        sign = 1
        if (y < 0) {
                sign = -1
@@ -458,7 +508,7 @@ function fp_log(x,  \
                err = term / sum
        } while (err > __REL_ERROR__)
 
-       return sign * (sum = 2 * sum + k * __LOG2__)
+       return sign * (sum = 2 * sum + exponent * __LOG2__)
 }
 
 
@@ -470,6 +520,8 @@ function taylor_exp(x,      \
        # sinh(x) = sqrt(cosh(x) * cosh(x) - 1)
        # exp(x) = cosh(x) + sinh(x)
 
+       if (x == 0)
+               return 1;
        xpow2 = x * x
        xpow_even = 1
        i = 0
@@ -485,12 +537,15 @@ function taylor_exp(x,    \
                err  = term / cosh
        } while (err > __REL_ERROR__)
 
-       sinh = fp_sqrt(cosh * cosh - 1) # sqrt is cheap
+#      sinh = fp_sqrt(cosh * cosh - 1) # sqrt is cheap
+       z = cosh - 1.0
+       sinh = z * fp_sqrt(1 + 2 / z)   
        return (sinh + cosh)
 }
 
+
 function fp_exp(x,     \
-               exp_val, k, sign)
+               y, exp_val, k, sign)
 {
        x = +x
        if (isnan(x) || x == __PLUS_INF__)
@@ -505,19 +560,18 @@ function fp_exp(x,        \
                sign = -1
                x = -x
        }
+
        k = fp_floor(x / __LOG2__)
 
        # range reduction -- 0 < x < log(2) (0.693...)
        if (k == 0)
                exp_val = taylor_exp(x)
        else {
-               exp_val = taylor_exp(x - k * __LOG2__)
-               while (k >= 64) {
-                       exp_val *= __POW2__[64]
-                       k -= 64
-               }
-               exp_val *= __POW2__[k]
+               y = x - klog2(k)
+               exp_val = taylor_exp(y)
+               exp_val *= pow2(k)
        }
+
        return sign < 0 ? (1 / exp_val) : exp_val
 }
 
@@ -791,6 +845,8 @@ BEGIN {
        __REL_ERROR__ = 5.0e-35
        LDBL_MAX_EXP = 16384
        LDBL_MANT_DIG = 113
+       DBL_MAX = 1.7976931348623157e+308
+       DBL_MIN = 2.2250738585072014E-308
 
        # We can read hex/octal numbers without using strtod/strtodl
        if (0x10000000000000000 == 0x10000000000000001) {
@@ -812,7 +868,7 @@ BEGIN {
 
        __SQRT_2__ = fp_sqrt(2)
        __1_OVER_SQRT_2__ = 1 / __SQRT_2__
-       __LOG2__ = __log2()     # cannot use fp_log()
+       __LOG2__ = klog2(1)     # cannot use fp_log()
        __PI_OVER_4__ = 4 * euler_atan_one_over(5) - euler_atan_one_over(239)
 
        # pre-calculate 2^0 - 2^64
diff --git a/misc/gawk_math.c b/misc/gawk_math.c
new file mode 100644
index 0000000..3e8e6ef
--- /dev/null
+++ b/misc/gawk_math.c
@@ -0,0 +1,72 @@
+/*
+ * gawk_math.c - routines for replacement AWKLDBL math functions.
+ */
+
+/* 
+ * Copyright (C) 2013 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+static AWKLDBL
+gawk_sinl(AWKLDBL x)
+{
+       return sin( (double) x);
+}
+
+static AWKLDBL
+gawk_cosl(AWKLDBL x)
+{
+       return cos( (double) x);
+}
+
+static AWKLDBL
+gawk_atan2l(AWKLDBL y, AWKLDBL x)
+{
+       return atan2( (double) y, (double) x);
+}
+
+static AWKLDBL
+gawk_logl(AWKLDBL x)
+{
+       return log( (double) x);
+}
+
+static AWKLDBL
+gawk_expl(AWKLDBL x)
+{
+       return exp( (double) x);
+}
+
+static AWKLDBL
+gawk_fmodl(AWKLDBL x, AWKLDBL y)
+{
+       return fmod( (double) x, (double) y);
+}
+
+static AWKLDBL
+gawk_powl(AWKLDBL x, AWKLDBL y)
+{
+       return pow( (double) x, (double) y);
+}
+
+static AWKLDBL
+gawk_sqrtl(AWKLDBL x)
+{
+       return sqrt( (double) x);
+}
diff --git a/misc/gawk_math.h b/misc/gawk_math.h
index 909bd69..5109d55 100644
--- a/misc/gawk_math.h
+++ b/misc/gawk_math.h
@@ -1,3 +1,28 @@
+/*
+ * gawk_math.h - replacement AWKLDBL math functions.
+ */
+
+/* 
+ * Copyright (C) 2013 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
 static AWKLDBL gawk_sinl(AWKLDBL x);
 static AWKLDBL gawk_cosl(AWKLDBL x);
 static AWKLDBL gawk_atan2l(AWKLDBL y, AWKLDBL x);
@@ -7,82 +32,3 @@ static AWKLDBL gawk_fmodl(AWKLDBL x, AWKLDBL y);
 static AWKLDBL gawk_powl(AWKLDBL x, AWKLDBL y);
 static AWKLDBL gawk_sqrtl(AWKLDBL x);
 
-static AWKLDBL
-gawk_sinl(AWKLDBL x)
-{
-#ifdef HAVE_SINL
-       return sinl( (long double) x);
-#else
-       return sin( (double) x);
-#endif
-}
-
-static AWKLDBL
-gawk_cosl(AWKLDBL x)
-{
-#ifdef HAVE_COSL
-       return cosl( (long double) x);
-#else
-       return cos( (double) x);
-#endif
-}
-
-static AWKLDBL
-gawk_atan2l(AWKLDBL y, AWKLDBL x)
-{
-#ifdef HAVE_ATAN2L
-       return atan2l( (long double) y, (long double) x);
-#else
-       return atan2( (double) y, (double) x);
-#endif
-}
-
-static AWKLDBL
-gawk_logl(AWKLDBL x)
-{
-#ifdef HAVE_LOGL
-       return logl( (long double) x);
-#else
-       return log( (double) x);
-#endif
-}
-
-static AWKLDBL
-gawk_expl(AWKLDBL x)
-{
-#ifdef HAVE_EXPL
-       return expl( (long double) x);
-#else
-       return exp( (double) x);
-#endif
-}
-
-static AWKLDBL
-gawk_fmodl(AWKLDBL x, AWKLDBL y)
-{
-#ifdef HAVE_FMODL
-       return fmodl( (long double) x, (long double) y);
-#else
-       return fmod( (double) x, (double) y);
-#endif
-}
-
-static AWKLDBL
-gawk_powl(AWKLDBL x, AWKLDBL y)
-{
-#ifdef HAVE_POWL
-       return powl( (long double) x, (long double) y);
-#else
-       return pow( (double) x, (double) y);
-#endif
-}
-
-static AWKLDBL
-gawk_sqrtl(AWKLDBL x)
-{
-#ifdef HAVE_SQRTL
-       return sqrtl( (long double) x);
-#else
-       return sqrt( (double) x);
-#endif 
-}
diff --git a/misc/ldblint64.awk b/misc/ldbl-tests/ldblint128.awk
similarity index 62%
copy from misc/ldblint64.awk
copy to misc/ldbl-tests/ldblint128.awk
index 65f3939..ad2b083 100644
--- a/misc/ldblint64.awk
+++ b/misc/ldbl-tests/ldblint128.awk
@@ -1,4 +1,4 @@
-# Usage gawk -B -f ldblint54.awk
+# Usage gawk -B -f ldblint128.awk
 
 BEGIN {
        for (i = -9.0; i < 2.0; i++) {
@@ -9,6 +9,6 @@ BEGIN {
                        j = -j
                        j = " - " j
                }
-               printf("2^64%s = %d\n", j, 2^64 + i)
+               printf("2^113%s = %d\n", j, 2^113 + i)
        }
 }
diff --git a/misc/ldbl-tests/ldblint128.ok b/misc/ldbl-tests/ldblint128.ok
new file mode 100644
index 0000000..0526d3b
--- /dev/null
+++ b/misc/ldbl-tests/ldblint128.ok
@@ -0,0 +1,11 @@
+2^113 - 9 = 10384593717069655257060992658440183
+2^113 - 8 = 10384593717069655257060992658440184
+2^113 - 7 = 10384593717069655257060992658440185
+2^113 - 6 = 10384593717069655257060992658440186
+2^113 - 5 = 10384593717069655257060992658440187
+2^113 - 4 = 10384593717069655257060992658440188
+2^113 - 3 = 10384593717069655257060992658440189
+2^113 - 2 = 10384593717069655257060992658440190
+2^113 - 1 = 10384593717069655257060992658440191
+2^113 + 0 = 10384593717069655257060992658440192
+2^113 + 1 = 10384593717069655257060992658440192
diff --git a/misc/ldblint64.awk b/misc/ldbl-tests/ldblint64.awk
similarity index 100%
rename from misc/ldblint64.awk
rename to misc/ldbl-tests/ldblint64.awk
diff --git a/misc/ldblint64.ok b/misc/ldbl-tests/ldblint64.ok
similarity index 100%
rename from misc/ldblint64.ok
rename to misc/ldbl-tests/ldblint64.ok

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=26bfdfdc9bb065dfc1ea7f2494070f826e81b874

commit 26bfdfdc9bb065dfc1ea7f2494070f826e81b874
Author: John Haque <address@hidden>
Date:   Wed Jan 23 06:25:50 2013 -0600

    Use different routines to format long double integers and floats.

diff --git a/ChangeLog b/ChangeLog
index 361a0e8..d0daef3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2013-01-23         John Haque      <address@hidden>
+
+       * long_double.c (format_uint_1): New inline routines to format integers.
+       * long_double.h (format_float_1): Remove integer formatting code.
+       (format_awkldbl_printf): Use format_uint_1() to format integers.
+       
 2013-01-19         John Haque      <address@hidden>
 
        For C long double and without "%Lf" in printf, provide "%.0Lf" to
diff --git a/float128.c b/float128.c
index 0910a68..15582b8 100644
--- a/float128.c
+++ b/float128.c
@@ -34,28 +34,42 @@
 
 /* end of Macros from quadmath.h */
 
+
 #define LDBL_FRAC_BITS FLT128_MANT_DIG
+#define        LDBL_INT_BITS   128
 
 #define AWKLDBL        __float128
 #define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
 #define LDC(x)         x##Q
 
-#define        LDBL_INT_BITS   128
-
 #define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float128")
 #define free_long_double(d)    efree(d)
 
-static int format_float_1(char *str, size_t size, const char *format, ...);
+static int format_float_1(char *str, size_t size, const char *format, int fw, 
int prec, AWKLDBL x);
+static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+
+/*
+ * format_uint_1 --- format a AWKLDBL as an unsigned integer. The double value
+ *     must be finite and >= 0.
+ */
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+       int ret;
+       if ((ret = format_uint_finite_p(str, size, x)) < 0)
+               return snprintf(str, size, "%.0f", (double) x);
+       return ret;
+}
+
 static AWKLDBL double_to_int(AWKLDBL);
 
+/* if have __float128, also have strtold. No ? */
+
 static inline AWKLDBL
 gawk_strtold(const char *str, char **endptr)
 {
-#ifdef HAVE_STRTOLD
        return strtold(str, endptr);
-#else
-       return strtod(str, endptr);
-#endif
 }
 
 /* Define isnan() and isinf() before including the two files */
@@ -73,8 +87,10 @@ static inline int isinf_awkldbl(AWKLDBL x) { return isnan(x 
- x); }
 #define isinf isinf_awkldbl
 
 #define GAWK_INFINITY  HUGE_VALQ
-#define GAWK_NAN       (LDC(0.0Q) / LDC(0.0Q))
+#define GAWK_NAN       (LDC(0.0) / LDC(0.0))
+
 
+/* XXX: Don't want floorl() or ceill() */ 
 
 #ifdef HAVE_FLOORL
 #undef HAVE_FLOORL
diff --git a/long_double.c b/long_double.c
index a2fc40e..593cd97 100644
--- a/long_double.c
+++ b/long_double.c
@@ -181,9 +181,40 @@ gawk_sqrtl(AWKLDBL x)
 #endif /* PRINTF_HAS_LF_FORMAT */
 
 #if ! defined(PRINTF_HAS_LF_FORMAT)
-static int format_float_1(char *str, size_t size, const char *format, ...);
+static int format_float_1(char *str, size_t size, const char *format, int fw, 
int prec, AWKLDBL x);
+static int format_uint_finite_p(char *str, size_t size, AWKLDBL x);
+
+/*
+ * format_uint_finite_p --- format a long double as an unsigned integer. The 
double value
+ *     must be finite and >= 0.
+ */
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+       int ret;
+       if ((ret = format_uint_finite_p(str, size, x)) < 0)
+               return snprintf(str, size, "%.0f", (double) x);
+       return ret;
+}
 #else
-#define format_float_1 snprintf
+
+/*
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ *     The value must be finite.       
+ */
+
+static inline int
+format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
+{
+       return snprintf(str, size, format, fw, prec, x);
+}
+
+static inline int
+format_uint_1(char *str, size_t size, AWKLDBL x)
+{
+       return snprintf(str, size, "%.0Lf", x);
+}
 #endif
 
 #if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
diff --git a/long_double.h b/long_double.h
index f117bb8..023ece1 100644
--- a/long_double.h
+++ b/long_double.h
@@ -1202,8 +1202,8 @@ get_ieee_magic_val(const char *val)
        if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
                if (first) {
                        first = false;
-                       nan = gawk_sqrtl(-LDC(1.0));
-                       inf = -gawk_logl(LDC(0.0));
+                       nan = gawk_sqrtl(-LDC(1.0));    /* FIXME -- this isn't 
right */
+                       inf = -gawk_logl(LDC(0.0));     /* Ditto */
                }
                v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
                if (val[0] == '-')
@@ -1429,7 +1429,7 @@ format_awkldbl_printf(NODE *arg, struct format_spec 
*spec, struct print_fmt_buf
                 * Use snprintf return value to tell if there
                 * is enough room in the buffer or not.
                 */
-               while ((i = format_float_1(intbuf, intbuf_size, "%.0Lf", 
tmpval)) >= intbuf_size) {
+               while ((i = format_uint_1(intbuf, intbuf_size, tmpval)) >= 
intbuf_size) {
                        if (intbuf == stackbuf)
                                intbuf = NULL;
                        intbuf_size = i + 1;
@@ -1725,8 +1725,8 @@ double_to_int(AWKLDBL x)
 #if ! defined(PRINTF_HAS_LF_FORMAT)
 
 /*
- * format_uint_finite_p --- format a double as an unsigned integer. The double 
value
- *     must be finite and >= 0.
+ * format_uint_finite_p --- format a AWKLDBL as an unsigned integer. The 
AWKLDBL value
+ *     must be finite and in the range 0 <= x < 2^LDBL_FRAC_BITS.
  */
 
 static int
@@ -1772,12 +1772,9 @@ format_uint_finite_p(char *str, size_t size, AWKLDBL x)
        gawk_uint_t d0, d1, d2, d3, d4, q;
        gawk_uint_t chunk[4];
 
-       assert(!!isnan(x) == 0);
-       assert(!!isinf(x) == 0);
        assert(x >= LDC(0.0));
 
-       if (size <= 35)         /* maximum size ever needed excluding 
terminating null */
-               return 35;
+       assert(size > 35);      /* maximum size ever needed excluding 
terminating null */
 
        if (gawk_floorl_finite_p(x, chunk) < LDC(0.0))  /* outside range */
                return -1;
@@ -1814,46 +1811,24 @@ format_uint_finite_p(char *str, size_t size, AWKLDBL x)
 }
 
 /*
- * format_float_1 --- format a single double value according to FORMAT.
- *     The value must be finite and >= 0.      
+ * format_float_1 --- format a single AWKLDBL value according to FORMAT.
+ *     The value must be finite.       
  */
 
 static int
-format_float_1(char *str, size_t size, const char *format, ...)
+format_float_1(char *str, size_t size, const char *format, int fw, int prec, 
AWKLDBL x)
 {
-        va_list argp;
        char alt_format[16];
        size_t len;
-       int ret = -1;
-       AWKLDBL x;
-
-        va_start(argp, format);
 
        len = strlen(format);
 
        /* expect %Lf, %LF, %Le, %LE, %Lg or %LG */
        assert(len >= 2 && format[len - 2] == 'L');
-       
+
        memcpy(alt_format, format, len - 2);
        alt_format[len - 2] = format[len - 1];  /* skip the `L' */ 
        alt_format[len - 1] = '\0';
-
-       if (strcmp(format, "%.0Lf") == 0) {
-               /* format as integer */
-               x = va_arg(argp, AWKLDBL);
-               va_end(argp);
-               if ((ret = format_uint_finite_p(str, size, x)) < 0)
-                       ret = snprintf(str, size, alt_format, (double) x);
-       } else {
-               int fw, prec;
-
-               fw = va_arg(argp, int);
-               prec = va_arg(argp, int);
-               x = va_arg(argp, AWKLDBL);
-               ret = snprintf(str, size, alt_format, fw, prec, (double) x);
-       }
-
-       va_end(argp);
-       return ret;
+       return snprintf(str, size, alt_format, fw, prec, (double) x);
 }
 #endif
diff --git a/misc/fp_math.awk b/misc/fp_math.awk
index 51583fa..80fe7d8 100644
--- a/misc/fp_math.awk
+++ b/misc/fp_math.awk
@@ -2,7 +2,9 @@
 
 #
 #      TODO:   * finish fmod().
-#              * replace all usages of %, and int() or any other math builtin; 
and() is ok!
+#              * replace all usages of %, and int() or any other math builtin; 
and() is ok!.
+#                implement double_to_int() and remove floor/ceil.
+#              * fix sqrt(x) for x > DBL_MAX or x < -DBL_MIN.
 #
 
 
@@ -370,9 +372,17 @@ function __log2( \
        return 2 * sum
 }
 
+function pow2(n, k)
+{
+       if (n <= 64)
+               return __POW2__[n]
+       for (k = 1; n > 64; n -= 64)
+               k *= __POW2__[64]
+       return k * __POW2__[n]
+}
 
 function fp_log(x,     \
-               k, i, y, ypow2, ypow_odd, sum, err, term, sqrt_2, sign)
+               k, i, y, ypow2, ypow_odd, sum, err, term, sign, high, low, mid)
 {
        #
        #       ln(x) = 2 * arctanh(y)
@@ -392,17 +402,33 @@ function fp_log(x,        \
                return __LOG2__
        k = 0
        if (x > 2) {
-               # FIXME -- use power2 table
-               while (x > 2) {
-                       x /= 2
-                       k++
+               low = 0
+               high = LDBL_MAX_EXP - 1         # XXX: should be 4 * 
LDBL_MAX_EXP - 1 if FLT_RADIX = 16
+               while (low <= high) {
+                       mid = int ((low + high) / 2)
+                       y = x / pow2(mid)
+                       if (y > 2)
+                               low = mid + 1
+                       else
+                               high = mid - 1
                }
+               x /= pow2(low)
+               k = low
+#              printf("x = %0.18e, k = %d\n", x / pow2(low), low)
+
        } else if (x < 1) {
-               # FIXME -- use power2 table
-               while (x < 1) {
-                       x *= 2
-                       k--
+               low = 0
+               high = LDBL_MAX_EXP - 1         # could be -LDBL_MIN_EXP, but 
no harm in using LDBL_MAX_EXP
+               while (low <= high) {
+                       mid = int ((low + high) / 2)
+                       y =  x * pow2(mid)
+                       if (y < 1)
+                               low = mid + 1
+                       else
+                               high = mid - 1
                }
+               x *= pow2(low)
+               k = -low
        }
 
        # arctanh(x) series has faster convergence when x is close to 1
@@ -724,7 +750,7 @@ function fixprec(str, numdigs, \
        if (str ~ /^[-+]?(nan|inf)/)
                return str
        if (! numdigs)
-               numdigs = __DIGITS__
+               numdigs = LDBL_DIG
        if (str ~ /^[-+]?0[\.]/)
                return str
        sign = ""
@@ -760,9 +786,24 @@ function fixprec(str, numdigs, \
 BEGIN {
        # define some constants
 
-       # reltive error < 5 X 10^-k for rounding to k significant digits
-       __DIGITS__ = 34
-       __REL_ERROR__ = 5.0e-34
+       LDBL_DIG = 33
+       # relative error < 5 X 10^-k for rounding to k significant digits
+       __REL_ERROR__ = 5.0e-35
+       LDBL_MAX_EXP = 16384
+       LDBL_MANT_DIG = 113
+
+       # We can read hex/octal numbers without using strtod/strtodl
+       if (0x10000000000000000 == 0x10000000000000001) {
+               # x86 long double
+               LDBL_MANT_DIG = 64
+               LDBL_DIG = 18
+               __REL_ERROR__ = 5.0e-20
+       } else if (0x400000000000000000000000000 == 
0x400000000000000000000000001) {
+               # double-double
+               LDBL_MANT_DIG = 106
+               LDBL_DIG = 31
+               LDBL_MAX_EXP = 309
+       }
 
        __PLUS_INF__ = "+inf" + 0
        __MINUS_INF__ = "-inf" + 0
@@ -774,15 +815,7 @@ BEGIN {
        __LOG2__ = __log2()     # cannot use fp_log()
        __PI_OVER_4__ = 4 * euler_atan_one_over(5) - euler_atan_one_over(239)
 
-
-##if LDBL_MANT_DIG == 64
-#       80 bit long double .. 18 or 34 digits?
-#      use 2^64 power 2 table
-##elif LDBL_MANT_DIG == 113
-#       128 bit long double .. 34 digits
-#      use 2^112 power 2 table
-##endif
-
+       # pre-calculate 2^0 - 2^64
        __POW2__[0] = 1
        for (i = 1; i <= 64; i++)
                __POW2__[i] = __POW2__[i - 1] * 2
diff --git a/misc/gawk_math.h b/misc/gawk_math.h
index e34bfae..909bd69 100644
--- a/misc/gawk_math.h
+++ b/misc/gawk_math.h
@@ -50,7 +50,7 @@ gawk_logl(AWKLDBL x)
 static AWKLDBL
 gawk_expl(AWKLDBL x)
 {
-#ifdef HAVE_LOGL
+#ifdef HAVE_EXPL
        return expl( (long double) x);
 #else
        return exp( (double) x);

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=ecf5161fabf105c8a50834e5bbc7ada5b322ce03

commit ecf5161fabf105c8a50834e5bbc7ada5b322ce03
Author: John Haque <address@hidden>
Date:   Sun Jan 20 07:33:11 2013 -0600

    Added facilities to use gcc __float128 as long double -- only for testing.

diff --git a/Makefile.am b/Makefile.am
index c7969d2..00d1b2c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -132,7 +132,7 @@ base_sources = \
        version.c \
        xalloc.h
 
-gawk_SOURCES = $(base_sources)
+gawk_SOURCES = $(base_sources) float128.c
 
 # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
 LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@
diff --git a/Makefile.in b/Makefile.in
index 82c8a92..243af73 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -115,7 +115,7 @@ am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) 
builtin.$(OBJEXT) \
        random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
        replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
        version.$(OBJEXT)
-am_gawk_OBJECTS = $(am__objects_1)
+am_gawk_OBJECTS = $(am__objects_1) float128.$(OBJEXT)
 gawk_OBJECTS = $(am_gawk_OBJECTS)
 gawk_LDADD = $(LDADD)
 am__DEPENDENCIES_1 =
@@ -465,7 +465,7 @@ base_sources = \
        version.c \
        xalloc.h
 
-gawk_SOURCES = $(base_sources)
+gawk_SOURCES = $(base_sources) float128.c
 
 # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS.
 LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@
@@ -598,6 +598,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/awk.h b/awk.h
index bd2a2ce..4aec8b5 100644
--- a/awk.h
+++ b/awk.h
@@ -861,8 +861,6 @@ typedef struct exp_instruction {
 /* Op_store_var */
 #define initval         x.xn
 
-
-#if ! (defined(TEST_NUMBR) && TEST_NUMBR == 1)
 #if SIZEOF_UNSIGNED_LONG == 8
 typedef long gawk_int_t;
 typedef unsigned long gawk_uint_t;
@@ -887,15 +885,6 @@ typedef unsigned int gawk_uint_t;
 #define        GAWK_UINT_MAX   UINT_MAX
 #endif
 #endif
-#else /* TEST_NUMBR */
-/* XXX: think twice before using these for any other purpose. */
-typedef long long gawk_int_t;
-typedef unsigned long long gawk_uint_t;
-#define SIZEOF_GAWK_INT        8
-#define        GAWK_INT_MAX    LLONG_MAX
-#define        GAWK_INT_MIN    LLONG_MIN
-#define        GAWK_UINT_MAX   ULLONG_MAX
-#endif /* TEST_NUMBR */
 
 
 typedef struct {
diff --git a/configure b/configure
index e027d3a..3d80b0d 100755
--- a/configure
+++ b/configure
@@ -5555,7 +5555,14 @@ $as_echo "yes" >&6; }
 else
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       CFLAGS="$CFLAGS"        # DONOT TURN OF ASSERTIONS
+       if test -f $srcdir/.dev
+       then
+               CFLAGS="$CFLAGS -DLDBLTEST=1"   # DO NOT TURN OFF ASSERTIONS
+#              cp $srcdir/misc/float128.c $srcdir/
+#              sed -i 's/^gawk_SOURCES = $(base_sources)$/& float128.c/' 
$srcdir/Makefile.am
+       else
+               CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
+       fi
 fi
 
 
diff --git a/configure.ac b/configure.ac
index e8686e0..2a13506 100644
--- a/configure.ac
+++ b/configure.ac
@@ -95,7 +95,14 @@ then
        AC_MSG_RESULT([yes])
 else
        AC_MSG_RESULT([no])
-       CFLAGS="$CFLAGS"        # DONOT TURN OF ASSERTIONS
+       if test -f $srcdir/.dev
+       then
+               CFLAGS="$CFLAGS -DLDBLTEST=1"   # DO NOT TURN OFF ASSERTIONS
+#              cp $srcdir/misc/float128.c $srcdir/
+#              sed -i 's/^gawk_SOURCES = $(base_sources)$/& float128.c/' 
$srcdir/Makefile.am
+       else
+               CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
+       fi
 fi
 
 AC_SUBST(CFLAGS)
diff --git a/float128.c b/float128.c
new file mode 100644
index 0000000..0910a68
--- /dev/null
+++ b/float128.c
@@ -0,0 +1,112 @@
+#include "awk.h"
+
+#if defined(LDBLTEST) && LDBLTEST == 1
+#include <math.h>
+#include "random.h"
+#if 0
+#include "floatmagic.h"        /* definition of isnan -- XXX: only for float 
or double or long double */
+#endif
+
+#include "format.h"
+
+/* XXX: No libquadmath, and don't want or need it anyway. */
+
+/*
+ * Macros copied from quadmath.h
+ *     https://github.com/mirrors/gcc/blob/master/libquadmath/quadmath.h
+ */
+
+#define FLT128_MAX 1.18973149535723176508575932662800702e4932Q
+#define FLT128_MIN 3.36210314311209350626267781732175260e-4932Q
+#define FLT128_EPSILON 1.92592994438723585305597794258492732e-34Q
+#define FLT128_DENORM_MIN 6.475175119438025110924438958227646552e-4966Q
+#define FLT128_MANT_DIG 113
+#define FLT128_MIN_EXP (-16381)
+#define FLT128_MAX_EXP 16384
+#define FLT128_DIG 33
+#define FLT128_MIN_10_EXP (-4931)
+#define FLT128_MAX_10_EXP 4932
+
+/* #define HUGE_VALQ __builtin_huge_valq() */
+/* The following alternative is valid, but brings the warning:
+   (floating constant exceeds range of ‘__float128’)  */
+#define HUGE_VALQ (__extension__ 0x1.0p32767Q)
+
+/* end of Macros from quadmath.h */
+
+#define LDBL_FRAC_BITS FLT128_MANT_DIG
+
+#define AWKLDBL        __float128
+#define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
+#define LDC(x)         x##Q
+
+#define        LDBL_INT_BITS   128
+
+#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), "float128")
+#define free_long_double(d)    efree(d)
+
+static int format_float_1(char *str, size_t size, const char *format, ...);
+static AWKLDBL double_to_int(AWKLDBL);
+
+static inline AWKLDBL
+gawk_strtold(const char *str, char **endptr)
+{
+#ifdef HAVE_STRTOLD
+       return strtold(str, endptr);
+#else
+       return strtod(str, endptr);
+#endif
+}
+
+/* Define isnan() and isinf() before including the two files */
+
+static inline int isnan_awkldbl(AWKLDBL x) { return x != x; }
+#ifdef isnan
+#undef isnan
+#endif
+#define isnan isnan_awkldbl
+
+static inline int isinf_awkldbl(AWKLDBL x) { return isnan(x - x); }
+#ifdef isinf
+#undef isinf
+#endif
+#define isinf isinf_awkldbl
+
+#define GAWK_INFINITY  HUGE_VALQ
+#define GAWK_NAN       (LDC(0.0Q) / LDC(0.0Q))
+
+
+#ifdef HAVE_FLOORL
+#undef HAVE_FLOORL
+#endif
+#ifdef HAVE_CEILL
+#undef HAVE_CEILL
+#endif
+#ifdef PRINTF_HAS_LF_FORMAT
+#undef PRINTF_HAS_LF_FORMAT
+#endif
+
+numbr_handler_t float128_hndlr;
+
+#define awkldbl_hndlr float128_hndlr
+
+#define gawk_int_t long long
+#define gawk_uint_t unsigned long long
+#ifdef SIZEOF_GAWK_INT
+#undef SIZEOF_GAWK_INT
+#undef GAWK_INT_MAX
+#undef GAWK_INT_MIN
+#undef GAWK_UINT_MAX
+#endif
+
+#define SIZEOF_GAWK_INT        8
+#define        GAWK_INT_MAX    LLONG_MAX
+#define        GAWK_INT_MIN    LLONG_MIN
+#define        GAWK_UINT_MAX   ULLONG_MAX
+
+#define TEST_NUMBR 1
+
+#include "misc/gawk_math.h"
+#include "long_double.h"
+
+#endif /* LDBLTEST == 1 */
diff --git a/long_double.c b/long_double.c
index ca2b206..a2fc40e 100644
--- a/long_double.c
+++ b/long_double.c
@@ -220,3 +220,15 @@ awkldbl_init(bltin_t **bltins)
        return false;
 }
 #endif
+
+
+numbr_handler_t *
+get_ldbl_handler(char *arg)
+{
+#if defined(LDBLTEST) && LDBLTEST == 1
+       extern numbr_handler_t float128_hndlr;
+       if (arg != NULL && arg[0] == '1')
+               return & float128_hndlr;
+#endif
+       return  & awkldbl_hndlr;
+}
diff --git a/main.c b/main.c
index a22429c..7857c42 100644
--- a/main.c
+++ b/main.c
@@ -62,6 +62,8 @@ static void print_numbr_hndlr_versions(void);
 extern int debug_prog(INSTRUCTION *pc); /* debug.c */
 extern int init_debug(void);   /* debug.c */
 extern void init_parser(const bltin_t *);      /* awkgram.c */
+extern numbr_handler_t *get_ldbl_handler(char *arg);
+
 
 /* These nodes store all the special variables AWK uses */
 NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
@@ -204,7 +206,7 @@ main(int argc, char **argv)
        /*
         * The + on the front tells GNU getopt not to rearrange argv.
         */
-       const char *optlist = 
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::BMPrStVY";
+       const char *optlist = 
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::B::MPrStVY";
        bool stopped_early = false;
        int old_optind;
        int i;
@@ -368,7 +370,7 @@ main(int argc, char **argv)
                        break;
 
                case 'B':
-                       numbr_hndlr = & awkldbl_hndlr;
+                       numbr_hndlr = get_ldbl_handler(optarg);
                        break;
                        
                case 'c':
diff --git a/misc/gawk_math.h b/misc/gawk_math.h
new file mode 100644
index 0000000..e34bfae
--- /dev/null
+++ b/misc/gawk_math.h
@@ -0,0 +1,88 @@
+static AWKLDBL gawk_sinl(AWKLDBL x);
+static AWKLDBL gawk_cosl(AWKLDBL x);
+static AWKLDBL gawk_atan2l(AWKLDBL y, AWKLDBL x);
+static AWKLDBL gawk_logl(AWKLDBL x);
+static AWKLDBL gawk_expl(AWKLDBL x);
+static AWKLDBL gawk_fmodl(AWKLDBL x, AWKLDBL y);
+static AWKLDBL gawk_powl(AWKLDBL x, AWKLDBL y);
+static AWKLDBL gawk_sqrtl(AWKLDBL x);
+
+static AWKLDBL
+gawk_sinl(AWKLDBL x)
+{
+#ifdef HAVE_SINL
+       return sinl( (long double) x);
+#else
+       return sin( (double) x);
+#endif
+}
+
+static AWKLDBL
+gawk_cosl(AWKLDBL x)
+{
+#ifdef HAVE_COSL
+       return cosl( (long double) x);
+#else
+       return cos( (double) x);
+#endif
+}
+
+static AWKLDBL
+gawk_atan2l(AWKLDBL y, AWKLDBL x)
+{
+#ifdef HAVE_ATAN2L
+       return atan2l( (long double) y, (long double) x);
+#else
+       return atan2( (double) y, (double) x);
+#endif
+}
+
+static AWKLDBL
+gawk_logl(AWKLDBL x)
+{
+#ifdef HAVE_LOGL
+       return logl( (long double) x);
+#else
+       return log( (double) x);
+#endif
+}
+
+static AWKLDBL
+gawk_expl(AWKLDBL x)
+{
+#ifdef HAVE_LOGL
+       return expl( (long double) x);
+#else
+       return exp( (double) x);
+#endif
+}
+
+static AWKLDBL
+gawk_fmodl(AWKLDBL x, AWKLDBL y)
+{
+#ifdef HAVE_FMODL
+       return fmodl( (long double) x, (long double) y);
+#else
+       return fmod( (double) x, (double) y);
+#endif
+}
+
+static AWKLDBL
+gawk_powl(AWKLDBL x, AWKLDBL y)
+{
+#ifdef HAVE_POWL
+       return powl( (long double) x, (long double) y);
+#else
+       return pow( (double) x, (double) y);
+#endif
+}
+
+static AWKLDBL
+gawk_sqrtl(AWKLDBL x)
+{
+#ifdef HAVE_SQRTL
+       return sqrtl( (long double) x);
+#else
+       return sqrt( (double) x);
+#endif 
+}

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=11961fbf6bc7340892176ea4911ba5ea2c130296

commit 11961fbf6bc7340892176ea4911ba5ea2c130296
Author: John Haque <address@hidden>
Date:   Sat Jan 19 06:39:40 2013 -0600

    Support "%0.Lf" integer formatting for platforms without "%Lf" in printf.

diff --git a/ChangeLog b/ChangeLog
index 0b96b4a..361a0e8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,22 @@
+2013-01-19         John Haque      <address@hidden>
+
+       For C long double and without "%Lf" in printf, provide "%.0Lf" to
+       format 64-bit wide (and wider with a 128-bit long double) integers
+       correctly; "%Lf" format support in printf is now optional. 
+
+       * awk.h (gawk_int_t, gawk_uint_t): New types.
+       * long_double.c: Restructured. Swap code with long_double.h. 
+       * long_double.h: Move all header includes and defines to long_double.c;
+       It is a template to be included in a *.c file.
+       (gawk_floorl_finite_p, format_uint_finite_p,
+       format_float_1, init_pow2d_table): New routines.
+       (double_to_int): Provide replacement routine definition.  
+
+       Unrelated:
+
+       * long_double.h (make_integer): Remove call to adjust_uint().
+       Install similar code suitable for a long double.
+
 2013-01-12         John Haque      <address@hidden>
 
        * format.c: New file.
diff --git a/Makefile.in b/Makefile.in
index 202d362..82c8a92 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -289,6 +289,7 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 POSUB = @POSUB@
+PRINTF_HAS_LF_FORMAT = @PRINTF_HAS_LF_FORMAT@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
diff --git a/TODO.LDBL b/TODO.LDBL
index f81fe53..f0bf2c9 100644
--- a/TODO.LDBL
+++ b/TODO.LDBL
@@ -12,5 +12,6 @@ for long doubles, these can't even get 64 bit integers!
 
 * Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM. What 
is the point
 of floor() and ceil() wrappers? Don't have a clue.
-
-
+       -- DONE. Not sure if it is necessary for any long double and uintmax_t
+       combination found in the wild. Looks like ceil() and floor() wrappers
+       are for VMS; one probably should update comments in floatcomp.c.
diff --git a/awk.h b/awk.h
index bb39b20..bd2a2ce 100644
--- a/awk.h
+++ b/awk.h
@@ -862,6 +862,42 @@ typedef struct exp_instruction {
 #define initval         x.xn
 
 
+#if ! (defined(TEST_NUMBR) && TEST_NUMBR == 1)
+#if SIZEOF_UNSIGNED_LONG == 8
+typedef long gawk_int_t;
+typedef unsigned long gawk_uint_t;
+#define SIZEOF_GAWK_INT        8
+#define        GAWK_INT_MAX    LONG_MAX
+#define        GAWK_INT_MIN    LONG_MIN
+#define        GAWK_UINT_MAX   ULONG_MAX
+#else
+#if SIZEOF_UNSIGNED_LONG == 4
+typedef long gawk_int_t;
+typedef unsigned long gawk_uint_t;
+#define SIZEOF_GAWK_INT        4
+#define        GAWK_INT_MAX    LONG_MAX
+#define        GAWK_INT_MIN    LONG_MIN
+#define        GAWK_UINT_MAX   ULONG_MAX
+#else
+typedef int gawk_int_t;
+typedef unsigned int gawk_uint_t;
+#define        SIZEOF_GAWK_INT SIZEOF_UNSIGNED_INT
+#define        GAWK_INT_MAX    INT_MAX
+#define        GAWK_INT_MIN    INT_MIN
+#define        GAWK_UINT_MAX   UINT_MAX
+#endif
+#endif
+#else /* TEST_NUMBR */
+/* XXX: think twice before using these for any other purpose. */
+typedef long long gawk_int_t;
+typedef unsigned long long gawk_uint_t;
+#define SIZEOF_GAWK_INT        8
+#define        GAWK_INT_MAX    LLONG_MAX
+#define        GAWK_INT_MIN    LLONG_MIN
+#define        GAWK_UINT_MAX   ULLONG_MAX
+#endif /* TEST_NUMBR */
+
+
 typedef struct {
        const char *name;       /* name of the built-in */
        NODE *(*ptr)(int);      /* function that implements this built-in */
diff --git a/awklib/Makefile.in b/awklib/Makefile.in
index 347d369..7bfc1bc 100644
--- a/awklib/Makefile.in
+++ b/awklib/Makefile.in
@@ -212,6 +212,7 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 POSUB = @POSUB@
+PRINTF_HAS_LF_FORMAT = @PRINTF_HAS_LF_FORMAT@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
diff --git a/configh.in b/configh.in
index af6b30f..66511a9 100644
--- a/configh.in
+++ b/configh.in
@@ -387,6 +387,9 @@
 /* Define to 1 if *printf supports %F format */
 #undef PRINTF_HAS_F_FORMAT
 
+/* Define to 1 if printf supports %Lf format. */
+#undef PRINTF_HAS_LF_FORMAT
+
 /* Define as the return type of signal handlers (`int' or `void'). */
 #undef RETSIGTYPE
 
diff --git a/configure b/configure
index 0bb8f5f..e027d3a 100755
--- a/configure
+++ b/configure
@@ -633,6 +633,7 @@ GAWKLIBEXT
 LIBMPFR
 LIBREADLINE
 SOCKET_LIBS
+PRINTF_HAS_LF_FORMAT
 USE_LONG_DOUBLE
 LIBSIGSEGV_PREFIX
 LTLIBSIGSEGV
@@ -10302,9 +10303,7 @@ fi
 fi
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gawk_cv_has_L_format" >&5
 $as_echo "$gawk_cv_has_L_format" >&6; }
-      if test $gawk_cv_has_L_format = yes; then
-        gawk_has_long_double=yes
-      fi
+       gawk_has_long_double=yes
     fi
   fi
 
@@ -10312,6 +10311,11 @@ $as_echo "$gawk_cv_has_L_format" >&6; }
 
 $as_echo "#define USE_LONG_DOUBLE 1" >>confdefs.h
 
+    if test $gawk_cv_has_L_format = yes; then
+
+$as_echo "#define PRINTF_HAS_LF_FORMAT 1" >>confdefs.h
+
+    fi
 
     ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold"
 if test "x$ac_cv_func_strtold" = xyes; then :
@@ -10830,6 +10834,7 @@ $as_echo "#define HAVE_SQRTL 1" >>confdefs.h
 
 
 
+
 gawk_have_sockets=no
 # Check for system-dependent location of socket libraries
 
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 691d030..1834719 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -207,6 +207,7 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 POSUB = @POSUB@
+PRINTF_HAS_LF_FORMAT = @PRINTF_HAS_LF_FORMAT@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
diff --git a/long_double.c b/long_double.c
index e85fea2..ca2b206 100644
--- a/long_double.c
+++ b/long_double.c
@@ -22,10 +22,10 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
-
 #include "awk.h"
 
 #ifdef USE_LONG_DOUBLE
+
 #include <math.h>
 #include "random.h"
 #include "floatmagic.h"        /* definition of isnan */
@@ -33,1597 +33,175 @@
 #include "format.h"
 
 #define AWKLDBL        long double
-
-#include "long_double.h"
-
 #define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
 #define LDC(x)         x##L
 
-/* Can declare these, since we always use the random shipped with gawk */
-extern char *initstate(unsigned long seed, char *state, long n);
-extern char *setstate(char *state);
-extern long random(void);
-extern void srandom(unsigned long seed);
+#ifndef FLT_RADIX
+#define FLT_RADIX 2
+#endif
 
 /*
- * Since we supply the version of random(), we know what
- * value to use here.
+ * XXX: LDBL_MANT_DIG is defined if we are here. Assume FLT_RADIX = 2 or 16.
  */
-#define GAWK_RANDOM_MAX 0x7fffffffL
+#if FLT_RADIX == 2
+#define LDBL_FRAC_BITS LDBL_MANT_DIG
+#else
+#define LDBL_FRAC_BITS (4 * LDBL_MANT_DIG)
+#endif
 
 /*
- * FIXME -- some of these are almost identical except for the number definition
- * #define DBLNUM      AWKNUM
- *     common routines
- * #undef DBLNUM
- * #define DBLNUM      AWKLDBL
- *     ...
+ * N.B: If printf does not have "%Lf" format and the long double type is 
capable of
+ * supporting integers wider than 64 bits, must have 64-bit long type.
+ *
+ * We actually use a maximum of 113 bits when LDBL_INT_BITS is 128.
  */
 
-/* exported routines */
-
-static NODE *make_awknum(AWKNUM);
-static void free_awkldbl(NODE *tmp);
-static int cmp_awkldbls(const NODE *, const NODE *);
-static void negate_awkldbl(NODE *);
-static NODE *str2awkldbl(char *, char **, int, bool);
-static NODE *force_awkldbl(NODE *);
-static NODE *format_awkldbl_val(const char *, int, NODE *);
-static unsigned long awkldbl_toulong(const NODE *);
-static long awkldbl_tolong(const NODE *);
-static double awkldbl_todouble(const NODE *);
-static uintmax_t awkldbl_touintmax_t(const NODE *);
-static int awkldbl_sgn(const NODE *);
-static bool awkldbl_isinteger(const NODE *);
-static bool awkldbl_isnan(const NODE *);
-static bool awkldbl_isinf(const NODE *);
-static NODE *awkldbl_copy(const NODE *);
-static int format_awkldbl_printf(NODE *, struct format_spec *, struct 
print_fmt_buf *);
-static bool awkldbl_init(bltin_t **);
-static NODE *awkldbl_add(const NODE *, const NODE *);
-static NODE *awkldbl_sub(const NODE *, const NODE *);
-static NODE *awkldbl_mul(const NODE *, const NODE *);
-static NODE *awkldbl_div(const NODE *, const NODE *);
-static NODE *awkldbl_mod(const NODE *, const NODE *);
-static NODE *awkldbl_pow(const NODE *, const NODE *);
-static NODE *awkldbl_add_long(const NODE *, long);
-static NODE *awkldbl_update_var(NODE *);
-static void awkldbl_set_var(const NODE *);
-static long awkldbl_increment_var(const NODE *, long);
-static void awkldbl_init_vars(void);
-
-static NODE *do_and(int);
-static NODE *do_atan2(int);
-static NODE *do_compl(int);
-static NODE *do_cos(int);
-static NODE *do_exp(int);
-static NODE *do_int(int);
-static NODE *do_log(int);
-static NODE *do_lshift(int);
-static NODE *do_or(int);
-static NODE *do_rand(int);
-static NODE *do_rshift(int);
-static NODE *do_sin(int);
-static NODE *do_sqrt(int);
-static NODE *do_srand(int);
-static NODE *do_strtonum(int);
-static NODE *do_xor(int);
-
-/* private routines */
-static int is_ieee_magic_val(const char *val);
-static AWKLDBL get_ieee_magic_val(const char *val);
-static AWKLDBL calc_exp(AWKLDBL x1, AWKLDBL x2);
-static AWKLDBL double_to_int(AWKLDBL d);
-static NODE *make_awkldbl(AWKLDBL);
-
-static long MFNR;
-static long MNR;
+#if SIZEOF_GAWK_INT == 8 && LDBL_FRAC_BITS > 64
+#define        LDBL_INT_BITS   128
+#else
+#define        LDBL_INT_BITS   64
+#endif
 
 #define get_long_double(d)     getblock(d, BLOCK_LDBL, AWKLDBL *)
 #define free_long_double(d)    freeblock(d, BLOCK_LDBL)
 
-#if 0
-#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), 
"long_double")
-#define free_long_double(d)    efree(d)
-#endif
-
-numbr_handler_t awkldbl_hndlr = {
-       awkldbl_init,
-       NULL,   /* version_str */
-       NULL,   /* load_procinfo */
-       make_awknum,
-       str2awkldbl,
-       awkldbl_copy,
-       free_awkldbl,
-       force_awkldbl,
-       negate_awkldbl,
-       cmp_awkldbls,
-       awkldbl_sgn,
-       awkldbl_isinteger,
-       awkldbl_isnan,
-       awkldbl_isinf,
-       format_awkldbl_val,
-       format_awkldbl_printf,
-       awkldbl_todouble,
-       awkldbl_tolong,
-       awkldbl_toulong,
-       awkldbl_touintmax_t,
-       awkldbl_add,
-       awkldbl_sub,
-       awkldbl_mul,
-       awkldbl_div,
-       awkldbl_mod,
-       awkldbl_pow,
-       awkldbl_add_long,
-       awkldbl_update_var,
-       awkldbl_set_var,
-       awkldbl_increment_var,
-       awkldbl_init_vars,
-};
-
-/* awkldbl_init --- initialization routine */
-
-static bool
-awkldbl_init(bltin_t **numbr_bltins)
-{
-       static bltin_t awkldbl_bltins[] = {
-               { "and",        do_and },
-               { "atan2",      do_atan2 },
-               { "compl",      do_compl },
-               { "cos",        do_cos },
-               { "exp",        do_exp },
-               { "int",        do_int },
-               { "log",        do_log },
-               { "lshift",     do_lshift },
-               { "or",         do_or },
-               { "rand",       do_rand },
-               { "rshift",     do_rshift },
-               { "sin",        do_sin },
-               { "sqrt",       do_sqrt },
-               { "srand",      do_srand },
-               { "strtonum",   do_strtonum },
-               { "xor",        do_xor },
-               { NULL, NULL },
-       };
-
-       /* set the numeric value of null string */
-       get_long_double(Nnull_string->qnumbr);
-       LDBL_VAL(Nnull_string) = LDC(0.0);
-       Nnull_string->flags |= (NUMCUR|NUMBER);
-
-       /* initialize TRUE and FALSE nodes */
-       false_node = make_awkldbl(LDC(0.0));
-       true_node = make_awkldbl(LDC(1.0));
-       false_node->flags |= NUMINT;
-       true_node->flags |= NUMINT;
-
-       *numbr_bltins = awkldbl_bltins;
-       return true;
-}
-
-/* awkldbl_toulong --- conversion to unsigned long */
-
-static unsigned long
-awkldbl_toulong(const NODE *n)
-{
-       return LDBL_VAL(n);
-}
-
-/* awkldbl_tolong --- conversion to long */
-
-static long
-awkldbl_tolong(const NODE *n)
-{
-       return LDBL_VAL(n);
-}
-
-/* awkldbl_todouble --- conversion to double */
-
-static double
-awkldbl_todouble(const NODE *n)
-{
-       return LDBL_VAL(n);
-}
-
-/* awkldbl_touintmax_t --- conversion to uintmax_t */
-
-static uintmax_t
-awkldbl_touintmax_t(const NODE *n)
-{
-       return LDBL_VAL(n);
-}
-
-/* awkldbl_sgn --- return 1 if number > 0, zero if number == 0, and -1 if 
number < 0 */
-
-static int
-awkldbl_sgn(const NODE *n)
-{
-       AWKLDBL d = LDBL_VAL(n);
-       return (d < LDC(0.0) ? -1 : d > LDC(0.0));
-}
-
-/* awkldbl_isinteger --- check if a number is an integer */
-
-static bool
-awkldbl_isinteger(const NODE *n)
-{
-       AWKLDBL d = LDBL_VAL(n);
-
-       if (isnan(d) || isinf(d))
-               return false;
-       return double_to_int(d) == d;
-}
-
-/* awkldbl_isnan --- check if number is NaN */
-
-static bool
-awkldbl_isnan(const NODE *n)
-{
-       return isnan(LDBL_VAL(n));
-}
-
-/* awkldbl_isinf --- check if number is infinity */
-
-static bool
-awkldbl_isinf(const NODE *n)
-{
-       return isinf(LDBL_VAL(n));
-}
-
-/* negate_awkldbl --- negate number in NODE */
-
-static void
-negate_awkldbl(NODE *n)
-{
-       LDBL_VAL(n) = - LDBL_VAL(n);
-}
-
-/* awkldbl_add --- add two numbers */
-
-static NODE *
-awkldbl_add(const NODE *t1, const NODE *t2)
-{
-       return make_awkldbl(LDBL_VAL(t1) + LDBL_VAL(t2));
-}
-
-/* awkldbl_sub --- subtract two numbers */
-
-static NODE *
-awkldbl_sub(const NODE *t1, const NODE *t2)
-{
-       return make_awkldbl(LDBL_VAL(t1) - LDBL_VAL(t2));
-}
-
-/* awkldbl_mul --- multiply two numbers */
-
-static NODE *
-awkldbl_mul(const NODE *t1, const NODE *t2)
-{
-       return make_awkldbl(LDBL_VAL(t1) * LDBL_VAL(t2));
-}
-
-/* awkldbl_add --- quotient of two numbers */
-
-static NODE *
-awkldbl_div(const NODE *t1, const NODE *t2)
-{
-       AWKLDBL d = LDBL_VAL(t2);
-       if (d == 0)
-               fatal(_("division by zero attempted"));
-       return make_awkldbl(LDBL_VAL(t1) / d);
-}
-
-/* awkldbl_add_long --- add long value to a number */
-
-static NODE *
-awkldbl_add_long(const NODE *t1, long n)
-{
-       return make_awkldbl(LDBL_VAL(t1) + (AWKLDBL) n);
-}
-
-/* awkldbl_copy --- copy a number */
-
-static NODE *
-awkldbl_copy(const NODE *t1)
-{
-       return make_awkldbl(LDBL_VAL(t1));
-}
-
-/* awkldbl_update_var --- update a special variable from internal variables */
-
-static NODE *
-awkldbl_update_var(NODE *var)
-{
-       NODE *val = var->var_value;
-       AWKLDBL d;
-
-       d = LDBL_VAL(val);
-       if (var == NR_node) {
-               if (MNR == 0 && d != NR) {
-                       unref(val);
-                       val = NR_node->var_value = make_awkldbl((AWKLDBL) NR);
-               } else if (MNR != 0) {
-                       unref(val);
-                       d = ((AWKLDBL) MNR) * LONG_MAX + (AWKLDBL) NR;
-                       val = var->var_value = make_awkldbl(d);
-               }
-               return val;
-       }
-
-       assert(var == FNR_node);
-       if (MFNR == 0 && d != FNR) {
-               unref(val);
-               val = FNR_node->var_value = make_awkldbl((AWKLDBL) FNR);
-       } else if (MFNR != 0) {
-               unref(val);
-               d = ((AWKLDBL) MFNR) * LONG_MAX + (AWKLDBL) FNR;
-               val = var->var_value = make_awkldbl(d);
-       }
-       return val;
-}
-
-/*
- * awkldbl_set_vars --- update internal variables for assignment
- *     to a special variable.
- */
-
-static void
-awkldbl_set_var(const NODE *var)
-{
-       NODE *val = var->var_value;
-       AWKLDBL d;
-
-       d = LDBL_VAL(val);
-       if (var == NR_node) {
-               MNR = d / LONG_MAX;
-               NR = d - ((AWKLDBL) MNR) * LONG_MAX;
-       } else if (var == FNR_node) {
-               MFNR = d / LONG_MAX;
-               FNR = d - ((AWKLDBL) MFNR) * LONG_MAX;
-       }
-       /* N.B: PREC and ROUNMODE -- not relevant */
-}
-
-/* awkldbl_increment_var --- increment NR or FNR */
-
-static long
-awkldbl_increment_var(const NODE *var, long nr)
-{
-       if (nr == LONG_MAX - 1) {
-               /* increment quotient, set remainder(NR or FNR) to 0 */
-               if (var == NR_node)
-                       MNR++;
-               else /* var == FNR_node */
-                       MFNR++;
-               return 0;
-       }
-       return ++nr;
-}
-
-/* awkldbl_init_vars --- initialize special variables */
-
-static void
-awkldbl_init_vars()
-{
-       /* dummy function */
-}
-
-/*
- * make_awkldbl --- allocate a node with defined number;
- *     this routine is not exported. 
- */
-
-static NODE *
-make_awkldbl(AWKLDBL x)
-{
-       NODE *r;
-       getnode(r);
-       r->type = Node_val;
-       get_long_double(r->qnumbr);
-       LDBL_VAL(r) = x;
-       r->flags = MALLOC|NUMBER|NUMCUR;
-       r->valref = 1;
-       r->stptr = NULL;
-       r->stlen = 0;
-#if MBS_SUPPORT
-       r->wstptr = NULL;
-       r->wstlen = 0;
-#endif /* defined MBS_SUPPORT */
-       return r;
-}
-
-/* make_awknum --- allocate a node with defined AWKNUM */
-
-static NODE *
-make_awknum(AWKNUM x)
-{
-       NODE *r;
-       getnode(r);
-       r->type = Node_val;
-       get_long_double(r->qnumbr);
-       LDBL_VAL(r) = (AWKLDBL) x;
-       r->flags = MALLOC|NUMBER|NUMCUR;
-       r->valref = 1;
-       r->stptr = NULL;
-       r->stlen = 0;
-#if MBS_SUPPORT
-       r->wstptr = NULL;
-       r->wstlen = 0;
-#endif /* defined MBS_SUPPORT */
-       return r;
-}
-
-/* free_awkldbl --- free all storage allocated for a AWKLDBL */
-
-static void
-free_awkldbl(NODE *tmp)
-{
-       assert((tmp->flags & (NUMBER|NUMCUR)) != 0);
-        free_long_double(tmp->qnumbr);
-}
-
-/* make_integer --- Convert an integer to a number node. */
-
-static inline NODE *
-make_integer(uintmax_t n)
-{
-       /* TODO -- check adjust_uint (floatcomp.c) */
-
-       n = adjust_uint(n);
-       return make_awkldbl(n);
-}
-
-/* do_lshift --- perform a << operation */
-
-static NODE *
-do_lshift(int nargs)
-{
-       NODE *s1, *s2;
-       uintmax_t uval, ushift, res;
-       AWKLDBL val, shift;
-
-       s2 = POP_SCALAR();
-       s1 = POP_SCALAR();
-       if (do_lint) {
-               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("lshift: received non-numeric first 
argument"));
-               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("lshift: received non-numeric second 
argument"));
-       }
-
-       (void) force_number(s1);
-       (void) force_number(s2);
-       val = LDBL_VAL(s1);
-       shift = LDBL_VAL(s2);
-
-       if (do_lint) {
-               if (val < 0 || shift < 0)
-                       lintwarn(_("lshift(%Lf, %Lf): negative values will give 
strange results"),
-                                       val, shift);
-               if (double_to_int(val) != val || double_to_int(shift) != shift)
-                       lintwarn(_("lshift(%Lf, %Lf): fractional values will be 
truncated"),
-                                       val, shift);
-               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
-                       lintwarn(_("lshift(%Lf, %Lf): too large shift value 
will give strange results"),
-                                       val, shift);
-       }
-
-       DEREF(s1);
-       DEREF(s2);
-       uval = (uintmax_t) val;
-       ushift = (uintmax_t) shift;
-       res = uval << ushift;
-       return make_integer(res);
-}
-
-/* do_rshift --- perform a >> operation */
-
-static NODE *
-do_rshift(int nargs)
-{
-       NODE *s1, *s2;
-       uintmax_t uval, ushift, res;
-       AWKLDBL val, shift;
-
-       s2 = POP_SCALAR();
-       s1 = POP_SCALAR();
-       if (do_lint) {
-               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("rshift: received non-numeric first 
argument"));
-               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("rshift: received non-numeric second 
argument"));
-       }
-       (void) force_number(s1);
-       (void) force_number(s2);
-       val = LDBL_VAL(s1);
-       shift = LDBL_VAL(s2);
-       if (do_lint) {
-               if (val < 0 || shift < 0)
-                       lintwarn(_("rshift(%Lf, %Lf): negative values will give 
strange results"),
-                                       val, shift);
-               if (double_to_int(val) != val || double_to_int(shift) != shift)
-                       lintwarn(_("rshift(%Lf, %Lf): fractional values will be 
truncated"),
-                                       val, shift);
-               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
-                       lintwarn(_("rshift(%Lf, %Lf): too large shift value 
will give strange results"),
-                                       val, shift);
-       }
-
-       DEREF(s1);
-       DEREF(s2);
-       uval = (uintmax_t) val;
-       ushift = (uintmax_t) shift;
-       res = uval >> ushift;
-       return make_integer(res);
-}
-
-/* do_and --- perform an & operation */
-
-static NODE *
-do_and(int nargs)
-{
-       NODE *s1;
-       uintmax_t res, uval;
-       AWKLDBL val;
-       int i;
-
-       res = ~0;       /* start off with all ones */
-       if (nargs < 2)
-               fatal(_("and: called with less than two arguments"));
-
-       for (i = 1; nargs > 0; nargs--, i++) {
-               s1 = POP_SCALAR();
-               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("and: argument %d is non-numeric"), i);
-
-               (void) force_number(s1);
-               val = LDBL_VAL(s1);
-               if (do_lint && val < 0)
-                       lintwarn(_("and: argument %d negative value %Lg will 
give strange results"),
-                                       i, val);
-
-               uval = (uintmax_t) val;
-               res &= uval;
-               DEREF(s1);
-       }
-
-       return make_integer(res);
-}
-
-/* do_or --- perform an | operation */
-
-static NODE *
-do_or(int nargs)
-{
-       NODE *s1;
-       uintmax_t res, uval;
-       AWKLDBL val;
-       int i;
-
-       res = 0;
-       if (nargs < 2)
-               fatal(_("or: called with less than two arguments"));
-
-       for (i = 1; nargs > 0; nargs--, i++) {
-               s1 = POP_SCALAR();
-               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("or: argument %d is non-numeric"), i);
-
-               (void) force_number(s1);
-               val = LDBL_VAL(s1);
-               if (do_lint && val < 0)
-                       lintwarn(_("or: argument %d negative value %Lg will 
give strange results"),
-                                       i, val);
-
-               uval = (uintmax_t) val;
-               res |= uval;
-
-               DEREF(s1);
-       }
-
-       return make_integer(res);
-}
-
-/* do_xor --- perform an ^ operation */
-
-static NODE *
-do_xor(int nargs)
-{
-       NODE *s1;
-       uintmax_t res, uval;
-       AWKLDBL val;
-       int i;
-
-       if (nargs < 2)
-               fatal(_("xor: called with less than two arguments"));
-
-       res = 0;        /* silence compiler warning */
-       for (i = 1; nargs > 0; nargs--, i++) {
-               s1 = POP_SCALAR();
-               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("xor: argument %d is non-numeric"), i);
-
-               (void) force_number(s1);
-               val = LDBL_VAL(s1);
-               if (do_lint && val < 0)
-                       lintwarn(_("xor: argument %d negative value %Lg will 
give strange results"),
-                                       i, val);
-
-               uval = (uintmax_t) val;
-               if (i == 1)
-                       res = uval;
-               else
-                       res ^= uval;
-               DEREF(s1);
-       }
-
-       return make_integer(res);
-}
-
-/* do_compl --- perform a ~ operation */
-
-static NODE *
-do_compl(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL d;
-       uintmax_t uval;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("compl: received non-numeric argument"));
-       (void) force_number(tmp);
-       d = LDBL_VAL(tmp);
-       DEREF(tmp);
-
-       if (do_lint) {
-               if (d < 0)
-                       lintwarn(_("compl(%Lf): negative value will give 
strange results"), d);
-               if (double_to_int(d) != d)
-                       lintwarn(_("compl(%Lf): fractional value will be 
truncated"), d);
-       }
-
-       uval = (uintmax_t) d;
-       uval = ~ uval;
-       return make_integer(uval);
-}
-
-/* nondec2awkldbl --- convert octal or hex value to long double */
-
-/*
- * Because of awk's concatenation rules and the way awk.y:yylex()
- * collects a number, this routine has to be willing to stop on the
- * first invalid character.
- */
-
-static AWKLDBL
-nondec2awkldbl(char *str, size_t len)
+#ifdef HAVE_SINL
+#define gawk_sinl      sinl
+#else
+static inline AWKLDBL
+gawk_sinl(AWKLDBL x)
 {
-       AWKLDBL retval = 0.0;
-       char save;
-       short val;
-       char *start = str;
-
-       if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
-               /*
-                * User called strtonum("0x") or some such,
-                * so just quit early.
-                */
-               if (len <= 2)
-                       return 0.0;
-
-               for (str += 2, len -= 2; len > 0; len--, str++) {
-                       switch (*str) {
-                       case '0':
-                       case '1':
-                       case '2':
-                       case '3':
-                       case '4':
-                       case '5':
-                       case '6':
-                       case '7':
-                       case '8':
-                       case '9':
-                               val = *str - '0';
-                               break;
-                       case 'a':
-                       case 'b':
-                       case 'c':
-                       case 'd':
-                       case 'e':
-                       case 'f':
-                               val = *str - 'a' + 10;
-                               break;
-                       case 'A':
-                       case 'B':
-                       case 'C':
-                       case 'D':
-                       case 'E':
-                       case 'F':
-                               val = *str - 'A' + 10;
-                               break;
-                       default:
-                               goto done;
-                       }
-                       retval = (retval * LDC(16.0)) + (AWKLDBL) val;
-               }
-       } else if (*str == '0') {
-               for (; len > 0; len--) {
-                       if (! isdigit((unsigned char) *str))
-                               goto done;
-                       else if (*str == '8' || *str == '9') {
-                               str = start;
-                               goto decimal;
-                       }
-                       retval = (retval * LDC(8.0)) + (AWKLDBL) (*str - '0');
-                       str++;
-               }
-       } else {
-decimal:
-               save = str[len];
-               retval = gawk_strtold(str, NULL);
-               str[len] = save;
-       }
-done:
-       return retval;
+       return sin( (double) x);
 }
+#endif
 
-
-/* do_rand --- do the rand function */
-
-static bool firstrand = true;
-/* Some systems require this array to be integer aligned. Sigh. */
-#define SIZEOF_STATE 256
-static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
-static char *const state = (char *const) istate;
-
-/* ARGSUSED */
-static NODE *
-do_rand(int nargs ATTRIBUTE_UNUSED)
+#ifdef HAVE_COSL 
+#define gawk_cosl      cosl
+#else
+static inline AWKLDBL
+gawk_cosl(AWKLDBL x)
 {
-       if (firstrand) {
-               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
-               /* don't need to srandom(1), initstate() does it for us. */
-               firstrand = false;
-               setstate(state);
-       }
-       /*
-        * Per historical practice and POSIX, return value N is
-        *
-        *      0 <= n < 1
-        */
-       return make_awkldbl((random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+       return cos( (double) x);
 }
+#endif
 
-/* do_srand --- seed the random number generator */
-
-static NODE *
-do_srand(int nargs)
+#ifdef HAVE_ATAN2L
+#define gawk_atan2l    atan2l
+#else
+static inline AWKLDBL
+gawk_atan2l(AWKLDBL y, AWKLDBL x)
 {
-       NODE *tmp;
-       static long save_seed = 1;
-       long ret = save_seed;   /* SVR4 awk srand returns previous seed */
-       AWKLDBL d;
-
-       if (firstrand) {
-               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
-               /* don't need to srandom(1), we're changing the seed below */
-               firstrand = false;
-               (void) setstate(state);
-       }
-
-       if (nargs == 0)
-               srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
-       else {
-               tmp = POP_SCALAR();
-               if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("srand: received non-numeric argument"));
-               (void) force_number(tmp);
-               d = LDBL_VAL(tmp);
-               srandom((unsigned int) (save_seed = (long) d));
-               DEREF(tmp);
-       }
-       return make_awkldbl(ret);
+       return atan2( (double) y, (double) x);
 }
+#endif
 
-/* str2awkldbl --- create a number node from string */
-
-static NODE *
-str2awkldbl(char *str, char **endptr, int base, bool is_integer 
ATTRIBUTE_UNUSED)
+#ifdef HAVE_LOGL
+#define gawk_logl      logl
+#else
+static inline AWKLDBL
+gawk_logl(AWKLDBL x)
 {
-       NODE *r;
-       AWKLDBL d;
-
-       if (base == 0) {
-               /*
-                * special case -- only used to parse input in the debugger?
-                * FIXME: reject ieee specials we don't want and/or use the same
-                * rules when reading numbers from a source file and nuke this 
case.
-                * Also in double.c.
-                */
-
-               errno = 0;
-               d = gawk_strtold(str, endptr);
-               if (errno != 0)
-                       d = LDC(0.0);
-       } else {
-               if (base == 8 || base == 16)
-                       d = nondec2awkldbl(str, strlen(str));
-               else {
-                       /* atof for double */
-                       errno = 0;
-                       d = gawk_strtold(str, NULL);
-                       if (errno != 0)
-                               d = LDC(0.0);
-                       errno = 0;
-               }
-       }
-
-       r = make_awkldbl(d);
-
-       /* XXX: is this relevant ? */
-       if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
-               r->flags |= NUMINT;
-
-       return r;
+       return log( (double) x);
 }
+#endif
 
-/* awkldbl_mod --- remainder from division of two numbers */
-
-static NODE *
-awkldbl_mod(const NODE *t1, const NODE *t2)
+#ifdef HAVE_EXPL
+#define gawk_expl      expl
+#else
+static inline AWKLDBL
+gawk_expl(AWKLDBL x)
 {
-       AWKLDBL d2;
-
-       d2 = LDBL_VAL(t2);
-       if (d2 == LDC(0.0))
-               fatal(_("division by zero attempted in `%%'"));
-       return make_awkldbl(gawk_fmodl(LDBL_VAL(t1), d2));
+       return exp( (double) x);
 }
+#endif
 
-/* awkldbl_pow --- power function */
-
-static NODE *
-awkldbl_pow(const NODE *t1, const NODE *t2)
+#ifdef HAVE_FMODL
+#define gawk_fmodl     fmodl
+#else
+static inline AWKLDBL
+gawk_fmodl(AWKLDBL x, AWKLDBL y)
 {
-       return make_awkldbl(calc_exp(LDBL_VAL(t1), LDBL_VAL(t2)));
+       return fmod( (double) x, (double) y);
 }
+#endif
 
-
-/*
- * calc_exp_posint --- calculate x^n for positive integral n,
- *     using exponentiation by squaring without recursion.
- */
-
-static AWKLDBL
-calc_exp_posint(AWKLDBL x, long n)
+#ifdef HAVE_STRTOLD
+#define gawk_strtold   strtold
+#else
+static inline AWKLDBL
+gawk_strtold(const char *str, char **endptr)
 {
-       AWKLDBL mult = LDC(1.0);
-
-       while (n > 1) {
-               if ((n % 2) == 1)
-                       mult *= x;
-               x *= x;
-               n /= 2;
-       }
-       return mult * x;
+       return strtod(str, endptr);
 }
+#endif
 
-/* calc_exp --- calculate x1^x2 */
-
-static AWKLDBL
-calc_exp(AWKLDBL x1, AWKLDBL x2)
+#ifdef HAVE_POWL
+#define gawk_powl      powl
+#else
+static inline AWKLDBL
+gawk_powl(AWKLDBL x, AWKLDBL y)
 {
-       long lx = x2;
-
-       if (((AWKLDBL) lx) == x2) {             /* integer exponent */
-               if (lx == 0)
-                       return LDC(1.0);
-               return (lx > 0) ? calc_exp_posint(x1, lx)
-                               : LDC(1.0) / calc_exp_posint(x1, -lx);
-       }
-       return gawk_powl(x1, x2);
+       return pow( (double) x, (double) y);
 }
+#endif
 
-/* cmp_awkldbls --- compare two doubles */
-
-static int
-cmp_awkldbls(const NODE *t1, const NODE *t2)
+#ifdef HAVE_SQRTL
+#define gawk_sqrtl     sqrtl
+#else
+static inline AWKLDBL
+gawk_sqrtl(AWKLDBL x)
 {
-       /*
-        * This routine is also used to sort numeric array indices or values.
-        * For the purposes of sorting, NaN is considered greater than
-        * any other value, and all NaN values are considered equivalent and 
equal.
-        * This isn't in compliance with IEEE standard, but compliance w.r.t. 
NaN
-        * comparison at the awk level is a different issue, and needs to be 
dealt
-        * with in the interpreter for each opcode seperately.
-        */
-       AWKLDBL d1 = LDBL_VAL(t1);
-       AWKLDBL d2 = LDBL_VAL(t2);
-
-       if (isnan(d1))
-               return ! isnan(d2);
-       if (isnan(d2))
-               return -1;
-       /* don't subtract, in case one or both are infinite */
-       if (d1 == d2)
-               return 0;
-       if (d1 < d2)
-               return -1;
-       return 1;
+       return sqrt( (double) x);
 }
+#endif
 
-/* force_awkldbl --- force a value to be numeric */
-
-static NODE *
-force_awkldbl(NODE *n)
-{
-       char *cp;
-       char *cpend;
-       char save;
-       char *ptr;
-       unsigned int newflags;
-
-       if ((n->flags & NUMCUR) != 0)
-               return n;
-
-       /* all the conditionals are an attempt to avoid the expensive strtod */
-
-       /* Note: only set NUMCUR if we actually convert some digits */
-
-       get_long_double(n->qnumbr);
-       LDBL_VAL(n) = LDC(0.0);
-
-       if (n->stlen == 0) {
-               return n;
-       }
-
-       cp = n->stptr;
-       /*
-        * 2/2007:
-        * POSIX, by way of severe language lawyering, seems to
-        * allow things like "inf" and "nan" to mean something.
-        * So if do_posix, the user gets what he deserves.
-        * This also allows hexadecimal floating point. Ugh.
-        */
-       if (! do_posix) {
-               if (isalpha((unsigned char) *cp)) {
-                       return n;
-               } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
-                       if ((n->flags & MAYBE_NUM) != 0)
-                               n->flags &= ~MAYBE_NUM;
-                       n->flags |= NUMBER|NUMCUR;
-                       LDBL_VAL(n) = get_ieee_magic_val(n->stptr);
-                       return n;
-               }
-               /* else
-                       fall through */
-       }
-       /* else not POSIX, so
-               fall through */
-
-       cpend = cp + n->stlen;
-       while (cp < cpend && isspace((unsigned char) *cp))
-               cp++;
-
-       if (   cp == cpend              /* only spaces, or */
-           || (! do_posix              /* not POSIXLY paranoid and */
-               && (isalpha((unsigned char) *cp)        /* letter, or */
-                                       /* CANNOT do non-decimal and saw 0x */
-                   || (! do_non_decimal_data && cp[0] == '0'
-                       && (cp[1] == 'x' || cp[1] == 'X'))))) {
-               return n;
-       }
-
-       if ((n->flags & MAYBE_NUM) != 0) {
-               newflags = NUMBER;
-               n->flags &= ~MAYBE_NUM;
-       } else
-               newflags = 0;
-
-       if (cpend - cp == 1) {          /* only one character */
-               if (isdigit((unsigned char) *cp)) {     /* it's a digit! */
-                       LDBL_VAL(n) = (AWKLDBL)(*cp - '0');
-                       n->flags |= newflags;
-                       n->flags |= NUMCUR;
-                       if (cp == n->stptr)             /* no leading spaces */
-                               n->flags |= NUMINT;
-               }
-               return n;
-       }
-
-       if (do_non_decimal_data) {      /* main.c assures false if do_posix */
-               errno = 0;
-               if (! do_traditional && get_numbase(cp, true) != 10) {
-                       LDBL_VAL(n) = nondec2awkldbl(cp, cpend - cp);
-                       n->flags |= NUMCUR;
-                       ptr = cpend;
-                       goto finish;
-               }
-       }
-
-       errno = 0;
-       save = *cpend;
-       *cpend = '\0';
-       LDBL_VAL(n) = gawk_strtold((const char *) cp, &ptr);
-
-       /* POSIX says trailing space is OK for NUMBER */
-       while (isspace((unsigned char) *ptr))
-               ptr++;
-       *cpend = save;
-finish:
-       if (errno == 0 && ptr == cpend) {
-               n->flags |= newflags;
-               n->flags |= NUMCUR;
-       } else {
-               errno = 0;
-       }
-       return n;
-}
 
+#if ! defined(PRINTF_HAS_LF_FORMAT)
+#ifdef HAVE_FLOORL
+#undef HAVE_FLOORL
+#endif
+#ifdef HAVE_CEILL
+#undef HAVE_CEILL
+#endif
+#else  /* PRINTF_HAS_LF_FORMAT */
 
 /*
- * The following lookup table is used as an optimization in force_string;
- * (more complicated) variations on this theme didn't seem to pay off, but 
- * systematic testing might be in order at some point.
+ * XXX: have "%Lf" but no floorl() and/or ceill(). ceill() (or ceil() for
+ * double) isn't really needed.
  */
-static const char *values[] = {
-       "0",
-       "1",
-       "2",
-       "3",
-       "4",
-       "5",
-       "6",
-       "7",
-       "8",
-       "9",
-};
-#define        NVAL    (sizeof(values)/sizeof(values[0]))
-
-/* format_awkldbl_val --- format a numeric value based on format */
-
-static NODE *
-format_awkldbl_val(const char *format, int index, NODE *s)
-{
-       char buf[BUFSIZ];
-       char *sp = buf;
-       AWKLDBL ival, d;
-
-       /*
-        * 2/2007: Simplify our lives here. Instead of worrying about
-        * whether or not the value will fit into a long just so we
-        * can use sprintf("%ld", val) on it, always format it ourselves.
-        * The only thing to worry about is that integral values always
-        * format as integers. %.0f does that very well.
-        *
-        * 6/2008: Would that things were so simple. Always using %.0f
-        * imposes a notable performance penalty for applications that
-        * do a lot of conversion of integers to strings. So, we reinstate
-        * the old code, but use %.0f for integral values that are outside
-        * the range of a long.  This seems a reasonable compromise.
-        *
-        * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
-        * < and > so that things work correctly on systems with 64 bit 
integers.
-        */
-
-       d = LDBL_VAL(s);
-
-       if ((s->flags & STRCUR) != 0)
-               efree(s->stptr);
-       free_wstr(s);
-
-       /* not an integral value, or out of range */
-       if ((ival = double_to_int(d)) != d
-                       || ival <= (AWKLDBL) LONG_MIN || ival >= (AWKLDBL) 
LONG_MAX
-       ) {
-               struct format_spec spec;
-               struct print_fmt_buf *outb;
-
-               /*
-                * Once upon a time, we just blindly did this:
-                *      sprintf(sp, format, s->numbr);
-                *      s->stlen = strlen(sp);
-                *      s->stfmt = (char) index;
-                * but that's no good if, e.g., OFMT is %s. So we punt,
-                * and just always format the value ourselves.
-                */
-
-               /* XXX: format_spec copied since can be altered in the 
formatting routine */
-
-               if (ival == d) {
-                       /* integral value, but outside range of %ld, use %.0f */
-                       spec = *fmt_list[INT_0f_FMT_INDEX].spec;
-                       s->stfmt = -1;
-               } else {
-                       assert(fmt_list[index].spec != NULL);   /* or can use 
fmt_parse() --- XXX */
-                       spec = *fmt_list[index].spec;
-                       s->stfmt = (char) index;        
-               }
-
-               outb = get_fmt_buf();
-               format_awkldbl_printf(s, & spec, outb);
-               (void) bytes2node(outb, s);
-               free_fmt_buf(outb);
-
-               s->stptr[s->stlen] = '\0';
-       } else {
-               /*
-                * integral value; force conversion to long only once.
-                */
-               long num = (long) ival;
-
-               if (num < NVAL && num >= 0) {
-                       sp = (char *) values[num];
-                       s->stlen = 1;
-               } else {
-                       (void) sprintf(sp, "%ld", num);
-                       s->stlen = strlen(sp);
-               }
-               s->stfmt = -1;
-               if ((s->flags & INTIND) != 0) {
-                       s->flags &= ~(INTIND|NUMBER);
-                       s->flags |= STRING;
-               }
-
-               emalloc(s->stptr, char *, s->stlen + 2, "format_awkldbl_val");
-               memcpy(s->stptr, sp, s->stlen + 1);
-       }
-
-       s->flags |= STRCUR;
-       return s;
-}
 
-/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
-
-static int
-is_ieee_magic_val(const char *val)
-{
-       /*
-        * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
-        * Assume the length is 4, as the caller checks this.
-        */
-       return (   (val[0] == '+' || val[0] == '-')
-               && (   (   (val[1] == 'i' || val[1] == 'I')
-                       && (val[2] == 'n' || val[2] == 'N')
-                       && (val[3] == 'f' || val[3] == 'F'))
-                   || (   (val[1] == 'n' || val[1] == 'N')
-                       && (val[2] == 'a' || val[2] == 'A')
-                       && (val[3] == 'n' || val[3] == 'N'))));
-}
-
-/* get_ieee_magic_val --- return magic value for string */
-
-static AWKLDBL
-get_ieee_magic_val(const char *val)
-{
-       static bool first = true;
-       static AWKLDBL inf;
-       static AWKLDBL nan;
-       char *ptr;
-       AWKLDBL v;
-
-       v = gawk_strtold(val, & ptr);
+#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
+#ifdef HAVE_FLOORL
+#undef HAVE_FLOORL
+#endif
+#ifdef HAVE_CEILL
+#undef HAVE_CEILL
+#endif
+#endif /* ! (HAVE_FLOORL && HAVE_CEILL) */ 
+#endif /* PRINTF_HAS_LF_FORMAT */
 
-       if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
-               if (first) {
-                       first = false;
-                       nan = gawk_sqrtl(-LDC(1.0));
-                       inf = -gawk_logl(LDC(0.0));
-               }
-               v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
-               if (val[0] == '-')
-                       v = -v;
-       }
+#if ! defined(PRINTF_HAS_LF_FORMAT)
+static int format_float_1(char *str, size_t size, const char *format, ...);
+#else
+#define format_float_1 snprintf
+#endif
 
-       return v;
-}
+#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
+static AWKLDBL double_to_int(AWKLDBL);
+#else
 
 /* double_to_int --- convert double to int, used in several places */
 
-static AWKLDBL
-double_to_int(AWKLDBL d)
-{
-       if (d >= LDC(0.0))
-               d = gawk_floorl(d);
-       else
-               d = gawk_ceill(d);
-       return d;
-}
-
-/* do_int --- convert double to int for awk */
-
-static NODE *
-do_int(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL d;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("int: received non-numeric argument"));
-       (void) force_number(tmp);
-       d = LDBL_VAL(tmp);
-       DEREF(tmp);
-       return make_awkldbl(double_to_int(d));
-}
-
-/* do_log --- the log function */
-
-static NODE *
-do_log(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL d, arg;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("log: received non-numeric argument"));
-       (void) force_number(tmp);
-       arg = LDBL_VAL(tmp);
-       if (arg < LDC(0.0))
-               warning(_("log: received negative argument %Lg"), arg);
-       d = gawk_logl(arg);
-       DEREF(tmp);
-       return make_awkldbl(d);
-}
-
-/* do_sqrt --- do the sqrt function */
-
-static NODE *
-do_sqrt(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL arg;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("sqrt: received non-numeric argument"));
-       (void) force_number(tmp);
-       arg = LDBL_VAL(tmp);
-       DEREF(tmp);
-       if (arg < LDC(0.0))
-               warning(_("sqrt: called with negative argument %Lg"), arg);
-       return make_awkldbl(gawk_sqrtl(arg));
-}
-
-/* do_exp --- exponential function */
-
-static NODE *
-do_exp(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL d, res;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("exp: received non-numeric argument"));
-       (void) force_number(tmp);
-       d = LDBL_VAL(tmp);
-       DEREF(tmp);
-       errno = 0;
-       res = gawk_expl(d);
-       if (errno == ERANGE)
-               warning(_("exp: argument %Lg is out of range"), d);
-       return make_awkldbl(res);
-}
-
-/* do_atan2 --- do the atan2 function */
-
-static NODE *
-do_atan2(int nargs)
-{
-       NODE *t1, *t2;
-       AWKLDBL d1, d2;
-
-       t2 = POP_SCALAR();
-       t1 = POP_SCALAR();
-       if (do_lint) {
-               if ((t1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("atan2: received non-numeric first 
argument"));
-               if ((t2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("atan2: received non-numeric second 
argument"));
-       }
-       (void) force_number(t1);
-       (void) force_number(t2);
-       d1 = LDBL_VAL(t1);
-       d2 = LDBL_VAL(t2);
-       DEREF(t1);
-       DEREF(t2);
-       return make_awkldbl(gawk_atan2l(d1, d2));
-}
-
-
-/* do_sin --- do the sin function */
-
-static NODE *
-do_sin(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL d;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("sin: received non-numeric argument"));
-       (void) force_number(tmp);
-       d = gawk_sinl(LDBL_VAL(tmp));
-       DEREF(tmp);
-       return make_awkldbl(d);
-}
-
-/* do_cos --- do the cos function */
-
-static NODE *
-do_cos(int nargs)
+static inline AWKLDBL
+double_to_int(AWKLDBL x)
 {
-       NODE *tmp;
-       AWKLDBL d;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("cos: received non-numeric argument"));
-       (void) force_number(tmp);
-       d = gawk_cosl(LDBL_VAL(tmp));
-       DEREF(tmp);
-       return make_awkldbl(d);
-}
-
-/* do_strtonum --- the strtonum function */
-
-static NODE *
-do_strtonum(int nargs)
-{
-       NODE *tmp;
-       AWKLDBL d;
-
-       tmp = POP_SCALAR();
-       if ((tmp->flags & (NUMBER|NUMCUR)) != 0) {
-               (void) force_number(tmp);
-               d = LDBL_VAL(tmp);
-       } else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
-               d = nondec2awkldbl(tmp->stptr, tmp->stlen);
-       else {
-               (void) force_number(tmp);
-               d = LDBL_VAL(tmp);
-       }
-
-       DEREF(tmp);
-       return make_awkldbl(d);
+       return (x >= LDC(0.0)) ? floorl(x) : ceill(x);
 }
-
-/* format_awkldbl_prinf --- format a number for (s)printf */
-
-static int
-format_awkldbl_printf(NODE *arg, struct format_spec *spec, struct 
print_fmt_buf *outb)
-{
-       AWKLDBL tmpval;
-       uintmax_t uval;
-       bool sgn;
-       int i, ii, jj;
-       char *chp, *cp;
-       char cs1;
-       int nc;
-
-       static char stackbuf[64];       /* temporary buffer for integer 
formatting */ 
-       static char *intbuf = stackbuf;
-       size_t intbuf_size = 64;
-
-#      define CP               cpbuf_start(outb)
-#      define CEND             cpbuf_end(outb)
-#      define CPBUF            cpbuf(outb)
-
-       tmpval = LDBL_VAL(arg);
-       spec->fill = space_string;
-       spec->chbuf = lchbuf;
-
-       cp = CP;
-       cs1 = spec->fmtchar;
-       switch (cs1) {
-       case 'd':
-       case 'i':
-               if (isnan(tmpval) || isinf(tmpval))
-                       goto out_of_range;
-               else
-                       tmpval = double_to_int(tmpval);
-
-               /*
-                * ``The result of converting a zero value with a
-                * precision of zero is no characters.''
-                */
-               if (spec->have_prec && spec->prec == 0 && tmpval == LDC(0.0)) {
-                       pr_num_tail(cp, spec->prec, spec, outb);
-                       return 0;
-               }
-
-               if (tmpval < LDC(0.0)) {
-                       tmpval = -tmpval;
-                       sgn = true;
-               } else {
-                       if (tmpval == - LDC(0.0))       /* avoid printing -0; 
XXX: does not really detect -0.0, +0.0 == -0.0 -- JH */
-                               tmpval = LDC(0.0);
-                       sgn = false;
-               }
-
-               /*
-                * Use snprintf return value to tell if there
-                * is enough room in the buffer or not.
-                */
-               while ((i = snprintf(intbuf, intbuf_size, "%.0Lf", tmpval)) >= 
intbuf_size) {
-                       if (intbuf == stackbuf)
-                               intbuf = NULL;
-                       intbuf_size = i + 1;
-                       erealloc(intbuf, char *, intbuf_size, "format_tree");
-               }
-
-               if (i < 1)
-                       goto out_of_range;
-
-               chp = & intbuf[i-1];
-               ii = jj = 0;
-               do {
-                       tmpbuf_prepend(outb, *chp);
-                       chp--; i--;
-#if defined(HAVE_LOCALE_H)
-                       if (spec->quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
-                               if (i)  /* only add if more digits coming */
-                                       tmpbuf_prepend(outb, 
loc.thousands_sep[0]);     /* XXX - assumption it's one char */
-                               if (loc.grouping[ii+1] == 0)
-                                       jj = 0;         /* keep using current 
val in loc.grouping[ii] */
-                               else if (loc.grouping[ii+1] == CHAR_MAX)
-                                       spec->quote_flag= false;
-                               else {                 
-                                       ii++;
-                                       jj = 0;
-                               }
-                       }
-#endif
-               } while (i > 0);
-
-
-               /* add more output digits to match the precision */
-               if (spec->have_prec) {
-                       while (CEND - CP < spec->prec)
-                               tmpbuf_prepend(outb, '0');
-               }
-
-               if (sgn)
-                       tmpbuf_prepend(outb, '-');
-               else if (spec->signchar)
-                       tmpbuf_prepend(outb, spec->signchar);
-               /*
-                * When to fill with zeroes is of course not simple.
-                * First: No zero fill if left-justifying.
-                * Next: There seem to be two cases:
-                *      A '0' without a precision, e.g. %06d
-                *      A precision with no field width, e.g. %.10d
-                * Any other case, we don't want to fill with zeroes.
-                */
-               if (! spec->lj
-                   && ((spec->zero_flag && ! spec->have_prec)
-                        || (spec->fw == 0 && spec->have_prec)))
-                       spec->fill = zero_string;
-               if (spec->prec > spec->fw)
-                       spec->fw = spec->prec;
-               spec->prec = CEND - CP;
-               if (spec->fw > spec->prec && ! spec->lj && spec->fill != 
space_string
-                   && (*CP == '-' || spec->signchar)) {
-                       bchunk_one(outb, CP);
-                       CP++;
-                       spec->prec--;
-                       spec->fw--;
-               }
-               cp = CP;
-
-               pr_num_tail(CP, spec->prec, spec, outb);
-               return 0;
-
-       case 'X':
-               spec->chbuf = Uchbuf;
-               /* FALL THROUGH */
-       case 'x':
-               /* FALL THROUGH */
-       case 'u':
-               /* FALL THROUGH */
-       case 'o':
-               /*
-                * ``The result of converting a zero value with a
-                * precision of zero is no characters.''
-                *
-                * If I remember the ANSI C standard, though,
-                * it says that for octal conversions
-                * the precision is artificially increased
-                * to add an extra 0 if # is supplied.
-                * Indeed, in C,
-                *      printf("%#.0o\n", 0);
-                * prints a single 0.
-                */
-       
-               if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval 
== LDC(0.0)) {
-                       pr_num_tail(cp, spec->prec, spec, outb);
-                       return 0;
-               }
-
-               if (tmpval < LDC(0.0)) {
-                       uval = (uintmax_t) (intmax_t) tmpval;
-                       if ((AWKLDBL)(intmax_t) uval != double_to_int(tmpval))
-                               goto out_of_range;
-               } else {
-                       uval = (uintmax_t) tmpval;
-                       if ((AWKLDBL) uval != double_to_int(tmpval))
-                               goto out_of_range;
-               }
-
-               /* spec->fmtchar = cs1; */
-               format_nondecimal(uval, spec, outb);
-               return 0;
-
-out_of_range:
-               /* out of range - emergency use of %g format */
-               if (do_lint)
-                       lintwarn(_("[s]printf: value %Lg is out of range for 
`%%%c' format"),
-                                       tmpval, cs1);
-               cs1 = 'g';
-               goto fmt1;
-
-       case 'F':
-#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
-               cs1 = 'f';
-               /* FALL THROUGH */
 #endif
-       case 'g':
-       case 'G':
-       case 'e':
-       case 'f':
-       case 'E':
-fmt1:
-               if (! spec->have_prec)
-                       spec->prec = DEFAULT_G_PRECISION;
 
-               chksize(outb, spec->fw + spec->prec + 11);      /* 11 == slop */
-               cp = CPBUF;     /* XXX --- using the temporary prepend-buffer 
and
-                                * we know it has enough room (>=11).
-                                 */
-               *cp++ = '%';
-               if (spec->lj)
-                       *cp++ = '-';
-               if (spec->signchar)
-                       *cp++ = spec->signchar;
-               if (spec->alt)
-                       *cp++ = '#';
-               if (spec->zero_flag)
-                       *cp++ = '0';
-               if (spec->quote_flag)
-                       *cp++ = '\'';
-
-#if defined(LC_NUMERIC)
-               if (spec->quote_flag && ! use_lc_numeric)
-                       setlocale(LC_NUMERIC, "");
-#endif
-
-               sprintf(cp, "*.*L%c", cs1);
-               while ((nc = snprintf(buf_end(outb), buf_space(outb), CPBUF,
-                               (int) spec->fw, (int) spec->prec, tmpval)) >= 
buf_space(outb))
-                       chksize(outb, nc + 1);
-
-#if defined(LC_NUMERIC)
-               if (spec->quote_flag && ! use_lc_numeric)
-                       setlocale(LC_NUMERIC, "C");
-#endif
-
-               buf_adjust(outb, nc); /* adjust data and free space in output 
buffer */
-               return 0;
-
-       default:
-               cant_happen();  
-       }
-
-       return -1;
-#undef CP
-#undef CEND
-#undef CPBUF
-}
+#include "long_double.h"
 
-#else
+#else  /* ! USE_LONG_DOUBLE */
 
 static bool awkldbl_init(bltin_t **bltins);
 
diff --git a/long_double.h b/long_double.h
index 9a11e55..f117bb8 100644
--- a/long_double.h
+++ b/long_double.h
@@ -1,5 +1,5 @@
 /*
- * long_double.h - math functions and replacements with long double arguments.
+ * long_double.h - routines for AWKLDBL number support in gawk.
  */
 
 /* 
@@ -23,112 +23,1837 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
-#ifdef HAVE_SINL
-#define gawk_sinl      sinl
-#else
-static inline long double
-gawk_sinl(long double x)
+
+/*
+ * XXX:        This is a only a template, and M*U**S***T N*O**T include any 
headers
+ *     nor any reference to the C long double type. Please see long_double.c.
+ */
+
+
+static AWKLDBL *pow2d_table;   /* 2^n table for 0 <= n <= LDBL_INT_BITS */
+static AWKLDBL init_pow2d_table(unsigned int);
+
+#define POW2LD(n)      (pow2d_table != NULL ? pow2d_table[n] : 
init_pow2d_table(n))
+
+
+/* Can declare these, since we always use the random shipped with gawk */
+extern char *initstate(unsigned long seed, char *state, long n);
+extern char *setstate(char *state);
+extern long random(void);
+extern void srandom(unsigned long seed);
+
+/*
+ * Since we supply the version of random(), we know what
+ * value to use here.
+ */
+#define GAWK_RANDOM_MAX 0x7fffffffL
+
+
+/* exported routines */
+
+static NODE *make_awknum(AWKNUM);
+static void free_awkldbl(NODE *tmp);
+static int cmp_awkldbls(const NODE *, const NODE *);
+static void negate_awkldbl(NODE *);
+static NODE *str2awkldbl(char *, char **, int, bool);
+static NODE *force_awkldbl(NODE *);
+static NODE *format_awkldbl_val(const char *, int, NODE *);
+static unsigned long awkldbl_toulong(const NODE *);
+static long awkldbl_tolong(const NODE *);
+static double awkldbl_todouble(const NODE *);
+static uintmax_t awkldbl_touintmax_t(const NODE *);
+static int awkldbl_sgn(const NODE *);
+static bool awkldbl_isinteger(const NODE *);
+static bool awkldbl_isnan(const NODE *);
+static bool awkldbl_isinf(const NODE *);
+static NODE *awkldbl_copy(const NODE *);
+static int format_awkldbl_printf(NODE *, struct format_spec *, struct 
print_fmt_buf *);
+static bool awkldbl_init(bltin_t **);
+static NODE *awkldbl_add(const NODE *, const NODE *);
+static NODE *awkldbl_sub(const NODE *, const NODE *);
+static NODE *awkldbl_mul(const NODE *, const NODE *);
+static NODE *awkldbl_div(const NODE *, const NODE *);
+static NODE *awkldbl_mod(const NODE *, const NODE *);
+static NODE *awkldbl_pow(const NODE *, const NODE *);
+static NODE *awkldbl_add_long(const NODE *, long);
+static NODE *awkldbl_update_var(NODE *);
+static void awkldbl_set_var(const NODE *);
+static long awkldbl_increment_var(const NODE *, long);
+static void awkldbl_init_vars(void);
+
+static NODE *do_and(int);
+static NODE *do_atan2(int);
+static NODE *do_compl(int);
+static NODE *do_cos(int);
+static NODE *do_exp(int);
+static NODE *do_int(int);
+static NODE *do_log(int);
+static NODE *do_lshift(int);
+static NODE *do_or(int);
+static NODE *do_rand(int);
+static NODE *do_rshift(int);
+static NODE *do_sin(int);
+static NODE *do_sqrt(int);
+static NODE *do_srand(int);
+static NODE *do_strtonum(int);
+static NODE *do_xor(int);
+
+/* private routines */
+static int is_ieee_magic_val(const char *val);
+static AWKLDBL get_ieee_magic_val(const char *val);
+static AWKLDBL calc_exp(AWKLDBL x1, AWKLDBL x2);
+static NODE *make_awkldbl(AWKLDBL);
+
+static long MFNR;
+static long MNR;
+
+numbr_handler_t awkldbl_hndlr = {
+       awkldbl_init,
+       NULL,   /* version_str */
+       NULL,   /* load_procinfo */
+       make_awknum,
+       str2awkldbl,
+       awkldbl_copy,
+       free_awkldbl,
+       force_awkldbl,
+       negate_awkldbl,
+       cmp_awkldbls,
+       awkldbl_sgn,
+       awkldbl_isinteger,
+       awkldbl_isnan,
+       awkldbl_isinf,
+       format_awkldbl_val,
+       format_awkldbl_printf,
+       awkldbl_todouble,
+       awkldbl_tolong,
+       awkldbl_toulong,
+       awkldbl_touintmax_t,
+       awkldbl_add,
+       awkldbl_sub,
+       awkldbl_mul,
+       awkldbl_div,
+       awkldbl_mod,
+       awkldbl_pow,
+       awkldbl_add_long,
+       awkldbl_update_var,
+       awkldbl_set_var,
+       awkldbl_increment_var,
+       awkldbl_init_vars,
+};
+
+/* awkldbl_init --- initialization routine */
+
+static bool
+awkldbl_init(bltin_t **numbr_bltins)
 {
-       return sin( (double) x);
+       static bltin_t awkldbl_bltins[] = {
+               { "and",        do_and },
+               { "atan2",      do_atan2 },
+               { "compl",      do_compl },
+               { "cos",        do_cos },
+               { "exp",        do_exp },
+               { "int",        do_int },
+               { "log",        do_log },
+               { "lshift",     do_lshift },
+               { "or",         do_or },
+               { "rand",       do_rand },
+               { "rshift",     do_rshift },
+               { "sin",        do_sin },
+               { "sqrt",       do_sqrt },
+               { "srand",      do_srand },
+               { "strtonum",   do_strtonum },
+               { "xor",        do_xor },
+               { NULL, NULL },
+       };
+
+       /* set the numeric value of null string */
+       get_long_double(Nnull_string->qnumbr);
+       LDBL_VAL(Nnull_string) = LDC(0.0);
+       Nnull_string->flags |= (NUMCUR|NUMBER);
+
+       /* initialize TRUE and FALSE nodes */
+       false_node = make_awkldbl(LDC(0.0));
+       true_node = make_awkldbl(LDC(1.0));
+       false_node->flags |= NUMINT;
+       true_node->flags |= NUMINT;
+
+       *numbr_bltins = awkldbl_bltins;
+       return true;
 }
-#endif
 
-#ifdef HAVE_COSL 
-#define gawk_cosl      cosl
-#else
-static inline long double
-gawk_cosl(long double x)
+/* awkldbl_toulong --- conversion to unsigned long */
+
+static unsigned long
+awkldbl_toulong(const NODE *n)
 {
-       return cos( (double) x);
+       return LDBL_VAL(n);
 }
-#endif
 
-#ifdef HAVE_ATAN2L
-#define gawk_atan2l    atan2l
-#else
-static inline long double
-gawk_atan2l(long double y, long double x)
+/* awkldbl_tolong --- conversion to long */
+
+static long
+awkldbl_tolong(const NODE *n)
 {
-       return atan2( (double) y, (double) x);
+       return LDBL_VAL(n);
 }
-#endif
 
-#ifdef HAVE_LOGL
-#define gawk_logl      logl
-#else
-static inline long double
-gawk_logl(long double x)
+/* awkldbl_todouble --- conversion to double */
+
+static double
+awkldbl_todouble(const NODE *n)
 {
-       return log( (double) x);
+       return LDBL_VAL(n);
 }
-#endif
 
-#ifdef HAVE_EXPL
-#define gawk_expl      expl
-#else
-static inline long double
-gawk_expl(long double x)
+/* awkldbl_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+awkldbl_touintmax_t(const NODE *n)
 {
-       return exp( (double) x);
+       return LDBL_VAL(n);
 }
-#endif
 
-#ifdef HAVE_FMODL
-#define gawk_fmodl     fmodl
-#else
-static inline long double
-gawk_fmodl(long double x, long double y)
+/* awkldbl_sgn --- return 1 if number > 0, zero if number == 0, and -1 if 
number < 0 */
+
+static int
+awkldbl_sgn(const NODE *n)
 {
-       return fmod( (double) x, (double) y);
+       AWKLDBL d = LDBL_VAL(n);
+       return (d < LDC(0.0) ? -1 : d > LDC(0.0));
 }
-#endif
 
-#ifdef HAVE_STRTOLD
-#define gawk_strtold   strtold
-#else
-static inline long double
-gawk_strtold(const char *str, char **endptr)
+/* awkldbl_isinteger --- check if a number is an integer */
+
+static bool
+awkldbl_isinteger(const NODE *n)
 {
-       return strtod(str, endptr);
+       AWKLDBL d = LDBL_VAL(n);
+
+       if (isnan(d) || isinf(d))
+               return false;
+       return double_to_int(d) == d;
 }
-#endif
 
-#ifdef HAVE_FLOORL
-#define gawk_floorl    floorl
-#else
-static inline long double
-gawk_floorl(long double x)
+/* awkldbl_isnan --- check if number is NaN */
+
+static bool
+awkldbl_isnan(const NODE *n)
+{
+       return isnan(LDBL_VAL(n));
+}
+
+/* awkldbl_isinf --- check if number is infinity */
+
+static bool
+awkldbl_isinf(const NODE *n)
+{
+       return isinf(LDBL_VAL(n));
+}
+
+/* negate_awkldbl --- negate number in NODE */
+
+static void
+negate_awkldbl(NODE *n)
+{
+       LDBL_VAL(n) = - LDBL_VAL(n);
+}
+
+/* awkldbl_add --- add two numbers */
+
+static NODE *
+awkldbl_add(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(LDBL_VAL(t1) + LDBL_VAL(t2));
+}
+
+/* awkldbl_sub --- subtract two numbers */
+
+static NODE *
+awkldbl_sub(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(LDBL_VAL(t1) - LDBL_VAL(t2));
+}
+
+/* awkldbl_mul --- multiply two numbers */
+
+static NODE *
+awkldbl_mul(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(LDBL_VAL(t1) * LDBL_VAL(t2));
+}
+
+/* awkldbl_add --- quotient of two numbers */
+
+static NODE *
+awkldbl_div(const NODE *t1, const NODE *t2)
+{
+       AWKLDBL d = LDBL_VAL(t2);
+       if (d == LDC(0.0))
+               fatal(_("division by zero attempted"));
+       return make_awkldbl(LDBL_VAL(t1) / d);
+}
+
+/* awkldbl_add_long --- add long value to a number */
+
+static NODE *
+awkldbl_add_long(const NODE *t1, long n)
+{
+       return make_awkldbl(LDBL_VAL(t1) + (AWKLDBL) n);
+}
+
+/* awkldbl_copy --- copy a number */
+
+static NODE *
+awkldbl_copy(const NODE *t1)
 {
-       return floor( (double) x);
+       return make_awkldbl(LDBL_VAL(t1));
+}
+
+/* awkldbl_update_var --- update a special variable from internal variables */
+
+static NODE *
+awkldbl_update_var(NODE *var)
+{
+       NODE *val = var->var_value;
+       AWKLDBL d;
+
+       d = LDBL_VAL(val);
+       if (var == NR_node) {
+               if (MNR == 0 && d != NR) {
+                       unref(val);
+                       val = NR_node->var_value = make_awkldbl((AWKLDBL) NR);
+               } else if (MNR != 0) {
+                       unref(val);
+                       d = ((AWKLDBL) MNR) * LONG_MAX + (AWKLDBL) NR;
+                       val = var->var_value = make_awkldbl(d);
+               }
+               return val;
+       }
+
+       assert(var == FNR_node);
+       if (MFNR == 0 && d != FNR) {
+               unref(val);
+               val = FNR_node->var_value = make_awkldbl((AWKLDBL) FNR);
+       } else if (MFNR != 0) {
+               unref(val);
+               d = ((AWKLDBL) MFNR) * LONG_MAX + (AWKLDBL) FNR;
+               val = var->var_value = make_awkldbl(d);
+       }
+       return val;
+}
+
+/*
+ * awkldbl_set_vars --- update internal variables for assignment
+ *     to a special variable.
+ */
+
+static void
+awkldbl_set_var(const NODE *var)
+{
+       NODE *val = var->var_value;
+       AWKLDBL d;
+
+       d = LDBL_VAL(val);
+       if (var == NR_node) {
+               MNR = d / LONG_MAX;
+               NR = d - ((AWKLDBL) MNR) * LONG_MAX;
+       } else if (var == FNR_node) {
+               MFNR = d / LONG_MAX;
+               FNR = d - ((AWKLDBL) MFNR) * LONG_MAX;
+       }
+       /* N.B: PREC and ROUNMODE -- not relevant */
+}
+
+/* awkldbl_increment_var --- increment NR or FNR */
+
+static long
+awkldbl_increment_var(const NODE *var, long nr)
+{
+       if (nr == LONG_MAX - 1) {
+               /* increment quotient, set remainder(NR or FNR) to 0 */
+               if (var == NR_node)
+                       MNR++;
+               else /* var == FNR_node */
+                       MFNR++;
+               return 0;
+       }
+       return ++nr;
+}
+
+/* awkldbl_init_vars --- initialize special variables */
+
+static void
+awkldbl_init_vars()
+{
+       /* dummy function */
+}
+
+/*
+ * make_awkldbl --- allocate a node with defined number;
+ *     this routine is not exported. 
+ */
+
+static NODE *
+make_awkldbl(AWKLDBL x)
+{
+       NODE *r;
+       getnode(r);
+       r->type = Node_val;
+       get_long_double(r->qnumbr);
+       LDBL_VAL(r) = x;
+       r->flags = MALLOC|NUMBER|NUMCUR;
+       r->valref = 1;
+       r->stptr = NULL;
+       r->stlen = 0;
+#if MBS_SUPPORT
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+       return r;
+}
+
+/* make_awknum --- allocate a node with defined AWKNUM */
+
+static NODE *
+make_awknum(AWKNUM x)
+{
+       NODE *r;
+       getnode(r);
+       r->type = Node_val;
+       get_long_double(r->qnumbr);
+       LDBL_VAL(r) = (AWKLDBL) x;
+       r->flags = MALLOC|NUMBER|NUMCUR;
+       r->valref = 1;
+       r->stptr = NULL;
+       r->stlen = 0;
+#if MBS_SUPPORT
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+       return r;
+}
+
+/* free_awkldbl --- free all storage allocated for a AWKLDBL */
+
+static void
+free_awkldbl(NODE *tmp)
+{
+       assert((tmp->flags & (NUMBER|NUMCUR)) != 0);
+        free_long_double(tmp->qnumbr);
+}
+
+/* make_integer --- Convert an integer to a number node. */
+
+static inline NODE *
+make_integer(uintmax_t n)
+{
+#ifdef HAVE_UINTMAX_T
+
+       /* N.B: -- see adjust_uint() in floatcomp.c */
+
+       /* XXX: is this really needed in this case ??? */
+       
+       if (LDBL_FRAC_BITS < CHAR_BIT * sizeof (n)) {
+               int i = CHAR_BIT * sizeof (n) - LDBL_FRAC_BITS;
+
+               /* strip leading `i' bits */
+
+               n = (n << i) >> i;      /* XXX: equivalent code in floatcomp.c
+                                        * generates compiler warning.
+                                        */ 
+       }
+#endif /* HAVE_UINTMAX_T */
+
+       return make_awkldbl(n);
+}
+
+/* do_lshift --- perform a << operation */
+
+static NODE *
+do_lshift(int nargs)
+{
+       NODE *s1, *s2;
+       uintmax_t uval, ushift, res;
+       AWKLDBL val, shift;
+
+       s2 = POP_SCALAR();
+       s1 = POP_SCALAR();
+       if (do_lint) {
+               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("lshift: received non-numeric first 
argument"));
+               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("lshift: received non-numeric second 
argument"));
+       }
+
+       (void) force_number(s1);
+       (void) force_number(s2);
+       val = LDBL_VAL(s1);
+       shift = LDBL_VAL(s2);
+
+       if (do_lint) {
+               if (val < LDC(0.0) || shift < LDC(0.0))
+                       lintwarn(_("lshift(%f, %f): negative values will give 
strange results"),
+                                       (double) val, (double) shift);
+               if (double_to_int(val) != val || double_to_int(shift) != shift)
+                       lintwarn(_("lshift(%f, %f): fractional values will be 
truncated"),
+                                       (double) val, (double) shift);
+               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+                       lintwarn(_("lshift(%f, %f): too large shift value will 
give strange results"),
+                                       (double) val, (double) shift);
+       }
+
+       DEREF(s1);
+       DEREF(s2);
+       uval = (uintmax_t) val;
+       ushift = (uintmax_t) shift;
+       res = uval << ushift;
+       return make_integer(res);
+}
+
+/* do_rshift --- perform a >> operation */
+
+static NODE *
+do_rshift(int nargs)
+{
+       NODE *s1, *s2;
+       uintmax_t uval, ushift, res;
+       AWKLDBL val, shift;
+
+       s2 = POP_SCALAR();
+       s1 = POP_SCALAR();
+       if (do_lint) {
+               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("rshift: received non-numeric first 
argument"));
+               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("rshift: received non-numeric second 
argument"));
+       }
+
+       (void) force_number(s1);
+       (void) force_number(s2);
+       val = LDBL_VAL(s1);
+       shift = LDBL_VAL(s2);
+       if (do_lint) {
+               if (val < LDC(0.0) || shift < LDC(0.0))
+                       lintwarn(_("rshift(%f, %f): negative values will give 
strange results"),
+                                       (double) val, (double) shift);
+               if (double_to_int(val) != val || double_to_int(shift) != shift)
+                       lintwarn(_("rshift(%f, %f): fractional values will be 
truncated"),
+                                       (double) val, (double) shift);
+               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+                       lintwarn(_("rshift(%f, %f): too large shift value will 
give strange results"),
+                                       (double) val, (double) shift);
+       }
+
+       DEREF(s1);
+       DEREF(s2);
+       uval = (uintmax_t) val;
+       ushift = (uintmax_t) shift;
+       res = uval >> ushift;
+       return make_integer(res);
+}
+
+/* do_and --- perform an & operation */
+
+static NODE *
+do_and(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKLDBL val;
+       int i;
+
+       res = ~0;       /* start off with all ones */
+       if (nargs < 2)
+               fatal(_("and: called with less than two arguments"));
+
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("and: argument %d is non-numeric"), i);
+
+               (void) force_number(s1);
+               val = LDBL_VAL(s1);
+               if (do_lint && val < LDC(0.0))
+                       lintwarn(_("and: argument %d negative value %g will 
give strange results"),
+                                       i, (double) val);
+
+               uval = (uintmax_t) val;
+               res &= uval;
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_or --- perform an | operation */
+
+static NODE *
+do_or(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKLDBL val;
+       int i;
+
+       res = 0;
+       if (nargs < 2)
+               fatal(_("or: called with less than two arguments"));
+
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("or: argument %d is non-numeric"), i);
+
+               (void) force_number(s1);
+               val = LDBL_VAL(s1);
+               if (do_lint && val < LDC(0.0))
+                       lintwarn(_("or: argument %d negative value %g will give 
strange results"),
+                                       i, (double) val);
+
+               uval = (uintmax_t) val;
+               res |= uval;
+
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_xor --- perform an ^ operation */
+
+static NODE *
+do_xor(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKLDBL val;
+       int i;
+
+       if (nargs < 2)
+               fatal(_("xor: called with less than two arguments"));
+
+       res = 0;        /* silence compiler warning */
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("xor: argument %d is non-numeric"), i);
+
+               (void) force_number(s1);
+               val = LDBL_VAL(s1);
+               if (do_lint && val < LDC(0.0))
+                       lintwarn(_("xor: argument %d negative value %g will 
give strange results"),
+                                       i, (double) val);
+
+               uval = (uintmax_t) val;
+               if (i == 1)
+                       res = uval;
+               else
+                       res ^= uval;
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_compl --- perform a ~ operation */
+
+static NODE *
+do_compl(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+       uintmax_t uval;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("compl: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = LDBL_VAL(tmp);
+       DEREF(tmp);
+
+       if (do_lint) {
+               if (d < LDC(0.0))
+                       lintwarn(_("compl(%f): negative value will give strange 
results"), (double) d);
+               if (double_to_int(d) != d)
+                       lintwarn(_("compl(%f): fractional value will be 
truncated"), (double) d);
+       }
+
+       uval = (uintmax_t) d;
+       uval = ~ uval;
+       return make_integer(uval);
+}
+
+/* nondec2awkldbl --- convert octal or hex value to long double */
+
+/*
+ * Because of awk's concatenation rules and the way awk.y:yylex()
+ * collects a number, this routine has to be willing to stop on the
+ * first invalid character.
+ */
+
+static AWKLDBL
+nondec2awkldbl(char *str, size_t len)
+{
+       AWKLDBL retval = 0.0;
+       char save;
+       short val;
+       char *start = str;
+
+       if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+               /*
+                * User called strtonum("0x") or some such,
+                * so just quit early.
+                */
+               if (len <= 2)
+                       return 0.0;
+
+               for (str += 2, len -= 2; len > 0; len--, str++) {
+                       switch (*str) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               val = *str - '0';
+                               break;
+                       case 'a':
+                       case 'b':
+                       case 'c':
+                       case 'd':
+                       case 'e':
+                       case 'f':
+                               val = *str - 'a' + 10;
+                               break;
+                       case 'A':
+                       case 'B':
+                       case 'C':
+                       case 'D':
+                       case 'E':
+                       case 'F':
+                               val = *str - 'A' + 10;
+                               break;
+                       default:
+                               goto done;
+                       }
+                       retval = (retval * LDC(16.0)) + (AWKLDBL) val;
+               }
+       } else if (*str == '0') {
+               for (; len > 0; len--) {
+                       if (! isdigit((unsigned char) *str))
+                               goto done;
+                       else if (*str == '8' || *str == '9') {
+                               str = start;
+                               goto decimal;
+                       }
+                       retval = (retval * LDC(8.0)) + (AWKLDBL) (*str - '0');
+                       str++;
+               }
+       } else {
+decimal:
+               save = str[len];
+               retval = gawk_strtold(str, NULL);
+               str[len] = save;
+       }
+done:
+       return retval;
+}
+
+
+/* do_rand --- do the rand function */
+
+static bool firstrand = true;
+/* Some systems require this array to be integer aligned. Sigh. */
+#define SIZEOF_STATE 256
+static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
+static char *const state = (char *const) istate;
+
+/* ARGSUSED */
+static NODE *
+do_rand(int nargs ATTRIBUTE_UNUSED)
+{
+       if (firstrand) {
+               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+               /* don't need to srandom(1), initstate() does it for us. */
+               firstrand = false;
+               setstate(state);
+       }
+       /*
+        * Per historical practice and POSIX, return value N is
+        *
+        *      0 <= n < 1
+        */
+       return make_awkldbl((random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+}
+
+/* do_srand --- seed the random number generator */
+
+static NODE *
+do_srand(int nargs)
+{
+       NODE *tmp;
+       static long save_seed = 1;
+       long ret = save_seed;   /* SVR4 awk srand returns previous seed */
+       AWKLDBL d;
+
+       if (firstrand) {
+               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+               /* don't need to srandom(1), we're changing the seed below */
+               firstrand = false;
+               (void) setstate(state);
+       }
+
+       if (nargs == 0)
+               srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
+       else {
+               tmp = POP_SCALAR();
+               if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("srand: received non-numeric argument"));
+               (void) force_number(tmp);
+               d = LDBL_VAL(tmp);
+               srandom((unsigned int) (save_seed = (long) d));
+               DEREF(tmp);
+       }
+       return make_awkldbl(ret);
+}
+
+/* str2awkldbl --- create a number node from string */
+
+static NODE *
+str2awkldbl(char *str, char **endptr, int base, bool is_integer 
ATTRIBUTE_UNUSED)
+{
+       NODE *r;
+       AWKLDBL d;
+
+       if (base == 0) {
+               /*
+                * special case -- only used to parse input in the debugger?
+                * FIXME: reject ieee specials we don't want and/or use the same
+                * rules when reading numbers from a source file and nuke this 
case.
+                * Also in double.c.
+                */
+
+               errno = 0;
+               d = gawk_strtold(str, endptr);
+               if (errno != 0)
+                       d = LDC(0.0);
+       } else {
+               if (base == 8 || base == 16)
+                       d = nondec2awkldbl(str, strlen(str));
+               else {
+                       /* atof for double */
+                       errno = 0;
+                       d = gawk_strtold(str, NULL);
+                       if (errno != 0)
+                               d = LDC(0.0);
+                       errno = 0;
+               }
+       }
+
+       r = make_awkldbl(d);
+
+       /* XXX: is this relevant ? */
+       if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+               r->flags |= NUMINT;
+
+       return r;
+}
+
+/* awkldbl_mod --- remainder from division of two numbers */
+
+static NODE *
+awkldbl_mod(const NODE *t1, const NODE *t2)
+{
+       AWKLDBL d2;
+
+       d2 = LDBL_VAL(t2);
+       if (d2 == LDC(0.0))
+               fatal(_("division by zero attempted in `%%'"));
+       return make_awkldbl(gawk_fmodl(LDBL_VAL(t1), d2));
 }
+
+/* awkldbl_pow --- power function */
+
+static NODE *
+awkldbl_pow(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(calc_exp(LDBL_VAL(t1), LDBL_VAL(t2)));
+}
+
+
+/*
+ * calc_exp_posint --- calculate x^n for positive integral n,
+ *     using exponentiation by squaring without recursion.
+ */
+
+static AWKLDBL
+calc_exp_posint(AWKLDBL x, long n)
+{
+       AWKLDBL mult = LDC(1.0);
+
+       while (n > 1) {
+               if ((n % 2) == 1)
+                       mult *= x;
+               x *= x;
+               n /= 2;
+       }
+       return mult * x;
+}
+
+/* calc_exp --- calculate x1^x2 */
+
+static AWKLDBL
+calc_exp(AWKLDBL x1, AWKLDBL x2)
+{
+       long lx = x2;
+
+       if (((AWKLDBL) lx) == x2) {             /* integer exponent */
+               if (lx == 0)
+                       return LDC(1.0);
+               return (lx > 0) ? calc_exp_posint(x1, lx)
+                               : LDC(1.0) / calc_exp_posint(x1, -lx);
+       }
+       return gawk_powl(x1, x2);
+}
+
+/* cmp_awkldbls --- compare two doubles */
+
+static int
+cmp_awkldbls(const NODE *t1, const NODE *t2)
+{
+       /*
+        * This routine is also used to sort numeric array indices or values.
+        * For the purposes of sorting, NaN is considered greater than
+        * any other value, and all NaN values are considered equivalent and 
equal.
+        * This isn't in compliance with IEEE standard, but compliance w.r.t. 
NaN
+        * comparison at the awk level is a different issue, and needs to be 
dealt
+        * with in the interpreter for each opcode seperately.
+        */
+       AWKLDBL d1 = LDBL_VAL(t1);
+       AWKLDBL d2 = LDBL_VAL(t2);
+
+       if (isnan(d1))
+               return ! isnan(d2);
+       if (isnan(d2))
+               return -1;
+       /* don't subtract, in case one or both are infinite */
+       if (d1 == d2)
+               return 0;
+       if (d1 < d2)
+               return -1;
+       return 1;
+}
+
+/* force_awkldbl --- force a value to be numeric */
+
+static NODE *
+force_awkldbl(NODE *n)
+{
+       char *cp;
+       char *cpend;
+       char save;
+       char *ptr;
+       unsigned int newflags;
+
+       if ((n->flags & NUMCUR) != 0)
+               return n;
+
+       /* all the conditionals are an attempt to avoid the expensive strtod */
+
+       /* Note: only set NUMCUR if we actually convert some digits */
+
+       get_long_double(n->qnumbr);
+       LDBL_VAL(n) = LDC(0.0);
+
+       if (n->stlen == 0)
+               return n;
+
+       cp = n->stptr;
+       /*
+        * 2/2007:
+        * POSIX, by way of severe language lawyering, seems to
+        * allow things like "inf" and "nan" to mean something.
+        * So if do_posix, the user gets what he deserves.
+        * This also allows hexadecimal floating point. Ugh.
+        */
+       if (! do_posix) {
+               if (isalpha((unsigned char) *cp)) {
+                       return n;
+               } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
+                       if ((n->flags & MAYBE_NUM) != 0)
+                               n->flags &= ~MAYBE_NUM;
+                       n->flags |= NUMBER|NUMCUR;
+                       LDBL_VAL(n) = get_ieee_magic_val(n->stptr);
+                       return n;
+               }
+               /* else
+                       fall through */
+       }
+       /* else not POSIX, so
+               fall through */
+
+       cpend = cp + n->stlen;
+       while (cp < cpend && isspace((unsigned char) *cp))
+               cp++;
+
+       if (   cp == cpend              /* only spaces, or */
+           || (! do_posix              /* not POSIXLY paranoid and */
+               && (isalpha((unsigned char) *cp)        /* letter, or */
+                                       /* CANNOT do non-decimal and saw 0x */
+                   || (! do_non_decimal_data && cp[0] == '0'
+                       && (cp[1] == 'x' || cp[1] == 'X'))))) {
+               return n;
+       }
+
+       if ((n->flags & MAYBE_NUM) != 0) {
+               newflags = NUMBER;
+               n->flags &= ~MAYBE_NUM;
+       } else
+               newflags = 0;
+
+       if (cpend - cp == 1) {          /* only one character */
+               if (isdigit((unsigned char) *cp)) {     /* it's a digit! */
+                       LDBL_VAL(n) = (AWKLDBL)(*cp - '0');
+                       n->flags |= newflags;
+                       n->flags |= NUMCUR;
+                       if (cp == n->stptr)             /* no leading spaces */
+                               n->flags |= NUMINT;
+               }
+               return n;
+       }
+
+       if (do_non_decimal_data) {      /* main.c assures false if do_posix */
+               errno = 0;
+               if (! do_traditional && get_numbase(cp, true) != 10) {
+                       LDBL_VAL(n) = nondec2awkldbl(cp, cpend - cp);
+                       n->flags |= NUMCUR;
+                       ptr = cpend;
+                       goto finish;
+               }
+       }
+
+       errno = 0;
+       save = *cpend;
+       *cpend = '\0';
+       LDBL_VAL(n) = gawk_strtold((const char *) cp, & ptr);
+
+       /* POSIX says trailing space is OK for NUMBER */
+       while (isspace((unsigned char) *ptr))
+               ptr++;
+       *cpend = save;
+finish:
+       if (errno == 0 && ptr == cpend) {
+               n->flags |= newflags;
+               n->flags |= NUMCUR;
+       } else {
+               errno = 0;
+       }
+       return n;
+}
+
+
+/*
+ * The following lookup table is used as an optimization in force_string;
+ * (more complicated) variations on this theme didn't seem to pay off, but 
+ * systematic testing might be in order at some point.
+ */
+static const char *values[] = {
+       "0",
+       "1",
+       "2",
+       "3",
+       "4",
+       "5",
+       "6",
+       "7",
+       "8",
+       "9",
+};
+#define        NVAL    (sizeof(values)/sizeof(values[0]))
+
+/* format_awkldbl_val --- format a numeric value based on format */
+
+static NODE *
+format_awkldbl_val(const char *format, int index, NODE *s)
+{
+       char buf[BUFSIZ];
+       char *sp = buf;
+       AWKLDBL ival, d;
+
+       /*
+        * 2/2007: Simplify our lives here. Instead of worrying about
+        * whether or not the value will fit into a long just so we
+        * can use sprintf("%ld", val) on it, always format it ourselves.
+        * The only thing to worry about is that integral values always
+        * format as integers. %.0f does that very well.
+        *
+        * 6/2008: Would that things were so simple. Always using %.0f
+        * imposes a notable performance penalty for applications that
+        * do a lot of conversion of integers to strings. So, we reinstate
+        * the old code, but use %.0f for integral values that are outside
+        * the range of a long.  This seems a reasonable compromise.
+        *
+        * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
+        * < and > so that things work correctly on systems with 64 bit 
integers.
+        */
+
+       d = LDBL_VAL(s);
+
+       if ((s->flags & STRCUR) != 0)
+               efree(s->stptr);
+       free_wstr(s);
+
+       /* not an integral value, or out of range */
+       if ((ival = double_to_int(d)) != d
+                       || ival <= (AWKLDBL) LONG_MIN || ival >= (AWKLDBL) 
LONG_MAX
+       ) {
+               struct format_spec spec;
+               struct print_fmt_buf *outb;
+
+               /*
+                * Once upon a time, we just blindly did this:
+                *      sprintf(sp, format, s->numbr);
+                *      s->stlen = strlen(sp);
+                *      s->stfmt = (char) index;
+                * but that's no good if, e.g., OFMT is %s. So we punt,
+                * and just always format the value ourselves.
+                */
+
+               /* XXX: format_spec copied since can be altered in the 
formatting routine */
+
+               if (ival == d) {
+                       /* integral value, but outside range of %ld, use %.0f */
+                       spec = *fmt_list[INT_0f_FMT_INDEX].spec;
+                       s->stfmt = -1;
+               } else {
+                       assert(fmt_list[index].spec != NULL);   /* or we can 
use fmt_parse() */
+                       spec = *fmt_list[index].spec;
+                       s->stfmt = (char) index;        
+               }
+
+               outb = get_fmt_buf();
+               format_awkldbl_printf(s, & spec, outb);
+               (void) bytes2node(outb, s);
+               free_fmt_buf(outb);
+
+               s->stptr[s->stlen] = '\0';
+       } else {
+               /*
+                * integral value; force conversion to long only once.
+                */
+               long num = (long) ival;
+
+               if (num < NVAL && num >= 0) {
+                       sp = (char *) values[num];
+                       s->stlen = 1;
+               } else {
+                       (void) sprintf(sp, "%ld", num);
+                       s->stlen = strlen(sp);
+               }
+               s->stfmt = -1;
+               if ((s->flags & INTIND) != 0) {
+                       s->flags &= ~(INTIND|NUMBER);
+                       s->flags |= STRING;
+               }
+
+               emalloc(s->stptr, char *, s->stlen + 2, "format_awkldbl_val");
+               memcpy(s->stptr, sp, s->stlen + 1);
+       }
+
+       s->flags |= STRCUR;
+       return s;
+}
+
+/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
+
+static int
+is_ieee_magic_val(const char *val)
+{
+       /*
+        * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
+        * Assume the length is 4, as the caller checks this.
+        */
+       return (   (val[0] == '+' || val[0] == '-')
+               && (   (   (val[1] == 'i' || val[1] == 'I')
+                       && (val[2] == 'n' || val[2] == 'N')
+                       && (val[3] == 'f' || val[3] == 'F'))
+                   || (   (val[1] == 'n' || val[1] == 'N')
+                       && (val[2] == 'a' || val[2] == 'A')
+                       && (val[3] == 'n' || val[3] == 'N'))));
+}
+
+/* get_ieee_magic_val --- return magic value for string */
+
+static AWKLDBL
+get_ieee_magic_val(const char *val)
+{
+       static bool first = true;
+       static AWKLDBL inf;
+       static AWKLDBL nan;
+       char *ptr;
+       AWKLDBL v;
+
+       v = gawk_strtold(val, & ptr);
+
+       if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
+               if (first) {
+                       first = false;
+                       nan = gawk_sqrtl(-LDC(1.0));
+                       inf = -gawk_logl(LDC(0.0));
+               }
+               v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
+               if (val[0] == '-')
+                       v = -v;
+       }
+
+       return v;
+}
+
+/* do_int --- convert double to int for awk */
+
+static NODE *
+do_int(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("int: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = LDBL_VAL(tmp);
+       DEREF(tmp);
+       return make_awkldbl(double_to_int(d));
+}
+
+/* do_log --- the log function */
+
+static NODE *
+do_log(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d, arg;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("log: received non-numeric argument"));
+       (void) force_number(tmp);
+       arg = LDBL_VAL(tmp);
+       if (arg < LDC(0.0))
+               warning(_("log: received negative argument %g"), (double) arg);
+       d = gawk_logl(arg);
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* do_sqrt --- do the sqrt function */
+
+static NODE *
+do_sqrt(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL arg;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("sqrt: received non-numeric argument"));
+       (void) force_number(tmp);
+       arg = LDBL_VAL(tmp);
+       DEREF(tmp);
+       if (arg < LDC(0.0))
+               warning(_("sqrt: called with negative argument %g"), (double) 
arg);
+       return make_awkldbl(gawk_sqrtl(arg));
+}
+
+/* do_exp --- exponential function */
+
+static NODE *
+do_exp(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d, res;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("exp: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = LDBL_VAL(tmp);
+       DEREF(tmp);
+       errno = 0;
+       res = gawk_expl(d);
+       if (errno == ERANGE)
+               warning(_("exp: argument %g is out of range"), (double) d);
+       return make_awkldbl(res);
+}
+
+/* do_atan2 --- do the atan2 function */
+
+static NODE *
+do_atan2(int nargs)
+{
+       NODE *t1, *t2;
+       AWKLDBL d1, d2;
+
+       t2 = POP_SCALAR();
+       t1 = POP_SCALAR();
+       if (do_lint) {
+               if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("atan2: received non-numeric first 
argument"));
+               if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("atan2: received non-numeric second 
argument"));
+       }
+       (void) force_number(t1);
+       (void) force_number(t2);
+       d1 = LDBL_VAL(t1);
+       d2 = LDBL_VAL(t2);
+       DEREF(t1);
+       DEREF(t2);
+       return make_awkldbl(gawk_atan2l(d1, d2));
+}
+
+/* do_sin --- do the sin function */
+
+static NODE *
+do_sin(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("sin: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = gawk_sinl(LDBL_VAL(tmp));
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* do_cos --- do the cos function */
+
+static NODE *
+do_cos(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("cos: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = gawk_cosl(LDBL_VAL(tmp));
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* do_strtonum --- the strtonum function */
+
+static NODE *
+do_strtonum(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if ((tmp->flags & (NUMBER|NUMCUR)) != 0) {
+               (void) force_number(tmp);
+               d = LDBL_VAL(tmp);
+       } else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
+               d = nondec2awkldbl(tmp->stptr, tmp->stlen);
+       else {
+               (void) force_number(tmp);
+               d = LDBL_VAL(tmp);
+       }
+
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* format_awkldbl_prinf --- format a number for (s)printf */
+
+static int
+format_awkldbl_printf(NODE *arg, struct format_spec *spec, struct 
print_fmt_buf *outb)
+{
+       AWKLDBL tmpval;
+       uintmax_t uval;
+       bool sgn;
+       int i, ii, jj;
+       char *chp, *cp;
+       char cs1;
+       int nc;
+
+       static char stackbuf[64];       /* temporary buffer for integer 
formatting */ 
+       static char *intbuf = stackbuf;
+       size_t intbuf_size = 64;
+
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
+
+       tmpval = LDBL_VAL(arg);
+       spec->fill = space_string;
+       spec->chbuf = lchbuf;
+
+       cp = CP;
+       cs1 = spec->fmtchar;
+       switch (cs1) {
+       case 'd':
+       case 'i':
+               if (isnan(tmpval) || isinf(tmpval))
+                       goto out_of_range;
+
+               tmpval = double_to_int(tmpval);
+
+               /*
+                * ``The result of converting a zero value with a
+                * precision of zero is no characters.''
+                */
+               if (spec->have_prec && spec->prec == 0 && tmpval == LDC(0.0)) {
+                       pr_num_tail(cp, spec->prec, spec, outb);
+                       return 0;
+               }
+
+               if (tmpval < LDC(0.0)) {
+                       tmpval = -tmpval;
+                       sgn = true;
+               } else {
+                       if (tmpval == - LDC(0.0))       /* avoid printing -0; 
XXX:  0.0 == -0.0, but does the job. */
+                               tmpval = LDC(0.0);
+                       sgn = false;
+               }
+
+               /*
+                * Use snprintf return value to tell if there
+                * is enough room in the buffer or not.
+                */
+               while ((i = format_float_1(intbuf, intbuf_size, "%.0Lf", 
tmpval)) >= intbuf_size) {
+                       if (intbuf == stackbuf)
+                               intbuf = NULL;
+                       intbuf_size = i + 1;
+                       erealloc(intbuf, char *, intbuf_size, "format_tree");
+               }
+
+               if (i < 1)
+                       goto out_of_range;
+
+               chp = & intbuf[i-1];
+               ii = jj = 0;
+               do {
+                       tmpbuf_prepend(outb, *chp);
+                       chp--; i--;
+#if defined(HAVE_LOCALE_H)
+                       if (spec->quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
+                               if (i)  /* only add if more digits coming */
+                                       tmpbuf_prepend(outb, 
loc.thousands_sep[0]);     /* XXX - assumption it's one char */
+                               if (loc.grouping[ii+1] == 0)
+                                       jj = 0;         /* keep using current 
val in loc.grouping[ii] */
+                               else if (loc.grouping[ii+1] == CHAR_MAX)
+                                       spec->quote_flag= false;
+                               else {                 
+                                       ii++;
+                                       jj = 0;
+                               }
+                       }
 #endif
+               } while (i > 0);
 
-#ifdef HAVE_CEILL
-#define gawk_ceill     ceill
-#else
-static inline long double
-gawk_ceill(long double x)
+
+               /* add more output digits to match the precision */
+               if (spec->have_prec) {
+                       while (CEND - CP < spec->prec)
+                               tmpbuf_prepend(outb, '0');
+               }
+
+               if (sgn)
+                       tmpbuf_prepend(outb, '-');
+               else if (spec->signchar)
+                       tmpbuf_prepend(outb, spec->signchar);
+               /*
+                * When to fill with zeroes is of course not simple.
+                * First: No zero fill if left-justifying.
+                * Next: There seem to be two cases:
+                *      A '0' without a precision, e.g. %06d
+                *      A precision with no field width, e.g. %.10d
+                * Any other case, we don't want to fill with zeroes.
+                */
+               if (! spec->lj
+                   && ((spec->zero_flag && ! spec->have_prec)
+                        || (spec->fw == 0 && spec->have_prec)))
+                       spec->fill = zero_string;
+               if (spec->prec > spec->fw)
+                       spec->fw = spec->prec;
+               spec->prec = CEND - CP;
+               if (spec->fw > spec->prec && ! spec->lj && spec->fill != 
space_string
+                   && (*CP == '-' || spec->signchar)) {
+                       bchunk_one(outb, CP);
+                       CP++;
+                       spec->prec--;
+                       spec->fw--;
+               }
+               cp = CP;
+
+               pr_num_tail(CP, spec->prec, spec, outb);
+               return 0;
+
+       case 'X':
+               spec->chbuf = Uchbuf;
+               /* FALL THROUGH */
+       case 'x':
+               /* FALL THROUGH */
+       case 'u':
+               /* FALL THROUGH */
+       case 'o':
+               /*
+                * ``The result of converting a zero value with a
+                * precision of zero is no characters.''
+                *
+                * If I remember the ANSI C standard, though,
+                * it says that for octal conversions
+                * the precision is artificially increased
+                * to add an extra 0 if # is supplied.
+                * Indeed, in C,
+                *      printf("%#.0o\n", 0);
+                * prints a single 0.
+                */
+       
+               if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval 
== LDC(0.0)) {
+                       pr_num_tail(cp, spec->prec, spec, outb);
+                       return 0;
+               }
+
+               if (tmpval < LDC(0.0)) {
+                       uval = (uintmax_t) (intmax_t) tmpval;
+                       if ((AWKLDBL)(intmax_t) uval != double_to_int(tmpval))
+                               goto out_of_range;
+               } else {
+                       uval = (uintmax_t) tmpval;
+                       if ((AWKLDBL) uval != double_to_int(tmpval))
+                               goto out_of_range;
+               }
+
+               format_nondecimal(uval, spec, outb);
+               return 0;
+
+out_of_range:
+               /* out of range - emergency use of %g format */
+               if (do_lint)
+                       lintwarn(_("[s]printf: value %g is out of range for 
`%%%c' format"),
+                                       (double) tmpval, cs1);
+               cs1 = 'g';
+               goto fmt1;
+
+       case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+               cs1 = 'f';
+               /* FALL THROUGH */
+#endif
+       case 'g':
+       case 'G':
+       case 'e':
+       case 'f':
+       case 'E':
+fmt1:
+               if (! spec->have_prec)
+                       spec->prec = DEFAULT_G_PRECISION;
+
+               chksize(outb, spec->fw + spec->prec + 11);      /* 11 == slop */
+               cp = CPBUF;     /* XXX:  using the temporary prepend-buffer and
+                                * we know it has enough room (>=11).
+                                 */
+               *cp++ = '%';
+               if (spec->lj)
+                       *cp++ = '-';
+               if (spec->signchar)
+                       *cp++ = spec->signchar;
+               if (spec->alt)
+                       *cp++ = '#';
+               if (spec->zero_flag)
+                       *cp++ = '0';
+               if (spec->quote_flag)
+                       *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "");
+#endif
+
+               sprintf(cp, "*.*L%c", cs1);
+               while ((nc = format_float_1(buf_end(outb), buf_space(outb), 
CPBUF,
+                               (int) spec->fw, (int) spec->prec, tmpval)) >= 
buf_space(outb))
+                       chksize(outb, nc + 1);
+
+#if defined(LC_NUMERIC)
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "C");
+#endif
+
+               buf_adjust(outb, nc); /* adjust data and free space in output 
buffer */
+               return 0;
+
+       default:
+               cant_happen();  
+       }
+
+       return -1;
+#undef CP
+#undef CEND
+#undef CPBUF
+}
+
+
+/*--------------- replacement routines for losing systems -----------*/
+
+
+/* init_pow2d_table --- populate powers of 2 table */
+
+static AWKLDBL
+init_pow2d_table(unsigned int n)
 {
-       return ceil( (double) x);
+       unsigned i;
+       emalloc(pow2d_table, AWKLDBL *, 129 * sizeof (AWKLDBL), 
"init_pow2d_table");
+       pow2d_table[0] = LDC(1.0);
+       for (i = 1; i <= 128; i++)
+               pow2d_table[i] = pow2d_table[i - 1] * LDC(2.0);
+       return pow2d_table[n];
 }
+
+
+#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL) && 
defined(PRINTF_HAS_LF_FORMAT))
+
+/*
+ * gawk_floorl_finite_p --- provide floor() for long double. The double value
+ *     must be finite and >= 0. If the 2nd array argument isn't NULL, also 
split the
+ *     integer value into 16 (32) bit chunks.
+ */
+
+static AWKLDBL
+gawk_floorl_finite_p(AWKLDBL x, gawk_uint_t *chunk)
+{
+       int high, low, mid;
+       AWKLDBL intval = LDC(0.0);
+
+#if    LDBL_INT_BITS == 128
+       if (x >= POW2LD(113))
+#else
+       if (x >= POW2LD(64))
 #endif
+               return -LDC(1.0);
+
+       if (chunk != NULL)
+               memset(chunk, '\0', 4 * sizeof (gawk_uint_t));
+
+       /* binary search */
+       high = LDBL_INT_BITS - 1;
+       while (x >= LDC(2.0)) {
+               low = 0;
+               while (low <= high) {
+                       mid = (low + high) / 2;
+                       if (x < POW2LD(mid))
+                               high = mid - 1;
+                       else
+                               low = mid + 1;
+               }
+
+               if (x < POW2LD(low)) {
+                       x -= POW2LD(low - 1);
+                       intval += POW2LD(low - 1);
+
+                       if (chunk != NULL) {
+                               /*
+                                * seperate the 64 (128) bits into 16 (32) bit 
chunks.
+                                *      | D[3]  |  D[2] |  D[1] | D[0]  |
+                                *      |<------- x (64/128 bits) ----->|
+                                */
 
-#ifdef HAVE_POWL
-#define gawk_powl      powl
+#if    LDBL_INT_BITS == 128
+                               if (low <= 32) chunk[0] += (gawk_uint_t) 
POW2LD(low - 1);
+                               else if (low <= 64) chunk[1] += (gawk_uint_t) 
POW2LD(low - 33);
+                               else if (low <= 96) chunk[2] += (gawk_uint_t) 
POW2LD(low - 65);
+                               else chunk[3] += (gawk_uint_t) POW2LD(low - 97);
 #else
-static inline long double
-gawk_powl(long double x, long double y)
+                               if (low <= 16) chunk[0] += (gawk_uint_t) 
POW2LD(low - 1);
+                               else if (low <= 32) chunk[1] += (gawk_uint_t) 
POW2LD(low - 17);
+                               else if (low <= 48) chunk[2] += (gawk_uint_t) 
POW2LD(low - 33);
+                               else chunk[3] += (gawk_uint_t) POW2LD(low - 49);
+#endif
+                       }
+               }
+
+               high = low;
+       }
+
+       if (x >= LDC(1.0)) {
+               if (chunk != NULL)
+                       chunk[0]++;
+               x -= LDC(1.0);
+               intval += LDC(1.0);
+       }
+       return intval;  /* >= 0.0 */
+}
+#endif
+
+
+#if ! (defined(HAVE_FLOORL) && defined(HAVE_CEILL))
+
+/* double_to_int --- convert double to int, used in several places */
+
+static AWKLDBL
+double_to_int(AWKLDBL x)
 {
-       return pow( (double) x, (double) y);
+       AWKLDBL intval;
+       int sign = 1;
+
+       if (isnan(x) || isinf(x) || x == LDC(0.0))
+               return x;
+
+       if (x < LDC(0.0)) {
+               sign = -1;
+               x = -x;
+       }
+
+       if ((intval = gawk_floorl_finite_p(x, NULL)) < LDC(0.0))
+               intval = (AWKLDBL) Floor((double) x);   /* outside range, use 
floor() for C double */
+       return intval * ((AWKLDBL) sign);
 }
+
 #endif
 
-#ifdef HAVE_SQRTL
-#define gawk_sqrtl     sqrtl
+
+#if ! defined(PRINTF_HAS_LF_FORMAT)
+
+/*
+ * format_uint_finite_p --- format a double as an unsigned integer. The double 
value
+ *     must be finite and >= 0.
+ */
+
+static int
+format_uint_finite_p(char *str, size_t size, AWKLDBL x)
+{
+       /*
+        * For an explanation of the algorithm, and the derivation for the
+        * magic numbers below, please see:
+        *
+        *  Binary to Decimal Conversion in Limited Precision
+        *  Part of the Arithmetic Tutorial Collection
+        *  by Douglas W. Jones
+        *  THE UNIVERSITY OF IOWA Department of Computer Science
+        *  URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+        */
+
+#if    LDBL_INT_BITS == 128
+       static gawk_uint_t coeff[] = { 
+               1, 4967296, 9551616,
+#if defined(TEST_NUMBR) && TEST_NUMBR == 1
+               3585223950336ULL,
+#else
+               3585223950336UL,
+#endif
+               429, 4407370, 3400832,
+               184467, 5142643,
+               79228162
+       };
+       static const char format[] = "%7.7u%7.7u%7.7u%7.7u%7.7u";
+       gawk_uint_t decimal_base = 10000000;
 #else
-static inline long double
-gawk_sqrtl(long double x)
+       static gawk_uint_t coeff[] = {
+               1, 5536, 7296, 656,
+               6, 9496, 7671,
+               42, 4749,
+               281
+       };
+       static const char format[] = "%4.4u%4.4u%4.4u%4.4u%4.4u";
+       gawk_uint_t decimal_base = 10000;
+#endif
+       char *p;
+       int len;
+       gawk_uint_t d0, d1, d2, d3, d4, q;
+       gawk_uint_t chunk[4];
+
+       assert(!!isnan(x) == 0);
+       assert(!!isinf(x) == 0);
+       assert(x >= LDC(0.0));
+
+       if (size <= 35)         /* maximum size ever needed excluding 
terminating null */
+               return 35;
+
+       if (gawk_floorl_finite_p(x, chunk) < LDC(0.0))  /* outside range */
+               return -1;
+
+        d0 = chunk[0] + coeff[1] * chunk[1] + coeff[2] * chunk[2] + coeff[3] * 
chunk[3];
+        q = d0 / decimal_base;
+        d0 = d0 % decimal_base;
+
+        d1 = q + coeff[4] * chunk[1] + coeff[5] * chunk[2] + coeff[6] * 
chunk[3];
+        q = d1 / decimal_base;
+        d1 = d1 % decimal_base;
+
+        d2 = q + coeff[7] * chunk[2] + coeff[8] * chunk[3];
+        q = d2 / decimal_base;
+        d2 = d2 % decimal_base;
+
+        d3 = q + coeff[9] * chunk[3];
+        q = d3 / decimal_base;
+        d3 = d3 % decimal_base;
+
+        d4 = q;
+
+       (void) sprintf(str, format, (unsigned) d4, (unsigned) d3,
+                               (unsigned) d2, (unsigned) d1, (unsigned) d0);
+
+       /* strip leading 0s */
+       for (p = str; *(p + 1); p++)    /* don't strip the last 0, the value 
can be "0" */
+               if (*p != '0')
+                       break;
+       len = strlen(p);
+       if (p != str)
+               memmove(str, p, len + 1);
+       return len;
+}
+
+/*
+ * format_float_1 --- format a single double value according to FORMAT.
+ *     The value must be finite and >= 0.      
+ */
+
+static int
+format_float_1(char *str, size_t size, const char *format, ...)
 {
-       return sqrt( (double) x);
+        va_list argp;
+       char alt_format[16];
+       size_t len;
+       int ret = -1;
+       AWKLDBL x;
+
+        va_start(argp, format);
+
+       len = strlen(format);
+
+       /* expect %Lf, %LF, %Le, %LE, %Lg or %LG */
+       assert(len >= 2 && format[len - 2] == 'L');
+       
+       memcpy(alt_format, format, len - 2);
+       alt_format[len - 2] = format[len - 1];  /* skip the `L' */ 
+       alt_format[len - 1] = '\0';
+
+       if (strcmp(format, "%.0Lf") == 0) {
+               /* format as integer */
+               x = va_arg(argp, AWKLDBL);
+               va_end(argp);
+               if ((ret = format_uint_finite_p(str, size, x)) < 0)
+                       ret = snprintf(str, size, alt_format, (double) x);
+       } else {
+               int fw, prec;
+
+               fw = va_arg(argp, int);
+               prec = va_arg(argp, int);
+               x = va_arg(argp, AWKLDBL);
+               ret = snprintf(str, size, alt_format, fw, prec, (double) x);
+       }
+
+       va_end(argp);
+       return ret;
 }
 #endif
diff --git a/m4/ChangeLog b/m4/ChangeLog
index a674df6..ea46ed3 100644
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,6 +1,10 @@
+2013-01-19         John Haque      <address@hidden>
+
+       * long_double.m4: Make "%Lf" support in printf optional.
+
 2012-12-29         John Haque      <address@hidden>
 
-        * long_double.m4: New file.
+       * long_double.m4: New file.
 
 2012-12-24         Arnold D. Robbins     <address@hidden>
 
diff --git a/m4/long_double.m4 b/m4/long_double.m4
index 87ef80f..5cac44d 100644
--- a/m4/long_double.m4
+++ b/m4/long_double.m4
@@ -49,15 +49,17 @@ AC_DEFUN([GAWK_USE_LONG_DOUBLE],
          [gawk_cv_has_L_format=yes],
         [gawk_cv_has_L_format=no])
        ])
-      if test $gawk_cv_has_L_format = yes; then
-        gawk_has_long_double=yes
-      fi
+       gawk_has_long_double=yes
     fi
   fi
 
   if test $gawk_has_long_double = yes; then
     AC_DEFINE([USE_LONG_DOUBLE], [1],
            [Define to 1 if can use 'long double'.])
+    if test $gawk_cv_has_L_format = yes; then
+      AC_DEFINE([PRINTF_HAS_LF_FORMAT], [1],
+           [Define to 1 if printf supports %Lf format.])
+    fi
 
     AC_CHECK_FUNC(strtold)
     if test $ac_cv_func_strtold = yes; then
@@ -107,4 +109,5 @@ AC_DEFUN([GAWK_USE_LONG_DOUBLE],
   fi
 
   AC_SUBST(USE_LONG_DOUBLE)
+  AC_SUBST(PRINTF_HAS_LF_FORMAT)
 ])
diff --git a/misc/bin2dec.awk b/misc/bin2dec.awk
index 04a82e1..01fb291 100644
--- a/misc/bin2dec.awk
+++ b/misc/bin2dec.awk
@@ -1,8 +1,8 @@
-#      bcd.awk --- Calculate the magic numbers in: 
+#      bin2dec.awk --- Calculate the magic numbers in: 
 #              Binary to Decimal Conversion in Limited Precision - Douglas B. 
Jones
 #              URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
 #
-#      Usage: ./gawk -M -f bin2dec.awk
+#      Usage: ./gawk -M -f misc/bin2dec.awk
 #
 
 BEGIN {
@@ -22,7 +22,7 @@ BEGIN {
 #      128-bit integers
        CHUNK_SIZE = 32
        CHUNK3_SIZE = 17        # the useful size of the first (MSB) chunk <= 
CHUNK_SIZE
-                               # 17 + 32 + 32 + 32 = 113, precision of 128-bit 
double
+                               # 17 + 32 + 32 + 32 = 113, precision of real 
128-bit double
        DEC_BASE = 10000000     # 7 decimal digits per chunk, 35 total
 
 ######################################################
diff --git a/misc/ldblint64.awk b/misc/ldblint64.awk
new file mode 100644
index 0000000..65f3939
--- /dev/null
+++ b/misc/ldblint64.awk
@@ -0,0 +1,14 @@
+# Usage gawk -B -f ldblint54.awk
+
+BEGIN {
+       for (i = -9.0; i < 2.0; i++) {
+               j = i
+               if (j >= 0.0)
+                       j = " + " j
+               else {
+                       j = -j
+                       j = " - " j
+               }
+               printf("2^64%s = %d\n", j, 2^64 + i)
+       }
+}
diff --git a/misc/ldblint64.ok b/misc/ldblint64.ok
new file mode 100644
index 0000000..e61ce9a
--- /dev/null
+++ b/misc/ldblint64.ok
@@ -0,0 +1,11 @@
+2^64 - 9 = 18446744073709551607
+2^64 - 8 = 18446744073709551608
+2^64 - 7 = 18446744073709551609
+2^64 - 6 = 18446744073709551610
+2^64 - 5 = 18446744073709551611
+2^64 - 4 = 18446744073709551612
+2^64 - 3 = 18446744073709551613
+2^64 - 2 = 18446744073709551614
+2^64 - 1 = 18446744073709551615
+2^64 + 0 = 18446744073709551616
+2^64 + 1 = 18446744073709551616
diff --git a/test/Makefile.in b/test/Makefile.in
index b2e0172..8ee67d2 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -172,6 +172,7 @@ PACKAGE_URL = @PACKAGE_URL@
 PACKAGE_VERSION = @PACKAGE_VERSION@
 PATH_SEPARATOR = @PATH_SEPARATOR@
 POSUB = @POSUB@
+PRINTF_HAS_LF_FORMAT = @PRINTF_HAS_LF_FORMAT@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=88304b52a0dc79b4b33b038acb6f20aaacf01092

commit 88304b52a0dc79b4b33b038acb6f20aaacf01092
Author: John Haque <address@hidden>
Date:   Wed Jan 16 05:38:11 2013 -0600

    Add files sprintf*_0Lf.awk, bin2dec.awk.

diff --git a/TODO.LDBL b/TODO.LDBL
index 3e2732f..f81fe53 100644
--- a/TODO.LDBL
+++ b/TODO.LDBL
@@ -9,10 +9,6 @@ Also, append suffix L to all long double constants.
 * Convert gawk math routines to C for platforms lacking any. Without ceil() 
and floor()
 for long doubles, these can't even get 64 bit integers!
        -- finish fp_fmod() in misc/fp_math.awk.
-       -- write test script(s) to verify (some) output, but DON'T add it to 
the dist.
-       80 bit vs 128 bit, and the C math library CANNOT be trusted to produce
-       correctly rounded results. Double check any discrepencies using 
arbitrary-precision
-       math.
 
 * Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM. What 
is the point
 of floor() and ceil() wrappers? Don't have a clue.
diff --git a/configure b/configure
index 4bf106b..0bb8f5f 100755
--- a/configure
+++ b/configure
@@ -5554,7 +5554,7 @@ $as_echo "yes" >&6; }
 else
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
+       CFLAGS="$CFLAGS"        # DONOT TURN OF ASSERTIONS
 fi
 
 
diff --git a/configure.ac b/configure.ac
index d3780bd..e8686e0 100644
--- a/configure.ac
+++ b/configure.ac
@@ -95,7 +95,7 @@ then
        AC_MSG_RESULT([yes])
 else
        AC_MSG_RESULT([no])
-       CFLAGS="$CFLAGS -DNDEBUG"       # turn off assertions
+       CFLAGS="$CFLAGS"        # DONOT TURN OF ASSERTIONS
 fi
 
 AC_SUBST(CFLAGS)
diff --git a/misc/bin2dec.awk b/misc/bin2dec.awk
new file mode 100644
index 0000000..04a82e1
--- /dev/null
+++ b/misc/bin2dec.awk
@@ -0,0 +1,83 @@
+#      bcd.awk --- Calculate the magic numbers in: 
+#              Binary to Decimal Conversion in Limited Precision - Douglas B. 
Jones
+#              URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+#
+#      Usage: ./gawk -M -f bin2dec.awk
+#
+
+BEGIN {
+       UINT32_MAX = 4294967296
+       UINT64_MAX = 18446744073709551616
+
+       N = 4   # number of chunks
+
+##     64-bit integers
+#      CHUNK_SIZE = CHUNK3_SIZE = 16
+#      DEC_BASE = 10000        # 4 decimal digits per chunk, 20 total
+
+##     96-bit integers
+#      CHUNK_SIZE = CHUNK3_SIZE = 24
+#      DEC_BASE = 10000000     # 7 decimal digits per chunk, 35 total
+
+#      128-bit integers
+       CHUNK_SIZE = 32
+       CHUNK3_SIZE = 17        # the useful size of the first (MSB) chunk <= 
CHUNK_SIZE
+                               # 17 + 32 + 32 + 32 = 113, precision of 128-bit 
double
+       DEC_BASE = 10000000     # 7 decimal digits per chunk, 35 total
+
+######################################################
+
+       CHUNK_MAX = 2^CHUNK_SIZE
+       CHUNK3_MAX = 2^CHUNK3_SIZE
+
+       print "CHUNK_SIZE = ", CHUNK_SIZE
+       print "N = ", N
+       print "DEC_BASE = ", DEC_BASE
+
+       # powers of 2^CHUNK_SIZE
+       POWER_2_C[0] = 1
+       for (i = 1; i < N; i++)
+               POWER_2_C[i] = 2 ^(CHUNK_SIZE * i)
+
+       # powers of DEC_BASE
+       POWER_BASE[0] = 1
+       for (i = 1; i < N; i++)
+               POWER_BASE[i] = DEC_BASE^i
+
+       coeff[N-1][N-1] = int(POWER_2_C[N-1] / POWER_BASE[N-1])
+       for (i = N-2; i >= 0; i--) {
+               for (k = N-1; k >= i; k--) {
+                       coeff[i][k] = int(POWER_2_C[k]/POWER_BASE[i])
+                       for (m = 1; m <= k - i; m++)
+                               coeff[i][k] -= POWER_BASE[m] * coeff[m + i][k]
+               }
+       }
+
+       for (i = N - 1; i >= 0; i--) {
+               for (j = N - 1; j >= i; j--) {
+                       printf("%d ", coeff[i][j])
+               }
+               print "";
+       }
+
+       print "----- a0, a1, a2, a4 upper bounds -----"
+       print "UINT32_MAX =", UINT32_MAX
+       print "UINT64_MAX =", UINT64_MAX
+       for (i = N - 1; i >= 0; i--) {
+               a[i] = 0;
+               for (j = N - 1; j >= i; j--) {
+                       if (j == 3)
+                               a[i] += coeff[i][j] * CHUNK3_MAX
+                       else
+                               a[i] += coeff[i][j] * CHUNK_MAX
+               }
+               printf("a%d        <= %d\n", i, a[i])
+       }
+
+       print "----- c1, c2, c3 upper bounds -----"
+       c[0] = 0
+       for (i = 1; i < N; i++) {
+               c[i] = (a[i - 1] + c[i - 1])/ DEC_BASE
+               printf("c%d        <= %d\n", i, c[i])
+       }
+}
diff --git a/misc/sprintf128_0Lf.awk b/misc/sprintf128_0Lf.awk
new file mode 100644
index 0000000..e3e61a9
--- /dev/null
+++ b/misc/sprintf128_0Lf.awk
@@ -0,0 +1,308 @@
+#
+#      sprintf128_0Lf.awk -- format integers stored as long doubles and
+#      don't have %Lf in (s)printf.
+#      This test script handles integers < 2^113 i.e. 128-bit long doubles.
+#      Requires -M -vPREC=113 (or -B if have 128-bit long doubles)
+#
+#      Usage:
+#
+#      $ echo "2^113-1" | ./gawk -M -vPREC=113 -f sprintf128_0Lf.awk
+#      2^113-1 (1.03845937170696552570609926584401910e+34) is an integer
+#      sprintf_int128 :10384593717069655257060992658440191
+#      arbitrary-prec :10384593717069655257060992658440191
+#      floor = 10384593717069655257060992658440191
+#      ceil  = 10384593717069655257060992658440191
+#      $ echo "2^113" | ./gawk -M -vPREC=113 -f sprintf128_0Lf.awk
+#      2^113 (1.03845937170696552570609926584401920e+34) is an integer
+#      sprintf_int128 :10384593717069655257060992658440192
+#      arbitrary-prec :10384593717069655257060992658440192
+#      floor = 10384593717069655257060992658440192
+#      ceil  = 10384593717069655257060992658440192
+#      $ echo "2^113+1" | ./gawk -M -vPREC=113 -f sprintf128_0Lf.awk
+#      2^113+1 (1.03845937170696552570609926584401920e+34) is an integer
+#      sprintf_int128 :10384593717069655257060992658440192 ***
+#      arbitrary-prec :10384593717069655257060992658440193 
+#      floor = 10384593717069655257060992658440192     ***
+#      ceil  = 10384593717069655257060992658440192     ***
+#
+
+BEGIN {
+       # Only need 113 for 128-bit long double.
+
+       LDBL_MANT_DIG = 128
+       POW2[0] = 1
+       for (i = 1; i <= LDBL_MANT_DIG; i++)
+               POW2[i] = POW2[i - 1] * 2       
+}
+
+{
+       #
+       # Compare apples to apples, setting PREC=128;
+       #
+
+       eval = sprintf("./gawk -M -vPREC=128 'BEGIN { printf(\"%%0.40e\", %s); 
print \"\";\
+               printf(\"%%035d\", %s); print \"\";\
+               printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0, 
$0)
+       eval | getline num
+       eval | getline ap_intval
+       eval | getline ap_isint
+       close(eval)
+
+       pnum = num + 0
+       sign = ""
+       if (pnum < 0) {
+               pnum = -pnum
+               sign = "-"
+       }
+
+       isint = isinteger(pnum, W)
+       if (isint) {
+               if (! ap_isint)
+                       print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
+               printf("%s (%s) is an integer\n", $0, sprintf("%0.35e", num))
+               printf("sprintf_int128 :%c%s\n", sign, sprintf_int128(W))
+               printf("arbitrary-prec :%s\n", ap_intval)
+       } else {
+               if (ap_isint)
+                       print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
+               printf("%s (%s) is not an integer\n", $0, sprintf("%0.35e", 
num))
+       }
+
+#
+#      Don't have %Lf ! 
+#      printf("floor = %d\n", floor(num))
+#      printf("ceil  = %d\n", ceil(num))
+#
+       # use MPFR to format floor(), ceil() returned value
+       eval = sprintf("./gawk -M -vPREC=128 'BEGIN { printf(\"%%d\", %s); 
print \"\";\
+               printf(\"%%d\", %s); print \"\"; }'", floor(num), ceil(num))
+       eval | getline floor_val
+       eval | getline ceil_val
+       close(eval)
+
+       print "floor =", floor_val
+       print "ceil  =", ceil_val
+}
+
+
+function sprintf_int128(chunk,         d0, d1, d2, d3, d4, q, k, dec_base)
+{
+       #
+       # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
+       # URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+       #
+
+       #
+       # Results from the application of the idea in the article to the 
128-bit conversion
+       # problem:
+       #
+       # Divide a 128-bit number into 32-bit chunks, and use 10,000,000 as the
+       # working decimal base. This gives us 7 digits per chunk, and 35 total 
decimal digits.
+       # Using the notations used in the article,
+       #
+       #       a3 = 79228162 n3
+       #       a2 = 5142643 n3 + 184467 n2
+       #       a1 = 3400832 n3 + 4407370 n2 + 429 n1
+       #       a0 = 3585223950336 n3 + 9551616 n2 + 4967296 n1 + 1 n0
+       #
+       #       n3, n2, n1 and n0 are the 32-bit chunks, n3 represents the most
+       #       significant 32 bits. Assuming these chunks are at their maximum 
possible
+       #       value, which is 2^32: 
+       #
+       #       UINT64_MAX = 18446744073709551616
+       #       a3        <= 340282364712189952
+       #       a2        <= 22879763232194560
+       #       a1        <= 33537814771531776
+       #       a0        <= 15398481973785556680704
+       #       c1        <= 1539848197378555
+       #       c2        <= 3507766296
+       #       c3        <= 2287976673
+       #
+       #       c1, c2 and c3 are carries from one digit position to the next
+       #       (results from integer divisions by the decimal base; see below).
+       #
+       #       The maximum value of a0 is > UINT64_MAX. If we restrict n3 to be
+       #       in the range 0 < n3 < 2^17, corresponding to the 113-bit 
precision available
+       #       from a 128-bit long double, we instead get these upper bounds:
+       #
+       #       UINT64_MAX = 18446744073709551616
+       #       a3        <= 10384593649664
+       #       a2        <= 792953788694528
+       #       a1        <= 18931798306193408
+       #       a0        <= 532280730126909440
+       #       c1        <= 53228073012
+       #       c2        <= 1893185153
+       #       c3        <= 79295568
+       #
+       #       We can use 64-bit signed or unsigned long type! QED.
+       #
+       #       All these numbers calculated using the script misc/bin2dec.awk. 
+       #
+ 
+
+       dec_base = 10000000
+
+       if (DEBUG) {
+               for (k = 0; k < 4; k++) {
+                       if (chunk[k] > 4294967296)
+                               printf("chunk[%d] > 4294967296, this ain't 
right\n", k)
+               }
+               print "(32 MSB bits first):", chunk[3], "|", chunk[2], "|", 
chunk[1], "|", chunk[0]
+       }
+
+        d0 = 3585223950336 * chunk[3] + 9551616 * chunk[2] + 4967296 * 
chunk[1] + chunk[0];
+
+        q = int(d0 / dec_base);        # int() may call floorl(), but double 
version is good enough
+                               # in this case. This is only a consideration in 
the awk code,
+                               # not in the C translation.
+
+        d0 = d0 - q * dec_base;        # not using % operator, may not have 
fmodl()
+
+        d1 = q + 3400832 * chunk[3] + 4407370 * chunk[2] + 429 * chunk[1];
+        q = int(d1 / dec_base);
+        d1 = d1 - q * dec_base;
+
+        d2 = q + 5142643 * chunk[3] + 184467 * chunk[2];
+        q = int(d2 / dec_base);
+        d2 = d2 - q * dec_base;
+
+        d3 = q + 79228162 * chunk[3];
+        q = int(d3 / dec_base);
+        d3 = d3 - q * dec_base;
+
+        d4 = q;
+       return sprintf("%7.7u%7.7u%7.7u%7.7u%7.7u", \
+                       d4, d3, d2, d1, d0);    # don't need %Lf support here
+}
+
+function floor(x,      d, sign, chunk, isint)
+{
+       x = +x
+
+#
+#      if (isnan(x) || isinf(x) || x == 0)
+#              return x
+
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+
+       #
+       # For x >= 2^LDBL_MANT_DIG, use floor for C-double. Bailing out here.
+       #
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.35e is too big (> %0.35e), bailing out\n", x, 
POW2[LDBL_MANT_DIG] - 1)
+               exit(1);
+       }
+
+       isint = isinteger(x, chunk)
+
+       # d is long double type
+       d = chunk[3] * POW2[96] + chunk[2] * POW2[64] + chunk[1] * POW2[32] + 
chunk[0]
+
+       if (isint)      # d == x
+               return sign * d
+       return (sign > 0) ? d : -d - 1
+}
+
+
+function ceil(x,       d, sign, chunk, isint)
+{
+       x = +x
+
+#
+#      if (isnan(x) || isinf(x) || x == 0)
+#              return x
+
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+
+       #
+       # For x >= 2^LDBL_MANT_DIG, use ceil for C-double. Bailing out here.
+       #
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.35e is too big (> %0.35e), bailing out\n", x, 
POW2[LDBL_MANT_DIG] - 1)
+               exit(1);
+       }
+
+       isint = isinteger(x, chunk)
+       # d is long double type
+       d = chunk[3] * POW2[96] + chunk[2] * POW2[64] + chunk[1] * POW2[32] + 
chunk[0]
+
+       if (isint)      # d == x
+               return sign * d
+       return (sign > 0) ? d + 1 : -d
+}
+
+
+function isinteger(x, D,       j, low, high)
+{
+       # x >= 0
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.40e is too big (> %0.40e), bailing out\n", x, 
2^LDBL_MANT_DIG - 1)
+               exit(1);
+       }
+
+       D[0] = D[1] = D[2] = D[3] = 0
+ 
+       # binary search
+       high = LDBL_MANT_DIG - 1
+       while (x >= 2) {
+               low = 0
+               while (low <= high) {
+                       mid = int((low + high) / 2)
+                       if (x < POW2[mid])
+                               high = mid - 1
+                       else
+                               low = mid + 1
+               }
+
+               if (x < POW2[low]) {
+                       x -= POW2[low - 1]
+
+                       #
+                       # Easier to seperate the 128 bits into 32-bit chunks now
+                       # then bit fiddling later.
+                       #       | D[3] | D[2] | D[1] | D[0]  |
+                       #       |<------- x (128 bits) ----->|
+                       #
+
+                       if (low <= 32) { D[0] += POW2[low - 1] }
+                       else if (low <= 64) { D[1] += POW2[low - 33] }
+                       else if (low <= 96) { D[2] += POW2[low - 65] }
+                       else { D[3] += POW2[low - 97] }
+               }
+
+               high = low
+       }
+
+#
+#      # XXX -- O(n^2) vs. O(n * log(n))  -- how much do we really gain?
+#      #       Consider extra additions and divisions, but lower # of < 
comparisons.
+#
+#      while (x >= 2) {
+#              for (j = 1; j <= LDBL_MANT_DIG; j++) {
+#                      if (x < POW2[j]) {
+#                              x -= POW2[j - 1]
+#                              break
+#                      }
+#              }
+#      }
+#
+
+       if (x >= 1) {
+               D[0]++
+               x -= 1
+       }
+
+       return (x == 0)
+}
+
diff --git a/misc/sprintf64_0Lf.awk b/misc/sprintf64_0Lf.awk
new file mode 100644
index 0000000..2ec38ac
--- /dev/null
+++ b/misc/sprintf64_0Lf.awk
@@ -0,0 +1,247 @@
+#
+#      sprintf64_0Lf.awk -- format integers stored as long doubles and
+#      don't have %Lf in (s)printf. This test script handles integers < 2^64.
+#      Requires both -M (for verification) and -B
+#      Usage:
+#              echo "2^63 + 2^54 + 2^13" | ./gawk -B -f misc/sprintf_0Lf.awk
+#
+
+BEGIN {
+       # 113 for 128-bit long double, but can only get 64-bit ints.
+       LDBL_MANT_DIG = 64
+       POW2[0] = 1
+       for (i = 1; i <= LDBL_MANT_DIG; i++)
+               POW2[i] = POW2[i - 1] * 2
+}
+
+{
+       #
+       # Compare apples to apples, setting PREC=64; With real 128-bit long 
doubles,
+       # one probably should use PREC=quad or 113.
+       # %0.34e ain't the right format but then ..
+       #
+
+       eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%0.34e\", %s); 
print \"\";\
+               printf(\"%%020d\", %s); print \"\";\
+               printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0, 
$0)
+       eval | getline num
+       eval | getline ap_intval
+       eval | getline ap_isint
+       close(eval)
+
+       pnum = num + 0
+       sign = ""
+       if (pnum < 0) {
+               pnum = -pnum
+               sign = "-"
+       }
+
+       isint = isinteger(pnum, chunk16)
+       if (isint) {
+               if (! ap_isint)
+                       print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
+               printf("%s (%s) is an integer\n", $0, sprintf("%0.34e", num))
+               printf("sprintf_int64  :%c%s\n", sign, sprintf_int64(chunk16))
+               printf("arbitrary-prec :%s\n", ap_intval)
+               printf("LDBL %%0.Lf     :%c%020d\n", sign, pnum)        # or 
garbage if no %Lf
+       } else {
+               if (ap_isint)
+                       print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
+               printf("%s (%s) is not an integer\n", $0, sprintf("%0.34e", 
num))
+       }
+
+#
+#      Don't have %Lf ! 
+#      printf("floor = %d\n", floor(num))
+#      printf("ceil  = %d\n", ceil(num))
+#
+       # use MPFR to format floor(), ceil() returned values
+       eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%d\", %s); print 
\"\";\
+               printf(\"%%d\", %s); print \"\"; }'", floor(num), ceil(num))
+       eval | getline floor_val
+       eval | getline ceil_val
+       close(eval)
+
+       print "floor =", floor_val
+       print "ceil  =", ceil_val
+}
+
+
+function sprintf_int64(chunk,  d0, d1, d2, d3, d4, q, k, dec_base)
+{
+       #
+       # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
+       # URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+       #
+
+       dec_base = 10000
+
+       if (DEBUG) {
+               for (k = 0; k < 4; k++) {
+                       if (chunk[k] > 65535)
+                               printf("chunk[%d] > 65535, this ain't right\n", 
k)
+               }
+               print "(16 MSB bits first):", chunk[3], "|", chunk[2], "|", 
chunk[1], "|", chunk[0]
+       }
+
+        d0 = 656 * chunk[3] + 7296 * chunk[2] + 5536 * chunk[1] + chunk[0];
+
+        q = int(d0 / dec_base);        # int() may call floorl(), but double 
version is good enough
+                               # in this case. This is only a consideration in 
the awk code,
+                               # not in the C translation.
+
+        d0 = d0 - q * dec_base;        # not using % operator, may not have 
fmodl()
+
+        d1 = q + 7671 * chunk[3] + 9496 * chunk[2] + 6 * chunk[1];
+        q = int(d1 / dec_base);
+        d1 = d1 - q * dec_base;
+
+        d2 = q + 4749 * chunk[3] + 42 * chunk[2];
+        q = int(d2 / dec_base);
+        d2 = d2 - q * dec_base;
+
+        d3 = q + 281 * chunk[3];
+        q = int(d3 / dec_base);
+        d3 = d3 - q * dec_base;
+
+        d4 = q;
+       return sprintf("%4.4u%4.4u%4.4u%4.4u%4.4u", \
+                       d4, d3, d2, d1, d0);    # don't need %Lf support here
+}
+
+
+function floor(x,      d, sign, chunk)
+{
+       x = +x
+
+#
+#      if (isnan(x) || isinf(x) || x == 0)
+#              return x
+
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+
+       #
+       # For x >= 2^LDBL_MANT_DIG, use floor for C-double. Bailing out here.
+       #
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.34e is too big (> %0.34e), bailing out\n", x, 
2^64 - 1)
+               exit(1);
+       }
+
+       isinteger(x, chunk)
+
+       # d is long double type
+       d = chunk[3] * POW2[48] + chunk[2] * POW2[32] + chunk[1] * POW2[16] + 
chunk[0]
+
+       if (d == x)
+               return sign * d
+       return (sign > 0) ? d : -d - 1
+}
+
+
+function ceil(x,       d, sign, chunk)
+{
+       x = +x
+
+#
+#      if (isnan(x) || isinf(x) || x == 0)
+#              return x
+
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+
+       #
+       # For x >= 2^LDBL_MANT_DIG, use ceil for C-double. Bailing out here.
+       #
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.34e is too big (> %0.34e), bailing out\n", x, 
2^64 - 1)
+               exit(1);
+       }
+
+       isinteger(x, chunk)
+       # d is long double type
+       d = chunk[3] * POW2[48] + chunk[2] * POW2[32] + chunk[1] * POW2[16] + 
chunk[0]
+
+       if (d == x)
+               return sign * d
+       return (sign > 0) ? d + 1 : -d
+}
+
+
+function isinteger(x, D,       j, low, high)
+{
+       # Assume x >= 0
+
+       #
+       # FIXME --  x >= 2^LDBL_MANT_DIG; C-double test is adequate, these 
integers have same representations.
+       #       output maybe incorrect anyway.
+       #
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.34e is too big (> %0.34e), bailing out\n", x, 
2^64 - 1)
+               exit(1);
+       }
+
+       D[0] = D[1] = D[2] = D[3] = 0
+ 
+       # binary search
+       high = LDBL_MANT_DIG - 1
+       while (x >= 2) {
+               low = 0
+               while (low <= high) {
+                       mid = int((low + high) / 2)
+                       if (x < POW2[mid])
+                               high = mid - 1
+                       else
+                               low = mid + 1
+               }
+
+               if (x < POW2[low]) {
+                       x -= POW2[low - 1]
+
+                       #
+                       # Easier to seperate the 64 bits into 16-bit chunks now
+                       # then bit fiddling later.
+                       #       | D[3] | D[2] | D[1] | D[0] |
+                       #       |<------- x (64 bits) ----->|
+                       #
+
+                       if (low <= 16) { D[0] += POW2[low - 1] }
+                       else if (low <= 32) { D[1] += POW2[low - 17] }
+                       else if (low <= 48) { D[2] += POW2[low - 33] }
+                       else { D[3] += POW2[low - 49] }
+               }
+
+               high = low
+       }
+
+#
+#      # XXX -- O(n^2) vs. O(n * log(n))  -- how much do we really gain?
+#      #       Consider extra additions and divisions, but lower # of < 
comparisons.
+#
+#      while (x >= 2) {
+#              for (j = 1; j <= LDBL_MANT_DIG; j++) {
+#                      if (x < POW2[j]) {
+#                              x -= POW2[j - 1]
+#                              break
+#                      }
+#              }
+#      }
+#
+
+       if (x >= 1) {
+               D[0]++
+               x -= 1
+       }
+       return (x == 0)
+}
+
diff --git a/misc/sprintf_0Lf.awk b/misc/sprintf_0Lf.awk
deleted file mode 100644
index d504604..0000000
--- a/misc/sprintf_0Lf.awk
+++ /dev/null
@@ -1,172 +0,0 @@
-#
-#      sprintf_0Lf.awk -- format integers stored as long doubles and
-#      don't have %Lf in (s)printf.
-#      This test script handles integers < 2^64 even with 128-bit long doubles.
-#      Requires both -M (for verification) and -B
-#      Usage: echo "2^63 + 2^54 + 2^13" | ./gawk -B -f misc/sprintf_0Lf.awk
-#
-
-BEGIN {
-       # 113 for 128-bit long double, but can only get 64-bit ints.
-       LDBL_MANT_DIG = 64
-       POW2[0] = 1
-       for (i = 1; i <= LDBL_MANT_DIG; i++)
-               POW2[i] = POW2[i - 1] * 2       
-}
-
-{
-       #
-       # Compare apples to apples, setting PREC=64; With real 128-bit long 
doubles,
-       # one probably should use PREC=quad or 113.
-       #
-
-       eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%0.34e\", %s); 
print \"\";\
-               printf(\"%%020d\", %s); print \"\";\
-               printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0, 
$0)
-       eval | getline num
-       eval | getline ap_intval
-       eval | getline ap_isint
-       close(eval)
-
-       pnum = num + 0
-       sign = ""
-       if (pnum < 0) {
-               pnum = -pnum
-               sign = "-"
-       }
-
-       isint = isinteger(pnum, W)
-       if (isint) {
-               if (! ap_isint)
-                       print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
-               printf("%s (%s) is an integer\n", $0, sprintf("%0.34e", num))
-               printf("sprintf_int64  :%c%s\n", sign, sprintf_int64(W))
-               printf("arbitrary-prec :%s\n", ap_intval)
-               printf("LDBL %%0.Lf     :%c%020d\n", sign, pnum)        # or 
garbage if no %Lf
-       } else {
-               if (ap_isint)
-                       print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
-               printf("%s (%s) is not an integer\n", $0, sprintf("%0.34e", 
num))
-       }
-}
-
-
-function sprintf_int64(d,      d0, d1, d2, d3, d4, q, k)
-{
-       #
-       # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
-       #       URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
-       #
-
-       if (DEBUG) {
-               for (k = 0; k < 4; k++) {
-                       if (d[k] > 65535)
-                               printf("d[%d] > 65535, this ain't right\n", k)
-               }
-               print "(16 MSB bits first):", d[3], "|", d[2], "|", d[1], "|", 
d[0]
-       }
-
-        d0 = 656 * d[3] + 7296 * d[2] + 5536 * d[1] + d[0];
-
-        q = int(d0 / 10000);   # int() may call floorl(), but double version 
is good enough
-                               # in this case. This is only a consideration in 
the awk code,
-                               # not in the C translation.
-
-        d0 = d0 - q * 10000;   # not using % operator, may not have fmodl()
-
-        d1 = q + 7671 * d[3] + 9496 * d[2] + 6 * d[1];
-        q = int(d1 / 10000);
-        d1 = d1 - q * 10000;
-
-        d2 = q + 4749 * d[3] + 42 * d[2];
-        q = int(d2 / 10000);
-        d2 = d2 - q * 10000;
-
-        d3 = q + 281 * d[3];
-        q = int(d3 / 10000);
-        d3 = d3 - q * 10000;
-
-        d4 = q;
-       return sprintf("%4.4u%4.4u%4.4u%4.4u%4.4u", \
-                       d4, d3, d2, d1, d0);    # don't need %Lf support here
-}
-
-
-function isinteger(x, D,       j, low, high)
-{
-       # Assume x >= 0
-
-       #
-       # XXX: x >= 2^LDBL_MANT_DIG
-       #       test using C-double is adequate at least in the range
-       #       2^LDBL_MANT_DIG <= x <= DBL_MAX; the integers have same
-       #       representations. Here in awk code, we simply crap out.
-       #
-
-       if (x >= POW2[LDBL_MANT_DIG]) {
-               printf("number %0.34e is too big (> %0.34e), bailing out\n", x, 
2^64 - 1)
-               exit(1);
-       }
-
-       D[0] = D[1] = D[2] = D[3] = 0
- 
-       # binary search
-       high = LDBL_MANT_DIG - 1
-       while (x >= 2) {
-               low = 0
-               while (low <= high) {
-                       mid = int((low + high) / 2)
-                       if (x < POW2[mid])
-                               high = mid - 1
-                       else
-                               low = mid + 1
-               }
-
-               if (x < POW2[low]) {
-                       x -= POW2[low - 1]
-
-                       #
-                       # Easier to seperate the 64 bits into 16-bit chunks now
-                       # then doing bit fiddling later.
-                       #       | D[3] | D[2] | D[1] | D[0] |
-                       #       |<------- x (64 bits) ----->|
-                       #
-
-                       if (low <= 16) { D[0] += POW2[low - 1] }
-                       else if (low <= 32) { D[1] += POW2[low - 17] }
-                       else if (low <= 48) { D[2] += POW2[low - 33] }
-                       else { D[3] += POW2[low - 49] }
-               }
-
-               high = low
-       }
-
-#
-#      # XXX -- O(n^2) vs. O(n * log(n))  -- how much do we really gain?
-#      #       Consider extra additions and divisions, but less # of < 
comparisons.
-#
-#      while (x >= 2) {
-#              for (j = 1; j <= LDBL_MANT_DIG; j++) {
-#                      if (x < POW2[j]) {
-#                              x -= POW2[j - 1]
-#                              break
-#                      }
-#              }
-#      }
-#
-
-       if (x == 0)
-               return 1;
-       if (x == 1) {
-               if (and(D[0], 1)) {
-                       ######## XXX: MAYBE ADDING A SECOND TIME ??? #######
-                       print "Opps! there may be a bug in code! D[0] = ", D[0] 
> "/dev/stderr"
-                       exit(1)
-               }
-
-               D[0]++
-               return 1
-       }
-
-       return 0
-} 

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=5f4dbd4819a7dae080c6ff4833a06cf1ca8d502c

commit 5f4dbd4819a7dae080c6ff4833a06cf1ca8d502c
Author: John Haque <address@hidden>
Date:   Tue Jan 15 04:55:45 2013 -0600

    Added file misc/sprintf_0Lf.awk, fixed bug in misc/fp_math.awk.

diff --git a/misc/fp_math.awk b/misc/fp_math.awk
index 634d128..51583fa 100644
--- a/misc/fp_math.awk
+++ b/misc/fp_math.awk
@@ -137,13 +137,17 @@ function fp_atan2(y, x,   \
 
 #
 #      Collect two terms in each iteration for the Taylor series:
-#              sin(x) = (x - x^3/3!) + (x^5/7! - x^9/9!) + ...
+#              sin(x) = (x - x^3/3!) + (x^5/5! - x^7/7!) + ...
 #
 
 function taylor_sin(x, \
                i, fact, xpow2, xpow_odd, sum, term, err)
 {
-       # XXX: this assumes x >= 0
+       # this assumes x >= 0
+       if (x < 0) {
+               print "taylor_sin: received x < 0 ! " > "/dev/stderr"
+               exit(1)
+       }
 
        if (x == 0)
                return x
@@ -208,7 +212,7 @@ function taylor_cos(x,      \
 
 #
 # For 0 <= x <= PI/4, using Taylor series approximation for sin(x):
-#      x - x^3/5! + x^5/7! - ...
+#      x - x^3/3! + x^5/5! - ...
 #
 # for PI/4 < x <= PI/2, use identity sin(x) = cos(PI/2 - x).
 #
@@ -279,11 +283,6 @@ function fp_cos(x, \
        return cv
 }
 
-function fp_atan2(y, x)
-{
-       return euler_atan2(y, x)
-}
-
 function isinf(x)
 {
        x = + x 
diff --git a/misc/sprintf_0Lf.awk b/misc/sprintf_0Lf.awk
new file mode 100644
index 0000000..d504604
--- /dev/null
+++ b/misc/sprintf_0Lf.awk
@@ -0,0 +1,172 @@
+#
+#      sprintf_0Lf.awk -- format integers stored as long doubles and
+#      don't have %Lf in (s)printf.
+#      This test script handles integers < 2^64 even with 128-bit long doubles.
+#      Requires both -M (for verification) and -B
+#      Usage: echo "2^63 + 2^54 + 2^13" | ./gawk -B -f misc/sprintf_0Lf.awk
+#
+
+BEGIN {
+       # 113 for 128-bit long double, but can only get 64-bit ints.
+       LDBL_MANT_DIG = 64
+       POW2[0] = 1
+       for (i = 1; i <= LDBL_MANT_DIG; i++)
+               POW2[i] = POW2[i - 1] * 2       
+}
+
+{
+       #
+       # Compare apples to apples, setting PREC=64; With real 128-bit long 
doubles,
+       # one probably should use PREC=quad or 113.
+       #
+
+       eval = sprintf("./gawk -M -vPREC=64 'BEGIN { printf(\"%%0.34e\", %s); 
print \"\";\
+               printf(\"%%020d\", %s); print \"\";\
+               printf(\"%%d\", int(%s) == %s + 0); print \"\"}'", $0, $0, $0, 
$0)
+       eval | getline num
+       eval | getline ap_intval
+       eval | getline ap_isint
+       close(eval)
+
+       pnum = num + 0
+       sign = ""
+       if (pnum < 0) {
+               pnum = -pnum
+               sign = "-"
+       }
+
+       isint = isinteger(pnum, W)
+       if (isint) {
+               if (! ap_isint)
+                       print "!!!!!!!!!MPFR says it is not an integer!!!!!!!!!"
+               printf("%s (%s) is an integer\n", $0, sprintf("%0.34e", num))
+               printf("sprintf_int64  :%c%s\n", sign, sprintf_int64(W))
+               printf("arbitrary-prec :%s\n", ap_intval)
+               printf("LDBL %%0.Lf     :%c%020d\n", sign, pnum)        # or 
garbage if no %Lf
+       } else {
+               if (ap_isint)
+                       print "!!!!!!!!!MPFR says it is an integer!!!!!!!!!"
+               printf("%s (%s) is not an integer\n", $0, sprintf("%0.34e", 
num))
+       }
+}
+
+
+function sprintf_int64(d,      d0, d1, d2, d3, d4, q, k)
+{
+       #
+       # Binary to Decimal Conversion in Limited Precision - Douglas B. Jones
+       #       URL: homepage.cs.uiowa.edu/~jones/bcd/decimal.html
+       #
+
+       if (DEBUG) {
+               for (k = 0; k < 4; k++) {
+                       if (d[k] > 65535)
+                               printf("d[%d] > 65535, this ain't right\n", k)
+               }
+               print "(16 MSB bits first):", d[3], "|", d[2], "|", d[1], "|", 
d[0]
+       }
+
+        d0 = 656 * d[3] + 7296 * d[2] + 5536 * d[1] + d[0];
+
+        q = int(d0 / 10000);   # int() may call floorl(), but double version 
is good enough
+                               # in this case. This is only a consideration in 
the awk code,
+                               # not in the C translation.
+
+        d0 = d0 - q * 10000;   # not using % operator, may not have fmodl()
+
+        d1 = q + 7671 * d[3] + 9496 * d[2] + 6 * d[1];
+        q = int(d1 / 10000);
+        d1 = d1 - q * 10000;
+
+        d2 = q + 4749 * d[3] + 42 * d[2];
+        q = int(d2 / 10000);
+        d2 = d2 - q * 10000;
+
+        d3 = q + 281 * d[3];
+        q = int(d3 / 10000);
+        d3 = d3 - q * 10000;
+
+        d4 = q;
+       return sprintf("%4.4u%4.4u%4.4u%4.4u%4.4u", \
+                       d4, d3, d2, d1, d0);    # don't need %Lf support here
+}
+
+
+function isinteger(x, D,       j, low, high)
+{
+       # Assume x >= 0
+
+       #
+       # XXX: x >= 2^LDBL_MANT_DIG
+       #       test using C-double is adequate at least in the range
+       #       2^LDBL_MANT_DIG <= x <= DBL_MAX; the integers have same
+       #       representations. Here in awk code, we simply crap out.
+       #
+
+       if (x >= POW2[LDBL_MANT_DIG]) {
+               printf("number %0.34e is too big (> %0.34e), bailing out\n", x, 
2^64 - 1)
+               exit(1);
+       }
+
+       D[0] = D[1] = D[2] = D[3] = 0
+ 
+       # binary search
+       high = LDBL_MANT_DIG - 1
+       while (x >= 2) {
+               low = 0
+               while (low <= high) {
+                       mid = int((low + high) / 2)
+                       if (x < POW2[mid])
+                               high = mid - 1
+                       else
+                               low = mid + 1
+               }
+
+               if (x < POW2[low]) {
+                       x -= POW2[low - 1]
+
+                       #
+                       # Easier to seperate the 64 bits into 16-bit chunks now
+                       # then doing bit fiddling later.
+                       #       | D[3] | D[2] | D[1] | D[0] |
+                       #       |<------- x (64 bits) ----->|
+                       #
+
+                       if (low <= 16) { D[0] += POW2[low - 1] }
+                       else if (low <= 32) { D[1] += POW2[low - 17] }
+                       else if (low <= 48) { D[2] += POW2[low - 33] }
+                       else { D[3] += POW2[low - 49] }
+               }
+
+               high = low
+       }
+
+#
+#      # XXX -- O(n^2) vs. O(n * log(n))  -- how much do we really gain?
+#      #       Consider extra additions and divisions, but less # of < 
comparisons.
+#
+#      while (x >= 2) {
+#              for (j = 1; j <= LDBL_MANT_DIG; j++) {
+#                      if (x < POW2[j]) {
+#                              x -= POW2[j - 1]
+#                              break
+#                      }
+#              }
+#      }
+#
+
+       if (x == 0)
+               return 1;
+       if (x == 1) {
+               if (and(D[0], 1)) {
+                       ######## XXX: MAYBE ADDING A SECOND TIME ??? #######
+                       print "Opps! there may be a bug in code! D[0] = ", D[0] 
> "/dev/stderr"
+                       exit(1)
+               }
+
+               D[0]++
+               return 1
+       }
+
+       return 0
+} 

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=e8561893a3ca3f7cee6ca23e4361abbb510502bb

commit e8561893a3ca3f7cee6ca23e4361abbb510502bb
Author: John Haque <address@hidden>
Date:   Sat Jan 12 09:24:26 2013 -0600

    Adding cast to long double, and suffix L for constants.

diff --git a/TODO.LDBL b/TODO.LDBL
new file mode 100644
index 0000000..3e2732f
--- /dev/null
+++ b/TODO.LDBL
@@ -0,0 +1,20 @@
+* Don't trust compiler with type promotion:
+       **** If an operation involves two operands, and one of them is of type 
long double,
+       **** the other one is converted to long double. 
+The latest version of GCC I have (4.4.3) seems to have different ideas. Start 
using cast
+to long double even when it seems unnecessary address@hidden@#
+
+Also, append suffix L to all long double constants.
+
+* Convert gawk math routines to C for platforms lacking any. Without ceil() 
and floor()
+for long doubles, these can't even get 64 bit integers!
+       -- finish fp_fmod() in misc/fp_math.awk.
+       -- write test script(s) to verify (some) output, but DON'T add it to 
the dist.
+       80 bit vs 128 bit, and the C math library CANNOT be trusted to produce
+       correctly rounded results. Double check any discrepencies using 
arbitrary-precision
+       math.
+
+* Don't use adjust_uint(uintmax_t n) from floatcomp.c, it is for AWKNUM. What 
is the point
+of floor() and ceil() wrappers? Don't have a clue.
+
+
diff --git a/long_double.c b/long_double.c
index 7d94afd..e85fea2 100644
--- a/long_double.c
+++ b/long_double.c
@@ -26,19 +26,18 @@
 #include "awk.h"
 
 #ifdef USE_LONG_DOUBLE
-#include "math.h"
+#include <math.h>
 #include "random.h"
 #include "floatmagic.h"        /* definition of isnan */
 
 #include "format.h"
 
-
 #define AWKLDBL        long double
 
-
 #include "long_double.h"
 
-#define LDBL(n)        (*((AWKLDBL *) (n)->qnumbr))
+#define LDBL_VAL(n)    (*((AWKLDBL *) (n)->qnumbr))
+#define LDC(x)         x##L
 
 /* Can declare these, since we always use the random shipped with gawk */
 extern char *initstate(unsigned long seed, char *state, long n);
@@ -189,12 +188,12 @@ awkldbl_init(bltin_t **numbr_bltins)
 
        /* set the numeric value of null string */
        get_long_double(Nnull_string->qnumbr);
-       LDBL(Nnull_string) = 0.0;
+       LDBL_VAL(Nnull_string) = LDC(0.0);
        Nnull_string->flags |= (NUMCUR|NUMBER);
 
        /* initialize TRUE and FALSE nodes */
-       false_node = make_awkldbl(0.0);
-       true_node = make_awkldbl(1.0);
+       false_node = make_awkldbl(LDC(0.0));
+       true_node = make_awkldbl(LDC(1.0));
        false_node->flags |= NUMINT;
        true_node->flags |= NUMINT;
 
@@ -207,7 +206,7 @@ awkldbl_init(bltin_t **numbr_bltins)
 static unsigned long
 awkldbl_toulong(const NODE *n)
 {
-       return LDBL(n);
+       return LDBL_VAL(n);
 }
 
 /* awkldbl_tolong --- conversion to long */
@@ -215,7 +214,7 @@ awkldbl_toulong(const NODE *n)
 static long
 awkldbl_tolong(const NODE *n)
 {
-       return LDBL(n);
+       return LDBL_VAL(n);
 }
 
 /* awkldbl_todouble --- conversion to double */
@@ -223,7 +222,7 @@ awkldbl_tolong(const NODE *n)
 static double
 awkldbl_todouble(const NODE *n)
 {
-       return LDBL(n);
+       return LDBL_VAL(n);
 }
 
 /* awkldbl_touintmax_t --- conversion to uintmax_t */
@@ -231,7 +230,7 @@ awkldbl_todouble(const NODE *n)
 static uintmax_t
 awkldbl_touintmax_t(const NODE *n)
 {
-       return LDBL(n);
+       return LDBL_VAL(n);
 }
 
 /* awkldbl_sgn --- return 1 if number > 0, zero if number == 0, and -1 if 
number < 0 */
@@ -239,8 +238,8 @@ awkldbl_touintmax_t(const NODE *n)
 static int
 awkldbl_sgn(const NODE *n)
 {
-       AWKLDBL d = LDBL(n);
-       return (d < 0.0 ? -1 : d > 0.0);
+       AWKLDBL d = LDBL_VAL(n);
+       return (d < LDC(0.0) ? -1 : d > LDC(0.0));
 }
 
 /* awkldbl_isinteger --- check if a number is an integer */
@@ -248,7 +247,7 @@ awkldbl_sgn(const NODE *n)
 static bool
 awkldbl_isinteger(const NODE *n)
 {
-       AWKLDBL d = LDBL(n);
+       AWKLDBL d = LDBL_VAL(n);
 
        if (isnan(d) || isinf(d))
                return false;
@@ -260,7 +259,7 @@ awkldbl_isinteger(const NODE *n)
 static bool
 awkldbl_isnan(const NODE *n)
 {
-       return isnan(LDBL(n));
+       return isnan(LDBL_VAL(n));
 }
 
 /* awkldbl_isinf --- check if number is infinity */
@@ -268,7 +267,7 @@ awkldbl_isnan(const NODE *n)
 static bool
 awkldbl_isinf(const NODE *n)
 {
-       return isinf(LDBL(n));
+       return isinf(LDBL_VAL(n));
 }
 
 /* negate_awkldbl --- negate number in NODE */
@@ -276,7 +275,7 @@ awkldbl_isinf(const NODE *n)
 static void
 negate_awkldbl(NODE *n)
 {
-       LDBL(n) = - LDBL(n);
+       LDBL_VAL(n) = - LDBL_VAL(n);
 }
 
 /* awkldbl_add --- add two numbers */
@@ -284,7 +283,7 @@ negate_awkldbl(NODE *n)
 static NODE *
 awkldbl_add(const NODE *t1, const NODE *t2)
 {
-       return make_awkldbl(LDBL(t1) + LDBL(t2));
+       return make_awkldbl(LDBL_VAL(t1) + LDBL_VAL(t2));
 }
 
 /* awkldbl_sub --- subtract two numbers */
@@ -292,7 +291,7 @@ awkldbl_add(const NODE *t1, const NODE *t2)
 static NODE *
 awkldbl_sub(const NODE *t1, const NODE *t2)
 {
-       return make_awkldbl(LDBL(t1) - LDBL(t2));
+       return make_awkldbl(LDBL_VAL(t1) - LDBL_VAL(t2));
 }
 
 /* awkldbl_mul --- multiply two numbers */
@@ -300,7 +299,7 @@ awkldbl_sub(const NODE *t1, const NODE *t2)
 static NODE *
 awkldbl_mul(const NODE *t1, const NODE *t2)
 {
-       return make_awkldbl(LDBL(t1) * LDBL(t2));
+       return make_awkldbl(LDBL_VAL(t1) * LDBL_VAL(t2));
 }
 
 /* awkldbl_add --- quotient of two numbers */
@@ -308,10 +307,10 @@ awkldbl_mul(const NODE *t1, const NODE *t2)
 static NODE *
 awkldbl_div(const NODE *t1, const NODE *t2)
 {
-       AWKLDBL d = LDBL(t2);
+       AWKLDBL d = LDBL_VAL(t2);
        if (d == 0)
                fatal(_("division by zero attempted"));
-       return make_awkldbl(LDBL(t1) / d);
+       return make_awkldbl(LDBL_VAL(t1) / d);
 }
 
 /* awkldbl_add_long --- add long value to a number */
@@ -319,7 +318,7 @@ awkldbl_div(const NODE *t1, const NODE *t2)
 static NODE *
 awkldbl_add_long(const NODE *t1, long n)
 {
-       return make_awkldbl(LDBL(t1) + n);
+       return make_awkldbl(LDBL_VAL(t1) + (AWKLDBL) n);
 }
 
 /* awkldbl_copy --- copy a number */
@@ -327,7 +326,7 @@ awkldbl_add_long(const NODE *t1, long n)
 static NODE *
 awkldbl_copy(const NODE *t1)
 {
-       return make_awkldbl(LDBL(t1));
+       return make_awkldbl(LDBL_VAL(t1));
 }
 
 /* awkldbl_update_var --- update a special variable from internal variables */
@@ -338,14 +337,14 @@ awkldbl_update_var(NODE *var)
        NODE *val = var->var_value;
        AWKLDBL d;
 
-       d = LDBL(val);
+       d = LDBL_VAL(val);
        if (var == NR_node) {
                if (MNR == 0 && d != NR) {
                        unref(val);
-                       val = NR_node->var_value = make_awkldbl(NR);
+                       val = NR_node->var_value = make_awkldbl((AWKLDBL) NR);
                } else if (MNR != 0) {
                        unref(val);
-                       d = ((AWKLDBL) MNR) * LONG_MAX + NR;
+                       d = ((AWKLDBL) MNR) * LONG_MAX + (AWKLDBL) NR;
                        val = var->var_value = make_awkldbl(d);
                }
                return val;
@@ -354,10 +353,10 @@ awkldbl_update_var(NODE *var)
        assert(var == FNR_node);
        if (MFNR == 0 && d != FNR) {
                unref(val);
-               val = FNR_node->var_value = make_awkldbl(FNR);
+               val = FNR_node->var_value = make_awkldbl((AWKLDBL) FNR);
        } else if (MFNR != 0) {
                unref(val);
-               d = ((AWKLDBL) MFNR) * LONG_MAX + FNR;
+               d = ((AWKLDBL) MFNR) * LONG_MAX + (AWKLDBL) FNR;
                val = var->var_value = make_awkldbl(d);
        }
        return val;
@@ -374,7 +373,7 @@ awkldbl_set_var(const NODE *var)
        NODE *val = var->var_value;
        AWKLDBL d;
 
-       d = LDBL(val);
+       d = LDBL_VAL(val);
        if (var == NR_node) {
                MNR = d / LONG_MAX;
                NR = d - ((AWKLDBL) MNR) * LONG_MAX;
@@ -421,7 +420,7 @@ make_awkldbl(AWKLDBL x)
        getnode(r);
        r->type = Node_val;
        get_long_double(r->qnumbr);
-       LDBL(r) = x;
+       LDBL_VAL(r) = x;
        r->flags = MALLOC|NUMBER|NUMCUR;
        r->valref = 1;
        r->stptr = NULL;
@@ -442,7 +441,7 @@ make_awknum(AWKNUM x)
        getnode(r);
        r->type = Node_val;
        get_long_double(r->qnumbr);
-       LDBL(r) = (AWKLDBL) x;
+       LDBL_VAL(r) = (AWKLDBL) x;
        r->flags = MALLOC|NUMBER|NUMCUR;
        r->valref = 1;
        r->stptr = NULL;
@@ -494,8 +493,8 @@ do_lshift(int nargs)
 
        (void) force_number(s1);
        (void) force_number(s2);
-       val = LDBL(s1);
-       shift = LDBL(s2);
+       val = LDBL_VAL(s1);
+       shift = LDBL_VAL(s2);
 
        if (do_lint) {
                if (val < 0 || shift < 0)
@@ -536,8 +535,8 @@ do_rshift(int nargs)
        }
        (void) force_number(s1);
        (void) force_number(s2);
-       val = LDBL(s1);
-       shift = LDBL(s2);
+       val = LDBL_VAL(s1);
+       shift = LDBL_VAL(s2);
        if (do_lint) {
                if (val < 0 || shift < 0)
                        lintwarn(_("rshift(%Lf, %Lf): negative values will give 
strange results"),
@@ -578,7 +577,7 @@ do_and(int nargs)
                        lintwarn(_("and: argument %d is non-numeric"), i);
 
                (void) force_number(s1);
-               val = LDBL(s1);
+               val = LDBL_VAL(s1);
                if (do_lint && val < 0)
                        lintwarn(_("and: argument %d negative value %Lg will 
give strange results"),
                                        i, val);
@@ -611,7 +610,7 @@ do_or(int nargs)
                        lintwarn(_("or: argument %d is non-numeric"), i);
 
                (void) force_number(s1);
-               val = LDBL(s1);
+               val = LDBL_VAL(s1);
                if (do_lint && val < 0)
                        lintwarn(_("or: argument %d negative value %Lg will 
give strange results"),
                                        i, val);
@@ -645,7 +644,7 @@ do_xor(int nargs)
                        lintwarn(_("xor: argument %d is non-numeric"), i);
 
                (void) force_number(s1);
-               val = LDBL(s1);
+               val = LDBL_VAL(s1);
                if (do_lint && val < 0)
                        lintwarn(_("xor: argument %d negative value %Lg will 
give strange results"),
                                        i, val);
@@ -674,7 +673,7 @@ do_compl(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("compl: received non-numeric argument"));
        (void) force_number(tmp);
-       d = LDBL(tmp);
+       d = LDBL_VAL(tmp);
        DEREF(tmp);
 
        if (do_lint) {
@@ -746,7 +745,7 @@ nondec2awkldbl(char *str, size_t len)
                        default:
                                goto done;
                        }
-                       retval = (retval * 16) + val;
+                       retval = (retval * LDC(16.0)) + (AWKLDBL) val;
                }
        } else if (*str == '0') {
                for (; len > 0; len--) {
@@ -756,7 +755,7 @@ nondec2awkldbl(char *str, size_t len)
                                str = start;
                                goto decimal;
                        }
-                       retval = (retval * 8) + (*str - '0');
+                       retval = (retval * LDC(8.0)) + (AWKLDBL) (*str - '0');
                        str++;
                }
        } else {
@@ -820,7 +819,7 @@ do_srand(int nargs)
                if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                        lintwarn(_("srand: received non-numeric argument"));
                (void) force_number(tmp);
-               d = LDBL(tmp);
+               d = LDBL_VAL(tmp);
                srandom((unsigned int) (save_seed = (long) d));
                DEREF(tmp);
        }
@@ -846,7 +845,7 @@ str2awkldbl(char *str, char **endptr, int base, bool 
is_integer ATTRIBUTE_UNUSED
                errno = 0;
                d = gawk_strtold(str, endptr);
                if (errno != 0)
-                       d = 0;
+                       d = LDC(0.0);
        } else {
                if (base == 8 || base == 16)
                        d = nondec2awkldbl(str, strlen(str));
@@ -855,7 +854,7 @@ str2awkldbl(char *str, char **endptr, int base, bool 
is_integer ATTRIBUTE_UNUSED
                        errno = 0;
                        d = gawk_strtold(str, NULL);
                        if (errno != 0)
-                               d = 0;
+                               d = LDC(0.0);
                        errno = 0;
                }
        }
@@ -876,10 +875,10 @@ awkldbl_mod(const NODE *t1, const NODE *t2)
 {
        AWKLDBL d2;
 
-       d2 = LDBL(t2);
-       if (d2 == 0)
+       d2 = LDBL_VAL(t2);
+       if (d2 == LDC(0.0))
                fatal(_("division by zero attempted in `%%'"));
-       return make_awkldbl(gawk_fmodl(LDBL(t1), d2));
+       return make_awkldbl(gawk_fmodl(LDBL_VAL(t1), d2));
 }
 
 /* awkldbl_pow --- power function */
@@ -887,7 +886,7 @@ awkldbl_mod(const NODE *t1, const NODE *t2)
 static NODE *
 awkldbl_pow(const NODE *t1, const NODE *t2)
 {
-       return make_awkldbl(calc_exp(LDBL(t1), LDBL(t2)));
+       return make_awkldbl(calc_exp(LDBL_VAL(t1), LDBL_VAL(t2)));
 }
 
 
@@ -899,7 +898,7 @@ awkldbl_pow(const NODE *t1, const NODE *t2)
 static AWKLDBL
 calc_exp_posint(AWKLDBL x, long n)
 {
-       AWKLDBL mult = 1;
+       AWKLDBL mult = LDC(1.0);
 
        while (n > 1) {
                if ((n % 2) == 1)
@@ -915,13 +914,13 @@ calc_exp_posint(AWKLDBL x, long n)
 static AWKLDBL
 calc_exp(AWKLDBL x1, AWKLDBL x2)
 {
-       long lx;
+       long lx = x2;
 
-       if ((lx = x2) == x2) {          /* integer exponent */
+       if (((AWKLDBL) lx) == x2) {             /* integer exponent */
                if (lx == 0)
-                       return 1;
+                       return LDC(1.0);
                return (lx > 0) ? calc_exp_posint(x1, lx)
-                               : 1.0 / calc_exp_posint(x1, -lx);
+                               : LDC(1.0) / calc_exp_posint(x1, -lx);
        }
        return gawk_powl(x1, x2);
 }
@@ -939,8 +938,8 @@ cmp_awkldbls(const NODE *t1, const NODE *t2)
         * comparison at the awk level is a different issue, and needs to be 
dealt
         * with in the interpreter for each opcode seperately.
         */
-       AWKLDBL d1 = LDBL(t1);
-       AWKLDBL d2 = LDBL(t2);
+       AWKLDBL d1 = LDBL_VAL(t1);
+       AWKLDBL d2 = LDBL_VAL(t2);
 
        if (isnan(d1))
                return ! isnan(d2);
@@ -973,7 +972,7 @@ force_awkldbl(NODE *n)
        /* Note: only set NUMCUR if we actually convert some digits */
 
        get_long_double(n->qnumbr);
-       LDBL(n) = 0.0;
+       LDBL_VAL(n) = LDC(0.0);
 
        if (n->stlen == 0) {
                return n;
@@ -994,7 +993,7 @@ force_awkldbl(NODE *n)
                        if ((n->flags & MAYBE_NUM) != 0)
                                n->flags &= ~MAYBE_NUM;
                        n->flags |= NUMBER|NUMCUR;
-                       LDBL(n) = get_ieee_magic_val(n->stptr);
+                       LDBL_VAL(n) = get_ieee_magic_val(n->stptr);
                        return n;
                }
                /* else
@@ -1024,7 +1023,7 @@ force_awkldbl(NODE *n)
 
        if (cpend - cp == 1) {          /* only one character */
                if (isdigit((unsigned char) *cp)) {     /* it's a digit! */
-                       LDBL(n) = (AWKLDBL)(*cp - '0');
+                       LDBL_VAL(n) = (AWKLDBL)(*cp - '0');
                        n->flags |= newflags;
                        n->flags |= NUMCUR;
                        if (cp == n->stptr)             /* no leading spaces */
@@ -1036,7 +1035,7 @@ force_awkldbl(NODE *n)
        if (do_non_decimal_data) {      /* main.c assures false if do_posix */
                errno = 0;
                if (! do_traditional && get_numbase(cp, true) != 10) {
-                       LDBL(n) = nondec2awkldbl(cp, cpend - cp);
+                       LDBL_VAL(n) = nondec2awkldbl(cp, cpend - cp);
                        n->flags |= NUMCUR;
                        ptr = cpend;
                        goto finish;
@@ -1046,7 +1045,7 @@ force_awkldbl(NODE *n)
        errno = 0;
        save = *cpend;
        *cpend = '\0';
-       LDBL(n) = gawk_strtold((const char *) cp, &ptr);
+       LDBL_VAL(n) = gawk_strtold((const char *) cp, &ptr);
 
        /* POSIX says trailing space is OK for NUMBER */
        while (isspace((unsigned char) *ptr))
@@ -1108,7 +1107,7 @@ format_awkldbl_val(const char *format, int index, NODE *s)
         * < and > so that things work correctly on systems with 64 bit 
integers.
         */
 
-       d = LDBL(s);
+       d = LDBL_VAL(s);
 
        if ((s->flags & STRCUR) != 0)
                efree(s->stptr);
@@ -1116,7 +1115,7 @@ format_awkldbl_val(const char *format, int index, NODE *s)
 
        /* not an integral value, or out of range */
        if ((ival = double_to_int(d)) != d
-                       || ival <= LONG_MIN || ival >= LONG_MAX
+                       || ival <= (AWKLDBL) LONG_MIN || ival >= (AWKLDBL) 
LONG_MAX
        ) {
                struct format_spec spec;
                struct print_fmt_buf *outb;
@@ -1209,8 +1208,8 @@ get_ieee_magic_val(const char *val)
        if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
                if (first) {
                        first = false;
-                       nan = gawk_sqrtl(-1.0);
-                       inf = -gawk_logl(0.0);
+                       nan = gawk_sqrtl(-LDC(1.0));
+                       inf = -gawk_logl(LDC(0.0));
                }
                v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
                if (val[0] == '-')
@@ -1225,7 +1224,7 @@ get_ieee_magic_val(const char *val)
 static AWKLDBL
 double_to_int(AWKLDBL d)
 {
-       if (d >= 0)
+       if (d >= LDC(0.0))
                d = gawk_floorl(d);
        else
                d = gawk_ceill(d);
@@ -1244,7 +1243,7 @@ do_int(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("int: received non-numeric argument"));
        (void) force_number(tmp);
-       d = LDBL(tmp);
+       d = LDBL_VAL(tmp);
        DEREF(tmp);
        return make_awkldbl(double_to_int(d));
 }
@@ -1261,8 +1260,8 @@ do_log(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("log: received non-numeric argument"));
        (void) force_number(tmp);
-       arg = LDBL(tmp);
-       if (arg < 0.0)
+       arg = LDBL_VAL(tmp);
+       if (arg < LDC(0.0))
                warning(_("log: received negative argument %Lg"), arg);
        d = gawk_logl(arg);
        DEREF(tmp);
@@ -1281,9 +1280,9 @@ do_sqrt(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("sqrt: received non-numeric argument"));
        (void) force_number(tmp);
-       arg = LDBL(tmp);
+       arg = LDBL_VAL(tmp);
        DEREF(tmp);
-       if (arg < 0.0)
+       if (arg < LDC(0.0))
                warning(_("sqrt: called with negative argument %Lg"), arg);
        return make_awkldbl(gawk_sqrtl(arg));
 }
@@ -1300,7 +1299,7 @@ do_exp(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("exp: received non-numeric argument"));
        (void) force_number(tmp);
-       d = LDBL(tmp);
+       d = LDBL_VAL(tmp);
        DEREF(tmp);
        errno = 0;
        res = gawk_expl(d);
@@ -1327,8 +1326,8 @@ do_atan2(int nargs)
        }
        (void) force_number(t1);
        (void) force_number(t2);
-       d1 = LDBL(t1);
-       d2 = LDBL(t2);
+       d1 = LDBL_VAL(t1);
+       d2 = LDBL_VAL(t2);
        DEREF(t1);
        DEREF(t2);
        return make_awkldbl(gawk_atan2l(d1, d2));
@@ -1347,7 +1346,7 @@ do_sin(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("sin: received non-numeric argument"));
        (void) force_number(tmp);
-       d = gawk_sinl(LDBL(tmp));
+       d = gawk_sinl(LDBL_VAL(tmp));
        DEREF(tmp);
        return make_awkldbl(d);
 }
@@ -1364,7 +1363,7 @@ do_cos(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("cos: received non-numeric argument"));
        (void) force_number(tmp);
-       d = gawk_cosl(LDBL(tmp));
+       d = gawk_cosl(LDBL_VAL(tmp));
        DEREF(tmp);
        return make_awkldbl(d);
 }
@@ -1380,12 +1379,12 @@ do_strtonum(int nargs)
        tmp = POP_SCALAR();
        if ((tmp->flags & (NUMBER|NUMCUR)) != 0) {
                (void) force_number(tmp);
-               d = LDBL(tmp);
+               d = LDBL_VAL(tmp);
        } else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
                d = nondec2awkldbl(tmp->stptr, tmp->stlen);
        else {
                (void) force_number(tmp);
-               d = LDBL(tmp);
+               d = LDBL_VAL(tmp);
        }
 
        DEREF(tmp);
@@ -1413,7 +1412,7 @@ format_awkldbl_printf(NODE *arg, struct format_spec 
*spec, struct print_fmt_buf
 #      define CEND             cpbuf_end(outb)
 #      define CPBUF            cpbuf(outb)
 
-       tmpval = LDBL(arg);
+       tmpval = LDBL_VAL(arg);
        spec->fill = space_string;
        spec->chbuf = lchbuf;
 
@@ -1431,17 +1430,17 @@ format_awkldbl_printf(NODE *arg, struct format_spec 
*spec, struct print_fmt_buf
                 * ``The result of converting a zero value with a
                 * precision of zero is no characters.''
                 */
-               if (spec->have_prec && spec->prec == 0 && tmpval == (AWKLDBL) 
0) {
+               if (spec->have_prec && spec->prec == 0 && tmpval == LDC(0.0)) {
                        pr_num_tail(cp, spec->prec, spec, outb);
                        return 0;
                }
 
-               if (tmpval < 0) {
+               if (tmpval < LDC(0.0)) {
                        tmpval = -tmpval;
                        sgn = true;
                } else {
-                       if (tmpval == - (AWKLDBL) 0.0)  /* avoid printing -0 */
-                               tmpval = (AWKLDBL) 0.0;
+                       if (tmpval == - LDC(0.0))       /* avoid printing -0; 
XXX: does not really detect -0.0, +0.0 == -0.0 -- JH */
+                               tmpval = LDC(0.0);
                        sgn = false;
                }
 
@@ -1539,12 +1538,12 @@ format_awkldbl_printf(NODE *arg, struct format_spec 
*spec, struct print_fmt_buf
                 * prints a single 0.
                 */
        
-               if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval 
== 0) {
+               if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval 
== LDC(0.0)) {
                        pr_num_tail(cp, spec->prec, spec, outb);
                        return 0;
                }
 
-               if (tmpval < 0) {
+               if (tmpval < LDC(0.0)) {
                        uval = (uintmax_t) (intmax_t) tmpval;
                        if ((AWKLDBL)(intmax_t) uval != double_to_int(tmpval))
                                goto out_of_range;
@@ -1561,8 +1560,8 @@ format_awkldbl_printf(NODE *arg, struct format_spec 
*spec, struct print_fmt_buf
 out_of_range:
                /* out of range - emergency use of %g format */
                if (do_lint)
-                       lintwarn(_("[s]printf: value %g is out of range for 
`%%%c' format"),
-                                       (double) tmpval, cs1);
+                       lintwarn(_("[s]printf: value %Lg is out of range for 
`%%%c' format"),
+                                       tmpval, cs1);
                cs1 = 'g';
                goto fmt1;
 
@@ -1619,6 +1618,9 @@ fmt1:
        }
 
        return -1;
+#undef CP
+#undef CEND
+#undef CPBUF
 }
 
 #else
diff --git a/misc/fp_math.awk b/misc/fp_math.awk
new file mode 100644
index 0000000..634d128
--- /dev/null
+++ b/misc/fp_math.awk
@@ -0,0 +1,790 @@
+# fp_math.awk --- finite precision math functions
+
+#
+#      TODO:   * finish fmod().
+#              * replace all usages of %, and int() or any other math builtin; 
and() is ok!
+#
+
+
+#
+# Machin's formula to compute pi 
(http://mathworld.wolfram.com/MachinsFormula.html):
+#      pi / 4 = 4 acot(5) - acot(239)
+#            = 4 atan(1/5) - atan(1/239)
+#
+# Euler atan formula (http://mathworld.wolfram.com/InverseTangent.html):
+#      atan(x) = (y/x) (1 + 2/3 y + (2·4)/(3·5) y^2 + (2·4·6)/(3·5·7) 
y^3 + ...)
+# where
+#      y = (x^2) / (1 + x^2) and -1 <= x <= 1
+#
+# Substituting x = 1/x, for x >= 1
+#      atan(1/x) = (x / (1 + x^2))    + (2/3) * (x / (1 + x^2)^2)
+#                                     + (2*4/(3*5)) * (x / (1 + x^2)^3)
+#                                     + (2*4*6/(3*5*7)) * (x / (1 + x^2)^4) + 
...
+#
+
+function euler_atan_one_over(x,        \
+               xpow2_plus_one, term, sum, i, sign, err)
+{
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+
+       xpow2_plus_one = x * x + 1
+       term = x / xpow2_plus_one
+       sum = term
+       i = 0
+
+       do {
+               term *= (i + 2) / (i + 3)
+               err = term /= xpow2_plus_one
+               i += 2
+               sum += term
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
+       return sign * sum
+}
+
+#
+# atan2(y, x) =        atan(y/x),              x > 0
+#             =        atan(y/x) + pi,         x < 0, y >= 0
+#             =        atan(y/x) - pi,         x < 0, y < 0
+#             =        pi/2,                   x = 0, y > 0
+#             =        -pi/2,                  x = 0, y < 0
+#             =        ?                       x = 0, y = 0
+#
+
+function fp_atan2(y, x,        \
+               sign, plus_inf, minus_inf)
+{
+       # Using Euler atan(1/x) and the identity:
+       #       atan(x) = - pi / 2 - atan(1/x),         x < 0
+       #               = pi / 2 - atan(1/x),           x > 0
+
+       # detect all the "abnormal" cases first
+       x = + x                 # or x += 0.0 or x = x + 0.0
+       y = + y
+       if (isnan(x) || isnan(y))
+               return __PLUS_NAN__
+
+       if (y == __PLUS_INF__) {
+               if (x == __MINUS_INF__)
+                       return 3 * __PI_OVER_4__
+               else if (x == __PLUS_INF__)
+                       return __PI_OVER_4__
+               else
+                       return 2 * __PI_OVER_4__
+       } else if (y == __MINUS_INF__) {
+               if (x == __MINUS_INF__)
+                       return - 3 * __PI_OVER_4__
+               else if (x == __PLUS_INF__)
+                       return - __PI_OVER_4__
+               else
+                       return - 2 * __PI_OVER_4__
+       }
+
+       if (x == __PLUS_INF__)
+               return atan2(y, x)      # use builtin, returns +0 or -0
+       if (x == __MINUS_INF__) {
+               if (y >= 0)
+                       return 4 * __PI_OVER_4__
+               # y < 0
+               return - 4 * __PI_OVER_4__
+       }
+
+       if (x > 0) {
+               if (y == 0)
+                       return atan2(y, x);     # use builtin; returns +0 or -0
+               sign = 1
+               if (y < 0) {
+                       sign = -1
+                       y = -y
+               }
+               if (y > x)
+                       return sign * (2 * __PI_OVER_4__ - 
euler_atan_one_over(y / x))
+               return sign * euler_atan_one_over(x / y)
+       }
+
+       if (x < 0) {
+               if (y == 0) {
+                       if (atan2(y, x) < 0)    # use builtin to detect sign
+                               return - 4 * __PI_OVER_4__
+                       return 4 * __PI_OVER_4__
+               }
+
+               if (y < 0) {
+                       y = -y
+                       x = -x
+                       if (y > x)
+                               return - 2 * __PI_OVER_4__ - 
euler_atan_one_over(y / x)
+                       return euler_atan_one_over(x / y) - 4 * __PI_OVER_4__
+               }
+               # y > 0
+               x = -x
+               if (y > x)
+                       return 2 * __PI_OVER_4__ + euler_atan_one_over(y / x)
+               return - euler_atan_one_over(x / y) + 4 * __PI_OVER_4__
+       }
+
+       if (atan2(y, x) < 0)    # atan2(-0, -0)
+               return - 4.0 * __PI_OVER_4__
+       if (atan2(y, x) > 0)    # atan2(+0, -0)
+               return 4.0 * __PI_OVER_4__
+       return 0;       # atan2(+0, +0) or atan2(-0, 0)
+}
+
+#
+#      Collect two terms in each iteration for the Taylor series:
+#              sin(x) = (x - x^3/3!) + (x^5/7! - x^9/9!) + ...
+#
+
+function taylor_sin(x, \
+               i, fact, xpow2, xpow_odd, sum, term, err)
+{
+       # XXX: this assumes x >= 0
+
+       if (x == 0)
+               return x
+       i = 3
+       fact = 6        # 3!
+       xpow2 = x * x
+       xpow_odd = xpow2 * x
+       sum = x - xpow_odd / fact
+
+       do {
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_odd *= xpow2
+               term = xpow_odd / fact
+
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_odd *= xpow2
+               term -= xpow_odd / fact
+
+               sum += term
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
+       return sum
+}
+
+#
+#      Collect two terms in each iteration for the Taylor series:
+#              cos(x) = (1 - x^2/2!) + (x^4/4! - x^6/6!)...
+#
+
+function taylor_cos(x, \
+               i, fact, xpow2, xpow_even, sum, term, err)
+{
+       if (x == 0)
+               return 1
+
+       i = 2
+       fact = 2        # 2!
+       xpow2 = x * x
+       xpow_even = xpow2
+       sum = 1 - xpow2 / fact
+
+       do {
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_even *= xpow2
+               term = xpow_even / fact
+
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_even *= xpow2
+               term -= xpow_even / fact
+
+               sum += term
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
+       return sum
+}
+
+#
+# For 0 <= x <= PI/4, using Taylor series approximation for sin(x):
+#      x - x^3/5! + x^5/7! - ...
+#
+# for PI/4 < x <= PI/2, use identity sin(x) = cos(PI/2 - x).
+#
+
+function fp_sin(x,     \
+               k, sign, y, sv)
+{
+       x = + x         # or x += 0.0 or x = x + 0.0 
+       if (isinf(x) || isnan(x))
+               return __PLUS_NAN__
+       if (x == 0)
+               return x
+       
+       if (x < 0) {
+               # sin(-x) = - sin(x)
+               sign = -1
+               x = -x
+       } else
+               sign = 1
+
+       # range reduction -- 0 <= y <= pi / 4
+
+       k = int(x / __PI_OVER_4__)
+       sign *= ( int(k / 4) % 2 ? -1 : 1 )
+
+       # XXX --- make sure y >= 0
+       switch (k % 4) {
+       case 0: y = x - k * __PI_OVER_4__; sv = taylor_sin(y); break;
+       case 1: y = (k + 1) * __PI_OVER_4__ - x; sv = taylor_cos(y); break;
+       case 2: y = x - k * __PI_OVER_4__; sv = taylor_cos(y); break;
+       case 3: y = (k + 1) * __PI_OVER_4__ - x; sv = taylor_sin(y); break;
+       }
+       sv *= sign
+       return sv; 
+}
+
+#
+# Using Taylor series approximation for sin(x) for 0 <= x <= PI/4:
+#      1 - x^2/2! + x^4/4! - ...
+# for PI/4 < x < PI/2, use identity cos(x) = sin(PI/2 - x).
+#
+
+function fp_cos(x,     \
+               k, sign, y, cv)
+{
+       x = + x         # or x += 0.0 or x = x + 0.0
+       if (isinf(x) || isnan(x))
+               return __PLUS_NAN__
+
+       if (x < 0)      # cos(x) = cos(-x)
+               x = -x
+       if (x == 0)
+               return 1.0
+
+       # range reduction -- 0 <= y <= pi / 4
+
+       k = int(x / __PI_OVER_4__)
+       sign = ( int(k / 4) % 2 ? -1 : 1 )
+
+       # XXX -- make sure y >= 0
+       switch (k % 4) {
+       case 0: y = x - k * __PI_OVER_4__; cv = taylor_cos(y); break;
+       case 1: y = (k + 1) * __PI_OVER_4__ - x; cv = taylor_sin(y); break;
+       case 2: y = x - k * __PI_OVER_4__; cv = -taylor_sin(y); break;
+       case 3: y = (k + 1) * __PI_OVER_4__ - x; cv = -taylor_cos(y); break;
+       }
+       cv *= sign
+       return cv
+}
+
+function fp_atan2(y, x)
+{
+       return euler_atan2(y, x)
+}
+
+function isinf(x)
+{
+       x = + x 
+       return x == __PLUS_INF__ || x == __MINUS_INF__
+}
+
+function isnan(x)
+{
+       x = + x 
+       return x == __PLUS_NAN__ || x == __MINUS_NAN__
+}
+
+#################################################################
+# Detecting a negative zero in gawk (signbit(x) in C where x is a signed 0):
+# $ gawk 'BEGIN { x = -0.0; print atan2(0.0, x) == atan2(-0.0, x)}'
+# 0
+# $ gawk 'BEGIN { x = 0.0; print atan2(0.0, x) == atan2(-0.0, x)}'
+# 1
+#
+#################################################################
+
+function ispluszero(x)
+{
+       x = +x
+       if (x != 0)
+               return 0 
+       return atan2(0.0, x) == atan2(-0.0, x)
+}
+
+function isminuszero(x)
+{
+       x = +x
+       if (x != 0)
+               return 0
+       return ! (atan2(0.0, x) == atan2(-0.0, x))
+}
+
+#
+# Newton-Raphson to calculate higher precision result from already known fixed
+# precision value. This usually converges in 2 to 3 iterations.
+#
+
+function fp_sqrt(x,    \
+               yn, err, last)
+{
+       if (isnan(x) || x == __PLUS_INF__)
+               return x
+       if (x == __MINUS_INF__ || x < 0)
+               return __MINUS_NAN__    # set errno = EDOM for x < -0?
+       if (x == 0)
+               return x        # return +0 or -0
+
+       yn = sqrt(x)    # double-precision sqrt
+       do {
+               last = yn
+               yn = (yn + x / yn) \
+                               / 2
+               err = (yn - last) / yn
+       } while (err > __REL_ERROR__)
+       return yn
+}
+
+# __log2 -- compute log(2)
+
+function __log2( \
+               i, three_pow, sum, err, term)
+{
+       #
+       #       ln(2) = 2 * arctanh(2)
+       #             = 2 * ((1/3) + (1/3)^3 / 3 + (1/3)^5 / 5 + ..) 
+       #
+
+       # y = (x - 1) / (x + 1) => y = 1 / 3
+       i = 1
+       three_pow = 3
+       sum = 1 / 3
+
+       do {
+               three_pow *= 9
+               i += 2
+               term = 1 / (three_pow * i)
+               sum += term
+               err = term / sum
+       } while (err > __REL_ERROR__)
+       return 2 * sum
+}
+
+
+function fp_log(x,     \
+               k, i, y, ypow2, ypow_odd, sum, err, term, sqrt_2, sign)
+{
+       #
+       #       ln(x) = 2 * arctanh(y)
+       #             = 2 * (y + y^3 / 3 + y^5 /5 + ..) where y = (x - 1) / (x 
+ 1) 
+       #
+       x = +x
+       if (isnan(x) || x == __PLUS_INF__)
+               return x
+       if (x == __MINUS_INF__ || x < 0)        # errno EDOM ?
+               return __PLUS_NAN__
+       if (x == 0)     # errno ERANGE ?
+               return __MINUS_INF__
+       
+       if (x == 1)     # special case
+               return 0
+       if (x == 2)     # special case
+               return __LOG2__
+       k = 0
+       if (x > 2) {
+               # FIXME -- use power2 table
+               while (x > 2) {
+                       x /= 2
+                       k++
+               }
+       } else if (x < 1) {
+               # FIXME -- use power2 table
+               while (x < 1) {
+                       x *= 2
+                       k--
+               }
+       }
+
+       # arctanh(x) series has faster convergence when x is close to 1
+       # range reduction -- 1/sqrt(2) <= x <= sqrt(2)
+       if (x > __SQRT_2__ || x < __1_OVER_SQRT_2__) {
+               x *= __1_OVER_SQRT_2__
+               k += 0.5
+       }
+
+       y = (x - 1) / (x + 1)
+       sign = 1
+       if (y < 0) {
+               sign = -1
+               y = -y
+       }
+
+       i = 1
+       ypow2 = y * y
+       ypow_odd = y
+       sum = y
+
+       do {
+               ypow_odd *= ypow2
+               i += 2
+               term = ypow_odd / i
+               sum += term
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
+       return sign * (sum = 2 * sum + k * __LOG2__)
+}
+
+
+function taylor_exp(x, \
+               xpow2, xpow_even, i, fact, cosh, sinh, err, term)
+{
+       # x < 1
+       # cosh(x) = (exp(x) + exp(-x)) / 2      -- faster convergence than 
exp(x)
+       # sinh(x) = sqrt(cosh(x) * cosh(x) - 1)
+       # exp(x) = cosh(x) + sinh(x)
+
+       xpow2 = x * x
+       xpow_even = 1
+       i = 0
+       fact = 1
+       cosh = 1
+
+       do {
+               fact *= (i + 1) * (i + 2)
+               xpow_even *= xpow2
+               term = xpow_even / fact
+               i += 2
+               cosh += term
+               err  = term / cosh
+       } while (err > __REL_ERROR__)
+
+       sinh = fp_sqrt(cosh * cosh - 1) # sqrt is cheap
+       return (sinh + cosh)
+}
+
+function fp_exp(x,     \
+               exp_val, k, sign)
+{
+       x = +x
+       if (isnan(x) || x == __PLUS_INF__)
+               return x
+       if (x == __MINUS_INF__)
+               return 0
+
+       if (x == 0)     # special case
+               return 1
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+       k = fp_floor(x / __LOG2__)
+
+       # range reduction -- 0 < x < log(2) (0.693...)
+       if (k == 0)
+               exp_val = taylor_exp(x)
+       else {
+               exp_val = taylor_exp(x - k * __LOG2__)
+               while (k >= 64) {
+                       exp_val *= __POW2__[64]
+                       k -= 64
+               }
+               exp_val *= __POW2__[k]
+       }
+       return sign < 0 ? (1 / exp_val) : exp_val
+}
+
+function isinteger(x)
+{
+       # assume != NaN or inf
+       return fp_floor(x) == fp_ceil(x)
+}
+
+function isodd(x)
+{
+       # assume != NaN or inf
+       # XXX -- not using % operator, either fmodl() is missing, or will get 
into
+       #       situation like: fp_fmod() -> isodd() -> fp_fmod() ..
+
+       return isinteger(x) && and(x, 1)
+}
+
+function iseven(x)
+{
+       # assume != NaN or inf
+       return isinteger(x) && ! and(x, 1)
+}
+
+function fp_abs(x)
+{
+       # assume != NaN or inf
+       return x < 0 ? -x : x
+}
+
+function fp_pow(x, y,  \
+               i, result, sign)
+{
+       x = +x
+       y = +y
+       if ((! isnan(x) && x == 1) || (! isnan(y) && y == 0))
+               return 1
+       if (isnan(x) || isnan(y))
+               return __PLUS_NAN__
+
+       # x or y not NaN
+       if (isinf(x)) {
+               if (x == __PLUS_INF__) {
+                       if (y < 0)
+                               return 0
+                       if (y > 0)
+                               return __PLUS_INF__
+               }
+               # x == -inf
+               if (y < 0) {
+                       if (! isinf(y) && isodd(y))
+                               return -0.0
+                       return 0
+               }
+               if (y > 0) {
+                       if (! isinf(y) && isodd(y))
+                               return __MINUS_INF__
+                       return __PLUS_INF__
+               }
+               # y == 0 handled above
+       } else {
+               # x isn't infinity
+               if (x < 0 && ! isinf(y) && ! isinteger(y))
+                       return __PLUS_NAN__
+
+               if (isinf(y)) {
+                       if (x == -1)
+                               return 1
+                       # x == +1 handled above
+                       if (fp_abs(x) < 1) {
+                               if (y == __MINUS_INF__)
+                                       return __PLUS_INF__
+                               return 0
+                       }
+                       # fp_abs(x) > 1)
+                       if (y == __MINUS_INF__)
+                               return 0
+                       return __PLUS_INF__
+               }
+               # y isn't infinity
+               if (x == 0 && y > 0) {
+                       if (isodd(y))
+                               return x        # +0 or -0
+                       else
+                               return 0
+               }
+               if (x == 0 && y < 0) {
+                       if (isodd(y)) {
+                               # HUGE_VALL with same sign as x
+                               if (ispluszero(x))
+                                       return __PLUS_INF__
+                               return __MINUS_INF__
+                       }
+                       # + HUGE_VALL
+                       return __PLUS_INF__ 
+               }
+               # x == 0 && y == 0 handled above 
+       }
+
+       if (x < 0) {
+               # y is integer, and != 0
+               # gawk has special code to handle this; can return junk!
+               # XXX: move the special code (at least for x < 0) in gawk_powl 
instead?
+               result = x
+               sign = 1
+               if (y < 0) {
+                       sign = -1
+                       y = -y
+               }
+               for (i = 1; i < y; i++)
+                       result *= x
+               return sign > 0 ? result : 1 / result
+       }
+
+       # x^y =  exp(y * log(x)), x > 0
+       return fp_exp(y * fp_log(x))
+}
+
+
+function fp_floor(x,   d)
+{
+       x = +x
+       if (isnan(x) || isinf(x) || x == 0)
+               return x
+       d = sprintf("%d", x) + 0
+       if (x == d || x > 0)
+               return d
+       return d - 1
+}
+
+function fp_ceil(x,    d)
+{
+       x = +x
+       if (isnan(x) || isinf(x) || x == 0)
+               return x
+       d = sprintf("%d", x) + 0
+       if (x == d || x < 0)
+               return d
+       return d + 1
+}
+
+#
+#      Calculating fmod with correctly rounded output isn't easy:
+#
+# BEGIN {
+#      POW2[0] = 1
+#      for (i = 1; i <= 64; i++) {
+#              POW2[i] = POW2[i - 1] * 2
+#      }
+#      x = 343.4341
+#      y = 1.324355
+#      printf("builtin: %0.18f\n", x % y)
+#
+#      q = int(x / y)  # floor
+#      printf("simple : %0.18f\n", x - q * y)
+#
+#      r = calc_fmod(x, y)
+#      printf("pow2   : %0.18f\n", r)
+# }
+#
+# function calc_fmod(x, y,     q, j)
+# {
+#      # x > 0, y > 0
+#      q = int(x / y)  # floor, q < 2^64
+#      while (q > 2) {
+#              # XXX: use binary search?
+#              for (j = 1; j <= 64; j++) {
+#                      if (q <= POW2[j]) {
+#                              x -= POW2[j - 1] * y
+#                              q -= POW2[j - 1]
+#                              break
+#                      }
+#              }
+#      }
+#      x -= q * y
+#      return x
+# }
+#
+# We can only get correctly rounded 16 digits (with 80 bit long double),
+# using math library or not:
+#
+# $ ./gawk -B -f fmod.awk 
+# builtin: 0.426155000000000019
+# simple : 0.426155000000000006
+# pow2   : 0.426155000000000019
+#
+# For comparison, MPFR quad precision output:
+#
+# $ ./gawk -M -vPREC=quad 'BEGIN { printf("%0.18f\n",  343.4341 % 1.324355) }'
+# 0.426155000000000000
+#
+
+
+function fp_fmod(x, y, \
+               z, sign)
+{
+       x = +x
+       y = +y
+       if (isnan(x) || isnan(y) \
+                       || isinf(x) || y == 0)          # errno = EDOM ?
+               return __PLUS_NAN__
+       if (x == 0)
+               return x        # +0 or -0
+       if (isinf(y))
+               return x
+
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+       if (y < 0)
+               y = -y
+
+       if (x < y) # nothing to do
+               return sign * x
+
+       q = fp_floor(x / y)
+
+       # FIXME -- see above, and also consider integer overflow (q >= 
2^LDBL_MANT_DIG)
+       return sign * (x - q * y)
+}
+
+
+# fixprec -- fixes "0.18e" output
+
+function fixprec(str, numdigs, \
+               sign, j, exponent, sigdigs, lastdig, nextdig)
+{
+       if (str ~ /^[-+]?(nan|inf)/)
+               return str
+       if (! numdigs)
+               numdigs = __DIGITS__
+       if (str ~ /^[-+]?0[\.]/)
+               return str
+       sign = ""
+       if (str ~ /^-/) {
+               sign = "-"
+               str = substr(str, 2)
+       } else if (str ~ /^+/) {
+               sign = "+"
+               str = substr(str, 2)
+       }
+       sub(/\./, "", str)
+
+       if ((j = index(str, "e-")) > 0) {
+               exponent = substr(str, j + 2)
+               exponent--
+               exponent = sprintf("e-%02d", exponent)
+       } else if ((j = index(str, "e+")) > 0) {
+               exponent = substr(str, j + 2)
+               exponent++
+               exponent = sprintf("e+%02d", exponent)
+       }
+       sigdigs = substr(str, 1, numdigs)
+       lastdig = substr(str, numdigs, 1) + 0
+       nextdig = substr(str, numdigs + 1, 1) + 0
+
+       # XXX: Don't use % to test even or odd, may not have fmodl() !
+       if (nextdig > 5 || (nextdig == 5 && and(lastdig, 1) != 0))
+               sub(/[0-9]$/, lastdig + 1, sigdigs)
+       return sign "0." sigdigs exponent
+}
+
+
+BEGIN {
+       # define some constants
+
+       # reltive error < 5 X 10^-k for rounding to k significant digits
+       __DIGITS__ = 34
+       __REL_ERROR__ = 5.0e-34
+
+       __PLUS_INF__ = "+inf" + 0
+       __MINUS_INF__ = "-inf" + 0
+       __PLUS_NAN__ = "+nan" + 0
+       __MINUS_NAN__ = "-nan" + 0
+
+       __SQRT_2__ = fp_sqrt(2)
+       __1_OVER_SQRT_2__ = 1 / __SQRT_2__
+       __LOG2__ = __log2()     # cannot use fp_log()
+       __PI_OVER_4__ = 4 * euler_atan_one_over(5) - euler_atan_one_over(239)
+
+
+##if LDBL_MANT_DIG == 64
+#       80 bit long double .. 18 or 34 digits?
+#      use 2^64 power 2 table
+##elif LDBL_MANT_DIG == 113
+#       128 bit long double .. 34 digits
+#      use 2^112 power 2 table
+##endif
+
+       __POW2__[0] = 1
+       for (i = 1; i <= 64; i++)
+               __POW2__[i] = __POW2__[i - 1] * 2
+}

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=c5b44e77f250e364a5c3a677722d513f88977eef

commit c5b44e77f250e364a5c3a677722d513f88977eef
Merge: 42dd951 2fec754
Author: John Haque <address@hidden>
Date:   Sat Jan 12 08:31:23 2013 -0600

    Merge branch 'num-handler' into long-double.

diff --cc Makefile.in
index f4f28bc,3144c0e..202d362
--- a/Makefile.in
+++ b/Makefile.in
@@@ -107,13 -106,13 +107,14 @@@ PROGRAMS = $(bin_PROGRAMS
  am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
        cint_array.$(OBJEXT) command.$(OBJEXT) debug.$(OBJEXT) \
        dfa.$(OBJEXT) double.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) \
-       field.$(OBJEXT) floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) \
-       gawkmisc.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
-       int_array.$(OBJEXT) io.$(OBJEXT) long_double.$(OBJEXT) \
-       main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
-       profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
-       regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
-       symbol.$(OBJEXT) version.$(OBJEXT)
+       field.$(OBJEXT) floatcomp.$(OBJEXT) format.$(OBJEXT) \
+       gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \
+       getopt1.$(OBJEXT) int_array.$(OBJEXT) io.$(OBJEXT) \
 -      main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
 -      profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
 -      regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
 -      symbol.$(OBJEXT) version.$(OBJEXT)
++      long_double.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) \
++      msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) \
++      random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
++      replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
++      version.$(OBJEXT)
  am_gawk_OBJECTS = $(am__objects_1)
  gawk_OBJECTS = $(am_gawk_OBJECTS)
  gawk_LDADD = $(LDADD)

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=2fec7545cd5e31c073d72caf69ac3507302c919b

commit 2fec7545cd5e31c073d72caf69ac3507302c919b
Author: John Haque <address@hidden>
Date:   Sat Jan 12 08:20:37 2013 -0600

    Add format.c file.

diff --git a/ChangeLog b/ChangeLog
index 8125721..64e2601 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+2013-01-12         John Haque      <address@hidden>
+
+       * format.c: New file.
+       * Makefile.am: Add format.c to the list of files.
+       * builtin.c (format_tree, format_nondecimal, fmt_parse,
+       get_fmt_buf, mbc_byte_count, mbc_char_count): Move to format.c.
+
 2013-01-11         John Haque      <address@hidden>
 
        Finish format_tree() refactoring.
diff --git a/Makefile.am b/Makefile.am
index 5346454..3ab46f1 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,6 +99,7 @@ base_sources = \
        field.c \
        floatcomp.c \
        floatmagic.h \
+       format.c \
        format.h \
        gawkapi.c \
        gawkapi.h \
diff --git a/Makefile.in b/Makefile.in
index 20c3a19..3144c0e 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -106,13 +106,13 @@ PROGRAMS = $(bin_PROGRAMS)
 am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
        cint_array.$(OBJEXT) command.$(OBJEXT) debug.$(OBJEXT) \
        dfa.$(OBJEXT) double.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) \
-       field.$(OBJEXT) floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) \
-       gawkmisc.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
-       int_array.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) \
-       msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) \
-       random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
-       replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
-       version.$(OBJEXT)
+       field.$(OBJEXT) floatcomp.$(OBJEXT) format.$(OBJEXT) \
+       gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \
+       getopt1.$(OBJEXT) int_array.$(OBJEXT) io.$(OBJEXT) \
+       main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
+       profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
+       regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
+       symbol.$(OBJEXT) version.$(OBJEXT)
 am_gawk_OBJECTS = $(am__objects_1)
 gawk_OBJECTS = $(am_gawk_OBJECTS)
 gawk_LDADD = $(LDADD)
@@ -428,6 +428,7 @@ base_sources = \
        field.c \
        floatcomp.c \
        floatmagic.h \
+       format.c \
        format.h \
        gawkapi.c \
        gawkapi.h \
@@ -592,6 +593,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/awk.h b/awk.h
index 85b0ff7..7a5695f 100644
--- a/awk.h
+++ b/awk.h
@@ -1413,7 +1413,6 @@ extern NODE *do_bindtextdomain(int nargs);
 extern int strncasecmpmbs(const unsigned char *,
                          const unsigned char *, size_t);
 #endif
-extern NODE *format_tree(const char *, size_t, NODE **, long);
 
 /* eval.c */
 extern void PUSH_CODE(INSTRUCTION *cp);
diff --git a/builtin.c b/builtin.c
index 8559c39..22f562d 100644
--- a/builtin.c
+++ b/builtin.c
@@ -24,6 +24,8 @@
  */
 
 #include "awk.h"
+#include "format.h"
+
 #if defined(HAVE_FCNTL_H)
 #include <fcntl.h>
 #endif
@@ -56,9 +58,6 @@
 #endif
 
 
-extern size_t mbc_byte_count(const char *ptr, size_t numchars);
-extern size_t mbc_char_count(const char *ptr, size_t numbytes);
-
 extern NODE **args_array;
 extern int max_args;
 extern NODE **fields_arr;
@@ -1995,756 +1994,3 @@ do_bindtextdomain(int nargs)
 
        return make_string(the_result, strlen(the_result));
 }
-
-
-/* mbc_byte_count --- return number of bytes for corresponding numchars 
multibyte characters */
-
-size_t
-mbc_byte_count(const char *ptr, size_t numchars)
-{
-#if MBS_SUPPORT
-       mbstate_t cur_state;
-       size_t sum = 0;
-       int mb_len;
-
-       memset(& cur_state, 0, sizeof(cur_state));
-
-       assert(gawk_mb_cur_max > 1);
-       mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
-       if (mb_len <= 0)
-               return numchars;        /* no valid m.b. char */
-
-       for (; numchars > 0; numchars--) {
-               mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
-               if (mb_len <= 0)
-                       break;
-               sum += mb_len;
-               ptr += mb_len;
-       }
-
-       return sum;
-#else
-       return numchars;
-#endif
-}
-
-/* mbc_char_count --- return number of m.b. chars in string, up to numbytes 
bytes */
-
-size_t
-mbc_char_count(const char *ptr, size_t numbytes)
-{
-#if MBS_SUPPORT
-       mbstate_t cur_state;
-       size_t sum = 0;
-       int mb_len;
-
-       if (gawk_mb_cur_max == 1)
-               return numbytes;
-
-       memset(& cur_state, 0, sizeof(cur_state));
-
-       mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
-       if (mb_len <= 0)
-               return numbytes;        /* no valid m.b. char */
-
-       for (; numbytes > 0; numbytes--) {
-               mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
-               if (mb_len <= 0)
-                       break;
-               sum++;
-               ptr += mb_len;
-       }
-
-       return sum;
-#else
-       return numbytes;
-#endif
-}
-
-
-#include "format.h"
-
-char lchbuf[] = "0123456789abcdef";
-char Uchbuf[] = "0123456789ABCDEF";
-char space_string[] = " ";
-char zero_string[] = "0";
-
-
-#define OUTBUF_INIT_SIZE       510
-
-/* chksize__internal --- make room for something LEN big in the output buffer 
*/
-
-static void
-chksize__internal(struct print_fmt_buf *outb, size_t len)
-{
-       size_t delta, newsize;
-
-       assert(outb->buf != NULL);
-       delta = outb->dataend - outb->buf;
-       newsize = delta + len + OUTBUF_INIT_SIZE;
-       erealloc(outb->buf, char *, newsize + 2, "chksize__internal");
-       outb->dataend = outb->buf + delta;
-       outb->bufsize = newsize;
-       outb->room_left = len + OUTBUF_INIT_SIZE;
-}
-
-/* cpbuf_chksize__internal --- enlarge the temporary buffer */
-
-static void
-cpbuf_chksize__internal(struct print_fmt_buf *outb)
-{
-       char *cp, *prev = outb->cpbuf.buf;
-       size_t oldsize = outb->cpbuf.bufsize;
-       size_t newsize;
-
-       newsize = outb->cpbuf.bufsize = 2 * oldsize;
-       emalloc(outb->cpbuf.buf, char *, newsize + 2, 
"cpbuf_chksize__internal");
-       memcpy((cp = outb->cpbuf.buf + oldsize), prev,  oldsize);
-       efree(prev);
-       outb->cpbuf.bufend = outb->cpbuf.buf + newsize;
-       outb->cpbuf.databegin = cp;
-}
-
-static struct print_fmt_buf static_outb;
-
-/* get_fmt_buf --- buffer(s) to manage (s)printf formatting */
- 
-struct print_fmt_buf *
-get_fmt_buf()
-{
-       struct print_fmt_buf *outb;
-
-       if (static_outb.buf == NULL)
-               outb = & static_outb;
-       else {
-               emalloc(outb, struct print_fmt_buf *, sizeof (struct 
print_fmt_buf), "get_fmt_buf");
-               outb->is_malloced = true;
-       }
-
-       emalloc(outb->buf, char *, OUTBUF_INIT_SIZE + 2, "get_fmt_buf");
-       outb->bufsize = OUTBUF_INIT_SIZE;
-       outb->room_left = outb->bufsize;
-       outb->dataend = outb->buf;
-       outb->chksize = chksize__internal;
-
-       emalloc(outb->cpbuf.buf, char *, 64, "get_fmt_buf");
-       outb->cpbuf.bufsize = 62;
-       outb->cpbuf.databegin = outb->cpbuf.bufend = outb->cpbuf.buf + 
outb->cpbuf.bufsize;
-       outb->cpbuf_chksize = cpbuf_chksize__internal;
-       return outb;
-}
-
-/* fmt_parse --- parse a single format code */  
-
-struct format_spec *
-fmt_parse(NODE *n, const char *fmt_string, size_t fmt_len)
-{
-       struct format_spec *spec = NULL;
-
-       spec = (struct format_spec *) format_tree(fmt_string, fmt_len, NULL, 
LONG_MIN);
-       if (spec != NULL && n == CONVFMT_node
-               && (spec->fmtchar == 's' || spec->fmtchar == 'c')
-       ) {
-               efree(spec);
-               spec = NULL;
-       }
-       return spec;
-}
-
-
-/* format_nondecimal --- output a nondecimal number according to a format */
-
-void
-format_nondecimal(uintmax_t val, struct format_spec *spec, struct 
print_fmt_buf *outb)
-{
-       uintmax_t uval = val;
-       int ii, jj;
-       const char *chbuf = spec->chbuf;
-
-#      define CP               cpbuf_start(outb)
-#      define CEND             cpbuf_end(outb)
-
-       /*
-        * When to fill with zeroes is of course not simple.
-        * First: No zero fill if left-justifying.
-        * Next: There seem to be two cases:
-        *      A '0' without a precision, e.g. %06d
-        *      A precision with no field width, e.g. %.10d
-        * Any other case, we don't want to fill with zeroes.
-        */
-       if (! spec->lj
-                   && ((spec->zero_flag && ! spec->have_prec)
-                       || (spec->fw == 0 && spec->have_prec))
-       )
-               spec->fill = zero_string;
-
-       ii = jj = 0;
-       do {
-               tmpbuf_prepend(outb, chbuf[uval % spec->base]);
-               uval /= spec->base;
-#if defined(HAVE_LOCALE_H)
-               if (spec->base == 10 && spec->quote_flag && loc.grouping[ii] && 
++jj == loc.grouping[ii]) {
-                       if (uval)       /* only add if more digits coming */
-                               tmpbuf_prepend(outb, loc.thousands_sep[0]);     
/* XXX --- assumption it's one char */
-                       if (loc.grouping[ii+1] == 0)                            
              
-                               jj = 0;     /* keep using current val in 
loc.grouping[ii] */
-                       else if (loc.grouping[ii+1] == CHAR_MAX)                
        
-                               spec->quote_flag= false;
-                       else {                 
-                               ii++;
-                               jj = 0;
-                       }
-               }
-#endif
-       } while (uval > 0);
-
-       /* add more output digits to match the precision */
-       if (spec->have_prec) {
-               while (CEND - CP < spec->prec)
-                       tmpbuf_prepend(outb, '0');
-       }
-
-       if (spec->alt && val != 0) {
-               if (spec->base == 16) {
-                       tmpbuf_prepend(outb, spec->fmtchar);
-                       tmpbuf_prepend(outb, '0');
-                       if (spec->fill != space_string) {
-                               bchunk(outb, CP, 2);
-                               CP += 2;
-                               spec->fw -= 2;
-                       }
-               } else if (spec->base == 8)
-                       tmpbuf_prepend(outb, '0');
-       }
-
-       spec->base = 0;
-       if (spec->prec > spec->fw)
-               spec->fw = spec->prec;
-       spec->prec = CEND - CP;
-       pr_num_tail(CP, spec->prec, spec, outb);
-
-#undef CP
-#undef CEND
-}
-
-
-/*
- * format_tree() formats arguments of sprintf,
- * and accordingly to a fmt_string providing a format like in
- * printf family from C library.  Returns a string node which value
- * is a formatted string.  Called by  sprintf function.
- *
- * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
- * for taming this beast and making it compatible with ANSI C.
- */
-
-
-NODE *
-format_tree(
-       const char *fmt_string,
-       size_t n0,
-       NODE **the_args,
-       long num_args)
-{
-       size_t cur_arg = 0;
-       NODE *retval = NULL;
-       bool toofew = false;
-       const char *s0, *s1;
-       int cs1;
-       NODE *arg;
-       long argnum;
-
-       bool used_dollar;
-       bool big_flag, bigbig_flag, small_flag, need_format;
-       long *cur = NULL;
-       uintmax_t uval;
-       char *cp;
-       size_t copy_count, char_count;
-
-       struct print_fmt_buf *outb;
-       struct format_spec spec;
-
-#      define CP               cpbuf_start(outb)
-#      define CEND             cpbuf_end(outb)
-#      define CPBUF            cpbuf(outb)
-
-/* parse a single format specifier */
-#define do_parse_fmt   (num_args == LONG_MIN)
-
-       /*
-        * Check first for use of `count$'.
-        * If plain argument retrieval was used earlier, choke.
-        *      Otherwise, return the requested argument.
-        * If not `count$' now, but it was used earlier, choke.
-        * If this format is more than total number of args, choke.
-        * Otherwise, return the current argument.
-        */
-#define parse_next_arg() { \
-       if (do_parse_fmt) \
-               goto out; \
-       else if (argnum > 0) { \
-               if (cur_arg > 1) { \
-                       msg(_("fatal: must use `count$' on all formats or 
none")); \
-                       goto out; \
-               } \
-               arg = the_args[argnum]; \
-       } else if (used_dollar) { \
-               msg(_("fatal: must use `count$' on all formats or none")); \
-               arg = 0; /* shutup the compiler */ \
-               goto out; \
-       } else if (cur_arg >= num_args) { \
-               arg = 0; /* shutup the compiler */ \
-               toofew = true; \
-               break; \
-       } else { \
-               arg = the_args[cur_arg]; \
-               cur_arg++; \
-       } \
-}
-
-       outb = get_fmt_buf();
-       cur_arg = 1;
-
-       need_format = false;
-       used_dollar = false;
-
-       s0 = s1 = fmt_string;
-
-       while (n0-- > 0) {
-               if (*s1 != '%') {
-                       s1++;
-                       continue;
-               }
-               need_format = true;
-               bchunk(outb, s0, s1 - s0);
-               s0 = s1;
-               argnum = 0;
-
-               memset(& spec, '\0', sizeof (spec));
-               cur = & spec.fw;
-               spec.fill = space_string;       /* always space for string */
-
-               big_flag = bigbig_flag = small_flag = false;
-               CP = CEND;
-               s1++;
-
-retry:
-               if (n0-- == 0)  /* ran out early! */
-                       break;
-
-               switch (cs1 = *s1++) {
-               case (-1):      /* dummy case to allow for checking */
-check_pos:
-                       if (cur != & spec.fw)
-                               break;          /* reject as a valid format */
-                       goto retry;
-               case '%':
-                       need_format = false;
-                       /*
-                        * 29 Oct. 2002:
-                        * The C99 standard pages 274 and 279 seem to imply that
-                        * since there's no arg converted, the field width 
doesn't
-                        * apply.  The code already was that way, but this
-                        * comment documents it, at least in the code.
-                        */
-                       if (do_lint) {
-                               const char *msg = NULL;
-
-                               if (spec.fw && ! spec.have_prec)
-                                       msg = _("field width is ignored for 
`%%' specifier");
-                               else if (spec.fw == 0 && spec.have_prec)
-                                       msg = _("precision is ignored for `%%' 
specifier");
-                               else if (spec.fw && spec.have_prec)
-                                       msg = _("field width and precision are 
ignored for `%%' specifier");
-
-                               if (msg != NULL)
-                                       lintwarn("%s", msg);
-                       }
-                       bchunk_one(outb, "%");
-                       s0 = s1;
-                       break;
-
-               case '0':
-                       /*
-                        * Only turn on zero_flag if we haven't seen
-                        * the field width or precision yet.  Otherwise,
-                        * screws up floating point formatting.
-                        */
-                       if (cur == & spec.fw)
-                               spec.zero_flag = true;
-                       if (spec.lj)
-                               goto retry;
-                       /* FALL through */
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                       if (cur == NULL)
-                               break;
-                       if (spec.prec >= 0)
-                               *cur = cs1 - '0';
-                       /*
-                        * with a negative precision *cur is already set
-                        * to -1, so it will remain negative, but we have
-                        * to "eat" precision digits in any case
-                        */
-                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
-                               --n0;
-                               *cur = *cur * 10 + *s1++ - '0';
-                       }
-                       if (spec.prec < 0)      /* negative precision is 
discarded */
-                               spec.have_prec = false;
-                       if (cur == & spec.prec)
-                               cur = NULL;
-                       if (n0 == 0)    /* badly formatted control string */
-                               continue;
-                       goto retry;
-               case '$':
-                       if (do_traditional) {
-                               msg(_("fatal: `$' is not permitted in awk 
formats"));
-                               goto out;
-                       }
-                       if (do_parse_fmt)
-                               goto out;
-
-                       if (cur == & spec.fw) {
-                               argnum = spec.fw;
-                               spec.fw = 0;
-                               used_dollar = true;
-                               if (argnum <= 0) {
-                                       msg(_("fatal: arg count with `$' must 
be > 0"));
-                                       goto out;
-                               }
-                               if (argnum >= num_args) {
-                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
-                                       goto out;
-                               }
-                       } else {
-                               msg(_("fatal: `$' not permitted after period in 
format"));
-                               goto out;
-                       }
-
-                       goto retry;
-               case '*':
-                       if (cur == NULL)
-                               break;
-                       if (! do_traditional && isdigit((unsigned char) *s1)) {
-                               int val = 0;
-
-                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
-                                       val *= 10;
-                                       val += *s1 - '0';
-                               }
-                               if (*s1 != '$') {
-                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
-                                       goto out;
-                               } else {
-                                       s1++;
-                                       n0--;
-                               }
-                               if (val >= num_args) {
-                                       toofew = true;
-                                       break;
-                               }
-                               arg = the_args[val];
-                       } else {
-                               parse_next_arg();
-                       }
-
-                       (void) force_number(arg);
-                       *cur = get_number_si(arg);
-                       if (*cur < 0 && cur == & spec.fw) {
-                               *cur = -*cur;
-                               spec.lj++;
-                       }
-                       if (cur == & spec.prec) {
-                               if (*cur >= 0)
-                                       spec.have_prec = true;
-                               else
-                                       spec.have_prec = false;
-                               cur = NULL;
-                       }
-                       goto retry;
-               case ' ':               /* print ' ' or '-' */
-                                       /* 'space' flag is ignored */
-                                       /* if '+' already present  */
-                       if (spec.signchar != false) 
-                               goto check_pos;
-                       /* FALL THROUGH */
-               case '+':               /* print '+' or '-' */
-                       spec.signchar = cs1;
-                       goto check_pos;
-               case '-':
-                       if (spec.prec < 0)
-                               break;
-                       if (cur == & spec.prec) {
-                               spec.prec = -1;
-                               goto retry;
-                       }
-                       spec.lj++;              /* filling is ignored */
-                       goto check_pos;
-               case '.':
-                       if (cur != & spec.fw)
-                               break;
-                       cur = & spec.prec;
-                       spec.have_prec = true;
-                       goto retry;
-               case '#':
-                       spec.alt = true;
-                       goto check_pos;
-               case '\'':
-#if defined(HAVE_LOCALE_H)       
-                       /* allow quote_flag if there is a thousands separator. 
*/
-                       if (loc.thousands_sep[0] != '\0')
-                               spec.quote_flag= true;
-                       goto check_pos;
-#else
-                       goto retry;  
-#endif
-               case 'l':
-                       if (big_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       big_flag = true;
-                       goto retry;
-               case 'L':
-                       if (bigbig_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       bigbig_flag = true;
-                       goto retry;
-               case 'h':
-                       if (small_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       small_flag = true;
-                       goto retry;
-               case 'c':
-                       need_format = false;
-                       spec.fmtchar = cs1;
-                       parse_next_arg();
-                       /* user input that looks numeric is numeric */
-                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
-                               (void) force_number(arg);
-                       if ((arg->flags & NUMBER) != 0) {
-                               uval = get_number_uj(arg);
-#if MBS_SUPPORT
-                               if (gawk_mb_cur_max > 1) {
-                                       char buf[100];
-                                       wchar_t wc;
-                                       mbstate_t mbs;
-                                       size_t count;
-
-                                       memset(& mbs, 0, sizeof(mbs));
-                                       wc = uval;
-
-                                       count = wcrtomb(buf, wc, & mbs);
-                                       if (count == 0
-                                           || count == (size_t)-1
-                                           || count == (size_t)-2)
-                                               goto out0;
-
-                                       memcpy(CPBUF, buf, count);
-                                       spec.prec = count;
-                                       cp = CPBUF;
-                                       goto pr_tail;
-                               }
-out0:
-                               ;
-                               /* else,
-                                       fall through */
-#endif
-                               if (do_lint && uval > 255) {
-                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
-                                                       get_number_d(arg));
-                               }
-                               CPBUF[0] = uval;
-                               spec.prec = 1;
-                               cp = CPBUF;
-                               goto pr_tail;
-                       }
-                       /*
-                        * As per POSIX, only output first character of a
-                        * string value.  Thus, we ignore any provided
-                        * precision, forcing it to 1.  (Didn't this
-                        * used to work? 6/2003.)
-                        */
-                       cp = arg->stptr;
-#if MBS_SUPPORT
-                       /*
-                        * First character can be multiple bytes if
-                        * it's a multibyte character. Grr.
-                        */
-                       if (gawk_mb_cur_max > 1) {
-                               mbstate_t state;
-                               size_t count;
-
-                               memset(& state, 0, sizeof(state));
-                               count = mbrlen(cp, arg->stlen, & state);
-                               if (count == 0
-                                   || count == (size_t)-1
-                                   || count == (size_t)-2)
-                                       goto out2;
-                               spec.prec = count;
-                               goto pr_tail;
-                       }
-out2:
-                       ;
-#endif
-                       spec.prec = 1;
-                       goto pr_tail;
-               case 's':
-                       need_format = false;
-                       spec.fmtchar = cs1;
-                       parse_next_arg();
-                       arg = force_string(arg);
-                       if (spec.fw == 0 && ! spec.have_prec)
-                               spec.prec = arg->stlen;
-                       else {
-                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
-                               if (! spec.have_prec || spec.prec > char_count)
-                                       spec.prec = char_count;
-                       }
-                       cp = arg->stptr;
-       pr_tail:
-                       if (! spec.lj)
-                               pr_fill(& spec, outb);
-
-                       copy_count = spec.prec;
-                       if (spec.fw == 0 && ! spec.have_prec)
-                               ;
-                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
-                               assert(cp == arg->stptr || cp == CPBUF);
-                               copy_count = mbc_byte_count(arg->stptr, 
spec.prec);
-                       }
-
-                       bchunk(outb, cp, copy_count);
-                       pr_fill(& spec, outb);
-
-                       s0 = s1;
-                       break;
-
-               case 'X':
-                       /* FALL THROUGH */
-               case 'x':
-                       spec.base += 6;
-                       /* FALL THROUGH */
-               case 'u':
-                       spec.base += 2;
-                       /* FALL THROUGH */
-               case 'o':
-                       spec.base += 8;
-                       goto fmt1;
-               case 'F':
-#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
-                       cs1 = 'f';
-                       /* FALL THROUGH */
-#endif
-               case 'g':
-               case 'G':
-               case 'e':
-               case 'f':
-               case 'E':
-               case 'd':
-               case 'i':
-       fmt1:
-                       need_format = false;
-                       spec.fmtchar = cs1;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       spec.fmtchar = cs1;
-                       if (format_number_printf(arg, & spec, outb) < 0)
-                               goto out;
-
-                       s0 = s1;
-                       break;
-
-               default:
-                       if (isalpha(cs1)) {
-                               if (do_lint)
-       lintwarn(_("ignoring unknown format specifier character `%c': no 
argument converted"), cs1);
-                               if (do_parse_fmt)
-                                       goto out;
-                       }
-                       break;
-               }
-               if (toofew) {
-                       msg("%s\n\t`%s'\n\t%*s%s",
-                             _("fatal: not enough arguments to satisfy format 
string"),
-                             fmt_string, (int) (s1 - fmt_string - 1), "",
-                             _("^ ran out for this one"));
-                       goto out;
-               }
-       }
-
-       if (do_lint) {
-               if (need_format)
-                       lintwarn(_("[s]printf: format specifier does not have 
control letter"));
-               if (cur_arg < num_args)
-                       lintwarn(_("too many arguments supplied for format 
string"));
-       }
-
-       bchunk(outb, s0, s1 - s0);
-       retval = bytes2node(outb, NULL);
-out:
-       free_fmt_buf(outb);
-
-       if (do_parse_fmt) {
-               struct format_spec *cp_spec;
-
-               assert(retval == NULL);
-               if (spec.fmtchar == (char) 0)
-                       return NULL;
-               emalloc(cp_spec, struct format_spec *, sizeof (*cp_spec), 
"format_tree");
-               *cp_spec = spec;
-               return (NODE *) cp_spec;
-       }
-
-       if (retval == NULL)
-               gawk_exit(EXIT_FATAL);  /* debugger needs this */
-
-       return retval;
-
-#undef CP
-#undef CEND
-#undef CPBUF
-}
-
diff --git a/debug.c b/debug.c
index e679209..7296cf3 100644
--- a/debug.c
+++ b/debug.c
@@ -40,6 +40,7 @@ extern FILE *output_fp;
 extern IOBUF *curfile;
 extern const char *command_file;
 extern const char *get_spec_varname(Func_ptr fptr);
+extern NODE *format_tree(const char *, size_t, NODE **, long); /* format.c */
 extern int zzparse(void);
 #define read_command()         (void) zzparse()
 
diff --git a/double.c b/double.c
index d127e3a..c75b07c 100644
--- a/double.c
+++ b/double.c
@@ -24,7 +24,7 @@
  */
 
 #include "awk.h"
-#include "math.h"
+#include <math.h>
 #include "random.h"
 #include "floatmagic.h"        /* definition of isnan */
 
diff --git a/format.c b/format.c
new file mode 100644
index 0000000..ba95201
--- /dev/null
+++ b/format.c
@@ -0,0 +1,776 @@
+/*
+ * format.c - routines for (s)printf formatting.
+ */
+
+/* 
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+
+#include "format.h"
+
+char lchbuf[] = "0123456789abcdef";
+char Uchbuf[] = "0123456789ABCDEF";
+char space_string[] = " ";
+char zero_string[] = "0";
+
+/* mbc_byte_count --- return number of bytes for corresponding numchars 
multibyte characters */
+
+static size_t
+mbc_byte_count(const char *ptr, size_t numchars)
+{
+#if MBS_SUPPORT
+       mbstate_t cur_state;
+       size_t sum = 0;
+       int mb_len;
+
+       memset(& cur_state, 0, sizeof(cur_state));
+
+       assert(gawk_mb_cur_max > 1);
+       mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
+       if (mb_len <= 0)
+               return numchars;        /* no valid m.b. char */
+
+       for (; numchars > 0; numchars--) {
+               mb_len = mbrlen(ptr, numchars * gawk_mb_cur_max, &cur_state);
+               if (mb_len <= 0)
+                       break;
+               sum += mb_len;
+               ptr += mb_len;
+       }
+
+       return sum;
+#else
+       return numchars;
+#endif
+}
+
+/* mbc_char_count --- return number of m.b. chars in string, up to numbytes 
bytes */
+
+static size_t
+mbc_char_count(const char *ptr, size_t numbytes)
+{
+#if MBS_SUPPORT
+       mbstate_t cur_state;
+       size_t sum = 0;
+       int mb_len;
+
+       if (gawk_mb_cur_max == 1)
+               return numbytes;
+
+       memset(& cur_state, 0, sizeof(cur_state));
+
+       mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
+       if (mb_len <= 0)
+               return numbytes;        /* no valid m.b. char */
+
+       for (; numbytes > 0; numbytes--) {
+               mb_len = mbrlen(ptr, numbytes * gawk_mb_cur_max, &cur_state);
+               if (mb_len <= 0)
+                       break;
+               sum++;
+               ptr += mb_len;
+       }
+
+       return sum;
+#else
+       return numbytes;
+#endif
+}
+
+
+#define OUTBUF_INIT_SIZE       510
+
+/* chksize__internal --- make room for something LEN big in the output buffer 
*/
+
+static void
+chksize__internal(struct print_fmt_buf *outb, size_t len)
+{
+       size_t delta, newsize;
+
+       assert(outb->buf != NULL);
+       delta = outb->dataend - outb->buf;
+       newsize = delta + len + OUTBUF_INIT_SIZE;
+       erealloc(outb->buf, char *, newsize + 2, "chksize__internal");
+       outb->dataend = outb->buf + delta;
+       outb->bufsize = newsize;
+       outb->room_left = len + OUTBUF_INIT_SIZE;
+}
+
+/* cpbuf_chksize__internal --- enlarge the temporary buffer */
+
+static void
+cpbuf_chksize__internal(struct print_fmt_buf *outb)
+{
+       char *cp, *prev = outb->cpbuf.buf;
+       size_t oldsize = outb->cpbuf.bufsize;
+       size_t newsize;
+
+       newsize = outb->cpbuf.bufsize = 2 * oldsize;
+       emalloc(outb->cpbuf.buf, char *, newsize + 2, 
"cpbuf_chksize__internal");
+       memcpy((cp = outb->cpbuf.buf + oldsize), prev,  oldsize);
+       efree(prev);
+       outb->cpbuf.bufend = outb->cpbuf.buf + newsize;
+       outb->cpbuf.databegin = cp;
+}
+
+static struct print_fmt_buf static_outb;
+
+/* get_fmt_buf --- buffer(s) to manage (s)printf formatting */
+ 
+struct print_fmt_buf *
+get_fmt_buf()
+{
+       struct print_fmt_buf *outb;
+
+       if (static_outb.buf == NULL)
+               outb = & static_outb;
+       else {
+               emalloc(outb, struct print_fmt_buf *, sizeof (struct 
print_fmt_buf), "get_fmt_buf");
+               outb->is_malloced = true;
+       }
+
+       emalloc(outb->buf, char *, OUTBUF_INIT_SIZE + 2, "get_fmt_buf");
+       outb->bufsize = OUTBUF_INIT_SIZE;
+       outb->room_left = outb->bufsize;
+       outb->dataend = outb->buf;
+       outb->chksize = chksize__internal;
+
+       emalloc(outb->cpbuf.buf, char *, 64, "get_fmt_buf");
+       outb->cpbuf.bufsize = 62;
+       outb->cpbuf.databegin = outb->cpbuf.bufend = outb->cpbuf.buf + 
outb->cpbuf.bufsize;
+       outb->cpbuf_chksize = cpbuf_chksize__internal;
+       return outb;
+}
+
+/* fmt_parse --- parse a single format code */  
+
+struct format_spec *
+fmt_parse(NODE *n, const char *fmt_string, size_t fmt_len)
+{
+       struct format_spec *spec = NULL;
+
+       spec = (struct format_spec *) format_tree(fmt_string, fmt_len, NULL, 
LONG_MIN);
+       if (spec != NULL && n == CONVFMT_node
+               && (spec->fmtchar == 's' || spec->fmtchar == 'c')
+       ) {
+               efree(spec);
+               spec = NULL;
+       }
+       return spec;
+}
+
+
+/* format_nondecimal --- output a nondecimal number according to a format */
+
+void
+format_nondecimal(uintmax_t val, struct format_spec *spec, struct 
print_fmt_buf *outb)
+{
+       uintmax_t uval = val;
+       int ii, jj;
+       const char *chbuf = spec->chbuf;
+
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+
+       /*
+        * When to fill with zeroes is of course not simple.
+        * First: No zero fill if left-justifying.
+        * Next: There seem to be two cases:
+        *      A '0' without a precision, e.g. %06d
+        *      A precision with no field width, e.g. %.10d
+        * Any other case, we don't want to fill with zeroes.
+        */
+       if (! spec->lj
+                   && ((spec->zero_flag && ! spec->have_prec)
+                       || (spec->fw == 0 && spec->have_prec))
+       )
+               spec->fill = zero_string;
+
+       ii = jj = 0;
+       do {
+               tmpbuf_prepend(outb, chbuf[uval % spec->base]);
+               uval /= spec->base;
+#if defined(HAVE_LOCALE_H)
+               if (spec->base == 10 && spec->quote_flag && loc.grouping[ii] && 
++jj == loc.grouping[ii]) {
+                       if (uval)       /* only add if more digits coming */
+                               tmpbuf_prepend(outb, loc.thousands_sep[0]);     
/* XXX --- assumption it's one char */
+                       if (loc.grouping[ii+1] == 0)                            
              
+                               jj = 0;     /* keep using current val in 
loc.grouping[ii] */
+                       else if (loc.grouping[ii+1] == CHAR_MAX)                
        
+                               spec->quote_flag= false;
+                       else {                 
+                               ii++;
+                               jj = 0;
+                       }
+               }
+#endif
+       } while (uval > 0);
+
+       /* add more output digits to match the precision */
+       if (spec->have_prec) {
+               while (CEND - CP < spec->prec)
+                       tmpbuf_prepend(outb, '0');
+       }
+
+       if (spec->alt && val != 0) {
+               if (spec->base == 16) {
+                       tmpbuf_prepend(outb, spec->fmtchar);
+                       tmpbuf_prepend(outb, '0');
+                       if (spec->fill != space_string) {
+                               bchunk(outb, CP, 2);
+                               CP += 2;
+                               spec->fw -= 2;
+                       }
+               } else if (spec->base == 8)
+                       tmpbuf_prepend(outb, '0');
+       }
+
+       spec->base = 0;
+       if (spec->prec > spec->fw)
+               spec->fw = spec->prec;
+       spec->prec = CEND - CP;
+       pr_num_tail(CP, spec->prec, spec, outb);
+
+#undef CP
+#undef CEND
+}
+
+
+/*
+ * format_tree() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library.  Returns a string node which value
+ * is a formatted string.  Called by  sprintf function.
+ *
+ * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+
+NODE *
+format_tree(
+       const char *fmt_string,
+       size_t n0,
+       NODE **the_args,
+       long num_args)
+{
+       size_t cur_arg = 0;
+       NODE *retval = NULL;
+       bool toofew = false;
+       const char *s0, *s1;
+       int cs1;
+       NODE *arg;
+       long argnum;
+
+       bool used_dollar;
+       bool big_flag, bigbig_flag, small_flag, need_format;
+       long *cur = NULL;
+       uintmax_t uval;
+       char *cp;
+       size_t copy_count, char_count;
+
+       struct print_fmt_buf *outb;
+       struct format_spec spec;
+
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
+
+/* parse a single format specifier */
+#define do_parse_fmt   (num_args == LONG_MIN)
+
+       /*
+        * Check first for use of `count$'.
+        * If plain argument retrieval was used earlier, choke.
+        *      Otherwise, return the requested argument.
+        * If not `count$' now, but it was used earlier, choke.
+        * If this format is more than total number of args, choke.
+        * Otherwise, return the current argument.
+        */
+#define parse_next_arg() { \
+       if (do_parse_fmt) \
+               goto out; \
+       else if (argnum > 0) { \
+               if (cur_arg > 1) { \
+                       msg(_("fatal: must use `count$' on all formats or 
none")); \
+                       goto out; \
+               } \
+               arg = the_args[argnum]; \
+       } else if (used_dollar) { \
+               msg(_("fatal: must use `count$' on all formats or none")); \
+               arg = 0; /* shutup the compiler */ \
+               goto out; \
+       } else if (cur_arg >= num_args) { \
+               arg = 0; /* shutup the compiler */ \
+               toofew = true; \
+               break; \
+       } else { \
+               arg = the_args[cur_arg]; \
+               cur_arg++; \
+       } \
+}
+
+       outb = get_fmt_buf();
+       cur_arg = 1;
+
+       need_format = false;
+       used_dollar = false;
+
+       s0 = s1 = fmt_string;
+
+       while (n0-- > 0) {
+               if (*s1 != '%') {
+                       s1++;
+                       continue;
+               }
+               need_format = true;
+               bchunk(outb, s0, s1 - s0);
+               s0 = s1;
+               argnum = 0;
+
+               memset(& spec, '\0', sizeof (spec));
+               cur = & spec.fw;
+               spec.fill = space_string;       /* always space for string */
+
+               big_flag = bigbig_flag = small_flag = false;
+               CP = CEND;
+               s1++;
+
+retry:
+               if (n0-- == 0)  /* ran out early! */
+                       break;
+
+               switch (cs1 = *s1++) {
+               case (-1):      /* dummy case to allow for checking */
+check_pos:
+                       if (cur != & spec.fw)
+                               break;          /* reject as a valid format */
+                       goto retry;
+               case '%':
+                       need_format = false;
+                       /*
+                        * 29 Oct. 2002:
+                        * The C99 standard pages 274 and 279 seem to imply that
+                        * since there's no arg converted, the field width 
doesn't
+                        * apply.  The code already was that way, but this
+                        * comment documents it, at least in the code.
+                        */
+                       if (do_lint) {
+                               const char *msg = NULL;
+
+                               if (spec.fw && ! spec.have_prec)
+                                       msg = _("field width is ignored for 
`%%' specifier");
+                               else if (spec.fw == 0 && spec.have_prec)
+                                       msg = _("precision is ignored for `%%' 
specifier");
+                               else if (spec.fw && spec.have_prec)
+                                       msg = _("field width and precision are 
ignored for `%%' specifier");
+
+                               if (msg != NULL)
+                                       lintwarn("%s", msg);
+                       }
+                       bchunk_one(outb, "%");
+                       s0 = s1;
+                       break;
+
+               case '0':
+                       /*
+                        * Only turn on zero_flag if we haven't seen
+                        * the field width or precision yet.  Otherwise,
+                        * screws up floating point formatting.
+                        */
+                       if (cur == & spec.fw)
+                               spec.zero_flag = true;
+                       if (spec.lj)
+                               goto retry;
+                       /* FALL through */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       if (cur == NULL)
+                               break;
+                       if (spec.prec >= 0)
+                               *cur = cs1 - '0';
+                       /*
+                        * with a negative precision *cur is already set
+                        * to -1, so it will remain negative, but we have
+                        * to "eat" precision digits in any case
+                        */
+                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+                               --n0;
+                               *cur = *cur * 10 + *s1++ - '0';
+                       }
+                       if (spec.prec < 0)      /* negative precision is 
discarded */
+                               spec.have_prec = false;
+                       if (cur == & spec.prec)
+                               cur = NULL;
+                       if (n0 == 0)    /* badly formatted control string */
+                               continue;
+                       goto retry;
+               case '$':
+                       if (do_traditional) {
+                               msg(_("fatal: `$' is not permitted in awk 
formats"));
+                               goto out;
+                       }
+                       if (do_parse_fmt)
+                               goto out;
+
+                       if (cur == & spec.fw) {
+                               argnum = spec.fw;
+                               spec.fw = 0;
+                               used_dollar = true;
+                               if (argnum <= 0) {
+                                       msg(_("fatal: arg count with `$' must 
be > 0"));
+                                       goto out;
+                               }
+                               if (argnum >= num_args) {
+                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
+                                       goto out;
+                               }
+                       } else {
+                               msg(_("fatal: `$' not permitted after period in 
format"));
+                               goto out;
+                       }
+
+                       goto retry;
+               case '*':
+                       if (cur == NULL)
+                               break;
+                       if (! do_traditional && isdigit((unsigned char) *s1)) {
+                               int val = 0;
+
+                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
+                                       val *= 10;
+                                       val += *s1 - '0';
+                               }
+                               if (*s1 != '$') {
+                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
+                                       goto out;
+                               } else {
+                                       s1++;
+                                       n0--;
+                               }
+                               if (val >= num_args) {
+                                       toofew = true;
+                                       break;
+                               }
+                               arg = the_args[val];
+                       } else {
+                               parse_next_arg();
+                       }
+
+                       (void) force_number(arg);
+                       *cur = get_number_si(arg);
+                       if (*cur < 0 && cur == & spec.fw) {
+                               *cur = -*cur;
+                               spec.lj++;
+                       }
+                       if (cur == & spec.prec) {
+                               if (*cur >= 0)
+                                       spec.have_prec = true;
+                               else
+                                       spec.have_prec = false;
+                               cur = NULL;
+                       }
+                       goto retry;
+               case ' ':               /* print ' ' or '-' */
+                                       /* 'space' flag is ignored */
+                                       /* if '+' already present  */
+                       if (spec.signchar != false) 
+                               goto check_pos;
+                       /* FALL THROUGH */
+               case '+':               /* print '+' or '-' */
+                       spec.signchar = cs1;
+                       goto check_pos;
+               case '-':
+                       if (spec.prec < 0)
+                               break;
+                       if (cur == & spec.prec) {
+                               spec.prec = -1;
+                               goto retry;
+                       }
+                       spec.lj++;              /* filling is ignored */
+                       goto check_pos;
+               case '.':
+                       if (cur != & spec.fw)
+                               break;
+                       cur = & spec.prec;
+                       spec.have_prec = true;
+                       goto retry;
+               case '#':
+                       spec.alt = true;
+                       goto check_pos;
+               case '\'':
+#if defined(HAVE_LOCALE_H)       
+                       /* allow quote_flag if there is a thousands separator. 
*/
+                       if (loc.thousands_sep[0] != '\0')
+                               spec.quote_flag= true;
+                       goto check_pos;
+#else
+                       goto retry;  
+#endif
+               case 'l':
+                       if (big_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       big_flag = true;
+                       goto retry;
+               case 'L':
+                       if (bigbig_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       bigbig_flag = true;
+                       goto retry;
+               case 'h':
+                       if (small_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       small_flag = true;
+                       goto retry;
+               case 'c':
+                       need_format = false;
+                       spec.fmtchar = cs1;
+                       parse_next_arg();
+                       /* user input that looks numeric is numeric */
+                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+                               (void) force_number(arg);
+                       if ((arg->flags & NUMBER) != 0) {
+                               uval = get_number_uj(arg);
+#if MBS_SUPPORT
+                               if (gawk_mb_cur_max > 1) {
+                                       char buf[100];
+                                       wchar_t wc;
+                                       mbstate_t mbs;
+                                       size_t count;
+
+                                       memset(& mbs, 0, sizeof(mbs));
+                                       wc = uval;
+
+                                       count = wcrtomb(buf, wc, & mbs);
+                                       if (count == 0
+                                           || count == (size_t)-1
+                                           || count == (size_t)-2)
+                                               goto out0;
+
+                                       memcpy(CPBUF, buf, count);
+                                       spec.prec = count;
+                                       cp = CPBUF;
+                                       goto pr_tail;
+                               }
+out0:
+                               ;
+                               /* else,
+                                       fall through */
+#endif
+                               if (do_lint && uval > 255) {
+                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
+                                                       get_number_d(arg));
+                               }
+                               CPBUF[0] = uval;
+                               spec.prec = 1;
+                               cp = CPBUF;
+                               goto pr_tail;
+                       }
+                       /*
+                        * As per POSIX, only output first character of a
+                        * string value.  Thus, we ignore any provided
+                        * precision, forcing it to 1.  (Didn't this
+                        * used to work? 6/2003.)
+                        */
+                       cp = arg->stptr;
+#if MBS_SUPPORT
+                       /*
+                        * First character can be multiple bytes if
+                        * it's a multibyte character. Grr.
+                        */
+                       if (gawk_mb_cur_max > 1) {
+                               mbstate_t state;
+                               size_t count;
+
+                               memset(& state, 0, sizeof(state));
+                               count = mbrlen(cp, arg->stlen, & state);
+                               if (count == 0
+                                   || count == (size_t)-1
+                                   || count == (size_t)-2)
+                                       goto out2;
+                               spec.prec = count;
+                               goto pr_tail;
+                       }
+out2:
+                       ;
+#endif
+                       spec.prec = 1;
+                       goto pr_tail;
+               case 's':
+                       need_format = false;
+                       spec.fmtchar = cs1;
+                       parse_next_arg();
+                       arg = force_string(arg);
+                       if (spec.fw == 0 && ! spec.have_prec)
+                               spec.prec = arg->stlen;
+                       else {
+                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
+                               if (! spec.have_prec || spec.prec > char_count)
+                                       spec.prec = char_count;
+                       }
+                       cp = arg->stptr;
+       pr_tail:
+                       if (! spec.lj)
+                               pr_fill(& spec, outb);
+
+                       copy_count = spec.prec;
+                       if (spec.fw == 0 && ! spec.have_prec)
+                               ;
+                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
+                               assert(cp == arg->stptr || cp == CPBUF);
+                               copy_count = mbc_byte_count(arg->stptr, 
spec.prec);
+                       }
+
+                       bchunk(outb, cp, copy_count);
+                       pr_fill(& spec, outb);
+
+                       s0 = s1;
+                       break;
+
+               case 'X':
+                       /* FALL THROUGH */
+               case 'x':
+                       spec.base += 6;
+                       /* FALL THROUGH */
+               case 'u':
+                       spec.base += 2;
+                       /* FALL THROUGH */
+               case 'o':
+                       spec.base += 8;
+                       goto fmt1;
+               case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+                       cs1 = 'f';
+                       /* FALL THROUGH */
+#endif
+               case 'g':
+               case 'G':
+               case 'e':
+               case 'f':
+               case 'E':
+               case 'd':
+               case 'i':
+       fmt1:
+                       need_format = false;
+                       spec.fmtchar = cs1;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       spec.fmtchar = cs1;
+                       if (format_number_printf(arg, & spec, outb) < 0)
+                               goto out;
+
+                       s0 = s1;
+                       break;
+
+               default:
+                       if (isalpha(cs1)) {
+                               if (do_lint)
+       lintwarn(_("ignoring unknown format specifier character `%c': no 
argument converted"), cs1);
+                               if (do_parse_fmt)
+                                       goto out;
+                       }
+                       break;
+               }
+               if (toofew) {
+                       msg("%s\n\t`%s'\n\t%*s%s",
+                             _("fatal: not enough arguments to satisfy format 
string"),
+                             fmt_string, (int) (s1 - fmt_string - 1), "",
+                             _("^ ran out for this one"));
+                       goto out;
+               }
+       }
+
+       if (do_lint) {
+               if (need_format)
+                       lintwarn(_("[s]printf: format specifier does not have 
control letter"));
+               if (cur_arg < num_args)
+                       lintwarn(_("too many arguments supplied for format 
string"));
+       }
+
+       bchunk(outb, s0, s1 - s0);
+       retval = bytes2node(outb, NULL);
+out:
+       free_fmt_buf(outb);
+
+       if (do_parse_fmt) {
+               struct format_spec *cp_spec;
+
+               assert(retval == NULL);
+               if (spec.fmtchar == (char) 0)
+                       return NULL;
+               emalloc(cp_spec, struct format_spec *, sizeof (*cp_spec), 
"format_tree");
+               *cp_spec = spec;
+               return (NODE *) cp_spec;
+       }
+
+       if (retval == NULL)
+               gawk_exit(EXIT_FATAL);  /* debugger needs this */
+
+       return retval;
+
+#undef CP
+#undef CEND
+#undef CPBUF
+}
diff --git a/format.h b/format.h
index 74d6f51..0c9140d 100644
--- a/format.h
+++ b/format.h
@@ -70,6 +70,12 @@ struct print_fmt_buf {
 
 extern struct print_fmt_buf *get_fmt_buf(void);
 extern void format_nondecimal(uintmax_t, struct format_spec *, struct 
print_fmt_buf *);
+extern NODE *format_tree(const char *, size_t, NODE **, long);
+
+extern char lchbuf[];
+extern char Uchbuf[];
+extern char space_string[];
+extern char zero_string[];
 
 #      define buf_start(ob)    ((ob)->buf)
 #      define buf_end(ob)      ((ob)->dataend)
@@ -78,10 +84,6 @@ extern void format_nondecimal(uintmax_t, struct format_spec 
*, struct print_fmt_
 #      define cpbuf_end(ob)    ((ob)->cpbuf.bufend)
 #      define cpbuf(ob)        ((ob)->cpbuf.buf)
 
-extern char lchbuf[];
-extern char Uchbuf[];
-extern char space_string[];
-extern char zero_string[];
 
 /* chksize --- make room for something LEN big in the output buffer */
 
diff --git a/awklib/eg/lib/repl_math.awk b/misc/ap_math.awk
similarity index 71%
rename from awklib/eg/lib/repl_math.awk
rename to misc/ap_math.awk
index 1788533..941a4d6 100644
--- a/awklib/eg/lib/repl_math.awk
+++ b/misc/ap_math.awk
@@ -1,9 +1,9 @@
-# repl_math.awk --- arbitrary-precision math functions
+# ap_math.awk --- arbitrary-precision math functions
 
 #
-#      repl_sin        -- Compute sin(x)
-#      repl_cos        -- Compute cos(x)
-#      repl_atan2      -- Compute atan2(y, x)
+#      ap_sin          -- Compute sin(x)
+#      ap_cos          -- Compute cos(x)
+#      ap_atan2        -- Compute atan2(y, x)
 #
 
 #
@@ -17,33 +17,38 @@
 #      y = (x^2) / (1 + x^2) and -1 <= x <= 1
 #
 # Substituting x = 1/x, for x >= 1
-#      atan(1/x) = (1 / (1 + x^2))    + (2/3) * (1 / (1 + x^2)^2)
-#                                     + (2*4/(3*5)) * (1 / (1 + x^2)^3)
-#                                     + (2*4*6/(3*5*7)) * (1 / (1 + x^2)^4)  + 
... 
+#      atan(1/x) = (x / (1 + x^2))    + (2/3) * (x / (1 + x^2)^2)
+#                                     + (2*4/(3*5)) * (x / (1 + x^2)^3)
+#                                     + (2*4*6/(3*5*7)) * (x / (1 + x^2)^4)  + 
... 
 #
 
 function euler_atan_one_over(x,        \
-               xpow2_plus_one, term, sum, i, err)
+               xpow2_plus_one, term, sum, i, sign, err)
 {
+       sign = 1
+       if (x < 0) {
+               sign = -1
+               x = -x
+       }
+
        xpow2_plus_one = x * x + 1
        term = x / xpow2_plus_one
        sum = term
        i = 0
-       err = 1.0
 
-       while (err > __EPSILON__) {
+       do {
                term *= (i + 2) / (i + 3)
                err = term /= xpow2_plus_one
                i += 2
                sum += term
-               if (err < 0)
-                       err = -err
-       }
-       return sum
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
+       return sign * sum
 }
 
-function setup_repl_math( \
-               prec, digits, extra_prec)
+function setup_ap_math( \
+               prec, curr_prec, digits, extra_prec)
 {
        switch (PREC) {
        case "half":    prec = 11; break;
@@ -59,16 +64,21 @@ function setup_repl_math( \
                print "PREC value not specified" > "/dev/stderr"
                exit(1)
        }
-       __SAVE_PREC__ = PREC
-       extra_prec = 10
-       prec += extra_prec      # temporarily raise precision
-       if (prec != __PI_PREC__) {
+
+       curr_prec = PREC
+       extra_prec = 10         # temporarily raise precision by this amount; 
Why 10???
+
+       # unlike PREC, `prec' is always a number 
+       PREC = prec + extra_prec
+
+       if (PREC != __PI_PREC__) {
                # compute PI only once for a given precision
-               digits = int ((prec - extra_prec) / 3.32193)
-               __EPSILON__ = sprintf("1.0e-%d", digits + 2) + 0
+               digits = int (PREC / 3.32193)
+               __REL_ERROR__ = sprintf("5.0e-%d", digits) + 0
+               __PI_PREC__ = PREC
                __PI_OVER_4__ = 4 * euler_atan_one_over(5) - 
euler_atan_one_over(239)
-               __PI_PREC__ = prec
        }
+       return curr_prec
 }
 
 #
@@ -163,67 +173,89 @@ function euler_atan2(y, x,        \
        return 0;       # atan2(+0, +0) or atan2(-0, 0)
 }
 
+#
+#      Collect two terms in each iteration for the Taylor series:
+#              sin(x) = (x - x^3/3!) + (x^5/5! - x^7/7!) + ...
+#
 
 function taylor_sin(x, \
-               i, fact, xpow2, xpow_odd, sum, term, sign, err)
+               i, fact, xpow2, xpow_odd, sum, term, err)
 {
-       i = 1
-       fact = 1
+       # XXX: this assumes x >= 0
+
+       if (x == 0)
+               return x
+       i = 3
+       fact = 6        # 3!
        xpow2 = x * x
-       xpow_odd = x
-       sum = x
-       sign = 1
-       err = 1.0
+       xpow_odd = xpow2 * x
+       sum = x - xpow_odd / fact
+
+       do {
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_odd *= xpow2
+               term = xpow_odd / fact
 
-       while (err > __EPSILON__) {
                fact *= (i + 1) * (i + 2)
                i += 2
                xpow_odd *= xpow2
-               sign *= -1
-               err = term = xpow_odd / fact  * sign
+               term -= xpow_odd / fact
+
                sum += term
-               if (err < 0)
-                       err = -err
-       }
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
        return sum
 }
 
+#
+#      Collect two terms in each iteration for the Taylor series:
+#              cos(x) = (1 - x^2/2!) + (x^4/4! - x^6/6!)...
+#
+
 function taylor_cos(x, \
-               i, fact, xpow2, xpow_even, sum, term, sign, err)
+               i, fact, xpow2, xpow_even, sum, term, err)
 {
-       i = 0
-       fact = 1
+       if (x == 0)
+               return 1
+
+       i = 2
+       fact = 2
        xpow2 = x * x
-       xpow_even = 1
-       sum = 1
-       sign = 1
-       err = 1.0
+       xpow_even = xpow2
+       sum = 1 - xpow2 / fact
 
-       while (err > __EPSILON__) {
+       do {
                fact *= (i + 1) * (i + 2)
                i += 2
                xpow_even *= xpow2
-               sign *= -1
-               err = term = xpow_even / fact * sign
+               term = xpow_even / fact
+
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_even *= xpow2
+               term -= xpow_even / fact
+
                sum += term
-               if (err < 0)
-                       err = -err
-       }
+               err = term / sum
+       } while (err > __REL_ERROR__)
+
        return sum
 }
 
 #
 # For 0 <= x <= PI/4, using Taylor series approximation for sin(x):
-#      x - x^3/5! + x^5/7! - ...
+#      x - x^3/3! + x^5/5! - ...
 #
 # for PI/4 < x <= PI/2, use identity sin(x) = cos(PI/2 - x).
 #
 #
 
-function repl_sin(x,   \
-               k, sign, y, sv)
+function ap_sin(x,     \
+               k, sign, y, sv, curr_prec)
 {
-       setup_repl_math()
+       curr_prec = setup_ap_math()
        x = + x         # or x += 0.0 or x = x + 0.0 
        if (x == "+inf" + 0 || x == "-inf" + 0 ||
                        x == "+nan" + 0 || x == "-nan" + 0)
@@ -248,7 +280,7 @@ function repl_sin(x,        \
        }
        sv *= sign
 
-       PREC = __SAVE_PREC__
+       PREC = curr_prec
        return +sv;     # unary plus returns a number with current precision 
 }
 
@@ -259,10 +291,10 @@ function repl_sin(x,      \
 #
 
 
-function repl_cos(x,   \
-               k, sign, y, cv)
+function ap_cos(x,     \
+               k, sign, y, cv, curr_prec)
 {
-       setup_repl_math()
+       curr_prec = setup_ap_math()
 
        x = + x         # or x += 0.0 or x = x + 0.0
        if (x == "+inf" + 0 || x == "-inf" + 0 ||
@@ -284,16 +316,16 @@ function repl_cos(x,      \
        }
        cv *= sign
 
-       PREC = __SAVE_PREC__
+       PREC = curr_prec
        return +cv      # unary plus to apply current precision
 }
 
-function repl_atan2(y, x, \
-               tv)
+function ap_atan2(y, x, \
+               tv, curr_prec)
 {
-       setup_repl_math()
+       curr_prec = setup_ap_math()
        tv = euler_atan2(y, x)
 
-       PREC = __SAVE_PREC__
+       PREC = curr_prec
        return +tv      # unary plus to apply current precision
 }
diff --git a/mpfr.c b/mpfr.c
index f0b7c3f..adcd0d8 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -1790,11 +1790,6 @@ finish:
        return mpfr_val;
 }
 
-
-extern size_t mbc_byte_count(const char *ptr, size_t numchars);
-extern size_t mbc_char_count(const char *ptr, size_t numbytes);
-
-
 /* mpfp_format_prinf --- format a number for (s)printf */
 
 static int
diff --git a/msg.c b/msg.c
index 4d67f60..330d0a8 100644
--- a/msg.c
+++ b/msg.c
@@ -26,6 +26,7 @@
 
 #include "awk.h"
 
+extern NODE *format_tree(const char *, size_t, NODE **, long); /* format.c */
 extern FILE *output_fp;
 int sourceline = 0;
 char *source = NULL;

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=42dd95107c29fc8f2e1ca370a083a2d63e17fb57

commit 42dd95107c29fc8f2e1ca370a083a2d63e17fb57
Author: John Haque <address@hidden>
Date:   Fri Jan 11 06:36:00 2013 -0600

    Updated long_double.c for format_tree() related changes.

diff --git a/long_double.c b/long_double.c
index e5a5261..7d94afd 100644
--- a/long_double.c
+++ b/long_double.c
@@ -35,17 +35,10 @@
 
 #define AWKLDBL        long double
 
-/* XXX: define to 1 to try AWKNUM as long double */
-/* #define AWKNUM_LDBL 1 */
-
 
 #include "long_double.h"
 
-#ifdef AWKNUM_LDBL
-#define LDBL(n)        ((n)->numbr)
-#else
 #define LDBL(n)        (*((AWKLDBL *) (n)->qnumbr))
-#endif
 
 /* Can declare these, since we always use the random shipped with gawk */
 extern char *initstate(unsigned long seed, char *state, long n);
@@ -59,8 +52,6 @@ extern void srandom(unsigned long seed);
  */
 #define GAWK_RANDOM_MAX 0x7fffffffL
 
-extern NODE **fmt_list;          /* declared in eval.c */
-
 /*
  * FIXME -- some of these are almost identical except for the number definition
  * #define DBLNUM      AWKNUM
@@ -124,20 +115,13 @@ static int is_ieee_magic_val(const char *val);
 static AWKLDBL get_ieee_magic_val(const char *val);
 static AWKLDBL calc_exp(AWKLDBL x1, AWKLDBL x2);
 static AWKLDBL double_to_int(AWKLDBL d);
-#ifndef AWKNUM_LDBL
 static NODE *make_awkldbl(AWKLDBL);
-#endif
 
 static long MFNR;
 static long MNR;
 
-#ifdef AWKNUM_LDBL
-#define get_long_double(d)     /* nothing */
-#define free_long_double(d)    /* nothing */
-#else
 #define get_long_double(d)     getblock(d, BLOCK_LDBL, AWKLDBL *)
 #define free_long_double(d)    freeblock(d, BLOCK_LDBL)
-#endif
 
 #if 0
 #define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), 
"long_double")
@@ -151,11 +135,7 @@ numbr_handler_t awkldbl_hndlr = {
        make_awknum,
        str2awkldbl,
        awkldbl_copy,
-#ifndef AWKNUM_LDBL
        free_awkldbl,
-#else
-       NULL,   /* free_awkldbl --- not needed for AWKNUM */
-#endif
        force_awkldbl,
        negate_awkldbl,
        cmp_awkldbls,
@@ -434,7 +414,6 @@ awkldbl_init_vars()
  *     this routine is not exported. 
  */
 
-#ifndef AWKNUM_LDBL
 static NODE *
 make_awkldbl(AWKLDBL x)
 {
@@ -453,7 +432,6 @@ make_awkldbl(AWKLDBL x)
 #endif /* defined MBS_SUPPORT */
        return r;
 }
-#endif
 
 /* make_awknum --- allocate a node with defined AWKNUM */
 
@@ -478,14 +456,12 @@ make_awknum(AWKNUM x)
 
 /* free_awkldbl --- free all storage allocated for a AWKLDBL */
 
-#ifndef AWKNUM_LDBL
 static void
 free_awkldbl(NODE *tmp)
 {
        assert((tmp->flags & (NUMBER|NUMCUR)) != 0);
         free_long_double(tmp->qnumbr);
 }
-#endif
 
 /* make_integer --- Convert an integer to a number node. */
 
@@ -1134,10 +1110,17 @@ format_awkldbl_val(const char *format, int index, NODE 
*s)
 
        d = LDBL(s);
 
+       if ((s->flags & STRCUR) != 0)
+               efree(s->stptr);
+       free_wstr(s);
+
        /* not an integral value, or out of range */
        if ((ival = double_to_int(d)) != d
                        || ival <= LONG_MIN || ival >= LONG_MAX
        ) {
+               struct format_spec spec;
+               struct print_fmt_buf *outb;
+
                /*
                 * Once upon a time, we just blindly did this:
                 *      sprintf(sp, format, s->numbr);
@@ -1147,30 +1130,24 @@ format_awkldbl_val(const char *format, int index, NODE 
*s)
                 * and just always format the value ourselves.
                 */
 
-               NODE *dummy[2], *r;
-               unsigned int oflags;
-
-               /* create dummy node for a sole use of format_tree */
-               dummy[1] = s;
-               oflags = s->flags;
+               /* XXX: format_spec copied since can be altered in the 
formatting routine */
 
                if (ival == d) {
                        /* integral value, but outside range of %ld, use %.0f */
-                       r = format_tree("%.0f", 4, dummy, 2);
+                       spec = *fmt_list[INT_0f_FMT_INDEX].spec;
                        s->stfmt = -1;
                } else {
-                       r = format_tree(format, fmt_list[index]->stlen, dummy, 
2);
-                       assert(r != NULL);
-                       s->stfmt = (char) index;
+                       assert(fmt_list[index].spec != NULL);   /* or can use 
fmt_parse() --- XXX */
+                       spec = *fmt_list[index].spec;
+                       s->stfmt = (char) index;        
                }
-               s->flags = oflags;
-               s->stlen = r->stlen;
-               if ((s->flags & STRCUR) != 0)
-                       efree(s->stptr);
-               s->stptr = r->stptr;
-               freenode(r);    /* Do not unref(r)! We want to keep s->stptr == 
r->stpr.  */
-
-               goto no_malloc;
+
+               outb = get_fmt_buf();
+               format_awkldbl_printf(s, & spec, outb);
+               (void) bytes2node(outb, s);
+               free_fmt_buf(outb);
+
+               s->stptr[s->stlen] = '\0';
        } else {
                /*
                 * integral value; force conversion to long only once.
@@ -1189,14 +1166,12 @@ format_awkldbl_val(const char *format, int index, NODE 
*s)
                        s->flags &= ~(INTIND|NUMBER);
                        s->flags |= STRING;
                }
+
+               emalloc(s->stptr, char *, s->stlen + 2, "format_awkldbl_val");
+               memcpy(s->stptr, sp, s->stlen + 1);
        }
-       if (s->stptr != NULL)
-               efree(s->stptr);
-       emalloc(s->stptr, char *, s->stlen + 2, "format_awkldbl_val");
-       memcpy(s->stptr, sp, s->stlen + 1);
-no_malloc:
+
        s->flags |= STRCUR;
-       free_wstr(s);
        return s;
 }
 

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=951972c4d26b8ae2f42fd4133a0983b2d10dc88d

commit 951972c4d26b8ae2f42fd4133a0983b2d10dc88d
Merge: 549fa6f b97f64a
Author: John Haque <address@hidden>
Date:   Fri Jan 11 06:13:47 2013 -0600

    Merge branch 'num-handler' into long-double


http://git.sv.gnu.org/cgit/gawk.git/commit/?id=b97f64ab95ef7407de4ce4f14b3477b8d62e5430

commit b97f64ab95ef7407de4ce4f14b3477b8d62e5430
Author: John Haque <address@hidden>
Date:   Fri Jan 11 06:12:15 2013 -0600

    More printf formatting changes.

diff --git a/ChangeLog b/ChangeLog
index 389c61f..8125721 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,15 @@
+2013-01-11         John Haque      <address@hidden>
+
+       Finish format_tree() refactoring.
+
+       * awk.h (struct fmt_list_item): New definition.
+       * builtin.c (fmt_parse): New routine to parse a single format code.
+       (format_tree): Adjusted.
+       * eval.c (fmt_index): (Pre-)compile and store format codes.
+       * double.c (format_awknum_val): Reworked to use compiled
+       format codes.
+       * mpfr.c (mpfp_format_val): Ditto.
+
 2013-01-03         John Haque      <address@hidden>
 
        Refactor format_tree() to seperate number formatting code.
diff --git a/TODO.NUMH b/TODO.NUMH
index 838b0f9..d95ed55 100644
--- a/TODO.NUMH
+++ b/TODO.NUMH
@@ -2,7 +2,7 @@
 
   [1] Remove direct calls to format_tree() in number to string (force_string)
 routines. Fix CONVFMT = "%s"/"%c" crash; present in all known gawk versions.
-Cache parsed format code in fmt_idx() ... 
+Cache parsed format code in fmt_idx() ...      DONE
 
   [2] Try to format NaN/inf in main gawk code, and not in the individual 
handlers.
 
@@ -14,3 +14,27 @@ May require additional tests e.g. SIZE_MAX <= UINT_MAX. In a 
nutshell, don't do
                        number => double => integer
 
 * Restore constant-folding code for numbers.
+
+* Consider special handling of integer-indexed arrays with non-double
+number handlers.
+       - Choose a reasonable range for integer indices.
+               #if SIZEOF_LONG <= 8
+               typedef gawk_int_t      long
+               #define GAWK_INT_MAX    LONG_MAX
+               #define GAWK_INT_MIN    LONG_MIN
+               #define GAWK_INT_BIT    SIZEOF_LONG * 8  ### may not need this
+               #else
+               typedef gawk_int_t      int
+               #define GAWK_INT_MAX    INT_MAX
+               #define GAWK_INT_MIN    INT_MIN
+               #define GAWK_INT_BIT    SIZEOF_INT * 8
+               #endif
+       Install gaurd code in array handlers (or adjust the defs) for size
+       anything but 4 or 8 (overthinking?). Use gawk_int_t instead
+       of int32_t or int64_t.
+
+       - Use additional struct field number_fits_gawk_int()
+       (MPFR has similarly named routines, e.g. mpfr_fits_slong()),
+       and avoid checking after conversion. Note that the type is
+       gawk_int_t and NOT necessarily long.
+
diff --git a/array.c b/array.c
index c5090d9..99dfa45 100644
--- a/array.c
+++ b/array.c
@@ -26,7 +26,6 @@
 #include "awk.h"
 
 extern FILE *output_fp;
-extern NODE **fmt_list;          /* declared in eval.c */
 
 static size_t SUBSEPlen;
 static char *SUBSEP;
@@ -72,7 +71,6 @@ register_array_func(afunc_t *afunc)
        return false;
 }
 
-
 /* array_init --- register all builtin array types */
 
 void
@@ -677,7 +675,7 @@ value_info(NODE *n)
                fprintf(output_fp, "][");
                fprintf(output_fp, "stfmt=%d, ", n->stfmt);     
                fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
-                                       : fmt_list[n->stfmt]->stptr);
+                                       : fmt_list[n->stfmt].fmt->stptr);
        }
 }
 
diff --git a/awk.h b/awk.h
index e459a95..85b0ff7 100644
--- a/awk.h
+++ b/awk.h
@@ -732,7 +732,6 @@ typedef struct exp_instruction {
 #define GENSUB          0x02   /* builtin is gensub */
 #define LITERAL         0x04   /* target is a literal string */
 
-
 /* Op_K_exit */
 #define target_end      d.di
 #define target_atexit   x.xi   
@@ -896,7 +895,8 @@ typedef struct {
        NODE *(*gawk_fmt_number)(const char *, int, NODE *);   /* stringify a 
numeric value
                                                                  based on awk 
input/output format */
 
-       int (*gawk_format_printf)(NODE *, struct format_spec *, struct 
print_fmt_buf *); /* (s)printf format */
+       /* (s)printf formatting of numbers */
+       int (*gawk_format_printf)(NODE *, struct format_spec *, struct 
print_fmt_buf *);
 
        /* conversion to C types */
        double (*gawk_todouble)(const NODE *);         /* number to double */
@@ -924,6 +924,11 @@ typedef struct {
 } numbr_handler_t;
 
 
+struct fmt_list_item {
+       NODE *fmt;                   /* format string */ 
+       struct format_spec *spec;    /* parsed format code */
+};
+
 typedef struct iobuf {
        awk_input_buf_t public; /* exposed to extensions */
        char *buf;              /* start data buffer */
@@ -1111,6 +1116,7 @@ extern uintmax_t (*get_number_uj)(const NODE *);
 extern int (*sgn_number)(const NODE *);
 extern int (*format_number_printf)(NODE *, struct format_spec *, struct 
print_fmt_buf *);
 
+extern struct fmt_list_item *fmt_list;
 
 /* built-in array types */
 extern afunc_t str_array_func[];
diff --git a/awklib/eg/lib/repl_math.awk b/awklib/eg/lib/repl_math.awk
index a57be27..1788533 100644
--- a/awklib/eg/lib/repl_math.awk
+++ b/awklib/eg/lib/repl_math.awk
@@ -74,10 +74,10 @@ function setup_repl_math( \
 #
 # atan2(y, x) =        atan(y/x),              x > 0
 #             =        atan(y/x) + pi,         x < 0, y >= 0
-#             = atan(y/x) - pi,                x < 0, y < 0
-#             = pi/2,                  x = 0, y > 0
-#             = -pi/2,                 x = 0, y < 0
-#             = ?                      x = 0, y = 0
+#             =        atan(y/x) - pi,         x < 0, y < 0
+#             =        pi/2,                   x = 0, y > 0
+#             =        -pi/2,                  x = 0, y < 0
+#             =        ?                       x = 0, y = 0
 #
 
 function euler_atan2(y, x,     \
@@ -114,7 +114,7 @@ function euler_atan2(y, x,  \
        }
 
        if (x == plus_inf)
-               return atan2(y, x)      # use builtin, -0 or -0
+               return atan2(y, x)      # use builtin, returns +0 or -0
        if (x == minus_inf) {
                if (y >= 0)
                        return 4 * __PI_OVER_4__
@@ -133,7 +133,9 @@ function euler_atan2(y, x,  \
                if (y > x)
                        return sign * (2 * __PI_OVER_4__ - 
euler_atan_one_over(y / x))
                return sign * euler_atan_one_over(x / y)
-       } else if (x < 0) {
+       }
+
+       if (x < 0) {
                if (y == 0) {
                        if (atan2(y, x) < 0)    # use builtin to detect sign
                                return - 4 * __PI_OVER_4__
@@ -154,8 +156,11 @@ function euler_atan2(y, x, \
                return - euler_atan_one_over(x / y) + 4 * __PI_OVER_4__
        }
 
-       # x == +0/-0 and y == +0/-0
-       return atan2(y, x);     # use builtin
+       if (atan2(y, x) < 0)    # atan2(-0, -0)
+               return - 4.0 * __PI_OVER_4__
+       if (atan2(y, x) > 0)    # atan2(+0, -0)
+               return 4.0 * __PI_OVER_4__
+       return 0;       # atan2(+0, +0) or atan2(-0, 0)
 }
 
 
@@ -225,7 +230,7 @@ function repl_sin(x,        \
                return "nan" + 0
 
        if (x < 0) {
-               # sin(x) = - sin(x)
+               # sin(-x) = - sin(x)
                sign = -1
                x = -x
        } else
diff --git a/builtin.c b/builtin.c
index 720a12c..8559c39 100644
--- a/builtin.c
+++ b/builtin.c
@@ -23,7 +23,6 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
  */
 
-
 #include "awk.h"
 #if defined(HAVE_FCNTL_H)
 #include <fcntl.h>
@@ -2135,10 +2134,22 @@ get_fmt_buf()
        return outb;
 }
 
+/* fmt_parse --- parse a single format code */  
 
-#      define CP               cpbuf_start(outb)
-#      define CEND             cpbuf_end(outb)
-#      define CPBUF            cpbuf(outb)
+struct format_spec *
+fmt_parse(NODE *n, const char *fmt_string, size_t fmt_len)
+{
+       struct format_spec *spec = NULL;
+
+       spec = (struct format_spec *) format_tree(fmt_string, fmt_len, NULL, 
LONG_MIN);
+       if (spec != NULL && n == CONVFMT_node
+               && (spec->fmtchar == 's' || spec->fmtchar == 'c')
+       ) {
+               efree(spec);
+               spec = NULL;
+       }
+       return spec;
+}
 
 
 /* format_nondecimal --- output a nondecimal number according to a format */
@@ -2150,6 +2161,9 @@ format_nondecimal(uintmax_t val, struct format_spec 
*spec, struct print_fmt_buf
        int ii, jj;
        const char *chbuf = spec->chbuf;
 
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+
        /*
         * When to fill with zeroes is of course not simple.
         * First: No zero fill if left-justifying.
@@ -2208,6 +2222,9 @@ format_nondecimal(uintmax_t val, struct format_spec 
*spec, struct print_fmt_buf
                spec->fw = spec->prec;
        spec->prec = CEND - CP;
        pr_num_tail(CP, spec->prec, spec, outb);
+
+#undef CP
+#undef CEND
 }
 
 
@@ -2230,7 +2247,7 @@ format_tree(
        long num_args)
 {
        size_t cur_arg = 0;
-       NODE *r = NULL;
+       NODE *retval = NULL;
        bool toofew = false;
        const char *s0, *s1;
        int cs1;
@@ -2247,6 +2264,12 @@ format_tree(
        struct print_fmt_buf *outb;
        struct format_spec spec;
 
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
+
+/* parse a single format specifier */
+#define do_parse_fmt   (num_args == LONG_MIN)
 
        /*
         * Check first for use of `count$'.
@@ -2257,7 +2280,9 @@ format_tree(
         * Otherwise, return the current argument.
         */
 #define parse_next_arg() { \
-       if (argnum > 0) { \
+       if (do_parse_fmt) \
+               goto out; \
+       else if (argnum > 0) { \
                if (cur_arg > 1) { \
                        msg(_("fatal: must use `count$' on all formats or 
none")); \
                        goto out; \
@@ -2384,6 +2409,8 @@ check_pos:
                                msg(_("fatal: `$' is not permitted in awk 
formats"));
                                goto out;
                        }
+                       if (do_parse_fmt)
+                               goto out;
 
                        if (cur == & spec.fw) {
                                argnum = spec.fw;
@@ -2532,6 +2559,7 @@ check_pos:
                        goto retry;
                case 'c':
                        need_format = false;
+                       spec.fmtchar = cs1;
                        parse_next_arg();
                        /* user input that looks numeric is numeric */
                        if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
@@ -2605,6 +2633,7 @@ out2:
                        goto pr_tail;
                case 's':
                        need_format = false;
+                       spec.fmtchar = cs1;
                        parse_next_arg();
                        arg = force_string(arg);
                        if (spec.fw == 0 && ! spec.have_prec)
@@ -2658,6 +2687,7 @@ out2:
                case 'i':
        fmt1:
                        need_format = false;
+                       spec.fmtchar = cs1;
                        parse_next_arg();
                        (void) force_number(arg);
                        spec.fmtchar = cs1;
@@ -2668,8 +2698,12 @@ out2:
                        break;
 
                default:
-                       if (do_lint && isalpha(cs1))
+                       if (isalpha(cs1)) {
+                               if (do_lint)
        lintwarn(_("ignoring unknown format specifier character `%c': no 
argument converted"), cs1);
+                               if (do_parse_fmt)
+                                       goto out;
+                       }
                        break;
                }
                if (toofew) {
@@ -2689,12 +2723,28 @@ out2:
        }
 
        bchunk(outb, s0, s1 - s0);
-       r = buf2node(outb);
+       retval = bytes2node(outb, NULL);
 out:
        free_fmt_buf(outb);
 
-       if (r == NULL)
-               gawk_exit(EXIT_FATAL);
-       return r;
+       if (do_parse_fmt) {
+               struct format_spec *cp_spec;
+
+               assert(retval == NULL);
+               if (spec.fmtchar == (char) 0)
+                       return NULL;
+               emalloc(cp_spec, struct format_spec *, sizeof (*cp_spec), 
"format_tree");
+               *cp_spec = spec;
+               return (NODE *) cp_spec;
+       }
+
+       if (retval == NULL)
+               gawk_exit(EXIT_FATAL);  /* debugger needs this */
+
+       return retval;
+
+#undef CP
+#undef CEND
+#undef CPBUF
 }
 
diff --git a/double.c b/double.c
index b5b7458..d127e3a 100644
--- a/double.c
+++ b/double.c
@@ -42,8 +42,6 @@ extern void srandom(unsigned long seed);
  */
 #define GAWK_RANDOM_MAX 0x7fffffffL
 
-extern NODE **fmt_list;          /* declared in eval.c */
-
 /* exported routines */
 
 static NODE *make_awknum(AWKNUM);
@@ -1005,10 +1003,18 @@ format_awknum_val(const char *format, int index, NODE 
*s)
         * < and > so that things work correctly on systems with 64 bit 
integers.
         */
 
+       if ((s->flags & STRCUR) != 0)
+               efree(s->stptr);
+       free_wstr(s);
+
+
        /* not an integral value, or out of range */
        if ((val = double_to_int(s->numbr)) != s->numbr
                        || val <= LONG_MIN || val >= LONG_MAX
        ) {
+               struct format_spec spec;
+               struct print_fmt_buf *outb;
+
                /*
                 * Once upon a time, we just blindly did this:
                 *      sprintf(sp, format, s->numbr);
@@ -1018,30 +1024,24 @@ format_awknum_val(const char *format, int index, NODE 
*s)
                 * and just always format the value ourselves.
                 */
 
-               NODE *dummy[2], *r;
-               unsigned int oflags;
-
-               /* create dummy node for a sole use of format_tree */
-               dummy[1] = s;
-               oflags = s->flags;
+               /* XXX: format_spec copied since can be altered in the 
formatting routine */
 
                if (val == s->numbr) {
                        /* integral value, but outside range of %ld, use %.0f */
-                       r = format_tree("%.0f", 4, dummy, 2);
+                       spec = *fmt_list[INT_0f_FMT_INDEX].spec;
                        s->stfmt = -1;
                } else {
-                       r = format_tree(format, fmt_list[index]->stlen, dummy, 
2);
-                       assert(r != NULL);
-                       s->stfmt = (char) index;
+                       assert(fmt_list[index].spec != NULL);   /* or can use 
fmt_parse() --- XXX */
+                       spec = *fmt_list[index].spec;
+                       s->stfmt = (char) index;        
                }
-               s->flags = oflags;
-               s->stlen = r->stlen;
-               if ((s->flags & STRCUR) != 0)
-                       efree(s->stptr);
-               s->stptr = r->stptr;
-               freenode(r);    /* Do not unref(r)! We want to keep s->stptr == 
r->stpr.  */
-
-               goto no_malloc;
+
+               outb = get_fmt_buf();
+               (void) format_awknum_printf(s, & spec, outb);
+               (void) bytes2node(outb, s);
+               free_fmt_buf(outb);
+
+               s->stptr[s->stlen] = '\0';
        } else {
                /*
                 * integral value; force conversion to long only once.
@@ -1060,14 +1060,12 @@ format_awknum_val(const char *format, int index, NODE 
*s)
                        s->flags &= ~(INTIND|NUMBER);
                        s->flags |= STRING;
                }
+
+               emalloc(s->stptr, char *, s->stlen + 2, "format_awknum_val");
+               memcpy(s->stptr, sp, s->stlen + 1);
        }
-       if (s->stptr != NULL)
-               efree(s->stptr);
-       emalloc(s->stptr, char *, s->stlen + 2, "format_awknum_val");
-       memcpy(s->stptr, sp, s->stlen + 1);
-no_malloc:
+       
        s->flags |= STRCUR;
-       free_wstr(s);
        return s;
 }
 
@@ -1507,4 +1505,7 @@ fmt1:
        }
 
        return -1;
+#undef CP
+#undef CEND
+#undef CPBUF
 }
diff --git a/eval.c b/eval.c
index b2cd797..537f26c 100644
--- a/eval.c
+++ b/eval.c
@@ -817,7 +817,7 @@ set_ORS()
 
 /* fmt_ok --- is the conversion format a valid one? */
 
-NODE **fmt_list = NULL;
+struct fmt_list_item *fmt_list = NULL;
 static int fmt_index(NODE *n);
 
 bool
@@ -859,18 +859,53 @@ static int
 fmt_index(NODE *n)
 {
        int ix = 0;
-       static int fmt_num = 4;
+       static int fmt_num = 6;
        static int fmt_hiwater = 0;
+       struct format_spec *spec = NULL;
+       extern struct format_spec *fmt_parse(NODE *, const char *, size_t);
+
+       /*
+        *      BEGIN { CONVFMT="%s"; print 1.1234567 "X" }
+        *      number -> force_string -> CONVFMT = %s -> force_string -> ...
+        */
+
+       if (fmt_list == NULL) {
+               NODE *t;
+
+               emalloc(fmt_list, struct fmt_list_item *, fmt_num * 
sizeof(*fmt_list), "fmt_index");
+
+               /*
+                * XXX: Insert "%d" and "%.0f" at known indices, used to 
convert integers.
+                * The indices are defined using `enum { INT_d_FMT_INDEX, 
INT_0f_FMT_INDEX }'
+                * in format.h;
+                * We want to avoid calling format_tree() directly in case the 
current
+                * number handler hasn't been initialized, or we need a 
different handler;
+                * may also be a bit more efficient.
+                */
+
+               t = make_string("%d", 2);
+               spec = fmt_parse(CONVFMT_node, t->stptr, t->stlen);
+               assert(spec != NULL);
+               fmt_list[fmt_hiwater].fmt = t;
+               fmt_list[fmt_hiwater].spec = spec;
+               fmt_hiwater++;
+
+               t = make_string("%.0f", 4);
+               spec = fmt_parse(CONVFMT_node, t->stptr, t->stlen);
+               assert(spec != NULL);
+               fmt_list[fmt_hiwater].fmt = t;
+               fmt_list[fmt_hiwater].spec = spec;
+               fmt_hiwater++;
+       }
 
-       if (fmt_list == NULL)
-               emalloc(fmt_list, NODE **, fmt_num*sizeof(*fmt_list), 
"fmt_index");
        n = force_string(n);
        while (ix < fmt_hiwater) {
-               if (cmp_nodes(fmt_list[ix], n) == 0)
+               if (cmp_nodes(fmt_list[ix].fmt, n) == 0)
                        return ix;
                ix++;
        }
        /* not found */
+
        n->stptr[n->stlen] = '\0';
        if (do_lint && ! fmt_ok(n->stptr))
                lintwarn(_("bad `%sFMT' specification `%s'"),
@@ -878,11 +913,23 @@ fmt_index(NODE *n)
                          : n == OFMT_node->var_value ? "O"
                          : "", n->stptr);
 
+       if (n == CONVFMT_node->var_value) {
+               /* XXX -- %s or %c not allowed for CONVFMT */
+               spec = fmt_parse(CONVFMT_node, n->stptr, n->stlen);
+               if (spec == NULL)
+                       fatal(_("invalid CONVFMT specification `%s'"), 
n->stptr);
+       } else if (n == OFMT_node->var_value) {
+               spec = fmt_parse(OFMT_node, n->stptr, n->stlen);
+               if (spec == NULL)
+                       fatal(_("invalid OFMT specification `%s'"), n->stptr);
+       }
+
        if (fmt_hiwater >= fmt_num) {
                fmt_num *= 2;
-               erealloc(fmt_list, NODE **, fmt_num * sizeof(*fmt_list), 
"fmt_index");
+               erealloc(fmt_list, struct fmt_list_item *, fmt_num * 
sizeof(*fmt_list), "fmt_index");
        }
-       fmt_list[fmt_hiwater] = dupnode(n);
+       fmt_list[fmt_hiwater].fmt = dupnode(n);
+       fmt_list[fmt_hiwater].spec = spec;
        return fmt_hiwater++;
 }
 
@@ -892,7 +939,7 @@ void
 set_OFMT()
 {
        OFMTidx = fmt_index(OFMT_node->var_value);
-       OFMT = fmt_list[OFMTidx]->stptr;
+       OFMT = fmt_list[OFMTidx].fmt->stptr;
 }
 
 /* set_CONVFMT --- track CONVFMT correctly */
@@ -901,7 +948,7 @@ void
 set_CONVFMT()
 {
        CONVFMTidx = fmt_index(CONVFMT_node->var_value);
-       CONVFMT = fmt_list[CONVFMTidx]->stptr;
+       CONVFMT = fmt_list[CONVFMTidx].fmt->stptr;
 }
 
 /* set_LINT --- update LINT as appropriate */
diff --git a/format.h b/format.h
index 1418a8b..74d6f51 100644
--- a/format.h
+++ b/format.h
@@ -1,3 +1,28 @@
+/*
+ * format.h - (s)printf formatting related definitions.
+ */
+
+/* 
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
 /* format specification */
 
 struct format_spec {
@@ -15,6 +40,10 @@ struct format_spec {
        char fmtchar;
 };
 
+/* indices in `fmt_index' for "%d" and "%.0f" */
+
+enum { INT_d_FMT_INDEX, INT_0f_FMT_INDEX };
+
 
 /* struct to manage awk (s)printf formatted string */
 
@@ -97,18 +126,21 @@ buf_adjust(struct print_fmt_buf *outb, size_t len)
        outb->room_left -= len;
 }
 
-/* buf2node --- convert bytes to string NODE */
+/* bytes2node --- convert bytes to string NODE */
 
 static inline NODE *
-buf2node(struct print_fmt_buf *outb)
+bytes2node(struct print_fmt_buf *outb, NODE *node)
 {
-       NODE *node;
-       node = make_str_node(outb->buf, outb->dataend - outb->buf, 
ALREADY_MALLOCED);
+       /* FIXME -- realloc buf? AFAIK, never done before or an issue at all -- 
JH */
+       if (node != NULL) {
+               node->stptr = outb->buf;
+               node->stlen = outb->dataend - outb->buf;
+       } else
+               node = make_str_node(outb->buf, outb->dataend - outb->buf, 
ALREADY_MALLOCED);
        outb->buf = NULL;
        return node;
 }
 
-
 /* tmpbuf_prepend --- prepend one byte to temporary buffer */
 
 static inline void
diff --git a/mpfr.c b/mpfr.c
index edb8fd7..f0b7c3f 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -46,8 +46,6 @@ typedef mp_exp_t mpfr_exp_t;
 #define DEFAULT_PREC           53
 #define DEFAULT_ROUNDMODE      "N"             /* round to nearest */
 
-extern NODE **fmt_list;          /* declared in eval.c */
-
 /* exported functions */
 static NODE *mpfp_make_number(AWKNUM);
 static int mpfp_compare(const NODE *, const NODE *);
@@ -99,7 +97,6 @@ static NODE *do_mpfp_srand(int);
 static NODE *do_mpfp_strtonum(int);
 static NODE *do_mpfp_xor(int);
 
-
 /* internal functions */
 static NODE *mpfp_make_node(unsigned int type);
 static int mpfp_format_ieee(mpfr_ptr, int);
@@ -108,7 +105,6 @@ static int mpfp_strtoui(mpz_ptr, char *, size_t, char **, 
int);
 static mpfr_rnd_t mpfp_get_rounding_mode(const char rmode);
 static mpfr_ptr mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val);
 
-
 static mpfr_rnd_t ROUND_MODE;
 static mpz_t MNR;
 static mpz_t MFNR;
@@ -602,35 +598,35 @@ mpfp_force_number(NODE *n)
 static NODE *
 mpfp_format_val(const char *format, int index, NODE *s)
 {
-       NODE *dummy[2], *r;
-       unsigned int oflags;
+       struct format_spec spec;
+       struct print_fmt_buf *outb;
+
+       if ((s->flags & STRCUR) != 0)
+               efree(s->stptr);
+       free_wstr(s);
 
-       /* create dummy node for a sole use of format_tree */
-       dummy[1] = s;
-       oflags = s->flags;
+       /* XXX: format_spec copied since can be altered in the formatting 
routine */
 
        if (is_mpfp_integer(s) || mpfr_integer_p(s->qnumbr)) {
                /* integral value, use %d */
-               r = format_tree("%d", 2, dummy, 2);
+               spec = *fmt_list[INT_d_FMT_INDEX].spec;
                s->stfmt = -1;
        } else {
-               r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
-               assert(r != NULL);
+               assert(fmt_list[index].spec != NULL);   /* or can use 
fmt_parse() --- XXX */
+               spec = *fmt_list[index].spec;
                s->stfmt = (char) index;
        }
-       s->flags = oflags;
-       s->stlen = r->stlen;
-       if ((s->flags & STRCUR) != 0)
-               efree(s->stptr);
-       s->stptr = r->stptr;
-       freenode(r);    /* Do not unref(r)! We want to keep s->stptr == 
r->stpr.  */
- 
-       s->flags |= STRCUR;
-       free_wstr(s);
+
+       outb = get_fmt_buf();
+       mpfp_format_printf(s, & spec, outb);
+       (void) bytes2node(outb, s);
+       free_fmt_buf(outb);
+
+       s->stptr[s->stlen] = '\0';
+       s->flags |= STRCUR;
        return s;
 }
 
-
 /* mpfp_str2node --- create an arbitrary-pecision number from string */
 
 static NODE *
@@ -968,8 +964,25 @@ mpfp_negate_num(NODE *n)
                int tval;
                tval = mpfr_neg(n->qnumbr, n->qnumbr, ROUND_MODE);
                IEEE_FMT(n->qnumbr, tval);
-       } else /* if (is_mpfp_integer(n)) */
-               mpz_neg(n->qnumbr, n->qnumbr);
+       } else {
+               /* GMP integer */
+               if (mpz_sgn(MPZ_T(n->qnumbr)) == 0) {
+                       /*
+                        * The result should be -0.0, a float.
+                        * XXX: atan2(0, -0) is PI not 0.
+                        */ 
+                       mpz_clear(n->qnumbr);
+                       efree(n->qnumbr);
+                       n->flags &= ~MPZN;
+                       emalloc(n->qnumbr, void *, sizeof (mpfr_t), 
"mpfp_negate_num");
+                       mpfr_init(n->qnumbr);
+                       n->flags |= MPFN;
+
+                       /* XXX: assuming IEEE 754 double, or could use 
mpfr_set_str(op, "-0.0", ...) */
+                       mpfr_set_d(n->qnumbr, -0.0, ROUND_MODE);
+               } else
+                       mpz_neg(n->qnumbr, n->qnumbr);
+       }
 }
 
 /* do_mpfp_atan2 --- do the atan2 function */
@@ -1797,7 +1810,6 @@ mpfp_format_printf(NODE *arg, struct format_spec *spec, 
struct print_fmt_buf *ou
        char *cp;
        char cs1;
        int nc;
-       /* const char *chbuf; */
 
 #      define CP               cpbuf_start(outb)
 #      define CEND             cpbuf_end(outb)
@@ -1849,56 +1861,53 @@ mpz0:
                        mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
                        goto fmt0;
 
-               } else {
-                       assert(is_mpfp_float(arg) == true);
+               }
+
+               assert(is_mpfp_float(arg) == true);
 mpf0:
-                       mf = arg->qnumbr;
-                       if (! mpfr_number_p(mf)) {
-                               /* inf or NaN */
-                               cs1 = 'g';
-                               mpfmt_spec = MP_FLOAT;
-                               goto fmt1;
-                       }
+               mf = arg->qnumbr;
+               if (! mpfr_number_p(mf)) {
+                       /* inf or NaN */
+                       cs1 = 'g';
+                       mpfmt_spec = MP_FLOAT;
+                       goto fmt1;
+               }
 
-                       if (cs1 != 'd' && cs1 != 'i') {
+               if (cs1 != 'd' && cs1 != 'i') {
 mpf1:
-                               /*
-                                * The output of printf("%#.0x", 0) is 0 
instead of 0x, hence <= in
-                                * the comparison below.
-                                */
-                               if (mpfr_sgn(mf) <= 0) {
-                                       if (! mpfr_fits_intmax_p(mf, 
ROUND_MODE)) {
-                                               /* -ve number is too large */
-                                               cs1 = 'g';
-                                               mpfmt_spec = MP_FLOAT;
-                                               goto fmt1;
-                                       }
-
-                                       uval = (uintmax_t) mpfr_get_sj(mf, 
ROUND_MODE);
-                                       if (! spec->alt && spec->have_prec && 
spec->prec == 0 && uval == 0) {
-                                               /* printf("%.0x", 0) is no 
characters */
-                                               pr_num_tail(cp, 0, spec, outb);
-                                               return 0;
-                                       }
-
-                                       /* spec->fmtchar = cs1; */
-                                       /* spec->chbuf = chbuf; */
-                                       format_nondecimal(uval, spec, outb);
-                                       return 0;
+                       /*
+                        * The output of printf("%#.0x", 0) is 0 instead of 0x, 
hence <= in
+                        * the comparison below.
+                        */
+                       if (mpfr_sgn(mf) <= 0) {
+                               if (! mpfr_fits_intmax_p(mf, ROUND_MODE)) {
+                                       /* -ve number is too large */
+                                       cs1 = 'g';
+                                       mpfmt_spec = MP_FLOAT;
+                                       goto fmt1;
                                }
-                               spec->signchar = '\0';  /* Don't print '+' */
+
+                               uval = (uintmax_t) mpfr_get_sj(mf, ROUND_MODE);
+                               if (! spec->alt && spec->have_prec && 
spec->prec == 0 && uval == 0) {
+                                       /* printf("%.0x", 0) is no characters */
+                                       pr_num_tail(cp, 0, spec, outb);
+                               } else
+                                       format_nondecimal(uval, spec, outb);
+                               return 0;
                        }
+                       spec->signchar = '\0';  /* Don't print '+' */
+               }
 
-                       /* See comments above about when to fill with zeros */
-                       spec->zero_flag = (! spec->lj
-                                           && ((spec->zero_flag && ! 
spec->have_prec)
-                                                || (spec->fw == 0 && 
spec->have_prec)));
+               /* See comments above about when to fill with zeros */
+               spec->zero_flag = (! spec->lj
+                                   && ((spec->zero_flag && ! spec->have_prec)
+                                        || (spec->fw == 0 && 
spec->have_prec)));
                        
-                       (void) mpfr_get_z(_mpzval, mf, MPFR_RNDZ);      /* 
convert to GMP integer */
-                       mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
-                       zi = _mpzval;
-                       goto fmt0;
-               }
+               (void) mpfr_get_z(_mpzval, mf, MPFR_RNDZ);      /* convert to 
GMP integer */
+               mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
+               zi = _mpzval;
+               goto fmt0;
+
 
 #if 0
 out_of_range:
@@ -1960,19 +1969,19 @@ fmt0:
                case MP_INT_WITH_PREC:
                        sprintf(cp, "*.*Z%c", cs1);
                        while ((nc = mpfr_snprintf(buf_end(outb), 
buf_space(outb), CPBUF,
-                                       (int) spec->fw, (int) spec->prec, zi)) 
>= buf_space(outb))
+               (int) spec->fw, (int) spec->prec, zi)) >= buf_space(outb))
                                chksize(outb, nc + 1);
                        break;
                case MP_INT_WITHOUT_PREC:
                        sprintf(cp, "*Z%c", cs1);
                        while ((nc = mpfr_snprintf(buf_end(outb), 
buf_space(outb), CPBUF,
-                                       (int) spec->fw, zi)) >= buf_space(outb))
+               (int) spec->fw, zi)) >= buf_space(outb))
                                chksize(outb, nc + 1);
                        break;
                case MP_FLOAT:
                        sprintf(cp, "*.*R*%c", cs1);
                        while ((nc = mpfr_snprintf(buf_end(outb), 
buf_space(outb), CPBUF,
-                                       (int) spec->fw, (int) spec->prec, 
ROUND_MODE, mf)) >= buf_space(outb))
+               (int) spec->fw, (int) spec->prec, ROUND_MODE, mf)) >= 
buf_space(outb))
                                chksize(outb, nc + 1);
                        break;
                default:
@@ -1992,8 +2001,11 @@ fmt0:
        }
 
        return -1;
-}
 
+#undef CP
+#undef CEND
+#undef CPBUF
+}
 
 #else
 

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=549fa6fcb6633c2e99c6853735443f4ae2880c5e

commit 549fa6fcb6633c2e99c6853735443f4ae2880c5e
Merge: 5690aed d898d83
Author: John Haque <address@hidden>
Date:   Sun Jan 6 09:08:28 2013 -0600

    Merge branch 'num-handler' into long-double


http://git.sv.gnu.org/cgit/gawk.git/commit/?id=d898d83434007253f314c8f3fabcb2686820026a

commit d898d83434007253f314c8f3fabcb2686820026a
Author: John Haque <address@hidden>
Date:   Sun Jan 6 09:01:49 2013 -0600

    Add repl_math.awk file.

diff --git a/awklib/ChangeLog b/awklib/ChangeLog
index 98bdc3d..178ce8b 100644
--- a/awklib/ChangeLog
+++ b/awklib/ChangeLog
@@ -1,3 +1,7 @@
+2013-01-06         John Haque            <address@hidden>
+
+       * eg/lib/repl_math.awk: New file.
+
 2012-12-24         Arnold D. Robbins     <address@hidden>
 
        * 4.0.2: Release tar ball made.
diff --git a/awklib/eg/lib/repl_math.awk b/awklib/eg/lib/repl_math.awk
new file mode 100644
index 0000000..a57be27
--- /dev/null
+++ b/awklib/eg/lib/repl_math.awk
@@ -0,0 +1,294 @@
+# repl_math.awk --- arbitrary-precision math functions
+
+#
+#      repl_sin        -- Compute sin(x)
+#      repl_cos        -- Compute cos(x)
+#      repl_atan2      -- Compute atan2(y, x)
+#
+
+#
+# Machin's formula to compute pi 
(http://mathworld.wolfram.com/MachinsFormula.html):
+#      pi / 4 = 4 acot(5) - acot(239)
+#            = 4 atan(1/5) - atan(1/239)
+#
+# Euler atan formula (http://mathworld.wolfram.com/InverseTangent.html):
+#      atan(x) = (y/x) (1 + 2/3 y + (2·4)/(3·5) y^2 + (2·4·6)/(3·5·7) 
y^3 +...)
+# where
+#      y = (x^2) / (1 + x^2) and -1 <= x <= 1
+#
+# Substituting x = 1/x, for x >= 1
+#      atan(1/x) = (1 / (1 + x^2))    + (2/3) * (1 / (1 + x^2)^2)
+#                                     + (2*4/(3*5)) * (1 / (1 + x^2)^3)
+#                                     + (2*4*6/(3*5*7)) * (1 / (1 + x^2)^4)  + 
... 
+#
+
+function euler_atan_one_over(x,        \
+               xpow2_plus_one, term, sum, i, err)
+{
+       xpow2_plus_one = x * x + 1
+       term = x / xpow2_plus_one
+       sum = term
+       i = 0
+       err = 1.0
+
+       while (err > __EPSILON__) {
+               term *= (i + 2) / (i + 3)
+               err = term /= xpow2_plus_one
+               i += 2
+               sum += term
+               if (err < 0)
+                       err = -err
+       }
+       return sum
+}
+
+function setup_repl_math( \
+               prec, digits, extra_prec)
+{
+       switch (PREC) {
+       case "half":    prec = 11; break;
+       case "single":  prec = 24; break;
+       case "double":  prec = 53; break;
+       case "quad":    prec = 113; break;
+       case "oct":     prec = 237; break;
+       default:        prec = PREC + 0;
+       }
+
+       if (prec <= 0) {
+               # double or long double ?
+               print "PREC value not specified" > "/dev/stderr"
+               exit(1)
+       }
+       __SAVE_PREC__ = PREC
+       extra_prec = 10
+       prec += extra_prec      # temporarily raise precision
+       if (prec != __PI_PREC__) {
+               # compute PI only once for a given precision
+               digits = int ((prec - extra_prec) / 3.32193)
+               __EPSILON__ = sprintf("1.0e-%d", digits + 2) + 0
+               __PI_OVER_4__ = 4 * euler_atan_one_over(5) - 
euler_atan_one_over(239)
+               __PI_PREC__ = prec
+       }
+}
+
+#
+# atan2(y, x) =        atan(y/x),              x > 0
+#             =        atan(y/x) + pi,         x < 0, y >= 0
+#             = atan(y/x) - pi,                x < 0, y < 0
+#             = pi/2,                  x = 0, y > 0
+#             = -pi/2,                 x = 0, y < 0
+#             = ?                      x = 0, y = 0
+#
+
+function euler_atan2(y, x,     \
+               sign, plus_inf, minus_inf)
+{
+       # Using Euler atan(1/x) and the identity:
+       #       atan(x) = - pi / 2 - atan(1/x),         x < 0
+       #               = pi / 2 - atan(1/x),           x > 0
+
+       plus_inf = "+inf" + 0
+       minus_inf = "-inf" + 0
+
+       # detect all the "abnormal" cases first
+       x = + x                 # or x += 0.0 or x = x + 0.0
+       y = + y
+       if (x == "+nan" + 0 || x == "-nan" + 0 ||
+                       y == "+nan" + 0 || y == "-nan" + 0)
+               return "nan" + 0
+
+       if (y == plus_inf) {
+               if (x == minus_inf)
+                       return 3 * __PI_OVER_4__
+               else if (x == plus_inf)
+                       return __PI_OVER_4__
+               else
+                       return 2 * __PI_OVER_4__
+       } else if (y == minus_inf) {
+               if (x == minus_inf)
+                       return - 3 * __PI_OVER_4__
+               else if (x == plus_inf)
+                       return - __PI_OVER_4__
+               else
+                       return - 2 * __PI_OVER_4__
+       }
+
+       if (x == plus_inf)
+               return atan2(y, x)      # use builtin, -0 or -0
+       if (x == minus_inf) {
+               if (y >= 0)
+                       return 4 * __PI_OVER_4__
+               # y < 0
+               return - 4 * __PI_OVER_4__
+       }
+
+       if (x > 0) {
+               if (y == 0)
+                       return atan2(y, x);     # use builtin; returns +0 or -0
+               sign = 1
+               if (y < 0) {
+                       sign = -1
+                       y = -y
+               }
+               if (y > x)
+                       return sign * (2 * __PI_OVER_4__ - 
euler_atan_one_over(y / x))
+               return sign * euler_atan_one_over(x / y)
+       } else if (x < 0) {
+               if (y == 0) {
+                       if (atan2(y, x) < 0)    # use builtin to detect sign
+                               return - 4 * __PI_OVER_4__
+                       return 4 * __PI_OVER_4__
+               }
+
+               if (y < 0) {
+                       y = -y
+                       x = -x
+                       if (y > x)
+                               return - 2 * __PI_OVER_4__ - 
euler_atan_one_over(y / x)
+                       return euler_atan_one_over(x / y) - 4 * __PI_OVER_4__
+               }
+               # y > 0
+               x = -x
+               if (y > x)
+                       return 2 * __PI_OVER_4__ + euler_atan_one_over(y / x)
+               return - euler_atan_one_over(x / y) + 4 * __PI_OVER_4__
+       }
+
+       # x == +0/-0 and y == +0/-0
+       return atan2(y, x);     # use builtin
+}
+
+
+function taylor_sin(x, \
+               i, fact, xpow2, xpow_odd, sum, term, sign, err)
+{
+       i = 1
+       fact = 1
+       xpow2 = x * x
+       xpow_odd = x
+       sum = x
+       sign = 1
+       err = 1.0
+
+       while (err > __EPSILON__) {
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_odd *= xpow2
+               sign *= -1
+               err = term = xpow_odd / fact  * sign
+               sum += term
+               if (err < 0)
+                       err = -err
+       }
+       return sum
+}
+
+function taylor_cos(x, \
+               i, fact, xpow2, xpow_even, sum, term, sign, err)
+{
+       i = 0
+       fact = 1
+       xpow2 = x * x
+       xpow_even = 1
+       sum = 1
+       sign = 1
+       err = 1.0
+
+       while (err > __EPSILON__) {
+               fact *= (i + 1) * (i + 2)
+               i += 2
+               xpow_even *= xpow2
+               sign *= -1
+               err = term = xpow_even / fact * sign
+               sum += term
+               if (err < 0)
+                       err = -err
+       }
+       return sum
+}
+
+#
+# For 0 <= x <= PI/4, using Taylor series approximation for sin(x):
+#      x - x^3/5! + x^5/7! - ...
+#
+# for PI/4 < x <= PI/2, use identity sin(x) = cos(PI/2 - x).
+#
+#
+
+function repl_sin(x,   \
+               k, sign, y, sv)
+{
+       setup_repl_math()
+       x = + x         # or x += 0.0 or x = x + 0.0 
+       if (x == "+inf" + 0 || x == "-inf" + 0 ||
+                       x == "+nan" + 0 || x == "-nan" + 0)
+               return "nan" + 0
+
+       if (x < 0) {
+               # sin(x) = - sin(x)
+               sign = -1
+               x = -x
+       } else
+               sign = 1
+
+       # range reduction -- 0 <= y <= pi / 4
+
+       k = int(x / __PI_OVER_4__)
+       sign *= ( int(k / 4) % 2 ? -1 : 1 )
+       switch (k % 4) {
+       case 0: y = x - k * __PI_OVER_4__; sv = taylor_sin(y); break;
+       case 1: y = (k + 1) * __PI_OVER_4__ - x; sv = taylor_cos(y); break;
+       case 2: y = x - k * __PI_OVER_4__; sv = taylor_cos(y); break;
+       case 3: y = (k + 1) * __PI_OVER_4__ - x; sv = taylor_sin(y); break;
+       }
+       sv *= sign
+
+       PREC = __SAVE_PREC__
+       return +sv;     # unary plus returns a number with current precision 
+}
+
+#
+# Using Taylor series approximation for sin(x) for 0 <= x <= PI/4:
+#      1 - x^2/2! + x^4/4! - ...
+# for PI/4 < x < PI/2, use identity cos(x) = sin(PI/2 - x).
+#
+
+
+function repl_cos(x,   \
+               k, sign, y, cv)
+{
+       setup_repl_math()
+
+       x = + x         # or x += 0.0 or x = x + 0.0
+       if (x == "+inf" + 0 || x == "-inf" + 0 ||
+                       x == "+nan" + 0 || x == "-nan" + 0)
+               return "nan" + 0
+
+       if (x < 0)      # cos(x) = cos(-x)
+               x = -x
+
+       # range reduction -- 0 <= y <= pi / 4
+
+       k = int(x / __PI_OVER_4__)
+       sign = ( int(k / 4) % 2 ? -1 : 1 )
+       switch (k % 4) {
+       case 0: y = x - k * __PI_OVER_4__; cv = taylor_cos(y); break;
+       case 1: y = (k + 1) * __PI_OVER_4__ - x; cv = taylor_sin(y); break;
+       case 2: y = x - k * __PI_OVER_4__; cv = -taylor_sin(y); break;
+       case 3: y = (k + 1) * __PI_OVER_4__ - x; cv = -taylor_cos(y); break;
+       }
+       cv *= sign
+
+       PREC = __SAVE_PREC__
+       return +cv      # unary plus to apply current precision
+}
+
+function repl_atan2(y, x, \
+               tv)
+{
+       setup_repl_math()
+       tv = euler_atan2(y, x)
+
+       PREC = __SAVE_PREC__
+       return +tv      # unary plus to apply current precision
+}

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=5089b03ccc67b6a5399a852b6d9acee8f20349a2

commit 5089b03ccc67b6a5399a852b6d9acee8f20349a2
Author: John Haque <address@hidden>
Date:   Sun Jan 6 08:51:19 2013 -0600

    Fix bug in GMP to MPFR number conversion.

diff --git a/mpfr.c b/mpfr.c
index e3215c9..edb8fd7 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -1737,7 +1737,7 @@ mpfp_sprintf(const char *mesg, ...)
 static mpfr_ptr
 mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val)
 {
-       size_t prec;
+       long prec, prec1;
        int tval;
 
        /*
@@ -1755,10 +1755,10 @@ mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val)
        /* estimate minimum precision for exact conversion */
        prec = mpz_sizeinbase(mpz_val, 2);      /* most significant 1 bit 
position starting at 1 */
 
-       if (mpfr_val != NULL && mpfr_get_prec(mpfr_val) >= prec)
+       if (mpfr_val != NULL && (prec1 = mpfr_get_prec(mpfr_val)) >= prec)
                goto finish;
 
-       prec -= (size_t) mpz_scan1(mpz_val, 0); /* least significant 1 bit 
index starting at 0 */
+       prec -= (long) mpz_scan1(mpz_val, 0);   /* least significant 1 bit 
index starting at 0 */
        if (prec < MPFR_PREC_MIN)
                prec = MPFR_PREC_MIN;
        else if (prec > MPFR_PREC_MAX)
@@ -1767,10 +1767,11 @@ mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val)
        if (mpfr_val == NULL) {
                emalloc(mpfr_val, mpfr_ptr, sizeof (mpfr_t), "mpz2mpfr");
                mpfr_init2(mpfr_val, prec);
-       } else if (prec < mpfr_get_prec(mpfr_val))
+       } else if (prec > prec1)
                mpfr_set_prec(mpfr_val, prec);
 
 finish:
+
        tval = mpfr_set_z(mpfr_val, mpz_val, ROUND_MODE);
        IEEE_FMT(mpfr_val, tval);
        return mpfr_val;

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=5690aed667670bd5f8dead3db885c9185d9e7dfc

commit 5690aed667670bd5f8dead3db885c9185d9e7dfc
Merge: e3a7f11 9d7c03c
Author: John Haque <address@hidden>
Date:   Thu Jan 3 05:33:12 2013 -0600

    Merge branch 'num-handler' into long-double


http://git.sv.gnu.org/cgit/gawk.git/commit/?id=9d7c03c2c55d28d9664881eff0a5e11b030cc67c

commit 9d7c03c2c55d28d9664881eff0a5e11b030cc67c
Author: John Haque <address@hidden>
Date:   Thu Jan 3 05:31:26 2013 -0600

    Update TODO.NUMH, add format.h to the list in Makefile.am.

diff --git a/Makefile.am b/Makefile.am
index 7a1b530..5346454 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -99,6 +99,7 @@ base_sources = \
        field.c \
        floatcomp.c \
        floatmagic.h \
+       format.h \
        gawkapi.c \
        gawkapi.h \
        gawkmisc.c \
diff --git a/Makefile.in b/Makefile.in
index 71df2f0..20c3a19 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -428,6 +428,7 @@ base_sources = \
        field.c \
        floatcomp.c \
        floatmagic.h \
+       format.h \
        gawkapi.c \
        gawkapi.h \
        gawkmisc.c \
diff --git a/TODO.NUMH b/TODO.NUMH
index c612bd5..838b0f9 100644
--- a/TODO.NUMH
+++ b/TODO.NUMH
@@ -1 +1,16 @@
-* put back constant-folding code for numbers
+* (Further) refactoring (s)printf formatting code:
+
+  [1] Remove direct calls to format_tree() in number to string (force_string)
+routines. Fix CONVFMT = "%s"/"%c" crash; present in all known gawk versions.
+Cache parsed format code in fmt_idx() ... 
+
+  [2] Try to format NaN/inf in main gawk code, and not in the individual 
handlers.
+
+* In non-number related routines (substr, index, ..), fetch an integer directly
+using get_number_si/get_number_ui to get the correct size at the int 
boundaries.
+Use isinteger() to test for a floating-point value instead of get_number_d() 
and ...
+May require additional tests e.g. SIZE_MAX <= UINT_MAX. In a nutshell, don't 
do this:
+
+                       number => double => integer
+
+* Restore constant-folding code for numbers.

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=e3a7f11e4c7aab2fbc1b77e2925e2254a6cde266

commit e3a7f11e4c7aab2fbc1b77e2925e2254a6cde266
Author: John Haque <address@hidden>
Date:   Wed Jan 2 19:13:52 2013 -0600

    Update long_double.c for changes in formatting routine.

diff --git a/long_double.c b/long_double.c
index 714dafc..e5a5261 100644
--- a/long_double.c
+++ b/long_double.c
@@ -30,6 +30,9 @@
 #include "random.h"
 #include "floatmagic.h"        /* definition of isnan */
 
+#include "format.h"
+
+
 #define AWKLDBL        long double
 
 /* XXX: define to 1 to try AWKNUM as long double */
@@ -78,12 +81,14 @@ static NODE *force_awkldbl(NODE *);
 static NODE *format_awkldbl_val(const char *, int, NODE *);
 static unsigned long awkldbl_toulong(const NODE *);
 static long awkldbl_tolong(const NODE *);
-static AWKNUM awkldbl_todouble(const NODE *);
+static double awkldbl_todouble(const NODE *);
 static uintmax_t awkldbl_touintmax_t(const NODE *);
 static int awkldbl_sgn(const NODE *);
-static bool awkldbl_is_integer(const NODE *);
+static bool awkldbl_isinteger(const NODE *);
+static bool awkldbl_isnan(const NODE *);
+static bool awkldbl_isinf(const NODE *);
 static NODE *awkldbl_copy(const NODE *);
-static NODE *format_nodes_awkldbl(const char *, size_t, NODE **, long);
+static int format_awkldbl_printf(NODE *, struct format_spec *, struct 
print_fmt_buf *);
 static bool awkldbl_init(bltin_t **);
 static NODE *awkldbl_add(const NODE *, const NODE *);
 static NODE *awkldbl_sub(const NODE *, const NODE *);
@@ -155,9 +160,11 @@ numbr_handler_t awkldbl_hndlr = {
        negate_awkldbl,
        cmp_awkldbls,
        awkldbl_sgn,
-       awkldbl_is_integer,
+       awkldbl_isinteger,
+       awkldbl_isnan,
+       awkldbl_isinf,
        format_awkldbl_val,
-       format_nodes_awkldbl,
+       format_awkldbl_printf,
        awkldbl_todouble,
        awkldbl_tolong,
        awkldbl_toulong,
@@ -231,9 +238,9 @@ awkldbl_tolong(const NODE *n)
        return LDBL(n);
 }
 
-/* awkldbl_todouble --- conversion to AWKNUM */
+/* awkldbl_todouble --- conversion to double */
 
-static AWKNUM
+static double
 awkldbl_todouble(const NODE *n)
 {
        return LDBL(n);
@@ -256,10 +263,10 @@ awkldbl_sgn(const NODE *n)
        return (d < 0.0 ? -1 : d > 0.0);
 }
 
-/* awkldbl_is_integer --- check if a number is an integer */
+/* awkldbl_isinteger --- check if a number is an integer */
 
 static bool
-awkldbl_is_integer(const NODE *n)
+awkldbl_isinteger(const NODE *n)
 {
        AWKLDBL d = LDBL(n);
 
@@ -268,6 +275,22 @@ awkldbl_is_integer(const NODE *n)
        return double_to_int(d) == d;
 }
 
+/* awkldbl_isnan --- check if number is NaN */
+
+static bool
+awkldbl_isnan(const NODE *n)
+{
+       return isnan(LDBL(n));
+}
+
+/* awkldbl_isinf --- check if number is infinity */
+
+static bool
+awkldbl_isinf(const NODE *n)
+{
+       return isinf(LDBL(n));
+}
+
 /* negate_awkldbl --- negate number in NODE */
 
 static void
@@ -1394,835 +1417,233 @@ do_strtonum(int nargs)
        return make_awkldbl(d);
 }
 
+/* format_awkldbl_prinf --- format a number for (s)printf */
 
-/*
- * format_tree() formats arguments of sprintf,
- * and accordingly to a fmt_string providing a format like in
- * printf family from C library.  Returns a string node which value
- * is a formatted string.  Called by  sprintf function.
- *
- * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
- * for taming this beast and making it compatible with ANSI C.
- */
-
-static NODE *
-format_nodes_awkldbl(
-       const char *fmt_string,
-       size_t n0,
-       NODE **the_args,
-       long num_args)
+static int
+format_awkldbl_printf(NODE *arg, struct format_spec *spec, struct 
print_fmt_buf *outb)
 {
-/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
-/* difference of pointers should be of ptrdiff_t type, but let us be kind */
-#define bchunk(s, l) if (l) { \
-       while ((l) > ofre) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       memcpy(obufout, s, (size_t) (l)); \
-       obufout += (l); \
-       ofre -= (l); \
-}
+       AWKLDBL tmpval;
+       uintmax_t uval;
+       bool sgn;
+       int i, ii, jj;
+       char *chp, *cp;
+       char cs1;
+       int nc;
+
+       static char stackbuf[64];       /* temporary buffer for integer 
formatting */ 
+       static char *intbuf = stackbuf;
+       size_t intbuf_size = 64;
+
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
+
+       tmpval = LDBL(arg);
+       spec->fill = space_string;
+       spec->chbuf = lchbuf;
+
+       cp = CP;
+       cs1 = spec->fmtchar;
+       switch (cs1) {
+       case 'd':
+       case 'i':
+               if (isnan(tmpval) || isinf(tmpval))
+                       goto out_of_range;
+               else
+                       tmpval = double_to_int(tmpval);
 
-/* copy one byte from 's' to 'obufout' checking for space in the process */
-#define bchunk_one(s) { \
-       if (ofre < 1) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       *obufout++ = *s; \
-       --ofre; \
-}
+               /*
+                * ``The result of converting a zero value with a
+                * precision of zero is no characters.''
+                */
+               if (spec->have_prec && spec->prec == 0 && tmpval == (AWKLDBL) 
0) {
+                       pr_num_tail(cp, spec->prec, spec, outb);
+                       return 0;
+               }
 
-/* Is there space for something L big in the buffer? */
-#define chksize(l)  if ((l) >= ofre) { \
-       size_t olen = obufout - obuf; \
-       size_t delta = osiz+l-ofre; \
-       erealloc(obuf, char *, osiz + delta, "format_tree"); \
-       obufout = obuf + olen; \
-       ofre += delta; \
-       osiz += delta; \
-}
+               if (tmpval < 0) {
+                       tmpval = -tmpval;
+                       sgn = true;
+               } else {
+                       if (tmpval == - (AWKLDBL) 0.0)  /* avoid printing -0 */
+                               tmpval = (AWKLDBL) 0.0;
+                       sgn = false;
+               }
 
-       size_t cur_arg = 0;
-       NODE *r = NULL;
-       int i, nc;
-       bool toofew = false;
-       char *obuf, *obufout;
-       size_t osiz, ofre;
-       const char *chbuf;
-       const char *s0, *s1;
-       int cs1;
-       NODE *arg;
-       long fw, prec, argnum;
-       bool used_dollar;
-       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
-       long *cur = NULL;
-       uintmax_t uval;
-       bool sgn;
-       int base;
-       /*
-        * Although this is an array, the elements serve two different
-        * purposes. The first element is the general buffer meant
-        * to hold the entire result string.  The second one is a
-        * temporary buffer for large floating point values. They
-        * could just as easily be separate variables, and the
-        * code might arguably be clearer.
-        */
-       struct {
-               char *buf;
-               size_t bufsize;
-               char stackbuf[30];
-       } cpbufs[2];
-#define cpbuf  cpbufs[0].buf
-       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
-       char *cp;
-       const char *fill;
-       AWKLDBL tmpval = 0.0;
-       char signchar = '\0';
-       size_t len;
-       bool zero_flag = false;
-       bool quote_flag = false;
-       int ii, jj;
-       char *chp;
-       size_t copy_count, char_count;
-
-       static const char sp[] = " ";
-       static const char zero_string[] = "0";
-       static const char lchbuf[] = "0123456789abcdef";
-       static const char Uchbuf[] = "0123456789ABCDEF";
-
-#define INITIAL_OUT_SIZE       512
-       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
-       obufout = obuf;
-       osiz = INITIAL_OUT_SIZE;
-       ofre = osiz - 2;
-
-       cur_arg = 1;
-
-       {
-               size_t k;
-               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
-                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
-                       cpbufs[k].buf = cpbufs[k].stackbuf;
+               /*
+                * Use snprintf return value to tell if there
+                * is enough room in the buffer or not.
+                */
+               while ((i = snprintf(intbuf, intbuf_size, "%.0Lf", tmpval)) >= 
intbuf_size) {
+                       if (intbuf == stackbuf)
+                               intbuf = NULL;
+                       intbuf_size = i + 1;
+                       erealloc(intbuf, char *, intbuf_size, "format_tree");
                }
-       }
 
-       /*
-        * The point of this goop is to grow the buffer
-        * holding the converted number, so that large
-        * values don't overflow a fixed length buffer.
-        */
-#define PREPEND(CH) do {       \
-       if (cp == cpbufs[0].buf) {      \
-               char *prev = cpbufs[0].buf;     \
-               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
-                       "format_tree"); \
-               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
-                      cpbufs[0].bufsize);      \
-               cpbufs[0].bufsize *= 2; \
-               if (prev != cpbufs[0].stackbuf) \
-                       efree(prev);    \
-               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
-       }       \
-       *--cp = (CH);   \
-} while(0)
+               if (i < 1)
+                       goto out_of_range;
 
-       /*
-        * Check first for use of `count$'.
-        * If plain argument retrieval was used earlier, choke.
-        *      Otherwise, return the requested argument.
-        * If not `count$' now, but it was used earlier, choke.
-        * If this format is more than total number of args, choke.
-        * Otherwise, return the current argument.
-        */
-#define parse_next_arg() { \
-       if (argnum > 0) { \
-               if (cur_arg > 1) { \
-                       msg(_("fatal: must use `count$' on all formats or 
none")); \
-                       goto out; \
-               } \
-               arg = the_args[argnum]; \
-       } else if (used_dollar) { \
-               msg(_("fatal: must use `count$' on all formats or none")); \
-               arg = 0; /* shutup the compiler */ \
-               goto out; \
-       } else if (cur_arg >= num_args) { \
-               arg = 0; /* shutup the compiler */ \
-               toofew = true; \
-               break; \
-       } else { \
-               arg = the_args[cur_arg]; \
-               cur_arg++; \
-       } \
-}
+               chp = & intbuf[i-1];
+               ii = jj = 0;
+               do {
+                       tmpbuf_prepend(outb, *chp);
+                       chp--; i--;
+#if defined(HAVE_LOCALE_H)
+                       if (spec->quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
+                               if (i)  /* only add if more digits coming */
+                                       tmpbuf_prepend(outb, 
loc.thousands_sep[0]);     /* XXX - assumption it's one char */
+                               if (loc.grouping[ii+1] == 0)
+                                       jj = 0;         /* keep using current 
val in loc.grouping[ii] */
+                               else if (loc.grouping[ii+1] == CHAR_MAX)
+                                       spec->quote_flag= false;
+                               else {                 
+                                       ii++;
+                                       jj = 0;
+                               }
+                       }
+#endif
+               } while (i > 0);
 
-       need_format = false;
-       used_dollar = false;
 
-       s0 = s1 = fmt_string;
-       while (n0-- > 0) {
-               if (*s1 != '%') {
-                       s1++;
-                       continue;
+               /* add more output digits to match the precision */
+               if (spec->have_prec) {
+                       while (CEND - CP < spec->prec)
+                               tmpbuf_prepend(outb, '0');
                }
-               need_format = true;
-               bchunk(s0, s1 - s0);
-               s0 = s1;
-               cur = &fw;
-               fw = 0;
-               prec = 0;
-               base = 0;
-               argnum = 0;
-               base = 0;
-               have_prec = false;
-               signchar = '\0';
-               zero_flag = false;
-               quote_flag = false;
-               lj = alt = big_flag = bigbig_flag = small_flag = false;
-               fill = sp;
-               cp = cend;
-               chbuf = lchbuf;
-               s1++;
-
-retry:
-               if (n0-- == 0)  /* ran out early! */
-                       break;
-
-               switch (cs1 = *s1++) {
-               case (-1):      /* dummy case to allow for checking */
-check_pos:
-                       if (cur != & fw)
-                               break;          /* reject as a valid format */
-                       goto retry;
-               case '%':
-                       need_format = false;
-                       /*
-                        * 29 Oct. 2002:
-                        * The C99 standard pages 274 and 279 seem to imply that
-                        * since there's no arg converted, the field width 
doesn't
-                        * apply.  The code already was that way, but this
-                        * comment documents it, at least in the code.
-                        */
-                       if (do_lint) {
-                               const char *msg = NULL;
-
-                               if (fw && ! have_prec)
-                                       msg = _("field width is ignored for 
`%%' specifier");
-                               else if (fw == 0 && have_prec)
-                                       msg = _("precision is ignored for `%%' 
specifier");
-                               else if (fw && have_prec)
-                                       msg = _("field width and precision are 
ignored for `%%' specifier");
-
-                               if (msg != NULL)
-                                       lintwarn("%s", msg);
-                       }
-                       bchunk_one("%");
-                       s0 = s1;
-                       break;
-
-               case '0':
-                       /*
-                        * Only turn on zero_flag if we haven't seen
-                        * the field width or precision yet.  Otherwise,
-                        * screws up floating point formatting.
-                        */
-                       if (cur == & fw)
-                               zero_flag = true;
-                       if (lj)
-                               goto retry;
-                       /* FALL through */
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                       if (cur == NULL)
-                               break;
-                       if (prec >= 0)
-                               *cur = cs1 - '0';
-                       /*
-                        * with a negative precision *cur is already set
-                        * to -1, so it will remain negative, but we have
-                        * to "eat" precision digits in any case
-                        */
-                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
-                               --n0;
-                               *cur = *cur * 10 + *s1++ - '0';
-                       }
-                       if (prec < 0)   /* negative precision is discarded */
-                               have_prec = false;
-                       if (cur == &prec)
-                               cur = NULL;
-                       if (n0 == 0)    /* badly formatted control string */
-                               continue;
-                       goto retry;
-               case '$':
-                       if (do_traditional) {
-                               msg(_("fatal: `$' is not permitted in awk 
formats"));
-                               goto out;
-                       }
 
-                       if (cur == &fw) {
-                               argnum = fw;
-                               fw = 0;
-                               used_dollar = true;
-                               if (argnum <= 0) {
-                                       msg(_("fatal: arg count with `$' must 
be > 0"));
-                                       goto out;
-                               }
-                               if (argnum >= num_args) {
-                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
-                                       goto out;
-                               }
-                       } else {
-                               msg(_("fatal: `$' not permitted after period in 
format"));
-                               goto out;
-                       }
+               if (sgn)
+                       tmpbuf_prepend(outb, '-');
+               else if (spec->signchar)
+                       tmpbuf_prepend(outb, spec->signchar);
+               /*
+                * When to fill with zeroes is of course not simple.
+                * First: No zero fill if left-justifying.
+                * Next: There seem to be two cases:
+                *      A '0' without a precision, e.g. %06d
+                *      A precision with no field width, e.g. %.10d
+                * Any other case, we don't want to fill with zeroes.
+                */
+               if (! spec->lj
+                   && ((spec->zero_flag && ! spec->have_prec)
+                        || (spec->fw == 0 && spec->have_prec)))
+                       spec->fill = zero_string;
+               if (spec->prec > spec->fw)
+                       spec->fw = spec->prec;
+               spec->prec = CEND - CP;
+               if (spec->fw > spec->prec && ! spec->lj && spec->fill != 
space_string
+                   && (*CP == '-' || spec->signchar)) {
+                       bchunk_one(outb, CP);
+                       CP++;
+                       spec->prec--;
+                       spec->fw--;
+               }
+               cp = CP;
 
-                       goto retry;
-               case '*':
-                       if (cur == NULL)
-                               break;
-                       if (! do_traditional && isdigit((unsigned char) *s1)) {
-                               int val = 0;
+               pr_num_tail(CP, spec->prec, spec, outb);
+               return 0;
 
-                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
-                                       val *= 10;
-                                       val += *s1 - '0';
-                               }
-                               if (*s1 != '$') {
-                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
-                                       goto out;
-                               } else {
-                                       s1++;
-                                       n0--;
-                               }
-                               if (val >= num_args) {
-                                       toofew = true;
-                                       break;
-                               }
-                               arg = the_args[val];
-                       } else {
-                               parse_next_arg();
-                       }
-                       (void) force_number(arg);
-                       *cur = get_number_si(arg);
-                       if (*cur < 0 && cur == & fw) {
-                               *cur = -*cur;
-                               lj++;
-                       }
-                       if (cur == & prec) {
-                               if (*cur >= 0)
-                                       have_prec = true;
-                               else
-                                       have_prec = false;
-                               cur = NULL;
-                       }
-                       goto retry;
-               case ' ':               /* print ' ' or '-' */
-                                       /* 'space' flag is ignored */
-                                       /* if '+' already present  */
-                       if (signchar != false) 
-                               goto check_pos;
-                       /* FALL THROUGH */
-               case '+':               /* print '+' or '-' */
-                       signchar = cs1;
-                       goto check_pos;
-               case '-':
-                       if (prec < 0)
-                               break;
-                       if (cur == & prec) {
-                               prec = -1;
-                               goto retry;
-                       }
-                       fill = sp;      /* if left justified then other */
-                       lj++;           /* filling is ignored */
-                       goto check_pos;
-               case '.':
-                       if (cur != & fw)
-                               break;
-                       cur = & prec;
-                       have_prec = true;
-                       goto retry;
-               case '#':
-                       alt = true;
-                       goto check_pos;
-               case '\'':
-#if defined(HAVE_LOCALE_H)       
-                       /* allow quote_flag if there is a thousands separator. 
*/
-                       if (loc.thousands_sep[0] != '\0')
-                               quote_flag = true;
-                       goto check_pos;
-#else
-                       goto retry;  
-#endif
-               case 'l':
-                       if (big_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       big_flag = true;
-                       goto retry;
-               case 'L':
-                       if (bigbig_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       bigbig_flag = true;
-                       goto retry;
-               case 'h':
-                       if (small_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       small_flag = true;
-                       goto retry;
-               case 'c':
-                       need_format = false;
-                       parse_next_arg();
-                       /* user input that looks numeric is numeric */
-                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
-                               (void) force_number(arg);
-                       if ((arg->flags & NUMBER) != 0) {
-                               uval = get_number_uj(arg);
-#if MBS_SUPPORT
-                               if (gawk_mb_cur_max > 1) {
-                                       char buf[100];
-                                       wchar_t wc;
-                                       mbstate_t mbs;
-                                       size_t count;
-
-                                       memset(& mbs, 0, sizeof(mbs));
-                                       wc = uval;
-
-                                       count = wcrtomb(buf, wc, & mbs);
-                                       if (count == 0
-                                           || count == (size_t)-1
-                                           || count == (size_t)-2)
-                                               goto out0;
-
-                                       memcpy(cpbuf, buf, count);
-                                       prec = count;
-                                       cp = cpbuf;
-                                       goto pr_tail;
-                               }
-out0:
-                               ;
-                               /* else,
-                                       fall through */
-#endif
-                               if (do_lint && uval > 255) {
-                                       lintwarn("[s]printf: value %Lg is too 
big for %%c format",
-                                                       LDBL(arg));
-                               }
-                               cpbuf[0] = uval;
-                               prec = 1;
-                               cp = cpbuf;
-                               goto pr_tail;
-                       }
-                       /*
-                        * As per POSIX, only output first character of a
-                        * string value.  Thus, we ignore any provided
-                        * precision, forcing it to 1.  (Didn't this
-                        * used to work? 6/2003.)
-                        */
-                       cp = arg->stptr;
-#if MBS_SUPPORT
-                       /*
-                        * First character can be multiple bytes if
-                        * it's a multibyte character. Grr.
-                        */
-                       if (gawk_mb_cur_max > 1) {
-                               mbstate_t state;
-                               size_t count;
-
-                               memset(& state, 0, sizeof(state));
-                               count = mbrlen(cp, arg->stlen, & state);
-                               if (count == 0
-                                   || count == (size_t)-1
-                                   || count == (size_t)-2)
-                                       goto out2;
-                               prec = count;
-                               goto pr_tail;
-                       }
-out2:
-                       ;
-#endif
-                       prec = 1;
-                       goto pr_tail;
-               case 's':
-                       need_format = false;
-                       parse_next_arg();
-                       arg = force_string(arg);
-                       if (fw == 0 && ! have_prec)
-                               prec = arg->stlen;
-                       else {
-                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
-                               if (! have_prec || prec > char_count)
-                                       prec = char_count;
-                       }
-                       cp = arg->stptr;
-                       goto pr_tail;
-               case 'd':
-               case 'i':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       tmpval = LDBL(arg);
-
-                       /*
-                        * Check for Nan or Inf.
-                        */
-                       if (isnan(tmpval) || isinf(tmpval))
+       case 'X':
+               spec->chbuf = Uchbuf;
+               /* FALL THROUGH */
+       case 'x':
+               /* FALL THROUGH */
+       case 'u':
+               /* FALL THROUGH */
+       case 'o':
+               /*
+                * ``The result of converting a zero value with a
+                * precision of zero is no characters.''
+                *
+                * If I remember the ANSI C standard, though,
+                * it says that for octal conversions
+                * the precision is artificially increased
+                * to add an extra 0 if # is supplied.
+                * Indeed, in C,
+                *      printf("%#.0o\n", 0);
+                * prints a single 0.
+                */
+       
+               if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval 
== 0) {
+                       pr_num_tail(cp, spec->prec, spec, outb);
+                       return 0;
+               }
+
+               if (tmpval < 0) {
+                       uval = (uintmax_t) (intmax_t) tmpval;
+                       if ((AWKLDBL)(intmax_t) uval != double_to_int(tmpval))
                                goto out_of_range;
-                       else
-                               tmpval = double_to_int(tmpval);
-
-                       /*
-                        * ``The result of converting a zero value with a
-                        * precision of zero is no characters.''
-                        */
-                       if (have_prec && prec == 0 && tmpval == 0)
-                               goto pr_tail;
-
-                       if (tmpval < 0) {
-                               tmpval = -tmpval;
-                               sgn = true;
-                       } else {
-                               if (tmpval == -0.0)
-                                       /* avoid printing -0 */
-                                       tmpval = 0.0;
-                               sgn = false;
-                       }
-                       /*
-                        * Use snprintf return value to tell if there
-                        * is enough room in the buffer or not.
-                        */
-                       while ((i = snprintf(cpbufs[1].buf,
-                                    cpbufs[1].bufsize, "%.0Lf", tmpval)) >= 
cpbufs[1].bufsize) {
-                               if (cpbufs[1].buf == cpbufs[1].stackbuf)
-                                       cpbufs[1].buf = NULL;
-                               if (i > 0) {
-                                       cpbufs[1].bufsize += ((i > 
cpbufs[1].bufsize) ?
-                                                             i : 
cpbufs[1].bufsize);
-                               }
-                               else
-                                       cpbufs[1].bufsize *= 2;
-                               assert(cpbufs[1].bufsize > 0);
-                               erealloc(cpbufs[1].buf, char *,
-                                        cpbufs[1].bufsize, "format_tree");
-                       }
-                       if (i < 1)
+               } else {
+                       uval = (uintmax_t) tmpval;
+                       if ((AWKLDBL) uval != double_to_int(tmpval))
                                goto out_of_range;
-                       chp = & cpbufs[1].buf[i-1];
-                       ii = jj = 0;
-                       do {
-                               PREPEND(*chp);
-                               chp--; i--;
-#if defined(HAVE_LOCALE_H)
-                               if (quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
-                                       if (i)  /* only add if more digits 
coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX - assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)
-                                               jj = 0;         /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == CHAR_MAX)
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
-                                       }
-                               }
-#endif
-                       } while (i > 0);
-
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
+               }
 
-                       if (sgn)
-                               PREPEND('-');
-                       else if (signchar)
-                               PREPEND(signchar);
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-                       if (fw > prec && ! lj && fill != sp
-                           && (*cp == '-' || signchar)) {
-                               bchunk_one(cp);
-                               cp++;
-                               prec--;
-                               fw--;
-                       }
-                       goto pr_tail;
-               case 'X':
-                       chbuf = Uchbuf; /* FALL THROUGH */
-               case 'x':
-                       base += 6;      /* FALL THROUGH */
-               case 'u':
-                       base += 2;      /* FALL THROUGH */
-               case 'o':
-                       base += 8;
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       tmpval = LDBL(arg);
-
-                       /*
-                        * ``The result of converting a zero value with a
-                        * precision of zero is no characters.''
-                        *
-                        * If I remember the ANSI C standard, though,
-                        * it says that for octal conversions
-                        * the precision is artificially increased
-                        * to add an extra 0 if # is supplied.
-                        * Indeed, in C,
-                        *      printf("%#.0o\n", 0);
-                        * prints a single 0.
-                        */
-                       if (! alt && have_prec && prec == 0 && tmpval == 0)
-                               goto pr_tail;
-
-                       if (tmpval < 0) {
-                               uval = (uintmax_t) (intmax_t) tmpval;
-                               if ((AWKLDBL)(intmax_t)uval != 
double_to_int(tmpval))
-                                       goto out_of_range;
-                       } else {
-                               /* FIXME --- Why is this the case ? */
-                               uval = (uintmax_t) tmpval;
-                               if ((AWKLDBL) uval != double_to_int(tmpval))
-                                       goto out_of_range;
-                       }
+               /* spec->fmtchar = cs1; */
+               format_nondecimal(uval, spec, outb);
+               return 0;
 
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       ii = jj = 0;
-                       do {
-                               PREPEND(chbuf[uval % base]);
-                               uval /= base;
-#if defined(HAVE_LOCALE_H)
-                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
-                                       if (uval)       /* only add if more 
digits coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)            
                              
-                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
-                                       }
-                               }
-#endif
-                       } while (uval > 0);
+out_of_range:
+               /* out of range - emergency use of %g format */
+               if (do_lint)
+                       lintwarn(_("[s]printf: value %g is out of range for 
`%%%c' format"),
+                                       (double) tmpval, cs1);
+               cs1 = 'g';
+               goto fmt1;
 
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
-
-                       if (alt && tmpval != 0) {
-                               if (base == 16) {
-                                       PREPEND(cs1);
-                                       PREPEND('0');
-                                       if (fill != sp) {
-                                               bchunk(cp, 2);
-                                               cp += 2;
-                                               fw -= 2;
-                                       }
-                               } else if (base == 8)
-                                       PREPEND('0');
-                       }
-                       base = 0;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-       pr_tail:
-                       if (! lj) {
-                               while (fw > prec) {
-                                       bchunk_one(fill);
-                                       fw--;
-                               }
-                       }
-                       copy_count = prec;
-                       if (fw == 0 && ! have_prec)
-                               ;
-                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
-                               assert(cp == arg->stptr || cp == cpbuf);
-                               copy_count = mbc_byte_count(arg->stptr, prec);
-                       }
-                       bchunk(cp, copy_count);
-                       while (fw > prec) {
-                               bchunk_one(fill);
-                               fw--;
-                       }
-                       s0 = s1;
-                       break;
-
-     out_of_range:
-                       /* out of range - emergency use of %g format */
-                       if (do_lint)
-                               lintwarn(_("[s]printf: value %Lg is out of 
range for `%%%c' format"),
-                                                       tmpval, cs1);
-                       cs1 = 'g';
-                       goto fmt1;
-
-               case 'F':
+       case 'F':
 #if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
-                       cs1 = 'f';
-                       /* FALL THROUGH */
+               cs1 = 'f';
+               /* FALL THROUGH */
 #endif
-               case 'g':
-               case 'G':
-               case 'e':
-               case 'f':
-               case 'E':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       tmpval = LDBL(arg);
-     fmt1:
-                       if (! have_prec)
-                               prec = DEFAULT_G_PRECISION;
-
-                       chksize(fw + prec + 11);        /* 11 == slop */
-                       cp = cpbuf;
-                       *cp++ = '%';
-                       if (lj)
-                               *cp++ = '-';
-                       if (signchar)
-                               *cp++ = signchar;
-                       if (alt)
-                               *cp++ = '#';
-                       if (zero_flag)
-                               *cp++ = '0';
-                       if (quote_flag)
-                               *cp++ = '\'';
+       case 'g':
+       case 'G':
+       case 'e':
+       case 'f':
+       case 'E':
+fmt1:
+               if (! spec->have_prec)
+                       spec->prec = DEFAULT_G_PRECISION;
+
+               chksize(outb, spec->fw + spec->prec + 11);      /* 11 == slop */
+               cp = CPBUF;     /* XXX --- using the temporary prepend-buffer 
and
+                                * we know it has enough room (>=11).
+                                 */
+               *cp++ = '%';
+               if (spec->lj)
+                       *cp++ = '-';
+               if (spec->signchar)
+                       *cp++ = spec->signchar;
+               if (spec->alt)
+                       *cp++ = '#';
+               if (spec->zero_flag)
+                       *cp++ = '0';
+               if (spec->quote_flag)
+                       *cp++ = '\'';
 
 #if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "");
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "");
 #endif
 
-                       sprintf(cp, "*.*L%c", cs1);
-                       while ((nc = snprintf(obufout, ofre, cpbuf,
-                                    (int) fw, (int) prec, tmpval)) >= ofre)
-                               chksize(nc)
+               sprintf(cp, "*.*L%c", cs1);
+               while ((nc = snprintf(buf_end(outb), buf_space(outb), CPBUF,
+                               (int) spec->fw, (int) spec->prec, tmpval)) >= 
buf_space(outb))
+                       chksize(outb, nc + 1);
 
 #if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "C");
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "C");
 #endif
 
-                       len = strlen(obufout);
-                       ofre -= len;
-                       obufout += len;
-                       s0 = s1;
-                       break;
-               default:
-                       if (do_lint && isalpha(cs1))
-                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
-                       break;
-               }
-               if (toofew) {
-                       msg("%s\n\t`%s'\n\t%*s%s",
-                             _("fatal: not enough arguments to satisfy format 
string"),
-                             fmt_string, (int) (s1 - fmt_string - 1), "",
-                             _("^ ran out for this one"));
-                       goto out;
-               }
-       }
-       if (do_lint) {
-               if (need_format)
-                       lintwarn(
-                       _("[s]printf: format specifier does not have control 
letter"));
-               if (cur_arg < num_args)
-                       lintwarn(
-                       _("too many arguments supplied for format string"));
-       }
-       bchunk(s0, s1 - s0);
-       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
-       obuf = NULL;
-out:
-       {
-               size_t k;
-               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
-               for (k = 0; k < count; k++) {
-                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
-                               efree(cpbufs[k].buf);
-               }
-               if (obuf != NULL)
-                       efree(obuf);
+               buf_adjust(outb, nc); /* adjust data and free space in output 
buffer */
+               return 0;
+
+       default:
+               cant_happen();  
        }
 
-       if (r == NULL)
-               gawk_exit(EXIT_FATAL);
-       return r;
+       return -1;
 }
 
 #else

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=19058ed2bceb9d22c139dfc9b41d5a54b853ae0a

commit 19058ed2bceb9d22c139dfc9b41d5a54b853ae0a
Merge: d118c9d 390353f
Author: John Haque <address@hidden>
Date:   Wed Jan 2 19:05:53 2013 -0600

    Merge branch 'num-handler' into long-double.

diff --cc ChangeLog
index 1694937,389c61f..43675f4
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,23 -1,29 +1,45 @@@
+ 2013-01-03         John Haque      <address@hidden>
+ 
+       Refactor format_tree() to seperate number formatting code.
+ 
+       * format.h: New file.
+       (format_spec, print_fmt_buf): Definitions.
+       (chksize, bchunk, bchunk_one, buf_adjust, buf2node,
+       tmpbuf_prepend, pr_fill, pr_num_tail, free_print_fmt_buf):
+       Inline routines.
+       * awk.h (num_handler_t): New fields gawk_format_printf,
+       gawk_isnan, gawk_isinf. Removed field gawk_format_nodes.
+       * builtin.c (chksize__internal, cpbuf_chksize__internal,
+       get_fmt_buf, format_nondecimal): New routines.
+       (format_tree): Restore function format_tree(). Adjusted to call
+       the current number formatting routine.
+       * double.c (awknum_isnan, awknum_isinf, format_awknum_printf):
+       New routines.
+       (format_nodes_awknum): Removed.
+       * mpfr.c (mpfp_isnan, mpfp_isinf, mpfp_format_printf):
+       New routines.
+       (mpfp_format_nodes): Removed.
+ 
 +2012-12-29         John Haque      <address@hidden>
 +
 +      Add support for long double numbers.
 +      
 +      * awk.h (awkldbl_hndlr): Declare.
 +      (enum block_id): Add BLOCK_LDBL.
 +      * gawkapi.c (api_sym_update_scalar): Update NODE flag
 +      after freeing number.
 +      * long_double.h: New file.
 +      * long_double.c: New file.
 +      * main.c (main): Added temporary option 'B' to select long double.
 +      (print_numbr_hndlr_versions(): New entry for awkldbl_hndlr.
 +      * node.c (BLOCK nextfree): New entry for long double.
 +      * configure.ac: Added GAWK_USE_LONG_DOUBLE.
 +      * Makefile.am: Added long_double.h and long_double.c.
 +
  2012-12-28         John Haque      <address@hidden>
  
        * double.c: Use make_awknum everywhere instead of make_number
--      in case a routine is called using not the current handler
++      in case a routine is called not using the current handler
        or before initialization.
   
  2012-12-27         John Haque      <address@hidden>

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=390353f51f36ca53515630d38b63d6bbb1c4f43d

commit 390353f51f36ca53515630d38b63d6bbb1c4f43d
Author: John Haque <address@hidden>
Date:   Wed Jan 2 18:58:01 2013 -0600

    Refactoring format_tree() routine.

diff --git a/ChangeLog b/ChangeLog
index 01829c7..389c61f 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+2013-01-03         John Haque      <address@hidden>
+
+       Refactor format_tree() to seperate number formatting code.
+
+       * format.h: New file.
+       (format_spec, print_fmt_buf): Definitions.
+       (chksize, bchunk, bchunk_one, buf_adjust, buf2node,
+       tmpbuf_prepend, pr_fill, pr_num_tail, free_print_fmt_buf):
+       Inline routines.
+       * awk.h (num_handler_t): New fields gawk_format_printf,
+       gawk_isnan, gawk_isinf. Removed field gawk_format_nodes.
+       * builtin.c (chksize__internal, cpbuf_chksize__internal,
+       get_fmt_buf, format_nondecimal): New routines.
+       (format_tree): Restore function format_tree(). Adjusted to call
+       the current number formatting routine.
+       * double.c (awknum_isnan, awknum_isinf, format_awknum_printf):
+       New routines.
+       (format_nodes_awknum): Removed.
+       * mpfr.c (mpfp_isnan, mpfp_isinf, mpfp_format_printf):
+       New routines.
+       (mpfp_format_nodes): Removed.
+
 2012-12-28         John Haque      <address@hidden>
 
        * double.c: Use make_awknum everywhere instead of make_number
diff --git a/awk.h b/awk.h
index 89f2682..e459a95 100644
--- a/awk.h
+++ b/awk.h
@@ -868,6 +868,8 @@ typedef struct {
        NODE *(*ptr)(int);      /* function that implements this built-in */
 } bltin_t;
 
+struct format_spec;
+struct print_fmt_buf;
 
 typedef struct {
        bool (*init)(bltin_t **);                /* initialization */
@@ -884,17 +886,20 @@ typedef struct {
        NODE *(*gawk_force_number)(NODE *);      /* force a NODE value to be 
numeric */
        void (*gawk_negate_number)(NODE *);      /* in place negation of a 
number */
        int (*gawk_cmp_numbers)(const NODE *, const NODE *);   /* compare two 
numbers */
+
        int (*gawk_sgn_number)(const NODE *);    /* test if a numeric node is 
zero,
                                                     positive or negative */
-       bool (*gawk_is_integer)(const NODE *);    /* test if a number is an 
integer */
+       bool (*gawk_isinteger)(const NODE *);    /* test if a number is an 
integer */
+       bool (*gawk_isnan)(const NODE *);        /* test if NaN */
+       bool (*gawk_isinf)(const NODE *);        /* test if infinity */
 
        NODE *(*gawk_fmt_number)(const char *, int, NODE *);   /* stringify a 
numeric value
                                                                  based on awk 
input/output format */
-       NODE *(*gawk_format_nodes)(const char *, size_t, NODE **, long); /* 
format NODES according to
-                                                                           
user-specified FORMAT */  
+
+       int (*gawk_format_printf)(NODE *, struct format_spec *, struct 
print_fmt_buf *); /* (s)printf format */
 
        /* conversion to C types */
-       AWKNUM (*gawk_todouble)(const NODE *);         /* number to AWKNUM */
+       double (*gawk_todouble)(const NODE *);         /* number to double */
        long (*gawk_tolong)(const NODE *);             /* number to long */
        unsigned long (*gawk_toulong)(const NODE *);   /* number to unsigned 
long */
        uintmax_t (*gawk_touintmax_t)(const NODE *);   /* number to uintmax_t */
@@ -1104,7 +1109,8 @@ extern long (*get_number_si)(const NODE *);
 extern double (*get_number_d)(const NODE *);
 extern uintmax_t (*get_number_uj)(const NODE *);
 extern int (*sgn_number)(const NODE *);
-extern NODE *(*format_tree)(const char *, size_t, NODE **, long);
+extern int (*format_number_printf)(NODE *, struct format_spec *, struct 
print_fmt_buf *);
+
 
 /* built-in array types */
 extern afunc_t str_array_func[];
@@ -1234,7 +1240,7 @@ DEREF(NODE *r)
 
 /* ------------------------- Pseudo-functions ------------------------- */
 #define iszero(n)      (sgn_number(n) == 0)
-#define isinteger(n)   numbr_hndlr->gawk_is_integer(n)
+#define isinteger(n)   numbr_hndlr->gawk_isinteger(n)
 
 #define var_uninitialized(n)   ((n)->var_value == Nnull_string)
 
@@ -1401,6 +1407,7 @@ extern NODE *do_bindtextdomain(int nargs);
 extern int strncasecmpmbs(const unsigned char *,
                          const unsigned char *, size_t);
 #endif
+extern NODE *format_tree(const char *, size_t, NODE **, long);
 
 /* eval.c */
 extern void PUSH_CODE(INSTRUCTION *cp);
diff --git a/builtin.c b/builtin.c
index f6c80d3..720a12c 100644
--- a/builtin.c
+++ b/builtin.c
@@ -2061,3 +2061,640 @@ mbc_char_count(const char *ptr, size_t numbytes)
        return numbytes;
 #endif
 }
+
+
+#include "format.h"
+
+char lchbuf[] = "0123456789abcdef";
+char Uchbuf[] = "0123456789ABCDEF";
+char space_string[] = " ";
+char zero_string[] = "0";
+
+
+#define OUTBUF_INIT_SIZE       510
+
+/* chksize__internal --- make room for something LEN big in the output buffer 
*/
+
+static void
+chksize__internal(struct print_fmt_buf *outb, size_t len)
+{
+       size_t delta, newsize;
+
+       assert(outb->buf != NULL);
+       delta = outb->dataend - outb->buf;
+       newsize = delta + len + OUTBUF_INIT_SIZE;
+       erealloc(outb->buf, char *, newsize + 2, "chksize__internal");
+       outb->dataend = outb->buf + delta;
+       outb->bufsize = newsize;
+       outb->room_left = len + OUTBUF_INIT_SIZE;
+}
+
+/* cpbuf_chksize__internal --- enlarge the temporary buffer */
+
+static void
+cpbuf_chksize__internal(struct print_fmt_buf *outb)
+{
+       char *cp, *prev = outb->cpbuf.buf;
+       size_t oldsize = outb->cpbuf.bufsize;
+       size_t newsize;
+
+       newsize = outb->cpbuf.bufsize = 2 * oldsize;
+       emalloc(outb->cpbuf.buf, char *, newsize + 2, 
"cpbuf_chksize__internal");
+       memcpy((cp = outb->cpbuf.buf + oldsize), prev,  oldsize);
+       efree(prev);
+       outb->cpbuf.bufend = outb->cpbuf.buf + newsize;
+       outb->cpbuf.databegin = cp;
+}
+
+static struct print_fmt_buf static_outb;
+
+/* get_fmt_buf --- buffer(s) to manage (s)printf formatting */
+ 
+struct print_fmt_buf *
+get_fmt_buf()
+{
+       struct print_fmt_buf *outb;
+
+       if (static_outb.buf == NULL)
+               outb = & static_outb;
+       else {
+               emalloc(outb, struct print_fmt_buf *, sizeof (struct 
print_fmt_buf), "get_fmt_buf");
+               outb->is_malloced = true;
+       }
+
+       emalloc(outb->buf, char *, OUTBUF_INIT_SIZE + 2, "get_fmt_buf");
+       outb->bufsize = OUTBUF_INIT_SIZE;
+       outb->room_left = outb->bufsize;
+       outb->dataend = outb->buf;
+       outb->chksize = chksize__internal;
+
+       emalloc(outb->cpbuf.buf, char *, 64, "get_fmt_buf");
+       outb->cpbuf.bufsize = 62;
+       outb->cpbuf.databegin = outb->cpbuf.bufend = outb->cpbuf.buf + 
outb->cpbuf.bufsize;
+       outb->cpbuf_chksize = cpbuf_chksize__internal;
+       return outb;
+}
+
+
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
+
+
+/* format_nondecimal --- output a nondecimal number according to a format */
+
+void
+format_nondecimal(uintmax_t val, struct format_spec *spec, struct 
print_fmt_buf *outb)
+{
+       uintmax_t uval = val;
+       int ii, jj;
+       const char *chbuf = spec->chbuf;
+
+       /*
+        * When to fill with zeroes is of course not simple.
+        * First: No zero fill if left-justifying.
+        * Next: There seem to be two cases:
+        *      A '0' without a precision, e.g. %06d
+        *      A precision with no field width, e.g. %.10d
+        * Any other case, we don't want to fill with zeroes.
+        */
+       if (! spec->lj
+                   && ((spec->zero_flag && ! spec->have_prec)
+                       || (spec->fw == 0 && spec->have_prec))
+       )
+               spec->fill = zero_string;
+
+       ii = jj = 0;
+       do {
+               tmpbuf_prepend(outb, chbuf[uval % spec->base]);
+               uval /= spec->base;
+#if defined(HAVE_LOCALE_H)
+               if (spec->base == 10 && spec->quote_flag && loc.grouping[ii] && 
++jj == loc.grouping[ii]) {
+                       if (uval)       /* only add if more digits coming */
+                               tmpbuf_prepend(outb, loc.thousands_sep[0]);     
/* XXX --- assumption it's one char */
+                       if (loc.grouping[ii+1] == 0)                            
              
+                               jj = 0;     /* keep using current val in 
loc.grouping[ii] */
+                       else if (loc.grouping[ii+1] == CHAR_MAX)                
        
+                               spec->quote_flag= false;
+                       else {                 
+                               ii++;
+                               jj = 0;
+                       }
+               }
+#endif
+       } while (uval > 0);
+
+       /* add more output digits to match the precision */
+       if (spec->have_prec) {
+               while (CEND - CP < spec->prec)
+                       tmpbuf_prepend(outb, '0');
+       }
+
+       if (spec->alt && val != 0) {
+               if (spec->base == 16) {
+                       tmpbuf_prepend(outb, spec->fmtchar);
+                       tmpbuf_prepend(outb, '0');
+                       if (spec->fill != space_string) {
+                               bchunk(outb, CP, 2);
+                               CP += 2;
+                               spec->fw -= 2;
+                       }
+               } else if (spec->base == 8)
+                       tmpbuf_prepend(outb, '0');
+       }
+
+       spec->base = 0;
+       if (spec->prec > spec->fw)
+               spec->fw = spec->prec;
+       spec->prec = CEND - CP;
+       pr_num_tail(CP, spec->prec, spec, outb);
+}
+
+
+/*
+ * format_tree() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library.  Returns a string node which value
+ * is a formatted string.  Called by  sprintf function.
+ *
+ * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+
+NODE *
+format_tree(
+       const char *fmt_string,
+       size_t n0,
+       NODE **the_args,
+       long num_args)
+{
+       size_t cur_arg = 0;
+       NODE *r = NULL;
+       bool toofew = false;
+       const char *s0, *s1;
+       int cs1;
+       NODE *arg;
+       long argnum;
+
+       bool used_dollar;
+       bool big_flag, bigbig_flag, small_flag, need_format;
+       long *cur = NULL;
+       uintmax_t uval;
+       char *cp;
+       size_t copy_count, char_count;
+
+       struct print_fmt_buf *outb;
+       struct format_spec spec;
+
+
+       /*
+        * Check first for use of `count$'.
+        * If plain argument retrieval was used earlier, choke.
+        *      Otherwise, return the requested argument.
+        * If not `count$' now, but it was used earlier, choke.
+        * If this format is more than total number of args, choke.
+        * Otherwise, return the current argument.
+        */
+#define parse_next_arg() { \
+       if (argnum > 0) { \
+               if (cur_arg > 1) { \
+                       msg(_("fatal: must use `count$' on all formats or 
none")); \
+                       goto out; \
+               } \
+               arg = the_args[argnum]; \
+       } else if (used_dollar) { \
+               msg(_("fatal: must use `count$' on all formats or none")); \
+               arg = 0; /* shutup the compiler */ \
+               goto out; \
+       } else if (cur_arg >= num_args) { \
+               arg = 0; /* shutup the compiler */ \
+               toofew = true; \
+               break; \
+       } else { \
+               arg = the_args[cur_arg]; \
+               cur_arg++; \
+       } \
+}
+
+       outb = get_fmt_buf();
+       cur_arg = 1;
+
+       need_format = false;
+       used_dollar = false;
+
+       s0 = s1 = fmt_string;
+
+       while (n0-- > 0) {
+               if (*s1 != '%') {
+                       s1++;
+                       continue;
+               }
+               need_format = true;
+               bchunk(outb, s0, s1 - s0);
+               s0 = s1;
+               argnum = 0;
+
+               memset(& spec, '\0', sizeof (spec));
+               cur = & spec.fw;
+               spec.fill = space_string;       /* always space for string */
+
+               big_flag = bigbig_flag = small_flag = false;
+               CP = CEND;
+               s1++;
+
+retry:
+               if (n0-- == 0)  /* ran out early! */
+                       break;
+
+               switch (cs1 = *s1++) {
+               case (-1):      /* dummy case to allow for checking */
+check_pos:
+                       if (cur != & spec.fw)
+                               break;          /* reject as a valid format */
+                       goto retry;
+               case '%':
+                       need_format = false;
+                       /*
+                        * 29 Oct. 2002:
+                        * The C99 standard pages 274 and 279 seem to imply that
+                        * since there's no arg converted, the field width 
doesn't
+                        * apply.  The code already was that way, but this
+                        * comment documents it, at least in the code.
+                        */
+                       if (do_lint) {
+                               const char *msg = NULL;
+
+                               if (spec.fw && ! spec.have_prec)
+                                       msg = _("field width is ignored for 
`%%' specifier");
+                               else if (spec.fw == 0 && spec.have_prec)
+                                       msg = _("precision is ignored for `%%' 
specifier");
+                               else if (spec.fw && spec.have_prec)
+                                       msg = _("field width and precision are 
ignored for `%%' specifier");
+
+                               if (msg != NULL)
+                                       lintwarn("%s", msg);
+                       }
+                       bchunk_one(outb, "%");
+                       s0 = s1;
+                       break;
+
+               case '0':
+                       /*
+                        * Only turn on zero_flag if we haven't seen
+                        * the field width or precision yet.  Otherwise,
+                        * screws up floating point formatting.
+                        */
+                       if (cur == & spec.fw)
+                               spec.zero_flag = true;
+                       if (spec.lj)
+                               goto retry;
+                       /* FALL through */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       if (cur == NULL)
+                               break;
+                       if (spec.prec >= 0)
+                               *cur = cs1 - '0';
+                       /*
+                        * with a negative precision *cur is already set
+                        * to -1, so it will remain negative, but we have
+                        * to "eat" precision digits in any case
+                        */
+                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+                               --n0;
+                               *cur = *cur * 10 + *s1++ - '0';
+                       }
+                       if (spec.prec < 0)      /* negative precision is 
discarded */
+                               spec.have_prec = false;
+                       if (cur == & spec.prec)
+                               cur = NULL;
+                       if (n0 == 0)    /* badly formatted control string */
+                               continue;
+                       goto retry;
+               case '$':
+                       if (do_traditional) {
+                               msg(_("fatal: `$' is not permitted in awk 
formats"));
+                               goto out;
+                       }
+
+                       if (cur == & spec.fw) {
+                               argnum = spec.fw;
+                               spec.fw = 0;
+                               used_dollar = true;
+                               if (argnum <= 0) {
+                                       msg(_("fatal: arg count with `$' must 
be > 0"));
+                                       goto out;
+                               }
+                               if (argnum >= num_args) {
+                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
+                                       goto out;
+                               }
+                       } else {
+                               msg(_("fatal: `$' not permitted after period in 
format"));
+                               goto out;
+                       }
+
+                       goto retry;
+               case '*':
+                       if (cur == NULL)
+                               break;
+                       if (! do_traditional && isdigit((unsigned char) *s1)) {
+                               int val = 0;
+
+                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
+                                       val *= 10;
+                                       val += *s1 - '0';
+                               }
+                               if (*s1 != '$') {
+                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
+                                       goto out;
+                               } else {
+                                       s1++;
+                                       n0--;
+                               }
+                               if (val >= num_args) {
+                                       toofew = true;
+                                       break;
+                               }
+                               arg = the_args[val];
+                       } else {
+                               parse_next_arg();
+                       }
+
+                       (void) force_number(arg);
+                       *cur = get_number_si(arg);
+                       if (*cur < 0 && cur == & spec.fw) {
+                               *cur = -*cur;
+                               spec.lj++;
+                       }
+                       if (cur == & spec.prec) {
+                               if (*cur >= 0)
+                                       spec.have_prec = true;
+                               else
+                                       spec.have_prec = false;
+                               cur = NULL;
+                       }
+                       goto retry;
+               case ' ':               /* print ' ' or '-' */
+                                       /* 'space' flag is ignored */
+                                       /* if '+' already present  */
+                       if (spec.signchar != false) 
+                               goto check_pos;
+                       /* FALL THROUGH */
+               case '+':               /* print '+' or '-' */
+                       spec.signchar = cs1;
+                       goto check_pos;
+               case '-':
+                       if (spec.prec < 0)
+                               break;
+                       if (cur == & spec.prec) {
+                               spec.prec = -1;
+                               goto retry;
+                       }
+                       spec.lj++;              /* filling is ignored */
+                       goto check_pos;
+               case '.':
+                       if (cur != & spec.fw)
+                               break;
+                       cur = & spec.prec;
+                       spec.have_prec = true;
+                       goto retry;
+               case '#':
+                       spec.alt = true;
+                       goto check_pos;
+               case '\'':
+#if defined(HAVE_LOCALE_H)       
+                       /* allow quote_flag if there is a thousands separator. 
*/
+                       if (loc.thousands_sep[0] != '\0')
+                               spec.quote_flag= true;
+                       goto check_pos;
+#else
+                       goto retry;  
+#endif
+               case 'l':
+                       if (big_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       big_flag = true;
+                       goto retry;
+               case 'L':
+                       if (bigbig_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       bigbig_flag = true;
+                       goto retry;
+               case 'h':
+                       if (small_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       small_flag = true;
+                       goto retry;
+               case 'c':
+                       need_format = false;
+                       parse_next_arg();
+                       /* user input that looks numeric is numeric */
+                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+                               (void) force_number(arg);
+                       if ((arg->flags & NUMBER) != 0) {
+                               uval = get_number_uj(arg);
+#if MBS_SUPPORT
+                               if (gawk_mb_cur_max > 1) {
+                                       char buf[100];
+                                       wchar_t wc;
+                                       mbstate_t mbs;
+                                       size_t count;
+
+                                       memset(& mbs, 0, sizeof(mbs));
+                                       wc = uval;
+
+                                       count = wcrtomb(buf, wc, & mbs);
+                                       if (count == 0
+                                           || count == (size_t)-1
+                                           || count == (size_t)-2)
+                                               goto out0;
+
+                                       memcpy(CPBUF, buf, count);
+                                       spec.prec = count;
+                                       cp = CPBUF;
+                                       goto pr_tail;
+                               }
+out0:
+                               ;
+                               /* else,
+                                       fall through */
+#endif
+                               if (do_lint && uval > 255) {
+                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
+                                                       get_number_d(arg));
+                               }
+                               CPBUF[0] = uval;
+                               spec.prec = 1;
+                               cp = CPBUF;
+                               goto pr_tail;
+                       }
+                       /*
+                        * As per POSIX, only output first character of a
+                        * string value.  Thus, we ignore any provided
+                        * precision, forcing it to 1.  (Didn't this
+                        * used to work? 6/2003.)
+                        */
+                       cp = arg->stptr;
+#if MBS_SUPPORT
+                       /*
+                        * First character can be multiple bytes if
+                        * it's a multibyte character. Grr.
+                        */
+                       if (gawk_mb_cur_max > 1) {
+                               mbstate_t state;
+                               size_t count;
+
+                               memset(& state, 0, sizeof(state));
+                               count = mbrlen(cp, arg->stlen, & state);
+                               if (count == 0
+                                   || count == (size_t)-1
+                                   || count == (size_t)-2)
+                                       goto out2;
+                               spec.prec = count;
+                               goto pr_tail;
+                       }
+out2:
+                       ;
+#endif
+                       spec.prec = 1;
+                       goto pr_tail;
+               case 's':
+                       need_format = false;
+                       parse_next_arg();
+                       arg = force_string(arg);
+                       if (spec.fw == 0 && ! spec.have_prec)
+                               spec.prec = arg->stlen;
+                       else {
+                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
+                               if (! spec.have_prec || spec.prec > char_count)
+                                       spec.prec = char_count;
+                       }
+                       cp = arg->stptr;
+       pr_tail:
+                       if (! spec.lj)
+                               pr_fill(& spec, outb);
+
+                       copy_count = spec.prec;
+                       if (spec.fw == 0 && ! spec.have_prec)
+                               ;
+                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
+                               assert(cp == arg->stptr || cp == CPBUF);
+                               copy_count = mbc_byte_count(arg->stptr, 
spec.prec);
+                       }
+
+                       bchunk(outb, cp, copy_count);
+                       pr_fill(& spec, outb);
+
+                       s0 = s1;
+                       break;
+
+               case 'X':
+                       /* FALL THROUGH */
+               case 'x':
+                       spec.base += 6;
+                       /* FALL THROUGH */
+               case 'u':
+                       spec.base += 2;
+                       /* FALL THROUGH */
+               case 'o':
+                       spec.base += 8;
+                       goto fmt1;
+               case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+                       cs1 = 'f';
+                       /* FALL THROUGH */
+#endif
+               case 'g':
+               case 'G':
+               case 'e':
+               case 'f':
+               case 'E':
+               case 'd':
+               case 'i':
+       fmt1:
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       spec.fmtchar = cs1;
+                       if (format_number_printf(arg, & spec, outb) < 0)
+                               goto out;
+
+                       s0 = s1;
+                       break;
+
+               default:
+                       if (do_lint && isalpha(cs1))
+       lintwarn(_("ignoring unknown format specifier character `%c': no 
argument converted"), cs1);
+                       break;
+               }
+               if (toofew) {
+                       msg("%s\n\t`%s'\n\t%*s%s",
+                             _("fatal: not enough arguments to satisfy format 
string"),
+                             fmt_string, (int) (s1 - fmt_string - 1), "",
+                             _("^ ran out for this one"));
+                       goto out;
+               }
+       }
+
+       if (do_lint) {
+               if (need_format)
+                       lintwarn(_("[s]printf: format specifier does not have 
control letter"));
+               if (cur_arg < num_args)
+                       lintwarn(_("too many arguments supplied for format 
string"));
+       }
+
+       bchunk(outb, s0, s1 - s0);
+       r = buf2node(outb);
+out:
+       free_fmt_buf(outb);
+
+       if (r == NULL)
+               gawk_exit(EXIT_FATAL);
+       return r;
+}
+
diff --git a/double.c b/double.c
index 985d4f4..b5b7458 100644
--- a/double.c
+++ b/double.c
@@ -28,6 +28,8 @@
 #include "random.h"
 #include "floatmagic.h"        /* definition of isnan */
 
+#include "format.h"
+
 /* Can declare these, since we always use the random shipped with gawk */
 extern char *initstate(unsigned long seed, char *state, long n);
 extern char *setstate(char *state);
@@ -52,12 +54,14 @@ static NODE *force_awknum(NODE *);
 static NODE *format_awknum_val(const char *, int, NODE *);
 static unsigned long awknum_toulong(const NODE *);
 static long awknum_tolong(const NODE *);
-static AWKNUM awknum_todouble(const NODE *);
+static double awknum_todouble(const NODE *);
 static uintmax_t awknum_touintmax_t(const NODE *);
 static int awknum_sgn(const NODE *);
-static bool awknum_is_integer(const NODE *);
+static bool awknum_isinteger(const NODE *);
+static bool awknum_isnan(const NODE *);
+static bool awknum_isinf(const NODE *);
 static NODE *awknum_copy(const NODE *);
-static NODE *format_nodes_awknum(const char *, size_t, NODE **, long);
+static int format_awknum_printf(NODE *, struct format_spec *, struct 
print_fmt_buf *);
 static bool awknum_init(bltin_t **);
 static NODE *awknum_add(const NODE *, const NODE *);
 static NODE *awknum_sub(const NODE *, const NODE *);
@@ -107,9 +111,11 @@ numbr_handler_t awknum_hndlr = {
        negate_awknum,
        cmp_awknums,
        awknum_sgn,
-       awknum_is_integer,
+       awknum_isinteger,
+       awknum_isnan,
+       awknum_isinf,
        format_awknum_val,
-       format_nodes_awknum,
+       format_awknum_printf,
        awknum_todouble,
        awknum_tolong,
        awknum_toulong,
@@ -184,7 +190,7 @@ awknum_tolong(const NODE *n)
 
 /* awknum_todouble --- conversion to AWKNUM */
 
-static AWKNUM
+static double
 awknum_todouble(const NODE *n)
 {
        return n->numbr;
@@ -206,16 +212,33 @@ awknum_sgn(const NODE *n)
        return (n->numbr < 0.0 ? -1 : n->numbr > 0.0);
 }
 
-/* awknum_is_integer --- check if a number is an integer */
+/* awknum_isinteger --- check if a number is an integer */
 
 static bool
-awknum_is_integer(const NODE *n)
+awknum_isinteger(const NODE *n)
 {
        if (isnan(n->numbr) || isinf(n->numbr))
                return false;
        return double_to_int(n->numbr) == n->numbr;
 }
 
+/* awknum_isnan --- check if number is NaN */
+
+static bool
+awknum_isnan(const NODE *n)
+{
+       return isnan(n->numbr);
+}
+
+/* awknum_isinf --- check if number is infinity */
+
+static bool
+awknum_isinf(const NODE *n)
+{
+       return isinf(n->numbr);
+}
+
+
 /* negate_awknum --- negate AWKNUM in NODE */
 
 static void
@@ -1256,835 +1279,232 @@ do_strtonum(int nargs)
        return make_awknum(d);
 }
 
+/* format_awknum_printf --- format a number for (s)printf */
 
-/*
- * format_tree() formats arguments of sprintf,
- * and accordingly to a fmt_string providing a format like in
- * printf family from C library.  Returns a string node which value
- * is a formatted string.  Called by  sprintf function.
- *
- * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
- * for taming this beast and making it compatible with ANSI C.
- */
-
-static NODE *
-format_nodes_awknum(
-       const char *fmt_string,
-       size_t n0,
-       NODE **the_args,
-       long num_args)
+static int
+format_awknum_printf(NODE *arg, struct format_spec *spec, struct print_fmt_buf 
*outb)
 {
-/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
-/* difference of pointers should be of ptrdiff_t type, but let us be kind */
-#define bchunk(s, l) if (l) { \
-       while ((l) > ofre) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       memcpy(obufout, s, (size_t) (l)); \
-       obufout += (l); \
-       ofre -= (l); \
-}
+       AWKNUM tmpval;
+       uintmax_t uval;
+       bool sgn;
+       int i, ii, jj;
+       char *chp, *cp;
+       char cs1;
+       int nc;
+
+       static char stackbuf[64];       /* temporary buffer for integer 
formatting */ 
+       static char *intbuf = stackbuf;
+       size_t intbuf_size = 64;
+
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
+
+
+       tmpval = arg->numbr;
+       spec->fill = space_string;
+       spec->chbuf = lchbuf;
+
+       cp = CP;
+       cs1 = spec->fmtchar;
+       switch (cs1) {
+       case 'd':
+       case 'i':
+               if (isnan(tmpval) || isinf(tmpval))
+                       goto out_of_range;
+               else
+                       tmpval = double_to_int(tmpval);
 
-/* copy one byte from 's' to 'obufout' checking for space in the process */
-#define bchunk_one(s) { \
-       if (ofre < 1) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       *obufout++ = *s; \
-       --ofre; \
-}
+               /*
+                * ``The result of converting a zero value with a
+                * precision of zero is no characters.''
+                */
+               if (spec->have_prec && spec->prec == 0 && tmpval == 0) {
+                       pr_num_tail(cp, spec->prec, spec, outb);
+                       return 0;
+               }
 
-/* Is there space for something L big in the buffer? */
-#define chksize(l)  if ((l) >= ofre) { \
-       size_t olen = obufout - obuf; \
-       size_t delta = osiz+l-ofre; \
-       erealloc(obuf, char *, osiz + delta, "format_tree"); \
-       obufout = obuf + olen; \
-       ofre += delta; \
-       osiz += delta; \
-}
+               if (tmpval < 0) {
+                       tmpval = -tmpval;
+                       sgn = true;
+               } else {
+                       if (tmpval == -0.0)     /* avoid printing -0 */
+                               tmpval = 0.0;
+                       sgn = false;
+               }
 
-       size_t cur_arg = 0;
-       NODE *r = NULL;
-       int i, nc;
-       bool toofew = false;
-       char *obuf, *obufout;
-       size_t osiz, ofre;
-       const char *chbuf;
-       const char *s0, *s1;
-       int cs1;
-       NODE *arg;
-       long fw, prec, argnum;
-       bool used_dollar;
-       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
-       long *cur = NULL;
-       uintmax_t uval;
-       bool sgn;
-       int base;
-       /*
-        * Although this is an array, the elements serve two different
-        * purposes. The first element is the general buffer meant
-        * to hold the entire result string.  The second one is a
-        * temporary buffer for large floating point values. They
-        * could just as easily be separate variables, and the
-        * code might arguably be clearer.
-        */
-       struct {
-               char *buf;
-               size_t bufsize;
-               char stackbuf[30];
-       } cpbufs[2];
-#define cpbuf  cpbufs[0].buf
-       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
-       char *cp;
-       const char *fill;
-       AWKNUM tmpval = 0.0;
-       char signchar = '\0';
-       size_t len;
-       bool zero_flag = false;
-       bool quote_flag = false;
-       int ii, jj;
-       char *chp;
-       size_t copy_count, char_count;
-
-       static const char sp[] = " ";
-       static const char zero_string[] = "0";
-       static const char lchbuf[] = "0123456789abcdef";
-       static const char Uchbuf[] = "0123456789ABCDEF";
-
-#define INITIAL_OUT_SIZE       512
-       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
-       obufout = obuf;
-       osiz = INITIAL_OUT_SIZE;
-       ofre = osiz - 2;
-
-       cur_arg = 1;
-
-       {
-               size_t k;
-               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
-                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
-                       cpbufs[k].buf = cpbufs[k].stackbuf;
+               /*
+                * Use snprintf return value to tell if there
+                * is enough room in the buffer or not.
+                */
+               while ((i = snprintf(intbuf, intbuf_size, "%.0f", tmpval)) >= 
intbuf_size) {
+                       if (intbuf == stackbuf)
+                               intbuf = NULL;
+                       intbuf_size = i + 1;
+                       erealloc(intbuf, char *, intbuf_size, "format_tree");
                }
-       }
 
-       /*
-        * The point of this goop is to grow the buffer
-        * holding the converted number, so that large
-        * values don't overflow a fixed length buffer.
-        */
-#define PREPEND(CH) do {       \
-       if (cp == cpbufs[0].buf) {      \
-               char *prev = cpbufs[0].buf;     \
-               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
-                       "format_tree"); \
-               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
-                      cpbufs[0].bufsize);      \
-               cpbufs[0].bufsize *= 2; \
-               if (prev != cpbufs[0].stackbuf) \
-                       efree(prev);    \
-               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
-       }       \
-       *--cp = (CH);   \
-} while(0)
+               if (i < 1)
+                       goto out_of_range;
 
-       /*
-        * Check first for use of `count$'.
-        * If plain argument retrieval was used earlier, choke.
-        *      Otherwise, return the requested argument.
-        * If not `count$' now, but it was used earlier, choke.
-        * If this format is more than total number of args, choke.
-        * Otherwise, return the current argument.
-        */
-#define parse_next_arg() { \
-       if (argnum > 0) { \
-               if (cur_arg > 1) { \
-                       msg(_("fatal: must use `count$' on all formats or 
none")); \
-                       goto out; \
-               } \
-               arg = the_args[argnum]; \
-       } else if (used_dollar) { \
-               msg(_("fatal: must use `count$' on all formats or none")); \
-               arg = 0; /* shutup the compiler */ \
-               goto out; \
-       } else if (cur_arg >= num_args) { \
-               arg = 0; /* shutup the compiler */ \
-               toofew = true; \
-               break; \
-       } else { \
-               arg = the_args[cur_arg]; \
-               cur_arg++; \
-       } \
-}
+               chp = & intbuf[i-1];
+               ii = jj = 0;
+               do {
+                       tmpbuf_prepend(outb, *chp);
+                       chp--; i--;
+#if defined(HAVE_LOCALE_H)
+                       if (spec->quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
+                               if (i)  /* only add if more digits coming */
+                                       tmpbuf_prepend(outb, 
loc.thousands_sep[0]);     /* XXX - assumption it's one char */
+                               if (loc.grouping[ii+1] == 0)
+                                       jj = 0;         /* keep using current 
val in loc.grouping[ii] */
+                               else if (loc.grouping[ii+1] == CHAR_MAX)
+                                       spec->quote_flag= false;
+                               else {                 
+                                       ii++;
+                                       jj = 0;
+                               }
+                       }
+#endif
+               } while (i > 0);
 
-       need_format = false;
-       used_dollar = false;
 
-       s0 = s1 = fmt_string;
-       while (n0-- > 0) {
-               if (*s1 != '%') {
-                       s1++;
-                       continue;
+               /* add more output digits to match the precision */
+               if (spec->have_prec) {
+                       while (CEND - CP < spec->prec)
+                               tmpbuf_prepend(outb, '0');
                }
-               need_format = true;
-               bchunk(s0, s1 - s0);
-               s0 = s1;
-               cur = &fw;
-               fw = 0;
-               prec = 0;
-               base = 0;
-               argnum = 0;
-               base = 0;
-               have_prec = false;
-               signchar = '\0';
-               zero_flag = false;
-               quote_flag = false;
-               lj = alt = big_flag = bigbig_flag = small_flag = false;
-               fill = sp;
-               cp = cend;
-               chbuf = lchbuf;
-               s1++;
-
-retry:
-               if (n0-- == 0)  /* ran out early! */
-                       break;
-
-               switch (cs1 = *s1++) {
-               case (-1):      /* dummy case to allow for checking */
-check_pos:
-                       if (cur != &fw)
-                               break;          /* reject as a valid format */
-                       goto retry;
-               case '%':
-                       need_format = false;
-                       /*
-                        * 29 Oct. 2002:
-                        * The C99 standard pages 274 and 279 seem to imply that
-                        * since there's no arg converted, the field width 
doesn't
-                        * apply.  The code already was that way, but this
-                        * comment documents it, at least in the code.
-                        */
-                       if (do_lint) {
-                               const char *msg = NULL;
-
-                               if (fw && ! have_prec)
-                                       msg = _("field width is ignored for 
`%%' specifier");
-                               else if (fw == 0 && have_prec)
-                                       msg = _("precision is ignored for `%%' 
specifier");
-                               else if (fw && have_prec)
-                                       msg = _("field width and precision are 
ignored for `%%' specifier");
-
-                               if (msg != NULL)
-                                       lintwarn("%s", msg);
-                       }
-                       bchunk_one("%");
-                       s0 = s1;
-                       break;
-
-               case '0':
-                       /*
-                        * Only turn on zero_flag if we haven't seen
-                        * the field width or precision yet.  Otherwise,
-                        * screws up floating point formatting.
-                        */
-                       if (cur == & fw)
-                               zero_flag = true;
-                       if (lj)
-                               goto retry;
-                       /* FALL through */
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                       if (cur == NULL)
-                               break;
-                       if (prec >= 0)
-                               *cur = cs1 - '0';
-                       /*
-                        * with a negative precision *cur is already set
-                        * to -1, so it will remain negative, but we have
-                        * to "eat" precision digits in any case
-                        */
-                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
-                               --n0;
-                               *cur = *cur * 10 + *s1++ - '0';
-                       }
-                       if (prec < 0)   /* negative precision is discarded */
-                               have_prec = false;
-                       if (cur == &prec)
-                               cur = NULL;
-                       if (n0 == 0)    /* badly formatted control string */
-                               continue;
-                       goto retry;
-               case '$':
-                       if (do_traditional) {
-                               msg(_("fatal: `$' is not permitted in awk 
formats"));
-                               goto out;
-                       }
 
-                       if (cur == &fw) {
-                               argnum = fw;
-                               fw = 0;
-                               used_dollar = true;
-                               if (argnum <= 0) {
-                                       msg(_("fatal: arg count with `$' must 
be > 0"));
-                                       goto out;
-                               }
-                               if (argnum >= num_args) {
-                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
-                                       goto out;
-                               }
-                       } else {
-                               msg(_("fatal: `$' not permitted after period in 
format"));
-                               goto out;
-                       }
+               if (sgn)
+                       tmpbuf_prepend(outb, '-');
+               else if (spec->signchar)
+                       tmpbuf_prepend(outb, spec->signchar);
+               /*
+                * When to fill with zeroes is of course not simple.
+                * First: No zero fill if left-justifying.
+                * Next: There seem to be two cases:
+                *      A '0' without a precision, e.g. %06d
+                *      A precision with no field width, e.g. %.10d
+                * Any other case, we don't want to fill with zeroes.
+                */
+               if (! spec->lj
+                   && ((spec->zero_flag && ! spec->have_prec)
+                        || (spec->fw == 0 && spec->have_prec)))
+                       spec->fill = zero_string;
+               if (spec->prec > spec->fw)
+                       spec->fw = spec->prec;
+               spec->prec = CEND - CP;
+               if (spec->fw > spec->prec && ! spec->lj && spec->fill != 
space_string
+                   && (*CP == '-' || spec->signchar)) {
+                       bchunk_one(outb, CP);
+                       CP++;
+                       spec->prec--;
+                       spec->fw--;
+               }
+               cp = CP;
 
-                       goto retry;
-               case '*':
-                       if (cur == NULL)
-                               break;
-                       if (! do_traditional && isdigit((unsigned char) *s1)) {
-                               int val = 0;
+               pr_num_tail(CP, spec->prec, spec, outb);
+               return 0;
 
-                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
-                                       val *= 10;
-                                       val += *s1 - '0';
-                               }
-                               if (*s1 != '$') {
-                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
-                                       goto out;
-                               } else {
-                                       s1++;
-                                       n0--;
-                               }
-                               if (val >= num_args) {
-                                       toofew = true;
-                                       break;
-                               }
-                               arg = the_args[val];
-                       } else {
-                               parse_next_arg();
-                       }
-                       (void) force_number(arg);
-                       *cur = get_number_si(arg);
-                       if (*cur < 0 && cur == &fw) {
-                               *cur = -*cur;
-                               lj++;
-                       }
-                       if (cur == &prec) {
-                               if (*cur >= 0)
-                                       have_prec = true;
-                               else
-                                       have_prec = false;
-                               cur = NULL;
-                       }
-                       goto retry;
-               case ' ':               /* print ' ' or '-' */
-                                       /* 'space' flag is ignored */
-                                       /* if '+' already present  */
-                       if (signchar != false) 
-                               goto check_pos;
-                       /* FALL THROUGH */
-               case '+':               /* print '+' or '-' */
-                       signchar = cs1;
-                       goto check_pos;
-               case '-':
-                       if (prec < 0)
-                               break;
-                       if (cur == &prec) {
-                               prec = -1;
-                               goto retry;
-                       }
-                       fill = sp;      /* if left justified then other */
-                       lj++;           /* filling is ignored */
-                       goto check_pos;
-               case '.':
-                       if (cur != &fw)
-                               break;
-                       cur = &prec;
-                       have_prec = true;
-                       goto retry;
-               case '#':
-                       alt = true;
-                       goto check_pos;
-               case '\'':
-#if defined(HAVE_LOCALE_H)       
-                       /* allow quote_flag if there is a thousands separator. 
*/
-                       if (loc.thousands_sep[0] != '\0')
-                               quote_flag = true;
-                       goto check_pos;
-#else
-                       goto retry;  
-#endif
-               case 'l':
-                       if (big_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       big_flag = true;
-                       goto retry;
-               case 'L':
-                       if (bigbig_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       bigbig_flag = true;
-                       goto retry;
-               case 'h':
-                       if (small_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       small_flag = true;
-                       goto retry;
-               case 'c':
-                       need_format = false;
-                       parse_next_arg();
-                       /* user input that looks numeric is numeric */
-                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
-                               (void) force_number(arg);
-                       if ((arg->flags & NUMBER) != 0) {
-                               uval = get_number_uj(arg);
-#if MBS_SUPPORT
-                               if (gawk_mb_cur_max > 1) {
-                                       char buf[100];
-                                       wchar_t wc;
-                                       mbstate_t mbs;
-                                       size_t count;
-
-                                       memset(& mbs, 0, sizeof(mbs));
-                                       wc = uval;
-
-                                       count = wcrtomb(buf, wc, & mbs);
-                                       if (count == 0
-                                           || count == (size_t)-1
-                                           || count == (size_t)-2)
-                                               goto out0;
-
-                                       memcpy(cpbuf, buf, count);
-                                       prec = count;
-                                       cp = cpbuf;
-                                       goto pr_tail;
-                               }
-out0:
-                               ;
-                               /* else,
-                                       fall through */
-#endif
-                               if (do_lint && uval > 255) {
-                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
-                                                       arg->numbr);
-                               }
-                               cpbuf[0] = uval;
-                               prec = 1;
-                               cp = cpbuf;
-                               goto pr_tail;
-                       }
-                       /*
-                        * As per POSIX, only output first character of a
-                        * string value.  Thus, we ignore any provided
-                        * precision, forcing it to 1.  (Didn't this
-                        * used to work? 6/2003.)
-                        */
-                       cp = arg->stptr;
-#if MBS_SUPPORT
-                       /*
-                        * First character can be multiple bytes if
-                        * it's a multibyte character. Grr.
-                        */
-                       if (gawk_mb_cur_max > 1) {
-                               mbstate_t state;
-                               size_t count;
-
-                               memset(& state, 0, sizeof(state));
-                               count = mbrlen(cp, arg->stlen, & state);
-                               if (count == 0
-                                   || count == (size_t)-1
-                                   || count == (size_t)-2)
-                                       goto out2;
-                               prec = count;
-                               goto pr_tail;
-                       }
-out2:
-                       ;
-#endif
-                       prec = 1;
-                       goto pr_tail;
-               case 's':
-                       need_format = false;
-                       parse_next_arg();
-                       arg = force_string(arg);
-                       if (fw == 0 && ! have_prec)
-                               prec = arg->stlen;
-                       else {
-                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
-                               if (! have_prec || prec > char_count)
-                                       prec = char_count;
-                       }
-                       cp = arg->stptr;
-                       goto pr_tail;
-               case 'd':
-               case 'i':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       tmpval = arg->numbr;
-
-                       /*
-                        * Check for Nan or Inf.
-                        */
-                       if (isnan(tmpval) || isinf(tmpval))
+       case 'X':
+               spec->chbuf = Uchbuf;
+               /* FALL THROUGH */
+       case 'x':
+               /* FALL THROUGH */
+       case 'u':
+               /* FALL THROUGH */
+       case 'o':
+               /*
+                * ``The result of converting a zero value with a
+                * precision of zero is no characters.''
+                *
+                * If I remember the ANSI C standard, though,
+                * it says that for octal conversions
+                * the precision is artificially increased
+                * to add an extra 0 if # is supplied.
+                * Indeed, in C,
+                *      printf("%#.0o\n", 0);
+                * prints a single 0.
+                */
+       
+               if (! spec->alt && spec->have_prec && spec->prec == 0 && tmpval 
== 0) {
+                       pr_num_tail(cp, spec->prec, spec, outb);
+                       return 0;
+               }
+
+               if (tmpval < 0) {
+                       uval = (uintmax_t) (intmax_t) tmpval;
+                       if ((AWKNUM)(intmax_t) uval != double_to_int(tmpval))
                                goto out_of_range;
-                       else
-                               tmpval = double_to_int(tmpval);
-
-                       /*
-                        * ``The result of converting a zero value with a
-                        * precision of zero is no characters.''
-                        */
-                       if (have_prec && prec == 0 && tmpval == 0)
-                               goto pr_tail;
-
-                       if (tmpval < 0) {
-                               tmpval = -tmpval;
-                               sgn = true;
-                       } else {
-                               if (tmpval == -0.0)
-                                       /* avoid printing -0 */
-                                       tmpval = 0.0;
-                               sgn = false;
-                       }
-                       /*
-                        * Use snprintf return value to tell if there
-                        * is enough room in the buffer or not.
-                        */
-                       while ((i = snprintf(cpbufs[1].buf,
-                                            cpbufs[1].bufsize, "%.0f",
-                                            tmpval)) >=
-                              cpbufs[1].bufsize) {
-                               if (cpbufs[1].buf == cpbufs[1].stackbuf)
-                                       cpbufs[1].buf = NULL;
-                               if (i > 0) {
-                                       cpbufs[1].bufsize += ((i > 
cpbufs[1].bufsize) ?
-                                                             i : 
cpbufs[1].bufsize);
-                               }
-                               else
-                                       cpbufs[1].bufsize *= 2;
-                               assert(cpbufs[1].bufsize > 0);
-                               erealloc(cpbufs[1].buf, char *,
-                                        cpbufs[1].bufsize, "format_tree");
-                       }
-                       if (i < 1)
+               } else {
+                       uval = (uintmax_t) tmpval;
+                       if ((AWKNUM) uval != double_to_int(tmpval))
                                goto out_of_range;
-                       chp = &cpbufs[1].buf[i-1];
-                       ii = jj = 0;
-                       do {
-                               PREPEND(*chp);
-                               chp--; i--;
-#if defined(HAVE_LOCALE_H)
-                               if (quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
-                                       if (i)  /* only add if more digits 
coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX - assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)
-                                               jj = 0;         /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == CHAR_MAX)
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
-                                       }
-                               }
-#endif
-                       } while (i > 0);
-
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
+               }
 
-                       if (sgn)
-                               PREPEND('-');
-                       else if (signchar)
-                               PREPEND(signchar);
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-                       if (fw > prec && ! lj && fill != sp
-                           && (*cp == '-' || signchar)) {
-                               bchunk_one(cp);
-                               cp++;
-                               prec--;
-                               fw--;
-                       }
-                       goto pr_tail;
-               case 'X':
-                       chbuf = Uchbuf; /* FALL THROUGH */
-               case 'x':
-                       base += 6;      /* FALL THROUGH */
-               case 'u':
-                       base += 2;      /* FALL THROUGH */
-               case 'o':
-                       base += 8;
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       tmpval = arg->numbr;
-
-                       /*
-                        * ``The result of converting a zero value with a
-                        * precision of zero is no characters.''
-                        *
-                        * If I remember the ANSI C standard, though,
-                        * it says that for octal conversions
-                        * the precision is artificially increased
-                        * to add an extra 0 if # is supplied.
-                        * Indeed, in C,
-                        *      printf("%#.0o\n", 0);
-                        * prints a single 0.
-                        */
-                       if (! alt && have_prec && prec == 0 && tmpval == 0)
-                               goto pr_tail;
-
-                       if (tmpval < 0) {
-                               uval = (uintmax_t) (intmax_t) tmpval;
-                               if ((AWKNUM)(intmax_t)uval != 
double_to_int(tmpval))
-                                       goto out_of_range;
-                       } else {
-                               uval = (uintmax_t) tmpval;
-                               if ((AWKNUM)uval != double_to_int(tmpval))
-                                       goto out_of_range;
-                       }
+               /* spec->fmtchar = cs1; */
+               format_nondecimal(uval, spec, outb);
+               return 0;
 
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       ii = jj = 0;
-                       do {
-                               PREPEND(chbuf[uval % base]);
-                               uval /= base;
-#if defined(HAVE_LOCALE_H)
-                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
-                                       if (uval)       /* only add if more 
digits coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)            
                              
-                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
-                                       }
-                               }
-#endif
-                       } while (uval > 0);
+out_of_range:
+               /* out of range - emergency use of %g format */
+               if (do_lint)
+                       lintwarn(_("[s]printf: value %g is out of range for 
`%%%c' format"),
+                                       (double) tmpval, cs1);
+               cs1 = 'g';
+               goto fmt1;
 
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
-
-                       if (alt && tmpval != 0) {
-                               if (base == 16) {
-                                       PREPEND(cs1);
-                                       PREPEND('0');
-                                       if (fill != sp) {
-                                               bchunk(cp, 2);
-                                               cp += 2;
-                                               fw -= 2;
-                                       }
-                               } else if (base == 8)
-                                       PREPEND('0');
-                       }
-                       base = 0;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-       pr_tail:
-                       if (! lj) {
-                               while (fw > prec) {
-                                       bchunk_one(fill);
-                                       fw--;
-                               }
-                       }
-                       copy_count = prec;
-                       if (fw == 0 && ! have_prec)
-                               ;
-                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
-                               assert(cp == arg->stptr || cp == cpbuf);
-                               copy_count = mbc_byte_count(arg->stptr, prec);
-                       }
-                       bchunk(cp, copy_count);
-                       while (fw > prec) {
-                               bchunk_one(fill);
-                               fw--;
-                       }
-                       s0 = s1;
-                       break;
-
-     out_of_range:
-                       /* out of range - emergency use of %g format */
-                       if (do_lint)
-                               lintwarn(_("[s]printf: value %g is out of range 
for `%%%c' format"),
-                                                       (double) tmpval, cs1);
-                       cs1 = 'g';
-                       goto fmt1;
-
-               case 'F':
+       case 'F':
 #if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
-                       cs1 = 'f';
-                       /* FALL THROUGH */
+               cs1 = 'f';
+               /* FALL THROUGH */
 #endif
-               case 'g':
-               case 'G':
-               case 'e':
-               case 'f':
-               case 'E':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-                       tmpval = arg->numbr;
-     fmt1:
-                       if (! have_prec)
-                               prec = DEFAULT_G_PRECISION;
-
-                       chksize(fw + prec + 11);        /* 11 == slop */
-                       cp = cpbuf;
-                       *cp++ = '%';
-                       if (lj)
-                               *cp++ = '-';
-                       if (signchar)
-                               *cp++ = signchar;
-                       if (alt)
-                               *cp++ = '#';
-                       if (zero_flag)
-                               *cp++ = '0';
-                       if (quote_flag)
-                               *cp++ = '\'';
+       case 'g':
+       case 'G':
+       case 'e':
+       case 'f':
+       case 'E':
+fmt1:
+               if (! spec->have_prec)
+                       spec->prec = DEFAULT_G_PRECISION;
+
+               chksize(outb, spec->fw + spec->prec + 11);      /* 11 == slop */
+               cp = CPBUF;     /* XXX --- using the temporary prepend-buffer 
and
+                                * we know it has enough room (>=11).
+                                 */
+               *cp++ = '%';
+               if (spec->lj)
+                       *cp++ = '-';
+               if (spec->signchar)
+                       *cp++ = spec->signchar;
+               if (spec->alt)
+                       *cp++ = '#';
+               if (spec->zero_flag)
+                       *cp++ = '0';
+               if (spec->quote_flag)
+                       *cp++ = '\'';
 
 #if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "");
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "");
 #endif
 
-                       sprintf(cp, "*.*%c", cs1);
-                       while ((nc = snprintf(obufout, ofre, cpbuf,
-                                    (int) fw, (int) prec,
-                                    (double) tmpval)) >= ofre)
-                               chksize(nc)
+               sprintf(cp, "*.*%c", cs1);
+               while ((nc = snprintf(buf_end(outb), buf_space(outb), CPBUF,
+                               (int) spec->fw, (int) spec->prec, tmpval)) >= 
buf_space(outb))
+                       chksize(outb, nc + 1);
 
 #if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "C");
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "C");
 #endif
 
-                       len = strlen(obufout);
-                       ofre -= len;
-                       obufout += len;
-                       s0 = s1;
-                       break;
-               default:
-                       if (do_lint && isalpha(cs1))
-                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
-                       break;
-               }
-               if (toofew) {
-                       msg("%s\n\t`%s'\n\t%*s%s",
-                             _("fatal: not enough arguments to satisfy format 
string"),
-                             fmt_string, (int) (s1 - fmt_string - 1), "",
-                             _("^ ran out for this one"));
-                       goto out;
-               }
-       }
-       if (do_lint) {
-               if (need_format)
-                       lintwarn(
-                       _("[s]printf: format specifier does not have control 
letter"));
-               if (cur_arg < num_args)
-                       lintwarn(
-                       _("too many arguments supplied for format string"));
-       }
-       bchunk(s0, s1 - s0);
-       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
-       obuf = NULL;
-out:
-       {
-               size_t k;
-               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
-               for (k = 0; k < count; k++) {
-                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
-                               efree(cpbufs[k].buf);
-               }
-               if (obuf != NULL)
-                       efree(obuf);
+               buf_adjust(outb, nc); /* adjust data and free space in output 
buffer */
+               return 0;
+
+       default:
+               cant_happen();  
        }
 
-       if (r == NULL)
-               gawk_exit(EXIT_FATAL);
-       return r;
+       return -1;
 }
diff --git a/format.h b/format.h
new file mode 100644
index 0000000..1418a8b
--- /dev/null
+++ b/format.h
@@ -0,0 +1,155 @@
+/* format specification */
+
+struct format_spec {
+       int base;
+       long fw;
+       long prec;
+       const char *fill;
+       const char *chbuf;
+       bool lj;
+       bool alt;
+       bool have_prec;
+       bool zero_flag;
+       bool quote_flag;
+       char signchar;
+       char fmtchar;
+};
+
+
+/* struct to manage awk (s)printf formatted string */
+
+struct print_fmt_buf {
+       char *buf;      /* beginning of buffer */
+       char *dataend;  /* end of current data */
+       size_t bufsize;
+       size_t room_left;
+       bool is_malloced;       /* true if this struct is malloc-ed */
+       void (*chksize)(struct print_fmt_buf *, size_t);
+       void (*cpbuf_chksize)(struct print_fmt_buf *);
+
+       /*
+        * temporary buffer: can be used to prepend one character at a time
+        *      without overflowing the buffer; used primarily to format 
integers.
+        */
+       struct {
+               char *buf;      /* beginning of buffer */
+               char *bufend;   /* end of buffer */
+               size_t bufsize;
+               char *databegin;        /* start of current data */
+       } cpbuf;
+};
+
+extern struct print_fmt_buf *get_fmt_buf(void);
+extern void format_nondecimal(uintmax_t, struct format_spec *, struct 
print_fmt_buf *);
+
+#      define buf_start(ob)    ((ob)->buf)
+#      define buf_end(ob)      ((ob)->dataend)
+#      define buf_space(ob)    ((ob)->room_left)
+#      define cpbuf_start(ob)  ((ob)->cpbuf.databegin)
+#      define cpbuf_end(ob)    ((ob)->cpbuf.bufend)
+#      define cpbuf(ob)        ((ob)->cpbuf.buf)
+
+extern char lchbuf[];
+extern char Uchbuf[];
+extern char space_string[];
+extern char zero_string[];
+
+/* chksize --- make room for something LEN big in the output buffer */
+
+static inline void
+chksize(struct print_fmt_buf *outb, size_t len)
+{
+       if (len > outb->room_left)
+               outb->chksize(outb, len);
+}
+
+/* bchunk --- copy LEN bytes from STR checking for space in the process */
+
+static inline void
+bchunk(struct print_fmt_buf *outb, const char *str, size_t len)
+{
+       if (len > 0) {
+               if (len > outb->room_left)
+                       outb->chksize(outb, len);
+               outb->dataend = (char *) memcpy(outb->dataend, str, len) + len;
+               outb->room_left -= len;
+       }
+}
+
+/* bchunk_one --- copy one byte from STR checking for space in the process */
+
+static inline void
+bchunk_one(struct print_fmt_buf *outb, const char *str)
+{
+       if (1 > outb->room_left)
+               outb->chksize(outb, 1);
+       *outb->dataend++ = *str;
+       --outb->room_left;
+}
+
+/* buf_adjust --- adjust buffer after appending LEN bytes */
+
+static inline void
+buf_adjust(struct print_fmt_buf *outb, size_t len)
+{
+       assert(len <= outb->room_left);
+       outb->dataend += len;
+       outb->room_left -= len;
+}
+
+/* buf2node --- convert bytes to string NODE */
+
+static inline NODE *
+buf2node(struct print_fmt_buf *outb)
+{
+       NODE *node;
+       node = make_str_node(outb->buf, outb->dataend - outb->buf, 
ALREADY_MALLOCED);
+       outb->buf = NULL;
+       return node;
+}
+
+
+/* tmpbuf_prepend --- prepend one byte to temporary buffer */
+
+static inline void
+tmpbuf_prepend(struct print_fmt_buf *outb, char ch)
+{
+       if (outb->cpbuf.databegin == outb->cpbuf.buf)
+               outb->cpbuf_chksize(outb);
+       *--outb->cpbuf.databegin = ch;
+}
+
+/* pr_fill --- fill buffer with current fill character */
+
+static inline void
+pr_fill(struct format_spec *spec, struct print_fmt_buf *outb)
+{
+       while (spec->fw > spec->prec) {
+               bchunk_one(outb, spec->fill);
+               spec->fw--;
+       }
+}
+
+static inline void
+pr_num_tail(const char *cp, size_t copy_count, struct format_spec *spec, 
struct print_fmt_buf *outb)
+{
+       if (! spec->lj)
+               pr_fill(spec, outb);
+       bchunk(outb, cp, copy_count);
+       pr_fill(spec, outb);
+}
+
+
+/* free_print_fmt_buf --- free buffer */
+
+static inline void
+free_fmt_buf(struct print_fmt_buf *outb)
+{
+       if (outb->buf != NULL) {
+               efree(outb->buf);
+               outb->buf = NULL;
+       }
+       efree(outb->cpbuf.buf);
+       if (outb->is_malloced)
+               efree(outb);
+}
diff --git a/main.c b/main.c
index 24dbb56..c7e9a89 100644
--- a/main.c
+++ b/main.c
@@ -1549,7 +1549,7 @@ init_numbr_handler(bltin_t **bltins)
        cmp_numbers = numbr_hndlr->gawk_cmp_numbers;
        str2node = numbr_hndlr->gawk_str2number;
        free_number = numbr_hndlr->gawk_free_number;
-       format_tree = numbr_hndlr->gawk_format_nodes;
+       format_number_printf = numbr_hndlr->gawk_format_printf;
        get_number_d = numbr_hndlr->gawk_todouble;
        get_number_si = numbr_hndlr->gawk_tolong;
        get_number_ui = numbr_hndlr->gawk_toulong;
diff --git a/mpfr.c b/mpfr.c
index 4697a9f..e3215c9 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -29,6 +29,8 @@
 #include <gmp.h>
 #include <mpfr.h>
 
+#include "format.h"
+
 #ifndef MPFR_RNDN
 /* for compatibility with MPFR 2.X */
 #define MPFR_RNDN GMP_RNDN
@@ -56,12 +58,14 @@ static void mpfp_free_num(NODE *);
 static NODE *mpfp_format_val(const char *, int, NODE *);
 static unsigned long mpfp_toulong(const NODE *);
 static long mpfp_tolong(const NODE *);
-static AWKNUM mpfp_todouble(const NODE *);
+static double mpfp_todouble(const NODE *);
 static uintmax_t mpfp_touintmax_t(const NODE *);
 static int mpfp_sgn(const NODE *);
-static bool mpfp_is_integer(const NODE *n);
+static bool mpfp_isinteger(const NODE *);
+static bool mpfp_isnan(const NODE *);
+static bool mpfp_isinf(const NODE *);
 static NODE *mpfp_copy_number(const NODE *);
-static NODE *mpfp_format_nodes(const char *, size_t, NODE **, long);
+static int mpfp_format_printf(NODE *, struct format_spec *, struct 
print_fmt_buf *);
 static bool mpfp_init(bltin_t **);
 static NODE *mpfp_add(const NODE *, const NODE *);
 static NODE *mpfp_sub(const NODE *, const NODE *);
@@ -162,9 +166,11 @@ numbr_handler_t mpfp_hndlr = {
        mpfp_negate_num,
        mpfp_compare,
        mpfp_sgn,
-       mpfp_is_integer,
+       mpfp_isinteger,
+       mpfp_isnan,
+       mpfp_isinf,
        mpfp_format_val,
-       mpfp_format_nodes,
+       mpfp_format_printf,
        mpfp_todouble,
        mpfp_tolong,
        mpfp_toulong,
@@ -275,7 +281,7 @@ mpfp_tolong(const NODE *n)
 
 /* mpfp_todouble --- conversion to AWKNUM */
 
-static AWKNUM
+static double
 mpfp_todouble(const NODE *n)
 {
        return (n->flags & MPFN) != 0 ? mpfr_get_d(n->qnumbr, ROUND_MODE) : 
mpz_get_d(n->qnumbr);
@@ -299,14 +305,31 @@ mpfp_sgn(const NODE *n)
                : mpz_sgn(MPZ_T(n->qnumbr));
 }
 
-/* mpfp_is_integer --- check if a number is an integer */
+/* mpfp_isinteger --- check if a number is an integer */
 
 static bool
-mpfp_is_integer(const NODE *n)
+mpfp_isinteger(const NODE *n)
 {
        return is_mpfp_integer(n) ? true : mpfr_integer_p(n->qnumbr);
 }
 
+/* mpfp_isnan --- check if a number is NaN */
+
+static bool
+mpfp_isnan(const NODE *n)
+{
+       return is_mpfp_float(n) && mpfr_nan_p(MPFR_T(n->qnumbr));
+}
+
+/* mpfp_isinf --- check if a number is infinity */
+
+static bool
+mpfp_isinf(const NODE *n)
+{
+       return is_mpfp_float(n) && mpfr_inf_p(MPFR_T(n->qnumbr));
+}
+
+
 /* mpfp_make_node --- allocate a node to store MPFR float or GMP integer */
 
 static NODE *
@@ -573,6 +596,7 @@ mpfp_force_number(NODE *n)
        return n;
 }
 
+
 /* mpfp_format_val --- format a numeric value based on format */
 
 static NODE *
@@ -587,10 +611,10 @@ mpfp_format_val(const char *format, int index, NODE *s)
 
        if (is_mpfp_integer(s) || mpfr_integer_p(s->qnumbr)) {
                /* integral value, use %d */
-               r = mpfp_format_nodes("%d", 2, dummy, 2);
+               r = format_tree("%d", 2, dummy, 2);
                s->stfmt = -1;
        } else {
-               r = mpfp_format_nodes(format, fmt_list[index]->stlen, dummy, 2);
+               r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
                assert(r != NULL);
                s->stfmt = (char) index;
        }
@@ -606,6 +630,7 @@ mpfp_format_val(const char *format, int index, NODE *s)
        return s;
 }
 
+
 /* mpfp_str2node --- create an arbitrary-pecision number from string */
 
 static NODE *
@@ -1752,845 +1777,223 @@ finish:
 }
 
 
-
 extern size_t mbc_byte_count(const char *ptr, size_t numchars);
 extern size_t mbc_char_count(const char *ptr, size_t numbytes);
 
-/*
- * mpfp_format_nodes() formats arguments of sprintf,
- * and accordingly to a fmt_string providing a format like in
- * printf family from C library.  Returns a string node which value
- * is a formatted string.  Called by  sprintf function.
- *
- * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
- * for taming this beast and making it compatible with ANSI C.
- */
-
-static NODE *
-mpfp_format_nodes(
-       const char *fmt_string,
-       size_t n0,
-       NODE **the_args,
-       long num_args)
-{
-/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
-/* difference of pointers should be of ptrdiff_t type, but let us be kind */
-#define bchunk(s, l) if (l) { \
-       while ((l) > ofre) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       memcpy(obufout, s, (size_t) (l)); \
-       obufout += (l); \
-       ofre -= (l); \
-}
 
-/* copy one byte from 's' to 'obufout' checking for space in the process */
-#define bchunk_one(s) { \
-       if (ofre < 1) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       *obufout++ = *s; \
-       --ofre; \
-}
+/* mpfp_format_prinf --- format a number for (s)printf */
 
-/* Is there space for something L big in the buffer? */
-#define chksize(l)  if ((l) >= ofre) { \
-       size_t olen = obufout - obuf; \
-       size_t delta = osiz+l-ofre; \
-       erealloc(obuf, char *, osiz + delta, "format_tree"); \
-       obufout = obuf + olen; \
-       ofre += delta; \
-       osiz += delta; \
-}
+static int
+mpfp_format_printf(NODE *arg, struct format_spec *spec, struct print_fmt_buf 
*outb)
+{
+       mpz_ptr zi;
+       mpfr_ptr mf;
+       enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } mpfmt_spec;
 
-       size_t cur_arg = 0;
-       NODE *r = NULL;
-       int i, nc;
-       bool toofew = false;
-       char *obuf, *obufout;
-       size_t osiz, ofre;
-       const char *chbuf;
-       const char *s0, *s1;
-       int cs1;
-       NODE *arg;
-       long fw, prec, argnum;
-       bool used_dollar;
-       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
-       long *cur = NULL;
        uintmax_t uval;
        bool sgn;
-       int base;
-       /*
-        * Although this is an array, the elements serve two different
-        * purposes. The first element is the general buffer meant
-        * to hold the entire result string.  The second one is a
-        * temporary buffer for large floating point values. They
-        * could just as easily be separate variables, and the
-        * code might arguably be clearer.
-        */
-       struct {
-               char *buf;
-               size_t bufsize;
-               char stackbuf[30];
-       } cpbufs[2];
-#define cpbuf  cpbufs[0].buf
-       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
+       int i, ii, jj;
        char *cp;
-       const char *fill;
-       AWKNUM tmpval = 0.0;
-       char signchar = '\0';
-       size_t len;
-       bool zero_flag = false;
-       bool quote_flag = false;
-       int ii, jj;
-       char *chp;
-       size_t copy_count, char_count;
-#ifdef HAVE_MPFR
-       mpz_ptr zi;
-       mpfr_ptr mf;
-#endif
-       enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type;
-
-       static const char sp[] = " ";
-       static const char zero_string[] = "0";
-       static const char lchbuf[] = "0123456789abcdef";
-       static const char Uchbuf[] = "0123456789ABCDEF";
-
-#define INITIAL_OUT_SIZE       512
-       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
-       obufout = obuf;
-       osiz = INITIAL_OUT_SIZE;
-       ofre = osiz - 2;
-
-       cur_arg = 1;
-
-       {
-               size_t k;
-               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
-                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
-                       cpbufs[k].buf = cpbufs[k].stackbuf;
-               }
-       }
-
-       /*
-        * The point of this goop is to grow the buffer
-        * holding the converted number, so that large
-        * values don't overflow a fixed length buffer.
-        */
-#define PREPEND(CH) do {       \
-       if (cp == cpbufs[0].buf) {      \
-               char *prev = cpbufs[0].buf;     \
-               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
-                       "format_tree"); \
-               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
-                      cpbufs[0].bufsize);      \
-               cpbufs[0].bufsize *= 2; \
-               if (prev != cpbufs[0].stackbuf) \
-                       efree(prev);    \
-               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
-       }       \
-       *--cp = (CH);   \
-} while(0)
-
-       /*
-        * Check first for use of `count$'.
-        * If plain argument retrieval was used earlier, choke.
-        *      Otherwise, return the requested argument.
-        * If not `count$' now, but it was used earlier, choke.
-        * If this format is more than total number of args, choke.
-        * Otherwise, return the current argument.
-        */
-#define parse_next_arg() { \
-       if (argnum > 0) { \
-               if (cur_arg > 1) { \
-                       msg(_("fatal: must use `count$' on all formats or 
none")); \
-                       goto out; \
-               } \
-               arg = the_args[argnum]; \
-       } else if (used_dollar) { \
-               msg(_("fatal: must use `count$' on all formats or none")); \
-               arg = 0; /* shutup the compiler */ \
-               goto out; \
-       } else if (cur_arg >= num_args) { \
-               arg = 0; /* shutup the compiler */ \
-               toofew = true; \
-               break; \
-       } else { \
-               arg = the_args[cur_arg]; \
-               cur_arg++; \
-       } \
-}
-
-       need_format = false;
-       used_dollar = false;
-
-       s0 = s1 = fmt_string;
-       while (n0-- > 0) {
-               if (*s1 != '%') {
-                       s1++;
-                       continue;
-               }
-               need_format = true;
-               bchunk(s0, s1 - s0);
-               s0 = s1;
-               cur = &fw;
-               fw = 0;
-               prec = 0;
-               base = 0;
-               argnum = 0;
-               base = 0;
-               have_prec = false;
-               signchar = '\0';
-               zero_flag = false;
-               quote_flag = false;
-#ifdef HAVE_MPFR
-               mf = NULL;
-               zi = NULL;
-#endif
-               fmt_type = 0;
+       char cs1;
+       int nc;
+       /* const char *chbuf; */
 
-               lj = alt = big_flag = bigbig_flag = small_flag = false;
-               fill = sp;
-               cp = cend;
-               chbuf = lchbuf;
-               s1++;
+#      define CP               cpbuf_start(outb)
+#      define CEND             cpbuf_end(outb)
+#      define CPBUF            cpbuf(outb)
 
-retry:
-               if (n0-- == 0)  /* ran out early! */
-                       break;
-
-               switch (cs1 = *s1++) {
-               case (-1):      /* dummy case to allow for checking */
-check_pos:
-                       if (cur != &fw)
-                               break;          /* reject as a valid format */
-                       goto retry;
-               case '%':
-                       need_format = false;
-                       /*
-                        * 29 Oct. 2002:
-                        * The C99 standard pages 274 and 279 seem to imply that
-                        * since there's no arg converted, the field width 
doesn't
-                        * apply.  The code already was that way, but this
-                        * comment documents it, at least in the code.
-                        */
-                       if (do_lint) {
-                               const char *msg = NULL;
-
-                               if (fw && ! have_prec)
-                                       msg = _("field width is ignored for 
`%%' specifier");
-                               else if (fw == 0 && have_prec)
-                                       msg = _("precision is ignored for `%%' 
specifier");
-                               else if (fw && have_prec)
-                                       msg = _("field width and precision are 
ignored for `%%' specifier");
-
-                               if (msg != NULL)
-                                       lintwarn("%s", msg);
-                       }
-                       bchunk_one("%");
-                       s0 = s1;
-                       break;
+       spec->fill = space_string;
+       spec->chbuf = lchbuf;
 
-               case '0':
-                       /*
-                        * Only turn on zero_flag if we haven't seen
-                        * the field width or precision yet.  Otherwise,
-                        * screws up floating point formatting.
-                        */
-                       if (cur == & fw)
-                               zero_flag = true;
-                       if (lj)
-                               goto retry;
-                       /* FALL through */
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                       if (cur == NULL)
-                               break;
-                       if (prec >= 0)
-                               *cur = cs1 - '0';
-                       /*
-                        * with a negative precision *cur is already set
-                        * to -1, so it will remain negative, but we have
-                        * to "eat" precision digits in any case
-                        */
-                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
-                               --n0;
-                               *cur = *cur * 10 + *s1++ - '0';
-                       }
-                       if (prec < 0)   /* negative precision is discarded */
-                               have_prec = false;
-                       if (cur == &prec)
-                               cur = NULL;
-                       if (n0 == 0)    /* badly formatted control string */
-                               continue;
-                       goto retry;
-               case '$':
-                       if (do_traditional) {
-                               msg(_("fatal: `$' is not permitted in awk 
formats"));
-                               goto out;
-                       }
+       cs1 = spec->fmtchar;
+       cp = CP;
 
-                       if (cur == &fw) {
-                               argnum = fw;
-                               fw = 0;
-                               used_dollar = true;
-                               if (argnum <= 0) {
-                                       msg(_("fatal: arg count with `$' must 
be > 0"));
-                                       goto out;
-                               }
-                               if (argnum >= num_args) {
-                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
-                                       goto out;
-                               }
-                       } else {
-                               msg(_("fatal: `$' not permitted after period in 
format"));
-                               goto out;
-                       }
-
-                       goto retry;
-               case '*':
-                       if (cur == NULL)
-                               break;
-                       if (! do_traditional && isdigit((unsigned char) *s1)) {
-                               int val = 0;
+       switch (cs1) {
+       case 'd':
+       case 'i':
+               if (is_mpfp_float(arg))
+                       goto mpf0;
+               goto mpz0;
+       case 'X':
+               spec->chbuf = Uchbuf;
+               /* FALL THROUGH */
+       case 'x':
+               /* FALL THROUGH */
+       case 'u':
+               /* FALL THROUGH */
+       case 'o':
+               if (is_mpfp_integer(arg)) {
+mpz0:
+                       zi = arg->qnumbr;
 
-                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
-                                       val *= 10;
-                                       val += *s1 - '0';
-                               }
-                               if (*s1 != '$') {
-                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
-                                       goto out;
-                               } else {
-                                       s1++;
-                                       n0--;
-                               }
-                               if (val >= num_args) {
-                                       toofew = true;
-                                       break;
-                               }
-                               arg = the_args[val];
-                       } else {
-                               parse_next_arg();
-                       }
-                       (void) force_number(arg);
-                       *cur = get_number_si(arg);
-                       if (*cur < 0 && cur == &fw) {
-                               *cur = -*cur;
-                               lj++;
-                       }
-                       if (cur == &prec) {
-                               if (*cur >= 0)
-                                       have_prec = true;
-                               else
-                                       have_prec = false;
-                               cur = NULL;
-                       }
-                       goto retry;
-               case ' ':               /* print ' ' or '-' */
-                                       /* 'space' flag is ignored */
-                                       /* if '+' already present  */
-                       if (signchar != false) 
-                               goto check_pos;
-                       /* FALL THROUGH */
-               case '+':               /* print '+' or '-' */
-                       signchar = cs1;
-                       goto check_pos;
-               case '-':
-                       if (prec < 0)
-                               break;
-                       if (cur == &prec) {
-                               prec = -1;
-                               goto retry;
-                       }
-                       fill = sp;      /* if left justified then other */
-                       lj++;           /* filling is ignored */
-                       goto check_pos;
-               case '.':
-                       if (cur != &fw)
-                               break;
-                       cur = &prec;
-                       have_prec = true;
-                       goto retry;
-               case '#':
-                       alt = true;
-                       goto check_pos;
-               case '\'':
-#if defined(HAVE_LOCALE_H)       
-                       /* allow quote_flag if there is a thousands separator. 
*/
-                       if (loc.thousands_sep[0] != '\0')
-                               quote_flag = true;
-                       goto check_pos;
-#else
-                       goto retry;  
-#endif
-               case 'l':
-                       if (big_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       big_flag = true;
-                       goto retry;
-               case 'L':
-                       if (bigbig_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       bigbig_flag = true;
-                       goto retry;
-               case 'h':
-                       if (small_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       small_flag = true;
-                       goto retry;
-               case 'c':
-                       need_format = false;
-                       parse_next_arg();
-                       /* user input that looks numeric is numeric */
-                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
-                               (void) force_number(arg);
-                       if ((arg->flags & NUMBER) != 0) {
-                               uval = get_number_uj(arg);
-#if MBS_SUPPORT
-                               if (gawk_mb_cur_max > 1) {
-                                       char buf[100];
-                                       wchar_t wc;
-                                       mbstate_t mbs;
-                                       size_t count;
-
-                                       memset(& mbs, 0, sizeof(mbs));
-                                       wc = uval;
-
-                                       count = wcrtomb(buf, wc, & mbs);
-                                       if (count == 0
-                                           || count == (size_t)-1
-                                           || count == (size_t)-2)
-                                               goto out0;
-
-                                       memcpy(cpbuf, buf, count);
-                                       prec = count;
-                                       cp = cpbuf;
-                                       goto pr_tail;
-                               }
-out0:
-                               ;
-                               /* else,
-                                       fall through */
-#endif
-                               if (do_lint && uval > 255) {
-                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
-                                                       arg->numbr);
+                       if (cs1 != 'd' && cs1 != 'i') {
+                               if (mpz_sgn(zi) <= 0) {
+                                       /*
+                                        * Negative value or 0 requires special 
handling.
+                                        * Unlike MPFR, GMP does not allow 
conversion
+                                        * to (u)intmax_t. So we first convert 
GMP type to
+                                        * a MPFR type.
+                                        */
+                                       mf = mpz2mpfr(zi, _mpfrval);
+                                       goto mpf1;
                                }
-                               cpbuf[0] = uval;
-                               prec = 1;
-                               cp = cpbuf;
-                               goto pr_tail;
-                       }
-                       /*
-                        * As per POSIX, only output first character of a
-                        * string value.  Thus, we ignore any provided
-                        * precision, forcing it to 1.  (Didn't this
-                        * used to work? 6/2003.)
-                        */
-                       cp = arg->stptr;
-#if MBS_SUPPORT
-                       /*
-                        * First character can be multiple bytes if
-                        * it's a multibyte character. Grr.
-                        */
-                       if (gawk_mb_cur_max > 1) {
-                               mbstate_t state;
-                               size_t count;
-
-                               memset(& state, 0, sizeof(state));
-                               count = mbrlen(cp, arg->stlen, & state);
-                               if (count == 0
-                                   || count == (size_t)-1
-                                   || count == (size_t)-2)
-                                       goto out2;
-                               prec = count;
-                               goto pr_tail;
-                       }
-out2:
-                       ;
-#endif
-                       prec = 1;
-                       goto pr_tail;
-               case 's':
-                       need_format = false;
-                       parse_next_arg();
-                       arg = force_string(arg);
-                       if (fw == 0 && ! have_prec)
-                               prec = arg->stlen;
-                       else {
-                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
-                               if (! have_prec || prec > char_count)
-                                       prec = char_count;
-                       }
-                       cp = arg->stptr;
-                       goto pr_tail;
-               case 'd':
-               case 'i':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-#ifdef HAVE_MPFR
-                       if (is_mpfp_float(arg))
-                               goto mpf0;
-                       else {
-                               assert(is_mpfp_integer(arg) == true);
-                               goto mpz0;
+                               spec->signchar = '\0';  /* Don't print '+' */
                        }
-#endif
-               case 'X':
-                       chbuf = Uchbuf; /* FALL THROUGH */
-               case 'x':
-                       base += 6;      /* FALL THROUGH */
-               case 'u':
-                       base += 2;      /* FALL THROUGH */
-               case 'o':
-                       base += 8;
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-#ifdef HAVE_MPFR
-                       if (is_mpfp_integer(arg)) {
-mpz0:
-                               zi = arg->qnumbr;
-
-                               if (cs1 != 'd' && cs1 != 'i') {
-                                       if (mpz_sgn(zi) <= 0) {
-                                               /*
-                                                * Negative value or 0 requires 
special handling.
-                                                * Unlike MPFR, GMP does not 
allow conversion
-                                                * to (u)intmax_t. So we first 
convert GMP type to
-                                                * a MPFR type.
-                                                */
-                                               mf = mpz2mpfr(zi, _mpfrval);
-                                               goto mpf1;
-                                       }
-                                       signchar = '\0';        /* Don't print 
'+' */
-                               }
 
-                               /* See comments above about when to fill with 
zeros */
-                               zero_flag = (! lj
-                                                   && ((zero_flag && ! 
have_prec)
-                                                        || (fw == 0 && 
have_prec)));
+                       /* See comments above about when to fill with zeros */
+                       spec->zero_flag = (! spec->lj
+                                           && ((spec->zero_flag && ! 
spec->have_prec)
+                                                || (spec->fw == 0 && 
spec->have_prec)));
 
-                               fmt_type = have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
-                               goto fmt0;
+                       mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
+                       goto fmt0;
 
-                       } else {
-                               assert(is_mpfp_float(arg) == true);
+               } else {
+                       assert(is_mpfp_float(arg) == true);
 mpf0:
-                               mf = arg->qnumbr;
-                               if (! mpfr_number_p(mf)) {
-                                       /* inf or NaN */
-                                       cs1 = 'g';
-                                       fmt_type = MP_FLOAT;
-                                       goto fmt1;
-                               }
+                       mf = arg->qnumbr;
+                       if (! mpfr_number_p(mf)) {
+                               /* inf or NaN */
+                               cs1 = 'g';
+                               mpfmt_spec = MP_FLOAT;
+                               goto fmt1;
+                       }
 
-                               if (cs1 != 'd' && cs1 != 'i') {
+                       if (cs1 != 'd' && cs1 != 'i') {
 mpf1:
-                                       /*
-                                        * The output of printf("%#.0x", 0) is 
0 instead of 0x, hence <= in
-                                        * the comparison below.
-                                        */
-                                       if (mpfr_sgn(mf) <= 0) {
-                                               if (! mpfr_fits_intmax_p(mf, 
ROUND_MODE)) {
-                                                       /* -ve number is too 
large */
-                                                       cs1 = 'g';
-                                                       fmt_type = MP_FLOAT;
-                                                       goto fmt1;
-                                               }
-
-                                               tmpval = uval = (uintmax_t) 
mpfr_get_sj(mf, ROUND_MODE);
-                                               if (! alt && have_prec && prec 
== 0 && tmpval == 0)
-                                                       goto pr_tail;   /* 
printf("%.0x", 0) is no characters */
-                                               goto int0;
+                               /*
+                                * The output of printf("%#.0x", 0) is 0 
instead of 0x, hence <= in
+                                * the comparison below.
+                                */
+                               if (mpfr_sgn(mf) <= 0) {
+                                       if (! mpfr_fits_intmax_p(mf, 
ROUND_MODE)) {
+                                               /* -ve number is too large */
+                                               cs1 = 'g';
+                                               mpfmt_spec = MP_FLOAT;
+                                               goto fmt1;
                                        }
-                                       signchar = '\0';        /* Don't print 
'+' */
-                               }
 
-                               /* See comments above about when to fill with 
zeros */
-                               zero_flag = (! lj
-                                                   && ((zero_flag && ! 
have_prec)
-                                                        || (fw == 0 && 
have_prec)));
-                               
-                               (void) mpfr_get_z(_mpzval, mf, MPFR_RNDZ);      
/* convert to GMP integer */
-                               fmt_type = have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
-                               zi = _mpzval;
-                               goto fmt0;
-                       }
-#endif
-
-#ifdef HAVE_MPFR
-       int0:
-#endif
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       ii = jj = 0;
-                       do {
-                               PREPEND(chbuf[uval % base]);
-                               uval /= base;
-#if defined(HAVE_LOCALE_H)
-                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
-                                       if (uval)       /* only add if more 
digits coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)            
                              
-                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
+                                       uval = (uintmax_t) mpfr_get_sj(mf, 
ROUND_MODE);
+                                       if (! spec->alt && spec->have_prec && 
spec->prec == 0 && uval == 0) {
+                                               /* printf("%.0x", 0) is no 
characters */
+                                               pr_num_tail(cp, 0, spec, outb);
+                                               return 0;
                                        }
-                               }
-#endif
-                       } while (uval > 0);
-
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
 
-                       if (alt && tmpval != 0) {
-                               if (base == 16) {
-                                       PREPEND(cs1);
-                                       PREPEND('0');
-                                       if (fill != sp) {
-                                               bchunk(cp, 2);
-                                               cp += 2;
-                                               fw -= 2;
-                                       }
-                               } else if (base == 8)
-                                       PREPEND('0');
-                       }
-                       base = 0;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-       pr_tail:
-                       if (! lj) {
-                               while (fw > prec) {
-                                       bchunk_one(fill);
-                                       fw--;
+                                       /* spec->fmtchar = cs1; */
+                                       /* spec->chbuf = chbuf; */
+                                       format_nondecimal(uval, spec, outb);
+                                       return 0;
                                }
+                               spec->signchar = '\0';  /* Don't print '+' */
                        }
-                       copy_count = prec;
-                       if (fw == 0 && ! have_prec)
-                               ;
-                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
-                               assert(cp == arg->stptr || cp == cpbuf);
-                               copy_count = mbc_byte_count(arg->stptr, prec);
-                       }
-                       bchunk(cp, copy_count);
-                       while (fw > prec) {
-                               bchunk_one(fill);
-                               fw--;
-                       }
-                       s0 = s1;
-                       break;
-
-     out_of_range:
-                       /* out of range - emergency use of %g format */
-                       if (do_lint)
-                               lintwarn(_("[s]printf: value %g is out of range 
for `%%%c' format"),
-                                                       (double) tmpval, cs1);
-                       cs1 = 'g';
-                       goto fmt1;
 
-               case 'F':
-#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
-                       cs1 = 'f';
-                       /* FALL THROUGH */
-#endif
-               case 'g':
-               case 'G':
-               case 'e':
-               case 'f':
-               case 'E':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
+                       /* See comments above about when to fill with zeros */
+                       spec->zero_flag = (! spec->lj
+                                           && ((spec->zero_flag && ! 
spec->have_prec)
+                                                || (spec->fw == 0 && 
spec->have_prec)));
+                       
+                       (void) mpfr_get_z(_mpzval, mf, MPFR_RNDZ);      /* 
convert to GMP integer */
+                       mpfmt_spec = spec->have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
+                       zi = _mpzval;
+                       goto fmt0;
+               }
 
-                       if (! is_mpfp_number(arg))
-                               tmpval = arg->numbr;
-#ifdef HAVE_MPFR
-                       else if (is_mpfp_float(arg)) {
-                               mf = arg->qnumbr;
-                               fmt_type = MP_FLOAT;
-                       } else {
-                               /* arbitrary-precision integer, convert to MPFR 
float */
-                               assert(mf == NULL);
-                               mf = mpz2mpfr(arg->qnumbr, _mpfrval);
-                               fmt_type = MP_FLOAT;
-                       }
-#endif
-     fmt1:
-                       if (! have_prec)
-                               prec = DEFAULT_G_PRECISION;
-#ifdef HAVE_MPFR
-     fmt0:
-#endif
-                       chksize(fw + prec + 11);        /* 11 == slop */
-                       cp = cpbuf;
-                       *cp++ = '%';
-                       if (lj)
-                               *cp++ = '-';
-                       if (signchar)
-                               *cp++ = signchar;
-                       if (alt)
-                               *cp++ = '#';
-                       if (zero_flag)
-                               *cp++ = '0';
-                       if (quote_flag)
-                               *cp++ = '\'';
+#if 0
+out_of_range:
+               /* out of range - emergency use of %g format */
+               if (do_lint)
+                       lintwarn(_("[s]printf: value %g is out of range for 
`%%%c' format"),
+                                               (double) tmpval, cs1);
+               cs1 = 'g';
+               goto fmt1;
 
-#if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "");
 #endif
 
-                       switch (fmt_type) {
-#ifdef HAVE_MPFR
-                       case MP_INT_WITH_PREC:
-                               sprintf(cp, "*.*Z%c", cs1);
-                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, (int) prec, zi)) >= ofre)
-                                       chksize(nc)
-                               break;
-                       case MP_INT_WITHOUT_PREC:
-                               sprintf(cp, "*Z%c", cs1);
-                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, zi)) >= ofre)
-                                       chksize(nc)
-                               break;
-                       case MP_FLOAT:
-                               sprintf(cp, "*.*R*%c", cs1);
-                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, (int) prec, ROUND_MODE, 
mf)) >= ofre)
-                                       chksize(nc)
-                               break;
+       case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+               cs1 = 'f';
+               /* FALL THROUGH */
 #endif
-                       default:
-                               sprintf(cp, "*.*%c", cs1);
-                               while ((nc = snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, (int) prec,
-                                            (double) tmpval)) >= ofre)
-                                       chksize(nc)
-                       }
+       case 'g':
+       case 'G':
+       case 'e':
+       case 'f':
+       case 'E':
+               if (is_mpfp_float(arg)) {
+                       mf = arg->qnumbr;
+                       mpfmt_spec = MP_FLOAT;
+               } else {
+                       /* arbitrary-precision integer, convert to MPFR float */
+                       assert(mf == NULL);
+                       mf = mpz2mpfr(arg->qnumbr, _mpfrval);
+                       mpfmt_spec = MP_FLOAT;
+               }
+fmt1:
+               if (! spec->have_prec)
+                       spec->prec = DEFAULT_G_PRECISION;
+
+fmt0:
+               chksize(outb, spec->fw + spec->prec + 11);      /* 11 == slop */
+               cp = CPBUF;     /* XXX --- using the temporary prepend-buffer 
and
+                                * we know it has enough room (>=11).
+                                 */
+               *cp++ = '%';
+               if (spec->lj)
+                       *cp++ = '-';
+               if (spec->signchar)
+                       *cp++ = spec->signchar;
+               if (spec->alt)
+                       *cp++ = '#';
+               if (spec->zero_flag)
+                       *cp++ = '0';
+               if (spec->quote_flag)
+                       *cp++ = '\'';
 
 #if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "C");
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "");
 #endif
 
-                       len = strlen(obufout);
-                       ofre -= len;
-                       obufout += len;
-                       s0 = s1;
+               switch (mpfmt_spec) {
+               case MP_INT_WITH_PREC:
+                       sprintf(cp, "*.*Z%c", cs1);
+                       while ((nc = mpfr_snprintf(buf_end(outb), 
buf_space(outb), CPBUF,
+                                       (int) spec->fw, (int) spec->prec, zi)) 
>= buf_space(outb))
+                               chksize(outb, nc + 1);
                        break;
-               default:
-                       if (do_lint && isalpha(cs1))
-                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
+               case MP_INT_WITHOUT_PREC:
+                       sprintf(cp, "*Z%c", cs1);
+                       while ((nc = mpfr_snprintf(buf_end(outb), 
buf_space(outb), CPBUF,
+                                       (int) spec->fw, zi)) >= buf_space(outb))
+                               chksize(outb, nc + 1);
                        break;
+               case MP_FLOAT:
+                       sprintf(cp, "*.*R*%c", cs1);
+                       while ((nc = mpfr_snprintf(buf_end(outb), 
buf_space(outb), CPBUF,
+                                       (int) spec->fw, (int) spec->prec, 
ROUND_MODE, mf)) >= buf_space(outb))
+                               chksize(outb, nc + 1);
+                       break;
+               default:
+                       cant_happen();
                }
-               if (toofew) {
-                       msg("%s\n\t`%s'\n\t%*s%s",
-                             _("fatal: not enough arguments to satisfy format 
string"),
-                             fmt_string, (int) (s1 - fmt_string - 1), "",
-                             _("^ ran out for this one"));
-                       goto out;
-               }
-       }
-       if (do_lint) {
-               if (need_format)
-                       lintwarn(
-                       _("[s]printf: format specifier does not have control 
letter"));
-               if (cur_arg < num_args)
-                       lintwarn(
-                       _("too many arguments supplied for format string"));
-       }
-       bchunk(s0, s1 - s0);
-       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
-       obuf = NULL;
-out:
-       {
-               size_t k;
-               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
-               for (k = 0; k < count; k++) {
-                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
-                               efree(cpbufs[k].buf);
-               }
-               if (obuf != NULL)
-                       efree(obuf);
+
+#if defined(LC_NUMERIC)
+               if (spec->quote_flag && ! use_lc_numeric)
+                       setlocale(LC_NUMERIC, "C");
+#endif
+
+               buf_adjust(outb, nc); /* adjust data and free space in output 
buffer */
+               return 0;
+
+       default:
+               cant_happen();
        }
 
-       if (r == NULL)
-               gawk_exit(EXIT_FATAL);
-       return r;
+       return -1;
 }
 
+
 #else
 
 static bool mpfp_init(bltin_t **bltins);
diff --git a/msg.c b/msg.c
index dd83759..4d67f60 100644
--- a/msg.c
+++ b/msg.c
@@ -91,8 +91,9 @@ err(bool isfatal, const char *s, const char *emsg, va_list 
argp)
 
 /*
  * fmt_number --- format a number node for use in error messages.
- *     N.B: format is awk printf format. MUST NOT throw warning in format
- *     tree. "%ld" is BAD, "%d" is Ok!
+ *
+ * N.B: format is awk printf format. MUST NOT generate warning
+ * in format_tree(). "%ld" is BAD, "%d" is OK!
  */
 
 const char *
diff --git a/node.c b/node.c
index 9efd767..55d7710 100644
--- a/node.c
+++ b/node.c
@@ -26,7 +26,7 @@
 
 #include "awk.h"
 
-NODE *(*format_tree)(const char *, size_t, NODE **, long);
+int (*format_number_printf)(NODE *, struct format_spec *, struct print_fmt_buf 
*);
 NODE *(*str2node)(char *, char **, int, bool);
 NODE *(*make_number)(AWKNUM);
 NODE *(*str2number)(NODE *);

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=d118c9d35073796a2c53862ce0d2db897260db71

commit d118c9d35073796a2c53862ce0d2db897260db71
Merge: 6eaca01 7c017f1
Author: John Haque <address@hidden>
Date:   Mon Dec 31 09:27:09 2012 -0600

    Merge branch 'num-handler' into long-double


http://git.sv.gnu.org/cgit/gawk.git/commit/?id=7c017f175f74131de421563b127f9a554cc8fa07

commit 7c017f175f74131de421563b127f9a554cc8fa07
Author: John Haque <address@hidden>
Date:   Mon Dec 31 09:25:56 2012 -0600

    Fixed  MPFR add_long.

diff --git a/mpfr.c b/mpfr.c
index 4d4de53..4697a9f 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -1645,7 +1645,7 @@ mpfp_add_long(const NODE *t1, long l)
                if (l >= 0)
                        mpz_add_ui(r->qnumbr, t1->qnumbr, l);
                else
-                       mpz_sub_ui(r->qnumbr, t1->qnumbr, l);
+                       mpz_sub_ui(r->qnumbr, t1->qnumbr, -l);
        } else {
                int tval;
 

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=6eaca011dff30eb685a01e3a7d16f22fa581e0ca

commit 6eaca011dff30eb685a01e3a7d16f22fa581e0ca
Author: John Haque <address@hidden>
Date:   Mon Dec 31 09:21:55 2012 -0600

    Fix exp() function for long-double.

diff --git a/long_double.c b/long_double.c
index e2a5fb2..714dafc 100644
--- a/long_double.c
+++ b/long_double.c
@@ -1302,6 +1302,7 @@ do_exp(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("exp: received non-numeric argument"));
        (void) force_number(tmp);
+       d = LDBL(tmp);
        DEREF(tmp);
        errno = 0;
        res = gawk_expl(d);

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=67c71cd618d07c6d832f1031564566f17fa36e69

commit 67c71cd618d07c6d832f1031564566f17fa36e69
Merge: 43b544c 9565731
Author: John Haque <address@hidden>
Date:   Mon Dec 31 04:55:56 2012 -0600

    Merge branch 'num-handler' into long-double


http://git.sv.gnu.org/cgit/gawk.git/commit/?id=9565731d6ee1a418444676846e860881cab78441

commit 9565731d6ee1a418444676846e860881cab78441
Author: John Haque <address@hidden>
Date:   Mon Dec 31 04:49:29 2012 -0600

    Initialize MNR, MFNR and set MALLOC flag for mpfr numbers.

diff --git a/io.c b/io.c
index 666bfde..0aa4aec 100644
--- a/io.c
+++ b/io.c
@@ -382,6 +382,7 @@ nextfile(IOBUF **curfile, bool skipping)
                        return 0;
        }
 
+       (void) force_number(ARGC_node->var_value);      /* make no assumptions! 
*/
        argc = get_number_si(ARGC_node->var_value);
        
        for (; i < argc; i++) {
diff --git a/mpfr.c b/mpfr.c
index 83b37a1..4d4de53 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -150,7 +150,6 @@ mpfp_tofloat(const NODE *t, mpfr_ptr pf)
 }
 
 
-
 numbr_handler_t mpfp_hndlr = {
        mpfp_init,
        mpfp_version_string,
@@ -214,6 +213,8 @@ mpfp_init(bltin_t **numbr_bltins)
        ROUND_MODE = mpfp_get_rounding_mode(rndmode[0]); 
        mpfr_set_default_rounding_mode(ROUND_MODE);
 
+       mpz_init(MNR);
+       mpz_init(MFNR);
        do_ieee_fmt = false;
 
        mpfr_init2(_mp1, PRECISION_MIN);
@@ -261,7 +262,7 @@ mpfp_version_string()
 static unsigned long
 mpfp_toulong(const NODE *n)
 {
-       return (n->flags & MPFN) ? mpfr_get_ui(n->qnumbr, ROUND_MODE) : 
mpz_get_ui(n->qnumbr);
+       return (n->flags & MPFN) != 0 ? mpfr_get_ui(n->qnumbr, ROUND_MODE) : 
mpz_get_ui(n->qnumbr);
 }
 
 /* mpfp_tolong --- conversion to long */
@@ -269,7 +270,7 @@ mpfp_toulong(const NODE *n)
 static long
 mpfp_tolong(const NODE *n)
 {
-       return (n->flags & MPFN) ? mpfr_get_si(n->qnumbr, ROUND_MODE) : 
mpz_get_si(n->qnumbr);
+       return (n->flags & MPFN) != 0 ? mpfr_get_si(n->qnumbr, ROUND_MODE) : 
mpz_get_si(n->qnumbr);
 }
 
 /* mpfp_todouble --- conversion to AWKNUM */
@@ -277,7 +278,7 @@ mpfp_tolong(const NODE *n)
 static AWKNUM
 mpfp_todouble(const NODE *n)
 {
-       return (n->flags & MPFN) ? mpfr_get_d(n->qnumbr, ROUND_MODE) : 
mpz_get_d(n->qnumbr);
+       return (n->flags & MPFN) != 0 ? mpfr_get_d(n->qnumbr, ROUND_MODE) : 
mpz_get_d(n->qnumbr);
 }
 
 /* mpfp_touintmax_t --- conversion to uintmax_t */
@@ -285,7 +286,7 @@ mpfp_todouble(const NODE *n)
 static uintmax_t
 mpfp_touintmax_t(const NODE *n)
 {
-       return (n->flags & MPFN) ? mpfr_get_uj(n->qnumbr, ROUND_MODE) \
+       return (n->flags & MPFN) != 0 ? mpfr_get_uj(n->qnumbr, ROUND_MODE) \
                        : (uintmax_t) mpz_get_d(n->qnumbr);
 }
 
@@ -294,7 +295,7 @@ mpfp_touintmax_t(const NODE *n)
 static int
 mpfp_sgn(const NODE *n)
 {
-       return (n->flags & MPFN) ? mpfr_sgn(MPFR_T(n->qnumbr)) \
+       return (n->flags & MPFN) != 0 ? mpfr_sgn(MPFR_T(n->qnumbr)) \
                : mpz_sgn(MPZ_T(n->qnumbr));
 }
 
@@ -328,7 +329,7 @@ mpfp_make_node(unsigned int type)
        }
        
        r->valref = 1;
-       r->flags |= (NUMBER|NUMCUR);
+       r->flags |= (MALLOC|NUMBER|NUMCUR);
        r->stptr = NULL;
        r->stlen = 0;
 #if MBS_SUPPORT
@@ -867,6 +868,7 @@ mpfp_set_var(const NODE *var)
                        NR = mpz_fdiv_q_ui(MNR, r, LONG_MAX);   /* MNR is 
quotient */
                else
                        FNR = mpz_fdiv_q_ui(MFNR, r, LONG_MAX);
+
                if (r != val->qnumbr)
                        mpz_clear(mpz_val);
        }
diff --git a/msg.c b/msg.c
index d61fea0..dd83759 100644
--- a/msg.c
+++ b/msg.c
@@ -90,13 +90,11 @@ err(bool isfatal, const char *s, const char *emsg, va_list 
argp)
 
 
 /*
- * N.B: format is awk printf format, NOT C format or any other special format
- * supported. MUST NOT throw warning in format tree. "%ld" is BAD, "%d" is Ok!
+ * fmt_number --- format a number node for use in error messages.
+ *     N.B: format is awk printf format. MUST NOT throw warning in format
+ *     tree. "%ld" is BAD, "%d" is Ok!
  */
 
-
-/* N.B: FORMAT must pass fmt_ok() used to check CONVFMT/OFMT specifier */
-
 const char *
 fmt_number(const char *format, const NODE *n)
 {
@@ -104,7 +102,7 @@ fmt_number(const char *format, const NODE *n)
        static char *num_str;
        extern bool fmt_ok(const char *p);
 
-       assert(fmt_ok(format) == true);
+       /* FIXME: %d etc -- assert(fmt_ok(format) == true); */
        assert((n->flags & (NUMBER|NUMCUR)) != 0);
 
        /* copy number so not to change state of the original including flags */

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=43b544c18ebb8dae961b8079b590bff9d84296ba

commit 43b544c18ebb8dae961b8079b590bff9d84296ba
Author: John Haque <address@hidden>
Date:   Sat Dec 29 22:15:49 2012 -0600

    Fixed to compile without long double.

diff --git a/long_double.c b/long_double.c
index b50e3fe..e2a5fb2 100644
--- a/long_double.c
+++ b/long_double.c
@@ -2226,7 +2226,7 @@ out:
 
 #else
 
-static bool mpfp_init(bltin_t **bltins);
+static bool awkldbl_init(bltin_t **bltins);
 
 numbr_handler_t awkldbl_hndlr = {
        awkldbl_init,

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=685a7ea80272a51da2b4c0051123ffd084abb2ec

commit 685a7ea80272a51da2b4c0051123ffd084abb2ec
Author: John Haque <address@hidden>
Date:   Sat Dec 29 06:30:46 2012 -0600

    Add support for long double numbers.

diff --git a/ChangeLog b/ChangeLog
index 01829c7..1694937 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2012-12-29         John Haque      <address@hidden>
+
+       Add support for long double numbers.
+       
+       * awk.h (awkldbl_hndlr): Declare.
+       (enum block_id): Add BLOCK_LDBL.
+       * gawkapi.c (api_sym_update_scalar): Update NODE flag
+       after freeing number.
+       * long_double.h: New file.
+       * long_double.c: New file.
+       * main.c (main): Added temporary option 'B' to select long double.
+       (print_numbr_hndlr_versions(): New entry for awkldbl_hndlr.
+       * node.c (BLOCK nextfree): New entry for long double.
+       * configure.ac: Added GAWK_USE_LONG_DOUBLE.
+       * Makefile.am: Added long_double.h and long_double.c.
+
 2012-12-28         John Haque      <address@hidden>
 
        * double.c: Use make_awknum everywhere instead of make_number
diff --git a/Makefile.am b/Makefile.am
index 7a1b530..92ec47d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -110,6 +110,8 @@ base_sources = \
        int_array.c \
        interpret.h \
        io.c \
+       long_double.c \
+       long_double.h \
        mbsupport.h \
        main.c \
        mpfr.c \
diff --git a/Makefile.in b/Makefile.in
index 71df2f0..b6ff304 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -88,11 +88,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
        $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
        $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
        $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
-       $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
-       $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
-       $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-       $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
-       $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+       $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+       $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+       $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -108,11 +109,11 @@ am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) 
builtin.$(OBJEXT) \
        dfa.$(OBJEXT) double.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) \
        field.$(OBJEXT) floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) \
        gawkmisc.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
-       int_array.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) \
-       msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) \
-       random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
-       replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
-       version.$(OBJEXT)
+       int_array.$(OBJEXT) io.$(OBJEXT) long_double.$(OBJEXT) \
+       main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
+       profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
+       regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
+       symbol.$(OBJEXT) version.$(OBJEXT)
 am_gawk_OBJECTS = $(am__objects_1)
 gawk_OBJECTS = $(am_gawk_OBJECTS)
 gawk_LDADD = $(LDADD)
@@ -291,6 +292,7 @@ SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
 STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
@@ -439,6 +441,8 @@ base_sources = \
        int_array.c \
        interpret.h \
        io.c \
+       long_double.c \
+       long_double.h \
        mbsupport.h \
        main.c \
        mpfr.c \
@@ -597,6 +601,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/aclocal.m4 b/aclocal.m4
index 1d4e9d2..d5c96fe 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -953,6 +953,7 @@ m4_include([m4/lib-ld.m4])
 m4_include([m4/lib-link.m4])
 m4_include([m4/lib-prefix.m4])
 m4_include([m4/libsigsegv.m4])
+m4_include([m4/long_double.m4])
 m4_include([m4/longlong.m4])
 m4_include([m4/mpfr.m4])
 m4_include([m4/nls.m4])
diff --git a/array.c b/array.c
index c5090d9..279cd09 100644
--- a/array.c
+++ b/array.c
@@ -701,7 +701,7 @@ assoc_info(NODE *subs, NODE *val, NODE *ndump, const char 
*aname)
        indent(indent_level);
        fprintf(output_fp, "I: [%s:", aname);
        if ((subs->flags & (MPFN|MPZN|INTIND)) == INTIND)
-               fprintf(output_fp, "<%ld>", (long) subs->numbr);
+               fprintf(output_fp, "<%ld>", get_number_si(subs));
        else
                value_info(subs);
        fprintf(output_fp, "]\n");
diff --git a/awk.h b/awk.h
index 89f2682..4f44e2b 100644
--- a/awk.h
+++ b/awk.h
@@ -1041,6 +1041,7 @@ enum block_id {
        BLOCK_INVALID = 0,      /* not legal */
        BLOCK_NODE,
        BLOCK_BUCKET,
+       BLOCK_LDBL,
        BLOCK_MAX       /* count */
 };     
 
@@ -1090,6 +1091,7 @@ extern char *source;
 extern int (*interpret)(INSTRUCTION *);        /* interpreter routine */
 
 extern numbr_handler_t awknum_hndlr;   /* double */
+extern numbr_handler_t awkldbl_hndlr;  /* long double */
 extern numbr_handler_t mpfp_hndlr;     /* arbitrary-precision floating-point */
 extern numbr_handler_t *numbr_hndlr;   /* active handler */
 
diff --git a/awkgram.c b/awkgram.c
index 772cc36..3156184 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -745,11 +745,11 @@ static const yytype_uint16 yyrline[] =
     1247,  1254,  1256,  1258,  1274,  1284,  1291,  1293,  1298,  1300,
     1302,  1310,  1312,  1317,  1319,  1324,  1326,  1328,  1378,  1380,
     1382,  1384,  1386,  1388,  1390,  1392,  1415,  1420,  1425,  1450,
-    1456,  1458,  1460,  1462,  1464,  1466,  1471,  1475,  1507,  1509,
-    1515,  1521,  1534,  1535,  1536,  1541,  1546,  1550,  1554,  1569,
-    1581,  1586,  1622,  1640,  1641,  1647,  1648,  1653,  1655,  1662,
-    1679,  1696,  1698,  1705,  1710,  1718,  1728,  1740,  1749,  1753,
-    1757,  1761,  1765,  1769,  1772,  1774,  1778,  1782,  1786
+    1456,  1458,  1460,  1462,  1464,  1466,  1471,  1475,  1489,  1491,
+    1497,  1503,  1516,  1517,  1518,  1523,  1528,  1532,  1536,  1551,
+    1563,  1568,  1604,  1622,  1623,  1629,  1630,  1635,  1637,  1644,
+    1661,  1678,  1680,  1687,  1692,  1700,  1710,  1722,  1731,  1735,
+    1739,  1743,  1747,  1751,  1754,  1756,  1760,  1764,  1768
 };
 #endif
 
@@ -3693,40 +3693,22 @@ regular_print:
                        (yyval) = 
list_append(list_append(list_create((yyvsp[(1) - (2)])),
                                                instruction(Op_field_spec)), 
(yyvsp[(2) - (2)]));
                } else {
-                       if (do_optimize > 1 && (yyvsp[(2) - (2)])->nexti == 
(yyvsp[(2) - (2)])->lasti
-                                       && (yyvsp[(2) - (2)])->nexti->opcode == 
Op_push_i
-                                       && ((yyvsp[(2) - 
(2)])->nexti->memory->flags & (MPFN|MPZN)) == 0
-                       ) {
-                               NODE *n = (yyvsp[(2) - (2)])->nexti->memory;
-                               if ((n->flags & (STRCUR|STRING)) != 0) {
-                                       n->numbr = (AWKNUM) (n->stlen == 0);
-                                       n->flags &= ~(STRCUR|STRING);
-                                       n->flags |= (NUMCUR|NUMBER);
-                                       efree(n->stptr);
-                                       n->stptr = NULL;
-                                       n->stlen = 0;
-                               } else
-                                       n->numbr = (AWKNUM) (n->numbr == 0.0);
-                               bcfree((yyvsp[(1) - (2)]));
-                               (yyval) = (yyvsp[(2) - (2)]);
-                       } else {
-                               (yyvsp[(1) - (2)])->opcode = Op_not;
-                               add_lint((yyvsp[(2) - (2)]), 
LINT_assign_in_cond);
-                               (yyval) = list_append((yyvsp[(2) - (2)]), 
(yyvsp[(1) - (2)]));
-                       }
+                       (yyvsp[(1) - (2)])->opcode = Op_not;
+                       add_lint((yyvsp[(2) - (2)]), LINT_assign_in_cond);
+                       (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - 
(2)]));
                }
           }
     break;
 
   case 148:
 /* Line 1792 of yacc.c  */
-#line 1508 "awkgram.y"
+#line 1490 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 149:
 /* Line 1792 of yacc.c  */
-#line 1510 "awkgram.y"
+#line 1492 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3736,7 +3718,7 @@ regular_print:
 
   case 150:
 /* Line 1792 of yacc.c  */
-#line 1516 "awkgram.y"
+#line 1498 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3746,7 +3728,7 @@ regular_print:
 
   case 151:
 /* Line 1792 of yacc.c  */
-#line 1522 "awkgram.y"
+#line 1504 "awkgram.y"
     {
                static bool warned = false;
 
@@ -3763,7 +3745,7 @@ regular_print:
 
   case 154:
 /* Line 1792 of yacc.c  */
-#line 1537 "awkgram.y"
+#line 1519 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3772,7 +3754,7 @@ regular_print:
 
   case 155:
 /* Line 1792 of yacc.c  */
-#line 1542 "awkgram.y"
+#line 1524 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3781,7 +3763,7 @@ regular_print:
 
   case 156:
 /* Line 1792 of yacc.c  */
-#line 1547 "awkgram.y"
+#line 1529 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3789,7 +3771,7 @@ regular_print:
 
   case 157:
 /* Line 1792 of yacc.c  */
-#line 1551 "awkgram.y"
+#line 1533 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3797,7 +3779,7 @@ regular_print:
 
   case 158:
 /* Line 1792 of yacc.c  */
-#line 1555 "awkgram.y"
+#line 1537 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
@@ -3816,7 +3798,7 @@ regular_print:
 
   case 159:
 /* Line 1792 of yacc.c  */
-#line 1570 "awkgram.y"
+#line 1552 "awkgram.y"
     {
            /*
             * was: $$ = $2
@@ -3829,7 +3811,7 @@ regular_print:
 
   case 160:
 /* Line 1792 of yacc.c  */
-#line 1582 "awkgram.y"
+#line 1564 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3838,7 +3820,7 @@ regular_print:
 
   case 161:
 /* Line 1792 of yacc.c  */
-#line 1587 "awkgram.y"
+#line 1569 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3875,7 +3857,7 @@ regular_print:
 
   case 162:
 /* Line 1792 of yacc.c  */
-#line 1623 "awkgram.y"
+#line 1605 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3893,37 +3875,37 @@ regular_print:
 
   case 163:
 /* Line 1792 of yacc.c  */
-#line 1640 "awkgram.y"
+#line 1622 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 164:
 /* Line 1792 of yacc.c  */
-#line 1642 "awkgram.y"
+#line 1624 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 165:
 /* Line 1792 of yacc.c  */
-#line 1647 "awkgram.y"
+#line 1629 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 166:
 /* Line 1792 of yacc.c  */
-#line 1649 "awkgram.y"
+#line 1631 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 167:
 /* Line 1792 of yacc.c  */
-#line 1654 "awkgram.y"
+#line 1636 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 168:
 /* Line 1792 of yacc.c  */
-#line 1656 "awkgram.y"
+#line 1638 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3931,7 +3913,7 @@ regular_print:
 
   case 169:
 /* Line 1792 of yacc.c  */
-#line 1663 "awkgram.y"
+#line 1645 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -3949,7 +3931,7 @@ regular_print:
 
   case 170:
 /* Line 1792 of yacc.c  */
-#line 1680 "awkgram.y"
+#line 1662 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -3967,13 +3949,13 @@ regular_print:
 
   case 171:
 /* Line 1792 of yacc.c  */
-#line 1697 "awkgram.y"
+#line 1679 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 172:
 /* Line 1792 of yacc.c  */
-#line 1699 "awkgram.y"
+#line 1681 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3981,13 +3963,13 @@ regular_print:
 
   case 173:
 /* Line 1792 of yacc.c  */
-#line 1706 "awkgram.y"
+#line 1688 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 174:
 /* Line 1792 of yacc.c  */
-#line 1711 "awkgram.y"
+#line 1693 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
@@ -3999,7 +3981,7 @@ regular_print:
 
   case 175:
 /* Line 1792 of yacc.c  */
-#line 1719 "awkgram.y"
+#line 1701 "awkgram.y"
     {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@ -4010,7 +3992,7 @@ regular_print:
 
   case 176:
 /* Line 1792 of yacc.c  */
-#line 1729 "awkgram.y"
+#line 1711 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@ -4026,7 +4008,7 @@ regular_print:
 
   case 177:
 /* Line 1792 of yacc.c  */
-#line 1741 "awkgram.y"
+#line 1723 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@ -4036,7 +4018,7 @@ regular_print:
 
   case 178:
 /* Line 1792 of yacc.c  */
-#line 1750 "awkgram.y"
+#line 1732 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@ -4044,7 +4026,7 @@ regular_print:
 
   case 179:
 /* Line 1792 of yacc.c  */
-#line 1754 "awkgram.y"
+#line 1736 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@ -4052,43 +4034,43 @@ regular_print:
 
   case 180:
 /* Line 1792 of yacc.c  */
-#line 1757 "awkgram.y"
+#line 1739 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 182:
 /* Line 1792 of yacc.c  */
-#line 1765 "awkgram.y"
+#line 1747 "awkgram.y"
     { yyerrok; }
     break;
 
   case 183:
 /* Line 1792 of yacc.c  */
-#line 1769 "awkgram.y"
+#line 1751 "awkgram.y"
     { yyerrok; }
     break;
 
   case 186:
 /* Line 1792 of yacc.c  */
-#line 1778 "awkgram.y"
+#line 1760 "awkgram.y"
     { yyerrok; }
     break;
 
   case 187:
 /* Line 1792 of yacc.c  */
-#line 1782 "awkgram.y"
+#line 1764 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
   case 188:
 /* Line 1792 of yacc.c  */
-#line 1786 "awkgram.y"
+#line 1768 "awkgram.y"
     { yyerrok; }
     break;
 
 
 /* Line 1792 of yacc.c  */
-#line 4104 "awkgram.c"
+#line 4086 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4320,7 +4302,7 @@ yyreturn:
 
 
 /* Line 2055 of yacc.c  */
-#line 1788 "awkgram.y"
+#line 1770 "awkgram.y"
 
 
 struct token {
diff --git a/awkgram.y b/awkgram.y
index 985f37f..6112414 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -1481,27 +1481,9 @@ non_post_simp_exp
                        $$ = list_append(list_append(list_create($1),
                                                instruction(Op_field_spec)), 
$2);
                } else {
-                       if (do_optimize > 1 && $2->nexti == $2->lasti
-                                       && $2->nexti->opcode == Op_push_i
-                                       && ($2->nexti->memory->flags & 
(MPFN|MPZN)) == 0
-                       ) {
-                               NODE *n = $2->nexti->memory;
-                               if ((n->flags & (STRCUR|STRING)) != 0) {
-                                       n->numbr = (AWKNUM) (n->stlen == 0);
-                                       n->flags &= ~(STRCUR|STRING);
-                                       n->flags |= (NUMCUR|NUMBER);
-                                       efree(n->stptr);
-                                       n->stptr = NULL;
-                                       n->stlen = 0;
-                               } else
-                                       n->numbr = (AWKNUM) (n->numbr == 0.0);
-                               bcfree($1);
-                               $$ = $2;
-                       } else {
-                               $1->opcode = Op_not;
-                               add_lint($2, LINT_assign_in_cond);
-                               $$ = list_append($2, $1);
-                       }
+                       $1->opcode = Op_not;
+                       add_lint($2, LINT_assign_in_cond);
+                       $$ = list_append($2, $1);
                }
           }
        | '(' exp r_paren
diff --git a/awklib/Makefile.in b/awklib/Makefile.in
index d4a7788..347d369 100644
--- a/awklib/Makefile.in
+++ b/awklib/Makefile.in
@@ -83,11 +83,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
        $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
        $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
        $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
-       $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
-       $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
-       $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-       $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
-       $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+       $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+       $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+       $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -215,6 +216,7 @@ SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
 STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
diff --git a/configh.in b/configh.in
index 350aac5..af6b30f 100644
--- a/configh.in
+++ b/configh.in
@@ -20,12 +20,18 @@
 /* Define to 1 if you have the <arpa/inet.h> header file. */
 #undef HAVE_ARPA_INET_H
 
+/* Define to 1 if you have 'atan2l' function. */
+#undef HAVE_ATAN2L
+
 /* Define to 1 if you have the `atexit' function. */
 #undef HAVE_ATEXIT
 
 /* Define to 1 if you have the `btowc' function. */
 #undef HAVE_BTOWC
 
+/* Define to 1 if you have 'ceill' function. */
+#undef HAVE_CEILL
+
 /* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
    CoreFoundation framework. */
 #undef HAVE_CFLOCALECOPYCURRENT
@@ -34,6 +40,9 @@
    the CoreFoundation framework. */
 #undef HAVE_CFPREFERENCESCOPYAPPVALUE
 
+/* Define to 1 if you have 'cosl' function. */
+#undef HAVE_COSL
+
 /* Define if the GNU dcgettext() function is already present or preinstalled.
    */
 #undef HAVE_DCGETTEXT
@@ -45,12 +54,21 @@
 /* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
 #undef HAVE_DOPRNT
 
+/* Define to 1 if you have 'expl' function. */
+#undef HAVE_EXPL
+
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
+/* Define to 1 if you have 'floorl' function. */
+#undef HAVE_FLOORL
+
 /* Define to 1 if you have the `fmod' function. */
 #undef HAVE_FMOD
 
+/* Define to 1 if you have 'fmodl' function. */
+#undef HAVE_FMODL
+
 /* have getaddrinfo */
 #undef HAVE_GETADDRINFO
 
@@ -111,6 +129,12 @@
 /* Define to 1 if you have the <locale.h> header file. */
 #undef HAVE_LOCALE_H
 
+/* Define to 1 if you have 'logl' function. */
+#undef HAVE_LOGL
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
 /* Define to 1 if the system has the type `long long int'. */
 #undef HAVE_LONG_LONG_INT
 
@@ -162,6 +186,9 @@
 /* Define to 1 if you have the `posix_openpt' function. */
 #undef HAVE_POSIX_OPENPT
 
+/* Define to 1 if you have 'powl' function. */
+#undef HAVE_POWL
+
 /* Define to 1 if you have the `setenv' function. */
 #undef HAVE_SETENV
 
@@ -171,6 +198,9 @@
 /* Define to 1 if you have the `setsid' function. */
 #undef HAVE_SETSID
 
+/* Define to 1 if you have 'sinl' function. */
+#undef HAVE_SINL
+
 /* Define to 1 if you have the `snprintf' function. */
 #undef HAVE_SNPRINTF
 
@@ -180,6 +210,9 @@
 /* we have sockets on this system */
 #undef HAVE_SOCKETS
 
+/* Define to 1 if you have 'sqrtl' function. */
+#undef HAVE_SQRTL
+
 /* Define to 1 if you have the <stdarg.h> header file. */
 #undef HAVE_STDARG_H
 
@@ -225,6 +258,9 @@
 /* Define to 1 if you have the `strtod' function. */
 #undef HAVE_STRTOD
 
+/* Define to 1 if you have 'strtold' function. */
+#undef HAVE_STRTOLD
+
 /* Define to 1 if you have the `strtoul' function. */
 #undef HAVE_STRTOUL
 
@@ -375,6 +411,9 @@
 /* force use of our version of strftime */
 #undef USE_INCLUDED_STRFTIME
 
+/* Define to 1 if can use 'long double'. */
+#undef USE_LONG_DOUBLE
+
 /* Enable extensions on AIX 3, Interix.  */
 #ifndef _ALL_SOURCE
 # undef _ALL_SOURCE
diff --git a/configure b/configure
index fb1ad69..4bf106b 100755
--- a/configure
+++ b/configure
@@ -633,6 +633,7 @@ GAWKLIBEXT
 LIBMPFR
 LIBREADLINE
 SOCKET_LIBS
+USE_LONG_DOUBLE
 LIBSIGSEGV_PREFIX
 LTLIBSIGSEGV
 LIBSIGSEGV
@@ -8694,6 +8695,48 @@ _ACEOF
 fi
 
 
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double" >&5
+$as_echo_n "checking for long double... " >&6; }
+if ${ac_cv_type_long_double+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$GCC" = yes; then
+       ac_cv_type_long_double=yes
+     else
+       cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* The Stardent Vistra knows sizeof (long double), but does
+                not support it.  */
+             long double foo = 0.0L;
+int
+main ()
+{
+static int test_array [1 - 2 * !(/* On Ultrix 4.3 cc, long double is 4 and 
double is 8.  */
+             sizeof (double) <= sizeof (long double))];
+test_array [0] = 0;
+return test_array [0];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_type_long_double=yes
+else
+  ac_cv_type_long_double=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+     fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double" >&5
+$as_echo "$ac_cv_type_long_double" >&6; }
+  if test $ac_cv_type_long_double = yes; then
+
+$as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h
+
+  fi
+
 ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t" 
"$ac_includes_default"
 if test "x$ac_cv_type_ssize_t" = xyes; then :
 
@@ -10182,6 +10225,611 @@ fi
 $as_echo "$has_f_format" >&6; }
 
 
+  gawk_has_long_double=no
+  USE_LONG_DOUBLE=
+
+
+  if test $ac_cv_type_long_double = yes; then
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether long double and 
double are the same" >&5
+$as_echo_n "checking whether long double and double are the same... " >&6; }
+if ${gl_cv_long_double_equals_double+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <float.h>
+int
+main ()
+{
+typedef int check[sizeof (long double) == sizeof (double)
+                           && LDBL_MANT_DIG == DBL_MANT_DIG
+                           && LDBL_MAX_EXP == DBL_MAX_EXP
+                           && LDBL_MIN_EXP == DBL_MIN_EXP
+                              ? 1 : -1];
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  gl_cv_long_double_equals_double=yes
+else
+  gl_cv_long_double_equals_double=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
$gl_cv_long_double_equals_double" >&5
+$as_echo "$gl_cv_long_double_equals_double" >&6; }
+    if test $gl_cv_long_double_equals_double = no; then
+      { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether printf 
supports %Lf" >&5
+$as_echo_n "checking whether printf supports %Lf... " >&6; }
+if ${gawk_cv_has_L_format+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "$cross_compiling" = yes; then :
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdio.h>
+int
+main ()
+{
+char buf[100];
+          sprintf(buf, "%Lf,%Lg,%Le", (long double) 1.0, (long double) 1.0, 
(long double) 1.0);
+           if (strcmp(buf, "1.000000,1,1.000000e+00") == 0)
+              return 0;
+          return 1;
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+  gawk_cv_has_L_format=yes
+else
+  gawk_cv_has_L_format=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gawk_cv_has_L_format" >&5
+$as_echo "$gawk_cv_has_L_format" >&6; }
+      if test $gawk_cv_has_L_format = yes; then
+        gawk_has_long_double=yes
+      fi
+    fi
+  fi
+
+  if test $gawk_has_long_double = yes; then
+
+$as_echo "#define USE_LONG_DOUBLE 1" >>confdefs.h
+
+
+    ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold"
+if test "x$ac_cv_func_strtold" = xyes; then :
+
+fi
+
+    if test $ac_cv_func_strtold = yes; then
+
+$as_echo "#define HAVE_STRTOLD 1" >>confdefs.h
+
+    fi
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sinl in -lm" >&5
+$as_echo_n "checking for sinl in -lm... " >&6; }
+if ${ac_cv_lib_m_sinl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sinl ();
+int
+main ()
+{
+return sinl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_sinl=yes
+else
+  ac_cv_lib_m_sinl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sinl" >&5
+$as_echo "$ac_cv_lib_m_sinl" >&6; }
+if test "x$ac_cv_lib_m_sinl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_sinl = yes; then
+
+$as_echo "#define HAVE_SINL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cosl in -lm" >&5
+$as_echo_n "checking for cosl in -lm... " >&6; }
+if ${ac_cv_lib_m_cosl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cosl ();
+int
+main ()
+{
+return cosl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_cosl=yes
+else
+  ac_cv_lib_m_cosl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cosl" >&5
+$as_echo "$ac_cv_lib_m_cosl" >&6; }
+if test "x$ac_cv_lib_m_cosl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_cosl = yes; then
+
+$as_echo "#define HAVE_COSL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l in -lm" >&5
+$as_echo_n "checking for atan2l in -lm... " >&6; }
+if ${ac_cv_lib_m_atan2l+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char atan2l ();
+int
+main ()
+{
+return atan2l ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_atan2l=yes
+else
+  ac_cv_lib_m_atan2l=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_atan2l" >&5
+$as_echo "$ac_cv_lib_m_atan2l" >&6; }
+if test "x$ac_cv_lib_m_atan2l" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_atan2l = yes; then
+
+$as_echo "#define HAVE_ATAN2L 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl in -lm" >&5
+$as_echo_n "checking for logl in -lm... " >&6; }
+if ${ac_cv_lib_m_logl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char logl ();
+int
+main ()
+{
+return logl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_logl=yes
+else
+  ac_cv_lib_m_logl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_logl" >&5
+$as_echo "$ac_cv_lib_m_logl" >&6; }
+if test "x$ac_cv_lib_m_logl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_logl = yes; then
+
+$as_echo "#define HAVE_LOGL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl in -lm" >&5
+$as_echo_n "checking for expl in -lm... " >&6; }
+if ${ac_cv_lib_m_expl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char expl ();
+int
+main ()
+{
+return expl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_expl=yes
+else
+  ac_cv_lib_m_expl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_expl" >&5
+$as_echo "$ac_cv_lib_m_expl" >&6; }
+if test "x$ac_cv_lib_m_expl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_expl = yes; then
+
+$as_echo "#define HAVE_EXPL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl in -lm" >&5
+$as_echo_n "checking for fmodl in -lm... " >&6; }
+if ${ac_cv_lib_m_fmodl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char fmodl ();
+int
+main ()
+{
+return fmodl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_fmodl=yes
+else
+  ac_cv_lib_m_fmodl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_fmodl" >&5
+$as_echo "$ac_cv_lib_m_fmodl" >&6; }
+if test "x$ac_cv_lib_m_fmodl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_fmodl = yes; then
+
+$as_echo "#define HAVE_FMODL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for floorl in -lm" >&5
+$as_echo_n "checking for floorl in -lm... " >&6; }
+if ${ac_cv_lib_m_floorl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char floorl ();
+int
+main ()
+{
+return floorl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_floorl=yes
+else
+  ac_cv_lib_m_floorl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floorl" >&5
+$as_echo "$ac_cv_lib_m_floorl" >&6; }
+if test "x$ac_cv_lib_m_floorl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_floorl = yes; then
+
+$as_echo "#define HAVE_FLOORL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ceill in -lm" >&5
+$as_echo_n "checking for ceill in -lm... " >&6; }
+if ${ac_cv_lib_m_ceill+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ceill ();
+int
+main ()
+{
+return ceill ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_ceill=yes
+else
+  ac_cv_lib_m_ceill=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_ceill" >&5
+$as_echo "$ac_cv_lib_m_ceill" >&6; }
+if test "x$ac_cv_lib_m_ceill" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_ceill = yes; then
+
+$as_echo "#define HAVE_CEILL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl in -lm" >&5
+$as_echo_n "checking for powl in -lm... " >&6; }
+if ${ac_cv_lib_m_powl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char powl ();
+int
+main ()
+{
+return powl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_powl=yes
+else
+  ac_cv_lib_m_powl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_powl" >&5
+$as_echo "$ac_cv_lib_m_powl" >&6; }
+if test "x$ac_cv_lib_m_powl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_powl = yes; then
+
+$as_echo "#define HAVE_POWL 1" >>confdefs.h
+
+    fi
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl in -lm" >&5
+$as_echo_n "checking for sqrtl in -lm... " >&6; }
+if ${ac_cv_lib_m_sqrtl+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sqrtl ();
+int
+main ()
+{
+return sqrtl ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_m_sqrtl=yes
+else
+  ac_cv_lib_m_sqrtl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrtl" >&5
+$as_echo "$ac_cv_lib_m_sqrtl" >&6; }
+if test "x$ac_cv_lib_m_sqrtl" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+  LIBS="-lm $LIBS"
+
+fi
+
+    if test $ac_cv_lib_m_sqrtl = yes; then
+
+$as_echo "#define HAVE_SQRTL 1" >>confdefs.h
+
+    fi
+  fi
+
+
+
+
+
 gawk_have_sockets=no
 # Check for system-dependent location of socket libraries
 
diff --git a/configure.ac b/configure.ac
index fef29e0..d3780bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,7 @@ AC_TYPE_LONG_LONG_INT
 AC_TYPE_UNSIGNED_LONG_LONG_INT
 AC_TYPE_INTMAX_T
 AC_TYPE_UINTMAX_T
+AC_TYPE_LONG_DOUBLE
 AC_CHECK_TYPE(ssize_t, int)
 AC_CHECK_SIZEOF(unsigned int)
 AC_CHECK_SIZEOF(unsigned long)
@@ -343,6 +344,9 @@ if test "$has_f_format" = yes; then
 fi
 AC_MSG_RESULT($has_f_format)
 
+dnl see if long double is usable
+GAWK_USE_LONG_DOUBLE
+
 dnl check for sockets
 GAWK_AC_LIB_SOCKETS
 
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 93e88c2..691d030 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -83,11 +83,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
        $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
        $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
        $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
-       $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
-       $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
-       $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-       $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
-       $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+       $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+       $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+       $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -210,6 +211,7 @@ SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
 STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@
diff --git a/gawkapi.c b/gawkapi.c
index a64a62c..c22b3b2 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -661,12 +661,15 @@ api_sym_update_scalar(awk_ext_id_t id,
                        if ((r->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
                                efree(r->stptr);
 
-                       if (free_number && (r->flags & (NUMBER|NUMCUR)) != 0)
+                       if (free_number && (r->flags & (NUMBER|NUMCUR)) != 0) {
                                free_number(r);
+                               r->flags &= ~(NUMBER|NUMCUR);
+                       }
                        free_wstr(r);
 
                        /* make_str_node(s, l, ALREADY_MALLOCED): */
                        r->numbr = 0;
+                       r->qnumbr = NULL;
                        r->flags = (MALLOC|STRING|STRCUR);
                        r->stfmt = -1;
                        r->stptr = value->str_value.str;
diff --git a/long_double.c b/long_double.c
new file mode 100644
index 0000000..b50e3fe
--- /dev/null
+++ b/long_double.c
@@ -0,0 +1,2245 @@
+/*
+ * long_double.c - routines for C long double support in gawk.
+ */
+
+/* 
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+
+#ifdef USE_LONG_DOUBLE
+#include "math.h"
+#include "random.h"
+#include "floatmagic.h"        /* definition of isnan */
+
+#define AWKLDBL        long double
+
+/* XXX: define to 1 to try AWKNUM as long double */
+/* #define AWKNUM_LDBL 1 */
+
+
+#include "long_double.h"
+
+#ifdef AWKNUM_LDBL
+#define LDBL(n)        ((n)->numbr)
+#else
+#define LDBL(n)        (*((AWKLDBL *) (n)->qnumbr))
+#endif
+
+/* Can declare these, since we always use the random shipped with gawk */
+extern char *initstate(unsigned long seed, char *state, long n);
+extern char *setstate(char *state);
+extern long random(void);
+extern void srandom(unsigned long seed);
+
+/*
+ * Since we supply the version of random(), we know what
+ * value to use here.
+ */
+#define GAWK_RANDOM_MAX 0x7fffffffL
+
+extern NODE **fmt_list;          /* declared in eval.c */
+
+/*
+ * FIXME -- some of these are almost identical except for the number definition
+ * #define DBLNUM      AWKNUM
+ *     common routines
+ * #undef DBLNUM
+ * #define DBLNUM      AWKLDBL
+ *     ...
+ */
+
+/* exported routines */
+
+static NODE *make_awknum(AWKNUM);
+static void free_awkldbl(NODE *tmp);
+static int cmp_awkldbls(const NODE *, const NODE *);
+static void negate_awkldbl(NODE *);
+static NODE *str2awkldbl(char *, char **, int, bool);
+static NODE *force_awkldbl(NODE *);
+static NODE *format_awkldbl_val(const char *, int, NODE *);
+static unsigned long awkldbl_toulong(const NODE *);
+static long awkldbl_tolong(const NODE *);
+static AWKNUM awkldbl_todouble(const NODE *);
+static uintmax_t awkldbl_touintmax_t(const NODE *);
+static int awkldbl_sgn(const NODE *);
+static bool awkldbl_is_integer(const NODE *);
+static NODE *awkldbl_copy(const NODE *);
+static NODE *format_nodes_awkldbl(const char *, size_t, NODE **, long);
+static bool awkldbl_init(bltin_t **);
+static NODE *awkldbl_add(const NODE *, const NODE *);
+static NODE *awkldbl_sub(const NODE *, const NODE *);
+static NODE *awkldbl_mul(const NODE *, const NODE *);
+static NODE *awkldbl_div(const NODE *, const NODE *);
+static NODE *awkldbl_mod(const NODE *, const NODE *);
+static NODE *awkldbl_pow(const NODE *, const NODE *);
+static NODE *awkldbl_add_long(const NODE *, long);
+static NODE *awkldbl_update_var(NODE *);
+static void awkldbl_set_var(const NODE *);
+static long awkldbl_increment_var(const NODE *, long);
+static void awkldbl_init_vars(void);
+
+static NODE *do_and(int);
+static NODE *do_atan2(int);
+static NODE *do_compl(int);
+static NODE *do_cos(int);
+static NODE *do_exp(int);
+static NODE *do_int(int);
+static NODE *do_log(int);
+static NODE *do_lshift(int);
+static NODE *do_or(int);
+static NODE *do_rand(int);
+static NODE *do_rshift(int);
+static NODE *do_sin(int);
+static NODE *do_sqrt(int);
+static NODE *do_srand(int);
+static NODE *do_strtonum(int);
+static NODE *do_xor(int);
+
+/* private routines */
+static int is_ieee_magic_val(const char *val);
+static AWKLDBL get_ieee_magic_val(const char *val);
+static AWKLDBL calc_exp(AWKLDBL x1, AWKLDBL x2);
+static AWKLDBL double_to_int(AWKLDBL d);
+#ifndef AWKNUM_LDBL
+static NODE *make_awkldbl(AWKLDBL);
+#endif
+
+static long MFNR;
+static long MNR;
+
+#ifdef AWKNUM_LDBL
+#define get_long_double(d)     /* nothing */
+#define free_long_double(d)    /* nothing */
+#else
+#define get_long_double(d)     getblock(d, BLOCK_LDBL, AWKLDBL *)
+#define free_long_double(d)    freeblock(d, BLOCK_LDBL)
+#endif
+
+#if 0
+#define get_long_double(d)     emalloc(d, void *, sizeof(AWKLDBL), 
"long_double")
+#define free_long_double(d)    efree(d)
+#endif
+
+numbr_handler_t awkldbl_hndlr = {
+       awkldbl_init,
+       NULL,   /* version_str */
+       NULL,   /* load_procinfo */
+       make_awknum,
+       str2awkldbl,
+       awkldbl_copy,
+#ifndef AWKNUM_LDBL
+       free_awkldbl,
+#else
+       NULL,   /* free_awkldbl --- not needed for AWKNUM */
+#endif
+       force_awkldbl,
+       negate_awkldbl,
+       cmp_awkldbls,
+       awkldbl_sgn,
+       awkldbl_is_integer,
+       format_awkldbl_val,
+       format_nodes_awkldbl,
+       awkldbl_todouble,
+       awkldbl_tolong,
+       awkldbl_toulong,
+       awkldbl_touintmax_t,
+       awkldbl_add,
+       awkldbl_sub,
+       awkldbl_mul,
+       awkldbl_div,
+       awkldbl_mod,
+       awkldbl_pow,
+       awkldbl_add_long,
+       awkldbl_update_var,
+       awkldbl_set_var,
+       awkldbl_increment_var,
+       awkldbl_init_vars,
+};
+
+/* awkldbl_init --- initialization routine */
+
+static bool
+awkldbl_init(bltin_t **numbr_bltins)
+{
+       static bltin_t awkldbl_bltins[] = {
+               { "and",        do_and },
+               { "atan2",      do_atan2 },
+               { "compl",      do_compl },
+               { "cos",        do_cos },
+               { "exp",        do_exp },
+               { "int",        do_int },
+               { "log",        do_log },
+               { "lshift",     do_lshift },
+               { "or",         do_or },
+               { "rand",       do_rand },
+               { "rshift",     do_rshift },
+               { "sin",        do_sin },
+               { "sqrt",       do_sqrt },
+               { "srand",      do_srand },
+               { "strtonum",   do_strtonum },
+               { "xor",        do_xor },
+               { NULL, NULL },
+       };
+
+       /* set the numeric value of null string */
+       get_long_double(Nnull_string->qnumbr);
+       LDBL(Nnull_string) = 0.0;
+       Nnull_string->flags |= (NUMCUR|NUMBER);
+
+       /* initialize TRUE and FALSE nodes */
+       false_node = make_awkldbl(0.0);
+       true_node = make_awkldbl(1.0);
+       false_node->flags |= NUMINT;
+       true_node->flags |= NUMINT;
+
+       *numbr_bltins = awkldbl_bltins;
+       return true;
+}
+
+/* awkldbl_toulong --- conversion to unsigned long */
+
+static unsigned long
+awkldbl_toulong(const NODE *n)
+{
+       return LDBL(n);
+}
+
+/* awkldbl_tolong --- conversion to long */
+
+static long
+awkldbl_tolong(const NODE *n)
+{
+       return LDBL(n);
+}
+
+/* awkldbl_todouble --- conversion to AWKNUM */
+
+static AWKNUM
+awkldbl_todouble(const NODE *n)
+{
+       return LDBL(n);
+}
+
+/* awkldbl_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+awkldbl_touintmax_t(const NODE *n)
+{
+       return LDBL(n);
+}
+
+/* awkldbl_sgn --- return 1 if number > 0, zero if number == 0, and -1 if 
number < 0 */
+
+static int
+awkldbl_sgn(const NODE *n)
+{
+       AWKLDBL d = LDBL(n);
+       return (d < 0.0 ? -1 : d > 0.0);
+}
+
+/* awkldbl_is_integer --- check if a number is an integer */
+
+static bool
+awkldbl_is_integer(const NODE *n)
+{
+       AWKLDBL d = LDBL(n);
+
+       if (isnan(d) || isinf(d))
+               return false;
+       return double_to_int(d) == d;
+}
+
+/* negate_awkldbl --- negate number in NODE */
+
+static void
+negate_awkldbl(NODE *n)
+{
+       LDBL(n) = - LDBL(n);
+}
+
+/* awkldbl_add --- add two numbers */
+
+static NODE *
+awkldbl_add(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(LDBL(t1) + LDBL(t2));
+}
+
+/* awkldbl_sub --- subtract two numbers */
+
+static NODE *
+awkldbl_sub(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(LDBL(t1) - LDBL(t2));
+}
+
+/* awkldbl_mul --- multiply two numbers */
+
+static NODE *
+awkldbl_mul(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(LDBL(t1) * LDBL(t2));
+}
+
+/* awkldbl_add --- quotient of two numbers */
+
+static NODE *
+awkldbl_div(const NODE *t1, const NODE *t2)
+{
+       AWKLDBL d = LDBL(t2);
+       if (d == 0)
+               fatal(_("division by zero attempted"));
+       return make_awkldbl(LDBL(t1) / d);
+}
+
+/* awkldbl_add_long --- add long value to a number */
+
+static NODE *
+awkldbl_add_long(const NODE *t1, long n)
+{
+       return make_awkldbl(LDBL(t1) + n);
+}
+
+/* awkldbl_copy --- copy a number */
+
+static NODE *
+awkldbl_copy(const NODE *t1)
+{
+       return make_awkldbl(LDBL(t1));
+}
+
+/* awkldbl_update_var --- update a special variable from internal variables */
+
+static NODE *
+awkldbl_update_var(NODE *var)
+{
+       NODE *val = var->var_value;
+       AWKLDBL d;
+
+       d = LDBL(val);
+       if (var == NR_node) {
+               if (MNR == 0 && d != NR) {
+                       unref(val);
+                       val = NR_node->var_value = make_awkldbl(NR);
+               } else if (MNR != 0) {
+                       unref(val);
+                       d = ((AWKLDBL) MNR) * LONG_MAX + NR;
+                       val = var->var_value = make_awkldbl(d);
+               }
+               return val;
+       }
+
+       assert(var == FNR_node);
+       if (MFNR == 0 && d != FNR) {
+               unref(val);
+               val = FNR_node->var_value = make_awkldbl(FNR);
+       } else if (MFNR != 0) {
+               unref(val);
+               d = ((AWKLDBL) MFNR) * LONG_MAX + FNR;
+               val = var->var_value = make_awkldbl(d);
+       }
+       return val;
+}
+
+/*
+ * awkldbl_set_vars --- update internal variables for assignment
+ *     to a special variable.
+ */
+
+static void
+awkldbl_set_var(const NODE *var)
+{
+       NODE *val = var->var_value;
+       AWKLDBL d;
+
+       d = LDBL(val);
+       if (var == NR_node) {
+               MNR = d / LONG_MAX;
+               NR = d - ((AWKLDBL) MNR) * LONG_MAX;
+       } else if (var == FNR_node) {
+               MFNR = d / LONG_MAX;
+               FNR = d - ((AWKLDBL) MFNR) * LONG_MAX;
+       }
+       /* N.B: PREC and ROUNMODE -- not relevant */
+}
+
+/* awkldbl_increment_var --- increment NR or FNR */
+
+static long
+awkldbl_increment_var(const NODE *var, long nr)
+{
+       if (nr == LONG_MAX - 1) {
+               /* increment quotient, set remainder(NR or FNR) to 0 */
+               if (var == NR_node)
+                       MNR++;
+               else /* var == FNR_node */
+                       MFNR++;
+               return 0;
+       }
+       return ++nr;
+}
+
+/* awkldbl_init_vars --- initialize special variables */
+
+static void
+awkldbl_init_vars()
+{
+       /* dummy function */
+}
+
+/*
+ * make_awkldbl --- allocate a node with defined number;
+ *     this routine is not exported. 
+ */
+
+#ifndef AWKNUM_LDBL
+static NODE *
+make_awkldbl(AWKLDBL x)
+{
+       NODE *r;
+       getnode(r);
+       r->type = Node_val;
+       get_long_double(r->qnumbr);
+       LDBL(r) = x;
+       r->flags = MALLOC|NUMBER|NUMCUR;
+       r->valref = 1;
+       r->stptr = NULL;
+       r->stlen = 0;
+#if MBS_SUPPORT
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+       return r;
+}
+#endif
+
+/* make_awknum --- allocate a node with defined AWKNUM */
+
+static NODE *
+make_awknum(AWKNUM x)
+{
+       NODE *r;
+       getnode(r);
+       r->type = Node_val;
+       get_long_double(r->qnumbr);
+       LDBL(r) = (AWKLDBL) x;
+       r->flags = MALLOC|NUMBER|NUMCUR;
+       r->valref = 1;
+       r->stptr = NULL;
+       r->stlen = 0;
+#if MBS_SUPPORT
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+       return r;
+}
+
+/* free_awkldbl --- free all storage allocated for a AWKLDBL */
+
+#ifndef AWKNUM_LDBL
+static void
+free_awkldbl(NODE *tmp)
+{
+       assert((tmp->flags & (NUMBER|NUMCUR)) != 0);
+        free_long_double(tmp->qnumbr);
+}
+#endif
+
+/* make_integer --- Convert an integer to a number node. */
+
+static inline NODE *
+make_integer(uintmax_t n)
+{
+       /* TODO -- check adjust_uint (floatcomp.c) */
+
+       n = adjust_uint(n);
+       return make_awkldbl(n);
+}
+
+/* do_lshift --- perform a << operation */
+
+static NODE *
+do_lshift(int nargs)
+{
+       NODE *s1, *s2;
+       uintmax_t uval, ushift, res;
+       AWKLDBL val, shift;
+
+       s2 = POP_SCALAR();
+       s1 = POP_SCALAR();
+       if (do_lint) {
+               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("lshift: received non-numeric first 
argument"));
+               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("lshift: received non-numeric second 
argument"));
+       }
+
+       (void) force_number(s1);
+       (void) force_number(s2);
+       val = LDBL(s1);
+       shift = LDBL(s2);
+
+       if (do_lint) {
+               if (val < 0 || shift < 0)
+                       lintwarn(_("lshift(%Lf, %Lf): negative values will give 
strange results"),
+                                       val, shift);
+               if (double_to_int(val) != val || double_to_int(shift) != shift)
+                       lintwarn(_("lshift(%Lf, %Lf): fractional values will be 
truncated"),
+                                       val, shift);
+               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+                       lintwarn(_("lshift(%Lf, %Lf): too large shift value 
will give strange results"),
+                                       val, shift);
+       }
+
+       DEREF(s1);
+       DEREF(s2);
+       uval = (uintmax_t) val;
+       ushift = (uintmax_t) shift;
+       res = uval << ushift;
+       return make_integer(res);
+}
+
+/* do_rshift --- perform a >> operation */
+
+static NODE *
+do_rshift(int nargs)
+{
+       NODE *s1, *s2;
+       uintmax_t uval, ushift, res;
+       AWKLDBL val, shift;
+
+       s2 = POP_SCALAR();
+       s1 = POP_SCALAR();
+       if (do_lint) {
+               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("rshift: received non-numeric first 
argument"));
+               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("rshift: received non-numeric second 
argument"));
+       }
+       (void) force_number(s1);
+       (void) force_number(s2);
+       val = LDBL(s1);
+       shift = LDBL(s2);
+       if (do_lint) {
+               if (val < 0 || shift < 0)
+                       lintwarn(_("rshift(%Lf, %Lf): negative values will give 
strange results"),
+                                       val, shift);
+               if (double_to_int(val) != val || double_to_int(shift) != shift)
+                       lintwarn(_("rshift(%Lf, %Lf): fractional values will be 
truncated"),
+                                       val, shift);
+               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+                       lintwarn(_("rshift(%Lf, %Lf): too large shift value 
will give strange results"),
+                                       val, shift);
+       }
+
+       DEREF(s1);
+       DEREF(s2);
+       uval = (uintmax_t) val;
+       ushift = (uintmax_t) shift;
+       res = uval >> ushift;
+       return make_integer(res);
+}
+
+/* do_and --- perform an & operation */
+
+static NODE *
+do_and(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKLDBL val;
+       int i;
+
+       res = ~0;       /* start off with all ones */
+       if (nargs < 2)
+               fatal(_("and: called with less than two arguments"));
+
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("and: argument %d is non-numeric"), i);
+
+               (void) force_number(s1);
+               val = LDBL(s1);
+               if (do_lint && val < 0)
+                       lintwarn(_("and: argument %d negative value %Lg will 
give strange results"),
+                                       i, val);
+
+               uval = (uintmax_t) val;
+               res &= uval;
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_or --- perform an | operation */
+
+static NODE *
+do_or(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKLDBL val;
+       int i;
+
+       res = 0;
+       if (nargs < 2)
+               fatal(_("or: called with less than two arguments"));
+
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("or: argument %d is non-numeric"), i);
+
+               (void) force_number(s1);
+               val = LDBL(s1);
+               if (do_lint && val < 0)
+                       lintwarn(_("or: argument %d negative value %Lg will 
give strange results"),
+                                       i, val);
+
+               uval = (uintmax_t) val;
+               res |= uval;
+
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_xor --- perform an ^ operation */
+
+static NODE *
+do_xor(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKLDBL val;
+       int i;
+
+       if (nargs < 2)
+               fatal(_("xor: called with less than two arguments"));
+
+       res = 0;        /* silence compiler warning */
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("xor: argument %d is non-numeric"), i);
+
+               (void) force_number(s1);
+               val = LDBL(s1);
+               if (do_lint && val < 0)
+                       lintwarn(_("xor: argument %d negative value %Lg will 
give strange results"),
+                                       i, val);
+
+               uval = (uintmax_t) val;
+               if (i == 1)
+                       res = uval;
+               else
+                       res ^= uval;
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_compl --- perform a ~ operation */
+
+static NODE *
+do_compl(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+       uintmax_t uval;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("compl: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = LDBL(tmp);
+       DEREF(tmp);
+
+       if (do_lint) {
+               if (d < 0)
+                       lintwarn(_("compl(%Lf): negative value will give 
strange results"), d);
+               if (double_to_int(d) != d)
+                       lintwarn(_("compl(%Lf): fractional value will be 
truncated"), d);
+       }
+
+       uval = (uintmax_t) d;
+       uval = ~ uval;
+       return make_integer(uval);
+}
+
+/* nondec2awkldbl --- convert octal or hex value to long double */
+
+/*
+ * Because of awk's concatenation rules and the way awk.y:yylex()
+ * collects a number, this routine has to be willing to stop on the
+ * first invalid character.
+ */
+
+static AWKLDBL
+nondec2awkldbl(char *str, size_t len)
+{
+       AWKLDBL retval = 0.0;
+       char save;
+       short val;
+       char *start = str;
+
+       if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+               /*
+                * User called strtonum("0x") or some such,
+                * so just quit early.
+                */
+               if (len <= 2)
+                       return 0.0;
+
+               for (str += 2, len -= 2; len > 0; len--, str++) {
+                       switch (*str) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               val = *str - '0';
+                               break;
+                       case 'a':
+                       case 'b':
+                       case 'c':
+                       case 'd':
+                       case 'e':
+                       case 'f':
+                               val = *str - 'a' + 10;
+                               break;
+                       case 'A':
+                       case 'B':
+                       case 'C':
+                       case 'D':
+                       case 'E':
+                       case 'F':
+                               val = *str - 'A' + 10;
+                               break;
+                       default:
+                               goto done;
+                       }
+                       retval = (retval * 16) + val;
+               }
+       } else if (*str == '0') {
+               for (; len > 0; len--) {
+                       if (! isdigit((unsigned char) *str))
+                               goto done;
+                       else if (*str == '8' || *str == '9') {
+                               str = start;
+                               goto decimal;
+                       }
+                       retval = (retval * 8) + (*str - '0');
+                       str++;
+               }
+       } else {
+decimal:
+               save = str[len];
+               retval = gawk_strtold(str, NULL);
+               str[len] = save;
+       }
+done:
+       return retval;
+}
+
+
+/* do_rand --- do the rand function */
+
+static bool firstrand = true;
+/* Some systems require this array to be integer aligned. Sigh. */
+#define SIZEOF_STATE 256
+static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
+static char *const state = (char *const) istate;
+
+/* ARGSUSED */
+static NODE *
+do_rand(int nargs ATTRIBUTE_UNUSED)
+{
+       if (firstrand) {
+               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+               /* don't need to srandom(1), initstate() does it for us. */
+               firstrand = false;
+               setstate(state);
+       }
+       /*
+        * Per historical practice and POSIX, return value N is
+        *
+        *      0 <= n < 1
+        */
+       return make_awkldbl((random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+}
+
+/* do_srand --- seed the random number generator */
+
+static NODE *
+do_srand(int nargs)
+{
+       NODE *tmp;
+       static long save_seed = 1;
+       long ret = save_seed;   /* SVR4 awk srand returns previous seed */
+       AWKLDBL d;
+
+       if (firstrand) {
+               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+               /* don't need to srandom(1), we're changing the seed below */
+               firstrand = false;
+               (void) setstate(state);
+       }
+
+       if (nargs == 0)
+               srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
+       else {
+               tmp = POP_SCALAR();
+               if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("srand: received non-numeric argument"));
+               (void) force_number(tmp);
+               d = LDBL(tmp);
+               srandom((unsigned int) (save_seed = (long) d));
+               DEREF(tmp);
+       }
+       return make_awkldbl(ret);
+}
+
+/* str2awkldbl --- create a number node from string */
+
+static NODE *
+str2awkldbl(char *str, char **endptr, int base, bool is_integer 
ATTRIBUTE_UNUSED)
+{
+       NODE *r;
+       AWKLDBL d;
+
+       if (base == 0) {
+               /*
+                * special case -- only used to parse input in the debugger?
+                * FIXME: reject ieee specials we don't want and/or use the same
+                * rules when reading numbers from a source file and nuke this 
case.
+                * Also in double.c.
+                */
+
+               errno = 0;
+               d = gawk_strtold(str, endptr);
+               if (errno != 0)
+                       d = 0;
+       } else {
+               if (base == 8 || base == 16)
+                       d = nondec2awkldbl(str, strlen(str));
+               else {
+                       /* atof for double */
+                       errno = 0;
+                       d = gawk_strtold(str, NULL);
+                       if (errno != 0)
+                               d = 0;
+                       errno = 0;
+               }
+       }
+
+       r = make_awkldbl(d);
+
+       /* XXX: is this relevant ? */
+       if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+               r->flags |= NUMINT;
+
+       return r;
+}
+
+/* awkldbl_mod --- remainder from division of two numbers */
+
+static NODE *
+awkldbl_mod(const NODE *t1, const NODE *t2)
+{
+       AWKLDBL d2;
+
+       d2 = LDBL(t2);
+       if (d2 == 0)
+               fatal(_("division by zero attempted in `%%'"));
+       return make_awkldbl(gawk_fmodl(LDBL(t1), d2));
+}
+
+/* awkldbl_pow --- power function */
+
+static NODE *
+awkldbl_pow(const NODE *t1, const NODE *t2)
+{
+       return make_awkldbl(calc_exp(LDBL(t1), LDBL(t2)));
+}
+
+
+/*
+ * calc_exp_posint --- calculate x^n for positive integral n,
+ *     using exponentiation by squaring without recursion.
+ */
+
+static AWKLDBL
+calc_exp_posint(AWKLDBL x, long n)
+{
+       AWKLDBL mult = 1;
+
+       while (n > 1) {
+               if ((n % 2) == 1)
+                       mult *= x;
+               x *= x;
+               n /= 2;
+       }
+       return mult * x;
+}
+
+/* calc_exp --- calculate x1^x2 */
+
+static AWKLDBL
+calc_exp(AWKLDBL x1, AWKLDBL x2)
+{
+       long lx;
+
+       if ((lx = x2) == x2) {          /* integer exponent */
+               if (lx == 0)
+                       return 1;
+               return (lx > 0) ? calc_exp_posint(x1, lx)
+                               : 1.0 / calc_exp_posint(x1, -lx);
+       }
+       return gawk_powl(x1, x2);
+}
+
+/* cmp_awkldbls --- compare two doubles */
+
+static int
+cmp_awkldbls(const NODE *t1, const NODE *t2)
+{
+       /*
+        * This routine is also used to sort numeric array indices or values.
+        * For the purposes of sorting, NaN is considered greater than
+        * any other value, and all NaN values are considered equivalent and 
equal.
+        * This isn't in compliance with IEEE standard, but compliance w.r.t. 
NaN
+        * comparison at the awk level is a different issue, and needs to be 
dealt
+        * with in the interpreter for each opcode seperately.
+        */
+       AWKLDBL d1 = LDBL(t1);
+       AWKLDBL d2 = LDBL(t2);
+
+       if (isnan(d1))
+               return ! isnan(d2);
+       if (isnan(d2))
+               return -1;
+       /* don't subtract, in case one or both are infinite */
+       if (d1 == d2)
+               return 0;
+       if (d1 < d2)
+               return -1;
+       return 1;
+}
+
+/* force_awkldbl --- force a value to be numeric */
+
+static NODE *
+force_awkldbl(NODE *n)
+{
+       char *cp;
+       char *cpend;
+       char save;
+       char *ptr;
+       unsigned int newflags;
+
+       if ((n->flags & NUMCUR) != 0)
+               return n;
+
+       /* all the conditionals are an attempt to avoid the expensive strtod */
+
+       /* Note: only set NUMCUR if we actually convert some digits */
+
+       get_long_double(n->qnumbr);
+       LDBL(n) = 0.0;
+
+       if (n->stlen == 0) {
+               return n;
+       }
+
+       cp = n->stptr;
+       /*
+        * 2/2007:
+        * POSIX, by way of severe language lawyering, seems to
+        * allow things like "inf" and "nan" to mean something.
+        * So if do_posix, the user gets what he deserves.
+        * This also allows hexadecimal floating point. Ugh.
+        */
+       if (! do_posix) {
+               if (isalpha((unsigned char) *cp)) {
+                       return n;
+               } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
+                       if ((n->flags & MAYBE_NUM) != 0)
+                               n->flags &= ~MAYBE_NUM;
+                       n->flags |= NUMBER|NUMCUR;
+                       LDBL(n) = get_ieee_magic_val(n->stptr);
+                       return n;
+               }
+               /* else
+                       fall through */
+       }
+       /* else not POSIX, so
+               fall through */
+
+       cpend = cp + n->stlen;
+       while (cp < cpend && isspace((unsigned char) *cp))
+               cp++;
+
+       if (   cp == cpend              /* only spaces, or */
+           || (! do_posix              /* not POSIXLY paranoid and */
+               && (isalpha((unsigned char) *cp)        /* letter, or */
+                                       /* CANNOT do non-decimal and saw 0x */
+                   || (! do_non_decimal_data && cp[0] == '0'
+                       && (cp[1] == 'x' || cp[1] == 'X'))))) {
+               return n;
+       }
+
+       if ((n->flags & MAYBE_NUM) != 0) {
+               newflags = NUMBER;
+               n->flags &= ~MAYBE_NUM;
+       } else
+               newflags = 0;
+
+       if (cpend - cp == 1) {          /* only one character */
+               if (isdigit((unsigned char) *cp)) {     /* it's a digit! */
+                       LDBL(n) = (AWKLDBL)(*cp - '0');
+                       n->flags |= newflags;
+                       n->flags |= NUMCUR;
+                       if (cp == n->stptr)             /* no leading spaces */
+                               n->flags |= NUMINT;
+               }
+               return n;
+       }
+
+       if (do_non_decimal_data) {      /* main.c assures false if do_posix */
+               errno = 0;
+               if (! do_traditional && get_numbase(cp, true) != 10) {
+                       LDBL(n) = nondec2awkldbl(cp, cpend - cp);
+                       n->flags |= NUMCUR;
+                       ptr = cpend;
+                       goto finish;
+               }
+       }
+
+       errno = 0;
+       save = *cpend;
+       *cpend = '\0';
+       LDBL(n) = gawk_strtold((const char *) cp, &ptr);
+
+       /* POSIX says trailing space is OK for NUMBER */
+       while (isspace((unsigned char) *ptr))
+               ptr++;
+       *cpend = save;
+finish:
+       if (errno == 0 && ptr == cpend) {
+               n->flags |= newflags;
+               n->flags |= NUMCUR;
+       } else {
+               errno = 0;
+       }
+       return n;
+}
+
+
+/*
+ * The following lookup table is used as an optimization in force_string;
+ * (more complicated) variations on this theme didn't seem to pay off, but 
+ * systematic testing might be in order at some point.
+ */
+static const char *values[] = {
+       "0",
+       "1",
+       "2",
+       "3",
+       "4",
+       "5",
+       "6",
+       "7",
+       "8",
+       "9",
+};
+#define        NVAL    (sizeof(values)/sizeof(values[0]))
+
+/* format_awkldbl_val --- format a numeric value based on format */
+
+static NODE *
+format_awkldbl_val(const char *format, int index, NODE *s)
+{
+       char buf[BUFSIZ];
+       char *sp = buf;
+       AWKLDBL ival, d;
+
+       /*
+        * 2/2007: Simplify our lives here. Instead of worrying about
+        * whether or not the value will fit into a long just so we
+        * can use sprintf("%ld", val) on it, always format it ourselves.
+        * The only thing to worry about is that integral values always
+        * format as integers. %.0f does that very well.
+        *
+        * 6/2008: Would that things were so simple. Always using %.0f
+        * imposes a notable performance penalty for applications that
+        * do a lot of conversion of integers to strings. So, we reinstate
+        * the old code, but use %.0f for integral values that are outside
+        * the range of a long.  This seems a reasonable compromise.
+        *
+        * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
+        * < and > so that things work correctly on systems with 64 bit 
integers.
+        */
+
+       d = LDBL(s);
+
+       /* not an integral value, or out of range */
+       if ((ival = double_to_int(d)) != d
+                       || ival <= LONG_MIN || ival >= LONG_MAX
+       ) {
+               /*
+                * Once upon a time, we just blindly did this:
+                *      sprintf(sp, format, s->numbr);
+                *      s->stlen = strlen(sp);
+                *      s->stfmt = (char) index;
+                * but that's no good if, e.g., OFMT is %s. So we punt,
+                * and just always format the value ourselves.
+                */
+
+               NODE *dummy[2], *r;
+               unsigned int oflags;
+
+               /* create dummy node for a sole use of format_tree */
+               dummy[1] = s;
+               oflags = s->flags;
+
+               if (ival == d) {
+                       /* integral value, but outside range of %ld, use %.0f */
+                       r = format_tree("%.0f", 4, dummy, 2);
+                       s->stfmt = -1;
+               } else {
+                       r = format_tree(format, fmt_list[index]->stlen, dummy, 
2);
+                       assert(r != NULL);
+                       s->stfmt = (char) index;
+               }
+               s->flags = oflags;
+               s->stlen = r->stlen;
+               if ((s->flags & STRCUR) != 0)
+                       efree(s->stptr);
+               s->stptr = r->stptr;
+               freenode(r);    /* Do not unref(r)! We want to keep s->stptr == 
r->stpr.  */
+
+               goto no_malloc;
+       } else {
+               /*
+                * integral value; force conversion to long only once.
+                */
+               long num = (long) ival;
+
+               if (num < NVAL && num >= 0) {
+                       sp = (char *) values[num];
+                       s->stlen = 1;
+               } else {
+                       (void) sprintf(sp, "%ld", num);
+                       s->stlen = strlen(sp);
+               }
+               s->stfmt = -1;
+               if ((s->flags & INTIND) != 0) {
+                       s->flags &= ~(INTIND|NUMBER);
+                       s->flags |= STRING;
+               }
+       }
+       if (s->stptr != NULL)
+               efree(s->stptr);
+       emalloc(s->stptr, char *, s->stlen + 2, "format_awkldbl_val");
+       memcpy(s->stptr, sp, s->stlen + 1);
+no_malloc:
+       s->flags |= STRCUR;
+       free_wstr(s);
+       return s;
+}
+
+/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
+
+static int
+is_ieee_magic_val(const char *val)
+{
+       /*
+        * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
+        * Assume the length is 4, as the caller checks this.
+        */
+       return (   (val[0] == '+' || val[0] == '-')
+               && (   (   (val[1] == 'i' || val[1] == 'I')
+                       && (val[2] == 'n' || val[2] == 'N')
+                       && (val[3] == 'f' || val[3] == 'F'))
+                   || (   (val[1] == 'n' || val[1] == 'N')
+                       && (val[2] == 'a' || val[2] == 'A')
+                       && (val[3] == 'n' || val[3] == 'N'))));
+}
+
+/* get_ieee_magic_val --- return magic value for string */
+
+static AWKLDBL
+get_ieee_magic_val(const char *val)
+{
+       static bool first = true;
+       static AWKLDBL inf;
+       static AWKLDBL nan;
+       char *ptr;
+       AWKLDBL v;
+
+       v = gawk_strtold(val, & ptr);
+
+       if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
+               if (first) {
+                       first = false;
+                       nan = gawk_sqrtl(-1.0);
+                       inf = -gawk_logl(0.0);
+               }
+               v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
+               if (val[0] == '-')
+                       v = -v;
+       }
+
+       return v;
+}
+
+/* double_to_int --- convert double to int, used in several places */
+
+static AWKLDBL
+double_to_int(AWKLDBL d)
+{
+       if (d >= 0)
+               d = gawk_floorl(d);
+       else
+               d = gawk_ceill(d);
+       return d;
+}
+
+/* do_int --- convert double to int for awk */
+
+static NODE *
+do_int(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("int: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = LDBL(tmp);
+       DEREF(tmp);
+       return make_awkldbl(double_to_int(d));
+}
+
+/* do_log --- the log function */
+
+static NODE *
+do_log(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d, arg;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("log: received non-numeric argument"));
+       (void) force_number(tmp);
+       arg = LDBL(tmp);
+       if (arg < 0.0)
+               warning(_("log: received negative argument %Lg"), arg);
+       d = gawk_logl(arg);
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* do_sqrt --- do the sqrt function */
+
+static NODE *
+do_sqrt(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL arg;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("sqrt: received non-numeric argument"));
+       (void) force_number(tmp);
+       arg = LDBL(tmp);
+       DEREF(tmp);
+       if (arg < 0.0)
+               warning(_("sqrt: called with negative argument %Lg"), arg);
+       return make_awkldbl(gawk_sqrtl(arg));
+}
+
+/* do_exp --- exponential function */
+
+static NODE *
+do_exp(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d, res;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("exp: received non-numeric argument"));
+       (void) force_number(tmp);
+       DEREF(tmp);
+       errno = 0;
+       res = gawk_expl(d);
+       if (errno == ERANGE)
+               warning(_("exp: argument %Lg is out of range"), d);
+       return make_awkldbl(res);
+}
+
+/* do_atan2 --- do the atan2 function */
+
+static NODE *
+do_atan2(int nargs)
+{
+       NODE *t1, *t2;
+       AWKLDBL d1, d2;
+
+       t2 = POP_SCALAR();
+       t1 = POP_SCALAR();
+       if (do_lint) {
+               if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("atan2: received non-numeric first 
argument"));
+               if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("atan2: received non-numeric second 
argument"));
+       }
+       (void) force_number(t1);
+       (void) force_number(t2);
+       d1 = LDBL(t1);
+       d2 = LDBL(t2);
+       DEREF(t1);
+       DEREF(t2);
+       return make_awkldbl(gawk_atan2l(d1, d2));
+}
+
+
+/* do_sin --- do the sin function */
+
+static NODE *
+do_sin(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("sin: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = gawk_sinl(LDBL(tmp));
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* do_cos --- do the cos function */
+
+static NODE *
+do_cos(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("cos: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = gawk_cosl(LDBL(tmp));
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+/* do_strtonum --- the strtonum function */
+
+static NODE *
+do_strtonum(int nargs)
+{
+       NODE *tmp;
+       AWKLDBL d;
+
+       tmp = POP_SCALAR();
+       if ((tmp->flags & (NUMBER|NUMCUR)) != 0) {
+               (void) force_number(tmp);
+               d = LDBL(tmp);
+       } else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
+               d = nondec2awkldbl(tmp->stptr, tmp->stlen);
+       else {
+               (void) force_number(tmp);
+               d = LDBL(tmp);
+       }
+
+       DEREF(tmp);
+       return make_awkldbl(d);
+}
+
+
+/*
+ * format_tree() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library.  Returns a string node which value
+ * is a formatted string.  Called by  sprintf function.
+ *
+ * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+static NODE *
+format_nodes_awkldbl(
+       const char *fmt_string,
+       size_t n0,
+       NODE **the_args,
+       long num_args)
+{
+/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
+/* difference of pointers should be of ptrdiff_t type, but let us be kind */
+#define bchunk(s, l) if (l) { \
+       while ((l) > ofre) { \
+               size_t olen = obufout - obuf; \
+               erealloc(obuf, char *, osiz * 2, "format_tree"); \
+               ofre += osiz; \
+               osiz *= 2; \
+               obufout = obuf + olen; \
+       } \
+       memcpy(obufout, s, (size_t) (l)); \
+       obufout += (l); \
+       ofre -= (l); \
+}
+
+/* copy one byte from 's' to 'obufout' checking for space in the process */
+#define bchunk_one(s) { \
+       if (ofre < 1) { \
+               size_t olen = obufout - obuf; \
+               erealloc(obuf, char *, osiz * 2, "format_tree"); \
+               ofre += osiz; \
+               osiz *= 2; \
+               obufout = obuf + olen; \
+       } \
+       *obufout++ = *s; \
+       --ofre; \
+}
+
+/* Is there space for something L big in the buffer? */
+#define chksize(l)  if ((l) >= ofre) { \
+       size_t olen = obufout - obuf; \
+       size_t delta = osiz+l-ofre; \
+       erealloc(obuf, char *, osiz + delta, "format_tree"); \
+       obufout = obuf + olen; \
+       ofre += delta; \
+       osiz += delta; \
+}
+
+       size_t cur_arg = 0;
+       NODE *r = NULL;
+       int i, nc;
+       bool toofew = false;
+       char *obuf, *obufout;
+       size_t osiz, ofre;
+       const char *chbuf;
+       const char *s0, *s1;
+       int cs1;
+       NODE *arg;
+       long fw, prec, argnum;
+       bool used_dollar;
+       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
+       long *cur = NULL;
+       uintmax_t uval;
+       bool sgn;
+       int base;
+       /*
+        * Although this is an array, the elements serve two different
+        * purposes. The first element is the general buffer meant
+        * to hold the entire result string.  The second one is a
+        * temporary buffer for large floating point values. They
+        * could just as easily be separate variables, and the
+        * code might arguably be clearer.
+        */
+       struct {
+               char *buf;
+               size_t bufsize;
+               char stackbuf[30];
+       } cpbufs[2];
+#define cpbuf  cpbufs[0].buf
+       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
+       char *cp;
+       const char *fill;
+       AWKLDBL tmpval = 0.0;
+       char signchar = '\0';
+       size_t len;
+       bool zero_flag = false;
+       bool quote_flag = false;
+       int ii, jj;
+       char *chp;
+       size_t copy_count, char_count;
+
+       static const char sp[] = " ";
+       static const char zero_string[] = "0";
+       static const char lchbuf[] = "0123456789abcdef";
+       static const char Uchbuf[] = "0123456789ABCDEF";
+
+#define INITIAL_OUT_SIZE       512
+       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
+       obufout = obuf;
+       osiz = INITIAL_OUT_SIZE;
+       ofre = osiz - 2;
+
+       cur_arg = 1;
+
+       {
+               size_t k;
+               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
+                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
+                       cpbufs[k].buf = cpbufs[k].stackbuf;
+               }
+       }
+
+       /*
+        * The point of this goop is to grow the buffer
+        * holding the converted number, so that large
+        * values don't overflow a fixed length buffer.
+        */
+#define PREPEND(CH) do {       \
+       if (cp == cpbufs[0].buf) {      \
+               char *prev = cpbufs[0].buf;     \
+               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
+                       "format_tree"); \
+               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
+                      cpbufs[0].bufsize);      \
+               cpbufs[0].bufsize *= 2; \
+               if (prev != cpbufs[0].stackbuf) \
+                       efree(prev);    \
+               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
+       }       \
+       *--cp = (CH);   \
+} while(0)
+
+       /*
+        * Check first for use of `count$'.
+        * If plain argument retrieval was used earlier, choke.
+        *      Otherwise, return the requested argument.
+        * If not `count$' now, but it was used earlier, choke.
+        * If this format is more than total number of args, choke.
+        * Otherwise, return the current argument.
+        */
+#define parse_next_arg() { \
+       if (argnum > 0) { \
+               if (cur_arg > 1) { \
+                       msg(_("fatal: must use `count$' on all formats or 
none")); \
+                       goto out; \
+               } \
+               arg = the_args[argnum]; \
+       } else if (used_dollar) { \
+               msg(_("fatal: must use `count$' on all formats or none")); \
+               arg = 0; /* shutup the compiler */ \
+               goto out; \
+       } else if (cur_arg >= num_args) { \
+               arg = 0; /* shutup the compiler */ \
+               toofew = true; \
+               break; \
+       } else { \
+               arg = the_args[cur_arg]; \
+               cur_arg++; \
+       } \
+}
+
+       need_format = false;
+       used_dollar = false;
+
+       s0 = s1 = fmt_string;
+       while (n0-- > 0) {
+               if (*s1 != '%') {
+                       s1++;
+                       continue;
+               }
+               need_format = true;
+               bchunk(s0, s1 - s0);
+               s0 = s1;
+               cur = &fw;
+               fw = 0;
+               prec = 0;
+               base = 0;
+               argnum = 0;
+               base = 0;
+               have_prec = false;
+               signchar = '\0';
+               zero_flag = false;
+               quote_flag = false;
+               lj = alt = big_flag = bigbig_flag = small_flag = false;
+               fill = sp;
+               cp = cend;
+               chbuf = lchbuf;
+               s1++;
+
+retry:
+               if (n0-- == 0)  /* ran out early! */
+                       break;
+
+               switch (cs1 = *s1++) {
+               case (-1):      /* dummy case to allow for checking */
+check_pos:
+                       if (cur != & fw)
+                               break;          /* reject as a valid format */
+                       goto retry;
+               case '%':
+                       need_format = false;
+                       /*
+                        * 29 Oct. 2002:
+                        * The C99 standard pages 274 and 279 seem to imply that
+                        * since there's no arg converted, the field width 
doesn't
+                        * apply.  The code already was that way, but this
+                        * comment documents it, at least in the code.
+                        */
+                       if (do_lint) {
+                               const char *msg = NULL;
+
+                               if (fw && ! have_prec)
+                                       msg = _("field width is ignored for 
`%%' specifier");
+                               else if (fw == 0 && have_prec)
+                                       msg = _("precision is ignored for `%%' 
specifier");
+                               else if (fw && have_prec)
+                                       msg = _("field width and precision are 
ignored for `%%' specifier");
+
+                               if (msg != NULL)
+                                       lintwarn("%s", msg);
+                       }
+                       bchunk_one("%");
+                       s0 = s1;
+                       break;
+
+               case '0':
+                       /*
+                        * Only turn on zero_flag if we haven't seen
+                        * the field width or precision yet.  Otherwise,
+                        * screws up floating point formatting.
+                        */
+                       if (cur == & fw)
+                               zero_flag = true;
+                       if (lj)
+                               goto retry;
+                       /* FALL through */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       if (cur == NULL)
+                               break;
+                       if (prec >= 0)
+                               *cur = cs1 - '0';
+                       /*
+                        * with a negative precision *cur is already set
+                        * to -1, so it will remain negative, but we have
+                        * to "eat" precision digits in any case
+                        */
+                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+                               --n0;
+                               *cur = *cur * 10 + *s1++ - '0';
+                       }
+                       if (prec < 0)   /* negative precision is discarded */
+                               have_prec = false;
+                       if (cur == &prec)
+                               cur = NULL;
+                       if (n0 == 0)    /* badly formatted control string */
+                               continue;
+                       goto retry;
+               case '$':
+                       if (do_traditional) {
+                               msg(_("fatal: `$' is not permitted in awk 
formats"));
+                               goto out;
+                       }
+
+                       if (cur == &fw) {
+                               argnum = fw;
+                               fw = 0;
+                               used_dollar = true;
+                               if (argnum <= 0) {
+                                       msg(_("fatal: arg count with `$' must 
be > 0"));
+                                       goto out;
+                               }
+                               if (argnum >= num_args) {
+                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
+                                       goto out;
+                               }
+                       } else {
+                               msg(_("fatal: `$' not permitted after period in 
format"));
+                               goto out;
+                       }
+
+                       goto retry;
+               case '*':
+                       if (cur == NULL)
+                               break;
+                       if (! do_traditional && isdigit((unsigned char) *s1)) {
+                               int val = 0;
+
+                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
+                                       val *= 10;
+                                       val += *s1 - '0';
+                               }
+                               if (*s1 != '$') {
+                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
+                                       goto out;
+                               } else {
+                                       s1++;
+                                       n0--;
+                               }
+                               if (val >= num_args) {
+                                       toofew = true;
+                                       break;
+                               }
+                               arg = the_args[val];
+                       } else {
+                               parse_next_arg();
+                       }
+                       (void) force_number(arg);
+                       *cur = get_number_si(arg);
+                       if (*cur < 0 && cur == & fw) {
+                               *cur = -*cur;
+                               lj++;
+                       }
+                       if (cur == & prec) {
+                               if (*cur >= 0)
+                                       have_prec = true;
+                               else
+                                       have_prec = false;
+                               cur = NULL;
+                       }
+                       goto retry;
+               case ' ':               /* print ' ' or '-' */
+                                       /* 'space' flag is ignored */
+                                       /* if '+' already present  */
+                       if (signchar != false) 
+                               goto check_pos;
+                       /* FALL THROUGH */
+               case '+':               /* print '+' or '-' */
+                       signchar = cs1;
+                       goto check_pos;
+               case '-':
+                       if (prec < 0)
+                               break;
+                       if (cur == & prec) {
+                               prec = -1;
+                               goto retry;
+                       }
+                       fill = sp;      /* if left justified then other */
+                       lj++;           /* filling is ignored */
+                       goto check_pos;
+               case '.':
+                       if (cur != & fw)
+                               break;
+                       cur = & prec;
+                       have_prec = true;
+                       goto retry;
+               case '#':
+                       alt = true;
+                       goto check_pos;
+               case '\'':
+#if defined(HAVE_LOCALE_H)       
+                       /* allow quote_flag if there is a thousands separator. 
*/
+                       if (loc.thousands_sep[0] != '\0')
+                               quote_flag = true;
+                       goto check_pos;
+#else
+                       goto retry;  
+#endif
+               case 'l':
+                       if (big_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       big_flag = true;
+                       goto retry;
+               case 'L':
+                       if (bigbig_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       bigbig_flag = true;
+                       goto retry;
+               case 'h':
+                       if (small_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       small_flag = true;
+                       goto retry;
+               case 'c':
+                       need_format = false;
+                       parse_next_arg();
+                       /* user input that looks numeric is numeric */
+                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+                               (void) force_number(arg);
+                       if ((arg->flags & NUMBER) != 0) {
+                               uval = get_number_uj(arg);
+#if MBS_SUPPORT
+                               if (gawk_mb_cur_max > 1) {
+                                       char buf[100];
+                                       wchar_t wc;
+                                       mbstate_t mbs;
+                                       size_t count;
+
+                                       memset(& mbs, 0, sizeof(mbs));
+                                       wc = uval;
+
+                                       count = wcrtomb(buf, wc, & mbs);
+                                       if (count == 0
+                                           || count == (size_t)-1
+                                           || count == (size_t)-2)
+                                               goto out0;
+
+                                       memcpy(cpbuf, buf, count);
+                                       prec = count;
+                                       cp = cpbuf;
+                                       goto pr_tail;
+                               }
+out0:
+                               ;
+                               /* else,
+                                       fall through */
+#endif
+                               if (do_lint && uval > 255) {
+                                       lintwarn("[s]printf: value %Lg is too 
big for %%c format",
+                                                       LDBL(arg));
+                               }
+                               cpbuf[0] = uval;
+                               prec = 1;
+                               cp = cpbuf;
+                               goto pr_tail;
+                       }
+                       /*
+                        * As per POSIX, only output first character of a
+                        * string value.  Thus, we ignore any provided
+                        * precision, forcing it to 1.  (Didn't this
+                        * used to work? 6/2003.)
+                        */
+                       cp = arg->stptr;
+#if MBS_SUPPORT
+                       /*
+                        * First character can be multiple bytes if
+                        * it's a multibyte character. Grr.
+                        */
+                       if (gawk_mb_cur_max > 1) {
+                               mbstate_t state;
+                               size_t count;
+
+                               memset(& state, 0, sizeof(state));
+                               count = mbrlen(cp, arg->stlen, & state);
+                               if (count == 0
+                                   || count == (size_t)-1
+                                   || count == (size_t)-2)
+                                       goto out2;
+                               prec = count;
+                               goto pr_tail;
+                       }
+out2:
+                       ;
+#endif
+                       prec = 1;
+                       goto pr_tail;
+               case 's':
+                       need_format = false;
+                       parse_next_arg();
+                       arg = force_string(arg);
+                       if (fw == 0 && ! have_prec)
+                               prec = arg->stlen;
+                       else {
+                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
+                               if (! have_prec || prec > char_count)
+                                       prec = char_count;
+                       }
+                       cp = arg->stptr;
+                       goto pr_tail;
+               case 'd':
+               case 'i':
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       tmpval = LDBL(arg);
+
+                       /*
+                        * Check for Nan or Inf.
+                        */
+                       if (isnan(tmpval) || isinf(tmpval))
+                               goto out_of_range;
+                       else
+                               tmpval = double_to_int(tmpval);
+
+                       /*
+                        * ``The result of converting a zero value with a
+                        * precision of zero is no characters.''
+                        */
+                       if (have_prec && prec == 0 && tmpval == 0)
+                               goto pr_tail;
+
+                       if (tmpval < 0) {
+                               tmpval = -tmpval;
+                               sgn = true;
+                       } else {
+                               if (tmpval == -0.0)
+                                       /* avoid printing -0 */
+                                       tmpval = 0.0;
+                               sgn = false;
+                       }
+                       /*
+                        * Use snprintf return value to tell if there
+                        * is enough room in the buffer or not.
+                        */
+                       while ((i = snprintf(cpbufs[1].buf,
+                                    cpbufs[1].bufsize, "%.0Lf", tmpval)) >= 
cpbufs[1].bufsize) {
+                               if (cpbufs[1].buf == cpbufs[1].stackbuf)
+                                       cpbufs[1].buf = NULL;
+                               if (i > 0) {
+                                       cpbufs[1].bufsize += ((i > 
cpbufs[1].bufsize) ?
+                                                             i : 
cpbufs[1].bufsize);
+                               }
+                               else
+                                       cpbufs[1].bufsize *= 2;
+                               assert(cpbufs[1].bufsize > 0);
+                               erealloc(cpbufs[1].buf, char *,
+                                        cpbufs[1].bufsize, "format_tree");
+                       }
+                       if (i < 1)
+                               goto out_of_range;
+                       chp = & cpbufs[1].buf[i-1];
+                       ii = jj = 0;
+                       do {
+                               PREPEND(*chp);
+                               chp--; i--;
+#if defined(HAVE_LOCALE_H)
+                               if (quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
+                                       if (i)  /* only add if more digits 
coming */
+                                               PREPEND(loc.thousands_sep[0]);  
/* XXX - assumption it's one char */
+                                       if (loc.grouping[ii+1] == 0)
+                                               jj = 0;         /* keep using 
current val in loc.grouping[ii] */
+                                       else if (loc.grouping[ii+1] == CHAR_MAX)
+                                               quote_flag = false;
+                                       else {                 
+                                               ii++;
+                                               jj = 0;
+                                       }
+                               }
+#endif
+                       } while (i > 0);
+
+                       /* add more output digits to match the precision */
+                       if (have_prec) {
+                               while (cend - cp < prec)
+                                       PREPEND('0');
+                       }
+
+                       if (sgn)
+                               PREPEND('-');
+                       else if (signchar)
+                               PREPEND(signchar);
+                       /*
+                        * When to fill with zeroes is of course not simple.
+                        * First: No zero fill if left-justifying.
+                        * Next: There seem to be two cases:
+                        *      A '0' without a precision, e.g. %06d
+                        *      A precision with no field width, e.g. %.10d
+                        * Any other case, we don't want to fill with zeroes.
+                        */
+                       if (! lj
+                           && ((zero_flag && ! have_prec)
+                                || (fw == 0 && have_prec)))
+                               fill = zero_string;
+                       if (prec > fw)
+                               fw = prec;
+                       prec = cend - cp;
+                       if (fw > prec && ! lj && fill != sp
+                           && (*cp == '-' || signchar)) {
+                               bchunk_one(cp);
+                               cp++;
+                               prec--;
+                               fw--;
+                       }
+                       goto pr_tail;
+               case 'X':
+                       chbuf = Uchbuf; /* FALL THROUGH */
+               case 'x':
+                       base += 6;      /* FALL THROUGH */
+               case 'u':
+                       base += 2;      /* FALL THROUGH */
+               case 'o':
+                       base += 8;
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       tmpval = LDBL(arg);
+
+                       /*
+                        * ``The result of converting a zero value with a
+                        * precision of zero is no characters.''
+                        *
+                        * If I remember the ANSI C standard, though,
+                        * it says that for octal conversions
+                        * the precision is artificially increased
+                        * to add an extra 0 if # is supplied.
+                        * Indeed, in C,
+                        *      printf("%#.0o\n", 0);
+                        * prints a single 0.
+                        */
+                       if (! alt && have_prec && prec == 0 && tmpval == 0)
+                               goto pr_tail;
+
+                       if (tmpval < 0) {
+                               uval = (uintmax_t) (intmax_t) tmpval;
+                               if ((AWKLDBL)(intmax_t)uval != 
double_to_int(tmpval))
+                                       goto out_of_range;
+                       } else {
+                               /* FIXME --- Why is this the case ? */
+                               uval = (uintmax_t) tmpval;
+                               if ((AWKLDBL) uval != double_to_int(tmpval))
+                                       goto out_of_range;
+                       }
+
+                       /*
+                        * When to fill with zeroes is of course not simple.
+                        * First: No zero fill if left-justifying.
+                        * Next: There seem to be two cases:
+                        *      A '0' without a precision, e.g. %06d
+                        *      A precision with no field width, e.g. %.10d
+                        * Any other case, we don't want to fill with zeroes.
+                        */
+                       if (! lj
+                           && ((zero_flag && ! have_prec)
+                                || (fw == 0 && have_prec)))
+                               fill = zero_string;
+                       ii = jj = 0;
+                       do {
+                               PREPEND(chbuf[uval % base]);
+                               uval /= base;
+#if defined(HAVE_LOCALE_H)
+                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
+                                       if (uval)       /* only add if more 
digits coming */
+                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
+                                       if (loc.grouping[ii+1] == 0)            
                              
+                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
+                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
+                                               quote_flag = false;
+                                       else {                 
+                                               ii++;
+                                               jj = 0;
+                                       }
+                               }
+#endif
+                       } while (uval > 0);
+
+                       /* add more output digits to match the precision */
+                       if (have_prec) {
+                               while (cend - cp < prec)
+                                       PREPEND('0');
+                       }
+
+                       if (alt && tmpval != 0) {
+                               if (base == 16) {
+                                       PREPEND(cs1);
+                                       PREPEND('0');
+                                       if (fill != sp) {
+                                               bchunk(cp, 2);
+                                               cp += 2;
+                                               fw -= 2;
+                                       }
+                               } else if (base == 8)
+                                       PREPEND('0');
+                       }
+                       base = 0;
+                       if (prec > fw)
+                               fw = prec;
+                       prec = cend - cp;
+       pr_tail:
+                       if (! lj) {
+                               while (fw > prec) {
+                                       bchunk_one(fill);
+                                       fw--;
+                               }
+                       }
+                       copy_count = prec;
+                       if (fw == 0 && ! have_prec)
+                               ;
+                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
+                               assert(cp == arg->stptr || cp == cpbuf);
+                               copy_count = mbc_byte_count(arg->stptr, prec);
+                       }
+                       bchunk(cp, copy_count);
+                       while (fw > prec) {
+                               bchunk_one(fill);
+                               fw--;
+                       }
+                       s0 = s1;
+                       break;
+
+     out_of_range:
+                       /* out of range - emergency use of %g format */
+                       if (do_lint)
+                               lintwarn(_("[s]printf: value %Lg is out of 
range for `%%%c' format"),
+                                                       tmpval, cs1);
+                       cs1 = 'g';
+                       goto fmt1;
+
+               case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+                       cs1 = 'f';
+                       /* FALL THROUGH */
+#endif
+               case 'g':
+               case 'G':
+               case 'e':
+               case 'f':
+               case 'E':
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       tmpval = LDBL(arg);
+     fmt1:
+                       if (! have_prec)
+                               prec = DEFAULT_G_PRECISION;
+
+                       chksize(fw + prec + 11);        /* 11 == slop */
+                       cp = cpbuf;
+                       *cp++ = '%';
+                       if (lj)
+                               *cp++ = '-';
+                       if (signchar)
+                               *cp++ = signchar;
+                       if (alt)
+                               *cp++ = '#';
+                       if (zero_flag)
+                               *cp++ = '0';
+                       if (quote_flag)
+                               *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+                       if (quote_flag && ! use_lc_numeric)
+                               setlocale(LC_NUMERIC, "");
+#endif
+
+                       sprintf(cp, "*.*L%c", cs1);
+                       while ((nc = snprintf(obufout, ofre, cpbuf,
+                                    (int) fw, (int) prec, tmpval)) >= ofre)
+                               chksize(nc)
+
+#if defined(LC_NUMERIC)
+                       if (quote_flag && ! use_lc_numeric)
+                               setlocale(LC_NUMERIC, "C");
+#endif
+
+                       len = strlen(obufout);
+                       ofre -= len;
+                       obufout += len;
+                       s0 = s1;
+                       break;
+               default:
+                       if (do_lint && isalpha(cs1))
+                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
+                       break;
+               }
+               if (toofew) {
+                       msg("%s\n\t`%s'\n\t%*s%s",
+                             _("fatal: not enough arguments to satisfy format 
string"),
+                             fmt_string, (int) (s1 - fmt_string - 1), "",
+                             _("^ ran out for this one"));
+                       goto out;
+               }
+       }
+       if (do_lint) {
+               if (need_format)
+                       lintwarn(
+                       _("[s]printf: format specifier does not have control 
letter"));
+               if (cur_arg < num_args)
+                       lintwarn(
+                       _("too many arguments supplied for format string"));
+       }
+       bchunk(s0, s1 - s0);
+       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
+       obuf = NULL;
+out:
+       {
+               size_t k;
+               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
+               for (k = 0; k < count; k++) {
+                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
+                               efree(cpbufs[k].buf);
+               }
+               if (obuf != NULL)
+                       efree(obuf);
+       }
+
+       if (r == NULL)
+               gawk_exit(EXIT_FATAL);
+       return r;
+}
+
+#else
+
+static bool mpfp_init(bltin_t **bltins);
+
+numbr_handler_t awkldbl_hndlr = {
+       awkldbl_init,
+       NULL,
+       NULL,
+};
+
+/* awkldbl_init --- initialization routine */
+
+static bool
+awkldbl_init(bltin_t **bltins)
+{
+       *bltins = NULL;
+       return false;
+}
+#endif
diff --git a/long_double.h b/long_double.h
new file mode 100644
index 0000000..9a11e55
--- /dev/null
+++ b/long_double.h
@@ -0,0 +1,134 @@
+/*
+ * long_double.h - math functions and replacements with long double arguments.
+ */
+
+/* 
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#ifdef HAVE_SINL
+#define gawk_sinl      sinl
+#else
+static inline long double
+gawk_sinl(long double x)
+{
+       return sin( (double) x);
+}
+#endif
+
+#ifdef HAVE_COSL 
+#define gawk_cosl      cosl
+#else
+static inline long double
+gawk_cosl(long double x)
+{
+       return cos( (double) x);
+}
+#endif
+
+#ifdef HAVE_ATAN2L
+#define gawk_atan2l    atan2l
+#else
+static inline long double
+gawk_atan2l(long double y, long double x)
+{
+       return atan2( (double) y, (double) x);
+}
+#endif
+
+#ifdef HAVE_LOGL
+#define gawk_logl      logl
+#else
+static inline long double
+gawk_logl(long double x)
+{
+       return log( (double) x);
+}
+#endif
+
+#ifdef HAVE_EXPL
+#define gawk_expl      expl
+#else
+static inline long double
+gawk_expl(long double x)
+{
+       return exp( (double) x);
+}
+#endif
+
+#ifdef HAVE_FMODL
+#define gawk_fmodl     fmodl
+#else
+static inline long double
+gawk_fmodl(long double x, long double y)
+{
+       return fmod( (double) x, (double) y);
+}
+#endif
+
+#ifdef HAVE_STRTOLD
+#define gawk_strtold   strtold
+#else
+static inline long double
+gawk_strtold(const char *str, char **endptr)
+{
+       return strtod(str, endptr);
+}
+#endif
+
+#ifdef HAVE_FLOORL
+#define gawk_floorl    floorl
+#else
+static inline long double
+gawk_floorl(long double x)
+{
+       return floor( (double) x);
+}
+#endif
+
+#ifdef HAVE_CEILL
+#define gawk_ceill     ceill
+#else
+static inline long double
+gawk_ceill(long double x)
+{
+       return ceil( (double) x);
+}
+#endif
+
+#ifdef HAVE_POWL
+#define gawk_powl      powl
+#else
+static inline long double
+gawk_powl(long double x, long double y)
+{
+       return pow( (double) x, (double) y);
+}
+#endif
+
+#ifdef HAVE_SQRTL
+#define gawk_sqrtl     sqrtl
+#else
+static inline long double
+gawk_sqrtl(long double x)
+{
+       return sqrt( (double) x);
+}
+#endif
diff --git a/m4/ChangeLog b/m4/ChangeLog
index 365ccde..a674df6 100644
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,7 @@
+2012-12-29         John Haque      <address@hidden>
+
+        * long_double.m4: New file.
+
 2012-12-24         Arnold D. Robbins     <address@hidden>
 
        * 4.0.2: Release tar ball made.
diff --git a/m4/long_double.m4 b/m4/long_double.m4
new file mode 100644
index 0000000..87ef80f
--- /dev/null
+++ b/m4/long_double.m4
@@ -0,0 +1,110 @@
+# long_double.m4
+dnl Copyright (C) 2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl size comparison copied from gnulib math_h.m4 serial 114
+dnl gl_LONG_DOUBLE_VS_DOUBLE
+dnl determines whether 'long double' and 'double' have the same representation.
+dnl Sets variable HAVE_SAME_LONG_DOUBLE_AS_DOUBLE to 0 or 1, and defines
+dnl HAVE_SAME_LONG_DOUBLE_AS_DOUBLE accordingly.
+dnl The currently known platforms where this is the case are:
+dnl Linux/HPPA, Minix 3.1.8, AIX 5, AIX 6 and 7 with xlc, MSVC 9.
+
+dnl Defines USE_LONG_DOUBLE to 1 if long double is found and usable.
+dnl Also checks for math functions with long double arguments.
+
+AC_DEFUN([GAWK_USE_LONG_DOUBLE],
+[
+  gawk_has_long_double=no
+  USE_LONG_DOUBLE=
+
+  AC_REQUIRE([AC_TYPE_LONG_DOUBLE])
+  if test $ac_cv_type_long_double = yes; then
+    AC_CACHE_CHECK([whether long double and double are the same],
+     [gl_cv_long_double_equals_double],
+     [AC_COMPILE_IFELSE(
+       [AC_LANG_PROGRAM([[#include <float.h>]],
+         [[typedef int check[sizeof (long double) == sizeof (double)
+                           && LDBL_MANT_DIG == DBL_MANT_DIG
+                           && LDBL_MAX_EXP == DBL_MAX_EXP
+                           && LDBL_MIN_EXP == DBL_MIN_EXP
+                              ? 1 : -1];
+         ]])],
+       [gl_cv_long_double_equals_double=yes],
+       [gl_cv_long_double_equals_double=no])
+     ])
+    if test $gl_cv_long_double_equals_double = no; then
+      AC_CACHE_CHECK([whether printf supports %Lf],
+       [gawk_cv_has_L_format],
+       [AC_RUN_IFELSE(
+         [AC_LANG_PROGRAM([[#include <stdio.h>]],
+           [[char buf[100];
+          sprintf(buf, "%Lf,%Lg,%Le", (long double) 1.0, (long double) 1.0, 
(long double) 1.0);
+           if (strcmp(buf, "1.000000,1,1.000000e+00") == 0)
+              return 0;
+          return 1;
+          ]])],
+         [gawk_cv_has_L_format=yes],
+        [gawk_cv_has_L_format=no])
+       ])
+      if test $gawk_cv_has_L_format = yes; then
+        gawk_has_long_double=yes
+      fi
+    fi
+  fi
+
+  if test $gawk_has_long_double = yes; then
+    AC_DEFINE([USE_LONG_DOUBLE], [1],
+           [Define to 1 if can use 'long double'.])
+
+    AC_CHECK_FUNC(strtold)
+    if test $ac_cv_func_strtold = yes; then
+      AC_DEFINE([HAVE_STRTOLD], 1, [Define to 1 if you have 'strtold' 
function.])
+    fi
+
+    AC_CHECK_LIB(m, sinl)
+    if test $ac_cv_lib_m_sinl = yes; then
+      AC_DEFINE([HAVE_SINL], 1,        [Define to 1 if you have 'sinl' 
function.])
+    fi
+    AC_CHECK_LIB(m, cosl)
+    if test $ac_cv_lib_m_cosl = yes; then
+      AC_DEFINE([HAVE_COSL], 1,        [Define to 1 if you have 'cosl' 
function.])
+    fi
+    AC_CHECK_LIB(m, atan2l)
+    if test $ac_cv_lib_m_atan2l = yes; then
+      AC_DEFINE([HAVE_ATAN2L], 1, [Define to 1 if you have 'atan2l' function.])
+    fi
+    AC_CHECK_LIB(m, logl)
+    if test $ac_cv_lib_m_logl = yes; then
+      AC_DEFINE([HAVE_LOGL], 1,        [Define to 1 if you have 'logl' 
function.])
+    fi
+    AC_CHECK_LIB(m, expl)
+    if test $ac_cv_lib_m_expl = yes; then
+      AC_DEFINE([HAVE_EXPL], 1,        [Define to 1 if you have 'expl' 
function.])
+    fi
+    AC_CHECK_LIB(m, fmodl)
+    if test $ac_cv_lib_m_fmodl = yes; then
+      AC_DEFINE([HAVE_FMODL], 1, [Define to 1 if you have 'fmodl' function.])
+    fi
+    AC_CHECK_LIB(m, floorl)
+    if test $ac_cv_lib_m_floorl = yes; then
+      AC_DEFINE([HAVE_FLOORL], 1, [Define to 1 if you have 'floorl' function.])
+    fi
+    AC_CHECK_LIB(m, ceill)
+    if test $ac_cv_lib_m_ceill = yes; then
+      AC_DEFINE([HAVE_CEILL], 1, [Define to 1 if you have 'ceill' function.])
+    fi
+    AC_CHECK_LIB(m, powl)
+    if test $ac_cv_lib_m_powl = yes; then
+      AC_DEFINE([HAVE_POWL], 1,        [Define to 1 if you have 'powl' 
function.])
+    fi
+    AC_CHECK_LIB(m, sqrtl)
+    if test $ac_cv_lib_m_sqrtl = yes; then
+      AC_DEFINE([HAVE_SQRTL], 1, [Define to 1 if you have 'sqrtl' function.])
+    fi
+  fi
+
+  AC_SUBST(USE_LONG_DOUBLE)
+])
diff --git a/main.c b/main.c
index 24dbb56..694eb92 100644
--- a/main.c
+++ b/main.c
@@ -204,7 +204,7 @@ main(int argc, char **argv)
        /*
         * The + on the front tells GNU getopt not to rearrange argv.
         */
-       const char *optlist = 
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::MPrStVY";
+       const char *optlist = 
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::BMPrStVY";
        bool stopped_early = false;
        int old_optind;
        int i;
@@ -367,6 +367,10 @@ main(int argc, char **argv)
                        do_binary = true;
                        break;
 
+               case 'B':
+                       numbr_hndlr = & awkldbl_hndlr;
+                       break;
+                       
                case 'c':
                        do_flags |= DO_TRADITIONAL;
                        break;
@@ -1562,6 +1566,7 @@ print_numbr_hndlr_versions()
 {
        static numbr_handler_t *hndlrs[] = {
                & awknum_hndlr,
+               & awkldbl_hndlr,
                & mpfp_hndlr,
        };
        int i;
diff --git a/node.c b/node.c
index 9efd767..664a61f 100644
--- a/node.c
+++ b/node.c
@@ -97,7 +97,8 @@ make_str_node(const char *s, size_t len, int flags)
        NODE *r;
        getnode(r);
        r->type = Node_val;
-       r->numbr = 0;
+       r->numbr = 0;   /* FIXME: uninitialized? it is NaN in MPFR */
+       r->qnumbr = NULL;
        r->flags = (MALLOC|STRING|STRCUR);
        r->valref = 1;
        r->stfmt = -1;
@@ -649,6 +650,7 @@ BLOCK nextfree[BLOCK_MAX] = {
        { 0, NULL},     /* invalid */   
        { sizeof(NODE), NULL },
        { sizeof(BUCKET), NULL },
+       { sizeof(long double), NULL},
 };
 
 
diff --git a/str_array.c b/str_array.c
index e5b3b40..fcb11e9 100644
--- a/str_array.c
+++ b/str_array.c
@@ -157,7 +157,7 @@ str_lookup(NODE *symbol, NODE *subs)
                * never be used.
                */
 
-               if ((subs->flags & (MPFN|MPZN|NUMCUR)) == NUMCUR) {
+               if ((subs->flags & NUMCUR) != 0 && numbr_hndlr == & 
awknum_hndlr) {
                        tmp->numbr = subs->numbr;
                        tmp->flags |= NUMCUR;
                }
diff --git a/test/Makefile.in b/test/Makefile.in
index e4b22fd..b2e0172 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -82,11 +82,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
        $(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
        $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
        $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
-       $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
-       $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
-       $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
-       $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
-       $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+       $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+       $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+       $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+       $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+       $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+       $(top_srcdir)/configure.ac
 am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
        $(ACLOCAL_M4)
 mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -175,6 +176,7 @@ SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
 SOCKET_LIBS = @SOCKET_LIBS@
 STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
 USE_NLS = @USE_NLS@
 VERSION = @VERSION@
 XGETTEXT = @XGETTEXT@

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=c5a43d6d92022ff834f28563085fa9bcf0f38d85

commit c5a43d6d92022ff834f28563085fa9bcf0f38d85
Author: John Haque <address@hidden>
Date:   Fri Dec 28 17:23:53 2012 -0600

    Change all instances of make_number() to make_awknum() in double.c.

diff --git a/ChangeLog b/ChangeLog
index d45cb32..01829c7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2012-12-28         John Haque      <address@hidden>
+
+       * double.c: Use make_awknum everywhere instead of make_number
+       in case a routine is called using not the current handler
+       or before initialization.
+ 
 2012-12-27         John Haque      <address@hidden>
 
        Number handling interface.
diff --git a/double.c b/double.c
index 2c80d82..985d4f4 100644
--- a/double.c
+++ b/double.c
@@ -42,9 +42,7 @@ extern void srandom(unsigned long seed);
 
 extern NODE **fmt_list;          /* declared in eval.c */
 
-static int is_ieee_magic_val(const char *val);
-static AWKNUM get_ieee_magic_val(const char *val);
-static AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
+/* exported routines */
 
 static NODE *make_awknum(AWKNUM);
 static int cmp_awknums(const NODE *, const NODE *);
@@ -90,8 +88,11 @@ static NODE *do_srand(int);
 static NODE *do_strtonum(int);
 static NODE *do_xor(int);
 
-/* internal functions */
+/* internal routines */
 static double double_to_int(double d);
+static int is_ieee_magic_val(const char *val);
+static AWKNUM get_ieee_magic_val(const char *val);
+static AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
 
 
 numbr_handler_t awknum_hndlr = {
@@ -356,7 +357,7 @@ static inline NODE *
 make_integer(uintmax_t n)
 {
        n = adjust_uint(n);
-       return make_number(n);
+       return make_awknum(n);
 }
 
 /* do_lshift --- perform a << operation */
@@ -676,7 +677,7 @@ do_rand(int nargs ATTRIBUTE_UNUSED)
         *
         *      0 <= n < 1
         */
-       return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / 
GAWK_RANDOM_MAX);
+       return make_awknum((AWKNUM) (random() % GAWK_RANDOM_MAX) / 
GAWK_RANDOM_MAX);
 }
 
 /* do_srand --- seed the random number generator */
@@ -704,11 +705,11 @@ do_srand(int nargs)
                srandom((unsigned int) (save_seed = (long) 
force_number(tmp)->numbr));
                DEREF(tmp);
        }
-       return make_number((AWKNUM) ret);
+       return make_awknum((AWKNUM) ret);
 }
 
 
-/*-------------------------------------------------------------------*/
+/* str2awknum --- create a number node from string */
 
 static NODE *
 str2awknum(char *str, char **endptr, int base, bool is_integer 
ATTRIBUTE_UNUSED)
@@ -837,7 +838,6 @@ force_awknum(NODE *n)
        char save;
        char *ptr;
        unsigned int newflags;
-       extern double strtod();
 
        if ((n->flags & NUMCUR) != 0)
                return n;
@@ -868,7 +868,6 @@ force_awknum(NODE *n)
                                n->flags &= ~MAYBE_NUM;
                        n->flags |= NUMBER|NUMCUR;
                        n->numbr = get_ieee_magic_val(n->stptr);
-
                        return n;
                }
                /* else
@@ -1121,7 +1120,7 @@ do_int(int nargs)
        (void) force_number(tmp);
        d = tmp->numbr;
        DEREF(tmp);
-       return make_number(double_to_int(d));
+       return make_awknum(double_to_int(d));
 }
 
 /* do_log --- the log function */
@@ -1140,7 +1139,7 @@ do_log(int nargs)
                warning(_("log: received negative argument %g"), (double) arg);
        d = log(arg);
        DEREF(tmp);
-       return make_number(d);
+       return make_awknum(d);
 }
 
 /* do_sqrt --- do the sqrt function */
@@ -1158,7 +1157,7 @@ do_sqrt(int nargs)
        DEREF(tmp);
        if (arg < 0.0)
                warning(_("sqrt: called with negative argument %g"), (double) 
arg);
-       return make_number(sqrt(arg));
+       return make_awknum(sqrt(arg));
 }
 
 /* do_exp --- exponential function */
@@ -1178,7 +1177,7 @@ do_exp(int nargs)
        res = exp(d);
        if (errno == ERANGE)
                warning(_("exp: argument %g is out of range"), (double) d);
-       return make_number(res);
+       return make_awknum(res);
 }
 
 
@@ -1202,7 +1201,7 @@ do_atan2(int nargs)
        d2 = force_number(t2)->numbr;
        DEREF(t1);
        DEREF(t2);
-       return make_number(atan2(d1, d2));
+       return make_awknum(atan2(d1, d2));
 }
 
 /* do_sin --- do the sin function */
@@ -1218,7 +1217,7 @@ do_sin(int nargs)
                lintwarn(_("sin: received non-numeric argument"));
        d = sin(force_number(tmp)->numbr);
        DEREF(tmp);
-       return make_number(d);
+       return make_awknum(d);
 }
 
 /* do_cos --- do the cos function */
@@ -1234,7 +1233,7 @@ do_cos(int nargs)
                lintwarn(_("cos: received non-numeric argument"));
        d = cos(force_number(tmp)->numbr);
        DEREF(tmp);
-       return make_number(d);
+       return make_awknum(d);
 }
 
 /* do_strtonum --- the strtonum function */
@@ -1254,7 +1253,7 @@ do_strtonum(int nargs)
                d = force_number(tmp)->numbr;
 
        DEREF(tmp);
-       return make_number(d);
+       return make_awknum(d);
 }
 
 

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=ac7857c7ab32ec0aae509cd63da2127f9c664165

commit ac7857c7ab32ec0aae509cd63da2127f9c664165
Merge: bb146e0 566df67
Author: John Haque <address@hidden>
Date:   Thu Dec 27 05:45:42 2012 -0600

    Merge branch 'master' into num-handler

diff --cc ChangeLog
index b8381a9,b3a8936..d45cb32
--- a/ChangeLog
+++ b/ChangeLog
@@@ -1,13 -1,36 +1,46 @@@
 +2012-12-27         John Haque      <address@hidden>
 +
 +      Number handling interface.
 +      
 +      * awk.h (numbr_handler_t, bltin_t): New definitions.
 +      * double.c: New file for C double numbers.
 +      * mpfr.c: Reworked.
 +
 +      Lots of other changes.
 +
+ 2012-12-25         Arnold D. Robbins     <address@hidden>
+ 
+       Remove sym-constant from API after discussions with John
+       Haque and Andy Schorr.
+ 
+       * gawkapi.h (api_sym_constant): Removed field in API struct.
+       (sym_constant): Remove macro.
+       * gawkapi.c (set_constant, api_sym_update, api_sym_constant): Removed.
+       (sym_update_real): Renamed to api_sym_update(). is_const parameter
+       removed and code adjusted.
+ 
+ 2012-12-24         Arnold D. Robbins     <address@hidden>
+ 
+       * 4.0.2: Release tar ball made.
+ 
+ 2012-12-23         John Haque      <address@hidden>
+ 
+       * eval.c (r_get_lhs): Node_array_ref. If original is Node_var,
+       don't assign null-string as value.
+       * ext.c (get_argument): Node_array_ref. Check if already a scalar.
+ 
+ 2011-12-23         John Haque      <address@hidden>
+ 
+       * awkgram.y (is_deferred_variable): New function.
+       (func_install): Call it.
+       * eval.c (r_interpret): Op_push_arg. Check for uninitialized scalar.
+ 
+ 2012-12-23         Arnold D. Robbins     <address@hidden>
+ 
+       * awkgram.y (tokentab): Whitespace fix for "include".
+       * builtin.c (printf_common): Do a fatal error if no args to printf()
+       or sprintf().
+ 
  2012-12-19         Arnold D. Robbins     <address@hidden>
  
        * bootstrap.sh: Touch extension/aclocal.m4 also.
diff --cc awkgram.c
index 22269b5,228fd66..772cc36
--- a/awkgram.c
+++ b/awkgram.c
@@@ -197,7 -199,7 +198,7 @@@ extern double fmod(double x, double y)
  #define is_identchar(c)               (isalnum(c) || (c) == '_')
  
  /* Line 371 of yacc.c  */
- #line 201 "awkgram.c"
 -#line 203 "awkgram.c"
++#line 202 "awkgram.c"
  
  # ifndef YY_NULL
  #  if defined __cplusplus && 201103L <= __cplusplus
@@@ -366,7 -368,7 +367,7 @@@ int yyparse ()
  /* Copy the second part of user declarations.  */
  
  /* Line 390 of yacc.c  */
- #line 370 "awkgram.c"
 -#line 372 "awkgram.c"
++#line 371 "awkgram.c"
  
  #ifdef short
  # undef short
@@@ -730,25 -732,25 +731,25 @@@ static const yytype_int16 yyrhs[] 
  /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
  static const yytype_uint16 yyrline[] =
  {
-        0,   198,   198,   200,   205,   206,   212,   224,   228,   239,
-      245,   250,   258,   266,   268,   273,   281,   283,   289,   290,
-      292,   318,   329,   340,   346,   355,   365,   367,   369,   375,
-      380,   381,   385,   404,   403,   437,   439,   444,   445,   458,
-      463,   464,   468,   470,   472,   479,   569,   611,   653,   766,
-      773,   780,   790,   799,   808,   817,   828,   844,   843,   867,
-      879,   879,   977,   977,  1010,  1040,  1046,  1047,  1053,  1054,
-     1061,  1066,  1078,  1092,  1094,  1102,  1107,  1109,  1117,  1119,
-     1128,  1129,  1137,  1142,  1142,  1153,  1157,  1165,  1166,  1169,
-     1171,  1176,  1177,  1186,  1187,  1192,  1197,  1203,  1205,  1207,
-     1214,  1215,  1221,  1222,  1227,  1229,  1234,  1236,  1238,  1240,
-     1246,  1253,  1255,  1257,  1273,  1283,  1290,  1292,  1297,  1299,
-     1301,  1309,  1311,  1316,  1318,  1323,  1325,  1327,  1377,  1379,
-     1381,  1383,  1385,  1387,  1389,  1391,  1414,  1419,  1424,  1449,
-     1455,  1457,  1459,  1461,  1463,  1465,  1470,  1474,  1506,  1508,
-     1514,  1520,  1533,  1534,  1535,  1540,  1545,  1549,  1553,  1568,
-     1580,  1585,  1621,  1639,  1640,  1646,  1647,  1652,  1654,  1661,
-     1678,  1695,  1697,  1704,  1709,  1717,  1727,  1739,  1748,  1752,
-     1756,  1760,  1764,  1768,  1771,  1773,  1777,  1781,  1785
 -       0,   200,   200,   202,   207,   208,   214,   226,   230,   241,
 -     247,   252,   260,   268,   270,   275,   283,   285,   291,   292,
 -     294,   320,   331,   342,   348,   357,   367,   369,   371,   377,
 -     382,   383,   387,   406,   405,   439,   441,   446,   447,   460,
 -     465,   466,   470,   472,   474,   481,   571,   613,   655,   768,
 -     775,   782,   792,   801,   810,   819,   830,   846,   845,   869,
 -     881,   881,   979,   979,  1012,  1042,  1048,  1049,  1055,  1056,
 -    1063,  1068,  1080,  1094,  1096,  1104,  1109,  1111,  1119,  1121,
 -    1130,  1131,  1139,  1144,  1144,  1155,  1159,  1167,  1168,  1171,
 -    1173,  1178,  1179,  1188,  1189,  1194,  1199,  1205,  1207,  1209,
 -    1216,  1217,  1223,  1224,  1229,  1231,  1236,  1238,  1240,  1242,
 -    1248,  1255,  1257,  1259,  1275,  1285,  1292,  1294,  1299,  1301,
 -    1303,  1311,  1313,  1318,  1320,  1325,  1327,  1329,  1379,  1381,
 -    1383,  1385,  1387,  1389,  1391,  1393,  1416,  1421,  1426,  1451,
 -    1457,  1459,  1461,  1463,  1465,  1467,  1472,  1476,  1508,  1510,
 -    1516,  1522,  1535,  1536,  1537,  1542,  1547,  1551,  1555,  1570,
 -    1583,  1588,  1624,  1642,  1643,  1649,  1650,  1655,  1657,  1664,
 -    1681,  1698,  1700,  1707,  1712,  1720,  1730,  1742,  1751,  1755,
 -    1759,  1763,  1767,  1771,  1774,  1776,  1780,  1784,  1788
++       0,   199,   199,   201,   206,   207,   213,   225,   229,   240,
++     246,   251,   259,   267,   269,   274,   282,   284,   290,   291,
++     293,   319,   330,   341,   347,   356,   366,   368,   370,   376,
++     381,   382,   386,   405,   404,   438,   440,   445,   446,   459,
++     464,   465,   469,   471,   473,   480,   570,   612,   654,   767,
++     774,   781,   791,   800,   809,   818,   829,   845,   844,   868,
++     880,   880,   978,   978,  1011,  1041,  1047,  1048,  1054,  1055,
++    1062,  1067,  1079,  1093,  1095,  1103,  1108,  1110,  1118,  1120,
++    1129,  1130,  1138,  1143,  1143,  1154,  1158,  1166,  1167,  1170,
++    1172,  1177,  1178,  1187,  1188,  1193,  1198,  1204,  1206,  1208,
++    1215,  1216,  1222,  1223,  1228,  1230,  1235,  1237,  1239,  1241,
++    1247,  1254,  1256,  1258,  1274,  1284,  1291,  1293,  1298,  1300,
++    1302,  1310,  1312,  1317,  1319,  1324,  1326,  1328,  1378,  1380,
++    1382,  1384,  1386,  1388,  1390,  1392,  1415,  1420,  1425,  1450,
++    1456,  1458,  1460,  1462,  1464,  1466,  1471,  1475,  1507,  1509,
++    1515,  1521,  1534,  1535,  1536,  1541,  1546,  1550,  1554,  1569,
++    1581,  1586,  1622,  1640,  1641,  1647,  1648,  1653,  1655,  1662,
++    1679,  1696,  1698,  1705,  1710,  1718,  1728,  1740,  1749,  1753,
++    1757,  1761,  1765,  1769,  1772,  1774,  1778,  1782,  1786
  };
  #endif
  
@@@ -2035,7 -2037,7 +2036,7 @@@ yyreduce
      {
          case 3:
  /* Line 1792 of yacc.c  */
- #line 201 "awkgram.y"
 -#line 203 "awkgram.y"
++#line 202 "awkgram.y"
      {
                rule = 0;
                yyerrok;
@@@ -2044,7 -2046,7 +2045,7 @@@
  
    case 5:
  /* Line 1792 of yacc.c  */
- #line 207 "awkgram.y"
 -#line 209 "awkgram.y"
++#line 208 "awkgram.y"
      {
                next_sourcefile();
                if (sourcefile == srcfiles)
@@@ -2054,7 -2056,7 +2055,7 @@@
  
    case 6:
  /* Line 1792 of yacc.c  */
- #line 213 "awkgram.y"
 -#line 215 "awkgram.y"
++#line 214 "awkgram.y"
      {
                rule = 0;
                /*
@@@ -2067,7 -2069,7 +2068,7 @@@
  
    case 7:
  /* Line 1792 of yacc.c  */
- #line 225 "awkgram.y"
 -#line 227 "awkgram.y"
++#line 226 "awkgram.y"
      {
                (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@@ -2075,7 -2077,7 +2076,7 @@@
  
    case 8:
  /* Line 1792 of yacc.c  */
- #line 229 "awkgram.y"
 -#line 231 "awkgram.y"
++#line 230 "awkgram.y"
      {
                if (rule != Rule) {
                        msg(_("%s blocks must have an action part"), 
ruletab[rule]);
@@@ -2090,7 -2092,7 +2091,7 @@@
  
    case 9:
  /* Line 1792 of yacc.c  */
- #line 240 "awkgram.y"
 -#line 242 "awkgram.y"
++#line 241 "awkgram.y"
      {
                in_function = NULL;
                (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
@@@ -2100,7 -2102,7 +2101,7 @@@
  
    case 10:
  /* Line 1792 of yacc.c  */
- #line 246 "awkgram.y"
 -#line 248 "awkgram.y"
++#line 247 "awkgram.y"
      {
                want_source = false;
                yyerrok;
@@@ -2109,7 -2111,7 +2110,7 @@@
  
    case 11:
  /* Line 1792 of yacc.c  */
- #line 251 "awkgram.y"
 -#line 253 "awkgram.y"
++#line 252 "awkgram.y"
      {
                want_source = false;
                yyerrok;
@@@ -2118,7 -2120,7 +2119,7 @@@
  
    case 12:
  /* Line 1792 of yacc.c  */
- #line 259 "awkgram.y"
 -#line 261 "awkgram.y"
++#line 260 "awkgram.y"
      {
                if (include_source((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@@ -2130,19 -2132,19 +2131,19 @@@
  
    case 13:
  /* Line 1792 of yacc.c  */
- #line 267 "awkgram.y"
 -#line 269 "awkgram.y"
++#line 268 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 14:
  /* Line 1792 of yacc.c  */
- #line 269 "awkgram.y"
 -#line 271 "awkgram.y"
++#line 270 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 15:
  /* Line 1792 of yacc.c  */
- #line 274 "awkgram.y"
 -#line 276 "awkgram.y"
++#line 275 "awkgram.y"
      {
                if (load_library((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@@ -2154,31 -2156,31 +2155,31 @@@
  
    case 16:
  /* Line 1792 of yacc.c  */
- #line 282 "awkgram.y"
 -#line 284 "awkgram.y"
++#line 283 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 17:
  /* Line 1792 of yacc.c  */
- #line 284 "awkgram.y"
 -#line 286 "awkgram.y"
++#line 285 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 18:
  /* Line 1792 of yacc.c  */
- #line 289 "awkgram.y"
 -#line 291 "awkgram.y"
++#line 290 "awkgram.y"
      { (yyval) = NULL; rule = Rule; }
      break;
  
    case 19:
  /* Line 1792 of yacc.c  */
- #line 291 "awkgram.y"
 -#line 293 "awkgram.y"
++#line 292 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
      break;
  
    case 20:
  /* Line 1792 of yacc.c  */
- #line 293 "awkgram.y"
 -#line 295 "awkgram.y"
++#line 294 "awkgram.y"
      {
                INSTRUCTION *tp;
  
@@@ -2208,7 -2210,7 +2209,7 @@@
  
    case 21:
  /* Line 1792 of yacc.c  */
- #line 319 "awkgram.y"
 -#line 321 "awkgram.y"
++#line 320 "awkgram.y"
      {
                static int begin_seen = 0;
                if (do_lint_old && ++begin_seen == 2)
@@@ -2223,7 -2225,7 +2224,7 @@@
  
    case 22:
  /* Line 1792 of yacc.c  */
- #line 330 "awkgram.y"
 -#line 332 "awkgram.y"
++#line 331 "awkgram.y"
      {
                static int end_seen = 0;
                if (do_lint_old && ++end_seen == 2)
@@@ -2238,7 -2240,7 +2239,7 @@@
  
    case 23:
  /* Line 1792 of yacc.c  */
- #line 341 "awkgram.y"
 -#line 343 "awkgram.y"
++#line 342 "awkgram.y"
      {
                (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@@ -2248,7 -2250,7 +2249,7 @@@
  
    case 24:
  /* Line 1792 of yacc.c  */
- #line 347 "awkgram.y"
 -#line 349 "awkgram.y"
++#line 348 "awkgram.y"
      {
                (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@@ -2258,7 -2260,7 +2259,7 @@@
  
    case 25:
  /* Line 1792 of yacc.c  */
- #line 356 "awkgram.y"
 -#line 358 "awkgram.y"
++#line 357 "awkgram.y"
      {
                if ((yyvsp[(2) - (5)]) == NULL)
                        (yyval) = list_create(instruction(Op_no_op));
@@@ -2269,19 -2271,19 +2270,19 @@@
  
    case 26:
  /* Line 1792 of yacc.c  */
- #line 366 "awkgram.y"
 -#line 368 "awkgram.y"
++#line 367 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 27:
  /* Line 1792 of yacc.c  */
- #line 368 "awkgram.y"
 -#line 370 "awkgram.y"
++#line 369 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 28:
  /* Line 1792 of yacc.c  */
- #line 370 "awkgram.y"
 -#line 372 "awkgram.y"
++#line 371 "awkgram.y"
      {
                yyerror(_("`%s' is a built-in function, it cannot be 
redefined"),
                                        tokstart);
@@@ -2291,13 -2293,13 +2292,13 @@@
  
    case 29:
  /* Line 1792 of yacc.c  */
- #line 376 "awkgram.y"
 -#line 378 "awkgram.y"
++#line 377 "awkgram.y"
      { (yyval) = (yyvsp[(2) - (2)]); }
      break;
  
    case 32:
  /* Line 1792 of yacc.c  */
- #line 386 "awkgram.y"
 -#line 388 "awkgram.y"
++#line 387 "awkgram.y"
      {
                (yyvsp[(1) - (6)])->source_file = source;
                if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
@@@ -2312,13 -2314,13 +2313,13 @@@
  
    case 33:
  /* Line 1792 of yacc.c  */
- #line 404 "awkgram.y"
 -#line 406 "awkgram.y"
++#line 405 "awkgram.y"
      { want_regexp = true; }
      break;
  
    case 34:
  /* Line 1792 of yacc.c  */
- #line 406 "awkgram.y"
 -#line 408 "awkgram.y"
++#line 407 "awkgram.y"
      {
                  NODE *n, *exp;
                  char *re;
@@@ -2351,19 -2353,19 +2352,19 @@@
  
    case 35:
  /* Line 1792 of yacc.c  */
- #line 438 "awkgram.y"
 -#line 440 "awkgram.y"
++#line 439 "awkgram.y"
      { bcfree((yyvsp[(1) - (1)])); }
      break;
  
    case 37:
  /* Line 1792 of yacc.c  */
- #line 444 "awkgram.y"
 -#line 446 "awkgram.y"
++#line 445 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 38:
  /* Line 1792 of yacc.c  */
- #line 446 "awkgram.y"
 -#line 448 "awkgram.y"
++#line 447 "awkgram.y"
      {
                if ((yyvsp[(2) - (2)]) == NULL)
                        (yyval) = (yyvsp[(1) - (2)]);
@@@ -2380,25 -2382,25 +2381,25 @@@
  
    case 39:
  /* Line 1792 of yacc.c  */
- #line 459 "awkgram.y"
 -#line 461 "awkgram.y"
++#line 460 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 42:
  /* Line 1792 of yacc.c  */
- #line 469 "awkgram.y"
 -#line 471 "awkgram.y"
++#line 470 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 43:
  /* Line 1792 of yacc.c  */
- #line 471 "awkgram.y"
 -#line 473 "awkgram.y"
++#line 472 "awkgram.y"
      { (yyval) = (yyvsp[(2) - (3)]); }
      break;
  
    case 44:
  /* Line 1792 of yacc.c  */
- #line 473 "awkgram.y"
 -#line 475 "awkgram.y"
++#line 474 "awkgram.y"
      {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@@ -2409,7 -2411,7 +2410,7 @@@
  
    case 45:
  /* Line 1792 of yacc.c  */
- #line 480 "awkgram.y"
 -#line 482 "awkgram.y"
++#line 481 "awkgram.y"
      {
                INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
                INSTRUCTION *ip, *nextc, *tbreak;
@@@ -2503,7 -2505,7 +2504,7 @@@
  
    case 46:
  /* Line 1792 of yacc.c  */
- #line 570 "awkgram.y"
 -#line 572 "awkgram.y"
++#line 571 "awkgram.y"
      { 
                /*
                 *    -----------------
@@@ -2549,7 -2551,7 +2550,7 @@@
  
    case 47:
  /* Line 1792 of yacc.c  */
- #line 612 "awkgram.y"
 -#line 614 "awkgram.y"
++#line 613 "awkgram.y"
      {
                /*
                 *    -----------------
@@@ -2595,7 -2597,7 +2596,7 @@@
  
    case 48:
  /* Line 1792 of yacc.c  */
- #line 654 "awkgram.y"
 -#line 656 "awkgram.y"
++#line 655 "awkgram.y"
      {
                INSTRUCTION *ip;
                char *var_name = (yyvsp[(3) - (8)])->lextok;
@@@ -2712,7 -2714,7 +2713,7 @@@ regular_loop
  
    case 49:
  /* Line 1792 of yacc.c  */
- #line 767 "awkgram.y"
 -#line 769 "awkgram.y"
++#line 768 "awkgram.y"
      {
                (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), 
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
  
@@@ -2723,7 -2725,7 +2724,7 @@@
  
    case 50:
  /* Line 1792 of yacc.c  */
- #line 774 "awkgram.y"
 -#line 776 "awkgram.y"
++#line 775 "awkgram.y"
      {
                (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), 
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
  
@@@ -2734,7 -2736,7 +2735,7 @@@
  
    case 51:
  /* Line 1792 of yacc.c  */
- #line 781 "awkgram.y"
 -#line 783 "awkgram.y"
++#line 782 "awkgram.y"
      {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@@ -2745,7 -2747,7 +2746,7 @@@
  
    case 52:
  /* Line 1792 of yacc.c  */
- #line 791 "awkgram.y"
 -#line 793 "awkgram.y"
++#line 792 "awkgram.y"
      { 
                if (! break_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@@ -2758,7 -2760,7 +2759,7 @@@
  
    case 53:
  /* Line 1792 of yacc.c  */
- #line 800 "awkgram.y"
 -#line 802 "awkgram.y"
++#line 801 "awkgram.y"
      {
                if (! continue_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@@ -2771,7 -2773,7 +2772,7 @@@
  
    case 54:
  /* Line 1792 of yacc.c  */
- #line 809 "awkgram.y"
 -#line 811 "awkgram.y"
++#line 810 "awkgram.y"
      {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule && rule != Rule)
@@@ -2784,7 -2786,7 +2785,7 @@@
  
    case 55:
  /* Line 1792 of yacc.c  */
- #line 818 "awkgram.y"
 -#line 820 "awkgram.y"
++#line 819 "awkgram.y"
      {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule == BEGIN || rule == END || rule == ENDFILE)
@@@ -2799,7 -2801,7 +2800,7 @@@
  
    case 56:
  /* Line 1792 of yacc.c  */
- #line 829 "awkgram.y"
 -#line 831 "awkgram.y"
++#line 830 "awkgram.y"
      {
                /* Initialize the two possible jump targets, the actual target
                 * is resolved at run-time. 
@@@ -2818,7 -2820,7 +2819,7 @@@
  
    case 57:
  /* Line 1792 of yacc.c  */
- #line 844 "awkgram.y"
 -#line 846 "awkgram.y"
++#line 845 "awkgram.y"
      {
                if (! in_function)
                        yyerror(_("`return' used outside function context"));
@@@ -2827,7 -2829,7 +2828,7 @@@
  
    case 58:
  /* Line 1792 of yacc.c  */
- #line 847 "awkgram.y"
 -#line 849 "awkgram.y"
++#line 848 "awkgram.y"
      {
                if ((yyvsp[(3) - (4)]) == NULL) {
                        (yyval) = list_create((yyvsp[(1) - (4)]));
@@@ -2852,13 -2854,13 +2853,13 @@@
  
    case 60:
  /* Line 1792 of yacc.c  */
- #line 879 "awkgram.y"
 -#line 881 "awkgram.y"
++#line 880 "awkgram.y"
      { in_print = true; in_parens = 0; }
      break;
  
    case 61:
  /* Line 1792 of yacc.c  */
- #line 880 "awkgram.y"
 -#line 882 "awkgram.y"
++#line 881 "awkgram.y"
      {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@@ -2959,13 -2961,13 +2960,13 @@@ regular_print
  
    case 62:
  /* Line 1792 of yacc.c  */
- #line 977 "awkgram.y"
 -#line 979 "awkgram.y"
++#line 978 "awkgram.y"
      { sub_counter = 0; }
      break;
  
    case 63:
  /* Line 1792 of yacc.c  */
- #line 978 "awkgram.y"
 -#line 980 "awkgram.y"
++#line 979 "awkgram.y"
      {
                char *arr = (yyvsp[(2) - (4)])->lextok;
  
@@@ -3002,7 -3004,7 +3003,7 @@@
  
    case 64:
  /* Line 1792 of yacc.c  */
- #line 1015 "awkgram.y"
 -#line 1017 "awkgram.y"
++#line 1016 "awkgram.y"
      {
                static bool warned = false;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@@ -3032,31 -3034,31 +3033,31 @@@
  
    case 65:
  /* Line 1792 of yacc.c  */
- #line 1041 "awkgram.y"
 -#line 1043 "awkgram.y"
++#line 1042 "awkgram.y"
      { (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
      break;
  
    case 66:
  /* Line 1792 of yacc.c  */
- #line 1046 "awkgram.y"
 -#line 1048 "awkgram.y"
++#line 1047 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 67:
  /* Line 1792 of yacc.c  */
- #line 1048 "awkgram.y"
 -#line 1050 "awkgram.y"
++#line 1049 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 68:
  /* Line 1792 of yacc.c  */
- #line 1053 "awkgram.y"
 -#line 1055 "awkgram.y"
++#line 1054 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 69:
  /* Line 1792 of yacc.c  */
- #line 1055 "awkgram.y"
 -#line 1057 "awkgram.y"
++#line 1056 "awkgram.y"
      {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@@ -3067,13 -3069,13 +3068,13 @@@
  
    case 70:
  /* Line 1792 of yacc.c  */
- #line 1062 "awkgram.y"
 -#line 1064 "awkgram.y"
++#line 1063 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 71:
  /* Line 1792 of yacc.c  */
- #line 1067 "awkgram.y"
 -#line 1069 "awkgram.y"
++#line 1068 "awkgram.y"
      {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@@ -3089,7 -3091,7 +3090,7 @@@
  
    case 72:
  /* Line 1792 of yacc.c  */
- #line 1079 "awkgram.y"
 -#line 1081 "awkgram.y"
++#line 1080 "awkgram.y"
      {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@@ -3104,13 -3106,13 +3105,13 @@@
  
    case 73:
  /* Line 1792 of yacc.c  */
- #line 1093 "awkgram.y"
 -#line 1095 "awkgram.y"
++#line 1094 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 74:
  /* Line 1792 of yacc.c  */
- #line 1095 "awkgram.y"
 -#line 1097 "awkgram.y"
++#line 1096 "awkgram.y"
      { 
                NODE *n = (yyvsp[(2) - (2)])->memory;
                (void) force_number(n);
@@@ -3122,7 -3124,7 +3123,7 @@@
  
    case 75:
  /* Line 1792 of yacc.c  */
- #line 1103 "awkgram.y"
 -#line 1105 "awkgram.y"
++#line 1104 "awkgram.y"
      {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@@ -3131,13 -3133,13 +3132,13 @@@
  
    case 76:
  /* Line 1792 of yacc.c  */
- #line 1108 "awkgram.y"
 -#line 1110 "awkgram.y"
++#line 1109 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 77:
  /* Line 1792 of yacc.c  */
- #line 1110 "awkgram.y"
 -#line 1112 "awkgram.y"
++#line 1111 "awkgram.y"
      {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
@@@ -3146,19 -3148,19 +3147,19 @@@
  
    case 78:
  /* Line 1792 of yacc.c  */
- #line 1118 "awkgram.y"
 -#line 1120 "awkgram.y"
++#line 1119 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 79:
  /* Line 1792 of yacc.c  */
- #line 1120 "awkgram.y"
 -#line 1122 "awkgram.y"
++#line 1121 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 81:
  /* Line 1792 of yacc.c  */
- #line 1130 "awkgram.y"
 -#line 1132 "awkgram.y"
++#line 1131 "awkgram.y"
      {
                (yyval) = (yyvsp[(2) - (3)]);
          }
@@@ -3166,7 -3168,7 +3167,7 @@@
  
    case 82:
  /* Line 1792 of yacc.c  */
- #line 1137 "awkgram.y"
 -#line 1139 "awkgram.y"
++#line 1138 "awkgram.y"
      {
                in_print = false;
                in_parens = 0;
@@@ -3176,13 -3178,13 +3177,13 @@@
  
    case 83:
  /* Line 1792 of yacc.c  */
- #line 1142 "awkgram.y"
 -#line 1144 "awkgram.y"
++#line 1143 "awkgram.y"
      { in_print = false; in_parens = 0; }
      break;
  
    case 84:
  /* Line 1792 of yacc.c  */
- #line 1143 "awkgram.y"
 -#line 1145 "awkgram.y"
++#line 1144 "awkgram.y"
      {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@@ -3194,7 -3196,7 +3195,7 @@@
  
    case 85:
  /* Line 1792 of yacc.c  */
- #line 1154 "awkgram.y"
 -#line 1156 "awkgram.y"
++#line 1155 "awkgram.y"
      {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
@@@ -3202,7 -3204,7 +3203,7 @@@
  
    case 86:
  /* Line 1792 of yacc.c  */
- #line 1159 "awkgram.y"
 -#line 1161 "awkgram.y"
++#line 1160 "awkgram.y"
      {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
@@@ -3210,13 -3212,13 +3211,13 @@@
  
    case 91:
  /* Line 1792 of yacc.c  */
- #line 1176 "awkgram.y"
 -#line 1178 "awkgram.y"
++#line 1177 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 92:
  /* Line 1792 of yacc.c  */
- #line 1178 "awkgram.y"
 -#line 1180 "awkgram.y"
++#line 1179 "awkgram.y"
      {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@@ -3225,19 -3227,19 +3226,19 @@@
  
    case 93:
  /* Line 1792 of yacc.c  */
- #line 1186 "awkgram.y"
 -#line 1188 "awkgram.y"
++#line 1187 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 94:
  /* Line 1792 of yacc.c  */
- #line 1188 "awkgram.y"
 -#line 1190 "awkgram.y"
++#line 1189 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]) ; }
      break;
  
    case 95:
  /* Line 1792 of yacc.c  */
- #line 1193 "awkgram.y"
 -#line 1195 "awkgram.y"
++#line 1194 "awkgram.y"
      {
                (yyvsp[(1) - (1)])->param_count = 0;
                (yyval) = list_create((yyvsp[(1) - (1)]));
@@@ -3246,7 -3248,7 +3247,7 @@@
  
    case 96:
  /* Line 1792 of yacc.c  */
- #line 1198 "awkgram.y"
 -#line 1200 "awkgram.y"
++#line 1199 "awkgram.y"
      {
                (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
                (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@@ -3256,55 -3258,55 +3257,55 @@@
  
    case 97:
  /* Line 1792 of yacc.c  */
- #line 1204 "awkgram.y"
 -#line 1206 "awkgram.y"
++#line 1205 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 98:
  /* Line 1792 of yacc.c  */
- #line 1206 "awkgram.y"
 -#line 1208 "awkgram.y"
++#line 1207 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (2)]); }
      break;
  
    case 99:
  /* Line 1792 of yacc.c  */
- #line 1208 "awkgram.y"
 -#line 1210 "awkgram.y"
++#line 1209 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (3)]); }
      break;
  
    case 100:
  /* Line 1792 of yacc.c  */
- #line 1214 "awkgram.y"
 -#line 1216 "awkgram.y"
++#line 1215 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 101:
  /* Line 1792 of yacc.c  */
- #line 1216 "awkgram.y"
 -#line 1218 "awkgram.y"
++#line 1217 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 102:
  /* Line 1792 of yacc.c  */
- #line 1221 "awkgram.y"
 -#line 1223 "awkgram.y"
++#line 1222 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 103:
  /* Line 1792 of yacc.c  */
- #line 1223 "awkgram.y"
 -#line 1225 "awkgram.y"
++#line 1224 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 104:
  /* Line 1792 of yacc.c  */
- #line 1228 "awkgram.y"
 -#line 1230 "awkgram.y"
++#line 1229 "awkgram.y"
      { (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
      break;
  
    case 105:
  /* Line 1792 of yacc.c  */
- #line 1230 "awkgram.y"
 -#line 1232 "awkgram.y"
++#line 1231 "awkgram.y"
      {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
@@@ -3313,31 -3315,31 +3314,31 @@@
  
    case 106:
  /* Line 1792 of yacc.c  */
- #line 1235 "awkgram.y"
 -#line 1237 "awkgram.y"
++#line 1236 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 107:
  /* Line 1792 of yacc.c  */
- #line 1237 "awkgram.y"
 -#line 1239 "awkgram.y"
++#line 1238 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 108:
  /* Line 1792 of yacc.c  */
- #line 1239 "awkgram.y"
 -#line 1241 "awkgram.y"
++#line 1240 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 109:
  /* Line 1792 of yacc.c  */
- #line 1241 "awkgram.y"
 -#line 1243 "awkgram.y"
++#line 1242 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 110:
  /* Line 1792 of yacc.c  */
- #line 1247 "awkgram.y"
 -#line 1249 "awkgram.y"
++#line 1248 "awkgram.y"
      {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@@ -3348,19 -3350,19 +3349,19 @@@
  
    case 111:
  /* Line 1792 of yacc.c  */
- #line 1254 "awkgram.y"
 -#line 1256 "awkgram.y"
++#line 1255 "awkgram.y"
      { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
      break;
  
    case 112:
  /* Line 1792 of yacc.c  */
- #line 1256 "awkgram.y"
 -#line 1258 "awkgram.y"
++#line 1257 "awkgram.y"
      { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
      break;
  
    case 113:
  /* Line 1792 of yacc.c  */
- #line 1258 "awkgram.y"
 -#line 1260 "awkgram.y"
++#line 1259 "awkgram.y"
      {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@@ -3380,7 -3382,7 +3381,7 @@@
  
    case 114:
  /* Line 1792 of yacc.c  */
- #line 1274 "awkgram.y"
 -#line 1276 "awkgram.y"
++#line 1275 "awkgram.y"
      {
                if (do_lint_old)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@@ -3394,7 -3396,7 +3395,7 @@@
  
    case 115:
  /* Line 1792 of yacc.c  */
- #line 1284 "awkgram.y"
 -#line 1286 "awkgram.y"
++#line 1285 "awkgram.y"
      {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@@ -3405,31 -3407,31 +3406,31 @@@
  
    case 116:
  /* Line 1792 of yacc.c  */
- #line 1291 "awkgram.y"
 -#line 1293 "awkgram.y"
++#line 1292 "awkgram.y"
      { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
      break;
  
    case 117:
  /* Line 1792 of yacc.c  */
- #line 1293 "awkgram.y"
 -#line 1295 "awkgram.y"
++#line 1294 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 118:
  /* Line 1792 of yacc.c  */
- #line 1298 "awkgram.y"
 -#line 1300 "awkgram.y"
++#line 1299 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 119:
  /* Line 1792 of yacc.c  */
- #line 1300 "awkgram.y"
 -#line 1302 "awkgram.y"
++#line 1301 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 120:
  /* Line 1792 of yacc.c  */
- #line 1302 "awkgram.y"
 -#line 1304 "awkgram.y"
++#line 1303 "awkgram.y"
      { 
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
@@@ -3438,43 -3440,43 +3439,43 @@@
  
    case 121:
  /* Line 1792 of yacc.c  */
- #line 1310 "awkgram.y"
 -#line 1312 "awkgram.y"
++#line 1311 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 122:
  /* Line 1792 of yacc.c  */
- #line 1312 "awkgram.y"
 -#line 1314 "awkgram.y"
++#line 1313 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 123:
  /* Line 1792 of yacc.c  */
- #line 1317 "awkgram.y"
 -#line 1319 "awkgram.y"
++#line 1318 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 124:
  /* Line 1792 of yacc.c  */
- #line 1319 "awkgram.y"
 -#line 1321 "awkgram.y"
++#line 1320 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 125:
  /* Line 1792 of yacc.c  */
- #line 1324 "awkgram.y"
 -#line 1326 "awkgram.y"
++#line 1325 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 126:
  /* Line 1792 of yacc.c  */
- #line 1326 "awkgram.y"
 -#line 1328 "awkgram.y"
++#line 1327 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 127:
  /* Line 1792 of yacc.c  */
- #line 1328 "awkgram.y"
 -#line 1330 "awkgram.y"
++#line 1329 "awkgram.y"
      {
                int count = 2;
                bool is_simple_var = false;
@@@ -3525,43 -3527,43 +3526,43 @@@
  
    case 129:
  /* Line 1792 of yacc.c  */
- #line 1380 "awkgram.y"
 -#line 1382 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1381 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 130:
  /* Line 1792 of yacc.c  */
- #line 1382 "awkgram.y"
 -#line 1384 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1383 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 131:
  /* Line 1792 of yacc.c  */
- #line 1384 "awkgram.y"
 -#line 1386 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1385 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 132:
  /* Line 1792 of yacc.c  */
- #line 1386 "awkgram.y"
 -#line 1388 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1387 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 133:
  /* Line 1792 of yacc.c  */
- #line 1388 "awkgram.y"
 -#line 1390 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1389 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 134:
  /* Line 1792 of yacc.c  */
- #line 1390 "awkgram.y"
 -#line 1392 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1391 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 135:
  /* Line 1792 of yacc.c  */
- #line 1392 "awkgram.y"
 -#line 1394 "awkgram.y"
++#line 1393 "awkgram.y"
      {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@@ -3588,7 -3590,7 +3589,7 @@@
  
    case 136:
  /* Line 1792 of yacc.c  */
- #line 1415 "awkgram.y"
 -#line 1417 "awkgram.y"
++#line 1416 "awkgram.y"
      {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@@ -3597,7 -3599,7 +3598,7 @@@
  
    case 137:
  /* Line 1792 of yacc.c  */
- #line 1420 "awkgram.y"
 -#line 1422 "awkgram.y"
++#line 1421 "awkgram.y"
      {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@@ -3606,7 -3608,7 +3607,7 @@@
  
    case 138:
  /* Line 1792 of yacc.c  */
- #line 1425 "awkgram.y"
 -#line 1427 "awkgram.y"
++#line 1426 "awkgram.y"
      {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@@ -3630,7 -3632,7 +3631,7 @@@
  
    case 139:
  /* Line 1792 of yacc.c  */
- #line 1450 "awkgram.y"
 -#line 1452 "awkgram.y"
++#line 1451 "awkgram.y"
      {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
@@@ -3639,43 -3641,43 +3640,43 @@@
  
    case 140:
  /* Line 1792 of yacc.c  */
- #line 1456 "awkgram.y"
 -#line 1458 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1457 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 141:
  /* Line 1792 of yacc.c  */
- #line 1458 "awkgram.y"
 -#line 1460 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1459 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 142:
  /* Line 1792 of yacc.c  */
- #line 1460 "awkgram.y"
 -#line 1462 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1461 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 143:
  /* Line 1792 of yacc.c  */
- #line 1462 "awkgram.y"
 -#line 1464 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1463 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 144:
  /* Line 1792 of yacc.c  */
- #line 1464 "awkgram.y"
 -#line 1466 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1465 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 145:
  /* Line 1792 of yacc.c  */
- #line 1466 "awkgram.y"
 -#line 1468 "awkgram.y"
 -    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
++#line 1467 "awkgram.y"
 +    { (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
      break;
  
    case 146:
  /* Line 1792 of yacc.c  */
- #line 1471 "awkgram.y"
 -#line 1473 "awkgram.y"
++#line 1472 "awkgram.y"
      {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@@ -3683,7 -3685,7 +3684,7 @@@
  
    case 147:
  /* Line 1792 of yacc.c  */
- #line 1475 "awkgram.y"
 -#line 1477 "awkgram.y"
++#line 1476 "awkgram.y"
      {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@@ -3719,13 -3721,13 +3720,13 @@@
  
    case 148:
  /* Line 1792 of yacc.c  */
- #line 1507 "awkgram.y"
 -#line 1509 "awkgram.y"
++#line 1508 "awkgram.y"
      { (yyval) = (yyvsp[(2) - (3)]); }
      break;
  
    case 149:
  /* Line 1792 of yacc.c  */
- #line 1509 "awkgram.y"
 -#line 1511 "awkgram.y"
++#line 1510 "awkgram.y"
      {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@@ -3735,7 -3737,7 +3736,7 @@@
  
    case 150:
  /* Line 1792 of yacc.c  */
- #line 1515 "awkgram.y"
 -#line 1517 "awkgram.y"
++#line 1516 "awkgram.y"
      {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@@ -3745,7 -3747,7 +3746,7 @@@
  
    case 151:
  /* Line 1792 of yacc.c  */
- #line 1521 "awkgram.y"
 -#line 1523 "awkgram.y"
++#line 1522 "awkgram.y"
      {
                static bool warned = false;
  
@@@ -3762,7 -3764,7 +3763,7 @@@
  
    case 154:
  /* Line 1792 of yacc.c  */
- #line 1536 "awkgram.y"
 -#line 1538 "awkgram.y"
++#line 1537 "awkgram.y"
      {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@@ -3771,7 -3773,7 +3772,7 @@@
  
    case 155:
  /* Line 1792 of yacc.c  */
- #line 1541 "awkgram.y"
 -#line 1543 "awkgram.y"
++#line 1542 "awkgram.y"
      {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@@ -3780,7 -3782,7 +3781,7 @@@
  
    case 156:
  /* Line 1792 of yacc.c  */
- #line 1546 "awkgram.y"
 -#line 1548 "awkgram.y"
++#line 1547 "awkgram.y"
      {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@@ -3788,7 -3790,7 +3789,7 @@@
  
    case 157:
  /* Line 1792 of yacc.c  */
- #line 1550 "awkgram.y"
 -#line 1552 "awkgram.y"
++#line 1551 "awkgram.y"
      {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@@ -3796,7 -3798,7 +3797,7 @@@
  
    case 158:
  /* Line 1792 of yacc.c  */
- #line 1554 "awkgram.y"
 -#line 1556 "awkgram.y"
++#line 1555 "awkgram.y"
      {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
@@@ -3815,7 -3817,7 +3816,7 @@@
  
    case 159:
  /* Line 1792 of yacc.c  */
- #line 1569 "awkgram.y"
 -#line 1571 "awkgram.y"
++#line 1570 "awkgram.y"
      {
            /*
             * was: $$ = $2
@@@ -3828,7 -3831,7 +3829,7 @@@
  
    case 160:
  /* Line 1792 of yacc.c  */
- #line 1581 "awkgram.y"
 -#line 1584 "awkgram.y"
++#line 1582 "awkgram.y"
      {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@@ -3837,7 -3840,7 +3838,7 @@@
  
    case 161:
  /* Line 1792 of yacc.c  */
- #line 1586 "awkgram.y"
 -#line 1589 "awkgram.y"
++#line 1587 "awkgram.y"
      {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@@ -3874,7 -3877,7 +3875,7 @@@
  
    case 162:
  /* Line 1792 of yacc.c  */
- #line 1622 "awkgram.y"
 -#line 1625 "awkgram.y"
++#line 1623 "awkgram.y"
      {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@@ -3892,37 -3895,37 +3893,37 @@@
  
    case 163:
  /* Line 1792 of yacc.c  */
- #line 1639 "awkgram.y"
 -#line 1642 "awkgram.y"
++#line 1640 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 164:
  /* Line 1792 of yacc.c  */
- #line 1641 "awkgram.y"
 -#line 1644 "awkgram.y"
++#line 1642 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 165:
  /* Line 1792 of yacc.c  */
- #line 1646 "awkgram.y"
 -#line 1649 "awkgram.y"
++#line 1647 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 166:
  /* Line 1792 of yacc.c  */
- #line 1648 "awkgram.y"
 -#line 1651 "awkgram.y"
++#line 1649 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (2)]); }
      break;
  
    case 167:
  /* Line 1792 of yacc.c  */
- #line 1653 "awkgram.y"
 -#line 1656 "awkgram.y"
++#line 1654 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 168:
  /* Line 1792 of yacc.c  */
- #line 1655 "awkgram.y"
 -#line 1658 "awkgram.y"
++#line 1656 "awkgram.y"
      {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@@ -3930,7 -3933,7 +3931,7 @@@
  
    case 169:
  /* Line 1792 of yacc.c  */
- #line 1662 "awkgram.y"
 -#line 1665 "awkgram.y"
++#line 1663 "awkgram.y"
      {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@@ -3948,7 -3951,7 +3949,7 @@@
  
    case 170:
  /* Line 1792 of yacc.c  */
- #line 1679 "awkgram.y"
 -#line 1682 "awkgram.y"
++#line 1680 "awkgram.y"
      {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@@ -3966,13 -3969,13 +3967,13 @@@
  
    case 171:
  /* Line 1792 of yacc.c  */
- #line 1696 "awkgram.y"
 -#line 1699 "awkgram.y"
++#line 1697 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); }
      break;
  
    case 172:
  /* Line 1792 of yacc.c  */
- #line 1698 "awkgram.y"
 -#line 1701 "awkgram.y"
++#line 1699 "awkgram.y"
      {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@@ -3980,13 -3983,13 +3981,13 @@@
  
    case 173:
  /* Line 1792 of yacc.c  */
- #line 1705 "awkgram.y"
 -#line 1708 "awkgram.y"
++#line 1706 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (2)]); }
      break;
  
    case 174:
  /* Line 1792 of yacc.c  */
- #line 1710 "awkgram.y"
 -#line 1713 "awkgram.y"
++#line 1711 "awkgram.y"
      {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
  
@@@ -3998,7 -4001,7 +3999,7 @@@
  
    case 175:
  /* Line 1792 of yacc.c  */
- #line 1718 "awkgram.y"
 -#line 1721 "awkgram.y"
++#line 1719 "awkgram.y"
      {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@@ -4009,7 -4012,7 +4010,7 @@@
  
    case 176:
  /* Line 1792 of yacc.c  */
- #line 1728 "awkgram.y"
 -#line 1731 "awkgram.y"
++#line 1729 "awkgram.y"
      {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@@ -4025,7 -4028,7 +4026,7 @@@
  
    case 177:
  /* Line 1792 of yacc.c  */
- #line 1740 "awkgram.y"
 -#line 1743 "awkgram.y"
++#line 1741 "awkgram.y"
      {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@@ -4035,7 -4038,7 +4036,7 @@@
  
    case 178:
  /* Line 1792 of yacc.c  */
- #line 1749 "awkgram.y"
 -#line 1752 "awkgram.y"
++#line 1750 "awkgram.y"
      {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@@ -4043,7 -4046,7 +4044,7 @@@
  
    case 179:
  /* Line 1792 of yacc.c  */
- #line 1753 "awkgram.y"
 -#line 1756 "awkgram.y"
++#line 1754 "awkgram.y"
      {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@@ -4051,43 -4054,43 +4052,43 @@@
  
    case 180:
  /* Line 1792 of yacc.c  */
- #line 1756 "awkgram.y"
 -#line 1759 "awkgram.y"
++#line 1757 "awkgram.y"
      { (yyval) = NULL; }
      break;
  
    case 182:
  /* Line 1792 of yacc.c  */
- #line 1764 "awkgram.y"
 -#line 1767 "awkgram.y"
++#line 1765 "awkgram.y"
      { yyerrok; }
      break;
  
    case 183:
  /* Line 1792 of yacc.c  */
- #line 1768 "awkgram.y"
 -#line 1771 "awkgram.y"
++#line 1769 "awkgram.y"
      { yyerrok; }
      break;
  
    case 186:
  /* Line 1792 of yacc.c  */
- #line 1777 "awkgram.y"
 -#line 1780 "awkgram.y"
++#line 1778 "awkgram.y"
      { yyerrok; }
      break;
  
    case 187:
  /* Line 1792 of yacc.c  */
- #line 1781 "awkgram.y"
 -#line 1784 "awkgram.y"
++#line 1782 "awkgram.y"
      { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
      break;
  
    case 188:
  /* Line 1792 of yacc.c  */
- #line 1785 "awkgram.y"
 -#line 1788 "awkgram.y"
++#line 1786 "awkgram.y"
      { yyerrok; }
      break;
  
  
  /* Line 1792 of yacc.c  */
- #line 4103 "awkgram.c"
 -#line 4106 "awkgram.c"
++#line 4104 "awkgram.c"
        default: break;
      }
    /* User semantic actions sometimes alter yychar, and that requires
@@@ -4319,7 -4322,7 +4320,7 @@@ yyreturn
  
  
  /* Line 2055 of yacc.c  */
- #line 1787 "awkgram.y"
 -#line 1790 "awkgram.y"
++#line 1788 "awkgram.y"
  
  
  struct token {

http://git.sv.gnu.org/cgit/gawk.git/commit/?id=bb146e0626acb7e3020f037303fdc8890cb84b46

commit bb146e0626acb7e3020f037303fdc8890cb84b46
Author: John Haque <address@hidden>
Date:   Wed Dec 26 22:06:08 2012 -0600

    Number handler.

diff --git a/ChangeLog b/ChangeLog
index cb0e2d9..b8381a9 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2012-12-27         John Haque      <address@hidden>
+
+       Number handling interface.
+       
+       * awk.h (numbr_handler_t, bltin_t): New definitions.
+       * double.c: New file for C double numbers.
+       * mpfr.c: Reworked.
+
+       Lots of other changes.
+
 2012-12-19         Arnold D. Robbins     <address@hidden>
 
        * bootstrap.sh: Touch extension/aclocal.m4 also.
diff --git a/Makefile.am b/Makefile.am
index 085eadf..7a1b530 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -93,6 +93,7 @@ base_sources = \
        debug.c \
        dfa.c \
        dfa.h \
+       double.c \
        eval.c \
        ext.c \
        field.c \
diff --git a/Makefile.in b/Makefile.in
index 2c7e948..71df2f0 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -105,13 +105,14 @@ am__installdirs = "$(DESTDIR)$(bindir)" 
"$(DESTDIR)$(includedir)"
 PROGRAMS = $(bin_PROGRAMS)
 am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \
        cint_array.$(OBJEXT) command.$(OBJEXT) debug.$(OBJEXT) \
-       dfa.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \
-       floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) gawkmisc.$(OBJEXT) \
-       getopt.$(OBJEXT) getopt1.$(OBJEXT) int_array.$(OBJEXT) \
-       io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) \
-       node.$(OBJEXT) profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
-       regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
-       symbol.$(OBJEXT) version.$(OBJEXT)
+       dfa.$(OBJEXT) double.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) \
+       field.$(OBJEXT) floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) \
+       gawkmisc.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
+       int_array.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) \
+       msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) \
+       random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
+       replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
+       version.$(OBJEXT)
 am_gawk_OBJECTS = $(am__objects_1)
 gawk_OBJECTS = $(am_gawk_OBJECTS)
 gawk_LDADD = $(LDADD)
@@ -421,6 +422,7 @@ base_sources = \
        debug.c \
        dfa.c \
        dfa.h \
+       double.c \
        eval.c \
        ext.c \
        field.c \
@@ -584,6 +586,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/TODO.NUMH b/TODO.NUMH
new file mode 100644
index 0000000..c612bd5
--- /dev/null
+++ b/TODO.NUMH
@@ -0,0 +1 @@
+* put back constant-folding code for numbers
diff --git a/array.c b/array.c
index 1953bfe..c5090d9 100644
--- a/array.c
+++ b/array.c
@@ -79,7 +79,7 @@ void
 array_init()
 {
        (void) register_array_func(str_array_func);     /* the default */
-       if (! do_mpfr) {
+       if (numbr_hndlr == & awknum_hndlr) {
                (void) register_array_func(int_array_func);
                (void) register_array_func(cint_array_func);
        }
@@ -652,10 +652,6 @@ do_delete_loop(NODE *symbol, NODE **lhs)
 static void
 value_info(NODE *n)
 {
-
-#define PREC_NUM -1
-#define PREC_STR -1
-
        if (n == Nnull_string || n == Null_field) {
                fprintf(output_fp, "<(null)>");
                return;
@@ -663,30 +659,12 @@ value_info(NODE *n)
 
        if ((n->flags & (STRING|STRCUR)) != 0) {
                fprintf(output_fp, "<");
-               fprintf(output_fp, "\"%.*s\"", PREC_STR, n->stptr);
-               if ((n->flags & (NUMBER|NUMCUR)) != 0) {
-#ifdef HAVE_MPFR
-                       if (is_mpg_float(n))
-                               fprintf(output_fp, ":%s",
-                                       mpg_fmt("%.*R*g", PREC_NUM, ROUND_MODE, 
n->mpg_numbr));
-                       else if (is_mpg_integer(n))
-                               fprintf(output_fp, ":%s", mpg_fmt("%Zd", 
n->mpg_i));
-                       else
-#endif
-                       fprintf(output_fp, ":%.*g", PREC_NUM, n->numbr);
-               }
+               fprintf(output_fp, "\"%.*s\"", -1, n->stptr);
+               if ((n->flags & (NUMBER|NUMCUR)) != 0)
+                       fprintf(output_fp, ":%s", fmt_number("%.17g", n));
                fprintf(output_fp, ">");
-       } else {
-#ifdef HAVE_MPFR
-               if (is_mpg_float(n))
-                       fprintf(output_fp, "<%s>",
-                               mpg_fmt("%.*R*g", PREC_NUM, ROUND_MODE, 
n->mpg_numbr));
-               else if (is_mpg_integer(n))
-                       fprintf(output_fp, "<%s>", mpg_fmt("%Zd", n->mpg_i));
-               else
-#endif
-               fprintf(output_fp, "<%.*g>", PREC_NUM, n->numbr);
-       }
+       } else
+               fprintf(output_fp, "<%s>", fmt_number("%.17g", n));
 
        fprintf(output_fp, ":%s", flags2str(n->flags));
 
@@ -701,9 +679,6 @@ value_info(NODE *n)
                fprintf(output_fp, "CONVFMT=\"%s\"", n->stfmt <= -1 ? "%ld"
                                        : fmt_list[n->stfmt]->stptr);
        }
-
-#undef PREC_NUM
-#undef PREC_STR
 }
 
 
@@ -1215,22 +1190,11 @@ sort_user_func(const void *p1, const void *p2)
        PUSH(val2);
 
        /* execute the comparison function */
-       (void) (*interpret)(code);
+       interpret(code);
 
        /* return value of the comparison function */
        r = POP_NUMBER();
-#ifdef HAVE_MPFR
-       /*
-        * mpfr_sgn(mpz_sgn): Returns a positive value if op > 0,
-        * zero if op = 0, and a negative value if op < 0.
-        */
-       if (is_mpg_float(r))
-               ret = mpfr_sgn(r->mpg_numbr);
-       else if (is_mpg_integer(r))
-               ret = mpz_sgn(r->mpg_i);
-       else
-#endif
-               ret = (r->numbr < 0.0) ? -1 : (r->numbr > 0.0);
+        ret = sgn_number(r);
        DEREF(r);
        return ret;
 }
diff --git a/awk.h b/awk.h
index 0f9b2ec..89f2682 100644
--- a/awk.h
+++ b/awk.h
@@ -210,18 +210,6 @@ typedef void *stackoverflow_context_t;
    this is a hack but it gives us the right semantics */
 #define lintwarn (*(set_loc(__FILE__, __LINE__),lintfunc))
 
-#ifdef HAVE_MPFR
-#include <gmp.h>
-#include <mpfr.h>
-#ifndef MPFR_RNDN
-/* for compatibility with MPFR 2.X */
-#define MPFR_RNDN GMP_RNDN
-#define MPFR_RNDZ GMP_RNDZ
-#define MPFR_RNDU GMP_RNDU
-#define MPFR_RNDD GMP_RNDD
-#endif
-#endif
-
 #include "regex.h"
 #include "dfa.h"
 typedef struct Regexp {
@@ -244,6 +232,13 @@ typedef struct Regexp {
 #define RE_NEED_START  1       /* need to know start/end of match */
 #define RE_NO_BOL      2       /* not allowed to match ^ in regexp */
 
+
+#ifndef CHAR_BIT
+# define CHAR_BIT 8
+#endif
+
+#define DEFAULT_G_PRECISION 6
+
 #include "gawkapi.h"
 
 /* Stuff for losing systems. */
@@ -386,17 +381,6 @@ typedef struct exp_node {
                } nodep;
 
                struct {
-#ifdef HAVE_MPFR
-                       union {
-                               AWKNUM fltnum;
-                               mpfr_t mpnum;
-                               mpz_t mpi;
-                       } nm;
-#else
-                       AWKNUM fltnum;  /* this is here for optimal packing of
-                                        * the structure on many machines
-                                        */
-#endif
                        char *sp;
                        size_t slen;
                        long sref;
@@ -404,7 +388,14 @@ typedef struct exp_node {
 #if MBS_SUPPORT
                        wchar_t *wsp;
                        size_t wslen;
-#endif
+#endif         
+                       union {
+                               AWKNUM fltnum;
+                               void *pq;
+                       } nmb;
+#define numbr  sub.val.nmb.fltnum
+#define        qnumbr  sub.val.nmb.pq
+
                } val;
        } sub;
        NODETYPE type;
@@ -469,13 +460,6 @@ typedef struct exp_node {
 #define stfmt  sub.val.idx
 #define wstptr sub.val.wsp
 #define wstlen sub.val.wslen
-#ifdef HAVE_MPFR
-#define mpg_numbr      sub.val.nm.mpnum
-#define mpg_i          sub.val.nm.mpi
-#define numbr          sub.val.nm.fltnum
-#else
-#define numbr          sub.val.fltnum
-#endif
 
 /* Node_arrayfor */
 #define for_list       sub.nodep.r.av
@@ -553,18 +537,19 @@ typedef enum opcodeval {
        Op_illegal,
 
        /* binary operators */
+       Op_plus,
+       Op_minus,
        Op_times,
-       Op_times_i,
        Op_quotient,
-       Op_quotient_i,
        Op_mod,
-       Op_mod_i,
-       Op_plus,
-       Op_plus_i,
-       Op_minus,
-       Op_minus_i,
        Op_exp,
-       Op_exp_i,
+       Op_assign_plus,
+       Op_assign_minus,
+       Op_assign_times,
+       Op_assign_quotient,
+       Op_assign_mod,
+       Op_assign_exp,
+
        Op_concat,
 
        /* line range instruction pair */
@@ -579,6 +564,7 @@ typedef enum opcodeval {
        Op_predecrement,
        Op_postincrement,
        Op_postdecrement,
+       Op_unary_plus,
        Op_unary_minus,
        Op_field_spec,
 
@@ -590,12 +576,6 @@ typedef enum opcodeval {
        Op_store_var,           /* simple variable assignment optimization */
        Op_store_sub,           /* array[subscript] assignment optimization */
        Op_store_field,         /* $n assignment optimization */
-       Op_assign_times,
-       Op_assign_quotient,
-       Op_assign_mod,
-       Op_assign_plus,
-       Op_assign_minus,
-       Op_assign_exp,
        Op_assign_concat,
 
        /* boolean binaries */
@@ -882,6 +862,63 @@ typedef struct exp_instruction {
 /* Op_store_var */
 #define initval         x.xn
 
+
+typedef struct {
+       const char *name;       /* name of the built-in */
+       NODE *(*ptr)(int);      /* function that implements this built-in */
+} bltin_t;
+
+
+typedef struct {
+       bool (*init)(bltin_t **);                /* initialization */
+       const char *(*version_str)(void);        /* library version */
+       void (*load_procinfo)(void);             /* load relevant PROCINFO 
entries */
+
+       NODE *(*gawk_make_number)(AWKNUM);       /* convert AWKNUM to numeric 
value */
+       NODE *(*gawk_str2number)(char *, char **, int, bool);   /* convert a 
C-style string
+                                                                   to number */
+       NODE *(*gawk_copy_number)(const NODE *); /* deep-copy a numeric NODE */
+
+       void (*gawk_free_number)(NODE *);        /* free internally allocated 
space */
+
+       NODE *(*gawk_force_number)(NODE *);      /* force a NODE value to be 
numeric */
+       void (*gawk_negate_number)(NODE *);      /* in place negation of a 
number */
+       int (*gawk_cmp_numbers)(const NODE *, const NODE *);   /* compare two 
numbers */
+       int (*gawk_sgn_number)(const NODE *);    /* test if a numeric node is 
zero,
+                                                    positive or negative */
+       bool (*gawk_is_integer)(const NODE *);    /* test if a number is an 
integer */
+
+       NODE *(*gawk_fmt_number)(const char *, int, NODE *);   /* stringify a 
numeric value
+                                                                 based on awk 
input/output format */
+       NODE *(*gawk_format_nodes)(const char *, size_t, NODE **, long); /* 
format NODES according to
+                                                                           
user-specified FORMAT */  
+
+       /* conversion to C types */
+       AWKNUM (*gawk_todouble)(const NODE *);         /* number to AWKNUM */
+       long (*gawk_tolong)(const NODE *);             /* number to long */
+       unsigned long (*gawk_toulong)(const NODE *);   /* number to unsigned 
long */
+       uintmax_t (*gawk_touintmax_t)(const NODE *);   /* number to uintmax_t */
+
+       /* operators */
+       NODE *(*add)(const NODE *, const NODE *);      /* addition */
+       NODE *(*sub)(const NODE *, const NODE *);      /* subtraction */
+       NODE *(*mul)(const NODE *, const NODE *);      /* multiplication */
+       NODE *(*div)(const NODE *, const NODE *);      /* division */
+       NODE *(*mod)(const NODE *, const NODE *);      /* remainder */
+       NODE *(*pow)(const NODE *, const NODE *);      /* exponentiation */
+
+       NODE *(*add_long)(const NODE *, long);    /* add a long to a number */
+
+       NODE *(*update_numvar)(NODE *);           /* update a NODE value from
+                                                     internal variable(s) */
+       void (*set_numvar)(const NODE *);         /* update internal variable(s)
+                                                     from a NODE value */
+       long (*increment_var)(const NODE *, long);     /* update NR or FNR 
related internal
+                                                          variables -- 
efficiency hack */
+       void (*init_numvars)(void);               /* set default values for 
PREC etc. */
+} numbr_handler_t;
+
+
 typedef struct iobuf {
        awk_input_buf_t public; /* exposed to extensions */
        char *buf;              /* start data buffer */
@@ -1046,14 +1083,28 @@ extern NODE *LINT_node, *ERRNO_node, *TEXTDOMAIN_node, 
*FPAT_node;
 extern NODE *PREC_node, *ROUNDMODE_node;
 extern NODE *Nnull_string;
 extern NODE *Null_field;
+extern NODE *true_node, *false_node;
 extern NODE **fields_arr;
 extern int sourceline;
 extern char *source;
 extern int (*interpret)(INSTRUCTION *);        /* interpreter routine */
-extern NODE *(*make_number)(double);   /* double instead of AWKNUM on purpose 
*/
+
+extern numbr_handler_t awknum_hndlr;   /* double */
+extern numbr_handler_t mpfp_hndlr;     /* arbitrary-precision floating-point */
+extern numbr_handler_t *numbr_hndlr;   /* active handler */
+
+extern NODE *(*make_number)(AWKNUM);
 extern NODE *(*str2number)(NODE *);
 extern NODE *(*format_val)(const char *, int, NODE *);
 extern int (*cmp_numbers)(const NODE *, const NODE *);
+extern NODE *(*str2node)(char *, char **, int, bool);
+extern void (*free_number)(NODE *);
+extern unsigned long (*get_number_ui)(const NODE *);
+extern long (*get_number_si)(const NODE *);
+extern double (*get_number_d)(const NODE *);
+extern uintmax_t (*get_number_uj)(const NODE *);
+extern int (*sgn_number)(const NODE *);
+extern NODE *(*format_tree)(const char *, size_t, NODE **, long);
 
 /* built-in array types */
 extern afunc_t str_array_func[];
@@ -1080,7 +1131,6 @@ enum do_flag_values {
        DO_SANDBOX      = 0x0800,       /* sandbox mode - disable 'system' 
function & redirections */
        DO_PROFILE      = 0x1000,       /* profile the program */
        DO_DEBUG        = 0x2000,       /* debug the program */
-       DO_MPFR         = 0x4000        /* arbitrary-precision floating-point 
math */
 };
 
 #define do_traditional      (do_flags & DO_TRADITIONAL)
@@ -1094,7 +1144,6 @@ enum do_flag_values {
 #define do_tidy_mem         (do_flags & DO_TIDY_MEM)
 #define do_sandbox          (do_flags & DO_SANDBOX)
 #define do_debug            (do_flags & DO_DEBUG)
-#define do_mpfr             (do_flags & DO_MPFR)
 
 extern bool do_optimize;
 extern int use_lc_numeric;
@@ -1122,15 +1171,6 @@ extern int ngroups;
 extern struct lconv loc;
 #endif /* HAVE_LOCALE_H */
 
-#ifdef HAVE_MPFR
-extern mpfr_prec_t PRECISION;
-extern mpfr_rnd_t ROUND_MODE;
-extern mpz_t MNR;
-extern mpz_t MFNR;
-extern mpz_t mpzval;
-extern bool do_ieee_fmt;       /* emulate IEEE 754 floating-point format */
-#endif
-
 
 extern const char *myname;
 extern const char def_strftime_format[];
@@ -1193,43 +1233,8 @@ DEREF(NODE *r)
 #define TOP_NUMBER() force_number(TOP_SCALAR())
 
 /* ------------------------- Pseudo-functions ------------------------- */
-#ifdef HAVE_MPFR
-/* conversion to C types */
-#define get_number_ui(n)       (((n)->flags & MPFN) ? 
mpfr_get_ui((n)->mpg_numbr, ROUND_MODE) \
-                               : ((n)->flags & MPZN) ? mpz_get_ui((n)->mpg_i) \
-                               : (unsigned long) (n)->numbr)
-#define get_number_si(n)       (((n)->flags & MPFN) ? 
mpfr_get_si((n)->mpg_numbr, ROUND_MODE) \
-                               : ((n)->flags & MPZN) ? mpz_get_si((n)->mpg_i) \
-                               : (long) (n)->numbr)
-#define get_number_d(n)                (((n)->flags & MPFN) ? 
mpfr_get_d((n)->mpg_numbr, ROUND_MODE) \
-                               : ((n)->flags & MPZN) ? mpz_get_d((n)->mpg_i) \
-                               : (double) (n)->numbr)
-#define get_number_uj(n)       (((n)->flags & MPFN) ? 
mpfr_get_uj((n)->mpg_numbr, ROUND_MODE) \
-                               : ((n)->flags & MPZN) ? (uintmax_t) 
mpz_get_d((n)->mpg_i) \
-                               : (uintmax_t) (n)->numbr)
-
-#define iszero(n)              (((n)->flags & MPFN) ? 
mpfr_zero_p((n)->mpg_numbr) \
-                               : ((n)->flags & MPZN) ? (mpz_sgn((n)->mpg_i) == 
0) \
-                               : ((n)->numbr == 0.0))
-
-#define IEEE_FMT(r, t)         (void) (do_ieee_fmt && format_ieee(r, t))
-
-#define mpg_float()            mpg_node(MPFN)
-#define mpg_integer()          mpg_node(MPZN)
-#define is_mpg_float(n)                (((n)->flags & MPFN) != 0)
-#define is_mpg_integer(n)      (((n)->flags & MPZN) != 0)
-#define is_mpg_number(n)       (((n)->flags & (MPZN|MPFN)) != 0)
-#else
-#define get_number_ui(n)       (unsigned long) (n)->numbr
-#define get_number_si(n)       (long) (n)->numbr
-#define get_number_d(n)                (double) (n)->numbr
-#define get_number_uj(n)       (uintmax_t) (n)->numbr
-
-#define is_mpg_number(n)       0
-#define is_mpg_float(n)                0
-#define is_mpg_integer(n)      0
-#define iszero(n)              ((n)->numbr == 0.0)
-#endif
+#define iszero(n)      (sgn_number(n) == 0)
+#define isinteger(n)   numbr_hndlr->gawk_is_integer(n)
 
 #define var_uninitialized(n)   ((n)->var_value == Nnull_string)
 
@@ -1355,6 +1360,7 @@ extern NODE *do_aoption(int nargs);
 extern NODE *do_asort(int nargs);
 extern NODE *do_asorti(int nargs);
 extern unsigned long (*hash)(const char *s, size_t len, unsigned long hsize, 
size_t *code);
+
 /* awkgram.c */
 extern NODE *variable(int location, char *name, NODETYPE type);
 extern int parse_program(INSTRUCTION **pcode);
@@ -1369,21 +1375,15 @@ extern SRCFILE *add_srcfile(int stype, char *src, 
SRCFILE *curr, bool *already_i
 extern void register_deferred_variable(const char *name, NODE 
*(*load_func)(void));
 extern int files_are_same(char *path, SRCFILE *src);
 extern void valinfo(NODE *n, Func_print print_func, FILE *fp);
-extern void negate_num(NODE *n);
+
 /* builtin.c */
-extern double double_to_int(double d);
-extern NODE *do_exp(int nargs);
 extern NODE *do_fflush(int nargs);
 extern NODE *do_index(int nargs);
-extern NODE *do_int(int nargs);
 extern NODE *do_isarray(int nargs);
 extern NODE *do_length(int nargs);
-extern NODE *do_log(int nargs);
 extern NODE *do_mktime(int nargs);
 extern NODE *do_sprintf(int nargs);
 extern void do_printf(int nargs, int redirtype);
-extern void print_simple(NODE *tree, FILE *fp);
-extern NODE *do_sqrt(int nargs);
 extern NODE *do_substr(int nargs);
 extern NODE *do_strftime(int nargs);
 extern NODE *do_systime(int nargs);
@@ -1392,22 +1392,8 @@ extern void do_print(int nargs, int redirtype);
 extern void do_print_rec(int args, int redirtype);
 extern NODE *do_tolower(int nargs);
 extern NODE *do_toupper(int nargs);
-extern NODE *do_atan2(int nargs);
-extern NODE *do_sin(int nargs);
-extern NODE *do_cos(int nargs);
-extern NODE *do_rand(int nargs);
-extern NODE *do_srand(int nargs);
 extern NODE *do_match(int nargs);
 extern NODE *do_sub(int nargs, unsigned int flags);
-extern NODE *format_tree(const char *, size_t, NODE **, long);
-extern NODE *do_lshift(int nargs);
-extern NODE *do_rshift(int nargs);
-extern NODE *do_and(int nargs);
-extern NODE *do_or(int nargs);
-extern NODE *do_xor(int nargs);
-extern NODE *do_compl(int nargs);
-extern NODE *do_strtonum(int nargs);
-extern AWKNUM nondec2awknum(char *str, size_t len);
 extern NODE *do_dcgettext(int nargs);
 extern NODE *do_dcngettext(int nargs);
 extern NODE *do_bindtextdomain(int nargs);
@@ -1415,12 +1401,12 @@ extern NODE *do_bindtextdomain(int nargs);
 extern int strncasecmpmbs(const unsigned char *,
                          const unsigned char *, size_t);
 #endif
+
 /* eval.c */
 extern void PUSH_CODE(INSTRUCTION *cp);
 extern INSTRUCTION *POP_CODE(void);
 extern void init_interpret(void);
 extern int cmp_nodes(NODE *t1, NODE *t2);
-extern int cmp_awknums(const NODE *t1, const NODE *t2);
 extern void set_IGNORECASE(void);
 extern void set_OFS(void);
 extern void set_ORS(void);
@@ -1440,13 +1426,13 @@ extern const char *flags2str(int);
 extern const char *genflags2str(int flagval, const struct flagtab *tab);
 extern const char *nodetype2str(NODETYPE type);
 extern void load_casetable(void);
-extern AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
 extern const char *opcode2str(OPCODE type);
 extern const char *op2str(OPCODE type);
 extern NODE **r_get_lhs(NODE *n, bool reference);
 extern STACK_ITEM *grow_stack(void);
 extern void dump_fcall_stack(FILE *fp);
 extern int register_exec_hook(Func_pre_exec preh, Func_post_exec posth);
+
 /* ext.c */
 extern NODE *do_ext(int nargs);
 void load_ext(const char *lib_name);   /* temporary */
@@ -1460,11 +1446,14 @@ extern NODE *get_actual_argument(int, bool, bool);
 #define get_scalar_argument(i, opt)  get_actual_argument((i), (opt), false)
 #define get_array_argument(i, opt)   get_actual_argument((i), (opt), true)
 #endif
+
 /* field.c */
 extern void init_fields(void);
 extern void set_record(const char *buf, int cnt);
 extern void reset_record(void);
 extern void set_NF(void);
+extern void set_PREC(void);
+extern void set_ROUNDMODE(void);
 extern NODE **get_field(long num, Func_ptr *assign);
 extern NODE *do_split(int nargs);
 extern NODE *do_patsplit(int nargs);
@@ -1512,7 +1501,6 @@ extern void register_output_wrapper(awk_output_wrapper_t 
*wrapper);
 extern void register_two_way_processor(awk_two_way_processor_t *processor);
 extern void set_FNR(void);
 extern void set_NR(void);
-
 extern struct redirect *redirect(NODE *redir_exp, int redirtype, int *errflg);
 extern NODE *do_close(int nargs);
 extern int flush_io(void);
@@ -1525,6 +1513,7 @@ extern NODE *do_getline(int intovar, IOBUF *iop);
 extern struct redirect *getredirect(const char *str, int len);
 extern int inrec(IOBUF *iop, int *errcode);
 extern int nextfile(IOBUF **curfile, bool skipping);
+
 /* main.c */
 extern int arg_assign(char *arg, bool initing);
 extern int is_std_var(const char *var);
@@ -1533,40 +1522,11 @@ extern char *estrdup(const char *str, size_t len);
 extern void update_global_values();
 extern long getenv_long(const char *name);
 
-/* mpfr.c */
-extern void set_PREC(void);
-extern void set_ROUNDMODE(void);
-extern void mpfr_unset(NODE *n);
-#ifdef HAVE_MPFR
-extern int mpg_cmp(const NODE *, const NODE *);
-extern int format_ieee(mpfr_ptr, int);
-extern NODE *mpg_update_var(NODE *);
-extern long mpg_set_var(NODE *);
-extern NODE *do_mpfr_and(int);
-extern NODE *do_mpfr_atan2(int);
-extern NODE *do_mpfr_compl(int);
-extern NODE *do_mpfr_cos(int);
-extern NODE *do_mpfr_exp(int);
-extern NODE *do_mpfr_int(int);
-extern NODE *do_mpfr_log(int);
-extern NODE *do_mpfr_lshift(int);
-extern NODE *do_mpfr_or(int);
-extern NODE *do_mpfr_rand(int);
-extern NODE *do_mpfr_rhift(int);
-extern NODE *do_mpfr_sin(int);
-extern NODE *do_mpfr_sqrt(int);
-extern NODE *do_mpfr_srand(int);
-extern NODE *do_mpfr_strtonum(int);
-extern NODE *do_mpfr_xor(int);
-extern void init_mpfr(mpfr_prec_t, const char *);
-extern NODE *mpg_node(unsigned int);
-extern const char *mpg_fmt(const char *, ...);
-extern int mpg_strtoui(mpz_ptr, char *, size_t, char **, int);
-#endif
 /* msg.c */
 extern void gawk_exit(int status);
 extern void final_exit(int status) ATTRIBUTE_NORETURN;
 extern void err(bool isfatal, const char *s, const char *emsg, va_list argp) 
ATTRIBUTE_PRINTF(3, 0);
+const char *fmt_number(const char *format, const NODE *n);
 extern void msg (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
 extern void error (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
 extern void warning (const char *mesg, ...) ATTRIBUTE_PRINTF_1;
@@ -1577,6 +1537,7 @@ extern void (*lintfunc)(const char *mesg, ...) 
ATTRIBUTE_PRINTF_1;
 #else
 extern void (*lintfunc)(const char *mesg, ...);
 #endif
+
 /* profile.c */
 extern void init_profiling_signals(void);
 extern void set_prof_file(const char *filename);
@@ -1587,6 +1548,7 @@ extern char *pp_node(NODE *n);
 extern int pp_func(INSTRUCTION *pc, void *);
 extern void pp_string_fp(Func_print print_func, FILE *fp, const char *str,
                size_t namelen, int delim, bool breaklines);
+
 /* node.c */
 extern NODE *r_force_number(NODE *n);
 extern NODE *r_format_val(const char *format, int index, NODE *s);
@@ -1594,6 +1556,7 @@ extern NODE *r_dupnode(NODE *n);
 extern NODE *make_str_node(const char *s, size_t len, int flags);
 extern void *more_blocks(int id);
 extern int parse_escape(const char **string_ptr);
+extern int get_numbase(const char *str, bool use_locale);
 #if MBS_SUPPORT
 extern NODE *str2wstr(NODE *n, size_t **ptr);
 extern NODE *wstr2str(NODE *n);
@@ -1611,6 +1574,7 @@ extern void init_btowc_cache();
 #else
 #define free_wstr(NODE)        /* empty */
 #endif
+
 /* re.c */
 extern Regexp *make_regexp(const char *s, size_t len, bool ignorecase, bool 
dfa, bool canfatal);
 extern int research(Regexp *rp, char *str, int start, size_t len, int flags);
@@ -1621,7 +1585,6 @@ extern void resyntax(int syntax);
 extern void resetup(void);
 extern int avoid_dfa(NODE *re, char *str, size_t len);
 extern int reisstring(const char *text, size_t len, Regexp *re, const char 
*buf);
-extern int get_numbase(const char *str, bool use_locale);
 
 /* symbol.c */
 extern void load_symbols();
@@ -1767,7 +1730,7 @@ in_array(NODE *a, NODE *s)
        NODE **ret;
 
        ret = a->aexists(a, s);
-       
+
        return ret ? *ret : NULL;
 }
 
diff --git a/awkgram.c b/awkgram.c
index 9fd1156..22269b5 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -110,7 +110,6 @@ static INSTRUCTION *mk_expression_list(INSTRUCTION *list, 
INSTRUCTION *s1);
 static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, 
INSTRUCTION *cond,
                INSTRUCTION *incr, INSTRUCTION *body);
 static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, 
INSTRUCTION *c_target);
-static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION 
*op);
 static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, 
INSTRUCTION *op);
 static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, 
INSTRUCTION *op);
 static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, 
INSTRUCTION *redir, int redirtype);
@@ -198,7 +197,7 @@ extern double fmod(double x, double y);
 #define is_identchar(c)                (isalnum(c) || (c) == '_')
 
 /* Line 371 of yacc.c  */
-#line 202 "awkgram.c"
+#line 201 "awkgram.c"
 
 # ifndef YY_NULL
 #  if defined __cplusplus && 201103L <= __cplusplus
@@ -367,7 +366,7 @@ int yyparse ();
 /* Copy the second part of user declarations.  */
 
 /* Line 390 of yacc.c  */
-#line 371 "awkgram.c"
+#line 370 "awkgram.c"
 
 #ifdef short
 # undef short
@@ -731,25 +730,25 @@ static const yytype_int16 yyrhs[] =
 /* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
 static const yytype_uint16 yyrline[] =
 {
-       0,   199,   199,   201,   206,   207,   213,   225,   229,   240,
-     246,   251,   259,   267,   269,   274,   282,   284,   290,   291,
-     293,   319,   330,   341,   347,   356,   366,   368,   370,   376,
-     381,   382,   386,   405,   404,   438,   440,   445,   446,   459,
-     464,   465,   469,   471,   473,   480,   570,   612,   654,   767,
-     774,   781,   791,   800,   809,   818,   829,   845,   844,   868,
-     880,   880,   978,   978,  1011,  1041,  1047,  1048,  1054,  1055,
-    1062,  1067,  1079,  1093,  1095,  1103,  1108,  1110,  1118,  1120,
-    1129,  1130,  1138,  1143,  1143,  1154,  1158,  1166,  1167,  1170,
-    1172,  1177,  1178,  1187,  1188,  1193,  1198,  1204,  1206,  1208,
-    1215,  1216,  1222,  1223,  1228,  1230,  1235,  1237,  1239,  1241,
-    1247,  1254,  1256,  1258,  1274,  1284,  1291,  1293,  1298,  1300,
-    1302,  1310,  1312,  1317,  1319,  1324,  1326,  1328,  1378,  1380,
-    1382,  1384,  1386,  1388,  1390,  1392,  1415,  1420,  1425,  1450,
-    1456,  1458,  1460,  1462,  1464,  1466,  1471,  1475,  1507,  1509,
-    1515,  1521,  1534,  1535,  1536,  1541,  1546,  1550,  1554,  1569,
-    1582,  1587,  1623,  1641,  1642,  1648,  1649,  1654,  1656,  1663,
-    1680,  1697,  1699,  1706,  1711,  1719,  1729,  1741,  1750,  1754,
-    1758,  1762,  1766,  1770,  1773,  1775,  1779,  1783,  1787
+       0,   198,   198,   200,   205,   206,   212,   224,   228,   239,
+     245,   250,   258,   266,   268,   273,   281,   283,   289,   290,
+     292,   318,   329,   340,   346,   355,   365,   367,   369,   375,
+     380,   381,   385,   404,   403,   437,   439,   444,   445,   458,
+     463,   464,   468,   470,   472,   479,   569,   611,   653,   766,
+     773,   780,   790,   799,   808,   817,   828,   844,   843,   867,
+     879,   879,   977,   977,  1010,  1040,  1046,  1047,  1053,  1054,
+    1061,  1066,  1078,  1092,  1094,  1102,  1107,  1109,  1117,  1119,
+    1128,  1129,  1137,  1142,  1142,  1153,  1157,  1165,  1166,  1169,
+    1171,  1176,  1177,  1186,  1187,  1192,  1197,  1203,  1205,  1207,
+    1214,  1215,  1221,  1222,  1227,  1229,  1234,  1236,  1238,  1240,
+    1246,  1253,  1255,  1257,  1273,  1283,  1290,  1292,  1297,  1299,
+    1301,  1309,  1311,  1316,  1318,  1323,  1325,  1327,  1377,  1379,
+    1381,  1383,  1385,  1387,  1389,  1391,  1414,  1419,  1424,  1449,
+    1455,  1457,  1459,  1461,  1463,  1465,  1470,  1474,  1506,  1508,
+    1514,  1520,  1533,  1534,  1535,  1540,  1545,  1549,  1553,  1568,
+    1580,  1585,  1621,  1639,  1640,  1646,  1647,  1652,  1654,  1661,
+    1678,  1695,  1697,  1704,  1709,  1717,  1727,  1739,  1748,  1752,
+    1756,  1760,  1764,  1768,  1771,  1773,  1777,  1781,  1785
 };
 #endif
 
@@ -2036,7 +2035,7 @@ yyreduce:
     {
         case 3:
 /* Line 1792 of yacc.c  */
-#line 202 "awkgram.y"
+#line 201 "awkgram.y"
     {
                rule = 0;
                yyerrok;
@@ -2045,7 +2044,7 @@ yyreduce:
 
   case 5:
 /* Line 1792 of yacc.c  */
-#line 208 "awkgram.y"
+#line 207 "awkgram.y"
     {
                next_sourcefile();
                if (sourcefile == srcfiles)
@@ -2055,7 +2054,7 @@ yyreduce:
 
   case 6:
 /* Line 1792 of yacc.c  */
-#line 214 "awkgram.y"
+#line 213 "awkgram.y"
     {
                rule = 0;
                /*
@@ -2068,7 +2067,7 @@ yyreduce:
 
   case 7:
 /* Line 1792 of yacc.c  */
-#line 226 "awkgram.y"
+#line 225 "awkgram.y"
     {
                (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -2076,7 +2075,7 @@ yyreduce:
 
   case 8:
 /* Line 1792 of yacc.c  */
-#line 230 "awkgram.y"
+#line 229 "awkgram.y"
     {
                if (rule != Rule) {
                        msg(_("%s blocks must have an action part"), 
ruletab[rule]);
@@ -2091,7 +2090,7 @@ yyreduce:
 
   case 9:
 /* Line 1792 of yacc.c  */
-#line 241 "awkgram.y"
+#line 240 "awkgram.y"
     {
                in_function = NULL;
                (void) mk_function((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
@@ -2101,7 +2100,7 @@ yyreduce:
 
   case 10:
 /* Line 1792 of yacc.c  */
-#line 247 "awkgram.y"
+#line 246 "awkgram.y"
     {
                want_source = false;
                yyerrok;
@@ -2110,7 +2109,7 @@ yyreduce:
 
   case 11:
 /* Line 1792 of yacc.c  */
-#line 252 "awkgram.y"
+#line 251 "awkgram.y"
     {
                want_source = false;
                yyerrok;
@@ -2119,7 +2118,7 @@ yyreduce:
 
   case 12:
 /* Line 1792 of yacc.c  */
-#line 260 "awkgram.y"
+#line 259 "awkgram.y"
     {
                if (include_source((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2131,19 +2130,19 @@ yyreduce:
 
   case 13:
 /* Line 1792 of yacc.c  */
-#line 268 "awkgram.y"
+#line 267 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 14:
 /* Line 1792 of yacc.c  */
-#line 270 "awkgram.y"
+#line 269 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 15:
 /* Line 1792 of yacc.c  */
-#line 275 "awkgram.y"
+#line 274 "awkgram.y"
     {
                if (load_library((yyvsp[(1) - (1)])) < 0)
                        YYABORT;
@@ -2155,31 +2154,31 @@ yyreduce:
 
   case 16:
 /* Line 1792 of yacc.c  */
-#line 283 "awkgram.y"
+#line 282 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 17:
 /* Line 1792 of yacc.c  */
-#line 285 "awkgram.y"
+#line 284 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 18:
 /* Line 1792 of yacc.c  */
-#line 290 "awkgram.y"
+#line 289 "awkgram.y"
     {  (yyval) = NULL; rule = Rule; }
     break;
 
   case 19:
 /* Line 1792 of yacc.c  */
-#line 292 "awkgram.y"
+#line 291 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); rule = Rule; }
     break;
 
   case 20:
 /* Line 1792 of yacc.c  */
-#line 294 "awkgram.y"
+#line 293 "awkgram.y"
     {
                INSTRUCTION *tp;
 
@@ -2209,7 +2208,7 @@ yyreduce:
 
   case 21:
 /* Line 1792 of yacc.c  */
-#line 320 "awkgram.y"
+#line 319 "awkgram.y"
     {
                static int begin_seen = 0;
                if (do_lint_old && ++begin_seen == 2)
@@ -2224,7 +2223,7 @@ yyreduce:
 
   case 22:
 /* Line 1792 of yacc.c  */
-#line 331 "awkgram.y"
+#line 330 "awkgram.y"
     {
                static int end_seen = 0;
                if (do_lint_old && ++end_seen == 2)
@@ -2239,7 +2238,7 @@ yyreduce:
 
   case 23:
 /* Line 1792 of yacc.c  */
-#line 342 "awkgram.y"
+#line 341 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2249,7 +2248,7 @@ yyreduce:
 
   case 24:
 /* Line 1792 of yacc.c  */
-#line 348 "awkgram.y"
+#line 347 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE;
                (yyvsp[(1) - (1)])->source_file = source;
@@ -2259,7 +2258,7 @@ yyreduce:
 
   case 25:
 /* Line 1792 of yacc.c  */
-#line 357 "awkgram.y"
+#line 356 "awkgram.y"
     {
                if ((yyvsp[(2) - (5)]) == NULL)
                        (yyval) = list_create(instruction(Op_no_op));
@@ -2270,19 +2269,19 @@ yyreduce:
 
   case 26:
 /* Line 1792 of yacc.c  */
-#line 367 "awkgram.y"
+#line 366 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 27:
 /* Line 1792 of yacc.c  */
-#line 369 "awkgram.y"
+#line 368 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 28:
 /* Line 1792 of yacc.c  */
-#line 371 "awkgram.y"
+#line 370 "awkgram.y"
     {
                yyerror(_("`%s' is a built-in function, it cannot be 
redefined"),
                                        tokstart);
@@ -2292,13 +2291,13 @@ yyreduce:
 
   case 29:
 /* Line 1792 of yacc.c  */
-#line 377 "awkgram.y"
+#line 376 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (2)]); }
     break;
 
   case 32:
 /* Line 1792 of yacc.c  */
-#line 387 "awkgram.y"
+#line 386 "awkgram.y"
     {
                (yyvsp[(1) - (6)])->source_file = source;
                if (install_function((yyvsp[(2) - (6)])->lextok, (yyvsp[(1) - 
(6)]), (yyvsp[(4) - (6)])) < 0)
@@ -2313,13 +2312,13 @@ yyreduce:
 
   case 33:
 /* Line 1792 of yacc.c  */
-#line 405 "awkgram.y"
+#line 404 "awkgram.y"
     { want_regexp = true; }
     break;
 
   case 34:
 /* Line 1792 of yacc.c  */
-#line 407 "awkgram.y"
+#line 406 "awkgram.y"
     {
                  NODE *n, *exp;
                  char *re;
@@ -2352,19 +2351,19 @@ yyreduce:
 
   case 35:
 /* Line 1792 of yacc.c  */
-#line 439 "awkgram.y"
+#line 438 "awkgram.y"
     { bcfree((yyvsp[(1) - (1)])); }
     break;
 
   case 37:
 /* Line 1792 of yacc.c  */
-#line 445 "awkgram.y"
+#line 444 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
   case 38:
 /* Line 1792 of yacc.c  */
-#line 447 "awkgram.y"
+#line 446 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)]) == NULL)
                        (yyval) = (yyvsp[(1) - (2)]);
@@ -2381,25 +2380,25 @@ yyreduce:
 
   case 39:
 /* Line 1792 of yacc.c  */
-#line 460 "awkgram.y"
+#line 459 "awkgram.y"
     {  (yyval) = NULL; }
     break;
 
   case 42:
 /* Line 1792 of yacc.c  */
-#line 470 "awkgram.y"
+#line 469 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 43:
 /* Line 1792 of yacc.c  */
-#line 472 "awkgram.y"
+#line 471 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 44:
 /* Line 1792 of yacc.c  */
-#line 474 "awkgram.y"
+#line 473 "awkgram.y"
     {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2410,7 +2409,7 @@ yyreduce:
 
   case 45:
 /* Line 1792 of yacc.c  */
-#line 481 "awkgram.y"
+#line 480 "awkgram.y"
     {
                INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt;
                INSTRUCTION *ip, *nextc, *tbreak;
@@ -2504,7 +2503,7 @@ yyreduce:
 
   case 46:
 /* Line 1792 of yacc.c  */
-#line 571 "awkgram.y"
+#line 570 "awkgram.y"
     { 
                /*
                 *    -----------------
@@ -2550,7 +2549,7 @@ yyreduce:
 
   case 47:
 /* Line 1792 of yacc.c  */
-#line 613 "awkgram.y"
+#line 612 "awkgram.y"
     {
                /*
                 *    -----------------
@@ -2596,7 +2595,7 @@ yyreduce:
 
   case 48:
 /* Line 1792 of yacc.c  */
-#line 655 "awkgram.y"
+#line 654 "awkgram.y"
     {
                INSTRUCTION *ip;
                char *var_name = (yyvsp[(3) - (8)])->lextok;
@@ -2713,7 +2712,7 @@ regular_loop:
 
   case 49:
 /* Line 1792 of yacc.c  */
-#line 768 "awkgram.y"
+#line 767 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), 
(yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)]));
 
@@ -2724,7 +2723,7 @@ regular_loop:
 
   case 50:
 /* Line 1792 of yacc.c  */
-#line 775 "awkgram.y"
+#line 774 "awkgram.y"
     {
                (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), 
(INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)]));
 
@@ -2735,7 +2734,7 @@ regular_loop:
 
   case 51:
 /* Line 1792 of yacc.c  */
-#line 782 "awkgram.y"
+#line 781 "awkgram.y"
     {
                if (do_pretty_print)
                        (yyval) = list_prepend((yyvsp[(1) - (1)]), 
instruction(Op_exec_count));
@@ -2746,7 +2745,7 @@ regular_loop:
 
   case 52:
 /* Line 1792 of yacc.c  */
-#line 792 "awkgram.y"
+#line 791 "awkgram.y"
     { 
                if (! break_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2759,7 +2758,7 @@ regular_loop:
 
   case 53:
 /* Line 1792 of yacc.c  */
-#line 801 "awkgram.y"
+#line 800 "awkgram.y"
     {
                if (! continue_allowed)
                        error_ln((yyvsp[(1) - (2)])->source_line,
@@ -2772,7 +2771,7 @@ regular_loop:
 
   case 54:
 /* Line 1792 of yacc.c  */
-#line 810 "awkgram.y"
+#line 809 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule && rule != Rule)
@@ -2785,7 +2784,7 @@ regular_loop:
 
   case 55:
 /* Line 1792 of yacc.c  */
-#line 819 "awkgram.y"
+#line 818 "awkgram.y"
     {
                /* if inside function (rule = 0), resolve context at run-time */
                if (rule == BEGIN || rule == END || rule == ENDFILE)
@@ -2800,7 +2799,7 @@ regular_loop:
 
   case 56:
 /* Line 1792 of yacc.c  */
-#line 830 "awkgram.y"
+#line 829 "awkgram.y"
     {
                /* Initialize the two possible jump targets, the actual target
                 * is resolved at run-time. 
@@ -2819,7 +2818,7 @@ regular_loop:
 
   case 57:
 /* Line 1792 of yacc.c  */
-#line 845 "awkgram.y"
+#line 844 "awkgram.y"
     {
                if (! in_function)
                        yyerror(_("`return' used outside function context"));
@@ -2828,7 +2827,7 @@ regular_loop:
 
   case 58:
 /* Line 1792 of yacc.c  */
-#line 848 "awkgram.y"
+#line 847 "awkgram.y"
     {
                if ((yyvsp[(3) - (4)]) == NULL) {
                        (yyval) = list_create((yyvsp[(1) - (4)]));
@@ -2853,13 +2852,13 @@ regular_loop:
 
   case 60:
 /* Line 1792 of yacc.c  */
-#line 880 "awkgram.y"
+#line 879 "awkgram.y"
     { in_print = true; in_parens = 0; }
     break;
 
   case 61:
 /* Line 1792 of yacc.c  */
-#line 881 "awkgram.y"
+#line 880 "awkgram.y"
     {
                /*
                 * Optimization: plain `print' has no expression list, so $3 is 
null.
@@ -2960,13 +2959,13 @@ regular_print:
 
   case 62:
 /* Line 1792 of yacc.c  */
-#line 978 "awkgram.y"
+#line 977 "awkgram.y"
     { sub_counter = 0; }
     break;
 
   case 63:
 /* Line 1792 of yacc.c  */
-#line 979 "awkgram.y"
+#line 978 "awkgram.y"
     {
                char *arr = (yyvsp[(2) - (4)])->lextok;
 
@@ -3003,7 +3002,7 @@ regular_print:
 
   case 64:
 /* Line 1792 of yacc.c  */
-#line 1016 "awkgram.y"
+#line 1015 "awkgram.y"
     {
                static bool warned = false;
                char *arr = (yyvsp[(3) - (4)])->lextok;
@@ -3033,31 +3032,31 @@ regular_print:
 
   case 65:
 /* Line 1792 of yacc.c  */
-#line 1042 "awkgram.y"
+#line 1041 "awkgram.y"
     {  (yyval) = optimize_assignment((yyvsp[(1) - (1)])); }
     break;
 
   case 66:
 /* Line 1792 of yacc.c  */
-#line 1047 "awkgram.y"
+#line 1046 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 67:
 /* Line 1792 of yacc.c  */
-#line 1049 "awkgram.y"
+#line 1048 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 68:
 /* Line 1792 of yacc.c  */
-#line 1054 "awkgram.y"
+#line 1053 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 69:
 /* Line 1792 of yacc.c  */
-#line 1056 "awkgram.y"
+#line 1055 "awkgram.y"
     {
                if ((yyvsp[(1) - (2)]) == NULL)
                        (yyval) = list_create((yyvsp[(2) - (2)]));
@@ -3068,13 +3067,13 @@ regular_print:
 
   case 70:
 /* Line 1792 of yacc.c  */
-#line 1063 "awkgram.y"
+#line 1062 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 71:
 /* Line 1792 of yacc.c  */
-#line 1068 "awkgram.y"
+#line 1067 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(5) - (5)]);
                if ((yyvsp[(5) - (5)]) == NULL)
@@ -3090,7 +3089,7 @@ regular_print:
 
   case 72:
 /* Line 1792 of yacc.c  */
-#line 1080 "awkgram.y"
+#line 1079 "awkgram.y"
     {
                INSTRUCTION *casestmt = (yyvsp[(4) - (4)]);
                if ((yyvsp[(4) - (4)]) == NULL)
@@ -3105,17 +3104,17 @@ regular_print:
 
   case 73:
 /* Line 1792 of yacc.c  */
-#line 1094 "awkgram.y"
+#line 1093 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 74:
 /* Line 1792 of yacc.c  */
-#line 1096 "awkgram.y"
+#line 1095 "awkgram.y"
     { 
                NODE *n = (yyvsp[(2) - (2)])->memory;
                (void) force_number(n);
-               negate_num(n);
+               numbr_hndlr->gawk_negate_number(n);
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
          }
@@ -3123,7 +3122,7 @@ regular_print:
 
   case 75:
 /* Line 1792 of yacc.c  */
-#line 1104 "awkgram.y"
+#line 1103 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3132,13 +3131,13 @@ regular_print:
 
   case 76:
 /* Line 1792 of yacc.c  */
-#line 1109 "awkgram.y"
+#line 1108 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 77:
 /* Line 1792 of yacc.c  */
-#line 1111 "awkgram.y"
+#line 1110 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_push_re;
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3147,19 +3146,19 @@ regular_print:
 
   case 78:
 /* Line 1792 of yacc.c  */
-#line 1119 "awkgram.y"
+#line 1118 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 79:
 /* Line 1792 of yacc.c  */
-#line 1121 "awkgram.y"
+#line 1120 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 81:
 /* Line 1792 of yacc.c  */
-#line 1131 "awkgram.y"
+#line 1130 "awkgram.y"
     {
                (yyval) = (yyvsp[(2) - (3)]);
          }
@@ -3167,7 +3166,7 @@ regular_print:
 
   case 82:
 /* Line 1792 of yacc.c  */
-#line 1138 "awkgram.y"
+#line 1137 "awkgram.y"
     {
                in_print = false;
                in_parens = 0;
@@ -3177,13 +3176,13 @@ regular_print:
 
   case 83:
 /* Line 1792 of yacc.c  */
-#line 1143 "awkgram.y"
+#line 1142 "awkgram.y"
     { in_print = false; in_parens = 0; }
     break;
 
   case 84:
 /* Line 1792 of yacc.c  */
-#line 1144 "awkgram.y"
+#line 1143 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway
                        && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_K_getline_redir
@@ -3195,7 +3194,7 @@ regular_print:
 
   case 85:
 /* Line 1792 of yacc.c  */
-#line 1155 "awkgram.y"
+#line 1154 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), 
(yyvsp[(6) - (6)]), NULL, NULL);
          }
@@ -3203,7 +3202,7 @@ regular_print:
 
   case 86:
 /* Line 1792 of yacc.c  */
-#line 1160 "awkgram.y"
+#line 1159 "awkgram.y"
     {
                (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), 
(yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)]));
          }
@@ -3211,13 +3210,13 @@ regular_print:
 
   case 91:
 /* Line 1792 of yacc.c  */
-#line 1177 "awkgram.y"
+#line 1176 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 92:
 /* Line 1792 of yacc.c  */
-#line 1179 "awkgram.y"
+#line 1178 "awkgram.y"
     {
                bcfree((yyvsp[(1) - (2)]));
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3226,19 +3225,19 @@ regular_print:
 
   case 93:
 /* Line 1792 of yacc.c  */
-#line 1187 "awkgram.y"
+#line 1186 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 94:
 /* Line 1792 of yacc.c  */
-#line 1189 "awkgram.y"
+#line 1188 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]) ; }
     break;
 
   case 95:
 /* Line 1792 of yacc.c  */
-#line 1194 "awkgram.y"
+#line 1193 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->param_count = 0;
                (yyval) = list_create((yyvsp[(1) - (1)]));
@@ -3247,7 +3246,7 @@ regular_print:
 
   case 96:
 /* Line 1792 of yacc.c  */
-#line 1199 "awkgram.y"
+#line 1198 "awkgram.y"
     {
                (yyvsp[(3) - (3)])->param_count =  (yyvsp[(1) - 
(3)])->lasti->param_count + 1;
                (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]));
@@ -3257,55 +3256,55 @@ regular_print:
 
   case 97:
 /* Line 1792 of yacc.c  */
-#line 1205 "awkgram.y"
+#line 1204 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 98:
 /* Line 1792 of yacc.c  */
-#line 1207 "awkgram.y"
+#line 1206 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 99:
 /* Line 1792 of yacc.c  */
-#line 1209 "awkgram.y"
+#line 1208 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (3)]); }
     break;
 
   case 100:
 /* Line 1792 of yacc.c  */
-#line 1215 "awkgram.y"
+#line 1214 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 101:
 /* Line 1792 of yacc.c  */
-#line 1217 "awkgram.y"
+#line 1216 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 102:
 /* Line 1792 of yacc.c  */
-#line 1222 "awkgram.y"
+#line 1221 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 103:
 /* Line 1792 of yacc.c  */
-#line 1224 "awkgram.y"
+#line 1223 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 104:
 /* Line 1792 of yacc.c  */
-#line 1229 "awkgram.y"
+#line 1228 "awkgram.y"
     {  (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); }
     break;
 
   case 105:
 /* Line 1792 of yacc.c  */
-#line 1231 "awkgram.y"
+#line 1230 "awkgram.y"
     {
                (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)]));
                yyerrok;
@@ -3314,31 +3313,31 @@ regular_print:
 
   case 106:
 /* Line 1792 of yacc.c  */
-#line 1236 "awkgram.y"
+#line 1235 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 107:
 /* Line 1792 of yacc.c  */
-#line 1238 "awkgram.y"
+#line 1237 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 108:
 /* Line 1792 of yacc.c  */
-#line 1240 "awkgram.y"
+#line 1239 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 109:
 /* Line 1792 of yacc.c  */
-#line 1242 "awkgram.y"
+#line 1241 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 110:
 /* Line 1792 of yacc.c  */
-#line 1248 "awkgram.y"
+#line 1247 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3349,19 +3348,19 @@ regular_print:
 
   case 111:
 /* Line 1792 of yacc.c  */
-#line 1255 "awkgram.y"
+#line 1254 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 112:
 /* Line 1792 of yacc.c  */
-#line 1257 "awkgram.y"
+#line 1256 "awkgram.y"
     {  (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) 
- (3)])); }
     break;
 
   case 113:
 /* Line 1792 of yacc.c  */
-#line 1259 "awkgram.y"
+#line 1258 "awkgram.y"
     {
                if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3381,7 +3380,7 @@ regular_print:
 
   case 114:
 /* Line 1792 of yacc.c  */
-#line 1275 "awkgram.y"
+#line 1274 "awkgram.y"
     {
                if (do_lint_old)
                        warning_ln((yyvsp[(2) - (3)])->source_line,
@@ -3395,7 +3394,7 @@ regular_print:
 
   case 115:
 /* Line 1792 of yacc.c  */
-#line 1285 "awkgram.y"
+#line 1284 "awkgram.y"
     {
                if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == 
Op_match_rec)
                        lintwarn_ln((yyvsp[(2) - (3)])->source_line,
@@ -3406,31 +3405,31 @@ regular_print:
 
   case 116:
 /* Line 1792 of yacc.c  */
-#line 1292 "awkgram.y"
+#line 1291 "awkgram.y"
     { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), 
(yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); }
     break;
 
   case 117:
 /* Line 1792 of yacc.c  */
-#line 1294 "awkgram.y"
+#line 1293 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 118:
 /* Line 1792 of yacc.c  */
-#line 1299 "awkgram.y"
+#line 1298 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 119:
 /* Line 1792 of yacc.c  */
-#line 1301 "awkgram.y"
+#line 1300 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 120:
 /* Line 1792 of yacc.c  */
-#line 1303 "awkgram.y"
+#line 1302 "awkgram.y"
     {  
                (yyvsp[(2) - (2)])->opcode = Op_assign_quotient;
                (yyval) = (yyvsp[(2) - (2)]);
@@ -3439,43 +3438,43 @@ regular_print:
 
   case 121:
 /* Line 1792 of yacc.c  */
-#line 1311 "awkgram.y"
+#line 1310 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 122:
 /* Line 1792 of yacc.c  */
-#line 1313 "awkgram.y"
+#line 1312 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 123:
 /* Line 1792 of yacc.c  */
-#line 1318 "awkgram.y"
+#line 1317 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 124:
 /* Line 1792 of yacc.c  */
-#line 1320 "awkgram.y"
+#line 1319 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 125:
 /* Line 1792 of yacc.c  */
-#line 1325 "awkgram.y"
+#line 1324 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 126:
 /* Line 1792 of yacc.c  */
-#line 1327 "awkgram.y"
+#line 1326 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 127:
 /* Line 1792 of yacc.c  */
-#line 1329 "awkgram.y"
+#line 1328 "awkgram.y"
     {
                int count = 2;
                bool is_simple_var = false;
@@ -3526,43 +3525,43 @@ regular_print:
 
   case 129:
 /* Line 1792 of yacc.c  */
-#line 1381 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1380 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 130:
 /* Line 1792 of yacc.c  */
-#line 1383 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1382 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 131:
 /* Line 1792 of yacc.c  */
-#line 1385 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1384 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 132:
 /* Line 1792 of yacc.c  */
-#line 1387 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1386 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 133:
 /* Line 1792 of yacc.c  */
-#line 1389 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1388 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 134:
 /* Line 1792 of yacc.c  */
-#line 1391 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1390 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 135:
 /* Line 1792 of yacc.c  */
-#line 1393 "awkgram.y"
+#line 1392 "awkgram.y"
     {
                /*
                 * In BEGINFILE/ENDFILE, allow `getline var < file'
@@ -3589,7 +3588,7 @@ regular_print:
 
   case 136:
 /* Line 1792 of yacc.c  */
-#line 1416 "awkgram.y"
+#line 1415 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postincrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3598,7 +3597,7 @@ regular_print:
 
   case 137:
 /* Line 1792 of yacc.c  */
-#line 1421 "awkgram.y"
+#line 1420 "awkgram.y"
     {
                (yyvsp[(2) - (2)])->opcode = Op_postdecrement;
                (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - 
(2)]));
@@ -3607,7 +3606,7 @@ regular_print:
 
   case 138:
 /* Line 1792 of yacc.c  */
-#line 1426 "awkgram.y"
+#line 1425 "awkgram.y"
     {
                if (do_lint_old) {
                    warning_ln((yyvsp[(4) - (5)])->source_line,
@@ -3631,7 +3630,7 @@ regular_print:
 
   case 139:
 /* Line 1792 of yacc.c  */
-#line 1451 "awkgram.y"
+#line 1450 "awkgram.y"
     {
                  (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), 
(yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type);
                  bcfree((yyvsp[(2) - (4)]));
@@ -3640,43 +3639,43 @@ regular_print:
 
   case 140:
 /* Line 1792 of yacc.c  */
-#line 1457 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1456 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 141:
 /* Line 1792 of yacc.c  */
-#line 1459 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1458 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 142:
 /* Line 1792 of yacc.c  */
-#line 1461 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1460 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 143:
 /* Line 1792 of yacc.c  */
-#line 1463 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1462 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 144:
 /* Line 1792 of yacc.c  */
-#line 1465 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1464 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 145:
 /* Line 1792 of yacc.c  */
-#line 1467 "awkgram.y"
-    { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - 
(3)])); }
+#line 1466 "awkgram.y"
+    {  (yyval) = list_append(list_merge((yyvsp[(1) - (3)]), (yyvsp[(3) - 
(3)])), (yyvsp[(2) - (3)])); }
     break;
 
   case 146:
 /* Line 1792 of yacc.c  */
-#line 1472 "awkgram.y"
+#line 1471 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3684,7 +3683,7 @@ regular_print:
 
   case 147:
 /* Line 1792 of yacc.c  */
-#line 1476 "awkgram.y"
+#line 1475 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) {
                        (yyvsp[(2) - (2)])->opcode = Op_nomatch;
@@ -3720,13 +3719,13 @@ regular_print:
 
   case 148:
 /* Line 1792 of yacc.c  */
-#line 1508 "awkgram.y"
+#line 1507 "awkgram.y"
     { (yyval) = (yyvsp[(2) - (3)]); }
     break;
 
   case 149:
 /* Line 1792 of yacc.c  */
-#line 1510 "awkgram.y"
+#line 1509 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3736,7 +3735,7 @@ regular_print:
 
   case 150:
 /* Line 1792 of yacc.c  */
-#line 1516 "awkgram.y"
+#line 1515 "awkgram.y"
     {
                (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
                if ((yyval) == NULL)
@@ -3746,7 +3745,7 @@ regular_print:
 
   case 151:
 /* Line 1792 of yacc.c  */
-#line 1522 "awkgram.y"
+#line 1521 "awkgram.y"
     {
                static bool warned = false;
 
@@ -3763,7 +3762,7 @@ regular_print:
 
   case 154:
 /* Line 1792 of yacc.c  */
-#line 1537 "awkgram.y"
+#line 1536 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_preincrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3772,7 +3771,7 @@ regular_print:
 
   case 155:
 /* Line 1792 of yacc.c  */
-#line 1542 "awkgram.y"
+#line 1541 "awkgram.y"
     {
                (yyvsp[(1) - (2)])->opcode = Op_predecrement;
                (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - 
(2)]));
@@ -3781,7 +3780,7 @@ regular_print:
 
   case 156:
 /* Line 1792 of yacc.c  */
-#line 1547 "awkgram.y"
+#line 1546 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3789,7 +3788,7 @@ regular_print:
 
   case 157:
 /* Line 1792 of yacc.c  */
-#line 1551 "awkgram.y"
+#line 1550 "awkgram.y"
     {
                (yyval) = list_create((yyvsp[(1) - (1)]));
          }
@@ -3797,14 +3796,14 @@ regular_print:
 
   case 158:
 /* Line 1792 of yacc.c  */
-#line 1555 "awkgram.y"
+#line 1554 "awkgram.y"
     {
                if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
                        && ((yyvsp[(2) - (2)])->lasti->memory->flags & 
(STRCUR|STRING)) == 0
                ) {
                        NODE *n = (yyvsp[(2) - (2)])->lasti->memory;
                        (void) force_number(n);
-                       negate_num(n);                  
+                       numbr_hndlr->gawk_negate_number(n);
                        (yyval) = (yyvsp[(2) - (2)]);
                        bcfree((yyvsp[(1) - (2)]));
                } else {
@@ -3816,21 +3815,20 @@ regular_print:
 
   case 159:
 /* Line 1792 of yacc.c  */
-#line 1570 "awkgram.y"
+#line 1569 "awkgram.y"
     {
            /*
             * was: $$ = $2
             * POSIX semantics: force a conversion to numeric type
             */
-               (yyvsp[(1) - (2)])->opcode = Op_plus_i;
-               (yyvsp[(1) - (2)])->memory = make_number(0.0);
+               (yyvsp[(1) - (2)])->opcode = Op_unary_plus;
                (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) - (2)]));
          }
     break;
 
   case 160:
 /* Line 1792 of yacc.c  */
-#line 1583 "awkgram.y"
+#line 1581 "awkgram.y"
     {
                func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
                (yyval) = (yyvsp[(1) - (1)]);
@@ -3839,7 +3837,7 @@ regular_print:
 
   case 161:
 /* Line 1792 of yacc.c  */
-#line 1588 "awkgram.y"
+#line 1586 "awkgram.y"
     {
                /* indirect function call */
                INSTRUCTION *f, *t;
@@ -3876,7 +3874,7 @@ regular_print:
 
   case 162:
 /* Line 1792 of yacc.c  */
-#line 1624 "awkgram.y"
+#line 1622 "awkgram.y"
     {
                param_sanity((yyvsp[(3) - (4)]));
                (yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3894,37 +3892,37 @@ regular_print:
 
   case 163:
 /* Line 1792 of yacc.c  */
-#line 1641 "awkgram.y"
+#line 1639 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 164:
 /* Line 1792 of yacc.c  */
-#line 1643 "awkgram.y"
+#line 1641 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 165:
 /* Line 1792 of yacc.c  */
-#line 1648 "awkgram.y"
+#line 1646 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 166:
 /* Line 1792 of yacc.c  */
-#line 1650 "awkgram.y"
+#line 1648 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 167:
 /* Line 1792 of yacc.c  */
-#line 1655 "awkgram.y"
+#line 1653 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 168:
 /* Line 1792 of yacc.c  */
-#line 1657 "awkgram.y"
+#line 1655 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3932,7 +3930,7 @@ regular_print:
 
   case 169:
 /* Line 1792 of yacc.c  */
-#line 1664 "awkgram.y"
+#line 1662 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; 
                int count = ip->sub_count;      /* # of SUBSEP-seperated 
expressions */
@@ -3950,7 +3948,7 @@ regular_print:
 
   case 170:
 /* Line 1792 of yacc.c  */
-#line 1681 "awkgram.y"
+#line 1679 "awkgram.y"
     {
                INSTRUCTION *t = (yyvsp[(2) - (3)]);
                if ((yyvsp[(2) - (3)]) == NULL) {
@@ -3968,13 +3966,13 @@ regular_print:
 
   case 171:
 /* Line 1792 of yacc.c  */
-#line 1698 "awkgram.y"
+#line 1696 "awkgram.y"
     {  (yyval) = (yyvsp[(1) - (1)]); }
     break;
 
   case 172:
 /* Line 1792 of yacc.c  */
-#line 1700 "awkgram.y"
+#line 1698 "awkgram.y"
     {
                (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
          }
@@ -3982,13 +3980,13 @@ regular_print:
 
   case 173:
 /* Line 1792 of yacc.c  */
-#line 1707 "awkgram.y"
+#line 1705 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (2)]); }
     break;
 
   case 174:
 /* Line 1792 of yacc.c  */
-#line 1712 "awkgram.y"
+#line 1710 "awkgram.y"
     {
                char *var_name = (yyvsp[(1) - (1)])->lextok;
 
@@ -4000,7 +3998,7 @@ regular_print:
 
   case 175:
 /* Line 1792 of yacc.c  */
-#line 1720 "awkgram.y"
+#line 1718 "awkgram.y"
     {
                char *arr = (yyvsp[(1) - (2)])->lextok;
                (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - 
(2)])->source_line, arr, Node_var_new);
@@ -4011,7 +4009,7 @@ regular_print:
 
   case 176:
 /* Line 1792 of yacc.c  */
-#line 1730 "awkgram.y"
+#line 1728 "awkgram.y"
     {
                INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
                if (ip->opcode == Op_push
@@ -4027,7 +4025,7 @@ regular_print:
 
   case 177:
 /* Line 1792 of yacc.c  */
-#line 1742 "awkgram.y"
+#line 1740 "awkgram.y"
     {
                (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
                if ((yyvsp[(3) - (3)]) != NULL)
@@ -4037,7 +4035,7 @@ regular_print:
 
   case 178:
 /* Line 1792 of yacc.c  */
-#line 1751 "awkgram.y"
+#line 1749 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postincrement;
          }
@@ -4045,7 +4043,7 @@ regular_print:
 
   case 179:
 /* Line 1792 of yacc.c  */
-#line 1755 "awkgram.y"
+#line 1753 "awkgram.y"
     {
                (yyvsp[(1) - (1)])->opcode = Op_postdecrement;
          }
@@ -4053,43 +4051,43 @@ regular_print:
 
   case 180:
 /* Line 1792 of yacc.c  */
-#line 1758 "awkgram.y"
+#line 1756 "awkgram.y"
     { (yyval) = NULL; }
     break;
 
   case 182:
 /* Line 1792 of yacc.c  */
-#line 1766 "awkgram.y"
+#line 1764 "awkgram.y"
     { yyerrok; }
     break;
 
   case 183:
 /* Line 1792 of yacc.c  */
-#line 1770 "awkgram.y"
+#line 1768 "awkgram.y"
     { yyerrok; }
     break;
 
   case 186:
 /* Line 1792 of yacc.c  */
-#line 1779 "awkgram.y"
+#line 1777 "awkgram.y"
     { yyerrok; }
     break;
 
   case 187:
 /* Line 1792 of yacc.c  */
-#line 1783 "awkgram.y"
+#line 1781 "awkgram.y"
     { (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
     break;
 
   case 188:
 /* Line 1792 of yacc.c  */
-#line 1787 "awkgram.y"
+#line 1785 "awkgram.y"
     { yyerrok; }
     break;
 
 
 /* Line 1792 of yacc.c  */
-#line 4105 "awkgram.c"
+#line 4103 "awkgram.c"
       default: break;
     }
   /* User semantic actions sometimes alter yychar, and that requires
@@ -4321,7 +4319,7 @@ yyreturn:
 
 
 /* Line 2055 of yacc.c  */
-#line 1789 "awkgram.y"
+#line 1787 "awkgram.y"
 
 
 struct token {
@@ -4339,7 +4337,6 @@ struct token {
 #      define  CONTINUE        0x1000  /* continue allowed inside */
        
        NODE *(*ptr)(int);      /* function that implements this keyword */
-       NODE *(*ptr2)(int);     /* alternate arbitrary-precision function */
 };
 
 #if 'a' == 0x81 /* it's EBCDIC */
@@ -4363,90 +4360,85 @@ tokcompare(const void *l, const void *r)
  * Function pointers come from declarations in awk.h.
  */
 
-#ifdef HAVE_MPFR
-#define MPF(F) do_mpfr_##F
-#else
-#define MPF(F) 0
-#endif
 
-static const struct token tokentab[] = {
-{"BEGIN",      Op_rule,         LEX_BEGIN,     0,              0,      0},
-{"BEGINFILE",  Op_rule,         LEX_BEGINFILE, GAWKX,          0,      0},
-{"END",                Op_rule,         LEX_END,       0,              0,      
0},
-{"ENDFILE",            Op_rule,         LEX_ENDFILE,   GAWKX,          0,      
0},
+static struct token tokentab[] = {
+{"BEGIN",      Op_rule,         LEX_BEGIN,     0,              0 },
+{"BEGINFILE",  Op_rule,         LEX_BEGINFILE, GAWKX,          0 },
+{"END",                Op_rule,         LEX_END,       0,              0 },
+{"ENDFILE",            Op_rule,         LEX_ENDFILE,   GAWKX,          0 },
 #ifdef ARRAYDEBUG
-{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1)|A(2),        
do_adump,       0},
+{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1)|A(2),        
do_adump },
 #endif
-{"and",                Op_builtin,    LEX_BUILTIN,     GAWKX,          do_and, 
MPF(and)},
-{"asort",      Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asort,       0},
-{"asorti",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asorti,      0},
-{"atan2",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2),   do_atan2,       
MPF(atan2)},
-{"bindtextdomain",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2),        
do_bindtextdomain,      0},
-{"break",      Op_K_break,      LEX_BREAK,     0,              0,      0},
-{"case",       Op_K_case,       LEX_CASE,      GAWKX,          0,      0},
-{"close",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1)|A(2),      
do_close,       0},
-{"compl",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_compl,       
MPF(compl)},
-{"continue",   Op_K_continue, LEX_CONTINUE,    0,              0,      0},
-{"cos",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_cos, 
MPF(cos)},
-{"dcgettext",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_dcgettext,   0},
-{"dcngettext", Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), 
do_dcngettext,  0},
-{"default",    Op_K_default,    LEX_DEFAULT,   GAWKX,          0,      0},
-{"delete",     Op_K_delete,     LEX_DELETE,    NOT_OLD,        0,      0},
-{"do",         Op_K_do,         LEX_DO,        NOT_OLD|BREAK|CONTINUE, 0,      
0},
-{"else",       Op_K_else,       LEX_ELSE,      0,              0,      0},
-{"eval",       Op_symbol,       LEX_EVAL,      0,              0,      0},
-{"exit",       Op_K_exit,       LEX_EXIT,      0,              0,      0},
-{"exp",                Op_builtin,      LEX_BUILTIN,   A(1),           do_exp, 
MPF(exp)},
+{"and",                Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
+{"asort",      Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asort },
+{"asorti",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asorti },
+{"atan2",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2),   0 },
+{"bindtextdomain",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2),        
do_bindtextdomain },
+{"break",      Op_K_break,      LEX_BREAK,     0,              0 },
+{"case",       Op_K_case,       LEX_CASE,      GAWKX,          0 },
+{"close",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1)|A(2),      
do_close },
+{"compl",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     0 },
+{"continue",   Op_K_continue, LEX_CONTINUE,    0,              0 },
+{"cos",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   0 },
+{"dcgettext",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_dcgettext },
+{"dcngettext", Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), 
do_dcngettext },
+{"default",    Op_K_default,    LEX_DEFAULT,   GAWKX,          0 },
+{"delete",     Op_K_delete,     LEX_DELETE,    NOT_OLD,        0 },
+{"do",         Op_K_do,         LEX_DO,        NOT_OLD|BREAK|CONTINUE, 0 },
+{"else",       Op_K_else,       LEX_ELSE,      0,              0 },
+{"eval",       Op_symbol,       LEX_EVAL,      0,              0 },
+{"exit",       Op_K_exit,       LEX_EXIT,      0,              0 },
+{"exp",                Op_builtin,      LEX_BUILTIN,   A(1),           0 },
 #ifdef DYNAMIC
-{"extension",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   do_ext, 
0},
+{"extension",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   do_ext 
},
 #endif
-{"fflush",     Op_builtin,      LEX_BUILTIN,   A(0)|A(1), do_fflush,   0},
-{"for",                Op_K_for,        LEX_FOR,       BREAK|CONTINUE, 0,      
0},
-{"func",       Op_func, LEX_FUNCTION,  NOT_POSIX|NOT_OLD,      0,      0},
-{"function",Op_func, LEX_FUNCTION,     NOT_OLD,        0,      0},
-{"gensub",     Op_sub_builtin,  LEX_BUILTIN,   GAWKX|A(3)|A(4), 0,     0},
-{"getline",    Op_K_getline_redir,      LEX_GETLINE,   NOT_OLD,        0,      
0},
-{"gsub",       Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0,   0},
-{"if",         Op_K_if,         LEX_IF,        0,              0,      0},
-{"in",         Op_symbol,       LEX_IN,        0,              0,      0},
-{"include",  Op_symbol,         LEX_INCLUDE,   GAWKX,  0,      0},
-{"index",      Op_builtin,      LEX_BUILTIN,   A(2),           do_index,       
0},
-{"int",                Op_builtin,      LEX_BUILTIN,   A(1),           do_int, 
MPF(int)},
-{"isarray",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_isarray,     
0},
-{"length",     Op_builtin,      LEX_LENGTH,    A(0)|A(1),      do_length,      
0},
-{"load",       Op_symbol,       LEX_LOAD,      GAWKX,          0,      0},
-{"log",                Op_builtin,      LEX_BUILTIN,   A(1),           do_log, 
MPF(log)},
-{"lshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_lshift,      
MPF(lshift)},
-{"match",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_match,    
0},
-{"mktime",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_mktime,      
0},
-{"next",       Op_K_next,       LEX_NEXT,      0,              0,      0},
-{"nextfile",   Op_K_nextfile, LEX_NEXTFILE,    0,              0,      0},
-{"or",         Op_builtin,    LEX_BUILTIN,     GAWKX,          do_or,  
MPF(or)},
-{"patsplit",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(2)|A(3)|A(4), 
do_patsplit,      0},
-{"print",      Op_K_print,      LEX_PRINT,     0,              0,      0},
-{"printf",     Op_K_printf,     LEX_PRINTF,    0,              0,      0},
-{"rand",       Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0),   do_rand,        
MPF(rand)},
-{"return",     Op_K_return,     LEX_RETURN,    NOT_OLD,        0,      0},
-{"rshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_rshift,      
MPF(rhift)},
-{"sin",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_sin, 
MPF(sin)},
-{"split",      Op_builtin,      LEX_BUILTIN,   A(2)|A(3)|A(4), do_split,       
0},
-{"sprintf",    Op_builtin,      LEX_BUILTIN,   0,              do_sprintf,     
0},
-{"sqrt",       Op_builtin,      LEX_BUILTIN,   A(1),           do_sqrt,        
MPF(sqrt)},
-{"srand",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0)|A(1), do_srand,    
MPF(srand)},
+{"fflush",     Op_builtin,      LEX_BUILTIN,   A(0)|A(1), do_fflush },
+{"for",                Op_K_for,        LEX_FOR,       BREAK|CONTINUE, 0 },
+{"func",       Op_func, LEX_FUNCTION,  NOT_POSIX|NOT_OLD,      0 },
+{"function",Op_func, LEX_FUNCTION,     NOT_OLD,        0 },
+{"gensub",     Op_sub_builtin,  LEX_BUILTIN,   GAWKX|A(3)|A(4), 0 },
+{"getline",    Op_K_getline_redir,      LEX_GETLINE,   NOT_OLD,        0 },
+{"gsub",       Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0 },
+{"if",         Op_K_if,         LEX_IF,        0,              0 },
+{"in",         Op_symbol,       LEX_IN,        0,              0 },
+{"include",  Op_symbol,         LEX_INCLUDE,   GAWKX,  0 },
+{"index",      Op_builtin,      LEX_BUILTIN,   A(2),   do_index },
+{"int",                Op_builtin,      LEX_BUILTIN,   A(1),   0 },
+{"isarray",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_isarray },
+{"length",     Op_builtin,      LEX_LENGTH,    A(0)|A(1),      do_length },
+{"load",       Op_symbol,       LEX_LOAD,      GAWKX,          0 },
+{"log",                Op_builtin,      LEX_BUILTIN,   A(1),           0 },
+{"lshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     0 },
+{"match",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_match },
+{"mktime",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_mktime },
+{"next",       Op_K_next,       LEX_NEXT,      0,              0 },
+{"nextfile",   Op_K_nextfile, LEX_NEXTFILE,    0,              0 },
+{"or",         Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
+{"patsplit",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(2)|A(3)|A(4), 
do_patsplit },
+{"print",      Op_K_print,      LEX_PRINT,     0,              0 },
+{"printf",     Op_K_printf,     LEX_PRINTF,    0,              0 },
+{"rand",       Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0),   0 },
+{"return",     Op_K_return,     LEX_RETURN,    NOT_OLD,        0 },
+{"rshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     0 },
+{"sin",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   0 },
+{"split",      Op_builtin,      LEX_BUILTIN,   A(2)|A(3)|A(4), do_split },
+{"sprintf",    Op_builtin,      LEX_BUILTIN,   0,              do_sprintf },
+{"sqrt",       Op_builtin,      LEX_BUILTIN,   A(1),           0 },
+{"srand",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0)|A(1), 0 },
 #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"stopme",     Op_builtin,     LEX_BUILTIN,    GAWKX|A(0),     stopme,         
0},
+{"stopme",     Op_builtin,     LEX_BUILTIN,    GAWKX|A(0),     stopme },
 #endif
-{"strftime",   Op_builtin,      LEX_BUILTIN,   GAWKX|A(0)|A(1)|A(2)|A(3), 
do_strftime, 0},
-{"strtonum",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_strtonum, 
MPF(strtonum)},
-{"sub",                Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0,   
0},
-{"substr",     Op_builtin,      LEX_BUILTIN,   A(2)|A(3),      do_substr,      
0},
-{"switch",     Op_K_switch,     LEX_SWITCH,    GAWKX|BREAK,    0,      0},
-{"system",     Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_system,      
0},
-{"systime",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(0),     do_systime,     
0},
-{"tolower",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_tolower,     
0},
-{"toupper",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_toupper,     
0},
-{"while",      Op_K_while,      LEX_WHILE,     BREAK|CONTINUE, 0,      0},
-{"xor",                Op_builtin,    LEX_BUILTIN,     GAWKX,          do_xor, 
MPF(xor)},
+{"strftime",   Op_builtin,      LEX_BUILTIN,   GAWKX|A(0)|A(1)|A(2)|A(3), 
do_strftime },
+{"strtonum",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     0 },
+{"sub",                Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0 },
+{"substr",     Op_builtin,      LEX_BUILTIN,   A(2)|A(3),      do_substr },
+{"switch",     Op_K_switch,     LEX_SWITCH,    GAWKX|BREAK,    0 },
+{"system",     Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_system },
+{"systime",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(0),     do_systime },
+{"tolower",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_tolower },
+{"toupper",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_toupper },
+{"while",      Op_K_while,      LEX_WHILE,     BREAK|CONTINUE, 0 },
+{"xor",                Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
 };
 
 #if MBS_SUPPORT
@@ -4482,22 +4474,6 @@ getfname(NODE *(*fptr)(int))
        return NULL;
 }
 
-/* negate_num --- negate a number in NODE */
-
-void
-negate_num(NODE *n)
-{
-#ifdef HAVE_MPFR
-       if (is_mpg_float(n)) {
-               int tval;
-               tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
-               IEEE_FMT(n->mpg_numbr, tval);
-       } else if (is_mpg_integer(n)) {
-               mpz_neg(n->mpg_i, n->mpg_i);
-       } else
-#endif
-               n->numbr = -n->numbr;
-}
 
 /* print_included_from --- print `Included from ..' file names and locations */
 
@@ -4667,6 +4643,18 @@ yyerror(const char *m, ...)
        efree(buf);
 }
 
+void
+init_parser(const bltin_t *numbr_bltins)
+{
+       int i, tokentab_idx;
+
+       for (i = 0; numbr_bltins[i].name != NULL; i++) {
+               tokentab_idx = check_special(numbr_bltins[i].name);
+               tokentab[tokentab_idx].ptr = numbr_bltins[i].ptr;
+       }
+}
+
+
 /* mk_program --- create a single list of instructions */
 
 static INSTRUCTION *
@@ -6038,32 +6026,7 @@ retry:
                        }
                }
 
-#ifdef HAVE_MPFR
-               if (do_mpfr) {
-                       NODE *r;
-
-                       if (! seen_point && ! seen_e) {
-                               r = mpg_integer();
-                               mpg_strtoui(r->mpg_i, tokstart, 
strlen(tokstart), NULL, base);
-                               errno = 0;
-                       } else {
-                               int tval;
-                               r = mpg_float();
-                               tval = mpfr_strtofr(r->mpg_numbr, tokstart, 
NULL, base, ROUND_MODE);
-                               errno = 0;
-                               IEEE_FMT(r->mpg_numbr, tval);
-                       }
-                       yylval->memory = r;
-                       return lasttok = YNUMBER;
-               }
-#endif
-               if (base != 10)
-                       d = nondec2awknum(tokstart, strlen(tokstart));
-               else
-                       d = atof(tokstart);
-               yylval->memory = make_number(d);
-               if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
-                       yylval->memory->flags |= NUMINT;
+               yylval->memory = str2node(tokstart, NULL, base, ! (seen_point 
|| seen_e));
                return lasttok = YNUMBER;
 
        case '&':
@@ -6367,13 +6330,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                }
        }
 
-#ifdef HAVE_MPFR
-       /* N.B.: There isn't any special processing for an alternate function 
below */
-       if (do_mpfr && tokentab[idx].ptr2)
-               r->builtin =  tokentab[idx].ptr2;
-       else
-#endif
-               r->builtin = tokentab[idx].ptr;
+       r->builtin = tokentab[idx].ptr;
 
        /* special case processing for a few builtins */
 
@@ -6580,26 +6537,12 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
                pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
                print_func(fp, "\n");
        } else if (n->flags & NUMBER) {
-#ifdef HAVE_MPFR
-               if (is_mpg_float(n))
-                       print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, 
n->mpg_numbr));
-               else if (is_mpg_integer(n))
-                       print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
-               else
-#endif
-               print_func(fp, "%.17g\n", n->numbr);
+               print_func(fp, "%s\n", fmt_number("%.17g", n));
        } else if (n->flags & STRCUR) {
                pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
                print_func(fp, "\n");
        } else if (n->flags & NUMCUR) {
-#ifdef HAVE_MPFR
-               if (is_mpg_float(n))
-                       print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, 
n->mpg_numbr));
-               else if (is_mpg_integer(n))
-                       print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
-               else
-#endif
-               print_func(fp, "%.17g\n", n->numbr);
+               print_func(fp, "%s\n", fmt_number("%.17g", n));
        } else
                print_func(fp, "?? flags %s\n", flags2str(n->flags));
 }
@@ -7060,20 +7003,15 @@ isnoeffect(OPCODE type)
 {
        switch (type) {
        case Op_times:
-       case Op_times_i:
        case Op_quotient:
-       case Op_quotient_i:
        case Op_mod:
-       case Op_mod_i:
        case Op_plus:
-       case Op_plus_i:
        case Op_minus:
-       case Op_minus_i:
        case Op_subscript:
        case Op_concat:
        case Op_exp:
-       case Op_exp_i:
        case Op_unary_minus:
+       case Op_unary_plus:
        case Op_field_spec:
        case Op_and_final:
        case Op_or_final:
@@ -7176,112 +7114,6 @@ dumpintlstr2(const char *str1, size_t len1, const char 
*str2, size_t len2)
        fflush(stdout);
 }
 
-/* mk_binary --- instructions for binary operators */
-
-static INSTRUCTION *
-mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
-{
-       INSTRUCTION *ip1,*ip2;
-       AWKNUM res;
-
-       ip2 = s2->nexti;
-       if (s2->lasti == ip2 && ip2->opcode == Op_push_i) {
-       /* do any numeric constant folding */
-               ip1 = s1->nexti;
-               if (do_optimize > 1
-                               && ip1 == s1->lasti && ip1->opcode == Op_push_i
-                               && (ip1->memory->flags & 
(MPFN|MPZN|STRCUR|STRING)) == 0
-                               && (ip2->memory->flags & 
(MPFN|MPZN|STRCUR|STRING)) == 0
-               ) {
-                       NODE *n1 = ip1->memory, *n2 = ip2->memory;
-                       res = force_number(n1)->numbr;
-                       (void) force_number(n2);
-                       switch (op->opcode) {
-                       case Op_times:
-                               res *= n2->numbr;
-                               break;
-                       case Op_quotient:
-                               if (n2->numbr == 0.0) {
-                                       /* don't fatalize, allow parsing rest 
of the input */
-                                       error_ln(op->source_line, _("division 
by zero attempted"));
-                                       goto regular;
-                               }
-
-                               res /= n2->numbr;
-                               break;
-                       case Op_mod:
-                               if (n2->numbr == 0.0) {
-                                       /* don't fatalize, allow parsing rest 
of the input */
-                                       error_ln(op->source_line, _("division 
by zero attempted in `%%'"));
-                                       goto regular;
-                               }
-#ifdef HAVE_FMOD
-                               res = fmod(res, n2->numbr);
-#else  /* ! HAVE_FMOD */
-                               (void) modf(res / n2->numbr, &res);
-                               res = n1->numbr - res * n2->numbr;
-#endif /* ! HAVE_FMOD */
-                               break;
-                       case Op_plus:
-                               res += n2->numbr;
-                               break;
-                       case Op_minus:
-                               res -= n2->numbr;
-                               break;
-                       case Op_exp:
-                               res = calc_exp(res, n2->numbr);
-                               break;
-                       default:
-                               goto regular;
-                       }
-
-                       op->opcode = Op_push_i;
-                       op->memory = make_number(res);
-                       unref(n1);
-                       unref(n2);
-                       bcfree(ip1);
-                       bcfree(ip2);
-                       bcfree(s1);
-                       bcfree(s2);
-                       return list_create(op);
-               } else {
-               /* do basic arithmetic optimisation */
-               /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i 
Node_val) */
-                       switch (op->opcode) {
-                       case Op_times:
-                               op->opcode = Op_times_i;
-                               break;
-                       case Op_quotient:
-                               op->opcode = Op_quotient_i;
-                               break;
-                       case Op_mod:
-                               op->opcode = Op_mod_i;
-                               break;
-                       case Op_plus:
-                               op->opcode = Op_plus_i;
-                               break;
-                       case Op_minus:
-                               op->opcode = Op_minus_i;
-                               break;
-                       case Op_exp:
-                               op->opcode = Op_exp_i;
-                               break;
-                       default:
-                               goto regular;
-                       }       
-
-                       op->memory = ip2->memory;
-                       bcfree(ip2);
-                       bcfree(s2);     /* Op_list */
-                       return list_append(s1, op);
-               }
-       }
-
-regular:
-       /* append lists s1, s2 and add `op' bytecode */
-       (void) list_merge(s1, s2);
-       return list_append(s1, op);
-}
 
 /* mk_boolean --- instructions for boolean and, or */
  
@@ -7677,8 +7509,8 @@ optimize_assignment(INSTRUCTION *exp)
                                        i3->opcode = Op_store_sub;
                                        i3->memory = i2->memory;
                                        i3->expr_count = 1;  /* sub_count 
shadows memory,
-                                          * so use expr_count instead.
-                                                         */
+                                                             * so use 
expr_count instead
+                                                             */
                                        i3->nexti = NULL;
                                        i2->opcode = Op_no_op;                  
                
                                        bcfree(i1);          /* Op_assign */
diff --git a/awkgram.y b/awkgram.y
index b1574c8..bf5ca36 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -69,7 +69,6 @@ static INSTRUCTION *mk_expression_list(INSTRUCTION *list, 
INSTRUCTION *s1);
 static INSTRUCTION *mk_for_loop(INSTRUCTION *forp, INSTRUCTION *init, 
INSTRUCTION *cond,
                INSTRUCTION *incr, INSTRUCTION *body);
 static void fix_break_continue(INSTRUCTION *list, INSTRUCTION *b_target, 
INSTRUCTION *c_target);
-static INSTRUCTION *mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION 
*op);
 static INSTRUCTION *mk_boolean(INSTRUCTION *left, INSTRUCTION *right, 
INSTRUCTION *op);
 static INSTRUCTION *mk_assignment(INSTRUCTION *lhs, INSTRUCTION *rhs, 
INSTRUCTION *op);
 static INSTRUCTION *mk_getline(INSTRUCTION *op, INSTRUCTION *opt_var, 
INSTRUCTION *redir, int redirtype);
@@ -1096,7 +1095,7 @@ case_value
          { 
                NODE *n = $2->memory;
                (void) force_number(n);
-               negate_num(n);
+               numbr_hndlr->gawk_negate_number(n);
                bcfree($1);
                $$ = $2;
          }
@@ -1378,17 +1377,17 @@ simp_exp
        : non_post_simp_exp
        /* Binary operators in order of decreasing precedence.  */
        | simp_exp '^' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp '*' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp '/' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp '%' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp '+' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp '-' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | LEX_GETLINE opt_variable input_redir
          {
                /*
@@ -1454,17 +1453,17 @@ simp_exp_nc
                }
        /* Binary operators in order of decreasing precedence.  */
        | simp_exp_nc '^' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp_nc '*' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp_nc '/' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp_nc '%' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp_nc '+' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        | simp_exp_nc '-' simp_exp
-         { $$ = mk_binary($1, $3, $2); }
+         {     $$ = list_append(list_merge($1, $3), $2); }
        ;
 
 non_post_simp_exp
@@ -1558,7 +1557,7 @@ non_post_simp_exp
                ) {
                        NODE *n = $2->lasti->memory;
                        (void) force_number(n);
-                       negate_num(n);                  
+                       numbr_hndlr->gawk_negate_number(n);
                        $$ = $2;
                        bcfree($1);
                } else {
@@ -1572,8 +1571,7 @@ non_post_simp_exp
             * was: $$ = $2
             * POSIX semantics: force a conversion to numeric type
             */
-               $1->opcode = Op_plus_i;
-               $1->memory = make_number(0.0);
+               $1->opcode = Op_unary_plus;
                $$ = list_append($2, $1);
          }
        ;
@@ -1803,7 +1801,6 @@ struct token {
 #      define  CONTINUE        0x1000  /* continue allowed inside */
        
        NODE *(*ptr)(int);      /* function that implements this keyword */
-       NODE *(*ptr2)(int);     /* alternate arbitrary-precision function */
 };
 
 #if 'a' == 0x81 /* it's EBCDIC */
@@ -1827,90 +1824,85 @@ tokcompare(const void *l, const void *r)
  * Function pointers come from declarations in awk.h.
  */
 
-#ifdef HAVE_MPFR
-#define MPF(F) do_mpfr_##F
-#else
-#define MPF(F) 0
-#endif
 
-static const struct token tokentab[] = {
-{"BEGIN",      Op_rule,         LEX_BEGIN,     0,              0,      0},
-{"BEGINFILE",  Op_rule,         LEX_BEGINFILE, GAWKX,          0,      0},
-{"END",                Op_rule,         LEX_END,       0,              0,      
0},
-{"ENDFILE",            Op_rule,         LEX_ENDFILE,   GAWKX,          0,      
0},
+static struct token tokentab[] = {
+{"BEGIN",      Op_rule,         LEX_BEGIN,     0,              0 },
+{"BEGINFILE",  Op_rule,         LEX_BEGINFILE, GAWKX,          0 },
+{"END",                Op_rule,         LEX_END,       0,              0 },
+{"ENDFILE",            Op_rule,         LEX_ENDFILE,   GAWKX,          0 },
 #ifdef ARRAYDEBUG
-{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1)|A(2),        
do_adump,       0},
+{"adump",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1)|A(2),        
do_adump },
 #endif
-{"and",                Op_builtin,    LEX_BUILTIN,     GAWKX,          do_and, 
MPF(and)},
-{"asort",      Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asort,       0},
-{"asorti",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asorti,      0},
-{"atan2",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2),   do_atan2,       
MPF(atan2)},
-{"bindtextdomain",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2),        
do_bindtextdomain,      0},
-{"break",      Op_K_break,      LEX_BREAK,     0,              0,      0},
-{"case",       Op_K_case,       LEX_CASE,      GAWKX,          0,      0},
-{"close",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1)|A(2),      
do_close,       0},
-{"compl",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_compl,       
MPF(compl)},
-{"continue",   Op_K_continue, LEX_CONTINUE,    0,              0,      0},
-{"cos",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_cos, 
MPF(cos)},
-{"dcgettext",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_dcgettext,   0},
-{"dcngettext", Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), 
do_dcngettext,  0},
-{"default",    Op_K_default,    LEX_DEFAULT,   GAWKX,          0,      0},
-{"delete",     Op_K_delete,     LEX_DELETE,    NOT_OLD,        0,      0},
-{"do",         Op_K_do,         LEX_DO,        NOT_OLD|BREAK|CONTINUE, 0,      
0},
-{"else",       Op_K_else,       LEX_ELSE,      0,              0,      0},
-{"eval",       Op_symbol,       LEX_EVAL,      0,              0,      0},
-{"exit",       Op_K_exit,       LEX_EXIT,      0,              0,      0},
-{"exp",                Op_builtin,      LEX_BUILTIN,   A(1),           do_exp, 
MPF(exp)},
+{"and",                Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
+{"asort",      Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asort },
+{"asorti",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_asorti },
+{"atan2",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2),   0 },
+{"bindtextdomain",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2),        
do_bindtextdomain },
+{"break",      Op_K_break,      LEX_BREAK,     0,              0 },
+{"case",       Op_K_case,       LEX_CASE,      GAWKX,          0 },
+{"close",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1)|A(2),      
do_close },
+{"compl",      Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     0 },
+{"continue",   Op_K_continue, LEX_CONTINUE,    0,              0 },
+{"cos",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   0 },
+{"dcgettext",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   
do_dcgettext },
+{"dcngettext", Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3)|A(4)|A(5), 
do_dcngettext },
+{"default",    Op_K_default,    LEX_DEFAULT,   GAWKX,          0 },
+{"delete",     Op_K_delete,     LEX_DELETE,    NOT_OLD,        0 },
+{"do",         Op_K_do,         LEX_DO,        NOT_OLD|BREAK|CONTINUE, 0 },
+{"else",       Op_K_else,       LEX_ELSE,      0,              0 },
+{"eval",       Op_symbol,       LEX_EVAL,      0,              0 },
+{"exit",       Op_K_exit,       LEX_EXIT,      0,              0 },
+{"exp",                Op_builtin,      LEX_BUILTIN,   A(1),           0 },
 #ifdef DYNAMIC
-{"extension",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   do_ext, 
0},
+{"extension",  Op_builtin,      LEX_BUILTIN,   GAWKX|A(1)|A(2)|A(3),   do_ext 
},
 #endif
-{"fflush",     Op_builtin,      LEX_BUILTIN,   A(0)|A(1), do_fflush,   0},
-{"for",                Op_K_for,        LEX_FOR,       BREAK|CONTINUE, 0,      
0},
-{"func",       Op_func, LEX_FUNCTION,  NOT_POSIX|NOT_OLD,      0,      0},
-{"function",Op_func, LEX_FUNCTION,     NOT_OLD,        0,      0},
-{"gensub",     Op_sub_builtin,  LEX_BUILTIN,   GAWKX|A(3)|A(4), 0,     0},
-{"getline",    Op_K_getline_redir,      LEX_GETLINE,   NOT_OLD,        0,      
0},
-{"gsub",       Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0,   0},
-{"if",         Op_K_if,         LEX_IF,        0,              0,      0},
-{"in",         Op_symbol,       LEX_IN,        0,              0,      0},
-{"include",  Op_symbol,         LEX_INCLUDE,   GAWKX,  0,      0},
-{"index",      Op_builtin,      LEX_BUILTIN,   A(2),           do_index,       
0},
-{"int",                Op_builtin,      LEX_BUILTIN,   A(1),           do_int, 
MPF(int)},
-{"isarray",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_isarray,     
0},
-{"length",     Op_builtin,      LEX_LENGTH,    A(0)|A(1),      do_length,      
0},
-{"load",       Op_symbol,       LEX_LOAD,      GAWKX,          0,      0},
-{"log",                Op_builtin,      LEX_BUILTIN,   A(1),           do_log, 
MPF(log)},
-{"lshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_lshift,      
MPF(lshift)},
-{"match",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_match,    
0},
-{"mktime",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_mktime,      
0},
-{"next",       Op_K_next,       LEX_NEXT,      0,              0,      0},
-{"nextfile",   Op_K_nextfile, LEX_NEXTFILE,    0,              0,      0},
-{"or",         Op_builtin,    LEX_BUILTIN,     GAWKX,          do_or,  
MPF(or)},
-{"patsplit",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(2)|A(3)|A(4), 
do_patsplit,      0},
-{"print",      Op_K_print,      LEX_PRINT,     0,              0,      0},
-{"printf",     Op_K_printf,     LEX_PRINTF,    0,              0,      0},
-{"rand",       Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0),   do_rand,        
MPF(rand)},
-{"return",     Op_K_return,     LEX_RETURN,    NOT_OLD,        0,      0},
-{"rshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     do_rshift,      
MPF(rhift)},
-{"sin",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_sin, 
MPF(sin)},
-{"split",      Op_builtin,      LEX_BUILTIN,   A(2)|A(3)|A(4), do_split,       
0},
-{"sprintf",    Op_builtin,      LEX_BUILTIN,   0,              do_sprintf,     
0},
-{"sqrt",       Op_builtin,      LEX_BUILTIN,   A(1),           do_sqrt,        
MPF(sqrt)},
-{"srand",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0)|A(1), do_srand,    
MPF(srand)},
+{"fflush",     Op_builtin,      LEX_BUILTIN,   A(0)|A(1), do_fflush },
+{"for",                Op_K_for,        LEX_FOR,       BREAK|CONTINUE, 0 },
+{"func",       Op_func, LEX_FUNCTION,  NOT_POSIX|NOT_OLD,      0 },
+{"function",Op_func, LEX_FUNCTION,     NOT_OLD,        0 },
+{"gensub",     Op_sub_builtin,  LEX_BUILTIN,   GAWKX|A(3)|A(4), 0 },
+{"getline",    Op_K_getline_redir,      LEX_GETLINE,   NOT_OLD,        0 },
+{"gsub",       Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0 },
+{"if",         Op_K_if,         LEX_IF,        0,              0 },
+{"in",         Op_symbol,       LEX_IN,        0,              0 },
+{"include",  Op_symbol,         LEX_INCLUDE,   GAWKX,  0 },
+{"index",      Op_builtin,      LEX_BUILTIN,   A(2),   do_index },
+{"int",                Op_builtin,      LEX_BUILTIN,   A(1),   0 },
+{"isarray",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_isarray },
+{"length",     Op_builtin,      LEX_LENGTH,    A(0)|A(1),      do_length },
+{"load",       Op_symbol,       LEX_LOAD,      GAWKX,          0 },
+{"log",                Op_builtin,      LEX_BUILTIN,   A(1),           0 },
+{"lshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     0 },
+{"match",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(2)|A(3), do_match },
+{"mktime",     Op_builtin,      LEX_BUILTIN,   GAWKX|A(1),     do_mktime },
+{"next",       Op_K_next,       LEX_NEXT,      0,              0 },
+{"nextfile",   Op_K_nextfile, LEX_NEXTFILE,    0,              0 },
+{"or",         Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
+{"patsplit",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(2)|A(3)|A(4), 
do_patsplit },
+{"print",      Op_K_print,      LEX_PRINT,     0,              0 },
+{"printf",     Op_K_printf,     LEX_PRINTF,    0,              0 },
+{"rand",       Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0),   0 },
+{"return",     Op_K_return,     LEX_RETURN,    NOT_OLD,        0 },
+{"rshift",     Op_builtin,    LEX_BUILTIN,     GAWKX|A(2),     0 },
+{"sin",                Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   0 },
+{"split",      Op_builtin,      LEX_BUILTIN,   A(2)|A(3)|A(4), do_split },
+{"sprintf",    Op_builtin,      LEX_BUILTIN,   0,              do_sprintf },
+{"sqrt",       Op_builtin,      LEX_BUILTIN,   A(1),           0 },
+{"srand",      Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(0)|A(1), 0 },
 #if defined(GAWKDEBUG) || defined(ARRAYDEBUG) /* || ... */
-{"stopme",     Op_builtin,     LEX_BUILTIN,    GAWKX|A(0),     stopme,         
0},
+{"stopme",     Op_builtin,     LEX_BUILTIN,    GAWKX|A(0),     stopme },
 #endif
-{"strftime",   Op_builtin,      LEX_BUILTIN,   GAWKX|A(0)|A(1)|A(2)|A(3), 
do_strftime, 0},
-{"strtonum",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     do_strtonum, 
MPF(strtonum)},
-{"sub",                Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0,   
0},
-{"substr",     Op_builtin,      LEX_BUILTIN,   A(2)|A(3),      do_substr,      
0},
-{"switch",     Op_K_switch,     LEX_SWITCH,    GAWKX|BREAK,    0,      0},
-{"system",     Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_system,      
0},
-{"systime",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(0),     do_systime,     
0},
-{"tolower",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_tolower,     
0},
-{"toupper",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_toupper,     
0},
-{"while",      Op_K_while,      LEX_WHILE,     BREAK|CONTINUE, 0,      0},
-{"xor",                Op_builtin,    LEX_BUILTIN,     GAWKX,          do_xor, 
MPF(xor)},
+{"strftime",   Op_builtin,      LEX_BUILTIN,   GAWKX|A(0)|A(1)|A(2)|A(3), 
do_strftime },
+{"strtonum",   Op_builtin,    LEX_BUILTIN,     GAWKX|A(1),     0 },
+{"sub",                Op_sub_builtin,  LEX_BUILTIN,   NOT_OLD|A(2)|A(3), 0 },
+{"substr",     Op_builtin,      LEX_BUILTIN,   A(2)|A(3),      do_substr },
+{"switch",     Op_K_switch,     LEX_SWITCH,    GAWKX|BREAK,    0 },
+{"system",     Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_system },
+{"systime",    Op_builtin,      LEX_BUILTIN,   GAWKX|A(0),     do_systime },
+{"tolower",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_tolower },
+{"toupper",    Op_builtin,      LEX_BUILTIN,   NOT_OLD|A(1),   do_toupper },
+{"while",      Op_K_while,      LEX_WHILE,     BREAK|CONTINUE, 0 },
+{"xor",                Op_builtin,    LEX_BUILTIN,     GAWKX,          0 },
 };
 
 #if MBS_SUPPORT
@@ -1946,22 +1938,6 @@ getfname(NODE *(*fptr)(int))
        return NULL;
 }
 
-/* negate_num --- negate a number in NODE */
-
-void
-negate_num(NODE *n)
-{
-#ifdef HAVE_MPFR
-       if (is_mpg_float(n)) {
-               int tval;
-               tval = mpfr_neg(n->mpg_numbr, n->mpg_numbr, ROUND_MODE);
-               IEEE_FMT(n->mpg_numbr, tval);
-       } else if (is_mpg_integer(n)) {
-               mpz_neg(n->mpg_i, n->mpg_i);
-       } else
-#endif
-               n->numbr = -n->numbr;
-}
 
 /* print_included_from --- print `Included from ..' file names and locations */
 
@@ -2131,6 +2107,18 @@ yyerror(const char *m, ...)
        efree(buf);
 }
 
+void
+init_parser(const bltin_t *numbr_bltins)
+{
+       int i, tokentab_idx;
+
+       for (i = 0; numbr_bltins[i].name != NULL; i++) {
+               tokentab_idx = check_special(numbr_bltins[i].name);
+               tokentab[tokentab_idx].ptr = numbr_bltins[i].ptr;
+       }
+}
+
+
 /* mk_program --- create a single list of instructions */
 
 static INSTRUCTION *
@@ -3502,32 +3490,7 @@ retry:
                        }
                }
 
-#ifdef HAVE_MPFR
-               if (do_mpfr) {
-                       NODE *r;
-
-                       if (! seen_point && ! seen_e) {
-                               r = mpg_integer();
-                               mpg_strtoui(r->mpg_i, tokstart, 
strlen(tokstart), NULL, base);
-                               errno = 0;
-                       } else {
-                               int tval;
-                               r = mpg_float();
-                               tval = mpfr_strtofr(r->mpg_numbr, tokstart, 
NULL, base, ROUND_MODE);
-                               errno = 0;
-                               IEEE_FMT(r->mpg_numbr, tval);
-                       }
-                       yylval->memory = r;
-                       return lasttok = YNUMBER;
-               }
-#endif
-               if (base != 10)
-                       d = nondec2awknum(tokstart, strlen(tokstart));
-               else
-                       d = atof(tokstart);
-               yylval->memory = make_number(d);
-               if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
-                       yylval->memory->flags |= NUMINT;
+               yylval->memory = str2node(tokstart, NULL, base, ! (seen_point 
|| seen_e));
                return lasttok = YNUMBER;
 
        case '&':
@@ -3831,13 +3794,7 @@ snode(INSTRUCTION *subn, INSTRUCTION *r)
                }
        }
 
-#ifdef HAVE_MPFR
-       /* N.B.: There isn't any special processing for an alternate function 
below */
-       if (do_mpfr && tokentab[idx].ptr2)
-               r->builtin =  tokentab[idx].ptr2;
-       else
-#endif
-               r->builtin = tokentab[idx].ptr;
+       r->builtin = tokentab[idx].ptr;
 
        /* special case processing for a few builtins */
 
@@ -4044,26 +4001,12 @@ valinfo(NODE *n, Func_print print_func, FILE *fp)
                pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
                print_func(fp, "\n");
        } else if (n->flags & NUMBER) {
-#ifdef HAVE_MPFR
-               if (is_mpg_float(n))
-                       print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, 
n->mpg_numbr));
-               else if (is_mpg_integer(n))
-                       print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
-               else
-#endif
-               print_func(fp, "%.17g\n", n->numbr);
+               print_func(fp, "%s\n", fmt_number("%.17g", n));
        } else if (n->flags & STRCUR) {
                pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', false);
                print_func(fp, "\n");
        } else if (n->flags & NUMCUR) {
-#ifdef HAVE_MPFR
-               if (is_mpg_float(n))
-                       print_func(fp, "%s\n", mpg_fmt("%.17R*g", ROUND_MODE, 
n->mpg_numbr));
-               else if (is_mpg_integer(n))
-                       print_func(fp, "%s\n", mpg_fmt("%Zd", n->mpg_i));
-               else
-#endif
-               print_func(fp, "%.17g\n", n->numbr);
+               print_func(fp, "%s\n", fmt_number("%.17g", n));
        } else
                print_func(fp, "?? flags %s\n", flags2str(n->flags));
 }
@@ -4524,20 +4467,15 @@ isnoeffect(OPCODE type)
 {
        switch (type) {
        case Op_times:
-       case Op_times_i:
        case Op_quotient:
-       case Op_quotient_i:
        case Op_mod:
-       case Op_mod_i:
        case Op_plus:
-       case Op_plus_i:
        case Op_minus:
-       case Op_minus_i:
        case Op_subscript:
        case Op_concat:
        case Op_exp:
-       case Op_exp_i:
        case Op_unary_minus:
+       case Op_unary_plus:
        case Op_field_spec:
        case Op_and_final:
        case Op_or_final:
@@ -4640,112 +4578,6 @@ dumpintlstr2(const char *str1, size_t len1, const char 
*str2, size_t len2)
        fflush(stdout);
 }
 
-/* mk_binary --- instructions for binary operators */
-
-static INSTRUCTION *
-mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op)
-{
-       INSTRUCTION *ip1,*ip2;
-       AWKNUM res;
-
-       ip2 = s2->nexti;
-       if (s2->lasti == ip2 && ip2->opcode == Op_push_i) {
-       /* do any numeric constant folding */
-               ip1 = s1->nexti;
-               if (do_optimize > 1
-                               && ip1 == s1->lasti && ip1->opcode == Op_push_i
-                               && (ip1->memory->flags & 
(MPFN|MPZN|STRCUR|STRING)) == 0
-                               && (ip2->memory->flags & 
(MPFN|MPZN|STRCUR|STRING)) == 0
-               ) {
-                       NODE *n1 = ip1->memory, *n2 = ip2->memory;
-                       res = force_number(n1)->numbr;
-                       (void) force_number(n2);
-                       switch (op->opcode) {
-                       case Op_times:
-                               res *= n2->numbr;
-                               break;
-                       case Op_quotient:
-                               if (n2->numbr == 0.0) {
-                                       /* don't fatalize, allow parsing rest 
of the input */
-                                       error_ln(op->source_line, _("division 
by zero attempted"));
-                                       goto regular;
-                               }
-
-                               res /= n2->numbr;
-                               break;
-                       case Op_mod:
-                               if (n2->numbr == 0.0) {
-                                       /* don't fatalize, allow parsing rest 
of the input */
-                                       error_ln(op->source_line, _("division 
by zero attempted in `%%'"));
-                                       goto regular;
-                               }
-#ifdef HAVE_FMOD
-                               res = fmod(res, n2->numbr);
-#else  /* ! HAVE_FMOD */
-                               (void) modf(res / n2->numbr, &res);
-                               res = n1->numbr - res * n2->numbr;
-#endif /* ! HAVE_FMOD */
-                               break;
-                       case Op_plus:
-                               res += n2->numbr;
-                               break;
-                       case Op_minus:
-                               res -= n2->numbr;
-                               break;
-                       case Op_exp:
-                               res = calc_exp(res, n2->numbr);
-                               break;
-                       default:
-                               goto regular;
-                       }
-
-                       op->opcode = Op_push_i;
-                       op->memory = make_number(res);
-                       unref(n1);
-                       unref(n2);
-                       bcfree(ip1);
-                       bcfree(ip2);
-                       bcfree(s1);
-                       bcfree(s2);
-                       return list_create(op);
-               } else {
-               /* do basic arithmetic optimisation */
-               /* convert (Op_push_i Node_val) + (Op_plus) to (Op_plus_i 
Node_val) */
-                       switch (op->opcode) {
-                       case Op_times:
-                               op->opcode = Op_times_i;
-                               break;
-                       case Op_quotient:
-                               op->opcode = Op_quotient_i;
-                               break;
-                       case Op_mod:
-                               op->opcode = Op_mod_i;
-                               break;
-                       case Op_plus:
-                               op->opcode = Op_plus_i;
-                               break;
-                       case Op_minus:
-                               op->opcode = Op_minus_i;
-                               break;
-                       case Op_exp:
-                               op->opcode = Op_exp_i;
-                               break;
-                       default:
-                               goto regular;
-                       }       
-
-                       op->memory = ip2->memory;
-                       bcfree(ip2);
-                       bcfree(s2);     /* Op_list */
-                       return list_append(s1, op);
-               }
-       }
-
-regular:
-       /* append lists s1, s2 and add `op' bytecode */
-       (void) list_merge(s1, s2);
-       return list_append(s1, op);
-}
 
 /* mk_boolean --- instructions for boolean and, or */
  
@@ -5141,8 +4973,8 @@ optimize_assignment(INSTRUCTION *exp)
                                        i3->opcode = Op_store_sub;
                                        i3->memory = i2->memory;
                                        i3->expr_count = 1;  /* sub_count 
shadows memory,
-                                          * so use expr_count instead.
-                                                         */
+                                                             * so use 
expr_count instead
+                                                             */
                                        i3->nexti = NULL;
                                        i2->opcode = Op_no_op;                  
                
                                        bcfree(i1);          /* Op_assign */
diff --git a/builtin.c b/builtin.c
index 07169a3..464b6fc 100644
--- a/builtin.c
+++ b/builtin.c
@@ -28,9 +28,6 @@
 #if defined(HAVE_FCNTL_H)
 #include <fcntl.h>
 #endif
-#include <math.h>
-#include "random.h"
-#include "floatmagic.h"
 
 #if defined(HAVE_POPEN_H)
 #include "popen.h"
@@ -59,16 +56,9 @@
 #define SIZE_MAX ((size_t) -1)
 #endif
 
-#define DEFAULT_G_PRECISION 6
 
-static size_t mbc_byte_count(const char *ptr, size_t numchars);
-static size_t mbc_char_count(const char *ptr, size_t numbytes);
-
-/* Can declare these, since we always use the random shipped with gawk */
-extern char *initstate(unsigned long seed, char *state, long n);
-extern char *setstate(char *state);
-extern long random(void);
-extern void srandom(unsigned long seed);
+extern size_t mbc_byte_count(const char *ptr, size_t numchars);
+extern size_t mbc_char_count(const char *ptr, size_t numbytes);
 
 extern NODE **args_array;
 extern int max_args;
@@ -86,12 +76,6 @@ fatal(_("attempt to use array `%s' in a scalar context"), 
array_vname(s1)); \
 }} while (false)
 
 
-/*
- * Since we supply the version of random(), we know what
- * value to use here.
- */
-#define GAWK_RANDOM_MAX 0x7fffffffL
-
 /* efwrite --- like fwrite, but with error checking */
 
 static void
@@ -130,25 +114,6 @@ wrerror:
                errno ? strerror(errno) : _("reason unknown"));
 }
 
-/* do_exp --- exponential function */
-
-NODE *
-do_exp(int nargs)
-{
-       NODE *tmp;
-       double d, res;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("exp: received non-numeric argument"));
-       d = force_number(tmp)->numbr;
-       DEREF(tmp);
-       errno = 0;
-       res = exp(d);
-       if (errno == ERANGE)
-               warning(_("exp: argument %g is out of range"), d);
-       return make_number((AWKNUM) res);
-}
 
 /* stdfile --- return fp for a standard file */
 
@@ -458,35 +423,6 @@ out:
        return make_number((AWKNUM) ret);
 }
 
-/* double_to_int --- convert double to int, used several places */
-
-double
-double_to_int(double d)
-{
-       if (d >= 0)
-               d = Floor(d);
-       else
-               d = Ceil(d);
-       return d;
-}
-
-/* do_int --- convert double to int for awk */
-
-NODE *
-do_int(int nargs)
-{
-       NODE *tmp;
-       double d;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("int: received non-numeric argument"));
-       d = force_number(tmp)->numbr;
-       d = double_to_int(d);
-       DEREF(tmp);
-       return make_number((AWKNUM) d);
-}
-
 /* do_isarray --- check if argument is array */
 
 NODE *
@@ -557,1022 +493,6 @@ do_length(int nargs)
        return make_number((AWKNUM) len);
 }
 
-/* do_log --- the log function */
-
-NODE *
-do_log(int nargs)
-{
-       NODE *tmp;
-       double d, arg;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("log: received non-numeric argument"));
-       arg = force_number(tmp)->numbr;
-       if (arg < 0.0)
-               warning(_("log: received negative argument %g"), arg);
-       d = log(arg);
-       DEREF(tmp);
-       return make_number((AWKNUM) d);
-}
-
-
-#ifdef HAVE_MPFR
-
-/*
- * mpz2mpfr --- convert an arbitrary-precision integer to a float
- *     without any loss of precision. The returned value is only
- *     good for temporary use.
- */
-
-
-static mpfr_ptr
-mpz2mpfr(mpz_ptr zi)
-{
-       size_t prec;
-       static mpfr_t mpfrval;
-       static bool inited = false;
-       int tval;
-
-       /* estimate minimum precision for exact conversion */
-       prec = mpz_sizeinbase(zi, 2);   /* most significant 1 bit position 
starting at 1 */
-       prec -= (size_t) mpz_scan1(zi, 0);      /* least significant 1 bit 
index starting at 0 */
-       if (prec < MPFR_PREC_MIN)
-               prec = MPFR_PREC_MIN;
-       else if (prec > MPFR_PREC_MAX)
-               prec = MPFR_PREC_MAX;
-
-       if (! inited) {
-               mpfr_init2(mpfrval, prec);
-               inited = true;
-       } else
-               mpfr_set_prec(mpfrval, prec);
-       tval = mpfr_set_z(mpfrval, zi, ROUND_MODE);
-       IEEE_FMT(mpfrval, tval);
-       return mpfrval;
-}
-#endif
-
-/*
- * format_tree() formats arguments of sprintf,
- * and accordingly to a fmt_string providing a format like in
- * printf family from C library.  Returns a string node which value
- * is a formatted string.  Called by  sprintf function.
- *
- * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
- * for taming this beast and making it compatible with ANSI C.
- */
-
-NODE *
-format_tree(
-       const char *fmt_string,
-       size_t n0,
-       NODE **the_args,
-       long num_args)
-{
-/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
-/* difference of pointers should be of ptrdiff_t type, but let us be kind */
-#define bchunk(s, l) if (l) { \
-       while ((l) > ofre) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       memcpy(obufout, s, (size_t) (l)); \
-       obufout += (l); \
-       ofre -= (l); \
-}
-
-/* copy one byte from 's' to 'obufout' checking for space in the process */
-#define bchunk_one(s) { \
-       if (ofre < 1) { \
-               size_t olen = obufout - obuf; \
-               erealloc(obuf, char *, osiz * 2, "format_tree"); \
-               ofre += osiz; \
-               osiz *= 2; \
-               obufout = obuf + olen; \
-       } \
-       *obufout++ = *s; \
-       --ofre; \
-}
-
-/* Is there space for something L big in the buffer? */
-#define chksize(l)  if ((l) >= ofre) { \
-       size_t olen = obufout - obuf; \
-       size_t delta = osiz+l-ofre; \
-       erealloc(obuf, char *, osiz + delta, "format_tree"); \
-       obufout = obuf + olen; \
-       ofre += delta; \
-       osiz += delta; \
-}
-
-       size_t cur_arg = 0;
-       NODE *r = NULL;
-       int i, nc;
-       bool toofew = false;
-       char *obuf, *obufout;
-       size_t osiz, ofre;
-       const char *chbuf;
-       const char *s0, *s1;
-       int cs1;
-       NODE *arg;
-       long fw, prec, argnum;
-       bool used_dollar;
-       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
-       long *cur = NULL;
-       uintmax_t uval;
-       bool sgn;
-       int base;
-       /*
-        * Although this is an array, the elements serve two different
-        * purposes. The first element is the general buffer meant
-        * to hold the entire result string.  The second one is a
-        * temporary buffer for large floating point values. They
-        * could just as easily be separate variables, and the
-        * code might arguably be clearer.
-        */
-       struct {
-               char *buf;
-               size_t bufsize;
-               char stackbuf[30];
-       } cpbufs[2];
-#define cpbuf  cpbufs[0].buf
-       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
-       char *cp;
-       const char *fill;
-       AWKNUM tmpval = 0.0;
-       char signchar = '\0';
-       size_t len;
-       bool zero_flag = false;
-       bool quote_flag = false;
-       int ii, jj;
-       char *chp;
-       size_t copy_count, char_count;
-#ifdef HAVE_MPFR
-       mpz_ptr zi;
-       mpfr_ptr mf;
-#endif
-       enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type;
-
-       static const char sp[] = " ";
-       static const char zero_string[] = "0";
-       static const char lchbuf[] = "0123456789abcdef";
-       static const char Uchbuf[] = "0123456789ABCDEF";
-
-#define INITIAL_OUT_SIZE       512
-       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
-       obufout = obuf;
-       osiz = INITIAL_OUT_SIZE;
-       ofre = osiz - 2;
-
-       cur_arg = 1;
-
-       {
-               size_t k;
-               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
-                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
-                       cpbufs[k].buf = cpbufs[k].stackbuf;
-               }
-       }
-
-       /*
-        * The point of this goop is to grow the buffer
-        * holding the converted number, so that large
-        * values don't overflow a fixed length buffer.
-        */
-#define PREPEND(CH) do {       \
-       if (cp == cpbufs[0].buf) {      \
-               char *prev = cpbufs[0].buf;     \
-               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
-                       "format_tree"); \
-               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
-                      cpbufs[0].bufsize);      \
-               cpbufs[0].bufsize *= 2; \
-               if (prev != cpbufs[0].stackbuf) \
-                       efree(prev);    \
-               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
-       }       \
-       *--cp = (CH);   \
-} while(0)
-
-       /*
-        * Check first for use of `count$'.
-        * If plain argument retrieval was used earlier, choke.
-        *      Otherwise, return the requested argument.
-        * If not `count$' now, but it was used earlier, choke.
-        * If this format is more than total number of args, choke.
-        * Otherwise, return the current argument.
-        */
-#define parse_next_arg() { \
-       if (argnum > 0) { \
-               if (cur_arg > 1) { \
-                       msg(_("fatal: must use `count$' on all formats or 
none")); \
-                       goto out; \
-               } \
-               arg = the_args[argnum]; \
-       } else if (used_dollar) { \
-               msg(_("fatal: must use `count$' on all formats or none")); \
-               arg = 0; /* shutup the compiler */ \
-               goto out; \
-       } else if (cur_arg >= num_args) { \
-               arg = 0; /* shutup the compiler */ \
-               toofew = true; \
-               break; \
-       } else { \
-               arg = the_args[cur_arg]; \
-               cur_arg++; \
-       } \
-}
-
-       need_format = false;
-       used_dollar = false;
-
-       s0 = s1 = fmt_string;
-       while (n0-- > 0) {
-               if (*s1 != '%') {
-                       s1++;
-                       continue;
-               }
-               need_format = true;
-               bchunk(s0, s1 - s0);
-               s0 = s1;
-               cur = &fw;
-               fw = 0;
-               prec = 0;
-               base = 0;
-               argnum = 0;
-               base = 0;
-               have_prec = false;
-               signchar = '\0';
-               zero_flag = false;
-               quote_flag = false;
-#ifdef HAVE_MPFR
-               mf = NULL;
-               zi = NULL;
-#endif
-               fmt_type = 0;
-
-               lj = alt = big_flag = bigbig_flag = small_flag = false;
-               fill = sp;
-               cp = cend;
-               chbuf = lchbuf;
-               s1++;
-
-retry:
-               if (n0-- == 0)  /* ran out early! */
-                       break;
-
-               switch (cs1 = *s1++) {
-               case (-1):      /* dummy case to allow for checking */
-check_pos:
-                       if (cur != &fw)
-                               break;          /* reject as a valid format */
-                       goto retry;
-               case '%':
-                       need_format = false;
-                       /*
-                        * 29 Oct. 2002:
-                        * The C99 standard pages 274 and 279 seem to imply that
-                        * since there's no arg converted, the field width 
doesn't
-                        * apply.  The code already was that way, but this
-                        * comment documents it, at least in the code.
-                        */
-                       if (do_lint) {
-                               const char *msg = NULL;
-
-                               if (fw && ! have_prec)
-                                       msg = _("field width is ignored for 
`%%' specifier");
-                               else if (fw == 0 && have_prec)
-                                       msg = _("precision is ignored for `%%' 
specifier");
-                               else if (fw && have_prec)
-                                       msg = _("field width and precision are 
ignored for `%%' specifier");
-
-                               if (msg != NULL)
-                                       lintwarn("%s", msg);
-                       }
-                       bchunk_one("%");
-                       s0 = s1;
-                       break;
-
-               case '0':
-                       /*
-                        * Only turn on zero_flag if we haven't seen
-                        * the field width or precision yet.  Otherwise,
-                        * screws up floating point formatting.
-                        */
-                       if (cur == & fw)
-                               zero_flag = true;
-                       if (lj)
-                               goto retry;
-                       /* FALL through */
-               case '1':
-               case '2':
-               case '3':
-               case '4':
-               case '5':
-               case '6':
-               case '7':
-               case '8':
-               case '9':
-                       if (cur == NULL)
-                               break;
-                       if (prec >= 0)
-                               *cur = cs1 - '0';
-                       /*
-                        * with a negative precision *cur is already set
-                        * to -1, so it will remain negative, but we have
-                        * to "eat" precision digits in any case
-                        */
-                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
-                               --n0;
-                               *cur = *cur * 10 + *s1++ - '0';
-                       }
-                       if (prec < 0)   /* negative precision is discarded */
-                               have_prec = false;
-                       if (cur == &prec)
-                               cur = NULL;
-                       if (n0 == 0)    /* badly formatted control string */
-                               continue;
-                       goto retry;
-               case '$':
-                       if (do_traditional) {
-                               msg(_("fatal: `$' is not permitted in awk 
formats"));
-                               goto out;
-                       }
-
-                       if (cur == &fw) {
-                               argnum = fw;
-                               fw = 0;
-                               used_dollar = true;
-                               if (argnum <= 0) {
-                                       msg(_("fatal: arg count with `$' must 
be > 0"));
-                                       goto out;
-                               }
-                               if (argnum >= num_args) {
-                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
-                                       goto out;
-                               }
-                       } else {
-                               msg(_("fatal: `$' not permitted after period in 
format"));
-                               goto out;
-                       }
-
-                       goto retry;
-               case '*':
-                       if (cur == NULL)
-                               break;
-                       if (! do_traditional && isdigit((unsigned char) *s1)) {
-                               int val = 0;
-
-                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
-                                       val *= 10;
-                                       val += *s1 - '0';
-                               }
-                               if (*s1 != '$') {
-                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
-                                       goto out;
-                               } else {
-                                       s1++;
-                                       n0--;
-                               }
-                               if (val >= num_args) {
-                                       toofew = true;
-                                       break;
-                               }
-                               arg = the_args[val];
-                       } else {
-                               parse_next_arg();
-                       }
-                       (void) force_number(arg);
-                       *cur = get_number_si(arg);
-                       if (*cur < 0 && cur == &fw) {
-                               *cur = -*cur;
-                               lj++;
-                       }
-                       if (cur == &prec) {
-                               if (*cur >= 0)
-                                       have_prec = true;
-                               else
-                                       have_prec = false;
-                               cur = NULL;
-                       }
-                       goto retry;
-               case ' ':               /* print ' ' or '-' */
-                                       /* 'space' flag is ignored */
-                                       /* if '+' already present  */
-                       if (signchar != false) 
-                               goto check_pos;
-                       /* FALL THROUGH */
-               case '+':               /* print '+' or '-' */
-                       signchar = cs1;
-                       goto check_pos;
-               case '-':
-                       if (prec < 0)
-                               break;
-                       if (cur == &prec) {
-                               prec = -1;
-                               goto retry;
-                       }
-                       fill = sp;      /* if left justified then other */
-                       lj++;           /* filling is ignored */
-                       goto check_pos;
-               case '.':
-                       if (cur != &fw)
-                               break;
-                       cur = &prec;
-                       have_prec = true;
-                       goto retry;
-               case '#':
-                       alt = true;
-                       goto check_pos;
-               case '\'':
-#if defined(HAVE_LOCALE_H)       
-                       /* allow quote_flag if there is a thousands separator. 
*/
-                       if (loc.thousands_sep[0] != '\0')
-                               quote_flag = true;
-                       goto check_pos;
-#else
-                       goto retry;  
-#endif
-               case 'l':
-                       if (big_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       big_flag = true;
-                       goto retry;
-               case 'L':
-                       if (bigbig_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       bigbig_flag = true;
-                       goto retry;
-               case 'h':
-                       if (small_flag)
-                               break;
-                       else {
-                               static bool warned = false;
-                               
-                               if (do_lint && ! warned) {
-                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
-                                       warned = true;
-                               }
-                               if (do_posix) {
-                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
-                                       goto out;
-                               }
-                       }
-                       small_flag = true;
-                       goto retry;
-               case 'c':
-                       need_format = false;
-                       parse_next_arg();
-                       /* user input that looks numeric is numeric */
-                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
-                               (void) force_number(arg);
-                       if ((arg->flags & NUMBER) != 0) {
-                               uval = get_number_uj(arg);
-#if MBS_SUPPORT
-                               if (gawk_mb_cur_max > 1) {
-                                       char buf[100];
-                                       wchar_t wc;
-                                       mbstate_t mbs;
-                                       size_t count;
-
-                                       memset(& mbs, 0, sizeof(mbs));
-                                       wc = uval;
-
-                                       count = wcrtomb(buf, wc, & mbs);
-                                       if (count == 0
-                                           || count == (size_t)-1
-                                           || count == (size_t)-2)
-                                               goto out0;
-
-                                       memcpy(cpbuf, buf, count);
-                                       prec = count;
-                                       cp = cpbuf;
-                                       goto pr_tail;
-                               }
-out0:
-                               ;
-                               /* else,
-                                       fall through */
-#endif
-                               if (do_lint && uval > 255) {
-                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
-                                                       arg->numbr);
-                               }
-                               cpbuf[0] = uval;
-                               prec = 1;
-                               cp = cpbuf;
-                               goto pr_tail;
-                       }
-                       /*
-                        * As per POSIX, only output first character of a
-                        * string value.  Thus, we ignore any provided
-                        * precision, forcing it to 1.  (Didn't this
-                        * used to work? 6/2003.)
-                        */
-                       cp = arg->stptr;
-#if MBS_SUPPORT
-                       /*
-                        * First character can be multiple bytes if
-                        * it's a multibyte character. Grr.
-                        */
-                       if (gawk_mb_cur_max > 1) {
-                               mbstate_t state;
-                               size_t count;
-
-                               memset(& state, 0, sizeof(state));
-                               count = mbrlen(cp, arg->stlen, & state);
-                               if (count == 0
-                                   || count == (size_t)-1
-                                   || count == (size_t)-2)
-                                       goto out2;
-                               prec = count;
-                               goto pr_tail;
-                       }
-out2:
-                       ;
-#endif
-                       prec = 1;
-                       goto pr_tail;
-               case 's':
-                       need_format = false;
-                       parse_next_arg();
-                       arg = force_string(arg);
-                       if (fw == 0 && ! have_prec)
-                               prec = arg->stlen;
-                       else {
-                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
-                               if (! have_prec || prec > char_count)
-                                       prec = char_count;
-                       }
-                       cp = arg->stptr;
-                       goto pr_tail;
-               case 'd':
-               case 'i':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-#ifdef HAVE_MPFR
-                       if (is_mpg_float(arg))
-                               goto mpf0;
-                       else if (is_mpg_integer(arg))
-                               goto mpz0;
-                       else
-#endif
-                       tmpval = arg->numbr;
-
-                       /*
-                        * Check for Nan or Inf.
-                        */
-                       if (isnan(tmpval) || isinf(tmpval))
-                               goto out_of_range;
-                       else
-                               tmpval = double_to_int(tmpval);
-
-                       /*
-                        * ``The result of converting a zero value with a
-                        * precision of zero is no characters.''
-                        */
-                       if (have_prec && prec == 0 && tmpval == 0)
-                               goto pr_tail;
-
-                       if (tmpval < 0) {
-                               tmpval = -tmpval;
-                               sgn = true;
-                       } else {
-                               if (tmpval == -0.0)
-                                       /* avoid printing -0 */
-                                       tmpval = 0.0;
-                               sgn = false;
-                       }
-                       /*
-                        * Use snprintf return value to tell if there
-                        * is enough room in the buffer or not.
-                        */
-                       while ((i = snprintf(cpbufs[1].buf,
-                                            cpbufs[1].bufsize, "%.0f",
-                                            tmpval)) >=
-                              cpbufs[1].bufsize) {
-                               if (cpbufs[1].buf == cpbufs[1].stackbuf)
-                                       cpbufs[1].buf = NULL;
-                               if (i > 0) {
-                                       cpbufs[1].bufsize += ((i > 
cpbufs[1].bufsize) ?
-                                                             i : 
cpbufs[1].bufsize);
-                               }
-                               else
-                                       cpbufs[1].bufsize *= 2;
-                               assert(cpbufs[1].bufsize > 0);
-                               erealloc(cpbufs[1].buf, char *,
-                                        cpbufs[1].bufsize, "format_tree");
-                       }
-                       if (i < 1)
-                               goto out_of_range;
-                       chp = &cpbufs[1].buf[i-1];
-                       ii = jj = 0;
-                       do {
-                               PREPEND(*chp);
-                               chp--; i--;
-#if defined(HAVE_LOCALE_H)
-                               if (quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
-                                       if (i)  /* only add if more digits 
coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX - assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)
-                                               jj = 0;         /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == CHAR_MAX)
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
-                                       }
-                               }
-#endif
-                       } while (i > 0);
-
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
-
-                       if (sgn)
-                               PREPEND('-');
-                       else if (signchar)
-                               PREPEND(signchar);
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-                       if (fw > prec && ! lj && fill != sp
-                           && (*cp == '-' || signchar)) {
-                               bchunk_one(cp);
-                               cp++;
-                               prec--;
-                               fw--;
-                       }
-                       goto pr_tail;
-               case 'X':
-                       chbuf = Uchbuf; /* FALL THROUGH */
-               case 'x':
-                       base += 6;      /* FALL THROUGH */
-               case 'u':
-                       base += 2;      /* FALL THROUGH */
-               case 'o':
-                       base += 8;
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-#ifdef HAVE_MPFR
-                       if (is_mpg_integer(arg)) {
-mpz0:
-                               zi = arg->mpg_i;
-
-                               if (cs1 != 'd' && cs1 != 'i') {
-                                       if (mpz_sgn(zi) <= 0) {
-                                               /*
-                                                * Negative value or 0 requires 
special handling.
-                                                * Unlike MPFR, GMP does not 
allow conversion
-                                                * to (u)intmax_t. So we first 
convert GMP type to
-                                                * a MPFR type.
-                                                */
-                                               mf = mpz2mpfr(zi);
-                                               goto mpf1;
-                                       }
-                                       signchar = '\0';        /* Don't print 
'+' */
-                               }
-
-                               /* See comments above about when to fill with 
zeros */
-                               zero_flag = (! lj
-                                                   && ((zero_flag && ! 
have_prec)
-                                                        || (fw == 0 && 
have_prec)));
-
-                               fmt_type = have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
-                               goto fmt0;
-
-                       } else if (is_mpg_float(arg)) {
-mpf0:
-                               mf = arg->mpg_numbr;
-                               if (! mpfr_number_p(mf)) {
-                                       /* inf or NaN */
-                                       cs1 = 'g';
-                                       fmt_type = MP_FLOAT;
-                                       goto fmt1;
-                               }
-
-                               if (cs1 != 'd' && cs1 != 'i') {
-mpf1:
-                                       /*
-                                        * The output of printf("%#.0x", 0) is 
0 instead of 0x, hence <= in
-                                        * the comparison below.
-                                        */
-                                       if (mpfr_sgn(mf) <= 0) {
-                                               if (! mpfr_fits_intmax_p(mf, 
ROUND_MODE)) {
-                                                       /* -ve number is too 
large */
-                                                       cs1 = 'g';
-                                                       fmt_type = MP_FLOAT;
-                                                       goto fmt1;
-                                               }
-
-                                               tmpval = uval = (uintmax_t) 
mpfr_get_sj(mf, ROUND_MODE);
-                                               if (! alt && have_prec && prec 
== 0 && tmpval == 0)
-                                                       goto pr_tail;   /* 
printf("%.0x", 0) is no characters */
-                                               goto int0;
-                                       }
-                                       signchar = '\0';        /* Don't print 
'+' */
-                               }
-
-                               /* See comments above about when to fill with 
zeros */
-                               zero_flag = (! lj
-                                                   && ((zero_flag && ! 
have_prec)
-                                                        || (fw == 0 && 
have_prec)));
-                               
-                               (void) mpfr_get_z(mpzval, mf, MPFR_RNDZ);       
/* convert to GMP integer */
-                               fmt_type = have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
-                               zi = mpzval;
-                               goto fmt0;
-                       } else
-#endif
-                               tmpval = arg->numbr;
-
-                       /*
-                        * ``The result of converting a zero value with a
-                        * precision of zero is no characters.''
-                        *
-                        * If I remember the ANSI C standard, though,
-                        * it says that for octal conversions
-                        * the precision is artificially increased
-                        * to add an extra 0 if # is supplied.
-                        * Indeed, in C,
-                        *      printf("%#.0o\n", 0);
-                        * prints a single 0.
-                        */
-                       if (! alt && have_prec && prec == 0 && tmpval == 0)
-                               goto pr_tail;
-
-                       if (tmpval < 0) {
-                               uval = (uintmax_t) (intmax_t) tmpval;
-                               if ((AWKNUM)(intmax_t)uval != 
double_to_int(tmpval))
-                                       goto out_of_range;
-                       } else {
-                               uval = (uintmax_t) tmpval;
-                               if ((AWKNUM)uval != double_to_int(tmpval))
-                                       goto out_of_range;
-                       }
-#ifdef HAVE_MPFR
-       int0:
-#endif
-                       /*
-                        * When to fill with zeroes is of course not simple.
-                        * First: No zero fill if left-justifying.
-                        * Next: There seem to be two cases:
-                        *      A '0' without a precision, e.g. %06d
-                        *      A precision with no field width, e.g. %.10d
-                        * Any other case, we don't want to fill with zeroes.
-                        */
-                       if (! lj
-                           && ((zero_flag && ! have_prec)
-                                || (fw == 0 && have_prec)))
-                               fill = zero_string;
-                       ii = jj = 0;
-                       do {
-                               PREPEND(chbuf[uval % base]);
-                               uval /= base;
-#if defined(HAVE_LOCALE_H)
-                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
-                                       if (uval)       /* only add if more 
digits coming */
-                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
-                                       if (loc.grouping[ii+1] == 0)            
                              
-                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
-                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
-                                               quote_flag = false;
-                                       else {                 
-                                               ii++;
-                                               jj = 0;
-                                       }
-                               }
-#endif
-                       } while (uval > 0);
-
-                       /* add more output digits to match the precision */
-                       if (have_prec) {
-                               while (cend - cp < prec)
-                                       PREPEND('0');
-                       }
-
-                       if (alt && tmpval != 0) {
-                               if (base == 16) {
-                                       PREPEND(cs1);
-                                       PREPEND('0');
-                                       if (fill != sp) {
-                                               bchunk(cp, 2);
-                                               cp += 2;
-                                               fw -= 2;
-                                       }
-                               } else if (base == 8)
-                                       PREPEND('0');
-                       }
-                       base = 0;
-                       if (prec > fw)
-                               fw = prec;
-                       prec = cend - cp;
-       pr_tail:
-                       if (! lj) {
-                               while (fw > prec) {
-                                       bchunk_one(fill);
-                                       fw--;
-                               }
-                       }
-                       copy_count = prec;
-                       if (fw == 0 && ! have_prec)
-                               ;
-                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
-                               assert(cp == arg->stptr || cp == cpbuf);
-                               copy_count = mbc_byte_count(arg->stptr, prec);
-                       }
-                       bchunk(cp, copy_count);
-                       while (fw > prec) {
-                               bchunk_one(fill);
-                               fw--;
-                       }
-                       s0 = s1;
-                       break;
-
-     out_of_range:
-                       /* out of range - emergency use of %g format */
-                       if (do_lint)
-                               lintwarn(_("[s]printf: value %g is out of range 
for `%%%c' format"),
-                                                       (double) tmpval, cs1);
-                       cs1 = 'g';
-                       goto fmt1;
-
-               case 'F':
-#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
-                       cs1 = 'f';
-                       /* FALL THROUGH */
-#endif
-               case 'g':
-               case 'G':
-               case 'e':
-               case 'f':
-               case 'E':
-                       need_format = false;
-                       parse_next_arg();
-                       (void) force_number(arg);
-
-                       if (! is_mpg_number(arg))
-                               tmpval = arg->numbr;
-#ifdef HAVE_MPFR
-                       else if (is_mpg_float(arg)) {
-                               mf = arg->mpg_numbr;
-                               fmt_type = MP_FLOAT;
-                       } else {
-                               /* arbitrary-precision integer, convert to MPFR 
float */
-                               assert(mf == NULL);
-                               mf = mpz2mpfr(arg->mpg_i);
-                               fmt_type = MP_FLOAT;
-                       }
-#endif
-     fmt1:
-                       if (! have_prec)
-                               prec = DEFAULT_G_PRECISION;
-#ifdef HAVE_MPFR
-     fmt0:
-#endif
-                       chksize(fw + prec + 11);        /* 11 == slop */
-                       cp = cpbuf;
-                       *cp++ = '%';
-                       if (lj)
-                               *cp++ = '-';
-                       if (signchar)
-                               *cp++ = signchar;
-                       if (alt)
-                               *cp++ = '#';
-                       if (zero_flag)
-                               *cp++ = '0';
-                       if (quote_flag)
-                               *cp++ = '\'';
-
-#if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "");
-#endif
-
-                       switch (fmt_type) {
-#ifdef HAVE_MPFR
-                       case MP_INT_WITH_PREC:
-                               sprintf(cp, "*.*Z%c", cs1);
-                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, (int) prec, zi)) >= ofre)
-                                       chksize(nc)
-                               break;
-                       case MP_INT_WITHOUT_PREC:
-                               sprintf(cp, "*Z%c", cs1);
-                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, zi)) >= ofre)
-                                       chksize(nc)
-                               break;
-                       case MP_FLOAT:
-                               sprintf(cp, "*.*R*%c", cs1);
-                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, (int) prec, ROUND_MODE, 
mf)) >= ofre)
-                                       chksize(nc)
-                               break;
-#endif
-                       default:
-                               sprintf(cp, "*.*%c", cs1);
-                               while ((nc = snprintf(obufout, ofre, cpbuf,
-                                            (int) fw, (int) prec,
-                                            (double) tmpval)) >= ofre)
-                                       chksize(nc)
-                       }
-
-#if defined(LC_NUMERIC)
-                       if (quote_flag && ! use_lc_numeric)
-                               setlocale(LC_NUMERIC, "C");
-#endif
-
-                       len = strlen(obufout);
-                       ofre -= len;
-                       obufout += len;
-                       s0 = s1;
-                       break;
-               default:
-                       if (do_lint && isalpha(cs1))
-                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
-                       break;
-               }
-               if (toofew) {
-                       msg("%s\n\t`%s'\n\t%*s%s",
-                             _("fatal: not enough arguments to satisfy format 
string"),
-                             fmt_string, (int) (s1 - fmt_string - 1), "",
-                             _("^ ran out for this one"));
-                       goto out;
-               }
-       }
-       if (do_lint) {
-               if (need_format)
-                       lintwarn(
-                       _("[s]printf: format specifier does not have control 
letter"));
-               if (cur_arg < num_args)
-                       lintwarn(
-                       _("too many arguments supplied for format string"));
-       }
-       bchunk(s0, s1 - s0);
-       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
-       obuf = NULL;
-out:
-       {
-               size_t k;
-               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
-               for (k = 0; k < count; k++) {
-                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
-                               efree(cpbufs[k].buf);
-               }
-               if (obuf != NULL)
-                       efree(obuf);
-       }
-
-       if (r == NULL)
-               gawk_exit(EXIT_FATAL);
-       return r;
-}
-
 
 /* printf_common --- common code for sprintf and printf */
 
@@ -1668,45 +588,25 @@ do_printf(int nargs, int redirtype)
                gawk_exit(EXIT_FATAL);
 }
 
-/* do_sqrt --- do the sqrt function */
-
-NODE *
-do_sqrt(int nargs)
-{
-       NODE *tmp;
-       double arg;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("sqrt: received non-numeric argument"));
-       arg = (double) force_number(tmp)->numbr;
-       DEREF(tmp);
-       if (arg < 0.0)
-               warning(_("sqrt: called with negative argument %g"), arg);
-       return make_number((AWKNUM) sqrt(arg));
-}
-
 /* do_substr --- do the substr function */
 
 NODE *
 do_substr(int nargs)
 {
-       NODE *t1;
-       NODE *r;
+       NODE *t1, *t2, *t3 = NULL;
+       NODE *r = NULL;
        size_t indx;
        size_t length = 0;
        double d_index = 0, d_length = 0;
        size_t src_len;
 
        if (nargs == 3) {
-               t1 = POP_NUMBER();
-               d_length = get_number_d(t1);
-               DEREF(t1);
+               t3 = POP_NUMBER();
+               d_length = get_number_d(t3);
        }
 
-       t1 = POP_NUMBER();
-       d_index = get_number_d(t1);
-       DEREF(t1);
+       t2 = POP_NUMBER();
+       d_index = get_number_d(t2);
 
        t1 = POP_STRING();
 
@@ -1716,11 +616,11 @@ do_substr(int nargs)
                                lintwarn(_("substr: length %g is not >= 1"), 
d_length);
                        else if (do_lint == DO_LINT_INVALID && ! (d_length >= 
0))
                                lintwarn(_("substr: length %g is not >= 0"), 
d_length);
-                       DEREF(t1);
-                       return dupnode(Nnull_string);
+                       r = dupnode(Nnull_string);
+                       goto finish;
                }
                if (do_lint) {
-                       if (double_to_int(d_length) != d_length)
+                       if (! isinteger(t3))
                                lintwarn(
                        _("substr: non-integer length %g will be truncated"),
                                        d_length);
@@ -1743,7 +643,7 @@ do_substr(int nargs)
                                 d_index);
                d_index = 1;
        }
-       if (do_lint && double_to_int(d_index) != d_index)
+       if (do_lint && ! isinteger(t2))
                lintwarn(_("substr: non-integer start index %g will be 
truncated"),
                         d_index);
 
@@ -1770,8 +670,8 @@ do_substr(int nargs)
                /* substr("", 1, 0) produces a warning only if LINT_ALL */
                if (do_lint && (do_lint == DO_LINT_ALL || ((indx | length) != 
0)))
                        lintwarn(_("substr: source string is zero length"));
-               DEREF(t1);
-               return dupnode(Nnull_string);
+               r = dupnode(Nnull_string);
+               goto finish;
        }
 
        /* get total len of input string, for following checks */
@@ -1787,8 +687,8 @@ do_substr(int nargs)
                if (do_lint)
                        lintwarn(_("substr: start index %g is past end of 
string"),
                                d_index);
-               DEREF(t1);
-               return dupnode(Nnull_string);
+               r = dupnode(Nnull_string);
+               goto finish;
        }
        if (length > src_len - indx) {
                if (do_lint)
@@ -1832,6 +732,10 @@ do_substr(int nargs)
        r = make_string(t1->stptr + indx, length);
 #endif
 
+finish:
+       if (t3 != NULL)
+               DEREF(t3);
+       DEREF(t2);
        DEREF(t1);
        return r;
 }
@@ -2295,113 +1199,6 @@ do_toupper(int nargs)
        return t2;
 }
 
-/* do_atan2 --- do the atan2 function */
-
-NODE *
-do_atan2(int nargs)
-{
-       NODE *t1, *t2;
-       double d1, d2;
-
-       POP_TWO_SCALARS(t1, t2);
-       if (do_lint) {
-               if ((t1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("atan2: received non-numeric first 
argument"));
-               if ((t2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("atan2: received non-numeric second 
argument"));
-       }
-       d1 = force_number(t1)->numbr;
-       d2 = force_number(t2)->numbr;
-       DEREF(t1);
-       DEREF(t2);
-       return make_number((AWKNUM) atan2(d1, d2));
-}
-
-/* do_sin --- do the sin function */
-
-NODE *
-do_sin(int nargs)
-{
-       NODE *tmp;
-       double d;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("sin: received non-numeric argument"));
-       d = sin((double) force_number(tmp)->numbr);
-       DEREF(tmp);
-       return make_number((AWKNUM) d);
-}
-
-/* do_cos --- do the cos function */
-
-NODE *
-do_cos(int nargs)
-{
-       NODE *tmp;
-       double d;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("cos: received non-numeric argument"));
-       d = cos((double) force_number(tmp)->numbr);
-       DEREF(tmp);
-       return make_number((AWKNUM) d);
-}
-
-/* do_rand --- do the rand function */
-
-static bool firstrand = true;
-/* Some systems require this array to be integer aligned. Sigh. */
-#define SIZEOF_STATE 256
-static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
-static char *const state = (char *const) istate;
-
-/* ARGSUSED */
-NODE *
-do_rand(int nargs ATTRIBUTE_UNUSED)
-{
-       if (firstrand) {
-               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
-               /* don't need to srandom(1), initstate() does it for us. */
-               firstrand = false;
-               setstate(state);
-       }
-       /*
-        * Per historical practice and POSIX, return value N is
-        *
-        *      0 <= n < 1
-        */
-       return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / 
GAWK_RANDOM_MAX);
-}
-
-/* do_srand --- seed the random number generator */
-
-NODE *
-do_srand(int nargs)
-{
-       NODE *tmp;
-       static long save_seed = 1;
-       long ret = save_seed;   /* SVR4 awk srand returns previous seed */
-
-       if (firstrand) {
-               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
-               /* don't need to srandom(1), we're changing the seed below */
-               firstrand = false;
-               (void) setstate(state);
-       }
-
-       if (nargs == 0)
-               srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
-       else {
-               tmp = POP_SCALAR();
-               if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("srand: received non-numeric argument"));
-               srandom((unsigned int) (save_seed = (long) 
force_number(tmp)->numbr));
-               DEREF(tmp);
-       }
-       return make_number((AWKNUM) ret);
-}
 
 /* do_match --- match a regexp, set RSTART and RLENGTH,
  *     optional third arg is array filled with text of
@@ -2970,316 +1767,6 @@ done:
 }
 
 
-/* make_integer - Convert an integer to a number node.  */
-
-static NODE *
-make_integer(uintmax_t n)
-{
-       n = adjust_uint(n);
-
-       return make_number((AWKNUM) n);
-}
-
-/* do_lshift --- perform a << operation */
-
-NODE *
-do_lshift(int nargs)
-{
-       NODE *s1, *s2;
-       uintmax_t uval, ushift, res;
-       AWKNUM val, shift;
-
-       POP_TWO_SCALARS(s1, s2);
-       if (do_lint) {
-               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("lshift: received non-numeric first 
argument"));
-               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("lshift: received non-numeric second 
argument"));
-       }
-       val = force_number(s1)->numbr;
-       shift = force_number(s2)->numbr;
-       if (do_lint) {
-               if (val < 0 || shift < 0)
-                       lintwarn(_("lshift(%f, %f): negative values will give 
strange results"), val, shift);
-               if (double_to_int(val) != val || double_to_int(shift) != shift)
-                       lintwarn(_("lshift(%f, %f): fractional values will be 
truncated"), val, shift);
-               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
-                       lintwarn(_("lshift(%f, %f): too large shift value will 
give strange results"), val, shift);
-       }
-
-       DEREF(s1);
-       DEREF(s2);
-
-       uval = (uintmax_t) val;
-       ushift = (uintmax_t) shift;
-
-       res = uval << ushift;
-       return make_integer(res);
-}
-
-/* do_rshift --- perform a >> operation */
-
-NODE *
-do_rshift(int nargs)
-{
-       NODE *s1, *s2;
-       uintmax_t uval, ushift, res;
-       AWKNUM val, shift;
-
-       POP_TWO_SCALARS(s1, s2);
-       if (do_lint) {
-               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("rshift: received non-numeric first 
argument"));
-               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("rshift: received non-numeric second 
argument"));
-       }
-       val = force_number(s1)->numbr;
-       shift = force_number(s2)->numbr;
-       if (do_lint) {
-               if (val < 0 || shift < 0)
-                       lintwarn(_("rshift(%f, %f): negative values will give 
strange results"), val, shift);
-               if (double_to_int(val) != val || double_to_int(shift) != shift)
-                       lintwarn(_("rshift(%f, %f): fractional values will be 
truncated"), val, shift);
-               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
-                       lintwarn(_("rshift(%f, %f): too large shift value will 
give strange results"), val, shift);
-       }
-
-       DEREF(s1);
-       DEREF(s2);
-
-       uval = (uintmax_t) val;
-       ushift = (uintmax_t) shift;
-
-       res = uval >> ushift;
-       return make_integer(res);
-}
-
-/* do_and --- perform an & operation */
-
-NODE *
-do_and(int nargs)
-{
-       NODE *s1;
-       uintmax_t res, uval;
-       AWKNUM val;
-       int i;
-
-       res = ~0;       /* start off with all ones */
-       if (nargs < 2)
-               fatal(_("and: called with less than two arguments"));
-
-       for (i = 1; nargs > 0; nargs--, i++) {
-               s1 = POP_SCALAR();
-               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("and: argument %d is non-numeric"), i);
-
-               val = force_number(s1)->numbr;
-               if (do_lint && val < 0)
-                       lintwarn(_("and: argument %d negative value %g will 
give strange results"), i, val);
-
-               uval = (uintmax_t) val;
-               res &= uval;
-
-               DEREF(s1);
-       }
-
-       return make_integer(res);
-}
-
-/* do_or --- perform an | operation */
-
-NODE *
-do_or(int nargs)
-{
-       NODE *s1;
-       uintmax_t res, uval;
-       AWKNUM val;
-       int i;
-
-       res = 0;
-       if (nargs < 2)
-               fatal(_("or: called with less than two arguments"));
-
-       for (i = 1; nargs > 0; nargs--, i++) {
-               s1 = POP_SCALAR();
-               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("or: argument %d is non-numeric"), i);
-
-               val = force_number(s1)->numbr;
-               if (do_lint && val < 0)
-                       lintwarn(_("or: argument %d negative value %g will give 
strange results"), i, val);
-
-               uval = (uintmax_t) val;
-               res |= uval;
-
-               DEREF(s1);
-       }
-
-       return make_integer(res);
-}
-
-/* do_xor --- perform an ^ operation */
-
-NODE *
-do_xor(int nargs)
-{
-       NODE *s1;
-       uintmax_t res, uval;
-       AWKNUM val;
-       int i;
-
-       if (nargs < 2)
-               fatal(_("xor: called with less than two arguments"));
-
-       res = 0;        /* silence compiler warning */
-       for (i = 1; nargs > 0; nargs--, i++) {
-               s1 = POP_SCALAR();
-               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("xor: argument %d is non-numeric"), i);
-
-               val = force_number(s1)->numbr;
-               if (do_lint && val < 0)
-                       lintwarn(_("xor: argument %d negative value %g will 
give strange results"), i, val);
-
-               uval = (uintmax_t) val;
-               if (i == 1)
-                       res = uval;
-               else
-                       res ^= uval;
-
-               DEREF(s1);
-       }
-
-       return make_integer(res);
-}
-
-/* do_compl --- perform a ~ operation */
-
-NODE *
-do_compl(int nargs)
-{
-       NODE *tmp;
-       double d;
-       uintmax_t uval;
-
-       tmp = POP_SCALAR();
-       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
-               lintwarn(_("compl: received non-numeric argument"));
-       d = force_number(tmp)->numbr;
-       DEREF(tmp);
-
-       if (do_lint) {
-               if (d < 0)
-                       lintwarn(_("compl(%f): negative value will give strange 
results"), d);
-               if (double_to_int(d) != d)
-                       lintwarn(_("compl(%f): fractional value will be 
truncated"), d);
-       }
-
-       uval = (uintmax_t) d;
-       uval = ~ uval;
-       return make_integer(uval);
-}
-
-/* do_strtonum --- the strtonum function */
-
-NODE *
-do_strtonum(int nargs)
-{
-       NODE *tmp;
-       AWKNUM d;
-
-       tmp = POP_SCALAR();
-       if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
-               d = (AWKNUM) force_number(tmp)->numbr;
-       else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
-               d = nondec2awknum(tmp->stptr, tmp->stlen);
-       else
-               d = (AWKNUM) force_number(tmp)->numbr;
-
-       DEREF(tmp);
-       return make_number((AWKNUM) d);
-}
-
-/* nondec2awknum --- convert octal or hex value to double */
-
-/*
- * Because of awk's concatenation rules and the way awk.y:yylex()
- * collects a number, this routine has to be willing to stop on the
- * first invalid character.
- */
-
-AWKNUM
-nondec2awknum(char *str, size_t len)
-{
-       AWKNUM retval = 0.0;
-       char save;
-       short val;
-       char *start = str;
-
-       if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
-               /*
-                * User called strtonum("0x") or some such,
-                * so just quit early.
-                */
-               if (len <= 2)
-                       return (AWKNUM) 0.0;
-
-               for (str += 2, len -= 2; len > 0; len--, str++) {
-                       switch (*str) {
-                       case '0':
-                       case '1':
-                       case '2':
-                       case '3':
-                       case '4':
-                       case '5':
-                       case '6':
-                       case '7':
-                       case '8':
-                       case '9':
-                               val = *str - '0';
-                               break;
-                       case 'a':
-                       case 'b':
-                       case 'c':
-                       case 'd':
-                       case 'e':
-                       case 'f':
-                               val = *str - 'a' + 10;
-                               break;
-                       case 'A':
-                       case 'B':
-                       case 'C':
-                       case 'D':
-                       case 'E':
-                       case 'F':
-                               val = *str - 'A' + 10;
-                               break;
-                       default:
-                               goto done;
-                       }
-                       retval = (retval * 16) + val;
-               }
-       } else if (*str == '0') {
-               for (; len > 0; len--) {
-                       if (! isdigit((unsigned char) *str))
-                               goto done;
-                       else if (*str == '8' || *str == '9') {
-                               str = start;
-                               goto decimal;
-                       }
-                       retval = (retval * 8) + (*str - '0');
-                       str++;
-               }
-       } else {
-decimal:
-               save = str[len];
-               retval = strtod(str, NULL);
-               str[len] = save;
-       }
-done:
-       return retval;
-}
-
 /* do_dcgettext, do_dcngettext --- handle i18n translations */
 
 #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
@@ -3413,7 +1900,6 @@ do_dcngettext(int nargs)
        NODE *tmp, *t1, *t2, *t3;
        char *string1, *string2;
        unsigned long number;
-       AWKNUM d;
        char *the_result;
 
 #if ENABLE_NLS && defined(LC_MESSAGES) && HAVE_DCGETTEXT
@@ -3445,10 +1931,9 @@ do_dcngettext(int nargs)
 #endif
 
        t2 = POP_NUMBER();      /* third argument */
-       d = get_number_d(t2);
+       number = get_number_ui(t2);
        DEREF(t2);
 
-       number = (unsigned long) double_to_int(d);
        t2 = POP_STRING();      /* second argument */
        string2 = t2->stptr;
        t1 = POP_STRING();      /* first argument */
@@ -3512,7 +1997,7 @@ do_bindtextdomain(int nargs)
 
 /* mbc_byte_count --- return number of bytes for corresponding numchars 
multibyte characters */
 
-static size_t
+size_t
 mbc_byte_count(const char *ptr, size_t numchars)
 {
 #if MBS_SUPPORT
@@ -3543,7 +2028,7 @@ mbc_byte_count(const char *ptr, size_t numchars)
 
 /* mbc_char_count --- return number of m.b. chars in string, up to numbytes 
bytes */
 
-static size_t
+size_t
 mbc_char_count(const char *ptr, size_t numbytes)
 {
 #if MBS_SUPPORT
diff --git a/command.c b/command.c
index 0944a9d..6139cf0 100644
--- a/command.c
+++ b/command.c
@@ -2350,7 +2350,7 @@ yyreduce:
                if ((n->flags & NUMBER) == 0)
                        yyerror(_("non-numeric value found, numeric expected"));
                else
-                       negate_num(n);
+                       numbr_hndlr->gawk_negate_number(n);
                (yyval) = (yyvsp[(2) - (2)]);
          }
     break;
@@ -3168,24 +3168,9 @@ err:
        if (isdigit((unsigned char) tokstart[0])) {
                NODE *r = NULL;
 
-               errno = 0;
-#ifdef HAVE_MPFR
-               if (do_mpfr) {
-                       int tval;
-                       r = mpg_float();
-                       tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 
0, ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
-                       if (mpfr_integer_p(r->mpg_numbr)) {
-                               /* integral value, convert to a GMP type. */
-                               NODE *tmp = r;
-                               r = mpg_integer();
-                               mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
-                               unref(tmp);
-                       }                       
-               } else 
-#endif
-                       r = make_number(strtod(tokstart, & lexptr));
-
+               /* XXX: not accepting a hex or octal number, maybe should? */
+  
+               r = str2node(tokstart, & lexptr, 0, false);
                if (errno != 0) {
                        yyerror(strerror(errno));
                        unref(r);
@@ -3383,7 +3368,8 @@ do_help(CMDARG *arg, int cmd)
 }
 
 
-/* next_word --- find the next word in a line to complete 
+/*
+ * next_word --- find the next word in a line to complete 
  *               (word seperation characters are space and tab).
  */
    
@@ -3411,9 +3397,10 @@ next_word(char *p, int len, char **endp)
 
 #ifdef HAVE_LIBREADLINE
 
-/* command_completion --- attempt to complete based on the word number in line;
- *    try to complete on command names if this is the first word; for the next
- *    word(s), the type of completion depends on the command name (first word).
+/*
+ * command_completion --- attempt to complete based on the word number in line;
+ *     try to complete on command names if this is the first word; for the next
+ *     word(s), the type of completion depends on the command name (first 
word).
  */
 
 #ifndef RL_READLINE_VERSION            /* < 4.2a */
diff --git a/command.y b/command.y
index f6c7981..301d4e3 100644
--- a/command.y
+++ b/command.y
@@ -686,7 +686,7 @@ node
                if ((n->flags & NUMBER) == 0)
                        yyerror(_("non-numeric value found, numeric expected"));
                else
-                       negate_num(n);
+                       numbr_hndlr->gawk_negate_number(n);
                $$ = $2;
          }
        ;
@@ -1244,24 +1244,9 @@ err:
        if (isdigit((unsigned char) tokstart[0])) {
                NODE *r = NULL;
 
-               errno = 0;
-#ifdef HAVE_MPFR
-               if (do_mpfr) {
-                       int tval;
-                       r = mpg_float();
-                       tval = mpfr_strtofr(r->mpg_numbr, tokstart, & lexptr, 
0, ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
-                       if (mpfr_integer_p(r->mpg_numbr)) {
-                               /* integral value, convert to a GMP type. */
-                               NODE *tmp = r;
-                               r = mpg_integer();
-                               mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
-                               unref(tmp);
-                       }                       
-               } else 
-#endif
-                       r = make_number(strtod(tokstart, & lexptr));
-
+               /* XXX: not accepting a hex or octal number, maybe should? */
+  
+               r = str2node(tokstart, & lexptr, 0, false);
                if (errno != 0) {
                        yyerror(strerror(errno));
                        unref(r);
@@ -1459,7 +1444,8 @@ do_help(CMDARG *arg, int cmd)
 }
 
 
-/* next_word --- find the next word in a line to complete 
+/*
+ * next_word --- find the next word in a line to complete 
  *               (word seperation characters are space and tab).
  */
    
@@ -1487,9 +1473,10 @@ next_word(char *p, int len, char **endp)
 
 #ifdef HAVE_LIBREADLINE
 
-/* command_completion --- attempt to complete based on the word number in line;
- *    try to complete on command names if this is the first word; for the next
- *    word(s), the type of completion depends on the command name (first word).
+/*
+ * command_completion --- attempt to complete based on the word number in line;
+ *     try to complete on command names if this is the first word; for the next
+ *     word(s), the type of completion depends on the command name (first 
word).
  */
 
 #ifndef RL_READLINE_VERSION            /* < 4.2a */
diff --git a/debug.c b/debug.c
index a69b7e3..e679209 100644
--- a/debug.c
+++ b/debug.c
@@ -3656,27 +3656,13 @@ print_memory(NODE *m, NODE *func, Func_print 
print_func, FILE *fp)
                case Node_val:
                        if (m == Nnull_string)
                                print_func(fp, "Nnull_string");
-                       else if ((m->flags & NUMBER) != 0) {
-#ifdef HAVE_MPFR
-                               if ((m->flags & MPFN) != 0)
-                                       print_func(fp, "%s", mpg_fmt("%R*g", 
ROUND_MODE, m->mpg_numbr));
-                               else if ((m->flags & MPZN) != 0)
-                                       print_func(fp, "%s", mpg_fmt("%Zd", 
m->mpg_i));
-                               else
-#endif
-                                       print_func(fp, "%g", m->numbr);
-                       } else if ((m->flags & STRING) != 0)
+                       else if ((m->flags & NUMBER) != 0)
+                               print_func(fp, "%s", fmt_number("%0.17g", m));
+                       else if ((m->flags & STRING) != 0)
                                pp_string_fp(print_func, fp, m->stptr, 
m->stlen, '"', false);
-                       else if ((m->flags & NUMCUR) != 0) {
-#ifdef HAVE_MPFR
-                               if ((m->flags & MPFN) != 0)
-                                       print_func(fp, "%s", mpg_fmt("%R*g", 
ROUND_MODE, m->mpg_numbr));
-                               else if ((m->flags & MPZN) != 0)
-                                       print_func(fp, "%s", mpg_fmt("%Zd", 
m->mpg_i));
-                               else
-#endif
-                                       print_func(fp, "%g", m->numbr);
-                       } else if ((m->flags & STRCUR) != 0)
+                       else if ((m->flags & NUMCUR) != 0)
+                               print_func(fp, "%s", fmt_number("%0.17g", m));
+                       else if ((m->flags & STRCUR) != 0)
                                pp_string_fp(print_func, fp, m->stptr, 
m->stlen, '"', false);
                        else
                                print_func(fp, "-?-");
@@ -3968,12 +3954,6 @@ print_instruction(INSTRUCTION *pc, Func_print 
print_func, FILE *fp, int in_dump)
        case Op_match_rec:
        case Op_match:
        case Op_nomatch:
-       case Op_plus_i:
-       case Op_minus_i:
-       case Op_times_i:
-       case Op_exp_i:
-       case Op_quotient_i:
-       case Op_mod_i:
        case Op_assign_concat:
                print_memory(pc->memory, func, print_func, fp);
                /* fall through */
diff --git a/double.c b/double.c
new file mode 100644
index 0000000..2c80d82
--- /dev/null
+++ b/double.c
@@ -0,0 +1,2091 @@
+/*
+ * double.c - routines for C double support in gawk.
+ */
+
+/* 
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ * 
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ * 
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ * 
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 
USA
+ */
+
+#include "awk.h"
+#include "math.h"
+#include "random.h"
+#include "floatmagic.h"        /* definition of isnan */
+
+/* Can declare these, since we always use the random shipped with gawk */
+extern char *initstate(unsigned long seed, char *state, long n);
+extern char *setstate(char *state);
+extern long random(void);
+extern void srandom(unsigned long seed);
+
+/*
+ * Since we supply the version of random(), we know what
+ * value to use here.
+ */
+#define GAWK_RANDOM_MAX 0x7fffffffL
+
+extern NODE **fmt_list;          /* declared in eval.c */
+
+static int is_ieee_magic_val(const char *val);
+static AWKNUM get_ieee_magic_val(const char *val);
+static AWKNUM calc_exp(AWKNUM x1, AWKNUM x2);
+
+static NODE *make_awknum(AWKNUM);
+static int cmp_awknums(const NODE *, const NODE *);
+static void negate_awknum(NODE *);
+static NODE *str2awknum(char *, char **, int, bool);
+static NODE *force_awknum(NODE *);
+static NODE *format_awknum_val(const char *, int, NODE *);
+static unsigned long awknum_toulong(const NODE *);
+static long awknum_tolong(const NODE *);
+static AWKNUM awknum_todouble(const NODE *);
+static uintmax_t awknum_touintmax_t(const NODE *);
+static int awknum_sgn(const NODE *);
+static bool awknum_is_integer(const NODE *);
+static NODE *awknum_copy(const NODE *);
+static NODE *format_nodes_awknum(const char *, size_t, NODE **, long);
+static bool awknum_init(bltin_t **);
+static NODE *awknum_add(const NODE *, const NODE *);
+static NODE *awknum_sub(const NODE *, const NODE *);
+static NODE *awknum_mul(const NODE *, const NODE *);
+static NODE *awknum_div(const NODE *, const NODE *);
+static NODE *awknum_mod(const NODE *, const NODE *);
+static NODE *awknum_pow(const NODE *, const NODE *);
+static NODE *awknum_add_long(const NODE *, long);
+static NODE *awknum_update_var(NODE *);
+static void awknum_set_var(const NODE *);
+static long awknum_increment_var(const NODE *, long);
+static void awknum_init_vars(void);
+
+static NODE *do_and(int);
+static NODE *do_atan2(int);
+static NODE *do_compl(int);
+static NODE *do_cos(int);
+static NODE *do_exp(int);
+static NODE *do_int(int);
+static NODE *do_log(int);
+static NODE *do_lshift(int);
+static NODE *do_or(int);
+static NODE *do_rand(int);
+static NODE *do_rshift(int);
+static NODE *do_sin(int);
+static NODE *do_sqrt(int);
+static NODE *do_srand(int);
+static NODE *do_strtonum(int);
+static NODE *do_xor(int);
+
+/* internal functions */
+static double double_to_int(double d);
+
+
+numbr_handler_t awknum_hndlr = {
+       awknum_init,
+       NULL,   /* version_str */
+       NULL,   /* load_procinfo */
+       make_awknum,
+       str2awknum,
+       awknum_copy,
+       NULL,   /* free_awknum --- not needed for AWKNUM */
+       force_awknum,
+       negate_awknum,
+       cmp_awknums,
+       awknum_sgn,
+       awknum_is_integer,
+       format_awknum_val,
+       format_nodes_awknum,
+       awknum_todouble,
+       awknum_tolong,
+       awknum_toulong,
+       awknum_touintmax_t,
+       awknum_add,
+       awknum_sub,
+       awknum_mul,
+       awknum_div,
+       awknum_mod,
+       awknum_pow,
+       awknum_add_long,
+       awknum_update_var,
+       awknum_set_var,
+       awknum_increment_var,
+       awknum_init_vars,
+};
+
+/* awknum_init --- initialization routine */
+
+static bool
+awknum_init(bltin_t **numbr_bltins)
+{
+       static bltin_t awknum_bltins[] = {
+               { "and",        do_and },
+               { "atan2",      do_atan2 },
+               { "compl",      do_compl },
+               { "cos",        do_cos },
+               { "exp",        do_exp },
+               { "int",        do_int },
+               { "log",        do_log },
+               { "lshift",     do_lshift },
+               { "or",         do_or },
+               { "rand",       do_rand },
+               { "rshift",     do_rshift },
+               { "sin",        do_sin },
+               { "sqrt",       do_sqrt },
+               { "srand",      do_srand },
+               { "strtonum",   do_strtonum },
+               { "xor",        do_xor },
+               { NULL, NULL },
+       };
+
+       /* set the numeric value of null string */
+       Nnull_string->numbr = 0.0;
+       Nnull_string->flags |= (NUMCUR|NUMBER);
+
+       /* initialize TRUE and FALSE nodes */
+       false_node = make_awknum(0.0);
+       true_node = make_awknum(1.0);
+       false_node->flags |= NUMINT;
+       true_node->flags |= NUMINT;
+
+       *numbr_bltins = awknum_bltins;
+       return true;
+}
+
+/* awknum_toulong --- conversion to unsigned long */
+
+static unsigned long
+awknum_toulong(const NODE *n)
+{
+       return n->numbr;
+}
+
+/* awknum_tolong --- conversion to long */
+
+static long
+awknum_tolong(const NODE *n)
+{
+       return n->numbr;
+}
+
+/* awknum_todouble --- conversion to AWKNUM */
+
+static AWKNUM
+awknum_todouble(const NODE *n)
+{
+       return n->numbr;
+}
+
+/* awknum_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+awknum_touintmax_t(const NODE *n)
+{
+       return n->numbr;
+}
+
+/* awknum_sgn --- return 1 if number > 0, zero if number == 0, and -1 if 
number < 0 */
+
+static int
+awknum_sgn(const NODE *n)
+{
+       return (n->numbr < 0.0 ? -1 : n->numbr > 0.0);
+}
+
+/* awknum_is_integer --- check if a number is an integer */
+
+static bool
+awknum_is_integer(const NODE *n)
+{
+       if (isnan(n->numbr) || isinf(n->numbr))
+               return false;
+       return double_to_int(n->numbr) == n->numbr;
+}
+
+/* negate_awknum --- negate AWKNUM in NODE */
+
+static void
+negate_awknum(NODE *n)
+{
+       n->numbr = - n->numbr;
+}
+
+/* awknum_add --- add two numbers */
+
+static NODE *
+awknum_add(const NODE *t1, const NODE *t2)
+{
+       return make_awknum(t1->numbr + t2->numbr);
+}
+
+/* awknum_sub --- subtract two numbers */
+
+static NODE *
+awknum_sub(const NODE *t1, const NODE *t2)
+{
+       return make_awknum(t1->numbr - t2->numbr);
+}
+
+/* awknum_mul --- multiply two numbers */
+
+static NODE *
+awknum_mul(const NODE *t1, const NODE *t2)
+{
+       return make_awknum(t1->numbr * t2->numbr);
+}
+
+/* awknum_add --- quotient of two numbers */
+
+static NODE *
+awknum_div(const NODE *t1, const NODE *t2)
+{
+       if (t2->numbr == 0)
+               fatal(_("division by zero attempted"));
+       return make_awknum(t1->numbr / t2->numbr);
+}
+
+/* awknum_add_long --- add long value to a number */
+
+static NODE *
+awknum_add_long(const NODE *t1, long n)
+{
+       return make_awknum(t1->numbr + n);
+}
+
+/* awknum_copy --- copy a number */
+
+static NODE *
+awknum_copy(const NODE *t1)
+{
+       return make_awknum(t1->numbr);
+}
+
+/* awknum_update_var --- update a special variable from internal variables */
+
+static NODE *
+awknum_update_var(NODE *var)
+{
+       NODE *val = var->var_value;
+
+       if (var == NR_node) {
+               if (val->numbr != NR) {
+                       unref(val);
+                       val = NR_node->var_value = make_awknum(NR);
+               }
+               return val;
+       }
+
+       assert(var == FNR_node);
+       if (val->numbr != FNR) {
+               unref(val);
+               val = FNR_node->var_value = make_awknum(FNR);
+       }
+       return val;
+}
+
+/*
+ * awknum_set_vars --- update internal variables for assignment
+ *     to a special variable.
+ */
+
+static void
+awknum_set_var(const NODE *var)
+{
+       NODE *val = var->var_value;
+       if (var == NR_node)
+               NR = val->numbr;
+       else if (var == FNR_node)
+               FNR = val->numbr;
+
+       /* N.B: PREC and ROUNMODE -- not relevant */
+}
+
+/* awknum_increment_var --- increment NR or FNR */
+
+static long
+awknum_increment_var(const NODE *var ATTRIBUTE_UNUSED, long nr)
+{
+       /* var == (F)NR_node */
+       return ++nr;
+}
+
+/* awknum_init_vars --- initialize special variables */
+
+static void
+awknum_init_vars()
+{
+       /* dummy function */
+}
+
+/* make_awknum --- allocate a node with defined number */
+
+static NODE *
+make_awknum(AWKNUM x)
+{
+       NODE *r;
+       getnode(r);
+       r->type = Node_val;
+       r->numbr = x;
+       r->flags = MALLOC|NUMBER|NUMCUR;
+       r->valref = 1;
+       r->stptr = NULL;
+       r->stlen = 0;
+#if MBS_SUPPORT
+       r->wstptr = NULL;
+       r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+       return r;
+}
+
+/* make_integer - Convert an integer to a number node.  */
+
+static inline NODE *
+make_integer(uintmax_t n)
+{
+       n = adjust_uint(n);
+       return make_number(n);
+}
+
+/* do_lshift --- perform a << operation */
+
+static NODE *
+do_lshift(int nargs)
+{
+       NODE *s1, *s2;
+       uintmax_t uval, ushift, res;
+       AWKNUM val, shift;
+
+       s2 = POP_SCALAR();
+       s1 = POP_SCALAR();
+       if (do_lint) {
+               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("lshift: received non-numeric first 
argument"));
+               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("lshift: received non-numeric second 
argument"));
+       }
+       val = force_number(s1)->numbr;
+       shift = force_number(s2)->numbr;
+       if (do_lint) {
+               if (val < 0 || shift < 0)
+                       lintwarn(_("lshift(%f, %f): negative values will give 
strange results"),
+                                       (double) val, (double) shift);
+               if (double_to_int(val) != val || double_to_int(shift) != shift)
+                       lintwarn(_("lshift(%f, %f): fractional values will be 
truncated"),
+                                       (double) val, (double) shift);
+               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+                       lintwarn(_("lshift(%f, %f): too large shift value will 
give strange results"),
+                                       (double) val, (double) shift);
+       }
+
+       DEREF(s1);
+       DEREF(s2);
+
+       uval = (uintmax_t) val;
+       ushift = (uintmax_t) shift;
+
+       res = uval << ushift;
+       return make_integer(res);
+}
+
+/* do_rshift --- perform a >> operation */
+
+static NODE *
+do_rshift(int nargs)
+{
+       NODE *s1, *s2;
+       uintmax_t uval, ushift, res;
+       AWKNUM val, shift;
+
+       s2 = POP_SCALAR();
+       s1 = POP_SCALAR();
+       if (do_lint) {
+               if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("rshift: received non-numeric first 
argument"));
+               if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("rshift: received non-numeric second 
argument"));
+       }
+       val = force_number(s1)->numbr;
+       shift = force_number(s2)->numbr;
+       if (do_lint) {
+               if (val < 0 || shift < 0)
+                       lintwarn(_("rshift(%f, %f): negative values will give 
strange results"),
+                                       (double) val, (double) shift);
+               if (double_to_int(val) != val || double_to_int(shift) != shift)
+                       lintwarn(_("rshift(%f, %f): fractional values will be 
truncated"),
+                                       (double) val, (double) shift);
+               if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+                       lintwarn(_("rshift(%f, %f): too large shift value will 
give strange results"),
+                                       (double) val, (double) shift);
+       }
+
+       DEREF(s1);
+       DEREF(s2);
+
+       uval = (uintmax_t) val;
+       ushift = (uintmax_t) shift;
+
+       res = uval >> ushift;
+       return make_integer(res);
+}
+
+/* do_and --- perform an & operation */
+
+static NODE *
+do_and(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKNUM val;
+       int i;
+
+       res = ~0;       /* start off with all ones */
+       if (nargs < 2)
+               fatal(_("and: called with less than two arguments"));
+
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("and: argument %d is non-numeric"), i);
+
+               val = force_number(s1)->numbr;
+               if (do_lint && val < 0)
+                       lintwarn(_("and: argument %d negative value %g will 
give strange results"),
+                                       i, (double) val);
+
+               uval = (uintmax_t) val;
+               res &= uval;
+
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_or --- perform an | operation */
+
+static NODE *
+do_or(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKNUM val;
+       int i;
+
+       res = 0;
+       if (nargs < 2)
+               fatal(_("or: called with less than two arguments"));
+
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("or: argument %d is non-numeric"), i);
+
+               val = force_number(s1)->numbr;
+               if (do_lint && val < 0)
+                       lintwarn(_("or: argument %d negative value %g will give 
strange results"),
+                                       i, (double) val);
+
+               uval = (uintmax_t) val;
+               res |= uval;
+
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_xor --- perform an ^ operation */
+
+static NODE *
+do_xor(int nargs)
+{
+       NODE *s1;
+       uintmax_t res, uval;
+       AWKNUM val;
+       int i;
+
+       if (nargs < 2)
+               fatal(_("xor: called with less than two arguments"));
+
+       res = 0;        /* silence compiler warning */
+       for (i = 1; nargs > 0; nargs--, i++) {
+               s1 = POP_SCALAR();
+               if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("xor: argument %d is non-numeric"), i);
+
+               val = force_number(s1)->numbr;
+               if (do_lint && val < 0)
+                       lintwarn(_("xor: argument %d negative value %g will 
give strange results"),
+                                       i, (double) val);
+
+               uval = (uintmax_t) val;
+               if (i == 1)
+                       res = uval;
+               else
+                       res ^= uval;
+
+               DEREF(s1);
+       }
+
+       return make_integer(res);
+}
+
+/* do_compl --- perform a ~ operation */
+
+static NODE *
+do_compl(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d;
+       uintmax_t uval;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("compl: received non-numeric argument"));
+       d = force_number(tmp)->numbr;
+       DEREF(tmp);
+
+       if (do_lint) {
+               if (d < 0)
+                       lintwarn(_("compl(%f): negative value will give strange 
results"),
+                                       (double) d);
+               if (double_to_int(d) != d)
+                       lintwarn(_("compl(%f): fractional value will be 
truncated"),
+                                       (double) d);
+       }
+
+       uval = (uintmax_t) d;
+       uval = ~ uval;
+       return make_integer(uval);
+}
+
+/* nondec2awknum --- convert octal or hex value to double */
+
+/*
+ * Because of awk's concatenation rules and the way awk.y:yylex()
+ * collects a number, this routine has to be willing to stop on the
+ * first invalid character.
+ */
+
+static AWKNUM
+nondec2awknum(char *str, size_t len)
+{
+       AWKNUM retval = 0.0;
+       char save;
+       short val;
+       char *start = str;
+
+       if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+               /*
+                * User called strtonum("0x") or some such,
+                * so just quit early.
+                */
+               if (len <= 2)
+                       return (AWKNUM) 0.0;
+
+               for (str += 2, len -= 2; len > 0; len--, str++) {
+                       switch (*str) {
+                       case '0':
+                       case '1':
+                       case '2':
+                       case '3':
+                       case '4':
+                       case '5':
+                       case '6':
+                       case '7':
+                       case '8':
+                       case '9':
+                               val = *str - '0';
+                               break;
+                       case 'a':
+                       case 'b':
+                       case 'c':
+                       case 'd':
+                       case 'e':
+                       case 'f':
+                               val = *str - 'a' + 10;
+                               break;
+                       case 'A':
+                       case 'B':
+                       case 'C':
+                       case 'D':
+                       case 'E':
+                       case 'F':
+                               val = *str - 'A' + 10;
+                               break;
+                       default:
+                               goto done;
+                       }
+                       retval = (retval * 16) + val;
+               }
+       } else if (*str == '0') {
+               for (; len > 0; len--) {
+                       if (! isdigit((unsigned char) *str))
+                               goto done;
+                       else if (*str == '8' || *str == '9') {
+                               str = start;
+                               goto decimal;
+                       }
+                       retval = (retval * 8) + (*str - '0');
+                       str++;
+               }
+       } else {
+decimal:
+               save = str[len];
+               retval = strtod(str, NULL);
+               str[len] = save;
+       }
+done:
+       return retval;
+}
+
+
+/* do_rand --- do the rand function */
+
+static bool firstrand = true;
+/* Some systems require this array to be integer aligned. Sigh. */
+#define SIZEOF_STATE 256
+static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
+static char *const state = (char *const) istate;
+
+/* ARGSUSED */
+static NODE *
+do_rand(int nargs ATTRIBUTE_UNUSED)
+{
+       if (firstrand) {
+               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+               /* don't need to srandom(1), initstate() does it for us. */
+               firstrand = false;
+               setstate(state);
+       }
+       /*
+        * Per historical practice and POSIX, return value N is
+        *
+        *      0 <= n < 1
+        */
+       return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / 
GAWK_RANDOM_MAX);
+}
+
+/* do_srand --- seed the random number generator */
+
+static NODE *
+do_srand(int nargs)
+{
+       NODE *tmp;
+       static long save_seed = 1;
+       long ret = save_seed;   /* SVR4 awk srand returns previous seed */
+
+       if (firstrand) {
+               (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+               /* don't need to srandom(1), we're changing the seed below */
+               firstrand = false;
+               (void) setstate(state);
+       }
+
+       if (nargs == 0)
+               srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
+       else {
+               tmp = POP_SCALAR();
+               if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("srand: received non-numeric argument"));
+               srandom((unsigned int) (save_seed = (long) 
force_number(tmp)->numbr));
+               DEREF(tmp);
+       }
+       return make_number((AWKNUM) ret);
+}
+
+
+/*-------------------------------------------------------------------*/
+
+static NODE *
+str2awknum(char *str, char **endptr, int base, bool is_integer 
ATTRIBUTE_UNUSED)
+{
+       NODE *r;
+       AWKNUM d;
+
+       if (base == 0) {
+               /*
+                * special case -- only used to parse input in the debugger?
+                * FIXME: reject ieee specials we don't want and/or use the same
+                * rules when reading numbers from a source file and nuke this 
case.
+                */
+
+               errno = 0;
+               d = strtod(str, endptr);
+               if (errno != 0)
+                       d = 0;
+       } else {
+               if (base == 8 || base == 16)
+                       d = nondec2awknum(str, strlen(str));
+               else
+                       d = atof(str);
+       }
+       r = make_awknum(d);
+       if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+               r->flags |= NUMINT;
+       return r;
+}
+
+/* awknum_mod --- remainder from division of two numbers */
+
+static NODE *
+awknum_mod(const NODE *t1, const NODE *t2)
+{
+       AWKNUM x;
+
+       if (t2->numbr == 0)
+               fatal(_("division by zero attempted in `%%'"));
+#ifdef HAVE_FMOD
+       x = fmod(t1->numbr, t2->numbr);
+#else  /* ! HAVE_FMOD */
+       (void) modf(t1->numbr / t2->numbr, & x);
+       x = t1->numbr - x * t2->numbr;
+#endif /* ! HAVE_FMOD */
+       return make_awknum(x);
+}
+
+/* awknum_pow --- power function */
+
+static NODE *
+awknum_pow(const NODE *t1, const NODE *t2)
+{
+       return make_awknum(calc_exp(t1->numbr, t2->numbr));
+}
+
+
+/*
+ * calc_exp_posint --- calculate x^n for positive integral n,
+ *     using exponentiation by squaring without recursion.
+ */
+
+static AWKNUM
+calc_exp_posint(AWKNUM x, long n)
+{
+       AWKNUM mult = 1;
+
+       while (n > 1) {
+               if ((n % 2) == 1)
+                       mult *= x;
+               x *= x;
+               n /= 2;
+       }
+       return mult * x;
+}
+
+/* calc_exp --- calculate x1^x2 */
+
+static AWKNUM
+calc_exp(AWKNUM x1, AWKNUM x2)
+{
+       long lx;
+
+       if ((lx = x2) == x2) {          /* integer exponent */
+               if (lx == 0)
+                       return 1;
+               return (lx > 0) ? calc_exp_posint(x1, lx)
+                               : 1.0 / calc_exp_posint(x1, -lx);
+       }
+       return (AWKNUM) pow((double) x1, (double) x2);
+}
+
+/* cmp_awknums --- compare two AWKNUMs */
+
+static int
+cmp_awknums(const NODE *t1, const NODE *t2)
+{
+       /*
+        * This routine is also used to sort numeric array indices or values.
+        * For the purposes of sorting, NaN is considered greater than
+        * any other value, and all NaN values are considered equivalent and 
equal.
+        * This isn't in compliance with IEEE standard, but compliance w.r.t. 
NaN
+        * comparison at the awk level is a different issue, and needs to be 
dealt
+        * with in the interpreter for each opcode seperately.
+        */
+
+       if (isnan(t1->numbr))
+               return ! isnan(t2->numbr);
+       if (isnan(t2->numbr))
+               return -1;
+       /* don't subtract, in case one or both are infinite */
+       if (t1->numbr == t2->numbr)
+               return 0;
+       if (t1->numbr < t2->numbr)
+               return -1;
+       return 1;
+}
+
+/* force_awknum --- force a value to be numeric */
+
+static NODE *
+force_awknum(NODE *n)
+{
+       char *cp;
+       char *cpend;
+       char save;
+       char *ptr;
+       unsigned int newflags;
+       extern double strtod();
+
+       if ((n->flags & NUMCUR) != 0)
+               return n;
+
+       /* all the conditionals are an attempt to avoid the expensive strtod */
+
+       /* Note: only set NUMCUR if we actually convert some digits */
+
+       n->numbr = 0.0;
+
+       if (n->stlen == 0) {
+               return n;
+       }
+
+       cp = n->stptr;
+       /*
+        * 2/2007:
+        * POSIX, by way of severe language lawyering, seems to
+        * allow things like "inf" and "nan" to mean something.
+        * So if do_posix, the user gets what he deserves.
+        * This also allows hexadecimal floating point. Ugh.
+        */
+       if (! do_posix) {
+               if (isalpha((unsigned char) *cp)) {
+                       return n;
+               } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
+                       if ((n->flags & MAYBE_NUM) != 0)
+                               n->flags &= ~MAYBE_NUM;
+                       n->flags |= NUMBER|NUMCUR;
+                       n->numbr = get_ieee_magic_val(n->stptr);
+
+                       return n;
+               }
+               /* else
+                       fall through */
+       }
+       /* else not POSIX, so
+               fall through */
+
+       cpend = cp + n->stlen;
+       while (cp < cpend && isspace((unsigned char) *cp))
+               cp++;
+
+       if (   cp == cpend              /* only spaces, or */
+           || (! do_posix              /* not POSIXLY paranoid and */
+               && (isalpha((unsigned char) *cp)        /* letter, or */
+                                       /* CANNOT do non-decimal and saw 0x */
+                   || (! do_non_decimal_data && cp[0] == '0'
+                       && (cp[1] == 'x' || cp[1] == 'X'))))) {
+               return n;
+       }
+
+       if ((n->flags & MAYBE_NUM) != 0) {
+               newflags = NUMBER;
+               n->flags &= ~MAYBE_NUM;
+       } else
+               newflags = 0;
+
+       if (cpend - cp == 1) {          /* only one character */
+               if (isdigit((unsigned char) *cp)) {     /* it's a digit! */
+                       n->numbr = (AWKNUM)(*cp - '0');
+                       n->flags |= newflags;
+                       n->flags |= NUMCUR;
+                       if (cp == n->stptr)             /* no leading spaces */
+                               n->flags |= NUMINT;
+               }
+               return n;
+       }
+
+       if (do_non_decimal_data) {      /* main.c assures false if do_posix */
+               errno = 0;
+               if (! do_traditional && get_numbase(cp, true) != 10) {
+                       n->numbr = nondec2awknum(cp, cpend - cp);
+                       n->flags |= NUMCUR;
+                       ptr = cpend;
+                       goto finish;
+               }
+       }
+
+       errno = 0;
+       save = *cpend;
+       *cpend = '\0';
+       n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
+
+       /* POSIX says trailing space is OK for NUMBER */
+       while (isspace((unsigned char) *ptr))
+               ptr++;
+       *cpend = save;
+finish:
+       if (errno == 0 && ptr == cpend) {
+               n->flags |= newflags;
+               n->flags |= NUMCUR;
+       } else {
+               errno = 0;
+       }
+
+       return n;
+}
+
+
+/*
+ * The following lookup table is used as an optimization in force_string;
+ * (more complicated) variations on this theme didn't seem to pay off, but 
+ * systematic testing might be in order at some point.
+ */
+static const char *values[] = {
+       "0",
+       "1",
+       "2",
+       "3",
+       "4",
+       "5",
+       "6",
+       "7",
+       "8",
+       "9",
+};
+#define        NVAL    (sizeof(values)/sizeof(values[0]))
+
+/* format_awknum_val --- format a numeric value based on format */
+
+static NODE *
+format_awknum_val(const char *format, int index, NODE *s)
+{
+       char buf[BUFSIZ];
+       char *sp = buf;
+       double val;
+
+       /*
+        * 2/2007: Simplify our lives here. Instead of worrying about
+        * whether or not the value will fit into a long just so we
+        * can use sprintf("%ld", val) on it, always format it ourselves.
+        * The only thing to worry about is that integral values always
+        * format as integers. %.0f does that very well.
+        *
+        * 6/2008: Would that things were so simple. Always using %.0f
+        * imposes a notable performance penalty for applications that
+        * do a lot of conversion of integers to strings. So, we reinstate
+        * the old code, but use %.0f for integral values that are outside
+        * the range of a long.  This seems a reasonable compromise.
+        *
+        * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
+        * < and > so that things work correctly on systems with 64 bit 
integers.
+        */
+
+       /* not an integral value, or out of range */
+       if ((val = double_to_int(s->numbr)) != s->numbr
+                       || val <= LONG_MIN || val >= LONG_MAX
+       ) {
+               /*
+                * Once upon a time, we just blindly did this:
+                *      sprintf(sp, format, s->numbr);
+                *      s->stlen = strlen(sp);
+                *      s->stfmt = (char) index;
+                * but that's no good if, e.g., OFMT is %s. So we punt,
+                * and just always format the value ourselves.
+                */
+
+               NODE *dummy[2], *r;
+               unsigned int oflags;
+
+               /* create dummy node for a sole use of format_tree */
+               dummy[1] = s;
+               oflags = s->flags;
+
+               if (val == s->numbr) {
+                       /* integral value, but outside range of %ld, use %.0f */
+                       r = format_tree("%.0f", 4, dummy, 2);
+                       s->stfmt = -1;
+               } else {
+                       r = format_tree(format, fmt_list[index]->stlen, dummy, 
2);
+                       assert(r != NULL);
+                       s->stfmt = (char) index;
+               }
+               s->flags = oflags;
+               s->stlen = r->stlen;
+               if ((s->flags & STRCUR) != 0)
+                       efree(s->stptr);
+               s->stptr = r->stptr;
+               freenode(r);    /* Do not unref(r)! We want to keep s->stptr == 
r->stpr.  */
+
+               goto no_malloc;
+       } else {
+               /*
+                * integral value; force conversion to long only once.
+                */
+               long num = (long) val;
+
+               if (num < NVAL && num >= 0) {
+                       sp = (char *) values[num];
+                       s->stlen = 1;
+               } else {
+                       (void) sprintf(sp, "%ld", num);
+                       s->stlen = strlen(sp);
+               }
+               s->stfmt = -1;
+               if ((s->flags & INTIND) != 0) {
+                       s->flags &= ~(INTIND|NUMBER);
+                       s->flags |= STRING;
+               }
+       }
+       if (s->stptr != NULL)
+               efree(s->stptr);
+       emalloc(s->stptr, char *, s->stlen + 2, "format_awknum_val");
+       memcpy(s->stptr, sp, s->stlen + 1);
+no_malloc:
+       s->flags |= STRCUR;
+       free_wstr(s);
+       return s;
+}
+
+/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
+
+static int
+is_ieee_magic_val(const char *val)
+{
+       /*
+        * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
+        * Assume the length is 4, as the caller checks this.
+        */
+       return (   (val[0] == '+' || val[0] == '-')
+               && (   (   (val[1] == 'i' || val[1] == 'I')
+                       && (val[2] == 'n' || val[2] == 'N')
+                       && (val[3] == 'f' || val[3] == 'F'))
+                   || (   (val[1] == 'n' || val[1] == 'N')
+                       && (val[2] == 'a' || val[2] == 'A')
+                       && (val[3] == 'n' || val[3] == 'N'))));
+}
+
+/* get_ieee_magic_val --- return magic value for string */
+
+static AWKNUM
+get_ieee_magic_val(const char *val)
+{
+       static bool first = true;
+       static AWKNUM inf;
+       static AWKNUM nan;
+       char *ptr;
+       AWKNUM v;
+
+       v = strtod(val, & ptr);
+
+       if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
+               if (first) {
+                       first = false;
+                       nan = sqrt(-1.0);
+                       inf = -log(0.0);
+               }
+
+               v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
+               if (val[0] == '-')
+                       v = -v;
+       }
+
+       return v;
+}
+
+/* double_to_int --- convert double to int, used in several places */
+
+static double
+double_to_int(double d)
+{
+       if (d >= 0)
+               d = Floor(d);
+       else
+               d = Ceil(d);
+       return d;
+}
+
+/* do_int --- convert double to int for awk */
+
+static NODE *
+do_int(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("int: received non-numeric argument"));
+       (void) force_number(tmp);
+       d = tmp->numbr;
+       DEREF(tmp);
+       return make_number(double_to_int(d));
+}
+
+/* do_log --- the log function */
+
+static NODE *
+do_log(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d, arg;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("log: received non-numeric argument"));
+       arg = force_number(tmp)->numbr;
+       if (arg < 0.0)
+               warning(_("log: received negative argument %g"), (double) arg);
+       d = log(arg);
+       DEREF(tmp);
+       return make_number(d);
+}
+
+/* do_sqrt --- do the sqrt function */
+
+static NODE *
+do_sqrt(int nargs)
+{
+       NODE *tmp;
+       AWKNUM arg;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("sqrt: received non-numeric argument"));
+       arg = force_number(tmp)->numbr;
+       DEREF(tmp);
+       if (arg < 0.0)
+               warning(_("sqrt: called with negative argument %g"), (double) 
arg);
+       return make_number(sqrt(arg));
+}
+
+/* do_exp --- exponential function */
+
+static NODE *
+do_exp(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d, res;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("exp: received non-numeric argument"));
+       d = force_number(tmp)->numbr;
+       DEREF(tmp);
+       errno = 0;
+       res = exp(d);
+       if (errno == ERANGE)
+               warning(_("exp: argument %g is out of range"), (double) d);
+       return make_number(res);
+}
+
+
+/* do_atan2 --- do the atan2 function */
+
+static NODE *
+do_atan2(int nargs)
+{
+       NODE *t1, *t2;
+       AWKNUM d1, d2;
+
+       t2 = POP_SCALAR();
+       t1 = POP_SCALAR();
+       if (do_lint) {
+               if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("atan2: received non-numeric first 
argument"));
+               if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+                       lintwarn(_("atan2: received non-numeric second 
argument"));
+       }
+       d1 = force_number(t1)->numbr;
+       d2 = force_number(t2)->numbr;
+       DEREF(t1);
+       DEREF(t2);
+       return make_number(atan2(d1, d2));
+}
+
+/* do_sin --- do the sin function */
+
+static NODE *
+do_sin(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("sin: received non-numeric argument"));
+       d = sin(force_number(tmp)->numbr);
+       DEREF(tmp);
+       return make_number(d);
+}
+
+/* do_cos --- do the cos function */
+
+static NODE *
+do_cos(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d;
+
+       tmp = POP_SCALAR();
+       if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("cos: received non-numeric argument"));
+       d = cos(force_number(tmp)->numbr);
+       DEREF(tmp);
+       return make_number(d);
+}
+
+/* do_strtonum --- the strtonum function */
+
+static NODE *
+do_strtonum(int nargs)
+{
+       NODE *tmp;
+       AWKNUM d;
+
+       tmp = POP_SCALAR();
+       if ((tmp->flags & (NUMBER|NUMCUR)) != 0)
+               d = force_number(tmp)->numbr;
+       else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
+               d = nondec2awknum(tmp->stptr, tmp->stlen);
+       else
+               d = force_number(tmp)->numbr;
+
+       DEREF(tmp);
+       return make_number(d);
+}
+
+
+/*
+ * format_tree() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library.  Returns a string node which value
+ * is a formatted string.  Called by  sprintf function.
+ *
+ * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+static NODE *
+format_nodes_awknum(
+       const char *fmt_string,
+       size_t n0,
+       NODE **the_args,
+       long num_args)
+{
+/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
+/* difference of pointers should be of ptrdiff_t type, but let us be kind */
+#define bchunk(s, l) if (l) { \
+       while ((l) > ofre) { \
+               size_t olen = obufout - obuf; \
+               erealloc(obuf, char *, osiz * 2, "format_tree"); \
+               ofre += osiz; \
+               osiz *= 2; \
+               obufout = obuf + olen; \
+       } \
+       memcpy(obufout, s, (size_t) (l)); \
+       obufout += (l); \
+       ofre -= (l); \
+}
+
+/* copy one byte from 's' to 'obufout' checking for space in the process */
+#define bchunk_one(s) { \
+       if (ofre < 1) { \
+               size_t olen = obufout - obuf; \
+               erealloc(obuf, char *, osiz * 2, "format_tree"); \
+               ofre += osiz; \
+               osiz *= 2; \
+               obufout = obuf + olen; \
+       } \
+       *obufout++ = *s; \
+       --ofre; \
+}
+
+/* Is there space for something L big in the buffer? */
+#define chksize(l)  if ((l) >= ofre) { \
+       size_t olen = obufout - obuf; \
+       size_t delta = osiz+l-ofre; \
+       erealloc(obuf, char *, osiz + delta, "format_tree"); \
+       obufout = obuf + olen; \
+       ofre += delta; \
+       osiz += delta; \
+}
+
+       size_t cur_arg = 0;
+       NODE *r = NULL;
+       int i, nc;
+       bool toofew = false;
+       char *obuf, *obufout;
+       size_t osiz, ofre;
+       const char *chbuf;
+       const char *s0, *s1;
+       int cs1;
+       NODE *arg;
+       long fw, prec, argnum;
+       bool used_dollar;
+       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
+       long *cur = NULL;
+       uintmax_t uval;
+       bool sgn;
+       int base;
+       /*
+        * Although this is an array, the elements serve two different
+        * purposes. The first element is the general buffer meant
+        * to hold the entire result string.  The second one is a
+        * temporary buffer for large floating point values. They
+        * could just as easily be separate variables, and the
+        * code might arguably be clearer.
+        */
+       struct {
+               char *buf;
+               size_t bufsize;
+               char stackbuf[30];
+       } cpbufs[2];
+#define cpbuf  cpbufs[0].buf
+       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
+       char *cp;
+       const char *fill;
+       AWKNUM tmpval = 0.0;
+       char signchar = '\0';
+       size_t len;
+       bool zero_flag = false;
+       bool quote_flag = false;
+       int ii, jj;
+       char *chp;
+       size_t copy_count, char_count;
+
+       static const char sp[] = " ";
+       static const char zero_string[] = "0";
+       static const char lchbuf[] = "0123456789abcdef";
+       static const char Uchbuf[] = "0123456789ABCDEF";
+
+#define INITIAL_OUT_SIZE       512
+       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
+       obufout = obuf;
+       osiz = INITIAL_OUT_SIZE;
+       ofre = osiz - 2;
+
+       cur_arg = 1;
+
+       {
+               size_t k;
+               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
+                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
+                       cpbufs[k].buf = cpbufs[k].stackbuf;
+               }
+       }
+
+       /*
+        * The point of this goop is to grow the buffer
+        * holding the converted number, so that large
+        * values don't overflow a fixed length buffer.
+        */
+#define PREPEND(CH) do {       \
+       if (cp == cpbufs[0].buf) {      \
+               char *prev = cpbufs[0].buf;     \
+               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
+                       "format_tree"); \
+               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
+                      cpbufs[0].bufsize);      \
+               cpbufs[0].bufsize *= 2; \
+               if (prev != cpbufs[0].stackbuf) \
+                       efree(prev);    \
+               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
+       }       \
+       *--cp = (CH);   \
+} while(0)
+
+       /*
+        * Check first for use of `count$'.
+        * If plain argument retrieval was used earlier, choke.
+        *      Otherwise, return the requested argument.
+        * If not `count$' now, but it was used earlier, choke.
+        * If this format is more than total number of args, choke.
+        * Otherwise, return the current argument.
+        */
+#define parse_next_arg() { \
+       if (argnum > 0) { \
+               if (cur_arg > 1) { \
+                       msg(_("fatal: must use `count$' on all formats or 
none")); \
+                       goto out; \
+               } \
+               arg = the_args[argnum]; \
+       } else if (used_dollar) { \
+               msg(_("fatal: must use `count$' on all formats or none")); \
+               arg = 0; /* shutup the compiler */ \
+               goto out; \
+       } else if (cur_arg >= num_args) { \
+               arg = 0; /* shutup the compiler */ \
+               toofew = true; \
+               break; \
+       } else { \
+               arg = the_args[cur_arg]; \
+               cur_arg++; \
+       } \
+}
+
+       need_format = false;
+       used_dollar = false;
+
+       s0 = s1 = fmt_string;
+       while (n0-- > 0) {
+               if (*s1 != '%') {
+                       s1++;
+                       continue;
+               }
+               need_format = true;
+               bchunk(s0, s1 - s0);
+               s0 = s1;
+               cur = &fw;
+               fw = 0;
+               prec = 0;
+               base = 0;
+               argnum = 0;
+               base = 0;
+               have_prec = false;
+               signchar = '\0';
+               zero_flag = false;
+               quote_flag = false;
+               lj = alt = big_flag = bigbig_flag = small_flag = false;
+               fill = sp;
+               cp = cend;
+               chbuf = lchbuf;
+               s1++;
+
+retry:
+               if (n0-- == 0)  /* ran out early! */
+                       break;
+
+               switch (cs1 = *s1++) {
+               case (-1):      /* dummy case to allow for checking */
+check_pos:
+                       if (cur != &fw)
+                               break;          /* reject as a valid format */
+                       goto retry;
+               case '%':
+                       need_format = false;
+                       /*
+                        * 29 Oct. 2002:
+                        * The C99 standard pages 274 and 279 seem to imply that
+                        * since there's no arg converted, the field width 
doesn't
+                        * apply.  The code already was that way, but this
+                        * comment documents it, at least in the code.
+                        */
+                       if (do_lint) {
+                               const char *msg = NULL;
+
+                               if (fw && ! have_prec)
+                                       msg = _("field width is ignored for 
`%%' specifier");
+                               else if (fw == 0 && have_prec)
+                                       msg = _("precision is ignored for `%%' 
specifier");
+                               else if (fw && have_prec)
+                                       msg = _("field width and precision are 
ignored for `%%' specifier");
+
+                               if (msg != NULL)
+                                       lintwarn("%s", msg);
+                       }
+                       bchunk_one("%");
+                       s0 = s1;
+                       break;
+
+               case '0':
+                       /*
+                        * Only turn on zero_flag if we haven't seen
+                        * the field width or precision yet.  Otherwise,
+                        * screws up floating point formatting.
+                        */
+                       if (cur == & fw)
+                               zero_flag = true;
+                       if (lj)
+                               goto retry;
+                       /* FALL through */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       if (cur == NULL)
+                               break;
+                       if (prec >= 0)
+                               *cur = cs1 - '0';
+                       /*
+                        * with a negative precision *cur is already set
+                        * to -1, so it will remain negative, but we have
+                        * to "eat" precision digits in any case
+                        */
+                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+                               --n0;
+                               *cur = *cur * 10 + *s1++ - '0';
+                       }
+                       if (prec < 0)   /* negative precision is discarded */
+                               have_prec = false;
+                       if (cur == &prec)
+                               cur = NULL;
+                       if (n0 == 0)    /* badly formatted control string */
+                               continue;
+                       goto retry;
+               case '$':
+                       if (do_traditional) {
+                               msg(_("fatal: `$' is not permitted in awk 
formats"));
+                               goto out;
+                       }
+
+                       if (cur == &fw) {
+                               argnum = fw;
+                               fw = 0;
+                               used_dollar = true;
+                               if (argnum <= 0) {
+                                       msg(_("fatal: arg count with `$' must 
be > 0"));
+                                       goto out;
+                               }
+                               if (argnum >= num_args) {
+                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
+                                       goto out;
+                               }
+                       } else {
+                               msg(_("fatal: `$' not permitted after period in 
format"));
+                               goto out;
+                       }
+
+                       goto retry;
+               case '*':
+                       if (cur == NULL)
+                               break;
+                       if (! do_traditional && isdigit((unsigned char) *s1)) {
+                               int val = 0;
+
+                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
+                                       val *= 10;
+                                       val += *s1 - '0';
+                               }
+                               if (*s1 != '$') {
+                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
+                                       goto out;
+                               } else {
+                                       s1++;
+                                       n0--;
+                               }
+                               if (val >= num_args) {
+                                       toofew = true;
+                                       break;
+                               }
+                               arg = the_args[val];
+                       } else {
+                               parse_next_arg();
+                       }
+                       (void) force_number(arg);
+                       *cur = get_number_si(arg);
+                       if (*cur < 0 && cur == &fw) {
+                               *cur = -*cur;
+                               lj++;
+                       }
+                       if (cur == &prec) {
+                               if (*cur >= 0)
+                                       have_prec = true;
+                               else
+                                       have_prec = false;
+                               cur = NULL;
+                       }
+                       goto retry;
+               case ' ':               /* print ' ' or '-' */
+                                       /* 'space' flag is ignored */
+                                       /* if '+' already present  */
+                       if (signchar != false) 
+                               goto check_pos;
+                       /* FALL THROUGH */
+               case '+':               /* print '+' or '-' */
+                       signchar = cs1;
+                       goto check_pos;
+               case '-':
+                       if (prec < 0)
+                               break;
+                       if (cur == &prec) {
+                               prec = -1;
+                               goto retry;
+                       }
+                       fill = sp;      /* if left justified then other */
+                       lj++;           /* filling is ignored */
+                       goto check_pos;
+               case '.':
+                       if (cur != &fw)
+                               break;
+                       cur = &prec;
+                       have_prec = true;
+                       goto retry;
+               case '#':
+                       alt = true;
+                       goto check_pos;
+               case '\'':
+#if defined(HAVE_LOCALE_H)       
+                       /* allow quote_flag if there is a thousands separator. 
*/
+                       if (loc.thousands_sep[0] != '\0')
+                               quote_flag = true;
+                       goto check_pos;
+#else
+                       goto retry;  
+#endif
+               case 'l':
+                       if (big_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       big_flag = true;
+                       goto retry;
+               case 'L':
+                       if (bigbig_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       bigbig_flag = true;
+                       goto retry;
+               case 'h':
+                       if (small_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       small_flag = true;
+                       goto retry;
+               case 'c':
+                       need_format = false;
+                       parse_next_arg();
+                       /* user input that looks numeric is numeric */
+                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+                               (void) force_number(arg);
+                       if ((arg->flags & NUMBER) != 0) {
+                               uval = get_number_uj(arg);
+#if MBS_SUPPORT
+                               if (gawk_mb_cur_max > 1) {
+                                       char buf[100];
+                                       wchar_t wc;
+                                       mbstate_t mbs;
+                                       size_t count;
+
+                                       memset(& mbs, 0, sizeof(mbs));
+                                       wc = uval;
+
+                                       count = wcrtomb(buf, wc, & mbs);
+                                       if (count == 0
+                                           || count == (size_t)-1
+                                           || count == (size_t)-2)
+                                               goto out0;
+
+                                       memcpy(cpbuf, buf, count);
+                                       prec = count;
+                                       cp = cpbuf;
+                                       goto pr_tail;
+                               }
+out0:
+                               ;
+                               /* else,
+                                       fall through */
+#endif
+                               if (do_lint && uval > 255) {
+                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
+                                                       arg->numbr);
+                               }
+                               cpbuf[0] = uval;
+                               prec = 1;
+                               cp = cpbuf;
+                               goto pr_tail;
+                       }
+                       /*
+                        * As per POSIX, only output first character of a
+                        * string value.  Thus, we ignore any provided
+                        * precision, forcing it to 1.  (Didn't this
+                        * used to work? 6/2003.)
+                        */
+                       cp = arg->stptr;
+#if MBS_SUPPORT
+                       /*
+                        * First character can be multiple bytes if
+                        * it's a multibyte character. Grr.
+                        */
+                       if (gawk_mb_cur_max > 1) {
+                               mbstate_t state;
+                               size_t count;
+
+                               memset(& state, 0, sizeof(state));
+                               count = mbrlen(cp, arg->stlen, & state);
+                               if (count == 0
+                                   || count == (size_t)-1
+                                   || count == (size_t)-2)
+                                       goto out2;
+                               prec = count;
+                               goto pr_tail;
+                       }
+out2:
+                       ;
+#endif
+                       prec = 1;
+                       goto pr_tail;
+               case 's':
+                       need_format = false;
+                       parse_next_arg();
+                       arg = force_string(arg);
+                       if (fw == 0 && ! have_prec)
+                               prec = arg->stlen;
+                       else {
+                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
+                               if (! have_prec || prec > char_count)
+                                       prec = char_count;
+                       }
+                       cp = arg->stptr;
+                       goto pr_tail;
+               case 'd':
+               case 'i':
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       tmpval = arg->numbr;
+
+                       /*
+                        * Check for Nan or Inf.
+                        */
+                       if (isnan(tmpval) || isinf(tmpval))
+                               goto out_of_range;
+                       else
+                               tmpval = double_to_int(tmpval);
+
+                       /*
+                        * ``The result of converting a zero value with a
+                        * precision of zero is no characters.''
+                        */
+                       if (have_prec && prec == 0 && tmpval == 0)
+                               goto pr_tail;
+
+                       if (tmpval < 0) {
+                               tmpval = -tmpval;
+                               sgn = true;
+                       } else {
+                               if (tmpval == -0.0)
+                                       /* avoid printing -0 */
+                                       tmpval = 0.0;
+                               sgn = false;
+                       }
+                       /*
+                        * Use snprintf return value to tell if there
+                        * is enough room in the buffer or not.
+                        */
+                       while ((i = snprintf(cpbufs[1].buf,
+                                            cpbufs[1].bufsize, "%.0f",
+                                            tmpval)) >=
+                              cpbufs[1].bufsize) {
+                               if (cpbufs[1].buf == cpbufs[1].stackbuf)
+                                       cpbufs[1].buf = NULL;
+                               if (i > 0) {
+                                       cpbufs[1].bufsize += ((i > 
cpbufs[1].bufsize) ?
+                                                             i : 
cpbufs[1].bufsize);
+                               }
+                               else
+                                       cpbufs[1].bufsize *= 2;
+                               assert(cpbufs[1].bufsize > 0);
+                               erealloc(cpbufs[1].buf, char *,
+                                        cpbufs[1].bufsize, "format_tree");
+                       }
+                       if (i < 1)
+                               goto out_of_range;
+                       chp = &cpbufs[1].buf[i-1];
+                       ii = jj = 0;
+                       do {
+                               PREPEND(*chp);
+                               chp--; i--;
+#if defined(HAVE_LOCALE_H)
+                               if (quote_flag && loc.grouping[ii] && ++jj == 
loc.grouping[ii]) {
+                                       if (i)  /* only add if more digits 
coming */
+                                               PREPEND(loc.thousands_sep[0]);  
/* XXX - assumption it's one char */
+                                       if (loc.grouping[ii+1] == 0)
+                                               jj = 0;         /* keep using 
current val in loc.grouping[ii] */
+                                       else if (loc.grouping[ii+1] == CHAR_MAX)
+                                               quote_flag = false;
+                                       else {                 
+                                               ii++;
+                                               jj = 0;
+                                       }
+                               }
+#endif
+                       } while (i > 0);
+
+                       /* add more output digits to match the precision */
+                       if (have_prec) {
+                               while (cend - cp < prec)
+                                       PREPEND('0');
+                       }
+
+                       if (sgn)
+                               PREPEND('-');
+                       else if (signchar)
+                               PREPEND(signchar);
+                       /*
+                        * When to fill with zeroes is of course not simple.
+                        * First: No zero fill if left-justifying.
+                        * Next: There seem to be two cases:
+                        *      A '0' without a precision, e.g. %06d
+                        *      A precision with no field width, e.g. %.10d
+                        * Any other case, we don't want to fill with zeroes.
+                        */
+                       if (! lj
+                           && ((zero_flag && ! have_prec)
+                                || (fw == 0 && have_prec)))
+                               fill = zero_string;
+                       if (prec > fw)
+                               fw = prec;
+                       prec = cend - cp;
+                       if (fw > prec && ! lj && fill != sp
+                           && (*cp == '-' || signchar)) {
+                               bchunk_one(cp);
+                               cp++;
+                               prec--;
+                               fw--;
+                       }
+                       goto pr_tail;
+               case 'X':
+                       chbuf = Uchbuf; /* FALL THROUGH */
+               case 'x':
+                       base += 6;      /* FALL THROUGH */
+               case 'u':
+                       base += 2;      /* FALL THROUGH */
+               case 'o':
+                       base += 8;
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       tmpval = arg->numbr;
+
+                       /*
+                        * ``The result of converting a zero value with a
+                        * precision of zero is no characters.''
+                        *
+                        * If I remember the ANSI C standard, though,
+                        * it says that for octal conversions
+                        * the precision is artificially increased
+                        * to add an extra 0 if # is supplied.
+                        * Indeed, in C,
+                        *      printf("%#.0o\n", 0);
+                        * prints a single 0.
+                        */
+                       if (! alt && have_prec && prec == 0 && tmpval == 0)
+                               goto pr_tail;
+
+                       if (tmpval < 0) {
+                               uval = (uintmax_t) (intmax_t) tmpval;
+                               if ((AWKNUM)(intmax_t)uval != 
double_to_int(tmpval))
+                                       goto out_of_range;
+                       } else {
+                               uval = (uintmax_t) tmpval;
+                               if ((AWKNUM)uval != double_to_int(tmpval))
+                                       goto out_of_range;
+                       }
+
+                       /*
+                        * When to fill with zeroes is of course not simple.
+                        * First: No zero fill if left-justifying.
+                        * Next: There seem to be two cases:
+                        *      A '0' without a precision, e.g. %06d
+                        *      A precision with no field width, e.g. %.10d
+                        * Any other case, we don't want to fill with zeroes.
+                        */
+                       if (! lj
+                           && ((zero_flag && ! have_prec)
+                                || (fw == 0 && have_prec)))
+                               fill = zero_string;
+                       ii = jj = 0;
+                       do {
+                               PREPEND(chbuf[uval % base]);
+                               uval /= base;
+#if defined(HAVE_LOCALE_H)
+                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
+                                       if (uval)       /* only add if more 
digits coming */
+                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
+                                       if (loc.grouping[ii+1] == 0)            
                              
+                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
+                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
+                                               quote_flag = false;
+                                       else {                 
+                                               ii++;
+                                               jj = 0;
+                                       }
+                               }
+#endif
+                       } while (uval > 0);
+
+                       /* add more output digits to match the precision */
+                       if (have_prec) {
+                               while (cend - cp < prec)
+                                       PREPEND('0');
+                       }
+
+                       if (alt && tmpval != 0) {
+                               if (base == 16) {
+                                       PREPEND(cs1);
+                                       PREPEND('0');
+                                       if (fill != sp) {
+                                               bchunk(cp, 2);
+                                               cp += 2;
+                                               fw -= 2;
+                                       }
+                               } else if (base == 8)
+                                       PREPEND('0');
+                       }
+                       base = 0;
+                       if (prec > fw)
+                               fw = prec;
+                       prec = cend - cp;
+       pr_tail:
+                       if (! lj) {
+                               while (fw > prec) {
+                                       bchunk_one(fill);
+                                       fw--;
+                               }
+                       }
+                       copy_count = prec;
+                       if (fw == 0 && ! have_prec)
+                               ;
+                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
+                               assert(cp == arg->stptr || cp == cpbuf);
+                               copy_count = mbc_byte_count(arg->stptr, prec);
+                       }
+                       bchunk(cp, copy_count);
+                       while (fw > prec) {
+                               bchunk_one(fill);
+                               fw--;
+                       }
+                       s0 = s1;
+                       break;
+
+     out_of_range:
+                       /* out of range - emergency use of %g format */
+                       if (do_lint)
+                               lintwarn(_("[s]printf: value %g is out of range 
for `%%%c' format"),
+                                                       (double) tmpval, cs1);
+                       cs1 = 'g';
+                       goto fmt1;
+
+               case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+                       cs1 = 'f';
+                       /* FALL THROUGH */
+#endif
+               case 'g':
+               case 'G':
+               case 'e':
+               case 'f':
+               case 'E':
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+                       tmpval = arg->numbr;
+     fmt1:
+                       if (! have_prec)
+                               prec = DEFAULT_G_PRECISION;
+
+                       chksize(fw + prec + 11);        /* 11 == slop */
+                       cp = cpbuf;
+                       *cp++ = '%';
+                       if (lj)
+                               *cp++ = '-';
+                       if (signchar)
+                               *cp++ = signchar;
+                       if (alt)
+                               *cp++ = '#';
+                       if (zero_flag)
+                               *cp++ = '0';
+                       if (quote_flag)
+                               *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+                       if (quote_flag && ! use_lc_numeric)
+                               setlocale(LC_NUMERIC, "");
+#endif
+
+                       sprintf(cp, "*.*%c", cs1);
+                       while ((nc = snprintf(obufout, ofre, cpbuf,
+                                    (int) fw, (int) prec,
+                                    (double) tmpval)) >= ofre)
+                               chksize(nc)
+
+#if defined(LC_NUMERIC)
+                       if (quote_flag && ! use_lc_numeric)
+                               setlocale(LC_NUMERIC, "C");
+#endif
+
+                       len = strlen(obufout);
+                       ofre -= len;
+                       obufout += len;
+                       s0 = s1;
+                       break;
+               default:
+                       if (do_lint && isalpha(cs1))
+                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
+                       break;
+               }
+               if (toofew) {
+                       msg("%s\n\t`%s'\n\t%*s%s",
+                             _("fatal: not enough arguments to satisfy format 
string"),
+                             fmt_string, (int) (s1 - fmt_string - 1), "",
+                             _("^ ran out for this one"));
+                       goto out;
+               }
+       }
+       if (do_lint) {
+               if (need_format)
+                       lintwarn(
+                       _("[s]printf: format specifier does not have control 
letter"));
+               if (cur_arg < num_args)
+                       lintwarn(
+                       _("too many arguments supplied for format string"));
+       }
+       bchunk(s0, s1 - s0);
+       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
+       obuf = NULL;
+out:
+       {
+               size_t k;
+               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
+               for (k = 0; k < count; k++) {
+                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
+                               efree(cpbufs[k].buf);
+               }
+               if (obuf != NULL)
+                       efree(obuf);
+       }
+
+       if (r == NULL)
+               gawk_exit(EXIT_FATAL);
+       return r;
+}
diff --git a/eval.c b/eval.c
index 1908c47..5312289 100644
--- a/eval.c
+++ b/eval.c
@@ -34,6 +34,8 @@ long fcall_count = 0;
 int currule = 0;
 IOBUF *curfile = NULL;         /* current data file */
 bool exiting = false;
+NODE *true_node;
+NODE *false_node;
 
 int (*interpret)(INSTRUCTION *);
 #define MAX_EXEC_HOOKS 10
@@ -48,7 +50,6 @@ int ORSlen;
 int OFMTidx;
 int CONVFMTidx;
 
-static NODE *node_Boolean[2];
 
 /* This rather ugly macro is for VMS C */
 #ifdef C
@@ -263,18 +264,18 @@ static struct optypetab {
        char *operator;
 } optypes[] = {
        { "Op_illegal", NULL },
+       { "Op_plus", " + " },
+       { "Op_minus", " - " },
        { "Op_times", " * " },
-       { "Op_times_i", " * " },
        { "Op_quotient", " / " },
-       { "Op_quotient_i", " / " },
        { "Op_mod", " % " },
-       { "Op_mod_i", " % " },
-       { "Op_plus", " + " },
-       { "Op_plus_i", " + " },
-       { "Op_minus", " - " },
-       { "Op_minus_i", " - " },
        { "Op_exp", " ^ " },
-       { "Op_exp_i", " ^ " },
+       { "Op_assign_plus", " += " },
+       { "Op_assign_minus", " -= " },
+       { "Op_assign_times", " *= " },
+       { "Op_assign_quotient", " /= " },
+       { "Op_assign_mod", " %= " },
+       { "Op_assign_exp", " ^= " },
        { "Op_concat", " " },
        { "Op_line_range", NULL },
        { "Op_cond_pair", ", " },
@@ -284,6 +285,7 @@ static struct optypetab {
        { "Op_predecrement", "--" },
        { "Op_postincrement", "++" },
        { "Op_postdecrement", "--" },
+       { "Op_unary_plus", "+" },
        { "Op_unary_minus", "-" },
        { "Op_field_spec", "$" },
        { "Op_not", "! " },
@@ -291,12 +293,6 @@ static struct optypetab {
        { "Op_store_var", " = " },
        { "Op_store_sub", " = " },
        { "Op_store_field", " = " },
-       { "Op_assign_times", " *= " },
-       { "Op_assign_quotient", " /= " },
-       { "Op_assign_mod", " %= " },
-       { "Op_assign_plus", " += " },
-       { "Op_assign_minus", " -= " },
-       { "Op_assign_exp", " ^= " },
        { "Op_assign_concat", " " },
        { "Op_and", " && " },
        { "Op_and_final", NULL },
@@ -822,15 +818,11 @@ set_ORS()
 /* fmt_ok --- is the conversion format a valid one? */
 
 NODE **fmt_list = NULL;
-static int fmt_ok(NODE *n);
 static int fmt_index(NODE *n);
 
-static int
-fmt_ok(NODE *n)
+bool
+fmt_ok(const char *p)
 {
-       NODE *tmp = force_string(n);
-       const char *p = tmp->stptr;
-
 #if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
        static const char float_formats[] = "efgEG";
 #else
@@ -843,22 +835,22 @@ fmt_ok(NODE *n)
 #endif
 
        if (*p++ != '%')
-               return 0;
+               return false;
        while (*p && strchr(flags, *p) != NULL) /* flags */
                p++;
        while (*p && isdigit((unsigned char) *p))       /* width - %*.*g is NOT 
allowed */
                p++;
        if (*p == '\0' || (*p != '.' && ! isdigit((unsigned char) *p)))
-               return 0;
+               return false;
        if (*p == '.')
                p++;
        while (*p && isdigit((unsigned char) *p))       /* precision */
                p++;
        if (*p == '\0' || strchr(float_formats, *p) == NULL)
-               return 0;
+               return false;
        if (*++p != '\0')
-               return 0;
-       return 1;
+               return false;
+       return true;
 }
 
 /* fmt_index --- track values of OFMT and CONVFMT to keep semantics correct */
@@ -880,7 +872,7 @@ fmt_index(NODE *n)
        }
        /* not found */
        n->stptr[n->stlen] = '\0';
-       if (do_lint && ! fmt_ok(n))
+       if (do_lint && ! fmt_ok(n->stptr))
                lintwarn(_("bad `%sFMT' specification `%s'"),
                            n == CONVFMT_node->var_value ? "CONV"
                          : n == OFMT_node->var_value ? "O"
@@ -990,6 +982,23 @@ set_TEXTDOMAIN()
         */
 }
 
+/* set_PREC --- tarck PREC correctly */
+
+void
+set_PREC()
+{
+       numbr_hndlr->set_numvar(PREC_node);
+}
+
+/* set_ROUNDMODE --- track ROUNDMODE correctly */
+
+void
+set_ROUNDMODE()
+{
+       numbr_hndlr->set_numvar(ROUNDMODE_node);
+}
+
+
 /* update_ERRNO_int --- update the value of ERRNO based on argument */
 
 void
@@ -1029,15 +1038,7 @@ unset_ERRNO(void)
 void
 update_NR()
 {
-#ifdef HAVE_MPFR
-       if (is_mpg_number(NR_node->var_value))
-               (void) mpg_update_var(NR_node);
-       else
-#endif
-       if (NR_node->var_value->numbr != NR) {
-               unref(NR_node->var_value);
-               NR_node->var_value = make_number(NR);
-       }
+       (void) numbr_hndlr->update_numvar(NR_node);
 }
 
 /* update_NF --- update the value of NF */
@@ -1061,15 +1062,7 @@ update_NF()
 void
 update_FNR()
 {
-#ifdef HAVE_MPFR
-       if (is_mpg_number(FNR_node->var_value))
-               (void) mpg_update_var(FNR_node);
-       else
-#endif
-       if (FNR_node->var_value->numbr != FNR) {
-               unref(FNR_node->var_value);
-               FNR_node->var_value = make_number(FNR);
-       }
+       (void) numbr_hndlr->update_numvar(FNR_node);
 }
 
 
@@ -1185,42 +1178,6 @@ r_get_field(NODE *n, Func_ptr *assign, bool reference)
 }
 
 
-/*
- * calc_exp_posint --- calculate x^n for positive integral n,
- * using exponentiation by squaring without recursion.
- */
-
-static AWKNUM
-calc_exp_posint(AWKNUM x, long n)
-{
-       AWKNUM mult = 1;
-
-       while (n > 1) {
-               if ((n % 2) == 1)
-                       mult *= x;
-               x *= x;
-               n /= 2;
-       }
-       return mult * x;
-}
-
-/* calc_exp --- calculate x1^x2 */
-
-AWKNUM
-calc_exp(AWKNUM x1, AWKNUM x2)
-{
-       long lx;
-
-       if ((lx = x2) == x2) {          /* integer exponent */
-               if (lx == 0)
-                       return 1;
-               return (lx > 0) ? calc_exp_posint(x1, lx)
-                               : 1.0 / calc_exp_posint(x1, -lx);
-       }
-       return (AWKNUM) pow((double) x1, (double) x2);
-}
-
-
 /* setup_frame --- setup new frame for function call */ 
 
 static INSTRUCTION *
@@ -1490,10 +1447,10 @@ unwind_stack(long n)
 static inline int
 eval_condition(NODE *t)
 {
-       if (t == node_Boolean[false])
+       if (t == false_node)
                return false;
 
-       if (t == node_Boolean[true])
+       if (t == true_node)
                return true;
 
        if ((t->flags & MAYBE_NUM) != 0)
@@ -1533,63 +1490,42 @@ static void
 op_assign(OPCODE op)
 {
        NODE **lhs;
-       NODE *t1, *t2;
-       AWKNUM x = 0.0, x1, x2;
+       NODE *r, *t1, *t2;
 
        lhs = POP_ADDRESS();
        t1 = *lhs;
-       x1 = force_number(t1)->numbr;
+       (void) force_number(t1);
 
-       t2 = TOP_SCALAR();
-       x2 = force_number(t2)->numbr;
-       DEREF(t2);
+       t2 = TOP_NUMBER();
 
        switch (op) {
        case Op_assign_plus:
-               x = x1 + x2;
+               r = numbr_hndlr->add(t1, t2);
                break;
        case Op_assign_minus:
-               x = x1 - x2;
+               r = numbr_hndlr->sub(t1, t2);
                break;
        case Op_assign_times:
-               x = x1 * x2;
+               r = numbr_hndlr->mul(t1, t2);
                break;
        case Op_assign_quotient:
-               if (x2 == (AWKNUM) 0) {
-                       decr_sp();
-                       fatal(_("division by zero attempted in `/='"));
-               }
-               x = x1 / x2;
+               r = numbr_hndlr->div(t1, t2);
                break;
        case Op_assign_mod:
-               if (x2 == (AWKNUM) 0) {
-                       decr_sp();
-                       fatal(_("division by zero attempted in `%%='"));
-               }
-#ifdef HAVE_FMOD
-               x = fmod(x1, x2);
-#else   /* ! HAVE_FMOD */
-               (void) modf(x1 / x2, &x);
-               x = x1 - x2 * x;
-#endif  /* ! HAVE_FMOD */
+               r = numbr_hndlr->mod(t1, t2);
                break;
        case Op_assign_exp:
-               x = calc_exp((double) x1, (double) x2);
+               r = numbr_hndlr->pow(t1, t2);
                break;
        default:
-               break;
-       }
-
-       if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) {
-               /* optimization */
-               t1->numbr = x;
-       } else {
-               unref(t1);
-               t1 = *lhs = make_number(x);
+               cant_happen();
        }
 
-       UPREF(t1);
-       REPLACE(t1);
+       DEREF(t2);
+       unref(*lhs);
+       *lhs = r;
+       UPREF(r);
+       REPLACE(r);
 }
 
 /* PUSH_CODE --- push a code onto the runtime stack */
@@ -1729,7 +1665,7 @@ register_exec_hook(Func_pre_exec preh, Func_post_exec 
posth)
 /* interpreter routine when not debugging */ 
 #include "interpret.h"
 
-/* interpreter routine with exec hook(s). Used when debugging and/or with 
MPFR. */
+/* interpreter routine with exec hook(s). Used when debugging */
 #define r_interpret h_interpret
 #define EXEC_HOOK 1
 #include "interpret.h"
@@ -1757,14 +1693,6 @@ init_interpret()
        frame_ptr->num_tail_calls = 0;
        frame_ptr->vname = NULL;
 
-       /* initialize true and false nodes */
-       node_Boolean[false] = make_number(0.0);
-       node_Boolean[true] = make_number(1.0);
-       if (! is_mpg_number(node_Boolean[false])) {
-               node_Boolean[false]->flags |= NUMINT;
-               node_Boolean[true]->flags |= NUMINT;
-       }
-
        /*
         * Select the interpreter routine. The version without
         * any exec hook support (r_interpret) is faster by about
diff --git a/field.c b/field.c
index 3edd5d8..de5dfce 100644
--- a/field.c
+++ b/field.c
@@ -195,28 +195,24 @@ rebuild_record()
         */
        for (cops = ops, i = 1; i <= NF; i++) {
                NODE *r = fields_arr[i];
+
                if (r->stlen > 0) {
                        NODE *n;
-                       getnode(n);
 
                        if ((r->flags & FIELD) == 0) {
-                               *n = *Null_field;
-                               n->stlen = r->stlen;
                                if ((r->flags & (NUMCUR|NUMBER)) != 0) {
-                                       n->flags |= (r->flags & 
(MPFN|MPZN|NUMCUR|NUMBER));
-#ifdef HAVE_MPFR
-                                       if (is_mpg_float(r)) {
-                                               mpfr_init(n->mpg_numbr);
-                                               mpfr_set(n->mpg_numbr, 
r->mpg_numbr, ROUND_MODE);
-                                       } else if (is_mpg_integer(r)) {
-                                               mpz_init(n->mpg_i);
-                                               mpz_set(n->mpg_i, r->mpg_i);
-                                       } else
-#endif
-                                       n->numbr = r->numbr;
+                                       n = numbr_hndlr->gawk_copy_number(r);
+                                       n->flags |= Null_field->flags;
+                                       n->flags &= ~MALLOC;
+                               } else {
+                                       getnode(n);
+                                       *n = *Null_field;
                                }
+                               n->stlen = r->stlen;
                        } else {
+                               getnode(n);
                                *n = *r;
+                               assert((n->flags & (NUMCUR|NUMBER)) == 0);
                                n->flags &= ~(MALLOC|STRING);
                        }
 
diff --git a/gawkapi.c b/gawkapi.c
index b89bdbc..5ee18f3 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -665,7 +665,7 @@ api_sym_update_scalar(awk_ext_id_t id,
         */
        switch (value->val_type) {
        case AWK_NUMBER:
-               if (node->var_value->valref == 1 && ! do_mpfr) {
+               if (node->var_value->valref == 1 && numbr_hndlr == & 
awknum_hndlr) {
                        NODE *r = node->var_value;
 
                        /* r_unref: */
@@ -689,7 +689,8 @@ api_sym_update_scalar(awk_ext_id_t id,
                        if ((r->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
                                efree(r->stptr);
 
-                       mpfr_unset(r);
+                       if (free_number && (r->flags & (NUMBER|NUMCUR)) != 0)
+                               free_number(r);
                        free_wstr(r);
 
                        /* make_str_node(s, l, ALREADY_MALLOCED): */
@@ -1149,7 +1150,7 @@ init_ext_api()
        api_impl.do_flags[2] = (do_profile ? 1 : 0);
        api_impl.do_flags[3] = (do_sandbox ? 1 : 0);
        api_impl.do_flags[4] = (do_debug ? 1 : 0);
-       api_impl.do_flags[5] = (do_mpfr ? 1 : 0);
+       api_impl.do_flags[5] = (numbr_hndlr != & awknum_hndlr);
 }
 
 /* update_ext_api --- update the variables in the API that can change */
diff --git a/int_array.c b/int_array.c
index 769ac9b..04c7a9a 100644
--- a/int_array.c
+++ b/int_array.c
@@ -85,7 +85,7 @@ is_integer(NODE *symbol, NODE *subs)
        long l;
        AWKNUM d;
 
-       if (subs == Nnull_string || do_mpfr)
+       if (subs == Nnull_string)
                return NULL;
 
        if ((subs->flags & NUMINT) != 0)
diff --git a/interpret.h b/interpret.h
index c652624..0cf15b8 100644
--- a/interpret.h
+++ b/interpret.h
@@ -37,6 +37,7 @@ r_interpret(INSTRUCTION *code)
        AWKNUM x, x2;
        int di;
        Regexp *rp;
+       NODE *booleans[] = { false_node, true_node };
        NODE *set_array = NULL; /* array with a post-assignment routine */
        NODE *set_idx = NULL;   /* the index of the array element */
 
@@ -180,7 +181,7 @@ top:
                                cant_happen();
                        }
                }
-                       break;  
+                       break;
 
                case Op_push_param:             /* function argument */
                        m = pc->memory;
@@ -392,7 +393,7 @@ top:
                        DEREF(t1);
                        if ((op == Op_and && di) || (op == Op_or && ! di))
                                break;
-                       r = node_Boolean[di];
+                       r = booleans[di];
                        UPREF(r);
                        PUSH(r);
                        ni = pc->target_jmp;
@@ -401,7 +402,7 @@ top:
                case Op_and_final:
                case Op_or_final:
                        t1 = TOP_SCALAR();
-                       r = node_Boolean[eval_condition(t1)];
+                       r = booleans[eval_condition(t1)];
                        DEREF(t1);
                        UPREF(r);
                        REPLACE(r);
@@ -409,181 +410,115 @@ top:
 
                case Op_not:
                        t1 = TOP_SCALAR();
-                       r = node_Boolean[! eval_condition(t1)];
+                       r = booleans[! eval_condition(t1)];
                        DEREF(t1);
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_equal:
-                       r = node_Boolean[cmp_scalars() == 0];
+                       r = booleans[cmp_scalars() == 0];
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_notequal:
-                       r = node_Boolean[cmp_scalars() != 0];
+                       r = booleans[cmp_scalars() != 0];
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_less:
-                       r = node_Boolean[cmp_scalars() < 0];
+                       r = booleans[cmp_scalars() < 0];
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_greater:
-                       r = node_Boolean[cmp_scalars() > 0];
+                       r = booleans[cmp_scalars() > 0];
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_leq:
-                       r = node_Boolean[cmp_scalars() <= 0];
+                       r = booleans[cmp_scalars() <= 0];
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_geq:
-                       r = node_Boolean[cmp_scalars() >= 0];
+                       r = booleans[cmp_scalars() >= 0];
                        UPREF(r);
                        REPLACE(r);
                        break;
 
-               case Op_plus_i:
-                       x2 = force_number(pc->memory)->numbr;
-                       goto plus;
+#define ARITHOP(OP)    \
+t2 = POP_NUMBER();     \
+t1 = TOP_NUMBER();     \
+r = numbr_hndlr->OP(t1, t2);   \
+DEREF(t1);             \
+DEREF(t2); REPLACE(r)
+
                case Op_plus:
-                       t2 = POP_NUMBER();
-                       x2 = t2->numbr;
-                       DEREF(t2);
-plus:
-                       t1 = TOP_NUMBER();
-                       r = make_number(t1->numbr + x2);
-                       DEREF(t1);
-                       REPLACE(r);
+                       ARITHOP(add);
                        break;
 
-               case Op_minus_i:
-                       x2 = force_number(pc->memory)->numbr;
-                       goto minus;
                case Op_minus:
-                       t2 = POP_NUMBER();
-                       x2 = t2->numbr;
-                       DEREF(t2);                      
-minus:
-                       t1 = TOP_NUMBER();
-                       r = make_number(t1->numbr - x2);
-                       DEREF(t1);
-                       REPLACE(r);
+                       ARITHOP(sub);
                        break;
 
-               case Op_times_i:
-                       x2 = force_number(pc->memory)->numbr;
-                       goto times;
                case Op_times:
-                       t2 = POP_NUMBER();
-                       x2 = t2->numbr;
-                       DEREF(t2);
-times:
-                       t1 = TOP_NUMBER();
-                       r = make_number(t1->numbr * x2);
-                       DEREF(t1);
-                       REPLACE(r);
+                       ARITHOP(mul);
                        break;
 
-               case Op_exp_i:
-                       x2 = force_number(pc->memory)->numbr;
-                       goto exp;
-               case Op_exp:
-                       t2 = POP_NUMBER();
-                       x2 = t2->numbr;
-                       DEREF(t2);
-exp:
-                       t1 = TOP_NUMBER();
-                       r = make_number(calc_exp(t1->numbr, x2));
-                       DEREF(t1);
-                       REPLACE(r);
+               case Op_quotient:
+                       ARITHOP(div);
                        break;
 
-               case Op_quotient_i:
-                       x2 = force_number(pc->memory)->numbr;
-                       goto quotient;
-               case Op_quotient:
-                       t2 = POP_NUMBER();
-                       x2 = t2->numbr;
-                       DEREF(t2);
-quotient:
-                       t1 = TOP_NUMBER();
-                       if (x2 == 0)
-                               fatal(_("division by zero attempted"));
-                       r = make_number(t1->numbr / x2);
-                       DEREF(t1);
-                       REPLACE(r);
-                       break;          
+               case Op_exp:
+                       ARITHOP(pow);
+                       break;
 
-               case Op_mod_i:
-                       x2 = force_number(pc->memory)->numbr;
-                       goto mod;
                case Op_mod:
-                       t2 = POP_NUMBER();
-                       x2 = t2->numbr;
-                       DEREF(t2);
-mod:
-                       t1 = TOP_NUMBER();
-                       if (x2 == 0)
-                               fatal(_("division by zero attempted in `%%'"));
-#ifdef HAVE_FMOD
-                       x = fmod(t1->numbr, x2);
-#else  /* ! HAVE_FMOD */
-                       (void) modf(t1->numbr / x2, &x);
-                       x = t1->numbr - x * x2;
-#endif /* ! HAVE_FMOD */
-                       r = make_number(x);
-
-                       DEREF(t1);
-                       REPLACE(r);
+                       ARITHOP(mod);
                        break;
+#undef ARITHOP
 
                case Op_preincrement:
                case Op_predecrement:
-                       x = op == Op_preincrement ? 1.0 : -1.0;
                        lhs = TOP_ADDRESS();
-                       t1 = *lhs;
-                       force_number(t1);
-                       if (t1->valref == 1 && t1->flags == 
(MALLOC|NUMCUR|NUMBER)) {
-                               /* optimization */
-                               t1->numbr += x;
-                               r = t1;
-                       } else {
-                               r = *lhs = make_number(t1->numbr + x);
-                               unref(t1);
-                       }
+                       t1 = force_number(*lhs);
+                       r = *lhs = numbr_hndlr->add_long(t1, op == 
Op_preincrement ? 1 : -1);
+                       unref(t1);
                        UPREF(r);
                        REPLACE(r);
                        break;
 
                case Op_postincrement:
                case Op_postdecrement:
-                       x = op == Op_postincrement ? 1.0 : -1.0;
                        lhs = TOP_ADDRESS();
-                       t1 = *lhs;
-                       force_number(t1);
-                       r = make_number(t1->numbr);
-                       if (t1->valref == 1 && t1->flags == 
(MALLOC|NUMCUR|NUMBER)) {
-                               /* optimization */
-                               t1->numbr += x;
-                       } else {
-                               *lhs = make_number(t1->numbr + x);
-                               unref(t1);
-                       }
+                       t1 = force_number(*lhs);
+                       r = numbr_hndlr->gawk_copy_number(t1);
+                       *lhs = numbr_hndlr->add_long(t1, op == Op_postincrement 
? 1 : -1);
+                       unref(t1);
+                       REPLACE(r);
+                       break;
+
+               case Op_unary_plus:
+                       /*
+                        * POSIX semantics: force a conversion to numeric type.
+                        * Arbitrary-precision semantics: force the working 
precision.
+                        */
+                       t1 = TOP_NUMBER();
+                       r = numbr_hndlr->gawk_copy_number(t1);
+                       DEREF(t1);
                        REPLACE(r);
                        break;
 
                case Op_unary_minus:
                        t1 = TOP_NUMBER();
-                       r = make_number(-t1->numbr);
+                       r = numbr_hndlr->gawk_copy_number(t1);
+                       numbr_hndlr->gawk_negate_number(r);
                        DEREF(t1);
                        REPLACE(r);
                        break;
@@ -834,7 +769,7 @@ mod:
                case Op_in_array:
                        t1 = POP_ARRAY();
                        t2 = mk_sub(pc->expr_count);
-                       r = node_Boolean[(in_array(t1, t2) != NULL)];
+                       r = booleans[(in_array(t1, t2) != NULL)];
                        DEREF(t2);
                        UPREF(r);
                        PUSH(r);
@@ -983,13 +918,13 @@ match_re:
                         */
 
                        di = research(rp, t1->stptr, 0, t1->stlen,
-                                                               avoid_dfa(m, 
t1->stptr, t1->stlen));
+                                                       avoid_dfa(m, t1->stptr, 
t1->stlen));
                        di = (di == -1) ^ (op != Op_nomatch);
                        if (op != Op_match_rec) {
                                decr_sp();
                                DEREF(t1);
                        }
-                       r = node_Boolean[di];
+                       r = booleans[di];
                        UPREF(r);
                        PUSH(r);
                        break;
@@ -1328,8 +1263,8 @@ match_re:
                        }
 
                        result = ip->triggered || di;
-                       ip->triggered ^= di;          /* update triggered flag 
*/
-                       r = node_Boolean[result];      /* final value of 
condition pair */
+                       ip->triggered ^= di;       /* update triggered flag */
+                       r = booleans[result];      /* final value of condition 
pair */
                        UPREF(r);
                        REPLACE(r);
                        JUMPTO(pc->target_jmp);
diff --git a/io.c b/io.c
index 0b008fc..666bfde 100644
--- a/io.c
+++ b/io.c
@@ -144,14 +144,6 @@
 #define PIPES_SIMULATED
 #endif
 
-#ifdef HAVE_MPFR
-/* increment NR or FNR */
-#define INCREMENT_REC(X)       (do_mpfr && X == (LONG_MAX - 1)) ? \
-                               (mpz_add_ui(M##X, M##X, 1), X = 0) : X++
-#else
-#define INCREMENT_REC(X)       X++
-#endif
-
 typedef enum { CLOSE_ALL, CLOSE_TO, CLOSE_FROM } two_way_close_type;
 
 /* Several macros to make the code a bit clearer. */
@@ -413,11 +405,11 @@ nextfile(IOBUF **curfile, bool skipping)
                        /* manage the awk variables: */
                        unref(FILENAME_node->var_value);
                        FILENAME_node->var_value = dupnode(arg);
-#ifdef HAVE_MPFR
-                       if (is_mpg_number(FNR_node->var_value))
-                               mpz_set_ui(MFNR, 0);
-#endif
-                       FNR = 0;
+
+                       unref(FNR_node->var_value);
+                       FNR_node->var_value = dupnode(false_node);
+                       numbr_hndlr->set_numvar(FNR_node);
+                       assert(FNR == 0);
 
                        /* IOBUF management: */
                        errno = 0;
@@ -474,14 +466,8 @@ nextfile(IOBUF **curfile, bool skipping)
 void
 set_FNR()
 {
-       NODE *n = FNR_node->var_value;
-       (void) force_number(n);
-#ifdef HAVE_MPFR
-       if (is_mpg_number(n))
-               FNR = mpg_set_var(FNR_node);
-       else
-#endif
-       FNR = get_number_si(n);
+       (void) force_number(FNR_node->var_value);
+       numbr_hndlr->set_numvar(FNR_node);
 }
 
 /* set_NR --- update internal NR from awk variable */
@@ -489,14 +475,8 @@ set_FNR()
 void
 set_NR()
 {
-       NODE *n = NR_node->var_value;
-       (void) force_number(n);
-#ifdef HAVE_MPFR
-       if (is_mpg_number(n))
-               NR = mpg_set_var(NR_node);
-       else
-#endif
-       NR = get_number_si(n);
+       (void) force_number(NR_node->var_value);
+       numbr_hndlr->set_numvar(NR_node);
 }
 
 /* inrec --- This reads in a record from the input file */
@@ -520,8 +500,17 @@ inrec(IOBUF *iop, int *errcode)
                if (*errcode > 0)
                        update_ERRNO_int(*errcode);
        } else {
-               INCREMENT_REC(NR);
-               INCREMENT_REC(FNR);
+#if 0
+               /* XXX: looser if AWKNUM is long double */
+               if (numbr_hndlr == & awknum_hndlr) {
+                       NR++;
+                       FNR++;
+               } else
+#endif
+               {
+                       NR = numbr_hndlr->increment_var(NR_node, NR);
+                       FNR = numbr_hndlr->increment_var(FNR_node, FNR);
+               }
                set_record(begin, cnt);
        }
 
@@ -2393,8 +2382,17 @@ do_getline(int into_variable, IOBUF *iop)
 
        if (cnt == EOF)
                return NULL;    /* try next file */
-       INCREMENT_REC(NR);
-       INCREMENT_REC(FNR);
+#if 0
+       /* XXX: looser if AWKNUM is long double */
+       if (numbr_hndlr == & awknum_hndlr) {
+               NR++;
+               FNR++;
+       } else
+#endif
+       {
+               NR = numbr_hndlr->increment_var(NR_node, NR);
+               FNR = numbr_hndlr->increment_var(FNR_node, FNR);
+       }
 
        if (! into_variable)    /* no optional var. */
                set_record(s, cnt);
diff --git a/main.c b/main.c
index 437c0cd..24dbb56 100644
--- a/main.c
+++ b/main.c
@@ -35,8 +35,6 @@
 
 #define DEFAULT_PROFILE                "awkprof.out"   /* where to put profile 
*/
 #define DEFAULT_VARFILE                "awkvars.out"   /* where to put vars */
-#define DEFAULT_PREC           53
-#define DEFAULT_ROUNDMODE      "N"             /* round to nearest */
 
 static const char *varfile = DEFAULT_VARFILE;
 const char *command_file = NULL;       /* debugger commands */
@@ -58,9 +56,12 @@ static void version(void) ATTRIBUTE_NORETURN;
 static void init_fds(void);
 static void init_groupset(void);
 static void save_argv(int, char **);
+static void init_numbr_handler(bltin_t **);
+static void print_numbr_hndlr_versions(void);
 
 extern int debug_prog(INSTRUCTION *pc); /* debug.c */
-extern int init_debug();       /* debug.c */
+extern int init_debug(void);   /* debug.c */
+extern void init_parser(const bltin_t *);      /* awkgram.c */
 
 /* These nodes store all the special variables AWK uses */
 NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node;
@@ -111,6 +112,8 @@ INSTRUCTION *rule_list;
 
 int exit_val = EXIT_SUCCESS;           /* exit value */
 
+numbr_handler_t *numbr_hndlr;  /* number handler */
+
 #if defined(YYDEBUG) || defined(GAWKDEBUG)
 extern int yydebug;
 #endif
@@ -210,6 +213,10 @@ main(int argc, char **argv)
        char *extra_stack;
        int have_srcfile = 0;
        SRCFILE *s;
+       bltin_t *numbr_bltins;
+
+       /* default number handler */
+       numbr_hndlr = & awknum_hndlr;
 
        /* do these checks early */
        if (getenv("TIDYMEM") != NULL)
@@ -281,7 +288,7 @@ main(int argc, char **argv)
 #undef STACK_SIZE
 
        myname = gawk_name(argv[0]);
-       os_arg_fixup(&argc, &argv); /* emulate redirection, expand wildcards */
+       os_arg_fixup(& argc, & argv); /* emulate redirection, expand wildcards 
*/
 
        if (argc < 2)
                usage(EXIT_FAILURE, stderr);
@@ -292,12 +299,6 @@ main(int argc, char **argv)
        /* Robustness: check that file descriptors 0, 1, 2 are open */
        init_fds();
 
-       /* init array handling. */
-       array_init();
-
-       /* init the symbol tables */
-       init_symbol_table();
-
        output_fp = stdout;
 
        /* we do error messages ourselves on invalid options */
@@ -456,9 +457,7 @@ main(int argc, char **argv)
                        break;
 
                case 'M':
-#ifdef HAVE_MPFR
-                       do_flags |= DO_MPFR;
-#endif
+                       numbr_hndlr = & mpfp_hndlr;
                        break;
 
                case 'P':
@@ -580,29 +579,21 @@ out:
        }
 #endif
 
+       /* Set up number handler */
+       init_numbr_handler(& numbr_bltins);
+
        if (do_debug)   /* Need to register the debugger pre-exec hook before 
any other */
                init_debug();
 
-#ifdef HAVE_MPFR
-       /* Set up MPFR defaults, and register pre-exec hook to process 
arithmetic opcodes */ 
-       if (do_mpfr)
-               init_mpfr(DEFAULT_PREC, DEFAULT_ROUNDMODE);
-#endif
+       /* init array handling. */
+       array_init();
+
+       /* init the symbol tables */
+       init_symbol_table();
 
        /* load group set */
        init_groupset();
 
-#ifdef HAVE_MPFR
-       if (do_mpfr) {
-               mpz_init(Nnull_string->mpg_i);
-               Nnull_string->flags = (MALLOC|STRCUR|STRING|MPZN|NUMCUR|NUMBER);
-       } else
-#endif
-       {
-               Nnull_string->numbr = 0.0;
-               Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER);
-       }
-
        /*
         * Tell the regex routines how they should work.
         * Do this before initializing variables, since
@@ -667,7 +658,7 @@ out:
                optind++;
        }
 
-       /* Select the interpreter routine */
+       /* select the interpreter routine */
        init_interpret();
 
        init_args(optind, argc,
@@ -682,6 +673,10 @@ out:
         */
        setlocale(LC_NUMERIC, "C");
 #endif
+
+       /* initialize parser related variables */
+       init_parser(numbr_bltins);
+
        /* Read in the program */
        if (parse_program(& code_block) != 0)
                exit(EXIT_FAILURE);
@@ -980,7 +975,7 @@ static const struct varinit varinit[] = {
 {&FPAT_node,   "FPAT",         "[^[:space:]]+", 0,  NULL, set_FPAT,    false, 
NON_STANDARD },
 {&IGNORECASE_node, "IGNORECASE", NULL, 0,  NULL, set_IGNORECASE,       false, 
NON_STANDARD },
 {&LINT_node,   "LINT",         NULL,   0,  NULL, set_LINT,     false, 
NON_STANDARD },
-{&PREC_node,   "PREC",         NULL,   DEFAULT_PREC,   NULL,   set_PREC,       
false,  NON_STANDARD},  
+{&PREC_node,   "PREC",         NULL,   0,      NULL,   set_PREC,       false,  
NON_STANDARD},  
 {&NF_node,     "NF",           NULL,   -1, update_NF, set_NF,  false, 0 },
 {&NR_node,     "NR",           NULL,   0,  update_NR, set_NR,  true, 0 },
 {&OFMT_node,   "OFMT",         "%.6g", 0,  NULL, set_OFMT,     true, 0 },
@@ -988,7 +983,7 @@ static const struct varinit varinit[] = {
 {&ORS_node,    "ORS",          "\n",   0,  NULL, set_ORS,      true, 0 },
 {NULL,         "PROCINFO",     NULL,   0,  NULL, NULL, false, NO_INSTALL | 
NON_STANDARD | NOT_OFF_LIMITS },
 {&RLENGTH_node, "RLENGTH",     NULL,   0,  NULL, NULL, false, 0 },
-{&ROUNDMODE_node, "ROUNDMODE", DEFAULT_ROUNDMODE,      0,  NULL, 
set_ROUNDMODE,        false, NON_STANDARD },
+{&ROUNDMODE_node, "ROUNDMODE", "",     0,  NULL, set_ROUNDMODE,        false, 
NON_STANDARD },
 {&RS_node,     "RS",           "\n",   0,  NULL, set_RS,       true, 0 },
 {&RSTART_node, "RSTART",       NULL,   0,  NULL, NULL, false, 0 },
 {&RT_node,     "RT",           "",     0,  NULL, NULL, false, NON_STANDARD },
@@ -1019,6 +1014,8 @@ init_vars()
                        (*(vp->assign))();
        }
 
+       numbr_hndlr->init_numvars();    /* set default values for variables 
e.g. PREC */ 
+
        /* Set up deferred variables (loaded only when accessed). */
        if (! do_traditional)
                register_deferred_variable("PROCINFO", load_procinfo);
@@ -1107,7 +1104,7 @@ load_procinfo()
 #if defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0
        int i;
 #endif
-#if (defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0) || 
defined(HAVE_MPFR)
+#if (defined (HAVE_GETGROUPS) && defined(NGROUPS_MAX) && NGROUPS_MAX > 0)
        char name[100];
 #endif
        AWKNUM value;
@@ -1123,14 +1120,8 @@ load_procinfo()
        update_PROCINFO_str("version", VERSION);
        update_PROCINFO_str("strftime", def_strftime_format);
 
-#ifdef HAVE_MPFR
-       sprintf(name, "GNU MPFR %s", mpfr_get_version());
-       update_PROCINFO_str("mpfr_version", name);
-       sprintf(name, "GNU MP %s", gmp_version);
-       update_PROCINFO_str("gmp_version", name);
-       update_PROCINFO_num("prec_max", MPFR_PREC_MAX);
-       update_PROCINFO_num("prec_min", MPFR_PREC_MIN);
-#endif
+       if (numbr_hndlr != & awknum_hndlr && numbr_hndlr->load_procinfo)
+               numbr_hndlr->load_procinfo();
 
 #ifdef GETPGRP_VOID
 #define getpgrp_arg() /* nothing */
@@ -1426,9 +1417,7 @@ static void
 version()
 {
        printf("%s", version_string);
-#ifdef HAVE_MPFR
-       printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version);
-#endif
+       print_numbr_hndlr_versions();
        printf("\n"); 
        print_ext_versions();
 
@@ -1545,6 +1534,44 @@ init_locale(struct lconv *l)
 }
 #endif /* LOCALE_H */
 
+static void
+init_numbr_handler(bltin_t **bltins)
+{
+       if (! numbr_hndlr->init(bltins)) {
+               /* not available */
+               numbr_hndlr = & awknum_hndlr;   /* fall back to AWKNUM */
+               (void) numbr_hndlr->init(bltins);
+       }
+
+       make_number = numbr_hndlr->gawk_make_number;
+       str2number = numbr_hndlr->gawk_force_number;
+       format_val = numbr_hndlr->gawk_fmt_number;
+       cmp_numbers = numbr_hndlr->gawk_cmp_numbers;
+       str2node = numbr_hndlr->gawk_str2number;
+       free_number = numbr_hndlr->gawk_free_number;
+       format_tree = numbr_hndlr->gawk_format_nodes;
+       get_number_d = numbr_hndlr->gawk_todouble;
+       get_number_si = numbr_hndlr->gawk_tolong;
+       get_number_ui = numbr_hndlr->gawk_toulong;
+       get_number_uj = numbr_hndlr->gawk_touintmax_t;
+       sgn_number = numbr_hndlr->gawk_sgn_number;
+}
+
+static void
+print_numbr_hndlr_versions()
+{
+       static numbr_handler_t *hndlrs[] = {
+               & awknum_hndlr,
+               & mpfp_hndlr,
+       };
+       int i;
+
+       for (i = 0; i < sizeof(hndlrs) / sizeof(hndlrs[0]); i++)
+               if (hndlrs[i]->version_str)
+                       printf(" (%s)", hndlrs[i]->version_str());
+}
+
+
 /* save_argv --- save argv array */
 
 static void
diff --git a/mpfr.c b/mpfr.c
index 48fa072..83b37a1 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -26,103 +26,309 @@
 #include "awk.h"
 
 #ifdef HAVE_MPFR
+#include <gmp.h>
+#include <mpfr.h>
+
+#ifndef MPFR_RNDN
+/* for compatibility with MPFR 2.X */
+#define MPFR_RNDN GMP_RNDN
+#define MPFR_RNDZ GMP_RNDZ
+#define MPFR_RNDU GMP_RNDU
+#define MPFR_RNDD GMP_RNDD
+#endif
 
 #if !defined(MPFR_VERSION_MAJOR) || MPFR_VERSION_MAJOR < 3
 typedef mp_exp_t mpfr_exp_t;
 #endif
 
-extern NODE **fmt_list;          /* declared in eval.c */
+#define DEFAULT_PREC           53
+#define DEFAULT_ROUNDMODE      "N"             /* round to nearest */
 
-mpz_t mpzval;  /* GMP integer type, used as temporary in few places */
-mpz_t MNR;
-mpz_t MFNR;
-bool do_ieee_fmt;      /* IEEE-754 floating-point emulation */
-mpfr_rnd_t ROUND_MODE;
+extern NODE **fmt_list;          /* declared in eval.c */
 
-static mpfr_rnd_t get_rnd_mode(const char rmode);
-static NODE *mpg_force_number(NODE *n);
-static NODE *mpg_make_number(double);
-static NODE *mpg_format_val(const char *format, int index, NODE *s);
-static int mpg_interpret(INSTRUCTION **cp);
+/* exported functions */
+static NODE *mpfp_make_number(AWKNUM);
+static int mpfp_compare(const NODE *, const NODE *);
+static void mpfp_negate_num(NODE *);
+static NODE *mpfp_str2node(char *, char **, int, bool);
+static NODE *mpfp_force_number(NODE *);
+static void mpfp_free_num(NODE *);
+static NODE *mpfp_format_val(const char *, int, NODE *);
+static unsigned long mpfp_toulong(const NODE *);
+static long mpfp_tolong(const NODE *);
+static AWKNUM mpfp_todouble(const NODE *);
+static uintmax_t mpfp_touintmax_t(const NODE *);
+static int mpfp_sgn(const NODE *);
+static bool mpfp_is_integer(const NODE *n);
+static NODE *mpfp_copy_number(const NODE *);
+static NODE *mpfp_format_nodes(const char *, size_t, NODE **, long);
+static bool mpfp_init(bltin_t **);
+static NODE *mpfp_add(const NODE *, const NODE *);
+static NODE *mpfp_sub(const NODE *, const NODE *);
+static NODE *mpfp_mul(const NODE *, const NODE *);
+static NODE *mpfp_div(const NODE *, const NODE *);
+static NODE *mpfp_mod(const NODE *, const NODE *);
+static NODE *mpfp_pow(const NODE *, const NODE *);
+static NODE *mpfp_add_long(const NODE *, long);
+static NODE *mpfp_update_var(NODE *);
+static void mpfp_set_var(const NODE *);
+static long mpfp_increment_var(const NODE *, long);
+static void mpfp_init_vars(void);
+static void mpfp_load_procinfo(void);
+static const char *mpfp_version_string(void);
+
+/* builtins */
+static NODE *do_mpfp_and(int);
+static NODE *do_mpfp_atan2(int);
+static NODE *do_mpfp_compl(int);
+static NODE *do_mpfp_cos(int);
+static NODE *do_mpfp_exp(int);
+static NODE *do_mpfp_int(int);
+static NODE *do_mpfp_log(int);
+static NODE *do_mpfp_lshift(int);
+static NODE *do_mpfp_or(int);
+static NODE *do_mpfp_rand(int);
+static NODE *do_mpfp_rshift(int);
+static NODE *do_mpfp_sin(int);
+static NODE *do_mpfp_sqrt(int);
+static NODE *do_mpfp_srand(int);
+static NODE *do_mpfp_strtonum(int);
+static NODE *do_mpfp_xor(int);
+
+
+/* internal functions */
+static NODE *mpfp_make_node(unsigned int type);
+static int mpfp_format_ieee(mpfr_ptr, int);
+static const char *mpfp_sprintf(const char *, ...);
+static int mpfp_strtoui(mpz_ptr, char *, size_t, char **, int);
+static mpfr_rnd_t mpfp_get_rounding_mode(const char rmode);
+static mpfr_ptr mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val);
+
+
+static mpfr_rnd_t ROUND_MODE;
+static mpz_t MNR;
+static mpz_t MFNR;
+static bool do_ieee_fmt;       /* emulate IEEE 754 floating-point format */
 
 static mpfr_exp_t min_exp = MPFR_EMIN_DEFAULT;
 static mpfr_exp_t max_exp = MPFR_EMAX_DEFAULT;
 
-/* temporaries used in bit ops */
-static NODE *_tz1;
-static NODE *_tz2;
-static mpz_t _mpz1;
-static mpz_t _mpz2;
-static mpz_ptr mpz1;
-static mpz_ptr mpz2;
+/* needed for MPFR and GMP macros */
+#define MPFR_T(x)      ((mpfr_ptr) x)
+#define MPZ_T(x)       ((mpz_ptr) x)
 
-static NODE *get_bit_ops(const char *op);
-#define free_bit_ops() (DEREF(_tz1), DEREF(_tz2))
 
 /* temporary MPFR floats used to hold converted GMP integer operands */
-static mpfr_t _mpf_t1;
-static mpfr_t _mpf_t2;
+static mpfr_t _mp1;
+static mpfr_t _mp2;
 
 /*
- * PRECISION_MIN is the precision used to initialize _mpf_t1 and _mpf_t2.
+ * PRECISION_MIN is the precision used to initialize _mp1 and _mp2.
  * 64 bits should be enough for exact conversion of most integers to floats.
  */
 
 #define PRECISION_MIN  64
 
-/* mf = { _mpf_t1, _mpf_t2 } */
-static inline mpfr_ptr mpg_tofloat(mpfr_ptr mf, mpz_ptr mz);
-/* T = {t1, t2} */
-#define MP_FLOAT(T) is_mpg_integer(T) ? mpg_tofloat(_mpf_##T, (T)->mpg_i) : 
(T)->mpg_numbr
+static mpz_t _mpzval;  /* GMP type for float to int conversion in 
format_tree() */
+static mpfr_t _mpfrval;        /* MPFR type for int to float conversion in 
format_tree() */
+
+#define IEEE_FMT(r, t)         (void) (do_ieee_fmt && mpfp_format_ieee(r, t))
+
+#define mpfp_float()           mpfp_make_node(MPFN)
+#define mpfp_integer()         mpfp_make_node(MPZN)
+#define is_mpfp_float(n)       (((n)->flags & MPFN) != 0)
+#define is_mpfp_integer(n)     (((n)->flags & MPZN) != 0)
+#define is_mpfp_number(n)      (((n)->flags & (MPZN|MPFN)) != 0)
+
+
+/* mpfp_tofloat --- convert GMP integer to MPFR float without loosing any 
precision */
+
+static inline mpfr_ptr
+mpfp_tofloat(const NODE *t, mpfr_ptr pf)
+{
+       return is_mpfp_float(t) ? t->qnumbr : mpz2mpfr(t->qnumbr, pf);
+}
 
 
-/* init_mpfr --- set up MPFR related variables */
 
-void
-init_mpfr(mpfr_prec_t prec, const char *rmode)
+numbr_handler_t mpfp_hndlr = {
+       mpfp_init,
+       mpfp_version_string,
+       mpfp_load_procinfo,
+       mpfp_make_number,
+       mpfp_str2node,
+       mpfp_copy_number,
+       mpfp_free_num,
+       mpfp_force_number,
+       mpfp_negate_num,
+       mpfp_compare,
+       mpfp_sgn,
+       mpfp_is_integer,
+       mpfp_format_val,
+       mpfp_format_nodes,
+       mpfp_todouble,
+       mpfp_tolong,
+       mpfp_toulong,
+       mpfp_touintmax_t,
+       mpfp_add,
+       mpfp_sub,
+       mpfp_mul,
+       mpfp_div,
+       mpfp_mod,
+       mpfp_pow,
+       mpfp_add_long,
+       mpfp_update_var,
+       mpfp_set_var,
+       mpfp_increment_var,
+       mpfp_init_vars,
+};
+
+
+/* mpfp_init --- set up MPFR related variables */
+
+static bool
+mpfp_init(bltin_t **numbr_bltins)
 {
-       mpfr_set_default_prec(prec);
-       ROUND_MODE = get_rnd_mode(rmode[0]);
+       static bltin_t mpfp_bltins[] = {
+               { "and",        do_mpfp_and },
+               { "atan2",      do_mpfp_atan2 },
+               { "compl",      do_mpfp_compl },
+               { "cos",        do_mpfp_cos },
+               { "exp",        do_mpfp_exp },
+               { "int",        do_mpfp_int },
+               { "log",        do_mpfp_log },
+               { "lshift",     do_mpfp_lshift },
+               { "or",         do_mpfp_or },
+               { "rand",       do_mpfp_rand },
+               { "rshift",     do_mpfp_rshift },
+               { "sin",        do_mpfp_sin },
+               { "sqrt",       do_mpfp_sqrt },
+               { "srand",      do_mpfp_srand },
+               { "strtonum",   do_mpfp_strtonum },
+               { "xor",        do_mpfp_xor },
+               { NULL, NULL },
+       };
+       const char *rndmode = DEFAULT_ROUNDMODE;
+
+       mpfr_set_default_prec(DEFAULT_PREC);
+       ROUND_MODE = mpfp_get_rounding_mode(rndmode[0]); 
        mpfr_set_default_rounding_mode(ROUND_MODE);
-       make_number = mpg_make_number;
-       str2number = mpg_force_number;
-       format_val = mpg_format_val;
-       cmp_numbers = mpg_cmp;
 
-       mpz_init(MNR);
-       mpz_init(MFNR);
        do_ieee_fmt = false;
 
-       mpz_init(_mpz1);
-       mpz_init(_mpz2);
-       mpfr_init2(_mpf_t1, PRECISION_MIN);
-       mpfr_init2(_mpf_t2, PRECISION_MIN);
-       mpz_init(mpzval);
+       mpfr_init2(_mp1, PRECISION_MIN);
+       mpfr_init2(_mp2, PRECISION_MIN);
+       mpz_init(_mpzval);
+       mpfr_init2(_mpfrval, PRECISION_MIN);
+
+       /* set the numeric value of null string */
+       emalloc(Nnull_string->qnumbr, void *, sizeof (mpz_t), "mpfp_init");
+       mpz_init(Nnull_string->qnumbr); /* initialized to 0 */
+       Nnull_string->flags |= (MPZN|NUMCUR|NUMBER);
+
+       /* initialize TRUE and FALSE nodes */
+       false_node = mpfp_integer();
+       true_node = mpfp_integer();
+       mpz_set_si(true_node->qnumbr, 1);
+
+       *numbr_bltins = mpfp_bltins;
+       return true;
+}
+
+static void
+mpfp_load_procinfo()
+{
+       char name[64];
+
+       snprintf(name, 64, "GNU MPFR %s", mpfr_get_version());
+       update_PROCINFO_str("mpfr_version", name);
+       snprintf(name, 64, "GNU MP %s", gmp_version);
+       update_PROCINFO_str("gmp_version", name);
+       update_PROCINFO_num("prec_max", MPFR_PREC_MAX);
+       update_PROCINFO_num("prec_min", MPFR_PREC_MIN);
+}
+
+static const char *
+mpfp_version_string()
+{
+       static char version_string[64];
+       snprintf(version_string, 64, "GNU MPFR %s, GNU MP %s", 
mpfr_get_version(), gmp_version);
+       return version_string;
+}
+
+/* mpfp_toulong --- conversion to unsigned long */
+
+static unsigned long
+mpfp_toulong(const NODE *n)
+{
+       return (n->flags & MPFN) ? mpfr_get_ui(n->qnumbr, ROUND_MODE) : 
mpz_get_ui(n->qnumbr);
+}
+
+/* mpfp_tolong --- conversion to long */
+
+static long
+mpfp_tolong(const NODE *n)
+{
+       return (n->flags & MPFN) ? mpfr_get_si(n->qnumbr, ROUND_MODE) : 
mpz_get_si(n->qnumbr);
+}
+
+/* mpfp_todouble --- conversion to AWKNUM */
 
-       register_exec_hook(mpg_interpret, 0);
+static AWKNUM
+mpfp_todouble(const NODE *n)
+{
+       return (n->flags & MPFN) ? mpfr_get_d(n->qnumbr, ROUND_MODE) : 
mpz_get_d(n->qnumbr);
+}
+
+/* mpfp_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+mpfp_touintmax_t(const NODE *n)
+{
+       return (n->flags & MPFN) ? mpfr_get_uj(n->qnumbr, ROUND_MODE) \
+                       : (uintmax_t) mpz_get_d(n->qnumbr);
+}
+
+/* mpfp_sgn --- return 1 if number > 0, zero if number == 0, and -1 if number 
< 0 */
+
+static int
+mpfp_sgn(const NODE *n)
+{
+       return (n->flags & MPFN) ? mpfr_sgn(MPFR_T(n->qnumbr)) \
+               : mpz_sgn(MPZ_T(n->qnumbr));
+}
+
+/* mpfp_is_integer --- check if a number is an integer */
+
+static bool
+mpfp_is_integer(const NODE *n)
+{
+       return is_mpfp_integer(n) ? true : mpfr_integer_p(n->qnumbr);
 }
 
-/* mpg_node --- allocate a node to store MPFR float or GMP integer */
+/* mpfp_make_node --- allocate a node to store MPFR float or GMP integer */
 
-NODE *
-mpg_node(unsigned int tp)
+static NODE *
+mpfp_make_node(unsigned int type)
 {
        NODE *r;
+
        getnode(r);
        r->type = Node_val;
-
-       if (tp == MPFN) {
+       if (type == MPFN) {
                /* Initialize, set precision to the default precision, and 
value to NaN */
-               mpfr_init(r->mpg_numbr);
+               emalloc(r->qnumbr, void *, sizeof (mpfr_t), "mpfp_make_node");
+               mpfr_init(r->qnumbr);
                r->flags = MPFN;
        } else {
                /* Initialize and set value to 0 */
-               mpz_init(r->mpg_i);
+               emalloc(r->qnumbr, void *, sizeof (mpz_t), "mpfp_make_node");
+               mpz_init(r->qnumbr);
                r->flags = MPZN;
        }
        
        r->valref = 1;
-       r->flags |= MALLOC|NUMBER|NUMCUR;
+       r->flags |= (NUMBER|NUMCUR);
        r->stptr = NULL;
        r->stlen = 0;
 #if MBS_SUPPORT
@@ -133,32 +339,26 @@ mpg_node(unsigned int tp)
 }
 
 /*
- * mpg_make_number --- make a arbitrary-precision number node
- *     and initialize with a C double
+ * mpfp_make_number --- make a arbitrary-precision number node
+ *     and initialize with AWKNUM.
  */
 
 static NODE *
-mpg_make_number(double x)
+mpfp_make_number(AWKNUM x)
 {
        NODE *r;
-       double ival;
+       int tval;
 
-       if ((ival = double_to_int(x)) != x) {
-               int tval;
-               r = mpg_float();
-               tval = mpfr_set_d(r->mpg_numbr, x, ROUND_MODE);
-               IEEE_FMT(r->mpg_numbr, tval);
-       } else {
-               r = mpg_integer();
-               mpz_set_d(r->mpg_i, ival);
-       }
+       r = mpfp_float();
+       tval = mpfr_set_d(r->qnumbr, x, ROUND_MODE);
+       IEEE_FMT(r->qnumbr, tval);
        return r;
 }
 
-/* mpg_strtoui --- assign arbitrary-precision integral value from a string */ 
+/* mpfp_strtoui --- assign arbitrary-precision integral value from a string */ 
 
-int
-mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
+static int
+mpfp_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base)
 {
        char *s = str;
        char *start;
@@ -223,10 +423,10 @@ done:
 }
 
 
-/* mpg_maybe_float --- test if a string may contain arbitrary-precision float 
*/
+/* mpfp_maybe_float --- test if a string may contain arbitrary-precision float 
*/
 
 static int
-mpg_maybe_float(const char *str, int use_locale)
+mpfp_maybe_float(const char *str, int use_locale)
 {
        int dec_point = '.';
        const char *s = str;
@@ -258,34 +458,40 @@ mpg_maybe_float(const char *str, int use_locale)
 }
 
 
-/* mpg_zero --- initialize with arbitrary-precision integer(GMP) and set value 
to zero */
+/*
+ * mpfp_init_zero --- initialize with arbitrary-precision integer and set 
value to zero.
+ *     N.B. : this function also converts MPFR number to GMP number.
+ */
 
-static inline void
-mpg_zero(NODE *n)
+static void
+mpfp_init_zero(NODE *n)
 {
-       if (is_mpg_float(n)) {
-               mpfr_clear(n->mpg_numbr);
+       if (is_mpfp_float(n)) {
+               mpfr_clear(n->qnumbr);
+               efree(n->qnumbr);
+               n->qnumbr = NULL;
                n->flags &= ~MPFN;
        }
-       if (! is_mpg_integer(n)) {
-               mpz_init(n->mpg_i);     /* this also sets its value to 0 */ 
+       if (! is_mpfp_integer(n)) {
+               emalloc(n->qnumbr, void *, sizeof (mpz_t), "mpfp_init_zero");
+               mpz_init(n->qnumbr);    /* this also sets its value to 0 */ 
                n->flags |= MPZN;
        } else
-               mpz_set_si(n->mpg_i, 0);
+               mpz_set_si(n->qnumbr, 0);
 }
 
 
-/* force_mpnum --- force a value to be a GMP integer or MPFR float */
+/* mpfp_str2num --- force a value to be a GMP integer or MPFR float */
 
-static int
-force_mpnum(NODE *n, int do_nondec, int use_locale)
+static bool
+mpfp_str2num(NODE *n, int do_nondec, int use_locale)
 {
        char *cp, *cpend, *ptr, *cp1;
        char save;
        int tval, base = 10;
 
        if (n->stlen == 0) {
-               mpg_zero(n);
+               mpfp_init_zero(n);      /* GMP integer */
                return false;
        }
 
@@ -294,7 +500,7 @@ force_mpnum(NODE *n, int do_nondec, int use_locale)
        while (cp < cpend && isspace((unsigned char) *cp))
                cp++;
        if (cp == cpend) {      /* only spaces */
-               mpg_zero(n);
+               mpfp_init_zero(n);
                return false;
        }
 
@@ -309,28 +515,30 @@ force_mpnum(NODE *n, int do_nondec, int use_locale)
        if (do_nondec)
                base = get_numbase(cp1, use_locale);
 
-       if (! mpg_maybe_float(cp1, use_locale)) {
-               mpg_zero(n);
+       if (! mpfp_maybe_float(cp1, use_locale)) {
+               mpfp_init_zero(n);      /* GMP integer */
                errno = 0;
-               mpg_strtoui(n->mpg_i, cp1, cpend - cp1, & ptr, base);
+               mpfp_strtoui(n->qnumbr, cp1, cpend - cp1, & ptr, base);
                if (*cp == '-')
-                       mpz_neg(n->mpg_i, n->mpg_i);
+                       mpz_neg(n->qnumbr, n->qnumbr);
                goto done;
        }
 
-       if (is_mpg_integer(n)) {
-               mpz_clear(n->mpg_i);
+       if (is_mpfp_integer(n)) {
+               mpz_clear(n->qnumbr);
+               efree(n->qnumbr);
                n->flags &= ~MPZN;
        }
 
-       if (! is_mpg_float(n)) {
-               mpfr_init(n->mpg_numbr);
+       if (! is_mpfp_float(n)) {
+               emalloc(n->qnumbr, void *, sizeof (mpfr_t), "mpfp_str2num");
+               mpfr_init(n->qnumbr);
                n->flags |= MPFN;
        }
 
        errno = 0;
-       tval = mpfr_strtofr(n->mpg_numbr, cp, & ptr, base, ROUND_MODE);
-       IEEE_FMT(n->mpg_numbr, tval);
+       tval = mpfr_strtofr(n->qnumbr, cp, & ptr, base, ROUND_MODE);
+       IEEE_FMT(n->qnumbr, tval);
 done:
        /* trailing space is OK for NUMBER */
        while (isspace((unsigned char) *ptr))
@@ -339,17 +547,17 @@ done:
        if (errno == 0 && ptr == cpend)
                return true;
        errno = 0;
-       return false; 
+       return false;
 }
 
-/* mpg_force_number --- force a value to be a multiple-precision number */
+/* mpfp_force_number --- force a value to be a multiple-precision number */
 
 static NODE *
-mpg_force_number(NODE *n)
+mpfp_force_number(NODE *n)
 {
        unsigned int newflags = 0;
 
-       if (is_mpg_number(n) && (n->flags & NUMCUR) != 0)
+       if (is_mpfp_number(n) && (n->flags & NUMCUR) != 0)
                return n;
 
        if ((n->flags & MAYBE_NUM) != 0) {
@@ -357,17 +565,17 @@ mpg_force_number(NODE *n)
                newflags = NUMBER;
        }
 
-       if (force_mpnum(n, (do_non_decimal_data && ! do_traditional), true)) {
+       if (mpfp_str2num(n, (do_non_decimal_data && ! do_traditional), true)) {
                n->flags |= newflags;
                n->flags |= NUMCUR;
        }
        return n;
 }
 
-/* mpg_format_val --- format a numeric value based on format */
+/* mpfp_format_val --- format a numeric value based on format */
 
 static NODE *
-mpg_format_val(const char *format, int index, NODE *s)
+mpfp_format_val(const char *format, int index, NODE *s)
 {
        NODE *dummy[2], *r;
        unsigned int oflags;
@@ -376,12 +584,12 @@ mpg_format_val(const char *format, int index, NODE *s)
        dummy[1] = s;
        oflags = s->flags;
 
-       if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) {
+       if (is_mpfp_integer(s) || mpfr_integer_p(s->qnumbr)) {
                /* integral value, use %d */
-               r = format_tree("%d", 2, dummy, 2);
+               r = mpfp_format_nodes("%d", 2, dummy, 2);
                s->stfmt = -1;
        } else {
-               r = format_tree(format, fmt_list[index]->stlen, dummy, 2);
+               r = mpfp_format_nodes(format, fmt_list[index]->stlen, dummy, 2);
                assert(r != NULL);
                s->stfmt = (char) index;
        }
@@ -397,110 +605,88 @@ mpg_format_val(const char *format, int index, NODE *s)
        return s;
 }
 
-/* mpg_cmp --- compare two numbers */
+/* mpfp_str2node --- create an arbitrary-pecision number from string */
+
+static NODE *
+mpfp_str2node(char *str, char **endptr, int base, bool is_integer)
+{
+       NODE *r;
+
+       if (is_integer) {
+               r = mpfp_integer();
+               mpfp_strtoui(r->qnumbr, str, strlen(str), endptr, base);
+       } else {
+               int tval;
+               r = mpfp_float();
+               tval = mpfr_strtofr(r->qnumbr, str, endptr, base, ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
+       }
+       return r;
+}
+
+/* mpfp_free_num --- free all storage allocated for a multiple-precision 
number */
+
+static void
+mpfp_free_num(NODE *tmp)
+{
+       assert((tmp->flags & (MPFN|MPZN)) != 0);
+        if (is_mpfp_float(tmp))
+                mpfr_clear(tmp->qnumbr);
+        else /* if (is_mpfp_integer(tmp)) */
+                mpz_clear(tmp->qnumbr);
+       efree(tmp->qnumbr);
+       tmp->qnumbr = NULL;
+}
+
+/* mpfp_compare --- compare two numbers */
 
-int
-mpg_cmp(const NODE *t1, const NODE *t2)
+static int
+mpfp_compare(const NODE *t1, const NODE *t2)
 {
        /*
         * For the purposes of sorting, NaN is considered greater than
         * any other value, and all NaN values are considered equivalent and 
equal.
         */
 
-       if (is_mpg_float(t1)) {
-               if (is_mpg_float(t2)) {
-                       if (mpfr_nan_p(t1->mpg_numbr))
-                               return ! mpfr_nan_p(t2->mpg_numbr);
-                       if (mpfr_nan_p(t2->mpg_numbr))
+       if (is_mpfp_float(t1)) {
+               if (is_mpfp_float(t2)) {
+                       if (mpfr_nan_p(MPFR_T(t1->qnumbr)))
+                               return ! mpfr_nan_p(MPFR_T(t2->qnumbr));
+                       if (mpfr_nan_p(MPFR_T(t2->qnumbr)))
                                return -1;
-                       return mpfr_cmp(t1->mpg_numbr, t2->mpg_numbr);
+                       return mpfr_cmp(t1->qnumbr, t2->qnumbr);
                }
-               if (mpfr_nan_p(t1->mpg_numbr))
+               if (mpfr_nan_p(MPFR_T(t1->qnumbr)))
                        return 1;
-               return mpfr_cmp_z(t1->mpg_numbr, t2->mpg_i);
-       } else if (is_mpg_float(t2)) {
+               return mpfr_cmp_z(t1->qnumbr, t2->qnumbr);
+       } else if (is_mpfp_float(t2)) {
                int ret;
-               if (mpfr_nan_p(t2->mpg_numbr))
+
+               if (mpfr_nan_p(MPFR_T(t2->qnumbr)))
                        return -1;
-               ret = mpfr_cmp_z(t2->mpg_numbr, t1->mpg_i);
+               ret = mpfr_cmp_z(t2->qnumbr, t1->qnumbr);
                return ret > 0 ? -1 : (ret < 0);
-       } else if (is_mpg_integer(t1)) {
-               return mpz_cmp(t1->mpg_i, t2->mpg_i);
        }
-
-       /* t1 and t2 are AWKNUMs */
-       return cmp_awknums(t1, t2);
+       assert(is_mpfp_integer(t1) == true);
+       return mpz_cmp(t1->qnumbr, t2->qnumbr);
 }
 
+/* mpfp_init_vars --- set PREC and ROUNDMODE defaults */
 
-/*
- * mpg_update_var --- update NR or FNR. 
- *     NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long) 
- */
-
-NODE *
-mpg_update_var(NODE *n)
+static void
+mpfp_init_vars()
 {
-       NODE *val = n->var_value;
-       long nr = 0;
-       mpz_ptr nq = 0;
-
-       if (n == NR_node) {
-               nr = NR;
-               nq = MNR;
-       } else if (n == FNR_node) {
-               nr = FNR;
-               nq = MFNR;
-       } else
-               cant_happen();
-
-       if (mpz_sgn(nq) == 0) {
-               /* Efficiency hack similar to that for AWKNUM */
-               if (is_mpg_float(val) || mpz_get_si(val->mpg_i) != nr) {
-                       unref(n->var_value);
-                       val = n->var_value = mpg_integer();
-                       mpz_set_si(val->mpg_i, nr);
-               }
-       } else {
-               unref(n->var_value);
-               val = n->var_value = mpg_integer();
-               mpz_set_si(val->mpg_i, nr);
-               mpz_addmul_ui(val->mpg_i, nq, LONG_MAX);        /* val->mpg_i 
+= nq * LONG_MAX */
-       }
-       return val;
+       unref(PREC_node->var_value);
+       PREC_node->var_value = mpfp_make_number(DEFAULT_PREC);
+       unref(ROUNDMODE_node->var_value);
+       ROUNDMODE_node->var_value = make_string(DEFAULT_ROUNDMODE, 
strlen(DEFAULT_ROUNDMODE));
 }
 
-/* mpg_set_var --- set NR or FNR */
-
-long
-mpg_set_var(NODE *n)
-{
-       long nr = 0;
-       mpz_ptr nq = 0, r;
-       NODE *val = n->var_value;
-
-       if (n == NR_node)
-               nq = MNR;
-       else if (n == FNR_node)
-               nq = MFNR;
-       else
-               cant_happen();
-
-       if (is_mpg_integer(val))
-               r = val->mpg_i;
-       else {
-               /* convert float to integer */ 
-               mpfr_get_z(mpzval, val->mpg_numbr, MPFR_RNDZ);
-               r = mpzval;
-       }
-       nr = mpz_fdiv_q_ui(nq, r, LONG_MAX);    /* nq (MNR or MFNR) is quotient 
*/
-       return nr;      /* remainder (NR or FNR) */
-}
 
-/* set_PREC --- update MPFR PRECISION related variables when PREC assigned to 
*/
+/* mpfp_set_PREC --- update MPFR PRECISION related variables when PREC 
assigned to */
 
-void
-set_PREC()
+static void
+mpfp_set_PREC(const NODE *var)
 {
        long prec = 0;
        NODE *val;
@@ -524,12 +710,9 @@ set_PREC()
                 */
        };
 
-       if (! do_mpfr)
-               return;
-
-       val = PREC_node->var_value;
+       val = var->var_value;
        if ((val->flags & MAYBE_NUM) != 0)
-               force_number(val);
+               (void) force_number(val);
 
        if ((val->flags & (STRING|NUMBER)) == STRING) {
                int i, j;
@@ -550,7 +733,6 @@ set_PREC()
                         */
                        max_exp = ieee_fmts[i].emax;
                        min_exp = ieee_fmts[i].emin;
-
                        do_ieee_fmt = true;
                }
        }
@@ -559,7 +741,7 @@ set_PREC()
                force_number(val);
                prec = get_number_si(val);              
                if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) {
-                       force_string(val);
+                       (void) force_string(val);
                        warning(_("PREC value `%.*s' is invalid"), (int) 
val->stlen, val->stptr);
                        prec = 0;
                } else
@@ -571,10 +753,10 @@ set_PREC()
 }
 
 
-/* get_rnd_mode --- convert string to MPFR rounding mode */
+/* mpfp_get_rounding_mode --- convert string to MPFR rounding mode */
 
 static mpfr_rnd_t
-get_rnd_mode(const char rmode)
+mpfp_get_rounding_mode(const char rmode)
 {
        switch (rmode) {
        case 'N':
@@ -601,32 +783,115 @@ get_rnd_mode(const char rmode)
 }
 
 /*
- * set_ROUNDMODE --- update MPFR rounding mode related variables
+ * mpfp_set_ROUNDMODE --- update MPFR rounding mode related variables
  *     when ROUNDMODE assigned to
  */
 
-void
-set_ROUNDMODE()
+static void
+mpfp_set_ROUNDMODE(const NODE *var)
 {
-       if (do_mpfr) {
-               mpfr_rnd_t rndm = -1;
-               NODE *n;
-               n = force_string(ROUNDMODE_node->var_value);
-               if (n->stlen == 1)
-                       rndm = get_rnd_mode(n->stptr[0]);
-               if (rndm != -1) {
-                       mpfr_set_default_rounding_mode(rndm);
-                       ROUND_MODE = rndm;
-               } else
-                       warning(_("RNDMODE value `%.*s' is invalid"), (int) 
n->stlen, n->stptr);
+       mpfr_rnd_t rndmode = -1;
+       NODE *val;
+
+       val = force_string(var->var_value);
+       if (val->stlen == 1)
+               rndmode = mpfp_get_rounding_mode(val->stptr[0]);
+       if (rndmode != -1) {
+               mpfr_set_default_rounding_mode(rndmode);
+               ROUND_MODE = rndmode;
+       } else
+               warning(_("ROUNDMODE value `%.*s' is invalid"), (int) 
val->stlen, val->stptr);
+}
+
+/*
+ * mpfp_update_var --- update NR or FNR. 
+ *     NR_node->var_value(mpz_t) = MNR(mpz_t) * LONG_MAX + NR(long) 
+ */
+
+static NODE *
+mpfp_update_var(NODE *n)
+{
+       NODE *val = n->var_value;
+       long nr = 0;
+       mpz_ptr nq = 0;
+
+       if (n == NR_node) {
+               nr = NR;
+               nq = MNR;
+       } else {
+               assert(n == FNR_node);
+               nr = FNR;
+               nq = MFNR;
+       }
+
+       if (mpz_sgn(nq) == 0) {
+               /* Efficiency hack similar to that for AWKNUM */
+               if (is_mpfp_float(val) || mpz_get_si(val->qnumbr) != nr) {
+                       unref(val);
+                       val = n->var_value = mpfp_integer();
+                       mpz_set_si(val->qnumbr, nr);
+               }
+       } else {
+               unref(val);
+               val = n->var_value = mpfp_integer();
+               mpz_set_si(val->qnumbr, nr);
+               mpz_addmul_ui(val->qnumbr, nq, LONG_MAX);       /* val->mpg_i 
+= nq * LONG_MAX */
+       }
+       return val;
+}
+
+/* mpfp_set_var --- set internal variables */
+
+static void
+mpfp_set_var(const NODE *var)
+{
+       if (var == PREC_node)
+               mpfp_set_PREC(var);
+       else if (var == ROUNDMODE_node)
+               mpfp_set_ROUNDMODE(var);
+       else {
+               NODE *val = var->var_value;
+               mpz_ptr r;
+               mpz_t mpz_val;
+
+               if (is_mpfp_integer(val))
+                       r = val->qnumbr;
+               else {
+                       /* convert float to integer */
+                       mpz_init(mpz_val);
+                       mpfr_get_z(mpz_val, val->qnumbr, MPFR_RNDZ);
+                       r = mpz_val;
+               }
+
+               if (var == NR_node)
+                       NR = mpz_fdiv_q_ui(MNR, r, LONG_MAX);   /* MNR is 
quotient */
+               else
+                       FNR = mpz_fdiv_q_ui(MFNR, r, LONG_MAX);
+               if (r != val->qnumbr)
+                       mpz_clear(mpz_val);
        }
 }
 
+/* mpfp_increment_var --- increment NR or FNR */
+
+static long
+mpfp_increment_var(const NODE *var, long nr)
+{
+       if (nr == LONG_MAX - 1) {
+               /* increment quotient, set remainder(NR or FNR) to 0 */
+               if (var == NR_node)
+                       mpz_add_ui(MNR, MNR, 1);
+               else /* if (var == FNR_node) */
+                       mpz_add_ui(MFNR, MFNR, 1);
+               return 0;
+       }
+       return ++nr;
+}
 
-/* format_ieee --- make sure a number follows IEEE-754 floating-point standard 
*/
+/* mpfp_format_ieee --- make sure a number follows IEEE-754 floating-point 
standard */
 
-int
-format_ieee(mpfr_ptr x, int tval)
+static int
+mpfp_format_ieee(mpfr_ptr x, int tval)
 {
        /*
         * The MPFR doc says that it's our responsibility to make sure all 
numbers
@@ -667,11 +932,23 @@ format_ieee(mpfr_ptr x, int tval)
        return tval;
 }
 
+/* mpfp_negate_num --- negate a number in NODE */
+
+static void
+mpfp_negate_num(NODE *n)
+{
+       if (is_mpfp_float(n)) {
+               int tval;
+               tval = mpfr_neg(n->qnumbr, n->qnumbr, ROUND_MODE);
+               IEEE_FMT(n->qnumbr, tval);
+       } else /* if (is_mpfp_integer(n)) */
+               mpz_neg(n->qnumbr, n->qnumbr);
+}
 
-/* do_mpfr_atan2 --- do the atan2 function */
+/* do_mpfp_atan2 --- do the atan2 function */
 
-NODE *
-do_mpfr_atan2(int nargs)
+static NODE *
+do_mpfp_atan2(int nargs)
 {
        NODE *t1, *t2, *res;
        mpfr_ptr p1, p2;
@@ -686,15 +963,17 @@ do_mpfr_atan2(int nargs)
                if ((t2->flags & (NUMCUR|NUMBER)) == 0)
                        lintwarn(_("atan2: received non-numeric second 
argument"));
        }
-       force_number(t1);
-       force_number(t2);
 
-       p1 = MP_FLOAT(t1);
-       p2 = MP_FLOAT(t2);
-       res = mpg_float();
+       (void) force_number(t1);
+       (void) force_number(t2);
+
+       p1 = mpfp_tofloat(t1, _mp1);
+       p2 = mpfp_tofloat(t2, _mp2);
+
+       res = mpfp_float();
        /* See MPFR documentation for handling of special values like +inf as 
an argument */ 
-       tval = mpfr_atan2(res->mpg_numbr, p1, p2, ROUND_MODE);
-       IEEE_FMT(res->mpg_numbr, tval);
+       tval = mpfr_atan2(res->qnumbr, p1, p2, ROUND_MODE);
+       IEEE_FMT(res->qnumbr, tval);
 
        DEREF(t1);
        DEREF(t2);
@@ -702,95 +981,94 @@ do_mpfr_atan2(int nargs)
 }
 
 
-#define SPEC_MATH(X)                                           \
+#define MPFPFUNC(X)                                            \
 NODE *t1, *res;                                                        \
 mpfr_ptr p1;                                                   \
 int tval;                                                      \
 t1 = POP_SCALAR();                                             \
 if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)             \
        lintwarn(_("%s: received non-numeric argument"), #X);   \
-force_number(t1);                                              \
-p1 = MP_FLOAT(t1);                                             \
-res = mpg_float();                                             \
-tval = mpfr_##X(res->mpg_numbr, p1, ROUND_MODE);                       \
-IEEE_FMT(res->mpg_numbr, tval);                                        \
+t1 = force_number(t1);                                         \
+p1 = mpfp_tofloat(t1, _mp1);                                   \
+res = mpfp_float();                                            \
+tval = mpfr_##X(res->qnumbr, p1, ROUND_MODE);                  \
+IEEE_FMT(res->qnumbr, tval);                                   \
 DEREF(t1);                                                     \
 return res
 
 
-/* do_mpfr_sin --- do the sin function */
+/* do_mpfp_sin --- do the sin function */
 
-NODE *
-do_mpfr_sin(int nargs)
+static NODE *
+do_mpfp_sin(int nargs)
 {
-       SPEC_MATH(sin);
+       MPFPFUNC(sin);
 }
 
-/* do_mpfr_cos --- do the cos function */
+/* do_mpfp_cos --- do the cos function */
 
-NODE *
-do_mpfr_cos(int nargs)
+static NODE *
+do_mpfp_cos(int nargs)
 {
-       SPEC_MATH(cos);
+       MPFPFUNC(cos);
 }
 
-/* do_mpfr_exp --- exponential function */
+/* do_mpfp_exp --- exponential function */
 
-NODE *
-do_mpfr_exp(int nargs)
+static NODE *
+do_mpfp_exp(int nargs)
 {
-       SPEC_MATH(exp);
+       MPFPFUNC(exp);
 }
 
-/* do_mpfr_log --- the log function */
+/* do_mpfp_log --- the log function */
 
-NODE *
-do_mpfr_log(int nargs)
+static NODE *
+do_mpfp_log(int nargs)
 {
-       SPEC_MATH(log);
+       MPFPFUNC(log);
 }
 
-/* do_mpfr_sqrt --- do the sqrt function */
+/* do_mpfp_sqrt --- do the sqrt function */
 
-NODE *
-do_mpfr_sqrt(int nargs)
+static NODE *
+do_mpfp_sqrt(int nargs)
 {
-       SPEC_MATH(sqrt);
+       MPFPFUNC(sqrt);
 }
 
-/* do_mpfr_int --- convert double to int for awk */
+/* do_mpfp_int --- convert floating point number to integer for awk */
 
-NODE *
-do_mpfr_int(int nargs)
+static NODE *
+do_mpfp_int(int nargs)
 {
        NODE *tmp, *r;
 
        tmp = POP_SCALAR();
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("int: received non-numeric argument"));
-       force_number(tmp);
+       tmp = force_number(tmp);
 
-       if (is_mpg_integer(tmp)) {
-               r = mpg_integer();
-               mpz_set(r->mpg_i, tmp->mpg_i);
+       if (is_mpfp_integer(tmp)) {
+               r = mpfp_integer();
+               mpz_set(r->qnumbr, tmp->qnumbr);
        } else {
-               if (! mpfr_number_p(tmp->mpg_numbr)) {
+               if (! mpfr_number_p(tmp->qnumbr)) {
                        /* [+-]inf or NaN */
                        return tmp;
                }
-
-               r = mpg_integer();
-               mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ);
+               r = mpfp_integer();
+               mpfr_get_z(r->qnumbr, tmp->qnumbr, MPFR_RNDZ);
        }
 
        DEREF(tmp);
        return r;
 }
 
-/* do_mpfr_compl --- perform a ~ operation */
+/* do_mpfp_compl --- perform a ~ operation */
 
-NODE *
-do_mpfr_compl(int nargs)
+static NODE *
+do_mpfp_compl(int nargs)
 {
        NODE *tmp, *r;
        mpz_ptr zptr;
@@ -799,9 +1077,9 @@ do_mpfr_compl(int nargs)
        if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                lintwarn(_("compl: received non-numeric argument"));
 
-       force_number(tmp);
-       if (is_mpg_float(tmp)) {
-               mpfr_ptr p = tmp->mpg_numbr;
+       (void) force_number(tmp);
+       if (is_mpfp_float(tmp)) {
+               mpfr_ptr p = tmp->qnumbr;
 
                if (! mpfr_number_p(p)) {
                        /* [+-]inf or NaN */
@@ -810,236 +1088,288 @@ do_mpfr_compl(int nargs)
                if (do_lint) {
                        if (mpfr_sgn(p) < 0)
                                lintwarn("%s",
-                       mpg_fmt(_("compl(%Rg): negative value will give strange 
results"), p)
+                       mpfp_sprintf(_("compl(%Rg): negative value will give 
strange results"), p)
                                        );
                        if (! mpfr_integer_p(p))
                                lintwarn("%s",
-                       mpg_fmt(_("comp(%Rg): fractional value will be 
truncated"), p)
+                       mpfp_sprintf(_("comp(%Rg): fractional value will be 
truncated"), p)
                                        );
                }
-               
-               mpfr_get_z(mpzval, p, MPFR_RNDZ);       /* float to integer 
conversion */
-               zptr = mpzval;
+
+               emalloc(zptr, mpz_ptr, sizeof (mpz_t), "do_mpfr_compl");
+               mpz_init(zptr);
+               mpfr_get_z(zptr, p, MPFR_RNDZ); /* float to integer conversion 
*/
+
        } else {
                /* (tmp->flags & MPZN) != 0 */ 
-               zptr = tmp->mpg_i;
+               zptr = tmp->qnumbr;
                if (do_lint) {
                        if (mpz_sgn(zptr) < 0)
                                lintwarn("%s",
-                       mpg_fmt(_("cmpl(%Zd): negative values will give strange 
results"), zptr)
+                       mpfp_sprintf(_("cmpl(%Zd): negative values will give 
strange results"), zptr)
                                        );
                }
        }
 
-       r = mpg_integer();
-       mpz_com(r->mpg_i, zptr);
+       r = mpfp_integer();
+       mpz_com(r->qnumbr, zptr);
+
+       if (zptr != tmp->qnumbr) {
+               mpz_clear(zptr);
+               efree(zptr);
+       }
        DEREF(tmp);
        return r;
 }
 
 
-/*
- * get_bit_ops --- get the numeric operands of a binary function.
- *     Returns a copy of the operand if either is inf or nan. Otherwise
- *     each operand is converted to an integer if necessary, and
- *     the results are placed in the variables mpz1 and mpz2.
- */
+/* get_intval --- get the (converted) integral operand of a binary function. */
 
-static NODE *
-get_bit_ops(const char *op)
+static mpz_ptr
+get_intval(NODE *t1, int argnum, const char *op)
 {
-       _tz2 = POP_SCALAR();
-       _tz1 = POP_SCALAR();
+       mpz_ptr pz;
 
-       if (do_lint) {
-               if ((_tz1->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("%s: received non-numeric first argument"), 
op);
-               if ((_tz2->flags & (NUMCUR|NUMBER)) == 0)
-                       lintwarn(_("%s: received non-numeric second argument"), 
op);
-       }
+       if (do_lint && (t1->flags & (NUMCUR|NUMBER)) == 0)
+               lintwarn(_("%s: received non-numeric argument #%d"), op, 
argnum);
 
-       force_number(_tz1);
-       force_number(_tz2);
+       (void) force_number(t1);
 
-       if (is_mpg_float(_tz1)) {
-               mpfr_ptr left = _tz1->mpg_numbr;
+       if (is_mpfp_float(t1)) {
+               mpfr_ptr left = t1->qnumbr;
                if (! mpfr_number_p(left)) {
                        /* inf or NaN */
                        NODE *res;
-                       res = mpg_float();
-                       mpfr_set(res->mpg_numbr, _tz1->mpg_numbr, ROUND_MODE);
-                       return res;
+                       if (do_lint)
+                                       lintwarn("%s",
+               mpfp_sprintf(_("%s: argument #%d has invalid value %Rg, using 
0"),
+                                       op, argnum, left)
+                               );
+                       emalloc(pz, mpz_ptr, sizeof (mpz_t), "get_intval");
+                       mpz_init(pz);
+                       return pz;      /* should be freed */
                }
 
                if (do_lint) {
                        if (mpfr_sgn(left) < 0)
                                lintwarn("%s",
-                       mpg_fmt(_("%s(%Rg, ..): negative values will give 
strange results"),
-                                               op, left)
-                                       );
+               mpfp_sprintf(_("%s: argument #%d negative value %Rg will give 
strange results"),
+                                       op, argnum, left)
+                               );
+
                        if (! mpfr_integer_p(left))
                                lintwarn("%s",
-                       mpg_fmt(_("%s(%Rg, ..): fractional values will be 
truncated"),
-                                               op, left)
+               mpfp_sprintf(_("%s: argument #%d fractional value %Rg will be 
truncated"),
+                                       op, argnum, left)
                                );
                }
-               
-               mpfr_get_z(_mpz1, left, MPFR_RNDZ);     /* float to integer 
conversion */
-               mpz1 = _mpz1;
-       } else {
-               /* (_tz1->flags & MPZN) != 0 */ 
-               mpz1 = _tz1->mpg_i;
-               if (do_lint) {
-                       if (mpz_sgn(mpz1) < 0)
-                               lintwarn("%s",
-                       mpg_fmt(_("%s(%Zd, ..): negative values will give 
strange results"),
-                                               op, mpz1)
-                                       );
-               }
-       }
 
-       if (is_mpg_float(_tz2)) {
-               mpfr_ptr right = _tz2->mpg_numbr;
-               if (! mpfr_number_p(right)) {
-                       /* inf or NaN */
-                       NODE *res;
-                       res = mpg_float();
-                       mpfr_set(res->mpg_numbr, _tz2->mpg_numbr, ROUND_MODE);
-                       return res;
-               }
+               emalloc(pz, mpz_ptr, sizeof (mpz_t), "get_intval");
+               mpz_init(pz);
+               mpfr_get_z(pz, left, MPFR_RNDZ);        /* float to integer 
conversion */
+               return pz;      /* should be freed */
+       }
 
-               if (do_lint) {
-                       if (mpfr_sgn(right) < 0)
-                               lintwarn("%s",
-                       mpg_fmt(_("%s(.., %Rg): negative values will give 
strange results"),
-                                               op, right)
-                                       );
-                       if (! mpfr_integer_p(right))
-                               lintwarn("%s",
-                       mpg_fmt(_("%s(.., %Rg): fractional values will be 
truncated"),
-                                               op, right)
+       /* (t1->flags & MPZN) != 0 */ 
+       pz = t1->qnumbr;
+       if (do_lint) {
+               if (mpz_sgn(pz) < 0)
+                       lintwarn("%s",
+       mpfp_sprintf(_("%s: argument #%d negative value %Zd will give strange 
results"),
+                                       op, argnum, pz)
                                );
-               }
-
-               mpfr_get_z(_mpz2, right, MPFR_RNDZ);    /* float to integer 
conversion */
-               mpz2 = _mpz2;
-       } else {
-               /* (_tz2->flags & MPZN) != 0 */ 
-               mpz2 = _tz2->mpg_i;
-               if (do_lint) {
-                       if (mpz_sgn(mpz2) < 0)
-                               lintwarn("%s",
-                       mpg_fmt(_("%s(.., %Zd): negative values will give 
strange results"),
-                                               op, mpz2)
-                                       );
-               }
        }
+       return pz;      /* must not be freed */
+}
+
+/* free_intval --- free the converted integer value returned by get_intval() */
 
-       return NULL;
+static inline void
+free_intval(NODE *t, mpz_ptr pz)
+{
+       if (t->qnumbr != pz) {
+               mpz_clear(pz);
+               efree(pz);
+       }
 }
 
-/* do_mpfr_lshift --- perform a << operation */
+/* do_mpfp_lshift --- perform a << operation */
 
-NODE *
-do_mpfr_lshift(int nargs)
+static NODE *
+do_mpfp_lshift(int nargs)
 {
-       NODE *res;
+       NODE *t1, *t2, *res;
        unsigned long shift;
+       mpz_ptr pz1, pz2;
+ 
+       t2 = POP_SCALAR();
+       t1 = POP_SCALAR();
 
-       if ((res = get_bit_ops("lshift")) == NULL) {
+       pz1 = get_intval(t1, 1, "lshift");
+       pz2 = get_intval(t2, 2, "lshift");
 
-               /*
-                * mpz_get_ui: If op is too big to fit an unsigned long then 
just
-                * the least significant bits that do fit are returned.
-                * The sign of op is ignored, only the absolute value is used.
-                */
+       /*
+        * mpz_get_ui: If op is too big to fit an unsigned long then just
+        * the least significant bits that do fit are returned.
+        * The sign of op is ignored, only the absolute value is used.
+        */
 
-               shift = mpz_get_ui(mpz2);       /* GMP integer => unsigned long 
conversion */
-               res = mpg_integer();
-               mpz_mul_2exp(res->mpg_i, mpz1, shift);          /* res = mpz1 * 
2^shift */
-       }
-       free_bit_ops();
+       shift = mpz_get_ui(pz2);        /* GMP integer => unsigned long 
conversion */
+       res = mpfp_integer();
+       mpz_mul_2exp(res->qnumbr, pz1, shift);          /* res = pz1 * 2^shift 
*/
+
+       free_intval(t1, pz1);
+       free_intval(t2, pz2);
+       DEREF(t2);
+       DEREF(t1);
        return res;
 }
 
-/* do_mpfr_rshift --- perform a >> operation */
+/* do_mpfp_rshift --- perform a >> operation */
 
-NODE *
-do_mpfr_rhift(int nargs)
+static NODE *
+do_mpfp_rshift(int nargs)
 {
-       NODE *res;
+       NODE *t1, *t2, *res;
        unsigned long shift;
+       mpz_ptr pz1, pz2;
+ 
+       t2 = POP_SCALAR();
+       t1 = POP_SCALAR();
 
-       if ((res = get_bit_ops("rshift")) == NULL) {
-               /*
-                * mpz_get_ui: If op is too big to fit an unsigned long then 
just
-                * the least significant bits that do fit are returned.
-                * The sign of op is ignored, only the absolute value is used.
-                */
+       pz1 = get_intval(t1, 1, "rshift");
+       pz2 = get_intval(t2, 2, "rshift");
 
-               shift = mpz_get_ui(mpz2);       /* GMP integer => unsigned long 
conversion */
-               res = mpg_integer();
-               mpz_fdiv_q_2exp(res->mpg_i, mpz1, shift);       /* res = mpz1 / 
2^shift, round towards −inf */
-       }
-       free_bit_ops();
+       /* N.B: See do_mpfp_lshift. */
+       shift = mpz_get_ui(pz2);        /* GMP integer => unsigned long 
conversion */
+       res = mpfp_integer();
+       mpz_fdiv_q_2exp(res->qnumbr, pz1, shift);       /* res = pz1 / 2^shift, 
round towards −inf */
+
+       free_intval(t1, pz1);
+       free_intval(t2, pz2);
+       DEREF(t2);
+       DEREF(t1);
        return res;
 }
 
-/* do_mpfr_and --- perform an & operation */
+/* do_mpfp_and --- perform an & operation */
 
-NODE *
-do_mpfr_and(int nargs)
+static NODE *
+do_mpfp_and(int nargs)
 {
-       NODE *res;
+       NODE *t1, *t2, *res;
+       mpz_ptr pz1, pz2;
+       int i;
 
-       if ((res = get_bit_ops("and")) == NULL) {
-               res = mpg_integer();
-               mpz_and(res->mpg_i, mpz1, mpz2);
+       if (nargs < 2)
+               fatal(_("and: called with less than two arguments"));
+
+       t2 = POP_SCALAR();
+       pz2 = get_intval(t2, nargs, "and");
+
+       res = mpfp_integer();
+       for (i = 1; i < nargs; i++) {
+               t1 = POP_SCALAR();
+               pz1 = get_intval(t1, nargs - i, "and");
+               mpz_and(res->qnumbr, pz1, pz2);
+               free_intval(t1, pz1);
+               DEREF(t1);
+               if (i == 1) {
+                       free_intval(t2, pz2);
+                       DEREF(t2);
+               }
+               pz2 = res->qnumbr;
        }
-       free_bit_ops();
        return res;
 }
 
-/* do_mpfr_or --- perform an | operation */
+/* do_mpfp_or --- perform an | operation */
 
-NODE *
-do_mpfr_or(int nargs)
+static NODE *
+do_mpfp_or(int nargs)
 {
-       NODE *res;
+       NODE *t1, *t2, *res;
+       mpz_ptr pz1, pz2;
+       int i;
 
-       if ((res = get_bit_ops("or")) == NULL) {
-               res = mpg_integer();
-               mpz_ior(res->mpg_i, mpz1, mpz2);
+       if (nargs < 2)
+               fatal(_("or: called with less than two arguments"));
+
+       t2 = POP_SCALAR();
+       pz2 = get_intval(t2, nargs, "or");
+
+       res = mpfp_integer();
+       for (i = 1; i < nargs; i++) {
+               t1 = POP_SCALAR();
+               pz1 = get_intval(t1, nargs - i, "or");
+               mpz_ior(res->qnumbr, pz1, pz2);
+               free_intval(t1, pz1);
+               DEREF(t1);
+               if (i == 1) {
+                       free_intval(t2, pz2);
+                       DEREF(t2);
+               }
+               pz2 = res->qnumbr;
        }
-       free_bit_ops();
        return res;
 }
 
-/* do_mpfr_strtonum --- the strtonum function */
+/* do_mpfp_xor --- perform an ^ operation */
 
-NODE *
-do_mpfr_strtonum(int nargs)
+static NODE *
+do_mpfp_xor(int nargs)
+{
+       NODE *t1, *t2, *res;
+       mpz_ptr pz1, pz2;
+       int i;
+
+       if (nargs < 2)
+               fatal(_("xor: called with less than two arguments"));
+
+       t2 = POP_SCALAR();
+       pz2 = get_intval(t2, nargs, "xor");
+
+       res = mpfp_integer();
+       for (i = 1; i < nargs; i++) {
+               t1 = POP_SCALAR();
+               pz1 = get_intval(t1, nargs - i, "xor");
+               mpz_xor(res->qnumbr, pz1, pz2);
+               free_intval(t1, pz1);
+               DEREF(t1);
+               if (i == 1) {
+                       free_intval(t2, pz2);
+                       DEREF(t2);
+               }
+               pz2 = res->qnumbr;
+       }
+       return res;
+}
+
+/* do_mpfp_strtonum --- the strtonum function */
+
+static NODE *
+do_mpfp_strtonum(int nargs)
 {
        NODE *tmp, *r;
 
        tmp = POP_SCALAR();
        if ((tmp->flags & (NUMBER|NUMCUR)) == 0) {
-               r = mpg_integer();      /* will be changed to MPFR float if 
necessary in force_mpnum() */
+               r = mpfp_integer();     /* will be changed to MPFR float if 
necessary in force_mpnum() */
                r->stptr = tmp->stptr;
                r->stlen = tmp->stlen;
-               force_mpnum(r, true, use_lc_numeric);
+               mpfp_str2num(r, true, use_lc_numeric);
                r->stptr = NULL;
                r->stlen = 0;
        } else {
                (void) force_number(tmp);
-               if (is_mpg_float(tmp)) {
+               if (is_mpfp_float(tmp)) {
                        int tval;
-                       r = mpg_float();
-                       tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, 
ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
+                       r = mpfp_float();
+                       tval = mpfr_set(r->qnumbr, (mpfr_ptr) tmp->qnumbr, 
ROUND_MODE);
+                       IEEE_FMT(r->qnumbr, tval);
                } else {
-                       r = mpg_integer();
-                       mpz_set(r->mpg_i, tmp->mpg_i);
+                       r = mpfp_integer();
+                       mpz_set(r->qnumbr, tmp->qnumbr);
                }
        }
 
@@ -1047,30 +1377,15 @@ do_mpfr_strtonum(int nargs)
        return r;
 }
 
-/* do_mpfr_xor --- perform an ^ operation */
-
-NODE *
-do_mpfr_xor(int nargs)
-{
-       NODE *res;
-
-       if ((res = get_bit_ops("xor")) == NULL) {
-               res = mpg_integer();
-               mpz_xor(res->mpg_i, mpz1, mpz2);
-       }
-       free_bit_ops();
-       return res;
-}
-
 
 static bool firstrand = true;
 static gmp_randstate_t state;
 static mpz_t seed;     /* current seed */
 
-/* do_mpfr_rand --- do the rand function */
+/* do_mpfp_rand --- do the rand function */
 
-NODE *
-do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
+static NODE *
+do_mpfp_rand(int nargs ATTRIBUTE_UNUSED)
 {
        NODE *res;
        int tval;
@@ -1093,17 +1408,17 @@ do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
                gmp_randseed(state, seed);
                firstrand = false;
        }
-       res = mpg_float();
-       tval = mpfr_urandomb(res->mpg_numbr, state);
-       IEEE_FMT(res->mpg_numbr, tval);
+       res = mpfp_float();
+       tval = mpfr_urandomb(res->qnumbr, state);
+       IEEE_FMT(res->qnumbr, tval);
        return res;
 }
 
 
-/* do_mpfr_srand --- seed the random number generator */
+/* do_mpfp_srand --- seed the random number generator */
 
-NODE *
-do_mpfr_srand(int nargs)
+static NODE *
+do_mpfp_srand(int nargs)
 {
        NODE *res;
 
@@ -1125,8 +1440,8 @@ do_mpfr_srand(int nargs)
                firstrand = false;
        }
 
-       res = mpg_integer();
-       mpz_set(res->mpg_i, seed);      /* previous seed */
+       res = mpfp_integer();
+       mpz_set(res->qnumbr, seed);     /* previous seed */
 
        if (nargs == 0)
                mpz_set_ui(seed, (unsigned long) time((time_t *) 0));
@@ -1135,11 +1450,11 @@ do_mpfr_srand(int nargs)
                tmp = POP_SCALAR();
                if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
                        lintwarn(_("srand: received non-numeric argument"));
-               force_number(tmp);
-               if (is_mpg_float(tmp))
-                       mpfr_get_z(seed, tmp->mpg_numbr, MPFR_RNDZ);
+               (void) force_number(tmp);
+               if (is_mpfp_float(tmp))
+                       mpfr_get_z(seed, tmp->qnumbr, MPFR_RNDZ);
                else /* MP integer */
-                       mpz_set(seed, tmp->mpg_i);
+                       mpz_set(seed, tmp->qnumbr);
                DEREF(tmp);
        }
 
@@ -1147,445 +1462,223 @@ do_mpfr_srand(int nargs)
        return res;
 }
 
-/*
- * mpg_tofloat --- convert an arbitrary-precision integer operand to
- *     a float without loss of precision. It is assumed that the
- *     MPFR variable has already been initialized.
- */
 
-static inline mpfr_ptr
-mpg_tofloat(mpfr_ptr mf, mpz_ptr mz)
-{
-       size_t prec;
-
-       /*
-        * When implicitely converting a GMP integer operand to a MPFR float, 
use
-        * a precision sufficiently large to hold the converted value exactly.
-        *      
-        *      $ ./gawk -M 'BEGIN { print 13 % 2 }'
-        *      1
-        * If the user-specified precision is used to convert the integer 13 to 
a
-        * float, one will get:
-        *      $ ./gawk -M 'BEGIN { PREC=2; print 13 % 2.0 }'
-        *      0       
-        */
-
-       prec = mpz_sizeinbase(mz, 2);   /* most significant 1 bit position 
starting at 1 */
-       if (prec > PRECISION_MIN) {
-               prec -= (size_t) mpz_scan1(mz, 0);      /* least significant 1 
bit index starting at 0 */
-               if (prec > MPFR_PREC_MAX)
-                       prec = MPFR_PREC_MAX;
-               if (prec > PRECISION_MIN) 
-                       mpfr_set_prec(mf, prec);
-       }
-
-       mpfr_set_z(mf, mz, ROUND_MODE);
-       return mf;
-}
-
-
-/* mpg_add --- add arbitrary-precision numbers */ 
+/* mpfp_add --- add arbitrary-precision numbers */ 
 
 static NODE *
-mpg_add(NODE *t1, NODE *t2)
+mpfp_add(const NODE *t1, const NODE *t2)
 {
        NODE *r;
        int tval;
 
-       if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
-               r = mpg_integer();
-               mpz_add(r->mpg_i, t1->mpg_i, t2->mpg_i);
+       if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+               r = mpfp_integer();
+               mpz_add(r->qnumbr, t1->qnumbr, t2->qnumbr);
        } else {
-               r = mpg_float();
-               if (is_mpg_integer(t2))
-                       tval = mpfr_add_z(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_i, ROUND_MODE);
-               else if (is_mpg_integer(t1))
-                       tval = mpfr_add_z(r->mpg_numbr, t2->mpg_numbr, 
t1->mpg_i, ROUND_MODE);
+               r = mpfp_float();
+               if (is_mpfp_integer(t2))
+                       tval = mpfr_add_z(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+               else if (is_mpfp_integer(t1))
+                       tval = mpfr_add_z(r->qnumbr, t2->qnumbr, t1->qnumbr, 
ROUND_MODE);
                else
-                       tval = mpfr_add(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_numbr, ROUND_MODE);
-               IEEE_FMT(r->mpg_numbr, tval);
+                       tval = mpfr_add(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
        }
        return r;
 }
 
-/* mpg_sub --- subtract arbitrary-precision numbers */
+/* mpfp_sub --- subtract arbitrary-precision numbers */
 
 static NODE *
-mpg_sub(NODE *t1, NODE *t2)
+mpfp_sub(const NODE *t1, const NODE *t2)
 {
        NODE *r;
        int tval;
 
-       if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
-               r = mpg_integer();
-               mpz_sub(r->mpg_i, t1->mpg_i, t2->mpg_i);
+       if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+               r = mpfp_integer();
+               mpz_sub(r->qnumbr, t1->qnumbr, t2->qnumbr);
        } else {
-               r = mpg_float();
-               if (is_mpg_integer(t2))
-                       tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_i, ROUND_MODE);
-               else if (is_mpg_integer(t1)) {
+               r = mpfp_float();
+               if (is_mpfp_integer(t2))
+                       tval = mpfr_sub_z(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+               else if (is_mpfp_integer(t1)) {
 #if (!defined(MPFR_VERSION) || (MPFR_VERSION < MPFR_VERSION_NUM(3,1,0)))
-                       NODE *tmp = t1;
+                       const NODE *tmp = t1;
+
                        t1 = t2;
                        t2 = tmp;
-                       tval = mpfr_sub_z(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_i, ROUND_MODE);
-                       tval = mpfr_neg(r->mpg_numbr, r->mpg_numbr, ROUND_MODE);
+                       tval = mpfr_sub_z(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+                       tval = mpfr_neg(r->qnumbr, r->qnumbr, ROUND_MODE);
                        t2 = t1;
                        t1 = tmp;
 #else
-                       tval = mpfr_z_sub(r->mpg_numbr, t1->mpg_i, 
t2->mpg_numbr, ROUND_MODE);
+                       tval = mpfr_z_sub(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
 #endif
                } else
-                       tval = mpfr_sub(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_numbr, ROUND_MODE);
-               IEEE_FMT(r->mpg_numbr, tval);
+                       tval = mpfr_sub(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
        }
        return r;
 }
 
-/* mpg_mul --- multiply arbitrary-precision numbers */
+/* mpfp_mul --- multiply arbitrary-precision numbers */
 
 static NODE *
-mpg_mul(NODE *t1, NODE *t2)
+mpfp_mul(const NODE *t1, const NODE *t2)
 {
        NODE *r;
        int tval;
 
-       if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
-               r = mpg_integer();
-               mpz_mul(r->mpg_i, t1->mpg_i, t2->mpg_i);
+       if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+               r = mpfp_integer();
+               mpz_mul(r->qnumbr, t1->qnumbr, t2->qnumbr);
        } else {
-               r = mpg_float();
-               if (is_mpg_integer(t2))
-                       tval = mpfr_mul_z(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_i, ROUND_MODE);
-               else if (is_mpg_integer(t1))
-                       tval = mpfr_mul_z(r->mpg_numbr, t2->mpg_numbr, 
t1->mpg_i, ROUND_MODE);
+               r = mpfp_float();
+               if (is_mpfp_integer(t2))
+                       tval = mpfr_mul_z(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+               else if (is_mpfp_integer(t1))
+                       tval = mpfr_mul_z(r->qnumbr, t2->qnumbr, t1->qnumbr, 
ROUND_MODE);
                else
-                       tval = mpfr_mul(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_numbr, ROUND_MODE);
-               IEEE_FMT(r->mpg_numbr, tval);
+                       tval = mpfr_mul(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
        }
        return r;
 }
 
-
-/* mpg_pow --- exponentiation involving arbitrary-precision numbers */ 
+/* mpfp_pow --- exponentiation involving arbitrary-precision numbers */ 
 
 static NODE *
-mpg_pow(NODE *t1, NODE *t2)
+mpfp_pow(const NODE *t1, const NODE *t2)
 {
        NODE *r;
        int tval;
 
-       if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
-               if (mpz_sgn(t2->mpg_i) >= 0 && mpz_fits_ulong_p(t2->mpg_i)) {
-                       r = mpg_integer();
-                       mpz_pow_ui(r->mpg_i, t1->mpg_i, mpz_get_ui(t2->mpg_i));
+       if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+               if (mpz_sgn(MPZ_T(t2->qnumbr)) >= 0 && 
mpz_fits_ulong_p(t2->qnumbr)) {
+                       r = mpfp_integer();
+                       mpz_pow_ui(r->qnumbr, t1->qnumbr, 
mpz_get_ui(t2->qnumbr));
                } else {
                        mpfr_ptr p1, p2;
-                       p1 = MP_FLOAT(t1);
-                       p2 = MP_FLOAT(t2);
-                       r = mpg_float();
-                       tval = mpfr_pow(r->mpg_numbr, p1, p2, ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
+
+                       p1 = mpfp_tofloat(t1, _mp1);
+                       p2 = mpfp_tofloat(t2, _mp2);
+                       r = mpfp_float();
+                       tval = mpfr_pow(r->qnumbr, p1, p2, ROUND_MODE);
+                       IEEE_FMT(r->qnumbr, tval);
                }
        } else {
-               r = mpg_float();
-               if (is_mpg_integer(t2))
-                       tval = mpfr_pow_z(r->mpg_numbr, t1->mpg_numbr, 
t2->mpg_i, ROUND_MODE);
+               r = mpfp_float();
+               if (is_mpfp_integer(t2))
+                       tval = mpfr_pow_z(r->qnumbr, t1->qnumbr, t2->qnumbr, 
ROUND_MODE);
                else {
                        mpfr_ptr p1;
-                       p1 = MP_FLOAT(t1);
-                       tval = mpfr_pow(r->mpg_numbr, p1, t2->mpg_numbr, 
ROUND_MODE);
+
+                       p1 = mpfp_tofloat(t1, _mp1);
+                       tval = mpfr_pow(r->qnumbr, p1, t2->qnumbr, ROUND_MODE);
                }
-               IEEE_FMT(r->mpg_numbr, tval);
+               IEEE_FMT(r->qnumbr, tval);
        }
        return r;
 }
 
-/* mpg_div --- arbitrary-precision division */
+/* mpfp_div --- arbitrary-precision division */
 
 static NODE *
-mpg_div(NODE *t1, NODE *t2)
+mpfp_div(const NODE *t1, const NODE *t2)
 {
        NODE *r;
        int tval;
 
-       if (is_mpg_integer(t1) && is_mpg_integer(t2)
-                       && (mpz_sgn(t2->mpg_i) != 0)    /* not dividing by 0 */
-                       && mpz_divisible_p(t1->mpg_i, t2->mpg_i)
+       if (is_mpfp_integer(t1) && is_mpfp_integer(t2)
+                       && (mpz_sgn(MPZ_T(t2->qnumbr)) != 0)    /* not dividing 
by 0 */
+                       && mpz_divisible_p(t1->qnumbr, t2->qnumbr)
        ) {
-               r = mpg_integer();
-               mpz_divexact(r->mpg_i, t1->mpg_i, t2->mpg_i);
+               r = mpfp_integer();
+               mpz_divexact(r->qnumbr, t1->qnumbr, t2->qnumbr);
        } else {
                mpfr_ptr p1, p2;
-               p1 = MP_FLOAT(t1);
-               p2 = MP_FLOAT(t2);
-               r = mpg_float();
-               tval = mpfr_div(r->mpg_numbr, p1, p2, ROUND_MODE);
-               IEEE_FMT(r->mpg_numbr, tval);
+
+               p1 = mpfp_tofloat(t1, _mp1);
+               p2 = mpfp_tofloat(t2, _mp2);
+               r = mpfp_float();
+               tval = mpfr_div(r->qnumbr, p1, p2, ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
        }
        return r;
 }
 
-/* mpg_mod --- modulus operation with arbitrary-precision numbers */
+/* mpfp_mod --- modulus operation with arbitrary-precision numbers */
 
 static NODE *
-mpg_mod(NODE *t1, NODE *t2)
+mpfp_mod(const NODE *t1, const NODE *t2)
 {
        NODE *r;
        int tval;
 
-       if (is_mpg_integer(t1) && is_mpg_integer(t2)) {
-               r = mpg_integer();
-               mpz_mod(r->mpg_i, t1->mpg_i, t2->mpg_i);
+       if (is_mpfp_integer(t1) && is_mpfp_integer(t2)) {
+               r = mpfp_integer();
+               mpz_mod(r->qnumbr, t1->qnumbr, t2->qnumbr);
        } else {
                mpfr_ptr p1, p2;
-               p1 = MP_FLOAT(t1);
-               p2 = MP_FLOAT(t2);
-               r = mpg_float();
-               tval = mpfr_fmod(r->mpg_numbr, p1, p2, ROUND_MODE);
-               IEEE_FMT(r->mpg_numbr, tval);
+
+               p1 = mpfp_tofloat(t1, _mp1);
+               p2 = mpfp_tofloat(t2, _mp2);
+               r = mpfp_float();
+               tval = mpfr_fmod(r->qnumbr, p1, p2, ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
        }
        return r;
 }
-       
-/*
- * mpg_interpret --- pre-exec hook in the interpreter. Handles
- *     arithmetic operations with MPFR/GMP numbers.
- */ 
-
-static int
-mpg_interpret(INSTRUCTION **cp)
-{
-       INSTRUCTION *pc = *cp;  /* current instruction */
-       OPCODE op;      /* current opcode */
-       NODE *r = NULL;
-       NODE *t1, *t2;
-       NODE **lhs;
-       int tval;       /* the ternary value returned by a MPFR function */
-
-       switch ((op = pc->opcode)) {
-       case Op_plus_i:
-               t2 = force_number(pc->memory);
-               goto plus;
-       case Op_plus:
-               t2 = POP_NUMBER();
-plus:
-               t1 = TOP_NUMBER();
-               r = mpg_add(t1, t2);
-               DEREF(t1);
-               if (op == Op_plus)
-                       DEREF(t2);
-               REPLACE(r);
-               break;
 
-       case Op_minus_i:
-               t2 = force_number(pc->memory);
-               goto minus;
-       case Op_minus:
-               t2 = POP_NUMBER();
-minus:
-               t1 = TOP_NUMBER();
-               r = mpg_sub(t1, t2);
-               DEREF(t1);
-               if (op == Op_minus)
-                       DEREF(t2);
-               REPLACE(r);
-               break;
+/* mpfp_add_long --- add aribitary-precision number to long */
 
-       case Op_times_i:
-               t2 = force_number(pc->memory);
-               goto times;
-       case Op_times:
-               t2 = POP_NUMBER();
-times:
-               t1 = TOP_NUMBER();
-               r = mpg_mul(t1, t2);
-               DEREF(t1);
-               if (op == Op_times)
-                       DEREF(t2);
-               REPLACE(r);
-               break;
-
-       case Op_exp_i:
-               t2 = force_number(pc->memory);
-               goto exp;
-       case Op_exp:
-               t2 = POP_NUMBER();
-exp:
-               t1 = TOP_NUMBER();
-               r = mpg_pow(t1, t2);
-               DEREF(t1);
-               if (op == Op_exp)
-                       DEREF(t2);
-               REPLACE(r);
-               break;
-
-       case Op_quotient_i:
-               t2 = force_number(pc->memory);
-               goto quotient;
-       case Op_quotient:
-               t2 = POP_NUMBER();
-quotient:
-               t1 = TOP_NUMBER();
-               r = mpg_div(t1, t2);
-               DEREF(t1);
-               if (op == Op_quotient)
-                       DEREF(t2);
-               REPLACE(r);
-               break;          
-
-       case Op_mod_i:
-               t2 = force_number(pc->memory);
-               goto mod;
-       case Op_mod:
-               t2 = POP_NUMBER();
-mod:
-               t1 = TOP_NUMBER();
-               r = mpg_mod(t1, t2);
-               DEREF(t1);
-               if (op == Op_mod)
-                       DEREF(t2);
-               REPLACE(r);
-               break;
-
-       case Op_preincrement:
-       case Op_predecrement:
-               lhs = TOP_ADDRESS();
-               t1 = *lhs;
-               force_number(t1);
-
-               if (is_mpg_integer(t1)) {
-                       if (t1->valref == 1 && t1->flags == 
(MALLOC|MPZN|NUMCUR|NUMBER))
-                       /* Efficiency hack. Big speed-up (> 30%) in a tight 
loop */
-                               r = t1;
-                       else
-                               r = *lhs = mpg_integer();
-                       if (op == Op_preincrement)
-                               mpz_add_ui(r->mpg_i, t1->mpg_i, 1);
-                       else
-                               mpz_sub_ui(r->mpg_i, t1->mpg_i, 1);
-               } else {
+static NODE *
+mpfp_add_long(const NODE *t1, long l)
+{
+       NODE *r;
 
-                       /*
-                        * An optimization like the one above is not going to 
work
-                        * for a floating-point number. With it,
-                        *   gawk -M 'BEGIN { PREC=53; i=2^53+0.0; PREC=113; 
++i; print i}'
-                        * will output 2^53 instead of 2^53+1.
-                        */
-
-                       r = *lhs = mpg_float();
-                       tval = mpfr_add_si(r->mpg_numbr, t1->mpg_numbr,
-                                       op == Op_preincrement ? 1 : -1,
-                                       ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
-               }
-               if (r != t1)
-                       unref(t1);
-               UPREF(r);
-               REPLACE(r);
-               break;
+       if (is_mpfp_integer(t1)) {
+               r = mpfp_integer();
+               if (l >= 0)
+                       mpz_add_ui(r->qnumbr, t1->qnumbr, l);
+               else
+                       mpz_sub_ui(r->qnumbr, t1->qnumbr, l);
+       } else {
+               int tval;
 
-       case Op_postincrement:
-       case Op_postdecrement:
-               lhs = TOP_ADDRESS();
-               t1 = *lhs;
-               force_number(t1);
-
-               if (is_mpg_integer(t1)) {
-                       r = mpg_integer();
-                       mpz_set(r->mpg_i, t1->mpg_i);
-                       if (t1->valref == 1 && t1->flags == 
(MALLOC|MPZN|NUMCUR|NUMBER))
-                       /* Efficiency hack. Big speed-up (> 30%) in a tight 
loop */
-                               t2 = t1;
-                       else
-                               t2 = *lhs = mpg_integer();
-                       if (op == Op_postincrement)
-                               mpz_add_ui(t2->mpg_i, t1->mpg_i, 1);
-                       else
-                               mpz_sub_ui(t2->mpg_i, t1->mpg_i, 1);
-               } else {
-                       r = mpg_float();
-                       tval = mpfr_set(r->mpg_numbr, t1->mpg_numbr, 
ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
-                       t2 = *lhs = mpg_float();
-                       tval = mpfr_add_si(t2->mpg_numbr, t1->mpg_numbr,
-                                       op == Op_postincrement ? 1 : -1,
-                                       ROUND_MODE);
-                       IEEE_FMT(t2->mpg_numbr, tval);
-               }
-               if (t2 != t1)
-                       unref(t1);
-               REPLACE(r);
-               break;
+               r = mpfp_float();
+               tval = mpfr_add_si(r->qnumbr, t1->qnumbr, l, ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
+       }
+       return r;
+}
 
-       case Op_unary_minus:
-               t1 = TOP_NUMBER();
-               if (is_mpg_float(t1)) {
-                       r = mpg_float();
-                       tval = mpfr_neg(r->mpg_numbr, t1->mpg_numbr, 
ROUND_MODE);
-                       IEEE_FMT(r->mpg_numbr, tval);
-               } else {
-                       r = mpg_integer();
-                       mpz_neg(r->mpg_i, t1->mpg_i);
-               }
-               DEREF(t1);
-               REPLACE(r);
-               break;
+/* mpfp_copy_number --- copy an arbitrary-precision number */
 
-       case Op_assign_plus:
-       case Op_assign_minus:
-       case Op_assign_times:
-       case Op_assign_quotient:
-       case Op_assign_mod:
-       case Op_assign_exp:
-               lhs = POP_ADDRESS();
-               t1 = *lhs;
-               force_number(t1);
-               t2 = TOP_NUMBER();
-
-               switch (op) {
-               case Op_assign_plus:
-                       r = mpg_add(t1, t2);
-                       break;
-               case Op_assign_minus:
-                       r = mpg_sub(t1, t2);
-                       break;
-               case Op_assign_times:
-                       r = mpg_mul(t1, t2);
-                       break;
-               case Op_assign_quotient:
-                       r = mpg_div(t1, t2);
-                       break;
-               case Op_assign_mod:
-                       r = mpg_mod(t1, t2);
-                       break;
-               case Op_assign_exp:
-                       r = mpg_pow(t1, t2);
-                       break;
-               default:
-                       cant_happen();
-               }
+static NODE *
+mpfp_copy_number(const NODE *n)
+{
+       NODE *r;
 
-               DEREF(t2);
-               unref(*lhs);
-               *lhs = r;
-               UPREF(r);
-               REPLACE(r);
-               break;
+       if (is_mpfp_integer(n)) {
+               r = mpfp_integer();
+               mpz_set(r->qnumbr, n->qnumbr);
+       } else {
+               int tval;
 
-       default:
-               return true;    /* unhandled */
+               r = mpfp_float();
+               tval = mpfr_set(r->qnumbr, MPFR_T(n->qnumbr), ROUND_MODE);
+               IEEE_FMT(r->qnumbr, tval);
        }
-
-       *cp = pc->nexti;        /* next instruction to execute */
-       return false;
+       return r;
 }
 
 
-/* mpg_fmt --- output formatted string with special MPFR/GMP conversion 
specifiers */
+/* mpfp_sprintf --- output formatted string with special MPFR/GMP conversion 
specifiers */
 
-const char *
-mpg_fmt(const char *mesg, ...)
+static const char *
+mpfp_sprintf(const char *mesg, ...)
 {
        static char *tmp = NULL;
        int ret;
@@ -1603,34 +1696,917 @@ mpg_fmt(const char *mesg, ...)
        return mesg;
 }
 
-/* mpfr_unset --- clear out the MPFR values */
 
-void
-mpfr_unset(NODE *n)
+/*
+ * mpz2mpfr --- convert an arbitrary-precision integer to a float
+ *     without any loss of precision. If the 2nd arg is NULL, the returned MPFR
+ *     value should be freed when done:
+ *             mpfr_clear(mpfrval); efree(mpfrval);
+ *     If the 2nd arg is not NULL, it is assumed that the MPFR variable has
+ *     already been initialized.
+ */
+
+
+static mpfr_ptr
+mpz2mpfr(mpz_ptr mpz_val, mpfr_ptr mpfr_val)
 {
-       if (is_mpg_float(n))
-               mpfr_clear(n->mpg_numbr);
-       else if (is_mpg_integer(n))
-               mpz_clear(n->mpg_i);
+       size_t prec;
+       int tval;
+
+       /*
+        * When implicitely converting a GMP integer operand to a MPFR float, 
use
+        * a precision sufficiently large to hold the converted value exactly.
+        *      
+        *      $ ./gawk -M 'BEGIN { print 13 % 2 }'
+        *      1
+        * If the user-specified precision is used to convert the integer 13 to 
a
+        * float, one will get:
+        *      $ ./gawk -M 'BEGIN { PREC=2; print 13 % 2.0 }'
+        *      0       
+        */
+
+       /* estimate minimum precision for exact conversion */
+       prec = mpz_sizeinbase(mpz_val, 2);      /* most significant 1 bit 
position starting at 1 */
+
+       if (mpfr_val != NULL && mpfr_get_prec(mpfr_val) >= prec)
+               goto finish;
+
+       prec -= (size_t) mpz_scan1(mpz_val, 0); /* least significant 1 bit 
index starting at 0 */
+       if (prec < MPFR_PREC_MIN)
+               prec = MPFR_PREC_MIN;
+       else if (prec > MPFR_PREC_MAX)
+               prec = MPFR_PREC_MAX;
+
+       if (mpfr_val == NULL) {
+               emalloc(mpfr_val, mpfr_ptr, sizeof (mpfr_t), "mpz2mpfr");
+               mpfr_init2(mpfr_val, prec);
+       } else if (prec < mpfr_get_prec(mpfr_val))
+               mpfr_set_prec(mpfr_val, prec);
+
+finish:
+       tval = mpfr_set_z(mpfr_val, mpz_val, ROUND_MODE);
+       IEEE_FMT(mpfr_val, tval);
+       return mpfr_val;
 }
 
-#else
 
-void
-set_PREC()
+
+extern size_t mbc_byte_count(const char *ptr, size_t numchars);
+extern size_t mbc_char_count(const char *ptr, size_t numbytes);
+
+/*
+ * mpfp_format_nodes() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library.  Returns a string node which value
+ * is a formatted string.  Called by  sprintf function.
+ *
+ * It is one of the uglier parts of gawk.  Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+static NODE *
+mpfp_format_nodes(
+       const char *fmt_string,
+       size_t n0,
+       NODE **the_args,
+       long num_args)
 {
-       /* dummy function */
+/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
+/* difference of pointers should be of ptrdiff_t type, but let us be kind */
+#define bchunk(s, l) if (l) { \
+       while ((l) > ofre) { \
+               size_t olen = obufout - obuf; \
+               erealloc(obuf, char *, osiz * 2, "format_tree"); \
+               ofre += osiz; \
+               osiz *= 2; \
+               obufout = obuf + olen; \
+       } \
+       memcpy(obufout, s, (size_t) (l)); \
+       obufout += (l); \
+       ofre -= (l); \
 }
 
-void
-set_ROUNDMODE()
-{
-       /* dummy function */
+/* copy one byte from 's' to 'obufout' checking for space in the process */
+#define bchunk_one(s) { \
+       if (ofre < 1) { \
+               size_t olen = obufout - obuf; \
+               erealloc(obuf, char *, osiz * 2, "format_tree"); \
+               ofre += osiz; \
+               osiz *= 2; \
+               obufout = obuf + olen; \
+       } \
+       *obufout++ = *s; \
+       --ofre; \
+}
+
+/* Is there space for something L big in the buffer? */
+#define chksize(l)  if ((l) >= ofre) { \
+       size_t olen = obufout - obuf; \
+       size_t delta = osiz+l-ofre; \
+       erealloc(obuf, char *, osiz + delta, "format_tree"); \
+       obufout = obuf + olen; \
+       ofre += delta; \
+       osiz += delta; \
+}
+
+       size_t cur_arg = 0;
+       NODE *r = NULL;
+       int i, nc;
+       bool toofew = false;
+       char *obuf, *obufout;
+       size_t osiz, ofre;
+       const char *chbuf;
+       const char *s0, *s1;
+       int cs1;
+       NODE *arg;
+       long fw, prec, argnum;
+       bool used_dollar;
+       bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
+       long *cur = NULL;
+       uintmax_t uval;
+       bool sgn;
+       int base;
+       /*
+        * Although this is an array, the elements serve two different
+        * purposes. The first element is the general buffer meant
+        * to hold the entire result string.  The second one is a
+        * temporary buffer for large floating point values. They
+        * could just as easily be separate variables, and the
+        * code might arguably be clearer.
+        */
+       struct {
+               char *buf;
+               size_t bufsize;
+               char stackbuf[30];
+       } cpbufs[2];
+#define cpbuf  cpbufs[0].buf
+       char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
+       char *cp;
+       const char *fill;
+       AWKNUM tmpval = 0.0;
+       char signchar = '\0';
+       size_t len;
+       bool zero_flag = false;
+       bool quote_flag = false;
+       int ii, jj;
+       char *chp;
+       size_t copy_count, char_count;
+#ifdef HAVE_MPFR
+       mpz_ptr zi;
+       mpfr_ptr mf;
+#endif
+       enum { MP_INT_WITH_PREC = 1, MP_INT_WITHOUT_PREC, MP_FLOAT } fmt_type;
+
+       static const char sp[] = " ";
+       static const char zero_string[] = "0";
+       static const char lchbuf[] = "0123456789abcdef";
+       static const char Uchbuf[] = "0123456789ABCDEF";
+
+#define INITIAL_OUT_SIZE       512
+       emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
+       obufout = obuf;
+       osiz = INITIAL_OUT_SIZE;
+       ofre = osiz - 2;
+
+       cur_arg = 1;
+
+       {
+               size_t k;
+               for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
+                       cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
+                       cpbufs[k].buf = cpbufs[k].stackbuf;
+               }
+       }
+
+       /*
+        * The point of this goop is to grow the buffer
+        * holding the converted number, so that large
+        * values don't overflow a fixed length buffer.
+        */
+#define PREPEND(CH) do {       \
+       if (cp == cpbufs[0].buf) {      \
+               char *prev = cpbufs[0].buf;     \
+               emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
+                       "format_tree"); \
+               memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev,    \
+                      cpbufs[0].bufsize);      \
+               cpbufs[0].bufsize *= 2; \
+               if (prev != cpbufs[0].stackbuf) \
+                       efree(prev);    \
+               cend = cpbufs[0].buf+cpbufs[0].bufsize; \
+       }       \
+       *--cp = (CH);   \
+} while(0)
+
+       /*
+        * Check first for use of `count$'.
+        * If plain argument retrieval was used earlier, choke.
+        *      Otherwise, return the requested argument.
+        * If not `count$' now, but it was used earlier, choke.
+        * If this format is more than total number of args, choke.
+        * Otherwise, return the current argument.
+        */
+#define parse_next_arg() { \
+       if (argnum > 0) { \
+               if (cur_arg > 1) { \
+                       msg(_("fatal: must use `count$' on all formats or 
none")); \
+                       goto out; \
+               } \
+               arg = the_args[argnum]; \
+       } else if (used_dollar) { \
+               msg(_("fatal: must use `count$' on all formats or none")); \
+               arg = 0; /* shutup the compiler */ \
+               goto out; \
+       } else if (cur_arg >= num_args) { \
+               arg = 0; /* shutup the compiler */ \
+               toofew = true; \
+               break; \
+       } else { \
+               arg = the_args[cur_arg]; \
+               cur_arg++; \
+       } \
+}
+
+       need_format = false;
+       used_dollar = false;
+
+       s0 = s1 = fmt_string;
+       while (n0-- > 0) {
+               if (*s1 != '%') {
+                       s1++;
+                       continue;
+               }
+               need_format = true;
+               bchunk(s0, s1 - s0);
+               s0 = s1;
+               cur = &fw;
+               fw = 0;
+               prec = 0;
+               base = 0;
+               argnum = 0;
+               base = 0;
+               have_prec = false;
+               signchar = '\0';
+               zero_flag = false;
+               quote_flag = false;
+#ifdef HAVE_MPFR
+               mf = NULL;
+               zi = NULL;
+#endif
+               fmt_type = 0;
+
+               lj = alt = big_flag = bigbig_flag = small_flag = false;
+               fill = sp;
+               cp = cend;
+               chbuf = lchbuf;
+               s1++;
+
+retry:
+               if (n0-- == 0)  /* ran out early! */
+                       break;
+
+               switch (cs1 = *s1++) {
+               case (-1):      /* dummy case to allow for checking */
+check_pos:
+                       if (cur != &fw)
+                               break;          /* reject as a valid format */
+                       goto retry;
+               case '%':
+                       need_format = false;
+                       /*
+                        * 29 Oct. 2002:
+                        * The C99 standard pages 274 and 279 seem to imply that
+                        * since there's no arg converted, the field width 
doesn't
+                        * apply.  The code already was that way, but this
+                        * comment documents it, at least in the code.
+                        */
+                       if (do_lint) {
+                               const char *msg = NULL;
+
+                               if (fw && ! have_prec)
+                                       msg = _("field width is ignored for 
`%%' specifier");
+                               else if (fw == 0 && have_prec)
+                                       msg = _("precision is ignored for `%%' 
specifier");
+                               else if (fw && have_prec)
+                                       msg = _("field width and precision are 
ignored for `%%' specifier");
+
+                               if (msg != NULL)
+                                       lintwarn("%s", msg);
+                       }
+                       bchunk_one("%");
+                       s0 = s1;
+                       break;
+
+               case '0':
+                       /*
+                        * Only turn on zero_flag if we haven't seen
+                        * the field width or precision yet.  Otherwise,
+                        * screws up floating point formatting.
+                        */
+                       if (cur == & fw)
+                               zero_flag = true;
+                       if (lj)
+                               goto retry;
+                       /* FALL through */
+               case '1':
+               case '2':
+               case '3':
+               case '4':
+               case '5':
+               case '6':
+               case '7':
+               case '8':
+               case '9':
+                       if (cur == NULL)
+                               break;
+                       if (prec >= 0)
+                               *cur = cs1 - '0';
+                       /*
+                        * with a negative precision *cur is already set
+                        * to -1, so it will remain negative, but we have
+                        * to "eat" precision digits in any case
+                        */
+                       while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+                               --n0;
+                               *cur = *cur * 10 + *s1++ - '0';
+                       }
+                       if (prec < 0)   /* negative precision is discarded */
+                               have_prec = false;
+                       if (cur == &prec)
+                               cur = NULL;
+                       if (n0 == 0)    /* badly formatted control string */
+                               continue;
+                       goto retry;
+               case '$':
+                       if (do_traditional) {
+                               msg(_("fatal: `$' is not permitted in awk 
formats"));
+                               goto out;
+                       }
+
+                       if (cur == &fw) {
+                               argnum = fw;
+                               fw = 0;
+                               used_dollar = true;
+                               if (argnum <= 0) {
+                                       msg(_("fatal: arg count with `$' must 
be > 0"));
+                                       goto out;
+                               }
+                               if (argnum >= num_args) {
+                                       msg(_("fatal: arg count %ld greater 
than total number of supplied arguments"), argnum);
+                                       goto out;
+                               }
+                       } else {
+                               msg(_("fatal: `$' not permitted after period in 
format"));
+                               goto out;
+                       }
+
+                       goto retry;
+               case '*':
+                       if (cur == NULL)
+                               break;
+                       if (! do_traditional && isdigit((unsigned char) *s1)) {
+                               int val = 0;
+
+                               for (; n0 > 0 && *s1 && isdigit((unsigned char) 
*s1); s1++, n0--) {
+                                       val *= 10;
+                                       val += *s1 - '0';
+                               }
+                               if (*s1 != '$') {
+                                       msg(_("fatal: no `$' supplied for 
positional field width or precision"));
+                                       goto out;
+                               } else {
+                                       s1++;
+                                       n0--;
+                               }
+                               if (val >= num_args) {
+                                       toofew = true;
+                                       break;
+                               }
+                               arg = the_args[val];
+                       } else {
+                               parse_next_arg();
+                       }
+                       (void) force_number(arg);
+                       *cur = get_number_si(arg);
+                       if (*cur < 0 && cur == &fw) {
+                               *cur = -*cur;
+                               lj++;
+                       }
+                       if (cur == &prec) {
+                               if (*cur >= 0)
+                                       have_prec = true;
+                               else
+                                       have_prec = false;
+                               cur = NULL;
+                       }
+                       goto retry;
+               case ' ':               /* print ' ' or '-' */
+                                       /* 'space' flag is ignored */
+                                       /* if '+' already present  */
+                       if (signchar != false) 
+                               goto check_pos;
+                       /* FALL THROUGH */
+               case '+':               /* print '+' or '-' */
+                       signchar = cs1;
+                       goto check_pos;
+               case '-':
+                       if (prec < 0)
+                               break;
+                       if (cur == &prec) {
+                               prec = -1;
+                               goto retry;
+                       }
+                       fill = sp;      /* if left justified then other */
+                       lj++;           /* filling is ignored */
+                       goto check_pos;
+               case '.':
+                       if (cur != &fw)
+                               break;
+                       cur = &prec;
+                       have_prec = true;
+                       goto retry;
+               case '#':
+                       alt = true;
+                       goto check_pos;
+               case '\'':
+#if defined(HAVE_LOCALE_H)       
+                       /* allow quote_flag if there is a thousands separator. 
*/
+                       if (loc.thousands_sep[0] != '\0')
+                               quote_flag = true;
+                       goto check_pos;
+#else
+                       goto retry;  
+#endif
+               case 'l':
+                       if (big_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`l' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `l' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       big_flag = true;
+                       goto retry;
+               case 'L':
+                       if (bigbig_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`L' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `L' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       bigbig_flag = true;
+                       goto retry;
+               case 'h':
+                       if (small_flag)
+                               break;
+                       else {
+                               static bool warned = false;
+                               
+                               if (do_lint && ! warned) {
+                                       lintwarn(_("`h' is meaningless in awk 
formats; ignored"));
+                                       warned = true;
+                               }
+                               if (do_posix) {
+                                       msg(_("fatal: `h' is not permitted in 
POSIX awk formats"));
+                                       goto out;
+                               }
+                       }
+                       small_flag = true;
+                       goto retry;
+               case 'c':
+                       need_format = false;
+                       parse_next_arg();
+                       /* user input that looks numeric is numeric */
+                       if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+                               (void) force_number(arg);
+                       if ((arg->flags & NUMBER) != 0) {
+                               uval = get_number_uj(arg);
+#if MBS_SUPPORT
+                               if (gawk_mb_cur_max > 1) {
+                                       char buf[100];
+                                       wchar_t wc;
+                                       mbstate_t mbs;
+                                       size_t count;
+
+                                       memset(& mbs, 0, sizeof(mbs));
+                                       wc = uval;
+
+                                       count = wcrtomb(buf, wc, & mbs);
+                                       if (count == 0
+                                           || count == (size_t)-1
+                                           || count == (size_t)-2)
+                                               goto out0;
+
+                                       memcpy(cpbuf, buf, count);
+                                       prec = count;
+                                       cp = cpbuf;
+                                       goto pr_tail;
+                               }
+out0:
+                               ;
+                               /* else,
+                                       fall through */
+#endif
+                               if (do_lint && uval > 255) {
+                                       lintwarn("[s]printf: value %g is too 
big for %%c format",
+                                                       arg->numbr);
+                               }
+                               cpbuf[0] = uval;
+                               prec = 1;
+                               cp = cpbuf;
+                               goto pr_tail;
+                       }
+                       /*
+                        * As per POSIX, only output first character of a
+                        * string value.  Thus, we ignore any provided
+                        * precision, forcing it to 1.  (Didn't this
+                        * used to work? 6/2003.)
+                        */
+                       cp = arg->stptr;
+#if MBS_SUPPORT
+                       /*
+                        * First character can be multiple bytes if
+                        * it's a multibyte character. Grr.
+                        */
+                       if (gawk_mb_cur_max > 1) {
+                               mbstate_t state;
+                               size_t count;
+
+                               memset(& state, 0, sizeof(state));
+                               count = mbrlen(cp, arg->stlen, & state);
+                               if (count == 0
+                                   || count == (size_t)-1
+                                   || count == (size_t)-2)
+                                       goto out2;
+                               prec = count;
+                               goto pr_tail;
+                       }
+out2:
+                       ;
+#endif
+                       prec = 1;
+                       goto pr_tail;
+               case 's':
+                       need_format = false;
+                       parse_next_arg();
+                       arg = force_string(arg);
+                       if (fw == 0 && ! have_prec)
+                               prec = arg->stlen;
+                       else {
+                               char_count = mbc_char_count(arg->stptr, 
arg->stlen);
+                               if (! have_prec || prec > char_count)
+                                       prec = char_count;
+                       }
+                       cp = arg->stptr;
+                       goto pr_tail;
+               case 'd':
+               case 'i':
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+#ifdef HAVE_MPFR
+                       if (is_mpfp_float(arg))
+                               goto mpf0;
+                       else {
+                               assert(is_mpfp_integer(arg) == true);
+                               goto mpz0;
+                       }
+#endif
+               case 'X':
+                       chbuf = Uchbuf; /* FALL THROUGH */
+               case 'x':
+                       base += 6;      /* FALL THROUGH */
+               case 'u':
+                       base += 2;      /* FALL THROUGH */
+               case 'o':
+                       base += 8;
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+#ifdef HAVE_MPFR
+                       if (is_mpfp_integer(arg)) {
+mpz0:
+                               zi = arg->qnumbr;
+
+                               if (cs1 != 'd' && cs1 != 'i') {
+                                       if (mpz_sgn(zi) <= 0) {
+                                               /*
+                                                * Negative value or 0 requires 
special handling.
+                                                * Unlike MPFR, GMP does not 
allow conversion
+                                                * to (u)intmax_t. So we first 
convert GMP type to
+                                                * a MPFR type.
+                                                */
+                                               mf = mpz2mpfr(zi, _mpfrval);
+                                               goto mpf1;
+                                       }
+                                       signchar = '\0';        /* Don't print 
'+' */
+                               }
+
+                               /* See comments above about when to fill with 
zeros */
+                               zero_flag = (! lj
+                                                   && ((zero_flag && ! 
have_prec)
+                                                        || (fw == 0 && 
have_prec)));
+
+                               fmt_type = have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
+                               goto fmt0;
+
+                       } else {
+                               assert(is_mpfp_float(arg) == true);
+mpf0:
+                               mf = arg->qnumbr;
+                               if (! mpfr_number_p(mf)) {
+                                       /* inf or NaN */
+                                       cs1 = 'g';
+                                       fmt_type = MP_FLOAT;
+                                       goto fmt1;
+                               }
+
+                               if (cs1 != 'd' && cs1 != 'i') {
+mpf1:
+                                       /*
+                                        * The output of printf("%#.0x", 0) is 
0 instead of 0x, hence <= in
+                                        * the comparison below.
+                                        */
+                                       if (mpfr_sgn(mf) <= 0) {
+                                               if (! mpfr_fits_intmax_p(mf, 
ROUND_MODE)) {
+                                                       /* -ve number is too 
large */
+                                                       cs1 = 'g';
+                                                       fmt_type = MP_FLOAT;
+                                                       goto fmt1;
+                                               }
+
+                                               tmpval = uval = (uintmax_t) 
mpfr_get_sj(mf, ROUND_MODE);
+                                               if (! alt && have_prec && prec 
== 0 && tmpval == 0)
+                                                       goto pr_tail;   /* 
printf("%.0x", 0) is no characters */
+                                               goto int0;
+                                       }
+                                       signchar = '\0';        /* Don't print 
'+' */
+                               }
+
+                               /* See comments above about when to fill with 
zeros */
+                               zero_flag = (! lj
+                                                   && ((zero_flag && ! 
have_prec)
+                                                        || (fw == 0 && 
have_prec)));
+                               
+                               (void) mpfr_get_z(_mpzval, mf, MPFR_RNDZ);      
/* convert to GMP integer */
+                               fmt_type = have_prec ? MP_INT_WITH_PREC : 
MP_INT_WITHOUT_PREC;
+                               zi = _mpzval;
+                               goto fmt0;
+                       }
+#endif
+
+#ifdef HAVE_MPFR
+       int0:
+#endif
+                       /*
+                        * When to fill with zeroes is of course not simple.
+                        * First: No zero fill if left-justifying.
+                        * Next: There seem to be two cases:
+                        *      A '0' without a precision, e.g. %06d
+                        *      A precision with no field width, e.g. %.10d
+                        * Any other case, we don't want to fill with zeroes.
+                        */
+                       if (! lj
+                           && ((zero_flag && ! have_prec)
+                                || (fw == 0 && have_prec)))
+                               fill = zero_string;
+                       ii = jj = 0;
+                       do {
+                               PREPEND(chbuf[uval % base]);
+                               uval /= base;
+#if defined(HAVE_LOCALE_H)
+                               if (base == 10 && quote_flag && 
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
+                                       if (uval)       /* only add if more 
digits coming */
+                                               PREPEND(loc.thousands_sep[0]);  
/* XXX --- assumption it's one char */
+                                       if (loc.grouping[ii+1] == 0)            
                              
+                                               jj = 0;     /* keep using 
current val in loc.grouping[ii] */
+                                       else if (loc.grouping[ii+1] == 
CHAR_MAX)                        
+                                               quote_flag = false;
+                                       else {                 
+                                               ii++;
+                                               jj = 0;
+                                       }
+                               }
+#endif
+                       } while (uval > 0);
+
+                       /* add more output digits to match the precision */
+                       if (have_prec) {
+                               while (cend - cp < prec)
+                                       PREPEND('0');
+                       }
+
+                       if (alt && tmpval != 0) {
+                               if (base == 16) {
+                                       PREPEND(cs1);
+                                       PREPEND('0');
+                                       if (fill != sp) {
+                                               bchunk(cp, 2);
+                                               cp += 2;
+                                               fw -= 2;
+                                       }
+                               } else if (base == 8)
+                                       PREPEND('0');
+                       }
+                       base = 0;
+                       if (prec > fw)
+                               fw = prec;
+                       prec = cend - cp;
+       pr_tail:
+                       if (! lj) {
+                               while (fw > prec) {
+                                       bchunk_one(fill);
+                                       fw--;
+                               }
+                       }
+                       copy_count = prec;
+                       if (fw == 0 && ! have_prec)
+                               ;
+                       else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 == 
'c')) {
+                               assert(cp == arg->stptr || cp == cpbuf);
+                               copy_count = mbc_byte_count(arg->stptr, prec);
+                       }
+                       bchunk(cp, copy_count);
+                       while (fw > prec) {
+                               bchunk_one(fill);
+                               fw--;
+                       }
+                       s0 = s1;
+                       break;
+
+     out_of_range:
+                       /* out of range - emergency use of %g format */
+                       if (do_lint)
+                               lintwarn(_("[s]printf: value %g is out of range 
for `%%%c' format"),
+                                                       (double) tmpval, cs1);
+                       cs1 = 'g';
+                       goto fmt1;
+
+               case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+                       cs1 = 'f';
+                       /* FALL THROUGH */
+#endif
+               case 'g':
+               case 'G':
+               case 'e':
+               case 'f':
+               case 'E':
+                       need_format = false;
+                       parse_next_arg();
+                       (void) force_number(arg);
+
+                       if (! is_mpfp_number(arg))
+                               tmpval = arg->numbr;
+#ifdef HAVE_MPFR
+                       else if (is_mpfp_float(arg)) {
+                               mf = arg->qnumbr;
+                               fmt_type = MP_FLOAT;
+                       } else {
+                               /* arbitrary-precision integer, convert to MPFR 
float */
+                               assert(mf == NULL);
+                               mf = mpz2mpfr(arg->qnumbr, _mpfrval);
+                               fmt_type = MP_FLOAT;
+                       }
+#endif
+     fmt1:
+                       if (! have_prec)
+                               prec = DEFAULT_G_PRECISION;
+#ifdef HAVE_MPFR
+     fmt0:
+#endif
+                       chksize(fw + prec + 11);        /* 11 == slop */
+                       cp = cpbuf;
+                       *cp++ = '%';
+                       if (lj)
+                               *cp++ = '-';
+                       if (signchar)
+                               *cp++ = signchar;
+                       if (alt)
+                               *cp++ = '#';
+                       if (zero_flag)
+                               *cp++ = '0';
+                       if (quote_flag)
+                               *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+                       if (quote_flag && ! use_lc_numeric)
+                               setlocale(LC_NUMERIC, "");
+#endif
+
+                       switch (fmt_type) {
+#ifdef HAVE_MPFR
+                       case MP_INT_WITH_PREC:
+                               sprintf(cp, "*.*Z%c", cs1);
+                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
+                                            (int) fw, (int) prec, zi)) >= ofre)
+                                       chksize(nc)
+                               break;
+                       case MP_INT_WITHOUT_PREC:
+                               sprintf(cp, "*Z%c", cs1);
+                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
+                                            (int) fw, zi)) >= ofre)
+                                       chksize(nc)
+                               break;
+                       case MP_FLOAT:
+                               sprintf(cp, "*.*R*%c", cs1);
+                               while ((nc = mpfr_snprintf(obufout, ofre, cpbuf,
+                                            (int) fw, (int) prec, ROUND_MODE, 
mf)) >= ofre)
+                                       chksize(nc)
+                               break;
+#endif
+                       default:
+                               sprintf(cp, "*.*%c", cs1);
+                               while ((nc = snprintf(obufout, ofre, cpbuf,
+                                            (int) fw, (int) prec,
+                                            (double) tmpval)) >= ofre)
+                                       chksize(nc)
+                       }
+
+#if defined(LC_NUMERIC)
+                       if (quote_flag && ! use_lc_numeric)
+                               setlocale(LC_NUMERIC, "C");
+#endif
+
+                       len = strlen(obufout);
+                       ofre -= len;
+                       obufout += len;
+                       s0 = s1;
+                       break;
+               default:
+                       if (do_lint && isalpha(cs1))
+                               lintwarn(_("ignoring unknown format specifier 
character `%c': no argument converted"), cs1);
+                       break;
+               }
+               if (toofew) {
+                       msg("%s\n\t`%s'\n\t%*s%s",
+                             _("fatal: not enough arguments to satisfy format 
string"),
+                             fmt_string, (int) (s1 - fmt_string - 1), "",
+                             _("^ ran out for this one"));
+                       goto out;
+               }
+       }
+       if (do_lint) {
+               if (need_format)
+                       lintwarn(
+                       _("[s]printf: format specifier does not have control 
letter"));
+               if (cur_arg < num_args)
+                       lintwarn(
+                       _("too many arguments supplied for format string"));
+       }
+       bchunk(s0, s1 - s0);
+       r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
+       obuf = NULL;
+out:
+       {
+               size_t k;
+               size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
+               for (k = 0; k < count; k++) {
+                       if (cpbufs[k].buf != cpbufs[k].stackbuf)
+                               efree(cpbufs[k].buf);
+               }
+               if (obuf != NULL)
+                       efree(obuf);
+       }
+
+       if (r == NULL)
+               gawk_exit(EXIT_FATAL);
+       return r;
 }
 
-void
-mpfr_unset(NODE *n)
+#else
+
+static bool mpfp_init(bltin_t **bltins);
+
+numbr_handler_t mpfp_hndlr = {
+       mpfp_init,
+       NULL,
+       NULL,
+};
+
+/* mpfp_init --- set up MPFR related variables */
+
+static bool
+mpfp_init(bltin_t **bltins)
 {
-       /* dummy function */
+       warning(_("this version of gawk does not support arbitrary-precision 
numbers"));
+       *bltins = NULL;
+       return false;
 }
+
 #endif
diff --git a/msg.c b/msg.c
index c0bf38a..d61fea0 100644
--- a/msg.c
+++ b/msg.c
@@ -63,26 +63,16 @@ err(bool isfatal, const char *s, const char *emsg, va_list 
argp)
                (void) fprintf(stderr, "%d: ", sourceline);
        }
 
-#ifdef HAVE_MPFR
-       if (FNR_node && is_mpg_number(FNR_node->var_value)) {
+       if (FNR_node != NULL && (FNR_node->var_value->flags & (NUMBER|NUMCUR)) 
!= 0) {
                NODE *val;
-               val = mpg_update_var(FNR_node);
-               assert((val->flags & MPZN) != 0);
-               if (mpz_sgn(val->mpg_i) > 0) {
+               val = numbr_hndlr->update_numvar(FNR_node);
+               if (sgn_number(val) > 0) {      /* positive nonzero number */ 
                        file = FILENAME_node->var_value->stptr;
                        (void) putc('(', stderr);
                        if (file)
                                (void) fprintf(stderr, "FILENAME=%s ", file);
-                       (void) mpfr_fprintf(stderr, "FNR=%Zd) ", val->mpg_i);
+                       fprintf(stderr, "FNR=%s) ", fmt_number("%d", val));
                }
-       } else
-#endif
-       if (FNR > 0) {
-               file = FILENAME_node->var_value->stptr;
-               (void) putc('(', stderr);
-               if (file)
-                       (void) fprintf(stderr, "FILENAME=%s ", file);
-               (void) fprintf(stderr, "FNR=%ld) ", FNR);
        }
 
        (void) fprintf(stderr, "%s", s);
@@ -98,6 +88,42 @@ err(bool isfatal, const char *s, const char *emsg, va_list 
argp)
        }
 }
 
+
+/*
+ * N.B: format is awk printf format, NOT C format or any other special format
+ * supported. MUST NOT throw warning in format tree. "%ld" is BAD, "%d" is Ok!
+ */
+
+
+/* N.B: FORMAT must pass fmt_ok() used to check CONVFMT/OFMT specifier */
+
+const char *
+fmt_number(const char *format, const NODE *n)
+{
+       NODE *dummy[2], *r, *tmp;
+       static char *num_str;
+       extern bool fmt_ok(const char *p);
+
+       assert(fmt_ok(format) == true);
+       assert((n->flags & (NUMBER|NUMCUR)) != 0);
+
+       /* copy number so not to change state of the original including flags */
+       tmp = numbr_hndlr->gawk_copy_number(n);
+       if (num_str != NULL)
+               efree(num_str);
+
+       /* create dummy node for sole use of format_tree */
+       dummy[1] = tmp;
+       r = format_tree(format, strlen(format), dummy, 2);
+       assert(r != NULL);
+       num_str = r->stptr;
+       num_str[r->stlen] = '\0';
+       freenode(r);
+       unref(tmp);
+       return num_str;
+}
+
+
 /* msg --- take a varargs error message and print it */
 
 void
diff --git a/node.c b/node.c
index 02c78ae..9efd767 100644
--- a/node.c
+++ b/node.c
@@ -25,240 +25,20 @@
  */
 
 #include "awk.h"
-#include "math.h"
-#include "floatmagic.h"        /* definition of isnan */
 
-static int is_ieee_magic_val(const char *val);
-static NODE *r_make_number(double x);
-static AWKNUM get_ieee_magic_val(const char *val);
-extern NODE **fmt_list;          /* declared in eval.c */
+NODE *(*format_tree)(const char *, size_t, NODE **, long);
+NODE *(*str2node)(char *, char **, int, bool);
+NODE *(*make_number)(AWKNUM);
+NODE *(*str2number)(NODE *);
+NODE *(*format_val)(const char *, int, NODE *);
+int (*cmp_numbers)(const NODE *, const NODE *);
+void (*free_number)(NODE *);
+unsigned long (*get_number_ui)(const NODE *);
+long (*get_number_si)(const NODE *);
+AWKNUM (*get_number_d)(const NODE *);
+uintmax_t (*get_number_uj)(const NODE *);
+int (*sgn_number)(const NODE *);
 
-NODE *(*make_number)(double) = r_make_number;
-NODE *(*str2number)(NODE *) = r_force_number;
-NODE *(*format_val)(const char *, int, NODE *) = r_format_val;
-int (*cmp_numbers)(const NODE *, const NODE *) = cmp_awknums;
-
-/* force_number --- force a value to be numeric */
-
-NODE *
-r_force_number(NODE *n)
-{
-       char *cp;
-       char *cpend;
-       char save;
-       char *ptr;
-       unsigned int newflags;
-       extern double strtod();
-
-       if ((n->flags & NUMCUR) != 0)
-               return n;
-
-       /* all the conditionals are an attempt to avoid the expensive strtod */
-
-       /* Note: only set NUMCUR if we actually convert some digits */
-
-       n->numbr = 0.0;
-
-       if (n->stlen == 0) {
-               return n;
-       }
-
-       cp = n->stptr;
-       /*
-        * 2/2007:
-        * POSIX, by way of severe language lawyering, seems to
-        * allow things like "inf" and "nan" to mean something.
-        * So if do_posix, the user gets what he deserves.
-        * This also allows hexadecimal floating point. Ugh.
-        */
-       if (! do_posix) {
-               if (isalpha((unsigned char) *cp)) {
-                       return n;
-               } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
-                       if ((n->flags & MAYBE_NUM) != 0)
-                               n->flags &= ~MAYBE_NUM;
-                       n->flags |= NUMBER|NUMCUR;
-                       n->numbr = get_ieee_magic_val(n->stptr);
-
-                       return n;
-               }
-               /* else
-                       fall through */
-       }
-       /* else not POSIX, so
-               fall through */
-
-       cpend = cp + n->stlen;
-       while (cp < cpend && isspace((unsigned char) *cp))
-               cp++;
-
-       if (   cp == cpend              /* only spaces, or */
-           || (! do_posix              /* not POSIXLY paranoid and */
-               && (isalpha((unsigned char) *cp)        /* letter, or */
-                                       /* CANNOT do non-decimal and saw 0x */
-                   || (! do_non_decimal_data && cp[0] == '0'
-                       && (cp[1] == 'x' || cp[1] == 'X'))))) {
-               return n;
-       }
-
-       if ((n->flags & MAYBE_NUM) != 0) {
-               newflags = NUMBER;
-               n->flags &= ~MAYBE_NUM;
-       } else
-               newflags = 0;
-
-       if (cpend - cp == 1) {          /* only one character */
-               if (isdigit((unsigned char) *cp)) {     /* it's a digit! */
-                       n->numbr = (AWKNUM)(*cp - '0');
-                       n->flags |= newflags;
-                       n->flags |= NUMCUR;
-                       if (cp == n->stptr)             /* no leading spaces */
-                               n->flags |= NUMINT;
-               }
-               return n;
-       }
-
-       if (do_non_decimal_data) {      /* main.c assures false if do_posix */
-               errno = 0;
-               if (! do_traditional && get_numbase(cp, true) != 10) {
-                       n->numbr = nondec2awknum(cp, cpend - cp);
-                       n->flags |= NUMCUR;
-                       ptr = cpend;
-                       goto finish;
-               }
-       }
-
-       errno = 0;
-       save = *cpend;
-       *cpend = '\0';
-       n->numbr = (AWKNUM) strtod((const char *) cp, &ptr);
-
-       /* POSIX says trailing space is OK for NUMBER */
-       while (isspace((unsigned char) *ptr))
-               ptr++;
-       *cpend = save;
-finish:
-       if (errno == 0 && ptr == cpend) {
-               n->flags |= newflags;
-               n->flags |= NUMCUR;
-       } else {
-               errno = 0;
-       }
-
-       return n;
-}
-
-
-/*
- * The following lookup table is used as an optimization in force_string;
- * (more complicated) variations on this theme didn't seem to pay off, but 
- * systematic testing might be in order at some point.
- */
-static const char *values[] = {
-       "0",
-       "1",
-       "2",
-       "3",
-       "4",
-       "5",
-       "6",
-       "7",
-       "8",
-       "9",
-};
-#define        NVAL    (sizeof(values)/sizeof(values[0]))
-
-/* r_format_val --- format a numeric value based on format */
-
-NODE *
-r_format_val(const char *format, int index, NODE *s)
-{
-       char buf[BUFSIZ];
-       char *sp = buf;
-       double val;
-
-       /*
-        * 2/2007: Simplify our lives here. Instead of worrying about
-        * whether or not the value will fit into a long just so we
-        * can use sprintf("%ld", val) on it, always format it ourselves.
-        * The only thing to worry about is that integral values always
-        * format as integers. %.0f does that very well.
-        *
-        * 6/2008: Would that things were so simple. Always using %.0f
-        * imposes a notable performance penalty for applications that
-        * do a lot of conversion of integers to strings. So, we reinstate
-        * the old code, but use %.0f for integral values that are outside
-        * the range of a long.  This seems a reasonable compromise.
-        *
-        * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
-        * < and > so that things work correctly on systems with 64 bit 
integers.
-        */
-
-       /* not an integral value, or out of range */
-       if ((val = double_to_int(s->numbr)) != s->numbr
-                       || val <= LONG_MIN || val >= LONG_MAX
-       ) {
-               /*
-                * Once upon a time, we just blindly did this:
-                *      sprintf(sp, format, s->numbr);
-                *      s->stlen = strlen(sp);
-                *      s->stfmt = (char) index;
-                * but that's no good if, e.g., OFMT is %s. So we punt,
-                * and just always format the value ourselves.
-                */
-
-               NODE *dummy[2], *r;
-               unsigned int oflags;
-
-               /* create dummy node for a sole use of format_tree */
-               dummy[1] = s;
-               oflags = s->flags;
-
-               if (val == s->numbr) {
-                       /* integral value, but outside range of %ld, use %.0f */
-                       r = format_tree("%.0f", 4, dummy, 2);
-                       s->stfmt = -1;
-               } else {
-                       r = format_tree(format, fmt_list[index]->stlen, dummy, 
2);
-                       assert(r != NULL);
-                       s->stfmt = (char) index;
-               }
-               s->flags = oflags;
-               s->stlen = r->stlen;
-               if ((s->flags & STRCUR) != 0)
-                       efree(s->stptr);
-               s->stptr = r->stptr;
-               freenode(r);    /* Do not unref(r)! We want to keep s->stptr == 
r->stpr.  */
-
-               goto no_malloc;
-       } else {
-               /*
-                * integral value; force conversion to long only once.
-                */
-               long num = (long) val;
-
-               if (num < NVAL && num >= 0) {
-                       sp = (char *) values[num];
-                       s->stlen = 1;
-               } else {
-                       (void) sprintf(sp, "%ld", num);
-                       s->stlen = strlen(sp);
-               }
-               s->stfmt = -1;
-               if ((s->flags & INTIND) != 0) {
-                       s->flags &= ~(INTIND|NUMBER);
-                       s->flags |= STRING;
-               }
-       }
-       if (s->stptr != NULL)
-               efree(s->stptr);
-       emalloc(s->stptr, char *, s->stlen + 2, "format_val");
-       memcpy(s->stptr, sp, s->stlen + 1);
-no_malloc:
-       s->flags |= STRCUR;
-       free_wstr(s);
-       return s;
-}
 
 /* r_dupnode --- duplicate a node */
 
@@ -309,53 +89,6 @@ r_dupnode(NODE *n)
        return r;
 }
 
-/* r_make_number --- allocate a node with defined number */
-
-static NODE *
-r_make_number(double x)
-{
-       NODE *r;
-       getnode(r);
-       r->type = Node_val;
-       r->numbr = x;
-       r->flags = MALLOC|NUMBER|NUMCUR;
-       r->valref = 1;
-       r->stptr = NULL;
-       r->stlen = 0;
-#if MBS_SUPPORT
-       r->wstptr = NULL;
-       r->wstlen = 0;
-#endif /* defined MBS_SUPPORT */
-       return r;
-}
-
-/* cmp_awknums --- compare two AWKNUMs */
-
-int
-cmp_awknums(const NODE *t1, const NODE *t2)
-{
-       /*
-        * This routine is also used to sort numeric array indices or values.
-        * For the purposes of sorting, NaN is considered greater than
-        * any other value, and all NaN values are considered equivalent and 
equal.
-        * This isn't in compliance with IEEE standard, but compliance w.r.t. 
NaN
-        * comparison at the awk level is a different issue, and needs to be 
dealt
-        * with in the interpreter for each opcode seperately.
-        */
-
-       if (isnan(t1->numbr))
-               return ! isnan(t2->numbr);
-       if (isnan(t2->numbr))
-               return -1;
-       /* don't subtract, in case one or both are infinite */
-       if (t1->numbr == t2->numbr)
-               return 0;
-       if (t1->numbr < t2->numbr)
-               return -1;
-       return 1;
-}
-
-
 /* make_str_node --- make a string node */
 
 NODE *
@@ -456,7 +189,8 @@ r_unref(NODE *tmp)
                efree(tmp->stptr);
 #endif
 
-       mpfr_unset(tmp);
+       if (free_number && (tmp->flags & (NUMBER|NUMCUR)) != 0)
+               free_number(tmp);
 
        free_wstr(tmp);
        freenode(tmp);
@@ -893,50 +627,6 @@ out:       ;
 }
 #endif /* MBS_SUPPORT */
 
-/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
-
-static int
-is_ieee_magic_val(const char *val)
-{
-       /*
-        * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
-        * Assume the length is 4, as the caller checks this.
-        */
-       return (   (val[0] == '+' || val[0] == '-')
-               && (   (   (val[1] == 'i' || val[1] == 'I')
-                       && (val[2] == 'n' || val[2] == 'N')
-                       && (val[3] == 'f' || val[3] == 'F'))
-                   || (   (val[1] == 'n' || val[1] == 'N')
-                       && (val[2] == 'a' || val[2] == 'A')
-                       && (val[3] == 'n' || val[3] == 'N'))));
-}
-
-/* get_ieee_magic_val --- return magic value for string */
-
-static AWKNUM
-get_ieee_magic_val(const char *val)
-{
-       static bool first = true;
-       static AWKNUM inf;
-       static AWKNUM nan;
-
-       char *ptr;
-       AWKNUM v = strtod(val, &ptr);
-
-       if (val == ptr) { /* Older strtod implementations don't support inf or 
nan. */
-               if (first) {
-                       first = false;
-                       nan = sqrt(-1.0);
-                       inf = -log(0.0);
-               }
-
-               v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
-               if (val[0] == '-')
-                       v = -v;
-       }
-
-       return v;
-}
 
 #if MBS_SUPPORT
 wint_t btowc_cache[256];
diff --git a/profile.c b/profile.c
index c3dea0e..b411fd6 100644
--- a/profile.c
+++ b/profile.c
@@ -330,27 +330,6 @@ cleanup:
                        pc = pc->target_jmp;
                        break;
 
-               case Op_plus_i:
-               case Op_minus_i:
-               case Op_times_i:
-               case Op_exp_i:
-               case Op_quotient_i:
-               case Op_mod_i:
-                       m = pc->memory;
-                       t1 = pp_pop();
-                       if (prec_level(pc->opcode) > prec_level(t1->type)
-                                       && is_binary(t1->type))  /* (a - b) * 1 
*/
-                               pp_parenthesize(t1);
-                       if ((m->flags & NUMBER) != 0)
-                               tmp = pp_number(m);
-                       else
-                               tmp = pp_string(m->stptr, m->stlen, '"');
-                       str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp);
-                       efree(tmp);
-                       pp_free(t1);
-                       pp_push(pc->opcode, str, CAN_FREE);
-                       break;
-
                case Op_plus:
                case Op_minus:
                case Op_times:
@@ -388,6 +367,7 @@ cleanup:
                case Op_field_spec:
                case Op_field_spec_lhs:
                case Op_unary_minus:
+               case Op_unary_plus:
                case Op_not:
                        t1 = pp_pop();
                        if (is_binary(t1->type))
@@ -971,7 +951,6 @@ prec_level(int type)
                return 14;
 
        case Op_exp:
-       case Op_exp_i:
                return 13;
 
        case Op_preincrement:
@@ -981,23 +960,15 @@ prec_level(int type)
                return 12;
 
        case Op_unary_minus:
+       case Op_unary_plus:
        case Op_not:
                return 11;
 
        case Op_times:
-       case Op_times_i:
        case Op_quotient:
-       case Op_quotient_i:
        case Op_mod:
-       case Op_mod_i:
                return 10;
 
-       case Op_plus:
-       case Op_plus_i:
-       case Op_minus:
-       case Op_minus_i:
-               return 9;
-
        case Op_concat:
        case Op_assign_concat:
                return 8;
@@ -1060,12 +1031,6 @@ is_binary(int type)
        case Op_mod:
        case Op_plus:
        case Op_minus:
-       case Op_exp_i:
-       case Op_times_i:
-       case Op_quotient_i:
-       case Op_mod_i:
-       case Op_plus_i:
-       case Op_minus_i:
        case Op_concat:
        case Op_assign_concat:
        case Op_match:
@@ -1206,20 +1171,9 @@ pp_string(const char *in_str, size_t len, int delim)
 char *
 pp_number(NODE *n)
 {
-#define PP_PRECISION 6
-       char *str;
-
-       emalloc(str, char *, PP_PRECISION + 10, "pp_number");
-#ifdef HAVE_MPFR
-       if (is_mpg_float(n))
-               mpfr_sprintf(str, "%0.*R*g", PP_PRECISION, ROUND_MODE, 
n->mpg_numbr);
-       else if (is_mpg_integer(n))
-               mpfr_sprintf(str, "%Zd", n->mpg_i);
-       else
-#endif
-       sprintf(str, "%0.*g", PP_PRECISION, n->numbr);
-       return str;
-#undef PP_PRECISION
+       const char *str;
+       str = fmt_number("%0.6g", n);
+       return estrdup(str, strlen(str));
 }
 
 /* pp_node --- pretty format a node */
diff --git a/test/dumpvars.ok b/test/dumpvars.ok
index 73d3d30..3670b7b 100644
--- a/test/dumpvars.ok
+++ b/test/dumpvars.ok
@@ -16,9 +16,9 @@ NR: 3
 OFMT: "%.6g"
 OFS: " "
 ORS: "\n"
-PREC: 53
+PREC: 0
 RLENGTH: 0
-ROUNDMODE: "N"
+ROUNDMODE: ""
 RS: "\n"
 RSTART: 0
 RT: "\n"
diff --git a/test/symtab1.ok b/test/symtab1.ok
index 04709e0..dc6a1b7 100644
--- a/test/symtab1.ok
+++ b/test/symtab1.ok
@@ -1,6 +1,6 @@
 ARGV[0] = gawk
 SYMTAB["i"] = "i"
-SYMTAB["ROUNDMODE"] = "N"
+SYMTAB["ROUNDMODE"] = ""
 SYMTAB["ORS"] = "
 "
 SYMTAB["OFS"] = " "
@@ -18,7 +18,7 @@ SYMTAB["ARGC"] = "1"
 SYMTAB["FIELDWIDTHS"] = ""
 SYMTAB["CONVFMT"] = "%.6g"
 SYMTAB["SUBSEP"] = ""
-SYMTAB["PREC"] = "53"
+SYMTAB["PREC"] = "0"
 SYMTAB["RS"] = "
 "
 SYMTAB["FPAT"] = "[^[:space:]]+"
diff --git a/test/symtab6.ok b/test/symtab6.ok
index 91f27e7..a1fcfb9 100644
--- a/test/symtab6.ok
+++ b/test/symtab6.ok
@@ -16,9 +16,9 @@ NR: 0
 OFMT: "%.6g"
 OFS: " "
 ORS: "\n"
-PREC: 53
+PREC: 0
 RLENGTH: 0
-ROUNDMODE: "N"
+ROUNDMODE: ""
 RS: "\n"
 RSTART: 0
 RT: ""
diff --git a/test/symtab8.ok b/test/symtab8.ok
index 8560c75..f0adb1a 100644
--- a/test/symtab8.ok
+++ b/test/symtab8.ok
@@ -17,9 +17,9 @@ NR: 1
 OFMT: "%.6g"
 OFS: " "
 ORS: "\n"
-PREC: 53
+PREC: 0
 RLENGTH: 0
-ROUNDMODE: "N"
+ROUNDMODE: ""
 RS: "\n"
 RSTART: 0
 RT: "\n"

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


hooks/post-receive
-- 
gawk



reply via email to

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