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