$OpenBSD: patch-nsprpub_pr_src_misc_prdtoa_c,v 1.2 2006/02/05 02:39:18 pvalchev Exp $
--- nsprpub/pr/src/misc/prdtoa.c.orig	Tue Apr 27 18:34:07 2004
+++ nsprpub/pr/src/misc/prdtoa.c	Sat Feb  4 18:47:53 2006
@@ -1,82 +1,8 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is the Netscape Portable Runtime (NSPR).
- *
- * The Initial Developer of the Original Code is
- * Netscape Communications Corporation.
- * Portions created by the Initial Developer are Copyright (C) 1998-2000
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#include "primpl.h"
-
-#define MULTIPLE_THREADS
-#define ACQUIRE_DTOA_LOCK(n)	PR_Lock(dtoa_lock[n])
-#define FREE_DTOA_LOCK(n)	PR_Unlock(dtoa_lock[n])
-
-static PRLock *dtoa_lock[2];
-
-void _PR_InitDtoa(void)
-{
-    dtoa_lock[0] = PR_NewLock();
-    dtoa_lock[1] = PR_NewLock();
-}
-
-void _PR_CleanupDtoa(void)
-{
-    PR_DestroyLock(dtoa_lock[0]);
-    dtoa_lock[0] = NULL;
-    PR_DestroyLock(dtoa_lock[1]);
-    dtoa_lock[1] = NULL;
-
-    /* FIXME: deal with freelist and p5s. */
-}
-
-#if defined(__arm) || defined(__arm__) || defined(__arm26__) \
-    || defined(__arm32__)
-#define IEEE_ARM
-#elif defined(IS_LITTLE_ENDIAN)
-#define IEEE_8087
-#else
-#define IEEE_MC68k
-#endif
-
-#define Long PRInt32
-#define ULong PRUint32
-#define NO_LONG_LONG
-
 /****************************************************************
  *
  * The author of this software is David M. Gay.
  *
- * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ * Copyright (c) 1991 by AT&T.
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose without fee is hereby granted, provided that this entire notice
@@ -85,24 +11,19 @@ void _PR_CleanupDtoa(void)
  * documentation for such software.
  *
  * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHOR NOR AT&T MAKES ANY
  * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
  * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
  *
  ***************************************************************/
 
-/* Please send bug reports to David M. Gay (dmg at acm dot org,
- * with " at " changed at "@" and " dot " changed to ".").	*/
-
-/* On a machine with IEEE extended-precision registers, it is
- * necessary to specify double-precision (53-bit) rounding precision
- * before invoking strtod or dtoa.  If the machine uses (the equivalent
- * of) Intel 80x87 arithmetic, the call
- *	_control87(PC_53, MCW_PC);
- * does this with many compilers.  Whether this or another call is
- * appropriate depends on the compiler; for this to work, it may be
- * necessary to #include "float.h" or another system-dependent header
- * file.
+/* Please send bug reports to
+	David M. Gay
+	AT&T Bell Laboratories, Room 2C-463
+	600 Mountain Avenue
+	Murray Hill, NJ 07974-2070
+	U.S.A.
+	dmg@research.att.com or research!dmg
  */
 
 /* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
@@ -136,37 +57,28 @@ void _PR_CleanupDtoa(void)
  */
 
 /*
- * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ * #define IEEE_LITTLE_ENDIAN for IEEE-arithmetic machines where the least
  *	significant byte has the lowest address.
- * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ * #define IEEE_BIG_ENDIAN for IEEE-arithmetic machines where the most
  *	significant byte has the lowest address.
- * #define IEEE_ARM for IEEE-arithmetic machines where the two words
- *	in a double are stored in big endian order but the two shorts
- *	in a word are still stored in little endian order.
  * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define Sudden_Underflow for IEEE-format machines without gradual
+ *	underflow (i.e., that flush to zero on underflow).
  * #define IBM for IBM mainframe-style floating-point arithmetic.
- * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define VAX for VAX-style floating-point arithmetic.
+ * #define Unsigned_Shifts if >> does treats its left operand as unsigned.
  * #define No_leftright to omit left-right logic in fast floating-point
  *	computation of dtoa.
- * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
- *	and strtod and dtoa should round accordingly.
- * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
- *	and Honor_FLT_ROUNDS is not #defined.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3.
  * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
  *	that use extended-precision instructions to compute rounded
  *	products and quotients) with IBM.
  * #define ROUND_BIASED for IEEE-format with biased rounding.
  * #define Inaccurate_Divide for IEEE-format with correctly rounded
  *	products but inaccurate quotients, e.g., for Intel i860.
- * #define NO_LONG_LONG on machines that do not have a "long long"
- *	integer type (of >= 64 bits).  On such machines, you can
- *	#define Just_16 to store 16 bits per 32-bit Long when doing
- *	high-precision integer arithmetic.  Whether this speeds things
- *	up or slows things down depends on the machine and the number
- *	being converted.  If long long is available and the name is
- *	something other than "long long", #define Llong to be the name,
- *	and if "unsigned Llong" does not work as an unsigned version of
- *	Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define Just_16 to store 16 bits per 32-bit Long when doing high-precision
+ *	integer arithmetic.  Whether this speeds things up or slows things
+ *	down depends on the machine and the number being converted.
  * #define KR_headers for old-style C function headers.
  * #define Bad_float_h if your system lacks a float.h or if it does not
  *	define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
@@ -175,89 +87,82 @@ void _PR_CleanupDtoa(void)
  *	if memory is available and otherwise does something you deem
  *	appropriate.  If MALLOC is undefined, malloc will be invoked
  *	directly -- and assumed always to succeed.
- * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
- *	memory allocations from a private pool of memory when possible.
- *	When used, the private pool is PRIVATE_MEM bytes long:  2304 bytes,
- *	unless #defined to be a different length.  This default length
- *	suffices to get rid of MALLOC calls except for unusual cases,
- *	such as decimal-to-binary conversion of a very long string of
- *	digits.  The longest string dtoa can return is about 751 bytes
- *	long.  For conversions by strtod of strings of 800 digits and
- *	all dtoa conversions in single-threaded executions with 8-byte
- *	pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
- *	pointers, PRIVATE_MEM >= 7112 appears adequate.
- * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
- *	Infinity and NaN (case insensitively).  On some systems (e.g.,
- *	some HP systems), it may be necessary to #define NAN_WORD0
- *	appropriately -- to the most significant word of a quiet NaN.
- *	(On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
- *	When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
- *	strtod also accepts (case insensitively) strings of the form
- *	NaN(x), where x is a string of hexadecimal digits and spaces;
- *	if there is only one string of hexadecimal digits, it is taken
- *	for the 52 fraction bits of the resulting NaN; if there are two
- *	or more strings of hex digits, the first is for the high 20 bits,
- *	the second and subsequent for the low 32 bits, with intervening
- *	white space ignored; but if this results in none of the 52
- *	fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
- *	and NAN_WORD1 are used instead.
- * #define MULTIPLE_THREADS if the system offers preemptively scheduled
- *	multiple threads.  In this case, you must provide (or suitably
- *	#define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
- *	by FREE_DTOA_LOCK(n) for n = 0 or 1.  (The second lock, accessed
- *	in pow5mult, ensures lazy evaluation of only one copy of high
- *	powers of 5; omitting this lock would introduce a small
- *	probability of wasting memory, but would otherwise be harmless.)
- *	You must also invoke freedtoa(s) to free the value s returned by
- *	dtoa.  You may do so whether or not MULTIPLE_THREADS is #defined.
- * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
- *	avoids underflows on inputs whose result does not underflow.
- *	If you #define NO_IEEE_Scale on a machine that uses IEEE-format
- *	floating-point numbers and flushes underflows to zero rather
- *	than implementing gradual underflow, then you must also #define
- *	Sudden_Underflow.
- * #define YES_ALIAS to permit aliasing certain double values with
- *	arrays of ULongs.  This leads to slightly better code with
- *	some compilers and was always used prior to 19990916, but it
- *	is not strictly legal and can cause trouble with aggressively
- *	optimizing compilers (e.g., gcc 2.95.1 under -O2).
- * #define USE_LOCALE to use the current locale's decimal_point value.
- * #define SET_INEXACT if IEEE arithmetic is being used and extra
- *	computation should be done to set the inexact flag when the
- *	result is inexact and avoid setting inexact when the result
- *	is exact.  In this case, dtoa.c must be compiled in
- *	an environment, perhaps provided by #include "dtoa.c" in a
- *	suitable wrapper, that defines two functions,
- *		int get_inexact(void);
- *		void clear_inexact(void);
- *	such that get_inexact() returns a nonzero value if the
- *	inexact bit is already set, and clear_inexact() sets the
- *	inexact bit to 0.  When SET_INEXACT is #defined, strtod
- *	also does extra computations to set the underflow and overflow
- *	flags when appropriate (i.e., when the result is tiny and
- *	inexact or when it is a numeric value rounded to +-infinity).
- * #define NO_ERRNO if strtod should not assign errno = ERANGE when
- *	the result overflows to +-Infinity or underflows to 0.
  */
 
-#ifndef Long
-#define Long long
+#if defined(LIBC_SCCS) && !defined(lint)
+static char *rcsid = "$OpenBSD: patch-nsprpub_pr_src_misc_prdtoa_c,v 1.2 2006/02/05 02:39:18 pvalchev Exp $";
+#endif /* LIBC_SCCS and not lint */
+
+#include "primpl.h"
+
+#define MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n)    PR_Lock(dtoa_lock[n])
+#define FREE_DTOA_LOCK(n)       PR_Unlock(dtoa_lock[n])
+
+static PRLock *dtoa_lock[2];
+
+void _PR_InitDtoa(void)
+{
+    dtoa_lock[0] = PR_NewLock();
+    dtoa_lock[1] = PR_NewLock();
+}
+
+void _PR_CleanupDtoa(void)
+{
+    PR_DestroyLock(dtoa_lock[0]);
+    dtoa_lock[0] = NULL;
+    PR_DestroyLock(dtoa_lock[1]);
+    dtoa_lock[1] = NULL;
+
+    /* FIXME: deal with freelist and p5s. */
+}
+
+#if defined(__m68k__) || defined(__sparc__) || defined(__i386__) || \
+    defined(__mips__) || defined(__ns32k__) || defined(__alpha__) || \
+    defined(__powerpc__) || defined(__m88k__) || defined(__hppa__) || \
+    defined(__x86_64__) || (defined(__arm__) && defined(__VFP_FP__))
+#include <sys/types.h>
+#if BYTE_ORDER == BIG_ENDIAN
+#define IEEE_BIG_ENDIAN
+#else
+#define IEEE_LITTLE_ENDIAN
 #endif
-#ifndef ULong
-typedef unsigned Long ULong;
 #endif
 
+#if defined(__arm__) && !defined(__VFP_FP__)
+/*
+ * Although the CPU is little endian the FP has different
+ * byte and word endianness. The byte order is still little endian
+ * but the word order is big endian.
+ */
+#define IEEE_BIG_ENDIAN
+#endif
+
+#ifdef __vax__
+#define VAX
+#endif
+
+#define Long	int32_t
+#define ULong	u_int32_t
+
 #ifdef DEBUG
 #include "stdio.h"
 #define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
 #endif
 
