xref: /freebsd/contrib/bc/include/library.h (revision cab6a39d7b343596a5823e65c0f7b426551ec22d)
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