xref: /aosp_15_r20/external/OpenCL-CTS/test_common/harness/os_helpers.cpp (revision 6467f958c7de8070b317fc65bcb0f6472e388d82)
1*6467f958SSadaf Ebrahimi //
2*6467f958SSadaf Ebrahimi // Copyright (c) 2017 The Khronos Group Inc.
3*6467f958SSadaf Ebrahimi //
4*6467f958SSadaf Ebrahimi // Licensed under the Apache License, Version 2.0 (the "License");
5*6467f958SSadaf Ebrahimi // you may not use this file except in compliance with the License.
6*6467f958SSadaf Ebrahimi // You may obtain a copy of the License at
7*6467f958SSadaf Ebrahimi //
8*6467f958SSadaf Ebrahimi //    http://www.apache.org/licenses/LICENSE-2.0
9*6467f958SSadaf Ebrahimi //
10*6467f958SSadaf Ebrahimi // Unless required by applicable law or agreed to in writing, software
11*6467f958SSadaf Ebrahimi // distributed under the License is distributed on an "AS IS" BASIS,
12*6467f958SSadaf Ebrahimi // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*6467f958SSadaf Ebrahimi // See the License for the specific language governing permissions and
14*6467f958SSadaf Ebrahimi // limitations under the License.
15*6467f958SSadaf Ebrahimi //
16*6467f958SSadaf Ebrahimi #include "os_helpers.h"
17*6467f958SSadaf Ebrahimi #include "errorHelpers.h"
18*6467f958SSadaf Ebrahimi 
19*6467f958SSadaf Ebrahimi // =================================================================================================
20*6467f958SSadaf Ebrahimi // C++ interface.
21*6467f958SSadaf Ebrahimi // =================================================================================================
22*6467f958SSadaf Ebrahimi 
23*6467f958SSadaf Ebrahimi #include <cerrno> // errno, error constants
24*6467f958SSadaf Ebrahimi #include <climits> // PATH_MAX
25*6467f958SSadaf Ebrahimi #include <cstdlib> // abort, _splitpath, _makepath
26*6467f958SSadaf Ebrahimi #include <cstring> // strdup, strerror_r
27*6467f958SSadaf Ebrahimi #include <sstream>
28*6467f958SSadaf Ebrahimi 
29*6467f958SSadaf Ebrahimi #include <vector>
30*6467f958SSadaf Ebrahimi 
31*6467f958SSadaf Ebrahimi #if defined(__ANDROID__)
32*6467f958SSadaf Ebrahimi #include <android/api-level.h>
33*6467f958SSadaf Ebrahimi #include "harness/mt19937.h"
34*6467f958SSadaf Ebrahimi #endif
35*6467f958SSadaf Ebrahimi 
36*6467f958SSadaf Ebrahimi #if !defined(_WIN32)
37*6467f958SSadaf Ebrahimi #if defined(__APPLE__)
38*6467f958SSadaf Ebrahimi #include <sys/sysctl.h>
39*6467f958SSadaf Ebrahimi #endif
40*6467f958SSadaf Ebrahimi #include <unistd.h>
41*6467f958SSadaf Ebrahimi #endif
42*6467f958SSadaf Ebrahimi 
43*6467f958SSadaf Ebrahimi 
44*6467f958SSadaf Ebrahimi #define CHECK_PTR(ptr)                                                         \
45*6467f958SSadaf Ebrahimi     if ((ptr) == NULL)                                                         \
46*6467f958SSadaf Ebrahimi     {                                                                          \
47*6467f958SSadaf Ebrahimi         abort();                                                               \
48*6467f958SSadaf Ebrahimi     }
49*6467f958SSadaf Ebrahimi 
50*6467f958SSadaf Ebrahimi typedef std::vector<char> buffer_t;
51*6467f958SSadaf Ebrahimi 
52*6467f958SSadaf Ebrahimi #if !defined(PATH_MAX)
53*6467f958SSadaf Ebrahimi #define PATH_MAX 1000
54*6467f958SSadaf Ebrahimi #endif
55*6467f958SSadaf Ebrahimi 
56*6467f958SSadaf Ebrahimi int const _size = PATH_MAX + 1; // Initial buffer size for path.
57*6467f958SSadaf Ebrahimi int const _count = 8; // How many times we will try to double buffer size.
58*6467f958SSadaf Ebrahimi 
59*6467f958SSadaf Ebrahimi // -------------------------------------------------------------------------------------------------
60*6467f958SSadaf Ebrahimi // MacOS X
61*6467f958SSadaf Ebrahimi // -------------------------------------------------------------------------------------------------
62*6467f958SSadaf Ebrahimi 
63*6467f958SSadaf Ebrahimi #if defined(__APPLE__)
64*6467f958SSadaf Ebrahimi 
65*6467f958SSadaf Ebrahimi 
66*6467f958SSadaf Ebrahimi #include <mach-o/dyld.h> // _NSGetExecutablePath
67*6467f958SSadaf Ebrahimi #include <libgen.h> // dirname
68*6467f958SSadaf Ebrahimi 
69*6467f958SSadaf Ebrahimi 
70*6467f958SSadaf Ebrahimi static std::string
_err_msg(int err,int level)71*6467f958SSadaf Ebrahimi _err_msg(int err, // Error number (e. g. errno).
72*6467f958SSadaf Ebrahimi          int level // Nesting level, for avoiding infinite recursion.
73*6467f958SSadaf Ebrahimi )
74*6467f958SSadaf Ebrahimi {
75*6467f958SSadaf Ebrahimi 
76*6467f958SSadaf Ebrahimi     /*
77*6467f958SSadaf Ebrahimi         There are 3 incompatible versions of strerror_r:
78*6467f958SSadaf Ebrahimi 
79*6467f958SSadaf Ebrahimi             char * strerror_r( int, char *, size_t );  // GNU version
80*6467f958SSadaf Ebrahimi             int    strerror_r( int, char *, size_t );  // BSD version
81*6467f958SSadaf Ebrahimi             int    strerror_r( int, char *, size_t );  // XSI version
82*6467f958SSadaf Ebrahimi 
83*6467f958SSadaf Ebrahimi         BSD version returns error code, while XSI version returns 0 or -1 and
84*6467f958SSadaf Ebrahimi        sets errno.
85*6467f958SSadaf Ebrahimi 
86*6467f958SSadaf Ebrahimi     */
87*6467f958SSadaf Ebrahimi 
88*6467f958SSadaf Ebrahimi     // BSD version of strerror_r.
89*6467f958SSadaf Ebrahimi     buffer_t buffer(100);
90*6467f958SSadaf Ebrahimi     int count = _count;
91*6467f958SSadaf Ebrahimi     for (;;)
92*6467f958SSadaf Ebrahimi     {
93*6467f958SSadaf Ebrahimi         int rc = strerror_r(err, &buffer.front(), buffer.size());
94*6467f958SSadaf Ebrahimi         if (rc == EINVAL)
95*6467f958SSadaf Ebrahimi         {
96*6467f958SSadaf Ebrahimi             // Error code is not recognized, but anyway we got the message.
97*6467f958SSadaf Ebrahimi             return &buffer.front();
98*6467f958SSadaf Ebrahimi         }
99*6467f958SSadaf Ebrahimi         else if (rc == ERANGE)
100*6467f958SSadaf Ebrahimi         {
101*6467f958SSadaf Ebrahimi             // Buffer is not enough.
102*6467f958SSadaf Ebrahimi             if (count > 0)
103*6467f958SSadaf Ebrahimi             {
104*6467f958SSadaf Ebrahimi                 // Enlarge the buffer.
105*6467f958SSadaf Ebrahimi                 --count;
106*6467f958SSadaf Ebrahimi                 buffer.resize(buffer.size() * 2);
107*6467f958SSadaf Ebrahimi             }
108*6467f958SSadaf Ebrahimi             else
109*6467f958SSadaf Ebrahimi             {
110*6467f958SSadaf Ebrahimi                 std::stringstream ostr;
111*6467f958SSadaf Ebrahimi                 ostr << "Error " << err << " "
112*6467f958SSadaf Ebrahimi                      << "(Getting error message failed: "
113*6467f958SSadaf Ebrahimi                      << "Buffer of " << buffer.size()
114*6467f958SSadaf Ebrahimi                      << " bytes is still too small"
115*6467f958SSadaf Ebrahimi                      << ")";
116*6467f958SSadaf Ebrahimi                 return ostr.str();
117*6467f958SSadaf Ebrahimi             }; // if
118*6467f958SSadaf Ebrahimi         }
119*6467f958SSadaf Ebrahimi         else if (rc == 0)
120*6467f958SSadaf Ebrahimi         {
121*6467f958SSadaf Ebrahimi             // We got the message.
122*6467f958SSadaf Ebrahimi             return &buffer.front();
123*6467f958SSadaf Ebrahimi         }
124*6467f958SSadaf Ebrahimi         else
125*6467f958SSadaf Ebrahimi         {
126*6467f958SSadaf Ebrahimi             std::stringstream ostr;
127*6467f958SSadaf Ebrahimi             ostr << "Error " << err << " "
128*6467f958SSadaf Ebrahimi                  << "(Getting error message failed: "
129*6467f958SSadaf Ebrahimi                  << (level < 2 ? _err_msg(rc, level + 1) : "Oops") << ")";
130*6467f958SSadaf Ebrahimi             return ostr.str();
131*6467f958SSadaf Ebrahimi         }; // if
132*6467f958SSadaf Ebrahimi     }; // forever
133*6467f958SSadaf Ebrahimi 
134*6467f958SSadaf Ebrahimi } // _err_msg
135*6467f958SSadaf Ebrahimi 
136*6467f958SSadaf Ebrahimi 
dir_sep()137*6467f958SSadaf Ebrahimi std::string dir_sep() { return "/"; } // dir_sep
138*6467f958SSadaf Ebrahimi 
139*6467f958SSadaf Ebrahimi 
exe_path()140*6467f958SSadaf Ebrahimi std::string exe_path()
141*6467f958SSadaf Ebrahimi {
142*6467f958SSadaf Ebrahimi     buffer_t path(_size);
143*6467f958SSadaf Ebrahimi     int count = _count;
144*6467f958SSadaf Ebrahimi     for (;;)
145*6467f958SSadaf Ebrahimi     {
146*6467f958SSadaf Ebrahimi         uint32_t size = path.size();
147*6467f958SSadaf Ebrahimi         int rc = _NSGetExecutablePath(&path.front(), &size);
148*6467f958SSadaf Ebrahimi         if (rc == 0)
149*6467f958SSadaf Ebrahimi         {
150*6467f958SSadaf Ebrahimi             break;
151*6467f958SSadaf Ebrahimi         }; // if
152*6467f958SSadaf Ebrahimi         if (count > 0)
153*6467f958SSadaf Ebrahimi         {
154*6467f958SSadaf Ebrahimi             --count;
155*6467f958SSadaf Ebrahimi             path.resize(size);
156*6467f958SSadaf Ebrahimi         }
157*6467f958SSadaf Ebrahimi         else
158*6467f958SSadaf Ebrahimi         {
159*6467f958SSadaf Ebrahimi             log_error("ERROR: Getting executable path failed: "
160*6467f958SSadaf Ebrahimi                       "_NSGetExecutablePath failed: Buffer of %lu bytes is "
161*6467f958SSadaf Ebrahimi                       "still too small\n",
162*6467f958SSadaf Ebrahimi                       (unsigned long)path.size());
163*6467f958SSadaf Ebrahimi             exit(2);
164*6467f958SSadaf Ebrahimi         }; // if
165*6467f958SSadaf Ebrahimi     }; // forever
166*6467f958SSadaf Ebrahimi     return &path.front();
167*6467f958SSadaf Ebrahimi } // exe_path
168*6467f958SSadaf Ebrahimi 
169*6467f958SSadaf Ebrahimi 
exe_dir()170*6467f958SSadaf Ebrahimi std::string exe_dir()
171*6467f958SSadaf Ebrahimi {
172*6467f958SSadaf Ebrahimi     std::string path = exe_path();
173*6467f958SSadaf Ebrahimi     // We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its
174*6467f958SSadaf Ebrahimi     // argument.
175*6467f958SSadaf Ebrahimi     buffer_t buffer(path.c_str(),
176*6467f958SSadaf Ebrahimi                     path.c_str() + path.size() + 1); // Copy with trailing zero.
177*6467f958SSadaf Ebrahimi     return dirname(&buffer.front());
178*6467f958SSadaf Ebrahimi } // exe_dir
179*6467f958SSadaf Ebrahimi 
180*6467f958SSadaf Ebrahimi 
181*6467f958SSadaf Ebrahimi #endif // __APPLE__
182*6467f958SSadaf Ebrahimi 
183*6467f958SSadaf Ebrahimi // -------------------------------------------------------------------------------------------------
184*6467f958SSadaf Ebrahimi // Linux
185*6467f958SSadaf Ebrahimi // -------------------------------------------------------------------------------------------------
186*6467f958SSadaf Ebrahimi 
187*6467f958SSadaf Ebrahimi #if defined(__linux__)
188*6467f958SSadaf Ebrahimi 
189*6467f958SSadaf Ebrahimi 
190*6467f958SSadaf Ebrahimi #include <cerrno> // errno
191*6467f958SSadaf Ebrahimi #include <libgen.h> // dirname
192*6467f958SSadaf Ebrahimi #include <unistd.h> // readlink
193*6467f958SSadaf Ebrahimi 
194*6467f958SSadaf Ebrahimi 
_err_msg(int err,int level)195*6467f958SSadaf Ebrahimi static std::string _err_msg(int err, int level)
196*6467f958SSadaf Ebrahimi {
197*6467f958SSadaf Ebrahimi 
198*6467f958SSadaf Ebrahimi     /*
199*6467f958SSadaf Ebrahimi         There are 3 incompatible versions of strerror_r:
200*6467f958SSadaf Ebrahimi 
201*6467f958SSadaf Ebrahimi             char * strerror_r( int, char *, size_t );  // GNU version
202*6467f958SSadaf Ebrahimi             int    strerror_r( int, char *, size_t );  // BSD version
203*6467f958SSadaf Ebrahimi             int    strerror_r( int, char *, size_t );  // XSI version
204*6467f958SSadaf Ebrahimi 
205*6467f958SSadaf Ebrahimi         BSD version returns error code, while XSI version returns 0 or -1 and
206*6467f958SSadaf Ebrahimi        sets errno.
207*6467f958SSadaf Ebrahimi 
208*6467f958SSadaf Ebrahimi     */
209*6467f958SSadaf Ebrahimi 
210*6467f958SSadaf Ebrahimi #if (defined(__ANDROID__) && __ANDROID_API__ < 23)                             \
211*6467f958SSadaf Ebrahimi     || ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE)
212*6467f958SSadaf Ebrahimi 
213*6467f958SSadaf Ebrahimi // XSI version of strerror_r.
214*6467f958SSadaf Ebrahimi #warning Not tested!
215*6467f958SSadaf Ebrahimi     buffer_t buffer(200);
216*6467f958SSadaf Ebrahimi     int count = _count;
217*6467f958SSadaf Ebrahimi     for (;;)
218*6467f958SSadaf Ebrahimi     {
219*6467f958SSadaf Ebrahimi         int rc = strerror_r(err, &buffer.front(), buffer.size());
220*6467f958SSadaf Ebrahimi         if (rc == -1)
221*6467f958SSadaf Ebrahimi         {
222*6467f958SSadaf Ebrahimi             int _err = errno;
223*6467f958SSadaf Ebrahimi             if (_err == ERANGE)
224*6467f958SSadaf Ebrahimi             {
225*6467f958SSadaf Ebrahimi                 if (count > 0)
226*6467f958SSadaf Ebrahimi                 {
227*6467f958SSadaf Ebrahimi                     // Enlarge the buffer.
228*6467f958SSadaf Ebrahimi                     --count;
229*6467f958SSadaf Ebrahimi                     buffer.resize(buffer.size() * 2);
230*6467f958SSadaf Ebrahimi                 }
231*6467f958SSadaf Ebrahimi                 else
232*6467f958SSadaf Ebrahimi                 {
233*6467f958SSadaf Ebrahimi                     std::stringstream ostr;
234*6467f958SSadaf Ebrahimi                     ostr << "Error " << err << " "
235*6467f958SSadaf Ebrahimi                          << "(Getting error message failed: "
236*6467f958SSadaf Ebrahimi                          << "Buffer of " << buffer.size()
237*6467f958SSadaf Ebrahimi                          << " bytes is still too small"
238*6467f958SSadaf Ebrahimi                          << ")";
239*6467f958SSadaf Ebrahimi                     return ostr.str();
240*6467f958SSadaf Ebrahimi                 }; // if
241*6467f958SSadaf Ebrahimi             }
242*6467f958SSadaf Ebrahimi             else
243*6467f958SSadaf Ebrahimi             {
244*6467f958SSadaf Ebrahimi                 std::stringstream ostr;
245*6467f958SSadaf Ebrahimi                 ostr << "Error " << err << " "
246*6467f958SSadaf Ebrahimi                      << "(Getting error message failed: "
247*6467f958SSadaf Ebrahimi                      << (level < 2 ? _err_msg(_err, level + 1) : "Oops") << ")";
248*6467f958SSadaf Ebrahimi                 return ostr.str();
249*6467f958SSadaf Ebrahimi             }; // if
250*6467f958SSadaf Ebrahimi         }
251*6467f958SSadaf Ebrahimi         else
252*6467f958SSadaf Ebrahimi         {
253*6467f958SSadaf Ebrahimi             // We got the message.
254*6467f958SSadaf Ebrahimi             return &buffer.front();
255*6467f958SSadaf Ebrahimi         }; // if
256*6467f958SSadaf Ebrahimi     }; // forever
257*6467f958SSadaf Ebrahimi 
258*6467f958SSadaf Ebrahimi #else
259*6467f958SSadaf Ebrahimi 
260*6467f958SSadaf Ebrahimi     // GNU version of strerror_r.
261*6467f958SSadaf Ebrahimi     char buffer[2000];
262*6467f958SSadaf Ebrahimi     return strerror_r(err, buffer, sizeof(buffer));
263*6467f958SSadaf Ebrahimi 
264*6467f958SSadaf Ebrahimi #endif
265*6467f958SSadaf Ebrahimi 
266*6467f958SSadaf Ebrahimi } // _err_msg
267*6467f958SSadaf Ebrahimi 
268*6467f958SSadaf Ebrahimi 
dir_sep()269*6467f958SSadaf Ebrahimi std::string dir_sep() { return "/"; } // dir_sep
270*6467f958SSadaf Ebrahimi 
271*6467f958SSadaf Ebrahimi 
exe_path()272*6467f958SSadaf Ebrahimi std::string exe_path()
273*6467f958SSadaf Ebrahimi {
274*6467f958SSadaf Ebrahimi 
275*6467f958SSadaf Ebrahimi     static std::string const exe = "/proc/self/exe";
276*6467f958SSadaf Ebrahimi 
277*6467f958SSadaf Ebrahimi     buffer_t path(_size);
278*6467f958SSadaf Ebrahimi     int count = _count; // Max number of iterations.
279*6467f958SSadaf Ebrahimi 
280*6467f958SSadaf Ebrahimi     for (;;)
281*6467f958SSadaf Ebrahimi     {
282*6467f958SSadaf Ebrahimi 
283*6467f958SSadaf Ebrahimi         ssize_t len = readlink(exe.c_str(), &path.front(), path.size());
284*6467f958SSadaf Ebrahimi 
285*6467f958SSadaf Ebrahimi         if (len < 0)
286*6467f958SSadaf Ebrahimi         {
287*6467f958SSadaf Ebrahimi             // Oops.
288*6467f958SSadaf Ebrahimi             int err = errno;
289*6467f958SSadaf Ebrahimi             log_error("ERROR: Getting executable path failed: "
290*6467f958SSadaf Ebrahimi                       "Reading symlink `%s' failed: %s\n",
291*6467f958SSadaf Ebrahimi                       exe.c_str(), err_msg(err).c_str());
292*6467f958SSadaf Ebrahimi             exit(2);
293*6467f958SSadaf Ebrahimi         }; // if
294*6467f958SSadaf Ebrahimi 
295*6467f958SSadaf Ebrahimi         if (static_cast<size_t>(len) < path.size())
296*6467f958SSadaf Ebrahimi         {
297*6467f958SSadaf Ebrahimi             // We got the path.
298*6467f958SSadaf Ebrahimi             path.resize(len);
299*6467f958SSadaf Ebrahimi             break;
300*6467f958SSadaf Ebrahimi         }; // if
301*6467f958SSadaf Ebrahimi 
302*6467f958SSadaf Ebrahimi         // Oops, buffer is too small.
303*6467f958SSadaf Ebrahimi         if (count > 0)
304*6467f958SSadaf Ebrahimi         {
305*6467f958SSadaf Ebrahimi             --count;
306*6467f958SSadaf Ebrahimi             // Enlarge the buffer.
307*6467f958SSadaf Ebrahimi             path.resize(path.size() * 2);
308*6467f958SSadaf Ebrahimi         }
309*6467f958SSadaf Ebrahimi         else
310*6467f958SSadaf Ebrahimi         {
311*6467f958SSadaf Ebrahimi             log_error("ERROR: Getting executable path failed: "
312*6467f958SSadaf Ebrahimi                       "Reading symlink `%s' failed: Buffer of %lu bytes is "
313*6467f958SSadaf Ebrahimi                       "still too small\n",
314*6467f958SSadaf Ebrahimi                       exe.c_str(), (unsigned long)path.size());
315*6467f958SSadaf Ebrahimi             exit(2);
316*6467f958SSadaf Ebrahimi         }; // if
317*6467f958SSadaf Ebrahimi 
318*6467f958SSadaf Ebrahimi     }; // forever
319*6467f958SSadaf Ebrahimi 
320*6467f958SSadaf Ebrahimi     return std::string(&path.front(), path.size());
321*6467f958SSadaf Ebrahimi 
322*6467f958SSadaf Ebrahimi } // exe_path
323*6467f958SSadaf Ebrahimi 
324*6467f958SSadaf Ebrahimi 
exe_dir()325*6467f958SSadaf Ebrahimi std::string exe_dir()
326*6467f958SSadaf Ebrahimi {
327*6467f958SSadaf Ebrahimi     std::string path = exe_path();
328*6467f958SSadaf Ebrahimi     // We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its
329*6467f958SSadaf Ebrahimi     // argument.
330*6467f958SSadaf Ebrahimi     buffer_t buffer(path.c_str(),
331*6467f958SSadaf Ebrahimi                     path.c_str() + path.size() + 1); // Copy with trailing zero.
332*6467f958SSadaf Ebrahimi     return dirname(&buffer.front());
333*6467f958SSadaf Ebrahimi } // exe_dir
334*6467f958SSadaf Ebrahimi 
335*6467f958SSadaf Ebrahimi #endif // __linux__
336*6467f958SSadaf Ebrahimi 
337*6467f958SSadaf Ebrahimi // -------------------------------------------------------------------------------------------------
338*6467f958SSadaf Ebrahimi // MS Windows
339*6467f958SSadaf Ebrahimi // -------------------------------------------------------------------------------------------------
340*6467f958SSadaf Ebrahimi 
341*6467f958SSadaf Ebrahimi #if defined(_WIN32)
342*6467f958SSadaf Ebrahimi 
343*6467f958SSadaf Ebrahimi 
344*6467f958SSadaf Ebrahimi #include <windows.h>
345*6467f958SSadaf Ebrahimi 
346*6467f958SSadaf Ebrahimi #include <cctype>
347*6467f958SSadaf Ebrahimi #include <algorithm>
348*6467f958SSadaf Ebrahimi 
349*6467f958SSadaf Ebrahimi 
_err_msg(int err,int level)350*6467f958SSadaf Ebrahimi static std::string _err_msg(int err, int level)
351*6467f958SSadaf Ebrahimi {
352*6467f958SSadaf Ebrahimi 
353*6467f958SSadaf Ebrahimi     std::string msg;
354*6467f958SSadaf Ebrahimi 
355*6467f958SSadaf Ebrahimi     LPSTR buffer = NULL;
356*6467f958SSadaf Ebrahimi     DWORD flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
357*6467f958SSadaf Ebrahimi         | FORMAT_MESSAGE_IGNORE_INSERTS;
358*6467f958SSadaf Ebrahimi 
359*6467f958SSadaf Ebrahimi     DWORD len = FormatMessageA(flags, NULL, err, LANG_USER_DEFAULT,
360*6467f958SSadaf Ebrahimi                                reinterpret_cast<LPSTR>(&buffer), 0, NULL);
361*6467f958SSadaf Ebrahimi 
362*6467f958SSadaf Ebrahimi     if (buffer == NULL || len == 0)
363*6467f958SSadaf Ebrahimi     {
364*6467f958SSadaf Ebrahimi 
365*6467f958SSadaf Ebrahimi         int _err = GetLastError();
366*6467f958SSadaf Ebrahimi         char str[1024] = { 0 };
367*6467f958SSadaf Ebrahimi         snprintf(str, sizeof(str),
368*6467f958SSadaf Ebrahimi                  "Error 0x%08x (Getting error message failed: %s )", err,
369*6467f958SSadaf Ebrahimi                  (level < 2 ? _err_msg(_err, level + 1).c_str() : "Oops"));
370*6467f958SSadaf Ebrahimi         msg = std::string(str);
371*6467f958SSadaf Ebrahimi     }
372*6467f958SSadaf Ebrahimi     else
373*6467f958SSadaf Ebrahimi     {
374*6467f958SSadaf Ebrahimi 
375*6467f958SSadaf Ebrahimi         // Trim trailing whitespace (including `\r' and `\n').
376*6467f958SSadaf Ebrahimi         while (len > 0 && isspace(buffer[len - 1]))
377*6467f958SSadaf Ebrahimi         {
378*6467f958SSadaf Ebrahimi             --len;
379*6467f958SSadaf Ebrahimi         }; // while
380*6467f958SSadaf Ebrahimi 
381*6467f958SSadaf Ebrahimi         // Drop trailing full stop.
382*6467f958SSadaf Ebrahimi         if (len > 0 && buffer[len - 1] == '.')
383*6467f958SSadaf Ebrahimi         {
384*6467f958SSadaf Ebrahimi             --len;
385*6467f958SSadaf Ebrahimi         }; // if
386*6467f958SSadaf Ebrahimi 
387*6467f958SSadaf Ebrahimi         msg.assign(buffer, len);
388*6467f958SSadaf Ebrahimi 
389*6467f958SSadaf Ebrahimi     }; // if
390*6467f958SSadaf Ebrahimi 
391*6467f958SSadaf Ebrahimi     if (buffer != NULL)
392*6467f958SSadaf Ebrahimi     {
393*6467f958SSadaf Ebrahimi         LocalFree(buffer);
394*6467f958SSadaf Ebrahimi     }; // if
395*6467f958SSadaf Ebrahimi 
396*6467f958SSadaf Ebrahimi     return msg;
397*6467f958SSadaf Ebrahimi 
398*6467f958SSadaf Ebrahimi } // _get_err_msg
399*6467f958SSadaf Ebrahimi 
400*6467f958SSadaf Ebrahimi 
dir_sep()401*6467f958SSadaf Ebrahimi std::string dir_sep() { return "\\"; } // dir_sep
402*6467f958SSadaf Ebrahimi 
403*6467f958SSadaf Ebrahimi 
exe_path()404*6467f958SSadaf Ebrahimi std::string exe_path()
405*6467f958SSadaf Ebrahimi {
406*6467f958SSadaf Ebrahimi 
407*6467f958SSadaf Ebrahimi     buffer_t path(_size);
408*6467f958SSadaf Ebrahimi     int count = _count;
409*6467f958SSadaf Ebrahimi 
410*6467f958SSadaf Ebrahimi     for (;;)
411*6467f958SSadaf Ebrahimi     {
412*6467f958SSadaf Ebrahimi 
413*6467f958SSadaf Ebrahimi         DWORD len = GetModuleFileNameA(NULL, &path.front(),
414*6467f958SSadaf Ebrahimi                                        static_cast<DWORD>(path.size()));
415*6467f958SSadaf Ebrahimi 
416*6467f958SSadaf Ebrahimi         if (len == 0)
417*6467f958SSadaf Ebrahimi         {
418*6467f958SSadaf Ebrahimi             int err = GetLastError();
419*6467f958SSadaf Ebrahimi             log_error("ERROR: Getting executable path failed: %s\n",
420*6467f958SSadaf Ebrahimi                       err_msg(err).c_str());
421*6467f958SSadaf Ebrahimi             exit(2);
422*6467f958SSadaf Ebrahimi         }; // if
423*6467f958SSadaf Ebrahimi 
424*6467f958SSadaf Ebrahimi         if (len < path.size())
425*6467f958SSadaf Ebrahimi         {
426*6467f958SSadaf Ebrahimi             path.resize(len);
427*6467f958SSadaf Ebrahimi             break;
428*6467f958SSadaf Ebrahimi         }; // if
429*6467f958SSadaf Ebrahimi 
430*6467f958SSadaf Ebrahimi         // Buffer too small.
431*6467f958SSadaf Ebrahimi         if (count > 0)
432*6467f958SSadaf Ebrahimi         {
433*6467f958SSadaf Ebrahimi             --count;
434*6467f958SSadaf Ebrahimi             path.resize(path.size() * 2);
435*6467f958SSadaf Ebrahimi         }
436*6467f958SSadaf Ebrahimi         else
437*6467f958SSadaf Ebrahimi         {
438*6467f958SSadaf Ebrahimi             log_error("ERROR: Getting executable path failed: "
439*6467f958SSadaf Ebrahimi                       "Buffer of %lu bytes is still too small\n",
440*6467f958SSadaf Ebrahimi                       (unsigned long)path.size());
441*6467f958SSadaf Ebrahimi             exit(2);
442*6467f958SSadaf Ebrahimi         }; // if
443*6467f958SSadaf Ebrahimi 
444*6467f958SSadaf Ebrahimi     }; // forever
445*6467f958SSadaf Ebrahimi 
446*6467f958SSadaf Ebrahimi     return std::string(&path.front(), path.size());
447*6467f958SSadaf Ebrahimi 
448*6467f958SSadaf Ebrahimi } // exe_path
449*6467f958SSadaf Ebrahimi 
450*6467f958SSadaf Ebrahimi 
exe_dir()451*6467f958SSadaf Ebrahimi std::string exe_dir()
452*6467f958SSadaf Ebrahimi {
453*6467f958SSadaf Ebrahimi 
454*6467f958SSadaf Ebrahimi     std::string exe = exe_path();
455*6467f958SSadaf Ebrahimi     int count = 0;
456*6467f958SSadaf Ebrahimi 
457*6467f958SSadaf Ebrahimi     // Splitting path into components.
458*6467f958SSadaf Ebrahimi     buffer_t drv(_MAX_DRIVE);
459*6467f958SSadaf Ebrahimi     buffer_t dir(_MAX_DIR);
460*6467f958SSadaf Ebrahimi     count = _count;
461*6467f958SSadaf Ebrahimi #if defined(_MSC_VER)
462*6467f958SSadaf Ebrahimi     for (;;)
463*6467f958SSadaf Ebrahimi     {
464*6467f958SSadaf Ebrahimi         int rc =
465*6467f958SSadaf Ebrahimi             _splitpath_s(exe.c_str(), &drv.front(), drv.size(), &dir.front(),
466*6467f958SSadaf Ebrahimi                          dir.size(), NULL, 0, // We need neither name
467*6467f958SSadaf Ebrahimi                          NULL, 0 // nor extension
468*6467f958SSadaf Ebrahimi             );
469*6467f958SSadaf Ebrahimi         if (rc == 0)
470*6467f958SSadaf Ebrahimi         {
471*6467f958SSadaf Ebrahimi             break;
472*6467f958SSadaf Ebrahimi         }
473*6467f958SSadaf Ebrahimi         else if (rc == ERANGE)
474*6467f958SSadaf Ebrahimi         {
475*6467f958SSadaf Ebrahimi             if (count > 0)
476*6467f958SSadaf Ebrahimi             {
477*6467f958SSadaf Ebrahimi                 --count;
478*6467f958SSadaf Ebrahimi                 // Buffer is too small, but it is not clear which one.
479*6467f958SSadaf Ebrahimi                 // So we have to enlarge all.
480*6467f958SSadaf Ebrahimi                 drv.resize(drv.size() * 2);
481*6467f958SSadaf Ebrahimi                 dir.resize(dir.size() * 2);
482*6467f958SSadaf Ebrahimi             }
483*6467f958SSadaf Ebrahimi             else
484*6467f958SSadaf Ebrahimi             {
485*6467f958SSadaf Ebrahimi                 log_error("ERROR: Getting executable path failed: "
486*6467f958SSadaf Ebrahimi                           "Splitting path `%s' to components failed: "
487*6467f958SSadaf Ebrahimi                           "Buffers of %lu and %lu bytes are still too small\n",
488*6467f958SSadaf Ebrahimi                           exe.c_str(), (unsigned long)drv.size(),
489*6467f958SSadaf Ebrahimi                           (unsigned long)dir.size());
490*6467f958SSadaf Ebrahimi                 exit(2);
491*6467f958SSadaf Ebrahimi             }; // if
492*6467f958SSadaf Ebrahimi         }
493*6467f958SSadaf Ebrahimi         else
494*6467f958SSadaf Ebrahimi         {
495*6467f958SSadaf Ebrahimi             log_error("ERROR: Getting executable path failed: "
496*6467f958SSadaf Ebrahimi                       "Splitting path `%s' to components failed: %s\n",
497*6467f958SSadaf Ebrahimi                       exe.c_str(), err_msg(rc).c_str());
498*6467f958SSadaf Ebrahimi             exit(2);
499*6467f958SSadaf Ebrahimi         }; // if
500*6467f958SSadaf Ebrahimi     }; // forever
501*6467f958SSadaf Ebrahimi 
502*6467f958SSadaf Ebrahimi #else // __MINGW32__
503*6467f958SSadaf Ebrahimi 
504*6467f958SSadaf Ebrahimi     // MinGW does not have the "secure" _splitpath_s, use the insecure version
505*6467f958SSadaf Ebrahimi     // instead.
506*6467f958SSadaf Ebrahimi     _splitpath(exe.c_str(), &drv.front(), &dir.front(),
507*6467f958SSadaf Ebrahimi                NULL, // We need neither name
508*6467f958SSadaf Ebrahimi                NULL // nor extension
509*6467f958SSadaf Ebrahimi     );
510*6467f958SSadaf Ebrahimi #endif // __MINGW32__
511*6467f958SSadaf Ebrahimi 
512*6467f958SSadaf Ebrahimi     // Combining components back to path.
513*6467f958SSadaf Ebrahimi     // I failed with "secure" `_makepath_s'. If buffer is too small, instead of
514*6467f958SSadaf Ebrahimi     // returning ERANGE, `_makepath_s' pops up dialog box and offers to debug
515*6467f958SSadaf Ebrahimi     // the program. D'oh! So let us try to guess the size of result and go with
516*6467f958SSadaf Ebrahimi     // insecure `_makepath'.
517*6467f958SSadaf Ebrahimi     buffer_t path(std::max(drv.size() + dir.size(), size_t(_MAX_PATH)) + 10);
518*6467f958SSadaf Ebrahimi     _makepath(&path.front(), &drv.front(), &dir.front(), NULL, NULL);
519*6467f958SSadaf Ebrahimi 
520*6467f958SSadaf Ebrahimi     return &path.front();
521*6467f958SSadaf Ebrahimi 
522*6467f958SSadaf Ebrahimi } // exe_dir
523*6467f958SSadaf Ebrahimi 
524*6467f958SSadaf Ebrahimi 
525*6467f958SSadaf Ebrahimi #endif // _WIN32
526*6467f958SSadaf Ebrahimi 
527*6467f958SSadaf Ebrahimi 
err_msg(int err)528*6467f958SSadaf Ebrahimi std::string err_msg(int err) { return _err_msg(err, 0); } // err_msg
529*6467f958SSadaf Ebrahimi 
530*6467f958SSadaf Ebrahimi 
531*6467f958SSadaf Ebrahimi // =================================================================================================
532*6467f958SSadaf Ebrahimi // C interface.
533*6467f958SSadaf Ebrahimi // =================================================================================================
534*6467f958SSadaf Ebrahimi 
535*6467f958SSadaf Ebrahimi 
get_err_msg(int err)536*6467f958SSadaf Ebrahimi char* get_err_msg(int err)
537*6467f958SSadaf Ebrahimi {
538*6467f958SSadaf Ebrahimi     char* msg = strdup(err_msg(err).c_str());
539*6467f958SSadaf Ebrahimi     CHECK_PTR(msg);
540*6467f958SSadaf Ebrahimi     return msg;
541*6467f958SSadaf Ebrahimi } // get_err_msg
542*6467f958SSadaf Ebrahimi 
543*6467f958SSadaf Ebrahimi 
get_dir_sep()544*6467f958SSadaf Ebrahimi char* get_dir_sep()
545*6467f958SSadaf Ebrahimi {
546*6467f958SSadaf Ebrahimi     char* sep = strdup(dir_sep().c_str());
547*6467f958SSadaf Ebrahimi     CHECK_PTR(sep);
548*6467f958SSadaf Ebrahimi     return sep;
549*6467f958SSadaf Ebrahimi } // get_dir_sep
550*6467f958SSadaf Ebrahimi 
551*6467f958SSadaf Ebrahimi 
get_exe_path()552*6467f958SSadaf Ebrahimi char* get_exe_path()
553*6467f958SSadaf Ebrahimi {
554*6467f958SSadaf Ebrahimi     char* path = strdup(exe_path().c_str());
555*6467f958SSadaf Ebrahimi     CHECK_PTR(path);
556*6467f958SSadaf Ebrahimi     return path;
557*6467f958SSadaf Ebrahimi } // get_exe_path
558*6467f958SSadaf Ebrahimi 
559*6467f958SSadaf Ebrahimi 
get_exe_dir()560*6467f958SSadaf Ebrahimi char* get_exe_dir()
561*6467f958SSadaf Ebrahimi {
562*6467f958SSadaf Ebrahimi     char* dir = strdup(exe_dir().c_str());
563*6467f958SSadaf Ebrahimi     CHECK_PTR(dir);
564*6467f958SSadaf Ebrahimi     return dir;
565*6467f958SSadaf Ebrahimi } // get_exe_dir
566*6467f958SSadaf Ebrahimi 
567*6467f958SSadaf Ebrahimi 
get_temp_filename()568*6467f958SSadaf Ebrahimi char* get_temp_filename()
569*6467f958SSadaf Ebrahimi {
570*6467f958SSadaf Ebrahimi     char gFileName[256] = "";
571*6467f958SSadaf Ebrahimi     // Create a unique temporary file to allow parallel executed tests.
572*6467f958SSadaf Ebrahimi #if (defined(__linux__) || defined(__APPLE__)) && (!defined(__ANDROID__))
573*6467f958SSadaf Ebrahimi     sprintf(gFileName, "/tmp/tmpfile.XXXXXX");
574*6467f958SSadaf Ebrahimi     int fd = mkstemp(gFileName);
575*6467f958SSadaf Ebrahimi     if (fd == -1) return strdup(gFileName);
576*6467f958SSadaf Ebrahimi     close(fd);
577*6467f958SSadaf Ebrahimi #elif defined(_WIN32)
578*6467f958SSadaf Ebrahimi     UINT ret = GetTempFileName(".", "tmp", 0, gFileName);
579*6467f958SSadaf Ebrahimi     if (ret == 0) return gFileName;
580*6467f958SSadaf Ebrahimi #else
581*6467f958SSadaf Ebrahimi     MTdata d = init_genrand((cl_uint)time(NULL));
582*6467f958SSadaf Ebrahimi     sprintf(gFileName, "tmpfile.%u", genrand_int32(d));
583*6467f958SSadaf Ebrahimi #endif
584*6467f958SSadaf Ebrahimi 
585*6467f958SSadaf Ebrahimi     char* fn = strdup(gFileName);
586*6467f958SSadaf Ebrahimi     CHECK_PTR(fn);
587*6467f958SSadaf Ebrahimi     return fn;
588*6467f958SSadaf Ebrahimi }
589*6467f958SSadaf Ebrahimi 
590*6467f958SSadaf Ebrahimi 
591*6467f958SSadaf Ebrahimi // end of file //
592