1 /* 2 * ***************************************************************************** 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2018-2021 Gavin D. Howard and contributors. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions are met: 10 * 11 * * Redistributions of source code must retain the above copyright notice, this 12 * list of conditions and the following disclaimer. 13 * 14 * * Redistributions in binary form must reproduce the above copyright notice, 15 * this list of conditions and the following disclaimer in the documentation 16 * and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 19 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 22 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 23 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 24 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 25 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 26 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 27 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 * 30 * ***************************************************************************** 31 * 32 * The private header for the bc library. 33 * 34 */ 35 36 #ifndef LIBBC_PRIVATE_H 37 #define LIBBC_PRIVATE_H 38 39 #include <bcl.h> 40 41 #include <num.h> 42 43 /** 44 * A header for functions that need to lock and setjmp(). It also sets the 45 * variable that tells bcl that it is running. 46 * @param l The label to jump to on error. 47 */ 48 #define BC_FUNC_HEADER_LOCK(l) \ 49 do { \ 50 BC_SIG_LOCK; \ 51 BC_SETJMP_LOCKED(l); \ 52 vm.err = BCL_ERROR_NONE; \ 53 vm.running = 1; \ 54 } while (0) 55 56 /** 57 * A footer to unlock and stop the jumping if an error happened. It also sets 58 * the variable that tells bcl that it is running. 59 * @param e The error variable to set. 60 */ 61 #define BC_FUNC_FOOTER_UNLOCK(e) \ 62 do { \ 63 BC_SIG_ASSERT_LOCKED; \ 64 e = vm.err; \ 65 vm.running = 0; \ 66 BC_UNSETJMP; \ 67 BC_LONGJMP_STOP; \ 68 vm.sig_lock = 0; \ 69 } while (0) 70 71 /** 72 * A header that sets a jump and sets running. 73 * @param l The label to jump to on error. 74 */ 75 #define BC_FUNC_HEADER(l) \ 76 do { \ 77 BC_SETJMP(l); \ 78 vm.err = BCL_ERROR_NONE; \ 79 vm.running = 1; \ 80 } while (0) 81 82 /** 83 * A header that assumes that signals are already locked. It sets a jump and 84 * running. 85 * @param l The label to jump to on error. 86 */ 87 #define BC_FUNC_HEADER_INIT(l) \ 88 do { \ 89 BC_SETJMP_LOCKED(l); \ 90 vm.err = BCL_ERROR_NONE; \ 91 vm.running = 1; \ 92 } while (0) 93 94 /** 95 * A footer for functions that do not return an error code. It clears running 96 * and unlocks the signals. It also stops the jumping. 97 */ 98 #define BC_FUNC_FOOTER_NO_ERR \ 99 do { \ 100 vm.running = 0; \ 101 BC_UNSETJMP; \ 102 BC_LONGJMP_STOP; \ 103 vm.sig_lock = 0; \ 104 } while (0) 105 106 /** 107 * A footer for functions that *do* return an error code. It clears running and 108 * unlocks the signals. It also stops the jumping. 109 * @param e The error variable to set. 110 */ 111 #define BC_FUNC_FOOTER(e) \ 112 do { \ 113 e = vm.err; \ 114 BC_FUNC_FOOTER_NO_ERR; \ 115 } while (0) 116 117 /** 118 * A footer that sets up n based the value of e and sets up the return value in 119 * idx. 120 * @param c The context. 121 * @param e The error. 122 * @param n The number. 123 * @param idx The idx to set as the return value. 124 */ 125 #define BC_MAYBE_SETUP(c, e, n, idx) \ 126 do { \ 127 if (BC_ERR((e) != BCL_ERROR_NONE)) { \ 128 if ((n).num != NULL) bc_num_free(&(n)); \ 129 idx.i = 0 - (size_t) (e); \ 130 } \ 131 else idx = bcl_num_insert(c, &(n)); \ 132 } while (0) 133 134 /** 135 * A header to check the context and return an error encoded in a number if it 136 * is bad. 137 * @param c The context. 138 */ 139 #define BC_CHECK_CTXT(c) \ 140 do { \ 141 c = bcl_context(); \ 142 if (BC_ERR(c == NULL)) { \ 143 BclNumber n_num; \ 144 n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \ 145 return n_num; \ 146 } \ 147 } while (0) 148 149 150 /** 151 * A header to check the context and return an error directly if it is bad. 152 * @param c The context. 153 */ 154 #define BC_CHECK_CTXT_ERR(c) \ 155 do { \ 156 c = bcl_context(); \ 157 if (BC_ERR(c == NULL)) { \ 158 return BCL_ERROR_INVALID_CONTEXT; \ 159 } \ 160 } while (0) 161 162 /** 163 * A header to check the context and abort if it is bad. 164 * @param c The context. 165 */ 166 #define BC_CHECK_CTXT_ASSERT(c) \ 167 do { \ 168 c = bcl_context(); \ 169 assert(c != NULL); \ 170 } while (0) 171 172 /** 173 * A header to check the number in the context and return an error encoded as a 174 * @param c The context. 175 * number if it is bad. 176 * @param n The BclNumber. 177 */ 178 #define BC_CHECK_NUM(c, n) \ 179 do { \ 180 if (BC_ERR((n).i >= (c)->nums.len)) { \ 181 if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \ 182 else { \ 183 BclNumber n_num; \ 184 n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \ 185 return n_num; \ 186 } \ 187 } \ 188 } while (0) 189 190 /** 191 * A header to check the number in the context and return an error directly if 192 * it is bad. 193 * @param c The context. 194 * @param n The BclNumber. 195 */ 196 #define BC_CHECK_NUM_ERR(c, n) \ 197 do { \ 198 if (BC_ERR((n).i >= (c)->nums.len)) { \ 199 if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \ 200 return (BclError) (0 - (n).i); \ 201 else return BCL_ERROR_INVALID_NUM; \ 202 } \ 203 } while (0) 204 205 /** 206 * Turns a BclNumber into a BcNum. 207 * @param c The context. 208 * @param n The BclNumber. 209 */ 210 #define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i)) 211 212 /** 213 * Frees a BcNum for bcl. This is a destructor. 214 * @param num The BcNum to free, as a void pointer. 215 */ 216 void bcl_num_destruct(void *num); 217 218 /// The actual context struct. 219 typedef struct BclCtxt { 220 221 /// The context's scale. 222 size_t scale; 223 224 /// The context's ibase. 225 size_t ibase; 226 227 /// The context's obase. 228 size_t obase; 229 230 /// A vector of BcNum numbers. 231 BcVec nums; 232 233 /// A vector of BclNumbers. These are the indices in nums that are currently 234 /// not used (because they were freed). 235 BcVec free_nums; 236 237 } BclCtxt; 238 239 #endif // LIBBC_PRIVATE_H 240