+#ifdef __cplusplus
+#include "malloc.h"
+#include "memory.h"
+#else
+#ifndef KR_headers
 #include "stdlib.h"
 #include "string.h"
-
-#ifdef USE_LOCALE
 #include "locale.h"
+#else
+#include "malloc.h"
+#include "memory.h"
 #endif
+#endif
 
 #ifdef MALLOC
 #ifdef KR_headers
@@ -269,42 +174,32 @@ extern void *MALLOC(size_t);
 #define MALLOC malloc
 #endif
 
-#ifndef Omit_Private_Memory
-#ifndef PRIVATE_MEM
-#define PRIVATE_MEM 2304
-#endif
-#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
-static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
-#endif
+#include "ctype.h"
+#include "errno.h"
 
-#undef IEEE_Arith
-#undef Avoid_Underflow
-#ifdef IEEE_MC68k
-#define IEEE_Arith
+#ifdef Bad_float_h
+#ifdef IEEE_BIG_ENDIAN
+#define IEEE_ARITHMETIC
 #endif
-#ifdef IEEE_8087
-#define IEEE_Arith
+#ifdef IEEE_LITTLE_ENDIAN
+#define IEEE_ARITHMETIC
 #endif
-#ifdef IEEE_ARM
-#define IEEE_Arith
-#endif
 
-#include "errno.h"
-
-#ifdef Bad_float_h
-
-#ifdef IEEE_Arith
+#ifdef IEEE_ARITHMETIC
 #define DBL_DIG 15
 #define DBL_MAX_10_EXP 308
 #define DBL_MAX_EXP 1024
 #define FLT_RADIX 2
-#endif /*IEEE_Arith*/
+#define FLT_ROUNDS 1
+#define DBL_MAX 1.7976931348623157e+308
+#endif
 
 #ifdef IBM
 #define DBL_DIG 16
 #define DBL_MAX_10_EXP 75
 #define DBL_MAX_EXP 63
 #define FLT_RADIX 16
+#define FLT_ROUNDS 0
 #define DBL_MAX 7.2370055773322621e+75
 #endif
 
@@ -313,27 +208,16 @@ static double private_mem[PRIVATE_mem], 
 #define DBL_MAX_10_EXP 38
 #define DBL_MAX_EXP 127
 #define FLT_RADIX 2
+#define FLT_ROUNDS 1
 #define DBL_MAX 1.7014118346046923e+38
 #endif
 
 #ifndef LONG_MAX
 #define LONG_MAX 2147483647
 #endif
-
-#else /* ifndef Bad_float_h */
+#else
 #include "float.h"
-/*
- * MacOS 10.2 defines the macro FLT_ROUNDS to an internal function
- * which does not exist on 10.1.  We can safely #define it to 1 here
- * to allow 10.2 builds to run on 10.1, since we can't use fesetround()
- * (which does not exist on 10.1 either).
- */
-#if defined(MACOS_DEPLOYMENT_TARGET) && (MACOS_DEPLOYMENT_TARGET < 100200)
-#undef FLT_ROUNDS
-#define FLT_ROUNDS 1
 #endif
-#endif /* Bad_float_h */
-
 #ifndef __MATH_H__
 #include "math.h"
 #endif
@@ -350,37 +234,43 @@ extern "C" {
 #endif
 #endif
 
-#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) + defined(VAX) + defined(IBM) != 1
-Exactly one of IEEE_8087, IEEE_MC68k, IEEE_ARM, VAX, or IBM should be defined.
+#ifdef Unsigned_Shifts
+#define Sign_Extend(a,b) if (b < 0) a |= 0xffff0000;
+#else
+#define Sign_Extend(a,b) /*no-op*/
 #endif
 
-typedef union { double d; ULong L[2]; } U;
+#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN) + defined(VAX) + \
+    defined(IBM) != 1
+Exactly one of IEEE_LITTLE_ENDIAN IEEE_BIG_ENDIAN, VAX, or
+IBM should be defined.
+#endif
 
-#ifdef YES_ALIAS
-#define dval(x) x
-#ifdef IEEE_8087
+typedef union {
+	double d;
+	ULong ul[2];
+} _double;
+#define value(x) ((x).d)
+#ifdef IEEE_LITTLE_ENDIAN
+/*#define word0(x) ((x).ul[1])
+  #define word1(x) ((x).ul[0]) */
 #define word0(x) ((ULong *)&x)[1]
 #define word1(x) ((ULong *)&x)[0]
 #else
+/* #define word0(x) ((x).ul[0])
+   #define word1(x) ((x).ul[1]) */
 #define word0(x) ((ULong *)&x)[0]
 #define word1(x) ((ULong *)&x)[1]
+/* #define word0(x) ((U*)&x)->L[0]
+   #define word1(x) ((U*)&x)->L[1] */
 #endif
-#else
-#ifdef IEEE_8087
-#define word0(x) ((U*)&x)->L[1]
-#define word1(x) ((U*)&x)->L[0]
-#else
-#define word0(x) ((U*)&x)->L[0]
-#define word1(x) ((U*)&x)->L[1]
-#endif
-#define dval(x) ((U*)&x)->d
-#endif
+#define dval(x) x
 
 /* The following definition of Storeinc is appropriate for MIPS processors.
  * An alternative that might be better on some machines is
  * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
  */
-#if defined(IEEE_8087) + defined(IEEE_ARM) + defined(VAX)
+#if defined(IEEE_LITTLE_ENDIAN) + defined(VAX) + defined(__arm__)
 #define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
 ((unsigned short *)a)[0] = (unsigned short)c, a++)
 #else
@@ -394,7 +284,7 @@ typedef union { double d; ULong L[2]; } 
 /* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
 /* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
 
-#ifdef IEEE_Arith
+#if defined(IEEE_LITTLE_ENDIAN) + defined(IEEE_BIG_ENDIAN)
 #define Exp_shift  20
 #define Exp_shift1 20
 #define Exp_msk1    0x100000
@@ -402,6 +292,7 @@ typedef union { double d; ULong L[2]; } 
 #define Exp_mask  0x7ff00000
 #define P 53
 #define Bias 1023
+#define IEEE_Arith
 #define Emin (-1022)
 #define Exp_1  0x3ff00000
 #define Exp_11 0x3ff00000
@@ -419,38 +310,11 @@ typedef union { double d; ULong L[2]; } 
 #define Tiny1 1
 #define Quick_max 14
 #define Int_max 14
-#ifndef NO_IEEE_Scale
-#define Avoid_Underflow
-#ifdef Flush_Denorm	/* debugging option */
-#undef Sudden_Underflow
-#endif
-#endif
-
-#ifndef Flt_Rounds
-#ifdef FLT_ROUNDS
-#define Flt_Rounds FLT_ROUNDS
+#define Infinite(x) (word0(x) == 0x7ff00000) /* sufficient test for here */
 #else
-#define Flt_Rounds 1
-#endif
-#endif /*Flt_Rounds*/
-
-#ifdef Honor_FLT_ROUNDS
-#define Rounding rounding
-#undef Check_FLT_ROUNDS
-#define Check_FLT_ROUNDS
-#else
-#define Rounding Flt_Rounds
-#endif
-
-#else /* ifndef IEEE_Arith */
-#undef Check_FLT_ROUNDS
-#undef Honor_FLT_ROUNDS
-#undef SET_INEXACT
 #undef  Sudden_Underflow
 #define Sudden_Underflow
 #ifdef IBM
-#undef Flt_Rounds
-#define Flt_Rounds 0
 #define Exp_shift  24
 #define Exp_shift1 24
 #define Exp_msk1   0x1000000
@@ -475,8 +339,6 @@ typedef union { double d; ULong L[2]; } 
 #define Quick_max 14
 #define Int_max 15
 #else /* VAX */
-#undef Flt_Rounds
-#define Flt_Rounds 1
 #define Exp_shift  23
 #define Exp_shift1 7
 #define Exp_msk1    0x80
@@ -500,8 +362,8 @@ typedef union { double d; ULong L[2]; } 
 #define Tiny1 0
 #define Quick_max 15
 #define Int_max 15
-#endif /* IBM, VAX */
-#endif /* IEEE_Arith */
+#endif
+#endif
 
 #ifndef IEEE_Arith
 #define ROUND_BIASED
@@ -523,42 +385,25 @@ extern double rnd_prod(double, double), 
 #define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
 #define Big1 0xffffffff
 
-#ifndef Pack_32
-#define Pack_32
-#endif
-
-#ifdef KR_headers
-#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
-#else
-#define FFFFFFFF 0xffffffffUL
-#endif
-
-#ifdef NO_LONG_LONG
-#undef ULLong
-#ifdef Just_16
-#undef Pack_32
+#ifndef Just_16
 /* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
  * This makes some inner loops simpler and sometimes saves work
  * during multiplications, but it often seems to make things slightly
  * slower.  Hence the default is now to store 32 bits per Long.
  */
+#ifndef Pack_32
+#define Pack_32
 #endif
-#else	/* long long available */
-#ifndef Llong
-#define Llong long long
 #endif
-#ifndef ULLong
-#define ULLong unsigned Llong
-#endif
-#endif /* NO_LONG_LONG */
 
-#ifndef MULTIPLE_THREADS
-#define ACQUIRE_DTOA_LOCK(n)	/*nothing*/
-#define FREE_DTOA_LOCK(n)	/*nothing*/
-#endif
-
 #define Kmax 15
 
