150696a6eSStefan Eßer /* 250696a6eSStefan Eßer * ***************************************************************************** 350696a6eSStefan Eßer * 450696a6eSStefan Eßer * SPDX-License-Identifier: BSD-2-Clause 550696a6eSStefan Eßer * 6*a970610aSStefan Eßer * Copyright (c) 2018-2024 Gavin D. Howard and contributors. 750696a6eSStefan Eßer * 850696a6eSStefan Eßer * Redistribution and use in source and binary forms, with or without 950696a6eSStefan Eßer * modification, are permitted provided that the following conditions are met: 1050696a6eSStefan Eßer * 1150696a6eSStefan Eßer * * Redistributions of source code must retain the above copyright notice, this 1250696a6eSStefan Eßer * list of conditions and the following disclaimer. 1350696a6eSStefan Eßer * 1450696a6eSStefan Eßer * * Redistributions in binary form must reproduce the above copyright notice, 1550696a6eSStefan Eßer * this list of conditions and the following disclaimer in the documentation 1650696a6eSStefan Eßer * and/or other materials provided with the distribution. 1750696a6eSStefan Eßer * 1850696a6eSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1950696a6eSStefan Eßer * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2050696a6eSStefan Eßer * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2150696a6eSStefan Eßer * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 2250696a6eSStefan Eßer * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 2350696a6eSStefan Eßer * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 2450696a6eSStefan Eßer * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 2550696a6eSStefan Eßer * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 2650696a6eSStefan Eßer * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 2750696a6eSStefan Eßer * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2850696a6eSStefan Eßer * POSSIBILITY OF SUCH DAMAGE. 2950696a6eSStefan Eßer * 3050696a6eSStefan Eßer * ***************************************************************************** 3150696a6eSStefan Eßer * 3250696a6eSStefan Eßer * The private header for the bc library. 3350696a6eSStefan Eßer * 3450696a6eSStefan Eßer */ 3550696a6eSStefan Eßer 3650696a6eSStefan Eßer #ifndef LIBBC_PRIVATE_H 3750696a6eSStefan Eßer #define LIBBC_PRIVATE_H 3850696a6eSStefan Eßer 39d101cdd6SStefan Eßer #ifndef _WIN32 40d101cdd6SStefan Eßer 41d101cdd6SStefan Eßer #include <pthread.h> 42d101cdd6SStefan Eßer 43d101cdd6SStefan Eßer #endif // _WIN32 44d101cdd6SStefan Eßer 4550696a6eSStefan Eßer #include <bcl.h> 4650696a6eSStefan Eßer 4750696a6eSStefan Eßer #include <num.h> 48d101cdd6SStefan Eßer #include <vm.h> 4950696a6eSStefan Eßer 50175a4d10SStefan Eßer #if BC_ENABLE_MEMCHECK 51175a4d10SStefan Eßer 52175a4d10SStefan Eßer /** 53175a4d10SStefan Eßer * A typedef for Valgrind builds. This is to add a generation index for error 54175a4d10SStefan Eßer * checking. 55175a4d10SStefan Eßer */ 56175a4d10SStefan Eßer typedef struct BclNum 57175a4d10SStefan Eßer { 58175a4d10SStefan Eßer /// The number. 59175a4d10SStefan Eßer BcNum n; 60175a4d10SStefan Eßer 61175a4d10SStefan Eßer /// The generation index. 62175a4d10SStefan Eßer size_t gen_idx; 63175a4d10SStefan Eßer 64175a4d10SStefan Eßer } BclNum; 65175a4d10SStefan Eßer 66175a4d10SStefan Eßer /** 67175a4d10SStefan Eßer * Clears the generation byte in a BclNumber and returns the value. 68175a4d10SStefan Eßer * @param n The BclNumber. 69175a4d10SStefan Eßer * @return The value of the index. 70175a4d10SStefan Eßer */ 71175a4d10SStefan Eßer #define BCL_NO_GEN(n) \ 72175a4d10SStefan Eßer ((n).i & ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT))) 73175a4d10SStefan Eßer 74175a4d10SStefan Eßer /** 75175a4d10SStefan Eßer * Gets the generation index in a BclNumber. 76175a4d10SStefan Eßer * @param n The BclNumber. 77175a4d10SStefan Eßer * @return The generation index. 78175a4d10SStefan Eßer */ 79175a4d10SStefan Eßer #define BCL_GET_GEN(n) ((n).i >> ((sizeof(size_t) - 1) * CHAR_BIT)) 80175a4d10SStefan Eßer 81175a4d10SStefan Eßer /** 82175a4d10SStefan Eßer * Turns a BclNumber into a BcNum. 83175a4d10SStefan Eßer * @param c The context. 84175a4d10SStefan Eßer * @param n The BclNumber. 85175a4d10SStefan Eßer */ 86175a4d10SStefan Eßer #define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, BCL_NO_GEN(n))) 87175a4d10SStefan Eßer 88175a4d10SStefan Eßer /** 89175a4d10SStefan Eßer * Clears the generation index top byte in the BclNumber. 90175a4d10SStefan Eßer * @param n The BclNumber. 91175a4d10SStefan Eßer */ 92175a4d10SStefan Eßer #define BCL_CLEAR_GEN(n) \ 93175a4d10SStefan Eßer do \ 94175a4d10SStefan Eßer { \ 95175a4d10SStefan Eßer (n).i &= ~(((size_t) UCHAR_MAX) << ((sizeof(size_t) - 1) * CHAR_BIT)); \ 96175a4d10SStefan Eßer } \ 97175a4d10SStefan Eßer while (0) 98175a4d10SStefan Eßer 99175a4d10SStefan Eßer #define BCL_CHECK_NUM_GEN(c, bn) \ 100175a4d10SStefan Eßer do \ 101175a4d10SStefan Eßer { \ 102175a4d10SStefan Eßer size_t gen_ = BCL_GET_GEN(bn); \ 103175a4d10SStefan Eßer BclNum* ptr_ = BCL_NUM(c, bn); \ 104175a4d10SStefan Eßer if (BCL_NUM_ARRAY(ptr_) == NULL) \ 105175a4d10SStefan Eßer { \ 106175a4d10SStefan Eßer bcl_nonexistentNum(); \ 107175a4d10SStefan Eßer } \ 108175a4d10SStefan Eßer if (gen_ != ptr_->gen_idx) \ 109175a4d10SStefan Eßer { \ 110175a4d10SStefan Eßer bcl_invalidGeneration(); \ 111175a4d10SStefan Eßer } \ 112175a4d10SStefan Eßer } \ 113175a4d10SStefan Eßer while (0) 114175a4d10SStefan Eßer 115175a4d10SStefan Eßer #define BCL_CHECK_NUM_VALID(c, bn) \ 116175a4d10SStefan Eßer do \ 117175a4d10SStefan Eßer { \ 118175a4d10SStefan Eßer size_t idx_ = BCL_NO_GEN(bn); \ 119175a4d10SStefan Eßer if ((c)->nums.len <= idx_) \ 120175a4d10SStefan Eßer { \ 121175a4d10SStefan Eßer bcl_numIdxOutOfRange(); \ 122175a4d10SStefan Eßer } \ 123175a4d10SStefan Eßer BCL_CHECK_NUM_GEN(c, bn); \ 124175a4d10SStefan Eßer } \ 125175a4d10SStefan Eßer while (0) 126175a4d10SStefan Eßer 127175a4d10SStefan Eßer /** 128175a4d10SStefan Eßer * Returns the limb array of the number. 129175a4d10SStefan Eßer * @param bn The number. 130175a4d10SStefan Eßer * @return The limb array. 131175a4d10SStefan Eßer */ 132175a4d10SStefan Eßer #define BCL_NUM_ARRAY(bn) ((bn)->n.num) 133175a4d10SStefan Eßer 134175a4d10SStefan Eßer /** 135175a4d10SStefan Eßer * Returns the limb array of the number for a non-pointer. 136175a4d10SStefan Eßer * @param bn The number. 137175a4d10SStefan Eßer * @return The limb array. 138175a4d10SStefan Eßer */ 139175a4d10SStefan Eßer #define BCL_NUM_ARRAY_NP(bn) ((bn).n.num) 140175a4d10SStefan Eßer 141175a4d10SStefan Eßer /** 142175a4d10SStefan Eßer * Returns the BcNum pointer. 143175a4d10SStefan Eßer * @param bn The number. 144175a4d10SStefan Eßer * @return The BcNum pointer. 145175a4d10SStefan Eßer */ 146175a4d10SStefan Eßer #define BCL_NUM_NUM(bn) (&(bn)->n) 147175a4d10SStefan Eßer 148175a4d10SStefan Eßer /** 149175a4d10SStefan Eßer * Returns the BcNum pointer for a non-pointer. 150175a4d10SStefan Eßer * @param bn The number. 151175a4d10SStefan Eßer * @return The BcNum pointer. 152175a4d10SStefan Eßer */ 153175a4d10SStefan Eßer #define BCL_NUM_NUM_NP(bn) (&(bn).n) 154175a4d10SStefan Eßer 155175a4d10SStefan Eßer // These functions only abort. They exist to give developers some idea of what 156175a4d10SStefan Eßer // went wrong when bugs are found, if they look at the Valgrind stack trace. 157175a4d10SStefan Eßer 158175a4d10SStefan Eßer BC_NORETURN void 159175a4d10SStefan Eßer bcl_invalidGeneration(void); 160175a4d10SStefan Eßer 161175a4d10SStefan Eßer BC_NORETURN void 162175a4d10SStefan Eßer bcl_nonexistentNum(void); 163175a4d10SStefan Eßer 164175a4d10SStefan Eßer BC_NORETURN void 165175a4d10SStefan Eßer bcl_numIdxOutOfRange(void); 166175a4d10SStefan Eßer 167175a4d10SStefan Eßer #else // BC_ENABLE_MEMCHECK 168175a4d10SStefan Eßer 169175a4d10SStefan Eßer /** 170175a4d10SStefan Eßer * A typedef for non-Valgrind builds. 171175a4d10SStefan Eßer */ 172175a4d10SStefan Eßer typedef BcNum BclNum; 173175a4d10SStefan Eßer 174175a4d10SStefan Eßer #define BCL_NO_GEN(n) ((n).i) 175175a4d10SStefan Eßer #define BCL_NUM(c, n) ((BclNum*) bc_vec_item(&(c)->nums, (n).i)) 176175a4d10SStefan Eßer #define BCL_CLEAR_GEN(n) ((void) (n)) 177175a4d10SStefan Eßer 178175a4d10SStefan Eßer #define BCL_CHECK_NUM_GEN(c, bn) 179175a4d10SStefan Eßer #define BCL_CHECK_NUM_VALID(c, n) 180175a4d10SStefan Eßer 181175a4d10SStefan Eßer #define BCL_NUM_ARRAY(bn) ((bn)->num) 182175a4d10SStefan Eßer #define BCL_NUM_ARRAY_NP(bn) ((bn).num) 183175a4d10SStefan Eßer 184175a4d10SStefan Eßer #define BCL_NUM_NUM(bn) (bn) 185175a4d10SStefan Eßer #define BCL_NUM_NUM_NP(bn) (&(bn)) 186175a4d10SStefan Eßer 187175a4d10SStefan Eßer #endif // BC_ENABLE_MEMCHECK 188175a4d10SStefan Eßer 18944d4804dSStefan Eßer /** 190d101cdd6SStefan Eßer * A header that sets a jump. 191d101cdd6SStefan Eßer * @param vm The thread data. 19244d4804dSStefan Eßer * @param l The label to jump to on error. 19344d4804dSStefan Eßer */ 194d101cdd6SStefan Eßer #define BC_FUNC_HEADER(vm, l) \ 19578bc019dSStefan Eßer do \ 19678bc019dSStefan Eßer { \ 197d101cdd6SStefan Eßer BC_SETJMP(vm, l); \ 198d101cdd6SStefan Eßer vm->err = BCL_ERROR_NONE; \ 19978bc019dSStefan Eßer } \ 20078bc019dSStefan Eßer while (0) 20150696a6eSStefan Eßer 20244d4804dSStefan Eßer /** 203d101cdd6SStefan Eßer * A footer for functions that do not return an error code. 204d101cdd6SStefan Eßer */ 205d101cdd6SStefan Eßer #define BC_FUNC_FOOTER_NO_ERR(vm) \ 206d101cdd6SStefan Eßer do \ 207d101cdd6SStefan Eßer { \ 208d101cdd6SStefan Eßer BC_UNSETJMP(vm); \ 209d101cdd6SStefan Eßer } \ 210d101cdd6SStefan Eßer while (0) 211d101cdd6SStefan Eßer 212d101cdd6SStefan Eßer /** 213d101cdd6SStefan Eßer * A footer for functions that *do* return an error code. 214d101cdd6SStefan Eßer * @param vm The thread data. 21544d4804dSStefan Eßer * @param e The error variable to set. 21644d4804dSStefan Eßer */ 217d101cdd6SStefan Eßer #define BC_FUNC_FOOTER(vm, e) \ 21878bc019dSStefan Eßer do \ 21978bc019dSStefan Eßer { \ 220d101cdd6SStefan Eßer e = vm->err; \ 221d101cdd6SStefan Eßer BC_FUNC_FOOTER_NO_ERR(vm); \ 22278bc019dSStefan Eßer } \ 22378bc019dSStefan Eßer while (0) 22450696a6eSStefan Eßer 22544d4804dSStefan Eßer /** 22644d4804dSStefan Eßer * A footer that sets up n based the value of e and sets up the return value in 22744d4804dSStefan Eßer * idx. 22844d4804dSStefan Eßer * @param c The context. 22944d4804dSStefan Eßer * @param e The error. 230175a4d10SStefan Eßer * @param bn The number. 23144d4804dSStefan Eßer * @param idx The idx to set as the return value. 23244d4804dSStefan Eßer */ 233175a4d10SStefan Eßer #define BC_MAYBE_SETUP(c, e, bn, idx) \ 23478bc019dSStefan Eßer do \ 23578bc019dSStefan Eßer { \ 23678bc019dSStefan Eßer if (BC_ERR((e) != BCL_ERROR_NONE)) \ 23778bc019dSStefan Eßer { \ 238175a4d10SStefan Eßer if (BCL_NUM_ARRAY_NP(bn) != NULL) bc_num_free(BCL_NUM_NUM_NP(bn)); \ 23950696a6eSStefan Eßer idx.i = 0 - (size_t) (e); \ 24050696a6eSStefan Eßer } \ 241175a4d10SStefan Eßer else idx = bcl_num_insert(c, &(bn)); \ 24278bc019dSStefan Eßer } \ 24378bc019dSStefan Eßer while (0) 24450696a6eSStefan Eßer 24544d4804dSStefan Eßer /** 24644d4804dSStefan Eßer * A header to check the context and return an error encoded in a number if it 24744d4804dSStefan Eßer * is bad. 24844d4804dSStefan Eßer * @param c The context. 24944d4804dSStefan Eßer */ 250d101cdd6SStefan Eßer #define BC_CHECK_CTXT(vm, c) \ 25178bc019dSStefan Eßer do \ 25278bc019dSStefan Eßer { \ 253d101cdd6SStefan Eßer c = bcl_contextHelper(vm); \ 25478bc019dSStefan Eßer if (BC_ERR(c == NULL)) \ 25578bc019dSStefan Eßer { \ 256175a4d10SStefan Eßer BclNumber n_num_; \ 257175a4d10SStefan Eßer n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \ 258175a4d10SStefan Eßer return n_num_; \ 25950696a6eSStefan Eßer } \ 26078bc019dSStefan Eßer } \ 26178bc019dSStefan Eßer while (0) 26244d4804dSStefan Eßer 26344d4804dSStefan Eßer /** 26444d4804dSStefan Eßer * A header to check the context and return an error directly if it is bad. 26544d4804dSStefan Eßer * @param c The context. 26644d4804dSStefan Eßer */ 267d101cdd6SStefan Eßer #define BC_CHECK_CTXT_ERR(vm, c) \ 26878bc019dSStefan Eßer do \ 26978bc019dSStefan Eßer { \ 270d101cdd6SStefan Eßer c = bcl_contextHelper(vm); \ 27178bc019dSStefan Eßer if (BC_ERR(c == NULL)) \ 27278bc019dSStefan Eßer { \ 27350696a6eSStefan Eßer return BCL_ERROR_INVALID_CONTEXT; \ 27450696a6eSStefan Eßer } \ 27578bc019dSStefan Eßer } \ 27678bc019dSStefan Eßer while (0) 27750696a6eSStefan Eßer 27844d4804dSStefan Eßer /** 27944d4804dSStefan Eßer * A header to check the context and abort if it is bad. 28044d4804dSStefan Eßer * @param c The context. 28144d4804dSStefan Eßer */ 282d101cdd6SStefan Eßer #define BC_CHECK_CTXT_ASSERT(vm, c) \ 28378bc019dSStefan Eßer do \ 28478bc019dSStefan Eßer { \ 285d101cdd6SStefan Eßer c = bcl_contextHelper(vm); \ 28650696a6eSStefan Eßer assert(c != NULL); \ 28778bc019dSStefan Eßer } \ 28878bc019dSStefan Eßer while (0) 28950696a6eSStefan Eßer 29044d4804dSStefan Eßer /** 29144d4804dSStefan Eßer * A header to check the number in the context and return an error encoded as a 29244d4804dSStefan Eßer * @param c The context. 29344d4804dSStefan Eßer * number if it is bad. 29444d4804dSStefan Eßer * @param n The BclNumber. 29544d4804dSStefan Eßer */ 29650696a6eSStefan Eßer #define BC_CHECK_NUM(c, n) \ 29778bc019dSStefan Eßer do \ 29878bc019dSStefan Eßer { \ 299175a4d10SStefan Eßer size_t no_gen_ = BCL_NO_GEN(n); \ 300175a4d10SStefan Eßer if (BC_ERR(no_gen_ >= (c)->nums.len)) \ 30178bc019dSStefan Eßer { \ 30250696a6eSStefan Eßer if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \ 30378bc019dSStefan Eßer else \ 30478bc019dSStefan Eßer { \ 305175a4d10SStefan Eßer BclNumber n_num_; \ 306175a4d10SStefan Eßer n_num_.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \ 307175a4d10SStefan Eßer return n_num_; \ 30850696a6eSStefan Eßer } \ 30950696a6eSStefan Eßer } \ 310175a4d10SStefan Eßer BCL_CHECK_NUM_GEN(c, n); \ 31178bc019dSStefan Eßer } \ 31278bc019dSStefan Eßer while (0) 31378bc019dSStefan Eßer 31478bc019dSStefan Eßer //clang-format off 31550696a6eSStefan Eßer 31644d4804dSStefan Eßer /** 31744d4804dSStefan Eßer * A header to check the number in the context and return an error directly if 31844d4804dSStefan Eßer * it is bad. 31944d4804dSStefan Eßer * @param c The context. 32044d4804dSStefan Eßer * @param n The BclNumber. 32144d4804dSStefan Eßer */ 32250696a6eSStefan Eßer #define BC_CHECK_NUM_ERR(c, n) \ 32378bc019dSStefan Eßer do \ 32478bc019dSStefan Eßer { \ 325175a4d10SStefan Eßer size_t no_gen_ = BCL_NO_GEN(n); \ 326175a4d10SStefan Eßer if (BC_ERR(no_gen_ >= (c)->nums.len)) \ 32778bc019dSStefan Eßer { \ 32850696a6eSStefan Eßer if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \ 32978bc019dSStefan Eßer { \ 33050696a6eSStefan Eßer return (BclError) (0 - (n).i); \ 33178bc019dSStefan Eßer } \ 33250696a6eSStefan Eßer else return BCL_ERROR_INVALID_NUM; \ 33350696a6eSStefan Eßer } \ 334175a4d10SStefan Eßer BCL_CHECK_NUM_GEN(c, n); \ 33578bc019dSStefan Eßer } \ 33678bc019dSStefan Eßer while (0) 33778bc019dSStefan Eßer 33878bc019dSStefan Eßer //clang-format on 33950696a6eSStefan Eßer 34044d4804dSStefan Eßer /** 341175a4d10SStefan Eßer * Grows the context's nums array if necessary. 34244d4804dSStefan Eßer * @param c The context. 34344d4804dSStefan Eßer */ 344175a4d10SStefan Eßer #define BCL_GROW_NUMS(c) \ 345175a4d10SStefan Eßer do \ 346175a4d10SStefan Eßer { \ 347175a4d10SStefan Eßer if ((c)->free_nums.len == 0) \ 348175a4d10SStefan Eßer { \ 349175a4d10SStefan Eßer bc_vec_grow(&((c)->nums), 1); \ 350175a4d10SStefan Eßer } \ 351175a4d10SStefan Eßer } \ 352175a4d10SStefan Eßer while (0) 35350696a6eSStefan Eßer 35444d4804dSStefan Eßer /** 35544d4804dSStefan Eßer * Frees a BcNum for bcl. This is a destructor. 35644d4804dSStefan Eßer * @param num The BcNum to free, as a void pointer. 35744d4804dSStefan Eßer */ 35878bc019dSStefan Eßer void 35978bc019dSStefan Eßer bcl_num_destruct(void* num); 36050696a6eSStefan Eßer 36144d4804dSStefan Eßer /// The actual context struct. 36278bc019dSStefan Eßer typedef struct BclCtxt 36378bc019dSStefan Eßer { 36444d4804dSStefan Eßer /// The context's scale. 36550696a6eSStefan Eßer size_t scale; 36644d4804dSStefan Eßer 36744d4804dSStefan Eßer /// The context's ibase. 36850696a6eSStefan Eßer size_t ibase; 36944d4804dSStefan Eßer 37044d4804dSStefan Eßer /// The context's obase. 37150696a6eSStefan Eßer size_t obase; 37250696a6eSStefan Eßer 37344d4804dSStefan Eßer /// A vector of BcNum numbers. 37450696a6eSStefan Eßer BcVec nums; 37544d4804dSStefan Eßer 37644d4804dSStefan Eßer /// A vector of BclNumbers. These are the indices in nums that are currently 37744d4804dSStefan Eßer /// not used (because they were freed). 37850696a6eSStefan Eßer BcVec free_nums; 37950696a6eSStefan Eßer 38050696a6eSStefan Eßer } BclCtxt; 38150696a6eSStefan Eßer 382d101cdd6SStefan Eßer /** 383d101cdd6SStefan Eßer * Returns the @a BcVm for the current thread. 384d101cdd6SStefan Eßer * @return The vm for the current thread. 385d101cdd6SStefan Eßer */ 386d101cdd6SStefan Eßer BcVm* 387d101cdd6SStefan Eßer bcl_getspecific(void); 388d101cdd6SStefan Eßer 389d101cdd6SStefan Eßer #ifndef _WIN32 390d101cdd6SStefan Eßer 391d101cdd6SStefan Eßer typedef pthread_key_t BclTls; 392d101cdd6SStefan Eßer 393d101cdd6SStefan Eßer #else // _WIN32 394d101cdd6SStefan Eßer 395d101cdd6SStefan Eßer typedef DWORD BclTls; 396d101cdd6SStefan Eßer 397d101cdd6SStefan Eßer #endif // _WIN32 398d101cdd6SStefan Eßer 39950696a6eSStefan Eßer #endif // LIBBC_PRIVATE_H 400