aboutsummaryrefslogtreecommitdiffstats
path: root/builtin.c
diff options
context:
space:
mode:
Diffstat (limited to 'builtin.c')
-rw-r--r--builtin.c166
1 files changed, 155 insertions, 11 deletions
diff --git a/builtin.c b/builtin.c
index dde3121c..99293b9a 100644
--- a/builtin.c
+++ b/builtin.c
@@ -129,10 +129,14 @@ wrerror:
if (fp == stdout && errno == EPIPE)
gawk_exit(EXIT_FATAL);
+
/* otherwise die verbosely */
- fatal(_("%s to \"%s\" failed (%s)"), from,
- rp ? rp->value : _("standard output"),
- errno ? strerror(errno) : _("reason unknown"));
+ if ((rp != NULL) ? is_non_fatal_redirect(rp->value) : is_non_fatal_std(fp))
+ update_ERRNO_int(errno);
+ else
+ fatal(_("%s to \"%s\" failed (%s)"), from,
+ rp ? rp->value : _("standard output"),
+ errno ? strerror(errno) : _("reason unknown"));
}
/* do_exp --- exponential function */
@@ -1639,7 +1643,7 @@ do_printf(int nargs, int redirtype)
FILE *fp = NULL;
NODE *tmp;
struct redirect *rp = NULL;
- int errflg; /* not used, sigh */
+ int errflg = 0;
NODE *redir_exp = NULL;
if (nargs == 0) {
@@ -1650,7 +1654,7 @@ do_printf(int nargs, int redirtype)
redir_exp = TOP();
if (redir_exp->type != Node_val)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
DEREF(redir_exp);
decr_sp();
}
@@ -1663,9 +1667,13 @@ do_printf(int nargs, int redirtype)
redir_exp = PEEK(nargs);
if (redir_exp->type != Node_val)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
if (rp != NULL)
fp = rp->output.fp;
+ else if (errflg) {
+ update_ERRNO_int(errflg);
+ return;
+ }
} else if (do_debug) /* only the debugger can change the default output */
fp = output_fp;
else
@@ -2078,7 +2086,7 @@ void
do_print(int nargs, int redirtype)
{
struct redirect *rp = NULL;
- int errflg; /* not used, sigh */
+ int errflg = 0;
FILE *fp = NULL;
int i;
NODE *redir_exp = NULL;
@@ -2090,9 +2098,13 @@ do_print(int nargs, int redirtype)
redir_exp = PEEK(nargs);
if (redir_exp->type != Node_val)
fatal(_("attempt to use array `%s' in a scalar context"), array_vname(redir_exp));
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
if (rp != NULL)
fp = rp->output.fp;
+ else if (errflg) {
+ update_ERRNO_int(errflg);
+ return;
+ }
} else if (do_debug) /* only the debugger can change the default output */
fp = output_fp;
else
@@ -2148,13 +2160,13 @@ do_print_rec(int nargs, int redirtype)
FILE *fp = NULL;
NODE *f0;
struct redirect *rp = NULL;
- int errflg; /* not used, sigh */
+ int errflg = 0;
NODE *redir_exp = NULL;
assert(nargs == 0);
if (redirtype != 0) {
redir_exp = TOP();
- rp = redirect(redir_exp, redirtype, & errflg);
+ rp = redirect(redir_exp, redirtype, & errflg, true);
if (rp != NULL)
fp = rp->output.fp;
DEREF(redir_exp);
@@ -2162,6 +2174,11 @@ do_print_rec(int nargs, int redirtype)
} else
fp = output_fp;
+ if (errflg) {
+ update_ERRNO_int(errflg);
+ return;
+ }
+
if (fp == NULL)
return;
@@ -2375,6 +2392,8 @@ static char *const state = (char *const) istate;
NODE *
do_rand(int nargs ATTRIBUTE_UNUSED)
{
+ double tmprand;
+#define RAND_DIVISOR ((double)GAWK_RANDOM_MAX+1.0)
if (firstrand) {
(void) initstate((unsigned) 1, state, SIZEOF_STATE);
/* don't need to srandom(1), initstate() does it for us. */
@@ -2386,7 +2405,66 @@ do_rand(int nargs ATTRIBUTE_UNUSED)
*
* 0 <= n < 1
*/
- return make_number((AWKNUM) (random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+ /*
+ * Date: Wed, 28 Aug 2013 17:52:46 -0700
+ * From: Bob Jewett <jewett@bill.scs.agilent.com>
+ *
+ * Call random() twice to fill in more bits in the value
+ * of the double. Also, there is a bug in random() such
+ * that when the values of successive values are combined
+ * like (rand1*rand2)^2, (rand3*rand4)^2, ... the
+ * resulting time series is not white noise. The
+ * following also seems to fix that bug.
+ *
+ * The add/subtract 0.5 keeps small bits from filling
+ * below 2^-53 in the double, not that anyone should be
+ * looking down there.
+ *
+ * Date: Wed, 25 Sep 2013 10:45:38 -0600 (MDT)
+ * From: "Nelson H. F. Beebe" <beebe@math.utah.edu>
+ * (4) The code is typical of many published fragments for converting
+ * from integer to floating-point, and I discuss the serious pitfalls
+ * in my book, because it leads to platform-dependent behavior at the
+ * end points of the interval [0,1]
+ *
+ * (5) the documentation in the gawk info node says
+ *
+ * `rand()'
+ * Return a random number. The values of `rand()' are uniformly
+ * distributed between zero and one. The value could be zero but is
+ * never one.(1)
+ *
+ * The division by RAND_DIVISOR may not guarantee that 1.0 is never
+ * returned: the programmer forgot the platform-dependent issue of
+ * rounding.
+ *
+ * For points 4 and 5, the safe way is a loop:
+ *
+ * double
+ * rand(void) // return value in [0.0, 1.0)
+ * {
+ * value = internal_rand();
+ *
+ * while (value == 1.0)
+ * value = internal_rand();
+ *
+ * return (value);
+ * }
+ */
+
+ do {
+ long d1, d2;
+ /*
+ * Do the calls in predictable order to avoid
+ * compiler differences in order of evaluation.
+ */
+ d1 = random();
+ d2 = random();
+ tmprand = 0.5 + ( (d1/RAND_DIVISOR + d2) / RAND_DIVISOR );
+ tmprand -= 0.5;
+ } while (tmprand == 1.0);
+
+ return make_number((AWKNUM) tmprand);
}
/* do_srand --- seed the random number generator */
@@ -3674,6 +3752,72 @@ do_bindtextdomain(int nargs)
return make_string(the_result, strlen(the_result));
}
+/* do_div --- do integer division, return quotient and remainder in dest array */
+
+/*
+ * We define the semantics as:
+ * numerator = int(numerator)
+ * denominator = int(denonmator)
+ * quotient = int(numerator / denomator)
+ * remainder = int(numerator % denomator)
+ */
+
+NODE *
+do_div(int nargs)
+{
+ NODE *numerator, *denominator, *result;
+ double num, denom, quotient, remainder;
+ NODE *sub, **lhs;
+
+ result = POP_PARAM();
+ if (result->type != Node_var_array)
+ fatal(_("div: third argument is not an array"));
+ assoc_clear(result);
+
+ denominator = POP_SCALAR();
+ numerator = POP_SCALAR();
+
+ if (do_lint) {
+ if ((numerator->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("div: received non-numeric first argument"));
+ if ((denominator->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("div: received non-numeric second argument"));
+ }
+
+ (void) force_number(numerator);
+ (void) force_number(denominator);
+ num = double_to_int(get_number_d(numerator));
+ denom = double_to_int(get_number_d(denominator));
+
+ if (denom == 0.0)
+ fatal(_("div: division by zero attempted"));
+
+ quotient = double_to_int(num / denom);
+ /*
+ * FIXME: This code is duplicated, factor it out to a
+ * separate function.
+ */
+#ifdef HAVE_FMOD
+ remainder = fmod(num, denom);
+#else /* ! HAVE_FMOD */
+ (void) modf(num / denom, & remainder);
+ remainder = num - remainder * denom;
+#endif /* ! HAVE_FMOD */
+ remainder = double_to_int(remainder);
+
+ sub = make_string("quotient", 8);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = make_number((AWKNUM) quotient);
+
+ sub = make_string("remainder", 9);
+ lhs = assoc_lookup(result, sub);
+ unref(*lhs);
+ *lhs = make_number((AWKNUM) remainder);
+
+ return make_number((AWKNUM) 0.0);
+}
+
/* mbc_byte_count --- return number of bytes for corresponding numchars multibyte characters */