1 /**
2  * Portable routines for functions that have different implementations on different platforms.
3  *
4  * Copyright: Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
5  * Authors:   Walter Bright, https://www.digitalmars.com
6  * License:   $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/root/port.d, root/_port.d)
8  * Documentation:  https://dlang.org/phobos/dmd_root_port.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/root/port.d
10  */
11 
12 module dmd.root.port;
13 
14 import core.stdc.ctype;
15 import core.stdc.errno;
16 import core.stdc.string;
17 import core.stdc.stdint;
18 import core.stdc.stdio;
19 import core.stdc.stdlib;
20 
21 nothrow @nogc:
22 
23 private extern (C)
24 {
25     version(CRuntime_DigitalMars) __gshared extern const(char)* __locale_decpoint;
26 
27     version(CRuntime_Microsoft)
28     {
29         enum _OVERFLOW  = 3;   /* overflow range error */
30         enum _UNDERFLOW = 4;   /* underflow range error */
31 
32         int _atoflt(float*  value, const(char)* str);
33         int _atodbl(double* value, const(char)* str);
34     }
35 }
36 
37 extern (C++) struct Port
38 {
39     nothrow @nogc:
40 
41     static int memicmp(scope const char* s1, scope const char* s2, size_t n) pure
42     {
43         int result = 0;
44 
45         foreach (i; 0 .. n)
46         {
47             char c1 = s1[i];
48             char c2 = s2[i];
49 
50             result = c1 - c2;
51             if (result)
52             {
53                 result = toupper(c1) - toupper(c2);
54                 if (result)
55                     break;
56             }
57         }
58         return result;
59     }
60 
61     static char* strupr(char* s) pure
62     {
63         char* t = s;
64 
65         while (*s)
66         {
67             *s = cast(char)toupper(*s);
68             s++;
69         }
70 
71         return t;
72     }
73     private extern (D) static bool resultOutOfRange(FloatingType)(const FloatingType x, const int errnoValue)
74     {
75         import core.stdc.math : HUGE_VAL, HUGE_VALF;
76         static if (is(FloatingType == double))
77             const FloatingType hugeVal = HUGE_VAL;
78         else static if (is(FloatingType == float))
79             const FloatingType hugeVal = HUGE_VALF;
80         else static assert(0, "This function does not support " ~ FloatingType);
81 
82         if (errnoValue == ERANGE)
83         {
84             return x == hugeVal || x == 0.0f;
85         }
86         return false;
87     }
88     static bool isFloat32LiteralOutOfRange(scope const(char)* s)
89     {
90         errno = 0;
91         version (CRuntime_DigitalMars)
92         {
93             auto save = __locale_decpoint;
94             __locale_decpoint = ".";
95             scope(exit)
96                 __locale_decpoint = save;
97         }
98         version (CRuntime_Microsoft)
99         {
100             float r;
101             int res = _atoflt(&r, s);
102             if (res == _UNDERFLOW || res == _OVERFLOW)
103                 errno = ERANGE;
104             return errno == ERANGE;
105         }
106         else
107         {
108             const result = strtof(s, null);
109             return resultOutOfRange(result, errno);
110         }
111     }
112 
113     static bool isFloat64LiteralOutOfRange(scope const(char)* s)
114     {
115         errno = 0;
116         version (CRuntime_DigitalMars)
117         {
118             auto save = __locale_decpoint;
119             __locale_decpoint = ".";
120             scope(exit)
121                 __locale_decpoint = save;
122         }
123         version (CRuntime_Microsoft)
124         {
125             double r;
126             int res = _atodbl(&r, s);
127             if (res == _UNDERFLOW || res == _OVERFLOW)
128                 errno = ERANGE;
129             return errno == ERANGE;
130         }
131         else
132         {
133             const result = strtod(s, null);
134             return resultOutOfRange(result, errno);
135         }
136     }
137 
138     // Little endian
139     static void writelongLE(uint value, scope void* buffer) pure
140     {
141         auto p = cast(ubyte*)buffer;
142         p[3] = cast(ubyte)(value >> 24);
143         p[2] = cast(ubyte)(value >> 16);
144         p[1] = cast(ubyte)(value >> 8);
145         p[0] = cast(ubyte)(value);
146     }
147 
148     // Little endian
149     static uint readlongLE(scope const void* buffer) pure
150     {
151         auto p = cast(const ubyte*)buffer;
152         return (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
153     }
154 
155     // Big endian
156     static void writelongBE(uint value, scope void* buffer) pure
157     {
158         auto p = cast(ubyte*)buffer;
159         p[0] = cast(ubyte)(value >> 24);
160         p[1] = cast(ubyte)(value >> 16);
161         p[2] = cast(ubyte)(value >> 8);
162         p[3] = cast(ubyte)(value);
163     }
164 
165     // Big endian
166     static uint readlongBE(scope const void* buffer) pure
167     {
168         auto p = cast(const ubyte*)buffer;
169         return (((((p[0] << 8) | p[1]) << 8) | p[2]) << 8) | p[3];
170     }
171 
172     // Little endian
173     static uint readwordLE(scope const void* buffer) pure
174     {
175         auto p = cast(const ubyte*)buffer;
176         return (p[1] << 8) | p[0];
177     }
178 
179     // Big endian
180     static uint readwordBE(scope const void* buffer) pure
181     {
182         auto p = cast(const ubyte*)buffer;
183         return (p[0] << 8) | p[1];
184     }
185 
186     static void valcpy(scope void *dst, uint64_t val, size_t size) pure
187     {
188         assert((cast(size_t)dst) % size == 0);
189         switch (size)
190         {
191             case 1: *cast(ubyte *)dst = cast(ubyte)val; break;
192             case 2: *cast(ushort *)dst = cast(ushort)val; break;
193             case 4: *cast(uint *)dst = cast(uint)val; break;
194             case 8: *cast(ulong *)dst = cast(ulong)val; break;
195             default: assert(0);
196         }
197     }
198 }