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 #define BC_FUNC_HEADER_LOCK(l)   \
44 	do {                         \
45 		BC_SIG_LOCK;             \
46 		BC_SETJMP_LOCKED(l);     \
47 		vm.err = BCL_ERROR_NONE; \
48 		vm.running = 1;          \
49 	} while (0)
50 
51 #define BC_FUNC_FOOTER_UNLOCK(e) \
52 	do {                         \
53 		BC_SIG_ASSERT_LOCKED;    \
54 		e = vm.err;              \
55 		vm.running = 0;          \
56 		BC_UNSETJMP;             \
57 		BC_LONGJMP_STOP;         \
58 		vm.sig_lock = 0;         \
59 	} while (0)
60 
61 #define BC_FUNC_HEADER(l)        \
62 	do {                         \
63 		BC_SETJMP(l);            \
64 		vm.err = BCL_ERROR_NONE; \
65 		vm.running = 1;          \
66 	} while (0)
67 
68 #define BC_FUNC_HEADER_INIT(l)   \
69 	do {                         \
70 		BC_SETJMP_LOCKED(l);     \
71 		vm.err = BCL_ERROR_NONE; \
72 		vm.running = 1;          \
73 	} while (0)
74 
75 #define BC_FUNC_FOOTER_NO_ERR \
76 	do {                      \
77 		vm.running = 0;       \
78 		BC_UNSETJMP;          \
79 		BC_LONGJMP_STOP;      \
80 		vm.sig_lock = 0;      \
81 	} while (0)
82 
83 #define BC_FUNC_FOOTER(e)      \
84 	do {                       \
85 		e = vm.err;            \
86 		BC_FUNC_FOOTER_NO_ERR; \
87 	} while (0)
88 
89 #define BC_FUNC_RESETJMP(l)   \
90 	do {                      \
91 		BC_SIG_ASSERT_LOCKED; \
92 		BC_UNSETJMP;          \
93 		BC_SETJMP_LOCKED(l);  \
94 	} while (0)
95 
96 #define BC_MAYBE_SETUP(c, e, n, idx)                \
97 	do {                                            \
98 		if (BC_ERR((e) != BCL_ERROR_NONE)) {        \
99 			if ((n).num != NULL) bc_num_free(&(n)); \
100 			idx.i = 0 - (size_t) (e);               \
101 		}                                           \
102 		else idx = bcl_num_insert(c, &(n));         \
103 	} while (0)
104 
105 #define BC_CHECK_CTXT(c)                                      \
106 	do {                                                      \
107 		c = bcl_context();                                    \
108 		if (BC_ERR(c == NULL)) {                              \
109 			BclNumber n_num;                                  \
110 			n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
111 			return n_num;                                     \
112 		}                                                     \
113 	} while (0)
114 
115 #define BC_CHECK_CTXT_ERR(c)                  \
116 	do {                                      \
117 		c = bcl_context();                    \
118 		if (BC_ERR(c == NULL)) {              \
119 			return BCL_ERROR_INVALID_CONTEXT; \
120 		}                                     \
121 	} while (0)
122 
123 #define BC_CHECK_CTXT_ASSERT(c) \
124 	do {                        \
125 		c = bcl_context();      \
126 		assert(c != NULL);      \
127 	} while (0)
128 
129 #define BC_CHECK_NUM(c, n)                                         \
130 	do {                                                           \
131 		if (BC_ERR((n).i >= (c)->nums.len)) {                      \
132 			if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
133 			else {                                                 \
134 				BclNumber n_num;                                   \
135 				n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM;      \
136 				return n_num;                                      \
137 			}                                                      \
138 		}                                                          \
139 	} while (0)
140 
141 #define BC_CHECK_NUM_ERR(c, n)                         \
142 	do {                                               \
143 		if (BC_ERR((n).i >= (c)->nums.len)) {          \
144 			if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \
145 				return (BclError) (0 - (n).i);         \
146 			else return BCL_ERROR_INVALID_NUM;         \
147 		}                                              \
148 	} while (0)
149 
150 #define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
151 
152 typedef size_t (*BcReqOp)(const BcNum*, const BcNum*, size_t);
153 
154 typedef struct BclCtxt {
155 
156 	size_t scale;
157 	size_t ibase;
158 	size_t obase;
159 
160 	BcVec nums;
161 	BcVec free_nums;
162 
163 } BclCtxt;
164 
165 #endif // LIBBC_PRIVATE_H
166