michael@0: /* michael@0: * Copyright (c) 1999 michael@0: * Silicon Graphics Computer Systems, Inc. michael@0: * michael@0: * Copyright (c) 1999 michael@0: * Boris Fomitchev michael@0: * michael@0: * This material is provided "as is", with absolutely no warranty expressed michael@0: * or implied. Any use is at your own risk. michael@0: * michael@0: * Permission to use or copy this software for any purpose is hereby granted michael@0: * without fee, provided the above notices are retained on all copies. michael@0: * Permission to modify the code and to distribute modified code is granted, michael@0: * provided the above notices are retained, and a notice that the code was michael@0: * modified is included with the above copyright notice. michael@0: * michael@0: */ michael@0: michael@0: #include "stlport_prefix.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #if defined (__DECCXX) michael@0: # define NDIG 400 michael@0: #else michael@0: # define NDIG 82 michael@0: #endif michael@0: michael@0: #define todigit(x) ((x)+'0') michael@0: michael@0: #if defined (_STLP_UNIX) michael@0: michael@0: # if defined (__sun) michael@0: # include michael@0: # endif michael@0: michael@0: # if defined (__sun) || defined (__digital__) || defined (__sgi) || defined (_STLP_SCO_OPENSERVER) || defined (__NCR_SVR) michael@0: // DEC, SGI & Solaris need this michael@0: # include michael@0: # include michael@0: # endif michael@0: michael@0: # if defined (__QNXNTO__) || ( defined(__GNUC__) && defined(__APPLE__) ) || defined(_STLP_USE_UCLIBC) /* 0.9.26 */ || \ michael@0: defined(__FreeBSD__) michael@0: # define USE_SPRINTF_INSTEAD michael@0: # endif michael@0: michael@0: # if defined (_AIX) // JFA 3-Aug-2000 michael@0: # include michael@0: # include michael@0: # endif michael@0: michael@0: # include michael@0: #endif michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #if defined (_STLP_MSVC_LIB) || defined (__MINGW32__) || defined (__BORLANDC__) || defined (__DJGPP) || \ michael@0: defined (_STLP_SCO_OPENSERVER) || defined (__NCR_SVR) michael@0: # include michael@0: #endif michael@0: michael@0: #if defined (__MRC__) || defined (__SC__) || defined (_CRAY) //*TY 02/24/2000 - added support for MPW michael@0: # include michael@0: #endif michael@0: michael@0: #if defined (__CYGWIN__) michael@0: # include michael@0: #endif michael@0: michael@0: #if defined (__MSL__) michael@0: # include // for atoi michael@0: # include // for snprintf michael@0: # include michael@0: # include michael@0: #endif michael@0: michael@0: #if defined (__ISCPP__) michael@0: # include michael@0: #endif michael@0: michael@0: #include michael@0: michael@0: #if defined (__DMC__) michael@0: # define snprintf _snprintf michael@0: #endif michael@0: michael@0: _STLP_BEGIN_NAMESPACE michael@0: michael@0: _STLP_MOVE_TO_PRIV_NAMESPACE michael@0: michael@0: #if defined (__MWERKS__) || defined(__BEOS__) michael@0: # define USE_SPRINTF_INSTEAD michael@0: #endif michael@0: michael@0: template michael@0: struct _Dig michael@0: { michael@0: enum { dig = _Dig::dig + 1 }; michael@0: }; michael@0: michael@0: _STLP_TEMPLATE_NULL michael@0: struct _Dig<0> michael@0: { michael@0: enum { dig = 0 }; michael@0: }; michael@0: michael@0: #ifdef _STLP_NO_LONG_DOUBLE michael@0: # define MAXEDIGITS int(_Dig::dig) michael@0: # define MAXFSIG DBL_DIG michael@0: # define MAXFCVT (DBL_DIG + 1) michael@0: #else michael@0: # define MAXEDIGITS int(_Dig::dig) michael@0: # define MAXFSIG LDBL_DIG michael@0: # define MAXFCVT (LDBL_DIG + 1) michael@0: #endif michael@0: michael@0: // Tests for infinity and NaN differ on different OSs. We encapsulate michael@0: // these differences here. michael@0: #if !defined (USE_SPRINTF_INSTEAD) michael@0: # if defined (__hpux) && defined (__GNUC__) michael@0: # define _STLP_USE_SIGN_HELPER michael@0: # elif defined (__DJGPP) || (defined (_STLP_USE_GLIBC) && ! defined (__MSL__)) || \ michael@0: defined (__CYGWIN__) || \ michael@0: defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \ michael@0: defined (__HP_aCC) michael@0: static inline bool _Stl_is_nan_or_inf(double x) michael@0: # if defined (isfinite) michael@0: { return !isfinite(x); } michael@0: # else michael@0: { return !finite(x); } michael@0: # endif michael@0: static inline bool _Stl_is_neg_nan(double x) { return isnan(x) && ( copysign(1., x) < 0 ); } michael@0: static inline bool _Stl_is_inf(double x) { return isinf(x); } michael@0: // inline bool _Stl_is_neg_inf(double x) { return isinf(x) < 0; } michael@0: static inline bool _Stl_is_neg_inf(double x) { return isinf(x) && x < 0; } michael@0: # elif (defined (__unix) || defined (__unix__)) && \ michael@0: !defined (__APPLE__) && !defined (__DJGPP) && !defined(__osf__) && \ michael@0: !defined (_CRAY) && !defined (__ANDROID__) michael@0: static inline bool _Stl_is_nan_or_inf(double x) { return IsNANorINF(x); } michael@0: static inline bool _Stl_is_inf(double x) { return IsNANorINF(x) && IsINF(x); } michael@0: static inline bool _Stl_is_neg_inf(double x) { return (IsINF(x)) && (x < 0.0); } michael@0: static inline bool _Stl_is_neg_nan(double x) { return IsNegNAN(x); } michael@0: # elif defined (_STLP_MSVC_LIB) || defined (__MINGW32__) || defined (__BORLANDC__) michael@0: static inline bool _Stl_is_nan_or_inf(double x) { return !_finite(x); } michael@0: # if !defined (__BORLANDC__) michael@0: static inline bool _Stl_is_inf(double x) { michael@0: int fclass = _fpclass(x); michael@0: return fclass == _FPCLASS_NINF || fclass == _FPCLASS_PINF; michael@0: } michael@0: static inline bool _Stl_is_neg_inf(double x) { return _fpclass(x) == _FPCLASS_NINF; } michael@0: # else michael@0: static inline bool _Stl_is_inf(double x) { return _Stl_is_nan_or_inf(x) && !_isnan(x);} michael@0: static inline bool _Stl_is_neg_inf(double x) { return _Stl_is_inf(x) && x < 0 ; } michael@0: # endif michael@0: static inline bool _Stl_is_neg_nan(double x) { return _isnan(x) && _copysign(1., x) < 0 ; } michael@0: # if defined (__BORLANDC__) michael@0: static inline bool _Stl_is_nan_or_inf(long double x) { return !_finitel(x); } michael@0: static inline bool _Stl_is_inf(long double x) { return _Stl_is_nan_or_inf(x) && !_isnanl(x);} michael@0: static inline bool _Stl_is_neg_inf(long double x) { return _Stl_is_inf(x) && x < 0 ; } michael@0: static inline bool _Stl_is_neg_nan(long double x) { return _isnanl(x) && _copysignl(1.l, x) < 0 ; } michael@0: # elif !defined (_STLP_NO_LONG_DOUBLE) michael@0: // Simply there to avoid warning long double -> double implicit conversion: michael@0: static inline bool _Stl_is_nan_or_inf(long double x) { return _Stl_is_nan_or_inf(__STATIC_CAST(double, x)); } michael@0: static inline bool _Stl_is_inf(long double x) { return _Stl_is_inf(__STATIC_CAST(double, x));} michael@0: static inline bool _Stl_is_neg_inf(long double x) { return _Stl_is_neg_inf(__STATIC_CAST(double, x)); } michael@0: static inline bool _Stl_is_neg_nan(long double x) { return _Stl_is_neg_nan(__STATIC_CAST(double, x)); } michael@0: # endif michael@0: # elif defined (__MRC__) || defined (__SC__) || defined (__DMC__) michael@0: static bool _Stl_is_nan_or_inf(double x) { return isnan(x) || !isfinite(x); } michael@0: static bool _Stl_is_inf(double x) { return !isfinite(x); } michael@0: static bool _Stl_is_neg_inf(double x) { return !isfinite(x) && signbit(x); } michael@0: static bool _Stl_is_neg_nan(double x) { return isnan(x) && signbit(x); } michael@0: # elif /* defined(__FreeBSD__) || defined(__OpenBSD__) || */ (defined(__GNUC__) && defined(__APPLE__)) michael@0: static inline bool _Stl_is_nan_or_inf(double x) { return !finite(x); } michael@0: static inline bool _Stl_is_inf(double x) { return _Stl_is_nan_or_inf(x) && ! isnan(x); } michael@0: static inline bool _Stl_is_neg_inf(double x) { return _Stl_is_inf(x) && x < 0 ; } michael@0: static inline bool _Stl_is_neg_nan(double x) { return isnan(x) && copysign(1., x) < 0 ; } michael@0: # elif defined( _AIX ) // JFA 11-Aug-2000 michael@0: static bool _Stl_is_nan_or_inf(double x) { return isnan(x) || !finite(x); } michael@0: static bool _Stl_is_inf(double x) { return !finite(x); } michael@0: // bool _Stl_is_neg_inf(double x) { return _class(x) == FP_MINUS_INF; } michael@0: static bool _Stl_is_neg_inf(double x) { return _Stl_is_inf(x) && ( copysign(1., x) < 0 ); } michael@0: static bool _Stl_is_neg_nan(double x) { return isnan(x) && ( copysign(1., x) < 0 ); } michael@0: # elif defined (__ISCPP__) michael@0: static inline bool _Stl_is_nan_or_inf (double x) { return _fp_isINF(x) || _fp_isNAN(x); } michael@0: static inline bool _Stl_is_inf (double x) { return _fp_isINF(x); } michael@0: static inline bool _Stl_is_neg_inf (double x) { return _fp_isINF(x) && x < 0; } michael@0: static inline bool _Stl_is_neg_nan (double x) { return _fp_isNAN(x) && x < 0; } michael@0: # elif defined (_CRAY) michael@0: # if defined (_CRAYIEEE) michael@0: static inline bool _Stl_is_nan_or_inf(double x) { return isnan(x) || isinf(x); } michael@0: static inline bool _Stl_is_inf(double x) { return isinf(x); } michael@0: static inline bool _Stl_is_neg_inf(double x) { return isinf(x) && signbit(x); } michael@0: static inline bool _Stl_is_neg_nan(double x) { return isnan(x) && signbit(x); } michael@0: # else michael@0: static inline bool _Stl_is_nan_or_inf(double x) { return false; } michael@0: static inline bool _Stl_is_inf(double x) { return false; } michael@0: static inline bool _Stl_is_neg_inf(double x) { return false; } michael@0: static inline bool _Stl_is_neg_nan(double x) { return false; } michael@0: # endif michael@0: # else // nothing from above michael@0: # define USE_SPRINTF_INSTEAD michael@0: # endif michael@0: #endif // !USE_SPRINTF_INSTEAD michael@0: michael@0: #if !defined (USE_SPRINTF_INSTEAD) michael@0: // Reentrant versions of floating-point conversion functions. The argument michael@0: // lists look slightly different on different operating systems, so we're michael@0: // encapsulating the differences here. michael@0: michael@0: # if defined (__CYGWIN__) || defined(__DJGPP) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return ecvtbuf(x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return fcvtbuf(x, n, pt, sign, buf); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: # if defined (__CYGWIN__) michael@0: # define _STLP_EMULATE_LONG_DOUBLE_CVT michael@0: # else michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return ecvtbuf(x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return fcvtbuf(x, n, pt, sign, buf); } michael@0: # endif michael@0: # endif michael@0: # elif defined (_STLP_USE_GLIBC) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return ecvt_r(x, n, pt, sign, buf, bsize) == 0 ? buf : 0; } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return fcvt_r(x, n, pt, sign, buf, bsize) == 0 ? buf : 0; } michael@0: # ifndef _STLP_NO_LONG_DOUBLE michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return qecvt_r(x, n, pt, sign, buf, bsize) == 0 ? buf : 0; } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return qfcvt_r(x, n, pt, sign, buf, bsize) == 0 ? buf : 0; } michael@0: # endif michael@0: # define _STLP_NEED_CVT_BUFFER_SIZE michael@0: # elif defined (__sun) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return econvert(x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return fconvert(x, n, pt, sign, buf); } michael@0: # ifndef _STLP_NO_LONG_DOUBLE michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return qeconvert(&x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return qfconvert(&x, n, pt, sign, buf); } michael@0: # endif michael@0: # elif defined (__DECCXX) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return (ecvt_r(x, n, pt, sign, buf, bsize) == 0 ? buf : 0); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return (fcvt_r(x, n, pt, sign, buf, bsize) == 0 ? buf : 0); } michael@0: # ifndef _STLP_NO_LONG_DOUBLE michael@0: // fbp : no "long double" conversions ! michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return (ecvt_r((double)x, n, pt, sign, buf, bsize) == 0 ? buf : 0) ; } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf, size_t bsize) michael@0: { return (fcvt_r((double)x, n, pt, sign, buf, bsize) == 0 ? buf : 0); } michael@0: # endif michael@0: # define _STLP_NEED_CVT_BUFFER_SIZE michael@0: # elif defined (__hpux) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign) michael@0: { return ecvt(x, n, pt, sign); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign) michael@0: { return fcvt(x, n, pt, sign); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign) michael@0: { return _ldecvt(*(long_double*)&x, n, pt, sign); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign) michael@0: { return _ldfcvt(*(long_double*)&x, n, pt, sign); } michael@0: # endif michael@0: # define _STLP_CVT_NEED_SYNCHRONIZATION michael@0: # elif defined (__unix) && !defined (__APPLE__) && !defined (_CRAY) && \ michael@0: !defined (__ANDROID__) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return ecvt_r(x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return fcvt_r(x, n, pt, sign, buf); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return qecvt_r(x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return qfcvt_r(x, n, pt, sign, buf); } michael@0: # endif michael@0: # elif defined (_STLP_MSVC_LIB) || defined (__MINGW32__) || defined (__BORLANDC__) michael@0: # if defined (_STLP_USE_SAFE_STRING_FUNCTIONS) michael@0: # define _STLP_APPEND(a, b) a##b michael@0: # define _STLP_BUF_PARAMS , char* buf, size_t bsize michael@0: # define _STLP_SECURE_FUN(F, X, N, PT, SIGN) _STLP_APPEND(F, _s)(buf, bsize, X, N, PT, SIGN); return buf michael@0: # else michael@0: # define _STLP_BUF_PARAMS michael@0: # define _STLP_SECURE_FUN(F, X, N, PT, SIGN) return F(X, N, PT, SIGN) michael@0: # define _STLP_CVT_NEED_SYNCHRONIZATION michael@0: # endif michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign _STLP_BUF_PARAMS) michael@0: { _STLP_SECURE_FUN(_ecvt, x, n, pt, sign); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign _STLP_BUF_PARAMS) michael@0: { _STLP_SECURE_FUN(_fcvt, x, n, pt, sign); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: # if defined (_STLP_USE_SAFE_STRING_FUNCTIONS) michael@0: # define _STLP_PARAMS , buf, bsize michael@0: # else michael@0: # define _STLP_PARAMS michael@0: # endif michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign _STLP_BUF_PARAMS) michael@0: { return _Stl_ecvtR(__STATIC_CAST(double, x), n, pt, sign _STLP_PARAMS); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign _STLP_BUF_PARAMS) michael@0: { return _Stl_fcvtR(__STATIC_CAST(double, x), n, pt, sign _STLP_PARAMS); } michael@0: # undef _STLP_PARAMS michael@0: # endif michael@0: # undef _STLP_SECURE_FUN michael@0: # undef _STLP_BUF_PARAMS michael@0: # undef _STLP_APPEND michael@0: # if defined (__BORLANDC__) /* || defined (__GNUC__) MinGW do not support 'L' modifier so emulation do not work */ michael@0: # define _STLP_EMULATE_LONG_DOUBLE_CVT michael@0: # endif michael@0: # elif defined (__ISCPP__) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return _fp_ecvt( x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf) michael@0: { return _fp_fcvt(x, n, pt, sign, buf); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return _fp_ecvt( x, n, pt, sign, buf); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf) michael@0: { return _fp_fcvt(x, n, pt, sign, buf); } michael@0: # endif michael@0: # elif defined (_AIX) || defined (__FreeBSD__) || defined (__NetBSD__) || defined (__OpenBSD__) || \ michael@0: defined (__MRC__) || defined (__SC__) || defined (_CRAY) || \ michael@0: defined (_STLP_SCO_OPENSERVER) || defined (__NCR_SVR) || \ michael@0: defined (__DMC__) michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign) michael@0: { return ecvt(x, n, pt, sign ); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign) michael@0: { return fcvt(x, n, pt, sign); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign) michael@0: { return ecvt(x, n, pt, sign ); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign) michael@0: { return fcvt(x, n, pt, sign); } michael@0: # endif michael@0: # define _STLP_CVT_NEED_SYNCHRONIZATION michael@0: # else michael@0: # error Missing _Stl_ecvtR and _Stl_fcvtR implementations. michael@0: # endif michael@0: michael@0: #if defined (_STLP_CVT_NEED_SYNCHRONIZATION) michael@0: /* STLport synchronize access to *cvt functions but those methods might michael@0: * be called from outside, in this case we will still have a race condition. */ michael@0: # if defined (_STLP_THREADS) michael@0: static _STLP_STATIC_MUTEX& put_float_mutex() { michael@0: static _STLP_STATIC_MUTEX __put_float_mutex _STLP_MUTEX_INITIALIZER; michael@0: return __put_float_mutex; michael@0: } michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char* buf) { michael@0: _STLP_auto_lock lock(put_float_mutex()); michael@0: strcpy(buf, _Stl_ecvtR(x, n, pt, sign)); return buf; michael@0: } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char* buf) { michael@0: _STLP_auto_lock lock(put_float_mutex()); michael@0: strcpy(buf, _Stl_fcvtR(x, n, pt, sign)); return buf; michael@0: } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) && !defined (_STLP_EMULATE_LONG_DOUBLE_CVT) michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf) { michael@0: _STLP_auto_lock lock(put_float_mutex()); michael@0: strcpy(buf, _Stl_ecvtR(x, n, pt, sign)); return buf; michael@0: } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf) { michael@0: _STLP_auto_lock lock(put_float_mutex()); michael@0: strcpy(buf, _Stl_fcvtR(x, n, pt, sign)); return buf; michael@0: } michael@0: # endif michael@0: # else michael@0: static inline char* _Stl_ecvtR(double x, int n, int* pt, int* sign, char*) michael@0: { return _Stl_ecvtR(x, n, pt, sign); } michael@0: static inline char* _Stl_fcvtR(double x, int n, int* pt, int* sign, char*) michael@0: { return _Stl_fcvtR(x, n, pt, sign); } michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) && !defined (_STLP_EMULATE_LONG_DOUBLE_CVT) michael@0: static inline char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char*) michael@0: { return _Stl_ecvtR(x, n, pt, sign); } michael@0: static inline char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char*) michael@0: { return _Stl_fcvtR(x, n, pt, sign); } michael@0: # endif michael@0: # endif michael@0: #endif michael@0: michael@0: # if !defined (_STLP_USE_SAFE_STRING_FUNCTIONS) && !defined (_STLP_NEED_CVT_BUFFER_SIZE) michael@0: # define _STLP_CVT_BUFFER(B) B michael@0: # else michael@0: # define _STLP_CVT_BUFFER(B) _STLP_ARRAY_AND_SIZE(B) michael@0: # endif michael@0: michael@0: # if defined (_STLP_EMULATE_LONG_DOUBLE_CVT) michael@0: static void __fill_fmtbuf(char* fmtbuf, ios_base::fmtflags flags, char long_modifier); michael@0: michael@0: // Emulation of ecvt/fcvt functions using sprintf: michael@0: static char* _Stl_ecvtR(long double x, int n, int* pt, int* sign, char* buf) { michael@0: // If long double value can be safely converted to double without losing precision michael@0: // we use the ecvt function for double: michael@0: double y = __STATIC_CAST(double, x); michael@0: if (x == y) michael@0: return _Stl_ecvtR(y, n, pt, sign, buf); michael@0: michael@0: char fmtbuf[32]; michael@0: __fill_fmtbuf(fmtbuf, 0, 'L'); michael@0: sprintf(buf, fmtbuf, n, x < 0.0l ? -x : x); michael@0: /* We are waiting for something having the form x.xxxe+yyyy */ michael@0: *pt = 0; michael@0: *sign = 0; michael@0: int i = -1; michael@0: int offset = 0; michael@0: while (buf[++i] != 0 && n != 0) { michael@0: if (buf[i] >= '0' && buf[i] <= '9') { michael@0: --n; michael@0: if (offset != 0) michael@0: buf[i - offset] = buf[i]; michael@0: } michael@0: else { michael@0: if (offset != 0) break; michael@0: ++offset; michael@0: *pt = i; michael@0: } michael@0: } michael@0: if (offset != 0) michael@0: buf[i - offset] = 0; michael@0: // Extract exponent part in point position: michael@0: int e = 0; michael@0: while (buf[++i] != 0) { michael@0: if (buf[i] >= '0' && buf[i] <= '9') { michael@0: e = e * 10 + (buf[i] - '0'); michael@0: } michael@0: } michael@0: *pt += e; michael@0: return buf; michael@0: } michael@0: michael@0: static char* _Stl_fcvtR(long double x, int n, int* pt, int* sign, char* buf) { michael@0: // If long double value can be safely converted to double without losing precision michael@0: // we use the fcvt function for double: michael@0: double y = __STATIC_CAST(double, x); michael@0: if (x == y) michael@0: return _Stl_fcvtR(y, n, pt, sign, buf); michael@0: michael@0: char fmtbuf[32]; michael@0: __fill_fmtbuf(fmtbuf, ios_base::fixed, 'L'); michael@0: sprintf(buf, fmtbuf, n, x < 0.0l ? -x : x); michael@0: *pt = 0; michael@0: *sign = 0; michael@0: int i = -1; michael@0: int offset = 0; michael@0: while (buf[++i] != 0 && (offset == 0 || n != 0)) { michael@0: if (buf[i] >= '0' && buf[i] <= '9') { michael@0: if (offset != 0) { michael@0: --n; michael@0: buf[i - offset] = buf[i]; michael@0: } michael@0: } michael@0: else { michael@0: ++offset; michael@0: *pt = i; michael@0: } michael@0: } michael@0: if (offset != 0) michael@0: buf[i - offset] = 0; michael@0: else michael@0: *pt = i; michael@0: return buf; michael@0: } michael@0: #endif michael@0: michael@0: //---------------------------------------------------------------------- michael@0: // num_put michael@0: michael@0: // __format_float formats a mantissa and exponent as returned by michael@0: // one of the conversion functions (ecvt_r, fcvt_r, qecvt_r, qfcvt_r) michael@0: // according to the specified precision and format flags. This is michael@0: // based on doprnt but is much simpler since it is concerned only michael@0: // with floating point input and does not consider all formats. It michael@0: // also does not deal with blank padding, which is handled by michael@0: // __copy_float_and_fill. michael@0: michael@0: static size_t __format_float_scientific( __iostring& buf, const char *bp, michael@0: int decpt, int sign, bool is_zero, michael@0: ios_base::fmtflags flags, michael@0: int precision) { michael@0: // sign if required michael@0: if (sign) michael@0: buf += '-'; michael@0: else if (flags & ios_base::showpos) michael@0: buf += '+'; michael@0: michael@0: // first digit of mantissa michael@0: buf += *bp++; michael@0: michael@0: // start of grouping position, grouping won't occur in scientific notation michael@0: // as it is impossible to have something like 1234.0e04 but we return a correct michael@0: // group position for coherency with __format_float_fixed. michael@0: size_t __group_pos = buf.size(); michael@0: michael@0: // decimal point if required michael@0: if (precision != 0 || flags & ios_base::showpoint) { michael@0: buf += '.'; michael@0: } michael@0: michael@0: // rest of mantissa michael@0: while (*bp != 0 && precision--) michael@0: buf += *bp++; michael@0: michael@0: // trailing 0 if needed michael@0: if (precision > 0) michael@0: buf.append(precision, '0'); michael@0: michael@0: // exponent size = number of digits + exponent sign + exponent symbol + trailing zero michael@0: char expbuf[MAXEDIGITS + 3]; michael@0: //We start filling at the buffer end michael@0: char *suffix = expbuf + MAXEDIGITS + 2; michael@0: *suffix = 0; michael@0: if (!is_zero) { michael@0: int nn = decpt - 1; michael@0: if (nn < 0) michael@0: nn = -nn; michael@0: for (; nn > 9; nn /= 10) michael@0: *--suffix = (char) todigit(nn % 10); michael@0: *--suffix = (char) todigit(nn); michael@0: } michael@0: michael@0: // prepend leading zeros to exponent michael@0: // C89 Standard says that it should be at least 2 digits, C99 Standard says that michael@0: // we stop prepend zeros if more than 3 digits. To repect both STLport prepend zeros michael@0: // until it is 2 digits. michael@0: while (suffix > &expbuf[MAXEDIGITS]) michael@0: *--suffix = '0'; michael@0: michael@0: // put in the exponent sign michael@0: *--suffix = (char) ((decpt > 0 || is_zero ) ? '+' : '-'); michael@0: michael@0: // put in the e michael@0: *--suffix = flags & ios_base::uppercase ? 'E' : 'e'; michael@0: michael@0: // copy the suffix michael@0: buf += suffix; michael@0: return __group_pos; michael@0: } michael@0: michael@0: static size_t __format_float_fixed( __iostring &buf, const char *bp, michael@0: int decpt, int sign, michael@0: ios_base::fmtflags flags, michael@0: int precision) { michael@0: if ( sign && (decpt > -precision) && (*bp != 0) ) michael@0: buf += '-'; michael@0: else if ( flags & ios_base::showpos ) michael@0: buf += '+'; michael@0: michael@0: // digits before decimal point michael@0: int nnn = decpt; michael@0: do { michael@0: buf += (nnn <= 0 || *bp == 0) ? '0' : *bp++; michael@0: } while ( --nnn > 0 ); michael@0: michael@0: // start of grouping position michael@0: size_t __group_pos = buf.size(); michael@0: michael@0: // decimal point if needed michael@0: if ( flags & ios_base::showpoint || precision > 0 ) { michael@0: buf += '.'; michael@0: } michael@0: michael@0: // digits after decimal point if any michael@0: while ( *bp != 0 && --precision >= 0 ) { michael@0: buf += (++decpt <= 0) ? '0' : *bp++; michael@0: } michael@0: michael@0: // trailing zeros if needed michael@0: if (precision > 0) michael@0: buf.append(precision, '0'); michael@0: michael@0: return __group_pos; michael@0: } michael@0: michael@0: #if defined (_STLP_USE_SIGN_HELPER) michael@0: template michael@0: struct float_sign_helper { michael@0: float_sign_helper(_FloatT __x) michael@0: { _M_number._num = __x; } michael@0: michael@0: bool is_negative() const { michael@0: const unsigned short sign_mask(1 << (sizeof(unsigned short) * CHAR_BIT - 1)); michael@0: return (get_sign_word() & sign_mask) != 0; michael@0: } michael@0: private: michael@0: union { michael@0: unsigned short _Words[8]; michael@0: _FloatT _num; michael@0: } _M_number; michael@0: michael@0: unsigned short get_word_higher() const _STLP_NOTHROW michael@0: { return _M_number._Words[0]; } michael@0: unsigned short get_word_lower() const _STLP_NOTHROW michael@0: { return _M_number._Words[(sizeof(_FloatT) >= 12 ? 10 : sizeof(_FloatT)) / sizeof(unsigned short) - 1]; } michael@0: unsigned short get_sign_word() const _STLP_NOTHROW michael@0: # if defined (_STLP_BIG_ENDIAN) michael@0: { return get_word_higher(); } michael@0: # else /* _STLP_LITTLE_ENDIAN */ michael@0: { return get_word_lower(); } michael@0: # endif michael@0: }; michael@0: #endif michael@0: michael@0: template michael@0: static size_t __format_nan_or_inf(__iostring& buf, _FloatT x, ios_base::fmtflags flags) { michael@0: static const char* inf[2] = { "inf", "Inf" }; michael@0: static const char* nan[2] = { "nan", "NaN" }; michael@0: const char** inf_or_nan; michael@0: #if !defined (_STLP_USE_SIGN_HELPER) michael@0: if (_Stl_is_inf(x)) { // Infinity michael@0: inf_or_nan = inf; michael@0: if (_Stl_is_neg_inf(x)) michael@0: buf += '-'; michael@0: else if (flags & ios_base::showpos) michael@0: buf += '+'; michael@0: } else { // NaN michael@0: inf_or_nan = nan; michael@0: if (_Stl_is_neg_nan(x)) michael@0: buf += '-'; michael@0: else if (flags & ios_base::showpos) michael@0: buf += '+'; michael@0: } michael@0: #else michael@0: typedef numeric_limits<_FloatT> limits; michael@0: if (x == limits::infinity() || x == -limits::infinity()) { michael@0: inf_or_nan = inf; michael@0: } else { // NaN michael@0: inf_or_nan = nan; michael@0: } michael@0: float_sign_helper<_FloatT> helper(x); michael@0: if (helper.is_negative()) michael@0: buf += '-'; michael@0: else if (flags & ios_base::showpos) michael@0: buf += '+'; michael@0: #endif michael@0: size_t ret = buf.size(); michael@0: buf += inf_or_nan[flags & ios_base::uppercase ? 1 : 0]; michael@0: return ret; michael@0: } michael@0: michael@0: static inline size_t __format_float(__iostring &buf, const char * bp, michael@0: int decpt, int sign, bool is_zero, michael@0: ios_base::fmtflags flags, michael@0: int precision) { michael@0: size_t __group_pos = 0; michael@0: switch (flags & ios_base::floatfield) { michael@0: case ios_base::scientific: michael@0: __group_pos = __format_float_scientific( buf, bp, decpt, sign, is_zero, michael@0: flags, precision); michael@0: break; michael@0: case ios_base::fixed: michael@0: __group_pos = __format_float_fixed( buf, bp, decpt, sign, michael@0: flags, precision); michael@0: break; michael@0: default: // g format michael@0: // establish default precision michael@0: if (flags & ios_base::showpoint || precision > 0) { michael@0: if (precision == 0) precision = 1; michael@0: } else michael@0: precision = 6; michael@0: michael@0: // reset exponent if value is zero michael@0: if (is_zero) michael@0: decpt = 1; michael@0: michael@0: int kk = precision; michael@0: if (!(flags & ios_base::showpoint)) { michael@0: size_t n = strlen(bp); michael@0: if (n < (size_t)kk) michael@0: kk = (int)n; michael@0: while (kk >= 1 && bp[kk-1] == '0') michael@0: --kk; michael@0: } michael@0: michael@0: if (decpt < -3 || decpt > precision) { michael@0: precision = kk - 1; michael@0: __group_pos = __format_float_scientific( buf, bp, decpt, sign, is_zero, michael@0: flags, precision); michael@0: } else { michael@0: precision = kk - decpt; michael@0: __group_pos = __format_float_fixed( buf, bp, decpt, sign, michael@0: flags, precision); michael@0: } michael@0: break; michael@0: } /* switch */ michael@0: return __group_pos; michael@0: } michael@0: michael@0: #endif michael@0: michael@0: #if defined (USE_SPRINTF_INSTEAD) || defined (_STLP_EMULATE_LONG_DOUBLE_CVT) michael@0: struct GroupPos { michael@0: bool operator () (char __c) const { michael@0: return __c == '.' || michael@0: __c == 'e' || __c == 'E'; michael@0: } michael@0: }; michael@0: michael@0: // Creates a format string for sprintf() michael@0: static void __fill_fmtbuf(char* fmtbuf, ios_base::fmtflags flags, char long_modifier) { michael@0: fmtbuf[0] = '%'; michael@0: int i = 1; michael@0: michael@0: if (flags & ios_base::showpos) michael@0: fmtbuf[i++] = '+'; michael@0: michael@0: if (flags & ios_base::showpoint) michael@0: fmtbuf[i++] = '#'; michael@0: michael@0: fmtbuf[i++] = '.'; michael@0: fmtbuf[i++] = '*'; michael@0: michael@0: if (long_modifier) michael@0: fmtbuf[i++] = long_modifier; michael@0: michael@0: switch (flags & ios_base::floatfield) michael@0: { michael@0: case ios_base::scientific: michael@0: fmtbuf[i++] = (flags & ios_base::uppercase) ? 'E' : 'e'; michael@0: break; michael@0: case ios_base::fixed: michael@0: # if defined (__FreeBSD__) michael@0: fmtbuf[i++] = 'f'; michael@0: # else michael@0: fmtbuf[i++] = (flags & ios_base::uppercase) ? 'F' : 'f'; michael@0: # endif michael@0: break; michael@0: default: michael@0: fmtbuf[i++] = (flags & ios_base::uppercase) ? 'G' : 'g'; michael@0: break; michael@0: } michael@0: michael@0: fmtbuf[i] = 0; michael@0: } michael@0: michael@0: #endif /* USE_SPRINTF_INSTEAD */ michael@0: michael@0: template michael@0: static size_t __write_floatT(__iostring &buf, ios_base::fmtflags flags, int precision, michael@0: _FloatT x michael@0: #if defined (USE_SPRINTF_INSTEAD) michael@0: , char modifier) { michael@0: /* In theory, if we want 'arbitrary' precision, we should use 'arbitrary' michael@0: * buffer size below, but really we limited by exponent part in double. michael@0: * - ptr michael@0: */ michael@0: typedef numeric_limits<_FloatT> limits; michael@0: char static_buf[limits::max_exponent10 + 6]; // 6: -xxx.yyyE-zzz (sign, dot, E, exp sign, \0) michael@0: char fmtbuf[32]; michael@0: __fill_fmtbuf(fmtbuf, flags, modifier); michael@0: snprintf(_STLP_ARRAY_AND_SIZE(static_buf), fmtbuf, precision, x); michael@0: buf = static_buf; michael@0: return find_if(buf.begin(), buf.end(), GroupPos()) - buf.begin(); michael@0: #else michael@0: ) { michael@0: typedef numeric_limits<_FloatT> limits; michael@0: //If numeric_limits support is correct we use the exposed values to detect NaN and infinity: michael@0: if (limits::has_infinity && limits::has_quiet_NaN) { michael@0: if (!(x == x) || // NaN check michael@0: (x == limits::infinity() || x == -limits::infinity())) { michael@0: return __format_nan_or_inf(buf, x, flags); michael@0: } michael@0: } michael@0: // numeric_limits support is not good enough, we rely on platform dependent function michael@0: // _Stl_is_nan_or_inf that do not support long double. michael@0: else if (_Stl_is_nan_or_inf(x)) { michael@0: return __format_nan_or_inf(buf, x, flags); michael@0: } michael@0: # if defined (__MINGW32__) michael@0: //For the moment MinGW is limited to display at most numeric_limits::max() michael@0: if (x > numeric_limits::max() || michael@0: x < -numeric_limits::max()) { michael@0: return __format_nan_or_inf(buf, x, flags); michael@0: } michael@0: # endif michael@0: michael@0: /* Buffer size is max number of digits which is the addition of: michael@0: * - max_exponent10: max number of digits in fixed mode michael@0: * - digits10 + 2: max number of significant digits michael@0: * - trailing '\0' michael@0: */ michael@0: char cvtbuf[limits::max_exponent10 + limits::digits10 + 2 + 1]; michael@0: char *bp; michael@0: int decpt, sign; michael@0: michael@0: switch (flags & ios_base::floatfield) { michael@0: case ios_base::fixed: michael@0: { michael@0: /* Here, number of digits represents digits _after_ decimal point. michael@0: * In order to limit static buffer size we have to give 2 different values depending on x value. michael@0: * For small values (abs(x) < 1) we need as many digits as requested by precision limited by the maximum number of digits michael@0: * which is min_exponent10 + digits10 + 2 michael@0: * For bigger values we won't have more than limits::digits10 + 2 digits after decimal point. */ michael@0: int digits10 = (x > -1.0 && x < 1.0 ? -limits::min_exponent10 + limits::digits10 + 2 michael@0: : limits::digits10 + 2); michael@0: bp = _Stl_fcvtR(x, (min) (precision, digits10), &decpt, &sign, _STLP_CVT_BUFFER(cvtbuf) ); michael@0: } michael@0: break; michael@0: case ios_base::scientific: michael@0: default: michael@0: /* Here, number of digits is total number of digits which is limited to digits10 + 2. */ michael@0: { michael@0: int digits10 = limits::digits10 + 2; michael@0: bp = _Stl_ecvtR(x, (min) (precision, digits10), &decpt, &sign, _STLP_CVT_BUFFER(cvtbuf) ); michael@0: } michael@0: break; michael@0: } michael@0: return __format_float(buf, bp, decpt, sign, x == 0.0, flags, precision); michael@0: #endif michael@0: } michael@0: michael@0: size_t _STLP_CALL michael@0: __write_float(__iostring &buf, ios_base::fmtflags flags, int precision, michael@0: double x) { michael@0: return __write_floatT(buf, flags, precision, x michael@0: #if defined (USE_SPRINTF_INSTEAD) michael@0: , 0 michael@0: #endif michael@0: ); michael@0: } michael@0: michael@0: #if !defined (_STLP_NO_LONG_DOUBLE) michael@0: size_t _STLP_CALL michael@0: __write_float(__iostring &buf, ios_base::fmtflags flags, int precision, michael@0: long double x) { michael@0: return __write_floatT(buf, flags, precision, x michael@0: #if defined (USE_SPRINTF_INSTEAD) michael@0: , 'L' michael@0: #endif michael@0: ); michael@0: } michael@0: #endif michael@0: michael@0: void _STLP_CALL __get_floor_digits(__iostring &out, _STLP_LONGEST_FLOAT_TYPE __x) { michael@0: typedef numeric_limits<_STLP_LONGEST_FLOAT_TYPE> limits; michael@0: #if defined (USE_SPRINTF_INSTEAD) michael@0: char cvtbuf[limits::max_exponent10 + 6]; michael@0: # if !defined (_STLP_NO_LONG_DOUBLE) michael@0: snprintf(_STLP_ARRAY_AND_SIZE(cvtbuf), "%Lf", __x); // check for 1234.56! michael@0: # else michael@0: snprintf(_STLP_ARRAY_AND_SIZE(cvtbuf), "%f", __x); // check for 1234.56! michael@0: # endif michael@0: char *p = strchr( cvtbuf, '.' ); michael@0: if ( p == 0 ) { michael@0: out.append( cvtbuf ); michael@0: } else { michael@0: out.append( cvtbuf, p ); michael@0: } michael@0: #else michael@0: char cvtbuf[limits::max_exponent10 + 1]; michael@0: char * bp; michael@0: int decpt, sign; michael@0: bp = _Stl_fcvtR(__x, 0, &decpt, &sign, _STLP_CVT_BUFFER(cvtbuf)); michael@0: michael@0: if (sign) { michael@0: out += '-'; michael@0: } michael@0: out.append(bp, bp + decpt); michael@0: #endif michael@0: } michael@0: michael@0: michael@0: #if !defined (_STLP_NO_WCHAR_T) michael@0: void _STLP_CALL __convert_float_buffer( __iostring const& str, __iowstring &out, michael@0: const ctype& ct, wchar_t dot, bool __check_dot) { michael@0: string::const_iterator str_ite(str.begin()), str_end(str.end()); michael@0: michael@0: //First loop, check the dot char michael@0: if (__check_dot) { michael@0: while (str_ite != str_end) { michael@0: if (*str_ite != '.') { michael@0: out += ct.widen(*str_ite++); michael@0: } else { michael@0: out += dot; michael@0: break; michael@0: } michael@0: } michael@0: } else { michael@0: if (str_ite != str_end) { michael@0: out += ct.widen(*str_ite); michael@0: } michael@0: } michael@0: michael@0: if (str_ite != str_end) { michael@0: //Second loop, dot has been found, no check anymore michael@0: while (++str_ite != str_end) { michael@0: out += ct.widen(*str_ite); michael@0: } michael@0: } michael@0: } michael@0: michael@0: #endif michael@0: michael@0: void _STLP_CALL michael@0: __adjust_float_buffer(__iostring &str, char dot) { michael@0: if ('.' != dot) { michael@0: size_t __dot_pos = str.find('.'); michael@0: if (__dot_pos != string::npos) { michael@0: str[__dot_pos] = dot; michael@0: } michael@0: } michael@0: } michael@0: michael@0: _STLP_MOVE_TO_STD_NAMESPACE michael@0: _STLP_END_NAMESPACE michael@0: michael@0: // Local Variables: michael@0: // mode:C++ michael@0: // End: