aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog32
-rw-r--r--awk.h2
-rw-r--r--builtin.c99
-rw-r--r--doc/ChangeLog9
-rw-r--r--doc/gawk.info666
-rw-r--r--doc/gawk.texi28
-rw-r--r--doc/gawktexi.in28
-rw-r--r--field.c4
-rw-r--r--interpret.h17
-rw-r--r--mpfr.c20
-rw-r--r--pc/ChangeLog4
-rw-r--r--pc/Makefile.tst8
-rw-r--r--test/ChangeLog5
-rw-r--r--test/Makefile.am10
-rw-r--r--test/Makefile.in10
-rw-r--r--test/indirectbuiltin2.awk29
-rw-r--r--test/indirectbuiltin2.ok6
17 files changed, 640 insertions, 337 deletions
diff --git a/ChangeLog b/ChangeLog
index ebc22d9a..c4a9fe96 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,35 @@
+2022-02-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ Continue fixing indirect calls of builtins.
+
+ * awk.h (check_exact_args, check_args_min_max): Add declarations.
+ * builtin.c (check_exact_args, check_args_min_max): New functions.
+ (do_exp, do_fflush, do_index, do_int, do_isarray, do_length, do_log,
+ do_sqrt, do_strftime, do_systime, do_mktime, do_system, do_tolower,
+ do_toupper, do_atan2, do_sin, do_cos, do_rand, do_srand, do_match,
+ do_sub, do_lshift, do_rshift, do_compl, do_strtonum, do_dcgettext,
+ do_dcngettext, do_bindtextdomain, do_intdiv, do_typeof): Call
+ the argument checking functions.
+ (call_sub, call_match): Manually check argument count.
+ * field.c (do_split, do_patsplit): Call the argument checking
+ functions.
+ * interpret.h (r_interpret): For indirect call of extension functions,
+ pop the function name off the stack when done.
+ * mpfr.c (do_atan2, do_mpfr_func, do_mpfr_int, do_mpfr_compl,
+ do_mpfr_lshift, do_mpfr_rshift, do_mpfr_strtonum, do_mpfr_rand,
+ do_mpfr_srand, do_mpfr_intdiv): Call the argument checking functions.
+
+2022-02-04 Arnold D. Robbins <arnold@skeeve.com>
+
+ Start fixing issues with indirect calls of builtins.
+ Thanks to Denis Shirokov <cosmogen@gmail.com> for the initial report.
+ Much more remains to be done.
+
+ * builtin.c (do_length): Check number of arguments, fatal if not one.
+ If passed Node_var_new, turn it into the null string.
+ * interpret.h (r_interpret): For Op_indirect_call, pop the function
+ name off the stack.
+
2022-01-05 Arnold D. Robbins <arnold@skeeve.com>
* awkgram.y (change_namespace): New function. Extracted from
diff --git a/awk.h b/awk.h
index 581b977e..d1238c64 100644
--- a/awk.h
+++ b/awk.h
@@ -1520,6 +1520,8 @@ extern int strncasecmpmbs(const unsigned char *,
extern int sanitize_exit_status(int status);
extern void check_symtab_functab(NODE *dest, const char *fname, const char *msg);
extern NODE *do_mkbool(int nargs);
+extern void check_exact_args(int nargs, const char *fname, int count);
+extern void check_args_min_max(int nargs, const char *fname, int min, int max);
/* debug.c */
extern void init_debug(void);
extern int debug_prog(INSTRUCTION *pc);
diff --git a/builtin.c b/builtin.c
index a1f09690..2e772e87 100644
--- a/builtin.c
+++ b/builtin.c
@@ -90,6 +90,22 @@ fatal(_("attempt to use array `%s' in a scalar context"), array_vname(s1)); \
}} while (false)
+/* check argument counts --- for use when called indirectly */
+
+void
+check_exact_args(int nargs, const char *fname, int count)
+{
+ if (nargs != count)
+ fatal(_("%s: called with %d arguments"), fname, nargs);
+}
+
+void
+check_args_min_max(int nargs, const char *fname, int min, int max)
+{
+ if (nargs < min || nargs > max)
+ fatal(_("%s: called with %d arguments"), fname, nargs);
+}
+
/*
* Since we supply the version of random(), we know what
* value to use here.
@@ -173,6 +189,8 @@ do_exp(int nargs)
NODE *tmp;
double d, res;
+ check_exact_args(nargs, "exp", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "exp");
@@ -235,6 +253,8 @@ do_fflush(int nargs)
* Now, both calls flush everything.
*/
+ check_args_min_max(nargs, "fflush", 0, 1);
+
/* fflush() */
if (nargs == 0) {
status = flush_io(); // ERRNO updated
@@ -381,6 +401,8 @@ do_index(int nargs)
bool do_single_byte = false;
mbstate_t mbs1, mbs2;
+ check_exact_args(nargs, "index", 2);
+
if (gawk_mb_cur_max > 1) {
memset(& mbs1, 0, sizeof(mbstate_t));
memset(& mbs2, 0, sizeof(mbstate_t));
@@ -503,6 +525,8 @@ do_int(int nargs)
NODE *tmp;
double d;
+ check_exact_args(nargs, "int", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "int");
@@ -520,6 +544,8 @@ do_isarray(int nargs)
NODE *tmp;
int ret = 1;
+ check_exact_args(nargs, "isarray", 1);
+
tmp = POP();
if (tmp->type != Node_var_array) {
ret = 0;
@@ -538,6 +564,8 @@ do_length(int nargs)
NODE *tmp;
size_t len;
+ check_exact_args(nargs, "length", 1);
+
tmp = POP();
if (tmp->type == Node_var_array) {
static bool warned = false;
@@ -561,6 +589,10 @@ do_length(int nargs)
size = assoc_length(tmp);
return make_number(size);
+ } else if (tmp->type == Node_var_new) {
+ // this can happen from an indirect call
+ DEREF(tmp);
+ tmp = dupnode(Nnull_string);
}
assert(tmp->type == Node_val);
@@ -593,6 +625,8 @@ do_log(int nargs)
NODE *tmp;
double d, arg;
+ check_exact_args(nargs, "log", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "log");
@@ -1796,6 +1830,8 @@ do_sqrt(int nargs)
NODE *tmp;
double arg;
+ check_exact_args(nargs, "sqrt", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "sqrt");
@@ -1818,6 +1854,8 @@ do_substr(int nargs)
double d_index = 0, d_length = 0;
size_t src_len;
+ check_args_min_max(nargs, "substr", 2, 3);
+
if (nargs == 3) {
t1 = POP_NUMBER();
d_length = get_number_d(t1);
@@ -1982,6 +2020,8 @@ do_strftime(int nargs)
(void) time(& fclock); /* current time of day */
do_gmt = false;
+ check_args_min_max(nargs, "strftime", 0, 3);
+
if (PROCINFO_node != NULL) {
sub = make_string("strftime", 8);
val = in_array(PROCINFO_node, sub);
@@ -2098,6 +2138,8 @@ do_systime(int nargs ATTRIBUTE_UNUSED)
{
time_t lclock;
+ check_exact_args(nargs, "systime", 0);
+
(void) time(& lclock);
return make_number((AWKNUM) lclock);
}
@@ -2116,6 +2158,8 @@ do_mktime(int nargs)
char save;
bool do_gmt;
+ check_args_min_max(nargs, "mktime", 1, 2);
+
if (nargs == 2) {
t2 = POP_SCALAR();
do_gmt = boolval(t2);
@@ -2179,6 +2223,8 @@ do_system(int nargs)
char save;
int status;
+ check_exact_args(nargs, "system", 1);
+
if (do_sandbox)
fatal(_("'system' function not allowed in sandbox mode"));
@@ -2435,6 +2481,8 @@ do_tolower(int nargs)
{
NODE *t1, *t2;
+ check_exact_args(nargs, "tolower", 1);
+
t1 = POP_SCALAR();
if (do_lint && (fixtype(t1)->flags & STRING) == 0)
lintwarn(_("%s: received non-string argument"), "tolower");
@@ -2466,6 +2514,8 @@ do_toupper(int nargs)
{
NODE *t1, *t2;
+ check_exact_args(nargs, "toupper", 1);
+
t1 = POP_SCALAR();
if (do_lint && (fixtype(t1)->flags & STRING) == 0)
lintwarn(_("%s: received non-string argument"), "toupper");
@@ -2498,6 +2548,8 @@ do_atan2(int nargs)
NODE *t1, *t2;
double d1, d2;
+ check_exact_args(nargs, "atan2", 2);
+
POP_TWO_SCALARS(t1, t2);
if (do_lint) {
if ((fixtype(t1)->flags & NUMBER) == 0)
@@ -2520,6 +2572,8 @@ do_sin(int nargs)
NODE *tmp;
double d;
+ check_exact_args(nargs, "sin", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "sin");
@@ -2536,6 +2590,8 @@ do_cos(int nargs)
NODE *tmp;
double d;
+ check_exact_args(nargs, "cos", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "cos");
@@ -2557,6 +2613,9 @@ NODE *
do_rand(int nargs ATTRIBUTE_UNUSED)
{
double tmprand;
+
+ check_exact_args(nargs, "rand", 0);
+
#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0)
if (firstrand) {
(void) initstate((unsigned) 1, state, SIZEOF_STATE);
@@ -2647,6 +2706,8 @@ do_srand(int nargs)
(void) setstate(state);
}
+ check_args_min_max(nargs, "srand", 0, 1);
+
if (nargs == 0)
srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
else {
@@ -2679,6 +2740,8 @@ do_match(int nargs)
char *subsepstr;
size_t subseplen;
+ check_args_min_max(nargs, "match", 2, 3);
+
dest = NULL;
if (nargs == 3) { /* 3rd optional arg for the subpatterns */
dest = POP_PARAM();
@@ -2907,6 +2970,8 @@ do_sub(int nargs, unsigned int flags)
double d;
NODE *glob_flag;
+ check_exact_args(nargs, "gensub", 4);
+
tmp = PEEK(3);
rp = re_update(tmp);
@@ -2935,6 +3000,12 @@ do_sub(int nargs, unsigned int flags)
}
DEREF(glob_flag);
} else {
+ if ((flags & GSUB) != 0) {
+ check_exact_args(nargs, "gsub", 3);
+ } else {
+ check_exact_args(nargs, "sub", 3);
+ }
+
/* take care of regexp early, in case re_update is fatal */
tmp = PEEK(2);
@@ -3301,6 +3372,9 @@ call_sub(const char *name, int nargs)
PUSH_ADDRESS(lhs);
} else {
/* gensub */
+ if (nargs < 3 || nargs > 4)
+ fatal(_("indirect call to gensub requires three to four arguments"));
+
if (nargs == 4)
rhs = POP();
else
@@ -3360,6 +3434,9 @@ call_match(int nargs)
NODE *regex, *text, *array;
NODE *result;
+ if (nargs < 2 || nargs > 3)
+ fatal(_("indirect call to match requires two or three arguments"));
+
regex = text = array = NULL;
if (nargs == 3)
array = POP();
@@ -3401,8 +3478,8 @@ call_split_func(const char *name, int nargs)
NODE *result;
regex = seps = NULL;
- if (nargs < 2)
- fatal(_("indirect call to %s requires at least two arguments"),
+ if (nargs < 2 || nargs > 4)
+ fatal(_("indirect call to %s requires two to four arguments"),
name);
if (nargs == 4)
@@ -3466,6 +3543,8 @@ do_lshift(int nargs)
uintmax_t uval, ushift, res;
AWKNUM val, shift;
+ check_exact_args(nargs, "lshift", 2);
+
POP_TWO_SCALARS(s1, s2);
if (do_lint) {
if ((fixtype(s1)->flags & NUMBER) == 0)
@@ -3505,6 +3584,8 @@ do_rshift(int nargs)
uintmax_t uval, ushift, res;
AWKNUM val, shift;
+ check_exact_args(nargs, "rshift", 2);
+
POP_TWO_SCALARS(s1, s2);
if (do_lint) {
if ((fixtype(s1)->flags & NUMBER) == 0)
@@ -3637,6 +3718,8 @@ do_compl(int nargs)
double d;
uintmax_t uval;
+ check_exact_args(nargs, "compl", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), "compl");
@@ -3662,6 +3745,8 @@ do_strtonum(int nargs)
NODE *tmp;
AWKNUM d;
+ check_exact_args(nargs, "strtonum", 1);
+
tmp = fixtype(POP_SCALAR());
if ((tmp->flags & NUMBER) != 0)
d = (AWKNUM) tmp->numbr;
@@ -3863,6 +3948,8 @@ do_dcgettext(int nargs)
char *domain;
char save1 = '\0', save2 = '\0';
+ check_args_min_max(nargs, "dcgettext", 1, 3);
+
if (nargs == 3) { /* third argument */
tmp = POP_STRING();
lc_cat = localecategory_from_argument(tmp);
@@ -3924,6 +4011,8 @@ do_dcngettext(int nargs)
char save = '\0', save1 = '\0', save2 = '\0';
bool saved_end = false;
+ check_args_min_max(nargs, "dcngettext", 3, 5);
+
if (nargs == 5) { /* fifth argument */
tmp = POP_STRING();
lc_cat = localecategory_from_argument(tmp);
@@ -4005,6 +4094,8 @@ do_bindtextdomain(int nargs)
const char *directory, *domain;
const char *the_result;
+ check_args_min_max(nargs, "bindtextdomain", 1, 2);
+
t1 = t2 = NULL;
/* set defaults */
directory = NULL;
@@ -4058,6 +4149,8 @@ do_intdiv(int nargs)
NODE *numerator, *denominator, *result;
double num, denom, quotient, remainder;
+ check_exact_args(nargs, "intdiv", 3);
+
result = POP_PARAM();
if (result->type != Node_var_array)
fatal(_("intdiv: third argument is not an array"));
@@ -4115,6 +4208,8 @@ do_typeof(int nargs)
bool deref = true;
NODE *dbg;
+ check_args_min_max(nargs, "typeof", 1, 2);
+
if (nargs == 2) { /* 2nd optional arg for debugging */
dbg = POP_PARAM();
if (dbg->type != Node_var_array)
diff --git a/doc/ChangeLog b/doc/ChangeLog
index db08ab90..b44c5a8d 100644
--- a/doc/ChangeLog
+++ b/doc/ChangeLog
@@ -1,6 +1,13 @@
+2022-02-07 Arnold D. Robbins <arnold@skeeve.com>
+
+ * gawktexi.in (Indirect Calls): Expand discussion of calling
+ built-in functions directly.
+ (POSIX Floating Point Problems): Add a note that the sign of
+ NaN values can vary.
+
2022-01-05 Arnold D. Robbins <arnold@skeeve.com>
- * gawktexi.ini (Indirect Calls): Use `the_function' everywhere.
+ * gawktexi.in (Indirect Calls): Use `the_function' everywhere.
Thanks to John Naman, <gawker@703n.com> for the report.
2021-12-10 Arnold D. Robbins <arnold@skeeve.com>
diff --git a/doc/gawk.info b/doc/gawk.info
index 97cb96ca..f4afd8e3 100644
--- a/doc/gawk.info
+++ b/doc/gawk.info
@@ -15577,14 +15577,27 @@ Dynamic Extensions::). There are some limitations when calling built-in
functions indirectly, as follows.
* You cannot pass a regular expression constant to a built-in
- function through an indirect function call.(1) This applies to the
+ function through an indirect function call. This applies to the
'sub()', 'gsub()', 'gensub()', 'match()', 'split()' and
- 'patsplit()' functions.
+ 'patsplit()' functions. However, you can pass a strongly typed
+ regexp constant (*note Strong Regexp Constants::).
* If calling 'sub()' or 'gsub()', you may only pass two arguments,
since those functions are unusual in that they update their third
argument. This means that '$0' will be updated.
+ * You cannot indirectly call built-in functions that can take '$0' as
+ a default parameter; you must supply an argument instead. For
+ example, you must pass an argument to 'length()' if calling it
+ indirectly.
+
+ * Calling a built-in function indirectly with the wrong number of
+ arguments for that function causes a fatal error. For example,
+ calling 'length()' with two arguments. These errors are found at
+ runtime instead of when 'gawk' parses your program, since 'gawk'
+ doesn't know until runtime if you have passed the correct number of
+ arguments or not.
+
'gawk' does its best to make indirect function calls efficient. For
example, in the following case:
@@ -15593,11 +15606,6 @@ example, in the following case:
'gawk' looks up the actual function to call only once.
- ---------- Footnotes ----------
-
- (1) This may change in a future version; recheck the documentation
-that comes with your version of 'gawk' to see if it has.
-

File: gawk.info, Node: Functions Summary, Prev: Indirect Calls, Up: Functions
@@ -25278,6 +25286,13 @@ described: '+inf', '-inf', '+nan', or '-nan'. Similarly, in POSIX mode,
'gawk' prints the result of the system's C 'printf()' function using the
'%g' format string for the value, whatever that may be.
+ NOTE: The sign used for NaN values can vary! The result depends
+ upon both the underlying system architecture and the underlying
+ library used to format NaN values. In particular, it's possible to
+ get different results for the same function call depending upon
+ whether or not 'gawk' is running in MPFR mode ('-M') or not.
+ Caveat Emptor!
+
---------- Footnotes ----------
(1) You asked for it, you got it.
@@ -39042,325 +39057,324 @@ Ref: Function Caveats-Footnote-1637557
Node: Return Statement637677
Node: Dynamic Typing640656
Node: Indirect Calls641586
-Ref: Indirect Calls-Footnote-1651853
-Node: Functions Summary651981
-Node: Library Functions654686
-Ref: Library Functions-Footnote-1658293
-Ref: Library Functions-Footnote-2658436
-Node: Library Names658607
-Ref: Library Names-Footnote-1662274
-Ref: Library Names-Footnote-2662497
-Node: General Functions662583
-Node: Strtonum Function663765
-Node: Assert Function666787
-Node: Round Function670113
-Node: Cliff Random Function671653
-Node: Ordinal Functions672669
-Ref: Ordinal Functions-Footnote-1675732
-Ref: Ordinal Functions-Footnote-2675984
-Node: Join Function676194
-Ref: Join Function-Footnote-1677964
-Node: Getlocaltime Function678164
-Node: Readfile Function681906
-Node: Shell Quoting683883
-Node: Isnumeric Function685311
-Node: Data File Management686699
-Node: Filetrans Function687331
-Node: Rewind Function691427
-Node: File Checking693336
-Ref: File Checking-Footnote-1694670
-Node: Empty Files694871
-Node: Ignoring Assigns696850
-Node: Getopt Function698400
-Ref: Getopt Function-Footnote-1713697
-Node: Passwd Functions713897
-Ref: Passwd Functions-Footnote-1722736
-Node: Group Functions722824
-Ref: Group Functions-Footnote-1730722
-Node: Walking Arrays730929
-Node: Library Functions Summary733937
-Node: Library Exercises735343
-Node: Sample Programs735808
-Node: Running Examples736578
-Node: Clones737306
-Node: Cut Program738530
-Node: Egrep Program748670
-Node: Id Program757671
-Node: Split Program767606
-Ref: Split Program-Footnote-1777499
-Node: Tee Program777672
-Node: Uniq Program780462
-Node: Wc Program788050
-Node: Bytes vs. Characters788437
-Node: Using extensions789985
-Node: wc program790739
-Node: Miscellaneous Programs795604
-Node: Dupword Program796817
-Node: Alarm Program798847
-Node: Translate Program803702
-Ref: Translate Program-Footnote-1808267
-Node: Labels Program808537
-Ref: Labels Program-Footnote-1811888
-Node: Word Sorting811972
-Node: History Sorting816044
-Node: Extract Program818269
-Node: Simple Sed826282
-Node: Igawk Program829356
-Ref: Igawk Program-Footnote-1843687
-Ref: Igawk Program-Footnote-2843889
-Ref: Igawk Program-Footnote-3844011
-Node: Anagram Program844126
-Node: Signature Program847188
-Node: Programs Summary848435
-Node: Programs Exercises849649
-Ref: Programs Exercises-Footnote-1853779
-Node: Advanced Features853865
-Node: Nondecimal Data855996
-Node: Boolean Typed Values857594
-Node: Array Sorting859475
-Node: Controlling Array Traversal860180
-Ref: Controlling Array Traversal-Footnote-1868548
-Node: Array Sorting Functions868666
-Ref: Array Sorting Functions-Footnote-1874040
-Node: Two-way I/O874236
-Ref: Two-way I/O-Footnote-1881962
-Ref: Two-way I/O-Footnote-2882149
-Node: TCP/IP Networking882231
-Node: Profiling885307
-Node: Extension Philosophy894616
-Node: Advanced Features Summary896095
-Node: Internationalization898110
-Node: I18N and L10N899784
-Node: Explaining gettext900471
-Ref: Explaining gettext-Footnote-1906363
-Ref: Explaining gettext-Footnote-2906548
-Node: Programmer i18n906713
-Ref: Programmer i18n-Footnote-1911662
-Node: Translator i18n911711
-Node: String Extraction912505
-Ref: String Extraction-Footnote-1913637
-Node: Printf Ordering913723
-Ref: Printf Ordering-Footnote-1916509
-Node: I18N Portability916573
-Ref: I18N Portability-Footnote-1919029
-Node: I18N Example919092
-Ref: I18N Example-Footnote-1922367
-Ref: I18N Example-Footnote-2922440
-Node: Gawk I18N922549
-Node: I18N Summary923171
-Node: Debugger924512
-Node: Debugging925512
-Node: Debugging Concepts925953
-Node: Debugging Terms927762
-Node: Awk Debugging930337
-Ref: Awk Debugging-Footnote-1931282
-Node: Sample Debugging Session931414
-Node: Debugger Invocation931948
-Node: Finding The Bug933334
-Node: List of Debugger Commands939808
-Node: Breakpoint Control941141
-Node: Debugger Execution Control944835
-Node: Viewing And Changing Data948197
-Node: Execution Stack951738
-Node: Debugger Info953375
-Node: Miscellaneous Debugger Commands957446
-Node: Readline Support962508
-Node: Limitations963404
-Node: Debugging Summary965958
-Node: Namespaces967237
-Node: Global Namespace968348
-Node: Qualified Names969746
-Node: Default Namespace970745
-Node: Changing The Namespace971486
-Node: Naming Rules973100
-Node: Internal Name Management974948
-Node: Namespace Example975990
-Node: Namespace And Features978552
-Node: Namespace Summary979987
-Node: Arbitrary Precision Arithmetic981464
-Node: Computer Arithmetic982951
-Ref: table-numeric-ranges986717
-Ref: table-floating-point-ranges987211
-Ref: Computer Arithmetic-Footnote-1987870
-Node: Math Definitions987927
-Ref: table-ieee-formats990903
-Node: MPFR features991471
-Node: FP Math Caution993189
-Ref: FP Math Caution-Footnote-1994261
-Node: Inexactness of computations994630
-Node: Inexact representation995661
-Node: Comparing FP Values997021
-Node: Errors accumulate998262
-Node: Strange values999718
-Ref: Strange values-Footnote-11002306
-Node: Getting Accuracy1002411
-Node: Try To Round1005121
-Node: Setting precision1006020
-Ref: table-predefined-precision-strings1006717
-Node: Setting the rounding mode1008548
-Ref: table-gawk-rounding-modes1008922
-Ref: Setting the rounding mode-Footnote-11012854
-Node: Arbitrary Precision Integers1013033
-Ref: Arbitrary Precision Integers-Footnote-11016208
-Node: Checking for MPFR1016357
-Node: POSIX Floating Point Problems1017831
-Ref: POSIX Floating Point Problems-Footnote-11022116
-Node: Floating point summary1022154
-Node: Dynamic Extensions1024344
-Node: Extension Intro1025897
-Node: Plugin License1027163
-Node: Extension Mechanism Outline1027960
-Ref: figure-load-extension1028399
-Ref: figure-register-new-function1029965
-Ref: figure-call-new-function1031058
-Node: Extension API Description1033121
-Node: Extension API Functions Introduction1034834
-Ref: table-api-std-headers1036670
-Node: General Data Types1040920
-Ref: General Data Types-Footnote-11049626
-Node: Memory Allocation Functions1049925
-Ref: Memory Allocation Functions-Footnote-11054426
-Node: Constructor Functions1054525
-Node: API Ownership of MPFR and GMP Values1058178
-Node: Registration Functions1059491
-Node: Extension Functions1060191
-Node: Exit Callback Functions1065513
-Node: Extension Version String1066763
-Node: Input Parsers1067426
-Node: Output Wrappers1080147
-Node: Two-way processors1084659
-Node: Printing Messages1086924
-Ref: Printing Messages-Footnote-11088095
-Node: Updating ERRNO1088248
-Node: Requesting Values1088987
-Ref: table-value-types-returned1089724
-Node: Accessing Parameters1090833
-Node: Symbol Table Access1092070
-Node: Symbol table by name1092582
-Ref: Symbol table by name-Footnote-11095607
-Node: Symbol table by cookie1095735
-Ref: Symbol table by cookie-Footnote-11099920
-Node: Cached values1099984
-Ref: Cached values-Footnote-11103520
-Node: Array Manipulation1103673
-Ref: Array Manipulation-Footnote-11104764
-Node: Array Data Types1104801
-Ref: Array Data Types-Footnote-11107459
-Node: Array Functions1107551
-Node: Flattening Arrays1112049
-Node: Creating Arrays1119025
-Node: Redirection API1123792
-Node: Extension API Variables1126625
-Node: Extension Versioning1127336
-Ref: gawk-api-version1127765
-Node: Extension GMP/MPFR Versioning1129497
-Node: Extension API Informational Variables1131125
-Node: Extension API Boilerplate1132198
-Node: Changes from API V11136172
-Node: Finding Extensions1137744
-Node: Extension Example1138303
-Node: Internal File Description1139101
-Node: Internal File Ops1143181
-Ref: Internal File Ops-Footnote-11154531
-Node: Using Internal File Ops1154671
-Ref: Using Internal File Ops-Footnote-11157054
-Node: Extension Samples1157328
-Node: Extension Sample File Functions1158857
-Node: Extension Sample Fnmatch1166506
-Node: Extension Sample Fork1167993
-Node: Extension Sample Inplace1169211
-Node: Extension Sample Ord1172837
-Node: Extension Sample Readdir1173673
-Ref: table-readdir-file-types1174562
-Node: Extension Sample Revout1175630
-Node: Extension Sample Rev2way1176219
-Node: Extension Sample Read write array1176959
-Node: Extension Sample Readfile1180125
-Node: Extension Sample Time1181220
-Node: Extension Sample API Tests1182972
-Node: gawkextlib1183464
-Node: Extension summary1186382
-Node: Extension Exercises1190084
-Node: Language History1191326
-Node: V7/SVR3.11192982
-Node: SVR41195134
-Node: POSIX1196568
-Node: BTL1197949
-Node: POSIX/GNU1198678
-Node: Feature History1204456
-Node: Common Extensions1221631
-Node: Ranges and Locales1222914
-Ref: Ranges and Locales-Footnote-11227530
-Ref: Ranges and Locales-Footnote-21227557
-Ref: Ranges and Locales-Footnote-31227792
-Node: Contributors1228015
-Node: History summary1234012
-Node: Installation1235392
-Node: Gawk Distribution1236336
-Node: Getting1236820
-Node: Extracting1237783
-Node: Distribution contents1239421
-Node: Unix Installation1246482
-Node: Quick Installation1247286
-Node: Compiling with MPFR1249706
-Node: Shell Startup Files1250396
-Node: Additional Configuration Options1251485
-Node: Configuration Philosophy1253800
-Node: Compiling from Git1256196
-Node: Building the Documentation1256751
-Node: Non-Unix Installation1258135
-Node: PC Installation1258595
-Node: PC Binary Installation1259433
-Node: PC Compiling1260306
-Node: PC Using1261423
-Node: Cygwin1264976
-Node: MSYS1266200
-Node: VMS Installation1266802
-Node: VMS Compilation1267521
-Ref: VMS Compilation-Footnote-11268750
-Node: VMS Dynamic Extensions1268808
-Node: VMS Installation Details1270493
-Node: VMS Running1272755
-Node: VMS GNV1277034
-Node: Bugs1277748
-Node: Bug definition1278660
-Node: Bug address1281596
-Node: Usenet1284984
-Node: Performance bugs1286173
-Node: Asking for help1289094
-Node: Maintainers1291061
-Node: Other Versions1292255
-Node: Installation summary1300419
-Node: Notes1301783
-Node: Compatibility Mode1302577
-Node: Additions1303359
-Node: Accessing The Source1304284
-Node: Adding Code1305721
-Node: New Ports1311913
-Node: Derived Files1316288
-Ref: Derived Files-Footnote-11321948
-Ref: Derived Files-Footnote-21321983
-Ref: Derived Files-Footnote-31322581
-Node: Future Extensions1322695
-Node: Implementation Limitations1323353
-Node: Extension Design1324563
-Node: Old Extension Problems1325707
-Ref: Old Extension Problems-Footnote-11327225
-Node: Extension New Mechanism Goals1327282
-Ref: Extension New Mechanism Goals-Footnote-11330646
-Node: Extension Other Design Decisions1330835
-Node: Extension Future Growth1332948
-Node: Notes summary1333554
-Node: Basic Concepts1334712
-Node: Basic High Level1335393
-Ref: figure-general-flow1335675
-Ref: figure-process-flow1336361
-Ref: Basic High Level-Footnote-11339663
-Node: Basic Data Typing1339848
-Node: Glossary1343176
-Node: Copying1375063
-Node: GNU Free Documentation License1412606
-Node: Index1437726
+Node: Functions Summary652513
+Node: Library Functions655218
+Ref: Library Functions-Footnote-1658825
+Ref: Library Functions-Footnote-2658968
+Node: Library Names659139
+Ref: Library Names-Footnote-1662806
+Ref: Library Names-Footnote-2663029
+Node: General Functions663115
+Node: Strtonum Function664297
+Node: Assert Function667319
+Node: Round Function670645
+Node: Cliff Random Function672185
+Node: Ordinal Functions673201
+Ref: Ordinal Functions-Footnote-1676264
+Ref: Ordinal Functions-Footnote-2676516
+Node: Join Function676726
+Ref: Join Function-Footnote-1678496
+Node: Getlocaltime Function678696
+Node: Readfile Function682438
+Node: Shell Quoting684415
+Node: Isnumeric Function685843
+Node: Data File Management687231
+Node: Filetrans Function687863
+Node: Rewind Function691959
+Node: File Checking693868
+Ref: File Checking-Footnote-1695202
+Node: Empty Files695403
+Node: Ignoring Assigns697382
+Node: Getopt Function698932
+Ref: Getopt Function-Footnote-1714229
+Node: Passwd Functions714429
+Ref: Passwd Functions-Footnote-1723268
+Node: Group Functions723356
+Ref: Group Functions-Footnote-1731254
+Node: Walking Arrays731461
+Node: Library Functions Summary734469
+Node: Library Exercises735875
+Node: Sample Programs736340
+Node: Running Examples737110
+Node: Clones737838
+Node: Cut Program739062
+Node: Egrep Program749202
+Node: Id Program758203
+Node: Split Program768138
+Ref: Split Program-Footnote-1778031
+Node: Tee Program778204
+Node: Uniq Program780994
+Node: Wc Program788582
+Node: Bytes vs. Characters788969
+Node: Using extensions790517
+Node: wc program791271
+Node: Miscellaneous Programs796136
+Node: Dupword Program797349
+Node: Alarm Program799379
+Node: Translate Program804234
+Ref: Translate Program-Footnote-1808799
+Node: Labels Program809069
+Ref: Labels Program-Footnote-1812420
+Node: Word Sorting812504
+Node: History Sorting816576
+Node: Extract Program818801
+Node: Simple Sed826814
+Node: Igawk Program829888
+Ref: Igawk Program-Footnote-1844219
+Ref: Igawk Program-Footnote-2844421
+Ref: Igawk Program-Footnote-3844543
+Node: Anagram Program844658
+Node: Signature Program847720
+Node: Programs Summary848967
+Node: Programs Exercises850181
+Ref: Programs Exercises-Footnote-1854311
+Node: Advanced Features854397
+Node: Nondecimal Data856528
+Node: Boolean Typed Values858126
+Node: Array Sorting860007
+Node: Controlling Array Traversal860712
+Ref: Controlling Array Traversal-Footnote-1869080
+Node: Array Sorting Functions869198
+Ref: Array Sorting Functions-Footnote-1874572
+Node: Two-way I/O874768
+Ref: Two-way I/O-Footnote-1882494
+Ref: Two-way I/O-Footnote-2882681
+Node: TCP/IP Networking882763
+Node: Profiling885839
+Node: Extension Philosophy895148
+Node: Advanced Features Summary896627
+Node: Internationalization898642
+Node: I18N and L10N900316
+Node: Explaining gettext901003
+Ref: Explaining gettext-Footnote-1906895
+Ref: Explaining gettext-Footnote-2907080
+Node: Programmer i18n907245
+Ref: Programmer i18n-Footnote-1912194
+Node: Translator i18n912243
+Node: String Extraction913037
+Ref: String Extraction-Footnote-1914169
+Node: Printf Ordering914255
+Ref: Printf Ordering-Footnote-1917041
+Node: I18N Portability917105
+Ref: I18N Portability-Footnote-1919561
+Node: I18N Example919624
+Ref: I18N Example-Footnote-1922899
+Ref: I18N Example-Footnote-2922972
+Node: Gawk I18N923081
+Node: I18N Summary923703
+Node: Debugger925044
+Node: Debugging926044
+Node: Debugging Concepts926485
+Node: Debugging Terms928294
+Node: Awk Debugging930869
+Ref: Awk Debugging-Footnote-1931814
+Node: Sample Debugging Session931946
+Node: Debugger Invocation932480
+Node: Finding The Bug933866
+Node: List of Debugger Commands940340
+Node: Breakpoint Control941673
+Node: Debugger Execution Control945367
+Node: Viewing And Changing Data948729
+Node: Execution Stack952270
+Node: Debugger Info953907
+Node: Miscellaneous Debugger Commands957978
+Node: Readline Support963040
+Node: Limitations963936
+Node: Debugging Summary966490
+Node: Namespaces967769
+Node: Global Namespace968880
+Node: Qualified Names970278
+Node: Default Namespace971277
+Node: Changing The Namespace972018
+Node: Naming Rules973632
+Node: Internal Name Management975480
+Node: Namespace Example976522
+Node: Namespace And Features979084
+Node: Namespace Summary980519
+Node: Arbitrary Precision Arithmetic981996
+Node: Computer Arithmetic983483
+Ref: table-numeric-ranges987249
+Ref: table-floating-point-ranges987743
+Ref: Computer Arithmetic-Footnote-1988402
+Node: Math Definitions988459
+Ref: table-ieee-formats991435
+Node: MPFR features992003
+Node: FP Math Caution993721
+Ref: FP Math Caution-Footnote-1994793
+Node: Inexactness of computations995162
+Node: Inexact representation996193
+Node: Comparing FP Values997553
+Node: Errors accumulate998794
+Node: Strange values1000250
+Ref: Strange values-Footnote-11002838
+Node: Getting Accuracy1002943
+Node: Try To Round1005653
+Node: Setting precision1006552
+Ref: table-predefined-precision-strings1007249
+Node: Setting the rounding mode1009080
+Ref: table-gawk-rounding-modes1009454
+Ref: Setting the rounding mode-Footnote-11013386
+Node: Arbitrary Precision Integers1013565
+Ref: Arbitrary Precision Integers-Footnote-11016740
+Node: Checking for MPFR1016889
+Node: POSIX Floating Point Problems1018363
+Ref: POSIX Floating Point Problems-Footnote-11023016
+Node: Floating point summary1023054
+Node: Dynamic Extensions1025244
+Node: Extension Intro1026797
+Node: Plugin License1028063
+Node: Extension Mechanism Outline1028860
+Ref: figure-load-extension1029299
+Ref: figure-register-new-function1030865
+Ref: figure-call-new-function1031958
+Node: Extension API Description1034021
+Node: Extension API Functions Introduction1035734
+Ref: table-api-std-headers1037570
+Node: General Data Types1041820
+Ref: General Data Types-Footnote-11050526
+Node: Memory Allocation Functions1050825
+Ref: Memory Allocation Functions-Footnote-11055326
+Node: Constructor Functions1055425
+Node: API Ownership of MPFR and GMP Values1059078
+Node: Registration Functions1060391
+Node: Extension Functions1061091
+Node: Exit Callback Functions1066413
+Node: Extension Version String1067663
+Node: Input Parsers1068326
+Node: Output Wrappers1081047
+Node: Two-way processors1085559
+Node: Printing Messages1087824
+Ref: Printing Messages-Footnote-11088995
+Node: Updating ERRNO1089148
+Node: Requesting Values1089887
+Ref: table-value-types-returned1090624
+Node: Accessing Parameters1091733
+Node: Symbol Table Access1092970
+Node: Symbol table by name1093482
+Ref: Symbol table by name-Footnote-11096507
+Node: Symbol table by cookie1096635
+Ref: Symbol table by cookie-Footnote-11100820
+Node: Cached values1100884
+Ref: Cached values-Footnote-11104420
+Node: Array Manipulation1104573
+Ref: Array Manipulation-Footnote-11105664
+Node: Array Data Types1105701
+Ref: Array Data Types-Footnote-11108359
+Node: Array Functions1108451
+Node: Flattening Arrays1112949
+Node: Creating Arrays1119925
+Node: Redirection API1124692
+Node: Extension API Variables1127525
+Node: Extension Versioning1128236
+Ref: gawk-api-version1128665
+Node: Extension GMP/MPFR Versioning1130397
+Node: Extension API Informational Variables1132025
+Node: Extension API Boilerplate1133098
+Node: Changes from API V11137072
+Node: Finding Extensions1138644
+Node: Extension Example1139203
+Node: Internal File Description1140001
+Node: Internal File Ops1144081
+Ref: Internal File Ops-Footnote-11155431
+Node: Using Internal File Ops1155571
+Ref: Using Internal File Ops-Footnote-11157954
+Node: Extension Samples1158228
+Node: Extension Sample File Functions1159757
+Node: Extension Sample Fnmatch1167406
+Node: Extension Sample Fork1168893
+Node: Extension Sample Inplace1170111
+Node: Extension Sample Ord1173737
+Node: Extension Sample Readdir1174573
+Ref: table-readdir-file-types1175462
+Node: Extension Sample Revout1176530
+Node: Extension Sample Rev2way1177119
+Node: Extension Sample Read write array1177859
+Node: Extension Sample Readfile1181025
+Node: Extension Sample Time1182120
+Node: Extension Sample API Tests1183872
+Node: gawkextlib1184364
+Node: Extension summary1187282
+Node: Extension Exercises1190984
+Node: Language History1192226
+Node: V7/SVR3.11193882
+Node: SVR41196034
+Node: POSIX1197468
+Node: BTL1198849
+Node: POSIX/GNU1199578
+Node: Feature History1205356
+Node: Common Extensions1222531
+Node: Ranges and Locales1223814
+Ref: Ranges and Locales-Footnote-11228430
+Ref: Ranges and Locales-Footnote-21228457
+Ref: Ranges and Locales-Footnote-31228692
+Node: Contributors1228915
+Node: History summary1234912
+Node: Installation1236292
+Node: Gawk Distribution1237236
+Node: Getting1237720
+Node: Extracting1238683
+Node: Distribution contents1240321
+Node: Unix Installation1247382
+Node: Quick Installation1248186
+Node: Compiling with MPFR1250606
+Node: Shell Startup Files1251296
+Node: Additional Configuration Options1252385
+Node: Configuration Philosophy1254700
+Node: Compiling from Git1257096
+Node: Building the Documentation1257651
+Node: Non-Unix Installation1259035
+Node: PC Installation1259495
+Node: PC Binary Installation1260333
+Node: PC Compiling1261206
+Node: PC Using1262323
+Node: Cygwin1265876
+Node: MSYS1267100
+Node: VMS Installation1267702
+Node: VMS Compilation1268421
+Ref: VMS Compilation-Footnote-11269650
+Node: VMS Dynamic Extensions1269708
+Node: VMS Installation Details1271393
+Node: VMS Running1273655
+Node: VMS GNV1277934
+Node: Bugs1278648
+Node: Bug definition1279560
+Node: Bug address1282496
+Node: Usenet1285884
+Node: Performance bugs1287073
+Node: Asking for help1289994
+Node: Maintainers1291961
+Node: Other Versions1293155
+Node: Installation summary1301319
+Node: Notes1302683
+Node: Compatibility Mode1303477
+Node: Additions1304259
+Node: Accessing The Source1305184
+Node: Adding Code1306621
+Node: New Ports1312813
+Node: Derived Files1317188
+Ref: Derived Files-Footnote-11322848
+Ref: Derived Files-Footnote-21322883
+Ref: Derived Files-Footnote-31323481
+Node: Future Extensions1323595
+Node: Implementation Limitations1324253
+Node: Extension Design1325463
+Node: Old Extension Problems1326607
+Ref: Old Extension Problems-Footnote-11328125
+Node: Extension New Mechanism Goals1328182
+Ref: Extension New Mechanism Goals-Footnote-11331546
+Node: Extension Other Design Decisions1331735
+Node: Extension Future Growth1333848
+Node: Notes summary1334454
+Node: Basic Concepts1335612
+Node: Basic High Level1336293
+Ref: figure-general-flow1336575
+Ref: figure-process-flow1337261
+Ref: Basic High Level-Footnote-11340563
+Node: Basic Data Typing1340748
+Node: Glossary1344076
+Node: Copying1375963
+Node: GNU Free Documentation License1413506
+Node: Index1438626

End Tag Table
diff --git a/doc/gawk.texi b/doc/gawk.texi
index 7fb6a570..dbacdb2f 100644
--- a/doc/gawk.texi
+++ b/doc/gawk.texi
@@ -22281,16 +22281,28 @@ built-in functions indirectly, as follows.
@itemize @value{BULLET}
@item
You cannot pass a regular expression constant to a built-in function
-through an indirect function call.@footnote{This may change in a future
-version; recheck the documentation that comes with your version of
-@command{gawk} to see if it has.} This applies to the @code{sub()},
+through an indirect function call. This applies to the @code{sub()},
@code{gsub()}, @code{gensub()}, @code{match()}, @code{split()} and
-@code{patsplit()} functions.
+@code{patsplit()} functions. However, you can pass a strongly typed
+regexp constant (@pxref{Strong Regexp Constants}).
@item
If calling @code{sub()} or @code{gsub()}, you may only pass two arguments,
since those functions are unusual in that they update their third argument.
This means that @code{$0} will be updated.
+
+@item
+You cannot indirectly call built-in functions that can take @code{$0} as
+a default parameter; you must supply an argument instead. For example,
+you must pass an argument to @code{length()} if calling it indirectly.
+
+@item
+Calling a built-in function indirectly with the wrong number of arguments
+for that function causes a fatal error. For example, calling
+@code{length()} with two arguments. These errors are found at runtime
+instead of when @command{gawk} parses your program, since @command{gawk}
+doesn't know until runtime if you have passed the correct number of
+arguments or not.
@end itemize
@command{gawk} does its best to make indirect function calls efficient.
@@ -35284,6 +35296,14 @@ Similarly, in POSIX mode, @command{gawk} prints the result of
the system's C @code{printf()} function using the @code{%g} format string
for the value, whatever that may be.
+@quotation NOTE
+The sign used for NaN values can vary! The result depends upon both
+the underlying system architecture and the underlying library used to
+format NaN values. In particular, it's possible to get different results
+for the same function call depending upon whether or not @command{gawk}
+is running in MPFR mode (@option{-M}) or not. Caveat Emptor!
+@end quotation
+
@node Floating point summary
@section Summary
diff --git a/doc/gawktexi.in b/doc/gawktexi.in
index f8c164e9..36850146 100644
--- a/doc/gawktexi.in
+++ b/doc/gawktexi.in
@@ -21193,16 +21193,28 @@ built-in functions indirectly, as follows.
@itemize @value{BULLET}
@item
You cannot pass a regular expression constant to a built-in function
-through an indirect function call.@footnote{This may change in a future
-version; recheck the documentation that comes with your version of
-@command{gawk} to see if it has.} This applies to the @code{sub()},
+through an indirect function call. This applies to the @code{sub()},
@code{gsub()}, @code{gensub()}, @code{match()}, @code{split()} and
-@code{patsplit()} functions.
+@code{patsplit()} functions. However, you can pass a strongly typed
+regexp constant (@pxref{Strong Regexp Constants}).
@item
If calling @code{sub()} or @code{gsub()}, you may only pass two arguments,
since those functions are unusual in that they update their third argument.
This means that @code{$0} will be updated.
+
+@item
+You cannot indirectly call built-in functions that can take @code{$0} as
+a default parameter; you must supply an argument instead. For example,
+you must pass an argument to @code{length()} if calling it indirectly.
+
+@item
+Calling a built-in function indirectly with the wrong number of arguments
+for that function causes a fatal error. For example, calling
+@code{length()} with two arguments. These errors are found at runtime
+instead of when @command{gawk} parses your program, since @command{gawk}
+doesn't know until runtime if you have passed the correct number of
+arguments or not.
@end itemize
@command{gawk} does its best to make indirect function calls efficient.
@@ -34127,6 +34139,14 @@ Similarly, in POSIX mode, @command{gawk} prints the result of
the system's C @code{printf()} function using the @code{%g} format string
for the value, whatever that may be.
+@quotation NOTE
+The sign used for NaN values can vary! The result depends upon both
+the underlying system architecture and the underlying library used to
+format NaN values. In particular, it's possible to get different results
+for the same function call depending upon whether or not @command{gawk}
+is running in MPFR mode (@option{-M}) or not. Caveat Emptor!
+@end quotation
+
@node Floating point summary
@section Summary
diff --git a/field.c b/field.c
index 1cbd547d..88309a88 100644
--- a/field.c
+++ b/field.c
@@ -979,6 +979,8 @@ do_split(int nargs)
Regexp *, Setfunc, NODE *, NODE *, bool);
Regexp *rp = NULL;
+ check_args_min_max(nargs, "split", 3, 4);
+
if (nargs == 4) {
static bool warned = false;
@@ -1081,6 +1083,8 @@ do_patsplit(int nargs)
char *s;
Regexp *rp = NULL;
+ check_args_min_max(nargs, "patsplit", 3, 4);
+
if (nargs == 4) {
sep_arr = POP_PARAM();
if (sep_arr->type != Node_var_array)
diff --git a/interpret.h b/interpret.h
index df70bd09..3d9ba572 100644
--- a/interpret.h
+++ b/interpret.h
@@ -67,6 +67,7 @@ r_interpret(INSTRUCTION *code)
Regexp *rp;
NODE *set_array = NULL; /* array with a post-assignment routine */
NODE *set_idx = NULL; /* the index of the array element */
+ bool in_indirect_call = false;
/* array subscript */
@@ -1059,6 +1060,14 @@ arrayfor:
DEREF(t1);
}
free_api_string_copies();
+
+ if (in_indirect_call) {
+ // pop function name off the stack
+ NODE *fname = POP();
+ DEREF(fname);
+ in_indirect_call = false;
+ }
+
PUSH(r);
}
break;
@@ -1132,6 +1141,7 @@ match_re:
NODE *f = NULL;
int arg_count;
char save;
+ NODE *function_name;
arg_count = (pc + 1)->expr_count;
t1 = PEEK(arg_count); /* indirect var */
@@ -1174,6 +1184,12 @@ match_re:
r = the_func(arg_count);
str_restore(t1, save);
+ // Normally, setup_frame() handles getting rid of the
+ // function name. Since we have called the builtin directly,
+ // we have to manually do this here.
+ function_name = POP();
+ DEREF(function_name);
+
PUSH(r);
break;
} else if (f->type != Node_func) {
@@ -1195,6 +1211,7 @@ match_re:
npc[1] = pc[1];
npc[1].func_name = fname; /* name of the builtin */
npc[1].c_function = bc->c_function;
+ in_indirect_call = true;
ni = npc;
JUMPTO(ni);
} else
diff --git a/mpfr.c b/mpfr.c
index 829f1f34..c09d2f03 100644
--- a/mpfr.c
+++ b/mpfr.c
@@ -767,6 +767,8 @@ do_mpfr_atan2(int nargs)
mpfr_ptr p1, p2;
int tval;
+ check_exact_args(nargs, "atan2", 2);
+
t2 = POP_SCALAR();
t1 = POP_SCALAR();
@@ -803,6 +805,8 @@ do_mpfr_func(const char *name,
int tval;
mpfr_prec_t argprec;
+ check_exact_args(nargs, name, 1);
+
t1 = POP_SCALAR();
if (do_lint && (fixtype(t1)->flags & NUMBER) == 0)
lintwarn(_("%s: received non-numeric argument"), name);
@@ -874,6 +878,8 @@ do_mpfr_int(int nargs)
{
NODE *tmp, *r;
+ check_exact_args(nargs, "int", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("int: received non-numeric argument"));
@@ -904,6 +910,8 @@ do_mpfr_compl(int nargs)
NODE *tmp, *r;
mpz_ptr zptr;
+ check_exact_args(nargs, "compl", 1);
+
tmp = POP_SCALAR();
if (do_lint && (fixtype(tmp)->flags & NUMBER) == 0)
lintwarn(_("compl: received non-numeric argument"));
@@ -1023,6 +1031,8 @@ do_mpfr_lshift(int nargs)
unsigned long shift;
mpz_ptr pz1, pz2;
+ check_exact_args(nargs, "lshift", 2);
+
t2 = POP_SCALAR();
t1 = POP_SCALAR();
@@ -1055,6 +1065,8 @@ do_mpfr_rshift(int nargs)
unsigned long shift;
mpz_ptr pz1, pz2;
+ check_exact_args(nargs, "rshift", 2);
+
t2 = POP_SCALAR();
t1 = POP_SCALAR();
@@ -1175,6 +1187,8 @@ do_mpfr_strtonum(int nargs)
{
NODE *tmp, *r;
+ check_exact_args(nargs, "strtonum", 1);
+
tmp = fixtype(POP_SCALAR());
if ((tmp->flags & NUMBER) == 0) {
r = mpg_integer(); /* will be changed to MPFR float if necessary in force_mpnum() */
@@ -1212,6 +1226,8 @@ do_mpfr_rand(int nargs ATTRIBUTE_UNUSED)
NODE *res;
int tval;
+ check_exact_args(nargs, "rand", 0);
+
if (firstrand) {
#if 0
/* Choose the default algorithm */
@@ -1262,6 +1278,8 @@ do_mpfr_srand(int nargs)
firstrand = false;
}
+ check_args_min_max(nargs, "srand", 0, 1);
+
res = mpg_integer();
mpz_set(res->mpg_i, seed); /* previous seed */
@@ -1303,6 +1321,8 @@ do_mpfr_intdiv(int nargs)
NODE *quotient, *remainder;
NODE *sub, **lhs;
+ check_exact_args(nargs, "intdiv", 3);
+
result = POP_PARAM();
if (result->type != Node_var_array)
fatal(_("intdiv: third argument is not an array"));
diff --git a/pc/ChangeLog b/pc/ChangeLog
index 7b6bc9f7..cbca6b52 100644
--- a/pc/ChangeLog
+++ b/pc/ChangeLog
@@ -1,3 +1,7 @@
+2022-02-09 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.tst: Regenerated.
+
2022-01-05 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.tst: Regenerated.
diff --git a/pc/Makefile.tst b/pc/Makefile.tst
index 5caf38cc..775ad2c1 100644
--- a/pc/Makefile.tst
+++ b/pc/Makefile.tst
@@ -197,6 +197,7 @@ GAWK_EXT_TESTS = \
icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase \
incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
include include2 indirectbuiltin indirectcall indirectcall2 \
+ indirectbuiltin2 \
inf-nan-torture intarray iolint isarrayunset lint lintexp \
lintindex lintint lintlength lintold lintplus lintset lintwarn \
manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime \
@@ -1245,6 +1246,13 @@ argcasfile:
@echo $@
@-$(AWK) -f "$(srcdir)"/$@.awk ARGC=1 ' /no/such/file' < "$(srcdir)/$@.in" >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+indirectbuiltin2:
+ @echo $@
+ @-for test in 0 1 2 3 4 5 ; do \
+ $(AWK) -v test=$$test -f "$(srcdir)"/$@.awk ; \
+ done > _$@ 2>&1 || exit 0
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
Gt-dummy:
# file Maketests, generated from Makefile.am by the Gentests program
addcomma:
diff --git a/test/ChangeLog b/test/ChangeLog
index 47289312..6cd59729 100644
--- a/test/ChangeLog
+++ b/test/ChangeLog
@@ -1,3 +1,8 @@
+2022-02-09 Arnold D. Robbins <arnold@skeeve.com>
+
+ * Makefile.am (EXTRA_DIST): indirectbuiltin2, new test.
+ * indirectbuiltin2.awk, indirectbuiltin2.ok: New files.
+
2022-01-05 Arnold D. Robbins <arnold@skeeve.com>
* Makefile.am (EXTRA_DIST): nsidentifier, new test.
diff --git a/test/Makefile.am b/test/Makefile.am
index 16606b09..ca4920fe 100644
--- a/test/Makefile.am
+++ b/test/Makefile.am
@@ -569,6 +569,8 @@ EXTRA_DIST = \
include.ok \
indirectbuiltin.awk \
indirectbuiltin.ok \
+ indirectbuiltin2.awk \
+ indirectbuiltin2.ok \
indirectcall2.awk \
indirectcall2.ok \
indirectcall.awk \
@@ -1455,6 +1457,7 @@ GAWK_EXT_TESTS = \
icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase \
incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
include include2 indirectbuiltin indirectcall indirectcall2 \
+ indirectbuiltin2 \
inf-nan-torture intarray iolint isarrayunset lint lintexp \
lintindex lintint lintlength lintold lintplus lintset lintwarn \
manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime \
@@ -2504,6 +2507,13 @@ argcasfile:
@-$(AWK) -f "$(srcdir)"/$@.awk ARGC=1 ' /no/such/file' < "$(srcdir)/$@.in" >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+indirectbuiltin2:
+ @echo $@
+ @-for test in 0 1 2 3 4 5 ; do \
+ $(AWK) -v test=$$test -f "$(srcdir)"/$@.awk ; \
+ done > _$@ 2>&1 || exit 0
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
# Targets generated for other tests:
include Maketests
diff --git a/test/Makefile.in b/test/Makefile.in
index cb4551e2..380a7d90 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -835,6 +835,8 @@ EXTRA_DIST = \
include.ok \
indirectbuiltin.awk \
indirectbuiltin.ok \
+ indirectbuiltin2.awk \
+ indirectbuiltin2.ok \
indirectcall2.awk \
indirectcall2.ok \
indirectcall.awk \
@@ -1721,6 +1723,7 @@ GAWK_EXT_TESTS = \
icasefs icasers id igncdym igncfs ignrcas2 ignrcas4 ignrcase \
incdupe incdupe2 incdupe3 incdupe4 incdupe5 incdupe6 incdupe7 \
include include2 indirectbuiltin indirectcall indirectcall2 \
+ indirectbuiltin2 \
inf-nan-torture intarray iolint isarrayunset lint lintexp \
lintindex lintint lintlength lintold lintplus lintset lintwarn \
manyfiles match1 match2 match3 mbstr1 mbstr2 mixed1 mktime \
@@ -2952,6 +2955,13 @@ argcasfile:
@echo $@
@-$(AWK) -f "$(srcdir)"/$@.awk ARGC=1 ' /no/such/file' < "$(srcdir)/$@.in" >_$@ 2>&1 || echo EXIT CODE: $$? >>_$@
@-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
+
+indirectbuiltin2:
+ @echo $@
+ @-for test in 0 1 2 3 4 5 ; do \
+ $(AWK) -v test=$$test -f "$(srcdir)"/$@.awk ; \
+ done > _$@ 2>&1 || exit 0
+ @-$(CMP) "$(srcdir)"/$@.ok _$@ && rm -f _$@
Gt-dummy:
# file Maketests, generated from Makefile.am by the Gentests program
addcomma:
diff --git a/test/indirectbuiltin2.awk b/test/indirectbuiltin2.awk
new file mode 100644
index 00000000..6409f91a
--- /dev/null
+++ b/test/indirectbuiltin2.awk
@@ -0,0 +1,29 @@
+@load "ordchr"
+
+BEGIN {
+ o = "ord" # check stack for indirect call of ext function
+ l = "length" # check bad args for function of 1 argument
+ m = "match" # check bad args for function of 3-4 argument
+ s = "systime" # check bad args for function of 0 arguments
+
+ switch (test) {
+ case 0:
+ print "indirect, " @o("A")
+ break
+ case 1:
+ print @l()
+ break
+ case 2:
+ print @l("a", "b")
+ break
+ case 3:
+ print @m(@/foo/)
+ break
+ case 4:
+ print @m(@/foo/, "bar", a, b)
+ break
+ case 5:
+ print @s("xxx")
+ break
+ }
+}
diff --git a/test/indirectbuiltin2.ok b/test/indirectbuiltin2.ok
new file mode 100644
index 00000000..dfb2005e
--- /dev/null
+++ b/test/indirectbuiltin2.ok
@@ -0,0 +1,6 @@
+indirect, 65
+gawk: ./indirectbuiltin2.awk:14: fatal: length: called with 0 arguments
+gawk: ./indirectbuiltin2.awk:17: fatal: length: called with 2 arguments
+gawk: ./indirectbuiltin2.awk:20: fatal: indirect call to match requires two or three arguments
+gawk: ./indirectbuiltin2.awk:23: fatal: indirect call to match requires two or three arguments
+gawk: ./indirectbuiltin2.awk:26: fatal: systime: called with 1 arguments