+#ifdef __cplusplus
+extern "C" double PR_strtod(const char *s00, char **se);
+extern "C" char *dtoa(double d, int mode, int ndigits,
+			int *decpt, int *sign, char **rve);
+#endif
+
  struct
 Bigint {
 	struct Bigint *next;
@@ -580,32 +425,16 @@ Balloc
 {
 	int x;
 	Bigint *rv;
-#ifndef Omit_Private_Memory
-	unsigned int len;
-#endif
 
-	ACQUIRE_DTOA_LOCK(0);
-	if (rv = freelist[k]) {
+	if ((rv = freelist[k])) {
 		freelist[k] = rv->next;
 		}
 	else {
 		x = 1 << k;
-#ifdef Omit_Private_Memory
-		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
-#else
-		len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
-			/sizeof(double);
-		if (pmem_next - private_mem + len <= PRIVATE_mem) {
-			rv = (Bigint*)pmem_next;
-			pmem_next += len;
-			}
-		else
-			rv = (Bigint*)MALLOC(len*sizeof(double));
-#endif
+		rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
 		rv->k = k;
 		rv->maxwds = x;
 		}
-	FREE_DTOA_LOCK(0);
 	rv->sign = rv->wds = 0;
 	return rv;
 	}
@@ -619,10 +448,8 @@ Bfree
 #endif
 {
 	if (v) {
-		ACQUIRE_DTOA_LOCK(0);
 		v->next = freelist[v->k];
 		freelist[v->k] = v;
-		FREE_DTOA_LOCK(0);
 		}
 	}
 
@@ -638,49 +465,37 @@ multadd
 #endif
 {
 	int i, wds;
-#ifdef ULLong
-	ULong *x;
-	ULLong carry, y;
-#else
-	ULong carry, *x, y;
+	ULong *x, y;
 #ifdef Pack_32
 	ULong xi, z;
 #endif
-#endif
 	Bigint *b1;
 
 	wds = b->wds;
 	x = b->x;
 	i = 0;
-	carry = a;
 	do {
-#ifdef ULLong
-		y = *x * (ULLong)m + carry;
-		carry = y >> 32;
-		*x++ = y & FFFFFFFF;
-#else
 #ifdef Pack_32
 		xi = *x;
-		y = (xi & 0xffff) * m + carry;
+		y = (xi & 0xffff) * m + a;
 		z = (xi >> 16) * m + (y >> 16);
-		carry = z >> 16;
+		a = (int)(z >> 16);
 		*x++ = (z << 16) + (y & 0xffff);
 #else
-		y = *x * m + carry;
-		carry = y >> 16;
+		y = *x * m + a;
+		a = (int)(y >> 16);
 		*x++ = y & 0xffff;
 #endif
-#endif
 		}
 		while(++i < wds);
-	if (carry) {
+	if (a) {
 		if (wds >= b->maxwds) {
 			b1 = Balloc(b->k+1);
 			Bcopy(b1, b);
 			Bfree(b);
 			b = b1;
 			}
-		b->x[wds++] = carry;
+		b->x[wds++] = a;
 		b->wds = wds;
 		}
 	return b;
@@ -799,7 +614,7 @@ lo0bits
 	if (!(x & 1)) {
 		k++;
 		x >>= 1;
-		if (!x)
+		if (!x & 1)
 			return 32;
 		}
 	*y = x;
@@ -832,16 +647,11 @@ mult
 {
 	Bigint *c;
 	int k, wa, wb, wc;
+	ULong carry, y, z;
 	ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
-	ULong y;
-#ifdef ULLong
-	ULLong carry, z;
-#else
-	ULong carry, z;
 #ifdef Pack_32
 	ULong z2;
 #endif
-#endif
 
 	if (a->wds < b->wds) {
 		c = a;
@@ -862,25 +672,9 @@ mult
 	xb = b->x;
 	xbe = xb + wb;
 	xc0 = c->x;
-#ifdef ULLong
-	for(; xb < xbe; xc0++) {
-		if (y = *xb++) {
-			x = xa;
-			xc = xc0;
-			carry = 0;
-			do {
-				z = *x++ * (ULLong)y + *xc + carry;
-				carry = z >> 32;
-				*xc++ = z & FFFFFFFF;
-				}
-				while(x < xae);
-			*xc = carry;
-			}
-		}
-#else
 #ifdef Pack_32
 	for(; xb < xbe; xb++, xc0++) {
-		if (y = *xb & 0xffff) {
+		if ((y = *xb & 0xffff)) {
 			x = xa;
 			xc = xc0;
 			carry = 0;
@@ -894,7 +688,7 @@ mult
 				while(x < xae);
 			*xc = carry;
 			}
-		if (y = *xb >> 16) {
+		if ((y = *xb >> 16)) {
 			x = xa;
 			xc = xc0;
 			carry = 0;
@@ -926,7 +720,6 @@ mult
 			}
 		}
 #endif
-#endif
 	for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
 	c->wds = wc;
 	return c;
@@ -946,24 +739,15 @@ pow5mult
 	int i;
 	static int p05[3] = { 5, 25, 125 };
 
-	if (i = k & 3)
+	if ((i = k & 3))
 		b = multadd(b, p05[i-1], 0);
 
 	if (!(k >>= 2))
 		return b;
 	if (!(p5 = p5s)) {
 		/* first time */
-#ifdef MULTIPLE_THREADS
-		ACQUIRE_DTOA_LOCK(1);
-		if (!(p5 = p5s)) {
-			p5 = p5s = i2b(625);
-			p5->next = 0;
-			}
-		FREE_DTOA_LOCK(1);
-#else
 		p5 = p5s = i2b(625);
 		p5->next = 0;
-#endif
 		}
 	for(;;) {
 		if (k & 1) {
@@ -974,17 +758,8 @@ pow5mult
 		if (!(k >>= 1))
 			break;
 		if (!(p51 = p5->next)) {
-#ifdef MULTIPLE_THREADS
-			ACQUIRE_DTOA_LOCK(1);
-			if (!(p51 = p5->next)) {
-				p51 = p5->next = mult(p5,p5);
-				p51->next = 0;
-				}
-			FREE_DTOA_LOCK(1);
-#else
 			p51 = p5->next = mult(p5,p5);
 			p51->next = 0;
-#endif
 			}
 		p5 = p51;
 		}
@@ -1027,7 +802,7 @@ lshift
 			z = *x++ >> k1;
 			}
 			while(x < xe);
-		if (*x1 = z)
+		if ((*x1 = z))
 			++n1;
 		}
 #else
@@ -1095,15 +870,11 @@ diff
 {
 	Bigint *c;
 	int i, wa, wb;
+	Long borrow, y;	/* We need signed shifts here. */
 	ULong *xa, *xae, *xb, *xbe, *xc;
-#ifdef ULLong
-	ULLong borrow, y;
-#else
-	ULong borrow, y;
 #ifdef Pack_32
-	ULong z;
+	Long z;
 #endif
-#endif
 
 	i = cmp(a,b);
 	if (!i) {
@@ -1130,49 +901,41 @@ diff
 	xbe = xb + wb;
 	xc = c->x;
 	borrow = 0;
-#ifdef ULLong
-	do {
-		y = (ULLong)*xa++ - *xb++ - borrow;
-		borrow = y >> 32 & (ULong)1;
-		*xc++ = y & FFFFFFFF;
-		}
-		while(xb < xbe);
-	while(xa < xae) {
-		y = *xa++ - borrow;
-		borrow = y >> 32 & (ULong)1;
-		*xc++ = y & FFFFFFFF;
-		}
-#else
 #ifdef Pack_32
 	do {
-		y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
-		borrow = (y & 0x10000) >> 16;
-		z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
-		borrow = (z & 0x10000) >> 16;
+		y = (*xa & 0xffff) - (*xb & 0xffff) + borrow;
+		borrow = y >> 16;
+		Sign_Extend(borrow, y);
+		z = (*xa++ >> 16) - (*xb++ >> 16) + borrow;
+		borrow = z >> 16;
+		Sign_Extend(borrow, z);
 		Storeinc(xc, z, y);
 		}
 		while(xb < xbe);
 	while(xa < xae) {
-		y = (*xa & 0xffff) - borrow;
-		borrow = (y & 0x10000) >> 16;
-		z = (*xa++ >> 16) - borrow;
-		borrow = (z & 0x10000) >> 16;
+		y = (*xa & 0xffff) + borrow;
+		borrow = y >> 16;
+		Sign_Extend(borrow, y);
+		z = (*xa++ >> 16) + borrow;
+		borrow = z >> 16;
+		Sign_Extend(borrow, z);
 		Storeinc(xc, z, y);
 		}
 #else
 	do {
-		y = *xa++ - *xb++ - borrow;
-		borrow = (y & 0x10000) >> 16;
+		y = *xa++ - *xb++ + borrow;
+		borrow = y >> 16;
+		Sign_Extend(borrow, y);
 		*xc++ = y & 0xffff;
 		}
 		while(xb < xbe);
 	while(xa < xae) {
-		y = *xa++ - borrow;
-		borrow = (y & 0x10000) >> 16;
+		y = *xa++ + borrow;
+		borrow = y >> 16;
+		Sign_Extend(borrow, y);
 		*xc++ = y & 0xffff;
 		}
 #endif
-#endif
 	while(!*--xc)
 		wa--;
 	c->wds = wa;
@@ -1182,26 +945,25 @@ diff
  static double
 ulp
 #ifdef KR_headers
-	(x) double x;
+	(_x) double _x;
 #else
-	(double x)
+	(double _x)
 #endif
 {
+	_double x;
 	register Long L;
-	double a;
+	_double a;
 
+	value(x) = _x;
 	L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
-#ifndef Avoid_Underflow
 #ifndef Sudden_Underflow
 	if (L > 0) {
 #endif
-#endif
 #ifdef IBM
 		L |= Exp_msk1 >> 4;
 #endif
 		word0(a) = L;
 		word1(a) = 0;
-#ifndef Avoid_Underflow
 #ifndef Sudden_Underflow
 		}
 	else {
@@ -1217,8 +979,7 @@ ulp
 			}
 		}
 #endif
-#endif
-	return dval(a);
+	return value(a);
 	}
 
  static double
@@ -1231,7 +992,7 @@ b2d
 {
 	ULong *xa, *xa0, w, y, z;
 	int k;
-	double d;
+	_double d;
 #ifdef VAX
 	ULong d0, d1;
 #else
@@ -1288,25 +1049,27 @@ b2d
 #undef d0
 #undef d1
 #endif
-	return dval(d);
+	return value(d);
 	}
 
  static Bigint *
 d2b
 #ifdef KR_headers
-	(d, e, bits) double d; int *e, *bits;
+	(_d, e, bits) double d; int *e, *bits;
 #else
-	(double d, int *e, int *bits)
+	(double _d, int *e, int *bits)
 #endif
 {
 	Bigint *b;
-	int de, k;
+	int de, i, k;
 	ULong *x, y, z;
-#ifndef Sudden_Underflow
-	int i;
-#endif
+	_double d;
 #ifdef VAX
 	ULong d0, d1;
+#endif
+
+	value(d) = _d;
+#ifdef VAX
 	d0 = word0(d) >> 16 | word0(d) << 16;
 	d1 = word1(d) >> 16 | word1(d) << 16;
 #else
@@ -1340,10 +1103,7 @@ d2b
 			}
 		else
 			x[0] = y;
-#ifndef Sudden_Underflow
-		i =
-#endif
-		    b->wds = (x[1] = z) ? 2 : 1;
+		i = b->wds = (x[1] = z) ? 2 : 1;
 		}
 	else {
 #ifdef DEBUG
@@ -1352,10 +1112,7 @@ d2b
 #endif
 		k = lo0bits(&z);
 		x[0] = z;
-#ifndef Sudden_Underflow
-		i =
-#endif
-		    b->wds = 1;
+		i = b->wds = 1;
 		k += 32;
 		}
 #else
@@ -1437,11 +1194,11 @@ ratio
 	(Bigint *a, Bigint *b)
 #endif
 {
-	double da, db;
+	_double da, db;
 	int k, ka, kb;
 
-	dval(da) = b2d(a, &ka);
-	dval(db) = b2d(b, &kb);
+	value(da) = b2d(a, &ka);
+	value(db) = b2d(b, &kb);
 #ifdef Pack_32
 	k = ka - kb + 32*(a->wds - b->wds);
 #else
@@ -1451,13 +1208,13 @@ ratio
 	if (k > 0) {
 		word0(da) += (k >> 2)*Exp_msk1;
 		if (k &= 3)
-			dval(da) *= 1 << k;
+			da *= 1 << k;
 		}
 	else {
 		k = -k;
 		word0(db) += (k >> 2)*Exp_msk1;
 		if (k &= 3)
-			dval(db) *= 1 << k;
+			db *= 1 << k;
 		}
 #else
 	if (k > 0)
@@ -1467,10 +1224,10 @@ ratio
 		word0(db) += k*Exp_msk1;
 		}
 #endif
-	return dval(da) / dval(db);
+	return value(da) / value(db);
 	}
 
- static CONST double
+static CONST double
 tens[] = {
 		1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
 		1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
@@ -1480,124 +1237,23 @@ tens[] = {
 #endif
 		};
 
- static CONST double
 #ifdef IEEE_Arith
-bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
-static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
-#ifdef Avoid_Underflow
-		9007199254740992.*9007199254740992.e-256
-		/* = 2^106 * 1e-53 */
-#else
-		1e-256
-#endif
-		};
-/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
-/* flag unnecessarily.  It leads to a song and dance at the end of strtod. */
-#define Scale_Bit 0x10
+static CONST double bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128, 1e-256 };
 #define n_bigtens 5
 #else
 #ifdef IBM
-bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST double bigtens[] = { 1e16, 1e32, 1e64 };
 static CONST double tinytens[] = { 1e-16, 1e-32, 1e-64 };
 #define n_bigtens 3
 #else
-bigtens[] = { 1e16, 1e32 };
+static CONST double bigtens[] = { 1e16, 1e32 };
 static CONST double tinytens[] = { 1e-16, 1e-32 };
 #define n_bigtens 2
 #endif
 #endif
 
-#ifndef IEEE_Arith
-#undef INFNAN_CHECK
-#endif
-
-#ifdef INFNAN_CHECK
-
-#ifndef NAN_WORD0
-#define NAN_WORD0 0x7ff80000
-#endif
-
-#ifndef NAN_WORD1
-#define NAN_WORD1 0
-#endif
-
- static int
-match
-#ifdef KR_headers
-	(sp, t) char **sp, *t;
-#else
-	(CONST char **sp, char *t)
-#endif
-{
-	int c, d;
-	CONST char *s = *sp;
-
-	while(d = *t++) {
-		if ((c = *++s) >= 'A' && c <= 'Z')
-			c += 'a' - 'A';
-		if (c != d)
-			return 0;
-		}
-	*sp = s + 1;
-	return 1;
-	}
-
-#ifndef No_Hex_NaN
- static void
-hexnan
-#ifdef KR_headers
-	(rvp, sp) double *rvp; CONST char **sp;
-#else
-	(double *rvp, CONST char **sp)
-#endif
-{
-	ULong c, x[2];
-	CONST char *s;
-	int havedig, udx0, xshift;
-
-	x[0] = x[1] = 0;
-	havedig = xshift = 0;
-	udx0 = 1;
-	s = *sp;
-	while(c = *(CONST unsigned char*)++s) {
-		if (c >= '0' && c <= '9')
-			c -= '0';
-		else if (c >= 'a' && c <= 'f')
-			c += 10 - 'a';
-		else if (c >= 'A' && c <= 'F')
-			c += 10 - 'A';
-		else if (c <= ' ') {
-			if (udx0 && havedig) {
-				udx0 = 0;
-				xshift = 1;
-				}
-			continue;
-			}
-		else if (/*(*/ c == ')' && havedig) {
-			*sp = s + 1;
-			break;
-			}
-		else
-			return;	/* invalid form: don't change *sp */
-		havedig = 1;
-		if (xshift) {
-			xshift = 0;
-			x[0] = x[1];
-			x[1] = 0;
-			}
-		if (udx0)
-			x[0] = (x[0] << 4) | (x[1] >> 28);
-		x[1] = (x[1] << 4) | c;
-		}
-	if ((x[0] &= 0xfffff) || x[1]) {
-		word0(*rvp) = Exp_mask | x[0];
-		word1(*rvp) = x[1];
-		}
-	}
-#endif /*No_Hex_NaN*/
-#endif /* INFNAN_CHECK */
-
- PR_IMPLEMENT(double)
+ double
 PR_strtod
 #ifdef KR_headers
 	(s00, se) CONST char *s00; char **se;
@@ -1605,51 +1261,40 @@ PR_strtod
 	(CONST char *s00, char **se)
 #endif
 {
-#ifdef Avoid_Underflow
-	int scale;
-#endif
 	int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
 		 e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
 	CONST char *s, *s0, *s1;
-	double aadj, aadj1, adj, rv, rv0;
+	double aadj, aadj1, adj;
+	_double rv, rv0;
 	Long L;
 	ULong y, z;
 	Bigint *bb, *bb1, *bd, *bd0, *bs, *delta;
-#ifdef SET_INEXACT
-	int inexact, oldinexact;
+
+#ifndef KR_headers
+	CONST char decimal_point = localeconv()->decimal_point[0];
+#else
+	CONST char decimal_point = '.';
 #endif
-#ifdef Honor_FLT_ROUNDS
-	int rounding;
-#endif
-#ifdef USE_LOCALE
-	CONST char *s2;
-#endif
 
-	if (!_pr_initialized) _PR_ImplicitInitialization();
-
 	sign = nz0 = nz = 0;
-	dval(rv) = 0.;
-	for(s = s00;;s++) switch(*s) {
-		case '-':
-			sign = 1;
-			/* no break */
-		case '+':
-			if (*++s)
-				goto break2;
-			/* no break */
-		case 0:
-			goto ret0;
-		case '\t':
-		case '\n':
-		case '\v':
-		case '\f':
-		case '\r':
-		case ' ':
-			continue;
-		default:
-			goto break2;
-		}
- break2:
+	value(rv) = 0.;
+
+
+	for(s = s00; isspace((unsigned char) *s); s++)
+		;
+
+	if (*s == '-') {
+		sign = 1;
+		s++;
+	} else if (*s == '+') {
+		s++;
+	}
+
+	if (*s == '\0') {
+		s = s00;
+		goto ret;
+	}
+
 	if (*s == '0') {
 		nz0 = 1;
 		while(*++s == '0') ;
@@ -1664,26 +1309,7 @@ PR_strtod
 		else if (nd < 16)
 			z = 10*z + c - '0';
 	nd0 = nd;
-#ifdef USE_LOCALE
-	s1 = localeconv()->decimal_point;
-	if (c == *s1) {
-		c = '.';
-		if (*++s1) {
-			s2 = s;
-			for(;;) {
-				if (*++s2 != *s1) {
-					c = 0;
-					break;
-					}
-				if (!*++s1) {
-					s = s2;
-					break;
-					}
-				}
-			}
-		}
-#endif
-	if (c == '.') {
+	if (c == decimal_point) {
 		c = *++s;
 		if (!nd) {
 			for(; c == '0'; c = *++s)
@@ -1718,7 +1344,8 @@ PR_strtod
 	e = 0;
 	if (c == 'e' || c == 'E') {
 		if (!nd && !nz && !nz0) {
-			goto ret0;
+			s = s00;
+			goto ret;
 			}
 		s00 = s;
 		esign = 0;
@@ -1753,38 +1380,8 @@ PR_strtod
 			s = s00;
 		}
 	if (!nd) {
-		if (!nz && !nz0) {
-#ifdef INFNAN_CHECK
-			/* Check for Nan and Infinity */
-			switch(c) {
-			  case 'i':
-			  case 'I':
-				if (match(&s,"nf")) {
-					--s;
-					if (!match(&s,"inity"))
-						++s;
-					word0(rv) = 0x7ff00000;
-					word1(rv) = 0;
-					goto ret;
-					}
-				break;
-			  case 'n':
-			  case 'N':
-				if (match(&s, "an")) {
-					word0(rv) = NAN_WORD0;
-					word1(rv) = NAN_WORD1;
-#ifndef No_Hex_NaN
-					if (*s == '(') /*)*/
-						hexnan(&rv, &s);
-#endif
-					goto ret;
-					}
-			  }
-#endif /* INFNAN_CHECK */
- ret0:
+		if (!nz && !nz0)
 			s = s00;
-			sign = 0;
-			}
 		goto ret;
 		}
 	e1 = e -= nf;
@@ -1797,21 +1394,14 @@ PR_strtod
 	if (!nd0)
 		nd0 = nd;
 	k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
-	dval(rv) = y;
-	if (k > 9) {
-#ifdef SET_INEXACT
-		if (k > DBL_DIG)
-			oldinexact = get_inexact();
-#endif
-		dval(rv) = tens[k - 9] * dval(rv) + z;
-		}
+	value(rv) = y;
+	if (k > 9)
+		value(rv) = tens[k - 9] * value(rv) + z;
 	bd0 = 0;
 	if (nd <= DBL_DIG
 #ifndef RND_PRODQUOT
-#ifndef Honor_FLT_ROUNDS
-		&& Flt_Rounds == 1
+		&& FLT_ROUNDS == 1
 #endif
-#endif
 			) {
 		if (!e)
 			goto ret;
@@ -1820,14 +1410,8 @@ PR_strtod
 #ifdef VAX
 				goto vax_ovfl_check;
 #else
-#ifdef Honor_FLT_ROUNDS
-				/* round correctly FLT_ROUNDS = 2 or 3 */
-				if (sign) {
-					rv = -rv;
-					sign = 0;
-					}
-#endif
-				/* rv = */ rounded_product(dval(rv), tens[e]);
+				/* value(rv) = */ rounded_product(value(rv),
+				    tens[e]);
 				goto ret;
 #endif
 				}
@@ -1836,184 +1420,115 @@ PR_strtod
 				/* A fancier test would sometimes let us do
 				 * this for larger i values.
 				 */
-#ifdef Honor_FLT_ROUNDS
-				/* round correctly FLT_ROUNDS = 2 or 3 */
-				if (sign) {
-					rv = -rv;
-					sign = 0;
-					}
-#endif
 				e -= i;
-				dval(rv) *= tens[i];
+				value(rv) *= tens[i];
 #ifdef VAX
 				/* VAX exponent range is so narrow we must
 				 * worry about overflow here...
 				 */
  vax_ovfl_check:
 				word0(rv) -= P*Exp_msk1;
-				/* rv = */ rounded_product(dval(rv), tens[e]);
+				/* value(rv) = */ rounded_product(value(rv),
+				    tens[e]);
 				if ((word0(rv) & Exp_mask)
 				 > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
 					goto ovfl;
 				word0(rv) += P*Exp_msk1;
 #else
-				/* rv = */ rounded_product(dval(rv), tens[e]);
+				/* value(rv) = */ rounded_product(value(rv),
+				    tens[e]);
 #endif
 				goto ret;
 				}
 			}
 #ifndef Inaccurate_Divide
 		else if (e >= -Ten_pmax) {
-#ifdef Honor_FLT_ROUNDS
-			/* round correctly FLT_ROUNDS = 2 or 3 */
-			if (sign) {
-				rv = -rv;
-				sign = 0;
-				}
-#endif
-			/* rv = */ rounded_quotient(dval(rv), tens[-e]);
+			/* value(rv) = */ rounded_quotient(value(rv),
+			    tens[-e]);
 			goto ret;
 			}
 #endif
 		}
 	e1 += nd - k;
 
-#ifdef IEEE_Arith
-#ifdef SET_INEXACT
-	inexact = 1;
-	if (k <= DBL_DIG)
-		oldinexact = get_inexact();
-#endif
-#ifdef Avoid_Underflow
-	scale = 0;
-#endif
-#ifdef Honor_FLT_ROUNDS
-	if ((rounding = Flt_Rounds) >= 2) {
-		if (sign)
-			rounding = rounding == 2 ? 0 : 2;
-		else
-			if (rounding != 2)
-				rounding = 0;
-		}
-#endif
-#endif /*IEEE_Arith*/
-
 	/* Get starting approximation = rv * 10**e1 */
 
 	if (e1 > 0) {
 		if (i = e1 & 15)
-			dval(rv) *= tens[i];
+			value(rv) *= tens[i];
 		if (e1 &= ~15) {
 			if (e1 > DBL_MAX_10_EXP) {
  ovfl:
-#ifndef NO_ERRNO
-				PR_SetError(PR_RANGE_ERROR, 0);
-#endif
+				errno = ERANGE;
+#ifndef Bad_float_h
+				value(rv) = HUGE_VAL;
+#else
 				/* Can't trust HUGE_VAL */
 #ifdef IEEE_Arith
-#ifdef Honor_FLT_ROUNDS
-				switch(rounding) {
-				  case 0: /* toward 0 */
-				  case 3: /* toward -infinity */
-					word0(rv) = Big0;
-					word1(rv) = Big1;
-					break;
-				  default:
-					word0(rv) = Exp_mask;
-					word1(rv) = 0;
-				  }
-#else /*Honor_FLT_ROUNDS*/
 				word0(rv) = Exp_mask;
 				word1(rv) = 0;
-#endif /*Honor_FLT_ROUNDS*/
-#ifdef SET_INEXACT
-				/* set overflow bit */
-				dval(rv0) = 1e300;
-				dval(rv0) *= dval(rv0);
-#endif
-#else /*IEEE_Arith*/
+#else
 				word0(rv) = Big0;
 				word1(rv) = Big1;
-#endif /*IEEE_Arith*/
+#endif
+#endif
 				if (bd0)
 					goto retfree;
 				goto ret;
 				}
-			e1 >>= 4;
-			for(j = 0; e1 > 1; j++, e1 >>= 1)
-				if (e1 & 1)
-					dval(rv) *= bigtens[j];
-		/* The last multiplication could overflow. */
-			word0(rv) -= P*Exp_msk1;
-			dval(rv) *= bigtens[j];
-			if ((z = word0(rv) & Exp_mask)
-			 > Exp_msk1*(DBL_MAX_EXP+Bias-P))
-				goto ovfl;
-			if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
-				/* set to largest number */
-				/* (Can't trust DBL_MAX) */
-				word0(rv) = Big0;
-				word1(rv) = Big1;
+			if (e1 >>= 4) {
+				for(j = 0; e1 > 1; j++, e1 >>= 1)
+					if (e1 & 1)
+						value(rv) *= bigtens[j];
+			/* The last multiplication could overflow. */
+				word0(rv) -= P*Exp_msk1;
+				value(rv) *= bigtens[j];
+				if ((z = word0(rv) & Exp_mask)
+				 > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+					goto ovfl;
+				if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+					/* set to largest number */
+					/* (Can't trust DBL_MAX) */
+					word0(rv) = Big0;
+					word1(rv) = Big1;
+					}
+				else
+					word0(rv) += P*Exp_msk1;
 				}
-			else
-				word0(rv) += P*Exp_msk1;
+
 			}
 		}
 	else if (e1 < 0) {
 		e1 = -e1;
 		if (i = e1 & 15)
-			dval(rv) /= tens[i];
-		if (e1 >>= 4) {
+			value(rv) /= tens[i];
+		if (e1 &= ~15) {
+			e1 >>= 4;
 			if (e1 >= 1 << n_bigtens)
 				goto undfl;
-#ifdef Avoid_Underflow
-			if (e1 & Scale_Bit)
-				scale = 2*P;
-			for(j = 0; e1 > 0; j++, e1 >>= 1)
-				if (e1 & 1)
-					dval(rv) *= tinytens[j];
-			if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
-						>> Exp_shift)) > 0) {
-				/* scaled rv is denormal; zap j low bits */
-				if (j >= 32) {
-					word1(rv) = 0;
-					if (j >= 53)
-					 word0(rv) = (P+2)*Exp_msk1;
-					else
-					 word0(rv) &= 0xffffffff << j-32;
-					}
-				else
-					word1(rv) &= 0xffffffff << j;
-				}
-#else
 			for(j = 0; e1 > 1; j++, e1 >>= 1)
 				if (e1 & 1)
-					dval(rv) *= tinytens[j];
+					value(rv) *= tinytens[j];
 			/* The last multiplication could underflow. */
-			dval(rv0) = dval(rv);
-			dval(rv) *= tinytens[j];
-			if (!dval(rv)) {
-				dval(rv) = 2.*dval(rv0);
-				dval(rv) *= tinytens[j];
-#endif
-				if (!dval(rv)) {
+			value(rv0) = value(rv);
+			value(rv) *= tinytens[j];
+			if (!value(rv)) {
+				value(rv) = 2.*value(rv0);
+				value(rv) *= tinytens[j];
+				if (!value(rv)) {
  undfl:
-					dval(rv) = 0.;
-#ifndef NO_ERRNO
-					PR_SetError(PR_RANGE_ERROR, 0);
-#endif
+					value(rv) = 0.;
+					errno = ERANGE;
 					if (bd0)
 						goto retfree;
 					goto ret;
 					}
-#ifndef Avoid_Underflow
 				word0(rv) = Tiny0;
 				word1(rv) = Tiny1;
 				/* The refinement below will clean
 				 * this approximation up.
 				 */
 				}
-#endif
 			}
 		}
 
@@ -2026,7 +1541,7 @@ PR_strtod
 	for(;;) {
 		bd = Balloc(bd0->k);
 		Bcopy(bd, bd0);
-		bb = d2b(dval(rv), &bbe, &bbbits);	/* rv = bb * 2^bbe */
+		bb = d2b(value(rv), &bbe, &bbbits);	/* rv = bb * 2^bbe */
 		bs = i2b(1);
 
 		if (e >= 0) {
@@ -2042,38 +1557,21 @@ PR_strtod
 		else
 			bd2 -= bbe;
 		bs2 = bb2;
-#ifdef Honor_FLT_ROUNDS
-		if (rounding != 1)
-			bs2++;
-#endif
-#ifdef Avoid_Underflow
-		j = bbe - scale;
-		i = j + bbbits - 1;	/* logb(rv) */
-		if (i < Emin)	/* denormal */
-			j += P - Emin;
-		else
-			j = P + 1 - bbbits;
-#else /*Avoid_Underflow*/
 #ifdef Sudden_Underflow
 #ifdef IBM
 		j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
 #else
 		j = P + 1 - bbbits;
 #endif
-#else /*Sudden_Underflow*/
-		j = bbe;
-		i = j + bbbits - 1;	/* logb(rv) */
+#else
+		i = bbe + bbbits - 1;	/* logb(rv) */
 		if (i < Emin)	/* denormal */
-			j += P - Emin;
+			j = bbe + (P-Emin);
 		else
 			j = P + 1 - bbbits;
-#endif /*Sudden_Underflow*/
-#endif /*Avoid_Underflow*/
+#endif
 		bb2 += j;
 		bd2 += j;
-#ifdef Avoid_Underflow
-		bd2 += scale;
-#endif
 		i = bb2 < bd2 ? bb2 : bd2;
 		if (i > bs2)
 			i = bs2;
@@ -2100,123 +1598,12 @@ PR_strtod
 		dsign = delta->sign;
 		delta->sign = 0;
 		i = cmp(delta, bs);
-#ifdef Honor_FLT_ROUNDS
-		if (rounding != 1) {
-			if (i < 0) {
-				/* Error is less than an ulp */
-				if (!delta->x[0] && delta->wds <= 1) {
-					/* exact */
-#ifdef SET_INEXACT
-					inexact = 0;
-#endif
-					break;
-					}
-				if (rounding) {
-					if (dsign) {
-						adj = 1.;
-						goto apply_adj;
-						}
-					}
-				else if (!dsign) {
-					adj = -1.;
-					if (!word1(rv)
-					 && !(word0(rv) & Frac_mask)) {
-						y = word0(rv) & Exp_mask;
-#ifdef Avoid_Underflow
-						if (!scale || y > 2*P*Exp_msk1)
-#else
-						if (y)
-#endif
-						  {
-						  delta = lshift(delta,Log2P);
-						  if (cmp(delta, bs) <= 0)
-							adj = -0.5;
-						  }
-						}
- apply_adj:
-#ifdef Avoid_Underflow
-					if (scale && (y = word0(rv) & Exp_mask)
-						<= 2*P*Exp_msk1)
-					  word0(adj) += (2*P+1)*Exp_msk1 - y;
-#else
-#ifdef Sudden_Underflow
-					if ((word0(rv) & Exp_mask) <=
-							P*Exp_msk1) {
-						word0(rv) += P*Exp_msk1;
-						dval(rv) += adj*ulp(dval(rv));
-						word0(rv) -= P*Exp_msk1;
-						}
-					else
-#endif /*Sudden_Underflow*/
-#endif /*Avoid_Underflow*/
-					dval(rv) += adj*ulp(dval(rv));
-					}
-				break;
-				}
-			adj = ratio(delta, bs);
-			if (adj < 1.)
-				adj = 1.;
-			if (adj <= 0x7ffffffe) {
-				/* adj = rounding ? ceil(adj) : floor(adj); */
-				y = adj;
-				if (y != adj) {
-					if (!((rounding>>1) ^ dsign))
-						y++;
-					adj = y;
-					}
-				}
-#ifdef Avoid_Underflow
-			if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
-				word0(adj) += (2*P+1)*Exp_msk1 - y;
-#else
-#ifdef Sudden_Underflow
-			if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
-				word0(rv) += P*Exp_msk1;
-				adj *= ulp(dval(rv));
-				if (dsign)
-					dval(rv) += adj;
-				else
-					dval(rv) -= adj;
-				word0(rv) -= P*Exp_msk1;
-				goto cont;
-				}
-#endif /*Sudden_Underflow*/
-#endif /*Avoid_Underflow*/
-			adj *= ulp(dval(rv));
-			if (dsign)
-				dval(rv) += adj;
-			else
-				dval(rv) -= adj;
-			goto cont;
-			}
-#endif /*Honor_FLT_ROUNDS*/
-
 		if (i < 0) {
 			/* Error is less than half an ulp -- check for
 			 * special case of mantissa a power of two.
 			 */
-			if (dsign || word1(rv) || word0(rv) & Bndry_mask
-#ifdef IEEE_Arith
-#ifdef Avoid_Underflow
-			 || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
-#else
-			 || (word0(rv) & Exp_mask) <= Exp_msk1
-#endif
-#endif
-				) {
-#ifdef SET_INEXACT
-				if (!delta->x[0] && delta->wds <= 1)
-					inexact = 0;
-#endif
+			if (dsign || word1(rv) || word0(rv) & Bndry_mask)
 				break;
-				}
-			if (!delta->x[0] && delta->wds <= 1) {
-				/* exact result */
-#ifdef SET_INEXACT
-				inexact = 0;
-#endif
-				break;
-				}
 			delta = lshift(delta,Log2P);
 			if (cmp(delta, bs) > 0)
 				goto drop_down;
@@ -2226,12 +1613,7 @@ PR_strtod
 			/* exactly half-way between */
 			if (dsign) {
 				if ((word0(rv) & Bndry_mask1) == Bndry_mask1
-				 &&  word1(rv) == (
-#ifdef Avoid_Underflow
-			(scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
-		? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
-#endif
-						   0xffffffff)) {
+				 &&  word1(rv) == 0xffffffff) {
 					/*boundary case -- increment exponent*/
 					word0(rv) = (word0(rv) & Exp_mask)
 						+ Exp_msk1
@@ -2240,44 +1622,24 @@ PR_strtod
 #endif
 						;
 					word1(rv) = 0;
-#ifdef Avoid_Underflow
-					dsign = 0;
-#endif
 					break;
 					}
 				}
 			else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
  drop_down:
 				/* boundary case -- decrement exponent */
-#ifdef Sudden_Underflow /*{{*/
+#ifdef Sudden_Underflow
 				L = word0(rv) & Exp_mask;
 #ifdef IBM
 				if (L <  Exp_msk1)
 #else
-#ifdef Avoid_Underflow
-				if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
-#else
 				if (L <= Exp_msk1)
-#endif /*Avoid_Underflow*/
-#endif /*IBM*/
+#endif
 					goto undfl;
 				L -= Exp_msk1;
-#else /*Sudden_Underflow}{*/
-#ifdef Avoid_Underflow
-				if (scale) {
-					L = word0(rv) & Exp_mask;
-					if (L <= (2*P+1)*Exp_msk1) {
-						if (L > (P+2)*Exp_msk1)
-							/* round even ==> */
-							/* accept rv */
-							break;
-						/* rv = smallest denormal */
-						goto undfl;
-						}
-					}
-#endif /*Avoid_Underflow*/
+#else
 				L = (word0(rv) & Exp_mask) - Exp_msk1;
-#endif /*Sudden_Underflow}}*/
+#endif
 				word0(rv) = L | Bndry_mask1;
 				word1(rv) = 0xffffffff;
 #ifdef IBM
@@ -2291,19 +1653,16 @@ PR_strtod
 				break;
 #endif
 			if (dsign)
-				dval(rv) += ulp(dval(rv));
+				value(rv) += ulp(value(rv));
 #ifndef ROUND_BIASED
 			else {
-				dval(rv) -= ulp(dval(rv));
+				value(rv) -= ulp(value(rv));
 #ifndef Sudden_Underflow
-				if (!dval(rv))
+				if (!value(rv))
 					goto undfl;
 #endif
 				}
-#ifdef Avoid_Underflow
-			dsign = 1 - dsign;
 #endif
-#endif
 			break;
 			}
 		if ((aadj = ratio(delta, bs)) <= 2.) {
@@ -2332,7 +1691,7 @@ PR_strtod
 			aadj *= 0.5;
 			aadj1 = dsign ? aadj : -aadj;
 #ifdef Check_FLT_ROUNDS
-			switch(Rounding) {
+			switch(FLT_ROUNDS) {
 				case 2: /* towards +infinity */
 					aadj1 -= 0.5;
 					break;
@@ -2341,19 +1700,19 @@ PR_strtod
 					aadj1 += 0.5;
 				}
 #else
-			if (Flt_Rounds == 0)
+			if (FLT_ROUNDS == 0)
 				aadj1 += 0.5;
-#endif /*Check_FLT_ROUNDS*/
+#endif
 			}
 		y = word0(rv) & Exp_mask;
 
 		/* Check for overflow */
 
 		if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
-			dval(rv0) = dval(rv);
+			value(rv0) = value(rv);
 			word0(rv) -= P*Exp_msk1;
-			adj = aadj1 * ulp(dval(rv));
-			dval(rv) += adj;
+			adj = aadj1 * ulp(value(rv));
+			value(rv) += adj;
 			if ((word0(rv) & Exp_mask) >=
 					Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
 				if (word0(rv0) == Big0 && word1(rv0) == Big1)
@@ -2366,25 +1725,12 @@ PR_strtod
 				word0(rv) += P*Exp_msk1;
 			}
 		else {
-#ifdef Avoid_Underflow
-			if (scale && y <= 2*P*Exp_msk1) {
-				if (aadj <= 0x7fffffff) {
-					if ((z = aadj) <= 0)
-						z = 1;
-					aadj = z;
-					aadj1 = dsign ? aadj : -aadj;
-					}
-				word0(aadj1) += (2*P+1)*Exp_msk1 - y;
-				}
-			adj = aadj1 * ulp(dval(rv));
-			dval(rv) += adj;
-#else
 #ifdef Sudden_Underflow
 			if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
-				dval(rv0) = dval(rv);
+				value(rv0) = value(rv);
 				word0(rv) += P*Exp_msk1;
-				adj = aadj1 * ulp(dval(rv));
-				dval(rv) += adj;
+				adj = aadj1 * ulp(value(rv));
+				value(rv) += adj;
 #ifdef IBM
 				if ((word0(rv) & Exp_mask) <  P*Exp_msk1)
 #else
@@ -2402,10 +1748,10 @@ PR_strtod
 					word0(rv) -= P*Exp_msk1;
 				}
 			else {
-				adj = aadj1 * ulp(dval(rv));
-				dval(rv) += adj;
+				adj = aadj1 * ulp(value(rv));
+				value(rv) += adj;
 				}
-#else /*Sudden_Underflow*/
+#else
 			/* Compute adj so that the IEEE rounding rules will
 			 * correctly round rv + adj in some half-way cases.
 			 * If rv * ulp(rv) is denormalized (i.e.,
@@ -2413,24 +1759,19 @@ PR_strtod
 			 * trouble from bits lost to denormalization;
 			 * example: 1.2e-307 .
 			 */
-			if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+			if (y <= (P-1)*Exp_msk1 && aadj >= 1.) {
 				aadj1 = (double)(int)(aadj + 0.5);
 				if (!dsign)
 					aadj1 = -aadj1;
 				}
-			adj = aadj1 * ulp(dval(rv));
-			dval(rv) += adj;
-#endif /*Sudden_Underflow*/
-#endif /*Avoid_Underflow*/
+			adj = aadj1 * ulp(value(rv));
+			value(rv) += adj;
+#endif
 			}
 		z = word0(rv) & Exp_mask;
-#ifndef SET_INEXACT
-#ifdef Avoid_Underflow
-		if (!scale)
-#endif
 		if (y == z) {
 			/* Can we stop now? */
-			L = (Long)aadj;
+			L = aadj;
 			aadj -= L;
 			/* The tolerances below are conservative. */
 			if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
@@ -2440,43 +1781,12 @@ PR_strtod
 			else if (aadj < .4999999/FLT_RADIX)
 				break;
 			}
-#endif
  cont:
 		Bfree(bb);
 		Bfree(bd);
 		Bfree(bs);
 		Bfree(delta);
 		}
-#ifdef SET_INEXACT
-	if (inexact) {
-		if (!oldinexact) {
-			word0(rv0) = Exp_1 + (70 << Exp_shift);
-			word1(rv0) = 0;
-			dval(rv0) += 1.;
-			}
-		}
-	else if (!oldinexact)
-		clear_inexact();
-#endif
-#ifdef Avoid_Underflow
-	if (scale) {
-		word0(rv0) = Exp_1 - 2*P*Exp_msk1;
-		word1(rv0) = 0;
-		dval(rv) *= dval(rv0);
-#ifndef NO_ERRNO
-		/* try to avoid the bug of testing an 8087 register value */
-		if (word0(rv) == 0 && word1(rv) == 0)
-			PR_SetError(PR_RANGE_ERROR, 0);
-#endif
-		}
-#endif /* Avoid_Underflow */
-#ifdef SET_INEXACT
-	if (inexact && !(word0(rv) & Exp_mask)) {
-		/* set underflow bit */
-		dval(rv0) = 1e-300;
-		dval(rv0) *= dval(rv0);
-		}
-#endif
  retfree:
 	Bfree(bb);
 	Bfree(bd);
@@ -2486,7 +1796,7 @@ PR_strtod
  ret:
 	if (se)
 		*se = (char *)s;
-	return sign ? -dval(rv) : dval(rv);
+	return sign ? -value(rv) : value(rv);
 	}
 
  static int
@@ -2498,15 +1808,13 @@ quorem
 #endif
 {
 	int n;
-	ULong *bx, *bxe, q, *sx, *sxe;
-#ifdef ULLong
-	ULLong borrow, carry, y, ys;
-#else
-	ULong borrow, carry, y, ys;
+	Long borrow, y;
+	ULong carry, q, ys;
+	ULong *bx, *bxe, *sx, *sxe;
 #ifdef Pack_32
-	ULong si, z, zs;
+	Long z;
+	ULong si, zs;
 #endif
-#endif
 
 	n = S->wds;
 #ifdef DEBUG
@@ -2528,31 +1836,26 @@ quorem
 		borrow = 0;
 		carry = 0;
 		do {
-#ifdef ULLong
-			ys = *sx++ * (ULLong)q + carry;
-			carry = ys >> 32;
-			y = *bx - (ys & FFFFFFFF) - borrow;
-			borrow = y >> 32 & (ULong)1;
-			*bx++ = y & FFFFFFFF;
-#else
 #ifdef Pack_32
 			si = *sx++;
 			ys = (si & 0xffff) * q + carry;
 			zs = (si >> 16) * q + (ys >> 16);
 			carry = zs >> 16;
-			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
-			borrow = (y & 0x10000) >> 16;
-			z = (*bx >> 16) - (zs & 0xffff) - borrow;
-			borrow = (z & 0x10000) >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+			borrow = y >> 16;
+			Sign_Extend(borrow, y);
+			z = (*bx >> 16) - (zs & 0xffff) + borrow;
+			borrow = z >> 16;
+			Sign_Extend(borrow, z);
 			Storeinc(bx, z, y);
 #else
 			ys = *sx++ * q + carry;
 			carry = ys >> 16;
-			y = *bx - (ys & 0xffff) - borrow;
-			borrow = (y & 0x10000) >> 16;
+			y = *bx - (ys & 0xffff) + borrow;
+			borrow = y >> 16;
+			Sign_Extend(borrow, y);
 			*bx++ = y & 0xffff;
 #endif
-#endif
 			}
 			while(sx <= sxe);
 		if (!*bxe) {
@@ -2569,31 +1872,26 @@ quorem
 		bx = b->x;
 		sx = S->x;
 		do {
-#ifdef ULLong
-			ys = *sx++ + carry;
-			carry = ys >> 32;
-			y = *bx - (ys & FFFFFFFF) - borrow;
-			borrow = y >> 32 & (ULong)1;
-			*bx++ = y & FFFFFFFF;
-#else
 #ifdef Pack_32
 			si = *sx++;
 			ys = (si & 0xffff) + carry;
 			zs = (si >> 16) + (ys >> 16);
 			carry = zs >> 16;
-			y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
-			borrow = (y & 0x10000) >> 16;
-			z = (*bx >> 16) - (zs & 0xffff) - borrow;
-			borrow = (z & 0x10000) >> 16;
+			y = (*bx & 0xffff) - (ys & 0xffff) + borrow;
+			borrow = y >> 16;
+			Sign_Extend(borrow, y);
+			z = (*bx >> 16) - (zs & 0xffff) + borrow;
+			borrow = z >> 16;
+			Sign_Extend(borrow, z);
 			Storeinc(bx, z, y);
 #else
 			ys = *sx++ + carry;
 			carry = ys >> 16;
-			y = *bx - (ys & 0xffff) - borrow;
-			borrow = (y & 0x10000) >> 16;
+			y = *bx - (ys & 0xffff) + borrow;
+			borrow = y >> 16;
+			Sign_Extend(borrow, y);
 			*bx++ = y & 0xffff;
 #endif
-#endif
 			}
 			while(sx <= sxe);
 		bx = b->x;
@@ -2607,49 +1905,6 @@ quorem
 	return q;
 	}
 
-#ifndef MULTIPLE_THREADS
- static char *dtoa_result;
-#endif
-
- static char *
-#ifdef KR_headers
-rv_alloc(i) int i;
-#else
-rv_alloc(int i)
-#endif
-{
-	int j, k, *r;
-
-	j = sizeof(ULong);
-	for(k = 0;
-		sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= i;
-		j <<= 1)
-			k++;
-	r = (int*)Balloc(k);
-	*r = k;
-	return
-#ifndef MULTIPLE_THREADS
-	dtoa_result =
-#endif
-		(char *)(r+1);
-	}
-
- static char *
-#ifdef KR_headers
-nrv_alloc(s, rve, n) char *s, **rve; int n;
-#else
-nrv_alloc(char *s, char **rve, int n)
-#endif
-{
-	char *rv, *t;
-
-	t = rv = rv_alloc(n);
-	while(*t = *s++) t++;
-	if (rve)
-		*rve = t;
-	return rv;
-	}
-
 /* freedtoa(s) must be used to free values s returned by dtoa
  * when MULTIPLE_THREADS is #defined.  It should be used in all cases,
  * but for consistency with earlier versions of dtoa, it is optional
@@ -2663,19 +1918,19 @@ freedtoa(s) char *s;
 freedtoa(char *s)
 #endif
 {
-	Bigint *b = (Bigint *)((int *)s - 1);
-	b->maxwds = 1 << (b->k = *(int*)b);
-	Bfree(b);
+        Bigint *b = (Bigint *)((int *)s - 1);
+        b->maxwds = 1 << (b->k = *(int*)b);
+        Bfree(b);
 #ifndef MULTIPLE_THREADS
-	if (s == dtoa_result)
-		dtoa_result = 0;
+        if (s == dtoa_result)
+                dtoa_result = 0;
 #endif
-	}
+        }
 
 /* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
  *
  * Inspired by "How to Print Floating-Point Numbers Accurately" by
- * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 112-126].
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
  *
  * Modifications:
  *	1. Rather than iterating, we use a simple numeric overestimate
@@ -2706,13 +1961,13 @@ freedtoa(char *s)
  *	   calculation.
  */
 
- static char *
+ char *
 dtoa
 #ifdef KR_headers
-	(d, mode, ndigits, decpt, sign, rve)
-	double d; int mode, ndigits, *decpt, *sign; char **rve;
+	(_d, mode, ndigits, decpt, sign, rve)
+	double _d; int mode, ndigits, *decpt, *sign; char **rve;
 #else
-	(double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
+	(double _d, int mode, int ndigits, int *decpt, int *sign, char **rve)
 #endif
 {
  /*	Arguments ndigits, decpt, sign are similar to those
@@ -2734,14 +1989,14 @@ dtoa
 			gives a return value similar to that from fcvt,
 			except that trailing zeros are suppressed, and
 			ndigits can be negative.
-		4,5 ==> similar to 2 and 3, respectively, but (in
-			round-nearest mode) with the tests of mode 0 to
-			possibly return a shorter string that rounds to d.
-			With IEEE arithmetic and compilation with
-			-DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
-			as modes 2 and 3 when FLT_ROUNDS != 1.
-		6-9 ==> Debugging modes similar to mode - 4:  don't try
-			fast floating-point estimate (if applicable).
+		4-9 should give the same return values as 2-3, i.e.,
+			4 <= mode <= 9 ==> same return as mode
+			2 + (mode & 1).  These modes are mainly for
+			debugging; often they run slower but sometimes
+			faster than modes 2-3.
+		4,5,8,9 ==> left-to-right digit generation.
+		6-9 ==> don't try fast floating-point estimate
+			(if applicable).
 
 		Values of mode other than 0-9 are treated as mode 0.
 
@@ -2758,21 +2013,19 @@ dtoa
 	ULong x;
 #endif
 	Bigint *b, *b1, *delta, *mlo, *mhi, *S;
-	double d2, ds, eps;
+	double ds;
 	char *s, *s0;
-#ifdef Honor_FLT_ROUNDS
-	int rounding;
-#endif
-#ifdef SET_INEXACT
-	int inexact, oldinexact;
-#endif
+	static Bigint *result;
+	static int result_k;
+	_double d, d2, eps;
 
-#ifndef MULTIPLE_THREADS
-	if (dtoa_result) {
-		freedtoa(dtoa_result);
-		dtoa_result = 0;
+	value(d) = _d;
+	if (result) {
+		result->k = result_k;
+		result->maxwds = 1 << result_k;
+		Bfree(result);
+		result = 0;
 		}
-#endif
 
 	if (word0(d) & Sign_bit) {
 		/* set sign for everything, including 0's and NaNs */
@@ -2791,47 +2044,43 @@ dtoa
 		{
 		/* Infinity or NaN */
 		*decpt = 9999;
+		s =
 #ifdef IEEE_Arith
-		if (!word1(d) && !(word0(d) & 0xfffff))
-			return nrv_alloc("Infinity", rve, 8);
+			!word1(d) && !(word0(d) & 0xfffff) ? ndigits < 8 ? "Inf" : "Infinity" :
 #endif
-		return nrv_alloc("NaN", rve, 3);
+				"NaN";
+		if (rve)
+			*rve =
+#ifdef IEEE_Arith
+				s[3] ? s + 8 :
+#endif
+						s + 3;
+		return s;
 		}
 #endif
 #ifdef IBM
-	dval(d) += 0; /* normalize */
+	value(d) += 0; /* normalize */
 #endif
-	if (!dval(d)) {
+	if (!value(d)) {
 		*decpt = 1;
-		return nrv_alloc("0", rve, 1);
+		s = "0";
+		if (rve)
+			*rve = s + 1;
+		return s;
 		}
 
-#ifdef SET_INEXACT
-	try_quick = oldinexact = get_inexact();
-	inexact = 1;
-#endif
-#ifdef Honor_FLT_ROUNDS
-	if ((rounding = Flt_Rounds) >= 2) {
-		if (*sign)
-			rounding = rounding == 2 ? 0 : 2;
-		else
-			if (rounding != 2)
-				rounding = 0;
-		}
-#endif
-
-	b = d2b(dval(d), &be, &bbits);
+	b = d2b(value(d), &be, &bbits);
 #ifdef Sudden_Underflow
 	i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
 #else
 	if (i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1))) {
 #endif
-		dval(d2) = dval(d);
+		value(d2) = value(d);
 		word0(d2) &= Frac_mask1;
 		word0(d2) |= Exp_11;
 #ifdef IBM
 		if (j = 11 - hi0bits(word0(d2) & Frac_mask))
-			dval(d2) /= 1 << j;
+			value(d2) /= 1 << j;
 #endif
 
 		/* log(x)	~=~ log(1.5) + (x-1.5)/1.5
@@ -2870,19 +2119,20 @@ dtoa
 		i = bbits + be + (Bias + (P-1) - 1);
 		x = i > 32  ? word0(d) << 64 - i | word1(d) >> i - 32
 			    : word1(d) << 32 - i;
-		dval(d2) = x;
+		value(d2) = x;
 		word0(d2) -= 31*Exp_msk1; /* adjust exponent */
 		i -= (Bias + (P-1) - 1) + 1;
 		denorm = 1;
 		}
 #endif
-	ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+	ds = (value(d2)-1.5)*0.289529654602168 + 0.1760912590558 +
+	    i*0.301029995663981;
 	k = (int)ds;
 	if (ds < 0. && ds != k)
 		k--;	/* want k = floor(ds) */
 	k_check = 1;
 	if (k >= 0 && k <= Ten_pmax) {
-		if (dval(d) < tens[k])
+		if (value(d) < tens[k])
 			k--;
 		k_check = 0;
 		}
@@ -2907,15 +2157,7 @@ dtoa
 		}
 	if (mode < 0 || mode > 9)
 		mode = 0;
-
-#ifndef SET_INEXACT
-#ifdef Check_FLT_ROUNDS
-	try_quick = Rounding == 1;
-#else
 	try_quick = 1;
-#endif
-#endif /*SET_INEXACT*/
-
 	if (mode > 5) {
 		mode -= 4;
 		try_quick = 0;
@@ -2946,19 +2188,18 @@ dtoa
 			if (i <= 0)
 				i = 1;
 		}
-	s = s0 = rv_alloc(i);
+	j = sizeof(ULong);
+	for(result_k = 0; sizeof(Bigint) - sizeof(ULong) + j <= i;
+		j <<= 1) result_k++;
+	result = Balloc(result_k);
+	s = s0 = (char *)result;
 
-#ifdef Honor_FLT_ROUNDS
-	if (mode > 1 && rounding != 1)
-		leftright = 0;
-#endif
-
 	if (ilim >= 0 && ilim <= Quick_max && try_quick) {
 
 		/* Try to get by with floating-point arithmetic. */
 
 		i = 0;
-		dval(d2) = dval(d);
+		value(d2) = value(d);
 		k0 = k;
 		ilim0 = ilim;
 		ieps = 2; /* conservative */
@@ -2968,7 +2209,7 @@ dtoa
 			if (j & Bletch) {
 				/* prevent overflows */
 				j &= Bletch - 1;
-				dval(d) /= bigtens[n_bigtens-1];
+				value(d) /= bigtens[n_bigtens-1];
 				ieps++;
 				}
 			for(; j; j >>= 1, i++)
@@ -2976,32 +2217,32 @@ dtoa
 					ieps++;
 					ds *= bigtens[i];
 					}
-			dval(d) /= ds;
+			value(d) /= ds;
 			}
 		else if (j1 = -k) {
-			dval(d) *= tens[j1 & 0xf];
+			value(d) *= tens[j1 & 0xf];
 			for(j = j1 >> 4; j; j >>= 1, i++)
 				if (j & 1) {
 					ieps++;
-					dval(d) *= bigtens[i];
+					value(d) *= bigtens[i];
 					}
 			}
-		if (k_check && dval(d) < 1. && ilim > 0) {
+		if (k_check && value(d) < 1. && ilim > 0) {
 			if (ilim1 <= 0)
 				goto fast_failed;
 			ilim = ilim1;
 			k--;
-			dval(d) *= 10.;
+			value(d) *= 10.;
 			ieps++;
 			}
-		dval(eps) = ieps*dval(d) + 7.;
+		value(eps) = ieps*value(d) + 7.;
 		word0(eps) -= (P-1)*Exp_msk1;
 		if (ilim == 0) {
 			S = mhi = 0;
-			dval(d) -= 5.;
-			if (dval(d) > dval(eps))
+			value(d) -= 5.;
+			if (value(d) > value(eps))
 				goto one_digit;
-			if (dval(d) < -dval(eps))
+			if (value(d) < -value(eps))
 				goto no_digits;
 			goto fast_failed;
 			}
@@ -3010,34 +2251,33 @@ dtoa
 			/* Use Steele & White method of only
 			 * generating digits needed.
 			 */
-			dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+			value(eps) = 0.5/tens[ilim-1] - value(eps);
 			for(i = 0;;) {
-				L = dval(d);
-				dval(d) -= L;
+				L = value(d);
+				value(d) -= L;
 				*s++ = '0' + (int)L;
-				if (dval(d) < dval(eps))
+				if (value(d) < value(eps))
 					goto ret1;
-				if (1. - dval(d) < dval(eps))
+				if (1. - value(d) < value(eps))
 					goto bump_up;
 				if (++i >= ilim)
 					break;
-				dval(eps) *= 10.;
-				dval(d) *= 10.;
+				value(eps) *= 10.;
+				value(d) *= 10.;
 				}
 			}
 		else {
 #endif
 			/* Generate ilim digits, then fix them up. */
-			dval(eps) *= tens[ilim-1];
-			for(i = 1;; i++, dval(d) *= 10.) {
-				L = (Long)(dval(d));
-				if (!(dval(d) -= L))
-					ilim = i;
+			value(eps) *= tens[ilim-1];
+			for(i = 1;; i++, value(d) *= 10.) {
+				L = value(d);
+				value(d) -= L;
 				*s++ = '0' + (int)L;
 				if (i == ilim) {
-					if (dval(d) > 0.5 + dval(eps))
+					if (value(d) > 0.5 + value(eps))
 						goto bump_up;
-					else if (dval(d) < 0.5 - dval(eps)) {
+					else if (value(d) < 0.5 - value(eps)) {
 						while(*--s == '0');
 						s++;
 						goto ret1;
@@ -3050,7 +2290,7 @@ dtoa
 #endif
  fast_failed:
 		s = s0;
-		dval(d) = dval(d2);
+		value(d) = value(d2);
 		k = k0;
 		ilim = ilim0;
 		}
@@ -3062,37 +2302,24 @@ dtoa
 		ds = tens[k];
 		if (ndigits < 0 && ilim <= 0) {
 			S = mhi = 0;
-			if (ilim < 0 || dval(d) <= 5*ds)
+			if (ilim < 0 || value(d) <= 5*ds)
 				goto no_digits;
 			goto one_digit;
 			}
-		for(i = 1;; i++, dval(d) *= 10.) {
-			L = (Long)(dval(d) / ds);
-			dval(d) -= L*ds;
+		for(i = 1;; i++) {
+			L = value(d) / ds;
+			value(d) -= L*ds;
 #ifdef Check_FLT_ROUNDS
 			/* If FLT_ROUNDS == 2, L will usually be high by 1 */
-			if (dval(d) < 0) {
+			if (value(d) < 0) {
 				L--;
-				dval(d) += ds;
+				value(d) += ds;
 				}
 #endif
 			*s++ = '0' + (int)L;
-			if (!dval(d)) {
-#ifdef SET_INEXACT
-				inexact = 0;
-#endif
-				break;
-				}
 			if (i == ilim) {
-#ifdef Honor_FLT_ROUNDS
-				if (mode > 1)
-				switch(rounding) {
-				  case 0: goto ret1;
-				  case 2: goto bump_up;
-				  }
-#endif
-				dval(d) += dval(d);
-				if (dval(d) > ds || dval(d) == ds && L & 1) {
+				value(d) += value(d);
+				if (value(d) > ds || value(d) == ds && L & 1) {
  bump_up:
 					while(*--s == '9')
 						if (s == s0) {
@@ -3104,6 +2331,8 @@ dtoa
 					}
 				break;
 				}
+			if (!(value(d) *= 10.))
+				break;
 			}
 		goto ret1;
 		}
@@ -3112,15 +2341,31 @@ dtoa
 	m5 = b5;
 	mhi = mlo = 0;
 	if (leftright) {
-		i =
+		if (mode < 2) {
+			i =
 #ifndef Sudden_Underflow
-			denorm ? be + (Bias + (P-1) - 1 + 1) :
+				denorm ? be + (Bias + (P-1) - 1 + 1) :
 #endif
 #ifdef IBM
-			1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+				1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
 #else
-			1 + P - bbits;
+				1 + P - bbits;
 #endif
+			}
+		else {
+			j = ilim - 1;
+			if (m5 >= j)
+				m5 -= j;
+			else {
+				s5 += j -= m5;
+				b5 += j;
+				m5 = 0;
+				}
+			if ((i = ilim) < 0) {
+				m2 -= i;
+				i = 0;
+				}
+			}
 		b2 += i;
 		s2 += i;
 		mhi = i2b(1);
@@ -3151,15 +2396,10 @@ dtoa
 
 	/* Check for special case that d is a normalized power of 2. */
 
-	spec_case = 0;
-	if ((mode < 2 || leftright)
-#ifdef Honor_FLT_ROUNDS
-			&& rounding == 1
-#endif
-				) {
+	if (mode < 2) {
 		if (!word1(d) && !(word0(d) & Bndry_mask)
 #ifndef Sudden_Underflow
-		 && word0(d) & (Exp_mask & ~Exp_msk1)
+		 && word0(d) & Exp_mask
 #endif
 				) {
 			/* The special case */
@@ -3167,6 +2407,8 @@ dtoa
 			s2 += Log2P;
 			spec_case = 1;
 			}
+		else
+			spec_case = 0;
 		}
 
 	/* Arrange for convenient computation of quotients:
@@ -3208,7 +2450,7 @@ dtoa
 			ilim = ilim1;
 			}
 		}
-	if (ilim <= 0 && (mode == 3 || mode == 5)) {
+	if (ilim <= 0 && mode > 2) {
 		if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
 			/* no digits, fcvt style */
  no_digits:
@@ -3245,41 +2487,20 @@ dtoa
 			j1 = delta->sign ? 1 : cmp(b, delta);
 			Bfree(delta);
 #ifndef ROUND_BIASED
-			if (j1 == 0 && mode != 1 && !(word1(d) & 1)
-#ifdef Honor_FLT_ROUNDS
-				&& rounding >= 1
-#endif
-								   ) {
+			if (j1 == 0 && !mode && !(word1(d) & 1)) {
 				if (dig == '9')
 					goto round_9_up;
 				if (j > 0)
 					dig++;
-#ifdef SET_INEXACT
-				else if (!b->x[0] && b->wds <= 1)
-					inexact = 0;
-#endif
 				*s++ = dig;
 				goto ret;
 				}
 #endif
-			if (j < 0 || j == 0 && mode != 1
+			if (j < 0 || j == 0 && !mode
 #ifndef ROUND_BIASED
 							&& !(word1(d) & 1)
 #endif
 					) {
-				if (!b->x[0] && b->wds <= 1) {
-#ifdef SET_INEXACT
-					inexact = 0;
-#endif
-					goto accept_dig;
-					}
-#ifdef Honor_FLT_ROUNDS
-				if (mode > 1)
-				 switch(rounding) {
-				  case 0: goto accept_dig;
-				  case 2: goto keep_dig;
-				  }
-#endif /*Honor_FLT_ROUNDS*/
 				if (j1 > 0) {
 					b = lshift(b, 1);
 					j1 = cmp(b, S);
@@ -3287,15 +2508,10 @@ dtoa
 					&& dig++ == '9')
 						goto round_9_up;
 					}
- accept_dig:
 				*s++ = dig;
 				goto ret;
 				}
 			if (j1 > 0) {
-#ifdef Honor_FLT_ROUNDS
-				if (!rounding)
-					goto accept_dig;
-#endif
 				if (dig == '9') { /* possible if i == 1 */
  round_9_up:
 					*s++ = '9';
@@ -3304,9 +2520,6 @@ dtoa
 				*s++ = dig + 1;
 				goto ret;
 				}
-#ifdef Honor_FLT_ROUNDS
- keep_dig:
-#endif
 			*s++ = dig;
 			if (i == ilim)
 				break;
@@ -3322,12 +2535,6 @@ dtoa
 	else
 		for(i = 1;; i++) {
 			*s++ = dig = quorem(b,S) + '0';
-			if (!b->x[0] && b->wds <= 1) {
-#ifdef SET_INEXACT
-				inexact = 0;
-#endif
-				goto ret;
-				}
 			if (i >= ilim)
 				break;
 			b = multadd(b, 10, 0);
@@ -3335,12 +2542,6 @@ dtoa
 
 	/* Round off last digit */
 
-#ifdef Honor_FLT_ROUNDS
-	switch(rounding) {
-	  case 0: goto trimzeros;
-	  case 2: goto roundoff;
-	  }
-#endif
 	b = lshift(b, 1);
 	j = cmp(b, S);
 	if (j > 0 || j == 0 && dig & 1) {
@@ -3354,7 +2555,6 @@ dtoa
 		++*s++;
 		}
 	else {
- trimzeros:
 		while(*--s == '0');
 		s++;
 		}
@@ -3366,18 +2566,11 @@ dtoa
 		Bfree(mhi);
 		}
  ret1:
-#ifdef SET_INEXACT
-	if (inexact) {
-		if (!oldinexact) {
-			word0(d) = Exp_1 + (70 << Exp_shift);
-			word1(d) = 0;
-			dval(d) += 1.;
-			}
-		}
-	else if (!oldinexact)
-		clear_inexact();
-#endif
 	Bfree(b);
+	if (s == s0) {				/* don't return empty string */
+		*s++ = '0';
+		k = 0;
+	}
 	*s = 0;
 	*decpt = k + 1;
 	if (rve)
