Coverage Report

Created: 2024-08-28 06:17

/src/freeradius-server/src/freeradius-devel/build.h
Line
Count
Source (jump to first uncovered line)
1
#pragma once
2
/*
3
 *  This program is free software; you can redistribute it and/or modify
4
 *  it under the terms of the GNU General Public License as published by
5
 *  the Free Software Foundation; either version 2 of the License, or
6
 *  (at your option) any later version.
7
 *
8
 *  This program is distributed in the hope that it will be useful,
9
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
 *  GNU General Public License for more details.
12
 *
13
 *  You should have received a copy of the GNU General Public License
14
 *  along with this program; if not, write to the Free Software
15
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16
 */
17
18
/**
19
 * $Id: 7d079e1d2924dceb9eaf3eae0416f738e470f928 $
20
 *
21
 * @file include/build.h
22
 * @brief Source control functions
23
 *
24
 * @copyright 2013 The FreeRADIUS server project
25
 */
26
27
#ifdef __cplusplus
28
extern "C" {
29
#endif
30
31
/** For systems with an old version libc, define static_assert.
32
 *
33
 */
34
#ifndef static_assert
35
0
#  define static_assert _Static_assert
36
# else
37
#  include <assert.h>
38
#endif
39
40
/*
41
 *  Static analyzers don't notice or can't infer some properties
42
 *  of the code, and hence may give false positives. To deal with
43
 *  them, there is some conditionally compiled code in various
44
 *  places. The following lets the code change minimally if and
45
 *  when new static analyzers are added.
46
 */
47
#ifdef __clang_analyzer__
48
#define STATIC_ANALYZER 1
49
#endif
50
#ifdef __COVERITY__
51
#define STATIC_ANALYZER 1
52
#endif
53
54
/*
55
 *  Reduce spurious errors from static analyzers by having
56
 *  all paths that find the da to be NULL, result
57
 *  in program exit.
58
 */
59
#ifdef STATIC_ANALYZER
60
#  define WITH_VERIFY_PTR 1
61
#endif
62
63
/*
64
 *  GCC uses __SANITIZE_ADDRESS__, clang uses __has_feature, which
65
 *  GCC complains about.
66
 */
67
#ifndef __SANITIZE_ADDRESS__
68
#ifdef __has_feature
69
#if __has_feature(address_sanitizer)
70
#define __SANITIZE_ADDRESS__ (1)
71
#endif
72
#endif
73
#endif
74
75
/*
76
 *  Basic headers we want everywhere
77
 */
78
#include <stdint.h>
79
#include <stddef.h>
80
#include <string.h>
81
82
/*
83
 *  These are compile time options to toggle whether
84
 *  we're building with thread support.
85
 *
86
 *  With EMSCRIPTEN threading support isn't guaranteed
87
 *  as many browsers have explicitly disabled support
88
 *  due to spectre attacks.
89
 */
90
#if (defined(__EMSCRIPTEN__) && defined(__EMSCRIPTEN_PTHREADS__)) || !defined(__EMSCRIPTEN__) && defined(HAVE_PTHREAD_H)
91
#  define HAVE_PTHREADS 1
92
#endif
93
94
/*
95
 *  GCC will sometimes define "unix" as well as "__unix",
96
 *  which gets confusing and is unnecessary.
97
 */
98
#undef unix
99
100
/** Evaluates to +1 for a > b, and -1 for a < b
101
 */
102
345k
#define CMP_PREFER_SMALLER(_a,_b) (((_a) > (_b)) - ((_a) < (_b)))
103
104
/** Evaluates to -1 for a > b, and +1 for a < b
105
 */
106
#define CMP_PREFER_LARGER(_a,_b)  (((_a) < (_b)) - ((_a) > (_b)))
107
108
/** Same as CMP_PREFER_SMALLER use when you don't really care about ordering, you just want _an_ ordering.
109
 */
110
345k
#define CMP(_a, _b)     CMP_PREFER_SMALLER(_a, _b)
111
112
/** Return if the comparison is not 0 (is unequal)
113
 *
114
 * @param[in] _a  pointer to first structure.
115
 * @param[in] _b  pointer to second structure.
116
 * @param[in] _field  within the structs to compare.
117
 * @return The result of the comparison.
118
 */
119
0
#define CMP_RETURN(_a, _b, _field) \
120
0
do { \
121
0
  int8_t _ret = CMP((_a)->_field, (_b)->_field); \
122
0
  if (_ret != 0) return _ret; \
123
0
} while (0)
124
125
/** memcmp function which has similar behaviour as strncmp
126
 *
127
 * @param[in] a     First thing to compare.
128
 * @param[in] b     Second thing to compare.
129
 * @param[in] a_len   Length of first thing.
130
 * @param[in] b_len   Length of second thing.
131
 * @return
132
 *  - +1 if a > b
133
 *  - 0 if a == b
134
 *  - -1 if a < b
135
 */
136
static inline int8_t memcmp_return(void const *a, void const *b, size_t a_len, size_t b_len)
137
0
{
138
0
  size_t cmp_len = (a_len < b_len) ? a_len : b_len;
139
0
  int8_t l_ret = CMP(a_len, b_len);
140
0
  int8_t ret;
141
0
  ret = CMP(memcmp(a, b, cmp_len), 0);
142
0
  if (ret != 0) return ret;
143
0
  return l_ret;
144
0
}
Unexecuted instantiation: fuzzer_tacacs.c:memcmp_return
Unexecuted instantiation: fuzzer_vmps.c:memcmp_return
Unexecuted instantiation: fuzzer_tftp.c:memcmp_return
Unexecuted instantiation: fuzzer_dns.c:memcmp_return
Unexecuted instantiation: fuzzer_dhcpv6.c:memcmp_return
Unexecuted instantiation: fuzzer_radius.c:memcmp_return
Unexecuted instantiation: fuzzer_util.c:memcmp_return
Unexecuted instantiation: fuzzer_dhcpv4.c:memcmp_return
Unexecuted instantiation: fuzzer_bfd.c:memcmp_return
Unexecuted instantiation: atexit.c:memcmp_return
Unexecuted instantiation: base16.c:memcmp_return
Unexecuted instantiation: base32.c:memcmp_return
Unexecuted instantiation: base64.c:memcmp_return
Unexecuted instantiation: calc.c:memcmp_return
Unexecuted instantiation: cap.c:memcmp_return
Unexecuted instantiation: chap.c:memcmp_return
Unexecuted instantiation: dbuff.c:memcmp_return
Unexecuted instantiation: debug.c:memcmp_return
Unexecuted instantiation: decode.c:memcmp_return
Unexecuted instantiation: dict_ext.c:memcmp_return
Unexecuted instantiation: dict_fixup.c:memcmp_return
Unexecuted instantiation: dict_print.c:memcmp_return
Unexecuted instantiation: dict_test.c:memcmp_return
Unexecuted instantiation: dict_tokenize.c:memcmp_return
Unexecuted instantiation: dict_unknown.c:memcmp_return
Unexecuted instantiation: dict_util.c:memcmp_return
Unexecuted instantiation: dict_validate.c:memcmp_return
Unexecuted instantiation: dl.c:memcmp_return
Unexecuted instantiation: dns.c:memcmp_return
Unexecuted instantiation: edit.c:memcmp_return
Unexecuted instantiation: encode.c:memcmp_return
Unexecuted instantiation: event.c:memcmp_return
Unexecuted instantiation: ext.c:memcmp_return
Unexecuted instantiation: fifo.c:memcmp_return
Unexecuted instantiation: file.c:memcmp_return
Unexecuted instantiation: fopencookie.c:memcmp_return
Unexecuted instantiation: fring.c:memcmp_return
Unexecuted instantiation: getaddrinfo.c:memcmp_return
Unexecuted instantiation: hash.c:memcmp_return
Unexecuted instantiation: heap.c:memcmp_return
Unexecuted instantiation: hmac_md5.c:memcmp_return
Unexecuted instantiation: hmac_sha1.c:memcmp_return
Unexecuted instantiation: htrie.c:memcmp_return
Unexecuted instantiation: hw.c:memcmp_return
Unexecuted instantiation: inet.c:memcmp_return
Unexecuted instantiation: iovec.c:memcmp_return
Unexecuted instantiation: isaac.c:memcmp_return
Unexecuted instantiation: log.c:memcmp_return
Unexecuted instantiation: lst.c:memcmp_return
Unexecuted instantiation: machine.c:memcmp_return
Unexecuted instantiation: md4.c:memcmp_return
Unexecuted instantiation: md5.c:memcmp_return
Unexecuted instantiation: minmax_heap.c:memcmp_return
Unexecuted instantiation: misc.c:memcmp_return
Unexecuted instantiation: missing.c:memcmp_return
Unexecuted instantiation: net.c:memcmp_return
Unexecuted instantiation: packet.c:memcmp_return
Unexecuted instantiation: pair.c:memcmp_return
Unexecuted instantiation: pair_inline.c:memcmp_return
Unexecuted instantiation: pair_legacy.c:memcmp_return
Unexecuted instantiation: pair_print.c:memcmp_return
Unexecuted instantiation: pair_tokenize.c:memcmp_return
Unexecuted instantiation: paths.c:memcmp_return
Unexecuted instantiation: pcap.c:memcmp_return
Unexecuted instantiation: perm.c:memcmp_return
Unexecuted instantiation: print.c:memcmp_return
Unexecuted instantiation: proto.c:memcmp_return
Unexecuted instantiation: rand.c:memcmp_return
Unexecuted instantiation: rb.c:memcmp_return
Unexecuted instantiation: regex.c:memcmp_return
Unexecuted instantiation: retry.c:memcmp_return
Unexecuted instantiation: sbuff.c:memcmp_return
Unexecuted instantiation: sem.c:memcmp_return
Unexecuted instantiation: sha1.c:memcmp_return
Unexecuted instantiation: size.c:memcmp_return
Unexecuted instantiation: snprintf.c:memcmp_return
Unexecuted instantiation: socket.c:memcmp_return
Unexecuted instantiation: stats.c:memcmp_return
Unexecuted instantiation: strerror.c:memcmp_return
Unexecuted instantiation: strlcat.c:memcmp_return
Unexecuted instantiation: strlcpy.c:memcmp_return
Unexecuted instantiation: struct.c:memcmp_return
Unexecuted instantiation: syserror.c:memcmp_return
Unexecuted instantiation: table.c:memcmp_return
Unexecuted instantiation: talloc.c:memcmp_return
Unexecuted instantiation: time.c:memcmp_return
Unexecuted instantiation: timeval.c:memcmp_return
Unexecuted instantiation: token.c:memcmp_return
Unexecuted instantiation: trie.c:memcmp_return
Unexecuted instantiation: types.c:memcmp_return
Unexecuted instantiation: udp.c:memcmp_return
Unexecuted instantiation: udp_queue.c:memcmp_return
Unexecuted instantiation: udpfromto.c:memcmp_return
Unexecuted instantiation: uri.c:memcmp_return
Unexecuted instantiation: value.c:memcmp_return
Unexecuted instantiation: version.c:memcmp_return
Unexecuted instantiation: fuzzer.c:memcmp_return
Unexecuted instantiation: base.c:memcmp_return
Unexecuted instantiation: vmps.c:memcmp_return
Unexecuted instantiation: list.c:memcmp_return
Unexecuted instantiation: tcp.c:memcmp_return
Unexecuted instantiation: abinary.c:memcmp_return
Unexecuted instantiation: raw.c:memcmp_return
145
146
/** Return if the contents of the specified field is not identical between the specified structures
147
 *
148
 * @param[in] _a    pointer to first structure.
149
 * @param[in] _b    pointer to second structure.
150
 * @param[in] _field    within the structs to compare.
151
 * @param[in] _len_field  within the structs, specifying the length of the data.
152
 * @return The result of the comparison.
153
 */
154
0
#define MEMCMP_RETURN(_a, _b, _field, _len_field) \
155
0
do { \
156
0
  int8_t _ret = memcmp_return((_a)->_field, (_b)->_field, (_a)->_len_field, (_b)->_len_field); \
157
0
  if (_ret != 0) return _ret; \
158
0
} while (0)
159
160
/** Remove const qualification from a pointer
161
 *
162
 * @param[in] _type The non-const version of the type.
163
 * @param[in] _ptr  to de-const.
164
 */
165
14.4M
#define UNCONST(_type, _ptr)    ((_type)((uintptr_t)(_ptr)))
166
167
/** Typeof field
168
 *
169
 * @param[in] _type struct type containing the field.
170
 * @param[in] _field  to return the type of.
171
 */
172
1.25k
#define typeof_field(_type, _field) __typeof__(((_type *)NULL)->_field)
173
174
/** HEX concatenation macros
175
 *
176
 */
177
#ifndef HEXIFY
178
#  define XHEXIFY4(b1,b2,b3,b4) (0x ## b1 ## b2 ## b3 ## b4)
179
#  define HEXIFY4(b1,b2,b3,b4)  XHEXIFY4(b1, b2, b3, b4)
180
181
#  define XHEXIFY3(b1,b2,b3)  (0x ## b1 ## b2 ## b3)
182
#  define HEXIFY3(b1,b2,b3) XHEXIFY3(b1, b2, b3)
183
184
4.13M
#  define XHEXIFY2(b1,b2) (0x ## b1 ## b2)
185
4.13M
#  define HEXIFY2(b1,b2)  XHEXIFY2(b1, b2)
186
187
#  define XHEXIFY(b1)   (0x ## b1)
188
#  define HEXIFY(b1)    XHEXIFY(b1)
189
#endif
190
191
/** The ubiquitous stringify macros
192
 *
193
 */
194
#define XSTRINGIFY(x) #x
195
#define STRINGIFY(x)  XSTRINGIFY(x)
196
#define JOINSTR(x,y)  XSTRINGIFY(x ## y)
197
198
/** Join two values without stringifying
199
 *
200
 * Useful for calling different macros based on the output of
201
*/
202
70.4k
#define _JOIN(x,y)  x ## y
203
142k
#define JOIN(x,y) _JOIN(x,y)
204
205
/** Helper for initialising arrays of string literals
206
 */
207
0
#define L(_str)   { _str, sizeof(_str) - 1 }
208
209
/** Fill macros for array initialisation
210
 */
211
#define F1(_idx, _val)    [_idx] = _val
212
#define F2(_idx, _val)    F1(_idx, _val), F1(_idx + 1, _val)
213
#define F4(_idx, _val)    F2(_idx, _val), F2(_idx + 2, _val)
214
#define F8(_idx, _val)    F4(_idx, _val), F4(_idx + 4, _val)
215
#define F16(_idx, _val)   F8(_idx, _val), F8(_idx + 8, _val)
216
#define F32(_idx, _val)   F16(_idx, _val), F16(_idx + 16, _val)
217
#define F64(_idx, _val)   F32(_idx, _val), F32(_idx + 32, _val)
218
#define F128(_idx, _val)  F64(_idx, _val), F64(_idx + 64, _val)
219
#define F256(_idx, _val)  F128(_idx, _val), F128(_idx + 128, _val)
220
221
/** Variadic macro framework
222
 */
223
224
/**
225
 * The VA_NARG macro evaluates to the number of arguments that have been
226
 * passed to it.
227
 *
228
 * Laurent Deniau, "__VA_NARG__," 17 January 2006, <comp.std.c> (29 November 2007).
229
 */
230
#define VA_ARG_N( \
231
        _1, _2, _3, _4, _5, _6, _7, _8, _9,_10,  \
232
        _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
233
        _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
234
        _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
235
        _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
236
        _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
237
        _61,_62,_63,N,...) N
