ScummVM API documentation
scummsys.h
1/* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 */
21
22#ifndef COMMON_SCUMMSYS_H
23#define COMMON_SCUMMSYS_H
24
25#ifndef __has_feature // Optional of course.
26 #define __has_feature(x) 0 // Compatibility with non-clang compilers.
27#endif
28
29// This is a convenience macro to test whether the compiler used is a GCC
30// version, which is at least major.minor. Note that Clang will also define
31// it and report itself as GCC 4.2.1.
32#ifdef __GNUC__
33 #define GCC_ATLEAST(major, minor) (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor)))
34#else
35 #define GCC_ATLEAST(major, minor) 0
36#endif
37
38#if defined(_MSC_VER) && _MSC_VER < 1900
39 #error MSVC support requires MSVC 2015 or newer
40#endif
41
42#if defined(NONSTANDARD_PORT)
43
44 // Ports which need to perform #includes and #defines visible in
45 // virtually all the source of ScummVM should do so by providing a
46 // "portdefs.h" header file (and not by directly modifying this
47 // header file).
48 #include <portdefs.h>
49#else // defined(NONSTANDARD_PORT)
50
51 #if defined(WIN32)
52
53 #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
54 #define NOGDICAPMASKS
55 #define OEMRESOURCE
56 #define NONLS
57 #define NOICONS
58 #define NOMCX
59 #define NOPROFILER
60 #define NOKANJI
61 #define NOSERVICE
62 #define NOMETAFILE
63 #define NOCOMM
64 #define NOCRYPT
65 #define NOIME
66 #define NOATOM
67 #define NOCTLMGR
68 #define NOCLIPBOARD
69 #define NOMEMMGR
70 #define NOSYSMETRICS
71 #define NOMENUS
72 #define NOOPENFILE
73 #define NOWH
74 #define NOSOUND
75 #define NODRAWTEXT
76 #define NOMINMAX 1
77
78 #endif
79
80 #if defined(__QNXNTO__)
81 #include <strings.h> /* For strcasecmp */
82 #endif
83
84 #include <stdio.h>
85 #include <stdlib.h>
86 #include <string.h>
87 #include <stdarg.h>
88 #include <stddef.h>
89 #include <assert.h>
90 #include <ctype.h>
91
92 // In C99, the following macros were necessary to get some <inttypes.h>
93 // features we want. The C++11 standard removed this requirement, but in
94 // practice, some systems (such as RISC OS or macOS < 10.7) are not fully
95 // compliant, and still require the old defines.
96 #define __STDC_CONSTANT_MACROS
97 #define __STDC_FORMAT_MACROS
98 #define __STDC_LIMIT_MACROS
99 #include <inttypes.h>
100
101 // macOS 10.4 inttypes.h woes -- fixed in 10.5 SDK
102 #if defined(MACOSX) && defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1050
103 #undef __PRI_8_LENGTH_MODIFIER__
104 #undef __PRI_64_LENGTH_MODIFIER__
105 #undef __SCN_64_LENGTH_MODIFIER__
106 #define __PRI_8_LENGTH_MODIFIER__ "hh"
107 #define __PRI_64_LENGTH_MODIFIER__ "ll"
108 #define __SCN_64_LENGTH_MODIFIER__ "ll"
109 #endif
110
111 #include <limits.h>
112
113 // MSVC does not define M_PI, M_SQRT2 and other math defines by default.
114 // _USE_MATH_DEFINES must be defined in order to have these defined, thus
115 // we enable it here. For more information, check:
116 // https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants
117 #define _USE_MATH_DEFINES
118 #include <math.h>
119
120 // FIXME: We sadly can't assume standard C++ headers to be present on every
121 // system we support, so we should get rid of this. The solution should be to
122 // write a simple placement new on our own. It might be noteworthy we can't
123 // easily do that for systems which do have a <new>, since it might clash with
124 // the default definition otherwise!
125 #include <new>
126
127 // After having discussion about use of std::numeric_limits in
128 // https://github.com/scummvm/scummvm/pull/3966 we concluded that it is safe to
129 // use it as minimal STL code with low probability to bring any incompatibilities
130 #include <limits>
131#endif
132
133// The following math constants are usually defined by the system math.h header, but
134// they are not part of the ANSI C++ standards and so can NOT be relied upon to be
135// present i.e. when -std=c++11 is passed to GCC, enabling strict ANSI compliance.
136// As we rely on these being present, we define them if they are not set.
137
138#ifndef M_E
139 #define M_E 2.7182818284590452354 /* e */
140#endif
141
142#ifndef M_LOG2E
143 #define M_LOG2E 1.4426950408889634074 /* log_2 e */
144#endif
145
146#ifndef M_LOG10E
147 #define M_LOG10E 0.43429448190325182765 /* log_10 e */
148#endif
149
150#ifndef M_LN2
151 #define M_LN2 0.69314718055994530942 /* log_e 2 */
152#endif
153
154#ifndef M_LN10
155 #define M_LN10 2.30258509299404568402 /* log_e 10 */
156#endif
157
158#ifndef M_PI
159 #define M_PI 3.14159265358979323846 /* pi */
160#endif
161
162#ifndef M_PI_2
163 #define M_PI_2 1.57079632679489661923 /* pi/2 */
164#endif
165
166#ifndef M_PI_4
167 #define M_PI_4 0.78539816339744830962 /* pi/4 */
168#endif
169
170#ifndef M_1_PI
171 #define M_1_PI 0.31830988618379067154 /* 1/pi */
172#endif
173
174#ifndef M_2_PI
175 #define M_2_PI 0.63661977236758134308 /* 2/pi */
176#endif
177
178#ifndef M_2_SQRTPI
179 #define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
180#endif
181
182#ifndef M_SQRT2
183 #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
184#endif
185
186#ifndef M_SQRT1_2
187 #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
188#endif
189
190// Use config.h, generated by configure
191#if defined(HAVE_CONFIG_H)
192#include "config.h"
193#endif
194
195
196// In the following we configure various targets, in particular those
197// which can't use our "configure" tool and hence don't use config.h.
198//
199// Some #defines that occur here frequently:
200// SCUMM_LITTLE_ENDIAN
201// - Define this on a little endian target
202// SCUMM_BIG_ENDIAN
203// - Define this on a big endian target
204// SCUMM_NEED_ALIGNMENT
205// - Define this if your system has problems reading e.g. an int32 from an odd address
206// SMALL_SCREEN_DEVICE
207// - ...
208// ...
209
210//
211// If -fsanitize=alignment is in use (or UBSan enabled it), and the compiler
212// happens to report it, make sure SCUMM_NEED_ALIGNMENT is defined, in order
213// to avoid false positives. `alignment_sanitizer` may not be reported in
214// earlier releases though, so look for the UBSan flag in that case.
215//
216#if __has_feature(alignment_sanitizer) || __has_feature(undefined_behavior_sanitizer)
217 #define SCUMM_NEED_ALIGNMENT
218#endif
219
220//
221// By default we try to use pragma push/pop to ensure various structs we use
222// are "packed". If your compiler doesn't support this pragma, you are in for
223// a problem. If you are lucky, there is a compiler switch, or another pragma,
224// doing the same thing -- in that case, try to modify common/pack-begin.h and
225// common/pack-end.h accordingly. Or maybe your port simply *always* packs
226// everything, in which case you could #undefine SCUMMVM_USE_PRAGMA_PACK.
227//
228// If neither is possible, tough luck. Try to contact the team, maybe we can
229// come up with a solution, though I wouldn't hold my breath on it :-/.
230//
231#define SCUMMVM_USE_PRAGMA_PACK
232
233//
234// Determine the host endianess and whether memory alignment is required.
235//
236#if !defined(HAVE_CONFIG_H)
237
238 #if defined(__DC__) || \
239 defined(__DS__) || \
240 defined(__3DS__) || \
241 defined(IPHONE) || \
242 defined(__PSP__)
243
244 #define SCUMM_LITTLE_ENDIAN
245 #define SCUMM_NEED_ALIGNMENT
246
247 #elif defined(_MSC_VER) || defined(__MINGW32__)
248
249 #define SCUMM_LITTLE_ENDIAN
250
251 #elif defined(__MORPHOS__) || defined(__amigaos4__) || defined(__N64__) || defined(__WII__)
252
253 #define SCUMM_BIG_ENDIAN
254 #define SCUMM_NEED_ALIGNMENT
255
256 #elif defined(SDL_BACKEND)
257 // On SDL based ports, we try to use SDL_BYTEORDER to determine the
258 // endianess. We explicitly do this as the *last* thing we try, so that
259 // platform specific settings have precedence.
260 #include <SDL_endian.h>
261
262 #if SDL_BYTEORDER == SDL_LIL_ENDIAN
263 #define SCUMM_LITTLE_ENDIAN
264 #elif SDL_BYTEORDER == SDL_BIG_ENDIAN
265 #define SCUMM_BIG_ENDIAN
266 #else
267 #error Neither SDL_BIG_ENDIAN nor SDL_LIL_ENDIAN is set.
268 #endif
269
270 #else
271
272 #error No system type defined, host endianess unknown.
273
274 #endif
275#endif
276
277#if !defined(SCUMM_FLOAT_WORD_LITTLE_ENDIAN) && !defined(SCUMM_FLOAT_WORD_BIG_ENDIAN)
278
279 #if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
280
281 #if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
282 #define SCUMM_FLOAT_WORD_LITTLE_ENDIAN
283 #elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
284 #define SCUMM_FLOAT_WORD_BIG_ENDIAN
285 #else
286 #error Unsupported endianness
287 #endif
288
289 #else
290 #ifdef SCUMM_LITTLE_ENDIAN
291 #define SCUMM_FLOAT_WORD_LITTLE_ENDIAN
292 #else
293 #define SCUMM_FLOAT_WORD_BIG_ENDIAN
294 #endif
295
296 #endif
297#endif
298
299#if defined(USE_TREMOR) && !defined(USE_VORBIS)
300#define USE_VORBIS // make sure this one is defined together with USE_TREMOR!
301#endif
302
303//
304// Fallbacks / default values for various special macros
305//
306#ifndef GCC_PRINTF
307 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
308 #if defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO && !defined(__clang__)
309 #define GCC_PRINTF(x,y) __attribute__((__format__(__gnu_printf__, x, y)))
310 #else
311 #define GCC_PRINTF(x,y) __attribute__((__format__(__printf__, x, y)))
312 #endif
313 #else
314 #define GCC_PRINTF(x,y)
315 #endif
316#endif
317
318#ifndef MSVC_PRINTF
319 #if defined(_MSC_VER)
320 #define MSVC_PRINTF _Printf_format_string_
321 #else
322 #define MSVC_PRINTF
323 #endif
324#endif
325
326#ifndef PACKED_STRUCT
327 #if defined(__GNUC__) || defined(__INTEL_COMPILER)
328 #define PACKED_STRUCT __attribute__((__packed__))
329 #else
330 #define PACKED_STRUCT
331 #endif
332#endif
333
334#ifndef FORCEINLINE
335 #if defined(_MSC_VER)
336 #define FORCEINLINE __forceinline
337 #elif defined(__GNUC__)
338 #define FORCEINLINE inline __attribute__((__always_inline__))
339 #else
340 #define FORCEINLINE inline
341 #endif
342#endif
343
344#ifndef PLUGIN_EXPORT
345 #if defined(_MSC_VER) || defined(__MINGW32__)
346 #define PLUGIN_EXPORT __declspec(dllexport)
347 #else
348 #define PLUGIN_EXPORT
349 #endif
350#endif
351
352#ifndef NORETURN_PRE
353 #if defined(_MSC_VER)
354 #define NORETURN_PRE __declspec(noreturn)
355 #elif defined(__GNUC__)
356 #define NORETURN_PRE __attribute__((__noreturn__))
357 #else
358 #define NORETURN_PRE
359 #endif
360#endif
361
362#ifndef NORETURN_POST
363 #if defined(__INTEL_COMPILER)
364 #define NORETURN_POST __attribute__((__noreturn__))
365 #else
366 #define NORETURN_POST
367 #endif
368#endif
369
370#ifndef WARN_UNUSED_RESULT
371 #if __cplusplus >= 201703L
372 #define WARN_UNUSED_RESULT [[nodiscard]]
373 #elif defined(__GNUC__)
374 #define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
375 #elif defined(_Check_return_)
376 #define WARN_UNUSED_RESULT _Check_return_
377 #else
378 #define WARN_UNUSED_RESULT
379 #endif
380#endif
381
382#ifndef WARN_DEPRECATED
383 #if __cplusplus >= 201703L
384 #define WARN_DEPRECATED(msg) [[deprecated(msg)]]
385 #elif defined(__GNUC__)
386 #define WARN_DEPRECATED(msg) __attribute__((__deprecated__(msg)))
387 #elif defined(_MSC_VER)
388 #define WARN_DEPRECATED(msg) __declspec(deprecated(msg))
389 #else
390 #define WARN_DEPRECATED(msg)
391 #endif
392#endif
393
394#ifndef STRINGBUFLEN
395 #if defined(__N64__) || defined(__DS__) || defined(__3DS__)
396 #define STRINGBUFLEN 256
397 #else
398 #define STRINGBUFLEN 1024
399 #endif
400#endif
401
402#ifndef MAXPATHLEN
403#define MAXPATHLEN 256
404#endif
405
406#ifndef scumm_va_copy
407 #if defined(va_copy)
408 #define scumm_va_copy va_copy
409 #elif defined(__va_copy)
410 #define scumm_va_copy __va_copy
411 #elif defined(_MSC_VER)
412 #define scumm_va_copy(dst, src) ((dst) = (src))
413 #else
414 #error scumm_va_copy undefined for this port
415 #endif
416#endif
417
418
419
420//
421// Typedef our system types unless SCUMMVM_DONT_DEFINE_TYPES is set.
422// This is usually due to conflicts with the system headers.
423//
424#ifndef SCUMMVM_DONT_DEFINE_TYPES
425 typedef unsigned char byte;
426 typedef unsigned int uint;
427
428 typedef uint8_t uint8;
429 typedef int8_t int8;
430 typedef uint16_t uint16;
431 typedef int16_t int16;
432#if defined(__3DS__) || defined(__DC__) || defined(__PSP__)
437 typedef unsigned int uint32;
438 typedef int int32;
439#elif defined(__amigaos4__) || defined(__MORPHOS__)
445 typedef unsigned long uint32;
446 typedef signed long int32;
447#else
448 typedef uint32_t uint32;
449 typedef int32_t int32;
450#endif
451 typedef uint64_t uint64;
452 typedef int64_t int64;
453 typedef uintptr_t uintptr;
454 typedef intptr_t intptr;
455#endif
456
457//
458// std::nullptr_t when unavailable (e.g. the compiler supports C++11,
459// but the standard library is older and has incomplete C++11 support)
460//
461#if defined(NO_CXX11_NULLPTR_T)
462namespace std {
463 typedef decltype(nullptr) nullptr_t;
464}
465#endif
466
467//
468// std::initializer_list when unavailable (e.g. the compiler supports C++11,
469// but the standard library is older and has incomplete C++11 support)
470//
471#if defined(NO_CXX11_INITIALIZER_LIST)
472namespace std {
473 template<class T> class initializer_list {
474 public:
475 typedef T value_type;
476 typedef const T &reference;
477 typedef const T &const_reference;
478 typedef size_t size_type;
479 typedef const T *iterator;
480 typedef const T *const_iterator;
481
482 constexpr initializer_list() noexcept = default;
483 constexpr size_t size() const noexcept { return _size; };
484 constexpr const T *begin() const noexcept { return _begin; };
485 constexpr const T *end() const noexcept { return _begin + _size; }
486
487 private:
488 // Note: begin has to be first or the compiler may get very upset
489 const T *_begin = { nullptr };
490 size_t _size = { 0 };
491
492 // The compiler is allowed to call this constructor
493 constexpr initializer_list(const T* t, size_t s) noexcept : _begin(t) , _size(s) {}
494 };
495
496 template<class T> constexpr const T* begin(initializer_list<T> il) noexcept {
497 return il.begin();
498 }
499
500 template<class T> constexpr const T* end(initializer_list<T> il) noexcept {
501 return il.end();
502 }
503}
504
505#else
506
507#include <initializer_list>
508
509#endif // NO_CXX11_INITIALIZER_LIST
510
511//
512// Some more system specific settings.
513// TODO/FIXME: All of these should be moved to backend specific files (such as portdefs.h)
514//
515#if defined(DINGUX)
516
517 // Very BAD hack following, used to avoid triggering an assert in uClibc dingux library
518 // "toupper" when pressing keyboard function keys.
519 #undef toupper
520 #define toupper(c) __extension__ ({ auto _x = ((c) & 0xFF); (_x >= 97 && _x <= 122) ? (_x - 32) : _x; })
521
522#elif defined(__PSP__)
523
524 #include <malloc.h>
525 #include "backends/platform/psp/memory.h"
526
527 /* to make an efficient, inlined memcpy implementation */
528 #define memcpy(dst, src, size) psp_memcpy(dst, src, size)
529
530#endif
531
532#include "common/forbidden.h"
533
534#endif