Improve handling variables, which can be either string or string array.
[build.git] / src / system.h
blob0f7c5fc74bf9488c42ef5562b9be1571951b7e07
1 /* system.h -- system-independent miscellaneous defines.
3 Copyright (C) 2022 Sergey Sushilin <sergeysushilin@protonmail.com>
5 This file is part of Build.
7 Build is free software: you can redistribute it and/or
8 modify it under the terms of either the GNU General Public License
9 as published by the Free Software Foundation;
10 either version 2 of the License, or version 3 of the License,
11 or both in parallel, as here.
13 Build is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received copies of the GNU General Public License
19 version 2 and 3 along with this program.
20 If not, see http://www.gnu.org/licenses/. */
22 #pragma once
24 #if !defined (_WIN32) && !defined (_POSIX_C_SOURCE)
25 # error unsupported host.
26 #endif
28 #define bool _Bool
29 #define true (bool) +1u
30 #define false (bool) +0u
32 #define alignas(alignment) _Alignas (alignment)
33 #define alignof(expression) _Alignof (expression)
35 #if !defined (static_assert)
36 # define static_assert _Static_assert
37 #endif
39 #ifdef _WIN32
40 # define PRIuSIZE "%Iu"
41 #else
42 # define PRIuSIZE "%zu"
43 #endif
45 #ifdef _WIN32
46 # define file_offset_t __int64
47 # define file_set_offset _fseeki64
48 # define file_get_offset _ftelli64
49 #else
50 # include <sys/types.h>
51 # define file_offset_t off_t
52 # define file_set_offset fseeko
53 # define file_get_offset ftello
54 #endif
56 #ifdef _WIN32
57 # include <windows.h>
58 #endif
60 #if (defined (__i386) || defined (__amd64) || defined (__powerpc__)) && defined (__GNUC__)
61 # if defined (__clang__)
62 # define HAVE_ATOMIC 1
63 # endif
64 # if defined (__GLIBC__) && defined (__GLIBC_PREREQ)
65 # if (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC__ >= 1)) && __GLIBC_PREREQ (2, 6)
66 # define HAVE_ATOMIC 1
67 # endif
68 # endif
69 #endif
71 #if HAVE_ATOMIC || defined (__TINYC__)
72 # include <stdatomic.h>
74 # define atomic_exchange_acquire(object, value) \
75 atomic_exchange_explicit ((object), (value), memory_order_acquire)
77 # define atomic_load_relaxed(object) \
78 atomic_load_explicit ((object), memory_order_relaxed)
80 # define atomic_store_release(object, value) \
81 atomic_store_explicit ((object), (value), memory_order_release)
83 //# define atomic _Atomic
84 #elif defined (_WIN32)
85 # define atomic_init(object, value) \
86 do \
87 { \
88 *(object) = (value); \
89 } \
90 while (0)
92 #define atomic_store(object, value) \
93 InterlockedExchange (object, value)
95 #define atomic_load(object) \
96 InterlockedOr (object, 0)
98 # define atomic_increment(object) \
99 InterlockedIncrement (object)
101 # define atomic_decrement(object) \
102 InterlockedDecrement (object)
104 # define atomic_exchange(object, value) \
105 InterlockedExchange ((object), (value))
107 # define atomic_compare_exchange(object, value, desired) \
108 InterlockedCompareExchange ((object), (value), (desired))
110 # define atomic_compare_exchange_weak(object, value, desired) \
111 atomic_compare_exchange (object, value, desired)
113 # define atomic_exchange_acquire(object, value) \
114 atomic_exchange ((object), (value))
116 # define atomic_load_relaxed(object) \
117 atomic_load (object)
119 # define atomic_store_release(object, value) \
120 atomic_store ((object), (value))
122 typedef LONG atomic_size_t;
123 typedef LONG atomic_bool;
124 #else
125 # error "Unable to determine atomic operations for your platform"
126 #endif
128 /* Does the __typeof__ keyword work? This could be done by
129 'configure', but for now it's easier to do it by hand. */
130 #if __GNUC__ >= 2 \
131 || (__clang_major__ >= 4) \
132 || (__IBMC__ >= 1210 && defined (__IBM__TYPEOF__)) \
133 || (__SUNPRO_C >= 0x5110 && !__STDC__) \
134 || defined (__TINYC__)
135 # define HAVE___TYPEOF__ 1
136 #else
137 # define HAVE___TYPEOF__ 0
138 #endif
140 #include <stdint.h>
142 /* To check alignment gcc has an appropriate operator.
143 Other compilers do not. */
144 #if __GNUC__ >= 2 && !defined (__PCC__)
145 # define pointer_aligned(pointer, type) \
146 ((uintptr_t) (pointer) % __alignof__ (type) == 0)
147 #else
148 # define pointer_aligned(pointer, type) \
149 ((uintptr_t) (pointer) % sizeof (type) == 0)
150 #endif
152 /* Used for suppressing warning when we know what we are doing. */
153 #define pointer_unqualify(pointer) ((void *) (uintptr_t) (pointer))
155 #define BARF_IF_FAIL(e) (sizeof (char [1 - 2 * (!(e) ? 1 : 0)]) - 1)
157 #if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 1) \
158 || defined(__clang__) || defined(__PCC__) || defined(__TINYC__)) \
159 && HAVE___TYPEOF__
160 # define countof(array) \
161 (sizeof (array) / sizeof ((array)[0]) \
162 + BARF_IF_FAIL (!__builtin_types_compatible_p (__typeof__ (array), \
163 __typeof__ (&array[0]))))
165 /* Are two types/variables the same type (ignoring qualifiers)? */
166 # define __same_type(a, b) __builtin_types_compatible_p (typeof (a), typeof (b))
169 * container_of - cast a member of a structure out to the containing structure
170 * @ptr: the pointer to the member.
171 * @type: the type of the container struct this is embedded in.
172 * @member: the name of the member within the struct.
174 * WARNING: any const qualifier of @ptr is lost.
176 # define container_of(ptr, type, member) \
177 __extension__ \
178 ({ \
179 void *__member_pointer = (void *) (ptr); \
180 static_assert (__same_type (*(ptr), ((type *) 0)->member) \
181 || __same_type (*(ptr), void), \
182 "pointer type mismatch in container_of()"); \
183 ((type *) ((char *) __member_pointer - offsetof (type, member))); \
185 #else
186 # define countof(array) (sizeof (array) / sizeof ((array)[0]))
187 # define container_of(ptr, type, member) \
188 ((type *) ((char *) (ptr) - offsetof (type, member)))
189 #endif
192 * Optional: only supported since gcc >= 14
193 * Optional: only supported since clang >= 17
195 * gcc: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108896
196 * clang: https://reviews.llvm.org/D148381
198 #if (defined (__GNUC__) && __GNUC__ >= 14) || (defined (__clang__) && __clang_major__ >= 17)
199 # define counted_by(member) __attribute__ ((__element_count__ (#member)))
200 #else
201 # define counted_by(member)
202 #endif
204 #define STRLITEQ(s1, s2) (strncmp (s1, s2, countof (s2)) == 0)
206 /* __builtin_expect(CONDITION, EXPECTED_VALUE) evaluates to CONDITION,
207 but notifies the compiler that the most likely value of CONDITION
208 is EXPECTED_VALUE. */
209 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
210 # define LIKELY(condition) __builtin_expect (!!(condition), true)
211 # define UNLIKELY(condition) __builtin_expect (!!(condition), false)
212 #else
213 # define LIKELY(condition) (!!(condition))
214 # define UNLIKELY(condition) (!!(condition))
215 #endif
217 //TODO
218 #ifdef _WIN32
219 # undef PURE
220 # undef CONST
221 #endif
223 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
224 # define CONST __attribute__ ((__const__))
225 #else
226 # define CONST
227 #endif
229 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
230 # define PURE __attribute__ ((__pure__))
231 #else
232 # define PURE
233 #endif
235 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 3) || defined (__clang__)
236 # define NONNULL(...) __attribute__ ((__nonnull__ (__VA_ARGS__)))
237 #else
238 # define NONNULL(...)
239 #endif
241 /* Warn about unused results of certain
242 function calls which can lead to problems. */
243 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
244 # define NODISCARD __attribute__ ((__warn_unused_result__))
245 #else
246 # define NODISCARD
247 #endif
249 #if __GNUC__ >= 7
250 # define FALLTHROUGH __attribute__ ((__fallthrough__))
251 #else
252 # define FALLTHROUGH do { } while (0)
253 #endif
255 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
256 # define UNUSED __attribute__ ((__unused__))
257 #else
258 # define UNUSED
259 #endif
261 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 5)
262 # define FORMAT(type, p1, p2) __attribute__ ((__format__ (type, p1, p2)))
263 #else
264 # define FORMAT(type, p1, p2)
265 #endif
267 #if (defined (_MSC_VER) && _MSC_VER >= 1200) || defined (__CYGWIN__)
268 # define NORETURN __declspec (noreturn)
269 #elif (__GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 8)) || defined (__clang__)
270 # define NORETURN __attribute__ ((__noreturn__))
271 #else
272 # define NORETURN _Noreturn
273 #endif
275 /* Designates a 1-based positional argument ref-index of pointer type
276 that can be used to access size-index elements of the pointed-to
277 array according to access mode, or at least one element when
278 size-index is not provided:
279 access (access-mode, <ref-index> [, <size-index>]) */
280 #if __GNUC__ >= 10
281 # define ACCESS_read_only(...) \
282 __attribute__ ((__access__ (__read_only__, __VA_ARGS__)))
283 # define ACCESS_write_only(...) \
284 __attribute__ ((__access__ (__write_only__, __VA_ARGS__)))
285 # define ACCESS_read_write(...) \
286 __attribute__ ((__access__ (__read_write__, __VA_ARGS__)))
287 #else
288 # define ACCESS_read_only(...)
289 # define ACCESS_write_only(...)
290 # define ACCESS_read_write(...)
291 #endif
293 #if __GNUC__ >= 11
294 # define ACCESS_none(...) __attribute__ ((__access__ (__none__, __VA_ARGS__)))
295 #else
296 # define ACCESS_none(...)
297 #endif
299 #define ACCESS(mode, ...) ACCESS_##mode (__VA_ARGS__)
301 #if (__GNUC__ >= 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)) \
302 && !defined(__PCC__)
303 # define RETURNS_NONNULL __attribute__ ((__returns_nonnull__))
304 #else
305 # define RETURNS_NONNULL
306 #endif
308 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7)
309 # define PACKED __attribute__ ((__packed__))
310 #else
311 # define PACKED
312 #endif
314 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
315 # define MALLOC __attribute__ ((__malloc__))
316 #else
317 # define MALLOC
318 #endif
320 #if __GNUC__ >= 11
321 /* Designates dealloc as a function to call to deallocate objects
322 allocated by the declared function. */
323 # define DEALLOC(dealloc, argno) __attribute__ ((__malloc__ (dealloc, argno)))
324 #else
325 # define DEALLOC(dealloc, argno)
326 #endif
328 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
329 # define ALLOC_SIZE(...) __attribute__ ((__alloc_size__ (__VA_ARGS__)))
330 #else
331 # define ALLOC_SIZE(...)
332 #endif
334 #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 1)
335 # define ALWAYS_INLINE __attribute__ ((__always_inline__))
336 #else
337 # define ALWAYS_INLINE
338 #endif
340 /* Warningless cast from const pointer to usual pointer. */
341 static inline ALWAYS_INLINE void *
342 worst_cast (const void *p)
344 union
346 const void *p;
347 void *q;
348 } u = { .p = p };
350 return u.q;
353 #define pragma(x) _Pragma (#x)
354 #define TODO(x) pragma (message ("TODO: " #x))
356 /* Support for flexible arrays.
357 Usage:
359 struct foo
361 size_t size;
362 char bar[__flexible_array__];
365 stuct foo *
366 baz (size_t size)
368 return malloc (sizeof (struct foo) - __flexible_array_extra_size__ + size);
369 } */
370 #if defined (__STDC_VERSION__) && __STDC_VERSION__ > 199901L && !defined (__HP_cc)
371 # define __flexible_array__
372 # define __flexible_array_extra_size__ 0
373 #elif __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96) || defined (__clang__)
374 /* GCC 2.97 and clang support C99 flexible array members as an extension,
375 even when in C89 mode or compiling C++ (any version). */
376 # define __flexible_array__
377 # define __flexible_array_extra_size__ 0
378 #elif defined (__GNUC__)
379 /* Pre-2.97 GCC did not support C99 flexible arrays but did have
380 an equivalent extension with slightly different notation. */
381 # define __flexible_array__ 0
382 # define __flexible_array_extra_size__ 1
383 #else
384 /* Some other non-C99 compiler. Approximate with [1]. */
385 # define __flexible_array__ 1
386 # define __flexible_array_extra_size__ 1
387 #endif
389 /* How Build quotes filenames, to minimize use of outer quotes,
390 but also provide better support for copy and paste when used. */
391 #include "libquote/quote.h"
392 #include "libquote/quotearg.h"
394 /* Use these to shell quote only when necessary,
395 when the quoted item is already delimited with colons. */
396 #define quotef(qs, arg) \
397 quotearg_n_style_colon (qs, 0, quoting_style_shell_escape, arg)
398 #define quotef_n(qs, n, arg) \
399 quotearg_n_style_colon (qs, n, quoting_style_shell_escape, arg)
401 /* Use these when there are spaces around the file name,
402 in the error message. */
403 #define quoteaf(qs, arg) \
404 quotearg_style (qs, quoting_style_shell_escape_always, arg)
405 #define quoteaf_n(qs, n, arg) \
406 quotearg_n_style (qs, n, quoting_style_shell_escape_always, arg)
408 #if ENABLE_NLS
409 /* Get declarations of GNU message catalog functions. */
410 # include <libintl.h>
411 #else
412 /* Disabled NLS.
413 The casts to 'const char *' serve the purpose of producing warnings
414 for invalid uses of the value returned from these functions. */
415 # define gettext(msgid) ((const char *) (msgid))
416 # define ngettext(msgid1, msgid2, n) \
417 ((n) == 1 ? (const char *) (msgid1) : (const char *) (msgid2))
418 # define textdomain(domainname) \
419 ((const char *) (domainname))
420 # define bindtextdomain(domainname, dirname) \
421 ((void) (domainname), (const char *) (dirname))
422 # ifndef PACKAGE
423 # define PACKAGE ""
424 # endif
425 # ifndef LOCALEDIR
426 # define LOCALEDIR ""
427 # endif
428 #endif
430 /* A pseudo function call that serves as a marker for the automated
431 extraction of messages, but does not call gettext(). The run-time
432 translation is done at a different place in the code.
433 The argument, MSGID, should be a literal string. Concatenated strings
434 and other string expressions will not work.
435 The macro's expansion is not parenthesized, so that it is suitable as
436 initializer for static 'char[]' or 'const char[]' variables. */
437 #define gettext_noop(msgid) msgid
439 #define _(msgid) gettext (msgid)
440 #define N_(msgid) gettext_noop (msgid)
441 #define S_(msgid1, msgid2, n) ngettext (msgid1, msgid2, n)