238
239
#define VA_RSEQ_N() \
240
        63,62,61,60,                   \
241
        59,58,57,56,55,54,53,52,51,50, \
242
        49,48,47,46,45,44,43,42,41,40, \
243
        39,38,37,36,35,34,33,32,31,30, \
244
        29,28,27,26,25,24,23,22,21,20, \
245
        19,18,17,16,15,14,13,12,11,10, \
246
        9,8,7,6,5,4,3,2,1,0
247
248
#define _VA_NARG(...)   VA_ARG_N(__VA_ARGS__)
249
250
/** Return the number of variadic arguments up to 64
251
 *
252
 * @param[in] ... Variadic arguments to count.
253
 */
254
#define VA_NARG(...)    _VA_NARG(__VA_ARGS__, VA_RSEQ_N())
255
256
257
/** Pass caller information to the function
258
 *
259
 */
260
#ifndef NDEBUG
261
#  define NDEBUG_LOCATION_ARGS      char const *file, int line,
262
42.0k
#  define NDEBUG_LOCATION_VALS      file, line,
263
4.08M
#  define NDEBUG_LOCATION_EXP     __FILE__, __LINE__,
264
#  define NDEBUG_LOCATION_NONNULL(_num)   ((_num) + 2)
265
#else
266
#  define NDEBUG_LOCATION_ARGS
267
#  define NDEBUG_LOCATION_VALS
268
#  define NDEBUG_LOCATION_EXP
269
#  define NDEBUG_LOCATION_NONNULL(_num)   (_num)
270
#endif
271
272
/** Check if a given variable is the _const or not
273
 *
274
 * @param[in] _type The base type of the variable (should not be marked const)
275
 * @param[in] _var  to check.
276
 */
