Porting: Refactor initalizePaths()
[oweals/minetest.git] / src / porting.h
1 /*
2 Minetest
3 Copyright (C) 2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published by
7 the Free Software Foundation; either version 2.1 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License along
16 with this program; if not, write to the Free Software Foundation, Inc.,
17 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
20 /*
21         Random portability stuff
22 */
23
24 #ifndef PORTING_HEADER
25 #define PORTING_HEADER
26
27 #ifdef _WIN32
28         #ifdef _WIN32_WINNT
29                 #undef _WIN32_WINNT
30         #endif
31         #define _WIN32_WINNT 0x0501 // We need to do this before any other headers
32                 // because those might include sdkddkver.h which defines _WIN32_WINNT if not already set
33 #endif
34
35 #include <string>
36 #include <vector>
37 #include "irrlicht.h"
38 #include "irrlichttypes.h" // u32
39 #include "irrlichttypes_extrabloated.h"
40 #include "debug.h"
41 #include "constants.h"
42 #include "gettime.h"
43 #include "threads.h"
44
45 #ifdef _MSC_VER
46         #define SWPRINTF_CHARSTRING L"%S"
47 #else
48         #define SWPRINTF_CHARSTRING L"%s"
49 #endif
50
51 //currently not needed
52 //template<typename T> struct alignment_trick { char c; T member; };
53 //#define ALIGNOF(type) offsetof (alignment_trick<type>, member)
54
55 #ifdef _WIN32
56         #include <windows.h>
57
58         #define sleep_ms(x) Sleep(x)
59 #else
60         #include <unistd.h>
61         #include <stdint.h> //for uintptr_t
62
63 #if (defined(linux) || defined(__linux) || defined(__GNU__)) && !defined(_GNU_SOURCE)
64                 #define _GNU_SOURCE
65         #endif
66
67         #include <sched.h>
68
69         #ifdef __FreeBSD__
70                 #include <pthread_np.h>
71                 typedef cpuset_t cpu_set_t;
72         #elif defined(__sun) || defined(sun)
73                 #include <sys/types.h>
74                 #include <sys/processor.h>
75         #elif defined(_AIX)
76                 #include <sys/processor.h>
77         #elif __APPLE__
78                 #include <mach/mach_init.h>
79                 #include <mach/thread_policy.h>
80         #endif
81
82         #define sleep_ms(x) usleep(x*1000)
83
84         #define THREAD_PRIORITY_LOWEST       0
85         #define THREAD_PRIORITY_BELOW_NORMAL 1
86         #define THREAD_PRIORITY_NORMAL       2
87         #define THREAD_PRIORITY_ABOVE_NORMAL 3
88         #define THREAD_PRIORITY_HIGHEST      4
89 #endif
90
91 #ifdef _MSC_VER
92         #define ALIGNOF(x) __alignof(x)
93         #define strtok_r(x, y, z) strtok_s(x, y, z)
94         #define strtof(x, y) (float)strtod(x, y)
95         #define strtoll(x, y, z) _strtoi64(x, y, z)
96         #define strtoull(x, y, z) _strtoui64(x, y, z)
97         #define strcasecmp(x, y) stricmp(x, y)
98         #define strncasecmp(x, y, n) strnicmp(x, y, n)
99 #else
100         #define ALIGNOF(x) __alignof__(x)
101 #endif
102
103 #ifdef __MINGW32__
104         #define strtok_r(x, y, z) mystrtok_r(x, y, z)
105 #endif
106
107 // strlcpy is missing from glibc.  thanks a lot, drepper.
108 // strlcpy is also missing from AIX and HP-UX because they aim to be weird.
109 // We can't simply alias strlcpy to MSVC's strcpy_s, since strcpy_s by
110 // default raises an assertion error and aborts the program if the buffer is
111 // too small.
112 #if defined(__FreeBSD__) || defined(__NetBSD__)    || \
113         defined(__OpenBSD__) || defined(__DragonFly__) || \
114         defined(__APPLE__)   ||                           \
115         defined(__sun)       || defined(sun)           || \
116         defined(__QNX__)     || defined(__QNXNTO__)
117         #define HAVE_STRLCPY
118 #endif
119
120 // So we need to define our own.
121 #ifndef HAVE_STRLCPY
122         #define strlcpy(d, s, n) mystrlcpy(d, s, n)
123 #endif
124
125 #define PADDING(x, y) ((ALIGNOF(y) - ((uintptr_t)(x) & (ALIGNOF(y) - 1))) & (ALIGNOF(y) - 1))
126
127 #if defined(__APPLE__)
128         #include <mach-o/dyld.h>
129         #include <CoreFoundation/CoreFoundation.h>
130 #endif
131
132 namespace porting
133 {
134
135 /*
136         Signal handler (grabs Ctrl-C on POSIX systems)
137 */
138
139 void signal_handler_init(void);
140 // Returns a pointer to a bool.
141 // When the bool is true, program should quit.
142 bool * signal_handler_killstatus(void);
143
144 /*
145         Path of static data directory.
146 */
147 extern std::string path_share;
148
149 /*
150         Directory for storing user data. Examples:
151         Windows: "C:\Documents and Settings\user\Application Data\<PROJECT_NAME>"
152         Linux: "~/.<PROJECT_NAME>"
153         Mac: "~/Library/Application Support/<PROJECT_NAME>"
154 */
155 extern std::string path_user;
156
157 /*
158         Get full path of stuff in data directory.
159         Example: "stone.png" -> "../data/stone.png"
160 */
161 std::string getDataPath(const char *subpath);
162
163 /*
164         Initialize path_share and path_user.
165 */
166 void initializePaths();
167
168 /*
169         Get number of online processors in the system.
170 */
171 int getNumberOfProcessors();
172
173 /*
174         Set a thread's affinity to a particular processor.
175 */
176 bool threadBindToProcessor(threadid_t tid, int pnumber);
177
178 /*
179         Set a thread's priority.
180 */
181 bool threadSetPriority(threadid_t tid, int prio);
182
183 /*
184         Return system information
185         e.g. "Linux/3.12.7 x86_64"
186 */
187 std::string get_sysinfo();
188
189 void initIrrlicht(irr::IrrlichtDevice * );
190
191 /*
192         Resolution is 10-20ms.
193         Remember to check for overflows.
194         Overflow can occur at any value higher than 10000000.
195 */
196 #ifdef _WIN32 // Windows
197 #ifndef _WIN32_WINNT
198         #define _WIN32_WINNT 0x0501
199 #endif
200         #include <windows.h>
201
202         inline u32 getTimeS()
203         {
204                 return GetTickCount() / 1000;
205         }
206
207         inline u32 getTimeMs()
208         {
209                 return GetTickCount();
210         }
211
212         inline u32 getTimeUs()
213         {
214                 LARGE_INTEGER freq, t;
215                 QueryPerformanceFrequency(&freq);
216                 QueryPerformanceCounter(&t);
217                 return (double)(t.QuadPart) / ((double)(freq.QuadPart) / 1000000.0);
218         }
219
220         inline u32 getTimeNs()
221         {
222                 LARGE_INTEGER freq, t;
223                 QueryPerformanceFrequency(&freq);
224                 QueryPerformanceCounter(&t);
225                 return (double)(t.QuadPart) / ((double)(freq.QuadPart) / 1000000000.0);
226         }
227
228 #else // Posix
229 #include <sys/time.h>
230 #include <time.h>
231 #if defined(__MACH__) && defined(__APPLE__)
232 #include <mach/clock.h>
233 #include <mach/mach.h>
234 #endif
235
236         inline u32 getTimeS()
237         {
238                 struct timeval tv;
239                 gettimeofday(&tv, NULL);
240                 return tv.tv_sec;
241         }
242
243         inline u32 getTimeMs()
244         {
245                 struct timeval tv;
246                 gettimeofday(&tv, NULL);
247                 return tv.tv_sec * 1000 + tv.tv_usec / 1000;
248         }
249
250         inline u32 getTimeUs()
251         {
252                 struct timeval tv;
253                 gettimeofday(&tv, NULL);
254                 return tv.tv_sec * 1000000 + tv.tv_usec;
255         }
256
257         inline u32 getTimeNs()
258         {
259                 struct timespec ts;
260                 // from http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
261 #if defined(__MACH__) && defined(__APPLE__) // OS X does not have clock_gettime, use clock_get_time
262                 clock_serv_t cclock;
263                 mach_timespec_t mts;
264                 host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
265                 clock_get_time(cclock, &mts);
266                 mach_port_deallocate(mach_task_self(), cclock);
267                 ts.tv_sec = mts.tv_sec;
268                 ts.tv_nsec = mts.tv_nsec;
269 #else
270                 clock_gettime(CLOCK_REALTIME, &ts);
271 #endif
272                 return ts.tv_sec * 1000000000 + ts.tv_nsec;
273         }
274
275         /*#include <sys/timeb.h>
276         inline u32 getTimeMs()
277         {
278                 struct timeb tb;
279                 ftime(&tb);
280                 return tb.time * 1000 + tb.millitm;
281         }*/
282 #endif
283
284 inline u32 getTime(TimePrecision prec)
285 {
286         switch (prec) {
287                 case PRECISION_SECONDS:
288                         return getTimeS();
289                 case PRECISION_MILLI:
290                         return getTimeMs();
291                 case PRECISION_MICRO:
292                         return getTimeUs();
293                 case PRECISION_NANO:
294                         return getTimeNs();
295         }
296         return 0;
297 }
298
299 /**
300  * Delta calculation function taking two 32bit arguments.
301  * @param old_time_ms old time for delta calculation (order is relevant!)
302  * @param new_time_ms new time for delta calculation (order is relevant!)
303  * @return positive 32bit delta value
304  */
305 inline u32 getDeltaMs(u32 old_time_ms, u32 new_time_ms)
306 {
307         if (new_time_ms >= old_time_ms) {
308                 return (new_time_ms - old_time_ms);
309         } else {
310                 return (old_time_ms - new_time_ms);
311         }
312 }
313
314 #if defined(linux) || defined(__linux)
315         #include <sys/prctl.h>
316
317         inline void setThreadName(const char *name) {
318                 /* It would be cleaner to do this with pthread_setname_np,
319                  * which was added to glibc in version 2.12, but some major
320                  * distributions are still runing 2.11 and previous versions.
321                  */
322                 prctl(PR_SET_NAME, name);
323         }
324 #elif defined(__FreeBSD__) || defined(__OpenBSD__)
325         #include <pthread.h>
326         #include <pthread_np.h>
327
328         inline void setThreadName(const char *name) {
329                 pthread_set_name_np(pthread_self(), name);
330         }
331 #elif defined(__NetBSD__)
332         #include <pthread.h>
333
334         inline void setThreadName(const char *name) {
335                 pthread_setname_np(pthread_self(), name);
336         }
337 #elif defined(_MSC_VER)
338         typedef struct tagTHREADNAME_INFO {
339                 DWORD dwType; // must be 0x1000
340                 LPCSTR szName; // pointer to name (in user addr space)
341                 DWORD dwThreadID; // thread ID (-1=caller thread)
342                 DWORD dwFlags; // reserved for future use, must be zero
343         } THREADNAME_INFO;
344
345         inline void setThreadName(const char *name) {
346                 THREADNAME_INFO info;
347                 info.dwType = 0x1000;
348                 info.szName = name;
349                 info.dwThreadID = -1;
350                 info.dwFlags = 0;
351                 __try {
352                         RaiseException(0x406D1388, 0, sizeof(info) / sizeof(DWORD), (ULONG_PTR *) &info);
353                 } __except (EXCEPTION_CONTINUE_EXECUTION) {}
354         }
355 #elif defined(__APPLE__)
356         #include <pthread.h>
357
358         inline void setThreadName(const char *name) {
359                 pthread_setname_np(name);
360         }
361 #elif defined(_WIN32) || defined(__GNU__)
362         inline void setThreadName(const char* name) {}
363 #else
364         #warning "Unrecognized platform, thread names will not be available."
365         inline void setThreadName(const char* name) {}
366 #endif
367
368 #ifndef SERVER
369 float getDisplayDensity();
370
371 v2u32 getDisplaySize();
372 v2u32 getWindowSize();
373
374 std::vector<core::vector3d<u32> > getSupportedVideoModes();
375 std::vector<irr::video::E_DRIVER_TYPE> getSupportedVideoDrivers();
376 const char *getVideoDriverName(irr::video::E_DRIVER_TYPE type);
377 const char *getVideoDriverFriendlyName(irr::video::E_DRIVER_TYPE type);
378 #endif
379
380 inline const char *getPlatformName()
381 {
382         return
383 #if defined(ANDROID)
384         "Android"
385 #elif defined(linux) || defined(__linux) || defined(__linux__)
386         "Linux"
387 #elif defined(_WIN32) || defined(_WIN64)
388         "Windows"
389 #elif defined(__DragonFly__) || defined(__FreeBSD__) || \
390                 defined(__NetBSD__) || defined(__OpenBSD__)
391         "BSD"
392 #elif defined(__APPLE__) && defined(__MACH__)
393         #if TARGET_OS_MAC
394                 "OSX"
395         #elif TARGET_OS_IPHONE
396                 "iOS"
397         #else
398                 "Apple"
399         #endif
400 #elif defined(_AIX)
401         "AIX"
402 #elif defined(__hpux)
403         "HP-UX"
404 #elif defined(__sun) || defined(sun)
405         #if defined(__SVR4)
406                 "Solaris"
407         #else
408                 "SunOS"
409         #endif
410 #elif defined(__CYGWIN__)
411         "Cygwin"
412 #elif defined(__unix__) || defined(__unix)
413         #if defined(_POSIX_VERSION)
414                 "Posix"
415         #else
416                 "Unix"
417         #endif
418 #else
419         "?"
420 #endif
421         ;
422 }
423
424 void setXorgClassHint(const video::SExposedVideoData &video_data,
425         const std::string &name);
426
427 // This only needs to be called at the start of execution, since all future
428 // threads in the process inherit this exception handler
429 void setWin32ExceptionHandler();
430
431 } // namespace porting
432
433 #ifdef __ANDROID__
434 #include "porting_android.h"
435 #endif
436
437 #endif // PORTING_HEADER
438