BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 /**
2 * @file arithmetic.c
3 * @author Ambroz Bizjak <ambrop7@gmail.com>
4 *
5 * @section LICENSE
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of the author nor the
15 * names of its contributors may be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * @section DESCRIPTION
30 *
31 * Arithmetic functions for unsigned integers.
32 *
33 * Synopsis:
34 * num_lesser(string n1, string n2)
35 * num_greater(string n1, string n2)
36 * num_lesser_equal(string n1, string n2)
37 * num_greater_equal(string n1, string n2)
38 * num_equal(string n1, string n2)
39 * num_different(string n1, string n2)
40 *
41 * Variables:
42 * (empty) - "true" or "false", reflecting the value of the relation in question
43 *
44 * Description:
45 * These statements perform arithmetic comparisons. The operands passed must be
46 * non-negative decimal integers representable in a uintmax_t. Otherwise, an error
47 * is triggered.
48 *
49 * Synopsis:
50 * num_add(string n1, string n2)
51 * num_subtract(string n1, string n2)
52 * num_multiply(string n1, string n2)
53 * num_divide(string n1, string n2)
54 * num_modulo(string n1, string n2)
55 *
56 * Description:
57 * These statements perform arithmetic operations. The operands passed must be
58 * non-negative decimal integers representable in a uintmax_t, and the result must
59 * also be representable and non-negative. For divide and modulo, n2 must be non-zero.
60 * If any of these restrictions is violated, an error is triggered.
61 *
62 * Variables:
63 * is_error - whether there was an arithmetic error with the operation (true/false).
64 * (empty) - the result of the operation as a string representing a decimal number.
65 * If an attempt is made to access this variable after an arithmetic error,
66 * the variable resolution will fail, and an error will be logged including
67 * information about the particular arithemtic error.
68 */
69  
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <inttypes.h>
74 #include <limits.h>
75  
76 #include <misc/parse_number.h>
77  
78 #include <ncd/module_common.h>
79  
80 #include <generated/blog_channel_ncd_arithmetic.h>
81  
82 struct boolean_instance {
83 NCDModuleInst *i;
84 int value;
85 };
86  
87 typedef int (*boolean_compute_func) (uintmax_t n1, uintmax_t n2);
88  
89 struct number_instance {
90 NCDModuleInst *i;
91 char const *error;
92 uintmax_t value;
93 };
94  
95 typedef char const * (*number_compute_func) (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out);
96  
97 static int compute_lesser (uintmax_t n1, uintmax_t n2)
98 {
99 return n1 < n2;
100 }
101  
102 static int compute_greater (uintmax_t n1, uintmax_t n2)
103 {
104 return n1 > n2;
105 }
106  
107 static int compute_lesser_equal (uintmax_t n1, uintmax_t n2)
108 {
109 return n1 <= n2;
110 }
111  
112 static int compute_greater_equal (uintmax_t n1, uintmax_t n2)
113 {
114 return n1 >= n2;
115 }
116  
117 static int compute_equal (uintmax_t n1, uintmax_t n2)
118 {
119 return n1 == n2;
120 }
121  
122 static int compute_different (uintmax_t n1, uintmax_t n2)
123 {
124 return n1 != n2;
125 }
126  
127 static char const * compute_add (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
128 {
129 if (n1 > UINTMAX_MAX - n2) {
130 return "addition overflow";
131 }
132 *out = n1 + n2;
133 return NULL;
134 }
135  
136 static char const * compute_subtract (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
137 {
138 if (n1 < n2) {
139 return "subtraction underflow";
140 }
141 *out = n1 - n2;
142 return NULL;
143 }
144  
145 static char const * compute_multiply (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
146 {
147 if (n2 != 0 && n1 > UINTMAX_MAX / n2) {
148 return "multiplication overflow";
149 }
150 *out = n1 * n2;
151 return NULL;
152 }
153  
154 static char const * compute_divide (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
155 {
156 if (n2 == 0) {
157 return "division quotient is zero";
158 }
159 *out = n1 / n2;
160 return NULL;
161 }
162  
163 static char const * compute_modulo (NCDModuleInst *i, uintmax_t n1, uintmax_t n2, uintmax_t *out)
164 {
165 if (n2 == 0) {
166 return "modulo modulus is zero";
167 }
168 *out = n1 % n2;
169 return NULL;
170 }
171  
172 static void new_boolean_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, boolean_compute_func cfunc)
173 {
174 struct boolean_instance *o = vo;
175 o->i = i;
176  
177 NCDValRef n1_arg;
178 NCDValRef n2_arg;
179 if (!NCDVal_ListRead(params->args, 2, &n1_arg, &n2_arg)) {
180 ModuleLog(i, BLOG_ERROR, "wrong arity");
181 goto fail0;
182 }
183  
184 uintmax_t n1;
185 if (!ncd_read_uintmax(n1_arg, &n1)) {
186 ModuleLog(o->i, BLOG_ERROR, "wrong first argument");
187 goto fail0;
188 }
189  
190 uintmax_t n2;
191 if (!ncd_read_uintmax(n2_arg, &n2)) {
192 ModuleLog(o->i, BLOG_ERROR, "wrong second argument");
193 goto fail0;
194 }
195  
196 o->value = cfunc(n1, n2);
197  
198 NCDModuleInst_Backend_Up(i);
199 return;
200  
201 fail0:
202 NCDModuleInst_Backend_DeadError(i);
203 }
204  
205 static int boolean_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValRef *out)
206 {
207 struct boolean_instance *o = vo;
208  
209 if (name == NCD_STRING_EMPTY) {
210 *out = ncd_make_boolean(mem, o->value);
211 return 1;
212 }
213  
214 return 0;
215 }
216  
217 static void new_number_templ (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params, number_compute_func cfunc)
218 {
219 struct number_instance *o = vo;
220 o->i = i;
221  
222 NCDValRef n1_arg;
223 NCDValRef n2_arg;
224 if (!NCDVal_ListRead(params->args, 2, &n1_arg, &n2_arg)) {
225 ModuleLog(i, BLOG_ERROR, "wrong arity");
226 goto fail0;
227 }
228  
229 uintmax_t n1;
230 if (!ncd_read_uintmax(n1_arg, &n1)) {
231 ModuleLog(o->i, BLOG_ERROR, "wrong first argument");
232 goto fail0;
233 }
234  
235 uintmax_t n2;
236 if (!ncd_read_uintmax(n2_arg, &n2)) {
237 ModuleLog(o->i, BLOG_ERROR, "wrong second argument");
238 goto fail0;
239 }
240  
241 o->error = cfunc(i, n1, n2, &o->value);
242  
243 NCDModuleInst_Backend_Up(i);
244 return;
245  
246 fail0:
247 NCDModuleInst_Backend_DeadError(i);
248 }
249  
250 static int number_func_getvar2 (void *vo, NCD_string_id_t name, NCDValMem *mem, NCDValRef *out)
251 {
252 struct number_instance *o = vo;
253  
254 if (name == NCD_STRING_IS_ERROR) {
255 *out = ncd_make_boolean(mem, !!o->error);
256 return 1;
257 }
258  
259 if (name == NCD_STRING_EMPTY) {
260 if (o->error) {
261 ModuleLog(o->i, BLOG_ERROR, "%s", o->error);
262 return 0;
263 }
264 *out = ncd_make_uintmax(mem, o->value);
265 return 1;
266 }
267  
268 return 0;
269 }
270  
271 static void func_new_lesser (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
272 {
273 new_boolean_templ(vo, i, params, compute_lesser);
274 }
275  
276 static void func_new_greater (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
277 {
278 new_boolean_templ(vo, i, params, compute_greater);
279 }
280  
281 static void func_new_lesser_equal (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
282 {
283 new_boolean_templ(vo, i, params, compute_lesser_equal);
284 }
285  
286 static void func_new_greater_equal (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
287 {
288 new_boolean_templ(vo, i, params, compute_greater_equal);
289 }
290  
291 static void func_new_equal (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
292 {
293 new_boolean_templ(vo, i, params, compute_equal);
294 }
295  
296 static void func_new_different (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
297 {
298 new_boolean_templ(vo, i, params, compute_different);
299 }
300  
301 static void func_new_add (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
302 {
303 new_number_templ(vo, i, params, compute_add);
304 }
305  
306 static void func_new_subtract (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
307 {
308 new_number_templ(vo, i, params, compute_subtract);
309 }
310  
311 static void func_new_multiply (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
312 {
313 new_number_templ(vo, i, params, compute_multiply);
314 }
315  
316 static void func_new_divide (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
317 {
318 new_number_templ(vo, i, params, compute_divide);
319 }
320  
321 static void func_new_modulo (void *vo, NCDModuleInst *i, const struct NCDModuleInst_new_params *params)
322 {
323 new_number_templ(vo, i, params, compute_modulo);
324 }
325  
326 static struct NCDModule modules[] = {
327 {
328 .type = "num_lesser",
329 .func_new2 = func_new_lesser,
330 .func_getvar2 = boolean_func_getvar2,
331 .alloc_size = sizeof(struct boolean_instance)
332 }, {
333 .type = "num_greater",
334 .func_new2 = func_new_greater,
335 .func_getvar2 = boolean_func_getvar2,
336 .alloc_size = sizeof(struct boolean_instance)
337 }, {
338 .type = "num_lesser_equal",
339 .func_new2 = func_new_lesser_equal,
340 .func_getvar2 = boolean_func_getvar2,
341 .alloc_size = sizeof(struct boolean_instance)
342 }, {
343 .type = "num_greater_equal",
344 .func_new2 = func_new_greater_equal,
345 .func_getvar2 = boolean_func_getvar2,
346 .alloc_size = sizeof(struct boolean_instance)
347 }, {
348 .type = "num_equal",
349 .func_new2 = func_new_equal,
350 .func_getvar2 = boolean_func_getvar2,
351 .alloc_size = sizeof(struct boolean_instance)
352 }, {
353 .type = "num_different",
354 .func_new2 = func_new_different,
355 .func_getvar2 = boolean_func_getvar2,
356 .alloc_size = sizeof(struct boolean_instance)
357 }, {
358 .type = "num_add",
359 .func_new2 = func_new_add,
360 .func_getvar2 = number_func_getvar2,
361 .alloc_size = sizeof(struct number_instance)
362 }, {
363 .type = "num_subtract",
364 .func_new2 = func_new_subtract,
365 .func_getvar2 = number_func_getvar2,
366 .alloc_size = sizeof(struct number_instance)
367 }, {
368 .type = "num_multiply",
369 .func_new2 = func_new_multiply,
370 .func_getvar2 = number_func_getvar2,
371 .alloc_size = sizeof(struct number_instance)
372 }, {
373 .type = "num_divide",
374 .func_new2 = func_new_divide,
375 .func_getvar2 = number_func_getvar2,
376 .alloc_size = sizeof(struct number_instance)
377 }, {
378 .type = "num_modulo",
379 .func_new2 = func_new_modulo,
380 .func_getvar2 = number_func_getvar2,
381 .alloc_size = sizeof(struct number_instance)
382 }, {
383 .type = NULL
384 }
385 };
386  
387 const struct NCDModuleGroup ncdmodule_arithmetic = {
388 .modules = modules
389 };