277
#define IS_CONST(_type, _var) \
278
2.16M
  _Generic((_var), \
279
2.16M
     _type: false, \
280
2.16M
     const _type: true \
281
2.16M
  )
282
283
/** Check if a given variable is the const or unconst version of a type
284
 *
285
 * Expands to _var if _var matches type, otherwise throws a compiler error.
286
 *
287
 * Useful for creating typesafe wrapper macros around functions which take
288
 * void *s.
289
 *
290
 * @param[in] _type The base type of the variable (should not be marked const)
291
 * @param[in] _var  to check.
292
 */
293
#define IS_TYPE(_type, _var) \
294
  _Generic((_var), \
295
     _type: _var, \
296
     const _type: _var \
297
  )
298
/*
299
 *  Mark variables as unused
300
 */
301
#define UNUSED_VAR(_x) ((void)_x)
302
303
/** Pad _x to the next multiple of _y
304
 *
305
 */
306
#define PAD(_x, _y)   (_y - ((_x) % _y))
307
308
/** Should be placed before the function return type
309
 *
310
 */
311
#define NEVER_RETURNS   _Noreturn
312
#define HIDDEN      CC_HINT(visibility("hidden"))
313
#define UNUSED      CC_HINT(unused)
314
315
/** clang 10 doesn't recognised the FALL-THROUGH comment anymore
316
 */
