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(NONSTANDARD_PORT)
39 
40  // Ports which need to perform #includes and #defines visible in
41  // virtually all the source of ScummVM should do so by providing a
42  // "portdefs.h" header file (and not by directly modifying this
43  // header file).
44  #include <portdefs.h>
45 #else // defined(NONSTANDARD_PORT)
46 
47  #if defined(WIN32)
48 
49  #if defined(_MSC_VER) && _MSC_VER <= 1800
50 
51  // FIXME: The placement of the workaround functions for MSVC below
52  // require us to include stdio.h and stdarg.h for MSVC here. This
53  // is not exactly nice...
54  // We should think of a better way of doing this.
55  #include <stdio.h>
56  #include <stdarg.h>
57 
58  // MSVC's vsnprintf is either non-existent (2003) or bugged since it
59  // does not always include a terminating NULL (2005+). To work around
60  // that we fix up the _vsnprintf included. Note that the return value
61  // will still not match C99's specs!
62  inline int vsnprintf_msvc(char *str, size_t size, const char *format, va_list args) {
63  // We do not pass size - 1 here, to ensure we would get the same
64  // return value as when we would use _vsnprintf directly, since
65  // for example Common::String::format relies on this.
66  int retValue = _vsnprintf(str, size, format, args);
67  str[size - 1] = 0;
68  return retValue;
69  }
70 
71  #define vsnprintf vsnprintf_msvc
72 
73  // Visual Studio does not include snprintf in its standard C library.
74  // Instead it includes a function called _snprintf with somewhat
75  // similar semantics. The minor difference is that the return value in
76  // case the formatted string exceeds the buffer size is different.
77  // A much more dangerous one is that _snprintf does not always include
78  // a terminating null (Whoops!). Instead we map to our fixed vsnprintf.
79  inline int snprintf(char *str, size_t size, const char *format, ...) {
80  va_list args;
81  va_start(args, format);
82  int len = vsnprintf(str, size, format, args);
83  va_end(args);
84  return len;
85  }
86  #endif
87 
88  #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
89  #define NOGDICAPMASKS
90  #define OEMRESOURCE
91  #define NONLS
92  #define NOICONS
93  #define NOMCX
94  #define NOPROFILER
95  #define NOKANJI
96  #define NOSERVICE
97  #define NOMETAFILE
98  #define NOCOMM
99  #define NOCRYPT
100  #define NOIME
101  #define NOATOM
102  #define NOCTLMGR
103  #define NOCLIPBOARD
104  #define NOMEMMGR
105  #define NOSYSMETRICS
106  #define NOMENUS
107  #define NOOPENFILE
108  #define NOWH
109  #define NOSOUND
110  #define NODRAWTEXT
111  #define NOMINMAX 1
112 
113  #endif
114 
115  #if defined(__QNXNTO__)
116  #include <strings.h> /* For strcasecmp */
117  #endif
118 
119  #include <stdio.h>
120  #include <stdlib.h>
121  #include <string.h>
122  #include <stdarg.h>
123  #include <stddef.h>
124  #include <assert.h>
125  #include <ctype.h>
126  #include <limits.h>
127  // MSVC does not define M_PI, M_SQRT2 and other math defines by default.
128  // _USE_MATH_DEFINES must be defined in order to have these defined, thus
129  // we enable it here. For more information, check:
130  // https://docs.microsoft.com/en-us/cpp/c-runtime-library/math-constants
131  #define _USE_MATH_DEFINES
132  #include <math.h>
133 
134  // FIXME: We sadly can't assume standard C++ headers to be present on every
135  // system we support, so we should get rid of this. The solution should be to
136  // write a simple placement new on our own. It might be noteworthy we can't
137  // easily do that for systems which do have a <new>, since it might clash with
138  // the default definition otherwise!
139  #include <new>
140 
141  // After having discussion about use of std::numeric_limits in
142  // https://github.com/scummvm/scummvm/pull/3966 we concluded that it is safe to
143  // use it as minimal STL code with low probability to bring any incompatibilities
144  #include <limits>
145 #endif
146 
147 #ifndef STATIC_ASSERT
148 #if __cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER > 1600)
149 
156  #define STATIC_ASSERT(expression, message) \
157  static_assert((expression), #message)
158 #else
159 
166  #define STATIC_ASSERT(expression, message) \
167  do { \
168  extern int STATIC_ASSERT_##message[(expression) ? 1 : -1]; \
169  (void)(STATIC_ASSERT_##message); \
170  } while (false)
171 #endif
172 #endif
173 
174 // The following math constants are usually defined by the system math.h header, but
175 // they are not part of the ANSI C++ standards and so can NOT be relied upon to be
176 // present i.e. when -std=c++11 is passed to GCC, enabling strict ANSI compliance.
177 // As we rely on these being present, we define them if they are not set.
178 
179 #ifndef M_E
180  #define M_E 2.7182818284590452354 /* e */
181 #endif
182 
183 #ifndef M_LOG2E
184  #define M_LOG2E 1.4426950408889634074 /* log_2 e */
185 #endif
186 
187 #ifndef M_LOG10E
188  #define M_LOG10E 0.43429448190325182765 /* log_10 e */
189 #endif
190 
191 #ifndef M_LN2
192  #define M_LN2 0.69314718055994530942 /* log_e 2 */
193 #endif
194 
195 #ifndef M_LN10
196  #define M_LN10 2.30258509299404568402 /* log_e 10 */
197 #endif
198 
199 #ifndef M_PI
200  #define M_PI 3.14159265358979323846 /* pi */
201 #endif
202 
203 #ifndef M_PI_2
204  #define M_PI_2 1.57079632679489661923 /* pi/2 */
205 #endif
206 
207 #ifndef M_PI_4
208  #define M_PI_4 0.78539816339744830962 /* pi/4 */
209 #endif
210 
211 #ifndef M_1_PI
212  #define M_1_PI 0.31830988618379067154 /* 1/pi */
213 #endif
214 
215 #ifndef M_2_PI
216  #define M_2_PI 0.63661977236758134308 /* 2/pi */
217 #endif
218 
219 #ifndef M_2_SQRTPI
220  #define M_2_SQRTPI 1.12837916709551257390 /* 2/sqrt(pi) */
221 #endif
222 
223 #ifndef M_SQRT2
224  #define M_SQRT2 1.41421356237309504880 /* sqrt(2) */
225 #endif
226 
227 #ifndef M_SQRT1_2
228  #define M_SQRT1_2 0.70710678118654752440 /* 1/sqrt(2) */
229 #endif
230 
231 // Use config.h, generated by configure
232 #if defined(HAVE_CONFIG_H)
233 #include "config.h"
234 #endif
235 
236 
237 // In the following we configure various targets, in particular those
238 // which can't use our "configure" tool and hence don't use config.h.
239 //
240 // Some #defines that occur here frequently:
241 // SCUMM_LITTLE_ENDIAN
242 // - Define this on a little endian target
243 // SCUMM_BIG_ENDIAN
244 // - Define this on a big endian target
245 // SCUMM_NEED_ALIGNMENT
246 // - Define this if your system has problems reading e.g. an int32 from an odd address
247 // SMALL_SCREEN_DEVICE
248 // - ...
249 // ...
250 
251 
252 //
253 // By default we try to use pragma push/pop to ensure various structs we use
254 // are "packed". If your compiler doesn't support this pragma, you are in for
255 // a problem. If you are lucky, there is a compiler switch, or another pragma,
256 // doing the same thing -- in that case, try to modify common/pack-begin.h and
257 // common/pack-end.h accordingly. Or maybe your port simply *always* packs
258 // everything, in which case you could #undefine SCUMMVM_USE_PRAGMA_PACK.
259 //
260 // If neither is possible, tough luck. Try to contact the team, maybe we can
261 // come up with a solution, though I wouldn't hold my breath on it :-/.
262 //
263 #define SCUMMVM_USE_PRAGMA_PACK
264 
265 //
266 // Determine the host endianess and whether memory alignment is required.
267 //
268 #if !defined(HAVE_CONFIG_H)
269 
270  // If -fsanitize=undefined or -fsanitize=alignment is in use, and the
271  // compiler happens to report it, make sure SCUMM_NEED_ALIGNMENT is
272  // defined, in order to avoid false positives when not using the
273  // "configure" script to enable UBSan.
274  #if __has_feature(undefined_behavior_sanitizer)
275  #define SCUMM_NEED_ALIGNMENT
276  #endif
277 
278  #if defined(__DC__) || \
279  defined(__DS__) || \
280  defined(__3DS__) || \
281  defined(IPHONE) || \
282  defined(__PSP__)
283 
284  #define SCUMM_LITTLE_ENDIAN
285  #define SCUMM_NEED_ALIGNMENT
286 
287  #elif defined(_MSC_VER) || defined(__MINGW32__)
288 
289  #define SCUMM_LITTLE_ENDIAN
290 
291  #elif defined(__MORPHOS__) || defined(__amigaos4__) || defined(__N64__) || defined(__WII__)
292 
293  #define SCUMM_BIG_ENDIAN
294  #define SCUMM_NEED_ALIGNMENT
295 
296  #elif defined(SDL_BACKEND)
297  // On SDL based ports, we try to use SDL_BYTEORDER to determine the
298  // endianess. We explicitly do this as the *last* thing we try, so that
299  // platform specific settings have precedence.
300  #include <SDL_endian.h>
301 
302  #if SDL_BYTEORDER == SDL_LIL_ENDIAN
303  #define SCUMM_LITTLE_ENDIAN
304  #elif SDL_BYTEORDER == SDL_BIG_ENDIAN
305  #define SCUMM_BIG_ENDIAN
306  #else
307  #error Neither SDL_BIG_ENDIAN nor SDL_LIL_ENDIAN is set.
308  #endif
309 
310  #else
311 
312  #error No system type defined, host endianess unknown.
313 
314  #endif
315 #endif
316 
317 #if !defined(SCUMM_FLOAT_WORD_LITTLE_ENDIAN) && !defined(SCUMM_FLOAT_WORD_BIG_ENDIAN)
318 
319  #if defined(__ORDER_LITTLE_ENDIAN__) && defined(__ORDER_BIG_ENDIAN__) && defined(__FLOAT_WORD_ORDER__)
320 
321  #if (__FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__)
322  #define SCUMM_FLOAT_WORD_LITTLE_ENDIAN
323  #elif (__FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__)
324  #define SCUMM_FLOAT_WORD_BIG_ENDIAN
325  #else
326  #error Unsupported endianness
327  #endif
328 
329  #else
330  #ifdef SCUMM_LITTLE_ENDIAN
331  #define SCUMM_FLOAT_WORD_LITTLE_ENDIAN
332  #else
333  #define SCUMM_FLOAT_WORD_BIG_ENDIAN
334  #endif
335 
336  #endif
337 #endif
338 
339 //
340 // Some more system specific settings.
341 // TODO/FIXME: All of these should be moved to backend specific files (such as portdefs.h)
342 //
343 #if defined(DINGUX)
344 
345  // Very BAD hack following, used to avoid triggering an assert in uClibc dingux library
346  // "toupper" when pressing keyboard function keys.
347  #undef toupper
348  #define toupper(c) __extension__ ({ auto _x = ((c) & 0xFF); (_x >= 97 && _x <= 122) ? (_x - 32) : _x; })
349 
350 #elif defined(__PSP__)
351 
352  #include <malloc.h>
353  #include "backends/platform/psp/memory.h"
354 
355  /* to make an efficient, inlined memcpy implementation */
356  #define memcpy(dst, src, size) psp_memcpy(dst, src, size)
357 
358 #endif
359 
360 #if defined(USE_TREMOR) && !defined(USE_VORBIS)
361 #define USE_VORBIS // make sure this one is defined together with USE_TREMOR!
362 #endif
363 
364 //
365 // Fallbacks / default values for various special macros
366 //
367 #ifndef GCC_PRINTF
368  #if defined(__GNUC__) || defined(__INTEL_COMPILER)
369  #if defined(__USE_MINGW_ANSI_STDIO) && __USE_MINGW_ANSI_STDIO && !defined(__clang__)
370  #define GCC_PRINTF(x,y) __attribute__((__format__(__gnu_printf__, x, y)))
371  #else
372  #define GCC_PRINTF(x,y) __attribute__((__format__(__printf__, x, y)))
373  #endif
374  #else
375  #define GCC_PRINTF(x,y)
376  #endif
377 #endif
378 
379 #ifndef MSVC_PRINTF
380  #if defined(_MSC_VER) && _MSC_VER > 1400
381  #define MSVC_PRINTF _Printf_format_string_
382  #else
383  #define MSVC_PRINTF
384  #endif
385 #endif
386 
387 #ifndef PACKED_STRUCT
388  #if defined(__GNUC__) || defined(__INTEL_COMPILER)
389  #define PACKED_STRUCT __attribute__((__packed__))
390  #else
391  #define PACKED_STRUCT
392  #endif
393 #endif
394 
395 #ifndef FORCEINLINE
396  #if defined(_MSC_VER)
397  #define FORCEINLINE __forceinline
398  #elif defined(__GNUC__)
399  #define FORCEINLINE inline __attribute__((__always_inline__))
400  #else
401  #define FORCEINLINE inline
402  #endif
403 #endif
404 
405 #ifndef PLUGIN_EXPORT
406  #if defined(_MSC_VER) || defined(__MINGW32__)
407  #define PLUGIN_EXPORT __declspec(dllexport)
408  #else
409  #define PLUGIN_EXPORT
410  #endif
411 #endif
412 
413 #ifndef NORETURN_PRE
414  #if defined(_MSC_VER)
415  #define NORETURN_PRE __declspec(noreturn)
416  #elif defined(__GNUC__)
417  #define NORETURN_PRE __attribute__((__noreturn__))
418  #else
419  #define NORETURN_PRE
420  #endif
421 #endif
422 
423 #ifndef NORETURN_POST
424  #if defined(__INTEL_COMPILER)
425  #define NORETURN_POST __attribute__((__noreturn__))
426  #else
427  #define NORETURN_POST
428  #endif
429 #endif
430 
431 #ifndef WARN_UNUSED_RESULT
432  #if __cplusplus >= 201703L
433  #define WARN_UNUSED_RESULT [[nodiscard]]
434  #elif defined(__GNUC__)
435  #define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
436  #elif defined(_Check_return_)
437  #define WARN_UNUSED_RESULT _Check_return_
438  #else
439  #define WARN_UNUSED_RESULT
440  #endif
441 #endif
442 
443 #ifndef WARN_DEPRECATED
444  #if __cplusplus >= 201703L
445  #define WARN_DEPRECATED(msg) [[deprecated(msg)]]
446  #elif defined(__GNUC__)
447  #define WARN_DEPRECATED(msg) __attribute__((__deprecated__(msg)))
448  #elif defined(_MSC_VER)
449  #define WARN_DEPRECATED(msg) __declspec(deprecated(msg))
450  #else
451  #define WARN_DEPRECATED(msg)
452  #endif
453 #endif
454 
455 #ifndef STRINGBUFLEN
456  #if defined(__N64__) || defined(__DS__) || defined(__3DS__)
457  #define STRINGBUFLEN 256
458  #else
459  #define STRINGBUFLEN 1024
460  #endif
461 #endif
462 
463 #ifndef MAXPATHLEN
464 #define MAXPATHLEN 256
465 #endif
466 
467 #ifndef scumm_va_copy
468  #if defined(va_copy)
469  #define scumm_va_copy va_copy
470  #elif defined(__va_copy)
471  #define scumm_va_copy __va_copy
472  #elif defined(_MSC_VER)
473  #define scumm_va_copy(dst, src) ((dst) = (src))
474  #else
475  #error scumm_va_copy undefined for this port
476  #endif
477 #endif
478 
479 
480 
481 //
482 // Typedef our system types unless they have already been defined by config.h,
483 // or SCUMMVM_DONT_DEFINE_TYPES is set.
484 //
485 #if !defined(HAVE_CONFIG_H) && !defined(SCUMMVM_DONT_DEFINE_TYPES)
486  typedef unsigned char byte;
487  typedef unsigned char uint8;
488  typedef signed char int8;
489  typedef unsigned short uint16;
490  typedef signed short int16;
491  // HACK: Some ports, such as NDS and AmigaOS, are not frequently
492  // tested during development, but cause frequent buildbot failures
493  // because they need to use 'long' for int32. Windows 32-bit
494  // binaries have this nice property of being easy to build, having
495  // a 32-bit 'long' too, *and* being frequently tested (incl. Github
496  // Actions). We want to catch this case as early and frequently
497  // as possible, so Win32 is probably the best candidate for this...
498  #if defined(WIN32) && !defined(_WIN64)
499  typedef unsigned long uint32;
500  typedef signed long int32;
501  #else
502  typedef unsigned int uint32;
503  typedef signed int int32;
504  #endif
505  typedef unsigned int uint;
506  typedef signed long long int64;
507  typedef unsigned long long uint64;
508 #endif
509 
510 //
511 // Determine 64 bitness
512 // Reference: https://web.archive.org/web/20190413073704/http://nadeausoftware.com/articles/2012/02/c_c_tip_how_detect_processor_type_using_compiler_predefined_macros
513 //
514 #if !defined(HAVE_CONFIG_H)
515 
516 #if defined(__x86_64__) || \
517  defined(_M_X64) || \
518  defined(__ppc64__) || \
519  defined(__powerpc64__) || \
520  defined(__LP64__) || \
521  defined(_M_ARM64)
522 
523 typedef int64 intptr;
524 typedef uint64 uintptr;
525 
526 #else
527 
528 typedef int32 intptr;
529 typedef uint32 uintptr;
530 
531 #endif
532 
533 #endif
534 
535 //
536 // std::nullptr_t when this type is not available
537 //
538 #if defined(NO_CXX11_NULLPTR_T)
539 namespace std {
540  typedef decltype(nullptr) nullptr_t;
541 }
542 #endif
543 
544 //
545 // std::initializer_list
546 // Provide replacement when not available
547 //
548 #if defined(NO_CXX11_INITIALIZER_LIST)
549 namespace std {
550  template<class T> class initializer_list {
551  public:
552  typedef T value_type;
553  typedef const T &reference;
554  typedef const T &const_reference;
555  typedef size_t size_type;
556  typedef const T *iterator;
557  typedef const T *const_iterator;
558 
559  constexpr initializer_list() noexcept = default;
560  constexpr size_t size() const noexcept { return _size; };
561  constexpr const T *begin() const noexcept { return _begin; };
562  constexpr const T *end() const noexcept { return _begin + _size; }
563 
564  private:
565  // Note: begin has to be first or the compiler may get very upset
566  const T *_begin = { nullptr };
567  size_t _size = { 0 };
568 
569  // The compiler is allowed to call this constructor
570  constexpr initializer_list(const T* t, size_t s) noexcept : _begin(t) , _size(s) {}
571  };
572 
573  template<class T> constexpr const T* begin(initializer_list<T> il) noexcept {
574  return il.begin();
575  }
576 
577  template<class T> constexpr const T* end(initializer_list<T> il) noexcept {
578  return il.end();
579  }
580 }
581 
582 #else
583 
584 #include <initializer_list>
585 
586 #endif // NO_CXX11_INITIALIZER_LIST
587 
588 #include "common/forbidden.h"
589 
590 #endif