xref: /freebsd/contrib/bc/include/library.h (revision 9768746b)
1 /*
2  * *****************************************************************************
3  *
4  * SPDX-License-Identifier: BSD-2-Clause
5  *
6  * Copyright (c) 2018-2023 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 #ifndef _WIN32
40 
41 #include <pthread.h>
42 
43 #endif // _WIN32
44 
45 #include <bcl.h>
46 
47 #include <num.h>
48 #include <vm.h>
49 
50 /**
51  * A header that sets a jump.
52  * @param vm  The thread data.
53  * @param l   The label to jump to on error.
54  */
55 #define BC_FUNC_HEADER(vm, l)     \
56 	do                            \
57 	{                             \
58 		BC_SETJMP(vm, l);         \
59 		vm->err = BCL_ERROR_NONE; \
60 	}                             \
61 	while (0)
62 
63 /**
64  * A footer for functions that do not return an error code.
65  */
66 #define BC_FUNC_FOOTER_NO_ERR(vm) \
67 	do                            \
68 	{                             \
69 		BC_UNSETJMP(vm);          \
70 	}                             \
71 	while (0)
72 
73 /**
74  * A footer for functions that *do* return an error code.
75  * @param vm  The thread data.
76  * @param e   The error variable to set.
77  */
78 #define BC_FUNC_FOOTER(vm, e)      \
79 	do                             \
80 	{                              \
81 		e = vm->err;               \
82 		BC_FUNC_FOOTER_NO_ERR(vm); \
83 	}                              \
84 	while (0)
85 
86 /**
87  * A footer that sets up n based the value of e and sets up the return value in
88  * idx.
89  * @param c    The context.
90  * @param e    The error.
91  * @param n    The number.
92  * @param idx  The idx to set as the return value.
93  */
94 #define BC_MAYBE_SETUP(c, e, n, idx)                \
95 	do                                              \
96 	{                                               \
97 		if (BC_ERR((e) != BCL_ERROR_NONE))          \
98 		{                                           \
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 	}                                               \
104 	while (0)
105 
106 /**
107  * A header to check the context and return an error encoded in a number if it
108  * is bad.
109  * @param c  The context.
110  */
111 #define BC_CHECK_CTXT(vm, c)                                  \
112 	do                                                        \
113 	{                                                         \
114 		c = bcl_contextHelper(vm);                            \
115 		if (BC_ERR(c == NULL))                                \
116 		{                                                     \
117 			BclNumber n_num;                                  \
118 			n_num.i = 0 - (size_t) BCL_ERROR_INVALID_CONTEXT; \
119 			return n_num;                                     \
120 		}                                                     \
121 	}                                                         \
122 	while (0)
123 
124 /**
125  * A header to check the context and return an error directly if it is bad.
126  * @param c  The context.
127  */
128 #define BC_CHECK_CTXT_ERR(vm, c)              \
129 	do                                        \
130 	{                                         \
131 		c = bcl_contextHelper(vm);            \
132 		if (BC_ERR(c == NULL))                \
133 		{                                     \
134 			return BCL_ERROR_INVALID_CONTEXT; \
135 		}                                     \
136 	}                                         \
137 	while (0)
138 
139 /**
140  * A header to check the context and abort if it is bad.
141  * @param c  The context.
142  */
143 #define BC_CHECK_CTXT_ASSERT(vm, c) \
144 	do                              \
145 	{                               \
146 		c = bcl_contextHelper(vm);  \
147 		assert(c != NULL);          \
148 	}                               \
149 	while (0)
150 
151 /**
152  * A header to check the number in the context and return an error encoded as a
153  * @param c  The context.
154  * number if it is bad.
155  * @param n  The BclNumber.
156  */
157 #define BC_CHECK_NUM(c, n)                                         \
158 	do                                                             \
159 	{                                                              \
160 		if (BC_ERR((n).i >= (c)->nums.len))                        \
161 		{                                                          \
162 			if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) return (n); \
163 			else                                                   \
164 			{                                                      \
165 				BclNumber n_num;                                   \
166 				n_num.i = 0 - (size_t) BCL_ERROR_INVALID_NUM;      \
167 				return n_num;                                      \
168 			}                                                      \
169 		}                                                          \
170 	}                                                              \
171 	while (0)
172 
173 //clang-format off
174 
175 /**
176  * A header to check the number in the context and return an error directly if
177  * it is bad.
178  * @param c  The context.
179  * @param n  The BclNumber.
180  */
181 #define BC_CHECK_NUM_ERR(c, n)                         \
182 	do                                                 \
183 	{                                                  \
184 		if (BC_ERR((n).i >= (c)->nums.len))            \
185 		{                                              \
186 			if ((n).i > 0 - (size_t) BCL_ERROR_NELEMS) \
187 			{                                          \
188 				return (BclError) (0 - (n).i);         \
189 			}                                          \
190 			else return BCL_ERROR_INVALID_NUM;         \
191 		}                                              \
192 	}                                                  \
193 	while (0)
194 
195 //clang-format on
196 
197 /**
198  * Turns a BclNumber into a BcNum.
199  * @param c  The context.
200  * @param n  The BclNumber.
201  */
202 #define BC_NUM(c, n) ((BcNum*) bc_vec_item(&(c)->nums, (n).i))
203 
204 /**
205  * Frees a BcNum for bcl. This is a destructor.
206  * @param num  The BcNum to free, as a void pointer.
207  */
208 void
209 bcl_num_destruct(void* num);
210 
211 /// The actual context struct.
212 typedef struct BclCtxt
213 {
214 	/// The context's scale.
215 	size_t scale;
216 
217 	/// The context's ibase.
218 	size_t ibase;
219 
220 	/// The context's obase.
221 	size_t obase;
222 
223 	/// A vector of BcNum numbers.
224 	BcVec nums;
225 
226 	/// A vector of BclNumbers. These are the indices in nums that are currently
227 	/// not used (because they were freed).
228 	BcVec free_nums;
229 
230 } BclCtxt;
231 
232 /**
233  * Returns the @a BcVm for the current thread.
234  * @return  The vm for the current thread.
235  */
236 BcVm*
237 bcl_getspecific(void);
238 
239 #ifndef _WIN32
240 
241 typedef pthread_key_t BclTls;
242 
243 #else // _WIN32
244 
245 typedef DWORD BclTls;
246 
247 #endif // _WIN32
248 
249 #endif // LIBBC_PRIVATE_H
250