317
#if (defined(__clang__) && (__clang_major__ >= 10)) || (defined(__GNUC__) && __GNUC__ >= 7)
318
20.4k
#  define FALL_THROUGH    CC_HINT(fallthrough)
319
#else
320
#  define FALL_THROUGH    ((void)0)
321
#endif
322
323
#ifndef NDEBUG
324
#  define NDEBUG_UNUSED
325
#else
326
#  define NDEBUG_UNUSED   UNUSED
327
#endif
328
329
#define BLANK_FORMAT    " " /* GCC_LINT whines about empty formats */
330
331
/*
332
 *  struct field size
333
 */
334
#define SIZEOF_MEMBER(_t, _m) sizeof(((_t *)0)->_m)
335
1.10k
#define NUM_ELEMENTS(_t) (sizeof((_t)) / sizeof((_t)[0]))
336
337
/*
338
 *  For use with multidimensional arrays where
339
 *  the deeper array element has a size smaller than
340
 *  a pointer i.e. char foo[n][m]
341
 */
342
0
#define NUM_PTR_ELEMENTS(_t) (sizeof((_t)) / sizeof(void *))
343
344
/*
345
 *  Type checking
346
 */
347
348
/** Check if two types are compatible (the C11 way)
349
 *
350
 * Expands to 1 if types are compatible, else 0.
351
 *
352
 * @param[in] _x pointer to check.
353
 * @param[in] _t type to check compatibility with.
354
 */
