[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 = ≺
- 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 = ≺
- 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 = ≺
- 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 = ≺
+ 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 = ≺
+ 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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, long-double, created. 3963bf23516aa778881f22ac785352e74fcf6c6f,
Arnold Robbins <=