diff options
-rw-r--r-- | ChangeLog | 89 | ||||
-rw-r--r-- | FUTURES | 2 | ||||
-rw-r--r-- | Makefile.am | 3 | ||||
-rw-r--r-- | Makefile.in | 25 | ||||
-rw-r--r-- | README_d/ChangeLog | 8 | ||||
-rw-r--r-- | README_d/README.hacking | 11 | ||||
-rw-r--r-- | README_d/README.mpfr | 25 | ||||
-rw-r--r-- | TODO | 2 | ||||
-rw-r--r-- | aclocal.m4 | 1 | ||||
-rw-r--r-- | array.c | 157 | ||||
-rw-r--r-- | awk.h | 162 | ||||
-rw-r--r-- | awkgram.c | 877 | ||||
-rw-r--r-- | awkgram.y | 283 | ||||
-rw-r--r-- | awklib/Makefile.in | 13 | ||||
-rw-r--r-- | builtin.c | 293 | ||||
-rw-r--r-- | cint_array.c | 20 | ||||
-rw-r--r-- | command.c | 175 | ||||
-rw-r--r-- | command.y | 27 | ||||
-rw-r--r-- | configh.in | 3 | ||||
-rwxr-xr-x | configure | 78 | ||||
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | debug.c | 86 | ||||
-rw-r--r-- | doc/ChangeLog | 20 | ||||
-rw-r--r-- | doc/Makefile.in | 13 | ||||
-rw-r--r-- | doc/awkcard.in | 21 | ||||
-rw-r--r-- | doc/gawk.1 | 43 | ||||
-rw-r--r-- | doc/gawk.info | 1947 | ||||
-rw-r--r-- | doc/gawk.texi | 920 | ||||
-rw-r--r-- | eval.c | 222 | ||||
-rw-r--r-- | ext.c | 1 | ||||
-rw-r--r-- | field.c | 29 | ||||
-rw-r--r-- | int_array.c | 31 | ||||
-rw-r--r-- | interpret.h | 237 | ||||
-rw-r--r-- | io.c | 56 | ||||
-rw-r--r-- | m4/ChangeLog | 4 | ||||
-rw-r--r-- | m4/mpfr.m4 | 62 | ||||
-rw-r--r-- | main.c | 98 | ||||
-rw-r--r-- | mpfr.c | 1620 | ||||
-rw-r--r-- | msg.c | 16 | ||||
-rw-r--r-- | node.c | 93 | ||||
-rw-r--r-- | pc/ChangeLog | 34 | ||||
-rw-r--r-- | pc/Makefile | 100 | ||||
-rw-r--r-- | pc/Makefile.tst | 37 | ||||
-rw-r--r-- | profile.c | 17 | ||||
-rw-r--r-- | str_array.c | 35 | ||||
-rw-r--r-- | test/ChangeLog | 20 | ||||
-rwxr-xr-x | test/Gentests | 19 | ||||
-rw-r--r-- | test/Makefile.am | 60 | ||||
-rw-r--r-- | test/Makefile.in | 559 | ||||
-rw-r--r-- | test/Maketests | 487 | ||||
-rw-r--r-- | test/badargs.ok | 1 | ||||
-rw-r--r-- | test/dumpvars.ok | 2 | ||||
-rw-r--r-- | test/fmtspcl-mpfr.ok | 0 | ||||
-rw-r--r-- | test/fnarydel-mpfr.ok | 27 | ||||
-rw-r--r-- | test/fnparydl-mpfr.ok | 10 | ||||
-rw-r--r-- | test/mpfrbigint.awk | 11 | ||||
-rw-r--r-- | test/mpfrbigint.ok | 5 | ||||
-rw-r--r-- | test/mpfrexprange.awk | 7 | ||||
-rw-r--r-- | test/mpfrexprange.ok | 2 | ||||
-rw-r--r-- | test/mpfrieee.awk | 13 | ||||
-rw-r--r-- | test/mpfrieee.ok | 12 | ||||
-rw-r--r-- | test/mpfrnr.awk | 10 | ||||
-rw-r--r-- | test/mpfrnr.in | 3 | ||||
-rw-r--r-- | test/mpfrnr.ok | 1 | ||||
-rw-r--r-- | test/mpfrrnd.awk | 15 | ||||
-rw-r--r-- | test/mpfrrnd.ok | 10 | ||||
-rw-r--r-- | test/mpfrsort.awk | 8 | ||||
-rw-r--r-- | test/mpfrsort.ok | 11 | ||||
-rw-r--r-- | test/rand-mpfr.ok | 1 | ||||
-rw-r--r-- | test/rand-mpfr1.ok | 1 |
70 files changed, 7010 insertions, 2284 deletions
@@ -1,3 +1,92 @@ +2012-04-16 Eli Zaretskii <eliz@gnu.org> + + * io.c (read_with_timeout) [__MINGW32__]: Just call the blocking + 'read', as 'select' is only available for sockets. + * mpfr.c (set_ROUNDMODE) [!HAVE_MPFR]: Renamed from set_RNDMODE. + * main.c (load_procinfo): Declare name[] also when HAVE_MPFR is + defined even though HAVE_GETGROUPS etc. are not. + +2012-04-12 John Haque <j.eh@mchsi.com> + + * array.c, awk.h, awkgram.y, builtin.c, command.y, debug.c, + field.c, mpfr.c, profile.c: Change RND_MODE to ROUND_MODE. + +2012-04-11 John Haque <j.eh@mchsi.com> + + * main.c (varinit): Change RNDMODE to ROUNDMODE. + +2012-04-11 Arnold D. Robbins <arnold@skeeve.com> + + * main.c: Change --arbitrary-precision to --bignum. + +2012-04-02 John Haque <j.eh@mchsi.com> + + Add support for arbitrary-precision arithmetic. + + * mpfr.c: New file. + * awk.h (struct exp_node): Add union to handle different number types. + (MPFN, MPZN): New flag values. + (DO_MPFR, do_mpfr): New defines. + (PREC_node, RNDMODE_node): Add declarations. + (PRECISION, RND_MODE, MNR, MFNR, mpzval, do_ieee_fmt): Add declarations. + (make_number, str2number, format_val, cmp_numbers): Ditto. + (force_number): Change definition. + (Func_pre_exec, Func_post_exec): New typedefs. + (POP_NUMBER, TOP_NUMBER): Change definitions. + (get_number_ui, get_number_si, get_number_d, get_number_uj, + iszero, IEEE_FMT, mpg_float, mpg_integer, mpg_float, + mpg_integer): New defines. + * awkgram.y (tokentab): Add alternate function entries for MPFR/GMP. + (snode): Choose the appropriate function. + (negate_num): New function to negate a number. + (grammar): Use it. + (yylex): Adjust number handling code. + * array.c (value_info, asort_actual, sort_user_func): Adjust for + MPFR/GMP numbers. + (do_adump, indent): Minor changes. + (sort_up_index_number, sort_up_value_number, sort_up_value_type): Use + cmp_numbers() for numeric comparisons. + * builtin.c (mpz2mpfr): New function. + (format_tree): Adjust to handle MPFR and GMP numbers. + * eval.c (register_exec_hook): New function to manage interpreter hooks. + (num_exec_hook, pre_execute, post_execute): New and adjusted definitions. + (h_interpret): Renamed from debug_interpret. + (init_interpret): Changed to use the new name. + (flags2str): New entries for MPFN and MPZN. + (cmp_nodes): Reworked to use seperate routine for numeric comparisons. + (set_IGNORECASE, set_BINMODE, set_LINT, update_NR, update_FNR, + update_NF): Adjust code and some cleanup. + * field.c (rebuild_record): Field copying code reworked to handle + MPFR/GMP numbers. + (set_NF): Minor adjustment. + * io.c (INCREMENT_REC): New macro. + (inrec, do_getline): Use the new macro. + (nextfile, set_NR, set_FNR, get_read_timeout, pty_vs_pipe): Adjust code + to handle MPFR/GMP numbers. + * interpret.h (r_interpret): Adjust TOP_NUMBER/POP_NUMBER usage. + (EXEC_HOOK): New macro and definition. + (DEBUGGING): Removed. + * main.c (DEFAULT_PREC, DEFAULT_RNDMODE): New defines. + (opttab): New entry for option arbitrary-precision. + (main): Handle the new option. + (usage): Add to usage message. + (varinit): Add PREC and RNDMODE. + (load_procinfo): Install MPFR and GMP related items. + (version): Append MPFR and GMP versions to message. + * msg.c (err) : Adjust FNR handling with MPFR/GMP. + * node.c (r_format_val): Renamed from format_val. + (r_force_number): Return NODE * instead of AWKNUM. + (make_number, str2number, format_val, cmp_numpers: Defined and initialized. + (r_unref): Free MPFR/MPZ numbers. + (get_numbase): Renamed from isnondecimal and return the base. + (cmp_awknums): New function to compare two AWKNUMs. + * command.y (yylex): Adjust number handling code. + (grammar): Minor adjustments to handle negative numbers. + * debug.c (init_debug): New function. + (do_info, do_set_var, watchpoint_triggered, serialize, + initialize_watch_item, do_watch, print_watch_item): Minor adjustments. + (debug_pre_execute): Adjusted to handle MPFR and GMP numbers. + 2012-03-30 Arnold D. Robbins <arnold@skeeve.com> * configure.ac (GAWK_AC_NORETURN): Do as macro instead of inline. @@ -22,7 +22,7 @@ For 4.1 Merge xmlgawk XML extensions - Integrate MPFR to provide high precision arithmetic. + DONE: Integrate MPFR to provide high precision arithmetic. Continue code reviews / code cleanup diff --git a/Makefile.am b/Makefile.am index b9470617..8f6ee12e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -110,6 +110,7 @@ base_sources = \ io.c \ mbsupport.h \ main.c \ + mpfr.c \ msg.c \ node.c \ profile.c \ @@ -128,7 +129,7 @@ base_sources = \ gawk_SOURCES = $(base_sources) # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS. -LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ +LDADD = $(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 5c0d0273..b3da3c8e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -72,12 +72,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/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/stdint_h.m4 \ - $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ - $(top_srcdir)/configure.ac + $(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/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.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 \ @@ -93,10 +93,10 @@ am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT) builtin.$(OBJEXT) \ dfa.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) field.$(OBJEXT) \ floatcomp.$(OBJEXT) gawkmisc.$(OBJEXT) getopt.$(OBJEXT) \ getopt1.$(OBJEXT) int_array.$(OBJEXT) io.$(OBJEXT) \ - main.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) \ - random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \ - replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \ - version.$(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) @@ -202,6 +202,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -376,6 +377,7 @@ base_sources = \ io.c \ mbsupport.h \ main.c \ + mpfr.c \ msg.c \ node.c \ profile.c \ @@ -394,7 +396,7 @@ base_sources = \ gawk_SOURCES = $(base_sources) # Get extra libs as needed, Automake will supply LIBINTL and SOCKET_LIBS. -LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ +LDADD = $(LIBSIGSEGV) $(LIBINTL) $(SOCKET_LIBS) @LIBREADLINE@ @LIBMPFR@ # stuff for compiling gawk/pgawk DEFPATH = '".$(PATH_SEPARATOR)$(pkgdatadir)"' @@ -525,6 +527,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/int_array.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/io.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mpfr.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/msg.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/node.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/profile.Po@am__quote@ diff --git a/README_d/ChangeLog b/README_d/ChangeLog index b29f67a2..0310bd8d 100644 --- a/README_d/ChangeLog +++ b/README_d/ChangeLog @@ -1,3 +1,11 @@ +2012-04-11 John Haque <j.eh@mchsi.com> + + * README.hacking: New file. + +2012-04-01 John Haque <j.eh@mchsi.com> + + * README.mpfr: New file. + 2012-03-28 Arnold D. Robbins <arnold@skeeve.com> * 4.0.1: Release tar ball made. diff --git a/README_d/README.hacking b/README_d/README.hacking new file mode 100644 index 00000000..dcb57359 --- /dev/null +++ b/README_d/README.hacking @@ -0,0 +1,11 @@ +* Use one of the following macros to access the value of a numeric NODE: + Macro Returned C type + --------------------------------------- + get_number_ui(n) unsigned long + get_number_si(n) long + get_number_d(n) double + get_number_uj(n) uintmax_t + +* Use iszero(n) to test if a numeric NODE is zero. + +
\ No newline at end of file diff --git a/README_d/README.mpfr b/README_d/README.mpfr new file mode 100644 index 00000000..b12c19b6 --- /dev/null +++ b/README_d/README.mpfr @@ -0,0 +1,25 @@ +Sat Mar 17 07:32:01 CDT 2012 +============================= + +The MPFR and GMP versions known to work for Mac OS X on PPC: +GNU MPFR 3.1.0, GNU MP 4.3.1 + +---- +Precompiled binaries for GMP and MPFR in Windows may be available +from here: + + http://sourceforge.net/projects/ezwinports/files/ + +or here: + + http://sourceforge.net/projects/mingw/files/MinGW/Base/mpfr/ + http://sourceforge.net/projects/mingw/files/MinGW/Base/gmp/ + +You should try to use libraries downloaded from the same site +to avoid possible incompatibilities. + +---- +Gawk has been compiled and tested using the following combinations +of MPFR and GMP versions on GNU/Linux: +GNU MPFR 2.4.2, GNU MP 4.3.2 +GNU MPFR 3.1.0, GNU MP 5.0.3 @@ -11,6 +11,8 @@ Really make failure to open a socket a non-fatal error (for 4.1). ?? Scope IDs for IPv6 addresses ?? +Merge the chapter and the appendix on floating-point math (for 4.1). + ------ Code Review: @@ -963,6 +963,7 @@ m4_include([m4/lib-link.m4]) m4_include([m4/lib-prefix.m4]) m4_include([m4/libsigsegv.m4]) m4_include([m4/longlong.m4]) +m4_include([m4/mpfr.m4]) m4_include([m4/nls.m4]) m4_include([m4/noreturn.m4]) m4_include([m4/po.m4]) @@ -48,9 +48,6 @@ static array_ptr null_array_func[] = { null_afunc, null_afunc, null_dump, -#ifdef ARRAYDEBUG - null_afunc -#endif }; #define MAX_ATYPE 10 @@ -88,8 +85,10 @@ void array_init() { (void) register_array_func(str_array_func); /* the default */ - (void) register_array_func(int_array_func); - (void) register_array_func(cint_array_func); + if (! do_mpfr) { + (void) register_array_func(int_array_func); + (void) register_array_func(cint_array_func); + } } @@ -662,7 +661,6 @@ do_delete_loop(NODE *symbol, NODE **lhs) /* value_info --- print scalar node info */ - static void value_info(NODE *n) { @@ -678,11 +676,29 @@ 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) + 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, ">"); - } else + } 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); + } fprintf(output_fp, ":%s", flags2str(n->flags)); @@ -703,32 +719,6 @@ value_info(NODE *n) } -#ifdef ARRAYDEBUG - -NODE * -do_aoption(int nargs) -{ - int ret = -1; - NODE *opt, *val; - int i; - array_ptr *afunc; - - val = POP_SCALAR(); - opt = POP_SCALAR(); - for (i = 0; i < num_atypes; i++) { - afunc = atypes[i]; - if (afunc[NUM_AFUNCS] && (*afunc[NUM_AFUNCS])(opt, val) != NULL) { - ret = 0; - break; - } - } - DEREF(opt); - DEREF(val); - return make_number((AWKNUM) ret); -} - -#endif - void indent(int indent_level) { @@ -747,7 +737,7 @@ assoc_info(NODE *subs, NODE *val, NODE *ndump, const char *aname) indent_level++; indent(indent_level); fprintf(output_fp, "I: [%s:", aname); - if ((subs->flags & INTIND) != 0) + if ((subs->flags & (MPFN|MPZN|INTIND)) == INTIND) fprintf(output_fp, "<%ld>", (long) subs->numbr); else value_info(subs); @@ -785,8 +775,8 @@ do_adump(int nargs) */ if (nargs == 2) { - tmp = POP_SCALAR(); - depth = (long) force_number(tmp); + tmp = POP_NUMBER(); + depth = get_number_si(tmp); DEREF(tmp); } symbol = POP_PARAM(); @@ -885,21 +875,19 @@ asort_actual(int nargs, SORT_CTXT ctxt) result->parent_array = array->parent_array; } - subs = make_number((AWKNUM) 0.0); - if (ctxt == ASORTI) { /* We want the indices of the source array. */ for (i = 1, ptr = list; i <= num_elems; i++, ptr += 2) { - subs->numbr = (AWKNUM) i; - r = *ptr; - *assoc_lookup(result, subs) = r; + subs = make_number(i); + *assoc_lookup(result, subs) = *ptr; + unref(subs); } } else { /* We want the values of the source array. */ for (i = 1, ptr = list; i <= num_elems; i++) { - subs->numbr = (AWKNUM) i; + subs = make_number(i); /* free index node */ r = *ptr++; @@ -908,8 +896,6 @@ asort_actual(int nargs, SORT_CTXT ctxt) /* value node */ r = *ptr++; - /* FIXME: asort(a) optimization */ - if (r->type == Node_val) *assoc_lookup(result, subs) = dupnode(r); else { @@ -922,10 +908,10 @@ asort_actual(int nargs, SORT_CTXT ctxt) arr->parent_array = array; /* actual parent, not the temporary one. */ *assoc_lookup(result, subs) = assoc_copy(r, arr); } + unref(subs); } } - unref(subs); efree(list); if (result != dest) { @@ -958,13 +944,13 @@ do_asorti(int nargs) /* - * cmp_string --- compare two strings; logic similar to cmp_nodes() in eval.c + * cmp_strings --- compare two strings; logic similar to cmp_nodes() in eval.c * except the extra case-sensitive comparison when the case-insensitive * result is a match. */ static int -cmp_string(const NODE *n1, const NODE *n2) +cmp_strings(const NODE *n1, const NODE *n2) { char *s1, *s2; size_t len1, len2; @@ -1010,7 +996,6 @@ cmp_string(const NODE *n1, const NODE *n2) return (len1 < len2) ? -1 : 1; } - /* sort_up_index_string --- qsort comparison function; ascending index strings. */ static int @@ -1021,7 +1006,7 @@ sort_up_index_string(const void *p1, const void *p2) /* Array indices are strings */ t1 = *((const NODE *const *) p1); t2 = *((const NODE *const *) p2); - return cmp_string(t1, t2); + return cmp_strings(t1, t2); } @@ -1054,15 +1039,14 @@ sort_up_index_number(const void *p1, const void *p2) t1 = *((const NODE *const *) p1); t2 = *((const NODE *const *) p2); - if (t1->numbr < t2->numbr) - ret = -1; - else - ret = (t1->numbr > t2->numbr); + ret = cmp_numbers(t1, t2); + if (ret != 0) + return ret; /* break a tie with the index string itself */ - if (ret == 0) - return cmp_string(t1, t2); - return ret; + t1 = force_string((NODE *) t1); + t2 = force_string((NODE *) t2); + return cmp_strings(t1, t2); } /* sort_down_index_number --- qsort comparison function; descending index numbers */ @@ -1092,7 +1076,7 @@ sort_up_value_string(const void *p1, const void *p2) return -1; /* t1 (scalar) < t2 (sub-array) */ /* t1 and t2 both have string values */ - return cmp_string(t1, t2); + return cmp_strings(t1, t2); } @@ -1123,23 +1107,17 @@ sort_up_value_number(const void *p1, const void *p2) if (t2->type == Node_var_array) return -1; /* t1 (scalar) < t2 (sub-array) */ - /* t1 and t2 both Node_val, and force_number'ed */ - if (t1->numbr < t2->numbr) - ret = -1; - else - ret = (t1->numbr > t2->numbr); - - if (ret == 0) { - /* - * Use string value to guarantee same sort order on all - * versions of qsort(). - */ - t1 = force_string(t1); - t2 = force_string(t2); - ret = cmp_string(t1, t2); - } + ret = cmp_numbers(t1, t2); + if (ret != 0) + return ret; - return ret; + /* + * Use string value to guarantee same sort order on all + * versions of qsort(). + */ + t1 = force_string(t1); + t2 = force_string(t2); + return cmp_strings(t1, t2); } @@ -1186,12 +1164,7 @@ sort_up_value_type(const void *p1, const void *p2) (void) force_string(n2); if ((n1->flags & NUMBER) != 0 && (n2->flags & NUMBER) != 0) { - if (n1->numbr < n2->numbr) - return -1; - else if (n1->numbr > n2->numbr) - return 1; - else - return 0; + return cmp_numbers(n1, n2); } /* 3. All numbers are less than all strings. This is aribitrary. */ @@ -1202,7 +1175,7 @@ sort_up_value_type(const void *p1, const void *p2) } /* 4. Two strings */ - return cmp_string(n1, n2); + return cmp_strings(n1, n2); } /* sort_down_value_type --- qsort comparison function; descending value type */ @@ -1218,8 +1191,8 @@ sort_down_value_type(const void *p1, const void *p2) static int sort_user_func(const void *p1, const void *p2) { - NODE *idx1, *idx2, *val1, *val2; - AWKNUM ret; + NODE *idx1, *idx2, *val1, *val2, *r; + int ret; INSTRUCTION *code; idx1 = *((NODE *const *) p1); @@ -1246,9 +1219,21 @@ sort_user_func(const void *p1, const void *p2) (void) (*interpret)(code); /* return value of the comparison function */ - POP_NUMBER(ret); - - return (ret < 0.0) ? -1 : (ret > 0.0); + 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); + DEREF(r); + return ret; } @@ -195,6 +195,18 @@ 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 { @@ -369,9 +381,17 @@ 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; @@ -402,12 +422,14 @@ typedef struct exp_node { * lazy conversion to string. */ # define WSTRCUR 0x0400 /* wide str value is current */ +# define MPFN 0x0800 /* arbitrary-precision floating-point number */ +# define MPZN 0x1000 /* arbitrary-precision integer */ /* type = Node_var_array */ -# define ARRAYMAXED 0x0800 /* array is at max size */ -# define HALFHAT 0x1000 /* half-capacity Hashed Array Tree; +# define ARRAYMAXED 0x2000 /* array is at max size */ +# define HALFHAT 0x4000 /* half-capacity Hashed Array Tree; * See cint_array.c */ -# define XARRAY 0x2000 +# define XARRAY 0x8000 } NODE; #define vname sub.nodep.name @@ -446,7 +468,13 @@ typedef struct exp_node { #define stfmt sub.val.idx #define wstptr sub.val.wsp #define wstlen sub.val.wslen -#define numbr sub.val.fltnum +#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 @@ -602,7 +630,7 @@ typedef enum opcodeval { Op_indirect_func_call, Op_push, /* scalar variable */ - Op_push_arg, /* variable type (scalar or array) argument to built-in */ + Op_push_arg, /* variable type (scalar or array) argument to built-in */ Op_push_i, /* number, string */ Op_push_re, /* regex */ Op_push_array, @@ -990,13 +1018,20 @@ extern NODE *FNR_node, *FS_node, *IGNORECASE_node, *NF_node; extern NODE *NR_node, *OFMT_node, *OFS_node, *ORS_node, *RLENGTH_node; extern NODE *RSTART_node, *RS_node, *RT_node, *SUBSEP_node, *PROCINFO_node; 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 **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 NODE *(*str2number)(NODE *); +extern NODE *(*format_val)(const char *, int, NODE *); +extern int (*cmp_numbers)(const NODE *, const NODE *); +typedef int (*Func_pre_exec)(INSTRUCTION **); +typedef void (*Func_post_exec)(INSTRUCTION *); #if __GNUC__ < 2 extern NODE *_t; /* used as temporary in macros */ @@ -1036,7 +1071,8 @@ extern int do_flags; #define DO_PROFILE 0x1000 /* debug the program */ #define DO_DEBUG 0x2000 - +/* arbitrary-precision floating-point math */ +#define DO_MPFR 0x4000 #define do_traditional (do_flags & DO_TRADITIONAL) #define do_posix (do_flags & DO_POSIX) @@ -1049,7 +1085,7 @@ extern int do_flags; #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 int do_optimize; extern int use_lc_numeric; @@ -1077,6 +1113,16 @@ 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 int do_ieee_fmt; /* emulate IEEE 754 floating-point format */ +#endif + + extern const char *myname; extern const char def_strftime_format[]; @@ -1134,9 +1180,6 @@ extern STACK_ITEM *stack_top; #define POP_PARAM() ({ NODE *_t = POP(); \ _t->type == Node_var_array ? _t : get_array(_t, FALSE); }) -#define POP_NUMBER(x) ({ NODE *_t = POP_SCALAR(); x = force_number(_t); DEREF(_t); }) -#define TOP_NUMBER(x) ({ NODE *_t = TOP_SCALAR(); x = force_number(_t); DEREF(_t); }) - #define POP_SCALAR() ({ NODE *_t = POP(); _t->type != Node_var_array ? _t \ : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t);}) #define TOP_SCALAR() ({ NODE *_t = TOP(); _t->type != Node_var_array ? _t \ @@ -1153,9 +1196,6 @@ extern STACK_ITEM *stack_top; #define POP_PARAM() (_t = POP(), \ _t->type == Node_var_array ? _t : get_array(_t, FALSE)) -#define POP_NUMBER(x) (_t = POP_SCALAR(), x = force_number(_t), DEREF(_t)) -#define TOP_NUMBER(x) (_t = TOP_SCALAR(), x = force_number(_t), DEREF(_t)) - #define POP_SCALAR() (_t = POP(), _t->type != Node_var_array ? _t \ : (fatal(_("attempt to use array `%s' in a scalar context"), array_vname(_t)), _t)) #define TOP_SCALAR() (_t = TOP(), _t->type != Node_var_array ? _t \ @@ -1166,7 +1206,48 @@ extern STACK_ITEM *stack_top; #endif /* __GNUC__ */ +#define POP_NUMBER() force_number(POP_SCALAR()) +#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 is_identchar(c) (isalnum(c) || (c) == '_') #define var_uninitialized(n) ((n)->var_value == Nnull_string) @@ -1206,7 +1287,7 @@ extern STACK_ITEM *stack_top; #define efree(p) free(p) #ifdef GAWKDEBUG -#define force_number r_force_number +#define force_number str2number #define dupnode r_dupnode #define unref r_unref #define m_force_string r_force_string @@ -1224,8 +1305,8 @@ extern NODE *r_force_string(NODE *s); #define dupnode(n) __extension__ ({ NODE *_tn = (n); \ (_tn->flags & MALLOC) ? (_tn->valref++, _tn) : r_dupnode(_tn); }) -#define force_number(n) __extension__ ({ NODE *_tn = (n);\ - (_tn->flags & NUMCUR) ? _tn->numbr : r_force_number(_tn); }) +#define force_number(n) __extension__ ({ NODE *_tn = (n); \ + (_tn->flags & NUMCUR) ? _tn : str2number(_tn); }) #define force_string(s) __extension__ ({ NODE *_ts = (s); m_force_string(_ts); }) @@ -1233,7 +1314,7 @@ extern NODE *r_force_string(NODE *s); #define dupnode(n) (_t = (n), \ (_t->flags & MALLOC) ? (_t->valref++, _t) : r_dupnode(_t)) -#define force_number r_force_number +#define force_number str2number #define force_string(s) (_t = (s), m_force_string(_t)) #endif /* __GNUC__ */ #endif /* GAWKDEBUG */ @@ -1315,6 +1396,7 @@ extern SRCFILE *add_srcfile(int stype, char *src, SRCFILE *curr, int *already_in 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); @@ -1364,9 +1446,8 @@ extern int strncasecmpmbs(const unsigned char *, extern void PUSH_CODE(INSTRUCTION *cp); extern INSTRUCTION *POP_CODE(void); extern void init_interpret(void); -extern int r_interpret(INSTRUCTION *); -extern int debug_interpret(INSTRUCTION *); -extern int cmp_nodes(NODE *p1, NODE *p2); +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); @@ -1385,13 +1466,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, int 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 */ NODE *do_ext(int nargs); NODE *load_ext(const char *lib_name, const char *init_func, NODE *obj); @@ -1462,6 +1543,36 @@ extern int is_std_var(const char *var); 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); +#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 err(const char *s, const char *emsg, va_list argp) ATTRIBUTE_PRINTF(2, 0); @@ -1480,17 +1591,16 @@ extern void init_profiling(int *flag, const char *def_file); extern void init_profiling_signals(void); extern void set_prof_file(const char *filename); extern void dump_prog(INSTRUCTION *code); -extern char *pp_number(AWKNUM d); +extern char *pp_number(NODE *n); extern char *pp_string(const char *in_str, size_t len, int delim); 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, int breaklines); /* node.c */ -extern AWKNUM r_force_number(NODE *n); -extern NODE *format_val(const char *format, int index, NODE *s); +extern NODE *r_force_number(NODE *n); +extern NODE *r_format_val(const char *format, int index, NODE *s); extern NODE *r_dupnode(NODE *n); -extern NODE *make_number(AWKNUM x); extern NODE *r_make_str_node(const char *s, size_t len, int flags); extern void *more_blocks(int id); extern void r_unref(NODE *tmp); @@ -1522,7 +1632,7 @@ 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 remaybelong(const char *text, size_t len); -extern int isnondecimal(const char *str, int use_locale); +extern int get_numbase(const char *str, int use_locale); /* symbol.c */ extern NODE *install_symbol(char *name, NODETYPE type); @@ -708,20 +708,20 @@ static const yytype_uint16 yyrline[] = 318, 327, 337, 339, 341, 347, 352, 353, 357, 376, 375, 409, 411, 416, 417, 430, 435, 436, 440, 442, 444, 451, 541, 583, 625, 738, 745, 752, 762, 771, - 780, 789, 804, 820, 819, 843, 855, 855, 949, 949, - 974, 997, 1003, 1004, 1010, 1011, 1018, 1023, 1035, 1049, - 1051, 1057, 1062, 1064, 1072, 1074, 1083, 1084, 1092, 1097, - 1097, 1108, 1112, 1120, 1121, 1124, 1126, 1131, 1132, 1141, - 1142, 1147, 1152, 1158, 1160, 1162, 1169, 1170, 1176, 1177, - 1182, 1184, 1189, 1191, 1193, 1195, 1201, 1208, 1210, 1212, - 1228, 1238, 1245, 1247, 1252, 1254, 1256, 1264, 1266, 1271, - 1273, 1278, 1280, 1282, 1332, 1334, 1336, 1338, 1340, 1342, - 1344, 1346, 1369, 1374, 1379, 1404, 1410, 1412, 1414, 1416, - 1418, 1420, 1425, 1429, 1460, 1462, 1468, 1474, 1487, 1488, - 1489, 1494, 1499, 1503, 1507, 1520, 1533, 1538, 1574, 1592, - 1593, 1599, 1600, 1605, 1607, 1614, 1631, 1648, 1650, 1657, - 1662, 1670, 1680, 1692, 1701, 1705, 1709, 1713, 1717, 1721, - 1724, 1726, 1730, 1734, 1738 + 780, 789, 804, 820, 819, 843, 855, 855, 953, 953, + 978, 1001, 1007, 1008, 1014, 1015, 1022, 1027, 1039, 1053, + 1055, 1063, 1068, 1070, 1078, 1080, 1089, 1090, 1098, 1103, + 1103, 1114, 1118, 1126, 1127, 1130, 1132, 1137, 1138, 1147, + 1148, 1153, 1158, 1164, 1166, 1168, 1175, 1176, 1182, 1183, + 1188, 1190, 1195, 1197, 1199, 1201, 1207, 1214, 1216, 1218, + 1234, 1244, 1251, 1253, 1258, 1260, 1262, 1270, 1272, 1277, + 1279, 1284, 1286, 1288, 1338, 1340, 1342, 1344, 1346, 1348, + 1350, 1352, 1375, 1380, 1385, 1410, 1416, 1418, 1420, 1422, + 1424, 1426, 1431, 1435, 1467, 1469, 1475, 1481, 1494, 1495, + 1496, 1501, 1506, 1510, 1514, 1529, 1542, 1547, 1583, 1601, + 1602, 1608, 1609, 1614, 1616, 1623, 1640, 1657, 1659, 1666, + 1671, 1679, 1689, 1701, 1710, 1714, 1718, 1722, 1726, 1730, + 1733, 1735, 1739, 1743, 1747 }; #endif @@ -2039,7 +2039,7 @@ yyreduce: { case 3: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 195 "awkgram.y" { rule = 0; @@ -2049,7 +2049,7 @@ yyreduce: case 5: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 201 "awkgram.y" { next_sourcefile(); @@ -2058,7 +2058,7 @@ yyreduce: case 6: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 205 "awkgram.y" { rule = 0; @@ -2072,7 +2072,7 @@ yyreduce: case 7: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 217 "awkgram.y" { (void) append_rule((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); @@ -2081,7 +2081,7 @@ yyreduce: case 8: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 221 "awkgram.y" { if (rule != Rule) { @@ -2097,7 +2097,7 @@ yyreduce: case 9: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 232 "awkgram.y" { in_function = NULL; @@ -2108,7 +2108,7 @@ yyreduce: case 10: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 238 "awkgram.y" { want_source = FALSE; @@ -2118,7 +2118,7 @@ yyreduce: case 11: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 246 "awkgram.y" { if (include_source((yyvsp[(1) - (1)])) < 0) @@ -2131,35 +2131,35 @@ yyreduce: case 12: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 254 "awkgram.y" { (yyval) = NULL; } break; case 13: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 256 "awkgram.y" { (yyval) = NULL; } break; case 14: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 261 "awkgram.y" { (yyval) = NULL; rule = Rule; } break; case 15: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 263 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); rule = Rule; } break; case 16: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 265 "awkgram.y" { INSTRUCTION *tp; @@ -2190,7 +2190,7 @@ yyreduce: case 17: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 291 "awkgram.y" { static int begin_seen = 0; @@ -2206,7 +2206,7 @@ yyreduce: case 18: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 302 "awkgram.y" { static int end_seen = 0; @@ -2222,7 +2222,7 @@ yyreduce: case 19: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 313 "awkgram.y" { (yyvsp[(1) - (1)])->in_rule = rule = BEGINFILE; @@ -2233,7 +2233,7 @@ yyreduce: case 20: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 319 "awkgram.y" { (yyvsp[(1) - (1)])->in_rule = rule = ENDFILE; @@ -2244,7 +2244,7 @@ yyreduce: case 21: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 328 "awkgram.y" { if ((yyvsp[(2) - (5)]) == NULL) @@ -2256,21 +2256,21 @@ yyreduce: case 22: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 338 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 23: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 340 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 24: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 342 "awkgram.y" { yyerror(_("`%s' is a built-in function, it cannot be redefined"), @@ -2281,14 +2281,14 @@ yyreduce: case 25: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 348 "awkgram.y" { (yyval) = (yyvsp[(2) - (2)]); } break; case 28: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 358 "awkgram.y" { (yyvsp[(1) - (6)])->source_file = source; @@ -2304,14 +2304,14 @@ yyreduce: case 29: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 376 "awkgram.y" { ++want_regexp; } break; case 30: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 378 "awkgram.y" { NODE *n, *exp; @@ -2345,21 +2345,21 @@ yyreduce: case 31: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 410 "awkgram.y" { bcfree((yyvsp[(1) - (1)])); } break; case 33: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 416 "awkgram.y" { (yyval) = NULL; } break; case 34: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 418 "awkgram.y" { if ((yyvsp[(2) - (2)]) == NULL) @@ -2377,28 +2377,28 @@ yyreduce: case 35: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 431 "awkgram.y" { (yyval) = NULL; } break; case 38: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 441 "awkgram.y" { (yyval) = NULL; } break; case 39: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 443 "awkgram.y" { (yyval) = (yyvsp[(2) - (3)]); } break; case 40: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 445 "awkgram.y" { if (do_pretty_print) @@ -2410,7 +2410,7 @@ yyreduce: case 41: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 452 "awkgram.y" { INSTRUCTION *dflt, *curr = NULL, *cexp, *cstmt; @@ -2505,7 +2505,7 @@ yyreduce: case 42: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 542 "awkgram.y" { /* @@ -2552,7 +2552,7 @@ yyreduce: case 43: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 584 "awkgram.y" { /* @@ -2599,7 +2599,7 @@ yyreduce: case 44: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 626 "awkgram.y" { INSTRUCTION *ip; @@ -2651,16 +2651,16 @@ yyreduce: } else { INSTRUCTION *tbreak, *tcont; - /* [ Op_push_array a ] - * [ Op_arrayfor_init | ib ] - * ic:[ Op_arrayfor_incr | ib ] - * [ Op_var_assign if any ] - * - * body - * - * [Op_jmp | ic ] - * ib:[Op_arrayfor_final ] - */ + /* [ Op_push_array a ] + * [ Op_arrayfor_init | ib ] + * ic:[ Op_arrayfor_incr | ib ] + * [ Op_var_assign if any ] + * + * body + * + * [Op_jmp | ic ] + * ib:[Op_arrayfor_final ] + */ regular_loop: ip = (yyvsp[(5) - (8)]); ip->nexti->opcode = Op_push_array; @@ -2717,7 +2717,7 @@ regular_loop: case 45: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 739 "awkgram.y" { (yyval) = mk_for_loop((yyvsp[(1) - (12)]), (yyvsp[(3) - (12)]), (yyvsp[(6) - (12)]), (yyvsp[(9) - (12)]), (yyvsp[(12) - (12)])); @@ -2729,7 +2729,7 @@ regular_loop: case 46: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 746 "awkgram.y" { (yyval) = mk_for_loop((yyvsp[(1) - (11)]), (yyvsp[(3) - (11)]), (INSTRUCTION *) NULL, (yyvsp[(8) - (11)]), (yyvsp[(11) - (11)])); @@ -2741,7 +2741,7 @@ regular_loop: case 47: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 753 "awkgram.y" { if (do_pretty_print) @@ -2753,7 +2753,7 @@ regular_loop: case 48: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 763 "awkgram.y" { if (! break_allowed) @@ -2767,7 +2767,7 @@ regular_loop: case 49: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 772 "awkgram.y" { if (! continue_allowed) @@ -2781,7 +2781,7 @@ regular_loop: case 50: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 781 "awkgram.y" { /* if inside function (rule = 0), resolve context at run-time */ @@ -2795,7 +2795,7 @@ regular_loop: case 51: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 790 "awkgram.y" { if (do_traditional) @@ -2815,7 +2815,7 @@ regular_loop: case 52: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 805 "awkgram.y" { /* Initialize the two possible jump targets, the actual target @@ -2835,7 +2835,7 @@ regular_loop: case 53: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 820 "awkgram.y" { if (! in_function) @@ -2845,7 +2845,7 @@ regular_loop: case 54: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 823 "awkgram.y" { if ((yyvsp[(3) - (4)]) == NULL) { @@ -2871,14 +2871,14 @@ regular_loop: case 56: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 855 "awkgram.y" { in_print = TRUE; in_parens = 0; } break; case 57: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 856 "awkgram.y" { /* @@ -2892,8 +2892,7 @@ regular_loop: || ((yyvsp[(3) - (4)])->lasti->opcode == Op_field_spec && (yyvsp[(3) - (4)])->nexti->nexti->nexti == (yyvsp[(3) - (4)])->lasti && (yyvsp[(3) - (4)])->nexti->nexti->opcode == Op_push_i - && (yyvsp[(3) - (4)])->nexti->nexti->memory->type == Node_val - && (yyvsp[(3) - (4)])->nexti->nexti->memory->numbr == 0.0) + && (yyvsp[(3) - (4)])->nexti->nexti->memory->type == Node_val) ) ) { static short warned = FALSE; @@ -2907,11 +2906,16 @@ regular_loop: */ if ((yyvsp[(3) - (4)]) != NULL) { - bcfree((yyvsp[(3) - (4)])->lasti); /* Op_field_spec */ - unref((yyvsp[(3) - (4)])->nexti->nexti->memory); /* Node_val */ + NODE *n = (yyvsp[(3) - (4)])->nexti->nexti->memory; + + if (! iszero(n)) + goto regular_print; + + bcfree((yyvsp[(3) - (4)])->lasti); /* Op_field_spec */ + unref(n); /* Node_val */ bcfree((yyvsp[(3) - (4)])->nexti->nexti); /* Op_push_i */ - bcfree((yyvsp[(3) - (4)])->nexti); /* Op_list */ - bcfree((yyvsp[(3) - (4)])); /* Op_list */ + bcfree((yyvsp[(3) - (4)])->nexti); /* Op_list */ + bcfree((yyvsp[(3) - (4)])); /* Op_list */ } else { if (do_lint && (rule == BEGIN || rule == END) && ! warned) { warned = TRUE; @@ -2943,7 +2947,7 @@ regular_loop: * [$1 | NULL | redir_type | expr_count] * */ - +regular_print: if ((yyvsp[(4) - (4)]) == NULL) { /* no redirection */ if ((yyvsp[(3) - (4)]) == NULL) { /* printf without arg */ (yyvsp[(1) - (4)])->expr_count = 0; @@ -2976,15 +2980,15 @@ regular_loop: case 58: -/* Line 1806 of yacc.c */ -#line 949 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 953 "awkgram.y" { sub_counter = 0; } break; case 59: -/* Line 1806 of yacc.c */ -#line 950 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 954 "awkgram.y" { char *arr = (yyvsp[(2) - (4)])->lextok; @@ -3013,8 +3017,8 @@ regular_loop: case 60: -/* Line 1806 of yacc.c */ -#line 979 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 983 "awkgram.y" { static short warned = FALSE; char *arr = (yyvsp[(3) - (4)])->lextok; @@ -3037,36 +3041,36 @@ regular_loop: case 61: -/* Line 1806 of yacc.c */ -#line 998 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1002 "awkgram.y" { (yyval) = optimize_assignment((yyvsp[(1) - (1)])); } break; case 62: -/* Line 1806 of yacc.c */ -#line 1003 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1007 "awkgram.y" { (yyval) = NULL; } break; case 63: -/* Line 1806 of yacc.c */ -#line 1005 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1009 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 64: -/* Line 1806 of yacc.c */ -#line 1010 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1014 "awkgram.y" { (yyval) = NULL; } break; case 65: -/* Line 1806 of yacc.c */ -#line 1012 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1016 "awkgram.y" { if ((yyvsp[(1) - (2)]) == NULL) (yyval) = list_create((yyvsp[(2) - (2)])); @@ -3077,15 +3081,15 @@ regular_loop: case 66: -/* Line 1806 of yacc.c */ -#line 1019 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1023 "awkgram.y" { (yyval) = NULL; } break; case 67: -/* Line 1806 of yacc.c */ -#line 1024 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1028 "awkgram.y" { INSTRUCTION *casestmt = (yyvsp[(5) - (5)]); if ((yyvsp[(5) - (5)]) == NULL) @@ -3101,8 +3105,8 @@ regular_loop: case 68: -/* Line 1806 of yacc.c */ -#line 1036 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1040 "awkgram.y" { INSTRUCTION *casestmt = (yyvsp[(4) - (4)]); if ((yyvsp[(4) - (4)]) == NULL) @@ -3117,17 +3121,19 @@ regular_loop: case 69: -/* Line 1806 of yacc.c */ -#line 1050 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1054 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 70: -/* Line 1806 of yacc.c */ -#line 1052 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1056 "awkgram.y" { - (yyvsp[(2) - (2)])->memory->numbr = -(force_number((yyvsp[(2) - (2)])->memory)); + NODE *n = (yyvsp[(2) - (2)])->memory; + (void) force_number(n); + negate_num(n); bcfree((yyvsp[(1) - (2)])); (yyval) = (yyvsp[(2) - (2)]); } @@ -3135,8 +3141,8 @@ regular_loop: case 71: -/* Line 1806 of yacc.c */ -#line 1058 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1064 "awkgram.y" { bcfree((yyvsp[(1) - (2)])); (yyval) = (yyvsp[(2) - (2)]); @@ -3145,15 +3151,15 @@ regular_loop: case 72: -/* Line 1806 of yacc.c */ -#line 1063 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1069 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 73: -/* Line 1806 of yacc.c */ -#line 1065 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1071 "awkgram.y" { (yyvsp[(1) - (1)])->opcode = Op_push_re; (yyval) = (yyvsp[(1) - (1)]); @@ -3162,22 +3168,22 @@ regular_loop: case 74: -/* Line 1806 of yacc.c */ -#line 1073 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1079 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 75: -/* Line 1806 of yacc.c */ -#line 1075 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1081 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 77: -/* Line 1806 of yacc.c */ -#line 1085 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1091 "awkgram.y" { (yyval) = (yyvsp[(2) - (3)]); } @@ -3185,8 +3191,8 @@ regular_loop: case 78: -/* Line 1806 of yacc.c */ -#line 1092 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1098 "awkgram.y" { in_print = FALSE; in_parens = 0; @@ -3196,15 +3202,15 @@ regular_loop: case 79: -/* Line 1806 of yacc.c */ -#line 1097 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1103 "awkgram.y" { in_print = FALSE; in_parens = 0; } break; case 80: -/* Line 1806 of yacc.c */ -#line 1098 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1104 "awkgram.y" { if ((yyvsp[(1) - (3)])->redir_type == redirect_twoway && (yyvsp[(3) - (3)])->lasti->opcode == Op_K_getline_redir @@ -3216,8 +3222,8 @@ regular_loop: case 81: -/* Line 1806 of yacc.c */ -#line 1109 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1115 "awkgram.y" { (yyval) = mk_condition((yyvsp[(3) - (6)]), (yyvsp[(1) - (6)]), (yyvsp[(6) - (6)]), NULL, NULL); } @@ -3225,8 +3231,8 @@ regular_loop: case 82: -/* Line 1806 of yacc.c */ -#line 1114 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1120 "awkgram.y" { (yyval) = mk_condition((yyvsp[(3) - (9)]), (yyvsp[(1) - (9)]), (yyvsp[(6) - (9)]), (yyvsp[(7) - (9)]), (yyvsp[(9) - (9)])); } @@ -3234,15 +3240,15 @@ regular_loop: case 87: -/* Line 1806 of yacc.c */ -#line 1131 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1137 "awkgram.y" { (yyval) = NULL; } break; case 88: -/* Line 1806 of yacc.c */ -#line 1133 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1139 "awkgram.y" { bcfree((yyvsp[(1) - (2)])); (yyval) = (yyvsp[(2) - (2)]); @@ -3251,22 +3257,22 @@ regular_loop: case 89: -/* Line 1806 of yacc.c */ -#line 1141 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1147 "awkgram.y" { (yyval) = NULL; } break; case 90: -/* Line 1806 of yacc.c */ -#line 1143 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1149 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]) ; } break; case 91: -/* Line 1806 of yacc.c */ -#line 1148 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1154 "awkgram.y" { (yyvsp[(1) - (1)])->param_count = 0; (yyval) = list_create((yyvsp[(1) - (1)])); @@ -3275,8 +3281,8 @@ regular_loop: case 92: -/* Line 1806 of yacc.c */ -#line 1153 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1159 "awkgram.y" { (yyvsp[(3) - (3)])->param_count = (yyvsp[(1) - (3)])->lasti->param_count + 1; (yyval) = list_append((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])); @@ -3286,64 +3292,64 @@ regular_loop: case 93: -/* Line 1806 of yacc.c */ -#line 1159 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1165 "awkgram.y" { (yyval) = NULL; } break; case 94: -/* Line 1806 of yacc.c */ -#line 1161 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1167 "awkgram.y" { (yyval) = (yyvsp[(1) - (2)]); } break; case 95: -/* Line 1806 of yacc.c */ -#line 1163 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1169 "awkgram.y" { (yyval) = (yyvsp[(1) - (3)]); } break; case 96: -/* Line 1806 of yacc.c */ -#line 1169 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1175 "awkgram.y" { (yyval) = NULL; } break; case 97: -/* Line 1806 of yacc.c */ -#line 1171 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1177 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 98: -/* Line 1806 of yacc.c */ -#line 1176 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1182 "awkgram.y" { (yyval) = NULL; } break; case 99: -/* Line 1806 of yacc.c */ -#line 1178 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1184 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 100: -/* Line 1806 of yacc.c */ -#line 1183 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1189 "awkgram.y" { (yyval) = mk_expression_list(NULL, (yyvsp[(1) - (1)])); } break; case 101: -/* Line 1806 of yacc.c */ -#line 1185 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1191 "awkgram.y" { (yyval) = mk_expression_list((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)])); yyerrok; @@ -3352,36 +3358,36 @@ regular_loop: case 102: -/* Line 1806 of yacc.c */ -#line 1190 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1196 "awkgram.y" { (yyval) = NULL; } break; case 103: -/* Line 1806 of yacc.c */ -#line 1192 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1198 "awkgram.y" { (yyval) = NULL; } break; case 104: -/* Line 1806 of yacc.c */ -#line 1194 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1200 "awkgram.y" { (yyval) = NULL; } break; case 105: -/* Line 1806 of yacc.c */ -#line 1196 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1202 "awkgram.y" { (yyval) = NULL; } break; case 106: -/* Line 1806 of yacc.c */ -#line 1202 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1208 "awkgram.y" { if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec) lintwarn_ln((yyvsp[(2) - (3)])->source_line, @@ -3392,22 +3398,22 @@ regular_loop: case 107: -/* Line 1806 of yacc.c */ -#line 1209 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1215 "awkgram.y" { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 108: -/* Line 1806 of yacc.c */ -#line 1211 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1217 "awkgram.y" { (yyval) = mk_boolean((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 109: -/* Line 1806 of yacc.c */ -#line 1213 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1219 "awkgram.y" { if ((yyvsp[(1) - (3)])->lasti->opcode == Op_match_rec) warning_ln((yyvsp[(2) - (3)])->source_line, @@ -3427,8 +3433,8 @@ regular_loop: case 110: -/* Line 1806 of yacc.c */ -#line 1229 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1235 "awkgram.y" { if (do_lint_old) warning_ln((yyvsp[(2) - (3)])->source_line, @@ -3442,8 +3448,8 @@ regular_loop: case 111: -/* Line 1806 of yacc.c */ -#line 1239 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1245 "awkgram.y" { if (do_lint && (yyvsp[(3) - (3)])->lasti->opcode == Op_match_rec) lintwarn_ln((yyvsp[(2) - (3)])->source_line, @@ -3454,36 +3460,36 @@ regular_loop: case 112: -/* Line 1806 of yacc.c */ -#line 1246 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1252 "awkgram.y" { (yyval) = mk_condition((yyvsp[(1) - (5)]), (yyvsp[(2) - (5)]), (yyvsp[(3) - (5)]), (yyvsp[(4) - (5)]), (yyvsp[(5) - (5)])); } break; case 113: -/* Line 1806 of yacc.c */ -#line 1248 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1254 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 114: -/* Line 1806 of yacc.c */ -#line 1253 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1259 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 115: -/* Line 1806 of yacc.c */ -#line 1255 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1261 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 116: -/* Line 1806 of yacc.c */ -#line 1257 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1263 "awkgram.y" { (yyvsp[(2) - (2)])->opcode = Op_assign_quotient; (yyval) = (yyvsp[(2) - (2)]); @@ -3492,50 +3498,50 @@ regular_loop: case 117: -/* Line 1806 of yacc.c */ -#line 1265 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1271 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 118: -/* Line 1806 of yacc.c */ -#line 1267 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1273 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 119: -/* Line 1806 of yacc.c */ -#line 1272 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1278 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 120: -/* Line 1806 of yacc.c */ -#line 1274 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1280 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 121: -/* Line 1806 of yacc.c */ -#line 1279 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1285 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 122: -/* Line 1806 of yacc.c */ -#line 1281 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1287 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 123: -/* Line 1806 of yacc.c */ -#line 1283 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1289 "awkgram.y" { int count = 2; int is_simple_var = FALSE; @@ -3586,50 +3592,50 @@ regular_loop: case 125: -/* Line 1806 of yacc.c */ -#line 1335 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1341 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 126: -/* Line 1806 of yacc.c */ -#line 1337 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1343 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 127: -/* Line 1806 of yacc.c */ -#line 1339 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1345 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 128: -/* Line 1806 of yacc.c */ -#line 1341 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1347 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 129: -/* Line 1806 of yacc.c */ -#line 1343 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1349 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 130: -/* Line 1806 of yacc.c */ -#line 1345 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1351 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 131: -/* Line 1806 of yacc.c */ -#line 1347 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1353 "awkgram.y" { /* * In BEGINFILE/ENDFILE, allow `getline var < file' @@ -3656,8 +3662,8 @@ regular_loop: case 132: -/* Line 1806 of yacc.c */ -#line 1370 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1376 "awkgram.y" { (yyvsp[(2) - (2)])->opcode = Op_postincrement; (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - (2)])); @@ -3666,8 +3672,8 @@ regular_loop: case 133: -/* Line 1806 of yacc.c */ -#line 1375 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1381 "awkgram.y" { (yyvsp[(2) - (2)])->opcode = Op_postdecrement; (yyval) = mk_assignment((yyvsp[(1) - (2)]), NULL, (yyvsp[(2) - (2)])); @@ -3676,8 +3682,8 @@ regular_loop: case 134: -/* Line 1806 of yacc.c */ -#line 1380 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1386 "awkgram.y" { if (do_lint_old) { warning_ln((yyvsp[(4) - (5)])->source_line, @@ -3701,8 +3707,8 @@ regular_loop: case 135: -/* Line 1806 of yacc.c */ -#line 1405 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1411 "awkgram.y" { (yyval) = mk_getline((yyvsp[(3) - (4)]), (yyvsp[(4) - (4)]), (yyvsp[(1) - (4)]), (yyvsp[(2) - (4)])->redir_type); bcfree((yyvsp[(2) - (4)])); @@ -3711,50 +3717,50 @@ regular_loop: case 136: -/* Line 1806 of yacc.c */ -#line 1411 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1417 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 137: -/* Line 1806 of yacc.c */ -#line 1413 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1419 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 138: -/* Line 1806 of yacc.c */ -#line 1415 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1421 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 139: -/* Line 1806 of yacc.c */ -#line 1417 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1423 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 140: -/* Line 1806 of yacc.c */ -#line 1419 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1425 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 141: -/* Line 1806 of yacc.c */ -#line 1421 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1427 "awkgram.y" { (yyval) = mk_binary((yyvsp[(1) - (3)]), (yyvsp[(3) - (3)]), (yyvsp[(2) - (3)])); } break; case 142: -/* Line 1806 of yacc.c */ -#line 1426 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1432 "awkgram.y" { (yyval) = list_create((yyvsp[(1) - (1)])); } @@ -3762,8 +3768,8 @@ regular_loop: case 143: -/* Line 1806 of yacc.c */ -#line 1430 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1436 "awkgram.y" { if ((yyvsp[(2) - (2)])->opcode == Op_match_rec) { (yyvsp[(2) - (2)])->opcode = Op_nomatch; @@ -3774,6 +3780,7 @@ regular_loop: } 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) { @@ -3798,15 +3805,15 @@ regular_loop: case 144: -/* Line 1806 of yacc.c */ -#line 1461 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1468 "awkgram.y" { (yyval) = (yyvsp[(2) - (3)]); } break; case 145: -/* Line 1806 of yacc.c */ -#line 1463 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1470 "awkgram.y" { (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)])); if ((yyval) == NULL) @@ -3816,8 +3823,8 @@ regular_loop: case 146: -/* Line 1806 of yacc.c */ -#line 1469 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1476 "awkgram.y" { (yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)])); if ((yyval) == NULL) @@ -3827,8 +3834,8 @@ regular_loop: case 147: -/* Line 1806 of yacc.c */ -#line 1475 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1482 "awkgram.y" { static short warned1 = FALSE; @@ -3845,8 +3852,8 @@ regular_loop: case 150: -/* Line 1806 of yacc.c */ -#line 1490 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1497 "awkgram.y" { (yyvsp[(1) - (2)])->opcode = Op_preincrement; (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)])); @@ -3855,8 +3862,8 @@ regular_loop: case 151: -/* Line 1806 of yacc.c */ -#line 1495 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1502 "awkgram.y" { (yyvsp[(1) - (2)])->opcode = Op_predecrement; (yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) - (2)])); @@ -3865,8 +3872,8 @@ regular_loop: case 152: -/* Line 1806 of yacc.c */ -#line 1500 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1507 "awkgram.y" { (yyval) = list_create((yyvsp[(1) - (1)])); } @@ -3874,8 +3881,8 @@ regular_loop: case 153: -/* Line 1806 of yacc.c */ -#line 1504 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1511 "awkgram.y" { (yyval) = list_create((yyvsp[(1) - (1)])); } @@ -3883,13 +3890,15 @@ regular_loop: case 154: -/* Line 1806 of yacc.c */ -#line 1508 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1515 "awkgram.y" { if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i && ((yyvsp[(2) - (2)])->lasti->memory->flags & (STRCUR|STRING)) == 0 ) { - (yyvsp[(2) - (2)])->lasti->memory->numbr = -(force_number((yyvsp[(2) - (2)])->lasti->memory)); + NODE *n = (yyvsp[(2) - (2)])->lasti->memory; + (void) force_number(n); + negate_num(n); (yyval) = (yyvsp[(2) - (2)]); bcfree((yyvsp[(1) - (2)])); } else { @@ -3901,8 +3910,8 @@ regular_loop: case 155: -/* Line 1806 of yacc.c */ -#line 1521 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1530 "awkgram.y" { /* * was: $$ = $2 @@ -3916,8 +3925,8 @@ regular_loop: case 156: -/* Line 1806 of yacc.c */ -#line 1534 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1543 "awkgram.y" { func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE); (yyval) = (yyvsp[(1) - (1)]); @@ -3926,8 +3935,8 @@ regular_loop: case 157: -/* Line 1806 of yacc.c */ -#line 1539 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1548 "awkgram.y" { /* indirect function call */ INSTRUCTION *f, *t; @@ -3964,8 +3973,8 @@ regular_loop: case 158: -/* Line 1806 of yacc.c */ -#line 1575 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1584 "awkgram.y" { param_sanity((yyvsp[(3) - (4)])); (yyvsp[(1) - (4)])->opcode = Op_func_call; @@ -3983,43 +3992,43 @@ regular_loop: case 159: -/* Line 1806 of yacc.c */ -#line 1592 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1601 "awkgram.y" { (yyval) = NULL; } break; case 160: -/* Line 1806 of yacc.c */ -#line 1594 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1603 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 161: -/* Line 1806 of yacc.c */ -#line 1599 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1608 "awkgram.y" { (yyval) = NULL; } break; case 162: -/* Line 1806 of yacc.c */ -#line 1601 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1610 "awkgram.y" { (yyval) = (yyvsp[(1) - (2)]); } break; case 163: -/* Line 1806 of yacc.c */ -#line 1606 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1615 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 164: -/* Line 1806 of yacc.c */ -#line 1608 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1617 "awkgram.y" { (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); } @@ -4027,8 +4036,8 @@ regular_loop: case 165: -/* Line 1806 of yacc.c */ -#line 1615 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1624 "awkgram.y" { INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti; int count = ip->sub_count; /* # of SUBSEP-seperated expressions */ @@ -4046,8 +4055,8 @@ regular_loop: case 166: -/* Line 1806 of yacc.c */ -#line 1632 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1641 "awkgram.y" { INSTRUCTION *t = (yyvsp[(2) - (3)]); if ((yyvsp[(2) - (3)]) == NULL) { @@ -4065,15 +4074,15 @@ regular_loop: case 167: -/* Line 1806 of yacc.c */ -#line 1649 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1658 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 168: -/* Line 1806 of yacc.c */ -#line 1651 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1660 "awkgram.y" { (yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)])); } @@ -4081,15 +4090,15 @@ regular_loop: case 169: -/* Line 1806 of yacc.c */ -#line 1658 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1667 "awkgram.y" { (yyval) = (yyvsp[(1) - (2)]); } break; case 170: -/* Line 1806 of yacc.c */ -#line 1663 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1672 "awkgram.y" { char *var_name = (yyvsp[(1) - (1)])->lextok; @@ -4101,8 +4110,8 @@ regular_loop: case 171: -/* Line 1806 of yacc.c */ -#line 1671 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1680 "awkgram.y" { char *arr = (yyvsp[(1) - (2)])->lextok; (yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) - (2)])->source_line, arr, Node_var_new); @@ -4113,8 +4122,8 @@ regular_loop: case 172: -/* Line 1806 of yacc.c */ -#line 1681 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1690 "awkgram.y" { INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti; if (ip->opcode == Op_push @@ -4130,8 +4139,8 @@ regular_loop: case 173: -/* Line 1806 of yacc.c */ -#line 1693 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1702 "awkgram.y" { (yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)])); if ((yyvsp[(3) - (3)]) != NULL) @@ -4141,8 +4150,8 @@ regular_loop: case 174: -/* Line 1806 of yacc.c */ -#line 1702 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1711 "awkgram.y" { (yyvsp[(1) - (1)])->opcode = Op_postincrement; } @@ -4150,8 +4159,8 @@ regular_loop: case 175: -/* Line 1806 of yacc.c */ -#line 1706 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1715 "awkgram.y" { (yyvsp[(1) - (1)])->opcode = Op_postdecrement; } @@ -4159,50 +4168,50 @@ regular_loop: case 176: -/* Line 1806 of yacc.c */ -#line 1709 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1718 "awkgram.y" { (yyval) = NULL; } break; case 178: -/* Line 1806 of yacc.c */ -#line 1717 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1726 "awkgram.y" { yyerrok; } break; case 179: -/* Line 1806 of yacc.c */ -#line 1721 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1730 "awkgram.y" { yyerrok; } break; case 182: -/* Line 1806 of yacc.c */ -#line 1730 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1739 "awkgram.y" { yyerrok; } break; case 183: -/* Line 1806 of yacc.c */ -#line 1734 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1743 "awkgram.y" { (yyval) = (yyvsp[(1) - (1)]); yyerrok; } break; case 184: -/* Line 1806 of yacc.c */ -#line 1738 "awkgram.y" +/* Line 1821 of yacc.c */ +#line 1747 "awkgram.y" { yyerrok; } break; -/* Line 1806 of yacc.c */ -#line 4218 "awkgram.c" +/* Line 1821 of yacc.c */ +#line 4227 "awkgram.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -4433,7 +4442,7 @@ yyreturn: /* Line 2067 of yacc.c */ -#line 1740 "awkgram.y" +#line 1749 "awkgram.y" struct token { @@ -4452,6 +4461,7 @@ struct token { # define CONTINUE 0x2000 /* continue allowed inside */ NODE *(*ptr)(int); /* function that implements this keyword */ + NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ }; #if 'a' == 0x81 /* it's EBCDIC */ @@ -4475,81 +4485,84 @@ tokcompare(const void *l, const void *r) * Function pointers come from declarations in awk.h. */ -static const 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}, +#ifdef HAVE_MPFR +#define MPF(F) do_mpfr_##F +#else +#define MPF(F) 0 #endif -{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and}, + +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}, #ifdef ARRAYDEBUG -{"aoption", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_aoption}, +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump, 0}, #endif -{"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), do_atan2}, -{"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), do_compl}, -{"continue", Op_K_continue, LEX_CONTINUE, 0, 0}, -{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos}, -{"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), do_exp}, -{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext}, -{"fflush", Op_builtin, LEX_BUILTIN, RESX|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), do_int}, -{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray}, -{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length}, -{"log", Op_builtin, LEX_BUILTIN, A(1), do_log}, -{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift}, -{"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, GAWKX, 0}, -{"or", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_or}, -{"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), do_rand}, -{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0}, -{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift}, -{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin}, -{"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), do_sqrt}, -{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand}, -{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime}, -{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum}, -{"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|A(2), do_xor}, +{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 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)}, +{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext, 0}, +{"fflush", Op_builtin, LEX_BUILTIN, RESX|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}, +{"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, GAWKX, 0, 0}, +{"or", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 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)}, +{"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|A(2), do_xor, MPF(xor)}, }; #if MBS_SUPPORT @@ -4585,6 +4598,23 @@ 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 */ static void @@ -5486,6 +5516,7 @@ yylex(void) int seen_point = FALSE; int esc_seen; /* for literal strings */ int mid; + int base; static int did_newline = FALSE; char *tokkey; int inhex = FALSE; @@ -6054,17 +6085,42 @@ retry: tokadd('\0'); yylval = GET_INSTRUCTION(Op_push_i); - if (! do_traditional && isnondecimal(tokstart, FALSE)) { + + base = 10; + if (! do_traditional) { + base = get_numbase(tokstart, FALSE); if (do_lint) { - if (isdigit((unsigned char) tokstart[1])) /* not an 'x' or 'X' */ + if (base == 8) lintwarn("numeric constant `%.*s' treated as octal", (int) strlen(tokstart)-1, tokstart); - else if (tokstart[1] == 'x' || tokstart[1] == 'X') + else if (base == 16) lintwarn("numeric constant `%.*s' treated as hexadecimal", (int) strlen(tokstart)-1, tokstart); } + } + +#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 + else d = atof(tokstart); yylval->memory = make_number(d); if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) @@ -6350,7 +6406,13 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) } } - r->builtin = tokentab[idx].ptr; +#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; /* special case processing for a few builtins */ @@ -6556,14 +6618,28 @@ valinfo(NODE *n, Func_print print_func, FILE *fp) else if (n->flags & STRING) { pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); print_func(fp, "\n"); - } else if (n->flags & NUMBER) + } 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); - else if (n->flags & STRCUR) { + } 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) + } 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); - else + } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } @@ -7110,11 +7186,11 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) ip1 = s1->nexti; if (do_optimize > 1 && ip1 == s1->lasti && ip1->opcode == Op_push_i - && (ip1->memory->flags & (STRCUR|STRING)) == 0 - && (ip2->memory->flags & (STRCUR|STRING)) == 0 + && (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); + res = force_number(n1)->numbr; (void) force_number(n2); switch (op->opcode) { case Op_times: @@ -8066,3 +8142,4 @@ one_line_close(int fd) } + @@ -673,16 +673,16 @@ statement } else { INSTRUCTION *tbreak, *tcont; - /* [ Op_push_array a ] - * [ Op_arrayfor_init | ib ] - * ic:[ Op_arrayfor_incr | ib ] - * [ Op_var_assign if any ] - * - * body - * - * [Op_jmp | ic ] - * ib:[Op_arrayfor_final ] - */ + /* [ Op_push_array a ] + * [ Op_arrayfor_init | ib ] + * ic:[ Op_arrayfor_incr | ib ] + * [ Op_var_assign if any ] + * + * body + * + * [Op_jmp | ic ] + * ib:[Op_arrayfor_final ] + */ regular_loop: ip = $5; ip->nexti->opcode = Op_push_array; @@ -865,8 +865,7 @@ simple_stmt || ($3->lasti->opcode == Op_field_spec && $3->nexti->nexti->nexti == $3->lasti && $3->nexti->nexti->opcode == Op_push_i - && $3->nexti->nexti->memory->type == Node_val - && $3->nexti->nexti->memory->numbr == 0.0) + && $3->nexti->nexti->memory->type == Node_val) ) ) { static short warned = FALSE; @@ -880,11 +879,16 @@ simple_stmt */ if ($3 != NULL) { - bcfree($3->lasti); /* Op_field_spec */ - unref($3->nexti->nexti->memory); /* Node_val */ + NODE *n = $3->nexti->nexti->memory; + + if (! iszero(n)) + goto regular_print; + + bcfree($3->lasti); /* Op_field_spec */ + unref(n); /* Node_val */ bcfree($3->nexti->nexti); /* Op_push_i */ - bcfree($3->nexti); /* Op_list */ - bcfree($3); /* Op_list */ + bcfree($3->nexti); /* Op_list */ + bcfree($3); /* Op_list */ } else { if (do_lint && (rule == BEGIN || rule == END) && ! warned) { warned = TRUE; @@ -916,7 +920,7 @@ simple_stmt * [$1 | NULL | redir_type | expr_count] * */ - +regular_print: if ($4 == NULL) { /* no redirection */ if ($3 == NULL) { /* printf without arg */ $1->expr_count = 0; @@ -1050,7 +1054,9 @@ case_value { $$ = $1; } | '-' YNUMBER %prec UNARY { - $2->memory->numbr = -(force_number($2->memory)); + NODE *n = $2->memory; + (void) force_number(n); + negate_num(n); bcfree($1); $$ = $2; } @@ -1437,6 +1443,7 @@ non_post_simp_exp } 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) { @@ -1509,7 +1516,9 @@ non_post_simp_exp if ($2->lasti->opcode == Op_push_i && ($2->lasti->memory->flags & (STRCUR|STRING)) == 0 ) { - $2->lasti->memory->numbr = -(force_number($2->lasti->memory)); + NODE *n = $2->lasti->memory; + (void) force_number(n); + negate_num(n); $$ = $2; bcfree($1); } else { @@ -1755,6 +1764,7 @@ struct token { # define CONTINUE 0x2000 /* continue allowed inside */ NODE *(*ptr)(int); /* function that implements this keyword */ + NODE *(*ptr2)(int); /* alternate arbitrary-precision function */ }; #if 'a' == 0x81 /* it's EBCDIC */ @@ -1778,81 +1788,84 @@ tokcompare(const void *l, const void *r) * Function pointers come from declarations in awk.h. */ -static const 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}, +#ifdef HAVE_MPFR +#define MPF(F) do_mpfr_##F +#else +#define MPF(F) 0 #endif -{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_and}, + +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}, #ifdef ARRAYDEBUG -{"aoption", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_aoption}, +{"adump", Op_builtin, LEX_BUILTIN, GAWKX|A(1)|A(2), do_adump, 0}, #endif -{"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), do_atan2}, -{"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), do_compl}, -{"continue", Op_K_continue, LEX_CONTINUE, 0, 0}, -{"cos", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_cos}, -{"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), do_exp}, -{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext}, -{"fflush", Op_builtin, LEX_BUILTIN, RESX|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), do_int}, -{"isarray", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_isarray}, -{"length", Op_builtin, LEX_LENGTH, A(0)|A(1), do_length}, -{"log", Op_builtin, LEX_BUILTIN, A(1), do_log}, -{"lshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_lshift}, -{"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, GAWKX, 0}, -{"or", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_or}, -{"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), do_rand}, -{"return", Op_K_return, LEX_RETURN, NOT_OLD, 0}, -{"rshift", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_rshift}, -{"sin", Op_builtin, LEX_BUILTIN, NOT_OLD|A(1), do_sin}, -{"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), do_sqrt}, -{"srand", Op_builtin, LEX_BUILTIN, NOT_OLD|A(0)|A(1), do_srand}, -{"strftime", Op_builtin, LEX_BUILTIN, GAWKX|A(0)|A(1)|A(2)|A(3), do_strftime}, -{"strtonum", Op_builtin, LEX_BUILTIN, GAWKX|A(1), do_strtonum}, -{"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|A(2), do_xor}, +{"and", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 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)}, +{"extension", Op_builtin, LEX_BUILTIN, GAWKX|A(2), do_ext, 0}, +{"fflush", Op_builtin, LEX_BUILTIN, RESX|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}, +{"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, GAWKX, 0, 0}, +{"or", Op_builtin, LEX_BUILTIN, GAWKX|A(2), 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)}, +{"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|A(2), do_xor, MPF(xor)}, }; #if MBS_SUPPORT @@ -1888,6 +1901,23 @@ 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 */ static void @@ -2789,6 +2819,7 @@ yylex(void) int seen_point = FALSE; int esc_seen; /* for literal strings */ int mid; + int base; static int did_newline = FALSE; char *tokkey; int inhex = FALSE; @@ -3357,17 +3388,42 @@ retry: tokadd('\0'); yylval = GET_INSTRUCTION(Op_push_i); - if (! do_traditional && isnondecimal(tokstart, FALSE)) { + + base = 10; + if (! do_traditional) { + base = get_numbase(tokstart, FALSE); if (do_lint) { - if (isdigit((unsigned char) tokstart[1])) /* not an 'x' or 'X' */ + if (base == 8) lintwarn("numeric constant `%.*s' treated as octal", (int) strlen(tokstart)-1, tokstart); - else if (tokstart[1] == 'x' || tokstart[1] == 'X') + else if (base == 16) lintwarn("numeric constant `%.*s' treated as hexadecimal", (int) strlen(tokstart)-1, tokstart); } + } + +#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 + else d = atof(tokstart); yylval->memory = make_number(d); if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d) @@ -3653,7 +3709,13 @@ snode(INSTRUCTION *subn, INSTRUCTION *r) } } - r->builtin = tokentab[idx].ptr; +#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; /* special case processing for a few builtins */ @@ -3859,14 +3921,28 @@ valinfo(NODE *n, Func_print print_func, FILE *fp) else if (n->flags & STRING) { pp_string_fp(print_func, fp, n->stptr, n->stlen, '"', FALSE); print_func(fp, "\n"); - } else if (n->flags & NUMBER) + } 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); - else if (n->flags & STRCUR) { + } 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) + } 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); - else + } else print_func(fp, "?? flags %s\n", flags2str(n->flags)); } @@ -4413,11 +4489,11 @@ mk_binary(INSTRUCTION *s1, INSTRUCTION *s2, INSTRUCTION *op) ip1 = s1->nexti; if (do_optimize > 1 && ip1 == s1->lasti && ip1->opcode == Op_push_i - && (ip1->memory->flags & (STRCUR|STRING)) == 0 - && (ip2->memory->flags & (STRCUR|STRING)) == 0 + && (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); + res = force_number(n1)->numbr; (void) force_number(n2); switch (op->opcode) { case Op_times: @@ -5368,3 +5444,4 @@ one_line_close(int fd) return ret; } + diff --git a/awklib/Makefile.in b/awklib/Makefile.in index 5c1fc278..8ff83c41 100644 --- a/awklib/Makefile.in +++ b/awklib/Makefile.in @@ -67,12 +67,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/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/stdint_h.m4 \ - $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ - $(top_srcdir)/configure.ac + $(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/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.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 @@ -158,6 +158,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -135,7 +135,7 @@ do_exp(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("exp: received non-numeric argument")); - d = force_number(tmp); + d = force_number(tmp)->numbr; DEREF(tmp); errno = 0; res = exp(d); @@ -459,7 +459,7 @@ do_int(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("int: received non-numeric argument")); - d = force_number(tmp); + d = force_number(tmp)->numbr; d = double_to_int(d); DEREF(tmp); return make_number((AWKNUM) d); @@ -537,7 +537,7 @@ do_log(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("log: received non-numeric argument")); - arg = (double) force_number(tmp); + arg = force_number(tmp)->numbr; if (arg < 0.0) warning(_("log: received negative argument %g"), arg); d = log(arg); @@ -546,6 +546,42 @@ do_log(int nargs) } +#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 int 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 @@ -603,7 +639,7 @@ format_tree( size_t cur_arg = 0; NODE *r = NULL; - int i; + int i, nc; int toofew = FALSE; char *obuf, *obufout; size_t osiz, ofre; @@ -635,7 +671,7 @@ format_tree( char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)]; char *cp; const char *fill; - AWKNUM tmpval; + AWKNUM tmpval = 0.0; char signchar = FALSE; size_t len; int zero_flag = FALSE; @@ -643,6 +679,12 @@ format_tree( 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"; @@ -730,10 +772,17 @@ format_tree( prec = 0; base = 0; argnum = 0; + base = 0; have_prec = FALSE; signchar = FALSE; 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; @@ -865,7 +914,8 @@ check_pos: } else { parse_next_arg(); } - *cur = force_number(arg); + (void) force_number(arg); + *cur = get_number_si(arg); if (*cur < 0 && cur == &fw) { *cur = -*cur; lj++; @@ -973,7 +1023,7 @@ check_pos: if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM) (void) force_number(arg); if (arg->flags & NUMBER) { - uval = (uintmax_t) arg->numbr; + uval = get_number_uj(arg); #if MBS_SUPPORT if (gawk_mb_cur_max > 1) { char buf[100]; @@ -1056,7 +1106,16 @@ out2: case 'i': need_format = FALSE; parse_next_arg(); - tmpval = force_number(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. */ @@ -1167,7 +1226,78 @@ out2: base += 8; need_format = FALSE; parse_next_arg(); - tmpval = force_number(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 = FALSE; /* 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 = FALSE; /* 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 @@ -1186,14 +1316,16 @@ out2: if (tmpval < 0) { uval = (uintmax_t) (intmax_t) tmpval; - if ((AWKNUM)(intmax_t)uval != - double_to_int(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. @@ -1276,7 +1408,7 @@ out2: lintwarn(_("[s]printf: value %g is out of range for `%%%c' format"), (double) tmpval, cs1); cs1 = 'g'; - goto format_float; + goto fmt1; case 'F': #if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1 @@ -1290,11 +1422,28 @@ out2: case 'E': need_format = FALSE; parse_next_arg(); - tmpval = force_number(arg); - format_float: + (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; - chksize(fw + prec + 9); /* 9 == slop */ +#ifdef HAVE_MPFR + fmt0: +#endif + chksize(fw + prec + 11); /* 11 == slop */ cp = cpbuf; *cp++ = '%'; if (lj) @@ -1307,25 +1456,46 @@ out2: *cp++ = '0'; if (quote_flag) *cp++ = '\''; - strcpy(cp, "*.*"); - cp += 3; - *cp++ = cs1; - *cp = '\0'; + #if defined(LC_NUMERIC) if (quote_flag && ! use_lc_numeric) setlocale(LC_NUMERIC, ""); #endif - { - int n; - while ((n = snprintf(obufout, ofre, cpbuf, - (int) fw, (int) prec, - (double) tmpval)) >= ofre) - chksize(n) + + 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; @@ -1366,6 +1536,7 @@ out: if (obuf != NULL) efree(obuf); } + if (r == NULL) gawk_exit(EXIT_FATAL); return r; @@ -1477,7 +1648,7 @@ do_sqrt(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("sqrt: received non-numeric argument")); - arg = (double) force_number(tmp); + arg = (double) force_number(tmp)->numbr; DEREF(tmp); if (arg < 0.0) warning(_("sqrt: called with negative argument %g"), arg); @@ -1496,9 +1667,16 @@ do_substr(int nargs) double d_index = 0, d_length = 0; size_t src_len; - if (nargs == 3) - POP_NUMBER(d_length); - POP_NUMBER(d_index); + if (nargs == 3) { + t1 = POP_NUMBER(); + d_length = get_number_d(t1); + DEREF(t1); + } + + t1 = POP_NUMBER(); + d_index = get_number_d(t1); + DEREF(t1); + t1 = POP_STRING(); if (nargs == 3) { @@ -1682,7 +1860,8 @@ do_strftime(int nargs) t2 = POP_SCALAR(); if (do_lint && (t2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("strftime: received non-numeric second argument")); - clock_val = (long) force_number(t2); + (void) force_number(t2); + clock_val = get_number_si(t2); if (clock_val < 0) fatal(_("strftime: second argument less than 0 or too big for time_t")); fclock = (time_t) clock_val; @@ -2100,8 +2279,8 @@ do_atan2(int nargs) if ((t2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("atan2: received non-numeric second argument")); } - d1 = force_number(t1); - d2 = force_number(t2); + d1 = force_number(t1)->numbr; + d2 = force_number(t2)->numbr; DEREF(t1); DEREF(t2); return make_number((AWKNUM) atan2(d1, d2)); @@ -2118,7 +2297,7 @@ do_sin(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("sin: received non-numeric argument")); - d = sin((double) force_number(tmp)); + d = sin((double) force_number(tmp)->numbr); DEREF(tmp); return make_number((AWKNUM) d); } @@ -2134,7 +2313,7 @@ do_cos(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("cos: received non-numeric argument")); - d = cos((double) force_number(tmp)); + d = cos((double) force_number(tmp)->numbr); DEREF(tmp); return make_number((AWKNUM) d); } @@ -2187,7 +2366,7 @@ do_srand(int nargs) 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))); + srandom((unsigned int) (save_seed = (long) force_number(tmp)->numbr)); DEREF(tmp); } return make_number((AWKNUM) ret); @@ -2464,15 +2643,16 @@ do_sub(int nargs, unsigned int flags) if (t1->stlen > 0 && (t1->stptr[0] == 'g' || t1->stptr[0] == 'G')) how_many = -1; else { - d = force_number(t1); - + (void) force_number(t1); + d = get_number_d(t1); if ((t1->flags & NUMCUR) != 0) goto set_how_many; how_many = 1; } } else { - d = force_number(t1); + (void) force_number(t1); + d = get_number_d(t1); set_how_many: if (d < 1) how_many = 1; @@ -2778,8 +2958,8 @@ do_lshift(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("lshift: received non-numeric second argument")); } - val = force_number(s1); - shift = force_number(s2); + val = force_number(s1)->numbr; + shift = force_number(s2)->numbr; if (do_lint) { if (val < 0 || shift < 0) lintwarn(_("lshift(%lf, %lf): negative values will give strange results"), val, shift); @@ -2815,8 +2995,8 @@ do_rshift(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("rshift: received non-numeric second argument")); } - val = force_number(s1); - shift = force_number(s2); + val = force_number(s1)->numbr; + shift = force_number(s2)->numbr; if (do_lint) { if (val < 0 || shift < 0) lintwarn(_("rshift(%lf, %lf): negative values will give strange results"), val, shift); @@ -2852,8 +3032,8 @@ do_and(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("and: received non-numeric second argument")); } - left = force_number(s1); - right = force_number(s2); + left = force_number(s1)->numbr; + right = force_number(s2)->numbr; if (do_lint) { if (left < 0 || right < 0) lintwarn(_("and(%lf, %lf): negative values will give strange results"), left, right); @@ -2887,8 +3067,8 @@ do_or(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("or: received non-numeric second argument")); } - left = force_number(s1); - right = force_number(s2); + left = force_number(s1)->numbr; + right = force_number(s2)->numbr; if (do_lint) { if (left < 0 || right < 0) lintwarn(_("or(%lf, %lf): negative values will give strange results"), left, right); @@ -2916,8 +3096,6 @@ do_xor(int nargs) AWKNUM left, right; POP_TWO_SCALARS(s1, s2); - left = force_number(s1); - right = force_number(s2); if (do_lint) { if ((s1->flags & (NUMCUR|NUMBER)) == 0) @@ -2925,8 +3103,8 @@ do_xor(int nargs) if ((s2->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("xor: received non-numeric second argument")); } - left = force_number(s1); - right = force_number(s2); + left = force_number(s1)->numbr; + right = force_number(s2)->numbr; if (do_lint) { if (left < 0 || right < 0) lintwarn(_("xor(%lf, %lf): negative values will give strange results"), left, right); @@ -2956,12 +3134,10 @@ do_compl(int nargs) tmp = POP_SCALAR(); if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0) lintwarn(_("compl: received non-numeric argument")); - d = force_number(tmp); + d = force_number(tmp)->numbr; DEREF(tmp); if (do_lint) { - if ((tmp->flags & (NUMCUR|NUMBER)) == 0) - lintwarn(_("compl: received non-numeric argument")); if (d < 0) lintwarn(_("compl(%lf): negative value will give strange results"), d); if (double_to_int(d) != d) @@ -2983,11 +3159,11 @@ do_strtonum(int nargs) tmp = POP_SCALAR(); if ((tmp->flags & (NUMBER|NUMCUR)) != 0) - d = (AWKNUM) force_number(tmp); - else if (isnondecimal(tmp->stptr, use_lc_numeric)) + 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); + d = (AWKNUM) force_number(tmp)->numbr; DEREF(tmp); return make_number((AWKNUM) d); @@ -3237,7 +3413,10 @@ do_dcngettext(int nargs) } #endif - POP_NUMBER(d); /* third argument */ + t2 = POP_NUMBER(); /* third argument */ + d = get_number_d(t2); + DEREF(t2); + number = (unsigned long) double_to_int(d); t2 = POP_STRING(); /* second argument */ string2 = t2->stptr; diff --git a/cint_array.c b/cint_array.c index 8ec09239..f82eb4b6 100644 --- a/cint_array.c +++ b/cint_array.c @@ -52,7 +52,6 @@ static NODE **cint_list(NODE *symbol, NODE *t); static NODE **cint_copy(NODE *symbol, NODE *newsymb); static NODE **cint_dump(NODE *symbol, NODE *ndump); #ifdef ARRAYDEBUG -static NODE **cint_option(NODE *opt, NODE *val); static void cint_print(NODE *symbol); #endif @@ -66,9 +65,6 @@ array_ptr cint_array_func[] = { cint_list, cint_copy, cint_dump, -#ifdef ARRAYDEBUG - cint_option, -#endif }; static inline int cint_hash(long k); @@ -624,22 +620,6 @@ cint_find(NODE *symbol, long k, int h1) #ifdef ARRAYDEBUG -static NODE ** -cint_option(NODE *opt, NODE *val) -{ - NODE *tmp; - NODE **ret = (NODE **) ! NULL; - - tmp = force_string(opt); - (void) force_number(val); - if (strcmp(tmp->stptr, "NHAT") == 0) - NHAT = (int) val->numbr; - else - ret = NULL; - return ret; -} - - /* cint_print --- print structural info */ static void @@ -1713,7 +1713,7 @@ yyreduce: { case 3: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 109 "command.y" { cmd_idx = -1; @@ -1733,7 +1733,7 @@ yyreduce: case 5: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 128 "command.y" { if (errcount == 0 && cmd_idx >= 0) { @@ -1788,7 +1788,7 @@ yyreduce: case 6: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 178 "command.y" { yyerrok; @@ -1797,14 +1797,14 @@ yyreduce: case 22: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 212 "command.y" { want_nodeval = TRUE; } break; case 23: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 217 "command.y" { if (errcount == 0) { @@ -1824,7 +1824,7 @@ yyreduce: case 24: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 235 "command.y" { (yyval) = append_statement(arg_list, (char *) start_EVAL); @@ -1837,14 +1837,14 @@ yyreduce: case 25: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 242 "command.y" { (yyval) = append_statement((yyvsp[(1) - (2)]), lexptr_begin); } break; case 26: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 243 "command.y" { (yyval) = (yyvsp[(3) - (4)]); @@ -1853,7 +1853,7 @@ yyreduce: case 27: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 250 "command.y" { arg_list = append_statement((yyvsp[(2) - (3)]), (char *) end_EVAL); @@ -1874,7 +1874,7 @@ yyreduce: case 28: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 266 "command.y" { NODE *n; @@ -1890,7 +1890,7 @@ yyreduce: case 34: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 285 "command.y" { if (cmdtab[cmd_idx].class == D_FRAME @@ -1901,7 +1901,7 @@ yyreduce: case 35: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 291 "command.y" { int idx = find_argument((yyvsp[(2) - (2)])); @@ -1918,49 +1918,49 @@ yyreduce: case 38: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 304 "command.y" { want_nodeval = TRUE; } break; case 40: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 305 "command.y" { want_nodeval = TRUE; } break; case 46: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 310 "command.y" { want_nodeval = TRUE; } break; case 49: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 312 "command.y" { want_nodeval = TRUE; } break; case 51: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 313 "command.y" { want_nodeval = TRUE; } break; case 53: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 314 "command.y" { want_nodeval = TRUE; } break; case 57: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 318 "command.y" { if (in_cmd_src((yyvsp[(2) - (2)])->a_string)) @@ -1970,7 +1970,7 @@ yyreduce: case 58: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 323 "command.y" { if (! input_from_tty) @@ -1980,7 +1980,7 @@ yyreduce: case 59: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 328 "command.y" { int type = 0; @@ -2011,7 +2011,7 @@ yyreduce: case 60: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 354 "command.y" { if (! in_commands) @@ -2026,7 +2026,7 @@ yyreduce: case 61: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 364 "command.y" { if (! in_commands) @@ -2036,7 +2036,7 @@ yyreduce: case 62: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 369 "command.y" { int idx = find_argument((yyvsp[(2) - (2)])); @@ -2053,14 +2053,14 @@ yyreduce: case 63: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 380 "command.y" { want_nodeval = TRUE; } break; case 64: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 381 "command.y" { int type; @@ -2073,7 +2073,7 @@ yyreduce: case 65: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 389 "command.y" { if (in_commands) { @@ -2089,7 +2089,7 @@ yyreduce: case 66: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 403 "command.y" { if ((yyvsp[(1) - (1)]) != NULL) { @@ -2104,42 +2104,42 @@ yyreduce: case 68: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 417 "command.y" { (yyval) = NULL; } break; case 69: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 422 "command.y" { (yyval) = NULL; } break; case 74: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 431 "command.y" { (yyval) = NULL; } break; case 75: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 436 "command.y" { (yyval) = NULL; } break; case 77: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 439 "command.y" { (yyval) = NULL; } break; case 78: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 444 "command.y" { NODE *n; @@ -2151,14 +2151,14 @@ yyreduce: case 79: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 454 "command.y" { (yyval) = NULL; } break; case 80: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 456 "command.y" { if (find_option((yyvsp[(1) - (1)])->a_string) < 0) @@ -2168,7 +2168,7 @@ yyreduce: case 81: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 461 "command.y" { if (find_option((yyvsp[(1) - (3)])->a_string) < 0) @@ -2178,7 +2178,7 @@ yyreduce: case 82: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 469 "command.y" { NODE *n; @@ -2196,56 +2196,56 @@ yyreduce: case 83: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 485 "command.y" { (yyval) = NULL; } break; case 88: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 494 "command.y" { (yyval) = NULL; } break; case 89: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 495 "command.y" { want_nodeval = TRUE; } break; case 92: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 497 "command.y" { want_nodeval = TRUE; } break; case 95: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 503 "command.y" { (yyval) = NULL; } break; case 97: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 509 "command.y" { (yyval) = NULL; } break; case 99: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 515 "command.y" { (yyval) = NULL; } break; case 104: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 527 "command.y" { int idx = find_argument((yyvsp[(1) - (2)])); @@ -2262,7 +2262,7 @@ yyreduce: case 106: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 543 "command.y" { (yyvsp[(2) - (2)])->type = D_array; /* dump all items */ @@ -2272,7 +2272,7 @@ yyreduce: case 107: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 548 "command.y" { (yyvsp[(2) - (3)])->type = D_array; @@ -2282,21 +2282,21 @@ yyreduce: case 117: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 574 "command.y" { (yyval) = NULL; } break; case 118: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 576 "command.y" { (yyval) = NULL; } break; case 119: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 578 "command.y" { CMDARG *a; @@ -2308,7 +2308,7 @@ yyreduce: case 126: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 594 "command.y" { if ((yyvsp[(1) - (3)])->a_int > (yyvsp[(3) - (3)])->a_int) @@ -2322,28 +2322,28 @@ yyreduce: case 127: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 606 "command.y" { (yyval) = NULL; } break; case 134: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 620 "command.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 135: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 622 "command.y" { (yyval) = (yyvsp[(1) - (3)]); } break; case 137: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 628 "command.y" { CMDARG *a; @@ -2363,21 +2363,21 @@ yyreduce: case 139: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 647 "command.y" { (yyval) = (yyvsp[(1) - (1)]); num_dim = 1; } break; case 140: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 649 "command.y" { (yyval) = (yyvsp[(1) - (2)]); num_dim++; } break; case 142: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 655 "command.y" { NODE *n = (yyvsp[(2) - (2)])->a_node; @@ -2391,7 +2391,7 @@ yyreduce: case 143: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 664 "command.y" { /* a_string is array name, a_count is dimension count */ @@ -2403,14 +2403,14 @@ yyreduce: case 144: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 674 "command.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 145: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 676 "command.y" { NODE *n = (yyvsp[(2) - (2)])->a_node; @@ -2422,49 +2422,49 @@ yyreduce: case 146: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 683 "command.y" { NODE *n = (yyvsp[(2) - (2)])->a_node; if ((n->flags & NUMBER) == 0) yyerror(_("non-numeric value found, numeric expected")); else - (yyvsp[(2) - (2)])->a_node->numbr = - n->numbr; + negate_num(n); (yyval) = (yyvsp[(2) - (2)]); } break; case 147: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 695 "command.y" { (yyval) = NULL; } break; case 148: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 697 "command.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 149: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 702 "command.y" { (yyval) = NULL; } break; case 150: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 704 "command.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 151: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 709 "command.y" { if ((yyvsp[(1) - (1)])->a_int == 0) @@ -2475,7 +2475,7 @@ yyreduce: case 152: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 715 "command.y" { if ((yyvsp[(2) - (2)])->a_int == 0) @@ -2486,21 +2486,21 @@ yyreduce: case 153: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 724 "command.y" { (yyval) = (yyvsp[(1) - (1)]); } break; case 154: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 726 "command.y" { (yyval) = (yyvsp[(2) - (2)]); } break; case 155: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 728 "command.y" { (yyvsp[(2) - (2)])->a_int = - (yyvsp[(2) - (2)])->a_int; @@ -2510,7 +2510,7 @@ yyreduce: case 156: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 736 "command.y" { if (lexptr_begin != NULL) { @@ -2524,7 +2524,7 @@ yyreduce: -/* Line 1806 of yacc.c */ +/* Line 1821 of yacc.c */ #line 2541 "command.c" default: break; } @@ -3252,22 +3252,37 @@ err: return D_STRING; } - /* assert(want_nodval == TRUE); */ - /* look for awk number */ if (isdigit((unsigned char) tokstart[0])) { - double d; + NODE *r = NULL; errno = 0; - d = strtod(tokstart, &lexptr); +#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)); + if (errno != 0) { yyerror(strerror(errno)); + unref(r); errno = 0; return '\n'; } yylval = mk_cmdarg(D_node); - yylval->a_node = make_number(d); + yylval->a_node = r; append_cmdarg(yylval); return D_NODE; } @@ -685,7 +685,7 @@ node if ((n->flags & NUMBER) == 0) yyerror(_("non-numeric value found, numeric expected")); else - $2->a_node->numbr = - n->numbr; + negate_num(n); $$ = $2; } ; @@ -1238,22 +1238,37 @@ err: return D_STRING; } - /* assert(want_nodval == TRUE); */ - /* look for awk number */ if (isdigit((unsigned char) tokstart[0])) { - double d; + NODE *r = NULL; errno = 0; - d = strtod(tokstart, &lexptr); +#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)); + if (errno != 0) { yyerror(strerror(errno)); + unref(r); errno = 0; return '\n'; } yylval = mk_cmdarg(D_node); - yylval->a_node = make_number(d); + yylval->a_node = r; append_cmdarg(yylval); return D_NODE; } @@ -157,6 +157,9 @@ /* we have the mktime function */ #undef HAVE_MKTIME +/* Define to 1 if you have fully functional mpfr and gmp libraries. */ +#undef HAVE_MPFR + /* Define to 1 if you have the <netdb.h> header file. */ #undef HAVE_NETDB_H @@ -607,6 +607,7 @@ ac_func_list= ac_subst_vars='am__EXEEXT_FALSE am__EXEEXT_TRUE LTLIBOBJS +LIBMPFR LIBREADLINE SOCKET_LIBS LIBSIGSEGV_PREFIX @@ -736,6 +737,7 @@ with_libiconv_prefix with_libintl_prefix with_libsigsegv_prefix with_readline +with_mpfr ' ac_precious_vars='build_alias host_alias @@ -1387,6 +1389,7 @@ Optional Packages: --with-libsigsegv-prefix[=DIR] search for libsigsegv in DIR/include and DIR/lib --without-libsigsegv-prefix don't search for libsigsegv in includedir and libdir --with-readline=DIR look for the readline library in DIR + --with-mpfr=DIR look for the mpfr and gmp libraries in DIR Some influential environment variables: CC C compiler command @@ -10300,6 +10303,81 @@ $as_echo "#define HAVE_LIBREADLINE 1" >>confdefs.h fi + + +# Check whether --with-mpfr was given. +if test "${with_mpfr+set}" = set; then : + withval=$with_mpfr; _do_mpfr=$withval +else + _do_mpfr=yes +fi + + + if test "$_do_mpfr" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + _mpfr_save_libs=$LIBS + _combo="-lmpfr -lgmp" + LIBS="$LIBS $_combo" + + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether mpfr via \"$_combo\" is present and usable" >&5 +$as_echo_n "checking whether mpfr via \"$_combo\" is present and usable... " >&6; } + + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + + +#include <stdio.h> +#include <mpfr.h> +#include <gmp.h> + +int +main () +{ + +mpfr_t p; +mpz_t z; +mpfr_init(p); +mpz_init(z); +mpfr_printf("%Rf%Zd", p, z); +mpfr_clear(p); +mpz_clear(z); + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + _found_mpfr=yes +else + _found_mpfr=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $_found_mpfr" >&5 +$as_echo "$_found_mpfr" >&6; } + + LIBS=$_mpfr_save_libs + + if test $_found_mpfr = yes ; then + +$as_echo "#define HAVE_MPFR 1" >>confdefs.h + + LIBMPFR=$_combo + + break + fi + + unset _mpfr_save_libs + unset _combo + unset _found_mpfr + fi + + ac_fn_c_check_member "$LINENO" "struct stat" "st_blksize" "ac_cv_member_struct_stat_st_blksize" "$ac_includes_default" if test "x$ac_cv_member_struct_stat_st_blksize" = xyes; then : diff --git a/configure.ac b/configure.ac index 9de46582..e4ab7f44 100644 --- a/configure.ac +++ b/configure.ac @@ -342,6 +342,9 @@ GAWK_AC_LIB_SOCKETS dnl check for readline support GNUPG_CHECK_READLINE +dnl check for mpfr support +GNUPG_CHECK_MPFR + dnl checks for structure members AC_STRUCT_ST_BLKSIZE AC_HEADER_TIME @@ -51,7 +51,7 @@ static size_t linebuf_len; FILE *out_fp; char *dPrompt; char *commands_Prompt = "> "; /* breakpoint or watchpoint commands list */ -char *eval_Prompt = "@> "; /* awk statement(s) */ +char *eval_Prompt = "@> "; /* awk statement(s) */ int input_from_tty = FALSE; int input_fd; @@ -173,7 +173,7 @@ static struct { int break_point; /* non-zero (breakpoint number) if stopped at break point */ int watch_point; /* non-zero (watchpoint number) if stopped at watch point */ - int (*check_func)(INSTRUCTION **); /* function to decide when to suspend + int (*check_func)(INSTRUCTION **); /* function to decide when to suspend * awk interpreter and return control * to debugger command interpreter. */ @@ -231,10 +231,10 @@ static const char *options_file = DEFAULT_OPTFILE; static const char *history_file = DEFAULT_HISTFILE; #endif -/* keep all option variables in one place */ +/* debugger option related variables */ static char *output_file = "/dev/stdout"; /* gawk output redirection */ -char *dgawk_Prompt = NULL; /* initialized in do_debug */ +char *dgawk_Prompt = NULL; /* initialized in do_debug */ static int list_size = DEFAULT_LISTSIZE; /* # of lines that 'list' prints */ static int do_trace = FALSE; static int do_save_history = TRUE; @@ -307,9 +307,10 @@ static int watchpoint_triggered(struct list_item *w); static void print_instruction(INSTRUCTION *pc, Func_print print_func, FILE *fp, int in_dump); static int print_code(INSTRUCTION *pc, void *x); static void next_command(); +static void debug_post_execute(INSTRUCTION *pc); +static int debug_pre_execute(INSTRUCTION **pi); static char *g_readline(const char *prompt); static int prompt_yes_no(const char *, char , int , FILE *); - static struct pf_data { Func_print print_func; int defn; @@ -325,8 +326,8 @@ struct command_source char * (*read_func)(const char *); int (*close_func)(int); int eof_status; /* see push_cmd_src */ - int cmd; /* D_source or 0 */ - char *str; /* sourced file */ + int cmd; /* D_source or 0 */ + char *str; /* sourced file */ struct command_source *next; }; @@ -893,7 +894,7 @@ do_info(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) } gprintf(out_fp, "\n"); } else if (IS_FIELD(d)) - gprintf(out_fp, "%d:\t$%ld\n", d->number, (long) symbol->numbr); + gprintf(out_fp, "%d:\t$%ld\n", d->number, get_number_si(symbol)); else gprintf(out_fp, "%d:\t%s\n", d->number, d->sname); if (d->cndn.code != NULL) @@ -1179,7 +1180,7 @@ do_print_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) break; case D_field: - print_field(a->a_node->numbr); + print_field(get_number_si(a->a_node)); break; default: @@ -1283,7 +1284,7 @@ do_set_var(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) long field_num; Func_ptr assign = NULL; - field_num = (long) arg->a_node->numbr; + field_num = get_number_si(arg->a_node); assert(field_num >= 0); arg = arg->next; val = arg->a_node; @@ -1533,7 +1534,7 @@ display(struct list_item *d) } else if (IS_FIELD(d)) { NODE *r = d->symbol; fprintf(out_fp, "%d: ", d->number); - print_field(r->numbr); + print_field(get_number_si(r)); } else { print_sym: fprintf(out_fp, "%d: %s = ", d->number, d->sname); @@ -1590,7 +1591,7 @@ condition_triggered(struct condition *cndn) return FALSE; /* not triggered */ force_number(r); - di = (r->numbr != 0.0); + di = ! iszero(r); DEREF(r); return di; } @@ -1684,7 +1685,7 @@ watchpoint_triggered(struct list_item *w) (void) find_subscript(w, &t2); else if (IS_FIELD(w)) { long field_num; - field_num = (long) w->symbol->numbr; + field_num = get_number_si(w->symbol); t2 = *get_field(field_num, NULL); } else { switch (symbol->type) { @@ -1767,7 +1768,7 @@ initialize_watch_item(struct list_item *w) } else if (IS_FIELD(w)) { long field_num; t = w->symbol; - field_num = (long) t->numbr; + field_num = get_number_si(t); r = *get_field(field_num, NULL); w->cur_value = dupnode(r); } else { @@ -1806,7 +1807,7 @@ do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) fprintf(out_fp, "Watchpoint %d: ", w->number); symbol = w->symbol; -/* FIXME: common code also in print_watch_item */ + /* FIXME: common code also in print_watch_item */ if (IS_SUBSCRIPT(w)) { fprintf(out_fp, "%s", w->sname); for (i = 0; i < w->num_subs; i++) { @@ -1815,7 +1816,7 @@ do_watch(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) } fprintf(out_fp, "\n"); } else if (IS_FIELD(w)) - fprintf(out_fp, "$%ld\n", (long) symbol->numbr); + fprintf(out_fp, "$%ld\n", get_number_si(symbol)); else fprintf(out_fp, "%s\n", w->sname); @@ -2721,6 +2722,15 @@ initialize_readline() #endif +/* init_debug --- register debugger exec hooks */ + +void +init_debug() +{ + register_exec_hook(debug_pre_execute, debug_post_execute); +} + + /* debug_prog --- debugger entry point */ int @@ -3380,7 +3390,7 @@ print_watch_item(struct list_item *w) } fprintf(out_fp, "\n"); } else if (IS_FIELD(w)) - fprintf(out_fp, "$%ld\n", (long) symbol->numbr); + fprintf(out_fp, "$%ld\n", get_number_si(symbol)); else fprintf(out_fp, "%s\n", w->sname); @@ -3491,10 +3501,10 @@ no_output: read_command(); /* zzparse */ } -/* post_execute --- post_hook in the interpreter */ +/* debug_post_execute --- post_hook in the interpreter */ -void -post_execute(INSTRUCTION *pc) +static void +debug_post_execute(INSTRUCTION *pc) { if (! in_main_context()) return; @@ -3544,13 +3554,13 @@ post_execute(INSTRUCTION *pc) } } -/* pre_execute --- pre_hook, called by the interpreter before execution; +/* debug_pre_execute --- pre_hook, called by the interpreter before execution; * checks if execution needs to be suspended and control * transferred to the debugger. */ -int -pre_execute(INSTRUCTION **pi) +static int +debug_pre_execute(INSTRUCTION **pi) { static int cant_stop = FALSE; NODE *m; @@ -3645,13 +3655,27 @@ 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) - print_func(fp, "%g", m->numbr); - else if ((m->flags & STRING) != 0) + else if ((m->flags & NUMBER) != 0) { +#ifdef HAVE_MPFR + if (m->flags & MPFN) + print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr)); + else if (m->flags & MPZN) + print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i)); + else +#endif + print_func(fp, "%g", m->numbr); + } else if ((m->flags & STRING) != 0) pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', FALSE); - else if ((m->flags & NUMCUR) != 0) - print_func(fp, "%g", m->numbr); - else if ((m->flags & STRCUR) != 0) + else if ((m->flags & NUMCUR) != 0) { +#ifdef HAVE_MPFR + if (m->flags & MPFN) + print_func(fp, "%s", mpg_fmt("%R*g", ROUND_MODE, m->mpg_numbr)); + else if (m->flags & MPZN) + print_func(fp, "%s", mpg_fmt("%Zd", m->mpg_i)); + else +#endif + print_func(fp, "%g", m->numbr); + } else if ((m->flags & STRCUR) != 0) pp_string_fp(print_func, fp, m->stptr, m->stlen, '"', FALSE); else print_func(fp, "-?-"); @@ -4362,7 +4386,7 @@ enlarge_buffer: nchar = serialize_subscript(buf + bl, buflen - bl, wd); else if (IS_FIELD(wd)) nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%d%c", - wd->number, FSEP, D_field, FSEP, (int) wd->symbol->numbr, FSEP); + wd->number, FSEP, D_field, FSEP, (int) get_number_si(wd->symbol), FSEP); else nchar = snprintf(buf + bl, buflen - bl, "%d%c%d%c%s%c", wd->number, FSEP, D_variable, FSEP, wd->sname, FSEP); @@ -4929,7 +4953,7 @@ do_print_f(CMDARG *arg, int cmd ATTRIBUTE_UNUSED) { long field_num; r = a->a_node; - field_num = (long) r->numbr; + field_num = get_number_si(r); tmp[i] = *get_field(field_num, NULL); } break; diff --git a/doc/ChangeLog b/doc/ChangeLog index 43c9ffdd..6e4c0103 100644 --- a/doc/ChangeLog +++ b/doc/ChangeLog @@ -1,3 +1,23 @@ +2012-04-11 John Haque <j.eh@mchsi.com> + + * gawk.texi: Change RNDMODE to ROUNDMODE. + * gawk.1, awkcard.in: Ditto. + +2012-04-11 Arnold D. Robbins <arnold@skeeve.com> + + * gawk.texi: Change --arbitrary-precision to --bignum. + * gawk.1: Ditto. + * awkcard.in: Add --bignum, RNDMODE, PREC. + +2012-04-08 Arnold D. Robbins <arnold@skeeve.com> + + * gawk.texi: Editing on new chapter on arbitrary precision numbers. + +2012-03-31 John Haque <j.eh@mchsi.com> + + * gawk.texi, gawk.1: Add text on support for arbitrary precision + numbers. + 2012-02-06 Arnold D. Robbins <arnold@skeeve.com> * gawk.texi, gawk.1: And some minor edits thereunto. diff --git a/doc/Makefile.in b/doc/Makefile.in index 7c8d9dbe..e475208b 100644 --- a/doc/Makefile.in +++ b/doc/Makefile.in @@ -68,12 +68,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/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/stdint_h.m4 \ - $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ - $(top_srcdir)/configure.ac + $(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/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.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 @@ -154,6 +154,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ diff --git a/doc/awkcard.in b/doc/awkcard.in index adc506c3..b7d87691 100644 --- a/doc/awkcard.in +++ b/doc/awkcard.in @@ -282,6 +282,8 @@ If \*(FIvalue\*(FR is \*(FCinvalid\*(FR, only issue warnings about things that are actually invalid (not fully implemented yet). +.TI "\*(FC\-M\*(FR, \*(FC\-\^\-bignum\*(FR +Enable arbitrary-precision arithmetic. .TI "\*(FC\-n\*(FR, \*(FC\-\^\-non\-decimal\-data\*(FR Recognize octal and hexadecimal values in input data. \*(FIUse this option with great caution!\*(FR @@ -300,10 +302,11 @@ of each statement in the program. .TI "\*(FC\-P\*(FR, \*(FC\-\^\-posix\*(FR Disable common and GNU extensions. .TI "\*(FC\-r\*(FR, \*(FC\-\^\-re\-interval\*(FR -Enable \*(FIinterval expressions\*(FR in regular -expression matching (see \fHRegular -Expressions\fP below). Useful if -\*(FC\-\^\-traditional\*(FR is specified.\*(CB +Enable \*(FIinterval expressions\*(FR.\*(CB +... in regular +... expression matching (see \fHRegular +... Expressions\fP below). Useful if +... \*(FC\-\^\-traditional\*(FR is specified .in -4n .EB "\s+2\f(HBCOMMAND LINE ARGUMENTS (\*(GK\f(HB)\*(FR\s0" @@ -610,7 +613,11 @@ T} \*(FCORS\fP T{ Output record separator, a newline by default. T} -\*(CB\*(FCPROCINFO\fP T{ +\*(CB\*(FCPREC\fP T{ +The working precision of arbitrary precision floating-point +numbers, 53 by default. +T} +\*(FCPROCINFO\fP T{ Elements of this array provide access to information about the running AWK program. See \*(AM for details.\*(CD @@ -619,6 +626,10 @@ T} Length of the string matched by \*(FCmatch()\*(FR; \-1 if no match. T} +\*(CB\*(FCROUNDMODE\fP T{ +The rounding mode to use for arbitrary precision arithmetic, +by default \*(FC"N"\fP.\*(CD +T} \*(FCRS\fP T{ Input record separator, a newline by default (see \fHRecords\fP above). @@ -355,6 +355,16 @@ only warnings about things that are actually invalid are issued. (This is not fully implemented yet.) .TP .PD 0 +.B \-M +.TP +.PD +.B \-\^\-bignum +Force arbitrary precision arithmetic on numbers. This option has +no effect if +.I gawk +is not compiled to use the GNU MPFR and MP libraries. +.TP +.PD 0 .B \-n .TP .PD @@ -1031,6 +1041,10 @@ The output field separator, a space by default. .B ORS The output record separator, by default a newline. .TP +.B PREC +The working precision of arbitrary precision floating-point +numbers, 53 by default. +.TP .B PROCINFO The elements of this array provide access to information about the running \*(AK program. @@ -1137,11 +1151,40 @@ where is a redirection string or a filename. A value of zero or less than zero means no timeout. .TP +\fBPROCINFO["mpfr_version"]\fP +the version of the GNU MPFR library used for arbitrary precision +number support in +.IR gawk . +.TP +\fBPROCINFO["gmp_version"]\fP +the version of the GNU MP library used for arbitrary precision +number support in +.IR gawk . +.TP +\fBPROCINFO["prec_max"]\fP +the maximum precision supported by the GNU MPFR library for +arbitrary precision floating-point numbers. +.TP +\fBPROCINFO["prec_min"]\fP +the minimum precision allowed by the GNU MPFR library for +arbitrary precision floating-point numbers. +.TP \fBPROCINFO["version"]\fP the version of .IR gawk . .RE .TP +.B ROUNDMODE +The rounding mode to use for arbitrary precision arithmetic on +numbers, by default \fB"N"\fR (IEEE-754 roundTiesToEven mode). +The accepted values are +\fB"N"\fR or \fB"n"\fR for roundTiesToEven, +\fB"U"\fR or \fB"u"\fR for roundTowardPositive, +\fB"D"\fR or \fB"d"\fR for roundTowardNegative, +\fB"Z"\fR or \fB"z"\fR for roundTowardZero, +and if your version of GNU MPFR library supports it, +\fB"A"\fR or \fB"a"\fR for roundTiesToAway. +.TP .B RS The input record separator, by default a newline. .TP diff --git a/doc/gawk.info b/doc/gawk.info index ca6b661f..bf279828 100644 --- a/doc/gawk.info +++ b/doc/gawk.info @@ -89,6 +89,8 @@ texts being (a) (see below), and with the Back-Cover Texts being (b) * Functions:: Built-in and user-defined functions. * Internationalization:: Getting `gawk' to speak your language. +* Arbitrary Precision Arithmetic:: Arbitrary precision arithmetic with + `gawk'. * Advanced Features:: Stuff for advanced users, specific to `gawk'. * Library Functions:: A Library of `awk' Functions. @@ -354,6 +356,21 @@ texts being (a) (see below), and with the Back-Cover Texts being (b) * I18N Portability:: `awk'-level portability issues. * I18N Example:: A simple i18n example. * Gawk I18N:: `gawk' is also internationalized. +* Floating-point Programming:: Effective floating-point programming. +* Floating-point Representation:: Binary floating-point representation. +* Floating-point Context:: Floating-point context. +* Rounding Mode:: Floating-point rounding mode. +* Arbitrary Precision Floats:: Arbitrary precision floating-point + arithmetic with `gawk'. +* Setting Precision:: Setting the working precision. +* Setting Rounding Mode:: Setting the rounding mode. +* Floating-point Constants:: Representing floating-point constants. +* Changing Precision:: Changing the precision of a number. +* Exact Arithmetic:: Exact arithmetic with floating-point numbers. +* Integer Programming:: Effective integer programming. +* Arbitrary Precision Integers:: Arbitrary precision integer + arithmetic with `gawk'. +* MPFR and GMP Libraries:: Information about the MPFR and GMP libraries. * Nondecimal Data:: Allowing nondecimal input data. * Array Sorting:: Facilities for controlling array traversal and sorting arrays. @@ -1102,10 +1119,12 @@ it is today. It has been and continues to be a pleasure working with this team of fine people. John Haque contributed the modifications to convert `gawk' into a -byte-code interpreter, including the debugger. Stephen Davies -contributed to the effort to bring the byte-code changes into the -mainstream code base. Efraim Yawitz contributed the initial text of -*note Debugger::. +byte-code interpreter, including the debugger, and the additional +modifications for support of arbitrary precision arithmetic. Stephen +Davies contributed to the effort to bring the byte-code changes into +the mainstream code base. Efraim Yawitz contributed the initial text +of *note Debugger::. John Haque contributed the initial text of *note +Arbitrary Precision Arithmetic::. I would like to thank Brian Kernighan for invaluable assistance during the testing and debugging of `gawk', and for ongoing help and @@ -2295,6 +2314,12 @@ The following list describes options mandated by the POSIX standard: inappropriate construct. As `awk' programs are usually short, doing so is not burdensome. +`-M' +`--bignum' + Force arbitrary precision arithmetic on numbers. This option has + no effect if `gawk' is not compiled to use the GNU MPFR and MP + libraries (*note Arbitrary Precision Arithmetic::). + `-n' `--non-decimal-data' Enable automatic interpretation of octal and hexadecimal values in @@ -9303,6 +9328,15 @@ specific to `gawk' are marked with a pound sign (`#'). every `print' statement. Its default value is `"\n"', the newline character. (*Note Output Separators::.) +`PREC #' + The working precision of arbitrary precision floating-point + numbers, 53 by default (*note Setting Precision::). + +`ROUNDMODE #' + The rounding mode to use for arbitrary precision arithmetic on + numbers, by default `"N"' (`roundTiesToEven' in the IEEE-754 + standard) (*note Setting Rounding Mode::). + `RS' This is `awk''s input record separator. Its default value is a string containing a single newline character, which means that an @@ -9508,6 +9542,23 @@ with a pound sign (`#'). `PROCINFO["version"]' The version of `gawk'. + The following additional elements in the array are available to + provide information about the MPFR and GMP libraries if your + version of `gawk' supports arbitrary precision numbers (*note + Arbitrary Precision Arithmetic::): + + `PROCINFO["mpfr_version"]' + The version of the GNU MPFR library. + + `PROCINFO["gmp_version"]' + The version of the GNU MP library. + + `PROCINFO["prec_max"]' + The maximum precision supported by MPFR. + + `PROCINFO["prec_min"]' + The minimum precision required by MPFR. + On some systems, there may be elements in the array, `"group1"' through `"groupN"' for some N. N is the number of supplementary groups that the process has. Use the `in' operator to test for @@ -13021,7 +13072,7 @@ example, in the following case: `gawk' will look up the actual function to call only once. -File: gawk.info, Node: Internationalization, Next: Advanced Features, Prev: Functions, Up: Top +File: gawk.info, Node: Internationalization, Next: Arbitrary Precision Arithmetic, Prev: Functions, Up: Top 10 Internationalization with `gawk' *********************************** @@ -13601,9 +13652,745 @@ writing, the latest version of GNU `gettext' is version 0.18.1 usage messages, warnings, and fatal errors in the local language. -File: gawk.info, Node: Advanced Features, Next: Library Functions, Prev: Internationalization, Up: Top +File: gawk.info, Node: Arbitrary Precision Arithmetic, Next: Advanced Features, Prev: Internationalization, Up: Top + +11 Arbitrary Precision Arithmetic with `gawk' +********************************************* + + There's a credibility gap: We don't know how much of the + computer's answers to believe. Novice computer users solve this + problem by implicitly trusting in the computer as an infallible + authority; they tend to believe that all digits of a printed + answer are significant. Disillusioned computer users have just the + opposite approach; they are constantly afraid that their answers + are almost meaningless. + + Donald Knuth(1) + + This minor node decsribes how to use the arbitrary precision (also +known as "multiple precision" or "infinite precision") numeric +capabilites in `gawk' to produce maximally accurate results when you +need it. But first you should check if your version of `gawk' supports +arbitrary precision arithmetic. The easiest way to find out is to look +at the output of the following command: + + $ gawk --version + -| GNU Awk 4.1.0 (GNU MPFR 3.1.0, GNU MP 5.0.3) + -| Copyright (C) 1989, 1991-2012 Free Software Foundation. + ... + + `gawk' uses the GNU MPFR (http://www.mpfr.org) and GNU MP +(http://gmplib.org) (GMP) libraries for arbitrary precision arithmetic +on numbers. So if you do not see the names of these libraries in the +output, then your version of `gawk' does not support arbitrary +precision arithmetic. + + Even if you aren't interested in arbitrary precision arithmetic, you +may still benifit from knowing about how `gawk' handles numbers in +general, and the limitations of doing arithmetic with ordinary `gawk' +numbers. + +* Menu: + +* Floating-point Programming:: Effective Floating-point Programming. +* Floating-point Representation:: Binary Floating-point Representation. +* Floating-point Context:: Floating-point Context. +* Rounding Mode:: Floating-point Rounding Mode. +* Arbitrary Precision Floats:: Arbitrary Precision Floating-point + Arithmetic with `gawk'. +* Setting Precision:: Setting the Working Precision. +* Setting Rounding Mode:: Setting the Rounding Mode. +* Floating-point Constants:: Representing Floating-point Constants. +* Changing Precision:: Changing the Precision of a Number. +* Exact Arithmetic:: Exact Arithmetic with Floating-point Numbers. +* Integer Programming:: Effective Integer Programming. +* Arbitrary Precision Integers:: Arbitrary Precision Integer + Arithmetic with `gawk'. +* MPFR and GMP Libraries:: Information About the MPFR and GMP Libraries. + + ---------- Footnotes ---------- + + (1) Donald E. Knuth. `The Art of Computer Programming'. Volume 2, +`Seminumerical Algorithms', third edition, 1998, ISBN 0-201-89683-4, p. +229. + + +File: gawk.info, Node: Floating-point Programming, Next: Floating-point Representation, Up: Arbitrary Precision Arithmetic + +11.1 Effective Floating-point Programming +========================================= + +Numerical programming is an extensive area; if you need to develop +sophisticated numerical algorithms then `gawk' may not be the ideal +tool, and this documentation may not be sufficient. It might require a +book or two to communicate how to compute with ideal accuracy and +precision and the result often depends on the particular application. + + NOTE: A floating-point calculation's "accuracy" is how close it + comes to the real value. This is as opposed to the "precision", + which usually refers to the number of bits used to represent the + number (see the Wikipedia article + (http://en.wikipedia.org/wiki/Accuracy_and_precision) for more + information). + + Binary floating-point representations and arithmetic are inexact. +Simple values like 0.1 cannot be precisely represented using binary +floating-point numbers, and the limited precision of floating-point +numbers means that slight changes in the order of operations or the +precision of intermediate storage can change the result. To make +matters worse with arbitrary precision floating-point, you can set the +precision before starting a computation, but then you cannot be sure of +the number of significant decimal places in the final result. + + Sometimes you need to think more about what you really want and +what's really happening. Consider the two numbers in the following +example: + + x = 0.875 # 1/2 + 1/4 + 1/8 + y = 0.425 + + Unlike the number in `y', the number stored in `x' is exactly +representable in binary since it can be written as a finite sum of one +or more fractions whose denominators are all powers of two. When +`gawk' reads a floating-point number from program source, it +automatically rounds that number to whatever precision your machine +supports. If you try to print the numeric content of a variable using +an output format string of `"%.17g"', it may not produce the same +number as you assigned to it: + + $ gawk 'BEGIN { x = 0.875; y = 0.425 + > printf("%0.17g, %0.17g\n", x, y) }' + -| 0.875, 0.42499999999999999 + + Often the error is so small you do not even notice it, and if you do, +you can always specify how much precision you would like in your output. +Usually this is a format string like `"%.15g"', which when used in the +previous example, produces an output identical to the input. + + Because the underlying representation can be little bit off from the +exact value, comparing floats to see if they are equal is generally not +a good idea. Here is an example where it does not work like you expect: + + $ gawk 'BEGIN { print (0.1 + 12.2 == 12.3) }' + -| 0 + + The loss of accuracy during a single computation with floating-point +numbers usually isn't enough to worry about. However, if you compute a +value which is the result of a sequence of floating point operations, +the error can accumulate and greatly affect the computation itself. +Here is an attempt to compute the value of the constant pi using one of +its many series representations: + + BEGIN { + x = 1.0 / sqrt(3.0) + n = 6 + for (i = 1; i < 30; i++) { + n = n * 2.0 + x = (sqrt(x * x + 1) - 1) / x + printf("%.15f\n", n * x) + } + } + + When run, the early errors propagating through later computations +cause the loop to terminate prematurely after an attempt to divide by +zero. + + $ gawk -f pi.awk + -| 3.215390309173475 + -| 3.159659942097510 + -| 3.146086215131467 + -| 3.142714599645573 + ... + -| 3.224515243534819 + -| 2.791117213058638 + -| 0.000000000000000 + error--> gawk: pi.awk:6: fatal: division by zero attempted + + Here is one more example where the inaccuracies in internal +representations yield an unexpected result: + + $ gawk 'BEGIN { + > for (d = 1.1; d <= 1.5; d += 0.1) + > i++ + > print i + > }' + -| 4 + + Can computation using aribitrary precision help with the previous +examples? If you are impatient to know, see *note Exact Arithmetic::. + + Instead of aribitrary precision floating-point arithmetic, often all +you need is an adjustment of your logic or a different order for the +operations in your calculation. The stability and the accuracy of the +computation of the constant pi in the previous example can be enhanced +by using the following simple algebraic transformation: + + (sqrt(x * x + 1) - 1) / x = x / (sqrt(x * x + 1) + x) + + There is no need to be unduly suspicious about the results from +floating-point arithmetic. The lesson to remember is that +floating-point math is always more complex than the math using pencil +and paper. In order to take advantage of the power of computer +floating-point, you need to know its limitations and work within them. +For most casual use of floating-point arithmetic, you will often get +the expected result in the end if you simply round the display of your +final results to the correct number of significant decimal digits. +Avoid presenting numerical data in a manner that implies better +precision than is actually the case. + + +File: gawk.info, Node: Floating-point Representation, Next: Floating-point Context, Prev: Floating-point Programming, Up: Arbitrary Precision Arithmetic + +11.2 Binary Floating-point Representation +========================================= + +Although floating-point representations vary from machine to machine, +the most commonly encountered representation is that defined by the +IEEE 754 Standard. An IEEE-754 format value has three components: + + * a sign bit telling whether the number is positive or negative, + + * an "exponent" giving its order of magnitude, E, + + * and a "significand", S, specifying the actual digits of the number. + + The value of the number is then S * 2^E. The first bit of a +non-zero binary significand is always one, so the significand in an +IEEE-754 format only includes the fractional part, leaving the leading +one implicit. + + Three of the standard IEEE-754 types are 32-bit single precision, +64-bit double precision and 128-bit quadruple precision. The standard +also specifies extended precision formats to allow greater precisions +and larger exponent ranges. + + +File: gawk.info, Node: Floating-point Context, Next: Rounding Mode, Prev: Floating-point Representation, Up: Arbitrary Precision Arithmetic + +11.3 Floating-point Context +=========================== + +A floating-point context defines the environment for arithmetic +operations. It governs precision, sets rules for rounding and limits +range for exponents. The context has the following primary components: + +`precision' + Precision of the floating-point format in bits. + +`emax' + Maximum exponent allowed for this format. + +`emin' + Minimum exponent allowed for this format. + +`underflow behavior' + The format may or may not support gradual underflow. + +`rounding' + The rounding mode of this context. + + *note table-ieee-formats:: lists the precision and exponent field +values for the basic IEEE-754 binary formats: + +Name Total bits Precision emin emax +--------------------------------------------------------------------------- +Single 32 24 -126 +127 +Double 64 53 -1022 +1023 +Quadruple 128 113 -16382 +16383 + +Table 11.1: Basic IEEE Formats + + NOTE: The precision numbers include the implied leading one that + gives them one extra bit of significand. + + A floating-point context can also determine which signals are treated +as exceptions, and can set rules for arithmetic with special values. +Please consult the IEEE-754 standard or other resources for details. + + `gawk' ordinarily uses the hardware double precision representation +for numbers. On most systems, this is IEEE-754 floating-point format, +corresponding to 64-bit binary with 53 bits of precision. + + NOTE: In case an underflow occurs, the standard allows, but does + not require, the result from an arithmetic operation to be a + number smaller than the smallest nonzero normalized number. Such + numbers do not have as many significant digits as normal numbers, + and are called "denormals" or "subnormals". The alternative, + simply returning a zero, is called "flush to zero". The basic + IEEE-754 binary formats support subnormal numbers. + + +File: gawk.info, Node: Rounding Mode, Next: Arbitrary Precision Floats, Prev: Floating-point Context, Up: Arbitrary Precision Arithmetic + +11.4 Floating-point Rounding Mode +================================= + +The "rounding mode" specifies the behavior for the results of numerical +operations when discarding extra precision. Each rounding mode indicates +how the least significant returned digit of a rounded result is to be +calculated. The `ROUNDMODE' variable (*note Setting Rounding Mode::) +provides program level control over the rounding mode. *note +table-rounding-modes:: lists the IEEE-754 defined rounding modes: + +Rounding Mode IEEE Name `ROUNDMODE' +--------------------------------------------------------------------------- +Round to nearest, ties to even `roundTiesToEven' `"N"' or `"n"' +Round toward plus Infinity `roundTowardPositive' `"U"' or `"u"' +Round toward negative Infinity `roundTowardNegative' `"D"' or `"d"' +Round toward zero `roundTowardZero' `"Z"' or `"z"' +Round to nearest, ties away `roundTiesToAway' `"A"' or `"a"' +from zero + +Table 11.2: Rounding Modes + + The default mode `roundTiesToEven' is the most preferred, but the +least intuitive. This method does the obvious thing for most values, by +rounding them up or down to the nearest digit. For example, rounding +1.132 to two digits yields 1.13, and rounding 1.157 yields 1.16. + + However, when it comes to rounding a value that is exactly halfway +between, things do not work the way you probably learned in school. In +this case, the number is rounded to the nearest even digit. So +rounding 0.125 to two digits rounds down to 0.12, but rounding 0.6875 +to three digits rounds up to 0.688. You probably have already +encountered this rounding mode when using the `printf' routine to +format floating-point numbers. For example: + + BEGIN { + x = -4.5 + for (i = 1; i < 10; i++) { + x += 1.0 + printf("%4.1f => %2.0f\n", x, x) + } + } + +produces the following output when run(1): + + -3.5 => -4 + -2.5 => -2 + -1.5 => -2 + -0.5 => 0 + 0.5 => 0 + 1.5 => 2 + 2.5 => 2 + 3.5 => 4 + 4.5 => 4 + + The theory behind the rounding mode `roundTiesToEven' is that it +more or less evenly distributes upward and downward rounds of exact +halves, which might cause the round-off error to cancel itself out. +This is the default rounding mode used in IEEE-754 computing functions +and operators. + + The other rounding modes are rarely used. Round toward positive +infinity (`roundTowardPositive') and round toward negative infinity +(`roundTowardNegative') are often used to implement interval arithmetic, +where you adjust the rounding mode to calculate upper and lower bounds +for the range of output. The `roundTowardZero' mode can be used for +converting floating-point numbers to integers. The rounding mode +`roundTiesToAway' rounds the result to the nearest number and selects +the number with the larger magnitude if a tie occurs. + + Some numerical analysts will tell you that your choice of rounding +style has tremendous impact on the final outcome, and advise you to +wait until final output for any rounding. Instead, you can often +achieve this goal by setting the precision initially to some value +sufficiently larger than the final desired precision, so that the +accumulation of round-off error does not influence the outcome. If you +suspect that results from your computation are sensitive to +accumulation of round-off error, one way to be sure is to look for a +significant difference in output when you change the rounding mode. + + ---------- Footnotes ---------- + + (1) It is possible for the output to be completely different if the +C library in your system does not use the IEEE-754 even-rounding rule +to round halfway cases for `printf()'. + + +File: gawk.info, Node: Arbitrary Precision Floats, Next: Setting Precision, Prev: Rounding Mode, Up: Arbitrary Precision Arithmetic + +11.5 Arbitrary Precision Floating-point Arithmetic with `gawk' +============================================================== + +`gawk' uses the GNU MPFR library for arbitrary precision floating-point +arithmetic. The MPFR library provides precise control over precisions +and rounding modes, and gives correctly rounded reproducible +platform-independent results. With the command-line option `--bignum' +or `-M', all floating-point arithmetic operators and numeric functions +can yield results to any desired precision level supported by MPFR. +Two built-in variables `PREC' (*note Setting Precision::) and +`ROUNDMODE' (*note Setting Rounding Mode::) provide control over the +working precision and the rounding mode. The precision and the +rounding mode are set globally for every operation to follow. + + The default working precision for arbitrary precision floats is 53, +and the default value for `ROUNDMODE' is `"N"', which selects the +IEEE-754 `roundTiesToEven' (*note Rounding Mode::) rounding mode.(1) +`gawk' uses the default exponent range in MPFR (EMAX = 2^30 - 1, EMIN = +-EMAX) for all floating-point contexts. There is no explicit mechanism +to adjust the exponent range. MPFR does not implement subnormal +numbers by default, and this behavior cannot be changed in `gawk'. + + NOTE: When emulating an IEEE-754 format (*note Setting + Precision::), `gawk' internally adjusts the exponent range to the + value defined for the format and also performs computations needed + for gradual underflow (subnormal numbers). + + NOTE: MPFR numbers are variable-size entities, consuming only as + much space as needed to store the significant digits. Since the + performance using MPFR numbers pales in comparison to doing math + using the underlying machine types, you should consider using only + as much precision as needed by your program. + + ---------- Footnotes ---------- + + (1) The default precision is 53, since according to the MPFR +documentation, the library should be able to exactly reproduce all +computations with double-precision machine floating-point numbers +(`double' type in C), except the default exponent range is much wider +and subnormal numbers are not implemented. + + +File: gawk.info, Node: Setting Precision, Next: Setting Rounding Mode, Prev: Arbitrary Precision Floats, Up: Arbitrary Precision Arithmetic + +11.6 Setting the Working Precision +================================== + +`gawk' uses a global working precision; it does not keep track of the +precision or accuracy of individual numbers. Performing an arithmetic +operation or calling a built-in function rounds the result to the +current working precision. The default working precision is 53 which +can be modified using the built-in variable `PREC'. You can also set the +value to one of the following pre-defined case-insensitive strings to +emulate an IEEE-754 binary format: + +`PREC' IEEE-754 Binary Format +--------------------------------------------------- +`"half"' 16-bit half-precision. +`"single"' Basic 32-bit single precision. +`"double"' Basic 64-bit double precision. +`"quad"' Basic 128-bit quadruple precision. +`"oct"' 256-bit octuple precision. + + The following example illustrates the effects of changing precision +on arithmetic operations: + + $ gawk -M -vPREC=100 'BEGIN { x = 1.0e-400; print x + 0; \ + > PREC = "double"; print x + 0 }' + -| 1e-400 + -| 0 + + Binary and decimal precisions are related approximately according to +the formula: + + PREC = 3.322 * DPS + +Here, PREC denotes the binary precision (measured in bits) and DPS +(short for decimal places) is the decimal digits. We can easily +calculate how many decimal digits the 53-bit significand of an IEEE +double is equivalent to: 53 / 3.332 which is equal to about 15.95. But +what does 15.95 digits actually mean? It depends whether you are +concerned about how many digits you can rely on, or how many digits you +need. + + It is important to know how many bits it takes to uniquely identify +a double-precision value (the C type `double'). If you want to convert +from `double' to decimal and back to `double' (e.g., saving a `double' +representing an intermediate result to a file, and later reading it +back to restart the computation), then a few more decimal digits are +required. 17 digits is generally enough for a `double'. + + It can also be important to know what decimal numbers can be uniquely +represented with a `double'. If you want to convert from decimal to +`double' and back again, 15 digits is the most that you can get. Stated +differently, you should not present the numbers from your +floating-point computations with more than 15 significant digits in +them. + + Conversely, it takes a precision of 332 bits to hold an approximation +of constant pi that is accurate to 100 decimal places. You should +always add some extra bits in order to avoid the confusing round-off +issues that occur because numbers are stored internally in binary. + + +File: gawk.info, Node: Setting Rounding Mode, Next: Floating-point Constants, Prev: Setting Precision, Up: Arbitrary Precision Arithmetic + +11.7 Setting the Rounding Mode +============================== + +The built-in variable `ROUNDMODE' has the default value `"N"', which +selects the IEEE-754 rounding mode `roundTiesToEven'. The other +possible values for `ROUNDMODE' are `"U"' for rounding mode +`roundTowardPositive', `"D"' for `roundTowardNegative', and `"Z"' for +`roundTowardZero'. `gawk' also accepts `"A"' to select the IEEE-754 +mode `roundTiesToAway' if your version of the MPFR library supports it; +otherwise setting `ROUNDMODE' to this value has no effect. *Note +Rounding Mode::, for the meanings of the various rounding modes. + + Here is an example of how to change the default rounding behavior of +`printf''s output: + + $ gawk -M -vROUNDMODE="Z" 'BEGIN { printf("%.2f\n", 1.378) }' + -| 1.37 + + +File: gawk.info, Node: Floating-point Constants, Next: Changing Precision, Prev: Setting Rounding Mode, Up: Arbitrary Precision Arithmetic + +11.8 Representing Floating-point Constants +========================================== + +Be wary of floating-point constants! When reading a floating-point +constant from program source code, `gawk' uses the default precision, +unless overridden by an assignment to the special variable `PREC' on +the command line, to store it internally as a MPFR number. Changing +the precision using `PREC' in the program text does not change the +precision of a constant. If you need to represent a floating-point +constant at a higher precision than the default and cannot use a +command line assignment to `PREC', you should either specify the +constant as a string, or a rational number whenever possible. The +following example illustrates the differences among various ways to +print a floating-point constant: + + $ gawk -M 'BEGIN { PREC = 113; printf("%0.25f\n", 0.1) }' + -| 0.1000000000000000055511151 + $ gawk -M -vPREC = 113 'BEGIN { printf("%0.25f\n", 0.1) }' + -| 0.1000000000000000000000000 + $ gawk -M 'BEGIN { PREC = 113; printf("%0.25f\n", "0.1") }' + -| 0.1000000000000000000000000 + $ gawk -M 'BEGIN { PREC = 113; printf("%0.25f\n", 1/10) }' + -| 0.1000000000000000000000000 + + In the first case, the number is stored with the default precision +of 53. + + +File: gawk.info, Node: Changing Precision, Next: Exact Arithmetic, Prev: Floating-point Constants, Up: Arbitrary Precision Arithmetic + +11.9 Changing the Precision of a Number +======================================= + + The point is that in any variable-precision package, a decision is + made on how to treat numbers given as data, or arising in + intermediate results, which are represented in floating-point + format to a precision lower than working precision. Do we promote + them to full membership of the high-precision club, or do we treat + them and all their associates as second-class citizens? Sometimes + the first course is proper, sometimes the second, and it takes + careful analysis to tell which. + + Dirk Laurie(1) + + `gawk' does not implicitly modify the precision of any previously +computed results when the working precision is changed with an +assignment to `PREC'. The precision of a number is always the one that +was used at the time of its creation, and there is no way for the user +to explicitly change it afterwards. However, since the result of a +floating-point arithmetic operation is always an arbitrary precision +floating-point value--with a precision set by the value of `PREC'--one +of the following workarounds effectively accomplishes the desired +behavior: + + x = x + 0.0 + +or: + + x += 0.0 + + ---------- Footnotes ---------- + + (1) Dirk Laurie. `Variable-precision Arithmetic Considered Perilous +- A Detective Story'. Electronic Transactions on Numerical Analysis. +Volume 28, pp. 168-173, 2008. + + +File: gawk.info, Node: Exact Arithmetic, Next: Integer Programming, Prev: Changing Precision, Up: Arbitrary Precision Arithmetic + +11.10 Exact Arithmetic with Floating-point Numbers +================================================== + + CAUTION: Never depend on the exactness of floating-point + arithmetic, even for apparently simple expressions! -11 Advanced Features of `gawk' + Can arbitrary precision arithmetic give exact results? There are no +easy answers. The standard rules of algebra often do not apply when +using floating-point arithmetic. Among other things, the distributive +and associative laws do not hold completely, and order of operation may +be important for your computation. Rounding error, cumulative precision +loss and underflow are often troublesome. + + When `gawk' tests the expressions `0.1 + 12.2' and `12.3' for +equality using the machine double precision arithmetic, it decides that +they are not equal! (*Note Floating-point Programming::.) You can get +the result you want by increasing the precision; 56 in this case will +get the job done: + + $ gawk -M -vPREC=56 'BEGIN { print (0.1 + 12.2 == 12.3) }' + -| 1 + + If adding more bits is good, perhaps adding even more bits of +precision is better? Here is what happens if we use an even larger +value of `PREC': + + $ gawk -M -vPREC=201 'BEGIN { print (0.1 + 12.2 == 12.3) }' + -| 0 + + This is not a bug in `gawk' or in the MPFR library. It is easy to +forget that the finite number of bits used to store the value is often +just an approximation after proper rounding. The test for equality +succeeds if and only if _all_ bits in the two operands are exactly the +same. Since this is not necessarily true after floating-point +computations with a particular precision and effective rounding rule, a +straight test for equality may not work. + + So, don't assume that floating-point values can be compared for +equality. You should also exercise caution when using other forms of +comparisons. The standard way to compare between floating-point +numbers is to determine how much error (or "tolerance") you will allow +in a comparison and check to see if one value is within this error +range of the other. + + In applications where 15 or fewer decimal places suffice, hardware +double precision arithmetic can be adequate, and is usually much faster. +But you do need to keep in mind that every floating-point operation can +suffer a new rounding error with catastrophic consequences as +illustrated by our attempt to compute the value of the constant pi, +(*note Floating-point Programming::). Extra precision can greatly +enhance the stability and the accuracy of your computation in such +cases. + + Repeated addition is not necessarily equivalent to multiplication in +floating-point arithmetic. In the last example (*note Floating-point +Programming::), you may or may not succeed in getting the correct +result by choosing an arbitrarily large value for `PREC'. Reformulation +of the problem at hand is often the correct approach in such situations. + + +File: gawk.info, Node: Integer Programming, Next: Arbitrary Precision Integers, Prev: Exact Arithmetic, Up: Arbitrary Precision Arithmetic + +11.11 Effective Integer Programming +=================================== + +As has been mentioned already, `gawk' ordinarily uses hardware double +precision with 64-bit IEEE binary floating-point representation for +numbers on most systems. A large integer like 9007199254740997 has a +binary representation that, although finite, is more than 53 bits long; +it must also be rounded to 53 bits. The biggest integer that can be +stored in a C `double' is usually the same as the largest possible +value of a `double'. If your system `double' is an IEEE 64-bit +`double', this largest possible value is an integer and can be +represented precisely. What more should one know about integers? + + If you want to know what is the largest integer, such that it and +all smaller integers can be stored in 64-bit doubles without losing +precision, then the answer is 2^53. The next representable number is +the even number 2^53 + 2, meaning it is unlikely that you will be able +to make `gawk' print 2^53 + 1 in integer format. The range of integers +exactly representable by a 64-bit double is [-2^53, 2^53]. If you ever +see an integer outside this range in `gawk' using 64-bit doubles, you +have reason to be very suspicious about the accuracy of the output. +Here is a simple program with erroneous output: + + $ gawk 'BEGIN { i = 2^53 - 1; for (j = 0; j < 4; j++) print i + j }' + -| 9007199254740991 + -| 9007199254740992 + -| 9007199254740992 + -| 9007199254740994 + + The lesson is to not assume that any large integer printed by `gawk' +represents an exact result from your computation, especially if it wraps +around on your screen. + + +File: gawk.info, Node: Arbitrary Precision Integers, Next: MPFR and GMP Libraries, Prev: Integer Programming, Up: Arbitrary Precision Arithmetic + +11.12 Arbitrary Precision Integer Arithmetic with `gawk' +======================================================== + +If the option `--bignum' or `-M' is specified, `gawk' performs all +integer arithmetic using GMP arbitrary precision integers. Any number +that looks like an integer in a program source or data file is stored +as an arbitrary precision integer. The size of the integer is limited +only by your computer's memory. The current floating-point context has +no effect on operations involving integers. For example, the following +computes 5^4^3^2, the result of which is beyond the limits of ordinary +`gawk' numbers: + + $ gawk -M 'BEGIN { + > x = 5^4^3^2 + > print "# of digits =", length(x) + > print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20) + > }' + -| # of digits = 183231 + -| 62060698786608744707 ... 92256259918212890625 + + If you were to compute the same value using arbitrary precision +floating-point values instead, the precision needed for correct output +(using the formula `prec = 3.322 * dps'), would be 3.322 x 183231, or +608693. + + The result from an arithmetic operation with an integer and a +floating-point value is a floating-point value with a precision equal +to the working precision. The following program calculates the eighth +term in Sylvester's sequence(1) using a recurrence: + + $ gawk -M 'BEGIN { + > s = 2.0 + > for (i = 1; i <= 7; i++) + > s = s * (s - 1) + 1 + > print s + > }' + -| 113423713055421845118910464 + + The output differs from the acutal number, +113423713055421844361000443, because the default precision of 53 is not +enough to represent the floating-point results exactly. You can either +increase the precision (100 is enough in this case), or replace the +floating-point constant `2.0' with an integer, to perform all +computations using integer arithmetic to get the correct output. + + It will sometimes be necessary for `gawk' to implicitly convert an +arbitrary precision integer into an arbitrary precision floating-point +value. This is primarily because the MPFR library does not always +provide the relevant interface to process arbitrary precision integers +or mixed-mode numbers as needed by an operation or function. In such a +case, the precision is set to the minimum value necessary for exact +conversion, and the working precision is not used for this purpose. If +this is not what you need or want, you can employ a subterfuge like +this: + + gawk -M 'BEGIN { n = 13; print (n + 0.0) % 2.0 }' + + You can avoid this issue altogether by specifying the number as a +float to begin with: + + gawk -M 'BEGIN { n = 13.0; print n % 2.0 }' + + Note that for the particular example above, there is unlikely to be a +reason for simply not using the following: + + gawk -M 'BEGIN { n = 13; print n % 2 }' + + ---------- Footnotes ---------- + + (1) Weisstein, Eric W. `Sylvester's Sequence'. From MathWorld-A +Wolfram Web Resource. +`http://mathworld.wolfram.com/SylvestersSequence.html' + + +File: gawk.info, Node: MPFR and GMP Libraries, Prev: Arbitrary Precision Integers, Up: Arbitrary Precision Arithmetic + +11.13 Information About the MPFR and GMP Libraries +================================================== + +There are a few elements available in the `PROCINFO' array to provide +information about the MPFR and GMP libraries. *Note Auto-set::, for +more information. + + +File: gawk.info, Node: Advanced Features, Next: Library Functions, Prev: Arbitrary Precision Arithmetic, Up: Top + +12 Advanced Features of `gawk' ****************************** Write documentation as if whoever reads it is a violent psychopath @@ -13636,7 +14423,7 @@ and likely to change, its description is relegated to an appendix. File: gawk.info, Node: Nondecimal Data, Next: Array Sorting, Up: Advanced Features -11.1 Allowing Nondecimal Input Data +12.1 Allowing Nondecimal Input Data =================================== If you run `gawk' with the `--non-decimal-data' option, you can have @@ -13678,7 +14465,7 @@ request it. File: gawk.info, Node: Array Sorting, Next: Two-way I/O, Prev: Nondecimal Data, Up: Advanced Features -11.2 Controlling Array Traversal and Array Sorting +12.2 Controlling Array Traversal and Array Sorting ================================================== `gawk' lets you control the order in which a `for (i in array)' loop @@ -13697,7 +14484,7 @@ to order the elements during sorting. File: gawk.info, Node: Controlling Array Traversal, Next: Array Sorting Functions, Up: Array Sorting -11.2.1 Controlling Array Traversal +12.2.1 Controlling Array Traversal ---------------------------------- By default, the order in which a `for (i in array)' loop scans an array @@ -13928,7 +14715,7 @@ the default. File: gawk.info, Node: Array Sorting Functions, Prev: Controlling Array Traversal, Up: Array Sorting -11.2.2 Sorting Array Values and Indices with `gawk' +12.2.2 Sorting Array Values and Indices with `gawk' --------------------------------------------------- In most `awk' implementations, sorting an array requires writing a @@ -14023,7 +14810,7 @@ extensions, they are not available in that case. File: gawk.info, Node: Two-way I/O, Next: TCP/IP Networking, Prev: Array Sorting, Up: Advanced Features -11.3 Two-Way Communications with Another Process +12.3 Two-Way Communications with Another Process ================================================ From: brennan@whidbey.com (Mike Brennan) @@ -14158,7 +14945,7 @@ regular pipes. File: gawk.info, Node: TCP/IP Networking, Next: Profiling, Prev: Two-way I/O, Up: Advanced Features -11.4 Using `gawk' for Network Programming +12.4 Using `gawk' for Network Programming ========================================= `EMISTERED': @@ -14235,7 +15022,7 @@ examples. File: gawk.info, Node: Profiling, Prev: TCP/IP Networking, Up: Advanced Features -11.5 Profiling Your `awk' Programs +12.5 Profiling Your `awk' Programs ================================== You may produce execution traces of your `awk' programs. This is done @@ -14453,7 +15240,7 @@ without any execution counts. File: gawk.info, Node: Library Functions, Next: Sample Programs, Prev: Advanced Features, Up: Top -12 A Library of `awk' Functions +13 A Library of `awk' Functions ******************************* *note User-defined::, describes how to write your own `awk' functions. @@ -14525,7 +15312,7 @@ contents of the input record. File: gawk.info, Node: Library Names, Next: General Functions, Up: Library Functions -12.1 Naming Library Function Global Variables +13.1 Naming Library Function Global Variables ============================================= Due to the way the `awk' language evolved, variables are either @@ -14605,7 +15392,7 @@ verifying this. File: gawk.info, Node: General Functions, Next: Data File Management, Prev: Library Names, Up: Library Functions -12.2 General Programming +13.2 General Programming ======================== This minor node presents a number of functions that are of general @@ -14628,7 +15415,7 @@ programming use. File: gawk.info, Node: Strtonum Function, Next: Assert Function, Up: General Functions -12.2.1 Converting Strings To Numbers +13.2.1 Converting Strings To Numbers ------------------------------------ The `strtonum()' function (*note String Functions::) is a `gawk' @@ -14712,7 +15499,7 @@ be tested with `gawk' and the results compared to the built-in File: gawk.info, Node: Assert Function, Next: Round Function, Prev: Strtonum Function, Up: General Functions -12.2.2 Assertions +13.2.2 Assertions ----------------- When writing large programs, it is often useful to know that a @@ -14798,7 +15585,7 @@ rule always ends with an `exit' statement. File: gawk.info, Node: Round Function, Next: Cliff Random Function, Prev: Assert Function, Up: General Functions -12.2.3 Rounding Numbers +13.2.3 Rounding Numbers ----------------------- The way `printf' and `sprintf()' (*note Printf::) perform rounding @@ -14844,7 +15631,7 @@ might be useful if your `awk''s `printf' does unbiased rounding: File: gawk.info, Node: Cliff Random Function, Next: Ordinal Functions, Prev: Round Function, Up: General Functions -12.2.4 The Cliff Random Number Generator +13.2.4 The Cliff Random Number Generator ---------------------------------------- The Cliff random number generator @@ -14873,7 +15660,7 @@ might try using this function instead. File: gawk.info, Node: Ordinal Functions, Next: Join Function, Prev: Cliff Random Function, Up: General Functions -12.2.5 Translating Between Characters and Numbers +13.2.5 Translating Between Characters and Numbers ------------------------------------------------- One commercial implementation of `awk' supplies a built-in function, @@ -14971,7 +15758,7 @@ extensions, you can simplify `_ord_init' to loop from 0 to 255. File: gawk.info, Node: Join Function, Next: Gettimeofday Function, Prev: Ordinal Functions, Up: General Functions -12.2.6 Merging an Array into a String +13.2.6 Merging an Array into a String ------------------------------------- When doing string processing, it is often useful to be able to join all @@ -15018,7 +15805,7 @@ makes string operations more difficult than they really need to be. File: gawk.info, Node: Gettimeofday Function, Prev: Join Function, Up: General Functions -12.2.7 Managing the Time of Day +13.2.7 Managing the Time of Day ------------------------------- The `systime()' and `strftime()' functions described in *note Time @@ -15100,7 +15887,7 @@ optional timestamp value to use instead of the current time. File: gawk.info, Node: Data File Management, Next: Getopt Function, Prev: General Functions, Up: Library Functions -12.3 Data File Management +13.3 Data File Management ========================= This minor node presents functions that are useful for managing @@ -15117,7 +15904,7 @@ command-line data files. File: gawk.info, Node: Filetrans Function, Next: Rewind Function, Up: Data File Management -12.3.1 Noting Data File Boundaries +13.3.1 Noting Data File Boundaries ---------------------------------- The `BEGIN' and `END' rules are each executed exactly once at the @@ -15215,7 +16002,7 @@ it provides an easy way to do per-file cleanup processing. File: gawk.info, Node: Rewind Function, Next: File Checking, Prev: Filetrans Function, Up: Data File Management -12.3.2 Rereading the Current File +13.3.2 Rereading the Current File --------------------------------- Another request for a new built-in function was for a `rewind()' @@ -15257,7 +16044,7 @@ Nextfile Statement::). File: gawk.info, Node: File Checking, Next: Empty Files, Prev: Rewind Function, Up: Data File Management -12.3.3 Checking for Readable Data Files +13.3.3 Checking for Readable Data Files --------------------------------------- Normally, if you give `awk' a data file that isn't readable, it stops @@ -15286,7 +16073,7 @@ in the list). See also *note ARGC and ARGV::. File: gawk.info, Node: Empty Files, Next: Ignoring Assigns, Prev: File Checking, Up: Data File Management -12.3.4 Checking For Zero-length Files +13.3.4 Checking For Zero-length Files ------------------------------------- All known `awk' implementations silently skip over zero-length files. @@ -15343,7 +16130,7 @@ intervening value in `ARGV' is a variable assignment. File: gawk.info, Node: Ignoring Assigns, Prev: Empty Files, Up: Data File Management -12.3.5 Treating Assignments as File Names +13.3.5 Treating Assignments as File Names ----------------------------------------- Occasionally, you might not want `awk' to process command-line variable @@ -15386,7 +16173,7 @@ arguments are left alone. File: gawk.info, Node: Getopt Function, Next: Passwd Functions, Prev: Data File Management, Up: Library Functions -12.4 Processing Command-Line Options +13.4 Processing Command-Line Options ==================================== Most utilities on POSIX compatible systems take options on the command @@ -15679,7 +16466,7 @@ have left it alone, since using `substr()' is more portable. File: gawk.info, Node: Passwd Functions, Next: Group Functions, Prev: Getopt Function, Up: Library Functions -12.5 Reading the User Database +13.5 Reading the User Database ============================== The `PROCINFO' array (*note Built-in Variables::) provides access to @@ -15922,7 +16709,7 @@ network database. File: gawk.info, Node: Group Functions, Next: Walking Arrays, Prev: Passwd Functions, Up: Library Functions -12.6 Reading the Group Database +13.6 Reading the Group Database =============================== Much of the discussion presented in *note Passwd Functions::, applies @@ -16156,7 +16943,7 @@ very simple, relying on `awk''s associative arrays to do work. File: gawk.info, Node: Walking Arrays, Prev: Group Functions, Up: Library Functions -12.7 Traversing Arrays of Arrays +13.7 Traversing Arrays of Arrays ================================ *note Arrays of Arrays::, described how `gawk' provides arrays of @@ -16207,7 +16994,7 @@ value. Here is a main program to demonstrate: File: gawk.info, Node: Sample Programs, Next: Debugger, Prev: Library Functions, Up: Top -13 Practical `awk' Programs +14 Practical `awk' Programs *************************** *note Library Functions::, presents the idea that reading programs in a @@ -16227,7 +17014,7 @@ Library Functions::. File: gawk.info, Node: Running Examples, Next: Clones, Up: Sample Programs -13.1 Running the Example Programs +14.1 Running the Example Programs ================================= To run a given program, you would typically do something like this: @@ -16250,7 +17037,7 @@ OPTIONS are any command-line options for the program that start with a File: gawk.info, Node: Clones, Next: Miscellaneous Programs, Prev: Running Examples, Up: Sample Programs -13.2 Reinventing Wheels for Fun and Profit +14.2 Reinventing Wheels for Fun and Profit ========================================== This minor node presents a number of POSIX utilities implemented in @@ -16280,7 +17067,7 @@ programming for "real world" tasks. File: gawk.info, Node: Cut Program, Next: Egrep Program, Up: Clones -13.2.1 Cutting out Fields and Columns +14.2.1 Cutting out Fields and Columns ------------------------------------- The `cut' utility selects, or "cuts," characters or fields from its @@ -16539,7 +17326,7 @@ solution to the problem of picking the input line apart by characters. File: gawk.info, Node: Egrep Program, Next: Id Program, Prev: Cut Program, Up: Clones -13.2.2 Searching for Regular Expressions in Files +14.2.2 Searching for Regular Expressions in Files ------------------------------------------------- The `egrep' utility searches files for patterns. It uses regular @@ -16771,7 +17558,7 @@ the translated line, not the original. File: gawk.info, Node: Id Program, Next: Split Program, Prev: Egrep Program, Up: Clones -13.2.3 Printing out User Information +14.2.3 Printing out User Information ------------------------------------ The `id' utility lists a user's real and effective user ID numbers, @@ -16878,7 +17665,7 @@ body never executes. File: gawk.info, Node: Split Program, Next: Tee Program, Prev: Id Program, Up: Clones -13.2.4 Splitting a Large File into Pieces +14.2.4 Splitting a Large File into Pieces ----------------------------------------- The `split' program splits large text files into smaller pieces. Usage @@ -16986,7 +17773,7 @@ not relevant for what the program aims to demonstrate. File: gawk.info, Node: Tee Program, Next: Uniq Program, Prev: Split Program, Up: Clones -13.2.5 Duplicating Output into Multiple Files +14.2.5 Duplicating Output into Multiple Files --------------------------------------------- The `tee' program is known as a "pipe fitting." `tee' copies its @@ -17074,7 +17861,7 @@ N input records and M output files, the first method only executes N File: gawk.info, Node: Uniq Program, Next: Wc Program, Prev: Tee Program, Up: Clones -13.2.6 Printing Nonduplicated Lines of Text +14.2.6 Printing Nonduplicated Lines of Text ------------------------------------------- The `uniq' utility reads sorted lines of data on its standard input, @@ -17293,7 +18080,7 @@ line of input data: File: gawk.info, Node: Wc Program, Prev: Uniq Program, Up: Clones -13.2.7 Counting Things +14.2.7 Counting Things ---------------------- The `wc' (word count) utility counts lines, words, and characters in @@ -17438,7 +18225,7 @@ characters, not bytes. File: gawk.info, Node: Miscellaneous Programs, Prev: Clones, Up: Sample Programs -13.3 A Grab Bag of `awk' Programs +14.3 A Grab Bag of `awk' Programs ================================= This minor node is a large "grab bag" of miscellaneous programs. We @@ -17465,7 +18252,7 @@ hope you find them both interesting and enjoyable. File: gawk.info, Node: Dupword Program, Next: Alarm Program, Up: Miscellaneous Programs -13.3.1 Finding Duplicated Words in a Document +14.3.1 Finding Duplicated Words in a Document --------------------------------------------- A common error when writing large amounts of prose is to accidentally @@ -17513,7 +18300,7 @@ word, comparing it to the previous one: File: gawk.info, Node: Alarm Program, Next: Translate Program, Prev: Dupword Program, Up: Miscellaneous Programs -13.3.2 An Alarm Clock Program +14.3.2 An Alarm Clock Program ----------------------------- Nothing cures insomnia like a ringing alarm clock. @@ -17646,7 +18433,7 @@ necessary: File: gawk.info, Node: Translate Program, Next: Labels Program, Prev: Alarm Program, Up: Miscellaneous Programs -13.3.3 Transliterating Characters +14.3.3 Transliterating Characters --------------------------------- The system `tr' utility transliterates characters. For example, it is @@ -17772,7 +18559,7 @@ split each character in a string into separate array elements. File: gawk.info, Node: Labels Program, Next: Word Sorting, Prev: Translate Program, Up: Miscellaneous Programs -13.3.4 Printing Mailing Labels +14.3.4 Printing Mailing Labels ------------------------------ Here is a "real world"(1) program. This script reads lists of names and @@ -17879,7 +18666,7 @@ something done." File: gawk.info, Node: Word Sorting, Next: History Sorting, Prev: Labels Program, Up: Miscellaneous Programs -13.3.5 Generating Word-Usage Counts +14.3.5 Generating Word-Usage Counts ----------------------------------- When working with large amounts of text, it can be interesting to know @@ -17983,7 +18770,7 @@ operating system documentation for more information on how to use the File: gawk.info, Node: History Sorting, Next: Extract Program, Prev: Word Sorting, Up: Miscellaneous Programs -13.3.6 Removing Duplicates from Unsorted Text +14.3.6 Removing Duplicates from Unsorted Text --------------------------------------------- The `uniq' program (*note Uniq Program::), removes duplicate lines from @@ -18030,7 +18817,7 @@ seen. File: gawk.info, Node: Extract Program, Next: Simple Sed, Prev: History Sorting, Up: Miscellaneous Programs -13.3.7 Extracting Programs from Texinfo Source Files +14.3.7 Extracting Programs from Texinfo Source Files ---------------------------------------------------- The nodes *note Library Functions::, and *note Sample Programs::, are @@ -18230,7 +19017,7 @@ function. Consider how you might use it to simplify the code. File: gawk.info, Node: Simple Sed, Next: Igawk Program, Prev: Extract Program, Up: Miscellaneous Programs -13.3.8 A Simple Stream Editor +14.3.8 A Simple Stream Editor ----------------------------- The `sed' utility is a stream editor, a program that reads a stream of @@ -18311,7 +19098,7 @@ the single rule handles the printing scheme outlined above, using File: gawk.info, Node: Igawk Program, Next: Anagram Program, Prev: Simple Sed, Up: Miscellaneous Programs -13.3.9 An Easy Way to Use Library Functions +14.3.9 An Easy Way to Use Library Functions ------------------------------------------- In *note Include Files::, we saw how `gawk' provides a built-in @@ -18708,7 +19495,7 @@ can loop forever if the file exists but is empty. Caveat emptor. File: gawk.info, Node: Anagram Program, Next: Signature Program, Prev: Igawk Program, Up: Miscellaneous Programs -13.3.10 Finding Anagrams From A Dictionary +14.3.10 Finding Anagrams From A Dictionary ------------------------------------------ An interesting programming challenge is to search for "anagrams" in a @@ -18798,7 +19585,7 @@ otherwise the anagrams would appear in arbitrary order: File: gawk.info, Node: Signature Program, Prev: Anagram Program, Up: Miscellaneous Programs -13.3.11 And Now For Something Completely Different +14.3.11 And Now For Something Completely Different -------------------------------------------------- The following program was written by Davide Brini and is published on @@ -18825,7 +19612,7 @@ supplies the following copyright terms: File: gawk.info, Node: Debugger, Next: Language History, Prev: Sample Programs, Up: Top -14 Debugging `awk' Programs +15 Debugging `awk' Programs *************************** It would be nice if computer programs worked perfectly the first time @@ -18849,7 +19636,7 @@ program is easy. File: gawk.info, Node: Debugging, Next: Sample Debugging Session, Up: Debugger -14.1 Introduction to `gawk' Debugger +15.1 Introduction to `gawk' Debugger ==================================== This minor node introduces debugging in general and begins the @@ -18864,7 +19651,7 @@ discussion of debugging in `gawk'. File: gawk.info, Node: Debugging Concepts, Next: Debugging Terms, Up: Debugging -14.1.1 Debugging in General +15.1.1 Debugging in General --------------------------- (If you have used debuggers in other languages, you may want to skip @@ -18904,7 +19691,7 @@ functional program that you or someone else wrote). File: gawk.info, Node: Debugging Terms, Next: Awk Debugging, Prev: Debugging Concepts, Up: Debugging -14.1.2 Additional Debugging Concepts +15.1.2 Additional Debugging Concepts ------------------------------------ Before diving in to the details, we need to introduce several important @@ -18956,7 +19743,7 @@ defines terms used throughout the rest of this major node. File: gawk.info, Node: Awk Debugging, Prev: Debugging Terms, Up: Debugging -14.1.3 Awk Debugging +15.1.3 Awk Debugging -------------------- Debugging an `awk' program has some specific aspects that are not @@ -18978,7 +19765,7 @@ commands. File: gawk.info, Node: Sample Debugging Session, Next: List of Debugger Commands, Prev: Debugging, Up: Debugger -14.2 Sample Debugging Session +15.2 Sample Debugging Session ============================= In order to illustrate the use of `gawk' as a debugger, let's look at a @@ -18994,7 +19781,7 @@ example. File: gawk.info, Node: Debugger Invocation, Next: Finding The Bug, Up: Sample Debugging Session -14.2.1 How to Start the Debugger +15.2.1 How to Start the Debugger -------------------------------- Starting the debugger is almost exactly like running `awk', except you @@ -19026,7 +19813,7 @@ code has been executed. File: gawk.info, Node: Finding The Bug, Prev: Debugger Invocation, Up: Sample Debugging Session -14.2.2 Finding the Bug +15.2.2 Finding the Bug ---------------------- Let's say that we are having a problem using (a faulty version of) @@ -19223,7 +20010,7 @@ and problem solved! File: gawk.info, Node: List of Debugger Commands, Next: Readline Support, Prev: Sample Debugging Session, Up: Debugger -14.3 Main Debugger Commands +15.3 Main Debugger Commands =========================== The `gawk' debugger command set can be divided into the following @@ -19262,7 +20049,7 @@ when just hitting <Enter>. This works for the commands `list', `next', File: gawk.info, Node: Breakpoint Control, Next: Debugger Execution Control, Up: List of Debugger Commands -14.3.1 Control of Breakpoints +15.3.1 Control of Breakpoints ----------------------------- As we saw above, the first thing you probably want to do in a debugging @@ -19357,7 +20144,7 @@ controlling breakpoints are: File: gawk.info, Node: Debugger Execution Control, Next: Viewing And Changing Data, Prev: Breakpoint Control, Up: List of Debugger Commands -14.3.2 Control of Execution +15.3.2 Control of Execution --------------------------- Now that your breakpoints are ready, you can start running the program @@ -19447,7 +20234,7 @@ execution of the program than we saw in our earlier example: File: gawk.info, Node: Viewing And Changing Data, Next: Execution Stack, Prev: Debugger Execution Control, Up: List of Debugger Commands -14.3.3 Viewing and Changing Data +15.3.3 Viewing and Changing Data -------------------------------- The commands for viewing and changing variables inside of `gawk' are: @@ -19536,7 +20323,7 @@ AWK STATEMENTS File: gawk.info, Node: Execution Stack, Next: Debugger Info, Prev: Viewing And Changing Data, Up: List of Debugger Commands -14.3.4 Dealing with the Stack +15.3.4 Dealing with the Stack ----------------------------- Whenever you run a program which contains any function calls, `gawk' @@ -19573,7 +20360,7 @@ are: File: gawk.info, Node: Debugger Info, Next: Miscellaneous Debugger Commands, Prev: Execution Stack, Up: List of Debugger Commands -14.3.5 Obtaining Information about the Program and the Debugger State +15.3.5 Obtaining Information about the Program and the Debugger State --------------------------------------------------------------------- Besides looking at the values of variables, there is often a need to get @@ -19682,7 +20469,7 @@ from a file. The commands are: File: gawk.info, Node: Miscellaneous Debugger Commands, Prev: Debugger Info, Up: List of Debugger Commands -14.3.6 Miscellaneous Commands +15.3.6 Miscellaneous Commands ----------------------------- There are a few more commands which do not fit into the previous @@ -19802,7 +20589,7 @@ categories, as follows: File: gawk.info, Node: Readline Support, Next: Limitations, Prev: List of Debugger Commands, Up: Debugger -14.4 Readline Support +15.4 Readline Support ===================== If `gawk' is compiled with the `readline' library, you can take @@ -19829,7 +20616,7 @@ Variable name completion File: gawk.info, Node: Limitations, Prev: Readline Support, Up: Debugger -14.5 Limitations and Future Plans +15.5 Limitations and Future Plans ================================= We hope you find the `gawk' debugger useful and enjoyable to work with, @@ -24884,6 +25671,7 @@ Index * - (hyphen), filenames beginning with: Options. (line 59) * - (hyphen), in bracket expressions: Bracket Expressions. (line 17) * --assign option: Options. (line 32) +* --bignum option: Options. (line 182) * --c option: Options. (line 78) * --characters-as-bytes option: Options. (line 68) * --copyright option: Options. (line 85) @@ -24900,23 +25688,23 @@ Index * --gen-pot option <1>: String Extraction. (line 6) * --gen-pot option: Options. (line 144) * --help option: Options. (line 151) -* --L option: Options. (line 263) +* --L option: Options. (line 269) * --lint option <1>: Options. (line 163) * --lint option: Command Line. (line 20) -* --lint-old option: Options. (line 263) +* --lint-old option: Options. (line 269) * --load option: Options. (line 156) * --non-decimal-data option <1>: Nondecimal Data. (line 6) -* --non-decimal-data option: Options. (line 182) +* --non-decimal-data option: Options. (line 188) * --non-decimal-data option, strtonum() function and: Nondecimal Data. (line 36) -* --optimize option: Options. (line 203) -* --posix option: Options. (line 222) -* --posix option, --traditional option and: Options. (line 241) -* --pretty-print option: Options. (line 195) +* --optimize option: Options. (line 209) +* --posix option: Options. (line 228) +* --posix option, --traditional option and: Options. (line 247) +* --pretty-print option: Options. (line 201) * --profile option <1>: Profiling. (line 12) -* --profile option: Options. (line 210) -* --re-interval option: Options. (line 247) -* --sandbox option: Options. (line 254) +* --profile option: Options. (line 216) +* --re-interval option: Options. (line 253) +* --sandbox option: Options. (line 260) * --sandbox option, disabling system() function: I/O Functions. (line 85) * --sandbox option, input redirection with getline: Getline. (line 19) @@ -24924,9 +25712,9 @@ Index (line 6) * --source option: Options. (line 114) * --traditional option: Options. (line 78) -* --traditional option, --posix option and: Options. (line 241) -* --use-lc-numeric option: Options. (line 190) -* --version option: Options. (line 268) +* --traditional option, --posix option and: Options. (line 247) +* --use-lc-numeric option: Options. (line 196) +* --version option: Options. (line 274) * --with-whiny-user-strftime configuration option: Additional Configuration Options. (line 29) * -b option: Options. (line 68) @@ -24940,20 +25728,21 @@ Index * -f option: Options. (line 25) * -F option: Options. (line 21) * -f option: Long. (line 12) -* -F option, -Ft sets FS to TAB: Options. (line 276) -* -f option, on command line: Options. (line 281) +* -F option, -Ft sets FS to TAB: Options. (line 282) +* -f option, on command line: Options. (line 287) * -g option: Options. (line 144) * -h option: Options. (line 151) * -l option: Options. (line 156) -* -N option: Options. (line 190) -* -n option: Options. (line 182) -* -O option: Options. (line 203) -* -o option: Options. (line 195) -* -P option: Options. (line 222) -* -p option: Options. (line 210) -* -r option: Options. (line 247) -* -S option: Options. (line 254) -* -V option: Options. (line 268) +* -M option: Options. (line 182) +* -N option: Options. (line 196) +* -n option: Options. (line 188) +* -O option: Options. (line 209) +* -o option: Options. (line 201) +* -P option: Options. (line 228) +* -p option: Options. (line 216) +* -r option: Options. (line 253) +* -S option: Options. (line 260) +* -V option: Options. (line 274) * -v option: Options. (line 32) * -v option, variables, assigning: Assignment Options. (line 12) * -W option: Options. (line 46) @@ -25093,7 +25882,7 @@ Index (line 67) * advanced features, data files as single record: Records. (line 175) * advanced features, fixed-width data: Constant Size. (line 9) -* advanced features, FNR/NR variables: Auto-set. (line 207) +* advanced features, FNR/NR variables: Auto-set. (line 224) * advanced features, gawk: Advanced Features. (line 6) * advanced features, gawk, network programming: TCP/IP Networking. (line 6) @@ -25128,6 +25917,8 @@ Index * and Boolean-logic operator: Boolean Ops. (line 6) * and() function (gawk): Bitwise Functions. (line 39) * ANSI: Glossary. (line 35) +* arbitrary precision: Arbitrary Precision Arithmetic. + (line 6) * archeologists: Bugs. (line 6) * ARGC/ARGV variables <1>: ARGC and ARGV. (line 6) * ARGC/ARGV variables: Auto-set. (line 11) @@ -25210,9 +26001,9 @@ Index * atan2() function: Numeric Functions. (line 11) * awf (amazingly workable formatter) program: Glossary. (line 25) * awk debugging, enabling: Options. (line 105) -* awk enabling: Options. (line 195) +* awk enabling: Options. (line 201) * awk language, POSIX version: Assignment Ops. (line 136) -* awk profiling, enabling: Options. (line 210) +* awk profiling, enabling: Options. (line 216) * awk programs <1>: Two Rules. (line 6) * awk programs <2>: Executable Scripts. (line 6) * awk programs: Getting Started. (line 12) @@ -25543,8 +26334,12 @@ Index (line 29) * configuration options, gawk: Additional Configuration Options. (line 6) +* constants, floating-point: Floating-point Constants. + (line 6) * constants, nondecimal: Nondecimal Data. (line 6) * constants, types of: Constants. (line 6) +* context, floating-point: Floating-point Context. + (line 6) * continue statement: Continue Statement. (line 6) * control statements: Statements. (line 6) * converting, case: String Functions. (line 522) @@ -25567,7 +26362,7 @@ Index * cos() function: Numeric Functions. (line 15) * counting: Wc Program. (line 6) * csh utility: Statements/Lines. (line 44) -* csh utility, POSIXLY_CORRECT environment variable: Options. (line 323) +* csh utility, POSIXLY_CORRECT environment variable: Options. (line 329) * csh utility, |& operator, comparison with: Two-way I/O. (line 44) * ctime() user-defined function: Function Example. (line 72) * currency symbols, localization: Explaining gettext. (line 103) @@ -25599,7 +26394,7 @@ Index (line 47) * dark corner, FILENAME variable <1>: Auto-set. (line 92) * dark corner, FILENAME variable: Getline Notes. (line 19) -* dark corner, FNR/NR variables: Auto-set. (line 207) +* dark corner, FNR/NR variables: Auto-set. (line 224) * dark corner, format-control characters: Control Letters. (line 18) * dark corner, FS as null string: Single Character Fields. (line 20) @@ -25736,7 +26531,7 @@ Index (line 67) * debugging awk programs: Debugger. (line 6) * debugging gawk, bug reports: Bugs. (line 9) -* decimal point character, locale specific: Options. (line 238) +* decimal point character, locale specific: Options. (line 244) * decrement operators: Increment Ops. (line 35) * default keyword: Switch Statement. (line 6) * Deifik, Scott <1>: Bugs. (line 70) @@ -25798,7 +26593,7 @@ Index * differences in awk and gawk, regular expressions: Case-sensitivity. (line 26) * differences in awk and gawk, RS/RT variables: Records. (line 167) -* differences in awk and gawk, RT variable: Auto-set. (line 196) +* differences in awk and gawk, RT variable: Auto-set. (line 213) * differences in awk and gawk, single-character fields: Single Character Fields. (line 6) * differences in awk and gawk, split() function: String Functions. @@ -25808,7 +26603,7 @@ Index * differences in awk and gawk, strtonum() function (gawk): String Functions. (line 404) * differences in awk and gawk, TEXTDOMAIN variable: User-modified. - (line 153) + (line 162) * differences in awk and gawk, trunc-mod operation: Arithmetic Ops. (line 66) * directories, changing: Sample Library. (line 6) @@ -26074,12 +26869,14 @@ Index * fixed-width data: Constant Size. (line 9) * flag variables <1>: Tee Program. (line 20) * flag variables: Boolean Ops. (line 67) +* floating-point numbers, arbitrary precision: Arbitrary Precision Arithmetic. + (line 6) * floating-point, numbers <1>: Unexpected Results. (line 6) * floating-point, numbers: Basic Data Typing. (line 21) * floating-point, numbers, AWKNUM internal type: Internals. (line 19) * FNR variable <1>: Auto-set. (line 102) * FNR variable: Records. (line 6) -* FNR variable, changing: Auto-set. (line 207) +* FNR variable, changing: Auto-set. (line 224) * for statement: For Statement. (line 6) * for statement, in arrays: Scanning an Array. (line 20) * force_number() internal function: Internals. (line 27) @@ -26115,7 +26912,7 @@ Index * FS variable, --field-separator option and: Options. (line 21) * FS variable, as null string: Single Character Fields. (line 20) -* FS variable, as TAB character: Options. (line 234) +* FS variable, as TAB character: Options. (line 240) * FS variable, changing value of: Field Separators. (line 34) * FS variable, running awk programs and: Cut Program. (line 68) * FS variable, setting from command line: Command Line Field Separator. @@ -26172,7 +26969,7 @@ Index (line 44) * functions, user-defined, next/nextfile statements and: Next Statement. (line 45) -* G-d: Acknowledgments. (line 81) +* G-d: Acknowledgments. (line 83) * Garfinkle, Scott: Contributors. (line 35) * gawk program, dynamic profiling: Profiling. (line 171) * gawk, ARGIND variable in: Other Arguments. (line 12) @@ -26201,7 +26998,7 @@ Index (line 139) * gawk, ERRNO variable in: Getline. (line 19) * gawk, escape sequences: Escape Sequences. (line 125) -* gawk, extensions, disabling: Options. (line 222) +* gawk, extensions, disabling: Options. (line 228) * gawk, features, adding: Adding Code. (line 6) * gawk, features, advanced: Advanced Features. (line 6) * gawk, fflush() function in: I/O Functions. (line 44) @@ -26254,7 +27051,7 @@ Index * gawk, regular expressions, operators: GNU Regexp Operators. (line 6) * gawk, regular expressions, precedence: Regexp Operators. (line 161) -* gawk, RT variable in <1>: Auto-set. (line 196) +* gawk, RT variable in <1>: Auto-set. (line 213) * gawk, RT variable in <2>: Getline/Variable/File. (line 10) * gawk, RT variable in <3>: Multiple Line. (line 129) @@ -26263,10 +27060,10 @@ Index * gawk, source code, obtaining: Getting. (line 6) * gawk, splitting fields and: Constant Size. (line 87) * gawk, string-translation functions: I18N Functions. (line 6) -* gawk, TEXTDOMAIN variable in: User-modified. (line 153) +* gawk, TEXTDOMAIN variable in: User-modified. (line 162) * gawk, timestamps: Time Functions. (line 6) * gawk, uses for: Preface. (line 36) -* gawk, versions of, information about, printing: Options. (line 268) +* gawk, versions of, information about, printing: Options. (line 274) * gawk, VMS version of: VMS Installation. (line 6) * gawk, word-boundary operator: GNU Regexp Operators. (line 63) @@ -26318,6 +27115,8 @@ Index * gettext() function (C library): Explaining gettext. (line 62) * gettimeofday() user-defined function: Gettimeofday Function. (line 16) +* GMP: Arbitrary Precision Arithmetic. + (line 6) * GNITS mailing list: Acknowledgments. (line 52) * GNU awk, See gawk: Preface. (line 49) * GNU Free Documentation License: GNU Free Documentation License. @@ -26357,7 +27156,7 @@ Index * help debugger command: Miscellaneous Debugger Commands. (line 68) * hexadecimal numbers: Nondecimal-numbers. (line 6) -* hexadecimal values, enabling interpretation of: Options. (line 182) +* hexadecimal values, enabling interpretation of: Options. (line 188) * histsort.awk program: History Sorting. (line 25) * Hughes, Phil: Acknowledgments. (line 43) * HUP signal: Profiling. (line 203) @@ -26371,6 +27170,8 @@ Index * i debugger command (alias for info): Debugger Info. (line 13) * id utility: Id Program. (line 6) * id.awk program: Id Program. (line 30) +* IEEE-754 format: Floating-point Representation. + (line 6) * if statement <1>: If Statement. (line 6) * if statement: Regexp Usage. (line 19) * if statement, actions, changing: Ranges. (line 25) @@ -26403,6 +27204,8 @@ Index * index() function: String Functions. (line 155) * indexing arrays: Array Intro. (line 50) * indirect function calls: Indirect Calls. (line 6) +* infinite precision: Arbitrary Precision Arithmetic. + (line 6) * info debugger command: Debugger Info. (line 13) * initialization, automatic: More Complex. (line 38) * input files: Reading Files. (line 6) @@ -26430,6 +27233,8 @@ Index * installing gawk: Installation. (line 6) * INT signal (MS-Windows): Profiling. (line 206) * int() function: Numeric Functions. (line 23) +* integer, arbitrary precision: Arbitrary Precision Integers. + (line 6) * integers: Basic Data Typing. (line 21) * integers, unsigned: Basic Data Typing. (line 30) * interacting with other programs: I/O Functions. (line 63) @@ -26467,7 +27272,7 @@ Index * internationalization: I18N Functions. (line 6) * internationalization, localization <1>: Internationalization. (line 13) -* internationalization, localization: User-modified. (line 153) +* internationalization, localization: User-modified. (line 162) * internationalization, localization, character classes: Bracket Expressions. (line 90) * internationalization, localization, gawk and: Internationalization. @@ -26507,16 +27312,19 @@ Index * Kernighan, Brian <3>: Contributors. (line 12) * Kernighan, Brian <4>: BTL. (line 6) * Kernighan, Brian <5>: Concatenation. (line 6) -* Kernighan, Brian <6>: Acknowledgments. (line 75) +* Kernighan, Brian <6>: Acknowledgments. (line 77) * Kernighan, Brian <7>: Conventions. (line 34) * Kernighan, Brian: History. (line 17) * kill command, dynamic profiling: Profiling. (line 180) * Knights, jedi: Undocumented. (line 6) +* Knuth, Donald: Arbitrary Precision Arithmetic. + (line 6) * Kwok, Conrad: Contributors. (line 35) * l debugger command (alias for list): Miscellaneous Debugger Commands. (line 74) * labels.awk program: Labels Program. (line 51) * languages, data-driven: Basic High Level. (line 83) +* Laurie, Dirk: Changing Precision. (line 6) * LC_ALL locale category: Explaining gettext. (line 120) * LC_COLLATE locale category: Explaining gettext. (line 93) * LC_CTYPE locale category: Explaining gettext. (line 97) @@ -26579,7 +27387,7 @@ Index * lint checking, empty programs: Command Line. (line 16) * lint checking, issuing warnings: Options. (line 163) * lint checking, POSIXLY_CORRECT environment variable: Options. - (line 307) + (line 313) * lint checking, undefined functions: Pass By Value/Reference. (line 88) * LINT variable: User-modified. (line 98) @@ -26592,7 +27400,7 @@ Index * loading, library: Options. (line 156) * local variables: Variable Scope. (line 6) * locale categories: Explaining gettext. (line 80) -* locale decimal point character: Options. (line 238) +* locale decimal point character: Options. (line 244) * locale, definition of: Locales. (line 6) * localization: I18N and L10N. (line 6) * localization, See internationalization, localization: I18N and L10N. @@ -26643,7 +27451,11 @@ Index * mktime() function (gawk): Time Functions. (line 24) * modifiers, in format specifiers: Format Modifiers. (line 6) * monetary information, localization: Explaining gettext. (line 103) +* MPFR: Arbitrary Precision Arithmetic. + (line 6) * msgfmt utility: I18N Example. (line 62) +* multiple precision: Arbitrary Precision Arithmetic. + (line 6) * n debugger command (alias for next): Debugger Execution Control. (line 43) * names, arrays/variables <1>: Library Names. (line 6) @@ -26660,7 +27472,7 @@ Index * networks, programming: TCP/IP Networking. (line 6) * networks, support for: Special Network. (line 6) * newlines <1>: Boolean Ops. (line 67) -* newlines <2>: Options. (line 228) +* newlines <2>: Options. (line 234) * newlines: Statements/Lines. (line 6) * newlines, as field separators: Default Field Splitting. (line 6) @@ -26699,7 +27511,7 @@ Index * not Boolean-logic operator: Boolean Ops. (line 6) * NR variable <1>: Auto-set. (line 118) * NR variable: Records. (line 6) -* NR variable, changing: Auto-set. (line 207) +* NR variable, changing: Auto-set. (line 224) * null strings <1>: Basic Data Typing. (line 50) * null strings <2>: Truth Values. (line 6) * null strings <3>: Regexp Field Splitting. @@ -26740,7 +27552,7 @@ Index * oawk utility: Names. (line 17) * obsolete features: Obsolete. (line 6) * octal numbers: Nondecimal-numbers. (line 6) -* octal values, enabling interpretation of: Options. (line 182) +* octal values, enabling interpretation of: Options. (line 188) * OFMT variable <1>: User-modified. (line 115) * OFMT variable <2>: Conversion. (line 55) * OFMT variable: OFMT. (line 15) @@ -26885,7 +27697,7 @@ Index * portability, NF variable, decrementing: Changing Fields. (line 115) * portability, operators: Increment Ops. (line 61) * portability, operators, not in POSIX awk: Precedence. (line 98) -* portability, POSIXLY_CORRECT environment variable: Options. (line 328) +* portability, POSIXLY_CORRECT environment variable: Options. (line 334) * portability, substr() function: String Functions. (line 512) * portable object files <1>: Translator i18n. (line 6) * portable object files: Explaining gettext. (line 36) @@ -26935,11 +27747,13 @@ Index * POSIX awk, regular expressions and: Regexp Operators. (line 161) * POSIX awk, timestamps and: Time Functions. (line 6) * POSIX awk, | I/O operator and: Getline/Pipe. (line 52) -* POSIX mode: Options. (line 222) +* POSIX mode: Options. (line 228) * POSIX, awk and: Preface. (line 23) * POSIX, gawk extensions not included in: POSIX/GNU. (line 6) * POSIX, programs, implementing in awk: Clones. (line 6) -* POSIXLY_CORRECT environment variable: Options. (line 307) +* POSIXLY_CORRECT environment variable: Options. (line 313) +* PREC variable <1>: Setting Precision. (line 6) +* PREC variable: User-modified. (line 134) * precedence <1>: Precedence. (line 6) * precedence: Increment Ops. (line 61) * precedence, regexp operators: Regexp Operators. (line 156) @@ -27048,7 +27862,7 @@ Index * readable data files, checking: File Checking. (line 6) * readable.awk program: File Checking. (line 11) * recipe for a programming language: History. (line 6) -* record separators <1>: User-modified. (line 134) +* record separators <1>: User-modified. (line 143) * record separators: Records. (line 14) * record separators, changing: Records. (line 81) * record separators, regular expressions as: Records. (line 112) @@ -27096,7 +27910,7 @@ Index (line 59) * regular expressions, gawk, command-line options: GNU Regexp Operators. (line 70) -* regular expressions, interval expressions and: Options. (line 247) +* regular expressions, interval expressions and: Options. (line 253) * regular expressions, leftmost longest match: Leftmost Longest. (line 6) * regular expressions, operators <1>: Regexp Operators. (line 6) @@ -27130,7 +27944,7 @@ Index * right angle bracket (>), >> operator (I/O): Redirection. (line 50) * right shift, bitwise: Bitwise Functions. (line 32) * Ritchie, Dennis: Basic Data Typing. (line 74) -* RLENGTH variable: Auto-set. (line 183) +* RLENGTH variable: Auto-set. (line 200) * RLENGTH variable, match() function and: String Functions. (line 223) * Robbins, Arnold <1>: Future Extensions. (line 6) * Robbins, Arnold <2>: Bugs. (line 32) @@ -27141,23 +27955,27 @@ Index * Robbins, Arnold: Command Line Field Separator. (line 80) * Robbins, Bill: Getline/Pipe. (line 36) -* Robbins, Harry: Acknowledgments. (line 81) -* Robbins, Jean: Acknowledgments. (line 81) +* Robbins, Harry: Acknowledgments. (line 83) +* Robbins, Jean: Acknowledgments. (line 83) * Robbins, Miriam <1>: Passwd Functions. (line 90) * Robbins, Miriam <2>: Getline/Pipe. (line 36) -* Robbins, Miriam: Acknowledgments. (line 81) +* Robbins, Miriam: Acknowledgments. (line 83) * Robinson, Will: Dynamic Extensions. (line 6) * robot, the: Dynamic Extensions. (line 6) * Rommel, Kai Uwe: Contributors. (line 43) * round() user-defined function: Round Function. (line 16) +* rounding mode, floating-point: Rounding Mode. (line 6) * rounding numbers: Round Function. (line 6) -* RS variable <1>: User-modified. (line 134) +* ROUNDMODE variable <1>: Setting Rounding Mode. + (line 6) +* ROUNDMODE variable: User-modified. (line 138) +* RS variable <1>: User-modified. (line 143) * RS variable: Records. (line 20) * RS variable, multiline records and: Multiple Line. (line 17) * rshift() function (gawk): Bitwise Functions. (line 51) -* RSTART variable: Auto-set. (line 189) +* RSTART variable: Auto-set. (line 206) * RSTART variable, match() function and: String Functions. (line 223) -* RT variable <1>: Auto-set. (line 196) +* RT variable <1>: Auto-set. (line 213) * RT variable <2>: Getline/Variable/File. (line 10) * RT variable <3>: Multiple Line. (line 129) @@ -27170,7 +27988,7 @@ Index * rvalues/lvalues: Assignment Ops. (line 32) * s debugger command (alias for step): Debugger Execution Control. (line 68) -* sandbox mode: Options. (line 254) +* sandbox mode: Options. (line 260) * scalar values: Basic Data Typing. (line 13) * Schorr, Andrew: Acknowledgments. (line 60) * Schreiber, Bert: Acknowledgments. (line 38) @@ -27200,11 +28018,11 @@ Index * separators, field, FIELDWIDTHS variable and: User-modified. (line 35) * separators, field, FPAT variable and: User-modified. (line 45) * separators, field, POSIX and: Fields. (line 6) -* separators, for records <1>: User-modified. (line 134) +* separators, for records <1>: User-modified. (line 143) * separators, for records: Records. (line 14) * separators, for records, regular expressions as: Records. (line 112) * separators, for statements in actions: Action Overview. (line 19) -* separators, subscript: User-modified. (line 147) +* separators, subscript: User-modified. (line 156) * set debugger command: Viewing And Changing Data. (line 59) * shells, piping commands into: Redirection. (line 143) @@ -27337,7 +28155,7 @@ Index (line 43) * sub() function, arguments of: String Functions. (line 462) * sub() function, escape processing: Gory Details. (line 6) -* subscript separators: User-modified. (line 147) +* subscript separators: User-modified. (line 156) * subscripts in arrays, multidimensional: Multi-dimensional. (line 10) * subscripts in arrays, multidimensional, scanning: Multi-scanning. (line 11) @@ -27345,7 +28163,7 @@ Index (line 6) * subscripts in arrays, uninitialized variables as: Uninitialized Subscripts. (line 6) -* SUBSEP variable: User-modified. (line 147) +* SUBSEP variable: User-modified. (line 156) * SUBSEP variable, multidimensional arrays: Multi-dimensional. (line 16) * substr() function: String Functions. (line 481) @@ -27378,7 +28196,7 @@ Index * text, printing: Print. (line 22) * text, printing, unduplicated lines of: Uniq Program. (line 6) * TEXTDOMAIN variable <1>: Programmer i18n. (line 9) -* TEXTDOMAIN variable: User-modified. (line 153) +* TEXTDOMAIN variable: User-modified. (line 162) * TEXTDOMAIN variable, BEGIN pattern and: Programmer i18n. (line 60) * TEXTDOMAIN variable, portability and: I18N Portability. (line 20) * textdomain() function (C library): Explaining gettext. (line 27) @@ -27406,7 +28224,7 @@ Index * trace debugger command: Miscellaneous Debugger Commands. (line 110) * translate.awk program: Translate Program. (line 55) -* troubleshooting, --non-decimal-data option: Options. (line 182) +* troubleshooting, --non-decimal-data option: Options. (line 188) * troubleshooting, == operator: Comparison Operators. (line 37) * troubleshooting, awk uses FS not IFS: Field Separators. (line 29) @@ -27551,7 +28369,7 @@ Index * whitespace, as field separators: Default Field Splitting. (line 6) * whitespace, functions, calling: Calling Built-in. (line 10) -* whitespace, newlines as: Options. (line 228) +* whitespace, newlines as: Options. (line 234) * Williams, Kent: Contributors. (line 35) * Woehlke, Matthew: Contributors. (line 79) * Woods, John: Contributors. (line 28) @@ -27607,419 +28425,440 @@ Index Tag Table: Node: Top1352 -Node: Foreword30423 -Node: Preface34768 -Ref: Preface-Footnote-137821 -Ref: Preface-Footnote-237927 -Node: History38159 -Node: Names40550 -Ref: Names-Footnote-142027 -Node: This Manual42099 -Ref: This Manual-Footnote-147037 -Node: Conventions47137 -Node: Manual History49271 -Ref: Manual History-Footnote-152541 -Ref: Manual History-Footnote-252582 -Node: How To Contribute52656 -Node: Acknowledgments53800 -Node: Getting Started58131 -Node: Running gawk60510 -Node: One-shot61696 -Node: Read Terminal62921 -Ref: Read Terminal-Footnote-164571 -Ref: Read Terminal-Footnote-264847 -Node: Long65018 -Node: Executable Scripts66394 -Ref: Executable Scripts-Footnote-168263 -Ref: Executable Scripts-Footnote-268365 -Node: Comments68912 -Node: Quoting71379 -Node: DOS Quoting76002 -Node: Sample Data Files76677 -Node: Very Simple79709 -Node: Two Rules84308 -Node: More Complex86455 -Ref: More Complex-Footnote-189385 -Node: Statements/Lines89470 -Ref: Statements/Lines-Footnote-193932 -Node: Other Features94197 -Node: When95125 -Node: Invoking Gawk97272 -Node: Command Line98657 -Node: Options99440 -Ref: Options-Footnote-1113585 -Node: Other Arguments113610 -Node: Naming Standard Input116268 -Node: Environment Variables117362 -Node: AWKPATH Variable117806 -Ref: AWKPATH Variable-Footnote-1120403 -Node: Other Environment Variables120663 -Node: Exit Status123155 -Node: Include Files123830 -Node: Obsolete127315 -Node: Undocumented128001 -Node: Regexp128242 -Node: Regexp Usage129631 -Node: Escape Sequences131657 -Node: Regexp Operators137420 -Ref: Regexp Operators-Footnote-1144800 -Ref: Regexp Operators-Footnote-2144947 -Node: Bracket Expressions145045 -Ref: table-char-classes146935 -Node: GNU Regexp Operators149458 -Node: Case-sensitivity153181 -Ref: Case-sensitivity-Footnote-1156149 -Ref: Case-sensitivity-Footnote-2156384 -Node: Leftmost Longest156492 -Node: Computed Regexps157693 -Node: Reading Files161103 -Node: Records163107 -Ref: Records-Footnote-1171781 -Node: Fields171818 -Ref: Fields-Footnote-1174851 -Node: Nonconstant Fields174937 -Node: Changing Fields177139 -Node: Field Separators183120 -Node: Default Field Splitting185749 -Node: Regexp Field Splitting186866 -Node: Single Character Fields190208 -Node: Command Line Field Separator191267 -Node: Field Splitting Summary194708 -Ref: Field Splitting Summary-Footnote-1197900 -Node: Constant Size198001 -Node: Splitting By Content202585 -Ref: Splitting By Content-Footnote-1206311 -Node: Multiple Line206351 -Ref: Multiple Line-Footnote-1212198 -Node: Getline212377 -Node: Plain Getline214593 -Node: Getline/Variable216682 -Node: Getline/File217823 -Node: Getline/Variable/File219145 -Ref: Getline/Variable/File-Footnote-1220744 -Node: Getline/Pipe220831 -Node: Getline/Variable/Pipe223391 -Node: Getline/Coprocess224498 -Node: Getline/Variable/Coprocess225741 -Node: Getline Notes226455 -Node: Getline Summary228397 -Ref: table-getline-variants228740 -Node: Read Timeout229596 -Ref: Read Timeout-Footnote-1233341 -Node: Command line directories233398 -Node: Printing234028 -Node: Print235659 -Node: Print Examples236996 -Node: Output Separators239780 -Node: OFMT241540 -Node: Printf242898 -Node: Basic Printf243804 -Node: Control Letters245343 -Node: Format Modifiers249155 -Node: Printf Examples255164 -Node: Redirection257879 -Node: Special Files264863 -Node: Special FD265396 -Ref: Special FD-Footnote-1269021 -Node: Special Network269095 -Node: Special Caveats269945 -Node: Close Files And Pipes270741 -Ref: Close Files And Pipes-Footnote-1277764 -Ref: Close Files And Pipes-Footnote-2277912 -Node: Expressions278062 -Node: Values279194 -Node: Constants279870 -Node: Scalar Constants280550 -Ref: Scalar Constants-Footnote-1281409 -Node: Nondecimal-numbers281591 -Node: Regexp Constants284650 -Node: Using Constant Regexps285125 -Node: Variables288180 -Node: Using Variables288835 -Node: Assignment Options290559 -Node: Conversion292431 -Ref: table-locale-affects297807 -Ref: Conversion-Footnote-1298431 -Node: All Operators298540 -Node: Arithmetic Ops299170 -Node: Concatenation301675 -Ref: Concatenation-Footnote-1304468 -Node: Assignment Ops304588 -Ref: table-assign-ops309576 -Node: Increment Ops310984 -Node: Truth Values and Conditions314454 -Node: Truth Values315537 -Node: Typing and Comparison316586 -Node: Variable Typing317375 -Ref: Variable Typing-Footnote-1321272 -Node: Comparison Operators321394 -Ref: table-relational-ops321804 -Node: POSIX String Comparison325353 -Ref: POSIX String Comparison-Footnote-1326309 -Node: Boolean Ops326447 -Ref: Boolean Ops-Footnote-1330525 -Node: Conditional Exp330616 -Node: Function Calls332348 -Node: Precedence335942 -Node: Locales339611 -Node: Patterns and Actions340700 -Node: Pattern Overview341754 -Node: Regexp Patterns343423 -Node: Expression Patterns343966 -Node: Ranges347651 -Node: BEGIN/END350617 -Node: Using BEGIN/END351379 -Ref: Using BEGIN/END-Footnote-1354110 -Node: I/O And BEGIN/END354216 -Node: BEGINFILE/ENDFILE356498 -Node: Empty359391 -Node: Using Shell Variables359707 -Node: Action Overview361992 -Node: Statements364349 -Node: If Statement366203 -Node: While Statement367702 -Node: Do Statement369746 -Node: For Statement370902 -Node: Switch Statement374054 -Node: Break Statement376151 -Node: Continue Statement378141 -Node: Next Statement379934 -Node: Nextfile Statement382324 -Node: Exit Statement384869 -Node: Built-in Variables387285 -Node: User-modified388380 -Ref: User-modified-Footnote-1396406 -Node: Auto-set396468 -Ref: Auto-set-Footnote-1405759 -Node: ARGC and ARGV405964 -Node: Arrays409815 -Node: Array Basics411320 -Node: Array Intro412146 -Node: Reference to Elements416464 -Node: Assigning Elements418734 -Node: Array Example419225 -Node: Scanning an Array420957 -Node: Controlling Scanning423271 -Ref: Controlling Scanning-Footnote-1428204 -Node: Delete428520 -Ref: Delete-Footnote-1430955 -Node: Numeric Array Subscripts431012 -Node: Uninitialized Subscripts433195 -Node: Multi-dimensional434823 -Node: Multi-scanning437917 -Node: Arrays of Arrays439508 -Node: Functions444153 -Node: Built-in444975 -Node: Calling Built-in446053 -Node: Numeric Functions448041 -Ref: Numeric Functions-Footnote-1451873 -Ref: Numeric Functions-Footnote-2452230 -Ref: Numeric Functions-Footnote-3452278 -Node: String Functions452547 -Ref: String Functions-Footnote-1476044 -Ref: String Functions-Footnote-2476173 -Ref: String Functions-Footnote-3476421 -Node: Gory Details476508 -Ref: table-sub-escapes478187 -Ref: table-sub-posix-92479541 -Ref: table-sub-proposed480884 -Ref: table-posix-sub482234 -Ref: table-gensub-escapes483780 -Ref: Gory Details-Footnote-1484987 -Ref: Gory Details-Footnote-2485038 -Node: I/O Functions485189 -Ref: I/O Functions-Footnote-1491844 -Node: Time Functions491991 -Ref: Time Functions-Footnote-1502883 -Ref: Time Functions-Footnote-2502951 -Ref: Time Functions-Footnote-3503109 -Ref: Time Functions-Footnote-4503220 -Ref: Time Functions-Footnote-5503332 -Ref: Time Functions-Footnote-6503559 -Node: Bitwise Functions503825 -Ref: table-bitwise-ops504383 -Ref: Bitwise Functions-Footnote-1508543 -Node: Type Functions508727 -Node: I18N Functions509197 -Node: User-defined510824 -Node: Definition Syntax511628 -Ref: Definition Syntax-Footnote-1516538 -Node: Function Example516607 -Node: Function Caveats519201 -Node: Calling A Function519622 -Node: Variable Scope520737 -Node: Pass By Value/Reference522712 -Node: Return Statement526152 -Node: Dynamic Typing529133 -Node: Indirect Calls529868 -Node: Internationalization539553 -Node: I18N and L10N540979 -Node: Explaining gettext541665 -Ref: Explaining gettext-Footnote-1546731 -Ref: Explaining gettext-Footnote-2546915 -Node: Programmer i18n547080 -Node: Translator i18n551280 -Node: String Extraction552073 -Ref: String Extraction-Footnote-1553034 -Node: Printf Ordering553120 -Ref: Printf Ordering-Footnote-1555904 -Node: I18N Portability555968 -Ref: I18N Portability-Footnote-1558417 -Node: I18N Example558480 -Ref: I18N Example-Footnote-1561115 -Node: Gawk I18N561187 -Node: Advanced Features561804 -Node: Nondecimal Data563317 -Node: Array Sorting564900 -Node: Controlling Array Traversal565597 -Node: Array Sorting Functions573834 -Ref: Array Sorting Functions-Footnote-1577508 -Ref: Array Sorting Functions-Footnote-2577601 -Node: Two-way I/O577795 -Ref: Two-way I/O-Footnote-1583227 -Node: TCP/IP Networking583297 -Node: Profiling586141 -Node: Library Functions593595 -Ref: Library Functions-Footnote-1596602 -Node: Library Names596773 -Ref: Library Names-Footnote-1600244 -Ref: Library Names-Footnote-2600464 -Node: General Functions600550 -Node: Strtonum Function601503 -Node: Assert Function604433 -Node: Round Function607759 -Node: Cliff Random Function609302 -Node: Ordinal Functions610318 -Ref: Ordinal Functions-Footnote-1613388 -Ref: Ordinal Functions-Footnote-2613640 -Node: Join Function613849 -Ref: Join Function-Footnote-1615620 -Node: Gettimeofday Function615820 -Node: Data File Management619535 -Node: Filetrans Function620167 -Node: Rewind Function624306 -Node: File Checking625693 -Node: Empty Files626787 -Node: Ignoring Assigns629017 -Node: Getopt Function630570 -Ref: Getopt Function-Footnote-1641874 -Node: Passwd Functions642077 -Ref: Passwd Functions-Footnote-1651052 -Node: Group Functions651140 -Node: Walking Arrays659224 -Node: Sample Programs660793 -Node: Running Examples661458 -Node: Clones662186 -Node: Cut Program663410 -Node: Egrep Program673255 -Ref: Egrep Program-Footnote-1681028 -Node: Id Program681138 -Node: Split Program684754 -Ref: Split Program-Footnote-1688273 -Node: Tee Program688401 -Node: Uniq Program691204 -Node: Wc Program698633 -Ref: Wc Program-Footnote-1702899 -Ref: Wc Program-Footnote-2703099 -Node: Miscellaneous Programs703191 -Node: Dupword Program704379 -Node: Alarm Program706410 -Node: Translate Program711159 -Ref: Translate Program-Footnote-1715546 -Ref: Translate Program-Footnote-2715774 -Node: Labels Program715908 -Ref: Labels Program-Footnote-1719279 -Node: Word Sorting719363 -Node: History Sorting723247 -Node: Extract Program725086 -Ref: Extract Program-Footnote-1732569 -Node: Simple Sed732697 -Node: Igawk Program735759 -Ref: Igawk Program-Footnote-1750916 -Ref: Igawk Program-Footnote-2751117 -Node: Anagram Program751255 -Node: Signature Program754323 -Node: Debugger755423 -Node: Debugging756375 -Node: Debugging Concepts756808 -Node: Debugging Terms758664 -Node: Awk Debugging761261 -Node: Sample Debugging Session762153 -Node: Debugger Invocation762673 -Node: Finding The Bug764002 -Node: List of Debugger Commands770490 -Node: Breakpoint Control771824 -Node: Debugger Execution Control775488 -Node: Viewing And Changing Data778848 -Node: Execution Stack782204 -Node: Debugger Info783671 -Node: Miscellaneous Debugger Commands787652 -Node: Readline Support793097 -Node: Limitations793928 -Node: Language History796180 -Node: V7/SVR3.1797692 -Node: SVR4800013 -Node: POSIX801455 -Node: BTL802463 -Node: POSIX/GNU803197 -Node: Common Extensions808348 -Node: Ranges and Locales809455 -Ref: Ranges and Locales-Footnote-1814059 -Node: Contributors814280 -Node: Installation818541 -Node: Gawk Distribution819435 -Node: Getting819919 -Node: Extracting820745 -Node: Distribution contents822437 -Node: Unix Installation827659 -Node: Quick Installation828276 -Node: Additional Configuration Options830238 -Node: Configuration Philosophy831715 -Node: Non-Unix Installation834057 -Node: PC Installation834515 -Node: PC Binary Installation835814 -Node: PC Compiling837662 -Node: PC Testing840606 -Node: PC Using841782 -Node: Cygwin845967 -Node: MSYS846967 -Node: VMS Installation847481 -Node: VMS Compilation848084 -Ref: VMS Compilation-Footnote-1849091 -Node: VMS Installation Details849149 -Node: VMS Running850784 -Node: VMS Old Gawk852391 -Node: Bugs852865 -Node: Other Versions856717 -Node: Notes862032 -Node: Compatibility Mode862724 -Node: Additions863507 -Node: Accessing The Source864319 -Node: Adding Code865744 -Node: New Ports871711 -Node: Dynamic Extensions875824 -Node: Internals877264 -Node: Plugin License885783 -Node: Loading Extensions886421 -Node: Sample Library888231 -Node: Internal File Description888921 -Node: Internal File Ops892636 -Ref: Internal File Ops-Footnote-1897360 -Node: Using Internal File Ops897500 -Node: Future Extensions899877 -Node: Basic Concepts902381 -Node: Basic High Level903138 -Ref: Basic High Level-Footnote-1907173 -Node: Basic Data Typing907358 -Node: Floating Point Issues911883 -Node: String Conversion Precision912966 -Ref: String Conversion Precision-Footnote-1914666 -Node: Unexpected Results914775 -Node: POSIX Floating Point Problems916601 -Ref: POSIX Floating Point Problems-Footnote-1920306 -Node: Glossary920344 -Node: Copying945320 -Node: GNU Free Documentation License982877 -Node: Index1008014 +Node: Foreword31559 +Node: Preface35904 +Ref: Preface-Footnote-138957 +Ref: Preface-Footnote-239063 +Node: History39295 +Node: Names41686 +Ref: Names-Footnote-143163 +Node: This Manual43235 +Ref: This Manual-Footnote-148173 +Node: Conventions48273 +Node: Manual History50407 +Ref: Manual History-Footnote-153677 +Ref: Manual History-Footnote-253718 +Node: How To Contribute53792 +Node: Acknowledgments54936 +Node: Getting Started59432 +Node: Running gawk61811 +Node: One-shot62997 +Node: Read Terminal64222 +Ref: Read Terminal-Footnote-165872 +Ref: Read Terminal-Footnote-266148 +Node: Long66319 +Node: Executable Scripts67695 +Ref: Executable Scripts-Footnote-169564 +Ref: Executable Scripts-Footnote-269666 +Node: Comments70213 +Node: Quoting72680 +Node: DOS Quoting77303 +Node: Sample Data Files77978 +Node: Very Simple81010 +Node: Two Rules85609 +Node: More Complex87756 +Ref: More Complex-Footnote-190686 +Node: Statements/Lines90771 +Ref: Statements/Lines-Footnote-195233 +Node: Other Features95498 +Node: When96426 +Node: Invoking Gawk98573 +Node: Command Line99958 +Node: Options100741 +Ref: Options-Footnote-1115098 +Node: Other Arguments115123 +Node: Naming Standard Input117781 +Node: Environment Variables118875 +Node: AWKPATH Variable119319 +Ref: AWKPATH Variable-Footnote-1121916 +Node: Other Environment Variables122176 +Node: Exit Status124668 +Node: Include Files125343 +Node: Obsolete128828 +Node: Undocumented129514 +Node: Regexp129755 +Node: Regexp Usage131144 +Node: Escape Sequences133170 +Node: Regexp Operators138933 +Ref: Regexp Operators-Footnote-1146313 +Ref: Regexp Operators-Footnote-2146460 +Node: Bracket Expressions146558 +Ref: table-char-classes148448 +Node: GNU Regexp Operators150971 +Node: Case-sensitivity154694 +Ref: Case-sensitivity-Footnote-1157662 +Ref: Case-sensitivity-Footnote-2157897 +Node: Leftmost Longest158005 +Node: Computed Regexps159206 +Node: Reading Files162616 +Node: Records164620 +Ref: Records-Footnote-1173294 +Node: Fields173331 +Ref: Fields-Footnote-1176364 +Node: Nonconstant Fields176450 +Node: Changing Fields178652 +Node: Field Separators184633 +Node: Default Field Splitting187262 +Node: Regexp Field Splitting188379 +Node: Single Character Fields191721 +Node: Command Line Field Separator192780 +Node: Field Splitting Summary196221 +Ref: Field Splitting Summary-Footnote-1199413 +Node: Constant Size199514 +Node: Splitting By Content204098 +Ref: Splitting By Content-Footnote-1207824 +Node: Multiple Line207864 +Ref: Multiple Line-Footnote-1213711 +Node: Getline213890 +Node: Plain Getline216106 +Node: Getline/Variable218195 +Node: Getline/File219336 +Node: Getline/Variable/File220658 +Ref: Getline/Variable/File-Footnote-1222257 +Node: Getline/Pipe222344 +Node: Getline/Variable/Pipe224904 +Node: Getline/Coprocess226011 +Node: Getline/Variable/Coprocess227254 +Node: Getline Notes227968 +Node: Getline Summary229910 +Ref: table-getline-variants230253 +Node: Read Timeout231109 +Ref: Read Timeout-Footnote-1234854 +Node: Command line directories234911 +Node: Printing235541 +Node: Print237172 +Node: Print Examples238509 +Node: Output Separators241293 +Node: OFMT243053 +Node: Printf244411 +Node: Basic Printf245317 +Node: Control Letters246856 +Node: Format Modifiers250668 +Node: Printf Examples256677 +Node: Redirection259392 +Node: Special Files266376 +Node: Special FD266909 +Ref: Special FD-Footnote-1270534 +Node: Special Network270608 +Node: Special Caveats271458 +Node: Close Files And Pipes272254 +Ref: Close Files And Pipes-Footnote-1279277 +Ref: Close Files And Pipes-Footnote-2279425 +Node: Expressions279575 +Node: Values280707 +Node: Constants281383 +Node: Scalar Constants282063 +Ref: Scalar Constants-Footnote-1282922 +Node: Nondecimal-numbers283104 +Node: Regexp Constants286163 +Node: Using Constant Regexps286638 +Node: Variables289693 +Node: Using Variables290348 +Node: Assignment Options292072 +Node: Conversion293944 +Ref: table-locale-affects299320 +Ref: Conversion-Footnote-1299944 +Node: All Operators300053 +Node: Arithmetic Ops300683 +Node: Concatenation303188 +Ref: Concatenation-Footnote-1305981 +Node: Assignment Ops306101 +Ref: table-assign-ops311089 +Node: Increment Ops312497 +Node: Truth Values and Conditions315967 +Node: Truth Values317050 +Node: Typing and Comparison318099 +Node: Variable Typing318888 +Ref: Variable Typing-Footnote-1322785 +Node: Comparison Operators322907 +Ref: table-relational-ops323317 +Node: POSIX String Comparison326866 +Ref: POSIX String Comparison-Footnote-1327822 +Node: Boolean Ops327960 +Ref: Boolean Ops-Footnote-1332038 +Node: Conditional Exp332129 +Node: Function Calls333861 +Node: Precedence337455 +Node: Locales341124 +Node: Patterns and Actions342213 +Node: Pattern Overview343267 +Node: Regexp Patterns344936 +Node: Expression Patterns345479 +Node: Ranges349164 +Node: BEGIN/END352130 +Node: Using BEGIN/END352892 +Ref: Using BEGIN/END-Footnote-1355623 +Node: I/O And BEGIN/END355729 +Node: BEGINFILE/ENDFILE358011 +Node: Empty360904 +Node: Using Shell Variables361220 +Node: Action Overview363505 +Node: Statements365862 +Node: If Statement367716 +Node: While Statement369215 +Node: Do Statement371259 +Node: For Statement372415 +Node: Switch Statement375567 +Node: Break Statement377664 +Node: Continue Statement379654 +Node: Next Statement381447 +Node: Nextfile Statement383837 +Node: Exit Statement386382 +Node: Built-in Variables388798 +Node: User-modified389893 +Ref: User-modified-Footnote-1398248 +Node: Auto-set398310 +Ref: Auto-set-Footnote-1408156 +Node: ARGC and ARGV408361 +Node: Arrays412212 +Node: Array Basics413717 +Node: Array Intro414543 +Node: Reference to Elements418861 +Node: Assigning Elements421131 +Node: Array Example421622 +Node: Scanning an Array423354 +Node: Controlling Scanning425668 +Ref: Controlling Scanning-Footnote-1430601 +Node: Delete430917 +Ref: Delete-Footnote-1433352 +Node: Numeric Array Subscripts433409 +Node: Uninitialized Subscripts435592 +Node: Multi-dimensional437220 +Node: Multi-scanning440314 +Node: Arrays of Arrays441905 +Node: Functions446550 +Node: Built-in447372 +Node: Calling Built-in448450 +Node: Numeric Functions450438 +Ref: Numeric Functions-Footnote-1454270 +Ref: Numeric Functions-Footnote-2454627 +Ref: Numeric Functions-Footnote-3454675 +Node: String Functions454944 +Ref: String Functions-Footnote-1478441 +Ref: String Functions-Footnote-2478570 +Ref: String Functions-Footnote-3478818 +Node: Gory Details478905 +Ref: table-sub-escapes480584 +Ref: table-sub-posix-92481938 +Ref: table-sub-proposed483281 +Ref: table-posix-sub484631 +Ref: table-gensub-escapes486177 +Ref: Gory Details-Footnote-1487384 +Ref: Gory Details-Footnote-2487435 +Node: I/O Functions487586 +Ref: I/O Functions-Footnote-1494241 +Node: Time Functions494388 +Ref: Time Functions-Footnote-1505280 +Ref: Time Functions-Footnote-2505348 +Ref: Time Functions-Footnote-3505506 +Ref: Time Functions-Footnote-4505617 +Ref: Time Functions-Footnote-5505729 +Ref: Time Functions-Footnote-6505956 +Node: Bitwise Functions506222 +Ref: table-bitwise-ops506780 +Ref: Bitwise Functions-Footnote-1510940 +Node: Type Functions511124 +Node: I18N Functions511594 +Node: User-defined513221 +Node: Definition Syntax514025 +Ref: Definition Syntax-Footnote-1518935 +Node: Function Example519004 +Node: Function Caveats521598 +Node: Calling A Function522019 +Node: Variable Scope523134 +Node: Pass By Value/Reference525109 +Node: Return Statement528549 +Node: Dynamic Typing531530 +Node: Indirect Calls532265 +Node: Internationalization541950 +Node: I18N and L10N543389 +Node: Explaining gettext544075 +Ref: Explaining gettext-Footnote-1549141 +Ref: Explaining gettext-Footnote-2549325 +Node: Programmer i18n549490 +Node: Translator i18n553690 +Node: String Extraction554483 +Ref: String Extraction-Footnote-1555444 +Node: Printf Ordering555530 +Ref: Printf Ordering-Footnote-1558314 +Node: I18N Portability558378 +Ref: I18N Portability-Footnote-1560827 +Node: I18N Example560890 +Ref: I18N Example-Footnote-1563525 +Node: Gawk I18N563597 +Node: Arbitrary Precision Arithmetic564214 +Ref: Arbitrary Precision Arithmetic-Footnote-1567089 +Node: Floating-point Programming567237 +Node: Floating-point Representation572507 +Node: Floating-point Context573611 +Ref: table-ieee-formats574446 +Node: Rounding Mode575816 +Ref: table-rounding-modes576443 +Ref: Rounding Mode-Footnote-1579566 +Node: Arbitrary Precision Floats579747 +Ref: Arbitrary Precision Floats-Footnote-1581788 +Node: Setting Precision582099 +Node: Setting Rounding Mode584857 +Node: Floating-point Constants585774 +Node: Changing Precision587193 +Ref: Changing Precision-Footnote-1588593 +Node: Exact Arithmetic588766 +Node: Integer Programming591779 +Node: Arbitrary Precision Integers593559 +Ref: Arbitrary Precision Integers-Footnote-1596583 +Node: MPFR and GMP Libraries596729 +Node: Advanced Features597114 +Node: Nondecimal Data598637 +Node: Array Sorting600220 +Node: Controlling Array Traversal600917 +Node: Array Sorting Functions609154 +Ref: Array Sorting Functions-Footnote-1612828 +Ref: Array Sorting Functions-Footnote-2612921 +Node: Two-way I/O613115 +Ref: Two-way I/O-Footnote-1618547 +Node: TCP/IP Networking618617 +Node: Profiling621461 +Node: Library Functions628915 +Ref: Library Functions-Footnote-1631922 +Node: Library Names632093 +Ref: Library Names-Footnote-1635564 +Ref: Library Names-Footnote-2635784 +Node: General Functions635870 +Node: Strtonum Function636823 +Node: Assert Function639753 +Node: Round Function643079 +Node: Cliff Random Function644622 +Node: Ordinal Functions645638 +Ref: Ordinal Functions-Footnote-1648708 +Ref: Ordinal Functions-Footnote-2648960 +Node: Join Function649169 +Ref: Join Function-Footnote-1650940 +Node: Gettimeofday Function651140 +Node: Data File Management654855 +Node: Filetrans Function655487 +Node: Rewind Function659626 +Node: File Checking661013 +Node: Empty Files662107 +Node: Ignoring Assigns664337 +Node: Getopt Function665890 +Ref: Getopt Function-Footnote-1677194 +Node: Passwd Functions677397 +Ref: Passwd Functions-Footnote-1686372 +Node: Group Functions686460 +Node: Walking Arrays694544 +Node: Sample Programs696113 +Node: Running Examples696778 +Node: Clones697506 +Node: Cut Program698730 +Node: Egrep Program708575 +Ref: Egrep Program-Footnote-1716348 +Node: Id Program716458 +Node: Split Program720074 +Ref: Split Program-Footnote-1723593 +Node: Tee Program723721 +Node: Uniq Program726524 +Node: Wc Program733953 +Ref: Wc Program-Footnote-1738219 +Ref: Wc Program-Footnote-2738419 +Node: Miscellaneous Programs738511 +Node: Dupword Program739699 +Node: Alarm Program741730 +Node: Translate Program746479 +Ref: Translate Program-Footnote-1750866 +Ref: Translate Program-Footnote-2751094 +Node: Labels Program751228 +Ref: Labels Program-Footnote-1754599 +Node: Word Sorting754683 +Node: History Sorting758567 +Node: Extract Program760406 +Ref: Extract Program-Footnote-1767889 +Node: Simple Sed768017 +Node: Igawk Program771079 +Ref: Igawk Program-Footnote-1786236 +Ref: Igawk Program-Footnote-2786437 +Node: Anagram Program786575 +Node: Signature Program789643 +Node: Debugger790743 +Node: Debugging791695 +Node: Debugging Concepts792128 +Node: Debugging Terms793984 +Node: Awk Debugging796581 +Node: Sample Debugging Session797473 +Node: Debugger Invocation797993 +Node: Finding The Bug799322 +Node: List of Debugger Commands805810 +Node: Breakpoint Control807144 +Node: Debugger Execution Control810808 +Node: Viewing And Changing Data814168 +Node: Execution Stack817524 +Node: Debugger Info818991 +Node: Miscellaneous Debugger Commands822972 +Node: Readline Support828417 +Node: Limitations829248 +Node: Language History831500 +Node: V7/SVR3.1833012 +Node: SVR4835333 +Node: POSIX836775 +Node: BTL837783 +Node: POSIX/GNU838517 +Node: Common Extensions843668 +Node: Ranges and Locales844775 +Ref: Ranges and Locales-Footnote-1849379 +Node: Contributors849600 +Node: Installation853861 +Node: Gawk Distribution854755 +Node: Getting855239 +Node: Extracting856065 +Node: Distribution contents857757 +Node: Unix Installation862979 +Node: Quick Installation863596 +Node: Additional Configuration Options865558 +Node: Configuration Philosophy867035 +Node: Non-Unix Installation869377 +Node: PC Installation869835 +Node: PC Binary Installation871134 +Node: PC Compiling872982 +Node: PC Testing875926 +Node: PC Using877102 +Node: Cygwin881287 +Node: MSYS882287 +Node: VMS Installation882801 +Node: VMS Compilation883404 +Ref: VMS Compilation-Footnote-1884411 +Node: VMS Installation Details884469 +Node: VMS Running886104 +Node: VMS Old Gawk887711 +Node: Bugs888185 +Node: Other Versions892037 +Node: Notes897352 +Node: Compatibility Mode898044 +Node: Additions898827 +Node: Accessing The Source899639 +Node: Adding Code901064 +Node: New Ports907031 +Node: Dynamic Extensions911144 +Node: Internals912584 +Node: Plugin License921103 +Node: Loading Extensions921741 +Node: Sample Library923551 +Node: Internal File Description924241 +Node: Internal File Ops927956 +Ref: Internal File Ops-Footnote-1932680 +Node: Using Internal File Ops932820 +Node: Future Extensions935197 +Node: Basic Concepts937701 +Node: Basic High Level938458 +Ref: Basic High Level-Footnote-1942493 +Node: Basic Data Typing942678 +Node: Floating Point Issues947203 +Node: String Conversion Precision948286 +Ref: String Conversion Precision-Footnote-1949986 +Node: Unexpected Results950095 +Node: POSIX Floating Point Problems951921 +Ref: POSIX Floating Point Problems-Footnote-1955626 +Node: Glossary955664 +Node: Copying980640 +Node: GNU Free Documentation License1018197 +Node: Index1043334 End Tag Table diff --git a/doc/gawk.texi b/doc/gawk.texi index 0946f888..8cd7e38e 100644 --- a/doc/gawk.texi +++ b/doc/gawk.texi @@ -79,9 +79,11 @@ @c some special symbols @iftex @set LEQ @math{@leq} +@set PI @math{@pi} @end iftex @ifnottex @set LEQ <= +@set PI @i{pi} @end ifnottex @ifnottex @@ -285,6 +287,8 @@ particular records in a file and perform operations upon them. * Functions:: Built-in and user-defined functions. * Internationalization:: Getting @command{gawk} to speak your language. +* Arbitrary Precision Arithmetic:: Arbitrary precision arithmetic with + @command{gawk}. * Advanced Features:: Stuff for advanced users, specific to @command{gawk}. * Library Functions:: A Library of @command{awk} Functions. @@ -551,6 +555,21 @@ particular records in a file and perform operations upon them. * I18N Portability:: @command{awk}-level portability issues. * I18N Example:: A simple i18n example. * Gawk I18N:: @command{gawk} is also internationalized. +* Floating-point Programming:: Effective floating-point programming. +* Floating-point Representation:: Binary floating-point representation. +* Floating-point Context:: Floating-point context. +* Rounding Mode:: Floating-point rounding mode. +* Arbitrary Precision Floats:: Arbitrary precision floating-point + arithmetic with @command{gawk}. +* Setting Precision:: Setting the working precision. +* Setting Rounding Mode:: Setting the rounding mode. +* Floating-point Constants:: Representing floating-point constants. +* Changing Precision:: Changing the precision of a number. +* Exact Arithmetic:: Exact arithmetic with floating-point numbers. +* Integer Programming:: Effective integer programming. +* Arbitrary Precision Integers:: Arbitrary precision integer + arithmetic with @command{gawk}. +* MPFR and GMP Libraries:: Information about the MPFR and GMP libraries. * Nondecimal Data:: Allowing nondecimal input data. * Array Sorting:: Facilities for controlling array traversal and sorting arrays. @@ -1595,10 +1614,13 @@ has been and continues to be a pleasure working with this team of fine people. John Haque contributed the modifications to convert @command{gawk} -into a byte-code interpreter, including the debugger. Stephen Davies +into a byte-code interpreter, including the debugger, and the +additional modifications for support of arbitrary precision arithmetic. +Stephen Davies contributed to the effort to bring the byte-code changes into the mainstream code base. Efraim Yawitz contributed the initial text of @ref{Debugger}. +John Haque contributed the initial text of @ref{Arbitrary Precision Arithmetic}. @cindex Kernighan, Brian I would like to thank Brian Kernighan for invaluable assistance during the @@ -3214,6 +3236,14 @@ when eliminating problems pointed out by @option{--lint}, you should take care to search for all occurrences of each inappropriate construct. As @command{awk} programs are usually short, doing so is not burdensome. +@item -M +@itemx --bignum +@cindex @code{-M} option +@cindex @code{--bignum} option +Force arbitrary precision arithmetic on numbers. This option has no effect +if @command{gawk} is not compiled to use the GNU MPFR and MP libraries +(@pxref{Arbitrary Precision Arithmetic}). + @item -n @itemx --non-decimal-data @cindex @code{-n} option @@ -12606,6 +12636,18 @@ This is the output record separator. It is output at the end of every @code{print} statement. Its default value is @code{"\n"}, the newline character. (@xref{Output Separators}.) +@cindex @code{PREC} variable +@item PREC # +The working precision of arbitrary precision floating-point numbers, +53 by default (@pxref{Setting Precision}). + +@cindex @code{ROUNDMODE} variable +@item ROUNDMODE # +The rounding mode to use for arbitrary precision arithmetic on +numbers, by default @code{"N"} (@samp{roundTiesToEven} in +the IEEE-754 standard) +(@pxref{Setting Rounding Mode}). + @cindex @code{RS} variable @cindex separators, for records @cindex record separators @@ -12889,6 +12931,25 @@ The value of the @code{getuid()} system call. The version of @command{gawk}. @end table +The following additional elements in the array +are available to provide information about the MPFR and GMP libraries +if your version of @command{gawk} supports arbitrary precision numbers +(@pxref{Arbitrary Precision Arithmetic}): + +@table @code +@item PROCINFO["mpfr_version"] +The version of the GNU MPFR library. + +@item PROCINFO["gmp_version"] +The version of the GNU MP library. + +@item PROCINFO["prec_max"] +The maximum precision supported by MPFR. + +@item PROCINFO["prec_min"] +The minimum precision required by MPFR. +@end table + On some systems, there may be elements in the array, @code{"group1"} through @code{"group@var{N}"} for some @var{N}. @var{N} is the number of supplementary groups that the process has. Use the @code{in} operator @@ -18307,6 +18368,863 @@ then @command{gawk} produces usage messages, warnings, and fatal errors in the local language. @c ENDOFRANGE inloc +@node Arbitrary Precision Arithmetic +@chapter Arbitrary Precision Arithmetic with @command{gawk} +@cindex arbitrary precision +@cindex multiple precision +@cindex infinite precision +@cindex floating-point numbers, arbitrary precision +@cindex MPFR +@cindex GMP + +@cindex Knuth, Donald +@quotation +@i{There's a credibility gap: We don't know how much of the computer's answers +to believe. Novice computer users solve this problem by implicitly trusting +in the computer as an infallible authority; they tend to believe that all +digits of a printed answer are significant. Disillusioned computer users have +just the opposite approach; they are constantly afraid that their answers +are almost meaningless.} + +Donald Knuth@footnote{Donald E.@: Knuth. +@cite{The Art of Computer Programming}. Volume 2, +@cite{Seminumerical Algorithms}, third edition, +1998, ISBN 0-201-89683-4, p.@: 229.} +@end quotation + +This @value{SECTION} decsribes how to use the arbitrary precision +(also known as @dfn{multiple precision} or @dfn{infinite precision}) numeric +capabilites in @command{gawk} to produce maximally accurate results +when you need it. But first you should check if your version of +@command{gawk} supports arbitrary precision arithmetic. +The easiest way to find out is to look at the output of +the following command: + +@example +$ @kbd{gawk --version} +@print{} GNU Awk 4.1.0 (GNU MPFR 3.1.0, GNU MP 5.0.3) +@print{} Copyright (C) 1989, 1991-2012 Free Software Foundation. +@dots{} +@end example + +@command{gawk} uses the +@uref{http://www.mpfr.org, GNU MPFR} +and +@uref{http://gmplib.org, GNU MP} (GMP) +libraries for arbitrary precision +arithmetic on numbers. So if you do not see the names of these libraries +in the output, then your version of @command{gawk} does not support +arbitrary precision arithmetic. + +Even if you aren't interested in arbitrary precision arithmetic, you +may still benifit from knowing about how @command{gawk} handles numbers +in general, and the limitations of doing arithmetic with ordinary +@command{gawk} numbers. + +@menu +* Floating-point Programming:: Effective Floating-point Programming. +* Floating-point Representation:: Binary Floating-point Representation. +* Floating-point Context:: Floating-point Context. +* Rounding Mode:: Floating-point Rounding Mode. +* Arbitrary Precision Floats:: Arbitrary Precision Floating-point + Arithmetic with @command{gawk}. +* Setting Precision:: Setting the Working Precision. +* Setting Rounding Mode:: Setting the Rounding Mode. +* Floating-point Constants:: Representing Floating-point Constants. +* Changing Precision:: Changing the Precision of a Number. +* Exact Arithmetic:: Exact Arithmetic with Floating-point Numbers. +* Integer Programming:: Effective Integer Programming. +* Arbitrary Precision Integers:: Arbitrary Precision Integer + Arithmetic with @command{gawk}. +* MPFR and GMP Libraries:: Information About the MPFR and GMP Libraries. +@end menu + +@node Floating-point Programming +@section Effective Floating-point Programming + +Numerical programming is an extensive area; if you need to develop +sophisticated numerical algorithms then @command{gawk} may not be +the ideal tool, and this documentation may not be sufficient. +@c FIXME: JOHN: Do you want to cite some actual books? +It might require a book or two to communicate how to compute +with ideal accuracy and precision +and the result often depends on the particular application. + +@quotation NOTE +A floating-point calculation's @dfn{accuracy} is how close it comes +to the real value. This is as opposed to the @dfn{precision}, which +usually refers to the number of bits used to represent the number +(see @uref{http://en.wikipedia.org/wiki/Accuracy_and_precision, +the Wikipedia article} for more information). +@end quotation + +Binary floating-point representations and arithmetic are inexact. +Simple values like 0.1 cannot be precisely represented using +binary floating-point numbers, and the limited precision of +floating-point numbers means that slight changes in +the order of operations or the precision of intermediate storage +can change the result. To make matters worse with arbitrary precision +floating-point, you can set the precision before starting a computation, +but then you cannot be sure of the number of significant decimal places +in the final result. + +Sometimes you need to think more about what you really want +and what's really happening. Consider the two numbers +in the following example: + +@example +x = 0.875 # 1/2 + 1/4 + 1/8 +y = 0.425 +@end example + +Unlike the number in @code{y}, the number stored in @code{x} +is exactly representable +in binary since it can be written as a finite sum of one or +more fractions whose denominators are all powers of two. +When @command{gawk} reads a floating-point number from +program source, it automatically rounds that number to whatever +precision your machine supports. If you try to print the numeric +content of a variable using an output format string of @code{"%.17g"}, +it may not produce the same number as you assigned to it: + +@example +$ @kbd{gawk 'BEGIN @{ x = 0.875; y = 0.425} +> @kbd{ printf("%0.17g, %0.17g\n", x, y) @}'} +@print{} 0.875, 0.42499999999999999 +@end example + +Often the error is so small you do not even notice it, and if you do, +you can always specify how much precision you would like in your output. +Usually this is a format string like @code{"%.15g"}, which when +used in the previous example, produces an output identical to the input. + +Because the underlying representation can be little bit off from the exact value, +comparing floats to see if they are equal is generally not a good idea. +Here is an example where it does not work like you expect: + +@example +$ @kbd{gawk 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'} +@print{} 0 +@end example + +The loss of accuracy during a single computation with floating-point numbers +usually isn't enough to worry about. However, if you compute a value +which is the result of a sequence of floating point operations, +the error can accumulate and greatly affect the computation itself. +Here is an attempt to compute the value of the constant +@value{PI} using one of its many series representations: + +@example +BEGIN @{ + x = 1.0 / sqrt(3.0) + n = 6 + for (i = 1; i < 30; i++) @{ + n = n * 2.0 + x = (sqrt(x * x + 1) - 1) / x + printf("%.15f\n", n * x) + @} +@} +@end example + +When run, the early errors propagating through later computations +cause the loop to terminate prematurely after an attempt to divide by zero. + +@example +$ @kbd{gawk -f pi.awk} +@print{} 3.215390309173475 +@print{} 3.159659942097510 +@print{} 3.146086215131467 +@print{} 3.142714599645573 +@dots{} +@print{} 3.224515243534819 +@print{} 2.791117213058638 +@print{} 0.000000000000000 +@error{} gawk: pi.awk:6: fatal: division by zero attempted +@end example + +Here is one more example where the inaccuracies in internal representations +yield an unexpected result: + +@example +$ @kbd{gawk 'BEGIN @{} +> @kbd{for (d = 1.1; d <= 1.5; d += 0.1)} +> @kbd{i++} +> @kbd{print i} +> @kbd{@}'} +@print{} 4 +@end example + +Can computation using aribitrary precision help with the previous examples? +If you are impatient to know, see +@ref{Exact Arithmetic}. + +Instead of aribitrary precision floating-point arithmetic, +often all you need is an adjustment of your logic +or a different order for the operations in your calculation. +The stability and the accuracy of the computation of the constant @value{PI} +in the previous example can be enhanced by using the following +simple algebraic transformation: + +@example +(sqrt(x * x + 1) - 1) / x = x / (sqrt(x * x + 1) + x) +@end example + +There is no need to be unduly suspicious about the results from +floating-point arithmetic. The lesson to remember is that +floating-point math is always more complex than the math using +pencil and paper. In order to take advantage of the power +of computer floating-point, you need to know its limitations +and work within them. For most casual use of floating-point arithmetic, +you will often get the expected result in the end if you simply round +the display of your final results to the correct number of significant +decimal digits. Avoid presenting numerical data in a manner that +implies better precision than is actually the case. + +@node Floating-point Representation +@section Binary Floating-point Representation +@cindex IEEE-754 format + +Although floating-point representations vary from machine to machine, +the most commonly encountered representation is that defined by the +IEEE 754 Standard. An IEEE-754 format value has three components: + +@itemize @bullet +@item +a sign bit telling whether the number is positive or negative, + +@item +an @dfn{exponent} giving its order of magnitude, @var{e}, + +@item +and a @dfn{significand}, @var{s}, +specifying the actual digits of the number. +@end itemize + +The value of the +number is then +@iftex +@math{s @cdot 2^e}. +@end iftex +@ifnottex +@var{s * 2^e}. +@end ifnottex +The first bit of a non-zero binary significand +is always one, so the significand in an IEEE-754 format only includes the +fractional part, leaving the leading one implicit. + +Three of the standard IEEE-754 types are 32-bit single precision, +64-bit double precision and 128-bit quadruple precision. +The standard also specifies extended precision formats +to allow greater precisions and larger exponent ranges. + +@node Floating-point Context +@section Floating-point Context +@cindex context, floating-point + +A floating-point context defines the environment for arithmetic operations. +It governs precision, sets rules for rounding and limits range for exponents. +The context has the following primary components: + +@table @code +@item precision +Precision of the floating-point format in bits. +@item emax +Maximum exponent allowed for this format. +@item emin +Minimum exponent allowed for this format. +@item underflow behavior +The format may or may not support gradual underflow. +@item rounding +The rounding mode of this context. +@end table + +@ref{table-ieee-formats} lists the precision and exponent +field values for the basic IEEE-754 binary formats: + +@float Table,table-ieee-formats +@caption{Basic IEEE Formats} +@multitable @columnfractions .20 .20 .20 .20 .20 +@headitem Name @tab Total bits @tab Precision @tab emin @tab emax +@item Single @tab 32 @tab 24 @tab @minus{}126 @tab +127 +@item Double @tab 64 @tab 53 @tab @minus{}1022 @tab +1023 +@item Quadruple @tab 128 @tab 113 @tab @minus{}16382 @tab +16383 +@end multitable +@end float + +@quotation NOTE +The precision numbers include the implied leading one that gives them +one extra bit of significand. +@end quotation + +A floating-point context can also determine which signals are treated +as exceptions, and can set rules for arithmetic with special values. +Please consult the IEEE-754 standard or other resources for details. + +@command{gawk} ordinarily uses the hardware double precision +representation for numbers. On most systems, this is IEEE-754 +floating-point format, corresponding to 64-bit binary with 53 bits +of precision. + +@quotation NOTE +In case an underflow occurs, the standard allows, but does not require, +the result from an arithmetic operation to be a number smaller than +the smallest nonzero normalized number. Such numbers do +not have as many significant digits as normal numbers, and are called +@dfn{denormals} or @dfn{subnormals}. The alternative, simply returning a zero, +is called @dfn{flush to zero}. The basic IEEE-754 binary formats +support subnormal numbers. +@end quotation + +@node Rounding Mode +@section Floating-point Rounding Mode +@cindex rounding mode, floating-point + +The @dfn{rounding mode} specifies the behavior for the results of numerical +operations when discarding extra precision. Each rounding mode indicates +how the least significant returned digit of a rounded result is to +be calculated. +The @code{ROUNDMODE} variable (@pxref{Setting Rounding Mode}) provides +program level control over the rounding mode. +@ref{table-rounding-modes} lists the IEEE-754 defined +rounding modes: + +@float Table,table-rounding-modes +@caption{Rounding Modes} +@multitable @columnfractions .45 .30 .25 +@headitem Rounding Mode @tab IEEE Name @tab @code{ROUNDMODE} +@item Round to nearest, ties to even @tab @code{roundTiesToEven} @tab @code{"N"} or @code{"n"} +@item Round toward plus Infinity @tab @code{roundTowardPositive} @tab @code{"U"} or @code{"u"} +@item Round toward negative Infinity @tab @code{roundTowardNegative} @tab @code{"D"} or @code{"d"} +@item Round toward zero @tab @code{roundTowardZero} @tab @code{"Z"} or @code{"z"} +@item Round to nearest, ties away from zero @tab @code{roundTiesToAway} @tab @code{"A"} or @code{"a"} +@end multitable +@end float + +The default mode @samp{roundTiesToEven} is the most preferred, +but the least intuitive. This method does the obvious thing for most values, +by rounding them up or down to the nearest digit. +For example, rounding 1.132 to two digits yields 1.13, +and rounding 1.157 yields 1.16. + +However, when it comes to rounding a value that is exactly halfway between, +things do not work the way you probably learned in school. +In this case, the number is rounded to the nearest even digit. +So rounding 0.125 to two digits rounds down to 0.12, +but rounding 0.6875 to three digits rounds up to 0.688. +You probably have already encountered this rounding mode when +using the @code{printf} routine to format floating-point numbers. +For example: + +@example +BEGIN @{ + x = -4.5 + for (i = 1; i < 10; i++) @{ + x += 1.0 + printf("%4.1f => %2.0f\n", x, x) + @} +@} +@end example + +@noindent +produces the following output when run@footnote{It +is possible for the output to be completely different if the +C library in your system does not use the IEEE-754 even-rounding +rule to round halfway cases for @code{printf()}.}: + +@example +-3.5 => -4 +-2.5 => -2 +-1.5 => -2 +-0.5 => 0 + 0.5 => 0 + 1.5 => 2 + 2.5 => 2 + 3.5 => 4 + 4.5 => 4 +@end example + +The theory behind the rounding mode @samp{roundTiesToEven} is that +it more or less evenly distributes upward and downward rounds +of exact halves, which might cause the round-off error +to cancel itself out. This is the default rounding mode used +in IEEE-754 computing functions and operators. + +The other rounding modes are rarely used. +Round toward positive infinity (@samp{roundTowardPositive}) +and round toward negative infinity (@samp{roundTowardNegative}) +are often used to implement interval arithmetic, +where you adjust the rounding mode to calculate upper and lower bounds +for the range of output. The @samp{roundTowardZero} +mode can be used for converting floating-point numbers to integers. +The rounding mode @samp{roundTiesToAway} rounds the result to the +nearest number and selects the number with the larger magnitude +if a tie occurs. + +Some numerical analysts will tell you that your choice of rounding style +has tremendous impact on the final outcome, and advise you to wait until +final output for any rounding. Instead, you can often achieve this goal by +setting the precision initially to some value sufficiently larger than +the final desired precision, so that the accumulation of round-off error +does not influence the outcome. +If you suspect that results from your computation are +sensitive to accumulation of round-off error, +one way to be sure is to look for a significant difference in output +when you change the rounding mode. + +@node Arbitrary Precision Floats +@section Arbitrary Precision Floating-point Arithmetic with @command{gawk} + +@command{gawk} uses the GNU MPFR library +for arbitrary precision floating-point arithmetic. The MPFR library +provides precise control over precisions and rounding modes, and gives +correctly rounded reproducible platform-independent results. With the +command-line option @option{--bignum} or @option{-M}, +all floating-point arithmetic operators and numeric functions can yield +results to any desired precision level supported by MPFR. +Two built-in +variables @code{PREC} +(@pxref{Setting Precision}) +and @code{ROUNDMODE} +(@pxref{Setting Rounding Mode}) +provide control over the working precision and the rounding mode. +The precision and the rounding mode are set globally for every operation +to follow. + +The default working precision for arbitrary precision floats is 53, +and the default value for @code{ROUNDMODE} is @code{"N"}, +which selects the IEEE-754 +@samp{roundTiesToEven} (@pxref{Rounding Mode}) rounding mode.@footnote{The +default precision is 53, since according to the MPFR documentation, +the library should be able to exactly reproduce all computations with +double-precision machine floating-point numbers (@code{double} type +in C), except the default exponent range is much wider and subnormal +numbers are not implemented.} +@command{gawk} uses the default exponent range in MPFR +@iftex +(@math{emax = 2^{30} - 1, emin = -emax}) +@end iftex +@ifnottex +(@var{emax} = 2^30 @minus{} 1, @var{emin} = @minus{}@var{emax}) +@end ifnottex +for all floating-point contexts. +There is no explicit mechanism to adjust the exponent range. +MPFR does not implement subnormal numbers by default, +and this behavior cannot be changed in @command{gawk}. + +@quotation NOTE +When emulating an IEEE-754 format (@pxref{Setting Precision}), +@command{gawk} internally adjusts the exponent range +to the value defined for the format and also performs computations needed for +gradual underflow (subnormal numbers). +@end quotation + +@quotation NOTE +MPFR numbers are variable-size entities, consuming only as much space as +needed to store the significant digits. Since the performance using MPFR +numbers pales in comparison to doing math using the underlying machine +types, you should consider using only as much precision as needed by +your program. +@end quotation + +@node Setting Precision +@section Setting the Working Precision +@cindex @code{PREC} variable + +@command{gawk} uses a global working precision; it does not keep track of +the precision or accuracy of individual numbers. Performing an arithmetic +operation or calling a built-in function rounds the result to the current +working precision. The default working precision is 53 which can be +modified using the built-in variable @code{PREC}. You can also set the +value to one of the following pre-defined case-insensitive strings +to emulate an IEEE-754 binary format: + +@multitable {@code{"double"}} {12345678901234567890123456789012345} +@headitem @code{PREC} @tab IEEE-754 Binary Format +@item @code{"half"} @tab 16-bit half-precision. +@item @code{"single"} @tab Basic 32-bit single precision. +@item @code{"double"} @tab Basic 64-bit double precision. +@item @code{"quad"} @tab Basic 128-bit quadruple precision. +@item @code{"oct"} @tab 256-bit octuple precision. +@end multitable + +The following example illustrates the effects of changing precision +on arithmetic operations: + +@example +$ @kbd{gawk -M -vPREC=100 'BEGIN @{ x = 1.0e-400; print x + 0; \} +> @kbd{PREC = "double"; print x + 0 @}'} +@print{} 1e-400 +@print{} 0 +@end example + +Binary and decimal precisions are related approximately according to the +formula: + +@iftex +@math{prec = 3.322 @cdot dps} +@end iftex +@ifnottex +@var{prec} = 3.322 * @var{dps} +@end ifnottex + +@noindent +Here, @var{prec} denotes the binary precision +(measured in bits) and @var{dps} (short for decimal places) +is the decimal digits. We can easily calculate how many decimal +digits the 53-bit significand of an IEEE double is equivalent to: +53 / 3.332 which is equal to about 15.95. +But what does 15.95 digits actually mean? It depends whether you are +concerned about how many digits you can rely on, or how many digits +you need. + +It is important to know how many bits it takes to uniquely identify +a double-precision value (the C type @code{double}). If you want to +convert from @code{double} to decimal and back to @code{double} (e.g., +saving a @code{double} representing an intermediate result to a file, and +later reading it back to restart the computation), then a few more decimal +digits are required. 17 digits is generally enough for a @code{double}. + +It can also be important to know what decimal numbers can be uniquely +represented with a @code{double}. If you want to convert +from decimal to @code{double} and back again, 15 digits is the most that +you can get. Stated differently, you should not present +the numbers from your floating-point computations with more than 15 +significant digits in them. + +Conversely, it takes a precision of 332 bits to hold an approximation +of constant @value{PI} that is accurate to 100 decimal places. +You should always add some extra bits in order to avoid the confusing round-off +issues that occur because numbers are stored internally in binary. + +@node Setting Rounding Mode +@section Setting the Rounding Mode +@cindex @code{ROUNDMODE} variable + +The built-in variable @code{ROUNDMODE} has the default value @code{"N"}, +which selects the IEEE-754 rounding mode @samp{roundTiesToEven}. +The other possible values for @code{ROUNDMODE} are @code{"U"} for rounding mode +@samp{roundTowardPositive}, @code{"D"} for @samp{roundTowardNegative}, +and @code{"Z"} for @samp{roundTowardZero}. +@command{gawk} also accepts @code{"A"} to select the IEEE-754 mode +@samp{roundTiesToAway} +if your version of the MPFR library supports it; otherwise setting +@code{ROUNDMODE} to this value has no effect. @xref{Rounding Mode}, +for the meanings of the various rounding modes. + +Here is an example of how to change the default rounding behavior of +@code{printf}'s output: + +@example +$ @kbd{gawk -M -vROUNDMODE="Z" 'BEGIN @{ printf("%.2f\n", 1.378) @}'} +@print{} 1.37 +@end example + +@node Floating-point Constants +@section Representing Floating-point Constants +@cindex constants, floating-point + +Be wary of floating-point constants! When reading a floating-point constant +from program source code, @command{gawk} uses the default precision, +unless overridden +by an assignment to the special variable @code{PREC} on the command +line, to store it internally as a MPFR number. +Changing the precision using @code{PREC} in the program text does +not change the precision of a constant. If you need to +represent a floating-point constant at a higher precision than the +default and cannot use a command line assignment to @code{PREC}, +you should either specify the constant as a string, or +a rational number whenever possible. The following example +illustrates the differences among various ways to +print a floating-point constant: + +@example +$ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", 0.1) @}'} +@print{} 0.1000000000000000055511151 +$ @kbd{gawk -M -vPREC = 113 'BEGIN @{ printf("%0.25f\n", 0.1) @}'} +@print{} 0.1000000000000000000000000 +$ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", "0.1") @}'} +@print{} 0.1000000000000000000000000 +$ @kbd{gawk -M 'BEGIN @{ PREC = 113; printf("%0.25f\n", 1/10) @}'} +@print{} 0.1000000000000000000000000 +@end example + +In the first case, the number is stored with the default precision of 53. + +@node Changing Precision +@section Changing the Precision of a Number + +@cindex Laurie, Dirk +@quotation +@i{The point is that in any variable-precision package, +a decision is made on how to treat numbers given as data, +or arising in intermediate results, which are represented in +floating-point format to a precision lower than working precision. +Do we promote them to full membership of the high-precision club, +or do we treat them and all their associates as second-class citizens? +Sometimes the first course is proper, sometimes the second, and it takes +careful analysis to tell which.} + +Dirk Laurie@footnote{Dirk Laurie. +@cite{Variable-precision Arithmetic Considered Perilous -- A Detective Story}. +Electronic Transactions on Numerical Analysis. Volume 28, pp. 168-173, 2008.} +@end quotation + +@command{gawk} does not implicitly modify the precision of any previously +computed results when the working precision is changed with an assignment +to @code{PREC}. The precision of a number is always the one that was +used at the time of its creation, and there is no way for the user +to explicitly change it afterwards. However, since the result of a +floating-point arithmetic operation is always an arbitrary precision +floating-point value---with a precision set by the value of @code{PREC}---one of the +following workarounds effectively accomplishes the desired behavior: + +@example +x = x + 0.0 +@end example + +@noindent +or: + +@example +x += 0.0 +@end example + +@node Exact Arithmetic +@section Exact Arithmetic with Floating-point Numbers + +@quotation CAUTION +Never depend on the exactness of floating-point arithmetic, +even for apparently simple expressions! +@end quotation + +Can arbitrary precision arithmetic give exact results? There are +no easy answers. The standard rules of algebra often do not apply +when using floating-point arithmetic. +Among other things, the distributive and associative laws +do not hold completely, and order of operation may be important +for your computation. Rounding error, cumulative precision loss +and underflow are often troublesome. + +When @command{gawk} tests the expressions @samp{0.1 + 12.2} and @samp{12.3} +for equality +using the machine double precision arithmetic, it decides that they +are not equal! +(@xref{Floating-point Programming}.) +You can get the result you want by increasing the precision; +56 in this case will get the job done: + +@example +$ @kbd{gawk -M -vPREC=56 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'} +@print{} 1 +@end example + +If adding more bits is good, perhaps adding even more bits of +precision is better? +Here is what happens if we use an even larger value of @code{PREC}: + +@example +$ @kbd{gawk -M -vPREC=201 'BEGIN @{ print (0.1 + 12.2 == 12.3) @}'} +@print{} 0 +@end example + +This is not a bug in @command{gawk} or in the MPFR library. +It is easy to forget that the finite number of bits used to store the value +is often just an approximation after proper rounding. +The test for equality succeeds if and only if @emph{all} bits in the two operands +are exactly the same. Since this is not necessarily true after floating-point +computations with a particular precision and effective rounding rule, +a straight test for equality may not work. + +So, don't assume that floating-point values can be compared for equality. +You should also exercise caution when using other forms of comparisons. +The standard way to compare between floating-point numbers is to determine +how much error (or @dfn{tolerance}) you will allow in a comparison and +check to see if one value is within this error range of the other. + +In applications where 15 or fewer decimal places suffice, +hardware double precision arithmetic can be adequate, and is usually much faster. +But you do need to keep in mind that every floating-point operation +can suffer a new rounding error with catastrophic consequences as illustrated +by our attempt to compute the value of the constant @value{PI}, +(@pxref{Floating-point Programming}). +Extra precision can greatly enhance the stability and the accuracy +of your computation in such cases. + +Repeated addition is not necessarily equivalent to multiplication +in floating-point arithmetic. In the last example +(@pxref{Floating-point Programming}), +you may or may not succeed in getting the correct result by choosing +an arbitrarily large value for @code{PREC}. Reformulation of +the problem at hand is often the correct approach in such situations. + + +@node Integer Programming +@section Effective Integer Programming + +As has been mentioned already, @command{gawk} ordinarily uses hardware double +precision with 64-bit IEEE binary floating-point representation +for numbers on most systems. A large integer like 9007199254740997 +has a binary representation that, although finite, is more than 53 bits long; +it must also be rounded to 53 bits. +The biggest integer that can be stored in a C @code{double} is usually the same +as the largest possible value of a @code{double}. If your system @code{double} +is an IEEE 64-bit @code{double}, this largest possible value is an integer and +can be represented precisely. What more should one know about integers? + +If you want to know what is the largest integer, such that it and +all smaller integers can be stored in 64-bit doubles without losing precision, +then the answer is +@iftex +@math{2^{53}}. +@end iftex +@ifnottex +2^53. +@end ifnottex +The next representable number is the even number +@iftex +@math{2^{53} + 2}, +@end iftex +@ifnottex +2^53 + 2, +@end ifnottex +meaning it is unlikely that you will be able to make +@command{gawk} print +@iftex +@math{2^{53} + 1} +@end iftex +@ifnottex +2^53 + 1 +@end ifnottex +in integer format. +The range of integers exactly representable by a 64-bit double +is +@iftex +@math{[-2^{53}, 2^{53}]}. +@end iftex +@ifnottex +[@minus{}2^53, 2^53]. +@end ifnottex +If you ever see an integer outside this range in @command{gawk} +using 64-bit doubles, you have reason to be very suspicious about +the accuracy of the output. Here is a simple program with erroneous output: + +@example +$ @kbd{gawk 'BEGIN @{ i = 2^53 - 1; for (j = 0; j < 4; j++) print i + j @}'} +@print{} 9007199254740991 +@print{} 9007199254740992 +@print{} 9007199254740992 +@print{} 9007199254740994 +@end example + +The lesson is to not assume that any large integer printed by @command{gawk} +represents an exact result from your computation, especially if it wraps +around on your screen. + +@node Arbitrary Precision Integers +@section Arbitrary Precision Integer Arithmetic with @command{gawk} +@cindex integer, arbitrary precision + +If the option @option{--bignum} or @option{-M} is specified, +@command{gawk} performs all +integer arithmetic using GMP arbitrary precision integers. +Any number that looks like an integer in a program source or data file +is stored as an arbitrary precision integer. +The size of the integer is limited only by your computer's memory. +The current floating-point context has no effect on operations involving integers. +For example, the following computes +@iftex +@math{5^{4^{3^{2}}}}, +@end iftex +@ifnottex +5^4^3^2, +@end ifnottex +the result of which is beyond the +limits of ordinary @command{gawk} numbers: + +@example +$ @kbd{gawk -M 'BEGIN @{} +> @kbd{x = 5^4^3^2} +> @kbd{print "# of digits =", length(x)} +> @kbd{print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20)} +> @kbd{@}'} +@print{} # of digits = 183231 +@print{} 62060698786608744707 ... 92256259918212890625 +@end example + +If you were to compute the same value using arbitrary precision +floating-point values instead, the precision needed for correct output +(using the formula +@iftex +@math{prec = 3.322 @cdot dps}), +would be @math{3.322 @cdot 183231}, +@end iftex +@ifnottex +@samp{prec = 3.322 * dps}), +would be 3.322 x 183231, +@end ifnottex +or 608693. + +The result from an arithmetic operation with an integer and a floating-point value +is a floating-point value with a precision equal to the working precision. +The following program calculates the eighth term in +Sylvester's sequence@footnote{Weisstein, Eric W. +@cite{Sylvester's Sequence}. From MathWorld--A Wolfram Web Resource. +@url{http://mathworld.wolfram.com/SylvestersSequence.html}} +using a recurrence: + +@example +$ @kbd{gawk -M 'BEGIN @{} +> @kbd{s = 2.0} +> @kbd{for (i = 1; i <= 7; i++)} +> @kbd{s = s * (s - 1) + 1} +> @kbd{print s} +> @kbd{@}'} +@print{} 113423713055421845118910464 +@end example + +The output differs from the acutal number, 113423713055421844361000443, +because the default precision of 53 is not enough to represent the +floating-point results exactly. You can either increase the precision +(100 is enough in this case), or replace the floating-point constant +@code{2.0} with an integer, to perform all computations using integer +arithmetic to get the correct output. + +It will sometimes be necessary for @command{gawk} to implicitly convert an +arbitrary precision integer into an arbitrary precision floating-point value. +This is primarily because the MPFR library does not always provide the +relevant interface to process arbitrary precision integers or mixed-mode +numbers as needed by an operation or function. +In such a case, the precision is set to the minimum value necessary +for exact conversion, and the working precision is not used for this purpose. +If this is not what you need or want, you can employ a subterfuge +like this: + +@example +gawk -M 'BEGIN @{ n = 13; print (n + 0.0) % 2.0 @}' +@end example + +You can avoid this issue altogether by specifying the number as a float +to begin with: + +@example +gawk -M 'BEGIN @{ n = 13.0; print n % 2.0 @}' +@end example + +Note that for the particular example above, there is unlikely to be a +reason for simply not using the following: + +@example +gawk -M 'BEGIN @{ n = 13; print n % 2 @}' +@end example + + +@node MPFR and GMP Libraries +@section Information About the MPFR and GMP Libraries + +There are a few elements available in the @code{PROCINFO} array +to provide information about the MPFR and GMP libraries. +@xref{Auto-set}, for more information. + @node Advanced Features @chapter Advanced Features of @command{gawk} @cindex advanced features, network connections, See Also networks, connections @@ -36,9 +36,11 @@ IOBUF *curfile = NULL; /* current data file */ int exiting = FALSE; int (*interpret)(INSTRUCTION *); +#define MAX_EXEC_HOOKS 10 +static int num_exec_hook = 0; +static Func_pre_exec pre_execute[MAX_EXEC_HOOKS]; +static Func_post_exec post_execute = NULL; -extern int pre_execute(INSTRUCTION **); -extern void post_execute(INSTRUCTION *); extern void frame_popped(); #if __GNUC__ < 2 @@ -437,6 +439,8 @@ flags2str(int flagval) { NUMINT, "NUMINT" }, { INTIND, "INTIND" }, { WSTRCUR, "WSTRCUR" }, + { MPFN, "MPFN" }, + { MPZN, "MPZN" }, { ARRAYMAXED, "ARRAYMAXED" }, { HALFHAT, "HALFHAT" }, { XARRAY, "XARRAY" }, @@ -563,6 +567,7 @@ posix_compare(NODE *s1, NODE *s2) return ret; } + /* cmp_nodes --- compare two nodes, returning negative, 0, positive */ int @@ -582,21 +587,13 @@ cmp_nodes(NODE *t1, NODE *t2) if (t1->flags & INTIND) t1 = force_string(t1); if (t2->flags & INTIND) - t2 = force_string(t2); - - if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) { - if (t1->numbr == t2->numbr) - ret = 0; - /* don't subtract, in case one or both are infinite */ - else if (t1->numbr < t2->numbr) - ret = -1; - else - ret = 1; - return ret; - } + t2 = force_string(t2); - t1 = force_string(t1); - t2 = force_string(t2); + if ((t1->flags & NUMBER) && (t2->flags & NUMBER)) + return cmp_numbers(t1, t2); + + (void) force_string(t1); + (void) force_string(t2); len1 = t1->stlen; len2 = t2->stlen; ldiff = len1 - len2; @@ -700,6 +697,7 @@ void set_IGNORECASE() { static short warned = FALSE; + NODE *n = IGNORECASE_node->var_value; if ((do_lint || do_traditional) && ! warned) { warned = TRUE; @@ -708,17 +706,19 @@ set_IGNORECASE() load_casetable(); if (do_traditional) IGNORECASE = FALSE; - else if ((IGNORECASE_node->var_value->flags & (STRING|STRCUR)) != 0) { - if ((IGNORECASE_node->var_value->flags & MAYBE_NUM) == 0) { - IGNORECASE_node->var_value = force_string(IGNORECASE_node->var_value); - IGNORECASE = (IGNORECASE_node->var_value->stlen > 0); - } else - IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); - } else if ((IGNORECASE_node->var_value->flags & (NUMCUR|NUMBER)) != 0) - IGNORECASE = (force_number(IGNORECASE_node->var_value) != 0.0); + else if ((n->flags & (STRING|STRCUR)) != 0) { + if ((n->flags & MAYBE_NUM) == 0) { + (void) force_string(n); + IGNORECASE = (n->stlen > 0); + } else { + (void) force_number(n); + IGNORECASE = ! iszero(n); + } + } else if ((n->flags & (NUMCUR|NUMBER)) != 0) + IGNORECASE = ! iszero(n); else IGNORECASE = FALSE; /* shouldn't happen */ - + set_RS(); /* set_RS() calls set_FS() if need be, for us */ } @@ -729,7 +729,7 @@ set_BINMODE() { static short warned = FALSE; char *p; - NODE *v; + NODE *v = BINMODE_node->var_value; if ((do_lint || do_traditional) && ! warned) { warned = TRUE; @@ -737,16 +737,15 @@ set_BINMODE() } if (do_traditional) BINMODE = 0; - else if ((BINMODE_node->var_value->flags & NUMBER) != 0) { - BINMODE = (int) force_number(BINMODE_node->var_value); + else if ((v->flags & NUMBER) != 0) { + (void) force_number(v); + BINMODE = get_number_si(v); /* Make sure the value is rational. */ if (BINMODE < 0) BINMODE = 0; else if (BINMODE > 3) BINMODE = 3; - } - else if ((BINMODE_node->var_value->flags & STRING) != 0) { - v = BINMODE_node->var_value; + } else if ((v->flags & STRING) != 0) { p = v->stptr; /* @@ -795,8 +794,7 @@ set_BINMODE() break; } } - } - else + } else BINMODE = 3; /* shouldn't happen */ } @@ -922,16 +920,16 @@ set_LINT() { #ifndef NO_LINT int old_lint = do_lint; + NODE *n = LINT_node->var_value; - if ((LINT_node->var_value->flags & (STRING|STRCUR)) != 0) { - if ((LINT_node->var_value->flags & MAYBE_NUM) == 0) { + if ((n->flags & (STRING|STRCUR)) != 0) { + if ((n->flags & MAYBE_NUM) == 0) { const char *lintval; size_t lintlen; - NODE *tmp; - tmp = LINT_node->var_value = force_string(LINT_node->var_value); - lintval = tmp->stptr; - lintlen = tmp->stlen; + n = force_string(LINT_node->var_value); + lintval = n->stptr; + lintlen = n->stlen; if (lintlen > 0) { do_flags |= DO_LINT_ALL; if (lintlen == 5 && strncmp(lintval, "fatal", 5) == 0) @@ -946,14 +944,16 @@ set_LINT() lintfunc = warning; } } else { - if (force_number(LINT_node->var_value) != 0.0) + (void) force_number(n); + if (! iszero(n)) do_flags |= DO_LINT_ALL; else do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); lintfunc = warning; } - } else if ((LINT_node->var_value->flags & (NUMCUR|NUMBER)) != 0) { - if (force_number(LINT_node->var_value) != 0.0) + } else if ((n->flags & (NUMCUR|NUMBER)) != 0) { + (void) force_number(n); + if (! iszero(n)) do_flags |= DO_LINT_ALL; else do_flags &= ~(DO_LINT_ALL|DO_LINT_INVALID); @@ -1017,9 +1017,14 @@ update_ERRNO() 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((AWKNUM) NR); + NR_node->var_value = make_number(NR); } } @@ -1028,11 +1033,14 @@ update_NR() void update_NF() { - if (NF == -1 || NF_node->var_value->numbr != NF) { + long l; + + l = get_number_si(NF_node->var_value); + if (NF == -1 || l != NF) { if (NF == -1) (void) get_field(UNLIMITED - 1, NULL); /* parse record */ unref(NF_node->var_value); - NF_node->var_value = make_number((AWKNUM) NF); + NF_node->var_value = make_number(NF); } } @@ -1041,9 +1049,14 @@ 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((AWKNUM) FNR); + FNR_node->var_value = make_number(FNR); } } @@ -1141,7 +1154,9 @@ r_get_field(NODE *n, Func_ptr *assign, int reference) } } - field_num = (long) force_number(n); + (void) force_number(n); + field_num = get_number_si(n); + if (field_num < 0) fatal(_("attempt to access field %ld"), field_num); @@ -1398,7 +1413,8 @@ free_arrayfor(NODE *r) } -/* unwind_stack --- pop items off the run-time stack; +/* + * unwind_stack --- pop items off the run-time stack; * 'n' is the # of items left in the stack. */ @@ -1459,14 +1475,6 @@ unwind_stack(long n) #define pop_stack() (void) unwind_stack(0) -/* - * This generated compiler warnings from GCC 4.4. Who knows why. - * -#define eval_condition(t) (((t)->flags & MAYBE_NUM) && force_number(t), \ - ((t)->flags & NUMBER) ? ((t)->numbr != 0.0) : ((t)->stlen != 0)) -*/ - - static inline int eval_condition(NODE *t) { @@ -1480,15 +1488,15 @@ eval_condition(NODE *t) force_number(t); if ((t->flags & NUMBER) != 0) - return (t->numbr != 0.0); + return ! iszero(t); return (t->stlen != 0); } -/* cmp_scalar -- compare two nodes on the stack */ +/* cmp_scalars -- compare two nodes on the stack */ static inline int -cmp_scalar() +cmp_scalars() { NODE *t1, *t2; int di; @@ -1505,20 +1513,22 @@ cmp_scalar() return di; } - /* op_assign --- assignment operators excluding = */ static void op_assign(OPCODE op) { NODE **lhs; - NODE *t1; + NODE *t1, *t2; AWKNUM x = 0.0, x1, x2; lhs = POP_ADDRESS(); t1 = *lhs; - x1 = force_number(t1); - TOP_NUMBER(x2); + x1 = force_number(t1)->numbr; + + t2 = TOP_SCALAR(); + x2 = force_number(t2)->numbr; + DEREF(t2); switch (op) { case Op_assign_plus: @@ -1568,7 +1578,6 @@ op_assign(OPCODE op) REPLACE(t1); } - /* PUSH_CODE --- push a code onto the runtime stack */ void @@ -1595,7 +1604,8 @@ POP_CODE() } -/* Implementation of BEGINFILE and ENDFILE requires saving an execution +/* + * Implementation of BEGINFILE and ENDFILE requires saving an execution * state and the ability to return to that state. The state is * defined by the instruction triggering the BEGINFILE/ENDFILE rule, the * run-time stack, the rule and the source file. The source line is available in @@ -1663,6 +1673,56 @@ pop_exec_state(int *rule, char **src, long *sz) return cp; } + +/* register_exec_hook --- add exec hooks in the interpreter. */ + +int +register_exec_hook(Func_pre_exec preh, Func_post_exec posth) +{ + int pos = 0; + + /* + * multiple post-exec hooks aren't supported. post-exec hook is mainly + * for use by the debugger. + */ + + if (! preh || (post_execute && posth)) + return FALSE; + + if (num_exec_hook == MAX_EXEC_HOOKS) + return FALSE; + + /* + * Add to the beginning of the array but do not displace the + * debugger hook if it exists. + */ + if (num_exec_hook > 0) { + pos = !! do_debug; + if (num_exec_hook > pos) + memmove(pre_execute + pos + 1, pre_execute + pos, + (num_exec_hook - pos) * sizeof (preh)); + } + pre_execute[pos] = preh; + num_exec_hook++; + + if (posth) + post_execute = posth; + + return TRUE; +} + + +/* interpreter routine when not debugging */ +#include "interpret.h" + +/* interpreter routine with exec hook(s). Used when debugging and/or with MPFR. */ +#define r_interpret h_interpret +#define EXEC_HOOK 1 +#include "interpret.h" +#undef EXEC_HOOK +#undef r_interpret + + void init_interpret() { @@ -1684,26 +1744,22 @@ init_interpret() frame_ptr->vname = NULL; /* initialize TRUE and FALSE nodes */ - node_Boolean[FALSE] = make_number(0); - node_Boolean[FALSE]->flags |= NUMINT; + node_Boolean[FALSE] = make_number(0.0); node_Boolean[TRUE] = make_number(1.0); - node_Boolean[TRUE]->flags |= NUMINT; + if (! is_mpg_number(node_Boolean[FALSE])) { + node_Boolean[FALSE]->flags |= NUMINT; + node_Boolean[TRUE]->flags |= NUMINT; + } - /* select the interpreter routine */ - if (do_debug) - interpret = debug_interpret; + /* + * Select the interpreter routine. The version without + * any exec hook support (r_interpret) is faster by about + * 5%, or more depending on the opcodes. + */ + + if (num_exec_hook > 0) + interpret = h_interpret; else - interpret = r_interpret; + interpret = r_interpret; } - -/* interpreter routine when not debugging */ -#include "interpret.h" - -/* interpreter routine when deubugging with gawk --debug */ -#define r_interpret debug_interpret -#define DEBUGGING 1 -#include "interpret.h" -#undef DEBUGGING -#undef r_interpret - @@ -85,7 +85,6 @@ load_ext(const char *lib_name, const char *init_func, NODE *obj) if (gpl_compat == NULL) fatal(_("extension: library `%s': does not define `plugin_is_GPL_compatible' (%s)\n"), lib_name, dlerror()); - func = (NODE *(*)(NODE *, void *)) dlsym(dl, init_func); if (func == NULL) fatal(_("extension: library `%s': cannot call function `%s' (%s)\n"), @@ -194,24 +194,34 @@ rebuild_record() * so that unrefing a field doesn't try to unref into the old $0. */ for (cops = ops, i = 1; i <= NF; i++) { - if (fields_arr[i]->stlen > 0) { + NODE *r = fields_arr[i]; + if (r->stlen > 0) { NODE *n; getnode(n); - if ((fields_arr[i]->flags & FIELD) == 0) { + if ((r->flags & FIELD) == 0) { *n = *Null_field; - n->stlen = fields_arr[i]->stlen; - if ((fields_arr[i]->flags & (NUMCUR|NUMBER)) != 0) { - n->flags |= (fields_arr[i]->flags & (NUMCUR|NUMBER)); - n->numbr = fields_arr[i]->numbr; + 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; } } else { - *n = *(fields_arr[i]); + *n = *r; n->flags &= ~(MALLOC|STRING); } n->stptr = cops; - unref(fields_arr[i]); + unref(r); fields_arr[i] = n; assert((n->flags & WSTRCUR) == 0); } @@ -323,7 +333,8 @@ set_NF() assert(NF != -1); - nf = (long) force_number(NF_node->var_value); + (void) force_number(NF_node->var_value); + nf = get_number_si(NF_node->var_value); if (nf < 0) fatal(_("NF set to negative value")); NF = nf; diff --git a/int_array.c b/int_array.c index 9dd20bea..0fa37642 100644 --- a/int_array.c +++ b/int_array.c @@ -40,10 +40,6 @@ static NODE **int_list(NODE *symbol, NODE *t); static NODE **int_copy(NODE *symbol, NODE *newsymb); static NODE **int_dump(NODE *symbol, NODE *ndump); -#ifdef ARRAYDEBUG -static NODE **int_option(NODE *opt, NODE *val); -#endif - static uint32_t int_hash(uint32_t k, uint32_t hsize); static inline NODE **int_find(NODE *symbol, long k, uint32_t hash1); static NODE **int_insert(NODE *symbol, long k, uint32_t hash1); @@ -59,9 +55,6 @@ array_ptr int_array_func[] = { int_list, int_copy, int_dump, -#ifdef ARRAYDEBUG - int_option, -#endif }; @@ -86,7 +79,7 @@ is_integer(NODE *symbol, NODE *subs) long l; AWKNUM d; - if (subs == Nnull_string) + if (subs == Nnull_string || do_mpfr) return NULL; if ((subs->flags & NUMINT) != 0) @@ -804,25 +797,3 @@ grow_int_table(NODE *symbol) } efree(old); } - - -#ifdef ARRAYDEBUG - -static NODE ** -int_option(NODE *opt, NODE *val) -{ - int newval; - NODE *tmp; - NODE **ret = (NODE **) ! NULL; - - tmp = force_string(opt); - (void) force_number(val); - if (strcmp(tmp->stptr, "INT_CHAIN_MAX") == 0) { - newval = (int) val->numbr; - if (newval > 0) - INT_CHAIN_MAX = newval; - } else - ret = NULL; - return ret; -} -#endif diff --git a/interpret.h b/interpret.h index 67a702e3..009e6e10 100644 --- a/interpret.h +++ b/interpret.h @@ -1,37 +1,48 @@ /* - * interpret: - * code is a list of instructions to run. returns the exit value - * from the awk code. + * interpret.h --- run a list of instructions. */ - - /* N.B.: - * 1) reference counting done for both number and string values. - * 2) Stack operations: - * Use REPLACE[_XX] if last stack operation was TOP[_XX], - * PUSH[_XX] if last operation was POP[_XX] instead. - * 3) UPREF and DREF -- see awk.h + +/* + * Copyright (C) 1986, 1988, 1989, 1991-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 */ + int r_interpret(INSTRUCTION *code) { INSTRUCTION *pc; /* current instruction */ + OPCODE op; /* current opcode */ NODE *r = NULL; NODE *m; INSTRUCTION *ni; NODE *t1, *t2; - NODE *f; /* function definition */ NODE **lhs; - AWKNUM x, x1, x2; + AWKNUM x, x2; int di; Regexp *rp; - int stdio_problem = FALSE; /* array subscript */ #define mk_sub(n) (n == 1 ? POP_SCALAR() : concat_exp(n, TRUE)) -#ifdef DEBUGGING -#define JUMPTO(x) do { post_execute(pc); pc = (x); goto top; } while (FALSE) +#ifdef EXEC_HOOK +#define JUMPTO(x) do { if (post_execute) post_execute(pc); pc = (x); goto top; } while (FALSE) #else #define JUMPTO(x) do { pc = (x); goto top; } while (FALSE) #endif @@ -51,12 +62,14 @@ top: if (pc->source_line > 0) sourceline = pc->source_line; -#ifdef DEBUGGING - if (! pre_execute(&pc)) - goto top; +#ifdef EXEC_HOOK + for (di = 0; di < num_exec_hook; di++) { + if (! pre_execute[di](& pc)) + goto top; + } #endif - switch (pc->opcode) { + switch ((op = pc->opcode)) { case Op_rule: currule = pc->in_rule; /* for sole use in Op_K_next, Op_K_nextfile, Op_K_getline */ /* fall through */ @@ -65,6 +78,9 @@ top: break; case Op_atexit: + { + int stdio_problem = FALSE; + /* avoid false source indications */ source = NULL; sourceline = 0; @@ -87,6 +103,7 @@ top: */ if (stdio_problem && ! exiting && exit_val == 0) exit_val = 1; + } break; case Op_stop: @@ -147,7 +164,7 @@ top: break; case Node_var_array: - if (pc->opcode == Op_push_arg) + if (op == Op_push_arg) PUSH(m); else fatal(_("attempt to use array `%s' in a scalar context"), @@ -303,8 +320,7 @@ top: t1 = POP_SCALAR(); di = eval_condition(t1); DEREF(t1); - if ((pc->opcode == Op_and && di) - || (pc->opcode == Op_or && ! di)) + if ((op == Op_and && di) || (op == Op_or && ! di)) break; r = node_Boolean[di]; UPREF(r); @@ -330,164 +346,175 @@ top: break; case Op_equal: - r = node_Boolean[cmp_scalar() == 0]; + r = node_Boolean[cmp_scalars() == 0]; UPREF(r); REPLACE(r); break; case Op_notequal: - r = node_Boolean[cmp_scalar() != 0]; + r = node_Boolean[cmp_scalars() != 0]; UPREF(r); REPLACE(r); break; case Op_less: - r = node_Boolean[cmp_scalar() < 0]; + r = node_Boolean[cmp_scalars() < 0]; UPREF(r); REPLACE(r); break; case Op_greater: - r = node_Boolean[cmp_scalar() > 0]; + r = node_Boolean[cmp_scalars() > 0]; UPREF(r); REPLACE(r); break; case Op_leq: - r = node_Boolean[cmp_scalar() <= 0]; + r = node_Boolean[cmp_scalars() <= 0]; UPREF(r); REPLACE(r); break; case Op_geq: - r = node_Boolean[cmp_scalar() >= 0]; + r = node_Boolean[cmp_scalars() >= 0]; UPREF(r); REPLACE(r); break; case Op_plus_i: - x2 = force_number(pc->memory); + x2 = force_number(pc->memory)->numbr; goto plus; - case Op_plus: - POP_NUMBER(x2); + t2 = POP_NUMBER(); + x2 = t2->numbr; + DEREF(t2); plus: - TOP_NUMBER(x1); - r = make_number(x1 + x2); + t1 = TOP_NUMBER(); + r = make_number(t1->numbr + x2); + DEREF(t1); REPLACE(r); break; case Op_minus_i: - x2 = force_number(pc->memory); + x2 = force_number(pc->memory)->numbr; goto minus; - case Op_minus: - POP_NUMBER(x2); + t2 = POP_NUMBER(); + x2 = t2->numbr; + DEREF(t2); minus: - TOP_NUMBER(x1); - r = make_number(x1 - x2); + t1 = TOP_NUMBER(); + r = make_number(t1->numbr - x2); + DEREF(t1); REPLACE(r); break; case Op_times_i: - x2 = force_number(pc->memory); + x2 = force_number(pc->memory)->numbr; goto times; - case Op_times: - POP_NUMBER(x2); + t2 = POP_NUMBER(); + x2 = t2->numbr; + DEREF(t2); times: - TOP_NUMBER(x1); - r = make_number(x1 * x2); + t1 = TOP_NUMBER(); + r = make_number(t1->numbr * x2); + DEREF(t1); REPLACE(r); break; case Op_exp_i: - x2 = force_number(pc->memory); - goto exponent; - + x2 = force_number(pc->memory)->numbr; + goto exp; case Op_exp: - POP_NUMBER(x2); -exponent: - TOP_NUMBER(x1); - x = calc_exp(x1, x2); - r = make_number(x); + t2 = POP_NUMBER(); + x2 = t2->numbr; + DEREF(t2); +exp: + t1 = TOP_NUMBER(); + r = make_number(calc_exp(t1->numbr, x2)); + DEREF(t1); REPLACE(r); break; case Op_quotient_i: - x2 = force_number(pc->memory); + x2 = force_number(pc->memory)->numbr; goto quotient; - case Op_quotient: - POP_NUMBER(x2); + t2 = POP_NUMBER(); + x2 = t2->numbr; + DEREF(t2); quotient: + t1 = TOP_NUMBER(); if (x2 == 0) fatal(_("division by zero attempted")); - - TOP_NUMBER(x1); - x = x1 / x2; - r = make_number(x); + r = make_number(t1->numbr / x2); + DEREF(t1); REPLACE(r); break; case Op_mod_i: - x2 = force_number(pc->memory); + x2 = force_number(pc->memory)->numbr; goto mod; - case Op_mod: - POP_NUMBER(x2); + t2 = POP_NUMBER(); + x2 = t2->numbr; + DEREF(t2); mod: + t1 = TOP_NUMBER(); if (x2 == 0) fatal(_("division by zero attempted in `%%'")); - - TOP_NUMBER(x1); #ifdef HAVE_FMOD - x = fmod(x1, x2); + x = fmod(t1->numbr, x2); #else /* ! HAVE_FMOD */ - (void) modf(x1 / x2, &x); - x = x1 - x * x2; + (void) modf(t1->numbr / x2, &x); + x = t1->numbr - x * x2; #endif /* ! HAVE_FMOD */ r = make_number(x); + + DEREF(t1); REPLACE(r); - break; + break; case Op_preincrement: case Op_predecrement: - x2 = pc->opcode == Op_preincrement ? 1.0 : -1.0; + x = op == Op_preincrement ? 1.0 : -1.0; lhs = TOP_ADDRESS(); t1 = *lhs; - x1 = force_number(t1); + force_number(t1); if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) { /* optimization */ - t1->numbr = x1 + x2; + t1->numbr += x; + r = t1; } else { + r = *lhs = make_number(t1->numbr + x); unref(t1); - t1 = *lhs = make_number(x1 + x2); } - UPREF(t1); - REPLACE(t1); + UPREF(r); + REPLACE(r); break; case Op_postincrement: case Op_postdecrement: - x2 = pc->opcode == Op_postincrement ? 1.0 : -1.0; + x = op == Op_postincrement ? 1.0 : -1.0; lhs = TOP_ADDRESS(); t1 = *lhs; - x1 = force_number(t1); + force_number(t1); + r = make_number(t1->numbr); if (t1->valref == 1 && t1->flags == (MALLOC|NUMCUR|NUMBER)) { - /* optimization */ - t1->numbr = x1 + x2; + /* optimization */ + t1->numbr += x; } else { + *lhs = make_number(t1->numbr + x); unref(t1); - *lhs = make_number(x1 + x2); } - r = make_number(x1); REPLACE(r); break; case Op_unary_minus: - TOP_NUMBER(x1); - r = make_number(-x1); + t1 = TOP_NUMBER(); + r = make_number(-t1->numbr); + DEREF(t1); REPLACE(r); break; @@ -532,7 +559,7 @@ mod: Func_ptr assign; t1 = TOP_SCALAR(); - lhs = r_get_field(t1, &assign, FALSE); + lhs = r_get_field(t1, & assign, FALSE); decr_sp(); DEREF(t1); unref(*lhs); @@ -555,7 +582,7 @@ mod: *lhs = dupnode(t1); } - if (t1 != t2 && t1->valref == 1) { + if (t1 != t2 && t1->valref == 1 && (t1->flags & MPFN) == 0) { size_t nlen = t1->stlen + t2->stlen; erealloc(t1->stptr, char *, nlen + 2, "r_interpret"); @@ -592,7 +619,7 @@ mod: case Op_assign_quotient: case Op_assign_mod: case Op_assign_exp: - op_assign(pc->opcode); + op_assign(op); break; case Op_var_update: /* update value of NR, FNR or NF */ @@ -601,8 +628,9 @@ mod: case Op_var_assign: case Op_field_assign: + r = TOP(); if (pc->assign_ctxt == Op_sub_builtin - && TOP()->numbr == 0.0 /* top of stack has a number == 0 */ + && get_number_si(r) == 0 /* top of stack has a number == 0 */ ) { /* There wasn't any substitutions. If the target is a FIELD, * this means no field re-splitting or $0 reconstruction. @@ -612,14 +640,14 @@ mod: break; } else if ((pc->assign_ctxt == Op_K_getline || pc->assign_ctxt == Op_K_getline_redir) - && TOP()->numbr <= 0.0 /* top of stack has a number <= 0 */ + && get_number_si(r) <= 0 /* top of stack has a number <= 0 */ ) { /* getline returned EOF or error */ break; } - if (pc->opcode == Op_var_assign) + if (op == Op_var_assign) pc->assign_var(); else pc->field_assign(); @@ -649,7 +677,6 @@ mod: if (di) { /* match found */ - t2 = POP_SCALAR(); DEREF(t2); JUMPTO(pc->target_jmp); @@ -671,9 +698,10 @@ mod: case Op_in_array: t1 = POP_ARRAY(); t2 = mk_sub(pc->expr_count); - di = (in_array(t1, t2) != NULL); + r = node_Boolean[(in_array(t1, t2) != NULL)]; DEREF(t2); - PUSH(make_number((AWKNUM) di)); + UPREF(r); + PUSH(r); break; case Op_arrayfor_init: @@ -816,8 +844,8 @@ match_re: di = research(rp, t1->stptr, 0, t1->stlen, avoid_dfa(m, t1->stptr, t1->stlen)); - di = (di == -1) ^ (pc->opcode != Op_nomatch); - if(pc->opcode != Op_match_rec) { + di = (di == -1) ^ (op != Op_nomatch); + if (op != Op_match_rec) { decr_sp(); DEREF(t1); } @@ -842,9 +870,9 @@ match_re: case Op_indirect_func_call: { + NODE *f = NULL; int arg_count; - f = NULL; arg_count = (pc + 1)->expr_count; t1 = PEEK(arg_count); /* indirect var */ assert(t1->type == Node_val); /* @a[1](p) not allowed in grammar */ @@ -855,7 +883,8 @@ match_re: if (f != NULL && strcmp(f->vname, t1->stptr) == 0) { /* indirect var hasn't been reassigned */ - goto func_call; + ni = setup_frame(pc); + JUMPTO(ni); /* Op_func */ } f = lookup(t1->stptr); } @@ -865,10 +894,14 @@ match_re: pc->func_name); pc->func_body = f; /* save for next call */ - goto func_call; + ni = setup_frame(pc); + JUMPTO(ni); /* Op_func */ } case Op_func_call: + { + NODE *f; + /* retrieve function definition node */ f = pc->func_body; if (f == NULL) { @@ -894,11 +927,9 @@ match_re: JUMPTO(ni); } -func_call: ni = setup_frame(pc); - - /* run the function instructions */ - JUMPTO(ni); /* Op_func */ + JUMPTO(ni); /* Op_func */ + } case Op_K_return: m = POP_SCALAR(); /* return value */ @@ -1074,8 +1105,9 @@ func_call: fatal(_("`exit' cannot be called in the current context")); exiting = TRUE; - POP_NUMBER(x1); - exit_val = (int) x1; + t1 = POP_NUMBER(); + exit_val = (int) get_number_si(t1); + DEREF(t1); #ifdef VMS if (exit_val == 0) exit_val = EXIT_SUCCESS; @@ -1171,7 +1203,7 @@ func_call: break; default: - fatal(_("Sorry, don't know how to interpret `%s'"), opcode2str(pc->opcode)); + fatal(_("Sorry, don't know how to interpret `%s'"), opcode2str(op)); } JUMPTO(pc->nexti); @@ -1184,4 +1216,3 @@ func_call: #undef mk_sub #undef JUMPTO } - @@ -132,6 +132,14 @@ #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 make the code a bit clearer: */ @@ -233,6 +241,7 @@ extern NODE *ARGIND_node; extern NODE *ERRNO_node; extern NODE **fields_arr; +/* init_io --- set up timeout related variables */ void init_io() @@ -340,6 +349,7 @@ nextfile(IOBUF **curfile, int skipping) int fd = INVALID_HANDLE; int errcode; IOBUF *iop = *curfile; + long argc; if (skipping) { /* for 'nextfile' call */ errcode = 0; @@ -361,7 +371,9 @@ nextfile(IOBUF **curfile, int skipping) return 0; } - for (; i < (long) (ARGC_node->lnode->numbr); i++) { + argc = get_number_si(ARGC_node->var_value); + + for (; i < argc; i++) { tmp = make_number((AWKNUM) i); (void) force_string(tmp); arg = in_array(ARGV_node, tmp); @@ -387,6 +399,10 @@ nextfile(IOBUF **curfile, int skipping) /* This is a kludge. */ 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; iop = *curfile = iop_alloc(fd, fname, &mybuf, FALSE); if (fd == INVALID_HANDLE) @@ -432,7 +448,14 @@ nextfile(IOBUF **curfile, int skipping) void set_FNR() { - FNR = (long) FNR_node->var_value->numbr; + 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); } /* set_NR --- update internal NR from awk variable */ @@ -440,7 +463,14 @@ set_FNR() void set_NR() { - NR = (long) NR_node->var_value->numbr; + 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); } /* inrec --- This reads in a record from the input file */ @@ -464,8 +494,8 @@ inrec(IOBUF *iop, int *errcode) if (*errcode > 0) update_ERRNO_saved(*errcode); } else { - NR += 1; - FNR += 1; + INCREMENT_REC(NR); + INCREMENT_REC(FNR); set_record(begin, cnt); } @@ -2296,8 +2326,8 @@ do_getline(int intovar, IOBUF *iop) if (cnt == EOF) return NULL; /* try next file */ - NR++; - FNR++; + INCREMENT_REC(NR); + INCREMENT_REC(FNR); if (! intovar) /* no optional var. */ set_record(s, cnt); @@ -3250,7 +3280,7 @@ pty_vs_pipe(const char *command) if (val->flags & MAYBE_NUM) (void) force_number(val); if (val->flags & NUMBER) - return (val->numbr != 0.0); + return ! iszero(val); else return (val->stlen != 0); } @@ -3383,8 +3413,10 @@ get_read_timeout(IOBUF *iop) } else /* use cached full index */ val = in_array(PROCINFO_node, full_idx); - if (val != NULL) - tmout = (long) force_number(val); + if (val != NULL) { + (void) force_number(val); + tmout = get_number_si(val); + } } else tmout = read_default_timeout; /* initialized from env. variable in init_io() */ @@ -3400,6 +3432,7 @@ get_read_timeout(IOBUF *iop) static ssize_t read_with_timeout(int fd, char *buf, size_t size) { +#ifndef __MINGW32__ fd_set readfds; struct timeval tv; @@ -3425,6 +3458,9 @@ read_with_timeout(int fd, char *buf, size_t size) errno = EAGAIN; #endif return -1; +#else /* __MINGW32__ */ + return read(fd, buf, size); +#endif /* __MINGW32__ */ } diff --git a/m4/ChangeLog b/m4/ChangeLog index 9e6800ad..782171ab 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,7 @@ +2012-04-01 John Haque <j.eh@mchsi.com> + + * mpfr.m4: New file. + 2012-03-30 Arnold D. Robbins <arnold@skeeve.com> * noreturn.m4: New file. diff --git a/m4/mpfr.m4 b/m4/mpfr.m4 new file mode 100644 index 00000000..7d9e678b --- /dev/null +++ b/m4/mpfr.m4 @@ -0,0 +1,62 @@ +dnl Check for MPFR and dependencies +dnl Copyright (C) 2004, 2005 Free Software Foundation, Inc. +dnl +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. +dnl +dnl Defines HAVE_MPFR to 1 if a working MPFR/GMP setup is +dnl found, and sets @LIBMPFR@ to the necessary libraries. + +AC_DEFUN([GNUPG_CHECK_MPFR], +[ + AC_ARG_WITH([mpfr], + AC_HELP_STRING([--with-mpfr=DIR], + [look for the mpfr and gmp libraries in DIR]), + [_do_mpfr=$withval],[_do_mpfr=yes]) + + if test "$_do_mpfr" != "no" ; then + if test -d "$withval" ; then + CPPFLAGS="${CPPFLAGS} -I$withval/include" + LDFLAGS="${LDFLAGS} -L$withval/lib" + fi + + _mpfr_save_libs=$LIBS + _combo="-lmpfr -lgmp" + LIBS="$LIBS $_combo" + + AC_MSG_CHECKING([whether mpfr via \"$_combo\" is present and usable]) + + AC_LINK_IFELSE([ + AC_LANG_PROGRAM([ +#include <stdio.h> +#include <mpfr.h> +#include <gmp.h> +],[ +mpfr_t p; +mpz_t z; +mpfr_init(p); +mpz_init(z); +mpfr_printf("%Rf%Zd", p, z); +mpfr_clear(p); +mpz_clear(z); +])],_found_mpfr=yes,_found_mpfr=no) + + AC_MSG_RESULT([$_found_mpfr]) + + LIBS=$_mpfr_save_libs + + if test $_found_mpfr = yes ; then + AC_DEFINE(HAVE_MPFR,1, + [Define to 1 if you have fully functional mpfr and gmp libraries.]) + AC_SUBST(LIBMPFR,$_combo) + break + fi + + unset _mpfr_save_libs + unset _combo + unset _found_mpfr + fi +])dnl @@ -35,6 +35,8 @@ #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 */ @@ -55,11 +57,10 @@ static void nostalgia(void) ATTRIBUTE_NORETURN; static void version(void) ATTRIBUTE_NORETURN; static void init_fds(void); static void init_groupset(void); - static void save_argv(int, char **); extern int debug_prog(INSTRUCTION *pc); /* debug.c */ - +extern int init_debug(); /* debug.c */ /* These nodes store all the special variables AWK uses */ NODE *ARGC_node, *ARGIND_node, *ARGV_node, *BINMODE_node, *CONVFMT_node; @@ -67,6 +68,7 @@ NODE *ENVIRON_node, *ERRNO_node, *FIELDWIDTHS_node, *FILENAME_node; NODE *FNR_node, *FPAT_node, *FS_node, *IGNORECASE_node, *LINT_node; NODE *NF_node, *NR_node, *OFMT_node, *OFS_node, *ORS_node, *PROCINFO_node; NODE *RLENGTH_node, *RSTART_node, *RS_node, *RT_node, *SUBSEP_node; +NODE *PREC_node, *ROUNDMODE_node; NODE *TEXTDOMAIN_node; NODE *_r; /* used as temporary in stack macros */ @@ -160,30 +162,31 @@ void (*lintfunc)(const char *mesg, ...) = warning; static const struct option optab[] = { { "traditional", no_argument, NULL, 'c' }, - { "lint", optional_argument, NULL, 'L' }, + { "lint", optional_argument, NULL, 'L' }, { "lint-old", no_argument, NULL, 't' }, { "optimize", no_argument, NULL, 'O' }, { "posix", no_argument, NULL, 'P' }, { "nostalgia", no_argument, & do_nostalgia, 1 }, { "gen-pot", no_argument, NULL, 'g' }, - { "non-decimal-data", no_argument, NULL, 'n' }, - { "pretty-print", optional_argument, NULL, 'o' }, - { "profile", optional_argument, NULL, 'p' }, - { "debug", optional_argument, NULL, 'D' }, - { "copyright", no_argument, NULL, 'C' }, - { "field-separator", required_argument, NULL, 'F' }, - { "file", required_argument, NULL, 'f' }, + { "non-decimal-data", no_argument, NULL, 'n' }, + { "pretty-print", optional_argument, NULL, 'o' }, + { "profile", optional_argument, NULL, 'p' }, + { "debug", optional_argument, NULL, 'D' }, + { "copyright", no_argument, NULL, 'C' }, + { "field-separator", required_argument, NULL, 'F' }, + { "file", required_argument, NULL, 'f' }, { "re-interval", no_argument, NULL, 'r' }, - { "source", required_argument, NULL, 'e' }, - { "load", required_argument, NULL, 'l' }, - { "dump-variables", optional_argument, NULL, 'd' }, - { "assign", required_argument, NULL, 'v' }, - { "version", no_argument, NULL, 'V' }, - { "help", no_argument, NULL, 'h' }, - { "exec", required_argument, NULL, 'E' }, + { "source", required_argument, NULL, 'e' }, + { "load", required_argument, NULL, 'l' }, + { "dump-variables", optional_argument, NULL, 'd' }, + { "assign", required_argument, NULL, 'v' }, + { "version", no_argument, NULL, 'V' }, + { "help", no_argument, NULL, 'h' }, + { "exec", required_argument, NULL, 'E' }, { "use-lc-numeric", no_argument, & use_lc_numeric, 1 }, { "characters-as-bytes", no_argument, & do_binary, 'b' }, { "sandbox", no_argument, NULL, 'S' }, + { "bignum", no_argument, NULL, 'M' }, #if defined(YYDEBUG) || defined(GAWKDEBUG) { "parsedebug", no_argument, NULL, 'Y' }, #endif @@ -198,9 +201,8 @@ main(int argc, char **argv) { /* * The + on the front tells GNU getopt not to rearrange argv. - * Note: reserve -l for future use, for xgawk's -l option. */ - const char *optlist = "+F:f:v:W;m:bcCd::D::e:E:gh:l:L:nNo::Op::PrStVY"; + const char *optlist = "+F:f:v:W;m:bcCd::D::e:E:gh:l:L:nNo::Op::MPrStVY"; int stopped_early = FALSE; int old_optind; int i; @@ -444,6 +446,12 @@ main(int argc, char **argv) set_prof_file(DEFAULT_PROFILE); break; + case 'M': +#ifdef HAVE_MPFR + do_flags |= DO_MPFR; +#endif + break; + case 'P': do_flags |= DO_POSIX; break; @@ -560,13 +568,30 @@ out: } #endif + 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 + /* load group set */ init_groupset(); /* initialize the null string */ Nnull_string = make_string("", 0); - Nnull_string->numbr = 0.0; - Nnull_string->flags = (MALLOC|STRCUR|STRING|NUMCUR|NUMBER); +#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. @@ -575,8 +600,6 @@ out: */ resetup(); - init_interpret(); - /* Set up the special variables */ init_vars(); @@ -627,6 +650,9 @@ out: optind++; } + /* Select the interpreter routine */ + init_interpret(); + init_args(optind, argc, do_posix ? argv[0] : myname, argv); @@ -758,6 +784,7 @@ usage(int exitval, FILE *fp) fputs(_("\t-l library\t\t--load=library\n"), fp); fputs(_("\t-L [fatal]\t\t--lint[=fatal]\n"), fp); fputs(_("\t-n\t\t\t--non-decimal-data\n"), fp); + fputs(_("\t-M\t\t\t--bignum\n"), fp); fputs(_("\t-N\t\t\t--use-lc-numeric\n"), fp); fputs(_("\t-o[file]\t\t--pretty-print[=file]\n"), fp); fputs(_("\t-O\t\t\t--optimize\n"), fp); @@ -932,6 +959,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}, {&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 }, @@ -939,6 +967,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 }, {&RLENGTH_node, "RLENGTH", NULL, 0, NULL, NULL, FALSE, 0 }, +{&ROUNDMODE_node, "ROUNDMODE", DEFAULT_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 }, @@ -959,8 +988,10 @@ init_vars() if ((vp->flags & NO_INSTALL) != 0) continue; n = *(vp->spec) = install_symbol(estrdup(vp->name, strlen(vp->name)), Node_var); - n->var_value = vp->strval == NULL ? make_number(vp->numval) - : make_string(vp->strval, strlen(vp->strval)); + if (vp->strval != NULL) + n->var_value = make_string(vp->strval, strlen(vp->strval)); + else + n->var_value = make_number(vp->numval); n->var_assign = (Func_ptr) vp->assign; n->var_update = (Func_ptr) vp->update; if (vp->do_assign) @@ -1035,6 +1066,8 @@ 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) char name[100]; #endif AWKNUM value; @@ -1044,6 +1077,15 @@ 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 + #ifdef GETPGRP_VOID #define getpgrp_arg() /* nothing */ #else @@ -1320,7 +1362,11 @@ nostalgia() static void version() { - printf("%s\n", version_string); + printf("%s", version_string); +#ifdef HAVE_MPFR + printf(" (GNU MPFR %s, GNU MP %s)", mpfr_get_version(), gmp_version); +#endif + printf("\n"); /* * Per GNU coding standards, print copyright info, * then exit successfully, do nothing else. @@ -0,0 +1,1620 @@ +/* + * mpfr.c - routines for arbitrary-precision number 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 HAVE_MPFR + +#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 */ + +mpz_t mpzval; /* GMP integer type, used as temporary in few places */ +mpz_t MNR; +mpz_t MFNR; +int do_ieee_fmt; /* IEEE-754 floating-point emulation */ +mpfr_rnd_t ROUND_MODE; + +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); + +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; + +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; + +/* + * PRECISION_MIN is the precision used to initialize _mpf_t1 and _mpf_t2. + * 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 + + +/* init_mpfr --- set up MPFR related variables */ + +void +init_mpfr(mpfr_prec_t prec, const char *rmode) +{ + mpfr_set_default_prec(prec); + ROUND_MODE = get_rnd_mode(rmode[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); + + register_exec_hook(mpg_interpret, 0); +} + +/* mpg_node --- allocate a node to store MPFR float or GMP integer */ + +NODE * +mpg_node(unsigned int tp) +{ + NODE *r; + getnode(r); + r->type = Node_val; + + if (tp == MPFN) { + /* Initialize, set precision to the default precision, and value to NaN */ + mpfr_init(r->mpg_numbr); + r->flags = MPFN; + } else { + /* Initialize and set value to 0 */ + mpz_init(r->mpg_i); + r->flags = MPZN; + } + + r->valref = 1; + r->flags |= MALLOC|NUMBER|NUMCUR; + r->stptr = NULL; + r->stlen = 0; +#if MBS_SUPPORT + r->wstptr = NULL; + r->wstlen = 0; +#endif /* defined MBS_SUPPORT */ + return r; +} + +/* + * mpg_make_number --- make a arbitrary-precision number node + * and initialize with a C double + */ + +static NODE * +mpg_make_number(double x) +{ + NODE *r; + double ival; + + 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); + } + return r; +} + +/* mpg_strtoui --- assign arbitrary-precision integral value from a string */ + +int +mpg_strtoui(mpz_ptr zi, char *str, size_t len, char **end, int base) +{ + char *s = str; + char *start; + int ret = -1; + + /* + * mpz_set_str does not like leading 0x or 0X for hex (or 0 for octal) + * with a non-zero base argument. + */ + if (base == 16 && len >= 2 && *s == '0' && (s[1] == 'x' || s[1] == 'X')) { + s += 2; len -= 2; + } else if (base == 8 && len >= 1 && *s == '0') { + s++; len--; + } + start = s; + + while (len > 0) { + switch (*s) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + break; + case '8': + case '9': + if (base == 8) + goto done; + break; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + if (base == 16) + break; + default: + goto done; + } + s++; len--; + } +done: + if (s > start) { + char save = *s; + *s = '\0'; + ret = mpz_set_str(zi, start, base); + *s = save; + } + if (end != NULL) + *end = s; + return ret; +} + + +/* mpg_maybe_float --- test if a string may contain arbitrary-precision float */ + +static int +mpg_maybe_float(const char *str, int use_locale) +{ + int dec_point = '.'; + const char *s = str; + +#if defined(HAVE_LOCALE_H) + /* + * loc.decimal_point may not have been initialized yet, + * so double check it before using it. + */ + if (use_locale && loc.decimal_point != NULL && loc.decimal_point[0] != '\0') + dec_point = loc.decimal_point[0]; /* XXX --- assumes one char */ +#endif + + if (strlen(s) >= 3 + && ( ( (s[0] == 'i' || s[0] == 'I') + && (s[1] == 'n' || s[1] == 'N') + && (s[2] == 'f' || s[2] == 'F')) + || ( (s[0] == 'n' || s[0] == 'N') + && (s[1] == 'a' || s[1] == 'A') + && (s[2] == 'n' || s[2] == 'N')))) + return TRUE; + + for (; *s != '\0'; s++) { + if (*s == dec_point || *s == 'e' || *s == 'E') + return TRUE; + } + + return FALSE; +} + + +/* mpg_zero --- initialize with arbitrary-precision integer(GMP) and set value to zero */ + +static inline void +mpg_zero(NODE *n) +{ + if (is_mpg_float(n)) { + mpfr_clear(n->mpg_numbr); + n->flags &= ~MPFN; + } + if (! is_mpg_integer(n)) { + mpz_init(n->mpg_i); /* this also sets its value to 0 */ + n->flags |= MPZN; + } else + mpz_set_si(n->mpg_i, 0); +} + + +/* force_mpnum --- force a value to be a GMP integer or MPFR float */ + +static int +force_mpnum(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); + return FALSE; + } + + cp = n->stptr; + cpend = n->stptr + n->stlen; + while (cp < cpend && isspace((unsigned char) *cp)) + cp++; + if (cp == cpend) { /* only spaces */ + mpg_zero(n); + return FALSE; + } + + save = *cpend; + *cpend = '\0'; + + if (*cp == '+' || *cp == '-') + cp1 = cp + 1; + else + cp1 = cp; + + if (do_nondec) + base = get_numbase(cp1, use_locale); + + if (! mpg_maybe_float(cp1, use_locale)) { + mpg_zero(n); + errno = 0; + mpg_strtoui(n->mpg_i, cp1, cpend - cp1, & ptr, base); + if (*cp == '-') + mpz_neg(n->mpg_i, n->mpg_i); + goto done; + } + + if (is_mpg_integer(n)) { + mpz_clear(n->mpg_i); + n->flags &= ~MPZN; + } + + if (! is_mpg_float(n)) { + mpfr_init(n->mpg_numbr); + n->flags |= MPFN; + } + + errno = 0; + tval = mpfr_strtofr(n->mpg_numbr, cp, & ptr, base, ROUND_MODE); + IEEE_FMT(n->mpg_numbr, tval); +done: + /* trailing space is OK for NUMBER */ + while (isspace((unsigned char) *ptr)) + ptr++; + *cpend = save; + if (errno == 0 && ptr == cpend) + return TRUE; + errno = 0; + return FALSE; +} + +/* mpg_force_number --- force a value to be a multiple-precision number */ + +static NODE * +mpg_force_number(NODE *n) +{ + unsigned int newflags = 0; + + if (is_mpg_number(n) && (n->flags & NUMCUR)) + return n; + + if (n->flags & MAYBE_NUM) { + n->flags &= ~MAYBE_NUM; + newflags = NUMBER; + } + + if (force_mpnum(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 */ + +static NODE * +mpg_format_val(const char *format, int index, NODE *s) +{ + NODE *dummy[2], *r; + unsigned int oflags; + + /* create dummy node for a sole use of format_tree */ + dummy[1] = s; + oflags = s->flags; + + if (is_mpg_integer(s) || mpfr_integer_p(s->mpg_numbr)) { + /* integral value, use %d */ + r = format_tree("%d", 2, 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. */ + + s->flags |= STRCUR; + free_wstr(s); + return s; +} + +/* mpg_cmp --- compare two numbers */ + +int +mpg_cmp(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)) + return -1; + return mpfr_cmp(t1->mpg_numbr, t2->mpg_numbr); + } + if (mpfr_nan_p(t1->mpg_numbr)) + return 1; + return mpfr_cmp_z(t1->mpg_numbr, t2->mpg_i); + } else if (is_mpg_float(t2)) { + int ret; + if (mpfr_nan_p(t2->mpg_numbr)) + return -1; + ret = mpfr_cmp_z(t2->mpg_numbr, t1->mpg_i); + 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); +} + + +/* + * 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) +{ + 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; +} + +/* 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 */ + +void +set_PREC() +{ + long prec = 0; + NODE *val; + static const struct ieee_fmt { + const char *name; + mpfr_prec_t precision; + mpfr_exp_t emax; + mpfr_exp_t emin; + } ieee_fmts[] = { +{ "half", 11, 16, -23 }, /* binary16 */ +{ "single", 24, 128, -148 }, /* binary32 */ +{ "double", 53, 1024, -1073 }, /* binary64 */ +{ "quad", 113, 16384, -16493 }, /* binary128 */ +{ "oct", 237, 262144, -262377 }, /* binary256, not in the IEEE 754-2008 standard */ + + /* + * For any bitwidth = 32 * k ( k >= 4), + * precision = 13 + bitwidth - int(4 * log2(bitwidth)) + * emax = 1 << bitwidth - precision - 1 + * emin = 4 - emax - precision + */ + }; + + if (! do_mpfr) + return; + + val = PREC_node->var_value; + if (val->flags & MAYBE_NUM) + force_number(val); + + if ((val->flags & (STRING|NUMBER)) == STRING) { + int i, j; + + /* emulate IEEE-754 binary format */ + + for (i = 0, j = sizeof(ieee_fmts)/sizeof(ieee_fmts[0]); i < j; i++) { + if (strcasecmp(ieee_fmts[i].name, val->stptr) == 0) + break; + } + + if (i < j) { + prec = ieee_fmts[i].precision; + + /* + * We *DO NOT* change the MPFR exponent range using + * mpfr_set_{emin, emax} here. See format_ieee() for details. + */ + max_exp = ieee_fmts[i].emax; + min_exp = ieee_fmts[i].emin; + + do_ieee_fmt = TRUE; + } + } + + if (prec <= 0) { + force_number(val); + prec = get_number_si(val); + if (prec < MPFR_PREC_MIN || prec > MPFR_PREC_MAX) { + force_string(val); + warning(_("PREC value `%.*s' is invalid"), (int) val->stlen, val->stptr); + prec = 0; + } else + do_ieee_fmt = FALSE; + } + + if (prec > 0) + mpfr_set_default_prec(prec); +} + + +/* get_rnd_mode --- convert string to MPFR rounding mode */ + +static mpfr_rnd_t +get_rnd_mode(const char rmode) +{ + switch (rmode) { + case 'N': + case 'n': + return MPFR_RNDN; /* round to nearest (IEEE-754 roundTiesToEven) */ + case 'Z': + case 'z': + return MPFR_RNDZ; /* round toward zero (IEEE-754 roundTowardZero) */ + case 'U': + case 'u': + return MPFR_RNDU; /* round toward plus infinity (IEEE-754 roundTowardPositive) */ + case 'D': + case 'd': + return MPFR_RNDD; /* round toward minus infinity (IEEE-754 roundTowardNegative) */ +#if defined(MPFR_VERSION_MAJOR) && MPFR_VERSION_MAJOR > 2 + case 'A': + case 'a': + return MPFR_RNDA; /* round away from zero (IEEE-754 roundTiesToAway) */ +#endif + default: + break; + } + return -1; +} + +/* + * set_ROUNDMODE --- update MPFR rounding mode related variables + * when ROUNDMODE assigned to + */ + +void +set_ROUNDMODE() +{ + 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); + } +} + + +/* format_ieee --- make sure a number follows IEEE-754 floating-point standard */ + +int +format_ieee(mpfr_ptr x, int tval) +{ + /* + * The MPFR doc says that it's our responsibility to make sure all numbers + * including those previously created are in range after we've changed the + * exponent range. Most MPFR operations and functions require + * the input arguments to have exponents within the current exponent range. + * Any argument outside the range results in a MPFR assertion failure + * like this: + * + * $ gawk -M 'BEGIN { x=1.0e-10000; print x+0; PREC="double"; print x+0}' + * 1e-10000 + * init2.c:52: MPFR assertion failed .... + * + * A "naive" approach would be to keep track of the ternary state and + * the rounding mode for each number, and make sure it is in the current + * exponent range (using mpfr_check_range) before using it in an + * operation or function. Instead, we adopt the following strategy. + * + * When gawk starts, the exponent range is the MPFR default + * [MPFR_EMIN_DEFAULT, MPFR_EMAX_DEFAULT]. Any number that gawk + * creates must have exponent in this range (excluding infinities, NaNs and zeros). + * Each MPFR operation or function is performed with this default exponent + * range. + * + * When emulating IEEE-754 format, the exponents are *temporarily* changed, + * mpfr_check_range is called to make sure the number is in the new range, + * and mpfr_subnormalize is used to round following the rules of subnormal + * arithmetic. The exponent range is then *restored* to the original value + * [MPFR_EMIN_DEFAULT, MPFR_EMAX_DEFAULT]. + */ + + (void) mpfr_set_emin(min_exp); + (void) mpfr_set_emax(max_exp); + tval = mpfr_check_range(x, tval, ROUND_MODE); + tval = mpfr_subnormalize(x, tval, ROUND_MODE); + (void) mpfr_set_emin(MPFR_EMIN_DEFAULT); + (void) mpfr_set_emax(MPFR_EMAX_DEFAULT); + return tval; +} + + +/* do_mpfr_atan2 --- do the atan2 function */ + +NODE * +do_mpfr_atan2(int nargs) +{ + NODE *t1, *t2, *res; + mpfr_ptr p1, p2; + int tval; + + 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")); + } + force_number(t1); + force_number(t2); + + p1 = MP_FLOAT(t1); + p2 = MP_FLOAT(t2); + res = mpg_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); + + DEREF(t1); + DEREF(t2); + return res; +} + + +#define SPEC_MATH(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); \ +DEREF(t1); \ +return res + + +/* do_mpfr_sin --- do the sin function */ + +NODE * +do_mpfr_sin(int nargs) +{ + SPEC_MATH(sin); +} + +/* do_mpfr_cos --- do the cos function */ + +NODE * +do_mpfr_cos(int nargs) +{ + SPEC_MATH(cos); +} + +/* do_mpfr_exp --- exponential function */ + +NODE * +do_mpfr_exp(int nargs) +{ + SPEC_MATH(exp); +} + +/* do_mpfr_log --- the log function */ + +NODE * +do_mpfr_log(int nargs) +{ + SPEC_MATH(log); +} + +/* do_mpfr_sqrt --- do the sqrt function */ + +NODE * +do_mpfr_sqrt(int nargs) +{ + SPEC_MATH(sqrt); +} + +/* do_mpfr_int --- convert double to int for awk */ + +NODE * +do_mpfr_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); + + if (is_mpg_integer(tmp)) { + r = mpg_integer(); + mpz_set(r->mpg_i, tmp->mpg_i); + } else { + if (! mpfr_number_p(tmp->mpg_numbr)) { + /* [+-]inf or NaN */ + return tmp; + } + + r = mpg_integer(); + mpfr_get_z(r->mpg_i, tmp->mpg_numbr, MPFR_RNDZ); + } + + DEREF(tmp); + return r; +} + +/* do_mpfr_compl --- perform a ~ operation */ + +NODE * +do_mpfr_compl(int nargs) +{ + NODE *tmp, *r; + mpz_ptr zptr; + + tmp = POP_SCALAR(); + 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; + + if (! mpfr_number_p(p)) { + /* [+-]inf or NaN */ + return tmp; + } + if (do_lint) { + if (mpfr_sgn(p) < 0) + lintwarn("%s", + mpg_fmt(_("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) + ); + } + + mpfr_get_z(mpzval, p, MPFR_RNDZ); /* float to integer conversion */ + zptr = mpzval; + } else { + /* (tmp->flags & MPZN) != 0 */ + zptr = tmp->mpg_i; + if (do_lint) { + if (mpz_sgn(zptr) < 0) + lintwarn("%s", + mpg_fmt(_("cmpl(%Zd): negative values will give strange results"), zptr) + ); + } + } + + r = mpg_integer(); + mpz_com(r->mpg_i, 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. + */ + +static NODE * +get_bit_ops(const char *op) +{ + _tz2 = POP_SCALAR(); + _tz1 = POP_SCALAR(); + + 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); + } + + force_number(_tz1); + force_number(_tz2); + + if (is_mpg_float(_tz1)) { + mpfr_ptr left = _tz1->mpg_numbr; + 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) { + if (mpfr_sgn(left) < 0) + lintwarn("%s", + mpg_fmt(_("%s(%Rg, ..): negative values will give strange results"), + op, left) + ); + if (! mpfr_integer_p(left)) + lintwarn("%s", + mpg_fmt(_("%s(%Rg, ..): fractional values will be truncated"), + op, 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; + } + + 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) + ); + } + + 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 NULL; +} + +/* do_mpfr_lshift --- perform a << operation */ + +NODE * +do_mpfr_lshift(int nargs) +{ + NODE *res; + unsigned long shift; + + if ((res = get_bit_ops("lshift")) == 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. + */ + + 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(); + return res; +} + +/* do_mpfr_rshift --- perform a >> operation */ + +NODE * +do_mpfr_rhift(int nargs) +{ + NODE *res; + unsigned long shift; + + 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. + */ + + 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(); + return res; +} + +/* do_mpfr_and --- perform an & operation */ + +NODE * +do_mpfr_and(int nargs) +{ + NODE *res; + + if ((res = get_bit_ops("and")) == NULL) { + res = mpg_integer(); + mpz_and(res->mpg_i, mpz1, mpz2); + } + free_bit_ops(); + return res; +} + +/* do_mpfr_or --- perform an | operation */ + +NODE * +do_mpfr_or(int nargs) +{ + NODE *res; + + if ((res = get_bit_ops("or")) == NULL) { + res = mpg_integer(); + mpz_ior(res->mpg_i, mpz1, mpz2); + } + free_bit_ops(); + return res; +} + +/* do_mpfr_strtonum --- the strtonum function */ + +NODE * +do_mpfr_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->stptr = tmp->stptr; + r->stlen = tmp->stlen; + force_mpnum(r, TRUE, use_lc_numeric); + r->stptr = NULL; + r->stlen = 0; + } else { + (void) force_number(tmp); + if (is_mpg_float(tmp)) { + int tval; + r = mpg_float(); + tval = mpfr_set(r->mpg_numbr, tmp->mpg_numbr, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); + } else { + r = mpg_integer(); + mpz_set(r->mpg_i, tmp->mpg_i); + } + } + + DEREF(tmp); + 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 int firstrand = TRUE; +static gmp_randstate_t state; +static mpz_t seed; /* current seed */ + +/* do_mpfr_rand --- do the rand function */ + +NODE * +do_mpfr_rand(int nargs ATTRIBUTE_UNUSED) +{ + NODE *res; + int tval; + + if (firstrand) { +#if 0 + /* Choose the default algorithm */ + gmp_randinit_default(state); +#endif + /* + * Choose a specific (Mersenne Twister) algorithm in case the default + * changes in the future. + */ + + gmp_randinit_mt(state); + + mpz_init(seed); + mpz_set_ui(seed, 1); + /* seed state */ + gmp_randseed(state, seed); + firstrand = FALSE; + } + res = mpg_float(); + tval = mpfr_urandomb(res->mpg_numbr, state); + IEEE_FMT(res->mpg_numbr, tval); + return res; +} + + +/* do_mpfr_srand --- seed the random number generator */ + +NODE * +do_mpfr_srand(int nargs) +{ + NODE *res; + + if (firstrand) { +#if 0 + /* Choose the default algorithm */ + gmp_randinit_default(state); +#endif + /* + * Choose a specific algorithm (Mersenne Twister) in case default + * changes in the future. + */ + + gmp_randinit_mt(state); + + mpz_init(seed); + mpz_set_ui(seed, 1); + /* No need to seed state, will change it below */ + firstrand = FALSE; + } + + res = mpg_integer(); + mpz_set(res->mpg_i, seed); /* previous seed */ + + if (nargs == 0) + mpz_set_ui(seed, (unsigned long) time((time_t *) 0)); + else { + NODE *tmp; + 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); + else /* MP integer */ + mpz_set(seed, tmp->mpg_i); + DEREF(tmp); + } + + gmp_randseed(state, seed); + 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 */ + +static NODE * +mpg_add(NODE *t1, 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); + } 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); + else + tval = mpfr_add(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); + } + return r; +} + +/* mpg_sub --- subtract arbitrary-precision numbers */ + +static NODE * +mpg_sub(NODE *t1, 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); + } 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)) { +#if (!defined(MPFR_VERSION) || (MPFR_VERSION < MPFR_VERSION_NUM(3,1,0))) + 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); + t2 = t1; + t1 = tmp; +#else + tval = mpfr_z_sub(r->mpg_numbr, t1->mpg_i, t2->mpg_numbr, ROUND_MODE); +#endif + } else + tval = mpfr_sub(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); + } + return r; +} + +/* mpg_mul --- multiply arbitrary-precision numbers */ + +static NODE * +mpg_mul(NODE *t1, 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); + } 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); + else + tval = mpfr_mul(r->mpg_numbr, t1->mpg_numbr, t2->mpg_numbr, ROUND_MODE); + IEEE_FMT(r->mpg_numbr, tval); + } + return r; +} + + +/* mpg_pow --- exponentiation involving arbitrary-precision numbers */ + +static NODE * +mpg_pow(NODE *t1, 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)); + } 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); + } + } else { + r = mpg_float(); + if (is_mpg_integer(t2)) + tval = mpfr_pow_z(r->mpg_numbr, t1->mpg_numbr, t2->mpg_i, ROUND_MODE); + else { + mpfr_ptr p1; + p1 = MP_FLOAT(t1); + tval = mpfr_pow(r->mpg_numbr, p1, t2->mpg_numbr, ROUND_MODE); + } + IEEE_FMT(r->mpg_numbr, tval); + } + return r; +} + +/* mpg_div --- arbitrary-precision division */ + +static NODE * +mpg_div(NODE *t1, 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) + ) { + r = mpg_integer(); + mpz_divexact(r->mpg_i, t1->mpg_i, t2->mpg_i); + } 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); + } + return r; +} + +/* mpg_mod --- modulus operation with arbitrary-precision numbers */ + +static NODE * +mpg_mod(NODE *t1, 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); + } 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); + } + 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; + + 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 { + + /* + * 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; + + 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; + + 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; + + 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(); + } + + DEREF(t2); + unref(*lhs); + *lhs = r; + UPREF(r); + REPLACE(r); + break; + + default: + return TRUE; /* unhandled */ + } + + *cp = pc->nexti; /* next instruction to execute */ + return FALSE; +} + + +/* mpg_fmt --- output formatted string with special MPFR/GMP conversion specifiers */ + +const char * +mpg_fmt(const char *mesg, ...) +{ + static char *tmp = NULL; + int ret; + va_list args; + + if (tmp != NULL) { + mpfr_free_str(tmp); + tmp = NULL; + } + va_start(args, mesg); + ret = mpfr_vasprintf(& tmp, mesg, args); + va_end(args); + if (ret >= 0 && tmp != NULL) + return tmp; + return mesg; +} + +#else + +void +set_PREC() +{ + /* dummy function */ +} + +void +set_ROUNDMODE() +{ + /* dummy function */ +} + +#endif @@ -62,6 +62,21 @@ err(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)) { + NODE *val; + val = mpg_update_var(FNR_node); + assert((val->flags & MPZN) != 0); + if (mpz_sgn(val->mpg_i) > 0) { + 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); + } + } else +#endif if (FNR > 0) { file = FILENAME_node->var_value->stptr; (void) putc('(', stderr); @@ -69,6 +84,7 @@ err(const char *s, const char *emsg, va_list argp) (void) fprintf(stderr, "FILENAME=%s ", file); (void) fprintf(stderr, "FNR=%ld) ", FNR); } + (void) fprintf(stderr, "%s", s); vfprintf(stderr, emsg, argp); (void) fprintf(stderr, "\n"); @@ -26,15 +26,21 @@ #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 *(*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 */ -AWKNUM +NODE * r_force_number(NODE *n) { char *cp; @@ -45,7 +51,7 @@ r_force_number(NODE *n) extern double strtod(); if (n->flags & NUMCUR) - return n->numbr; + return n; /* all the conditionals are an attempt to avoid the expensive strtod */ @@ -54,7 +60,7 @@ r_force_number(NODE *n) n->numbr = 0.0; if (n->stlen == 0) { - return 0.0; + return n; } cp = n->stptr; @@ -67,14 +73,14 @@ r_force_number(NODE *n) */ if (! do_posix) { if (isalpha((unsigned char) *cp)) { - return 0.0; + return n; } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) { if (n->flags & MAYBE_NUM) n->flags &= ~MAYBE_NUM; n->flags |= NUMBER|NUMCUR; n->numbr = get_ieee_magic_val(n->stptr); - return n->numbr; + return n; } /* else fall through */ @@ -92,7 +98,7 @@ r_force_number(NODE *n) /* CANNOT do non-decimal and saw 0x */ || (! do_non_decimal_data && cp[0] == '0' && (cp[1] == 'x' || cp[1] == 'X'))))) { - return 0.0; + return n; } if (n->flags & MAYBE_NUM) { @@ -109,12 +115,12 @@ r_force_number(NODE *n) if (cp == n->stptr) /* no leading spaces */ n->flags |= NUMINT; } - return n->numbr; + return n; } if (do_non_decimal_data) { /* main.c assures false if do_posix */ errno = 0; - if (! do_traditional && isnondecimal(cp, TRUE)) { + if (! do_traditional && get_numbase(cp, TRUE) != 10) { n->numbr = nondec2awknum(cp, cpend - cp); n->flags |= NUMCUR; ptr = cpend; @@ -139,7 +145,7 @@ finish: errno = 0; } - return n->numbr; + return n; } @@ -162,10 +168,10 @@ static const char *values[] = { }; #define NVAL (sizeof(values)/sizeof(values[0])) -/* format_val --- format a numeric value based on format */ +/* r_format_val --- format a numeric value based on format */ NODE * -format_val(const char *format, int index, NODE *s) +r_format_val(const char *format, int index, NODE *s) { char buf[BUFSIZ]; char *sp = buf; @@ -190,7 +196,8 @@ format_val(const char *format, int index, NODE *s) /* not an integral value, or out of range */ if ((val = double_to_int(s->numbr)) != s->numbr - || val <= LONG_MIN || val >= LONG_MAX) { + || val <= LONG_MIN || val >= LONG_MAX + ) { /* * Once upon a time, we just blindly did this: * sprintf(sp, format, s->numbr); @@ -201,11 +208,12 @@ format_val(const char *format, int index, NODE *s) */ NODE *dummy[2], *r; - unsigned short oflags; + 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); @@ -316,17 +324,17 @@ r_dupnode(NODE *n) return r; } -/* make_number --- allocate a node with defined number */ +/* r_make_number --- allocate a node with defined number */ -NODE * -make_number(AWKNUM x) +static NODE * +r_make_number(double x) { NODE *r; getnode(r); r->type = Node_val; r->numbr = x; - r->valref = 1; r->flags = MALLOC|NUMBER|NUMCUR; + r->valref = 1; r->stptr = NULL; r->stlen = 0; #if MBS_SUPPORT @@ -336,6 +344,32 @@ make_number(AWKNUM x) 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; +} + /* r_make_str_node --- make a string node */ @@ -437,6 +471,13 @@ r_unref(NODE *tmp) efree(tmp->stptr); #endif +#ifdef HAVE_MPFR + if (is_mpg_float(tmp)) + mpfr_clear(tmp->mpg_numbr); + else if (is_mpg_integer(tmp)) + mpz_clear(tmp->mpg_i); +#endif + free_wstr(tmp); freenode(tmp); } @@ -577,12 +618,14 @@ parse_escape(const char **string_ptr) } } -/* isnondecimal --- return true if number is not a decimal number */ +/* get_numbase --- return the base to use for the number in 's' */ int -isnondecimal(const char *str, int use_locale) +get_numbase(const char *s, int use_locale) { int dec_point = '.'; + const char *str = s; + #if defined(HAVE_LOCALE_H) /* * loc.decimal_point may not have been initialized yet, @@ -593,11 +636,11 @@ isnondecimal(const char *str, int use_locale) #endif if (str[0] != '0') - return FALSE; + return 10; /* leading 0x or 0X */ if (str[1] == 'x' || str[1] == 'X') - return TRUE; + return 16; /* * Numbers with '.', 'e', or 'E' are decimal. @@ -607,12 +650,16 @@ isnondecimal(const char *str, int use_locale) */ for (; *str != '\0'; str++) { if (*str == 'e' || *str == 'E' || *str == dec_point) - return FALSE; + return 10; else if (! isdigit((unsigned char) *str)) break; } - return TRUE; + if (! isdigit((unsigned char) s[1]) + || s[1] == '8' || s[1] == '9' + ) + return 10; + return 8; } #if MBS_SUPPORT diff --git a/pc/ChangeLog b/pc/ChangeLog index 4d2cce30..8d340b45 100644 --- a/pc/ChangeLog +++ b/pc/ChangeLog @@ -1,3 +1,37 @@ +2012-04-16 Eli Zaretskii <eliz@gnu.org> + + * Makefile.tst (PGAWK): Redefine as "../gawk.exe -p". + (MPFR_TESTS): New variable, a list of MPFR-related tests. + (mpfr-tests): A new target. + (badargs): Reset GREP_OPTIONS to empty, to avoid gratuitous + failures when the user has something like -nH there. + (mpfrieee, mpfrexprange, mpfrrnd, mpfrnr, mpfrsort, mpfrbigint): + New tests. + + * Makefile (default): Add descriptions of mingw32-mpfr and + mingw32-libreadline-mpfr targets. + (PRSPFILE, DRSPFILE, PRSP, DRSP, PLDRSP, DLDRSP, DO_PLNK) + (DO_PBIND, DO_DLNK, DO_DBIND, PLDJG, DLDJG, PLMINGW32) + (DLMINGW32, PAWKOBJS1, PAWKOBJS2, DAWKOBJS2, PGAWKOBJS) + (DGAWKOBJS): Remove unused variables. + (djgpp, djgpp-debug, mingw32): Don't use them. + (mingw32): Add -D__USE_MINGW_ANSI_STDIO to compilation flags. + (mingw32-readline, mingw32-mpfr, mingw32-readline-mpfr): New targets. + (CFLAGS, AWKOBJS2): Don't reference obsolete DYN_FLAGS and DYN_OBJ + variables. + (AWKOBJS2): Add symbol$O. + (AWKOBJS3): New variable, lists MPFR-related object files. + (AWKOBJS): Add $(AWKOBJS3). + (all): Remove pgawk.exe and dgawk.exe. + (pgawk.exe, dgawk.exe, $(PRSPFILE) $(DRSPFILE), eval_p$O) + (profile_p$O): Remove targets. + (random$O, debug$O): Don't depend on floatmagic.h + (eval$O): Depend on interpret.h. + (clean): Prepend '-' to command line, to ignore errors due to + non-existent files. + + * config.h: Comment out "#undef HAVE_LIBREADLINE" (again). + 2012-03-29 Arnold D. Robbins <arnold@skeeve.com> * config.h: Add definition for _Noreturn. diff --git a/pc/Makefile b/pc/Makefile index af3044d3..21fe0bfe 100644 --- a/pc/Makefile +++ b/pc/Makefile @@ -16,6 +16,9 @@ default: @echo " mingw32 . Windows32 exe [Mingw32 GNU C] " @echo " mingw32-readline . Like mingw32, but with readline " @echo " [You will need to have GNU readline library installed.] " + @echo " mingw32-mpfr . Like mingw32, but with MPFR " + @echo " [You will need to have GNU MPFR library installed.] " + @echo " mingw32-readline-mpfr . mingw32 with readline and MPFR " @echo " ----------------------------------------------------- " @echo " test .... Perform tests (see README_d/README.pc) " @echo " install . Install gawk under $(prefix)/ " @@ -39,8 +42,6 @@ default: #======================= Configuration ================================== RSPFILE = gawk.rsp -PRSPFILE = pgawk.rsp -DRSPFILE = dgawk.rsp # # Choose method for passing arguments to the linker. # @@ -50,11 +51,7 @@ DRSPFILE = dgawk.rsp # # else use brain-dead approach (emxbnd will need 'tr'). RSP = $(RSPFILE) -PRSP = $(PRSPFILE) -DRSP = $(DRSPFILE) LDRSP = @$(RSP) -PLDRSP = @$(PRSP) -DLDRSP = @$(DRSP) LNKRSP = $(LDRSP) #------------------------------------------------------------------------ # Some makes do not define MAKE (and ndmake does not allow a define). @@ -80,10 +77,6 @@ install = 1 # that $($X) can be expanded. DO_LNK = $($(LNK)) DO_BIND= $($(BIND)) -DO_PLNK = $($(PLNK)) -DO_PBIND= $($(PBIND)) -DO_DLNK = $($(DLNK)) -DO_DBIND= $($(DBIND)) #======================================================================== # End of general configuration. Some platform-specific configuration # notes appear below. @@ -97,21 +90,19 @@ prefix = $(DJDIR) pkgdatadir = $(prefix)/share/awk endif LDJG = $(CC) $(LF) -o gawk.exe $(LDRSP) $(LF2) -PLDJG = $(CC) $(LF) -o pgawk.exe $(PLDRSP) $(LF2) -DLDJG = $(CC) $(LF) -o dgawk.exe $(DLDRSP) $(LF2) BDJG = stubify -g awk.exe | stubedit awk.exe runfile=gawk djgpp: $(MAK) all \ CC=gcc O=.o CF=-O2 \ - LNK=LDJG PLNK=PLDJG DLNK=DLDJG LF=-s LF2=-lm \ - BIND=BDJG PBIND='' DBIND='' + LNK=LDJG LF=-s LF2=-lm \ + BIND=BDJG djgpp-debug: $(MAK) all \ CC=gcc O=.o CF='-O2 -g' \ - LNK=LDJG PLNK=PLDJG DLNK=DLDJG LF2=-lm \ - BIND=BDJG PBIND='' DBIND='' + LNK=LDJG LF2=-lm \ + BIND=BDJG #======================================================================== #========================== EMX ========================================= @@ -158,16 +149,34 @@ emxbnd-debug: #======================================================================== LMINGW32 = $(CC) $(LF) -o $@ $(GAWKOBJS) $(LF2) -PLMINGW32 = $(CC) $(LF) -o $@ $(PGAWKOBJS) $(LF2) -DLMINGW32 = $(CC) $(LF) -o $@ $(DGAWKOBJS) $(LF2) # The following might work around command-line length limitations: #LMINGW32 = $(CC) $(LF) -o $@ *.o $(LF2) mingw32: $(MAK) all \ - CC=gcc O=.o CF="-O2 -gdwarf-2 -g3" OBJ=popen.o \ - LNK=LMINGW32 PLNK=PLMINGW32 DLNK=DLMINGW32 \ - LF="-gdwarf-2 -g3" LF2=-lmsvcp60 RSP= + CC=gcc O=.o CF="-D__USE_MINGW_ANSI_STDIO -O2 -gdwarf-2 -g3" \ + OBJ=popen.o LNK=LMINGW32 LF="-gdwarf-2 -g3" LF2=-lmsvcp60 RSP= + +mingw32-readline: + $(MAK) all \ + CC=gcc O=.o \ + CF="-D__USE_MINGW_ANSI_STDIO -DHAVE_LIBREADLINE -O2 -gdwarf-2 -g3" \ + OBJ=popen.o LNK=LMINGW32 LF="-gdwarf-2 -g3" \ + LF2="-lreadline -lmsvcp60 -Wl,--enable-auto-import" RSP= + +mingw32-mpfr: + $(MAK) all \ + CC=gcc O=.o \ + CF="-D__USE_MINGW_ANSI_STDIO -DHAVE_MPFR -O2 -gdwarf-2 -g3" \ + OBJ=popen.o LNK=LMINGW32 LF="-gdwarf-2 -g3" \ + LF2="-lmpfr -lgmp -lmsvcp60 -Wl,--enable-auto-import" RSP= + +mingw32-readline-mpfr: + $(MAK) all \ + CC=gcc O=.o \ + CF="-D__USE_MINGW_ANSI_STDIO -DHAVE_LIBREADLINE -DHAVE_MPFR -O2 -gdwarf-2 -g3" \ + OBJ=popen.o LNK=LMINGW32 LF="-gdwarf-2 -g3" \ + LF2="-lmpfr -lgmp -lreadline -lmsvcp60 -Wl,--enable-auto-import" RSP= mingw32-readline: $(MAK) all \ @@ -181,18 +190,13 @@ BIND = EMPTY PBIND = EMPTY EMPTY= -# bitwise operations (-DBITOPS) and non-decimal input data (-DNONDECDATA) are -# undocumented in 3.0.3. They may be enabled in config.h, or added to CFLAGS. -CFLAGS = $(CF) -DGAWK -I. -DHAVE_CONFIG_H $(DYN_FLAGS) +CFLAGS = $(CF) -DGAWK -I. -DHAVE_CONFIG_H # object files AWKOBJS1 = array$O builtin$O eval$O field$O floatcomp$O gawkmisc$O io$O main$O -AWKOBJS2 = ext$O msg$O node$O profile$O re$O replace$O version$O $(DYN_OBJ) -PAWKOBJS1 = array$O builtin$O eval_p$O field$O floatcomp$O gawkmisc$O io$O main$O -PAWKOBJS2 = ext$O msg$O node$O profile_p$O re$O replace$O version$O $(DYN_OBJ) -DAWKOBJS1 = array$O builtin$O debug$O eval_d$O field$O floatcomp$O gawkmisc$O io$O main$O -DAWKOBJS2 = ext$O msg$O node$O profile$O re$O replace$O version$O command$O $(DYN_OBJ) -AWKOBJS = $(AWKOBJS1) $(AWKOBJS2) +AWKOBJS2 = ext$O msg$O node$O profile$O re$O replace$O version$O symbol$O +AWKOBJS3 = debug$O cint_array$O int_array$O mpfr$O str_array$O command$O +AWKOBJS = $(AWKOBJS1) $(AWKOBJS2) $(AWKOBJS3) ALLOBJS = $(AWKOBJS) awkgram$O getid$O $(OBJ) @@ -201,8 +205,6 @@ ALLOBJS = $(AWKOBJS) awkgram$O getid$O $(OBJ) LIBOBJS= getopt$O getopt1$O dfa$O regex$O random$O GAWKOBJS = $(ALLOBJS) $(LIBOBJS) -PGAWKOBJS = $(PAWKOBJS1) $(PAWKOBJS2) $(LIBOBJS) awkgram$O getid$O $(OBJ) -DGAWKOBJS = $(DAWKOBJS1) $(DAWKOBJS2) $(LIBOBJS) awkgram$O getid$O $(OBJ) # clear out suffixes list # .SUFFIXES: @@ -212,52 +214,34 @@ DGAWKOBJS = $(DAWKOBJS1) $(DAWKOBJS2) $(LIBOBJS) awkgram$O getid$O $(OBJ) $(CC) -c $(CFLAGS) $< # rules to build gawk -all : gawk.exe pgawk.exe dgawk.exe +all : gawk.exe gawk.exe:: $(GAWKOBJS) $(RSP) $(DO_LNK) $(DO_BIND) -pgawk.exe:: $(PGAWKOBJS) $(PRSP) - $(DO_PLNK) - $(DO_PBIND) - -dgawk.exe:: $(DGAWKOBJS) $(DRSP) - $(DO_DLNK) - $(DO_DBIND) - $(RSPFILE) : $(GAWKOBJS) echo $(AWKOBJS1)$P > $@ echo $(AWKOBJS2)$P >> $@ echo awkgram$O getid$O $(OBJ) $(LIBOBJS)$P >> $@ -$(PRSPFILE) : $(PGAWKOBJS) - echo $(PAWKOBJS1)$P > $@ - echo $(PAWKOBJS2)$P >> $@ - echo awkgram$O getid$O $(OBJ) $(LIBOBJS)$P >> $@ - -$(DRSPFILE) : $(DGAWKOBJS) - echo $(DAWKOBJS1)$P > $@ - echo $(DAWKOBJS2)$P >> $@ - echo awkgram$O getid$O $(OBJ) $(LIBOBJS)$P >> $@ - # Notes to dependencies: # 1. The dependency on getopt.h is because unistd.h includes it, # and we have -I. on the compiler command line. unistd.h is # included by awk.h. # 2. custom.h is not mentioned because pc ports don't use it. -$(ALLOBJS) $(LIBOBJS) eval_p$O profile_p$O eval_d$O debug$O command$O: \ +$(ALLOBJS) $(LIBOBJS): \ awk.h regex.h config.h gettext.h mbsupport.h protos.h dfa.h getopt.h builtin$O: floatmagic.h random.h popen.h -random$O: floatmagic.h random.h +random$O: random.h -debug$O: floatmagic.h +node$O: floatmagic.h command$O debug$O: cmd.h -dfa$O: xalloc.h +dfa$O: xalloc.h gawkmisc$O: pc/gawkmisc.pc @@ -267,9 +251,7 @@ io$O: popen.h regex$O: regcomp.c regexec.c regex_internal.h -eval_p$O: eval.c - -profile_p$O: profile.c +eval$O: interpret.h # A bug in ndmake requires the following rule awkgram$O: awk.h awkgram.c @@ -300,7 +282,7 @@ install2: gawk -v prefix=$(prefix) -f install.awk clean: - rm -rf gawk pgawk dgawk *.exe gawk.map *.o *.obj core a.out $(RSPFILE) $(PRSPFILE) $(DRSPFILE) $(DYN_EXP) + -rm -rf gawk *.exe gawk.map *.o *.obj core a.out $(RSPFILE) $(PRSPFILE) $(DRSPFILE) $(DYN_EXP) # cd doc && $(MAKE) clean # cd test && $(MAKE) clean # cd awklib && $(MAKE) clean diff --git a/pc/Makefile.tst b/pc/Makefile.tst index c10430a7..ab566531 100644 --- a/pc/Makefile.tst +++ b/pc/Makefile.tst @@ -67,7 +67,7 @@ AWK2 = '..\gawk.exe' AWKPROG = ../gawk.exe # Define PGAWK -PGAWK = ../pgawk.exe +PGAWK = ../gawk.exe -p # Set your cmp command here (you can use most versions of diff instead of cmp # if you don't want to convert the .ok files to the DOS CR/LF format). @@ -186,6 +186,7 @@ GAWK_EXT_TESTS = \ EXTRA_TESTS = inftest regtest INET_TESTS = inetdayu inetdayt inetechu inetecht MACHINE_TESTS = double1 double2 fmtspcl intformat +MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint LOCALE_CHARSET_TESTS = \ asort asorti fmttest fnarydel fnparydl lc_num1 mbfw1 \ mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc @@ -233,6 +234,8 @@ inet: inetmesg $(INET_TESTS) machine-tests: $(MACHINE_TESTS) +mpfr-tests: $(MPFR_TESTS) + msg:: @echo "" @echo "Any output from $(CMP) is bad news, although some differences" @@ -360,7 +363,7 @@ argtest:: badargs:: @echo $@ - @-$(AWK) -f 2>&1 | grep -v patchlevel >_$@ + @-$(AWK) -f 2>&1 | GREP_OPTIONS='' grep -v patchlevel >_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nonl:: @@ -800,6 +803,36 @@ exit: @-AWK="$(AWKPROG)" $(srcdir)/$@.sh > _$@ 2>&1 @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +mpfrieee: + @echo mpfrieee + @$(AWK) -M -vPREC=double -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrexprange: + @echo mpfrexprange + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrrnd: + @echo mpfrrnd + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrnr: + @echo mpfrnr + @$(AWK) -M -vPREC=113 -f $(srcdir)/$@.awk $(srcdir)/$@.in > _$@ + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrsort: + @echo mpfrsort + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrbigint: + @echo mpfrbigint + @$(AWK) -M -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + rri1:: @echo $@ @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \ @@ -228,7 +228,7 @@ pprint(INSTRUCTION *startp, INSTRUCTION *endp, int in_for_header) if (m == Nnull_string) /* optional return or exit value; don't print 0 or "" */ pp_push(pc->opcode, m->stptr, DONT_FREE); else if ((m->flags & NUMBER) != 0) - pp_push(pc->opcode, pp_number(m->numbr), CAN_FREE); + pp_push(pc->opcode, pp_number(m), CAN_FREE); else { str = pp_string(m->stptr, m->stlen, '"'); if ((m->flags & INTLSTR) != 0) { @@ -341,7 +341,7 @@ cleanup: && is_binary(t1->type)) /* (a - b) * 1 */ pp_parenthesize(t1); if ((m->flags & NUMBER) != 0) - tmp = pp_number(m->numbr); + tmp = pp_number(m); else tmp = pp_string(m->stptr, m->stlen, '"'); str = pp_concat(t1->pp_str, op2str(pc->opcode), tmp); @@ -1202,13 +1202,20 @@ pp_string(const char *in_str, size_t len, int delim) /* pp_number --- pretty format a number */ char * -pp_number(AWKNUM d) +pp_number(NODE *n) { #define PP_PRECISION 6 char *str; emalloc(str, char *, PP_PRECISION + 10, "pp_number"); - sprintf(str, "%0.*g", PP_PRECISION, d); +#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 } @@ -1219,7 +1226,7 @@ char * pp_node(NODE *n) { if ((n->flags & NUMBER) != 0) - return pp_number(n->numbr); + return pp_number(n); return pp_string(n->stptr, n->stlen, '"'); } diff --git a/str_array.c b/str_array.c index 7ce617ed..1b3a33f1 100644 --- a/str_array.c +++ b/str_array.c @@ -55,11 +55,6 @@ static NODE **str_list(NODE *symbol, NODE *subs); static NODE **str_copy(NODE *symbol, NODE *newsymb); static NODE **str_dump(NODE *symbol, NODE *ndump); -#ifdef ARRAYDEBUG -static NODE **str_option(NODE *opt, NODE *val); -#endif - - array_ptr str_array_func[] = { str_array_init, (array_ptr) 0, @@ -70,9 +65,6 @@ array_ptr str_array_func[] = { str_list, str_copy, str_dump, -#ifdef ARRAYDEBUG - str_option -#endif }; static inline NODE **str_find(NODE *symbol, NODE *s1, size_t code1, unsigned long hash1); @@ -158,7 +150,7 @@ str_lookup(NODE *symbol, NODE *subs) * never be used. */ - if (subs->flags & NUMCUR) { + if ((subs->flags & (MPFN|MPZN|NUMCUR)) == NUMCUR) { tmp->numbr = subs->numbr; tmp->flags |= NUMCUR; } @@ -187,7 +179,6 @@ str_lookup(NODE *symbol, NODE *subs) static NODE ** str_exists(NODE *symbol, NODE *subs) { - NODE **lhs; unsigned long hash1; size_t code1; @@ -196,8 +187,7 @@ str_exists(NODE *symbol, NODE *subs) subs = force_string(subs); hash1 = hash(subs->stptr, subs->stlen, (unsigned long) symbol->array_size, & code1); - lhs = str_find(symbol, subs, code1, hash1); - return lhs; + return str_find(symbol, subs, code1, hash1); } /* str_clear --- flush all the values in symbol[] */ @@ -673,27 +663,6 @@ grow_table(NODE *symbol) } -#ifdef ARRAYDEBUG - -static NODE ** -str_option(NODE *opt, NODE *val) -{ - int newval; - NODE *tmp; - NODE **ret = (NODE **) ! NULL; - - tmp = force_string(opt); - (void) force_number(val); - if (strcmp(tmp->stptr, "STR_CHAIN_MAX") == 0) { - newval = (int) val->numbr; - if (newval > 0) - STR_CHAIN_MAX = newval; - } else - ret = NULL; - return ret; -} -#endif - /* From bonzini@gnu.org Mon Oct 28 16:05:26 2002 diff --git a/test/ChangeLog b/test/ChangeLog index 84c67a6a..4a2c7b2b 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -1,3 +1,23 @@ +2012-04-01 John Haque <j.eh@mchsi.com> + + * Makefile.am (mpfr-test): Add target for manual testing of MPFR + and GMP numbers. + * mpfrbigint.awk, mpfrexprange.awk, mpfrieee.awk, mpfrnr.awk, + mpfrrnd.awk, mpfrsort.awk: New tests. + (MPFR_TESTS): Add the new tests. + * mpfrnr.in, mpfrbigint.ok, mpfrexprange.ok, mpfrieee.ok, mpfrnr.ok, + mpfrrnd.ok, mpfrsort.ok: New files. + (AWK): Add AWKFLAGS; useful for testing with 'gawk -M' invocation. + +2012-02-28 Arnold D. Robbins <arnold@skeeve.com> + + * fmtspcl-mpfr.ok, fnarydel-mpfr.ok, fnparydl-mpfr.ok, + rand-mpfr.ok: New files. + * Makefile.am (EXTRA_DIST): Add them. + (CHECK_MPFR): New list of files that have MPFR variant .ok file. + * Gentests: Deal with MPFR files by modifying the generated + comparison command. + 2011-12-26 John Haque <j.eh@mchsi.com> * badargs.ok: Adjust for new and changed command line options. diff --git a/test/Gentests b/test/Gentests index fc779f00..ae56b8cc 100755 --- a/test/Gentests +++ b/test/Gentests @@ -45,6 +45,13 @@ BEGIN { next } +/^CHECK_MPFR *=/,/[^\\]$/ { + gsub(/(^CHECK_MPFR *=|\\$)/,"") + for (i = 1; i <= NF; i++) + mpfr[$i] + next +} + /^[[:alpha:]_][[:alnum:]_]*:/ { # remember all targets from Makefile.am sub(/:.*/,"") @@ -91,9 +98,17 @@ function generate(x, s) delete files[x".in"] } - printf "\t@echo %s\n", x + printf "\t@echo $@\n" printf "\t@AWKPATH=$(srcdir) $(AWK) -f $@.awk %s >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@\n", s - printf "\t@-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@\n\n" + + if (x in mpfr) { + delete mpfr[x] + printf "\t@-if test -z \"$$AWKFLAGS\" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \\\n" + printf "\t$(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \\\n" + printf "\tfi\n\n" + } else { + printf "\t@-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@\n\n" + } } END { diff --git a/test/Makefile.am b/test/Makefile.am index 12f251f1..54d48397 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -209,6 +209,7 @@ EXTRA_DIST = \ fldchgnf.ok \ fmtspcl.awk \ fmtspcl.tok \ + fmtspcl-mpfr.ok \ fmttest.awk \ fmttest.ok \ fnamedat.awk \ @@ -221,6 +222,7 @@ EXTRA_DIST = \ fnarray2.ok \ fnarydel.awk \ fnarydel.ok \ + fnarydel-mpfr.ok \ fnaryscl.awk \ fnaryscl.ok \ fnasgnm.awk \ @@ -230,6 +232,7 @@ EXTRA_DIST = \ fnmisc.ok \ fnparydl.awk \ fnparydl.ok \ + fnparydl-mpfr.ok \ fpat1.awk \ fpat1.in \ fpat1.ok \ @@ -592,6 +595,7 @@ EXTRA_DIST = \ pty1.ok \ rand.awk \ rand.ok \ + rand-mpfr.ok \ range1.awk \ range1.in \ range1.ok \ @@ -850,6 +854,8 @@ INET_TESTS = inetdayu inetdayt inetechu inetecht MACHINE_TESTS = double1 double2 fmtspcl intformat +MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint + LOCALE_CHARSET_TESTS = \ asort asorti fmttest fnarydel fnparydl lc_num1 mbfw1 \ mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc @@ -866,20 +872,23 @@ NEED_LINT_OLD = lintold 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 CMP = cmp AWKPROG = ../gawk$(EXEEXT) -PGAWKPROG = ../pgawk$(EXEEXT) # 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. -AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) -PGAWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(PGAWKPROG) +AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) $(AWKFLAGS) + # Message stuff is to make it a little easier to follow. # Make the pass-fail last and dependent on others to avoid @@ -907,6 +916,8 @@ inet: inetmesg $(INET_TESTS) machine-tests: $(MACHINE_TESTS) +mpfr-tests: $(MPFR_TESTS) + msg:: @echo '' @echo 'Any output from "cmp" is bad news, although some differences' @@ -1107,9 +1118,11 @@ 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: fmtspcl.ok - @echo fmtspcl + @echo $@ @$(AWK) -f $(srcdir)/fmtspcl.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $@.ok _$@ && rm -f _$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + $(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \ + fi reint:: @echo $@ @@ -1452,6 +1465,43 @@ rri1:: AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ +rand: + @echo $@ + @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + ($(CMP) $(srcdir)/$@-mpfr.ok _$@ || $(CMP) $(srcdir)/$@-mpfr1.ok _$@) && rm -f _$@ ; \ + fi + +mpfrieee: + @echo $@ + @$(AWK) -M -vPREC=double -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrexprange: + @echo $@ + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrrnd: + @echo $@ + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrnr: + @echo $@ + @$(AWK) -M -vPREC=113 -f $(srcdir)/$@.awk $(srcdir)/$@.in > _$@ + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrsort: + @echo $@ + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrbigint: + @echo $@ + @$(AWK) -M -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + # Targets generated for other tests: include Maketests diff --git a/test/Makefile.in b/test/Makefile.in index 64d4851f..838eca85 100644 --- a/test/Makefile.in +++ b/test/Makefile.in @@ -67,12 +67,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/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/stdint_h.m4 \ - $(top_srcdir)/m4/uintmax_t.m4 $(top_srcdir)/m4/ulonglong.m4 \ - $(top_srcdir)/configure.ac + $(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/stdint_h.m4 $(top_srcdir)/m4/uintmax_t.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 @@ -93,7 +93,7 @@ AUTOMAKE = @AUTOMAKE@ # # This can also be done in individual tests where we wish to # check things specifically not in the C locale. -AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) +AWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(AWKPROG) $(AWKFLAGS) CC = @CC@ CCDEPMODE = @CCDEPMODE@ CFLAGS = @CFLAGS@ @@ -122,6 +122,7 @@ INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ LDFLAGS = @LDFLAGS@ LIBICONV = @LIBICONV@ LIBINTL = @LIBINTL@ +LIBMPFR = @LIBMPFR@ LIBOBJS = @LIBOBJS@ LIBREADLINE = @LIBREADLINE@ LIBS = @LIBS@ @@ -394,6 +395,7 @@ EXTRA_DIST = \ fldchgnf.ok \ fmtspcl.awk \ fmtspcl.tok \ + fmtspcl-mpfr.ok \ fmttest.awk \ fmttest.ok \ fnamedat.awk \ @@ -406,6 +408,7 @@ EXTRA_DIST = \ fnarray2.ok \ fnarydel.awk \ fnarydel.ok \ + fnarydel-mpfr.ok \ fnaryscl.awk \ fnaryscl.ok \ fnasgnm.awk \ @@ -415,6 +418,7 @@ EXTRA_DIST = \ fnmisc.ok \ fnparydl.awk \ fnparydl.ok \ + fnparydl-mpfr.ok \ fpat1.awk \ fpat1.in \ fpat1.ok \ @@ -777,6 +781,7 @@ EXTRA_DIST = \ pty1.ok \ rand.awk \ rand.ok \ + rand-mpfr.ok \ range1.awk \ range1.in \ range1.ok \ @@ -1032,6 +1037,7 @@ GAWK_EXT_TESTS = \ EXTRA_TESTS = inftest regtest INET_TESTS = inetdayu inetdayt inetechu inetecht MACHINE_TESTS = double1 double2 fmtspcl intformat +MPFR_TESTS = mpfrnr mpfrrnd mpfrieee mpfrexprange mpfrsort mpfrbigint LOCALE_CHARSET_TESTS = \ asort asorti fmttest fnarydel fnparydl lc_num1 mbfw1 \ mbprintf1 mbprintf2 mbprintf3 rebt8b2 rtlenmb sort1 sprintfc @@ -1051,12 +1057,15 @@ 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 CMP = cmp AWKPROG = ../gawk$(EXEEXT) -PGAWKPROG = ../pgawk$(EXEEXT) -PGAWK = LC_ALL=$${GAWKLOCALE:-C} LANG=$${GAWKLOCALE:-C} $(PGAWKPROG) all: all-am .SUFFIXES: @@ -1260,6 +1269,8 @@ inet: inetmesg $(INET_TESTS) machine-tests: $(MACHINE_TESTS) +mpfr-tests: $(MPFR_TESTS) + msg:: @echo '' @echo 'Any output from "cmp" is bad news, although some differences' @@ -1458,9 +1469,11 @@ 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: fmtspcl.ok - @echo fmtspcl + @echo $@ @$(AWK) -f $(srcdir)/fmtspcl.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $@.ok _$@ && rm -f _$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + $(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \ + fi reint:: @echo $@ @@ -1802,1085 +1815,1117 @@ rri1:: @[ -z "$$GAWKLOCALE" ] && GAWKLOCALE=en_US.UTF-8; \ AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +rand: + @echo $@ + @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + ($(CMP) $(srcdir)/$@-mpfr.ok _$@ || $(CMP) $(srcdir)/$@-mpfr1.ok _$@) && rm -f _$@ ; \ + fi + +mpfrieee: + @echo $@ + @$(AWK) -M -vPREC=double -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrexprange: + @echo $@ + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrrnd: + @echo $@ + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrnr: + @echo $@ + @$(AWK) -M -vPREC=113 -f $(srcdir)/$@.awk $(srcdir)/$@.in > _$@ + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrsort: + @echo $@ + @$(AWK) -M -vPREC=53 -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + +mpfrbigint: + @echo $@ + @$(AWK) -M -f $(srcdir)/$@.awk > _$@ 2>&1 + @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ Gt-dummy: # file Maketests, generated from Makefile.am by the Gentests program addcomma: - @echo addcomma + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ anchgsub: - @echo anchgsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayparm: - @echo arrayparm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayprm2: - @echo arrayprm2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayprm3: - @echo arrayprm3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayref: - @echo arrayref + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrymem1: - @echo arrymem1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref2: - @echo arryref2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref3: - @echo arryref3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref4: - @echo arryref4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref5: - @echo arryref5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arynasty: - @echo arynasty + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm1: - @echo aryprm1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm2: - @echo aryprm2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm3: - @echo aryprm3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm4: - @echo aryprm4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm5: - @echo aryprm5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm6: - @echo aryprm6 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm7: - @echo aryprm7 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm8: - @echo aryprm8 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arysubnm: - @echo arysubnm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ asgext: - @echo asgext + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ back89: - @echo back89 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ backgsub: - @echo backgsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ childin: - @echo childin + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ closebad: - @echo closebad + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ clsflnam: - @echo clsflnam + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ compare2: - @echo compare2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ concat1: - @echo concat1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ concat2: - @echo concat2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ concat3: - @echo concat3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ convfmt: - @echo convfmt + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ datanonl: - @echo datanonl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ defref: - @echo defref + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delargv: - @echo delargv + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delarpm2: - @echo delarpm2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delarprm: - @echo delarprm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delfunc: - @echo delfunc + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ dfastress: - @echo dfastress + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ dynlj: - @echo dynlj + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ eofsplit: - @echo eofsplit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ exitval2: - @echo exitval2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fcall_exit: - @echo fcall_exit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fcall_exit2: - @echo fcall_exit2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fldchg: - @echo fldchg + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fldchgnf: - @echo fldchgnf + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnamedat: - @echo fnamedat + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnarray: - @echo fnarray + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnarray2: - @echo fnarray2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnaryscl: - @echo fnaryscl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnasgnm: - @echo fnasgnm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnmisc: - @echo fnmisc + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fordel: - @echo fordel + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ forref: - @echo forref + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ forsimp: - @echo forsimp + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fsbs: - @echo fsbs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fsrs: - @echo fsrs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fstabplus: - @echo fstabplus + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funsemnl: - @echo funsemnl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funsmnam: - @echo funsmnam + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funstack: - @echo funstack + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getline: - @echo getline + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getline3: - @echo getline3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getline4: - @echo getline4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getnr2tb: - @echo getnr2tb + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getnr2tm: - @echo getnr2tm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubasgn: - @echo gsubasgn + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtest: - @echo gsubtest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst2: - @echo gsubtst2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst4: - @echo gsubtst4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst5: - @echo gsubtst5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst7: - @echo gsubtst7 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst8: - @echo gsubtst8 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ hex: - @echo hex + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ hsprint: - @echo hsprint + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ inputred: - @echo inputred + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ intest: - @echo intest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ intprec: - @echo intprec + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ iobug1: - @echo iobug1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ leadnl: - @echo leadnl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ longsub: - @echo longsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ longwrds: - @echo longwrds + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ manglprm: - @echo manglprm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ math: - @echo math + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ membug1: - @echo membug1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ minusstr: - @echo minusstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nasty: - @echo nasty + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nasty2: - @echo nasty2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ negexp: - @echo negexp + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ negrange: - @echo negrange + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nested: - @echo nested + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nfldstr: - @echo nfldstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nfneg: - @echo nfneg + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nfset: - @echo nfset + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nlfldsep: - @echo nlfldsep + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nlinstr: - @echo nlinstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nlstrina: - @echo nlstrina + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noeffect: - @echo noeffect + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nofmtch: - @echo nofmtch + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noloop1: - @echo noloop1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noloop2: - @echo noloop2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noparms: - @echo noparms + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nulrsend: - @echo nulrsend + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ numindex: - @echo numindex + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ numsubstr: - @echo numsubstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ octsub: - @echo octsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmt: - @echo ofmt + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmta: - @echo ofmta + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmtbig: - @echo ofmtbig + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmtfidl: - @echo ofmtfidl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmts: - @echo ofmts + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ onlynl: - @echo onlynl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ opasnidx: - @echo opasnidx + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ opasnslf: - @echo opasnslf + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ paramdup: - @echo paramdup + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ paramres: - @echo paramres + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ paramtyp: - @echo paramtyp + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ parse1: - @echo parse1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ parsefld: - @echo parsefld + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ parseme: - @echo parseme + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ pcntplus: - @echo pcntplus + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prdupval: - @echo prdupval + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prec: - @echo prec + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ printf1: - @echo printf1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prmarscl: - @echo prmarscl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prmreuse: - @echo prmreuse + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prt1eval: - @echo prt1eval + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prtoeval: - @echo prtoeval - @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ - -rand: - @echo rand + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ range1: - @echo range1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rebt8b1: - @echo rebt8b1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ regeq: - @echo regeq + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ regrange: - @echo regrange + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ reindops: - @echo reindops + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ reparse: - @echo reparse + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ resplit: - @echo resplit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rs: - @echo rs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rsnul1nl: - @echo rsnul1nl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest1: - @echo rstest1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest2: - @echo rstest2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest3: - @echo rstest3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest4: - @echo rstest4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest5: - @echo rstest5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rswhite: - @echo rswhite + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ scalar: - @echo scalar + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sclforin: - @echo sclforin + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sclifin: - @echo sclifin + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sortempty: - @echo sortempty + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitargv: - @echo splitargv + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitarr: - @echo splitarr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitdef: - @echo splitdef + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitvar: - @echo splitvar + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitwht: - @echo splitwht + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strcat1: - @echo strcat1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strnum1: - @echo strnum1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strtod: - @echo strtod + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ subsepnm: - @echo subsepnm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ subslash: - @echo subslash + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ substr: - @echo substr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ swaplns: - @echo swaplns + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ synerr1: - @echo synerr1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ synerr2: - @echo synerr2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit2: - @echo uninit2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit3: - @echo uninit3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit4: - @echo uninit4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit5: - @echo uninit5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninitialized: - @echo uninitialized + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ unterm: - @echo unterm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uparrfs: - @echo uparrfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ wjposer1: - @echo wjposer1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ zero2: - @echo zero2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ zeroe0: - @echo zeroe0 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ zeroflag: - @echo zeroflag + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getlnhd: - @echo getlnhd + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aadelete1: - @echo aadelete1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aadelete2: - @echo aadelete2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aarray1: - @echo aarray1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aasort: - @echo aasort + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aasorti: - @echo aasorti + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arraysort: - @echo arraysort + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ backw: - @echo backw + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ clos1way: - @echo clos1way + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delsub: - @echo delsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fieldwdth: - @echo fieldwdth + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpat1: - @echo fpat1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpat2: - @echo fpat2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpat3: - @echo fpat3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpatnull: - @echo fpatnull + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fsfwfs: - @echo fsfwfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funlen: - @echo funlen + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fwtest: - @echo fwtest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fwtest2: - @echo fwtest2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fwtest3: - @echo fwtest3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gensub: - @echo gensub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gensub2: - @echo gensub2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getlndir: - @echo getlndir + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gnuops2: - @echo gnuops2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gnuops3: - @echo gnuops3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gnureops: - @echo gnureops + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ icasefs: - @echo icasefs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ icasers: - @echo icasers + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ igncdym: - @echo igncdym + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ igncfs: - @echo igncfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ignrcase: - @echo ignrcase + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ indirectcall: - @echo indirectcall + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ lint: - @echo lint + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ lintold: - @echo lintold + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint-old < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ lintwarn: - @echo lintwarn + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ match1: - @echo match1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ match2: - @echo match2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ match3: - @echo match3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nastyparm: - @echo nastyparm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nondec: - @echo nondec + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ patsplit: - @echo patsplit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ posix: - @echo posix + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ printfbad1: - @echo printfbad1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ @@ -2890,112 +2935,116 @@ printfbad3: @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ procinfs: - @echo procinfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ pty1: - @echo pty1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rebuf: - @echo rebuf + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ regx8bit: - @echo regx8bit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest6: - @echo rstest6 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ shadow: - @echo shadow + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sortfor: - @echo sortfor + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sortu: - @echo sortu + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitarg4: - @echo splitarg4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strtonum: - @echo strtonum + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ switch2: - @echo switch2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ double1: - @echo double1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ double2: - @echo double2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ intformat: - @echo intformat + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ asort: - @echo asort + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ asorti: - @echo asorti + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fmttest: - @echo fmttest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnarydel: - @echo fnarydel + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + $(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \ + fi fnparydl: - @echo fnparydl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + $(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \ + fi rebt8b2: - @echo rebt8b2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sort1: - @echo sort1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sprintfc: - @echo sprintfc + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ diff --git a/test/Maketests b/test/Maketests index b6168564..96825721 100644 --- a/test/Maketests +++ b/test/Maketests @@ -1,1082 +1,1077 @@ Gt-dummy: # file Maketests, generated from Makefile.am by the Gentests program addcomma: - @echo addcomma + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ anchgsub: - @echo anchgsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayparm: - @echo arrayparm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayprm2: - @echo arrayprm2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayprm3: - @echo arrayprm3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrayref: - @echo arrayref + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arrymem1: - @echo arrymem1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref2: - @echo arryref2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref3: - @echo arryref3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref4: - @echo arryref4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arryref5: - @echo arryref5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arynasty: - @echo arynasty + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm1: - @echo aryprm1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm2: - @echo aryprm2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm3: - @echo aryprm3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm4: - @echo aryprm4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm5: - @echo aryprm5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm6: - @echo aryprm6 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm7: - @echo aryprm7 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aryprm8: - @echo aryprm8 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arysubnm: - @echo arysubnm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ asgext: - @echo asgext + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ back89: - @echo back89 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ backgsub: - @echo backgsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ childin: - @echo childin + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ closebad: - @echo closebad + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ clsflnam: - @echo clsflnam + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ compare2: - @echo compare2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ concat1: - @echo concat1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ concat2: - @echo concat2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ concat3: - @echo concat3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ convfmt: - @echo convfmt + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ datanonl: - @echo datanonl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ defref: - @echo defref + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delargv: - @echo delargv + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delarpm2: - @echo delarpm2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delarprm: - @echo delarprm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delfunc: - @echo delfunc + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ dfastress: - @echo dfastress + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ dynlj: - @echo dynlj + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ eofsplit: - @echo eofsplit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ exitval2: - @echo exitval2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fcall_exit: - @echo fcall_exit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fcall_exit2: - @echo fcall_exit2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fldchg: - @echo fldchg + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fldchgnf: - @echo fldchgnf + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnamedat: - @echo fnamedat + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnarray: - @echo fnarray + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnarray2: - @echo fnarray2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnaryscl: - @echo fnaryscl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnasgnm: - @echo fnasgnm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnmisc: - @echo fnmisc + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fordel: - @echo fordel + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ forref: - @echo forref + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ forsimp: - @echo forsimp + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fsbs: - @echo fsbs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fsrs: - @echo fsrs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fstabplus: - @echo fstabplus + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funsemnl: - @echo funsemnl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funsmnam: - @echo funsmnam + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funstack: - @echo funstack + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getline: - @echo getline + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getline3: - @echo getline3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getline4: - @echo getline4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getnr2tb: - @echo getnr2tb + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getnr2tm: - @echo getnr2tm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubasgn: - @echo gsubasgn + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtest: - @echo gsubtest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst2: - @echo gsubtst2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst4: - @echo gsubtst4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst5: - @echo gsubtst5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst7: - @echo gsubtst7 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gsubtst8: - @echo gsubtst8 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ hex: - @echo hex + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ hsprint: - @echo hsprint + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ inputred: - @echo inputred + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ intest: - @echo intest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ intprec: - @echo intprec + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ iobug1: - @echo iobug1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ leadnl: - @echo leadnl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ longsub: - @echo longsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ longwrds: - @echo longwrds + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ manglprm: - @echo manglprm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ math: - @echo math + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ membug1: - @echo membug1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ minusstr: - @echo minusstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nasty: - @echo nasty + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nasty2: - @echo nasty2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ negexp: - @echo negexp + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ negrange: - @echo negrange + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nested: - @echo nested + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nfldstr: - @echo nfldstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nfneg: - @echo nfneg + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nfset: - @echo nfset + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nlfldsep: - @echo nlfldsep + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nlinstr: - @echo nlinstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nlstrina: - @echo nlstrina + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noeffect: - @echo noeffect + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nofmtch: - @echo nofmtch + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noloop1: - @echo noloop1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noloop2: - @echo noloop2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ noparms: - @echo noparms + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nulrsend: - @echo nulrsend + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ numindex: - @echo numindex + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ numsubstr: - @echo numsubstr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ octsub: - @echo octsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmt: - @echo ofmt + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmta: - @echo ofmta + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmtbig: - @echo ofmtbig + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmtfidl: - @echo ofmtfidl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ofmts: - @echo ofmts + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ onlynl: - @echo onlynl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ opasnidx: - @echo opasnidx + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ opasnslf: - @echo opasnslf + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ paramdup: - @echo paramdup + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ paramres: - @echo paramres + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ paramtyp: - @echo paramtyp + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ parse1: - @echo parse1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ parsefld: - @echo parsefld + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ parseme: - @echo parseme + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ pcntplus: - @echo pcntplus + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prdupval: - @echo prdupval + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prec: - @echo prec + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ printf1: - @echo printf1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prmarscl: - @echo prmarscl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prmreuse: - @echo prmreuse + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prt1eval: - @echo prt1eval + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ prtoeval: - @echo prtoeval - @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ - -rand: - @echo rand + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ range1: - @echo range1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rebt8b1: - @echo rebt8b1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ regeq: - @echo regeq + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ regrange: - @echo regrange + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ reindops: - @echo reindops + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ reparse: - @echo reparse + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ resplit: - @echo resplit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rs: - @echo rs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rsnul1nl: - @echo rsnul1nl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest1: - @echo rstest1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest2: - @echo rstest2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest3: - @echo rstest3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest4: - @echo rstest4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest5: - @echo rstest5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rswhite: - @echo rswhite + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ scalar: - @echo scalar + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sclforin: - @echo sclforin + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sclifin: - @echo sclifin + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sortempty: - @echo sortempty + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitargv: - @echo splitargv + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitarr: - @echo splitarr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitdef: - @echo splitdef + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitvar: - @echo splitvar + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitwht: - @echo splitwht + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strcat1: - @echo strcat1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strnum1: - @echo strnum1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strtod: - @echo strtod + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ subsepnm: - @echo subsepnm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ subslash: - @echo subslash + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ substr: - @echo substr + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ swaplns: - @echo swaplns + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ synerr1: - @echo synerr1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ synerr2: - @echo synerr2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit2: - @echo uninit2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit3: - @echo uninit3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit4: - @echo uninit4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninit5: - @echo uninit5 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uninitialized: - @echo uninitialized + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ unterm: - @echo unterm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ uparrfs: - @echo uparrfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ wjposer1: - @echo wjposer1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ zero2: - @echo zero2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ zeroe0: - @echo zeroe0 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ zeroflag: - @echo zeroflag + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getlnhd: - @echo getlnhd + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aadelete1: - @echo aadelete1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aadelete2: - @echo aadelete2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aarray1: - @echo aarray1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aasort: - @echo aasort + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ aasorti: - @echo aasorti + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ arraysort: - @echo arraysort + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ backw: - @echo backw + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ clos1way: - @echo clos1way + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ delsub: - @echo delsub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fieldwdth: - @echo fieldwdth + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpat1: - @echo fpat1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpat2: - @echo fpat2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpat3: - @echo fpat3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fpatnull: - @echo fpatnull + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fsfwfs: - @echo fsfwfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ funlen: - @echo funlen + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fwtest: - @echo fwtest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fwtest2: - @echo fwtest2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fwtest3: - @echo fwtest3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gensub: - @echo gensub + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gensub2: - @echo gensub2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ getlndir: - @echo getlndir + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gnuops2: - @echo gnuops2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gnuops3: - @echo gnuops3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ gnureops: - @echo gnureops + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ icasefs: - @echo icasefs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ icasers: - @echo icasers + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ igncdym: - @echo igncdym + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ igncfs: - @echo igncfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ignrcase: - @echo ignrcase + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ indirectcall: - @echo indirectcall + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ lint: - @echo lint + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ lintold: - @echo lintold + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint-old < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ lintwarn: - @echo lintwarn + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ match1: - @echo match1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ match2: - @echo match2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ match3: - @echo match3 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nastyparm: - @echo nastyparm + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ nondec: - @echo nondec + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ patsplit: - @echo patsplit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ posix: - @echo posix + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ printfbad1: - @echo printfbad1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ @@ -1086,112 +1081,116 @@ printfbad3: @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ procinfs: - @echo procinfs + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ pty1: - @echo pty1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rebuf: - @echo rebuf + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ regx8bit: - @echo regx8bit + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ rstest6: - @echo rstest6 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ shadow: - @echo shadow + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk --lint >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sortfor: - @echo sortfor + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sortu: - @echo sortu + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ splitarg4: - @echo splitarg4 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ strtonum: - @echo strtonum + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ switch2: - @echo switch2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ double1: - @echo double1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ double2: - @echo double2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ intformat: - @echo intformat + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ asort: - @echo asort + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ asorti: - @echo asorti + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fmttest: - @echo fmttest + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ fnarydel: - @echo fnarydel + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + $(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \ + fi fnparydl: - @echo fnparydl + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ - @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ + @-if test -z "$$AWKFLAGS" ; then $(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ ; else \ + $(CMP) $(srcdir)/$@-mpfr.ok _$@ && rm -f _$@ ; \ + fi rebt8b2: - @echo rebt8b2 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sort1: - @echo sort1 + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ sprintfc: - @echo sprintfc + @echo $@ @AWKPATH=$(srcdir) $(AWK) -f $@.awk < $(srcdir)/$@.in >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@ @-$(CMP) $(srcdir)/$@.ok _$@ && rm -f _$@ diff --git a/test/badargs.ok b/test/badargs.ok index cb140161..35c7d027 100644 --- a/test/badargs.ok +++ b/test/badargs.ok @@ -18,6 +18,7 @@ Short options: GNU long options: (extensions) -l library --load=library -L [fatal] --lint[=fatal] -n --non-decimal-data + -M --bignum -N --use-lc-numeric -o[file] --pretty-print[=file] -O --optimize diff --git a/test/dumpvars.ok b/test/dumpvars.ok index 01d5fb78..73d3d306 100644 --- a/test/dumpvars.ok +++ b/test/dumpvars.ok @@ -16,7 +16,9 @@ NR: 3 OFMT: "%.6g" OFS: " " ORS: "\n" +PREC: 53 RLENGTH: 0 +ROUNDMODE: "N" RS: "\n" RSTART: 0 RT: "\n" diff --git a/test/fmtspcl-mpfr.ok b/test/fmtspcl-mpfr.ok new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/test/fmtspcl-mpfr.ok diff --git a/test/fnarydel-mpfr.ok b/test/fnarydel-mpfr.ok new file mode 100644 index 00000000..7f3e4531 --- /dev/null +++ b/test/fnarydel-mpfr.ok @@ -0,0 +1,27 @@ +first loop +4 +5 +6 +7 +8 +9 +1 +2 +3 +second loop +third loop +4 +5 +6 +7 +8 +9 +1 +2 +3 +call func +fourth loop +You should just see: 4 4 +4 4 +You should see nothing between this line +And this one diff --git a/test/fnparydl-mpfr.ok b/test/fnparydl-mpfr.ok new file mode 100644 index 00000000..26a5c390 --- /dev/null +++ b/test/fnparydl-mpfr.ok @@ -0,0 +1,10 @@ +BEFORE LOOP +DELETING KEY 4 +DELETING KEY 5 +DELETING KEY 6 +DELETING KEY 7 +DELETING KEY 1 +DELETING KEY 2 +DELETING KEY 3 +AFTER LOOP +0 elements still in q[] diff --git a/test/mpfrbigint.awk b/test/mpfrbigint.awk new file mode 100644 index 00000000..bfdd871a --- /dev/null +++ b/test/mpfrbigint.awk @@ -0,0 +1,11 @@ +BEGIN { + x = 5^4^3^2 + print "# of digits =", length(x) + print substr(x, 1, 20), "...", substr(x, length(x) - 19, 20) + + PREC = 1 + 3.321928095 * length(x); # 1 + digits * log2(10) + print "floating-point computation with precision =", PREC + y = 5.0^4.0^3.0^2.0 + print "# of digits =", length(y) + print substr(y, 1, 20), "...", substr(y, length(y) - 19, 20) +} diff --git a/test/mpfrbigint.ok b/test/mpfrbigint.ok new file mode 100644 index 00000000..670d4e07 --- /dev/null +++ b/test/mpfrbigint.ok @@ -0,0 +1,5 @@ +# of digits = 183231 +62060698786608744707 ... 92256259918212890625 +floating-point computation with precision = 608681 +# of digits = 183231 +62060698786608744707 ... 92256259918212890625 diff --git a/test/mpfrexprange.awk b/test/mpfrexprange.awk new file mode 100644 index 00000000..68e95a39 --- /dev/null +++ b/test/mpfrexprange.awk @@ -0,0 +1,7 @@ +# test change of allowed exponent range +BEGIN { + x=1.0e-10000 + print x+0 + PREC="double" + print x+0 +} diff --git a/test/mpfrexprange.ok b/test/mpfrexprange.ok new file mode 100644 index 00000000..4700ee22 --- /dev/null +++ b/test/mpfrexprange.ok @@ -0,0 +1,2 @@ +1e-10000 +0 diff --git a/test/mpfrieee.awk b/test/mpfrieee.awk new file mode 100644 index 00000000..dc6e120d --- /dev/null +++ b/test/mpfrieee.awk @@ -0,0 +1,13 @@ +# Test IEEE-754 binary double format +BEGIN { + x = 1.0e-320 + i = 0 + while (x > 0) { + printf("%.15e\n", x) + x /= 2 + + # terminate early when the test is going to fail. + if (++i > 50) + break + } +} diff --git a/test/mpfrieee.ok b/test/mpfrieee.ok new file mode 100644 index 00000000..e88f5c79 --- /dev/null +++ b/test/mpfrieee.ok @@ -0,0 +1,12 @@ +9.999888671826830e-321 +4.999944335913415e-321 +2.499972167956708e-321 +1.249986083978354e-321 +6.225227137599706e-322 +3.112613568799853e-322 +1.581010066691989e-322 +7.905050333459945e-323 +3.952525166729972e-323 +1.976262583364986e-323 +9.881312916824931e-324 +4.940656458412465e-324 diff --git a/test/mpfrnr.awk b/test/mpfrnr.awk new file mode 100644 index 00000000..1a3b753a --- /dev/null +++ b/test/mpfrnr.awk @@ -0,0 +1,10 @@ +# Test NR and FNR for file(s) with records > LONG_MAX +BEGIN { + NR = 0x7FFFFFFF +} +BEGINFILE { + FNR = 0x7fffffffffffffff +} +END { + print NR, NR-0x7FFFFFFF, FNR, FNR-0x7fffffffffffffff +} diff --git a/test/mpfrnr.in b/test/mpfrnr.in new file mode 100644 index 00000000..6ad36e52 --- /dev/null +++ b/test/mpfrnr.in @@ -0,0 +1,3 @@ +Line 1 +Line 2 +Line 3 diff --git a/test/mpfrnr.ok b/test/mpfrnr.ok new file mode 100644 index 00000000..e472f8bf --- /dev/null +++ b/test/mpfrnr.ok @@ -0,0 +1 @@ +2147483650 3 9223372036854775810 3 diff --git a/test/mpfrrnd.awk b/test/mpfrrnd.awk new file mode 100644 index 00000000..508ac26b --- /dev/null +++ b/test/mpfrrnd.awk @@ -0,0 +1,15 @@ +BEGIN { + N = 22/7 + printf(" %.15f\n", N) + + printf("* %.10f\n", N) # default + ROUNDMODE="N"; printf("N %.10f\n", N) + ROUNDMODE="U"; printf("U %.10f\n", N) + ROUNDMODE="D"; printf("D %.10f\n", N) + ROUNDMODE="Z"; printf("Z %.10f\n", N) + N = -N + ROUNDMODE="N"; printf("N %.10f\n", N) + ROUNDMODE="U"; printf("U %.10f\n", N) + ROUNDMODE="D"; printf("D %.10f\n", N) + ROUNDMODE="Z"; printf("Z %.10f\n", N) +} diff --git a/test/mpfrrnd.ok b/test/mpfrrnd.ok new file mode 100644 index 00000000..fceb937b --- /dev/null +++ b/test/mpfrrnd.ok @@ -0,0 +1,10 @@ + 3.142857142857143 +* 3.1428571429 +N 3.1428571429 +U 3.1428571429 +D 3.1428571428 +Z 3.1428571428 +N -3.1428571429 +U -3.1428571428 +D -3.1428571429 +Z -3.1428571428 diff --git a/test/mpfrsort.awk b/test/mpfrsort.awk new file mode 100644 index 00000000..6f7fa65c --- /dev/null +++ b/test/mpfrsort.awk @@ -0,0 +1,8 @@ +BEGIN { +# s = "1.0 +nan 0.0 -1 +inf -0.0 1 nan 1.0 -nan -inf 2.0" + s = "1.0 +nan 0.0 -1 +inf -0.0 1 1.0 -nan -inf 2.0" + split(s, a) + PROCINFO["sorted_in"] = "@val_num_asc" + for (i in a) + print a[i] +} diff --git a/test/mpfrsort.ok b/test/mpfrsort.ok new file mode 100644 index 00000000..77a51ecf --- /dev/null +++ b/test/mpfrsort.ok @@ -0,0 +1,11 @@ +-inf +-1 +-0.0 +0.0 +1 +1.0 +1.0 +2.0 ++inf ++nan +-nan diff --git a/test/rand-mpfr.ok b/test/rand-mpfr.ok new file mode 100644 index 00000000..76ab51b4 --- /dev/null +++ b/test/rand-mpfr.ok @@ -0,0 +1 @@ + 27 89 11 47 77 49 13 34 78 93 76 96 91 53 3 94 25 51 10 diff --git a/test/rand-mpfr1.ok b/test/rand-mpfr1.ok new file mode 100644 index 00000000..448f4032 --- /dev/null +++ b/test/rand-mpfr1.ok @@ -0,0 +1 @@ + 25 42 47 49 80 5 4 92 59 96 8 63 92 28 41 37 80 51 48 |