[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[gawk-diffs] [SCM] gawk branch, long-double, created. 685a7ea80272a51da2
From: |
John Haque |
Subject: |
[gawk-diffs] [SCM] gawk branch, long-double, created. 685a7ea80272a51da2b4c0051123ffd084abb2ec |
Date: |
Sat, 29 Dec 2012 12:31:47 +0000 |
This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "gawk".
The branch, long-double has been created
at 685a7ea80272a51da2b4c0051123ffd084abb2ec (commit)
- Log -----------------------------------------------------------------
http://git.sv.gnu.org/cgit/gawk.git/commit/?id=685a7ea80272a51da2b4c0051123ffd084abb2ec
commit 685a7ea80272a51da2b4c0051123ffd084abb2ec
Author: John Haque <address@hidden>
Date: Sat Dec 29 06:30:46 2012 -0600
Add support for long double numbers.
diff --git a/ChangeLog b/ChangeLog
index 01829c7..1694937 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2012-12-29 John Haque <address@hidden>
+
+ Add support for long double numbers.
+
+ * awk.h (awkldbl_hndlr): Declare.
+ (enum block_id): Add BLOCK_LDBL.
+ * gawkapi.c (api_sym_update_scalar): Update NODE flag
+ after freeing number.
+ * long_double.h: New file.
+ * long_double.c: New file.
+ * main.c (main): Added temporary option 'B' to select long double.
+ (print_numbr_hndlr_versions(): New entry for awkldbl_hndlr.
+ * node.c (BLOCK nextfree): New entry for long double.
+ * configure.ac: Added GAWK_USE_LONG_DOUBLE.
+ * Makefile.am: Added long_double.h and long_double.c.
+
2012-12-28 John Haque <address@hidden>
* double.c: Use make_awknum everywhere instead of make_number
diff --git a/Makefile.am b/Makefile.am
index 7a1b530..92ec47d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -110,6 +110,8 @@ base_sources = \
int_array.c \
interpret.h \
io.c \
+ long_double.c \
+ long_double.h \
mbsupport.h \
main.c \
mpfr.c \
diff --git a/Makefile.in b/Makefile.in
index 71df2f0..b6ff304 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -88,11 +88,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
@@ -108,11 +109,11 @@ am__objects_1 = array.$(OBJEXT) awkgram.$(OBJEXT)
builtin.$(OBJEXT) \
dfa.$(OBJEXT) double.$(OBJEXT) eval.$(OBJEXT) ext.$(OBJEXT) \
field.$(OBJEXT) floatcomp.$(OBJEXT) gawkapi.$(OBJEXT) \
gawkmisc.$(OBJEXT) getopt.$(OBJEXT) getopt1.$(OBJEXT) \
- int_array.$(OBJEXT) io.$(OBJEXT) main.$(OBJEXT) mpfr.$(OBJEXT) \
- msg.$(OBJEXT) node.$(OBJEXT) profile.$(OBJEXT) \
- random.$(OBJEXT) re.$(OBJEXT) regex.$(OBJEXT) \
- replace.$(OBJEXT) str_array.$(OBJEXT) symbol.$(OBJEXT) \
- version.$(OBJEXT)
+ int_array.$(OBJEXT) io.$(OBJEXT) long_double.$(OBJEXT) \
+ main.$(OBJEXT) mpfr.$(OBJEXT) msg.$(OBJEXT) node.$(OBJEXT) \
+ profile.$(OBJEXT) random.$(OBJEXT) re.$(OBJEXT) \
+ regex.$(OBJEXT) replace.$(OBJEXT) str_array.$(OBJEXT) \
+ symbol.$(OBJEXT) version.$(OBJEXT)
am_gawk_OBJECTS = $(am__objects_1)
gawk_OBJECTS = $(am_gawk_OBJECTS)
gawk_LDADD = $(LDADD)
@@ -291,6 +292,7 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
@@ -439,6 +441,8 @@ base_sources = \
int_array.c \
interpret.h \
io.c \
+ long_double.c \
+ long_double.h \
mbsupport.h \
main.c \
mpfr.c \
@@ -597,6 +601,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
address@hidden@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
@AMDEP_TRUE@@am__include@ @address@hidden/$(DEPDIR)/address@hidden@
diff --git a/aclocal.m4 b/aclocal.m4
index 1d4e9d2..d5c96fe 100644
--- a/aclocal.m4
+++ b/aclocal.m4
@@ -953,6 +953,7 @@ m4_include([m4/lib-ld.m4])
m4_include([m4/lib-link.m4])
m4_include([m4/lib-prefix.m4])
m4_include([m4/libsigsegv.m4])
+m4_include([m4/long_double.m4])
m4_include([m4/longlong.m4])
m4_include([m4/mpfr.m4])
m4_include([m4/nls.m4])
diff --git a/array.c b/array.c
index c5090d9..279cd09 100644
--- a/array.c
+++ b/array.c
@@ -701,7 +701,7 @@ assoc_info(NODE *subs, NODE *val, NODE *ndump, const char
*aname)
indent(indent_level);
fprintf(output_fp, "I: [%s:", aname);
if ((subs->flags & (MPFN|MPZN|INTIND)) == INTIND)
- fprintf(output_fp, "<%ld>", (long) subs->numbr);
+ fprintf(output_fp, "<%ld>", get_number_si(subs));
else
value_info(subs);
fprintf(output_fp, "]\n");
diff --git a/awk.h b/awk.h
index 89f2682..4f44e2b 100644
--- a/awk.h
+++ b/awk.h
@@ -1041,6 +1041,7 @@ enum block_id {
BLOCK_INVALID = 0, /* not legal */
BLOCK_NODE,
BLOCK_BUCKET,
+ BLOCK_LDBL,
BLOCK_MAX /* count */
};
@@ -1090,6 +1091,7 @@ extern char *source;
extern int (*interpret)(INSTRUCTION *); /* interpreter routine */
extern numbr_handler_t awknum_hndlr; /* double */
+extern numbr_handler_t awkldbl_hndlr; /* long double */
extern numbr_handler_t mpfp_hndlr; /* arbitrary-precision floating-point */
extern numbr_handler_t *numbr_hndlr; /* active handler */
diff --git a/awkgram.c b/awkgram.c
index 772cc36..3156184 100644
--- a/awkgram.c
+++ b/awkgram.c
@@ -745,11 +745,11 @@ static const yytype_uint16 yyrline[] =
1247, 1254, 1256, 1258, 1274, 1284, 1291, 1293, 1298, 1300,
1302, 1310, 1312, 1317, 1319, 1324, 1326, 1328, 1378, 1380,
1382, 1384, 1386, 1388, 1390, 1392, 1415, 1420, 1425, 1450,
- 1456, 1458, 1460, 1462, 1464, 1466, 1471, 1475, 1507, 1509,
- 1515, 1521, 1534, 1535, 1536, 1541, 1546, 1550, 1554, 1569,
- 1581, 1586, 1622, 1640, 1641, 1647, 1648, 1653, 1655, 1662,
- 1679, 1696, 1698, 1705, 1710, 1718, 1728, 1740, 1749, 1753,
- 1757, 1761, 1765, 1769, 1772, 1774, 1778, 1782, 1786
+ 1456, 1458, 1460, 1462, 1464, 1466, 1471, 1475, 1489, 1491,
+ 1497, 1503, 1516, 1517, 1518, 1523, 1528, 1532, 1536, 1551,
+ 1563, 1568, 1604, 1622, 1623, 1629, 1630, 1635, 1637, 1644,
+ 1661, 1678, 1680, 1687, 1692, 1700, 1710, 1722, 1731, 1735,
+ 1739, 1743, 1747, 1751, 1754, 1756, 1760, 1764, 1768
};
#endif
@@ -3693,40 +3693,22 @@ regular_print:
(yyval) =
list_append(list_append(list_create((yyvsp[(1) - (2)])),
instruction(Op_field_spec)),
(yyvsp[(2) - (2)]));
} else {
- if (do_optimize > 1 && (yyvsp[(2) - (2)])->nexti ==
(yyvsp[(2) - (2)])->lasti
- && (yyvsp[(2) - (2)])->nexti->opcode ==
Op_push_i
- && ((yyvsp[(2) -
(2)])->nexti->memory->flags & (MPFN|MPZN)) == 0
- ) {
- NODE *n = (yyvsp[(2) - (2)])->nexti->memory;
- if ((n->flags & (STRCUR|STRING)) != 0) {
- n->numbr = (AWKNUM) (n->stlen == 0);
- n->flags &= ~(STRCUR|STRING);
- n->flags |= (NUMCUR|NUMBER);
- efree(n->stptr);
- n->stptr = NULL;
- n->stlen = 0;
- } else
- n->numbr = (AWKNUM) (n->numbr == 0.0);
- bcfree((yyvsp[(1) - (2)]));
- (yyval) = (yyvsp[(2) - (2)]);
- } else {
- (yyvsp[(1) - (2)])->opcode = Op_not;
- add_lint((yyvsp[(2) - (2)]),
LINT_assign_in_cond);
- (yyval) = list_append((yyvsp[(2) - (2)]),
(yyvsp[(1) - (2)]));
- }
+ (yyvsp[(1) - (2)])->opcode = Op_not;
+ add_lint((yyvsp[(2) - (2)]), LINT_assign_in_cond);
+ (yyval) = list_append((yyvsp[(2) - (2)]), (yyvsp[(1) -
(2)]));
}
}
break;
case 148:
/* Line 1792 of yacc.c */
-#line 1508 "awkgram.y"
+#line 1490 "awkgram.y"
{ (yyval) = (yyvsp[(2) - (3)]); }
break;
case 149:
/* Line 1792 of yacc.c */
-#line 1510 "awkgram.y"
+#line 1492 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3736,7 +3718,7 @@ regular_print:
case 150:
/* Line 1792 of yacc.c */
-#line 1516 "awkgram.y"
+#line 1498 "awkgram.y"
{
(yyval) = snode((yyvsp[(3) - (4)]), (yyvsp[(1) - (4)]));
if ((yyval) == NULL)
@@ -3746,7 +3728,7 @@ regular_print:
case 151:
/* Line 1792 of yacc.c */
-#line 1522 "awkgram.y"
+#line 1504 "awkgram.y"
{
static bool warned = false;
@@ -3763,7 +3745,7 @@ regular_print:
case 154:
/* Line 1792 of yacc.c */
-#line 1537 "awkgram.y"
+#line 1519 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_preincrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) -
(2)]));
@@ -3772,7 +3754,7 @@ regular_print:
case 155:
/* Line 1792 of yacc.c */
-#line 1542 "awkgram.y"
+#line 1524 "awkgram.y"
{
(yyvsp[(1) - (2)])->opcode = Op_predecrement;
(yyval) = mk_assignment((yyvsp[(2) - (2)]), NULL, (yyvsp[(1) -
(2)]));
@@ -3781,7 +3763,7 @@ regular_print:
case 156:
/* Line 1792 of yacc.c */
-#line 1547 "awkgram.y"
+#line 1529 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3789,7 +3771,7 @@ regular_print:
case 157:
/* Line 1792 of yacc.c */
-#line 1551 "awkgram.y"
+#line 1533 "awkgram.y"
{
(yyval) = list_create((yyvsp[(1) - (1)]));
}
@@ -3797,7 +3779,7 @@ regular_print:
case 158:
/* Line 1792 of yacc.c */
-#line 1555 "awkgram.y"
+#line 1537 "awkgram.y"
{
if ((yyvsp[(2) - (2)])->lasti->opcode == Op_push_i
&& ((yyvsp[(2) - (2)])->lasti->memory->flags &
(STRCUR|STRING)) == 0
@@ -3816,7 +3798,7 @@ regular_print:
case 159:
/* Line 1792 of yacc.c */
-#line 1570 "awkgram.y"
+#line 1552 "awkgram.y"
{
/*
* was: $$ = $2
@@ -3829,7 +3811,7 @@ regular_print:
case 160:
/* Line 1792 of yacc.c */
-#line 1582 "awkgram.y"
+#line 1564 "awkgram.y"
{
func_use((yyvsp[(1) - (1)])->lasti->func_name, FUNC_USE);
(yyval) = (yyvsp[(1) - (1)]);
@@ -3838,7 +3820,7 @@ regular_print:
case 161:
/* Line 1792 of yacc.c */
-#line 1587 "awkgram.y"
+#line 1569 "awkgram.y"
{
/* indirect function call */
INSTRUCTION *f, *t;
@@ -3875,7 +3857,7 @@ regular_print:
case 162:
/* Line 1792 of yacc.c */
-#line 1623 "awkgram.y"
+#line 1605 "awkgram.y"
{
param_sanity((yyvsp[(3) - (4)]));
(yyvsp[(1) - (4)])->opcode = Op_func_call;
@@ -3893,37 +3875,37 @@ regular_print:
case 163:
/* Line 1792 of yacc.c */
-#line 1640 "awkgram.y"
+#line 1622 "awkgram.y"
{ (yyval) = NULL; }
break;
case 164:
/* Line 1792 of yacc.c */
-#line 1642 "awkgram.y"
+#line 1624 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 165:
/* Line 1792 of yacc.c */
-#line 1647 "awkgram.y"
+#line 1629 "awkgram.y"
{ (yyval) = NULL; }
break;
case 166:
/* Line 1792 of yacc.c */
-#line 1649 "awkgram.y"
+#line 1631 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 167:
/* Line 1792 of yacc.c */
-#line 1654 "awkgram.y"
+#line 1636 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 168:
/* Line 1792 of yacc.c */
-#line 1656 "awkgram.y"
+#line 1638 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -3931,7 +3913,7 @@ regular_print:
case 169:
/* Line 1792 of yacc.c */
-#line 1663 "awkgram.y"
+#line 1645 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->lasti;
int count = ip->sub_count; /* # of SUBSEP-seperated
expressions */
@@ -3949,7 +3931,7 @@ regular_print:
case 170:
/* Line 1792 of yacc.c */
-#line 1680 "awkgram.y"
+#line 1662 "awkgram.y"
{
INSTRUCTION *t = (yyvsp[(2) - (3)]);
if ((yyvsp[(2) - (3)]) == NULL) {
@@ -3967,13 +3949,13 @@ regular_print:
case 171:
/* Line 1792 of yacc.c */
-#line 1697 "awkgram.y"
+#line 1679 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); }
break;
case 172:
/* Line 1792 of yacc.c */
-#line 1699 "awkgram.y"
+#line 1681 "awkgram.y"
{
(yyval) = list_merge((yyvsp[(1) - (2)]), (yyvsp[(2) - (2)]));
}
@@ -3981,13 +3963,13 @@ regular_print:
case 173:
/* Line 1792 of yacc.c */
-#line 1706 "awkgram.y"
+#line 1688 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (2)]); }
break;
case 174:
/* Line 1792 of yacc.c */
-#line 1711 "awkgram.y"
+#line 1693 "awkgram.y"
{
char *var_name = (yyvsp[(1) - (1)])->lextok;
@@ -3999,7 +3981,7 @@ regular_print:
case 175:
/* Line 1792 of yacc.c */
-#line 1719 "awkgram.y"
+#line 1701 "awkgram.y"
{
char *arr = (yyvsp[(1) - (2)])->lextok;
(yyvsp[(1) - (2)])->memory = variable((yyvsp[(1) -
(2)])->source_line, arr, Node_var_new);
@@ -4010,7 +3992,7 @@ regular_print:
case 176:
/* Line 1792 of yacc.c */
-#line 1729 "awkgram.y"
+#line 1711 "awkgram.y"
{
INSTRUCTION *ip = (yyvsp[(1) - (1)])->nexti;
if (ip->opcode == Op_push
@@ -4026,7 +4008,7 @@ regular_print:
case 177:
/* Line 1792 of yacc.c */
-#line 1741 "awkgram.y"
+#line 1723 "awkgram.y"
{
(yyval) = list_append((yyvsp[(2) - (3)]), (yyvsp[(1) - (3)]));
if ((yyvsp[(3) - (3)]) != NULL)
@@ -4036,7 +4018,7 @@ regular_print:
case 178:
/* Line 1792 of yacc.c */
-#line 1750 "awkgram.y"
+#line 1732 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postincrement;
}
@@ -4044,7 +4026,7 @@ regular_print:
case 179:
/* Line 1792 of yacc.c */
-#line 1754 "awkgram.y"
+#line 1736 "awkgram.y"
{
(yyvsp[(1) - (1)])->opcode = Op_postdecrement;
}
@@ -4052,43 +4034,43 @@ regular_print:
case 180:
/* Line 1792 of yacc.c */
-#line 1757 "awkgram.y"
+#line 1739 "awkgram.y"
{ (yyval) = NULL; }
break;
case 182:
/* Line 1792 of yacc.c */
-#line 1765 "awkgram.y"
+#line 1747 "awkgram.y"
{ yyerrok; }
break;
case 183:
/* Line 1792 of yacc.c */
-#line 1769 "awkgram.y"
+#line 1751 "awkgram.y"
{ yyerrok; }
break;
case 186:
/* Line 1792 of yacc.c */
-#line 1778 "awkgram.y"
+#line 1760 "awkgram.y"
{ yyerrok; }
break;
case 187:
/* Line 1792 of yacc.c */
-#line 1782 "awkgram.y"
+#line 1764 "awkgram.y"
{ (yyval) = (yyvsp[(1) - (1)]); yyerrok; }
break;
case 188:
/* Line 1792 of yacc.c */
-#line 1786 "awkgram.y"
+#line 1768 "awkgram.y"
{ yyerrok; }
break;
/* Line 1792 of yacc.c */
-#line 4104 "awkgram.c"
+#line 4086 "awkgram.c"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -4320,7 +4302,7 @@ yyreturn:
/* Line 2055 of yacc.c */
-#line 1788 "awkgram.y"
+#line 1770 "awkgram.y"
struct token {
diff --git a/awkgram.y b/awkgram.y
index 985f37f..6112414 100644
--- a/awkgram.y
+++ b/awkgram.y
@@ -1481,27 +1481,9 @@ non_post_simp_exp
$$ = list_append(list_append(list_create($1),
instruction(Op_field_spec)),
$2);
} else {
- if (do_optimize > 1 && $2->nexti == $2->lasti
- && $2->nexti->opcode == Op_push_i
- && ($2->nexti->memory->flags &
(MPFN|MPZN)) == 0
- ) {
- NODE *n = $2->nexti->memory;
- if ((n->flags & (STRCUR|STRING)) != 0) {
- n->numbr = (AWKNUM) (n->stlen == 0);
- n->flags &= ~(STRCUR|STRING);
- n->flags |= (NUMCUR|NUMBER);
- efree(n->stptr);
- n->stptr = NULL;
- n->stlen = 0;
- } else
- n->numbr = (AWKNUM) (n->numbr == 0.0);
- bcfree($1);
- $$ = $2;
- } else {
- $1->opcode = Op_not;
- add_lint($2, LINT_assign_in_cond);
- $$ = list_append($2, $1);
- }
+ $1->opcode = Op_not;
+ add_lint($2, LINT_assign_in_cond);
+ $$ = list_append($2, $1);
}
}
| '(' exp r_paren
diff --git a/awklib/Makefile.in b/awklib/Makefile.in
index d4a7788..347d369 100644
--- a/awklib/Makefile.in
+++ b/awklib/Makefile.in
@@ -83,11 +83,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -215,6 +216,7 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
diff --git a/configh.in b/configh.in
index 350aac5..af6b30f 100644
--- a/configh.in
+++ b/configh.in
@@ -20,12 +20,18 @@
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
+/* Define to 1 if you have 'atan2l' function. */
+#undef HAVE_ATAN2L
+
/* Define to 1 if you have the `atexit' function. */
#undef HAVE_ATEXIT
/* Define to 1 if you have the `btowc' function. */
#undef HAVE_BTOWC
+/* Define to 1 if you have 'ceill' function. */
+#undef HAVE_CEILL
+
/* Define to 1 if you have the MacOS X function CFLocaleCopyCurrent in the
CoreFoundation framework. */
#undef HAVE_CFLOCALECOPYCURRENT
@@ -34,6 +40,9 @@
the CoreFoundation framework. */
#undef HAVE_CFPREFERENCESCOPYAPPVALUE
+/* Define to 1 if you have 'cosl' function. */
+#undef HAVE_COSL
+
/* Define if the GNU dcgettext() function is already present or preinstalled.
*/
#undef HAVE_DCGETTEXT
@@ -45,12 +54,21 @@
/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */
#undef HAVE_DOPRNT
+/* Define to 1 if you have 'expl' function. */
+#undef HAVE_EXPL
+
/* Define to 1 if you have the <fcntl.h> header file. */
#undef HAVE_FCNTL_H
+/* Define to 1 if you have 'floorl' function. */
+#undef HAVE_FLOORL
+
/* Define to 1 if you have the `fmod' function. */
#undef HAVE_FMOD
+/* Define to 1 if you have 'fmodl' function. */
+#undef HAVE_FMODL
+
/* have getaddrinfo */
#undef HAVE_GETADDRINFO
@@ -111,6 +129,12 @@
/* Define to 1 if you have the <locale.h> header file. */
#undef HAVE_LOCALE_H
+/* Define to 1 if you have 'logl' function. */
+#undef HAVE_LOGL
+
+/* Define to 1 if the system has the type `long double'. */
+#undef HAVE_LONG_DOUBLE
+
/* Define to 1 if the system has the type `long long int'. */
#undef HAVE_LONG_LONG_INT
@@ -162,6 +186,9 @@
/* Define to 1 if you have the `posix_openpt' function. */
#undef HAVE_POSIX_OPENPT
+/* Define to 1 if you have 'powl' function. */
+#undef HAVE_POWL
+
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
@@ -171,6 +198,9 @@
/* Define to 1 if you have the `setsid' function. */
#undef HAVE_SETSID
+/* Define to 1 if you have 'sinl' function. */
+#undef HAVE_SINL
+
/* Define to 1 if you have the `snprintf' function. */
#undef HAVE_SNPRINTF
@@ -180,6 +210,9 @@
/* we have sockets on this system */
#undef HAVE_SOCKETS
+/* Define to 1 if you have 'sqrtl' function. */
+#undef HAVE_SQRTL
+
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
@@ -225,6 +258,9 @@
/* Define to 1 if you have the `strtod' function. */
#undef HAVE_STRTOD
+/* Define to 1 if you have 'strtold' function. */
+#undef HAVE_STRTOLD
+
/* Define to 1 if you have the `strtoul' function. */
#undef HAVE_STRTOUL
@@ -375,6 +411,9 @@
/* force use of our version of strftime */
#undef USE_INCLUDED_STRFTIME
+/* Define to 1 if can use 'long double'. */
+#undef USE_LONG_DOUBLE
+
/* Enable extensions on AIX 3, Interix. */
#ifndef _ALL_SOURCE
# undef _ALL_SOURCE
diff --git a/configure b/configure
index fb1ad69..4bf106b 100755
--- a/configure
+++ b/configure
@@ -633,6 +633,7 @@ GAWKLIBEXT
LIBMPFR
LIBREADLINE
SOCKET_LIBS
+USE_LONG_DOUBLE
LIBSIGSEGV_PREFIX
LTLIBSIGSEGV
LIBSIGSEGV
@@ -8694,6 +8695,48 @@ _ACEOF
fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for long double" >&5
+$as_echo_n "checking for long double... " >&6; }
+if ${ac_cv_type_long_double+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$GCC" = yes; then
+ ac_cv_type_long_double=yes
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* The Stardent Vistra knows sizeof (long double), but does
+ not support it. */
+ long double foo = 0.0L;
+int
+main ()
+{
+static int test_array [1 - 2 * !(/* On Ultrix 4.3 cc, long double is 4 and
double is 8. */
+ sizeof (double) <= sizeof (long double))];
+test_array [0] = 0;
+return test_array [0];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_type_long_double=yes
+else
+ ac_cv_type_long_double=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_type_long_double" >&5
+$as_echo "$ac_cv_type_long_double" >&6; }
+ if test $ac_cv_type_long_double = yes; then
+
+$as_echo "#define HAVE_LONG_DOUBLE 1" >>confdefs.h
+
+ fi
+
ac_fn_c_check_type "$LINENO" "ssize_t" "ac_cv_type_ssize_t"
"$ac_includes_default"
if test "x$ac_cv_type_ssize_t" = xyes; then :
@@ -10182,6 +10225,611 @@ fi
$as_echo "$has_f_format" >&6; }
+ gawk_has_long_double=no
+ USE_LONG_DOUBLE=
+
+
+ if test $ac_cv_type_long_double = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether long double and
double are the same" >&5
+$as_echo_n "checking whether long double and double are the same... " >&6; }
+if ${gl_cv_long_double_equals_double+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <float.h>
+int
+main ()
+{
+typedef int check[sizeof (long double) == sizeof (double)
+ && LDBL_MANT_DIG == DBL_MANT_DIG
+ && LDBL_MAX_EXP == DBL_MAX_EXP
+ && LDBL_MIN_EXP == DBL_MIN_EXP
+ ? 1 : -1];
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ gl_cv_long_double_equals_double=yes
+else
+ gl_cv_long_double_equals_double=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result:
$gl_cv_long_double_equals_double" >&5
+$as_echo "$gl_cv_long_double_equals_double" >&6; }
+ if test $gl_cv_long_double_equals_double = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether printf
supports %Lf" >&5
+$as_echo_n "checking whether printf supports %Lf... " >&6; }
+if ${gawk_cv_has_L_format+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run test program while cross compiling
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+char buf[100];
+ sprintf(buf, "%Lf,%Lg,%Le", (long double) 1.0, (long double) 1.0,
(long double) 1.0);
+ if (strcmp(buf, "1.000000,1,1.000000e+00") == 0)
+ return 0;
+ return 1;
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+ gawk_cv_has_L_format=yes
+else
+ gawk_cv_has_L_format=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gawk_cv_has_L_format" >&5
+$as_echo "$gawk_cv_has_L_format" >&6; }
+ if test $gawk_cv_has_L_format = yes; then
+ gawk_has_long_double=yes
+ fi
+ fi
+ fi
+
+ if test $gawk_has_long_double = yes; then
+
+$as_echo "#define USE_LONG_DOUBLE 1" >>confdefs.h
+
+
+ ac_fn_c_check_func "$LINENO" "strtold" "ac_cv_func_strtold"
+if test "x$ac_cv_func_strtold" = xyes; then :
+
+fi
+
+ if test $ac_cv_func_strtold = yes; then
+
+$as_echo "#define HAVE_STRTOLD 1" >>confdefs.h
+
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sinl in -lm" >&5
+$as_echo_n "checking for sinl in -lm... " >&6; }
+if ${ac_cv_lib_m_sinl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sinl ();
+int
+main ()
+{
+return sinl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_sinl=yes
+else
+ ac_cv_lib_m_sinl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sinl" >&5
+$as_echo "$ac_cv_lib_m_sinl" >&6; }
+if test "x$ac_cv_lib_m_sinl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_sinl = yes; then
+
+$as_echo "#define HAVE_SINL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cosl in -lm" >&5
+$as_echo_n "checking for cosl in -lm... " >&6; }
+if ${ac_cv_lib_m_cosl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cosl ();
+int
+main ()
+{
+return cosl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_cosl=yes
+else
+ ac_cv_lib_m_cosl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_cosl" >&5
+$as_echo "$ac_cv_lib_m_cosl" >&6; }
+if test "x$ac_cv_lib_m_cosl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_cosl = yes; then
+
+$as_echo "#define HAVE_COSL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for atan2l in -lm" >&5
+$as_echo_n "checking for atan2l in -lm... " >&6; }
+if ${ac_cv_lib_m_atan2l+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char atan2l ();
+int
+main ()
+{
+return atan2l ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_atan2l=yes
+else
+ ac_cv_lib_m_atan2l=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_atan2l" >&5
+$as_echo "$ac_cv_lib_m_atan2l" >&6; }
+if test "x$ac_cv_lib_m_atan2l" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_atan2l = yes; then
+
+$as_echo "#define HAVE_ATAN2L 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for logl in -lm" >&5
+$as_echo_n "checking for logl in -lm... " >&6; }
+if ${ac_cv_lib_m_logl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char logl ();
+int
+main ()
+{
+return logl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_logl=yes
+else
+ ac_cv_lib_m_logl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_logl" >&5
+$as_echo "$ac_cv_lib_m_logl" >&6; }
+if test "x$ac_cv_lib_m_logl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_logl = yes; then
+
+$as_echo "#define HAVE_LOGL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for expl in -lm" >&5
+$as_echo_n "checking for expl in -lm... " >&6; }
+if ${ac_cv_lib_m_expl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char expl ();
+int
+main ()
+{
+return expl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_expl=yes
+else
+ ac_cv_lib_m_expl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_expl" >&5
+$as_echo "$ac_cv_lib_m_expl" >&6; }
+if test "x$ac_cv_lib_m_expl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_expl = yes; then
+
+$as_echo "#define HAVE_EXPL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for fmodl in -lm" >&5
+$as_echo_n "checking for fmodl in -lm... " >&6; }
+if ${ac_cv_lib_m_fmodl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char fmodl ();
+int
+main ()
+{
+return fmodl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_fmodl=yes
+else
+ ac_cv_lib_m_fmodl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_fmodl" >&5
+$as_echo "$ac_cv_lib_m_fmodl" >&6; }
+if test "x$ac_cv_lib_m_fmodl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_fmodl = yes; then
+
+$as_echo "#define HAVE_FMODL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for floorl in -lm" >&5
+$as_echo_n "checking for floorl in -lm... " >&6; }
+if ${ac_cv_lib_m_floorl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char floorl ();
+int
+main ()
+{
+return floorl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_floorl=yes
+else
+ ac_cv_lib_m_floorl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_floorl" >&5
+$as_echo "$ac_cv_lib_m_floorl" >&6; }
+if test "x$ac_cv_lib_m_floorl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_floorl = yes; then
+
+$as_echo "#define HAVE_FLOORL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ceill in -lm" >&5
+$as_echo_n "checking for ceill in -lm... " >&6; }
+if ${ac_cv_lib_m_ceill+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ceill ();
+int
+main ()
+{
+return ceill ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_ceill=yes
+else
+ ac_cv_lib_m_ceill=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_ceill" >&5
+$as_echo "$ac_cv_lib_m_ceill" >&6; }
+if test "x$ac_cv_lib_m_ceill" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_ceill = yes; then
+
+$as_echo "#define HAVE_CEILL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for powl in -lm" >&5
+$as_echo_n "checking for powl in -lm... " >&6; }
+if ${ac_cv_lib_m_powl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char powl ();
+int
+main ()
+{
+return powl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_powl=yes
+else
+ ac_cv_lib_m_powl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_powl" >&5
+$as_echo "$ac_cv_lib_m_powl" >&6; }
+if test "x$ac_cv_lib_m_powl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_powl = yes; then
+
+$as_echo "#define HAVE_POWL 1" >>confdefs.h
+
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for sqrtl in -lm" >&5
+$as_echo_n "checking for sqrtl in -lm... " >&6; }
+if ${ac_cv_lib_m_sqrtl+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lm $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sqrtl ();
+int
+main ()
+{
+return sqrtl ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_m_sqrtl=yes
+else
+ ac_cv_lib_m_sqrtl=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_m_sqrtl" >&5
+$as_echo "$ac_cv_lib_m_sqrtl" >&6; }
+if test "x$ac_cv_lib_m_sqrtl" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBM 1
+_ACEOF
+
+ LIBS="-lm $LIBS"
+
+fi
+
+ if test $ac_cv_lib_m_sqrtl = yes; then
+
+$as_echo "#define HAVE_SQRTL 1" >>confdefs.h
+
+ fi
+ fi
+
+
+
+
+
gawk_have_sockets=no
# Check for system-dependent location of socket libraries
diff --git a/configure.ac b/configure.ac
index fef29e0..d3780bd 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,7 @@ AC_TYPE_LONG_LONG_INT
AC_TYPE_UNSIGNED_LONG_LONG_INT
AC_TYPE_INTMAX_T
AC_TYPE_UINTMAX_T
+AC_TYPE_LONG_DOUBLE
AC_CHECK_TYPE(ssize_t, int)
AC_CHECK_SIZEOF(unsigned int)
AC_CHECK_SIZEOF(unsigned long)
@@ -343,6 +344,9 @@ if test "$has_f_format" = yes; then
fi
AC_MSG_RESULT($has_f_format)
+dnl see if long double is usable
+GAWK_USE_LONG_DOUBLE
+
dnl check for sockets
GAWK_AC_LIB_SOCKETS
diff --git a/doc/Makefile.in b/doc/Makefile.in
index 93e88c2..691d030 100644
--- a/doc/Makefile.in
+++ b/doc/Makefile.in
@@ -83,11 +83,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -210,6 +211,7 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
diff --git a/gawkapi.c b/gawkapi.c
index a64a62c..c22b3b2 100644
--- a/gawkapi.c
+++ b/gawkapi.c
@@ -661,12 +661,15 @@ api_sym_update_scalar(awk_ext_id_t id,
if ((r->flags & (MALLOC|STRCUR)) == (MALLOC|STRCUR))
efree(r->stptr);
- if (free_number && (r->flags & (NUMBER|NUMCUR)) != 0)
+ if (free_number && (r->flags & (NUMBER|NUMCUR)) != 0) {
free_number(r);
+ r->flags &= ~(NUMBER|NUMCUR);
+ }
free_wstr(r);
/* make_str_node(s, l, ALREADY_MALLOCED): */
r->numbr = 0;
+ r->qnumbr = NULL;
r->flags = (MALLOC|STRING|STRCUR);
r->stfmt = -1;
r->stptr = value->str_value.str;
diff --git a/long_double.c b/long_double.c
new file mode 100644
index 0000000..b50e3fe
--- /dev/null
+++ b/long_double.c
@@ -0,0 +1,2245 @@
+/*
+ * long_double.c - routines for C long double support in gawk.
+ */
+
+/*
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA
+ */
+
+#include "awk.h"
+
+#ifdef USE_LONG_DOUBLE
+#include "math.h"
+#include "random.h"
+#include "floatmagic.h" /* definition of isnan */
+
+#define AWKLDBL long double
+
+/* XXX: define to 1 to try AWKNUM as long double */
+/* #define AWKNUM_LDBL 1 */
+
+
+#include "long_double.h"
+
+#ifdef AWKNUM_LDBL
+#define LDBL(n) ((n)->numbr)
+#else
+#define LDBL(n) (*((AWKLDBL *) (n)->qnumbr))
+#endif
+
+/* Can declare these, since we always use the random shipped with gawk */
+extern char *initstate(unsigned long seed, char *state, long n);
+extern char *setstate(char *state);
+extern long random(void);
+extern void srandom(unsigned long seed);
+
+/*
+ * Since we supply the version of random(), we know what
+ * value to use here.
+ */
+#define GAWK_RANDOM_MAX 0x7fffffffL
+
+extern NODE **fmt_list; /* declared in eval.c */
+
+/*
+ * FIXME -- some of these are almost identical except for the number definition
+ * #define DBLNUM AWKNUM
+ * common routines
+ * #undef DBLNUM
+ * #define DBLNUM AWKLDBL
+ * ...
+ */
+
+/* exported routines */
+
+static NODE *make_awknum(AWKNUM);
+static void free_awkldbl(NODE *tmp);
+static int cmp_awkldbls(const NODE *, const NODE *);
+static void negate_awkldbl(NODE *);
+static NODE *str2awkldbl(char *, char **, int, bool);
+static NODE *force_awkldbl(NODE *);
+static NODE *format_awkldbl_val(const char *, int, NODE *);
+static unsigned long awkldbl_toulong(const NODE *);
+static long awkldbl_tolong(const NODE *);
+static AWKNUM awkldbl_todouble(const NODE *);
+static uintmax_t awkldbl_touintmax_t(const NODE *);
+static int awkldbl_sgn(const NODE *);
+static bool awkldbl_is_integer(const NODE *);
+static NODE *awkldbl_copy(const NODE *);
+static NODE *format_nodes_awkldbl(const char *, size_t, NODE **, long);
+static bool awkldbl_init(bltin_t **);
+static NODE *awkldbl_add(const NODE *, const NODE *);
+static NODE *awkldbl_sub(const NODE *, const NODE *);
+static NODE *awkldbl_mul(const NODE *, const NODE *);
+static NODE *awkldbl_div(const NODE *, const NODE *);
+static NODE *awkldbl_mod(const NODE *, const NODE *);
+static NODE *awkldbl_pow(const NODE *, const NODE *);
+static NODE *awkldbl_add_long(const NODE *, long);
+static NODE *awkldbl_update_var(NODE *);
+static void awkldbl_set_var(const NODE *);
+static long awkldbl_increment_var(const NODE *, long);
+static void awkldbl_init_vars(void);
+
+static NODE *do_and(int);
+static NODE *do_atan2(int);
+static NODE *do_compl(int);
+static NODE *do_cos(int);
+static NODE *do_exp(int);
+static NODE *do_int(int);
+static NODE *do_log(int);
+static NODE *do_lshift(int);
+static NODE *do_or(int);
+static NODE *do_rand(int);
+static NODE *do_rshift(int);
+static NODE *do_sin(int);
+static NODE *do_sqrt(int);
+static NODE *do_srand(int);
+static NODE *do_strtonum(int);
+static NODE *do_xor(int);
+
+/* private routines */
+static int is_ieee_magic_val(const char *val);
+static AWKLDBL get_ieee_magic_val(const char *val);
+static AWKLDBL calc_exp(AWKLDBL x1, AWKLDBL x2);
+static AWKLDBL double_to_int(AWKLDBL d);
+#ifndef AWKNUM_LDBL
+static NODE *make_awkldbl(AWKLDBL);
+#endif
+
+static long MFNR;
+static long MNR;
+
+#ifdef AWKNUM_LDBL
+#define get_long_double(d) /* nothing */
+#define free_long_double(d) /* nothing */
+#else
+#define get_long_double(d) getblock(d, BLOCK_LDBL, AWKLDBL *)
+#define free_long_double(d) freeblock(d, BLOCK_LDBL)
+#endif
+
+#if 0
+#define get_long_double(d) emalloc(d, void *, sizeof(AWKLDBL),
"long_double")
+#define free_long_double(d) efree(d)
+#endif
+
+numbr_handler_t awkldbl_hndlr = {
+ awkldbl_init,
+ NULL, /* version_str */
+ NULL, /* load_procinfo */
+ make_awknum,
+ str2awkldbl,
+ awkldbl_copy,
+#ifndef AWKNUM_LDBL
+ free_awkldbl,
+#else
+ NULL, /* free_awkldbl --- not needed for AWKNUM */
+#endif
+ force_awkldbl,
+ negate_awkldbl,
+ cmp_awkldbls,
+ awkldbl_sgn,
+ awkldbl_is_integer,
+ format_awkldbl_val,
+ format_nodes_awkldbl,
+ awkldbl_todouble,
+ awkldbl_tolong,
+ awkldbl_toulong,
+ awkldbl_touintmax_t,
+ awkldbl_add,
+ awkldbl_sub,
+ awkldbl_mul,
+ awkldbl_div,
+ awkldbl_mod,
+ awkldbl_pow,
+ awkldbl_add_long,
+ awkldbl_update_var,
+ awkldbl_set_var,
+ awkldbl_increment_var,
+ awkldbl_init_vars,
+};
+
+/* awkldbl_init --- initialization routine */
+
+static bool
+awkldbl_init(bltin_t **numbr_bltins)
+{
+ static bltin_t awkldbl_bltins[] = {
+ { "and", do_and },
+ { "atan2", do_atan2 },
+ { "compl", do_compl },
+ { "cos", do_cos },
+ { "exp", do_exp },
+ { "int", do_int },
+ { "log", do_log },
+ { "lshift", do_lshift },
+ { "or", do_or },
+ { "rand", do_rand },
+ { "rshift", do_rshift },
+ { "sin", do_sin },
+ { "sqrt", do_sqrt },
+ { "srand", do_srand },
+ { "strtonum", do_strtonum },
+ { "xor", do_xor },
+ { NULL, NULL },
+ };
+
+ /* set the numeric value of null string */
+ get_long_double(Nnull_string->qnumbr);
+ LDBL(Nnull_string) = 0.0;
+ Nnull_string->flags |= (NUMCUR|NUMBER);
+
+ /* initialize TRUE and FALSE nodes */
+ false_node = make_awkldbl(0.0);
+ true_node = make_awkldbl(1.0);
+ false_node->flags |= NUMINT;
+ true_node->flags |= NUMINT;
+
+ *numbr_bltins = awkldbl_bltins;
+ return true;
+}
+
+/* awkldbl_toulong --- conversion to unsigned long */
+
+static unsigned long
+awkldbl_toulong(const NODE *n)
+{
+ return LDBL(n);
+}
+
+/* awkldbl_tolong --- conversion to long */
+
+static long
+awkldbl_tolong(const NODE *n)
+{
+ return LDBL(n);
+}
+
+/* awkldbl_todouble --- conversion to AWKNUM */
+
+static AWKNUM
+awkldbl_todouble(const NODE *n)
+{
+ return LDBL(n);
+}
+
+/* awkldbl_touintmax_t --- conversion to uintmax_t */
+
+static uintmax_t
+awkldbl_touintmax_t(const NODE *n)
+{
+ return LDBL(n);
+}
+
+/* awkldbl_sgn --- return 1 if number > 0, zero if number == 0, and -1 if
number < 0 */
+
+static int
+awkldbl_sgn(const NODE *n)
+{
+ AWKLDBL d = LDBL(n);
+ return (d < 0.0 ? -1 : d > 0.0);
+}
+
+/* awkldbl_is_integer --- check if a number is an integer */
+
+static bool
+awkldbl_is_integer(const NODE *n)
+{
+ AWKLDBL d = LDBL(n);
+
+ if (isnan(d) || isinf(d))
+ return false;
+ return double_to_int(d) == d;
+}
+
+/* negate_awkldbl --- negate number in NODE */
+
+static void
+negate_awkldbl(NODE *n)
+{
+ LDBL(n) = - LDBL(n);
+}
+
+/* awkldbl_add --- add two numbers */
+
+static NODE *
+awkldbl_add(const NODE *t1, const NODE *t2)
+{
+ return make_awkldbl(LDBL(t1) + LDBL(t2));
+}
+
+/* awkldbl_sub --- subtract two numbers */
+
+static NODE *
+awkldbl_sub(const NODE *t1, const NODE *t2)
+{
+ return make_awkldbl(LDBL(t1) - LDBL(t2));
+}
+
+/* awkldbl_mul --- multiply two numbers */
+
+static NODE *
+awkldbl_mul(const NODE *t1, const NODE *t2)
+{
+ return make_awkldbl(LDBL(t1) * LDBL(t2));
+}
+
+/* awkldbl_add --- quotient of two numbers */
+
+static NODE *
+awkldbl_div(const NODE *t1, const NODE *t2)
+{
+ AWKLDBL d = LDBL(t2);
+ if (d == 0)
+ fatal(_("division by zero attempted"));
+ return make_awkldbl(LDBL(t1) / d);
+}
+
+/* awkldbl_add_long --- add long value to a number */
+
+static NODE *
+awkldbl_add_long(const NODE *t1, long n)
+{
+ return make_awkldbl(LDBL(t1) + n);
+}
+
+/* awkldbl_copy --- copy a number */
+
+static NODE *
+awkldbl_copy(const NODE *t1)
+{
+ return make_awkldbl(LDBL(t1));
+}
+
+/* awkldbl_update_var --- update a special variable from internal variables */
+
+static NODE *
+awkldbl_update_var(NODE *var)
+{
+ NODE *val = var->var_value;
+ AWKLDBL d;
+
+ d = LDBL(val);
+ if (var == NR_node) {
+ if (MNR == 0 && d != NR) {
+ unref(val);
+ val = NR_node->var_value = make_awkldbl(NR);
+ } else if (MNR != 0) {
+ unref(val);
+ d = ((AWKLDBL) MNR) * LONG_MAX + NR;
+ val = var->var_value = make_awkldbl(d);
+ }
+ return val;
+ }
+
+ assert(var == FNR_node);
+ if (MFNR == 0 && d != FNR) {
+ unref(val);
+ val = FNR_node->var_value = make_awkldbl(FNR);
+ } else if (MFNR != 0) {
+ unref(val);
+ d = ((AWKLDBL) MFNR) * LONG_MAX + FNR;
+ val = var->var_value = make_awkldbl(d);
+ }
+ return val;
+}
+
+/*
+ * awkldbl_set_vars --- update internal variables for assignment
+ * to a special variable.
+ */
+
+static void
+awkldbl_set_var(const NODE *var)
+{
+ NODE *val = var->var_value;
+ AWKLDBL d;
+
+ d = LDBL(val);
+ if (var == NR_node) {
+ MNR = d / LONG_MAX;
+ NR = d - ((AWKLDBL) MNR) * LONG_MAX;
+ } else if (var == FNR_node) {
+ MFNR = d / LONG_MAX;
+ FNR = d - ((AWKLDBL) MFNR) * LONG_MAX;
+ }
+ /* N.B: PREC and ROUNMODE -- not relevant */
+}
+
+/* awkldbl_increment_var --- increment NR or FNR */
+
+static long
+awkldbl_increment_var(const NODE *var, long nr)
+{
+ if (nr == LONG_MAX - 1) {
+ /* increment quotient, set remainder(NR or FNR) to 0 */
+ if (var == NR_node)
+ MNR++;
+ else /* var == FNR_node */
+ MFNR++;
+ return 0;
+ }
+ return ++nr;
+}
+
+/* awkldbl_init_vars --- initialize special variables */
+
+static void
+awkldbl_init_vars()
+{
+ /* dummy function */
+}
+
+/*
+ * make_awkldbl --- allocate a node with defined number;
+ * this routine is not exported.
+ */
+
+#ifndef AWKNUM_LDBL
+static NODE *
+make_awkldbl(AWKLDBL x)
+{
+ NODE *r;
+ getnode(r);
+ r->type = Node_val;
+ get_long_double(r->qnumbr);
+ LDBL(r) = x;
+ r->flags = MALLOC|NUMBER|NUMCUR;
+ r->valref = 1;
+ r->stptr = NULL;
+ r->stlen = 0;
+#if MBS_SUPPORT
+ r->wstptr = NULL;
+ r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+ return r;
+}
+#endif
+
+/* make_awknum --- allocate a node with defined AWKNUM */
+
+static NODE *
+make_awknum(AWKNUM x)
+{
+ NODE *r;
+ getnode(r);
+ r->type = Node_val;
+ get_long_double(r->qnumbr);
+ LDBL(r) = (AWKLDBL) x;
+ r->flags = MALLOC|NUMBER|NUMCUR;
+ r->valref = 1;
+ r->stptr = NULL;
+ r->stlen = 0;
+#if MBS_SUPPORT
+ r->wstptr = NULL;
+ r->wstlen = 0;
+#endif /* defined MBS_SUPPORT */
+ return r;
+}
+
+/* free_awkldbl --- free all storage allocated for a AWKLDBL */
+
+#ifndef AWKNUM_LDBL
+static void
+free_awkldbl(NODE *tmp)
+{
+ assert((tmp->flags & (NUMBER|NUMCUR)) != 0);
+ free_long_double(tmp->qnumbr);
+}
+#endif
+
+/* make_integer --- Convert an integer to a number node. */
+
+static inline NODE *
+make_integer(uintmax_t n)
+{
+ /* TODO -- check adjust_uint (floatcomp.c) */
+
+ n = adjust_uint(n);
+ return make_awkldbl(n);
+}
+
+/* do_lshift --- perform a << operation */
+
+static NODE *
+do_lshift(int nargs)
+{
+ NODE *s1, *s2;
+ uintmax_t uval, ushift, res;
+ AWKLDBL val, shift;
+
+ s2 = POP_SCALAR();
+ s1 = POP_SCALAR();
+ if (do_lint) {
+ if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("lshift: received non-numeric first
argument"));
+ if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("lshift: received non-numeric second
argument"));
+ }
+
+ (void) force_number(s1);
+ (void) force_number(s2);
+ val = LDBL(s1);
+ shift = LDBL(s2);
+
+ if (do_lint) {
+ if (val < 0 || shift < 0)
+ lintwarn(_("lshift(%Lf, %Lf): negative values will give
strange results"),
+ val, shift);
+ if (double_to_int(val) != val || double_to_int(shift) != shift)
+ lintwarn(_("lshift(%Lf, %Lf): fractional values will be
truncated"),
+ val, shift);
+ if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+ lintwarn(_("lshift(%Lf, %Lf): too large shift value
will give strange results"),
+ val, shift);
+ }
+
+ DEREF(s1);
+ DEREF(s2);
+ uval = (uintmax_t) val;
+ ushift = (uintmax_t) shift;
+ res = uval << ushift;
+ return make_integer(res);
+}
+
+/* do_rshift --- perform a >> operation */
+
+static NODE *
+do_rshift(int nargs)
+{
+ NODE *s1, *s2;
+ uintmax_t uval, ushift, res;
+ AWKLDBL val, shift;
+
+ s2 = POP_SCALAR();
+ s1 = POP_SCALAR();
+ if (do_lint) {
+ if ((s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("rshift: received non-numeric first
argument"));
+ if ((s2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("rshift: received non-numeric second
argument"));
+ }
+ (void) force_number(s1);
+ (void) force_number(s2);
+ val = LDBL(s1);
+ shift = LDBL(s2);
+ if (do_lint) {
+ if (val < 0 || shift < 0)
+ lintwarn(_("rshift(%Lf, %Lf): negative values will give
strange results"),
+ val, shift);
+ if (double_to_int(val) != val || double_to_int(shift) != shift)
+ lintwarn(_("rshift(%Lf, %Lf): fractional values will be
truncated"),
+ val, shift);
+ if (shift >= sizeof(uintmax_t) * CHAR_BIT)
+ lintwarn(_("rshift(%Lf, %Lf): too large shift value
will give strange results"),
+ val, shift);
+ }
+
+ DEREF(s1);
+ DEREF(s2);
+ uval = (uintmax_t) val;
+ ushift = (uintmax_t) shift;
+ res = uval >> ushift;
+ return make_integer(res);
+}
+
+/* do_and --- perform an & operation */
+
+static NODE *
+do_and(int nargs)
+{
+ NODE *s1;
+ uintmax_t res, uval;
+ AWKLDBL val;
+ int i;
+
+ res = ~0; /* start off with all ones */
+ if (nargs < 2)
+ fatal(_("and: called with less than two arguments"));
+
+ for (i = 1; nargs > 0; nargs--, i++) {
+ s1 = POP_SCALAR();
+ if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("and: argument %d is non-numeric"), i);
+
+ (void) force_number(s1);
+ val = LDBL(s1);
+ if (do_lint && val < 0)
+ lintwarn(_("and: argument %d negative value %Lg will
give strange results"),
+ i, val);
+
+ uval = (uintmax_t) val;
+ res &= uval;
+ DEREF(s1);
+ }
+
+ return make_integer(res);
+}
+
+/* do_or --- perform an | operation */
+
+static NODE *
+do_or(int nargs)
+{
+ NODE *s1;
+ uintmax_t res, uval;
+ AWKLDBL val;
+ int i;
+
+ res = 0;
+ if (nargs < 2)
+ fatal(_("or: called with less than two arguments"));
+
+ for (i = 1; nargs > 0; nargs--, i++) {
+ s1 = POP_SCALAR();
+ if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("or: argument %d is non-numeric"), i);
+
+ (void) force_number(s1);
+ val = LDBL(s1);
+ if (do_lint && val < 0)
+ lintwarn(_("or: argument %d negative value %Lg will
give strange results"),
+ i, val);
+
+ uval = (uintmax_t) val;
+ res |= uval;
+
+ DEREF(s1);
+ }
+
+ return make_integer(res);
+}
+
+/* do_xor --- perform an ^ operation */
+
+static NODE *
+do_xor(int nargs)
+{
+ NODE *s1;
+ uintmax_t res, uval;
+ AWKLDBL val;
+ int i;
+
+ if (nargs < 2)
+ fatal(_("xor: called with less than two arguments"));
+
+ res = 0; /* silence compiler warning */
+ for (i = 1; nargs > 0; nargs--, i++) {
+ s1 = POP_SCALAR();
+ if (do_lint && (s1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("xor: argument %d is non-numeric"), i);
+
+ (void) force_number(s1);
+ val = LDBL(s1);
+ if (do_lint && val < 0)
+ lintwarn(_("xor: argument %d negative value %Lg will
give strange results"),
+ i, val);
+
+ uval = (uintmax_t) val;
+ if (i == 1)
+ res = uval;
+ else
+ res ^= uval;
+ DEREF(s1);
+ }
+
+ return make_integer(res);
+}
+
+/* do_compl --- perform a ~ operation */
+
+static NODE *
+do_compl(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d;
+ uintmax_t uval;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("compl: received non-numeric argument"));
+ (void) force_number(tmp);
+ d = LDBL(tmp);
+ DEREF(tmp);
+
+ if (do_lint) {
+ if (d < 0)
+ lintwarn(_("compl(%Lf): negative value will give
strange results"), d);
+ if (double_to_int(d) != d)
+ lintwarn(_("compl(%Lf): fractional value will be
truncated"), d);
+ }
+
+ uval = (uintmax_t) d;
+ uval = ~ uval;
+ return make_integer(uval);
+}
+
+/* nondec2awkldbl --- convert octal or hex value to long double */
+
+/*
+ * Because of awk's concatenation rules and the way awk.y:yylex()
+ * collects a number, this routine has to be willing to stop on the
+ * first invalid character.
+ */
+
+static AWKLDBL
+nondec2awkldbl(char *str, size_t len)
+{
+ AWKLDBL retval = 0.0;
+ char save;
+ short val;
+ char *start = str;
+
+ if (*str == '0' && (str[1] == 'x' || str[1] == 'X')) {
+ /*
+ * User called strtonum("0x") or some such,
+ * so just quit early.
+ */
+ if (len <= 2)
+ return 0.0;
+
+ for (str += 2, len -= 2; len > 0; len--, str++) {
+ switch (*str) {
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ val = *str - '0';
+ break;
+ case 'a':
+ case 'b':
+ case 'c':
+ case 'd':
+ case 'e':
+ case 'f':
+ val = *str - 'a' + 10;
+ break;
+ case 'A':
+ case 'B':
+ case 'C':
+ case 'D':
+ case 'E':
+ case 'F':
+ val = *str - 'A' + 10;
+ break;
+ default:
+ goto done;
+ }
+ retval = (retval * 16) + val;
+ }
+ } else if (*str == '0') {
+ for (; len > 0; len--) {
+ if (! isdigit((unsigned char) *str))
+ goto done;
+ else if (*str == '8' || *str == '9') {
+ str = start;
+ goto decimal;
+ }
+ retval = (retval * 8) + (*str - '0');
+ str++;
+ }
+ } else {
+decimal:
+ save = str[len];
+ retval = gawk_strtold(str, NULL);
+ str[len] = save;
+ }
+done:
+ return retval;
+}
+
+
+/* do_rand --- do the rand function */
+
+static bool firstrand = true;
+/* Some systems require this array to be integer aligned. Sigh. */
+#define SIZEOF_STATE 256
+static uint32_t istate[SIZEOF_STATE/sizeof(uint32_t)];
+static char *const state = (char *const) istate;
+
+/* ARGSUSED */
+static NODE *
+do_rand(int nargs ATTRIBUTE_UNUSED)
+{
+ if (firstrand) {
+ (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+ /* don't need to srandom(1), initstate() does it for us. */
+ firstrand = false;
+ setstate(state);
+ }
+ /*
+ * Per historical practice and POSIX, return value N is
+ *
+ * 0 <= n < 1
+ */
+ return make_awkldbl((random() % GAWK_RANDOM_MAX) / GAWK_RANDOM_MAX);
+}
+
+/* do_srand --- seed the random number generator */
+
+static NODE *
+do_srand(int nargs)
+{
+ NODE *tmp;
+ static long save_seed = 1;
+ long ret = save_seed; /* SVR4 awk srand returns previous seed */
+ AWKLDBL d;
+
+ if (firstrand) {
+ (void) initstate((unsigned) 1, state, SIZEOF_STATE);
+ /* don't need to srandom(1), we're changing the seed below */
+ firstrand = false;
+ (void) setstate(state);
+ }
+
+ if (nargs == 0)
+ srandom((unsigned int) (save_seed = (long) time((time_t *) 0)));
+ else {
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("srand: received non-numeric argument"));
+ (void) force_number(tmp);
+ d = LDBL(tmp);
+ srandom((unsigned int) (save_seed = (long) d));
+ DEREF(tmp);
+ }
+ return make_awkldbl(ret);
+}
+
+/* str2awkldbl --- create a number node from string */
+
+static NODE *
+str2awkldbl(char *str, char **endptr, int base, bool is_integer
ATTRIBUTE_UNUSED)
+{
+ NODE *r;
+ AWKLDBL d;
+
+ if (base == 0) {
+ /*
+ * special case -- only used to parse input in the debugger?
+ * FIXME: reject ieee specials we don't want and/or use the same
+ * rules when reading numbers from a source file and nuke this
case.
+ * Also in double.c.
+ */
+
+ errno = 0;
+ d = gawk_strtold(str, endptr);
+ if (errno != 0)
+ d = 0;
+ } else {
+ if (base == 8 || base == 16)
+ d = nondec2awkldbl(str, strlen(str));
+ else {
+ /* atof for double */
+ errno = 0;
+ d = gawk_strtold(str, NULL);
+ if (errno != 0)
+ d = 0;
+ errno = 0;
+ }
+ }
+
+ r = make_awkldbl(d);
+
+ /* XXX: is this relevant ? */
+ if (d <= INT32_MAX && d >= INT32_MIN && d == (int32_t) d)
+ r->flags |= NUMINT;
+
+ return r;
+}
+
+/* awkldbl_mod --- remainder from division of two numbers */
+
+static NODE *
+awkldbl_mod(const NODE *t1, const NODE *t2)
+{
+ AWKLDBL d2;
+
+ d2 = LDBL(t2);
+ if (d2 == 0)
+ fatal(_("division by zero attempted in `%%'"));
+ return make_awkldbl(gawk_fmodl(LDBL(t1), d2));
+}
+
+/* awkldbl_pow --- power function */
+
+static NODE *
+awkldbl_pow(const NODE *t1, const NODE *t2)
+{
+ return make_awkldbl(calc_exp(LDBL(t1), LDBL(t2)));
+}
+
+
+/*
+ * calc_exp_posint --- calculate x^n for positive integral n,
+ * using exponentiation by squaring without recursion.
+ */
+
+static AWKLDBL
+calc_exp_posint(AWKLDBL x, long n)
+{
+ AWKLDBL mult = 1;
+
+ while (n > 1) {
+ if ((n % 2) == 1)
+ mult *= x;
+ x *= x;
+ n /= 2;
+ }
+ return mult * x;
+}
+
+/* calc_exp --- calculate x1^x2 */
+
+static AWKLDBL
+calc_exp(AWKLDBL x1, AWKLDBL x2)
+{
+ long lx;
+
+ if ((lx = x2) == x2) { /* integer exponent */
+ if (lx == 0)
+ return 1;
+ return (lx > 0) ? calc_exp_posint(x1, lx)
+ : 1.0 / calc_exp_posint(x1, -lx);
+ }
+ return gawk_powl(x1, x2);
+}
+
+/* cmp_awkldbls --- compare two doubles */
+
+static int
+cmp_awkldbls(const NODE *t1, const NODE *t2)
+{
+ /*
+ * This routine is also used to sort numeric array indices or values.
+ * For the purposes of sorting, NaN is considered greater than
+ * any other value, and all NaN values are considered equivalent and
equal.
+ * This isn't in compliance with IEEE standard, but compliance w.r.t.
NaN
+ * comparison at the awk level is a different issue, and needs to be
dealt
+ * with in the interpreter for each opcode seperately.
+ */
+ AWKLDBL d1 = LDBL(t1);
+ AWKLDBL d2 = LDBL(t2);
+
+ if (isnan(d1))
+ return ! isnan(d2);
+ if (isnan(d2))
+ return -1;
+ /* don't subtract, in case one or both are infinite */
+ if (d1 == d2)
+ return 0;
+ if (d1 < d2)
+ return -1;
+ return 1;
+}
+
+/* force_awkldbl --- force a value to be numeric */
+
+static NODE *
+force_awkldbl(NODE *n)
+{
+ char *cp;
+ char *cpend;
+ char save;
+ char *ptr;
+ unsigned int newflags;
+
+ if ((n->flags & NUMCUR) != 0)
+ return n;
+
+ /* all the conditionals are an attempt to avoid the expensive strtod */
+
+ /* Note: only set NUMCUR if we actually convert some digits */
+
+ get_long_double(n->qnumbr);
+ LDBL(n) = 0.0;
+
+ if (n->stlen == 0) {
+ return n;
+ }
+
+ cp = n->stptr;
+ /*
+ * 2/2007:
+ * POSIX, by way of severe language lawyering, seems to
+ * allow things like "inf" and "nan" to mean something.
+ * So if do_posix, the user gets what he deserves.
+ * This also allows hexadecimal floating point. Ugh.
+ */
+ if (! do_posix) {
+ if (isalpha((unsigned char) *cp)) {
+ return n;
+ } else if (n->stlen == 4 && is_ieee_magic_val(n->stptr)) {
+ if ((n->flags & MAYBE_NUM) != 0)
+ n->flags &= ~MAYBE_NUM;
+ n->flags |= NUMBER|NUMCUR;
+ LDBL(n) = get_ieee_magic_val(n->stptr);
+ return n;
+ }
+ /* else
+ fall through */
+ }
+ /* else not POSIX, so
+ fall through */
+
+ cpend = cp + n->stlen;
+ while (cp < cpend && isspace((unsigned char) *cp))
+ cp++;
+
+ if ( cp == cpend /* only spaces, or */
+ || (! do_posix /* not POSIXLY paranoid and */
+ && (isalpha((unsigned char) *cp) /* letter, or */
+ /* CANNOT do non-decimal and saw 0x */
+ || (! do_non_decimal_data && cp[0] == '0'
+ && (cp[1] == 'x' || cp[1] == 'X'))))) {
+ return n;
+ }
+
+ if ((n->flags & MAYBE_NUM) != 0) {
+ newflags = NUMBER;
+ n->flags &= ~MAYBE_NUM;
+ } else
+ newflags = 0;
+
+ if (cpend - cp == 1) { /* only one character */
+ if (isdigit((unsigned char) *cp)) { /* it's a digit! */
+ LDBL(n) = (AWKLDBL)(*cp - '0');
+ n->flags |= newflags;
+ n->flags |= NUMCUR;
+ if (cp == n->stptr) /* no leading spaces */
+ n->flags |= NUMINT;
+ }
+ return n;
+ }
+
+ if (do_non_decimal_data) { /* main.c assures false if do_posix */
+ errno = 0;
+ if (! do_traditional && get_numbase(cp, true) != 10) {
+ LDBL(n) = nondec2awkldbl(cp, cpend - cp);
+ n->flags |= NUMCUR;
+ ptr = cpend;
+ goto finish;
+ }
+ }
+
+ errno = 0;
+ save = *cpend;
+ *cpend = '\0';
+ LDBL(n) = gawk_strtold((const char *) cp, &ptr);
+
+ /* POSIX says trailing space is OK for NUMBER */
+ while (isspace((unsigned char) *ptr))
+ ptr++;
+ *cpend = save;
+finish:
+ if (errno == 0 && ptr == cpend) {
+ n->flags |= newflags;
+ n->flags |= NUMCUR;
+ } else {
+ errno = 0;
+ }
+ return n;
+}
+
+
+/*
+ * The following lookup table is used as an optimization in force_string;
+ * (more complicated) variations on this theme didn't seem to pay off, but
+ * systematic testing might be in order at some point.
+ */
+static const char *values[] = {
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+};
+#define NVAL (sizeof(values)/sizeof(values[0]))
+
+/* format_awkldbl_val --- format a numeric value based on format */
+
+static NODE *
+format_awkldbl_val(const char *format, int index, NODE *s)
+{
+ char buf[BUFSIZ];
+ char *sp = buf;
+ AWKLDBL ival, d;
+
+ /*
+ * 2/2007: Simplify our lives here. Instead of worrying about
+ * whether or not the value will fit into a long just so we
+ * can use sprintf("%ld", val) on it, always format it ourselves.
+ * The only thing to worry about is that integral values always
+ * format as integers. %.0f does that very well.
+ *
+ * 6/2008: Would that things were so simple. Always using %.0f
+ * imposes a notable performance penalty for applications that
+ * do a lot of conversion of integers to strings. So, we reinstate
+ * the old code, but use %.0f for integral values that are outside
+ * the range of a long. This seems a reasonable compromise.
+ *
+ * 12/2009: Use <= and >= in the comparisons with LONG_xxx instead of
+ * < and > so that things work correctly on systems with 64 bit
integers.
+ */
+
+ d = LDBL(s);
+
+ /* not an integral value, or out of range */
+ if ((ival = double_to_int(d)) != d
+ || ival <= LONG_MIN || ival >= LONG_MAX
+ ) {
+ /*
+ * Once upon a time, we just blindly did this:
+ * sprintf(sp, format, s->numbr);
+ * s->stlen = strlen(sp);
+ * s->stfmt = (char) index;
+ * but that's no good if, e.g., OFMT is %s. So we punt,
+ * and just always format the value ourselves.
+ */
+
+ NODE *dummy[2], *r;
+ unsigned int oflags;
+
+ /* create dummy node for a sole use of format_tree */
+ dummy[1] = s;
+ oflags = s->flags;
+
+ if (ival == d) {
+ /* integral value, but outside range of %ld, use %.0f */
+ r = format_tree("%.0f", 4, dummy, 2);
+ s->stfmt = -1;
+ } else {
+ r = format_tree(format, fmt_list[index]->stlen, dummy,
2);
+ assert(r != NULL);
+ s->stfmt = (char) index;
+ }
+ s->flags = oflags;
+ s->stlen = r->stlen;
+ if ((s->flags & STRCUR) != 0)
+ efree(s->stptr);
+ s->stptr = r->stptr;
+ freenode(r); /* Do not unref(r)! We want to keep s->stptr ==
r->stpr. */
+
+ goto no_malloc;
+ } else {
+ /*
+ * integral value; force conversion to long only once.
+ */
+ long num = (long) ival;
+
+ if (num < NVAL && num >= 0) {
+ sp = (char *) values[num];
+ s->stlen = 1;
+ } else {
+ (void) sprintf(sp, "%ld", num);
+ s->stlen = strlen(sp);
+ }
+ s->stfmt = -1;
+ if ((s->flags & INTIND) != 0) {
+ s->flags &= ~(INTIND|NUMBER);
+ s->flags |= STRING;
+ }
+ }
+ if (s->stptr != NULL)
+ efree(s->stptr);
+ emalloc(s->stptr, char *, s->stlen + 2, "format_awkldbl_val");
+ memcpy(s->stptr, sp, s->stlen + 1);
+no_malloc:
+ s->flags |= STRCUR;
+ free_wstr(s);
+ return s;
+}
+
+/* is_ieee_magic_val --- return true for +inf, -inf, +nan, -nan */
+
+static int
+is_ieee_magic_val(const char *val)
+{
+ /*
+ * Avoid strncasecmp: it mishandles ASCII bytes in some locales.
+ * Assume the length is 4, as the caller checks this.
+ */
+ return ( (val[0] == '+' || val[0] == '-')
+ && ( ( (val[1] == 'i' || val[1] == 'I')
+ && (val[2] == 'n' || val[2] == 'N')
+ && (val[3] == 'f' || val[3] == 'F'))
+ || ( (val[1] == 'n' || val[1] == 'N')
+ && (val[2] == 'a' || val[2] == 'A')
+ && (val[3] == 'n' || val[3] == 'N'))));
+}
+
+/* get_ieee_magic_val --- return magic value for string */
+
+static AWKLDBL
+get_ieee_magic_val(const char *val)
+{
+ static bool first = true;
+ static AWKLDBL inf;
+ static AWKLDBL nan;
+ char *ptr;
+ AWKLDBL v;
+
+ v = gawk_strtold(val, & ptr);
+
+ if (val == ptr) { /* Older strtod implementations don't support inf or
nan. */
+ if (first) {
+ first = false;
+ nan = gawk_sqrtl(-1.0);
+ inf = -gawk_logl(0.0);
+ }
+ v = ((val[1] == 'i' || val[1] == 'I') ? inf : nan);
+ if (val[0] == '-')
+ v = -v;
+ }
+
+ return v;
+}
+
+/* double_to_int --- convert double to int, used in several places */
+
+static AWKLDBL
+double_to_int(AWKLDBL d)
+{
+ if (d >= 0)
+ d = gawk_floorl(d);
+ else
+ d = gawk_ceill(d);
+ return d;
+}
+
+/* do_int --- convert double to int for awk */
+
+static NODE *
+do_int(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("int: received non-numeric argument"));
+ (void) force_number(tmp);
+ d = LDBL(tmp);
+ DEREF(tmp);
+ return make_awkldbl(double_to_int(d));
+}
+
+/* do_log --- the log function */
+
+static NODE *
+do_log(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d, arg;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("log: received non-numeric argument"));
+ (void) force_number(tmp);
+ arg = LDBL(tmp);
+ if (arg < 0.0)
+ warning(_("log: received negative argument %Lg"), arg);
+ d = gawk_logl(arg);
+ DEREF(tmp);
+ return make_awkldbl(d);
+}
+
+/* do_sqrt --- do the sqrt function */
+
+static NODE *
+do_sqrt(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL arg;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("sqrt: received non-numeric argument"));
+ (void) force_number(tmp);
+ arg = LDBL(tmp);
+ DEREF(tmp);
+ if (arg < 0.0)
+ warning(_("sqrt: called with negative argument %Lg"), arg);
+ return make_awkldbl(gawk_sqrtl(arg));
+}
+
+/* do_exp --- exponential function */
+
+static NODE *
+do_exp(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d, res;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("exp: received non-numeric argument"));
+ (void) force_number(tmp);
+ DEREF(tmp);
+ errno = 0;
+ res = gawk_expl(d);
+ if (errno == ERANGE)
+ warning(_("exp: argument %Lg is out of range"), d);
+ return make_awkldbl(res);
+}
+
+/* do_atan2 --- do the atan2 function */
+
+static NODE *
+do_atan2(int nargs)
+{
+ NODE *t1, *t2;
+ AWKLDBL d1, d2;
+
+ t2 = POP_SCALAR();
+ t1 = POP_SCALAR();
+ if (do_lint) {
+ if ((t1->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("atan2: received non-numeric first
argument"));
+ if ((t2->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("atan2: received non-numeric second
argument"));
+ }
+ (void) force_number(t1);
+ (void) force_number(t2);
+ d1 = LDBL(t1);
+ d2 = LDBL(t2);
+ DEREF(t1);
+ DEREF(t2);
+ return make_awkldbl(gawk_atan2l(d1, d2));
+}
+
+
+/* do_sin --- do the sin function */
+
+static NODE *
+do_sin(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("sin: received non-numeric argument"));
+ (void) force_number(tmp);
+ d = gawk_sinl(LDBL(tmp));
+ DEREF(tmp);
+ return make_awkldbl(d);
+}
+
+/* do_cos --- do the cos function */
+
+static NODE *
+do_cos(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d;
+
+ tmp = POP_SCALAR();
+ if (do_lint && (tmp->flags & (NUMCUR|NUMBER)) == 0)
+ lintwarn(_("cos: received non-numeric argument"));
+ (void) force_number(tmp);
+ d = gawk_cosl(LDBL(tmp));
+ DEREF(tmp);
+ return make_awkldbl(d);
+}
+
+/* do_strtonum --- the strtonum function */
+
+static NODE *
+do_strtonum(int nargs)
+{
+ NODE *tmp;
+ AWKLDBL d;
+
+ tmp = POP_SCALAR();
+ if ((tmp->flags & (NUMBER|NUMCUR)) != 0) {
+ (void) force_number(tmp);
+ d = LDBL(tmp);
+ } else if (get_numbase(tmp->stptr, use_lc_numeric) != 10)
+ d = nondec2awkldbl(tmp->stptr, tmp->stlen);
+ else {
+ (void) force_number(tmp);
+ d = LDBL(tmp);
+ }
+
+ DEREF(tmp);
+ return make_awkldbl(d);
+}
+
+
+/*
+ * format_tree() formats arguments of sprintf,
+ * and accordingly to a fmt_string providing a format like in
+ * printf family from C library. Returns a string node which value
+ * is a formatted string. Called by sprintf function.
+ *
+ * It is one of the uglier parts of gawk. Thanks to Michal Jaegermann
+ * for taming this beast and making it compatible with ANSI C.
+ */
+
+static NODE *
+format_nodes_awkldbl(
+ const char *fmt_string,
+ size_t n0,
+ NODE **the_args,
+ long num_args)
+{
+/* copy 'l' bytes from 's' to 'obufout' checking for space in the process */
+/* difference of pointers should be of ptrdiff_t type, but let us be kind */
+#define bchunk(s, l) if (l) { \
+ while ((l) > ofre) { \
+ size_t olen = obufout - obuf; \
+ erealloc(obuf, char *, osiz * 2, "format_tree"); \
+ ofre += osiz; \
+ osiz *= 2; \
+ obufout = obuf + olen; \
+ } \
+ memcpy(obufout, s, (size_t) (l)); \
+ obufout += (l); \
+ ofre -= (l); \
+}
+
+/* copy one byte from 's' to 'obufout' checking for space in the process */
+#define bchunk_one(s) { \
+ if (ofre < 1) { \
+ size_t olen = obufout - obuf; \
+ erealloc(obuf, char *, osiz * 2, "format_tree"); \
+ ofre += osiz; \
+ osiz *= 2; \
+ obufout = obuf + olen; \
+ } \
+ *obufout++ = *s; \
+ --ofre; \
+}
+
+/* Is there space for something L big in the buffer? */
+#define chksize(l) if ((l) >= ofre) { \
+ size_t olen = obufout - obuf; \
+ size_t delta = osiz+l-ofre; \
+ erealloc(obuf, char *, osiz + delta, "format_tree"); \
+ obufout = obuf + olen; \
+ ofre += delta; \
+ osiz += delta; \
+}
+
+ size_t cur_arg = 0;
+ NODE *r = NULL;
+ int i, nc;
+ bool toofew = false;
+ char *obuf, *obufout;
+ size_t osiz, ofre;
+ const char *chbuf;
+ const char *s0, *s1;
+ int cs1;
+ NODE *arg;
+ long fw, prec, argnum;
+ bool used_dollar;
+ bool lj, alt, big_flag, bigbig_flag, small_flag, have_prec, need_format;
+ long *cur = NULL;
+ uintmax_t uval;
+ bool sgn;
+ int base;
+ /*
+ * Although this is an array, the elements serve two different
+ * purposes. The first element is the general buffer meant
+ * to hold the entire result string. The second one is a
+ * temporary buffer for large floating point values. They
+ * could just as easily be separate variables, and the
+ * code might arguably be clearer.
+ */
+ struct {
+ char *buf;
+ size_t bufsize;
+ char stackbuf[30];
+ } cpbufs[2];
+#define cpbuf cpbufs[0].buf
+ char *cend = &cpbufs[0].stackbuf[sizeof(cpbufs[0].stackbuf)];
+ char *cp;
+ const char *fill;
+ AWKLDBL tmpval = 0.0;
+ char signchar = '\0';
+ size_t len;
+ bool zero_flag = false;
+ bool quote_flag = false;
+ int ii, jj;
+ char *chp;
+ size_t copy_count, char_count;
+
+ static const char sp[] = " ";
+ static const char zero_string[] = "0";
+ static const char lchbuf[] = "0123456789abcdef";
+ static const char Uchbuf[] = "0123456789ABCDEF";
+
+#define INITIAL_OUT_SIZE 512
+ emalloc(obuf, char *, INITIAL_OUT_SIZE, "format_tree");
+ obufout = obuf;
+ osiz = INITIAL_OUT_SIZE;
+ ofre = osiz - 2;
+
+ cur_arg = 1;
+
+ {
+ size_t k;
+ for (k = 0; k < sizeof(cpbufs)/sizeof(cpbufs[0]); k++) {
+ cpbufs[k].bufsize = sizeof(cpbufs[k].stackbuf);
+ cpbufs[k].buf = cpbufs[k].stackbuf;
+ }
+ }
+
+ /*
+ * The point of this goop is to grow the buffer
+ * holding the converted number, so that large
+ * values don't overflow a fixed length buffer.
+ */
+#define PREPEND(CH) do { \
+ if (cp == cpbufs[0].buf) { \
+ char *prev = cpbufs[0].buf; \
+ emalloc(cpbufs[0].buf, char *, 2*cpbufs[0].bufsize, \
+ "format_tree"); \
+ memcpy((cp = cpbufs[0].buf+cpbufs[0].bufsize), prev, \
+ cpbufs[0].bufsize); \
+ cpbufs[0].bufsize *= 2; \
+ if (prev != cpbufs[0].stackbuf) \
+ efree(prev); \
+ cend = cpbufs[0].buf+cpbufs[0].bufsize; \
+ } \
+ *--cp = (CH); \
+} while(0)
+
+ /*
+ * Check first for use of `count$'.
+ * If plain argument retrieval was used earlier, choke.
+ * Otherwise, return the requested argument.
+ * If not `count$' now, but it was used earlier, choke.
+ * If this format is more than total number of args, choke.
+ * Otherwise, return the current argument.
+ */
+#define parse_next_arg() { \
+ if (argnum > 0) { \
+ if (cur_arg > 1) { \
+ msg(_("fatal: must use `count$' on all formats or
none")); \
+ goto out; \
+ } \
+ arg = the_args[argnum]; \
+ } else if (used_dollar) { \
+ msg(_("fatal: must use `count$' on all formats or none")); \
+ arg = 0; /* shutup the compiler */ \
+ goto out; \
+ } else if (cur_arg >= num_args) { \
+ arg = 0; /* shutup the compiler */ \
+ toofew = true; \
+ break; \
+ } else { \
+ arg = the_args[cur_arg]; \
+ cur_arg++; \
+ } \
+}
+
+ need_format = false;
+ used_dollar = false;
+
+ s0 = s1 = fmt_string;
+ while (n0-- > 0) {
+ if (*s1 != '%') {
+ s1++;
+ continue;
+ }
+ need_format = true;
+ bchunk(s0, s1 - s0);
+ s0 = s1;
+ cur = &fw;
+ fw = 0;
+ prec = 0;
+ base = 0;
+ argnum = 0;
+ base = 0;
+ have_prec = false;
+ signchar = '\0';
+ zero_flag = false;
+ quote_flag = false;
+ lj = alt = big_flag = bigbig_flag = small_flag = false;
+ fill = sp;
+ cp = cend;
+ chbuf = lchbuf;
+ s1++;
+
+retry:
+ if (n0-- == 0) /* ran out early! */
+ break;
+
+ switch (cs1 = *s1++) {
+ case (-1): /* dummy case to allow for checking */
+check_pos:
+ if (cur != & fw)
+ break; /* reject as a valid format */
+ goto retry;
+ case '%':
+ need_format = false;
+ /*
+ * 29 Oct. 2002:
+ * The C99 standard pages 274 and 279 seem to imply that
+ * since there's no arg converted, the field width
doesn't
+ * apply. The code already was that way, but this
+ * comment documents it, at least in the code.
+ */
+ if (do_lint) {
+ const char *msg = NULL;
+
+ if (fw && ! have_prec)
+ msg = _("field width is ignored for
`%%' specifier");
+ else if (fw == 0 && have_prec)
+ msg = _("precision is ignored for `%%'
specifier");
+ else if (fw && have_prec)
+ msg = _("field width and precision are
ignored for `%%' specifier");
+
+ if (msg != NULL)
+ lintwarn("%s", msg);
+ }
+ bchunk_one("%");
+ s0 = s1;
+ break;
+
+ case '0':
+ /*
+ * Only turn on zero_flag if we haven't seen
+ * the field width or precision yet. Otherwise,
+ * screws up floating point formatting.
+ */
+ if (cur == & fw)
+ zero_flag = true;
+ if (lj)
+ goto retry;
+ /* FALL through */
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ if (cur == NULL)
+ break;
+ if (prec >= 0)
+ *cur = cs1 - '0';
+ /*
+ * with a negative precision *cur is already set
+ * to -1, so it will remain negative, but we have
+ * to "eat" precision digits in any case
+ */
+ while (n0 > 0 && *s1 >= '0' && *s1 <= '9') {
+ --n0;
+ *cur = *cur * 10 + *s1++ - '0';
+ }
+ if (prec < 0) /* negative precision is discarded */
+ have_prec = false;
+ if (cur == &prec)
+ cur = NULL;
+ if (n0 == 0) /* badly formatted control string */
+ continue;
+ goto retry;
+ case '$':
+ if (do_traditional) {
+ msg(_("fatal: `$' is not permitted in awk
formats"));
+ goto out;
+ }
+
+ if (cur == &fw) {
+ argnum = fw;
+ fw = 0;
+ used_dollar = true;
+ if (argnum <= 0) {
+ msg(_("fatal: arg count with `$' must
be > 0"));
+ goto out;
+ }
+ if (argnum >= num_args) {
+ msg(_("fatal: arg count %ld greater
than total number of supplied arguments"), argnum);
+ goto out;
+ }
+ } else {
+ msg(_("fatal: `$' not permitted after period in
format"));
+ goto out;
+ }
+
+ goto retry;
+ case '*':
+ if (cur == NULL)
+ break;
+ if (! do_traditional && isdigit((unsigned char) *s1)) {
+ int val = 0;
+
+ for (; n0 > 0 && *s1 && isdigit((unsigned char)
*s1); s1++, n0--) {
+ val *= 10;
+ val += *s1 - '0';
+ }
+ if (*s1 != '$') {
+ msg(_("fatal: no `$' supplied for
positional field width or precision"));
+ goto out;
+ } else {
+ s1++;
+ n0--;
+ }
+ if (val >= num_args) {
+ toofew = true;
+ break;
+ }
+ arg = the_args[val];
+ } else {
+ parse_next_arg();
+ }
+ (void) force_number(arg);
+ *cur = get_number_si(arg);
+ if (*cur < 0 && cur == & fw) {
+ *cur = -*cur;
+ lj++;
+ }
+ if (cur == & prec) {
+ if (*cur >= 0)
+ have_prec = true;
+ else
+ have_prec = false;
+ cur = NULL;
+ }
+ goto retry;
+ case ' ': /* print ' ' or '-' */
+ /* 'space' flag is ignored */
+ /* if '+' already present */
+ if (signchar != false)
+ goto check_pos;
+ /* FALL THROUGH */
+ case '+': /* print '+' or '-' */
+ signchar = cs1;
+ goto check_pos;
+ case '-':
+ if (prec < 0)
+ break;
+ if (cur == & prec) {
+ prec = -1;
+ goto retry;
+ }
+ fill = sp; /* if left justified then other */
+ lj++; /* filling is ignored */
+ goto check_pos;
+ case '.':
+ if (cur != & fw)
+ break;
+ cur = & prec;
+ have_prec = true;
+ goto retry;
+ case '#':
+ alt = true;
+ goto check_pos;
+ case '\'':
+#if defined(HAVE_LOCALE_H)
+ /* allow quote_flag if there is a thousands separator.
*/
+ if (loc.thousands_sep[0] != '\0')
+ quote_flag = true;
+ goto check_pos;
+#else
+ goto retry;
+#endif
+ case 'l':
+ if (big_flag)
+ break;
+ else {
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ lintwarn(_("`l' is meaningless in awk
formats; ignored"));
+ warned = true;
+ }
+ if (do_posix) {
+ msg(_("fatal: `l' is not permitted in
POSIX awk formats"));
+ goto out;
+ }
+ }
+ big_flag = true;
+ goto retry;
+ case 'L':
+ if (bigbig_flag)
+ break;
+ else {
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ lintwarn(_("`L' is meaningless in awk
formats; ignored"));
+ warned = true;
+ }
+ if (do_posix) {
+ msg(_("fatal: `L' is not permitted in
POSIX awk formats"));
+ goto out;
+ }
+ }
+ bigbig_flag = true;
+ goto retry;
+ case 'h':
+ if (small_flag)
+ break;
+ else {
+ static bool warned = false;
+
+ if (do_lint && ! warned) {
+ lintwarn(_("`h' is meaningless in awk
formats; ignored"));
+ warned = true;
+ }
+ if (do_posix) {
+ msg(_("fatal: `h' is not permitted in
POSIX awk formats"));
+ goto out;
+ }
+ }
+ small_flag = true;
+ goto retry;
+ case 'c':
+ need_format = false;
+ parse_next_arg();
+ /* user input that looks numeric is numeric */
+ if ((arg->flags & (MAYBE_NUM|NUMBER)) == MAYBE_NUM)
+ (void) force_number(arg);
+ if ((arg->flags & NUMBER) != 0) {
+ uval = get_number_uj(arg);
+#if MBS_SUPPORT
+ if (gawk_mb_cur_max > 1) {
+ char buf[100];
+ wchar_t wc;
+ mbstate_t mbs;
+ size_t count;
+
+ memset(& mbs, 0, sizeof(mbs));
+ wc = uval;
+
+ count = wcrtomb(buf, wc, & mbs);
+ if (count == 0
+ || count == (size_t)-1
+ || count == (size_t)-2)
+ goto out0;
+
+ memcpy(cpbuf, buf, count);
+ prec = count;
+ cp = cpbuf;
+ goto pr_tail;
+ }
+out0:
+ ;
+ /* else,
+ fall through */
+#endif
+ if (do_lint && uval > 255) {
+ lintwarn("[s]printf: value %Lg is too
big for %%c format",
+ LDBL(arg));
+ }
+ cpbuf[0] = uval;
+ prec = 1;
+ cp = cpbuf;
+ goto pr_tail;
+ }
+ /*
+ * As per POSIX, only output first character of a
+ * string value. Thus, we ignore any provided
+ * precision, forcing it to 1. (Didn't this
+ * used to work? 6/2003.)
+ */
+ cp = arg->stptr;
+#if MBS_SUPPORT
+ /*
+ * First character can be multiple bytes if
+ * it's a multibyte character. Grr.
+ */
+ if (gawk_mb_cur_max > 1) {
+ mbstate_t state;
+ size_t count;
+
+ memset(& state, 0, sizeof(state));
+ count = mbrlen(cp, arg->stlen, & state);
+ if (count == 0
+ || count == (size_t)-1
+ || count == (size_t)-2)
+ goto out2;
+ prec = count;
+ goto pr_tail;
+ }
+out2:
+ ;
+#endif
+ prec = 1;
+ goto pr_tail;
+ case 's':
+ need_format = false;
+ parse_next_arg();
+ arg = force_string(arg);
+ if (fw == 0 && ! have_prec)
+ prec = arg->stlen;
+ else {
+ char_count = mbc_char_count(arg->stptr,
arg->stlen);
+ if (! have_prec || prec > char_count)
+ prec = char_count;
+ }
+ cp = arg->stptr;
+ goto pr_tail;
+ case 'd':
+ case 'i':
+ need_format = false;
+ parse_next_arg();
+ (void) force_number(arg);
+ tmpval = LDBL(arg);
+
+ /*
+ * Check for Nan or Inf.
+ */
+ if (isnan(tmpval) || isinf(tmpval))
+ goto out_of_range;
+ else
+ tmpval = double_to_int(tmpval);
+
+ /*
+ * ``The result of converting a zero value with a
+ * precision of zero is no characters.''
+ */
+ if (have_prec && prec == 0 && tmpval == 0)
+ goto pr_tail;
+
+ if (tmpval < 0) {
+ tmpval = -tmpval;
+ sgn = true;
+ } else {
+ if (tmpval == -0.0)
+ /* avoid printing -0 */
+ tmpval = 0.0;
+ sgn = false;
+ }
+ /*
+ * Use snprintf return value to tell if there
+ * is enough room in the buffer or not.
+ */
+ while ((i = snprintf(cpbufs[1].buf,
+ cpbufs[1].bufsize, "%.0Lf", tmpval)) >=
cpbufs[1].bufsize) {
+ if (cpbufs[1].buf == cpbufs[1].stackbuf)
+ cpbufs[1].buf = NULL;
+ if (i > 0) {
+ cpbufs[1].bufsize += ((i >
cpbufs[1].bufsize) ?
+ i :
cpbufs[1].bufsize);
+ }
+ else
+ cpbufs[1].bufsize *= 2;
+ assert(cpbufs[1].bufsize > 0);
+ erealloc(cpbufs[1].buf, char *,
+ cpbufs[1].bufsize, "format_tree");
+ }
+ if (i < 1)
+ goto out_of_range;
+ chp = & cpbufs[1].buf[i-1];
+ ii = jj = 0;
+ do {
+ PREPEND(*chp);
+ chp--; i--;
+#if defined(HAVE_LOCALE_H)
+ if (quote_flag && loc.grouping[ii] && ++jj ==
loc.grouping[ii]) {
+ if (i) /* only add if more digits
coming */
+ PREPEND(loc.thousands_sep[0]);
/* XXX - assumption it's one char */
+ if (loc.grouping[ii+1] == 0)
+ jj = 0; /* keep using
current val in loc.grouping[ii] */
+ else if (loc.grouping[ii+1] == CHAR_MAX)
+ quote_flag = false;
+ else {
+ ii++;
+ jj = 0;
+ }
+ }
+#endif
+ } while (i > 0);
+
+ /* add more output digits to match the precision */
+ if (have_prec) {
+ while (cend - cp < prec)
+ PREPEND('0');
+ }
+
+ if (sgn)
+ PREPEND('-');
+ else if (signchar)
+ PREPEND(signchar);
+ /*
+ * When to fill with zeroes is of course not simple.
+ * First: No zero fill if left-justifying.
+ * Next: There seem to be two cases:
+ * A '0' without a precision, e.g. %06d
+ * A precision with no field width, e.g. %.10d
+ * Any other case, we don't want to fill with zeroes.
+ */
+ if (! lj
+ && ((zero_flag && ! have_prec)
+ || (fw == 0 && have_prec)))
+ fill = zero_string;
+ if (prec > fw)
+ fw = prec;
+ prec = cend - cp;
+ if (fw > prec && ! lj && fill != sp
+ && (*cp == '-' || signchar)) {
+ bchunk_one(cp);
+ cp++;
+ prec--;
+ fw--;
+ }
+ goto pr_tail;
+ case 'X':
+ chbuf = Uchbuf; /* FALL THROUGH */
+ case 'x':
+ base += 6; /* FALL THROUGH */
+ case 'u':
+ base += 2; /* FALL THROUGH */
+ case 'o':
+ base += 8;
+ need_format = false;
+ parse_next_arg();
+ (void) force_number(arg);
+ tmpval = LDBL(arg);
+
+ /*
+ * ``The result of converting a zero value with a
+ * precision of zero is no characters.''
+ *
+ * If I remember the ANSI C standard, though,
+ * it says that for octal conversions
+ * the precision is artificially increased
+ * to add an extra 0 if # is supplied.
+ * Indeed, in C,
+ * printf("%#.0o\n", 0);
+ * prints a single 0.
+ */
+ if (! alt && have_prec && prec == 0 && tmpval == 0)
+ goto pr_tail;
+
+ if (tmpval < 0) {
+ uval = (uintmax_t) (intmax_t) tmpval;
+ if ((AWKLDBL)(intmax_t)uval !=
double_to_int(tmpval))
+ goto out_of_range;
+ } else {
+ /* FIXME --- Why is this the case ? */
+ uval = (uintmax_t) tmpval;
+ if ((AWKLDBL) uval != double_to_int(tmpval))
+ goto out_of_range;
+ }
+
+ /*
+ * When to fill with zeroes is of course not simple.
+ * First: No zero fill if left-justifying.
+ * Next: There seem to be two cases:
+ * A '0' without a precision, e.g. %06d
+ * A precision with no field width, e.g. %.10d
+ * Any other case, we don't want to fill with zeroes.
+ */
+ if (! lj
+ && ((zero_flag && ! have_prec)
+ || (fw == 0 && have_prec)))
+ fill = zero_string;
+ ii = jj = 0;
+ do {
+ PREPEND(chbuf[uval % base]);
+ uval /= base;
+#if defined(HAVE_LOCALE_H)
+ if (base == 10 && quote_flag &&
loc.grouping[ii] && ++jj == loc.grouping[ii]) {
+ if (uval) /* only add if more
digits coming */
+ PREPEND(loc.thousands_sep[0]);
/* XXX --- assumption it's one char */
+ if (loc.grouping[ii+1] == 0)
+ jj = 0; /* keep using
current val in loc.grouping[ii] */
+ else if (loc.grouping[ii+1] ==
CHAR_MAX)
+ quote_flag = false;
+ else {
+ ii++;
+ jj = 0;
+ }
+ }
+#endif
+ } while (uval > 0);
+
+ /* add more output digits to match the precision */
+ if (have_prec) {
+ while (cend - cp < prec)
+ PREPEND('0');
+ }
+
+ if (alt && tmpval != 0) {
+ if (base == 16) {
+ PREPEND(cs1);
+ PREPEND('0');
+ if (fill != sp) {
+ bchunk(cp, 2);
+ cp += 2;
+ fw -= 2;
+ }
+ } else if (base == 8)
+ PREPEND('0');
+ }
+ base = 0;
+ if (prec > fw)
+ fw = prec;
+ prec = cend - cp;
+ pr_tail:
+ if (! lj) {
+ while (fw > prec) {
+ bchunk_one(fill);
+ fw--;
+ }
+ }
+ copy_count = prec;
+ if (fw == 0 && ! have_prec)
+ ;
+ else if (gawk_mb_cur_max > 1 && (cs1 == 's' || cs1 ==
'c')) {
+ assert(cp == arg->stptr || cp == cpbuf);
+ copy_count = mbc_byte_count(arg->stptr, prec);
+ }
+ bchunk(cp, copy_count);
+ while (fw > prec) {
+ bchunk_one(fill);
+ fw--;
+ }
+ s0 = s1;
+ break;
+
+ out_of_range:
+ /* out of range - emergency use of %g format */
+ if (do_lint)
+ lintwarn(_("[s]printf: value %Lg is out of
range for `%%%c' format"),
+ tmpval, cs1);
+ cs1 = 'g';
+ goto fmt1;
+
+ case 'F':
+#if ! defined(PRINTF_HAS_F_FORMAT) || PRINTF_HAS_F_FORMAT != 1
+ cs1 = 'f';
+ /* FALL THROUGH */
+#endif
+ case 'g':
+ case 'G':
+ case 'e':
+ case 'f':
+ case 'E':
+ need_format = false;
+ parse_next_arg();
+ (void) force_number(arg);
+ tmpval = LDBL(arg);
+ fmt1:
+ if (! have_prec)
+ prec = DEFAULT_G_PRECISION;
+
+ chksize(fw + prec + 11); /* 11 == slop */
+ cp = cpbuf;
+ *cp++ = '%';
+ if (lj)
+ *cp++ = '-';
+ if (signchar)
+ *cp++ = signchar;
+ if (alt)
+ *cp++ = '#';
+ if (zero_flag)
+ *cp++ = '0';
+ if (quote_flag)
+ *cp++ = '\'';
+
+#if defined(LC_NUMERIC)
+ if (quote_flag && ! use_lc_numeric)
+ setlocale(LC_NUMERIC, "");
+#endif
+
+ sprintf(cp, "*.*L%c", cs1);
+ while ((nc = snprintf(obufout, ofre, cpbuf,
+ (int) fw, (int) prec, tmpval)) >= ofre)
+ chksize(nc)
+
+#if defined(LC_NUMERIC)
+ if (quote_flag && ! use_lc_numeric)
+ setlocale(LC_NUMERIC, "C");
+#endif
+
+ len = strlen(obufout);
+ ofre -= len;
+ obufout += len;
+ s0 = s1;
+ break;
+ default:
+ if (do_lint && isalpha(cs1))
+ lintwarn(_("ignoring unknown format specifier
character `%c': no argument converted"), cs1);
+ break;
+ }
+ if (toofew) {
+ msg("%s\n\t`%s'\n\t%*s%s",
+ _("fatal: not enough arguments to satisfy format
string"),
+ fmt_string, (int) (s1 - fmt_string - 1), "",
+ _("^ ran out for this one"));
+ goto out;
+ }
+ }
+ if (do_lint) {
+ if (need_format)
+ lintwarn(
+ _("[s]printf: format specifier does not have control
letter"));
+ if (cur_arg < num_args)
+ lintwarn(
+ _("too many arguments supplied for format string"));
+ }
+ bchunk(s0, s1 - s0);
+ r = make_str_node(obuf, obufout - obuf, ALREADY_MALLOCED);
+ obuf = NULL;
+out:
+ {
+ size_t k;
+ size_t count = sizeof(cpbufs)/sizeof(cpbufs[0]);
+ for (k = 0; k < count; k++) {
+ if (cpbufs[k].buf != cpbufs[k].stackbuf)
+ efree(cpbufs[k].buf);
+ }
+ if (obuf != NULL)
+ efree(obuf);
+ }
+
+ if (r == NULL)
+ gawk_exit(EXIT_FATAL);
+ return r;
+}
+
+#else
+
+static bool mpfp_init(bltin_t **bltins);
+
+numbr_handler_t awkldbl_hndlr = {
+ awkldbl_init,
+ NULL,
+ NULL,
+};
+
+/* awkldbl_init --- initialization routine */
+
+static bool
+awkldbl_init(bltin_t **bltins)
+{
+ *bltins = NULL;
+ return false;
+}
+#endif
diff --git a/long_double.h b/long_double.h
new file mode 100644
index 0000000..9a11e55
--- /dev/null
+++ b/long_double.h
@@ -0,0 +1,134 @@
+/*
+ * long_double.h - math functions and replacements with long double arguments.
+ */
+
+/*
+ * Copyright (C) 2012 the Free Software Foundation, Inc.
+ *
+ * This file is part of GAWK, the GNU implementation of the
+ * AWK Programming Language.
+ *
+ * GAWK is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GAWK is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
USA
+ */
+
+#ifdef HAVE_SINL
+#define gawk_sinl sinl
+#else
+static inline long double
+gawk_sinl(long double x)
+{
+ return sin( (double) x);
+}
+#endif
+
+#ifdef HAVE_COSL
+#define gawk_cosl cosl
+#else
+static inline long double
+gawk_cosl(long double x)
+{
+ return cos( (double) x);
+}
+#endif
+
+#ifdef HAVE_ATAN2L
+#define gawk_atan2l atan2l
+#else
+static inline long double
+gawk_atan2l(long double y, long double x)
+{
+ return atan2( (double) y, (double) x);
+}
+#endif
+
+#ifdef HAVE_LOGL
+#define gawk_logl logl
+#else
+static inline long double
+gawk_logl(long double x)
+{
+ return log( (double) x);
+}
+#endif
+
+#ifdef HAVE_EXPL
+#define gawk_expl expl
+#else
+static inline long double
+gawk_expl(long double x)
+{
+ return exp( (double) x);
+}
+#endif
+
+#ifdef HAVE_FMODL
+#define gawk_fmodl fmodl
+#else
+static inline long double
+gawk_fmodl(long double x, long double y)
+{
+ return fmod( (double) x, (double) y);
+}
+#endif
+
+#ifdef HAVE_STRTOLD
+#define gawk_strtold strtold
+#else
+static inline long double
+gawk_strtold(const char *str, char **endptr)
+{
+ return strtod(str, endptr);
+}
+#endif
+
+#ifdef HAVE_FLOORL
+#define gawk_floorl floorl
+#else
+static inline long double
+gawk_floorl(long double x)
+{
+ return floor( (double) x);
+}
+#endif
+
+#ifdef HAVE_CEILL
+#define gawk_ceill ceill
+#else
+static inline long double
+gawk_ceill(long double x)
+{
+ return ceil( (double) x);
+}
+#endif
+
+#ifdef HAVE_POWL
+#define gawk_powl powl
+#else
+static inline long double
+gawk_powl(long double x, long double y)
+{
+ return pow( (double) x, (double) y);
+}
+#endif
+
+#ifdef HAVE_SQRTL
+#define gawk_sqrtl sqrtl
+#else
+static inline long double
+gawk_sqrtl(long double x)
+{
+ return sqrt( (double) x);
+}
+#endif
diff --git a/m4/ChangeLog b/m4/ChangeLog
index 365ccde..a674df6 100644
--- a/m4/ChangeLog
+++ b/m4/ChangeLog
@@ -1,3 +1,7 @@
+2012-12-29 John Haque <address@hidden>
+
+ * long_double.m4: New file.
+
2012-12-24 Arnold D. Robbins <address@hidden>
* 4.0.2: Release tar ball made.
diff --git a/m4/long_double.m4 b/m4/long_double.m4
new file mode 100644
index 0000000..87ef80f
--- /dev/null
+++ b/m4/long_double.m4
@@ -0,0 +1,110 @@
+# long_double.m4
+dnl Copyright (C) 2012 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl size comparison copied from gnulib math_h.m4 serial 114
+dnl gl_LONG_DOUBLE_VS_DOUBLE
+dnl determines whether 'long double' and 'double' have the same representation.
+dnl Sets variable HAVE_SAME_LONG_DOUBLE_AS_DOUBLE to 0 or 1, and defines
+dnl HAVE_SAME_LONG_DOUBLE_AS_DOUBLE accordingly.
+dnl The currently known platforms where this is the case are:
+dnl Linux/HPPA, Minix 3.1.8, AIX 5, AIX 6 and 7 with xlc, MSVC 9.
+
+dnl Defines USE_LONG_DOUBLE to 1 if long double is found and usable.
+dnl Also checks for math functions with long double arguments.
+
+AC_DEFUN([GAWK_USE_LONG_DOUBLE],
+[
+ gawk_has_long_double=no
+ USE_LONG_DOUBLE=
+
+ AC_REQUIRE([AC_TYPE_LONG_DOUBLE])
+ if test $ac_cv_type_long_double = yes; then
+ AC_CACHE_CHECK([whether long double and double are the same],
+ [gl_cv_long_double_equals_double],
+ [AC_COMPILE_IFELSE(
+ [AC_LANG_PROGRAM([[#include <float.h>]],
+ [[typedef int check[sizeof (long double) == sizeof (double)
+ && LDBL_MANT_DIG == DBL_MANT_DIG
+ && LDBL_MAX_EXP == DBL_MAX_EXP
+ && LDBL_MIN_EXP == DBL_MIN_EXP
+ ? 1 : -1];
+ ]])],
+ [gl_cv_long_double_equals_double=yes],
+ [gl_cv_long_double_equals_double=no])
+ ])
+ if test $gl_cv_long_double_equals_double = no; then
+ AC_CACHE_CHECK([whether printf supports %Lf],
+ [gawk_cv_has_L_format],
+ [AC_RUN_IFELSE(
+ [AC_LANG_PROGRAM([[#include <stdio.h>]],
+ [[char buf[100];
+ sprintf(buf, "%Lf,%Lg,%Le", (long double) 1.0, (long double) 1.0,
(long double) 1.0);
+ if (strcmp(buf, "1.000000,1,1.000000e+00") == 0)
+ return 0;
+ return 1;
+ ]])],
+ [gawk_cv_has_L_format=yes],
+ [gawk_cv_has_L_format=no])
+ ])
+ if test $gawk_cv_has_L_format = yes; then
+ gawk_has_long_double=yes
+ fi
+ fi
+ fi
+
+ if test $gawk_has_long_double = yes; then
+ AC_DEFINE([USE_LONG_DOUBLE], [1],
+ [Define to 1 if can use 'long double'.])
+
+ AC_CHECK_FUNC(strtold)
+ if test $ac_cv_func_strtold = yes; then
+ AC_DEFINE([HAVE_STRTOLD], 1, [Define to 1 if you have 'strtold'
function.])
+ fi
+
+ AC_CHECK_LIB(m, sinl)
+ if test $ac_cv_lib_m_sinl = yes; then
+ AC_DEFINE([HAVE_SINL], 1, [Define to 1 if you have 'sinl'
function.])
+ fi
+ AC_CHECK_LIB(m, cosl)
+ if test $ac_cv_lib_m_cosl = yes; then
+ AC_DEFINE([HAVE_COSL], 1, [Define to 1 if you have 'cosl'
function.])
+ fi
+ AC_CHECK_LIB(m, atan2l)
+ if test $ac_cv_lib_m_atan2l = yes; then
+ AC_DEFINE([HAVE_ATAN2L], 1, [Define to 1 if you have 'atan2l' function.])
+ fi
+ AC_CHECK_LIB(m, logl)
+ if test $ac_cv_lib_m_logl = yes; then
+ AC_DEFINE([HAVE_LOGL], 1, [Define to 1 if you have 'logl'
function.])
+ fi
+ AC_CHECK_LIB(m, expl)
+ if test $ac_cv_lib_m_expl = yes; then
+ AC_DEFINE([HAVE_EXPL], 1, [Define to 1 if you have 'expl'
function.])
+ fi
+ AC_CHECK_LIB(m, fmodl)
+ if test $ac_cv_lib_m_fmodl = yes; then
+ AC_DEFINE([HAVE_FMODL], 1, [Define to 1 if you have 'fmodl' function.])
+ fi
+ AC_CHECK_LIB(m, floorl)
+ if test $ac_cv_lib_m_floorl = yes; then
+ AC_DEFINE([HAVE_FLOORL], 1, [Define to 1 if you have 'floorl' function.])
+ fi
+ AC_CHECK_LIB(m, ceill)
+ if test $ac_cv_lib_m_ceill = yes; then
+ AC_DEFINE([HAVE_CEILL], 1, [Define to 1 if you have 'ceill' function.])
+ fi
+ AC_CHECK_LIB(m, powl)
+ if test $ac_cv_lib_m_powl = yes; then
+ AC_DEFINE([HAVE_POWL], 1, [Define to 1 if you have 'powl'
function.])
+ fi
+ AC_CHECK_LIB(m, sqrtl)
+ if test $ac_cv_lib_m_sqrtl = yes; then
+ AC_DEFINE([HAVE_SQRTL], 1, [Define to 1 if you have 'sqrtl' function.])
+ fi
+ fi
+
+ AC_SUBST(USE_LONG_DOUBLE)
+])
diff --git a/main.c b/main.c
index 24dbb56..694eb92 100644
--- a/main.c
+++ b/main.c
@@ -204,7 +204,7 @@ main(int argc, char **argv)
/*
* The + on the front tells GNU getopt not to rearrange argv.
*/
- const char *optlist =
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::MPrStVY";
+ const char *optlist =
"+F:f:v:W;m:bcCd::D::e:E:gh:i:l:L:nNo::Op::BMPrStVY";
bool stopped_early = false;
int old_optind;
int i;
@@ -367,6 +367,10 @@ main(int argc, char **argv)
do_binary = true;
break;
+ case 'B':
+ numbr_hndlr = & awkldbl_hndlr;
+ break;
+
case 'c':
do_flags |= DO_TRADITIONAL;
break;
@@ -1562,6 +1566,7 @@ print_numbr_hndlr_versions()
{
static numbr_handler_t *hndlrs[] = {
& awknum_hndlr,
+ & awkldbl_hndlr,
& mpfp_hndlr,
};
int i;
diff --git a/node.c b/node.c
index 9efd767..664a61f 100644
--- a/node.c
+++ b/node.c
@@ -97,7 +97,8 @@ make_str_node(const char *s, size_t len, int flags)
NODE *r;
getnode(r);
r->type = Node_val;
- r->numbr = 0;
+ r->numbr = 0; /* FIXME: uninitialized? it is NaN in MPFR */
+ r->qnumbr = NULL;
r->flags = (MALLOC|STRING|STRCUR);
r->valref = 1;
r->stfmt = -1;
@@ -649,6 +650,7 @@ BLOCK nextfree[BLOCK_MAX] = {
{ 0, NULL}, /* invalid */
{ sizeof(NODE), NULL },
{ sizeof(BUCKET), NULL },
+ { sizeof(long double), NULL},
};
diff --git a/str_array.c b/str_array.c
index e5b3b40..fcb11e9 100644
--- a/str_array.c
+++ b/str_array.c
@@ -157,7 +157,7 @@ str_lookup(NODE *symbol, NODE *subs)
* never be used.
*/
- if ((subs->flags & (MPFN|MPZN|NUMCUR)) == NUMCUR) {
+ if ((subs->flags & NUMCUR) != 0 && numbr_hndlr == &
awknum_hndlr) {
tmp->numbr = subs->numbr;
tmp->flags |= NUMCUR;
}
diff --git a/test/Makefile.in b/test/Makefile.in
index e4b22fd..b2e0172 100644
--- a/test/Makefile.in
+++ b/test/Makefile.in
@@ -82,11 +82,12 @@ am__aclocal_m4_deps = $(top_srcdir)/m4/arch.m4 \
$(top_srcdir)/m4/isc-posix.m4 $(top_srcdir)/m4/lcmessage.m4 \
$(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
$(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libsigsegv.m4 \
- $(top_srcdir)/m4/longlong.m4 $(top_srcdir)/m4/mpfr.m4 \
- $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/noreturn.m4 \
- $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \
- $(top_srcdir)/m4/readline.m4 $(top_srcdir)/m4/socket.m4 \
- $(top_srcdir)/m4/ulonglong.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/long_double.m4 $(top_srcdir)/m4/longlong.m4 \
+ $(top_srcdir)/m4/mpfr.m4 $(top_srcdir)/m4/nls.m4 \
+ $(top_srcdir)/m4/noreturn.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/m4/readline.m4 \
+ $(top_srcdir)/m4/socket.m4 $(top_srcdir)/m4/ulonglong.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
@@ -175,6 +176,7 @@ SET_MAKE = @SET_MAKE@
SHELL = @SHELL@
SOCKET_LIBS = @SOCKET_LIBS@
STRIP = @STRIP@
+USE_LONG_DOUBLE = @USE_LONG_DOUBLE@
USE_NLS = @USE_NLS@
VERSION = @VERSION@
XGETTEXT = @XGETTEXT@
-----------------------------------------------------------------------
hooks/post-receive
--
gawk
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [gawk-diffs] [SCM] gawk branch, long-double, created. 685a7ea80272a51da2b4c0051123ffd084abb2ec,
John Haque <=