1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <math.h>
5 #include "lib/mlr_globals.h"
6 #include "lib/mlrutil.h"
7 #include "lib/mlrdatetime.h"
8 #include "lib/mlrregex.h"
9 #include "lib/mvfuncs.h"
10 #include "lib/utf8.h"
11 #include "lib/string_builder.h"
12 
13 // ================================================================
14 // See important notes at the top of mlrval.h.
15 // ================================================================
16 
17 typedef int mv_i_nn_comparator_func_t(mv_t* pa, mv_t* pb);
18 typedef int mv_i_xx_comparator_func_t(const mv_t* pa, const mv_t* pb);
19 
20 // ----------------------------------------------------------------
21 // Keystroke-savers for disposition matrices:
22 
23 // Unary:
_1u___(mv_t * pa)24 static mv_t _1u___(mv_t* pa) {
25 	return *pa;
26 }
_absn1(mv_t * pa)27 static mv_t _absn1(mv_t* pa) {
28 	return mv_absent();
29 }
_emt1(mv_t * pa)30 static mv_t _emt1(mv_t* pa) {
31 	return mv_empty();
32 }
_err1(mv_t * pa)33 static mv_t _err1(mv_t* pa) {
34 	return mv_error();
35 }
36 
37 // Binary:
_absn(mv_t * pa,mv_t * pb)38 static mv_t _absn(mv_t* pa, mv_t* pb) {
39 	return mv_absent();
40 }
_void(mv_t * pa,mv_t * pb)41 static mv_t _void(mv_t* pa, mv_t* pb) {
42 	return mv_empty();
43 }
_erro(mv_t * pa,mv_t * pb)44 static mv_t _erro(mv_t* pa, mv_t* pb) {
45 	return mv_error();
46 }
47 
_1___(mv_t * pa,mv_t * pb)48 static mv_t _1___(mv_t* pa, mv_t* pb) {
49 	return *pa;
50 }
_2___(mv_t * pa,mv_t * pb)51 static mv_t _2___(mv_t* pa, mv_t* pb) {
52 	return *pb;
53 }
_1f__(mv_t * pa,mv_t * pb)54 static mv_t _1f__(mv_t* pa, mv_t* pb) {
55 	mv_free(pb);
56 	return *pa;
57 }
_2f__(mv_t * pa,mv_t * pb)58 static mv_t _2f__(mv_t* pa, mv_t* pb) {
59 	mv_free(pa);
60 	return *pb;
61 }
_s1__(mv_t * pa,mv_t * pb)62 static mv_t _s1__(mv_t* pa, mv_t* pb) {
63 	return s_x_string_func(pa);
64 }
_s2__(mv_t * pa,mv_t * pb)65 static mv_t _s2__(mv_t* pa, mv_t* pb) {
66 	return s_x_string_func(pb);
67 }
_f0__(mv_t * pa,mv_t * pb)68 static mv_t _f0__(mv_t* pa, mv_t* pb) {
69 	return mv_from_float(0.0);
70 }
_i0__(mv_t * pa,mv_t * pb)71 static mv_t _i0__(mv_t* pa, mv_t* pb) {
72 	return mv_from_int(0LL);
73 }
74 
75 // ----------------------------------------------------------------
dot_strings(char * string1,char * string2)76 static mv_t dot_strings(char* string1, char* string2) {
77 	int len1 = strlen(string1);
78 	int len2 = strlen(string2);
79 	int len3 = len1 + len2 + 1; // for the null-terminator byte
80 	char* string3 = mlr_malloc_or_die(len3);
81 	strcpy(&string3[0], string1);
82 	strcpy(&string3[len1], string2);
83 	return mv_from_string_with_free(string3);
84 }
85 
dot_s_ss(mv_t * pval1,mv_t * pval2)86 mv_t dot_s_ss(mv_t* pval1, mv_t* pval2) {
87 	mv_t rv = dot_strings(pval1->u.strv, pval2->u.strv);
88 	mv_free(pval1);
89 	mv_free(pval2);
90 	return rv;
91 }
92 
dot_s_xs(mv_t * pval1,mv_t * pval2)93 mv_t dot_s_xs(mv_t* pval1, mv_t* pval2) {
94 	mv_t sval1 = s_x_string_func(pval1);
95 	mv_free(pval1);
96 	mv_t rv = dot_strings(sval1.u.strv, pval2->u.strv);
97 	mv_free(&sval1);
98 	mv_free(pval2);
99 	return rv;
100 }
101 
dot_s_sx(mv_t * pval1,mv_t * pval2)102 mv_t dot_s_sx(mv_t* pval1, mv_t* pval2) {
103 	mv_t sval2 = s_x_string_func(pval2);
104 	mv_free(pval2);
105 	mv_t rv = dot_strings(pval1->u.strv, sval2.u.strv);
106 	mv_free(pval1);
107 	mv_free(&sval2);
108 	return rv;
109 }
110 
dot_s_xx(mv_t * pval1,mv_t * pval2)111 mv_t dot_s_xx(mv_t* pval1, mv_t* pval2) {
112 	mv_t sval1 = s_x_string_func(pval1);
113 	mv_t sval2 = s_x_string_func(pval2);
114 	mv_t rv = dot_strings(sval1.u.strv, sval2.u.strv);
115 	mv_free(&sval1);
116 	mv_free(&sval2);
117 	return rv;
118 }
119 
120 static mv_binary_func_t* dot_dispositions[MT_DIM][MT_DIM] = {
121 	//         ERROR   ABSENT EMPTY  STRING    INT       FLOAT     BOOL
122 	/*ERROR*/  {_erro, _erro, _erro, _erro,    _erro,    _erro,    _erro},
123 	/*ABSENT*/ {_erro, _absn, _void, _2___,    _s2__,    _s2__,    _s2__},
124 	/*EMPTY*/  {_erro, _void, _void, _2___,    _s2__,    _s2__,    _s2__},
125 	/*STRING*/ {_erro, _1___, _1___, dot_s_ss, dot_s_sx, dot_s_sx, dot_s_sx},
126 	/*INT*/    {_erro, _s1__, _s1__, dot_s_xs, dot_s_xx, dot_s_xx, dot_s_xx},
127 	/*FLOAT*/  {_erro, _s1__, _s1__, dot_s_xs, dot_s_xx, dot_s_xx, dot_s_xx},
128 	/*BOOL*/   {_erro, _s1__, _s1__, dot_s_xs, dot_s_xx, dot_s_xx, dot_s_xx},
129 	};
130 
s_xx_dot_func(mv_t * pval1,mv_t * pval2)131 mv_t s_xx_dot_func(mv_t* pval1, mv_t* pval2) { return (dot_dispositions[pval1->type][pval2->type])(pval1,pval2); }
132 
133 // ----------------------------------------------------------------
sub_no_precomp_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)134 mv_t sub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
135 	regex_t regex;
136 	string_builder_t *psb = sb_alloc(MV_SB_ALLOC_LENGTH);
137 	mv_t rv = sub_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0), psb, pval3);
138 	sb_free(psb);
139 	regfree(&regex);
140 	mv_free(pval2);
141 	return rv;
142 }
143 
144 // ----------------------------------------------------------------
145 // Example:
146 // * pval1->u.strv = "hello"
147 // * regex = "l+"
148 // * pval3->u.strv = "yyy"
149 //
150 // *  len1 = 2 = length of "he"
151 // * olen2 = 2 = length of "ll"
152 // * nlen2 = 3 = length of "yyy"
153 // *  len3 = 1 = length of "o"
154 // *  len4 = 6 = 2+3+1
155 
sub_precomp_func(mv_t * pval1,regex_t * pregex,string_builder_t * psb,mv_t * pval3)156 mv_t sub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3) {
157 	int matched      = FALSE;
158 	int all_captured = FALSE;
159 	char* input      = pval1->u.strv;
160 	char* output     = regex_sub(input, pregex, psb, pval3->u.strv, &matched, &all_captured);
161 
162 	mv_free(pval1);
163 	mv_free(pval3);
164 	return mv_from_string_with_free(output);
165 }
166 
167 // ----------------------------------------------------------------
168 // Example:
169 // * pval1->u.strv = "hello"
170 // * regex = "l+"
171 // * pval3->u.strv = "yyy"
172 //
173 // *  len1 = 2 = length of "he"
174 // * olen2 = 2 = length of "ll"
175 // * nlen2 = 3 = length of "yyy"
176 // *  len3 = 1 = length of "o"
177 // *  len4 = 6 = 2+3+1
178 
gsub_no_precomp_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)179 mv_t gsub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
180 	regex_t regex;
181 	string_builder_t *psb = sb_alloc(MV_SB_ALLOC_LENGTH);
182 	mv_t rv = gsub_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0), psb, pval3);
183 	sb_free(psb);
184 	regfree(&regex);
185 	mv_free(pval2);
186 	return rv;
187 }
188 
gsub_precomp_func(mv_t * pval1,regex_t * pregex,string_builder_t * psb,mv_t * pval3)189 mv_t gsub_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, mv_t* pval3) {
190 	int matched      = FALSE;
191 	int all_captured = FALSE;
192 	char* input      = pval1->u.strv;
193 	char free_flags  = NO_FREE;
194 	char* output     = regex_gsub(input, pregex, psb, pval3->u.strv, &matched, &all_captured, &free_flags);
195 
196 	mv_free(pval1);
197 	mv_free(pval3);
198 	return mv_from_string(output, free_flags);
199 }
200 
201 // ----------------------------------------------------------------
regextract_no_precomp_func(mv_t * pval1,mv_t * pval2)202 mv_t regextract_no_precomp_func(mv_t* pval1, mv_t* pval2) {
203 	regex_t regex;
204 	mv_t rv = regextract_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0));
205 	regfree(&regex);
206 	mv_free(pval2);
207 	return rv;
208 }
209 
210 // ----------------------------------------------------------------
regextract_precomp_func(mv_t * pval1,regex_t * pregex)211 mv_t regextract_precomp_func(mv_t* pval1, regex_t* pregex) {
212 	char* input  = pval1->u.strv;
213 	char* output = regextract(input, pregex);
214 
215 	mv_free(pval1);
216 	if (output == NULL) {
217 		return mv_absent();
218 	} else {
219 		return mv_from_string_with_free(output);
220 	}
221 }
222 
223 // ----------------------------------------------------------------
regextract_or_else_no_precomp_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)224 mv_t regextract_or_else_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
225 	regex_t regex;
226 	mv_t rv = regextract_or_else_precomp_func(pval1, regcomp_or_die(&regex, pval2->u.strv, 0), pval3);
227 	regfree(&regex);
228 	mv_free(pval2);
229 	return rv;
230 }
231 
232 // ----------------------------------------------------------------
regextract_or_else_precomp_func(mv_t * pval1,regex_t * pregex,mv_t * pval3)233 mv_t regextract_or_else_precomp_func(mv_t* pval1, regex_t* pregex, mv_t* pval3) {
234 	char* input  = pval1->u.strv;
235 	char* default_value  = pval3->u.strv;
236 	char* output = regextract_or_else(input, pregex, default_value);
237 
238 	mv_free(pval1);
239 	mv_free(pval3);
240 	return mv_from_string_with_free(output);
241 }
242 
243 // ----------------------------------------------------------------
244 // String-substitution with no regexes or special characters.
245 // It is assumed that all inputs have already been checked to be strings.
s_sss_ssub_func(mv_t * pmvinput,mv_t * pmvold,mv_t * pmvnew)246 mv_t s_sss_ssub_func(mv_t* pmvinput, mv_t* pmvold, mv_t* pmvnew) {
247 	char* pinput = pmvinput->u.strv;
248 	char* pold = pmvold->u.strv;
249 	char* pnew = pmvnew->u.strv;
250 
251 	char* pmatch = strstr(pinput, pold);
252 
253 	if (pmatch == NULL) {
254 		mv_free(pmvold);
255 		mv_free(pmvnew);
256 		return *pmvinput;
257 	} else {
258 		// Example:
259 		// input: aaaaOOObbbbb
260 		// old:   OOO
261 		// new:   NNNNN
262 		// Output length: strlen(aaaa) + strlen(NNNNN) + strlen(bbbbb)
263 
264 		// Compute lengths
265 		int input_length = strlen(pinput);
266 		int old_length = strlen(pold);
267 		int new_length = strlen(pnew);
268 		int output_length = input_length - old_length + new_length + 1;
269 		int pre_length = pmatch - pinput; // the "aaaa" part
270 		int post_length = input_length - pre_length - old_length; // the "bbbbb" part
271 
272 		// Allocate output
273 		char* poutput = mlr_malloc_or_die(output_length);
274 		char* p = poutput;
275 
276 		// Populate output
277 		strncpy(p, pinput, pre_length);
278 		p += pre_length;
279 
280 		strcpy(p, pnew);
281 		p += new_length;
282 
283 		strcpy(p, &pinput[pre_length + old_length]);
284 		p += post_length;
285 
286 		*p = 0;
287 
288 		mv_free(pmvinput);
289 		mv_free(pmvold);
290 		mv_free(pmvnew);
291 		return mv_from_string(poutput, FREE_ENTRY_VALUE);
292 	}
293 }
294 
295 // ----------------------------------------------------------------
296 // https://en.wikipedia.org/wiki/Hamming_weight
297 
298 static const unsigned long long _m1  = 0x5555555555555555;
299 static const unsigned long long _m2  = 0x3333333333333333;
300 static const unsigned long long _m4  = 0x0f0f0f0f0f0f0f0f;
301 static const unsigned long long _m8  = 0x00ff00ff00ff00ff;
302 static const unsigned long long _m16 = 0x0000ffff0000ffff;
303 static const unsigned long long _m32 = 0x00000000ffffffff;
304 
i_i_bitcount_func(mv_t * pval1)305 mv_t i_i_bitcount_func(mv_t* pval1) {
306 	unsigned long long a = pval1->u.intv;
307 	a = (a & _m1 ) + ((a >>  1) & _m1 );
308 	a = (a & _m2 ) + ((a >>  2) & _m2 );
309 	a = (a & _m4 ) + ((a >>  4) & _m4 );
310 	a = (a & _m8 ) + ((a >>  8) & _m8 );
311 	a = (a & _m16) + ((a >> 16) & _m16);
312 	a = (a & _m32) + ((a >> 32) & _m32);
313 	return mv_from_int((long long)a);
314 }
315 
316 // ----------------------------------------------------------------
i_iii_modadd_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)317 mv_t i_iii_modadd_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
318 	long long m = pval3->u.intv;
319 	if (m <= 0LL)
320 		return mv_error();
321 	long long a = pval1->u.intv % m;
322 	if (a < 0LL)
323 		a += m; // crazy C-language mod operator
324 	long long b = pval2->u.intv % m;
325 	if (b < 0LL)
326 		b += m;
327 	long long c = (a + b) % m;
328 	return mv_from_int(c);
329 }
330 
i_iii_modsub_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)331 mv_t i_iii_modsub_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
332 	long long m = pval3->u.intv;
333 	if (m <= 0LL)
334 		return mv_error();
335 	long long a = pval1->u.intv % m;
336 	if (a < 0LL)
337 		a += m; // crazy C-language mod operator
338 	long long b = pval2->u.intv % m;
339 	if (b < 0LL)
340 		b += m;
341 	long long c = (a - b) % m;
342 	if (c < 0LL)
343 		c += m;
344 	return mv_from_int(c);
345 }
346 
i_iii_modmul_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)347 mv_t i_iii_modmul_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
348 	long long m = pval3->u.intv;
349 	if (m <= 0LL)
350 		return mv_error();
351 	long long a = pval1->u.intv % m;
352 	if (a < 0LL)
353 		a += m; // crazy C-language mod operator
354 	long long b = pval2->u.intv % m;
355 	if (b < 0LL)
356 		b += m;
357 	long long c = (a * b) % m;
358 	return mv_from_int(c);
359 }
360 
i_iii_modexp_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)361 mv_t i_iii_modexp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
362 	long long m = pval3->u.intv;
363 	if (m <= 0LL)
364 		return mv_error();
365 	long long a = pval1->u.intv % m;
366 	if (a < 0LL)
367 		a += m; // crazy C-language mod operator
368 
369 	long long e = pval2->u.intv;
370 
371 	long long c = 1LL;
372 	if (e == 1LL) {
373 		c = a;
374 	} else if (e == 0LL) {
375 		c = 1LL;
376 	} else if (e > 0) {
377 		long long ap = a;
378 		c = 1LL;
379 		unsigned long long u = (unsigned long long)e;
380 
381 		// repeated-squaring algorithm
382 		while (u != 0) {
383 			if ((u & 1LL) == 1LL) {
384 				c = (c * ap) % m;
385 			}
386 			u >>= 1;
387 			ap = (ap * ap) % m;
388 		}
389 	} else {
390 		return mv_error();
391 	}
392 
393 	return mv_from_int(c);
394 }
395 
396 // ----------------------------------------------------------------
i_s_strlen_func(mv_t * pval1)397 mv_t i_s_strlen_func(mv_t* pval1) {
398 	mv_t rv = mv_from_int(strlen_for_utf8_display(pval1->u.strv));
399 	mv_free(pval1);
400 	return rv;
401 }
402 
s_x_typeof_func(mv_t * pval1)403 mv_t s_x_typeof_func(mv_t* pval1) {
404 	mv_t rv = mv_from_string(mt_describe_type(pval1->type), NO_FREE);
405 	mv_free(pval1);
406 	return rv;
407 }
408 
409 // ----------------------------------------------------------------
s_s_tolower_func(mv_t * pval1)410 mv_t s_s_tolower_func(mv_t* pval1) {
411 	char* string = mlr_strdup_or_die(pval1->u.strv);
412 #if 0
413 	// ASCII only
414 	for (char* c = string; *c; c++)
415 		*c = tolower((unsigned char)*c);
416 #else
417 	// UTF-8
418 	utf8lwr(string);
419 #endif
420 	mv_free(pval1);
421 	pval1->u.strv = NULL;
422 
423 	return mv_from_string_with_free(string);
424 }
425 
s_s_toupper_func(mv_t * pval1)426 mv_t s_s_toupper_func(mv_t* pval1) {
427 	char* string = mlr_strdup_or_die(pval1->u.strv);
428 #if 0
429 	// ASCII only
430 	for (char* c = string; *c; c++)
431 		*c = toupper((unsigned char)*c);
432 #else
433 	// UTF-8
434 	utf8upr(string);
435 #endif
436 	mv_free(pval1);
437 	pval1->u.strv = NULL;
438 
439 	return mv_from_string_with_free(string);
440 }
441 
s_s_capitalize_func(mv_t * pval1)442 mv_t s_s_capitalize_func(mv_t* pval1) {
443 	char* string = mlr_strdup_or_die(pval1->u.strv);
444 
445 	if (*string) {
446 #if 0
447 		// ASCII
448 		*string = toupper((unsigned char)*string);
449 #else
450 		// UTF-8
451 		utf8upr1(string);
452 #endif
453 	}
454 
455 	mv_free(pval1);
456 	pval1->u.strv = NULL;
457 
458 	return mv_from_string_with_free(string);
459 }
460 
s_s_system_func(mv_t * pval1)461 mv_t s_s_system_func(mv_t* pval1) {
462 	char* cmd = pval1->u.strv;
463 
464 	mv_t retval = mv_from_string_no_free("error-running-system-command");
465 	string_builder_t* psb = sb_alloc(100);
466     char buffer[128];
467 	FILE* pipe = popen(cmd, "r");
468 	if (pipe != NULL) {
469 		while (fgets(buffer, sizeof buffer, pipe) != NULL) {
470 			sb_append_string(psb, buffer);
471 		}
472 		pclose(pipe);
473 		char* output_string = sb_finish(psb);
474 
475 		// xxx make a windows-friendly lib func for chomp
476 		int len = strlen(output_string);
477 		if (len > 0) {
478 			if (output_string[len-1] == '\n') {
479 				output_string[len-1] = 0;
480 			}
481 		}
482 
483 		retval = mv_from_string_with_free(output_string);
484 	}
485 	sb_free(psb);
486 
487 	mv_free(pval1);
488 	pval1->u.strv = NULL;
489 
490 	return retval;
491 }
492 
s_si_truncate_func(mv_t * pval1,mv_t * pval2)493 mv_t s_si_truncate_func(mv_t* pval1, mv_t* pval2) {
494 	char* string = pval1->u.strv;
495 	int len = strlen(string);
496 	int maxlen = pval2->u.intv;
497 
498 	if (len <= maxlen) {
499 		return *pval1;
500 	} else {
501 		char* buf = mlr_malloc_or_die(maxlen+1);
502 		strncpy(buf, string, maxlen);
503 		buf[maxlen] = 0;
504 		mv_free(pval1);
505 		pval1->u.strv = NULL;
506 		return mv_from_string_with_free(buf);
507 	}
508 }
509 
510 // ----------------------------------------------------------------
s_s_lstrip_func(mv_t * pval1)511 mv_t s_s_lstrip_func(mv_t* pval1) {
512 	if (!isspace(pval1->u.strv[0])) {
513 		return *pval1;
514 	} else {
515 		char* p = pval1->u.strv;
516 		while (isspace(*p)) {
517 			p++;
518 		}
519 		char* retval = mlr_strdup_or_die(p);
520 		mv_free(pval1);
521 		return mv_from_string(retval, FREE_ENTRY_VALUE);
522 	}
523 }
524 
s_s_rstrip_func(mv_t * pval1)525 mv_t s_s_rstrip_func(mv_t* pval1) {
526 	char* start = pval1->u.strv;
527 	int oldlen = strlen(start);
528 	char* last_non_space = &start[oldlen-1];
529 	while ((start <= last_non_space) && isspace(*last_non_space))
530 		last_non_space--;
531 	if (last_non_space < start) {
532 		mv_free(pval1);
533 		return mv_empty();
534 	} else {
535 		int newlen = (last_non_space - start) + 1;
536 		char* retval = mlr_malloc_or_die(newlen + 1);
537 		memcpy(retval, start, newlen);
538 		retval[newlen] = 0;
539 		mv_free(pval1);
540 		return mv_from_string(retval, FREE_ENTRY_VALUE);
541 	}
542 }
543 
s_s_strip_func(mv_t * pval1)544 mv_t s_s_strip_func(mv_t* pval1) {
545 	mv_t temp = s_s_rstrip_func(pval1);
546 	return s_s_lstrip_func(&temp);
547 }
548 
s_s_collapse_whitespace_func(mv_t * pval1)549 mv_t s_s_collapse_whitespace_func(mv_t* pval1) {
550 	int len = strlen(pval1->u.strv);
551 	char* retval = mlr_malloc_or_die(len+1);
552 	char* pdst = retval;
553 	int last_was_space = FALSE;
554 	for (char* psrc = pval1->u.strv; *psrc; psrc++) {
555 		int current_is_space = isspace(*psrc);
556 		if (last_was_space && current_is_space) {
557 		} else {
558 			*pdst = *psrc;
559 			pdst++;
560 		}
561 		last_was_space = current_is_space;
562 	}
563 	*pdst = 0;
564 	mv_free(pval1);
565 	return mv_from_string(retval, FREE_ENTRY_VALUE);
566 }
567 
s_s_clean_whitespace_func(mv_t * pval1)568 mv_t s_s_clean_whitespace_func(mv_t* pval1) {
569 	mv_t temp = s_s_collapse_whitespace_func(pval1);
570 	return s_s_strip_func(&temp);
571 }
572 
573 // ----------------------------------------------------------------
574 // Precondition: psec is either int or float.
time_string_from_seconds(mv_t * psec,char * format,timezone_handling_t timezone_handling)575 mv_t time_string_from_seconds(mv_t* psec, char* format,
576 	timezone_handling_t timezone_handling)
577 {
578 	double seconds_since_the_epoch = 0.0;
579 	if (psec->type == MT_FLOAT) {
580 		if (isinf(psec->u.fltv) || isnan(psec->u.fltv)) {
581 			return mv_error();
582 		}
583 		seconds_since_the_epoch = psec->u.fltv;
584 	} else {
585 		seconds_since_the_epoch = psec->u.intv;
586 	}
587 
588 	char* string = mlr_alloc_time_string_from_seconds(seconds_since_the_epoch, format,
589 		timezone_handling);
590 
591 	return mv_from_string_with_free(string);
592 }
593 
594 // ----------------------------------------------------------------
sec2gmt_s_n(mv_t * pa)595 static mv_t sec2gmt_s_n(mv_t* pa) {
596 	return time_string_from_seconds(pa, ISO8601_TIME_FORMAT, TIMEZONE_HANDLING_GMT);
597 }
598 
599 static mv_unary_func_t* sec2gmt_dispositions[MT_DIM] = {
600 	/*ERROR*/  _err1,
601 	/*ABSENT*/ _absn1,
602 	/*EMPTY*/  _emt1,
603 	/*STRING*/ _1u___,
604 	/*INT*/    sec2gmt_s_n,
605 	/*FLOAT*/  sec2gmt_s_n,
606 	/*BOOL*/   _1u___,
607 };
s_x_sec2gmt_func(mv_t * pval1)608 mv_t s_x_sec2gmt_func(mv_t* pval1) { return (sec2gmt_dispositions[pval1->type])(pval1); }
609 
610 // Precondition: val2 is already asserted int
sec2gmt_s_ni(mv_t * pa,mv_t * pb)611 static mv_t sec2gmt_s_ni(mv_t* pa, mv_t* pb) {
612 	switch (pb->u.intv) {
613 	case 1: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_1, TIMEZONE_HANDLING_GMT); break;
614 	case 2: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_2, TIMEZONE_HANDLING_GMT); break;
615 	case 3: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_3, TIMEZONE_HANDLING_GMT); break;
616 	case 4: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_4, TIMEZONE_HANDLING_GMT); break;
617 	case 5: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_5, TIMEZONE_HANDLING_GMT); break;
618 	case 6: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_6, TIMEZONE_HANDLING_GMT); break;
619 	case 7: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_7, TIMEZONE_HANDLING_GMT); break;
620 	case 8: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_8, TIMEZONE_HANDLING_GMT); break;
621 	case 9: return time_string_from_seconds(pa, ISO8601_TIME_FORMAT_9, TIMEZONE_HANDLING_GMT); break;
622 	default: return mv_error();
623 	}
624 }
625 
626 static mv_binary_func_t* sec2gmtn_dispositions[MT_DIM] = {
627 	/*ERROR*/  _erro,
628 	/*ABSENT*/ _absn,
629 	/*EMPTY*/  _void,
630 	/*STRING*/ _1___,
631 	/*INT*/    sec2gmt_s_ni,
632 	/*FLOAT*/  sec2gmt_s_ni,
633 	/*BOOL*/   _1___,
634 };
s_xi_sec2gmt_func(mv_t * pval1,mv_t * pval2)635 mv_t s_xi_sec2gmt_func(mv_t* pval1, mv_t* pval2) { return (sec2gmtn_dispositions[pval1->type])(pval1, pval2); }
636 
637 // ----------------------------------------------------------------
sec2gmtdate_s_n(mv_t * pa)638 static mv_t sec2gmtdate_s_n(mv_t* pa) {
639 	return time_string_from_seconds(pa, ISO8601_DATE_FORMAT, TIMEZONE_HANDLING_GMT);
640 }
641 
642 static mv_unary_func_t* sec2gmtdate_dispositions[MT_DIM] = {
643 	/*ERROR*/  _err1,
644 	/*ABSENT*/ _absn1,
645 	/*EMPTY*/  _emt1,
646 	/*STRING*/ _1u___,
647 	/*INT*/    sec2gmtdate_s_n,
648 	/*FLOAT*/  sec2gmtdate_s_n,
649 	/*BOOL*/   _1u___,
650 };
651 
s_x_sec2gmtdate_func(mv_t * pval1)652 mv_t s_x_sec2gmtdate_func(mv_t* pval1) { return (sec2gmtdate_dispositions[pval1->type])(pval1); }
653 
654 // ----------------------------------------------------------------
sec2localtime_s_n(mv_t * pa)655 static mv_t sec2localtime_s_n(mv_t* pa) {
656 	return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT, TIMEZONE_HANDLING_LOCAL);
657 }
658 
659 static mv_unary_func_t* sec2localtime_dispositions[MT_DIM] = {
660 	/*ERROR*/  _err1,
661 	/*ABSENT*/ _absn1,
662 	/*EMPTY*/  _emt1,
663 	/*STRING*/ _1u___,
664 	/*INT*/    sec2localtime_s_n,
665 	/*FLOAT*/  sec2localtime_s_n,
666 	/*BOOL*/   _1u___,
667 };
s_x_sec2localtime_func(mv_t * pval1)668 mv_t s_x_sec2localtime_func(mv_t* pval1) { return (sec2localtime_dispositions[pval1->type])(pval1); }
669 
670 // Precondition: val2 is already asserted int
sec2localtime_s_ni(mv_t * pa,mv_t * pb)671 static mv_t sec2localtime_s_ni(mv_t* pa, mv_t* pb) {
672 	switch (pb->u.intv) {
673 	case 1: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_1, TIMEZONE_HANDLING_LOCAL); break;
674 	case 2: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_2, TIMEZONE_HANDLING_LOCAL); break;
675 	case 3: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_3, TIMEZONE_HANDLING_LOCAL); break;
676 	case 4: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_4, TIMEZONE_HANDLING_LOCAL); break;
677 	case 5: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_5, TIMEZONE_HANDLING_LOCAL); break;
678 	case 6: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_6, TIMEZONE_HANDLING_LOCAL); break;
679 	case 7: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_7, TIMEZONE_HANDLING_LOCAL); break;
680 	case 8: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_8, TIMEZONE_HANDLING_LOCAL); break;
681 	case 9: return time_string_from_seconds(pa, ISO8601_LOCAL_TIME_FORMAT_9, TIMEZONE_HANDLING_LOCAL); break;
682 	default: return mv_error();
683 	}
684 }
685 
686 static mv_binary_func_t* sec2localn_dispositions[MT_DIM] = {
687 	/*ERROR*/  _erro,
688 	/*ABSENT*/ _absn,
689 	/*EMPTY*/  _void,
690 	/*STRING*/ _1___,
691 	/*INT*/    sec2localtime_s_ni,
692 	/*FLOAT*/  sec2localtime_s_ni,
693 	/*BOOL*/   _1___,
694 };
s_xi_sec2localtime_func(mv_t * pval1,mv_t * pval2)695 mv_t s_xi_sec2localtime_func(mv_t* pval1, mv_t* pval2) { return (sec2localn_dispositions[pval1->type])(pval1, pval2); }
696 
697 // ----------------------------------------------------------------
sec2localdate_s_n(mv_t * pa)698 static mv_t sec2localdate_s_n(mv_t* pa) {
699 	return time_string_from_seconds(pa, ISO8601_DATE_FORMAT, TIMEZONE_HANDLING_LOCAL);
700 }
701 
702 static mv_unary_func_t* sec2localdate_dispositions[MT_DIM] = {
703 	/*ERROR*/  _err1,
704 	/*ABSENT*/ _absn1,
705 	/*EMPTY*/  _emt1,
706 	/*STRING*/ _1u___,
707 	/*INT*/    sec2localdate_s_n,
708 	/*FLOAT*/  sec2localdate_s_n,
709 	/*BOOL*/   _1u___,
710 };
711 
s_x_sec2localdate_func(mv_t * pval1)712 mv_t s_x_sec2localdate_func(mv_t* pval1) { return (sec2localdate_dispositions[pval1->type])(pval1); }
713 
714 
715 // ----------------------------------------------------------------
s_ns_strftime_func(mv_t * pval1,mv_t * pval2)716 mv_t s_ns_strftime_func(mv_t* pval1, mv_t* pval2) {
717 	mv_t rv = time_string_from_seconds(pval1, pval2->u.strv, TIMEZONE_HANDLING_GMT);
718 	mv_free(pval2);
719 	return rv;
720 }
721 
722 // ----------------------------------------------------------------
s_ns_strftime_local_func(mv_t * pval1,mv_t * pval2)723 mv_t s_ns_strftime_local_func(mv_t* pval1, mv_t* pval2) {
724 	mv_t rv = time_string_from_seconds(pval1, pval2->u.strv, TIMEZONE_HANDLING_LOCAL);
725 	mv_free(pval2);
726 	return rv;
727 }
728 
729 // ----------------------------------------------------------------
seconds_from_time_string(char * string,char * format,timezone_handling_t timezone_handling)730 static mv_t seconds_from_time_string(char* string, char* format,
731 	timezone_handling_t timezone_handling)
732 {
733 	if (*string == '\0') {
734 		return mv_empty();
735 	} else {
736 		return mv_from_float(mlr_seconds_from_time_string(string, format, timezone_handling));
737 	}
738 }
739 
i_s_gmt2sec_func(mv_t * pval1)740 mv_t i_s_gmt2sec_func(mv_t* pval1) {
741 	mv_t rv = seconds_from_time_string(pval1->u.strv, ISO8601_TIME_FORMAT, TIMEZONE_HANDLING_GMT);
742 	mv_free(pval1);
743 	return rv;
744 }
745 
i_s_localtime2sec_func(mv_t * pval1)746 mv_t i_s_localtime2sec_func(mv_t* pval1) {
747 	mv_t rv = seconds_from_time_string(pval1->u.strv, ISO8601_LOCAL_TIME_FORMAT, TIMEZONE_HANDLING_LOCAL);
748 	mv_free(pval1);
749 	return rv;
750 }
751 
i_ss_strptime_func(mv_t * pval1,mv_t * pval2)752 mv_t i_ss_strptime_func(mv_t* pval1, mv_t* pval2) {
753 	mv_t rv = seconds_from_time_string(pval1->u.strv, pval2->u.strv, TIMEZONE_HANDLING_GMT);
754 	mv_free(pval1);
755 	mv_free(pval2);
756 	return rv;
757 }
758 
i_ss_strptime_local_func(mv_t * pval1,mv_t * pval2)759 mv_t i_ss_strptime_local_func(mv_t* pval1, mv_t* pval2) {
760 	mv_t rv = seconds_from_time_string(pval1->u.strv, pval2->u.strv, TIMEZONE_HANDLING_LOCAL);
761 	mv_free(pval1);
762 	mv_free(pval2);
763 	return rv;
764 }
765 
766 // ----------------------------------------------------------------
split_ull_to_hms(long long u,long long * ph,long long * pm,long long * ps)767 static void split_ull_to_hms(long long u, long long* ph, long long* pm, long long* ps) {
768 	long long h = 0LL, m = 0LL, s = 0LL;
769 	long long sign = 1LL;
770 	if (u < 0LL) {
771 		u = -u;
772 		sign = -1LL;
773 	}
774 	s = u % 60LL;
775 	u = u / 60LL;
776 	if (u == 0LL) {
777 		s = s * sign;
778 	} else {
779 		m = u % 60LL;
780 		u = u / 60LL;
781 		if (u == 0LL) {
782 			m = m * sign;
783 		} else {
784 			h = u * sign;
785 		}
786 	}
787 	*ph = h;
788 	*pm = m;
789 	*ps = s;
790 }
791 
split_ull_to_dhms(long long u,long long * pd,long long * ph,long long * pm,long long * ps)792 static void split_ull_to_dhms(long long u, long long* pd, long long* ph, long long* pm, long long* ps) {
793 	long long d = 0LL, h = 0LL, m = 0LL, s = 0LL;
794 	long long sign = 1LL;
795 	if (u < 0LL) {
796 		u = -u;
797 		sign = -1LL;
798 	}
799 	s = u % 60LL;
800 	u = u / 60LL;
801 	if (u == 0LL) {
802 		s = s * sign;
803 	} else {
804 		m = u % 60LL;
805 		u = u / 60LL;
806 		if (u == 0LL) {
807 			m = m * sign;
808 		} else {
809 			h = u % 24LL;
810 			u = u / 24LL;
811 			if (u == 0LL) {
812 				h = h * sign;
813 			} else {
814 				d = u * sign;
815 			}
816 		}
817 	}
818 	*pd = d;
819 	*ph = h;
820 	*pm = m;
821 	*ps = s;
822 }
823 
s_i_sec2hms_func(mv_t * pval1)824 mv_t s_i_sec2hms_func(mv_t* pval1) {
825 	long long u = pval1->u.intv;
826 	long long h, m, s;
827 	char* fmt = "%02lld:%02lld:%02lld";
828 	if (u < 0) {
829 		u = -u;
830 		fmt = "-%02lld:%02lld:%02lld";
831 	}
832 	split_ull_to_hms(u, &h, &m, &s);
833 	int n = snprintf(NULL, 0, fmt, h, m, s);
834 	char* string = mlr_malloc_or_die(n+1);
835 	sprintf(string, fmt, h, m, s);
836 	return mv_from_string_with_free(string);
837 }
838 
s_f_fsec2hms_func(mv_t * pval1)839 mv_t s_f_fsec2hms_func(mv_t* pval1) {
840 	double v = fabs(pval1->u.fltv);
841 	long long h, m, s;
842 	char* fmt = "%lld:%02lld:%09.6lf";
843 	long long u = (long long)trunc(v);
844 	double f = v - u;
845 	if (pval1->u.fltv < 0.0) {
846 		fmt = "-%02lld:%02lld:%09.6lf";
847 	}
848 	split_ull_to_hms(u, &h, &m, &s);
849 	int n = snprintf(NULL, 0, fmt, h, m, s+f);
850 	char* string = mlr_malloc_or_die(n+1);
851 	sprintf(string, fmt, h, m, s+f);
852 	return mv_from_string_with_free(string);
853 }
854 
s_i_sec2dhms_func(mv_t * pval1)855 mv_t s_i_sec2dhms_func(mv_t* pval1) {
856 	long long u = pval1->u.intv;
857 	long long d, h, m, s;
858 	split_ull_to_dhms(u, &d, &h, &m, &s);
859 	if (d != 0.0) {
860 		char* fmt = "%lldd%02lldh%02lldm%02llds";
861 		int n = snprintf(NULL, 0, fmt, d, h, m, s);
862 		char* string = mlr_malloc_or_die(n+1);
863 		sprintf(string, fmt, d, h, m, s);
864 		return mv_from_string_with_free(string);
865 	} else if (h != 0.0) {
866 		char* fmt = "%lldh%02lldm%02llds";
867 		int n = snprintf(NULL, 0, fmt, h, m, s);
868 		char* string = mlr_malloc_or_die(n+1);
869 		sprintf(string, fmt, h, m, s);
870 		return mv_from_string_with_free(string);
871 	} else if (m != 0.0) {
872 		char* fmt = "%lldm%02llds";
873 		int n = snprintf(NULL, 0, fmt, m, s);
874 		char* string = mlr_malloc_or_die(n+1);
875 		sprintf(string, fmt, m, s);
876 		return mv_from_string_with_free(string);
877 	} else {
878 		char* fmt = "%llds";
879 		int n = snprintf(NULL, 0, fmt, s);
880 		char* string = mlr_malloc_or_die(n+1);
881 		sprintf(string, fmt, s);
882 		return mv_from_string_with_free(string);
883 	}
884 }
885 
s_f_fsec2dhms_func(mv_t * pval1)886 mv_t s_f_fsec2dhms_func(mv_t* pval1) {
887 	double v = fabs(pval1->u.fltv);
888 	long long sign = pval1->u.fltv < 0.0 ? -1LL : 1LL;
889 	long long d, h, m, s;
890 	long long u = (long long)trunc(v);
891 	double f = v - u;
892 	split_ull_to_dhms(u, &d, &h, &m, &s);
893 	if (d != 0.0) {
894 		d = sign * d;
895 		char* fmt = "%lldd%02lldh%02lldm%09.6lfs";
896 		int n = snprintf(NULL, 0, fmt, d, h, m, s+f);
897 		char* string = mlr_malloc_or_die(n+1);
898 		sprintf(string, fmt, d, h, m, s+f);
899 		return mv_from_string_with_free(string);
900 	} else if (h != 0.0) {
901 		h = sign * h;
902 		char* fmt = "%lldh%02lldm%09.6lfs";
903 		int n = snprintf(NULL, 0, fmt, h, m, s+f);
904 		char* string = mlr_malloc_or_die(n+1);
905 		sprintf(string, fmt, h, m, s+f);
906 		return mv_from_string_with_free(string);
907 	} else if (m != 0.0) {
908 		m = sign * m;
909 		char* fmt = "%lldm%09.6lfs";
910 		int n = snprintf(NULL, 0, fmt, m, s+f);
911 		char* string = mlr_malloc_or_die(n+1);
912 		sprintf(string, fmt, m, s+f);
913 		return mv_from_string_with_free(string);
914 	} else {
915 		s = sign * s;
916 		f = sign * f;
917 		char* fmt = "%.6lfs";
918 		int n = snprintf(NULL, 0, fmt, s+f);
919 		char* string = mlr_malloc_or_die(n+1);
920 		sprintf(string, fmt, s+f);
921 		return mv_from_string_with_free(string);
922 	}
923 }
924 
925 // ----------------------------------------------------------------
i_s_hms2sec_func(mv_t * pval1)926 mv_t i_s_hms2sec_func(mv_t* pval1) {
927 	long long h = 0LL, m = 0LL, s = 0LL;
928 	long long sec = 0LL;
929 	char* p = pval1->u.strv;
930 	long long sign = 1LL;
931 	if (*p == '-') {
932 		p++;
933 		sign = -1LL;
934 	}
935 	if (sscanf(p, "%lld:%lld:%lld", &h, &m, &s) == 3) {
936 		if (h >= 0LL)
937 			sec = 3600LL*h + 60LL*m + s;
938 		else
939 			sec = -(-3600LL*h + 60LL*m + s);
940 	} else if (sscanf(p, "%lld:%lld", &m, &s) == 2) {
941 		if (m >= 0LL)
942 			sec = 60LL*m + s;
943 		else
944 			sec = -(-60LL*m + s);
945 	} else if (sscanf(p, "%lld", &s) == 1) {
946 		sec = s;
947 	} else {
948 		mv_free(pval1);
949 		return mv_error();
950 	}
951 	mv_free(pval1);
952 	return mv_from_int(sec * sign);
953 }
954 
f_s_hms2fsec_func(mv_t * pval1)955 mv_t f_s_hms2fsec_func(mv_t* pval1) {
956 	long long h = 0LL, m = 0LL;
957 	double s = 0.0;
958 	double sec = 0.0;
959 	char* p = pval1->u.strv;
960 	double sign = 1.0;
961 	if (*p == '-') {
962 		p++;
963 		sign = -1.0;
964 	}
965 	if (sscanf(p, "%lld:%lld:%lf", &h, &m, &s) == 3) {
966 		sec = 3600*h + 60*m + s;
967 	} else if (sscanf(p, "%lld:%lf", &m, &s) == 2) {
968 		sec = 60*m + s;
969 	} else if (sscanf(p, "%lf", &s) == 2) {
970 		sec = s;
971 	} else {
972 		mv_free(pval1);
973 		return mv_error();
974 	}
975 	mv_free(pval1);
976 	return mv_from_float(sec * sign);
977 }
978 
i_s_dhms2sec_func(mv_t * pval1)979 mv_t i_s_dhms2sec_func(mv_t* pval1) {
980 	long long d = 0LL, h = 0LL, m = 0LL, s = 0LL;
981 	long long sec = 0LL;
982 	char* p = pval1->u.strv;
983 	long long sign = 1LL;
984 	if (*p == '-') {
985 		p++;
986 		sign = -1LL;
987 	}
988 	if (sscanf(p, "%lldd%lldh%lldm%llds", &d, &h, &m, &s) == 4) {
989 		sec = 86400*d + 3600*h + 60*m + s;
990 	} else if (sscanf(p, "%lldh%lldm%llds", &h, &m, &s) == 3) {
991 		sec = 3600*h + 60*m + s;
992 	} else if (sscanf(p, "%lldm%llds", &m, &s) == 2) {
993 		sec = 60*m + s;
994 	} else if (sscanf(p, "%llds", &s) == 1) {
995 		sec = s;
996 	} else {
997 		mv_free(pval1);
998 		return mv_error();
999 	}
1000 	mv_free(pval1);
1001 	return mv_from_int(sec * sign);
1002 }
1003 
f_s_dhms2fsec_func(mv_t * pval1)1004 mv_t f_s_dhms2fsec_func(mv_t* pval1) {
1005 	long long d = 0LL, h = 0LL, m = 0LL;
1006 	double s = 0.0;
1007 	double sec = 0.0;
1008 	char* p = pval1->u.strv;
1009 	long long sign = 1.0;
1010 	if (*p == '-') {
1011 		p++;
1012 		sign = -1.0;
1013 	}
1014 	if (sscanf(p, "%lldd%lldh%lldm%lfs", &d, &h, &m, &s) == 4) {
1015 		sec = 86400*d + 3600*h + 60*m + s;
1016 	} else if (sscanf(p, "%lldh%lldm%lfs", &h, &m, &s) == 3) {
1017 		sec = 3600*h + 60*m + s;
1018 	} else if (sscanf(p, "%lldm%lfs", &m, &s) == 2) {
1019 		sec = 60*m + s;
1020 	} else if (sscanf(p, "%lfs", &s) == 1) {
1021 		sec = s;
1022 	} else {
1023 		mv_free(pval1);
1024 		return mv_error();
1025 	}
1026 	mv_free(pval1);
1027 	return mv_from_float(sec * sign);
1028 }
1029 
1030 // ================================================================
plus_f_ff(mv_t * pa,mv_t * pb)1031 static mv_t plus_f_ff(mv_t* pa, mv_t* pb) {
1032 	double a = pa->u.fltv;
1033 	double b = pb->u.fltv;
1034 	return mv_from_float(a + b);
1035 }
plus_f_fi(mv_t * pa,mv_t * pb)1036 static mv_t plus_f_fi(mv_t* pa, mv_t* pb) {
1037 	double a = pa->u.fltv;
1038 	double b = (double)pb->u.intv;
1039 	return mv_from_float(a + b);
1040 }
plus_f_if(mv_t * pa,mv_t * pb)1041 static mv_t plus_f_if(mv_t* pa, mv_t* pb) {
1042 	double a = (double)pa->u.intv;
1043 	double b = pb->u.fltv;
1044 	return mv_from_float(a + b);
1045 }
1046 // Adds & subtracts overflow by at most one bit so it suffices to check
1047 // sign-changes.
plus_n_ii(mv_t * pa,mv_t * pb)1048 static mv_t plus_n_ii(mv_t* pa, mv_t* pb) {
1049 	long long a = pa->u.intv;
1050 	long long b = pb->u.intv;
1051 	long long c = a + b;
1052 
1053 	int overflowed = FALSE;
1054 	if (a > 0LL) {
1055 		if (b > 0LL && c < 0LL)
1056 			overflowed = TRUE;
1057 	} else if (a < 0LL) {
1058 		if (b < 0LL && c > 0LL)
1059 			overflowed = TRUE;
1060 	}
1061 
1062 	if (overflowed) {
1063 		return mv_from_float((double)a + (double)b);
1064 	} else {
1065 		return mv_from_int(c);
1066 	}
1067 }
1068 
1069 static mv_binary_func_t* plus_dispositions[MT_DIM][MT_DIM] = {
1070 	//         ERROR   ABSENT EMPTY  STRING INT        FLOAT      BOOL
1071 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,     _erro,     _erro},
1072 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,     _2___,     _erro},
1073 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,     _void,     _erro},
1074 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,     _erro,     _erro},
1075 	/*INT*/    {_erro, _1___, _void, _erro, plus_n_ii, plus_f_if, _erro},
1076 	/*FLOAT*/  {_erro, _1___, _void, _erro, plus_f_fi, plus_f_ff, _erro},
1077 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,     _erro,     _erro},
1078 	};
1079 
x_xx_plus_func(mv_t * pval1,mv_t * pval2)1080 mv_t x_xx_plus_func(mv_t* pval1, mv_t* pval2) { return (plus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1081 
1082 // ----------------------------------------------------------------
minus_f_ff(mv_t * pa,mv_t * pb)1083 static mv_t minus_f_ff(mv_t* pa, mv_t* pb) {
1084 	double a = pa->u.fltv;
1085 	double b = pb->u.fltv;
1086 	return mv_from_float(a - b);
1087 }
minus_f_fi(mv_t * pa,mv_t * pb)1088 static mv_t minus_f_fi(mv_t* pa, mv_t* pb) {
1089 	double a = pa->u.fltv;
1090 	double b = (double)pb->u.intv;
1091 	return mv_from_float(a - b);
1092 }
minus_f_if(mv_t * pa,mv_t * pb)1093 static mv_t minus_f_if(mv_t* pa, mv_t* pb) {
1094 	double a = (double)pa->u.intv;
1095 	double b = pb->u.fltv;
1096 	return mv_from_float(a - b);
1097 }
1098 // Adds & subtracts overflow by at most one bit so it suffices to check
1099 // sign-changes.
minus_n_ii(mv_t * pa,mv_t * pb)1100 static mv_t minus_n_ii(mv_t* pa, mv_t* pb) {
1101 	long long a = pa->u.intv;
1102 	long long b = pb->u.intv;
1103 	long long c = a - b;
1104 
1105 	int overflowed = FALSE;
1106 	if (a > 0LL) {
1107 		if (b < 0LL && c < 0LL)
1108 			overflowed = TRUE;
1109 	} else if (a < 0LL) {
1110 		if (b > 0LL && c > 0LL)
1111 			overflowed = TRUE;
1112 	}
1113 
1114 	if (overflowed) {
1115 		return mv_from_float((double)a - (double)b);
1116 	} else {
1117 		return mv_from_int(c);
1118 	}
1119 }
1120 
1121 static mv_binary_func_t* minus_dispositions[MT_DIM][MT_DIM] = {
1122 	//         ERROR   ABSENT EMPTY  STRING INT         FLOAT       BOOL
1123 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1124 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,      _2___,      _erro},
1125 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,      _void,      _erro},
1126 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1127 	/*INT*/    {_erro, _1___, _void, _erro, minus_n_ii, minus_f_if, _erro},
1128 	/*FLOAT*/  {_erro, _1___, _void, _erro, minus_f_fi, minus_f_ff, _erro},
1129 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1130 	};
1131 
x_xx_minus_func(mv_t * pval1,mv_t * pval2)1132 mv_t x_xx_minus_func(mv_t* pval1, mv_t* pval2) { return (minus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1133 
1134 // ----------------------------------------------------------------
times_f_ff(mv_t * pa,mv_t * pb)1135 static mv_t times_f_ff(mv_t* pa, mv_t* pb) {
1136 	double a = pa->u.fltv;
1137 	double b = pb->u.fltv;
1138 	return mv_from_float(a * b);
1139 }
times_f_fi(mv_t * pa,mv_t * pb)1140 static mv_t times_f_fi(mv_t* pa, mv_t* pb) {
1141 	double a = pa->u.fltv;
1142 	double b = (double)pb->u.intv;
1143 	return mv_from_float(a * b);
1144 }
times_f_if(mv_t * pa,mv_t * pb)1145 static mv_t times_f_if(mv_t* pa, mv_t* pb) {
1146 	double a = (double)pa->u.intv;
1147 	double b = pb->u.fltv;
1148 	return mv_from_float(a * b);
1149 }
1150 // Unlike adds & subtracts which overflow by at most one bit, multiplies can
1151 // overflow by a word size. Thus detecting sign-changes does not suffice to
1152 // detect overflow. Instead we test whether the floating-point product exceeds
1153 // the representable integer range. Now 64-bit integers have 64-bit precision
1154 // while IEEE-doubles have only 52-bit mantissas -- so, 53 bits including
1155 // implicit leading one.
1156 //
1157 // The following experiment explicitly demonstrates the resolution at this range:
1158 //
1159 //    64-bit integer     64-bit integer     Casted to double           Back to 64-bit
1160 //        in hex           in decimal                                    integer
1161 // 0x7ffffffffffff9ff 9223372036854774271 9223372036854773760.000000 0x7ffffffffffff800
1162 // 0x7ffffffffffffa00 9223372036854774272 9223372036854773760.000000 0x7ffffffffffff800
1163 // 0x7ffffffffffffbff 9223372036854774783 9223372036854774784.000000 0x7ffffffffffffc00
1164 // 0x7ffffffffffffc00 9223372036854774784 9223372036854774784.000000 0x7ffffffffffffc00
1165 // 0x7ffffffffffffdff 9223372036854775295 9223372036854774784.000000 0x7ffffffffffffc00
1166 // 0x7ffffffffffffe00 9223372036854775296 9223372036854775808.000000 0x8000000000000000
1167 // 0x7ffffffffffffffe 9223372036854775806 9223372036854775808.000000 0x8000000000000000
1168 // 0x7fffffffffffffff 9223372036854775807 9223372036854775808.000000 0x8000000000000000
1169 //
1170 // That is, we cannot check an integer product to see if it is greater than
1171 // 2**63-1 (or is less than -2**63) using integer arithmetic (it may have
1172 // already overflowed) *or* using double-precision (granularity). Instead we
1173 // check if the absolute value of the product exceeds the largest representable
1174 // double less than 2**63. (An alterative would be to do all integer multiplies
1175 // using handcrafted multi-word 128-bit arithmetic).
times_n_ii(mv_t * pa,mv_t * pb)1176 static mv_t times_n_ii(mv_t* pa, mv_t* pb) {
1177 	long long a = pa->u.intv;
1178 	long long b = pb->u.intv;
1179 
1180 	double d = (double)a * (double)b;
1181 	if (fabs(d) > 9223372036854774784.0) {
1182 		return mv_from_float(d);
1183 	} else {
1184 		return mv_from_int(a * b);
1185 	}
1186 }
1187 
1188 static mv_binary_func_t* times_dispositions[MT_DIM][MT_DIM] = {
1189 	//         ERROR   ABSENT EMPTY  STRING INT         FLOAT       BOOL
1190 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1191 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,      _2___,      _erro},
1192 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,      _void,      _erro},
1193 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1194 	/*INT*/    {_erro, _1___, _void, _erro, times_n_ii, times_f_if, _erro},
1195 	/*FLOAT*/  {_erro, _1___, _void, _erro, times_f_fi, times_f_ff, _erro},
1196 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1197 	};
1198 
x_xx_times_func(mv_t * pval1,mv_t * pval2)1199 mv_t x_xx_times_func(mv_t* pval1, mv_t* pval2) { return (times_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1200 
1201 // ----------------------------------------------------------------
divide_f_ff(mv_t * pa,mv_t * pb)1202 static mv_t divide_f_ff(mv_t* pa, mv_t* pb) {
1203 	double a = pa->u.fltv;
1204 	double b = pb->u.fltv;
1205 	return mv_from_float(a / b);
1206 }
divide_f_fi(mv_t * pa,mv_t * pb)1207 static mv_t divide_f_fi(mv_t* pa, mv_t* pb) {
1208 	double a = pa->u.fltv;
1209 	double b = (double)pb->u.intv;
1210 	return mv_from_float(a / b);
1211 }
divide_f_if(mv_t * pa,mv_t * pb)1212 static mv_t divide_f_if(mv_t* pa, mv_t* pb) {
1213 	double a = (double)pa->u.intv;
1214 	double b = pb->u.fltv;
1215 	return mv_from_float(a / b);
1216 }
divide_n_ii(mv_t * pa,mv_t * pb)1217 static mv_t divide_n_ii(mv_t* pa, mv_t* pb) {
1218 	long long a = pa->u.intv;
1219 	long long b = pb->u.intv;
1220 	if (b == 0LL) { // Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
1221 		return mv_from_float((double)a / (double)b);
1222 	}
1223 	long long r = a % b;
1224 	// Pythonic division, not C division.
1225 	if (r == 0LL) {
1226 		return mv_from_int(a / b);
1227 	} else {
1228 		return mv_from_float((double)a / (double)b);
1229 	}
1230 }
1231 
1232 static mv_binary_func_t* divide_dispositions[MT_DIM][MT_DIM] = {
1233 	//         ERROR   ABSENT EMPTY  STRING INT          FLOAT        BOOL
1234 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1235 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _i0__,       _f0__,       _erro},
1236 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,       _void,       _erro},
1237 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1238 	/*INT*/    {_erro, _1___, _void, _erro, divide_n_ii, divide_f_if, _erro},
1239 	/*FLOAT*/  {_erro, _1___, _void, _erro, divide_f_fi, divide_f_ff, _erro},
1240 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1241 	};
1242 
x_xx_divide_func(mv_t * pval1,mv_t * pval2)1243 mv_t x_xx_divide_func(mv_t* pval1, mv_t* pval2) { return (divide_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1244 
1245 // ----------------------------------------------------------------
idiv_f_ff(mv_t * pa,mv_t * pb)1246 static mv_t idiv_f_ff(mv_t* pa, mv_t* pb) {
1247 	double a = pa->u.fltv;
1248 	double b = pb->u.fltv;
1249 	return mv_from_float(floor(a / b));
1250 }
idiv_f_fi(mv_t * pa,mv_t * pb)1251 static mv_t idiv_f_fi(mv_t* pa, mv_t* pb) {
1252 	double a = pa->u.fltv;
1253 	double b = (double)pb->u.intv;
1254 	return mv_from_float(floor(a / b));
1255 }
idiv_f_if(mv_t * pa,mv_t * pb)1256 static mv_t idiv_f_if(mv_t* pa, mv_t* pb) {
1257 	double a = (double)pa->u.intv;
1258 	double b = pb->u.fltv;
1259 	return mv_from_float(floor(a / b));
1260 }
idiv_i_ii(mv_t * pa,mv_t * pb)1261 static mv_t idiv_i_ii(mv_t* pa, mv_t* pb) {
1262 	long long a = pa->u.intv;
1263 	long long b = pb->u.intv;
1264 	if (b == 0LL) { // Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
1265 		return mv_from_float((double)a / (double)b);
1266 	}
1267 	// Pythonic division, not C division.
1268 	long long q = a / b;
1269 	long long r = a % b;
1270 	if (a < 0) {
1271 		if (b > 0) {
1272 			if (r != 0)
1273 				q--;
1274 		}
1275 	} else {
1276 		if (b < 0) {
1277 			if (r != 0)
1278 				q--;
1279 		}
1280 	}
1281 	return mv_from_int(q);
1282 }
1283 
1284 static mv_binary_func_t* idiv_dispositions[MT_DIM][MT_DIM] = {
1285 	//         ERROR   ABSENT EMPTY  STRING INT        FLOAT      BOOL
1286 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,     _erro,     _erro},
1287 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _i0__,     _f0__,     _erro},
1288 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,     _void,     _erro},
1289 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,     _erro,     _erro},
1290 	/*INT*/    {_erro, _1___, _void, _erro, idiv_i_ii, idiv_f_if, _erro},
1291 	/*FLOAT*/  {_erro, _1___, _void, _erro, idiv_f_fi, idiv_f_ff, _erro},
1292 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,     _erro,     _erro},
1293 	};
1294 
x_xx_int_divide_func(mv_t * pval1,mv_t * pval2)1295 mv_t x_xx_int_divide_func(mv_t* pval1, mv_t* pval2) {
1296 	return (idiv_dispositions[pval1->type][pval2->type])(pval1,pval2);
1297 }
1298 
1299 // ================================================================
oplus_f_ff(mv_t * pa,mv_t * pb)1300 static mv_t oplus_f_ff(mv_t* pa, mv_t* pb) {
1301 	double a = pa->u.fltv;
1302 	double b = pb->u.fltv;
1303 	return mv_from_float(a + b);
1304 }
oplus_f_fi(mv_t * pa,mv_t * pb)1305 static mv_t oplus_f_fi(mv_t* pa, mv_t* pb) {
1306 	double a = pa->u.fltv;
1307 	double b = (double)pb->u.intv;
1308 	return mv_from_float(a + b);
1309 }
oplus_f_if(mv_t * pa,mv_t * pb)1310 static mv_t oplus_f_if(mv_t* pa, mv_t* pb) {
1311 	double a = (double)pa->u.intv;
1312 	double b = pb->u.fltv;
1313 	return mv_from_float(a + b);
1314 }
oplus_i_ii(mv_t * pa,mv_t * pb)1315 static mv_t oplus_i_ii(mv_t* pa, mv_t* pb) {
1316 	long long a = pa->u.intv;
1317 	long long b = pb->u.intv;
1318 	long long c = a + b;
1319 	return mv_from_int(c);
1320 }
1321 
1322 static mv_binary_func_t* oplus_dispositions[MT_DIM][MT_DIM] = {
1323 	//         ERROR   ABSENT EMPTY  STRING INT         FLOAT       BOOL
1324 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1325 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,      _2___,      _erro},
1326 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,      _void,      _erro},
1327 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1328 	/*INT*/    {_erro, _1___, _void, _erro, oplus_i_ii, oplus_f_if, _erro},
1329 	/*FLOAT*/  {_erro, _1___, _void, _erro, oplus_f_fi, oplus_f_ff, _erro},
1330 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1331 	};
1332 
x_xx_oplus_func(mv_t * pval1,mv_t * pval2)1333 mv_t x_xx_oplus_func(mv_t* pval1, mv_t* pval2) { return (oplus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1334 
1335 // ----------------------------------------------------------------
ominus_f_ff(mv_t * pa,mv_t * pb)1336 static mv_t ominus_f_ff(mv_t* pa, mv_t* pb) {
1337 	double a = pa->u.fltv;
1338 	double b = pb->u.fltv;
1339 	return mv_from_float(a - b);
1340 }
ominus_f_fi(mv_t * pa,mv_t * pb)1341 static mv_t ominus_f_fi(mv_t* pa, mv_t* pb) {
1342 	double a = pa->u.fltv;
1343 	double b = (double)pb->u.intv;
1344 	return mv_from_float(a - b);
1345 }
ominus_f_if(mv_t * pa,mv_t * pb)1346 static mv_t ominus_f_if(mv_t* pa, mv_t* pb) {
1347 	double a = (double)pa->u.intv;
1348 	double b = pb->u.fltv;
1349 	return mv_from_float(a - b);
1350 }
ominus_n_ii(mv_t * pa,mv_t * pb)1351 static mv_t ominus_n_ii(mv_t* pa, mv_t* pb) {
1352 	long long a = pa->u.intv;
1353 	long long b = pb->u.intv;
1354 	long long c = a - b;
1355 	return mv_from_int(c);
1356 }
1357 
1358 static mv_binary_func_t* ominus_dispositions[MT_DIM][MT_DIM] = {
1359 	//         ERROR   ABSENT EMPTY  STRING INT          FLOAT        BOOL
1360 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1361 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,       _2___,       _erro},
1362 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,       _void,       _erro},
1363 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1364 	/*INT*/    {_erro, _1___, _void, _erro, ominus_n_ii, ominus_f_if, _erro},
1365 	/*FLOAT*/  {_erro, _1___, _void, _erro, ominus_f_fi, ominus_f_ff, _erro},
1366 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1367 	};
1368 
x_xx_ominus_func(mv_t * pval1,mv_t * pval2)1369 mv_t x_xx_ominus_func(mv_t* pval1, mv_t* pval2) { return (ominus_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1370 
1371 // ----------------------------------------------------------------
otimes_f_ff(mv_t * pa,mv_t * pb)1372 static mv_t otimes_f_ff(mv_t* pa, mv_t* pb) {
1373 	double a = pa->u.fltv;
1374 	double b = pb->u.fltv;
1375 	return mv_from_float(a * b);
1376 }
otimes_f_fi(mv_t * pa,mv_t * pb)1377 static mv_t otimes_f_fi(mv_t* pa, mv_t* pb) {
1378 	double a = pa->u.fltv;
1379 	double b = (double)pb->u.intv;
1380 	return mv_from_float(a * b);
1381 }
otimes_f_if(mv_t * pa,mv_t * pb)1382 static mv_t otimes_f_if(mv_t* pa, mv_t* pb) {
1383 	double a = (double)pa->u.intv;
1384 	double b = pb->u.fltv;
1385 	return mv_from_float(a * b);
1386 }
otimes_n_ii(mv_t * pa,mv_t * pb)1387 static mv_t otimes_n_ii(mv_t* pa, mv_t* pb) {
1388 	long long a = pa->u.intv;
1389 	long long b = pb->u.intv;
1390 	return mv_from_int(a * b);
1391 }
1392 
1393 static mv_binary_func_t* otimes_dispositions[MT_DIM][MT_DIM] = {
1394 	//         ERROR   ABSENT EMPTY  STRING INT          FLOAT        BOOL
1395 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1396 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,       _2___,       _erro},
1397 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,       _void,       _erro},
1398 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1399 	/*INT*/    {_erro, _1___, _void, _erro, otimes_n_ii, otimes_f_if, _erro},
1400 	/*FLOAT*/  {_erro, _1___, _void, _erro, otimes_f_fi, otimes_f_ff, _erro},
1401 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1402 	};
1403 
x_xx_otimes_func(mv_t * pval1,mv_t * pval2)1404 mv_t x_xx_otimes_func(mv_t* pval1, mv_t* pval2) { return (otimes_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1405 
1406 // ----------------------------------------------------------------
odivide_f_ff(mv_t * pa,mv_t * pb)1407 static mv_t odivide_f_ff(mv_t* pa, mv_t* pb) {
1408 	double a = pa->u.fltv;
1409 	double b = pb->u.fltv;
1410 	return mv_from_float(a / b);
1411 }
odivide_f_fi(mv_t * pa,mv_t * pb)1412 static mv_t odivide_f_fi(mv_t* pa, mv_t* pb) {
1413 	double a = pa->u.fltv;
1414 	double b = (double)pb->u.intv;
1415 	return mv_from_float(a / b);
1416 }
odivide_f_if(mv_t * pa,mv_t * pb)1417 static mv_t odivide_f_if(mv_t* pa, mv_t* pb) {
1418 	double a = (double)pa->u.intv;
1419 	double b = pb->u.fltv;
1420 	return mv_from_float(a / b);
1421 }
odivide_i_ii(mv_t * pa,mv_t * pb)1422 static mv_t odivide_i_ii(mv_t* pa, mv_t* pb) {
1423 	long long a = pa->u.intv;
1424 	long long b = pb->u.intv;
1425 	return mv_from_int(a / b);
1426 }
1427 
1428 static mv_binary_func_t* odivide_dispositions[MT_DIM][MT_DIM] = {
1429 	//         ERROR   ABSENT EMPTY  STRING INT           FLOAT         BOOL
1430 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,        _erro,        _erro},
1431 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _i0__,        _f0__,        _erro},
1432 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,        _void,        _erro},
1433 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,        _erro,        _erro},
1434 	/*INT*/    {_erro, _1___, _void, _erro, odivide_i_ii, odivide_f_if, _erro},
1435 	/*FLOAT*/  {_erro, _1___, _void, _erro, odivide_f_fi, odivide_f_ff, _erro},
1436 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,        _erro,        _erro},
1437 	};
1438 
x_xx_odivide_func(mv_t * pval1,mv_t * pval2)1439 mv_t x_xx_odivide_func(mv_t* pval1, mv_t* pval2) { return (odivide_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1440 
1441 // ----------------------------------------------------------------
oidiv_f_ff(mv_t * pa,mv_t * pb)1442 static mv_t oidiv_f_ff(mv_t* pa, mv_t* pb) {
1443 	double a = pa->u.fltv;
1444 	double b = pb->u.fltv;
1445 	return mv_from_float(floor(a / b));
1446 }
oidiv_f_fi(mv_t * pa,mv_t * pb)1447 static mv_t oidiv_f_fi(mv_t* pa, mv_t* pb) {
1448 	double a = pa->u.fltv;
1449 	double b = (double)pb->u.intv;
1450 	return mv_from_float(floor(a / b));
1451 }
oidiv_f_if(mv_t * pa,mv_t * pb)1452 static mv_t oidiv_f_if(mv_t* pa, mv_t* pb) {
1453 	double a = (double)pa->u.intv;
1454 	double b = pb->u.fltv;
1455 	return mv_from_float(floor(a / b));
1456 }
oidiv_i_ii(mv_t * pa,mv_t * pb)1457 static mv_t oidiv_i_ii(mv_t* pa, mv_t* pb) {
1458 	long long a = pa->u.intv;
1459 	long long b = pb->u.intv;
1460 
1461 	// Pythonic division, not C division.
1462 	long long q = a / b;
1463 	long long r = a % b;
1464 	if (a < 0) {
1465 		if (b > 0) {
1466 			if (r != 0)
1467 				q--;
1468 		}
1469 	} else {
1470 		if (b < 0) {
1471 			if (r != 0)
1472 				q--;
1473 		}
1474 	}
1475 	return mv_from_int(q);
1476 }
1477 
1478 static mv_binary_func_t* oidiv_dispositions[MT_DIM][MT_DIM] = {
1479 	//         ERROR   ABSENT EMPTY  STRING INT         FLOAT       BOOL
1480 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1481 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _i0__,      _f0__,      _erro},
1482 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,      _void,      _erro},
1483 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1484 	/*INT*/    {_erro, _1___, _void, _erro, oidiv_i_ii, oidiv_f_if, _erro},
1485 	/*FLOAT*/  {_erro, _1___, _void, _erro, oidiv_f_fi, oidiv_f_ff, _erro},
1486 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,      _erro,      _erro},
1487 	};
1488 
x_xx_int_odivide_func(mv_t * pval1,mv_t * pval2)1489 mv_t x_xx_int_odivide_func(mv_t* pval1, mv_t* pval2) {
1490 	return (oidiv_dispositions[pval1->type][pval2->type])(pval1,pval2);
1491 }
1492 
1493 // ================================================================
mod_f_ff(mv_t * pa,mv_t * pb)1494 static mv_t mod_f_ff(mv_t* pa, mv_t* pb) {
1495 	double a = pa->u.fltv;
1496 	double b = pb->u.fltv;
1497 	return mv_from_float(a - b * floor(a / b));
1498 }
mod_f_fi(mv_t * pa,mv_t * pb)1499 static mv_t mod_f_fi(mv_t* pa, mv_t* pb) {
1500 	double a = pa->u.fltv;
1501 	double b = (double)pb->u.intv;
1502 	return mv_from_float(a - b * floor(a / b));
1503 }
mod_f_if(mv_t * pa,mv_t * pb)1504 static mv_t mod_f_if(mv_t* pa, mv_t* pb) {
1505 	double a = (double)pa->u.intv;
1506 	double b = pb->u.fltv;
1507 	return mv_from_float(a - b * floor(a / b));
1508 }
mod_i_ii(mv_t * pa,mv_t * pb)1509 static mv_t mod_i_ii(mv_t* pa, mv_t* pb) {
1510 	long long a = pa->u.intv;
1511 	long long b = pb->u.intv;
1512 	if (b == 0LL) { // Compute inf/nan as with floats rather than fatal runtime FPE on integer divide by zero
1513 		return mv_from_float((double)a / (double)b);
1514 	}
1515 	long long u = a % b;
1516 	// Pythonic division, not C division.
1517 	if (a >= 0LL) {
1518 		if (b < 0LL) {
1519 			u += b;
1520 		}
1521 	} else {
1522 		if (b >= 0LL) {
1523 			u += b;
1524 		}
1525 	}
1526 	return mv_from_int(u);
1527 }
1528 
1529 static mv_binary_func_t* mod_dispositions[MT_DIM][MT_DIM] = {
1530 	//         ERROR   ABSENT EMPTY  STRING INT       FLOAT     BOOL
1531 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,    _erro,    _erro},
1532 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _i0__,    _f0__,    _erro},
1533 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,    _void,    _erro},
1534 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,    _erro,    _erro},
1535 	/*INT*/    {_erro, _1___, _void, _erro, mod_i_ii, mod_f_if, _erro},
1536 	/*FLOAT*/  {_erro, _1___, _void, _erro, mod_f_fi, mod_f_ff, _erro},
1537 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,    _erro,    _erro},
1538 	};
1539 
x_xx_mod_func(mv_t * pval1,mv_t * pval2)1540 mv_t x_xx_mod_func(mv_t* pval1, mv_t* pval2) {
1541 	return (mod_dispositions[pval1->type][pval2->type])(pval1,pval2);
1542 }
1543 
1544 // ----------------------------------------------------------------
upos_i_i(mv_t * pa)1545 static mv_t upos_i_i(mv_t* pa) {
1546 	return *pa;
1547 }
upos_f_f(mv_t * pa)1548 static mv_t upos_f_f(mv_t* pa) {
1549 	return *pa;
1550 }
1551 
1552 static mv_unary_func_t* upos_dispositions[MT_DIM] = {
1553 	/*ERROR*/  _err1,
1554 	/*ABSENT*/ _absn1,
1555 	/*EMPTY*/  _emt1,
1556 	/*STRING*/ _err1,
1557 	/*INT*/    upos_i_i,
1558 	/*FLOAT*/  upos_f_f,
1559 	/*BOOL*/   _err1,
1560 };
1561 
x_x_upos_func(mv_t * pval1)1562 mv_t x_x_upos_func(mv_t* pval1) { return (upos_dispositions[pval1->type])(pval1); }
1563 
1564 // ----------------------------------------------------------------
uneg_i_i(mv_t * pa)1565 static mv_t uneg_i_i(mv_t* pa) {
1566 	return mv_from_int(-pa->u.intv);
1567 }
uneg_f_f(mv_t * pa)1568 static mv_t uneg_f_f(mv_t* pa) {
1569 	return mv_from_float(-pa->u.fltv);
1570 }
1571 
1572 static mv_unary_func_t* uneg_disnegitions[MT_DIM] = {
1573 	/*ERROR*/  _err1,
1574 	/*ABSENT*/ _absn1,
1575 	/*EMPTY*/  _emt1,
1576 	/*STRING*/ _err1,
1577 	/*INT*/    uneg_i_i,
1578 	/*FLOAT*/  uneg_f_f,
1579 	/*BOOL*/   _err1,
1580 };
1581 
x_x_uneg_func(mv_t * pval1)1582 mv_t x_x_uneg_func(mv_t* pval1) { return (uneg_disnegitions[pval1->type])(pval1); }
1583 
1584 // ----------------------------------------------------------------
abs_n_f(mv_t * pa)1585 static mv_t abs_n_f(mv_t* pa) {
1586 	return mv_from_float(fabs(pa->u.fltv));
1587 }
abs_n_i(mv_t * pa)1588 static mv_t abs_n_i(mv_t* pa) {
1589 	return mv_from_int(pa->u.intv < 0LL ? -pa->u.intv : pa->u.intv);
1590 }
1591 
1592 static mv_unary_func_t* abs_dispositions[MT_DIM] = {
1593 	/*ERROR*/  _err1,
1594 	/*ABSENT*/ _absn1,
1595 	/*EMPTY*/  _emt1,
1596 	/*STRING*/ _err1,
1597 	/*INT*/    abs_n_i,
1598 	/*FLOAT*/  abs_n_f,
1599 	/*BOOL*/   _err1,
1600 };
1601 
x_x_abs_func(mv_t * pval1)1602 mv_t x_x_abs_func(mv_t* pval1) { return (abs_dispositions[pval1->type])(pval1); }
1603 
1604 // ----------------------------------------------------------------
sgn_n_f(mv_t * pa)1605 static mv_t sgn_n_f(mv_t* pa) {
1606 	if (pa->u.fltv > 0.0)
1607 		return mv_from_float(1.0);
1608 	if (pa->u.fltv < 0.0)
1609 		return mv_from_float(-1.0);
1610 	return mv_from_float(0.0);
1611 }
sgn_n_i(mv_t * pa)1612 static mv_t sgn_n_i(mv_t* pa) {
1613 	if (pa->u.intv > 0LL)
1614 		return mv_from_int(1LL);
1615 	if (pa->u.intv < 0LL)
1616 		return mv_from_int(-1LL);
1617 	return mv_from_int(0LL);
1618 }
1619 
1620 static mv_unary_func_t* sgn_dispositions[MT_DIM] = {
1621 	/*ERROR*/  _err1,
1622 	/*ABSENT*/ _absn1,
1623 	/*EMPTY*/  _emt1,
1624 	/*STRING*/ _err1,
1625 	/*INT*/    sgn_n_i,
1626 	/*FLOAT*/  sgn_n_f,
1627 	/*BOOL*/   _err1,
1628 };
1629 
x_x_sgn_func(mv_t * pval1)1630 mv_t x_x_sgn_func(mv_t* pval1) { return (sgn_dispositions[pval1->type])(pval1); }
1631 
1632 // ----------------------------------------------------------------
ceil_n_f(mv_t * pa)1633 static mv_t ceil_n_f(mv_t* pa) {
1634 	return mv_from_float(ceil(pa->u.fltv));
1635 }
ceil_n_i(mv_t * pa)1636 static mv_t ceil_n_i(mv_t* pa) {
1637 	return mv_from_int(pa->u.intv);
1638 }
1639 
1640 static mv_unary_func_t* ceil_dispositions[MT_DIM] = {
1641 	/*ERROR*/  _err1,
1642 	/*ABSENT*/ _absn1,
1643 	/*EMPTY*/  _emt1,
1644 	/*STRING*/ _err1,
1645 	/*INT*/    ceil_n_i,
1646 	/*FLOAT*/  ceil_n_f,
1647 	/*BOOL*/   _err1,
1648 };
1649 
x_x_ceil_func(mv_t * pval1)1650 mv_t x_x_ceil_func(mv_t* pval1) { return (ceil_dispositions[pval1->type])(pval1); }
1651 
1652 // ----------------------------------------------------------------
floor_n_f(mv_t * pa)1653 static mv_t floor_n_f(mv_t* pa) {
1654 	return mv_from_float(floor(pa->u.fltv));
1655 }
floor_n_i(mv_t * pa)1656 static mv_t floor_n_i(mv_t* pa) {
1657 	return mv_from_int(pa->u.intv);
1658 }
1659 
1660 static mv_unary_func_t* floor_dispositions[MT_DIM] = {
1661 	/*ERROR*/  _err1,
1662 	/*ABSENT*/ _absn1,
1663 	/*EMPTY*/  _emt1,
1664 	/*STRING*/ _err1,
1665 	/*INT*/    floor_n_i,
1666 	/*FLOAT*/  floor_n_f,
1667 	/*BOOL*/   _err1,
1668 };
1669 
x_x_floor_func(mv_t * pval1)1670 mv_t x_x_floor_func(mv_t* pval1) { return (floor_dispositions[pval1->type])(pval1); }
1671 
1672 // ----------------------------------------------------------------
round_n_f(mv_t * pa)1673 static mv_t round_n_f(mv_t* pa) {
1674 	return mv_from_float(round(pa->u.fltv));
1675 }
round_n_i(mv_t * pa)1676 static mv_t round_n_i(mv_t* pa) {
1677 	return mv_from_int(pa->u.intv);
1678 }
1679 
1680 static mv_unary_func_t* round_dispositions[MT_DIM] = {
1681 	/*ERROR*/  _err1,
1682 	/*ABSENT*/ _absn1,
1683 	/*EMPTY*/  _emt1,
1684 	/*STRING*/ _err1,
1685 	/*INT*/    round_n_i,
1686 	/*FLOAT*/  round_n_f,
1687 	/*BOOL*/   _err1,
1688 };
1689 
x_x_round_func(mv_t * pval1)1690 mv_t x_x_round_func(mv_t* pval1) { return (round_dispositions[pval1->type])(pval1); }
1691 
1692 // ----------------------------------------------------------------
roundm_f_ff(mv_t * pa,mv_t * pb)1693 static mv_t roundm_f_ff(mv_t* pa, mv_t* pb) {
1694 	double x = pa->u.fltv;
1695 	double m = pb->u.fltv;
1696 	return mv_from_float(round(x / m) * m);
1697 }
roundm_f_fi(mv_t * pa,mv_t * pb)1698 static mv_t roundm_f_fi(mv_t* pa, mv_t* pb) {
1699 	double x = pa->u.fltv;
1700 	double m = (double)pb->u.intv;
1701 	return mv_from_float(round(x / m) * m);
1702 }
roundm_f_if(mv_t * pa,mv_t * pb)1703 static mv_t roundm_f_if(mv_t* pa, mv_t* pb) {
1704 	double x = (double)pa->u.intv;
1705 	double m = pb->u.fltv;
1706 	return mv_from_float(round(x / m) * m);
1707 }
roundm_i_ii(mv_t * pa,mv_t * pb)1708 static mv_t roundm_i_ii(mv_t* pa, mv_t* pb) {
1709 	long long x = pa->u.intv;
1710 	long long m = pb->u.intv;
1711 	return mv_from_int((x / m) * m);
1712 }
1713 
1714 static mv_binary_func_t* roundm_dispositions[MT_DIM][MT_DIM] = {
1715 	//         ERROR   ABSENT EMPTY  STRING INT          FLOAT        BOOL
1716 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1717 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _absn,       _erro,       _erro},
1718 	/*EMPTY*/  {_erro, _absn, _void, _erro, _erro,       _erro,       _erro},
1719 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1720 	/*INT*/    {_erro, _absn, _erro, _erro, roundm_i_ii, roundm_f_if, _erro},
1721 	/*FLOAT*/  {_erro, _erro, _erro, _erro, roundm_f_fi, roundm_f_ff, _erro},
1722 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,       _erro,       _erro},
1723 	};
1724 
x_xx_roundm_func(mv_t * pval1,mv_t * pval2)1725 mv_t x_xx_roundm_func(mv_t* pval1, mv_t* pval2) { return (roundm_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1726 
1727 // ----------------------------------------------------------------
min_f_ff(mv_t * pa,mv_t * pb)1728 static mv_t min_f_ff(mv_t* pa, mv_t* pb) {
1729 	double a = pa->u.fltv;
1730 	double b = pb->u.fltv;
1731 	return mv_from_float(fmin(a, b));
1732 }
1733 
min_f_fi(mv_t * pa,mv_t * pb)1734 static mv_t min_f_fi(mv_t* pa, mv_t* pb) {
1735 	double a = pa->u.fltv;
1736 	double b = (double)pb->u.intv;
1737 	return mv_from_float(fmin(a, b));
1738 }
1739 
min_f_if(mv_t * pa,mv_t * pb)1740 static mv_t min_f_if(mv_t* pa, mv_t* pb) {
1741 	double a = (double)pa->u.intv;
1742 	double b = pb->u.fltv;
1743 	return mv_from_float(fmin(a, b));
1744 }
1745 
min_i_ii(mv_t * pa,mv_t * pb)1746 static mv_t min_i_ii(mv_t* pa, mv_t* pb) {
1747 	long long a = pa->u.intv;
1748 	long long b = pb->u.intv;
1749 	return mv_from_int(a < b ? a : b);
1750 }
1751 
min_b_bb(mv_t * pa,mv_t * pb)1752 static mv_t min_b_bb(mv_t* pa, mv_t* pb) {
1753 	int a = pa->u.boolv;
1754 	int b = pb->u.boolv;
1755 	return mv_from_bool(a < b ? a : b);
1756 }
1757 
min_s_ss(mv_t * pa,mv_t * pb)1758 static mv_t min_s_ss(mv_t* pa, mv_t* pb) {
1759 	char* a = pa->u.strv;
1760 	char* b = pb->u.strv;
1761 	int   c = strcmp(a, b);
1762 	if (c <= 0) {
1763 		mv_free(pb);
1764 		return *pa;
1765 	} else {
1766 		mv_free(pa);
1767 		return *pb;
1768 	}
1769 }
1770 
1771 // Sort rules (same for min, max, and comparator):
1772 // * NUMERICS < BOOL < STRINGS < ERROR < ABSENT
1773 // * error == error (singleton type)
1774 // * absent == absent (singleton type)
1775 // * string compares on strings
1776 // * numeric compares on numbers
1777 // * false < true
1778 // Exceptions for min & max:
1779 // * absent-null always loses
1780 // * empty-null always loses against numbers
1781 static mv_binary_func_t* min_dispositions[MT_DIM][MT_DIM] = {
1782 	//         ERROR   ABSENT EMPTY  STRING    INT       FLOAT     BOOL
1783 	/*ERROR*/  {_erro, _erro, _erro, _erro,    _erro,    _erro,    _erro},
1784 	/*ABSENT*/ {_erro, _absn, _2___, _2f__,    _2___,    _2___,    _2___},
1785 	/*EMPTY*/  {_erro, _1___, _void, _void,    _2___,    _2___,    _2___},
1786 	/*STRING*/ {_erro, _1f__, _void, min_s_ss, _2f__,    _2f__,    _2f__},
1787 	/*INT*/    {_erro, _1___, _1___, _1f__,    min_i_ii, min_f_if, _1___},
1788 	/*FLOAT*/  {_erro, _1___, _1___, _1f__,    min_f_fi, min_f_ff, _1___},
1789 	/*BOOL*/   {_erro, _1___, _1___, _1f__,    _2___,    _2___,    min_b_bb},
1790 	};
1791 
x_xx_min_func(mv_t * pval1,mv_t * pval2)1792 mv_t x_xx_min_func(mv_t* pval1, mv_t* pval2) {
1793 	return (min_dispositions[pval1->type][pval2->type])(pval1,pval2);
1794 }
1795 
variadic_min_func(mv_t * pvals,int nvals)1796 mv_t variadic_min_func(mv_t* pvals, int nvals) {
1797 	if (nvals == 0) {
1798 		return mv_empty();
1799 	} else {
1800 		mv_t rv = pvals[0];
1801 		for (int i = 1; i < nvals; i++) {
1802 			rv = x_xx_min_func(&rv, &pvals[i]);
1803 			// Disposition-matrix entries for min all free their non-return arguments
1804 		}
1805 		return rv;
1806 	}
1807 }
1808 
1809 // ----------------------------------------------------------------
max_f_ff(mv_t * pa,mv_t * pb)1810 static mv_t max_f_ff(mv_t* pa, mv_t* pb) {
1811 	double a = pa->u.fltv;
1812 	double b = pb->u.fltv;
1813 	return mv_from_float(fmax(a, b));
1814 }
1815 
max_f_fi(mv_t * pa,mv_t * pb)1816 static mv_t max_f_fi(mv_t* pa, mv_t* pb) {
1817 	double a = pa->u.fltv;
1818 	double b = (double)pb->u.intv;
1819 	return mv_from_float(fmax(a, b));
1820 }
1821 
max_f_if(mv_t * pa,mv_t * pb)1822 static mv_t max_f_if(mv_t* pa, mv_t* pb) {
1823 	double a = (double)pa->u.intv;
1824 	double b = pb->u.fltv;
1825 	return mv_from_float(fmax(a, b));
1826 }
1827 
max_i_ii(mv_t * pa,mv_t * pb)1828 static mv_t max_i_ii(mv_t* pa, mv_t* pb) {
1829 	long long a = pa->u.intv;
1830 	long long b = pb->u.intv;
1831 	return mv_from_int(a > b ? a : b);
1832 }
1833 
max_b_bb(mv_t * pa,mv_t * pb)1834 static mv_t max_b_bb(mv_t* pa, mv_t* pb) {
1835 	int a = pa->u.boolv;
1836 	int b = pb->u.boolv;
1837 	return mv_from_bool(a > b ? a : b);
1838 }
1839 
max_s_ss(mv_t * pa,mv_t * pb)1840 static mv_t max_s_ss(mv_t* pa, mv_t* pb) {
1841 	char* a = pa->u.strv;
1842 	char* b = pb->u.strv;
1843 	int   c = strcmp(a, b);
1844 	if (c >= 0) {
1845 		mv_free(pb);
1846 		return *pa;
1847 	} else {
1848 		mv_free(pa);
1849 		return *pb;
1850 	}
1851 }
1852 
1853 // Sort rules (same for min, max, and comparator):
1854 // * NUMERICS < BOOL < STRINGS < ERROR < ABSENT
1855 // * error == error (singleton type)
1856 // * absent == absent (singleton type)
1857 // * string compares on strings
1858 // * numeric compares on numbers
1859 // * false < true
1860 // Exceptions for min & max:
1861 // * absent-null always loses
1862 // * empty-null always loses against numbers
1863 static mv_binary_func_t* max_dispositions[MT_DIM][MT_DIM] = {
1864 	//         ERROR   ABSENT EMPTY  STRING    INT       FLOAT     BOOL
1865 	/*ERROR*/  {_erro, _erro, _erro, _erro,    _erro,    _erro,    _erro},
1866 	/*ABSENT*/ {_erro, _absn, _2___, _2f__,    _2___,    _2___,    _2___},
1867 	/*EMPTY*/  {_erro, _1___, _void, _2f__,    _2___,    _2___,    _2___},
1868 	/*STRING*/ {_erro, _1f__, _1f__, max_s_ss, _1f__,    _1f__,    _1f__},
1869 	/*INT*/    {_erro, _1___, _1___, _2f__,    max_i_ii, max_f_if, _2___},
1870 	/*FLOAT*/  {_erro, _1___, _1___, _2f__,    max_f_fi, max_f_ff, _2___},
1871 	/*BOOL*/   {_erro, _1___, _1___, _2f__,    _1___,    _1___,    max_b_bb},
1872 	};
1873 
x_xx_max_func(mv_t * pval1,mv_t * pval2)1874 mv_t x_xx_max_func(mv_t* pval1, mv_t* pval2) {
1875 	return (max_dispositions[pval1->type][pval2->type])(pval1,pval2);
1876 }
1877 
variadic_max_func(mv_t * pvals,int nvals)1878 mv_t variadic_max_func(mv_t* pvals, int nvals) {
1879 	if (nvals == 0) {
1880 		return mv_empty();
1881 	} else {
1882 		mv_t rv = pvals[0];
1883 		for (int i = 1; i < nvals; i++) {
1884 			rv = x_xx_max_func(&rv, &pvals[i]);
1885 			// Disposition-matrix entries for max all free their non-return arguments
1886 		}
1887 		return rv;
1888 	}
1889 }
1890 
1891 // ----------------------------------------------------------------
int_i_b(mv_t * pa)1892 static mv_t int_i_b(mv_t* pa) { return mv_from_int(pa->u.boolv ? 1 : 0); }
int_i_f(mv_t * pa)1893 static mv_t int_i_f(mv_t* pa) { return mv_from_int((long long)round(pa->u.fltv)); }
int_i_i(mv_t * pa)1894 static mv_t int_i_i(mv_t* pa) { return mv_from_int(pa->u.intv); }
int_i_s(mv_t * pa)1895 static mv_t int_i_s(mv_t* pa) {
1896 	if (*pa->u.strv == '\0') {
1897 		mv_free(pa);
1898 		return mv_empty();
1899 	}
1900 	mv_t retval = mv_from_int(0LL);
1901 	if (!mlr_try_int_from_string(pa->u.strv, &retval.u.intv)) {
1902 		mv_free(pa);
1903 		return mv_error();
1904 	}
1905 	mv_free(pa);
1906 	return retval;
1907 }
1908 
1909 static mv_unary_func_t* int_dispositions[MT_DIM] = {
1910 	/*ERROR*/  _err1,
1911 	/*ABSENT*/ _absn1,
1912 	/*EMPTY*/  _emt1,
1913 	/*STRING*/ int_i_s,
1914 	/*INT*/    int_i_i,
1915 	/*FLOAT*/  int_i_f,
1916 	/*BOOL*/   int_i_b,
1917 };
1918 
i_x_int_func(mv_t * pval1)1919 mv_t i_x_int_func(mv_t* pval1) { return (int_dispositions[pval1->type])(pval1); }
1920 
1921 // ----------------------------------------------------------------
float_f_b(mv_t * pa)1922 static mv_t float_f_b(mv_t* pa) { return mv_from_float(pa->u.boolv ? 1.0 : 0.0); }
float_f_f(mv_t * pa)1923 static mv_t float_f_f(mv_t* pa) { return mv_from_float(pa->u.fltv); }
float_f_i(mv_t * pa)1924 static mv_t float_f_i(mv_t* pa) { return mv_from_float((double)pa->u.intv); }
float_f_s(mv_t * pa)1925 static mv_t float_f_s(mv_t* pa) {
1926 	if (*pa->u.strv == '\0') {
1927 		mv_free(pa);
1928 		return mv_empty();
1929 	}
1930 	mv_t retval = mv_from_float(0.0);
1931 	if (!mlr_try_float_from_string(pa->u.strv, &retval.u.fltv)) {
1932 		mv_free(pa);
1933 		return mv_error();
1934 	}
1935 	mv_free(pa);
1936 	return retval;
1937 }
1938 
1939 static mv_unary_func_t* float_dispositions[MT_DIM] = {
1940 	/*ERROR*/  _err1,
1941 	/*ABSENT*/ _absn1,
1942 	/*EMPTY*/  _emt1,
1943 	/*STRING*/ float_f_s,
1944 	/*INT*/    float_f_i,
1945 	/*FLOAT*/  float_f_f,
1946 	/*BOOL*/   float_f_b,
1947 };
1948 
f_x_float_func(mv_t * pval1)1949 mv_t f_x_float_func(mv_t* pval1) { return (float_dispositions[pval1->type])(pval1); }
1950 
1951 // ----------------------------------------------------------------
band_i_ii(mv_t * pa,mv_t * pb)1952 static mv_t band_i_ii(mv_t* pa, mv_t* pb) {
1953 	return mv_from_int(pa->u.intv & pb->u.intv);
1954 }
1955 
1956 static mv_binary_func_t* band_dispositions[MT_DIM][MT_DIM] = {
1957 	//         ERROR   ABSENT EMPTY  STRING INT        FLOAT  BOOL
1958 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,     _erro, _erro},
1959 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,     _erro, _erro},
1960 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,     _void, _erro},
1961 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,     _erro, _erro},
1962 	/*INT*/    {_erro, _1___, _void, _erro, band_i_ii, _erro, _erro},
1963 	/*FLOAT*/  {_erro, _erro, _void, _erro, _erro,     _erro, _erro},
1964 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,     _erro, _erro},
1965 	};
1966 
x_xx_band_func(mv_t * pval1,mv_t * pval2)1967 mv_t x_xx_band_func(mv_t* pval1, mv_t* pval2) { return (band_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1968 
1969 // ----------------------------------------------------------------
bor_i_ii(mv_t * pa,mv_t * pb)1970 static mv_t bor_i_ii(mv_t* pa, mv_t* pb) {
1971 	return mv_from_int(pa->u.intv | pb->u.intv);
1972 }
1973 
1974 static mv_binary_func_t* bor_dispositions[MT_DIM][MT_DIM] = {
1975 	//         ERROR   ABSENT EMPTY  STRING INT       FLOAT  BOOL
1976 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,    _erro, _erro},
1977 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,    _erro, _erro},
1978 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,    _void, _erro},
1979 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,    _erro, _erro},
1980 	/*INT*/    {_erro, _1___, _void, _erro, bor_i_ii, _erro, _erro},
1981 	/*FLOAT*/  {_erro, _erro, _void, _erro, _erro,    _erro, _erro},
1982 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,    _erro, _erro},
1983 	};
1984 
x_xx_bor_func(mv_t * pval1,mv_t * pval2)1985 mv_t x_xx_bor_func(mv_t* pval1, mv_t* pval2) { return (bor_dispositions[pval1->type][pval2->type])(pval1,pval2); }
1986 
1987 // ----------------------------------------------------------------
bxor_i_ii(mv_t * pa,mv_t * pb)1988 static mv_t bxor_i_ii(mv_t* pa, mv_t* pb) {
1989 	return mv_from_int(pa->u.intv ^ pb->u.intv);
1990 }
1991 
1992 static mv_binary_func_t* bxor_dispositions[MT_DIM][MT_DIM] = {
1993 	//         ERROR   ABSENT EMPTY  STRING INT        FLOAT  BOOL
1994 	/*ERROR*/  {_erro, _erro, _erro, _erro, _erro,     _erro, _erro},
1995 	/*ABSENT*/ {_erro, _absn, _absn, _erro, _2___,     _erro, _erro},
1996 	/*EMPTY*/  {_erro, _absn, _void, _erro, _void,     _void, _erro},
1997 	/*STRING*/ {_erro, _erro, _erro, _erro, _erro,     _erro, _erro},
1998 	/*INT*/    {_erro, _1___, _void, _erro, bxor_i_ii, _erro, _erro},
1999 	/*FLOAT*/  {_erro, _erro, _void, _erro, _erro,     _erro, _erro},
2000 	/*BOOL*/   {_erro, _erro, _erro, _erro, _erro,     _erro, _erro},
2001 	};
2002 
x_xx_bxor_func(mv_t * pval1,mv_t * pval2)2003 mv_t x_xx_bxor_func(mv_t* pval1, mv_t* pval2) { return (bxor_dispositions[pval1->type][pval2->type])(pval1,pval2); }
2004 
2005 // ----------------------------------------------------------------
boolean_b_b(mv_t * pa)2006 static mv_t boolean_b_b(mv_t* pa) { return mv_from_bool(pa->u.boolv); }
boolean_b_f(mv_t * pa)2007 static mv_t boolean_b_f(mv_t* pa) { return mv_from_bool((pa->u.fltv == 0.0) ? FALSE : TRUE); }
boolean_b_i(mv_t * pa)2008 static mv_t boolean_b_i(mv_t* pa) { return mv_from_bool((pa->u.intv == 0LL) ? FALSE : TRUE); }
boolean_b_s(mv_t * pa)2009 static mv_t boolean_b_s(mv_t* pa) { return mv_from_bool((streq(pa->u.strv, "true") || streq(pa->u.strv, "TRUE")) ? TRUE : FALSE);}
2010 
2011 static mv_unary_func_t* boolean_dispositions[MT_DIM] = {
2012 	/*ERROR*/  _err1,
2013 	/*ABSENT*/ _absn1,
2014 	/*EMPTY*/  _emt1,
2015 	/*STRING*/ boolean_b_s,
2016 	/*INT*/    boolean_b_i,
2017 	/*FLOAT*/  boolean_b_f,
2018 	/*BOOL*/   boolean_b_b,
2019 };
2020 
b_x_boolean_func(mv_t * pval1)2021 mv_t b_x_boolean_func(mv_t* pval1) { return (boolean_dispositions[pval1->type])(pval1); }
2022 
2023 // ----------------------------------------------------------------
string_s_b(mv_t * pa)2024 static mv_t string_s_b(mv_t* pa) { return mv_from_string_no_free(pa->u.boolv?"true":"false"); }
string_s_f(mv_t * pa)2025 static mv_t string_s_f(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_string_from_double(pa->u.fltv, MLR_GLOBALS.ofmt)); }
string_s_i(mv_t * pa)2026 static mv_t string_s_i(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_string_from_ll(pa->u.intv)); }
string_s_s(mv_t * pa)2027 static mv_t string_s_s(mv_t* pa) {
2028 	char free_flags = pa->free_flags;
2029 	pa->free_flags = NO_FREE;
2030 	return mv_from_string(pa->u.strv, free_flags);
2031 }
2032 
2033 static mv_unary_func_t* string_dispositions[MT_DIM] = {
2034 	/*ERROR*/  _err1,
2035 	/*ABSENT*/ _absn1,
2036 	/*EMPTY*/  _emt1,
2037 	/*STRING*/ string_s_s,
2038 	/*INT*/    string_s_i,
2039 	/*FLOAT*/  string_s_f,
2040 	/*BOOL*/   string_s_b,
2041 };
2042 
s_x_string_func(mv_t * pval1)2043 mv_t s_x_string_func(mv_t* pval1) { return (string_dispositions[pval1->type])(pval1); }
2044 
2045 // ----------------------------------------------------------------
s_sii_substr_func(mv_t * pval1,mv_t * pval2,mv_t * pval3)2046 mv_t s_sii_substr_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
2047 	int m = pval2->u.intv; // inclusive lower; -len..-1 alias to 0..len-1
2048 	int n = pval3->u.intv; // inclusive upper; -len..-1 alias to 0..len-1
2049 	int len = strlen(pval1->u.strv);
2050 	mv_t rv;
2051 
2052 	if (m < 0)
2053 		m = len + m;
2054 	if (n < 0)
2055 		n = len + n;
2056 
2057 	if (m < 0 || m >= len || n < 0 || n >= len || n < m) {
2058 		rv = mv_from_string("", 0);
2059 	} else {
2060 		int olen = n - m + 1;
2061 		char* p = mlr_malloc_or_die(olen + 1);
2062 		strncpy(p, &pval1->u.strv[m], olen);
2063 		p[olen] = 0;
2064 		rv = mv_from_string(p, FREE_ENTRY_VALUE);
2065 	}
2066 	mv_free(pval1);
2067 	mv_free(pval2);
2068 	mv_free(pval3);
2069 	return rv;
2070 }
2071 
2072 // ----------------------------------------------------------------
hexfmt_s_b(mv_t * pa)2073 static mv_t hexfmt_s_b(mv_t* pa) { return mv_from_string_no_free(pa->u.boolv?"0x1":"0x0"); }
hexfmt_s_f(mv_t * pa)2074 static mv_t hexfmt_s_f(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_hexfmt_from_ll((long long)pa->u.fltv)); }
hexfmt_s_i(mv_t * pa)2075 static mv_t hexfmt_s_i(mv_t* pa) { return mv_from_string_with_free(mlr_alloc_hexfmt_from_ll(pa->u.intv)); }
hexfmt_s_s(mv_t * pa)2076 static mv_t hexfmt_s_s(mv_t* pa) {
2077 	char free_flags = pa->free_flags;
2078 	pa->free_flags = NO_FREE;
2079 	return mv_from_string(pa->u.strv, free_flags);
2080 }
2081 
2082 static mv_unary_func_t* hexfmt_dispositions[MT_DIM] = {
2083 	/*ERROR*/  _err1,
2084 	/*ABSENT*/ _absn1,
2085 	/*EMPTY*/  _emt1,
2086 	/*STRING*/ hexfmt_s_s,
2087 	/*INT*/    hexfmt_s_i,
2088 	/*FLOAT*/  hexfmt_s_f,
2089 	/*BOOL*/   hexfmt_s_b,
2090 };
2091 
s_x_hexfmt_func(mv_t * pval1)2092 mv_t s_x_hexfmt_func(mv_t* pval1) { return (hexfmt_dispositions[pval1->type])(pval1); }
2093 
2094 // ----------------------------------------------------------------
fmtnum_s_bs(mv_t * pa,mv_t * pfmt)2095 static mv_t fmtnum_s_bs(mv_t* pa, mv_t* pfmt) { return mv_from_string_no_free(pa->u.boolv?"0x1":"0x0"); }
fmtnum_s_ds(mv_t * pa,mv_t * pfmt)2096 static mv_t fmtnum_s_ds(mv_t* pa, mv_t* pfmt) {
2097 	mv_t rv = mv_from_string_with_free(mlr_alloc_string_from_double(pa->u.fltv, pfmt->u.strv));
2098 	mv_free(pfmt);
2099 	return rv;
2100 }
fmtnum_s_is(mv_t * pa,mv_t * pfmt)2101 static mv_t fmtnum_s_is(mv_t* pa, mv_t* pfmt) {
2102 	mv_t rv = mv_from_string_with_free(mlr_alloc_string_from_ll_and_format(pa->u.intv, pfmt->u.strv));
2103 	mv_free(pfmt);
2104 	return rv;
2105 }
2106 static mv_binary_func_t* fmtnum_dispositions[MT_DIM] = {
2107 	/*ERROR*/  _erro,
2108 	/*ABSENT*/ _absn,
2109 	/*EMPTY*/  _void,
2110 	/*STRING*/ _erro,
2111 	/*INT*/    fmtnum_s_is,
2112 	/*FLOAT*/  fmtnum_s_ds,
2113 	/*BOOL*/   fmtnum_s_bs,
2114 };
2115 
s_xs_fmtnum_func(mv_t * pval1,mv_t * pval2)2116 mv_t s_xs_fmtnum_func(mv_t* pval1, mv_t* pval2) { return (fmtnum_dispositions[pval1->type])(pval1, pval2); }
2117 
2118 // ----------------------------------------------------------------
eq_b_ii(mv_t * pa,mv_t * pb)2119 static mv_t eq_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv == pb->u.intv); }
ne_b_ii(mv_t * pa,mv_t * pb)2120 static mv_t ne_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv != pb->u.intv); }
gt_b_ii(mv_t * pa,mv_t * pb)2121 static mv_t gt_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >  pb->u.intv); }
ge_b_ii(mv_t * pa,mv_t * pb)2122 static mv_t ge_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >= pb->u.intv); }
lt_b_ii(mv_t * pa,mv_t * pb)2123 static mv_t lt_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <  pb->u.intv); }
le_b_ii(mv_t * pa,mv_t * pb)2124 static mv_t le_b_ii(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <= pb->u.intv); }
2125 
eq_b_ff(mv_t * pa,mv_t * pb)2126 static mv_t eq_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv == pb->u.fltv); }
ne_b_ff(mv_t * pa,mv_t * pb)2127 static mv_t ne_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv != pb->u.fltv); }
gt_b_ff(mv_t * pa,mv_t * pb)2128 static mv_t gt_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >  pb->u.fltv); }
ge_b_ff(mv_t * pa,mv_t * pb)2129 static mv_t ge_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >= pb->u.fltv); }
lt_b_ff(mv_t * pa,mv_t * pb)2130 static mv_t lt_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <  pb->u.fltv); }
le_b_ff(mv_t * pa,mv_t * pb)2131 static mv_t le_b_ff(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <= pb->u.fltv); }
2132 
eq_b_fi(mv_t * pa,mv_t * pb)2133 static mv_t eq_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv == pb->u.intv); }
ne_b_fi(mv_t * pa,mv_t * pb)2134 static mv_t ne_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv != pb->u.intv); }
gt_b_fi(mv_t * pa,mv_t * pb)2135 static mv_t gt_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >  pb->u.intv); }
ge_b_fi(mv_t * pa,mv_t * pb)2136 static mv_t ge_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv >= pb->u.intv); }
lt_b_fi(mv_t * pa,mv_t * pb)2137 static mv_t lt_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <  pb->u.intv); }
le_b_fi(mv_t * pa,mv_t * pb)2138 static mv_t le_b_fi(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.fltv <= pb->u.intv); }
2139 
eq_b_if(mv_t * pa,mv_t * pb)2140 static mv_t eq_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv == pb->u.fltv); }
ne_b_if(mv_t * pa,mv_t * pb)2141 static mv_t ne_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv != pb->u.fltv); }
gt_b_if(mv_t * pa,mv_t * pb)2142 static mv_t gt_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >  pb->u.fltv); }
ge_b_if(mv_t * pa,mv_t * pb)2143 static mv_t ge_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv >= pb->u.fltv); }
lt_b_if(mv_t * pa,mv_t * pb)2144 static mv_t lt_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <  pb->u.fltv); }
le_b_if(mv_t * pa,mv_t * pb)2145 static mv_t le_b_if(mv_t* pa, mv_t* pb) { return mv_from_bool(pa->u.intv <= pb->u.fltv); }
2146 
eq_b_xs(mv_t * pa,mv_t * pb)2147 static mv_t eq_b_xs(mv_t* pa, mv_t* pb) {
2148 	char free_flags;
2149 	char* sa = mv_format_val(pa, &free_flags);
2150 	mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) == 0);
2151 	if (free_flags & FREE_ENTRY_VALUE)
2152 		free(sa);
2153 	mv_free(pa);
2154 	mv_free(pb);
2155 	return rv;
2156 }
ne_b_xs(mv_t * pa,mv_t * pb)2157 static mv_t ne_b_xs(mv_t* pa, mv_t* pb) {
2158 	char free_flags;
2159 	char* sa = mv_format_val(pa, &free_flags);
2160 	mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) != 0);
2161 	if (free_flags & FREE_ENTRY_VALUE)
2162 		free(sa);
2163 	mv_free(pa);
2164 	mv_free(pb);
2165 	return rv;
2166 }
gt_b_xs(mv_t * pa,mv_t * pb)2167 static mv_t gt_b_xs(mv_t* pa, mv_t* pb) {
2168 	char free_flags;
2169 	char* sa = mv_format_val(pa, &free_flags);
2170 	mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) > 0);
2171 	if (free_flags & FREE_ENTRY_VALUE)
2172 		free(sa);
2173 	mv_free(pa);
2174 	mv_free(pb);
2175 	return rv;
2176 }
ge_b_xs(mv_t * pa,mv_t * pb)2177 static mv_t ge_b_xs(mv_t* pa, mv_t* pb) {
2178 	char free_flags;
2179 	char* sa = mv_format_val(pa, &free_flags);
2180 	mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) >= 0);
2181 	if (free_flags & FREE_ENTRY_VALUE)
2182 		free(sa);
2183 	mv_free(pa);
2184 	mv_free(pb);
2185 	return rv;
2186 }
lt_b_xs(mv_t * pa,mv_t * pb)2187 static mv_t lt_b_xs(mv_t* pa, mv_t* pb) {
2188 	char free_flags;
2189 	char* sa = mv_format_val(pa, &free_flags);
2190 	mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) < 0);
2191 	if (free_flags & FREE_ENTRY_VALUE)
2192 		free(sa);
2193 	mv_free(pa);
2194 	mv_free(pb);
2195 	return rv;
2196 }
le_b_xs(mv_t * pa,mv_t * pb)2197 static mv_t le_b_xs(mv_t* pa, mv_t* pb) {
2198 	char free_flags;
2199 	char* sa = mv_format_val(pa, &free_flags);
2200 	mv_t rv = mv_from_bool(strcmp(sa, pb->u.strv) <= 0);
2201 	if (free_flags & FREE_ENTRY_VALUE)
2202 		free(sa);
2203 	mv_free(pa);
2204 	mv_free(pb);
2205 	return rv;
2206 }
2207 
eq_b_sx(mv_t * pa,mv_t * pb)2208 static mv_t eq_b_sx(mv_t* pa, mv_t* pb) {
2209 	char free_flags;
2210 	char* sb = mv_format_val(pb, &free_flags);
2211 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) == 0);
2212 	if (free_flags & FREE_ENTRY_VALUE)
2213 		free(sb);
2214 	mv_free(pa);
2215 	mv_free(pb);
2216 	return rv;
2217 }
ne_b_sx(mv_t * pa,mv_t * pb)2218 static mv_t ne_b_sx(mv_t* pa, mv_t* pb) {
2219 	char free_flags;
2220 	char* sb = mv_format_val(pb, &free_flags);
2221 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) != 0);
2222 	if (free_flags & FREE_ENTRY_VALUE)
2223 		free(sb);
2224 	mv_free(pa);
2225 	mv_free(pb);
2226 	return rv;
2227 }
gt_b_sx(mv_t * pa,mv_t * pb)2228 static mv_t gt_b_sx(mv_t* pa, mv_t* pb) {
2229 	char free_flags;
2230 	char* sb = mv_format_val(pb, &free_flags);
2231 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) > 0);
2232 	if (free_flags & FREE_ENTRY_VALUE)
2233 		free(sb);
2234 	mv_free(pa);
2235 	mv_free(pb);
2236 	return rv;
2237 }
ge_b_sx(mv_t * pa,mv_t * pb)2238 static mv_t ge_b_sx(mv_t* pa, mv_t* pb) {
2239 	char free_flags;
2240 	char* sb = mv_format_val(pb, &free_flags);
2241 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) >= 0);
2242 	if (free_flags & FREE_ENTRY_VALUE)
2243 		free(sb);
2244 	mv_free(pa);
2245 	mv_free(pb);
2246 	return rv;
2247 }
lt_b_sx(mv_t * pa,mv_t * pb)2248 static mv_t lt_b_sx(mv_t* pa, mv_t* pb) {
2249 	char free_flags;
2250 	char* sb = mv_format_val(pb, &free_flags);
2251 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) < 0);
2252 	if (free_flags & FREE_ENTRY_VALUE)
2253 		free(sb);
2254 	mv_free(pa);
2255 	mv_free(pb);
2256 	return rv;
2257 }
le_b_sx(mv_t * pa,mv_t * pb)2258 static mv_t le_b_sx(mv_t* pa, mv_t* pb) {
2259 	char free_flags;
2260 	char* sb = mv_format_val(pb, &free_flags);
2261 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, sb) <= 0);
2262 	if (free_flags & FREE_ENTRY_VALUE)
2263 		free(sb);
2264 	mv_free(pa);
2265 	mv_free(pb);
2266 	return rv;
2267 }
2268 
eq_b_ss(mv_t * pa,mv_t * pb)2269 static mv_t eq_b_ss(mv_t*pa, mv_t*pb) {
2270 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) == 0);
2271 	mv_free(pa);
2272 	mv_free(pb);
2273 	return rv;
2274 }
ne_b_ss(mv_t * pa,mv_t * pb)2275 static mv_t ne_b_ss(mv_t*pa, mv_t*pb) {
2276 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) != 0);
2277 	mv_free(pa);
2278 	mv_free(pb);
2279 	return rv;
2280 }
gt_b_ss(mv_t * pa,mv_t * pb)2281 static mv_t gt_b_ss(mv_t*pa, mv_t*pb) {
2282 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) >  0);
2283 	mv_free(pa);
2284 	mv_free(pb);
2285 	return rv;
2286 }
ge_b_ss(mv_t * pa,mv_t * pb)2287 static mv_t ge_b_ss(mv_t*pa, mv_t*pb) {
2288 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) >= 0);
2289 	mv_free(pa);
2290 	mv_free(pb);
2291 	return rv;
2292 }
lt_b_ss(mv_t * pa,mv_t * pb)2293 static mv_t lt_b_ss(mv_t*pa, mv_t*pb) {
2294 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) <  0);
2295 	mv_free(pa);
2296 	mv_free(pb);
2297 	return rv;
2298 }
le_b_ss(mv_t * pa,mv_t * pb)2299 static mv_t le_b_ss(mv_t*pa, mv_t*pb) {
2300 	mv_t rv = mv_from_bool(strcmp(pa->u.strv, pb->u.strv) <= 0);
2301 	mv_free(pa);
2302 	mv_free(pb);
2303 	return rv;
2304 }
2305 
2306 static mv_binary_func_t* eq_dispositions[MT_DIM][MT_DIM] = {
2307 	//         ERROR   ABSENT EMPTY    STRING   INT      FLOAT    BOOL
2308 	/*ERROR*/  {_erro, _erro, _erro,   _erro,   _erro,   _erro,   _erro},
2309 	/*ABSENT*/ {_erro, _absn, _absn,   _absn,   _absn,   _absn,   _absn},
2310 	/*EMPTY*/  {_erro, _absn, eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _erro},
2311 	/*STRING*/ {_erro, _absn, eq_b_ss, eq_b_ss, eq_b_sx, eq_b_sx, _erro},
2312 	/*INT*/    {_erro, _absn, eq_b_xs, eq_b_xs, eq_b_ii, eq_b_if, _erro},
2313 	/*FLOAT*/  {_erro, _absn, eq_b_xs, eq_b_xs, eq_b_fi, eq_b_ff, _erro},
2314 	/*BOOL*/   {_erro, _erro, _absn,   _erro,   _erro,   _erro,   _erro},
2315 	};
2316 
2317 static mv_binary_func_t* ne_dispositions[MT_DIM][MT_DIM] = {
2318 	//         ERROR   ABSENT EMPTY    STRING   INT      FLOAT    BOOL
2319 	/*ERROR*/  {_erro, _erro, _erro,   _erro,   _erro,   _erro,   _erro},
2320 	/*ABSENT*/ {_erro, _absn, _absn,   _absn,   _absn,   _absn,   _absn},
2321 	/*EMPTY*/  {_erro, _absn, ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _erro},
2322 	/*STRING*/ {_erro, _absn, ne_b_ss, ne_b_ss, ne_b_sx, ne_b_sx, _erro},
2323 	/*INT*/    {_erro, _absn, ne_b_xs, ne_b_xs, ne_b_ii, ne_b_if, _erro},
2324 	/*FLOAT*/  {_erro, _absn, ne_b_xs, ne_b_xs, ne_b_fi, ne_b_ff, _erro},
2325 	/*BOOL*/   {_erro, _erro, _absn,   _erro,   _erro,   _erro,   _erro},
2326 	};
2327 
2328 static mv_binary_func_t* gt_dispositions[MT_DIM][MT_DIM] = {
2329 	//         ERROR   ABSENT EMPTY    STRING   INT      FLOAT    BOOL
2330 	/*ERROR*/  {_erro, _erro, _erro,   _erro,   _erro,   _erro,   _erro},
2331 	/*ABSENT*/ {_erro, _absn, _absn,   _absn,   _absn,   _absn,   _absn},
2332 	/*EMPTY*/  {_erro, _absn, gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _erro},
2333 	/*STRING*/ {_erro, _absn, gt_b_ss, gt_b_ss, gt_b_sx, gt_b_sx, _erro},
2334 	/*INT*/    {_erro, _absn, gt_b_xs, gt_b_xs, gt_b_ii, gt_b_if, _erro},
2335 	/*FLOAT*/  {_erro, _absn, gt_b_xs, gt_b_xs, gt_b_fi, gt_b_ff, _erro},
2336 	/*BOOL*/   {_erro, _erro, _absn,   _erro,   _erro,   _erro,   _erro},
2337 	};
2338 
2339 static mv_binary_func_t* ge_dispositions[MT_DIM][MT_DIM] = {
2340 	//         ERROR   ABSENT EMPTY    STRING   INT      FLOAT    BOOL
2341 	/*ERROR*/  {_erro, _erro, _erro,   _erro,   _erro,   _erro,   _erro},
2342 	/*ABSENT*/ {_erro, _absn, _absn,   _absn,   _absn,   _absn,   _absn},
2343 	/*EMPTY*/  {_erro, _absn, ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _erro},
2344 	/*STRING*/ {_erro, _absn, ge_b_ss, ge_b_ss, ge_b_sx, ge_b_sx, _erro},
2345 	/*INT*/    {_erro, _absn, ge_b_xs, ge_b_xs, ge_b_ii, ge_b_if, _erro},
2346 	/*FLOAT*/  {_erro, _absn, ge_b_xs, ge_b_xs, ge_b_fi, ge_b_ff, _erro},
2347 	/*BOOL*/   {_erro, _erro, _absn,   _erro,   _erro,   _erro,   _erro},
2348 	};
2349 
2350 static mv_binary_func_t* lt_dispositions[MT_DIM][MT_DIM] = {
2351 	//         ERROR   ABSENT EMPTY    STRING   INT      FLOAT    BOOL
2352 	/*ERROR*/  {_erro, _erro, _erro,   _erro,   _erro,   _erro,   _erro},
2353 	/*ABSENT*/ {_erro, _absn, _absn,   _absn,   _absn,   _absn,   _absn},
2354 	/*EMPTY*/  {_erro, _absn, lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _erro},
2355 	/*STRING*/ {_erro, _absn, lt_b_ss, lt_b_ss, lt_b_sx, lt_b_sx, _erro},
2356 	/*INT*/    {_erro, _absn, lt_b_xs, lt_b_xs, lt_b_ii, lt_b_if, _erro},
2357 	/*FLOAT*/  {_erro, _absn, lt_b_xs, lt_b_xs, lt_b_fi, lt_b_ff, _erro},
2358 	/*BOOL*/   {_erro, _erro, _absn,   _erro,   _erro,   _erro,   _erro},
2359 	};
2360 
2361 static mv_binary_func_t* le_dispositions[MT_DIM][MT_DIM] = {
2362 	//         ERROR   ABSENT EMPTY    STRING   INT      FLOAT    BOOL
2363 	/*ERROR*/  {_erro, _erro, _erro,   _erro,   _erro,   _erro,   _erro},
2364 	/*ABSENT*/ {_erro, _absn, _absn,   _absn,   _absn,   _absn,   _absn},
2365 	/*EMPTY*/  {_erro, _absn, le_b_ss, le_b_ss, le_b_sx, le_b_sx, _erro},
2366 	/*STRING*/ {_erro, _absn, le_b_ss, le_b_ss, le_b_sx, le_b_sx, _erro},
2367 	/*INT*/    {_erro, _absn, le_b_xs, le_b_xs, le_b_ii, le_b_if, _erro},
2368 	/*FLOAT*/  {_erro, _absn, le_b_xs, le_b_xs, le_b_fi, le_b_ff, _erro},
2369 	/*BOOL*/   {_erro, _erro, _absn,   _erro,   _erro,   _erro,   _erro},
2370 	};
2371 
eq_op_func(mv_t * pval1,mv_t * pval2)2372 mv_t eq_op_func(mv_t* pval1, mv_t* pval2) { return (eq_dispositions[pval1->type][pval2->type])(pval1, pval2); }
ne_op_func(mv_t * pval1,mv_t * pval2)2373 mv_t ne_op_func(mv_t* pval1, mv_t* pval2) { return (ne_dispositions[pval1->type][pval2->type])(pval1, pval2); }
gt_op_func(mv_t * pval1,mv_t * pval2)2374 mv_t gt_op_func(mv_t* pval1, mv_t* pval2) { return (gt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
ge_op_func(mv_t * pval1,mv_t * pval2)2375 mv_t ge_op_func(mv_t* pval1, mv_t* pval2) { return (ge_dispositions[pval1->type][pval2->type])(pval1, pval2); }
lt_op_func(mv_t * pval1,mv_t * pval2)2376 mv_t lt_op_func(mv_t* pval1, mv_t* pval2) { return (lt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
le_op_func(mv_t * pval1,mv_t * pval2)2377 mv_t le_op_func(mv_t* pval1, mv_t* pval2) { return (le_dispositions[pval1->type][pval2->type])(pval1, pval2); }
2378 
2379 // ----------------------------------------------------------------
mv_equals_si(mv_t * pa,mv_t * pb)2380 int mv_equals_si(mv_t* pa, mv_t* pb) {
2381 	if (pa->type == MT_INT) {
2382 		return (pb->type == MT_INT) ? pa->u.intv == pb->u.intv : FALSE;
2383 	} else {
2384 		return (pb->type == MT_STRING) ? streq(pa->u.strv, pb->u.strv) : FALSE;
2385 	}
2386 }
2387 
2388 // ----------------------------------------------------------------
eq_i_ii(mv_t * pa,mv_t * pb)2389 static int eq_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv == pb->u.intv; }
ne_i_ii(mv_t * pa,mv_t * pb)2390 static int ne_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv != pb->u.intv; }
gt_i_ii(mv_t * pa,mv_t * pb)2391 static int gt_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv >  pb->u.intv; }
ge_i_ii(mv_t * pa,mv_t * pb)2392 static int ge_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv >= pb->u.intv; }
lt_i_ii(mv_t * pa,mv_t * pb)2393 static int lt_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv <  pb->u.intv; }
le_i_ii(mv_t * pa,mv_t * pb)2394 static int le_i_ii(mv_t* pa, mv_t* pb) { return  pa->u.intv <= pb->u.intv; }
2395 
eq_i_ff(mv_t * pa,mv_t * pb)2396 static int eq_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv == pb->u.fltv; }
ne_i_ff(mv_t * pa,mv_t * pb)2397 static int ne_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv != pb->u.fltv; }
gt_i_ff(mv_t * pa,mv_t * pb)2398 static int gt_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv >  pb->u.fltv; }
ge_i_ff(mv_t * pa,mv_t * pb)2399 static int ge_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv >= pb->u.fltv; }
lt_i_ff(mv_t * pa,mv_t * pb)2400 static int lt_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv <  pb->u.fltv; }
le_i_ff(mv_t * pa,mv_t * pb)2401 static int le_i_ff(mv_t* pa, mv_t* pb) { return  pa->u.fltv <= pb->u.fltv; }
2402 
eq_i_fi(mv_t * pa,mv_t * pb)2403 static int eq_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv == pb->u.intv; }
ne_i_fi(mv_t * pa,mv_t * pb)2404 static int ne_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv != pb->u.intv; }
gt_i_fi(mv_t * pa,mv_t * pb)2405 static int gt_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv >  pb->u.intv; }
ge_i_fi(mv_t * pa,mv_t * pb)2406 static int ge_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv >= pb->u.intv; }
lt_i_fi(mv_t * pa,mv_t * pb)2407 static int lt_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv <  pb->u.intv; }
le_i_fi(mv_t * pa,mv_t * pb)2408 static int le_i_fi(mv_t* pa, mv_t* pb) { return  pa->u.fltv <= pb->u.intv; }
2409 
eq_i_if(mv_t * pa,mv_t * pb)2410 static int eq_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv == pb->u.fltv; }
ne_i_if(mv_t * pa,mv_t * pb)2411 static int ne_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv != pb->u.fltv; }
gt_i_if(mv_t * pa,mv_t * pb)2412 static int gt_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv >  pb->u.fltv; }
ge_i_if(mv_t * pa,mv_t * pb)2413 static int ge_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv >= pb->u.fltv; }
lt_i_if(mv_t * pa,mv_t * pb)2414 static int lt_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv <  pb->u.fltv; }
le_i_if(mv_t * pa,mv_t * pb)2415 static int le_i_if(mv_t* pa, mv_t* pb) { return  pa->u.intv <= pb->u.fltv; }
2416 
2417 static mv_i_nn_comparator_func_t* ieq_dispositions[MT_DIM][MT_DIM] = {
2418 	//         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
2419 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2420 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2421 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2422 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2423 	/*INT*/    {NULL, NULL,  NULL, NULL,  eq_i_ii, eq_i_if, NULL},
2424 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  eq_i_fi, eq_i_ff, NULL},
2425 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2426 	};
2427 
2428 static mv_i_nn_comparator_func_t* ine_dispositions[MT_DIM][MT_DIM] = {
2429 	//         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
2430 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2431 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2432 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2433 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2434 	/*INT*/    {NULL, NULL,  NULL, NULL,  ne_i_ii, ne_i_if, NULL},
2435 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  ne_i_fi, ne_i_ff, NULL},
2436 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2437 	};
2438 
2439 static mv_i_nn_comparator_func_t* igt_dispositions[MT_DIM][MT_DIM] = {
2440 	//         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
2441 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2442 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2443 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2444 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2445 	/*INT*/    {NULL, NULL,  NULL, NULL,  gt_i_ii, gt_i_if, NULL},
2446 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  gt_i_fi, gt_i_ff, NULL},
2447 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2448 	};
2449 
2450 static mv_i_nn_comparator_func_t* ige_dispositions[MT_DIM][MT_DIM] = {
2451 	//         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
2452 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2453 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2454 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2455 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2456 	/*INT*/    {NULL, NULL,  NULL, NULL,  ge_i_ii, ge_i_if, NULL},
2457 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  ge_i_fi, ge_i_ff, NULL},
2458 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2459 	};
2460 
2461 static mv_i_nn_comparator_func_t* ilt_dispositions[MT_DIM][MT_DIM] = {
2462 	//         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
2463 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2464 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2465 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2466 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2467 	/*INT*/    {NULL, NULL,  NULL, NULL,  lt_i_ii, lt_i_if, NULL},
2468 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  lt_i_fi, lt_i_ff, NULL},
2469 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2470 	};
2471 
2472 static mv_i_nn_comparator_func_t* ile_dispositions[MT_DIM][MT_DIM] = {
2473 	//         ERROR  ABSENT EMPTY STRING INT      FLOAT    BOOL
2474 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2475 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2476 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2477 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2478 	/*INT*/    {NULL, NULL,  NULL, NULL,  le_i_ii, le_i_if, NULL},
2479 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  le_i_fi, le_i_ff, NULL},
2480 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,    NULL,    NULL},
2481 	};
2482 
mv_i_nn_eq(mv_t * pval1,mv_t * pval2)2483 int mv_i_nn_eq(mv_t* pval1, mv_t* pval2) { return (ieq_dispositions[pval1->type][pval2->type])(pval1, pval2); }
mv_i_nn_ne(mv_t * pval1,mv_t * pval2)2484 int mv_i_nn_ne(mv_t* pval1, mv_t* pval2) { return (ine_dispositions[pval1->type][pval2->type])(pval1, pval2); }
mv_i_nn_gt(mv_t * pval1,mv_t * pval2)2485 int mv_i_nn_gt(mv_t* pval1, mv_t* pval2) { return (igt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
mv_i_nn_ge(mv_t * pval1,mv_t * pval2)2486 int mv_i_nn_ge(mv_t* pval1, mv_t* pval2) { return (ige_dispositions[pval1->type][pval2->type])(pval1, pval2); }
mv_i_nn_lt(mv_t * pval1,mv_t * pval2)2487 int mv_i_nn_lt(mv_t* pval1, mv_t* pval2) { return (ilt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
mv_i_nn_le(mv_t * pval1,mv_t * pval2)2488 int mv_i_nn_le(mv_t* pval1, mv_t* pval2) { return (ile_dispositions[pval1->type][pval2->type])(pval1, pval2); }
2489 
2490 // ----------------------------------------------------------------
2491 // For unit-test keystroke-saving
2492 
mveq(mv_t * pval1,mv_t * pval2)2493 int mveq(mv_t* pval1, mv_t* pval2) {
2494 	mv_t cmp = eq_op_func(pval1, pval2);
2495 	MLR_INTERNAL_CODING_ERROR_UNLESS(cmp.type == MT_BOOLEAN);
2496 	return cmp.u.boolv;
2497 }
2498 
mvne(mv_t * pval1,mv_t * pval2)2499 int mvne(mv_t* pval1, mv_t* pval2) {
2500 	return !mveq(pval1, pval2);
2501 }
2502 
mveqcopy(mv_t * pval1,mv_t * pval2)2503 int mveqcopy(mv_t* pval1, mv_t* pval2) {
2504 	mv_t c1 = mv_copy(pval1);
2505 	mv_t c2 = mv_copy(pval2);
2506 	return mveq(&c1, &c2);
2507 }
2508 
mvnecopy(mv_t * pval1,mv_t * pval2)2509 int mvnecopy(mv_t* pval1, mv_t* pval2) {
2510 	mv_t c1 = mv_copy(pval1);
2511 	mv_t c2 = mv_copy(pval2);
2512 	return mvne(&c1, &c2);
2513 }
2514 
2515 // ----------------------------------------------------------------
2516 // arg2 evaluates to string via compound expression; regexes compiled on each call.
matches_no_precomp_func(mv_t * pval1,mv_t * pval2,string_array_t ** ppregex_captures)2517 mv_t matches_no_precomp_func(mv_t* pval1, mv_t* pval2, string_array_t** ppregex_captures) {
2518 	char* s1 = pval1->u.strv;
2519 	char* s2 = pval2->u.strv;
2520 
2521 	regex_t regex;
2522 	char* sstr   = s1;
2523 	char* sregex = s2;
2524 
2525 	regcomp_or_die(&regex, sregex, REG_NOSUB);
2526 
2527 	const size_t nmatchmax = 10; // Capture-groups \1 through \9 supported, along with entire-string match
2528 	regmatch_t matches[nmatchmax];
2529 	if (regmatch_or_die(&regex, sstr, nmatchmax, matches)) {
2530 		if (ppregex_captures != NULL && *ppregex_captures != NULL)
2531 			save_regex_captures(ppregex_captures, pval1->u.strv, matches, nmatchmax);
2532 		regfree(&regex);
2533 		mv_free(pval1);
2534 		mv_free(pval2);
2535 		return mv_from_true();
2536 	} else {
2537 		regfree(&regex);
2538 		mv_free(pval1);
2539 		mv_free(pval2);
2540 		return mv_from_false();
2541 	}
2542 }
2543 
does_not_match_no_precomp_func(mv_t * pval1,mv_t * pval2,string_array_t ** ppregex_captures)2544 mv_t does_not_match_no_precomp_func(mv_t* pval1, mv_t* pval2, string_array_t** ppregex_captures) {
2545 	mv_t rv = matches_no_precomp_func(pval1, pval2, ppregex_captures);
2546 	rv.u.boolv = !rv.u.boolv;
2547 	return rv;
2548 }
2549 
2550 // ----------------------------------------------------------------
2551 // arg2 is a string, compiled to regex only once at alloc time
matches_precomp_func(mv_t * pval1,regex_t * pregex,string_builder_t * psb,string_array_t ** ppregex_captures)2552 mv_t matches_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, string_array_t** ppregex_captures) {
2553 	const size_t nmatchmax = 10; // Capture-groups \1 through \9 supported, along with entire-string match
2554 	regmatch_t matches[nmatchmax];
2555 	if (regmatch_or_die(pregex, pval1->u.strv, nmatchmax, matches)) {
2556 		if (ppregex_captures != NULL)
2557 			save_regex_captures(ppregex_captures, pval1->u.strv, matches, nmatchmax);
2558 		mv_free(pval1);
2559 		return mv_from_true();
2560 	} else {
2561 		// See comments in mapper_put.c. Setting this array to length 0 (i.e. zero matches) signals to the
2562 		// lrec-evaluator's from-literal function that we *are* in a regex-match context but there are *no* matches to
2563 		// be interpolated.
2564 		if (ppregex_captures != NULL) {
2565 			if (*ppregex_captures != NULL)
2566 				string_array_realloc(*ppregex_captures, 0);
2567 			else
2568 				*ppregex_captures = string_array_alloc(0);
2569 		}
2570 		mv_free(pval1);
2571 		return mv_from_false();
2572 	}
2573 }
2574 
does_not_match_precomp_func(mv_t * pval1,regex_t * pregex,string_builder_t * psb,string_array_t ** ppregex_captures)2575 mv_t does_not_match_precomp_func(mv_t* pval1, regex_t* pregex, string_builder_t* psb, string_array_t** ppregex_captures) {
2576 	mv_t rv = matches_precomp_func(pval1, pregex, psb, ppregex_captures);
2577 	rv.u.boolv = !rv.u.boolv;
2578 	return rv;
2579 }
2580 
2581 // ----------------------------------------------------------------
mv_ff_cmp(const mv_t * pa,const mv_t * pb)2582 static int mv_ff_cmp(const mv_t* pa, const mv_t* pb) {
2583 	double d = pa->u.fltv - pb->u.fltv;
2584 	return (d < 0) ? -1 : (d > 0) ? 1 : 0;
2585 }
mv_fi_cmp(const mv_t * pa,const mv_t * pb)2586 static int mv_fi_cmp(const mv_t* pa, const mv_t* pb) {
2587 	double d = pa->u.fltv - pb->u.intv;
2588 	return (d < 0) ? -1 : (d > 0) ? 1 : 0;
2589 }
mv_if_cmp(const mv_t * pa,const mv_t * pb)2590 static int mv_if_cmp(const mv_t* pa, const mv_t* pb) {
2591 	double d = pa->u.intv - pb->u.fltv;
2592 	return (d < 0) ? -1 : (d > 0) ? 1 : 0;
2593 }
mv_ii_cmp(const mv_t * pa,const mv_t * pb)2594 static int mv_ii_cmp(const mv_t* pa, const mv_t* pb) {
2595 	long long d = pa->u.intv - pb->u.intv;
2596 	return (d < 0) ? -1 : (d > 0) ? 1 : 0;
2597 }
2598 // We assume mv_t's coming into percentile keeper are int or double -- in particular, non-null.
2599 static mv_i_xx_comparator_func_t* mv_nn_comparator_dispositions[MT_DIM][MT_DIM] = {
2600 	//         ERROR  ABSENT EMPTY STRING INT        FLOAT      BOOL
2601 	/*ERROR*/  {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
2602 	/*ABSENT*/ {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
2603 	/*EMPTY*/  {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
2604 	/*STRING*/ {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
2605 	/*INT*/    {NULL, NULL,  NULL, NULL,  mv_ii_cmp, mv_if_cmp, NULL},
2606 	/*FLOAT*/  {NULL, NULL,  NULL, NULL,  mv_fi_cmp, mv_ff_cmp, NULL},
2607 	/*BOOL*/   {NULL, NULL,  NULL, NULL,  NULL,      NULL,      NULL},
2608 	};
2609 
mv_nn_comparator(const void * pva,const void * pvb)2610 int mv_nn_comparator(const void* pva, const void* pvb) {
2611 	const mv_t* pa = pva;
2612 	const mv_t* pb = pvb;
2613 	return mv_nn_comparator_dispositions[pa->type][pb->type](pa, pb);
2614 }
2615 
2616 // ----------------------------------------------------------------
2617 // For general qsorting of mv_t's
2618 
mv_cmp_eq(const mv_t * pa,const mv_t * pb)2619 static int mv_cmp_eq(const mv_t* pa, const mv_t* pb) { return  0; }
mv_cmp_lt(const mv_t * pa,const mv_t * pb)2620 static int mv_cmp_lt(const mv_t* pa, const mv_t* pb) { return -1; }
mv_cmp_gt(const mv_t * pa,const mv_t * pb)2621 static int mv_cmp_gt(const mv_t* pa, const mv_t* pb) { return  1; }
2622 
mv_bb_comparator(const mv_t * pa,const mv_t * pb)2623 static int mv_bb_comparator(const mv_t* pa, const mv_t* pb) {
2624 	int d = pa->u.boolv - pb->u.boolv;
2625 	return (d < 0) ? -1 : (d > 0) ? 1 : 0;
2626 }
mv_ss_cmp(const mv_t * pa,const mv_t * pb)2627 static int mv_ss_cmp(const mv_t* pa, const mv_t* pb) {
2628 	return strcmp(pa->u.strv, pb->u.strv);
2629 }
2630 
2631 // Sort rules (same for min, max, and comparator):
2632 // * NUMERICS < BOOL < STRINGS < ERROR < ABSENT
2633 // * error == error (singleton type)
2634 // * absent == absent (singleton type)
2635 // * string compares on strings
2636 // * numeric compares on numbers
2637 // * false < true
2638 static mv_i_xx_comparator_func_t* mv_xx_comparator_dispositions[MT_DIM][MT_DIM] = {
2639 	//         ERROR       ABSENT     EMPTY      STRING     INT        FLOAT      BOOL
2640 	/*ERROR*/  {mv_cmp_eq, mv_cmp_lt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
2641 	/*ABSENT*/ {mv_cmp_gt, mv_cmp_eq, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
2642 	/*EMPTY*/  {mv_cmp_lt, mv_cmp_lt, mv_cmp_eq, mv_ss_cmp, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
2643 	/*STRING*/ {mv_cmp_lt, mv_cmp_lt, mv_ss_cmp, mv_ss_cmp, mv_cmp_gt, mv_cmp_gt, mv_cmp_gt},
2644 	/*INT*/    {mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_ii_cmp, mv_if_cmp, mv_cmp_lt},
2645 	/*FLOAT*/  {mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_fi_cmp, mv_ff_cmp, mv_cmp_lt},
2646 	/*BOOL*/   {mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_lt, mv_cmp_gt, mv_cmp_gt, mv_bb_comparator},
2647 	};
2648 
mv_xx_comparator(const void * pva,const void * pvb)2649 int mv_xx_comparator(const void* pva, const void* pvb) {
2650 	const mv_t* pa = pva;
2651 	const mv_t* pb = pvb;
2652 	return mv_xx_comparator_dispositions[pa->type][pb->type](pa, pb);
2653 }
2654 
2655 // ----------------------------------------------------------------
mlr_bsearch_mv_n_for_insert(mv_t * array,int size,mv_t * pvalue)2656 int mlr_bsearch_mv_n_for_insert(mv_t* array, int size, mv_t* pvalue) {
2657 	int lo = 0;
2658 	int hi = size-1;
2659 	int mid = (hi+lo)/2;
2660 	int newmid;
2661 
2662 	if (size == 0)
2663 		return 0;
2664 	if (mv_i_nn_gt(pvalue, &array[0]))
2665 		return 0;
2666 	if (mv_i_nn_lt(pvalue, &array[hi]))
2667 		return size;
2668 
2669 	while (lo < hi) {
2670 		mv_t* pa = &array[mid];
2671 		if (mv_i_nn_eq(pvalue, pa)) {
2672 			return mid;
2673 		}
2674 		else if (mv_i_nn_gt(pvalue, pa)) {
2675 			hi = mid;
2676 			newmid = (hi+lo)/2;
2677 		}
2678 		else {
2679 			lo = mid;
2680 			newmid = (hi+lo)/2;
2681 		}
2682 		if (mid == newmid) {
2683 			if (mv_i_nn_ge(pvalue, &array[lo]))
2684 				return lo;
2685 			else if (mv_i_nn_ge(pvalue, &array[hi]))
2686 				return hi;
2687 			else
2688 				return hi+1;
2689 		}
2690 		mid = newmid;
2691 	}
2692 
2693 	return lo;
2694 }
2695