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 { \ 51 BC_SIG_LOCK; \ 52 BC_SETJMP_LOCKED(l); \ 53 vm.err = BCL_ERROR_NONE; \ 54 vm.running = 1; \ 55 } \ 56 while (0) 57 58 /** 59 * A footer to unlock and stop the jumping if an error happened. It also sets 60 * the variable that tells bcl that it is running. 61 * @param e The error variable to set. 62 */ 63 #define BC_FUNC_FOOTER_UNLOCK(e) \ 64 do \ 65 { \ 66 BC_SIG_ASSERT_LOCKED; \ 67 e = vm.err; \ 68 vm.running = 0; \ 69 BC_UNSETJMP; \ 70 BC_LONGJMP_STOP; \ 71 vm.sig_lock = 0; \ 72 } \ 73 while (0) 74 75 /** 76 * A header that sets a jump and sets running. 77 * @param l The label to jump to on error. 78 */ 79 #define BC_FUNC_HEADER(l) \ 80 do \ 81 { \ 82 BC_SETJMP(l); \ 83 vm.err = BCL_ERROR_NONE; \ 84 vm.running = 1; \ 85 } \ 86 while (0) 87 88 /** 89 * A header that assumes that signals are already locked. It sets a jump and 90 * running. 91 * @param l The label to jump to on error. 92 */ 93 #define BC_FUNC_HEADER_INIT(l) \ 94 do \ 95 { \ 96 BC_SETJMP_LOCKED(l); \ 97 vm.err = BCL_ERROR_NONE; \ 98 vm.running = 1; \ 99 } \ 100 while (0) 101 102 /** 103 * A footer for functions that do not return an error code. It clears running 104 * and unlocks the signals. It also stops the jumping. 105 */ 106 #define BC_FUNC_FOOTER_NO_ERR \ 107 do \ 108 { \ 109 vm.running = 0; \ 110 BC_UNSETJMP; \ 111 BC_LONGJMP_STOP; \ 112 vm.sig_lock = 0; \ 113 } \ 114 while (0) 115 116 /** 117 * A footer for functions that *do* return an error code. It clears running and 118 * unlocks the signals. It also stops the jumping. 119 * @param e The error variable to set. 120 */ 121 #define BC_FUNC_FOOTER(e) \ 122 do \ 123 { \ 124 e = vm.err; \ 125 BC_FUNC_FOOTER_NO_ERR; \ 126 } \ 127 while (0) 128 129 /** 130 * A footer that sets up n based the value of e and sets up the return value in 131 * idx. 132 * @param c The context. 133 * @param e The error. 134 * @param n The number. 135 * @param idx The idx to set as the return value. 136 */ 137 #define BC_MAYBE_SETUP(c, e, n, idx) \ 138 do \ 139 { \ 140 if (BC_ERR((e) != BCL_ERROR_NONE)) \ 141 { \ 142 if ((n).num != NULL) bc_num_free(&(n)); \ 143 idx.i = 0 - (size_t) (e); \ 144 } \ 145 else idx = bcl_num_insert(c, &(n)); \ 146 } \ 147 while (0) 148 149 /** 150 * A header to check the context and return an error encoded in a number if it 151 * is bad. 152 * @param c The context. 153 */ 154 #define BC_CHECK_CTXT(c) \ 155 do \ 156 { \ 157 c = bcl_context(); \ 158 if (BC_ERR(c == NULL)) \ 159 { \ 160 BclNumber n_num; \ 161 n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \ 162 return n_num; \ 163 } \ 164 } \ 165 while (0) 166 167 /** 168 * A header to check the context and return an error directly if it is bad. 169 * @param c The context. 170 */ 171 #define BC_CHECK_CTXT_ERR(c) \ 172 do \ 173 { \ 174 c = bcl_context(); \ 175 if (BC_ERR(c == NULL)) \ 176 { \ 177 return BCL_ERROR_INVALID_CONTEXT; \ 178 } \ 179 } \ 180 while (0) 181 182 /** 183 * A header to check the context and abort if it is bad. 184 * @param c The context. 185 */ 186 #define BC_CHECK_CTXT_ASSERT(c) \ 187 do \ 188 { \ 189 c = bcl_context(); \ 190 assert(c != NULL); \ 191 } \ 192 while (0) 193 194 /** 195 * A header to check the number in the context and return an error encoded as a 196 * @param c The context. 197 * number if it is bad. 198 * @param n The BclNumber. 199 */ 200 #define BC_CHECK_NUM(c, n) \ 201 do \ 202 { \ 203 if (BC_ERR((n).i >= (c)->nums.len)) \ 204 { \ 205 if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \ 206 else \ 207 { \ 208 BclNumber n_num; \ 209 n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM; \ 210 return n_num; \ 211 } \ 212 } \ 213 } \ 214 while (0) 215 216 //clang-format off 217 218 /** 219 * A header to check the number in the context and return an error directly if 220 * it is bad. 221 * @param c The context. 222 * @param n The BclNumber. 223 */ 224 #define BC_CHECK_NUM_ERR(c, n) \ 225 do \ 226 { \ 227 if (BC_ERR((n).i >= (c)->nums.len)) \ 228 { \ 229 if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \ 230 { \ 231 return (BclError) (0 - (n).i); \ 232 } \ 233 else return BCL_ERROR_INVALID_NUM; \ 234 } \ 235 } \ 236 while (0) 237 238 //clang-format on 239 240 /** 241 * Turns a BclNumber into a BcNum. 242 * @param c The context. 243 * @param n The BclNumber. 244 */ 245 #define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i)) 246 247 /** 248 * Frees a BcNum for bcl. This is a destructor. 249 * @param num The BcNum to free, as a void pointer. 250 */ 251 void 252 bcl_num_destruct(void* num); 253 254 /// The actual context struct. 255 typedef struct BclCtxt 256 { 257 /// The context's scale. 258 size_t scale; 259 260 /// The context's ibase. 261 size_t ibase; 262 263 /// The context's obase. 264 size_t obase; 265 266 /// A vector of BcNum numbers. 267 BcVec nums; 268 269 /// A vector of BclNumbers. These are the indices in nums that are currently 270 /// not used (because they were freed). 271 BcVec free_nums; 272 273 } BclCtxt; 274 275 #endif // LIBBC_PRIVATE_H 276