355
#define IS_COMPATIBLE(_x, _t) _Generic(_x, _t:1, default: 0)
356
357
/** Check if a field in a struct is compatible (the C11 way)
358
 *
359
 * Expands to 1 if types are compatible, else 0.
360
 *
361
 * @param[in] _s struct to check.
362
 * @param[in] _f field in struct.
363
 * @param[in] _t type to check compatibility with.
364
 */
365
#define IS_FIELD_COMPATIBLE(_s, _f, _t) _Generic(((_s *)0)->_f, _t:1, default: 0)
366
367
/*
368
 *  Only use GCC __attribute__ if were building with a GCClike
369
 *  compiler.
370
 */
371
#ifdef __GNUC__
372
20.4k
#  define CC_HINT(...)    __attribute__((__VA_ARGS__))
373
18.6M
#  define likely(_x)    __builtin_expect((_x), 1)
374
317M
#  define unlikely(_x)    __builtin_expect((_x), 0)
375
#  define unpredictable(_x) __builtin_unpredictable((_x))
376
#else
377
#  define CC_HINT(...)
378
#  define likely(_x) _x
379
#  define unlikely(_x) _x
380
#  define unpredictable(_x) _x
381
#endif
382
383
/*
384
 *  Macros to add pragmas
385
 */
386
#define PRAGMA(_x) _Pragma(#_x)
387
388
/*
389
 *  Handle acquire/release macros
390
 */
