1 // Compiler implementation of the D programming language
2 // Copyright (c) 1999-2015 by Digital Mars
3 // All Rights Reserved
4 // written by Walter Bright
5 // http://www.digitalmars.com
6 // Distributed under the Boost Software License, Version 1.0.
7 // http://www.boost.org/LICENSE_1_0.txt
8 
9 module ddmd.root.port;
10 
11 import core.stdc.ctype;
12 import core.stdc..string;
13 import core.stdc.stdio;
14 import core.stdc.errno;
15 import core.math;
16 
17 version(CRuntime_DigitalMars) __gshared extern (C) extern const(char)* __locale_decpoint;
18 version(CRuntime_Microsoft)   extern(C++) struct longdouble { real r; }
19 version(CRuntime_Microsoft)   extern(C++) size_t ld_sprint(char* str, int fmt, longdouble x);
20 
21 extern (C) float strtof(const(char)* p, char** endp);
22 extern (C) double strtod(const(char)* p, char** endp);
23 
24 version(CRuntime_Microsoft)
25     extern (C++) longdouble strtold_dm(const(char)* p, char** endp);
26 else
27     extern (C) real strtold(const(char)* p, char** endp);
28 
29 version(CRuntime_Microsoft)
30 {
31     enum _OVERFLOW = 3;   /* overflow range error */
32     enum _UNDERFLOW = 4;   /* underflow range error */
33 
34     extern (C) int _atoflt(float* value, const char * str);
35     extern (C) int _atodbl(double* value, const char * str);
36 }
37 
38 extern (C++) struct Port
39 {
40     enum nan = double.nan;
41     enum infinity = double.infinity;
42     enum ldbl_max = real.max;
43     enum ldbl_nan = real.nan;
44     enum ldbl_infinity = real.infinity;
45     version(DigitalMars)
46     {
47         static __gshared bool yl2x_supported = true;
48         static __gshared bool yl2xp1_supported = true;
49     }
50     else
51     {
52         static __gshared bool yl2x_supported = false;
53         static __gshared bool yl2xp1_supported = false;
54     }
55     static __gshared real snan;
56     static this()
57     {
58         /*
59          * Use a payload which is different from the machine NaN,
60          * so that uninitialised variables can be
61          * detected even if exceptions are disabled.
62          */
63         ushort* us = cast(ushort*)&snan;
64         us[0] = 0;
65         us[1] = 0;
66         us[2] = 0;
67         us[3] = 0xA000;
68         us[4] = 0x7FFF;
69     }
70 
71     static bool isNan(double r)
72     {
73         return !(r == r);
74     }
75 
76     static real sqrt(real x)
77     {
78         return .sqrt(x);
79     }
80 
81     static real fmodl(real a, real b)
82     {
83         return a % b;
84     }
85 
86     static real fequal(real a, real b)
87     {
88         return memcmp(&a, &b, 10) == 0;
89     }
90 
91     static int memicmp(const char* s1, const char* s2, size_t n)
92     {
93         int result = 0;
94 
95         for (int i = 0; i < n; i++)
96         {
97             char c1 = s1[i];
98             char c2 = s2[i];
99 
100             result = c1 - c2;
101             if (result)
102             {
103                 result = toupper(c1) - toupper(c2);
104                 if (result)
105                     break;
106             }
107         }
108         return result;
109     }
110 
111     static char* strupr(char* s)
112     {
113         char* t = s;
114 
115         while (*s)
116         {
117             *s = cast(char)toupper(*s);
118             s++;
119         }
120 
121         return t;
122     }
123 
124     static int isSignallingNan(double r)
125     {
126         return isNan(r) && !(((cast(ubyte*)&r)[6]) & 8);
127     }
128 
129     static int isSignallingNan(real r)
130     {
131         return isNan(r) && !(((cast(ubyte*)&r)[7]) & 0x40);
132     }
133 
134     version(CRuntime_Microsoft)
135     {
136         static int isSignallingNan(longdouble ld)
137         {
138             return isSignallingNan(*cast(real*)&ld);
139         }
140     }
141 
142     static int isInfinity(double r)
143     {
144         return r is double.infinity || r is -double.infinity;
145     }
146 
147     static float strtof(const(char)* p, char** endp)
148     {
149         version (CRuntime_DigitalMars)
150         {
151             auto save = __locale_decpoint;
152             __locale_decpoint = ".";
153         }
154         version (CRuntime_Microsoft)
155         {
156             float r;
157             if(endp)
158             {
159                 r = .strtod(p, endp); // does not set errno for underflows, but unused
160             }
161             else
162             {
163                 int res = _atoflt(&r, p);
164                 if (res == _UNDERFLOW || res == _OVERFLOW)
165                     errno = ERANGE;
166             }
167         }
168         else
169         {
170             auto r = .strtof(p, endp);
171         }
172         version (CRuntime_DigitalMars) __locale_decpoint = save;
173         return r;
174     }
175 
176     static double strtod(const(char)* p, char** endp)
177     {
178         version (CRuntime_DigitalMars)
179         {
180             auto save = __locale_decpoint;
181             __locale_decpoint = ".";
182         }
183         version (CRuntime_Microsoft)
184         {
185             double r;
186             if(endp)
187             {
188                 r = .strtod(p, endp); // does not set errno for underflows, but unused
189             }
190             else
191             {
192                 int res = _atodbl(&r, p);
193                 if (res == _UNDERFLOW || res == _OVERFLOW)
194                     errno = ERANGE;
195             }
196         }
197         else
198         {
199             auto r = .strtod(p, endp);
200         }
201         version (CRuntime_DigitalMars) __locale_decpoint = save;
202         return r;
203     }
204 
205     static real strtold(const(char)* p, char** endp)
206     {
207         version (CRuntime_DigitalMars)
208         {
209             auto save = __locale_decpoint;
210             __locale_decpoint = ".";
211         }
212 
213         version (CRuntime_Microsoft)
214             auto r = .strtold_dm(p, endp).r;
215         else
216             auto r = .strtold(p, endp);
217         version (CRuntime_DigitalMars) __locale_decpoint = save;
218         return r;
219     }
220 
221     static size_t ld_sprint(char* str, int fmt, real x)
222     {
223         version(CRuntime_Microsoft)
224         {
225             return .ld_sprint(str, fmt, longdouble(x));
226         }
227         else
228         {
229             if ((cast(real)cast(ulong)x) == x)
230             {
231                 // ((1.5 -> 1 -> 1.0) == 1.5) is false
232                 // ((1.0 -> 1 -> 1.0) == 1.0) is true
233                 // see http://en.cppreference.com/w/cpp/io/c/fprintf
234                 char[5] sfmt = "%#Lg\0";
235                 sfmt[3] = cast(char)fmt;
236                 return sprintf(str, sfmt.ptr, x);
237             }
238             else
239             {
240                 char[4] sfmt = "%Lg\0";
241                 sfmt[2] = cast(char)fmt;
242                 return sprintf(str, sfmt.ptr, x);
243             }
244         }
245     }
246 
247     static void yl2x_impl(real* x, real* y, real* res)
248     {
249         version(DigitalMars)
250             *res = yl2x(*x, *y);
251     }
252 
253     static void yl2xp1_impl(real* x, real* y, real* res)
254     {
255         version(DigitalMars)
256             *res = yl2xp1(*x, *y);
257     }
258 
259     // Little endian
260     static void writelongLE(uint value, void* buffer)
261     {
262         auto p = cast(ubyte*)buffer;
263         p[3] = cast(ubyte)(value >> 24);
264         p[2] = cast(ubyte)(value >> 16);
265         p[1] = cast(ubyte)(value >> 8);
266         p[0] = cast(ubyte)(value);
267     }
268 
269     // Little endian
270     static uint readlongLE(void* buffer)
271     {
272         auto p = cast(ubyte*)buffer;
273         return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
274     }
275 
276     // Big endian
277     static void writelongBE(uint value, void* buffer)
278     {
279         auto p = cast(ubyte*)buffer;
280         p[0] = cast(ubyte)(value >> 24);
281         p[1] = cast(ubyte)(value >> 16);
282         p[2] = cast(ubyte)(value >> 8);
283         p[3] = cast(ubyte)(value);
284     }
285 
286     // Big endian
287     static uint readlongBE(void* buffer)
288     {
289         auto p = cast(ubyte*)buffer;
290         return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3];
291     }
292 
293     // Little endian
294     static uint readwordLE(void* buffer)
295     {
296         auto p = cast(ubyte*)buffer;
297         return (p[1] << 8) | p[0];
298     }
299 
300     // Big endian
301     static uint readwordBE(void* buffer)
302     {
303         auto p = cast(ubyte*)buffer;
304         return (p[0] << 8) | p[1];
305     }
306 
307     static void valcpy(void *dst, ulong val, size_t size)
308     {
309         switch (size)
310         {
311             case 1: *cast(ubyte *)dst = cast(ubyte)val; break;
312             case 2: *cast(ushort *)dst = cast(ushort)val; break;
313             case 4: *cast(uint *)dst = cast(uint)val; break;
314             case 8: *cast(ulong *)dst = cast(ulong)val; break;
315             default: assert(0);
316         }
317     }
318 }