1 // Compatibility declarations for things which might not be present in
2 // certain build environments. It also levels the playing field caused
3 // by different platforms.
4
5 #ifndef compat_h_
6 #define compat_h_
7
8 #pragma once
9
10 #ifdef _WIN32
11 # include "windows_inc.h"
12 #endif
13
14 ////////// Compiler detection //////////
15
16 #ifdef __GNUC__
17 # define EDUKE32_GCC_PREREQ(major, minor) (major < __GNUC__ || (major == __GNUC__ && minor <= __GNUC_MINOR__))
18 #else
19 # define EDUKE32_GCC_PREREQ(major, minor) 0
20 #endif
21
22 #ifdef __clang__
23 # define EDUKE32_CLANG_PREREQ(major, minor) (major < __clang_major__ || (major == __clang_major__ && minor <= __clang_minor__))
24 #else
25 # define EDUKE32_CLANG_PREREQ(major, minor) 0
26 #endif
27 #ifndef __has_builtin
28 # define __has_builtin(x) 0 // Compatibility with non-clang compilers.
29 #endif
30 #ifndef __has_feature
31 # define __has_feature(x) 0 // Compatibility with non-clang compilers.
32 #endif
33 #ifndef __has_extension
34 # define __has_extension __has_feature // Compatibility with pre-3.0 compilers.
35 #endif
36 #ifndef __has_cpp_attribute
37 # define __has_cpp_attribute(x) 0
38 #endif
39
40 #ifdef _MSC_VER
41 # define EDUKE32_MSVC_PREREQ(major) ((major) <= (_MSC_VER))
42 # ifdef __cplusplus
43 # define EDUKE32_MSVC_CXX_PREREQ(major) ((major) <= (_MSC_VER))
44 # else
45 # define EDUKE32_MSVC_CXX_PREREQ(major) 0
46 # endif
47 #else
48 # define EDUKE32_MSVC_PREREQ(major) 0
49 # define EDUKE32_MSVC_CXX_PREREQ(major) 0
50 #endif
51
52
53 ////////// Language detection //////////
54
55 #if defined __STDC__
56 # if defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L
57 # define CSTD 2011
58 # elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
59 # define CSTD 1999
60 # elif defined __STDC_VERSION__ && __STDC_VERSION__ >= 199409L
61 # define CSTD 1994
62 # else
63 # define CSTD 1989
64 # endif
65 #else
66 # define CSTD 0
67 #endif
68
69 #if defined __cplusplus && __cplusplus >= 202002L
70 # define CXXSTD 2020
71 #elif defined __cplusplus && __cplusplus >= 201703L
72 # define CXXSTD 2017
73 #elif defined __cplusplus && __cplusplus >= 201402L
74 # define CXXSTD 2014
75 #elif defined __cplusplus && __cplusplus >= 201103L
76 # define CXXSTD 2011
77 #elif defined __cplusplus && __cplusplus >= 199711L
78 # define CXXSTD 1998
79 #else
80 # define CXXSTD 0
81 #endif
82
83
84 ////////// Language and compiler feature polyfills //////////
85
86 #ifdef __cplusplus
87 # define EXTERNC extern "C"
88 #else
89 # define EXTERNC
90 #endif
91
92 #ifndef UNREFERENCED_PARAMETER
93 # define UNREFERENCED_PARAMETER(x) (x) = (x)
94 #endif
95
96 #ifndef UNREFERENCED_CONST_PARAMETER
97 # ifdef _MSC_VER
98 # define UNREFERENCED_CONST_PARAMETER(x) ((void)(x))
99 # else
100 # define UNREFERENCED_CONST_PARAMETER(x)
101 # endif
102 #endif
103
104 #ifdef __GNUC__
105 # define UNUSED(x) UNUSED_ ## x __attribute__((unused))
106 # define PRINTF_FORMAT(stringindex, firstargindex) __attribute__((format (printf, stringindex, firstargindex)))
107 #else
108 # define UNUSED(x) x
109 # define PRINTF_FORMAT(stringindex, firstargindex)
110 #endif
111
112 #if defined __GNUC__ || defined __clang__
113 # define ATTRIBUTE(attrlist) __attribute__(attrlist)
114 #else
115 # define ATTRIBUTE(attrlist)
116 #endif
117
118 #if !defined __clang__ && !defined USING_LTO
119 # define ATTRIBUTE_OPTIMIZE(str) ATTRIBUTE((optimize(str)))
120 #else
121 # define ATTRIBUTE_OPTIMIZE(str)
122 #endif
123
124 #if EDUKE32_GCC_PREREQ(4,0)
125 # define WARN_UNUSED_RESULT __attribute__((warn_unused_result))
126 #else
127 # define WARN_UNUSED_RESULT
128 #endif
129
130 #if defined _MSC_VER && _MSC_VER < 1800
131 # define inline __inline
132 #endif
133
134 #ifndef MAY_ALIAS
135 # ifdef _MSC_VER
136 # define MAY_ALIAS
137 # else
138 # define MAY_ALIAS __attribute__((may_alias))
139 # endif
140 #endif
141
142 #ifndef FORCE_INLINE
143 # ifdef _MSC_VER
144 # define FORCE_INLINE __forceinline
145 # else
146 # ifdef __GNUC__
147 # define FORCE_INLINE inline __attribute__((always_inline))
148 # else
149 # define FORCE_INLINE inline
150 # endif
151 # endif
152 #endif
153
154 #ifndef _MSC_VER
155 # ifndef __fastcall
156 # if defined(__GNUC__) && defined(__i386__)
157 # define __fastcall __attribute__((fastcall))
158 # else
159 # define __fastcall
160 # endif
161 # endif
162 #endif
163
164 #ifndef DISABLE_INLINING
165 # define EXTERN_INLINE static inline
166 # define EXTERN_INLINE_HEADER static inline
167 #else
168 # define EXTERN_INLINE __fastcall
169 # define EXTERN_INLINE_HEADER extern __fastcall
170 #endif
171
172 #if 1 && defined(__OPTIMIZE__) && (defined __GNUC__ || __has_builtin(__builtin_expect))
173 #define EDUKE32_PREDICT_TRUE(x) __builtin_expect(!!(x),1)
174 #define EDUKE32_PREDICT_FALSE(x) __builtin_expect(!!(x),0)
175 #else
176 #define EDUKE32_PREDICT_TRUE(x) (x)
177 #define EDUKE32_PREDICT_FALSE(x) (x)
178 #endif
179
180 #ifdef DEBUG
181 # define EDUKE32_UNREACHABLE_SECTION(...) debug_break()
182 #else
183 # if EDUKE32_GCC_PREREQ(4,5) || __has_builtin(__builtin_unreachable)
184 # define EDUKE32_UNREACHABLE_SECTION(...) __builtin_unreachable()
185 # elif _MSC_VER
186 # define EDUKE32_UNREACHABLE_SECTION(...) __assume(0)
187 # else
188 # define EDUKE32_UNREACHABLE_SECTION(...) __VA_ARGS__
189 # endif
190 #endif
191 #if EDUKE32_GCC_PREREQ(2,0) || defined _MSC_VER
192 # define EDUKE32_FUNCTION __FUNCTION__
193 #elif CSTD >= 1999 || CXXSTD >= 2011
194 # define EDUKE32_FUNCTION __func__
195 #else
196 # define EDUKE32_FUNCTION "???"
197 #endif
198
199 #ifdef _MSC_VER
200 # define EDUKE32_PRETTY_FUNCTION __FUNCSIG__
201 #elif EDUKE32_GCC_PREREQ(2,0)
202 # define EDUKE32_PRETTY_FUNCTION __PRETTY_FUNCTION__
203 #else
204 # define EDUKE32_PRETTY_FUNCTION EDUKE32_FUNCTION
205 #endif
206
207 #ifdef __COUNTER__
208 # define EDUKE32_UNIQUE_SRC_ID __COUNTER__
209 #else
210 # define EDUKE32_UNIQUE_SRC_ID __LINE__
211 #endif
212
213 #if CXXSTD >= 2017
214 # define EDUKE32_STATIC_ASSERT(cond) static_assert(cond)
215 #elif CXXSTD >= 2011 || CSTD >= 2011 || EDUKE32_MSVC_PREREQ(1600)
216 # define EDUKE32_STATIC_ASSERT(cond) static_assert(cond, "")
217 #else
218 /* C99 / C++03 static assertions based on source found in LuaJIT's src/lj_def.h. */
219 # define EDUKE32_ASSERT_NAME2(name, line) name ## line
220 # define EDUKE32_ASSERT_NAME(line) EDUKE32_ASSERT_NAME2(eduke32_assert_, line)
221 # define EDUKE32_STATIC_ASSERT(cond) \
222 extern void EDUKE32_ASSERT_NAME(EDUKE32_UNIQUE_SRC_ID)(int STATIC_ASSERTION_FAILED[(cond)?1:-1])
223 #endif
224
225 #ifdef _MSC_VER
226 # define longlong(x) x##i64
227 #else
228 # define longlong(x) x##ll
229 #endif
230
231 #ifndef FP_OFF
232 # define FP_OFF(__p) ((uintptr_t)(__p))
233 #endif
234
235 #ifdef UNDERSCORES
236 # define ASMSYM(x) "_" x
237 #else
238 # define ASMSYM(x) x
239 #endif
240
241 #if defined __cplusplus
242 # define STATIC_CAST_OP(t) static_cast<t>
243 # define REINTERPRET_CAST_OP(t) reinterpret_cast<t>
244 #else
245 # define STATIC_CAST_OP(t) (t)
246 # define REINTERPRET_CAST_OP(t) (t)
247 #endif
248 #define STATIC_CAST(t, v) (STATIC_CAST_OP(t)(v))
249 #define REINTERPRET_CAST(t, v) (REINTERPRET_CAST_OP(t)(v))
250
251 #if defined __cplusplus && (__cplusplus >= 201103L || __has_feature(cxx_constexpr) || EDUKE32_MSVC_CXX_PREREQ(1900))
252 # define HAVE_CONSTEXPR
253 # define CONSTEXPR constexpr
254 #else
255 # define CONSTEXPR
256 #endif
257
258 #if CXXSTD >= 2011 || EDUKE32_MSVC_PREREQ(1700)
259 # define FINAL final
260 #else
261 # define FINAL
262 #endif
263
264 #if CXXSTD >= 2014
265 # define CONSTEXPR_CXX14 CONSTEXPR
266 #else
267 # define CONSTEXPR_CXX14
268 #endif
269
270 #if CXXSTD >= 2011
271 # if __has_cpp_attribute(fallthrough)
272 # define fallthrough__ [[fallthrough]]
273 # elif __has_cpp_attribute(clang::fallthrough)
274 # define fallthrough__ [[clang::fallthrough]]
275 # elif __has_cpp_attribute(gnu::fallthrough)
276 # define fallthrough__ [[gnu::fallthrough]]
277 # endif
278 #endif
279 #ifndef fallthrough__
280 # if !defined __clang__ && EDUKE32_GCC_PREREQ(7,0)
281 # define fallthrough__ __attribute__((fallthrough))
282 # elif defined _MSC_VER
283 # define fallthrough__ __fallthrough
284 # else
285 # define fallthrough__
286 # endif
287 #endif
288
289
290 ////////// Platform detection //////////
291
292 #if defined __FreeBSD__ || defined __NetBSD__ || defined __OpenBSD__ || defined __bsdi__ || defined __DragonFly__
293 # define EDUKE32_BSD
294 #endif
295
296 #ifdef __APPLE__
297 # include <TargetConditionals.h>
298 # if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR
299 # define EDUKE32_IOS
300 # else
301 # define EDUKE32_OSX
302 # endif
303 #endif
304
305
306 ////////// Architecture detection //////////
307
308 #if defined __arm__ || defined __aarch64__
309 # define EDUKE32_CPU_ARM
310 #elif defined __i386 || defined __i386__ || defined _M_IX86 || defined _M_X64 || defined __x86_64__
311 # define EDUKE32_CPU_X86
312 #elif defined _M_PPC || defined __powerpc__ || defined __powerpc64__
313 # define EDUKE32_CPU_PPC
314 #elif defined __MIPSEL__ || defined __mips_isa_rev
315 # define EDUKE32_CPU_MIPS
316 #endif
317
318 #if defined _LP64 || defined __LP64__ || defined __64BIT__ || _ADDR64 || defined _WIN64 || defined __arch64__ || \
319 __WORDSIZE == 64 || (defined __sparc && defined __sparcv9) || defined __x86_64 || defined __amd64 || \
320 defined __x86_64__ || defined __amd64__ || defined _M_X64 || defined _M_IA64 || defined __ia64 || defined __IA64__
321
322 # define BITNESS64
323
324 #endif
325
326 #if defined(__linux)
327 # include <endian.h>
328 # if __BYTE_ORDER == __LITTLE_ENDIAN
329 # define B_LITTLE_ENDIAN 1
330 # define B_BIG_ENDIAN 0
331 # elif __BYTE_ORDER == __BIG_ENDIAN
332 # define B_LITTLE_ENDIAN 0
333 # define B_BIG_ENDIAN 1
334 # endif
335
336 #elif defined(GEKKO) || defined(__ANDROID__)
337 # define B_LITTLE_ENDIAN 0
338 # define B_BIG_ENDIAN 1
339
340 #elif defined(__OpenBSD__)
341 # include <machine/endian.h>
342 # if _BYTE_ORDER == _LITTLE_ENDIAN
343 # define B_LITTLE_ENDIAN 1
344 # define B_BIG_ENDIAN 0
345 # elif _BYTE_ORDER == _BIG_ENDIAN
346 # define B_LITTLE_ENDIAN 0
347 # define B_BIG_ENDIAN 1
348 # endif
349
350 #elif defined EDUKE32_BSD
351 # include <sys/endian.h>
352 # if _BYTE_ORDER == _LITTLE_ENDIAN
353 # define B_LITTLE_ENDIAN 1
354 # define B_BIG_ENDIAN 0
355 # elif _BYTE_ORDER == _BIG_ENDIAN
356 # define B_LITTLE_ENDIAN 0
357 # define B_BIG_ENDIAN 1
358 # endif
359
360 #elif defined(__APPLE__)
361 # if defined(__LITTLE_ENDIAN__)
362 # define B_LITTLE_ENDIAN 1
363 # define B_BIG_ENDIAN 0
364 # elif defined(__BIG_ENDIAN__)
365 # define B_LITTLE_ENDIAN 0
366 # define B_BIG_ENDIAN 1
367 # endif
368 # include <libkern/OSByteOrder.h>
369
370 #elif defined(__BEOS__)
371 # include <posix/endian.h>
372 # if LITTLE_ENDIAN != 0
373 # define B_LITTLE_ENDIAN 1
374 # define B_BIG_ENDIAN 0
375 # elif BIG_ENDIAN != 0
376 # define B_LITTLE_ENDIAN 0
377 # define B_BIG_ENDIAN 1
378 # endif
379
380 #elif defined(__QNX__)
381 # if defined __LITTLEENDIAN__
382 # define B_LITTLE_ENDIAN 1
383 # define B_BIG_ENDIAN 0
384 # elif defined __BIGENDIAN__
385 # define B_LITTLE_ENDIAN 0
386 # define B_BIG_ENDIAN 1
387 # endif
388
389 #elif defined(__sun)
390 # if defined _LITTLE_ENDIAN
391 # define B_LITTLE_ENDIAN 1
392 # define B_BIG_ENDIAN 0
393 # elif defined _BIG_ENDIAN
394 # define B_LITTLE_ENDIAN 0
395 # define B_BIG_ENDIAN 1
396 # endif
397
398 #elif defined(_WIN32) || defined(SKYOS) || defined(__SYLLABLE__)
399 # define B_LITTLE_ENDIAN 1
400 # define B_BIG_ENDIAN 0
401 #endif
402
403 #if !defined(B_LITTLE_ENDIAN) || !defined(B_BIG_ENDIAN)
404 # error Unknown endianness
405 #endif
406
407
408 ////////// Standard library headers //////////
409
410 #undef __USE_MINGW_ANSI_STDIO // Workaround for MinGW-w64.
411
412 #ifndef __STDC_FORMAT_MACROS
413 # define __STDC_FORMAT_MACROS
414 #endif
415 #ifndef __STDC_LIMIT_MACROS
416 # define __STDC_LIMIT_MACROS
417 #endif
418
419 #ifndef _USE_MATH_DEFINES
420 # define _USE_MATH_DEFINES
421 #endif
422
423 #include <inttypes.h>
424 #include <stdint.h>
425
426 #include <limits.h>
427 #include <stdarg.h>
428 #include <stddef.h>
429 #ifndef USE_PHYSFS
430 #include <stdio.h>
431 #endif
432 #include <stdlib.h>
433 #include <string.h>
434
435 #if !(defined _WIN32 && defined __clang__)
436 #include <float.h>
437 #endif
438 #include <math.h>
439
440 #include <ctype.h>
441 #include <errno.h>
442 #include <time.h>
443
444 #include <assert.h>
445
446 #ifdef __cplusplus
447 # include <limits>
448 # if CXXSTD >= 2011 || EDUKE32_MSVC_PREREQ(1800)
449 # include <algorithm>
450 # include <functional>
451 # include <type_traits>
452 // we need this because MSVC does not properly identify C++11 support
453 # define HAVE_CXX11_HEADERS
454 # endif
455 #endif
456
457 ////////// Platform headers //////////
458
459 #if !defined __APPLE__ && (!defined EDUKE32_BSD || !__STDC__)
460 # include <malloc.h>
461 #endif
462
463 #ifndef USE_PHYSFS
464 #include <fcntl.h>
465 #include <sys/stat.h>
466 #include <sys/types.h>
467
468 #if defined(_WIN32)
469 # include <direct.h>
470 # include <io.h>
471 #else
472 # include <unistd.h>
473 #endif
474 #endif
475
476
477 ////////// DEPRECATED: Standard library prefixing //////////
478
479 #ifdef _MSC_VER
480 # if defined _M_AMD64 || defined _M_ARM64 || defined _M_X64 || defined _WIN64
481 // should be int64_t, if not for a suspected VS compiler bug
482 typedef int64_t ssize_t;
483 # else
484 typedef int32_t ssize_t;
485 # endif
486 #endif
487
488 typedef size_t bsize_t;
489 typedef ssize_t bssize_t;
490
491 typedef FILE BFILE;
492
493 #define BO_BINARY O_BINARY
494 #define BO_TEXT O_TEXT
495 #define BO_RDONLY O_RDONLY
496 #define BO_WRONLY O_WRONLY
497 #define BO_RDWR O_RDWR
498 #define BO_APPEND O_APPEND
499 #define BO_CREAT O_CREAT
500 #define BO_TRUNC O_TRUNC
501 #define BS_IRGRP S_IRGRP
502 #define BS_IWGRP S_IWGRP
503 #define BS_IEXEC S_IEXEC
504 #define BS_IFIFO S_IFIFO
505 #define BS_IFCHR S_IFCHR
506 #define BS_IFBLK S_IFBLK
507 #define BS_IFDIR S_IFDIR
508 #define BS_IFREG S_IFREG
509 #define BSEEK_SET SEEK_SET
510 #define BSEEK_CUR SEEK_CUR
511 #define BSEEK_END SEEK_END
512
513 #define BMAX_PATH 256
514
515 #define Bassert assert
516 #define Brand rand
517 #define Bmalloc malloc
518 #define Bcalloc calloc
519 #define Brealloc realloc
520 #define Bfree free
521 #define Bopen open
522 #define Bclose close
523 #define Bwrite write
524 #define Bread read
525 #define Blseek lseek
526 #define Bstat stat
527 #define Bfstat fstat
528 #define Bfileno fileno
529 #define Bferror ferror
530 #define Bfopen fopen
531 #define Bfclose fclose
532 #define Bfflush fflush
533 #define Bfeof feof
534 #define Bfgetc fgetc
535 #define Brewind rewind
536 #define Bfgets fgets
537 #define Bfputc fputc
538 #define Bfputs fputs
539 #define Bfread fread
540 #define Bfwrite fwrite
541 #define Bfprintf fprintf
542 #define Bfscanf fscanf
543 #define Bfseek fseek
544 #define Bftell ftell
545 #define Bputs puts
546 #define Bstrcpy strcpy
547 #define Bstrncpy strncpy
548 #define Bstrcmp strcmp
549 #define Bstrncmp strncmp
550 #define Bstrcat strcat
551 #define Bstrncat strncat
552 #define Bstrlen strlen
553 #define Bstrchr strchr
554 #define Bstrrchr strrchr
555 #define Bstrtol strtol
556 #define Bstrtoul strtoul
557 #define Bstrtod strtod
558 #define Bstrstr strstr
559 #define Bislower islower
560 #define Bisupper isupper
561 #define Bisdigit isdigit
562 #define Btoupper toupper
563 #define Btolower tolower
564 #define Bmemcpy memcpy
565 #define Bmemmove memmove
566 #define Bmemchr memchr
567 #define Bmemset memset
568 #define Bmemcmp memcmp
569 #define Bscanf scanf
570 #define Bprintf printf
571 #define Bsscanf sscanf
572 #define Bsprintf sprintf
573 #define Bvfprintf vfprintf
574 #define Bgetenv getenv
575 #define Butime utime
576
577
578 ////////// Standard library wrappers //////////
579
580 #ifdef __ANDROID__
581 # define BS_IWRITE S_IWUSR
582 # define BS_IREAD S_IRUSR
583 #else
584 # define BS_IWRITE S_IWRITE
585 # define BS_IREAD S_IREAD
586 #endif
587
588 #if defined(__cplusplus) && defined(_MSC_VER)
589 # define Bstrdup _strdup
590 # define Bchdir _chdir
591 # define Bgetcwd _getcwd
592 #else
593 # define Bstrdup strdup
594 # define Bchdir chdir
595 # define Bgetcwd getcwd
596 #endif
597
598 #if defined(__GNUC__)
599 # define Btell(h) lseek(h,0,SEEK_CUR)
600 #else
601 # define Btell tell
602 #endif
603
604 #if defined(_MSC_VER)
605 # define Bstrcasecmp _stricmp
606 # define Bstrncasecmp _strnicmp
607 #elif defined(__QNX__)
608 # define Bstrcasecmp stricmp
609 # define Bstrncasecmp strnicmp
610 #else
611 # define Bstrcasecmp strcasecmp
612 # define Bstrncasecmp strncasecmp
613 #endif
614
615 #ifdef _WIN32
616 # define Bsnprintf _snprintf
617 # define Bvsnprintf _vsnprintf
618 #else
619 # define Bsnprintf snprintf
620 # define Bvsnprintf vsnprintf
621 #endif
622
623 #ifdef _MSC_VER
624 # define Balloca _alloca
625 #elif defined __GNUC__
626 # define Balloca __builtin_alloca
627 #else
628 # define Balloca alloca
629 #endif
630
631 #ifdef _MSC_VER
632 # define Bmalloca _malloca
633 # define Bfreea _freea
634 #else
635 # define Bmalloca alloca
636 # define Bfreea(ptr) do { } while (0)
637 #endif
638
639 #define Btime() time(NULL)
640
641 #if defined(_WIN32)
642 # define Bmkdir(s,x) mkdir(s)
643 #else
644 # define Bmkdir mkdir
645 #endif
646
647 // XXX: different across 32- and 64-bit archs (e.g.
648 // parsing the decimal representation of 0xffffffff,
649 // 4294967295 -- long is signed, so strtol would
650 // return LONG_MAX (== 0x7fffffff on 32-bit archs))
651
atoi_safe(const char * str)652 static FORCE_INLINE int32_t atoi_safe(const char *str) { return (int32_t)Bstrtol(str, NULL, 10); }
653
654 #define Batoi(x) atoi_safe(x)
655 #define Batol(str) (strtol(str, NULL, 10))
656 #define Batof(str) (strtod(str, NULL))
657
658 #if defined BITNESS64 && (defined __SSE2__ || defined _MSC_VER) && !defined(_M_ARM64)
659 #include <emmintrin.h>
Blrintf(const float x)660 static FORCE_INLINE int32_t Blrintf(const float x)
661 {
662 __m128 xx = _mm_load_ss(&x);
663 return _mm_cvtss_si32(xx);
664 }
665 #elif defined(_MSC_VER) && !defined(_M_ARM64)
Blrintf(const float x)666 static FORCE_INLINE int32_t Blrintf(const float x)
667 {
668 int n;
669 __asm fld x;
670 __asm fistp n;
671 return n;
672 }
673 #else
674 #define Blrintf(x) ((int32_t)lrintf(x))
675 #endif
676
677 #if defined(__arm__)
678 # define Bsqrt __builtin_sqrt
679 # define Bsqrtf __builtin_sqrtf
680 #else
681 # define Bsqrt sqrt
682 # define Bsqrtf sqrtf
683 #endif
684
685 // redefined for apple/ppc, which chokes on stderr when linking...
686 #if defined EDUKE32_OSX && defined __BIG_ENDIAN__
687 # define ERRprintf(fmt, ...) printf(fmt, ## __VA_ARGS__)
688 #else
689 # define ERRprintf(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__)
690 #endif
691
692 // Bexit is ONLY for errors!
693 #ifdef DEBUGGINGAIDS
694 # define Bexit(status) do { initprintf("exit(%d) at %s:%d in %s()\n", status, __FILE__, __LINE__, EDUKE32_FUNCTION); exit(status); } while (0)
695 #else
696 # define Bexit exit
697 #endif
698
699 #ifdef _WIN32
700 #define fatal_exit__(x) FatalAppExitA(0, x)
701 #else
702 #define fatal_exit__(x) do { wm_msgbox("Fatal Error", "%s", x); exit(EXIT_FAILURE); } while(0)
703 #endif
704
705 #define fatal_exit(status) do { initprintf("fatal_exit(%s) at %s:%d in %s()\n", status, __FILE__, __LINE__, EDUKE32_FUNCTION); fatal_exit__(status); } while (0)
706
707 ////////// Standard library monkey patching //////////
708
709 #ifndef NULL
710 # define NULL ((void *)0)
711 #endif
712
713 #ifdef _MSC_VER
714 # define strtoll _strtoi64
715 #endif
716
717 #ifndef O_BINARY
718 # define O_BINARY 0
719 #endif
720 #ifndef O_TEXT
721 # define O_TEXT 0
722 #endif
723
724 #ifndef F_OK
725 # define F_OK 0
726 #endif
727
728 #ifdef GEKKO
729 # undef PRIdPTR
730 # define PRIdPTR "d"
731 # undef PRIxPTR
732 # define PRIxPTR "x"
733 # undef SCNx32
734 # define SCNx32 "x"
735 #endif
736
737 #if defined EDUKE32_OSX
738 # if !defined __x86_64__ && defined __GNUC__
739 // PK 20110617: is*() crashes for me in x86 code compiled from 64-bit, and gives link errors on ppc
740 // This hack patches all occurences.
741 # define isdigit(ch) ({ int32_t c__dontuse_=ch; c__dontuse_>='0' && c__dontuse_<='9'; })
742 # define isalpha(ch) ({ int32_t c__dontuse2_=ch; (c__dontuse2_>='A' && c__dontuse2_<='Z') || (c__dontuse2_>='a' && c__dontuse2_<='z'); })
743 # define isalnum(ch2) ({ int32_t c2__dontuse_=ch2; isalpha(c2__dontuse_) || isdigit(c2__dontuse_); })
744 # if defined __BIG_ENDIAN__
745 # define isspace(ch) ({ int32_t c__dontuse_=ch; (c__dontuse_==' ' || c__dontuse_=='\t' || c__dontuse_=='\n' || c__dontuse_=='\v' || c__dontuse_=='\f' || c__dontuse_=='\r'); })
746 # define isprint(ch) ({ int32_t c__dontuse_=ch; (c__dontuse_>=0x20 && c__dontuse_<0x7f); })
747 # endif
748 # endif
749 #endif
750
751 #ifdef __ANDROID__
752 void eduke32_exit_return(int) ATTRIBUTE((noreturn));
753 # define exit(x) eduke32_exit_return(x)
754 #endif
755
756
757 ////////// Metaprogramming structs //////////
758
759 #ifdef __cplusplus
760
761 # ifdef HAVE_CXX11_HEADERS
762 using std::is_integral;
763 template <typename T>
764 struct is_signed
765 {
766 static constexpr bool value = std::is_signed<T>::value;
767 };
768 template <typename T>
769 struct is_unsigned
770 {
771 static constexpr bool value = std::is_unsigned<T>::value;
772 };
773 # endif
774
775 # if CXXSTD >= 2014
776 using std::enable_if_t;
777 using std::conditional_t;
778 using std::make_signed_t;
779 using std::make_unsigned_t;
780 using std::remove_pointer_t;
781 # elif defined HAVE_CXX11_HEADERS
782 template <bool B, class T = void>
783 using enable_if_t = typename std::enable_if<B, T>::type;
784 template<bool B, class T, class F>
785 using conditional_t = typename std::conditional<B, T, F>::type;
786 template <typename T>
787 using make_signed_t = typename std::make_signed<T>::type;
788 template <typename T>
789 using make_unsigned_t = typename std::make_unsigned<T>::type;
790 template <class T>
791 using remove_pointer_t = typename std::remove_pointer<T>::type;
792 # endif
793
794 # ifdef HAVE_CXX11_HEADERS
795 template <typename type, typename other_type_with_sign>
796 using take_sign_t = conditional_t< is_signed<other_type_with_sign>::value, make_signed_t<type>, make_unsigned_t<type> >;
797 # endif
798
799 template <size_t size>
800 struct integers_of_size { };
801 template <>
802 struct integers_of_size<sizeof(int8_t)>
803 {
804 typedef int8_t i;
805 typedef uint8_t u;
806 };
807 template <>
808 struct integers_of_size<sizeof(int16_t)>
809 {
810 typedef int16_t i;
811 typedef uint16_t u;
812 };
813 template <>
814 struct integers_of_size<sizeof(int32_t)>
815 {
816 typedef int32_t i;
817 typedef uint32_t u;
818 };
819 template <>
820 struct integers_of_size<sizeof(int64_t)>
821 {
822 typedef int64_t i;
823 typedef uint64_t u;
824 };
825
826 #endif
827
828
829 ////////// Typedefs //////////
830
831 #ifdef __cplusplus
832 // for use in SFINAE constructs in place of the pointer trick (to which 0 can unintentionally be implicitly cast)
833 struct Dummy FINAL
834 {
835 FORCE_INLINE CONSTEXPR Dummy() : dummy(0) { }
836 char dummy;
837 };
838 #endif
839
840 #if defined(__x86_64__)
841 // for 32-bit pointers in x86_64 code, such as `gcc -mx32`
842 typedef uint64_t reg_t;
843 typedef int64_t sreg_t;
844 #else
845 typedef size_t reg_t;
846 typedef ssize_t sreg_t;
847 #endif
848
849 #ifdef HAVE_CXX11_HEADERS
850 using native_t = typename integers_of_size<sizeof(reg_t)>::i;
851 using unative_t = typename integers_of_size<sizeof(reg_t)>::u;
852 #else
853 typedef sreg_t native_t;
854 typedef reg_t unative_t;
855 #endif
856 EDUKE32_STATIC_ASSERT(sizeof(native_t) == sizeof(unative_t));
857
858 typedef struct MAY_ALIAS {
859 int32_t x, y;
860 } vec2_t;
861
862 typedef struct MAY_ALIAS {
863 int16_t x, y;
864 } vec2_16_t;
865
866 typedef struct {
867 uint32_t x, y;
868 } vec2u_t;
869
870 typedef struct {
871 float x, y;
872 } vec2f_t;
873
874 typedef struct {
875 double x, y;
876 } vec2d_t;
877
878 typedef struct MAY_ALIAS {
879 union {
880 struct { int32_t x, y, z; };
881 vec2_t vec2;
882 };
883 } vec3_t;
884
885 typedef struct MAY_ALIAS {
886 union {
887 struct { int16_t x, y, z; };
888 vec2_16_t vec2;
889 };
890 } vec3_16_t;
891
892 typedef struct {
893 union {
894 struct {
895 union { float x, d; };
896 union { float y, u; };
897 union { float z, v; };
898 };
899 vec2f_t vec2;
900 };
901 } vec3f_t;
902
903 EDUKE32_STATIC_ASSERT(sizeof(vec3f_t) == sizeof(float) * 3);
904
905 typedef struct {
906 union { double x; double d; };
907 union { double y; double u; };
908 union { double z; double v; };
909 } vec3d_t;
910
911 EDUKE32_STATIC_ASSERT(sizeof(vec3d_t) == sizeof(double) * 3);
912
913 typedef struct {
914 float x, y, z, w;
915 } vec4f_t;
916
917 typedef struct {
918 float x, y, z, w;
919 } vec4d_t;
920
921
922 ////////// Language tricks that depend on size_t //////////
923
924 #if defined _MSC_VER
925 # define ARRAY_SIZE(arr) _countof(arr)
926 #elif defined HAVE_CONSTEXPR
927 template <typename T, size_t N>
928 static FORCE_INLINE constexpr size_t ARRAY_SIZE(T const (&)[N]) noexcept
929 {
930 return N;
931 }
932 #elif defined __cplusplus
933 struct bad_arg_to_ARRAY_SIZE
934 {
935 class Is_pointer; // incomplete
936 class Is_array {};
937 template <typename T>
938 static Is_pointer check_type(const T*, const T* const*);
939 static Is_array check_type(const void*, const void*);
940 };
941 # define ARRAY_SIZE(arr) ( \
942 0 * sizeof(reinterpret_cast<const ::bad_arg_to_ARRAY_SIZE*>(arr)) + \
943 0 * sizeof(::bad_arg_to_ARRAY_SIZE::check_type((arr), &(arr))) + \
944 sizeof(arr) / sizeof((arr)[0]) )
945 #else
946 # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
947 #endif
948 #define ARRAY_SSIZE(arr) (native_t)ARRAY_SIZE(arr)
949
950
951 ////////// Memory management //////////
952
953 #if !defined NO_ALIGNED_MALLOC
954 static FORCE_INLINE void *Baligned_alloc(const size_t alignment, const size_t size)
955 {
956 #ifdef _WIN32
957 void *ptr = _aligned_malloc(size, alignment);
958 #elif defined __APPLE__ || defined EDUKE32_BSD
959 void *ptr = NULL;
960 posix_memalign(&ptr, alignment, size);
961 #else
962 void *ptr = memalign(alignment, size);
963 #endif
964
965 return ptr;
966 }
967 #else
968 # define Baligned_alloc(alignment, size) Bmalloc(size)
969 #endif
970
971 #if defined _WIN32 && !defined NO_ALIGNED_MALLOC
972 # define Baligned_free _aligned_free
973 #else
974 # define Baligned_free Bfree
975 #endif
976
977
978 ////////// Pointer management //////////
979
980 #define DO_FREE_AND_NULL(var) do { \
981 Xfree(var); (var) = NULL; \
982 } while (0)
983
984 #define ALIGNED_FREE_AND_NULL(var) do { \
985 Xaligned_free(var); (var) = NULL; \
986 } while (0)
987
988
989 ////////// Data serialization //////////
990
991 static FORCE_INLINE CONSTEXPR uint16_t B_SWAP16_impl(uint16_t value)
992 {
993 return
994 ((value & 0xFF00u) >> 8u) |
995 ((value & 0x00FFu) << 8u);
996 }
997 static FORCE_INLINE CONSTEXPR uint32_t B_SWAP32_impl(uint32_t value)
998 {
999 return
1000 ((value & 0xFF000000u) >> 24u) |
1001 ((value & 0x00FF0000u) >> 8u) |
1002 ((value & 0x0000FF00u) << 8u) |
1003 ((value & 0x000000FFu) << 24u);
1004 }
1005 static FORCE_INLINE CONSTEXPR uint64_t B_SWAP64_impl(uint64_t value)
1006 {
1007 return
1008 ((value & 0xFF00000000000000ULL) >> 56ULL) |
1009 ((value & 0x00FF000000000000ULL) >> 40ULL) |
1010 ((value & 0x0000FF0000000000ULL) >> 24ULL) |
1011 ((value & 0x000000FF00000000ULL) >> 8ULL) |
1012 ((value & 0x00000000FF000000ULL) << 8ULL) |
1013 ((value & 0x0000000000FF0000ULL) << 24ULL) |
1014 ((value & 0x000000000000FF00ULL) << 40ULL) |
1015 ((value & 0x00000000000000FFULL) << 56ULL);
1016 }
1017
1018 /* The purpose of B_PASS* as functions, as opposed to macros, is to prevent them from being used as lvalues. */
1019 #if defined __cplusplus && (CXXSTD >= 2011 || EDUKE32_MSVC_CXX_PREREQ(1900))
1020 template <typename T>
1021 static FORCE_INLINE CONSTEXPR take_sign_t<int16_t, T> B_SWAP16(T x)
1022 {
1023 return static_cast< take_sign_t<int16_t, T> >(B_SWAP16_impl(static_cast<uint16_t>(x)));
1024 }
1025 template <typename T>
1026 static FORCE_INLINE CONSTEXPR take_sign_t<int32_t, T> B_SWAP32(T x)
1027 {
1028 return static_cast< take_sign_t<int32_t, T> >(B_SWAP32_impl(static_cast<uint32_t>(x)));
1029 }
1030 template <typename T>
1031 static FORCE_INLINE CONSTEXPR take_sign_t<int64_t, T> B_SWAP64(T x)
1032 {
1033 return static_cast< take_sign_t<int64_t, T> >(B_SWAP64_impl(static_cast<uint64_t>(x)));
1034 }
1035
1036 template <typename T>
1037 static FORCE_INLINE CONSTEXPR take_sign_t<int16_t, T> B_PASS16(T x)
1038 {
1039 return static_cast< take_sign_t<int16_t, T> >(x);
1040 }
1041 template <typename T>
1042 static FORCE_INLINE CONSTEXPR take_sign_t<int32_t, T> B_PASS32(T x)
1043 {
1044 return static_cast< take_sign_t<int32_t, T> >(x);
1045 }
1046 template <typename T>
1047 static FORCE_INLINE CONSTEXPR take_sign_t<int64_t, T> B_PASS64(T x)
1048 {
1049 return static_cast< take_sign_t<int64_t, T> >(x);
1050 }
1051 #else
1052 #define B_SWAP16(x) B_SWAP16_impl(x)
1053 #define B_SWAP32(x) B_SWAP32_impl(x)
1054 #define B_SWAP64(x) B_SWAP64_impl(x)
1055
1056 static FORCE_INLINE CONSTEXPR uint16_t B_PASS16(uint16_t const x) { return x; }
1057 static FORCE_INLINE CONSTEXPR uint32_t B_PASS32(uint32_t const x) { return x; }
1058 static FORCE_INLINE CONSTEXPR uint64_t B_PASS64(uint64_t const x) { return x; }
1059 #endif
1060
1061 #if B_LITTLE_ENDIAN == 1
1062 # define B_LITTLE64(x) B_PASS64(x)
1063 # define B_BIG64(x) B_SWAP64(x)
1064 # define B_LITTLE32(x) B_PASS32(x)
1065 # define B_BIG32(x) B_SWAP32(x)
1066 # define B_LITTLE16(x) B_PASS16(x)
1067 # define B_BIG16(x) B_SWAP16(x)
1068 #elif B_BIG_ENDIAN == 1
1069 # define B_LITTLE64(x) B_SWAP64(x)
1070 # define B_BIG64(x) B_PASS64(x)
1071 # define B_LITTLE32(x) B_SWAP32(x)
1072 # define B_BIG32(x) B_PASS32(x)
1073 # define B_LITTLE16(x) B_SWAP16(x)
1074 # define B_BIG16(x) B_PASS16(x)
1075 #endif
1076
1077 // TODO: Determine when, if ever, we should use the bit-shift-and-mask variants
1078 // due to alignment issues or performance gains.
1079 #if 1
1080 static FORCE_INLINE void B_BUF16(void * const buf, uint16_t const x) { *(uint16_t *) buf = x; }
1081 static FORCE_INLINE void B_BUF32(void * const buf, uint32_t const x) { *(uint32_t *) buf = x; }
1082 static FORCE_INLINE void B_BUF64(void * const buf, uint64_t const x) { *(uint64_t *) buf = x; }
1083
1084 static FORCE_INLINE CONSTEXPR uint16_t B_UNBUF16(void const * const buf) { return *(uint16_t const *) buf; }
1085 static FORCE_INLINE CONSTEXPR uint32_t B_UNBUF32(void const * const buf) { return *(uint32_t const *) buf; }
1086 static FORCE_INLINE CONSTEXPR uint64_t B_UNBUF64(void const * const buf) { return *(uint64_t const *) buf; }
1087 #else
1088 static FORCE_INLINE void B_BUF16(void * const vbuf, uint16_t const x)
1089 {
1090 uint8_t * const buf = (uint8_t *) vbuf;
1091 buf[0] = (x & 0x00FF);
1092 buf[1] = (x & 0xFF00) >> 8;
1093 }
1094 static FORCE_INLINE void B_BUF32(void * const vbuf, uint32_t const x)
1095 {
1096 uint8_t * const buf = (uint8_t *) vbuf;
1097 buf[0] = (x & 0x000000FF);
1098 buf[1] = (x & 0x0000FF00) >> 8;
1099 buf[2] = (x & 0x00FF0000) >> 16;
1100 buf[3] = (x & 0xFF000000) >> 24;
1101 }
1102 # if 0
1103 // i686-apple-darwin11-llvm-gcc-4.2 complains "integer constant is too large for 'long' type"
1104 static FORCE_INLINE void B_BUF64(void * const vbuf, uint64_t const x)
1105 {
1106 uint8_t * const buf = (uint8_t *) vbuf;
1107 buf[0] = (x & 0x00000000000000FF);
1108 buf[1] = (x & 0x000000000000FF00) >> 8;
1109 buf[2] = (x & 0x0000000000FF0000) >> 16;
1110 buf[3] = (x & 0x00000000FF000000) >> 24;
1111 buf[4] = (x & 0x000000FF00000000) >> 32;
1112 buf[5] = (x & 0x0000FF0000000000) >> 40;
1113 buf[6] = (x & 0x00FF000000000000) >> 48;
1114 buf[7] = (x & 0xFF00000000000000) >> 56;
1115 }
1116 # endif
1117
1118 static FORCE_INLINE uint16_t B_UNBUF16(void const * const vbuf)
1119 {
1120 uint8_t const * const buf = (uint8_t const *) vbuf;
1121 return (buf[1] << 8) | (buf[0]);
1122 }
1123 static FORCE_INLINE uint32_t B_UNBUF32(void const * const vbuf)
1124 {
1125 uint8_t const * const buf = (uint8_t const *) vbuf;
1126 return (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0]);
1127 }
1128 static FORCE_INLINE uint64_t B_UNBUF64(void const * const vbuf)
1129 {
1130 uint8_t const * const buf = (uint8_t const *) vbuf;
1131 return ((uint64_t)buf[7] << 56) | ((uint64_t)buf[6] << 48) | ((uint64_t)buf[5] << 40) |
1132 ((uint64_t)buf[4] << 32) | (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | (buf[0]);
1133 }
1134 #endif
1135
1136
1137 ////////// Abstract data operations //////////
1138
1139 #define ABSTRACT_DECL static FORCE_INLINE WARN_UNUSED_RESULT CONSTEXPR
1140
1141 #ifdef __cplusplus
1142 template <typename T, typename X, typename Y> ABSTRACT_DECL T clamp(T in, X min, Y max) { return in <= (T) min ? (T) min : (in >= (T) max ? (T) max : in); }
1143 template <typename T, typename X, typename Y> ABSTRACT_DECL T clamp2(T in, X min, Y max) { return in >= (T) max ? (T) max : (in <= (T) min ? (T) min : in); }
1144 using std::min;
1145 using std::max;
1146 # define fclamp clamp
1147 # define fclamp2 clamp2
1148 #else
1149 // Clamp <in> to [<min>..<max>]. The case in <= min is handled first.
1150 ABSTRACT_DECL int32_t clamp(int32_t in, int32_t min, int32_t max) { return in <= min ? min : (in >= max ? max : in); }
1151 ABSTRACT_DECL float fclamp(float in, float min, float max) { return in <= min ? min : (in >= max ? max : in); }
1152 // Clamp <in> to [<min>..<max>]. The case in >= max is handled first.
1153 ABSTRACT_DECL int32_t clamp2(int32_t in, int32_t min, int32_t max) { return in >= max ? max : (in <= min ? min : in); }
1154 ABSTRACT_DECL float fclamp2(float in, float min, float max) { return in >= max ? max : (in <= min ? min : in); }
1155
1156 #ifndef min
1157 # define min(a, b) (((a) < (b)) ? (a) : (b))
1158 #endif
1159 #ifndef max
1160 # define max(a, b) (((a) > (b)) ? (a) : (b))
1161 #endif
1162 #endif
1163
1164 ////////// Mathematical operations //////////
1165
1166 #ifdef __cplusplus
1167 #ifdef HAVE_CXX11_HEADERS
1168 template <typename T>
1169 struct DivResult
1170 {
1171 T q; // quotient
1172 T r; // remainder
1173 };
1174 template <typename T>
1175 FORCE_INLINE CONSTEXPR DivResult<T> divide(T lhs, T rhs)
1176 {
1177 return DivResult<T>{(T)(lhs / rhs), (T)(lhs % rhs)};
1178 }
1179 template <native_t base, typename T>
1180 FORCE_INLINE CONSTEXPR DivResult<T> divrhs(T lhs)
1181 {
1182 return divide(lhs, (T)base);
1183 }
1184
1185 template <typename T, typename T2>
1186 static FORCE_INLINE CONSTEXPR_CXX14 enable_if_t<is_signed<T>::value, T> NEGATE_ON_CONDITION(T value, T2 condition)
1187 {
1188 T const invert = !!condition;
1189 return (value ^ -invert) + invert;
1190 }
1191 #endif
1192
1193 template <size_t base, typename T>
1194 CONSTEXPR size_t logbase(T n)
1195 {
1196 return n < static_cast<T>(base) ? 1 : 1 + logbase<base>(n / static_cast<T>(base));
1197 }
1198 // hackish version to work around the impossibility of representing abs(INT*_MIN)
1199 template <size_t base, typename T>
1200 CONSTEXPR size_t logbasenegative(T n)
1201 {
1202 return n > static_cast<T>(-(native_t)base) ? 1 : 1 + logbase<base>(n / static_cast<T>(-(native_t)base));
1203 }
1204
1205 #endif
1206
1207 #define isPow2OrZero(v) (((v) & ((v) - 1)) == 0)
1208 #define isPow2(v) (isPow2OrZero(v) && (v))
1209
1210 ////////// Bitfield manipulation //////////
1211
1212 static CONSTEXPR const char pow2char[8] = {1,2,4,8,16,32,64,128u};
1213
1214 static FORCE_INLINE void bitmap_set(uint8_t *const ptr, int const n) { ptr[n>>3] |= pow2char[n&7]; }
1215 static FORCE_INLINE void bitmap_clear(uint8_t *const ptr, int const n) { ptr[n>>3] &= ~pow2char[n&7]; }
1216 static FORCE_INLINE CONSTEXPR char bitmap_test(uint8_t const *const ptr, int const n) { return ptr[n>>3] & pow2char[n&7]; }
1217
1218 ////////// Utility functions //////////
1219
1220 // breadth-first search helpers
1221 #ifdef __cplusplus
1222 template <typename T>
1223 void bfirst_search_init(T *const list, uint8_t *const bitmap, T *const eltnumptr, int const maxelts, int const firstelt)
1224 {
1225 Bmemset(bitmap, 0, (maxelts+7)>>3);
1226
1227 list[0] = firstelt;
1228 bitmap_set(bitmap, firstelt);
1229 *eltnumptr = 1;
1230 }
1231
1232 template <typename T>
1233 void bfirst_search_try(T *const list, uint8_t *const bitmap, T *const eltnumptr, int const elt)
1234 {
1235 if (!bitmap_test(bitmap, elt))
1236 {
1237 bitmap_set(bitmap, elt);
1238 list[(*eltnumptr)++] = elt;
1239 }
1240 }
1241 #endif
1242
1243 #if RAND_MAX == 32767
1244 static FORCE_INLINE uint16_t system_15bit_rand(void) { return (uint16_t)rand(); }
1245 #else // RAND_MAX > 32767, assumed to be of the form 2^k - 1
1246 static FORCE_INLINE uint16_t system_15bit_rand(void) { return ((uint16_t)rand())&0x7fff; }
1247 #endif
1248
1249 // Copy min(strlen(src)+1, n) characters into dst, always terminate with a NUL.
1250 static FORCE_INLINE char *Bstrncpyz(char *dst, const char *src, bsize_t n)
1251 {
1252 Bstrncpy(dst, src, n);
1253 dst[n-1] = 0;
1254 return dst;
1255 }
1256
1257 // Append extension when <outbuf> contains no dot.
1258 // <ext> can be like ".mhk" or like "_crash.map", no need to start with a dot.
1259 // The ugly name is deliberate: we should be checking the sizes of all buffers!
1260 static inline void append_ext_UNSAFE(char *outbuf, const char *ext)
1261 {
1262 char *p = Bstrrchr(outbuf,'.');
1263
1264 if (!p)
1265 Bstrcat(outbuf, ext);
1266 else
1267 Bstrcpy(p, ext);
1268 }
1269
1270 /* Begin dependence on compat.o object. */
1271
1272
1273 #ifdef __cplusplus
1274 extern "C" {
1275 #endif
1276
1277
1278 #ifndef USE_PHYSFS
1279 ////////// Directory enumeration //////////
1280
1281 struct Bdirent
1282 {
1283 char *name;
1284 uint32_t mode;
1285 uint32_t size;
1286 uint32_t mtime;
1287 uint16_t namlen;
1288 };
1289
1290 typedef void BDIR;
1291
1292 BDIR *Bopendir(const char *name);
1293 struct Bdirent *Breaddir(BDIR *dir);
1294 int32_t Bclosedir(BDIR *dir);
1295 #endif
1296
1297
1298 ////////// Paths //////////
1299
1300 char *Bgethomedir(void);
1301 char *Bgetappdir(void);
1302
1303 int32_t Bcorrectfilename(char *filename, int32_t removefn);
1304 int32_t Bcanonicalisefilename(char *filename, int32_t removefn);
1305
1306 char *Bgetsystemdrives(void);
1307
1308
1309 ////////// String manipulation //////////
1310
1311 char *Bstrtoken(char *s, const char *delim, char **ptrptr, int chop);
1312 char *Bstrtolower(char *str);
1313
1314 #define Bwildmatch wildmatch
1315
1316 #ifdef _WIN32
1317 # ifdef _MSC_VER
1318 # define Bstrlwr _strlwr
1319 # define Bstrupr _strupr
1320 # else
1321 # define Bstrlwr strlwr
1322 # define Bstrupr strupr
1323 # endif
1324 #else
1325 char *Bstrlwr(char *);
1326 char *Bstrupr(char *);
1327 #endif
1328
1329 ////////// Miscellaneous //////////
1330
1331 int Bgetpagesize(void);
1332 size_t Bgetsysmemsize(void);
1333
1334 ////////// PANICKING ALLOCATION WRAPPERS //////////
1335
1336 #ifdef DEBUGGINGAIDS
1337 extern void xalloc_set_location(int32_t line, const char *file, const char *func);
1338 #endif
1339 void set_memerr_handler(void (*handlerfunc)(int32_t, const char *, const char *));
1340 void *handle_memerr(void *);
1341
1342 static FORCE_INLINE char *xstrdup(const char *s)
1343 {
1344 char *ptr = Bstrdup(s);
1345 return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : (char *)handle_memerr(ptr);
1346 }
1347
1348 static FORCE_INLINE void *xmalloc(const bsize_t size)
1349 {
1350 void *ptr = Bmalloc(size);
1351 return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : handle_memerr(ptr);
1352 }
1353
1354 static FORCE_INLINE void *xcalloc(const bsize_t nmemb, const bsize_t size)
1355 {
1356 void *ptr = Bcalloc(nmemb, size);
1357 return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : handle_memerr(ptr);
1358 }
1359
1360 static FORCE_INLINE void *xrealloc(void * const ptr, const bsize_t size)
1361 {
1362 void *newptr = Brealloc(ptr, size);
1363
1364 // According to the C Standard,
1365 // - ptr == NULL makes realloc() behave like malloc()
1366 // - size == 0 make it behave like free() if ptr != NULL
1367 // Since we want to catch an out-of-mem in the first case, this leaves:
1368 return (EDUKE32_PREDICT_TRUE(newptr != NULL || size == 0)) ? newptr: handle_memerr(ptr);
1369 }
1370
1371 #if !defined NO_ALIGNED_MALLOC
1372 static FORCE_INLINE void *xaligned_alloc(const bsize_t alignment, const bsize_t size)
1373 {
1374 void *ptr = Baligned_alloc(alignment, size);
1375 return (EDUKE32_PREDICT_TRUE(ptr != NULL)) ? ptr : handle_memerr(ptr);
1376 }
1377
1378 static FORCE_INLINE void *xaligned_calloc(const bsize_t alignment, const bsize_t count, const bsize_t size)
1379 {
1380 bsize_t const blocksize = count * size;
1381 void *ptr = Baligned_alloc(alignment, blocksize);
1382 if (EDUKE32_PREDICT_TRUE(ptr != NULL))
1383 {
1384 Bmemset(ptr, 0, blocksize);
1385 return ptr;
1386 }
1387 return handle_memerr(ptr);
1388 }
1389 #else
1390 # define xaligned_alloc(alignment, size) xmalloc(size)
1391 # define xaligned_calloc(alignment, count, size) xcalloc(count, size)
1392 #endif
1393
1394 #ifdef DEBUGGINGAIDS
1395 # define EDUKE32_PRE_XALLOC xalloc_set_location(__LINE__, __FILE__, EDUKE32_FUNCTION),
1396 #else
1397 # define EDUKE32_PRE_XALLOC
1398 #endif
1399
1400 #define Xstrdup(s) (EDUKE32_PRE_XALLOC xstrdup(s))
1401 #define Xmalloc(size) (EDUKE32_PRE_XALLOC xmalloc(size))
1402 #define Xcalloc(nmemb, size) (EDUKE32_PRE_XALLOC xcalloc(nmemb, size))
1403 #define Xrealloc(ptr, size) (EDUKE32_PRE_XALLOC xrealloc(ptr, size))
1404 #define Xaligned_alloc(alignment, size) (EDUKE32_PRE_XALLOC xaligned_alloc(alignment, size))
1405 #define Xaligned_calloc(alignment, count, size) (EDUKE32_PRE_XALLOC xaligned_calloc(alignment, count, size))
1406 #define Xfree(ptr) (Bfree(ptr))
1407 #define Xaligned_free(ptr) (Baligned_free(ptr))
1408
1409 #ifdef __cplusplus
1410 }
1411 #endif
1412
1413
1414 ////////// More utility functions //////////
1415
1416 static inline void maybe_grow_buffer(char ** const buffer, int32_t * const buffersize, int32_t const newsize)
1417 {
1418 if (newsize > *buffersize)
1419 {
1420 *buffer = (char *)Xrealloc(*buffer, newsize);
1421 *buffersize = newsize;
1422 }
1423 }
1424
1425
1426 ////////// Inlined external libraries //////////
1427
1428 #ifndef LIBDIVIDE_BODY
1429 # define LIBDIVIDE_HEADER_ONLY
1430 #endif
1431 #define LIBDIVIDE_C_HEADERS
1432 #define LIBDIVIDE_NONAMESPACE
1433 #define LIBDIVIDE_NOINLINE
1434 #include "fix16.h"
1435 #include "libdivide.h"
1436
1437 #ifdef __cplusplus
1438 #include "clockticks.hpp"
1439 #endif
1440
1441 #include "debugbreak.h"
1442
1443 #include "zpl.h"
1444
1445 /* End dependence on compat.o object. */
1446
1447
1448 ////////// EDuke32-specific features //////////
1449
1450 #ifndef TRUE
1451 # define TRUE 1
1452 #endif
1453
1454 #ifndef FALSE
1455 # define FALSE 0
1456 #endif
1457
1458 #define WITHKPLIB
1459
1460 #if defined __ANDROID__ || defined EDUKE32_IOS
1461 # define EDUKE32_TOUCH_DEVICES
1462 # define EDUKE32_GLES
1463 #endif
1464
1465 #if DEBUGGINGAIDS>=2
1466 # define DEBUG_MAIN_ARRAYS
1467 #endif
1468
1469 #if !defined DEBUG_MAIN_ARRAYS
1470 # define HAVE_CLIPSHAPE_FEATURE
1471 #endif
1472
1473 #endif // compat_h_
1474