391
#if defined(__clang__) && (__clang_major__ >= 13)
392
#  define CC_ACQUIRE_HANDLE(_tag) CC_HINT(acquire_handle(_tag))
393
#  define CC_USE_HANDLE(_tag) CC_HINT(use_handle(_tag))
394
#  define CC_RELEASE_HANDLE(_tag) CC_HINT(release_handle(_tag))
395
#else
396
#  define CC_ACQUIRE_HANDLE(_tag)
397
#  define CC_USE_HANDLE(_tag)
398
#  define CC_RELEASE_HANDLE(_tag)
399
#endif
400
401
/*
402
 *  Macros for controlling warnings in GCC >= 4.2 and clang >= 2.8
403
 */
404
#if defined(__clang__) && ((__clang_major__ * 100) + __clang_minor__ >= 208)
405
#  define DIAG_UNKNOWN_PRAGMAS unknown-pragmas
406
#  define DIAG_PRAGMA(_x) PRAGMA(clang diagnostic _x)
407
#  define DIAG_OFF(_x) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
408
#  define DIAG_ON(_x) DIAG_PRAGMA(warning JOINSTR(-W,_x))
409
#  define DIAG_PUSH() DIAG_PRAGMA(push)
410
#  define DIAG_POP() DIAG_PRAGMA(pop)
411
#elif !defined(__clang__) && defined(__GNUC__) && ((__GNUC__ * 100) + __GNUC_MINOR__) >= 402
412
#  define DIAG_UNKNOWN_PRAGMAS pragmas
413
#  define DIAG_PRAGMA(_x) PRAGMA(GCC diagnostic _x)
414
#  define DIAG_OFF(_x) DIAG_PRAGMA(ignored JOINSTR(-W,_x))
415
#  define DIAG_ON(_x)  DIAG_PRAGMA(warning JOINSTR(-W,_x))
416
#  define DIAG_PUSH() DIAG_PRAGMA(push)
417
#  define DIAG_POP() DIAG_PRAGMA(pop)
418
#else
419
#  define DIAG_UNKNOWN_PRAGMAS
420
#  define DIAG_OFF(_x)
421
#  define DIAG_ON(_x)
422
#  define DIAG_PUSH()
423
#  define DIAG_POP()
424
#endif
425
426
/*
427
 *  For dealing with APIs which are only deprecated in OSX (like the OpenSSL API)
428
 */
429
#ifdef __APPLE__
430
#  define USES_APPLE_DEPRECATED_API DIAG_OFF(deprecated-declarations)
431
#  define USES_APPLE_RST DIAG_ON(deprecated-declarations)
432
#else
433
#  define USES_APPLE_DEPRECATED_API
434
#  define USES_APPLE_RST
435
#endif
436
437
#if defined(__GNUC__)
438
/* force inclusion of ident keywords in the face of optimization */
439
#  define RCSID(id) static char const rcsid[] __attribute__ ((used)) = id;
440
#  define RCSIDH(h, id) static char const rcsid_ ## h [] __attribute__ ((used)) = id;
441
#elif defined(__SUNPRO_C)
442
/* put ident keyword into comment section (nicer than gcc way) */
443
#  define RCSID(id) PRAGMA(sun ident id)
444
#  define RCSIDH(h, id) PRAGMA(sun ident id)
445
#else
446
#  define RCSID(id)
447
#  define RCSIDH(h, id)
448
#endif
449
#ifdef __cplusplus
450
}
451
#endif
452
453
/*
454
 *  For closing macros which open a code block e.g. fr_rb_inorder_foreach
455
 */
456
#define endforeach }
457
458
/* Explicitly evaluate and ignore an expression
459
 *
460
 * Why this macro?
461
 * 1. gcc will warn about unused return values, even with the traditional cast to void.
462
 * 2. There are cases in which an error case wants to clean up, but the function to
463
 *    clean up itself returns a status. In this context you don't care, but then you
464
 *    have the Scylla of unused return value and the Charybdis of Coverity complaining
465
 *    about an if that doesn't affect control flow. The following evaluates _expr and
466
 *    stores it in a variable marked as unused
467
 * @param _expr   The expression to be evaluated and ignored
468
 * @param _type   The type of the expression
469
 */
470
#define IGNORE(_expr, _type) \
471
  do { \
472
    _type ignored UNUSED = (_expr); \
473
  } while (0)