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