// Compiler implementation of the D programming language // Copyright (c) 1999-2015 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // Distributed under the Boost Software License, Version 1.0. // http://www.boost.org/LICENSE_1_0.txt module ddmd.root.port; import core.stdc.ctype; import core.stdc.string; import core.stdc.stdio; import core.stdc.errno; import core.math; version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint; version(CRuntime_Microsoft) extern(C++) struct longdouble { real r; } version(CRuntime_Microsoft) extern(C++) size_t ld_sprint(char* str, int fmt, longdouble x); extern (C) float strtof(const(char)* p, char** endp); extern (C) double strtod(const(char)* p, char** endp); version(IN_LLVM_MSVC) extern (C) double strtold(const(char)* p, char** endp); else version(CRuntime_Microsoft) extern (C++) longdouble strtold_dm(const(char)* p, char** endp); else extern (C) real strtold(const(char)* p, char** endp); version(CRuntime_Microsoft) { enum _OVERFLOW = 3; /* overflow range error */ enum _UNDERFLOW = 4; /* underflow range error */ extern (C) int _atoflt(float* value, const char * str); extern (C) int _atodbl(double* value, const char * str); } extern (C++) struct Port { enum nan = double.nan; enum infinity = double.infinity; version(IN_LLVM_MSVC) private alias ldbl = double; else private alias ldbl = real; version(IN_LLVM) { enum ldbl_min_normal = ldbl.min_normal; enum ldbl_max = ldbl.max; enum ldbl_nan = ldbl.nan; enum ldbl_infinity = ldbl.infinity; enum ldbl_dig = ldbl.dig; enum ldbl_epsilon = ldbl.epsilon; enum ldbl_mant_dig = ldbl.mant_dig; enum ldbl_max_10_exp = ldbl.max_10_exp; enum ldbl_max_exp = ldbl.max_exp; enum ldbl_min_10_exp = ldbl.min_10_exp; enum ldbl_min_exp = ldbl.min_exp; } else { enum ldbl_max = real.max; enum ldbl_nan = real.nan; enum ldbl_infinity = real.infinity; } version(IN_LLVM) { static __gshared bool yl2x_supported = false; static __gshared bool yl2xp1_supported = false; } else version(DigitalMars) { static __gshared bool yl2x_supported = true; static __gshared bool yl2xp1_supported = true; } else { static __gshared bool yl2x_supported = false; static __gshared bool yl2xp1_supported = false; } static __gshared real snan; static bool isNan(double r) { return !(r == r); } static real sqrt(real x) { return .sqrt(x); } static real fmodl(real a, real b) { return a % b; } static bool fequal(real a, real b) { // don't compare pad bytes in extended precision enum sz = (real.mant_dig == 64) ? 10 : real.sizeof; return memcmp(&a, &b, sz) == 0; } static int memicmp(const char* s1, const char* s2, size_t n) { int result = 0; for (int i = 0; i < n; i++) { char c1 = s1[i]; char c2 = s2[i]; result = c1 - c2; if (result) { result = toupper(c1) - toupper(c2); if (result) break; } } return result; } static char* strupr(char* s) { char* t = s; while (*s) { *s = cast(char)toupper(*s); s++; } return t; } static int isSignallingNan(double r) { return isNan(r) && !(((cast(ubyte*)&r)[6]) & 8); } static int isSignallingNan(real r) { return isNan(r) && !(((cast(ubyte*)&r)[7]) & 0x40); } version(CRuntime_Microsoft) { static int isSignallingNan(longdouble ld) { return isSignallingNan(*cast(real*)&ld); } } static int isInfinity(double r) { return r is double.infinity || r is -double.infinity; } static float strtof(const(char)* p, char** endp) { version (CRuntime_DigitalMars) { auto save = __locale_decpoint; __locale_decpoint = "."; } version (CRuntime_Microsoft) { float r; if(endp) { r = .strtod(p, endp); // does not set errno for underflows, but unused } else { int res = _atoflt(&r, p); if (res == _UNDERFLOW || res == _OVERFLOW) errno = ERANGE; } } else { auto r = .strtof(p, endp); } version (CRuntime_DigitalMars) __locale_decpoint = save; return r; } static double strtod(const(char)* p, char** endp) { version (CRuntime_DigitalMars) { auto save = __locale_decpoint; __locale_decpoint = "."; } version (CRuntime_Microsoft) { double r; if(endp) { r = .strtod(p, endp); // does not set errno for underflows, but unused } else { int res = _atodbl(&r, p); if (res == _UNDERFLOW || res == _OVERFLOW) errno = ERANGE; } } else { auto r = .strtod(p, endp); } version (CRuntime_DigitalMars) __locale_decpoint = save; return r; } static real strtold(const(char)* p, char** endp) { version (CRuntime_DigitalMars) { auto save = __locale_decpoint; __locale_decpoint = "."; } version(IN_LLVM_MSVC) auto r = .strtold(p, endp); // C99 conformant since VS 2015 else version (CRuntime_Microsoft) auto r = .strtold_dm(p, endp).r; else auto r = .strtold(p, endp); version (CRuntime_DigitalMars) __locale_decpoint = save; return r; } static size_t ld_sprint(char* str, int fmt, real x) { version(IN_LLVM_MSVC) { if ((cast(real)cast(ulong)x) == x) { // ((1.5 -> 1 -> 1.0) == 1.5) is false // ((1.0 -> 1 -> 1.0) == 1.0) is true // see http://en.cppreference.com/w/cpp/io/c/fprintf char[4] sfmt = "%#g\0"; sfmt[2] = cast(char)fmt; return sprintf(str, sfmt.ptr, double(x)); } else { char[3] sfmt = "%g\0"; sfmt[1] = cast(char)fmt; return sprintf(str, sfmt.ptr, double(x)); } } else version(CRuntime_Microsoft) { return .ld_sprint(str, fmt, longdouble(x)); } else { if ((cast(real)cast(ulong)x) == x) { // ((1.5 -> 1 -> 1.0) == 1.5) is false // ((1.0 -> 1 -> 1.0) == 1.0) is true // see http://en.cppreference.com/w/cpp/io/c/fprintf char[5] sfmt = "%#Lg\0"; sfmt[3] = cast(char)fmt; return sprintf(str, sfmt.ptr, x); } else { char[4] sfmt = "%Lg\0"; sfmt[2] = cast(char)fmt; return sprintf(str, sfmt.ptr, x); } } } static void yl2x_impl(real* x, real* y, real* res) { version(DigitalMars) *res = yl2x(*x, *y); version(IN_LLVM) assert(0); } static void yl2xp1_impl(real* x, real* y, real* res) { version(DigitalMars) *res = yl2xp1(*x, *y); version(IN_LLVM) assert(0); } // Little endian static void writelongLE(uint value, void* buffer) { auto p = cast(ubyte*)buffer; p[3] = cast(ubyte)(value >> 24); p[2] = cast(ubyte)(value >> 16); p[1] = cast(ubyte)(value >> 8); p[0] = cast(ubyte)(value); } // Little endian static uint readlongLE(void* buffer) { auto p = cast(ubyte*)buffer; return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; } // Big endian static void writelongBE(uint value, void* buffer) { auto p = cast(ubyte*)buffer; p[0] = cast(ubyte)(value >> 24); p[1] = cast(ubyte)(value >> 16); p[2] = cast(ubyte)(value >> 8); p[3] = cast(ubyte)(value); } // Big endian static uint readlongBE(void* buffer) { auto p = cast(ubyte*)buffer; return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3]; } // Little endian static uint readwordLE(void* buffer) { auto p = cast(ubyte*)buffer; return (p[1] << 8) | p[0]; } // Big endian static uint readwordBE(void* buffer) { auto p = cast(ubyte*)buffer; return (p[0] << 8) | p[1]; } version(IN_LLVM) { // LDC_FIXME: Move this into our C++ code, since only driver/gen is // still using this. static int stricmp(const(char)* s1, const(char)* s2) { int result = 0; for (;;) { char c1 = *s1; char c2 = *s2; result = c1 - c2; if (result) { result = toupper(c1) - toupper(c2); if (result) break; } if (!c1) break; s1++; s2++; } return result; } } static void valcpy(void *dst, ulong val, size_t size) { switch (size) { case 1: *cast(ubyte *)dst = cast(ubyte)val; break; case 2: *cast(ushort *)dst = cast(ushort)val; break; case 4: *cast(uint *)dst = cast(uint)val; break; case 8: *cast(ulong *)dst = cast(ulong)val; break; default: assert(0); } } }