mirror of
https://github.com/johnkerl/miller.git
synced 2026-07-24 16:38:57 +00:00
920 lines
32 KiB
C
920 lines
32 KiB
C
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <math.h>
|
|
#include <time.h>
|
|
#include <regex.h>
|
|
#include "lib/mlr_globals.h"
|
|
#include "lib/mlrutil.h"
|
|
#include "mapping/mlr_val.h"
|
|
|
|
// ================================================================
|
|
// NOTES:
|
|
//
|
|
// * This is used by mlr filter and mlr put.
|
|
//
|
|
// * Unlike most files in Miller which are read top-down (with sufficient
|
|
// static prototypes at the top of the file to keep the compiler happy),
|
|
// please read this one from the bottom up.
|
|
//
|
|
// * Comparison to lrec_evaluators.c: this file is functions from mlr_val(s) to
|
|
// mlr_val; in lrec_evaluators.c we have the higher-level notion of
|
|
// evaluating lrec objects, using mlr_val.c to do so.
|
|
//
|
|
// * There are two kinds of functions here: those with _x_ in their names
|
|
// which accept various types of mlr_val, with disposition-matrices to select
|
|
// functions of the appropriate type, and those with _i_/_f_/_b_/_s_ (int,
|
|
// float, boolean, string) which only take specific types of mlr_val. In
|
|
// either case it's the job of lrec_evaluators.c to invoke functions here
|
|
// with mlr_vals of the correct type(s).
|
|
// ================================================================
|
|
|
|
// For some Linux distros, in spite of including time.h:
|
|
char *strptime(const char *s, const char *format, struct tm *tm);
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t MV_NULL = {
|
|
.type = MT_NULL,
|
|
.u.intv = 0
|
|
};
|
|
mv_t MV_ERROR = {
|
|
.type = MT_ERROR,
|
|
.u.intv = 0
|
|
};
|
|
|
|
// ----------------------------------------------------------------
|
|
char* mt_describe_type(int type) {
|
|
switch (type) {
|
|
case MT_NULL: return "T_NULL"; break;
|
|
case MT_ERROR: return "T_ERROR"; break;
|
|
case MT_BOOL: return "T_BOOL"; break;
|
|
case MT_FLOAT: return "T_FLOAT"; break;
|
|
case MT_INT: return "T_INT"; break;
|
|
case MT_STRING: return "T_STRING"; break;
|
|
default: return "???"; break;
|
|
}
|
|
}
|
|
|
|
// For debug only; the caller should free the return value
|
|
char* mt_format_val(mv_t* pval) {
|
|
switch(pval->type) {
|
|
case MT_NULL:
|
|
return mlr_strdup_or_die("");
|
|
break;
|
|
case MT_ERROR:
|
|
return mlr_strdup_or_die("(error)");
|
|
break;
|
|
case MT_BOOL:
|
|
return mlr_strdup_or_die(pval->u.boolv ? "true" : "false");
|
|
break;
|
|
case MT_FLOAT:
|
|
return mlr_alloc_string_from_double(pval->u.fltv, MLR_GLOBALS.ofmt);
|
|
break;
|
|
case MT_INT:
|
|
return mlr_alloc_string_from_ll(pval->u.intv);
|
|
break;
|
|
case MT_STRING:
|
|
return mlr_strdup_or_die(pval->u.strv);
|
|
break;
|
|
default:
|
|
return mlr_strdup_or_die("???");
|
|
break;
|
|
}
|
|
}
|
|
|
|
char* mt_describe_val(mv_t val) {
|
|
char* stype = mt_describe_type(val.type);
|
|
char* strv = mt_format_val(&val);
|
|
char* desc = mlr_malloc_or_die(strlen(stype) + strlen(strv) + 4);
|
|
strcpy(desc, "[");
|
|
strcat(desc, stype);
|
|
strcat(desc, "] ");
|
|
strcat(desc, strv);
|
|
return desc;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
void mt_get_boolean_strict(mv_t* pval) {
|
|
if (pval->type != MT_BOOL) {
|
|
char* desc = mt_describe_type(pval->type);
|
|
fprintf(stderr, "Expression does not evaluate to boolean: got %s.\n", desc);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
void mt_get_double_strict(mv_t* pval) {
|
|
if (pval->type == MT_NULL)
|
|
return;
|
|
if (pval->type == MT_ERROR)
|
|
return;
|
|
if (pval->type == MT_FLOAT)
|
|
return;
|
|
if (pval->type == MT_STRING) {
|
|
double fltv;
|
|
if (!mlr_try_double_from_string(pval->u.strv, &fltv)) {
|
|
pval->type = MT_ERROR;
|
|
pval->u.intv = 0;
|
|
} else {
|
|
pval->type = MT_FLOAT;
|
|
pval->u.fltv = fltv;
|
|
}
|
|
} else if (pval->type == MT_INT) {
|
|
pval ->type = MT_FLOAT;
|
|
pval->u.fltv = (double)pval->u.intv;
|
|
} else if (pval->type == MT_BOOL) {
|
|
pval->type = MT_ERROR;
|
|
pval->u.intv = 0;
|
|
} else {
|
|
fprintf(stderr, "%s: internal coding error detected at file %s, line %d.\n",
|
|
MLR_GLOBALS.argv0, __FILE__, __LINE__);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
void mt_get_double_nullable(mv_t* pval) {
|
|
if (pval->type == MT_NULL)
|
|
return;
|
|
if (pval->type == MT_ERROR)
|
|
return;
|
|
if (pval->type == MT_FLOAT)
|
|
return;
|
|
if (pval->type == MT_STRING) {
|
|
double fltv;
|
|
if (*pval->u.strv == '\0') {
|
|
pval->type = MT_NULL;
|
|
pval->u.intv = 0;
|
|
} else if (!mlr_try_double_from_string(pval->u.strv, &fltv)) {
|
|
pval->type = MT_ERROR;
|
|
pval->u.intv = 0;
|
|
} else {
|
|
pval->type = MT_FLOAT;
|
|
pval->u.fltv = fltv;
|
|
}
|
|
} else if (pval->type == MT_INT) {
|
|
pval ->type = MT_FLOAT;
|
|
pval->u.fltv = (double)pval->u.intv;
|
|
} else if (pval->type == MT_BOOL) {
|
|
pval->type = MT_ERROR;
|
|
pval->u.intv = 0;
|
|
} else {
|
|
fprintf(stderr, "%s: internal coding error detected at file %s, line %d.\n",
|
|
MLR_GLOBALS.argv0, __FILE__, __LINE__);
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t s_ss_dot_func(mv_t* pval1, mv_t* pval2) {
|
|
int len1 = strlen(pval1->u.strv);
|
|
int len2 = strlen(pval1->u.strv);
|
|
int len3 = len1 + len2 + 1; // for the null-terminator byte
|
|
char* string3 = mlr_malloc_or_die(len3);
|
|
strcpy(&string3[0], pval1->u.strv);
|
|
strcpy(&string3[len1], pval2->u.strv);
|
|
|
|
free(pval1->u.strv);
|
|
free(pval2->u.strv);
|
|
pval1->u.strv = NULL;
|
|
pval2->u.strv = NULL;
|
|
|
|
mv_t rv = {.type = MT_STRING, .u.strv = string3};
|
|
return rv;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t sub_no_precomp_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) {
|
|
regex_t regex;
|
|
mv_t rv = sub_precomp_func(pval1, regcomp_or_die(®ex, pval2->u.strv, 0), pval3);
|
|
regfree(®ex);
|
|
return rv;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// Example:
|
|
// * pval1->u.strv = "hello"
|
|
// * regex = "l+"
|
|
// * pval3->u.strv = "yyy"
|
|
//
|
|
// * len1 = 2 = length of "he"
|
|
// * olen2 = 2 = length of "ll"
|
|
// * nlen2 = 3 = length of "yyy"
|
|
// * len3 = 1 = length of "o"
|
|
// * len4 = 6 = 2+3+1
|
|
|
|
mv_t sub_precomp_func(mv_t* pval1, regex_t* pregex, mv_t* pval3) {
|
|
const size_t nmatch = 10; // xxx temp: parameterize after adding capture-group support
|
|
regmatch_t pmatch[nmatch];
|
|
int eflags = 0;
|
|
|
|
int matched = regmatch_or_die(pregex, pval1->u.strv, nmatch, pmatch, eflags);
|
|
if (!matched) {
|
|
return *pval1;
|
|
} else {
|
|
int so = pmatch[0].rm_so;
|
|
int eo = pmatch[0].rm_eo;
|
|
|
|
int len1 = so;
|
|
int olen2 = eo - so;
|
|
int nlen2 = strlen(pval3->u.strv);
|
|
int len3 = strlen(&pval1->u.strv[len1 + olen2]);
|
|
int len4 = len1 + nlen2 + len3;
|
|
|
|
char* string4 = mlr_malloc_or_die(len4 + 1);
|
|
strncpy(&string4[0], pval1->u.strv, len1);
|
|
strncpy(&string4[len1], pval3->u.strv, nlen2);
|
|
strncpy(&string4[len1+nlen2], &pval1->u.strv[len1+olen2], len3);
|
|
string4[len4] = 0;
|
|
|
|
free(pval1->u.strv);
|
|
free(pval3->u.strv);
|
|
pval1->u.strv = NULL;
|
|
pval3->u.strv = NULL;
|
|
|
|
mv_t rv = {.type = MT_STRING, .u.strv = string4};
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t s_s_tolower_func(mv_t* pval1) {
|
|
char* string = mlr_strdup_or_die(pval1->u.strv);
|
|
for (char* c = string; *c; c++)
|
|
*c = tolower((unsigned char)*c);
|
|
free(pval1->u.strv);
|
|
pval1->u.strv = NULL;
|
|
|
|
mv_t rv = {.type = MT_STRING, .u.strv = string};
|
|
return rv;
|
|
}
|
|
|
|
mv_t s_s_toupper_func(mv_t* pval1) {
|
|
char* string = mlr_strdup_or_die(pval1->u.strv);
|
|
for (char* c = string; *c; c++)
|
|
*c = toupper((unsigned char)*c);
|
|
free(pval1->u.strv);
|
|
pval1->u.strv = NULL;
|
|
|
|
mv_t rv = {.type = MT_STRING, .u.strv = string};
|
|
return rv;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t s_f_sec2gmt_func(mv_t* pval1) {
|
|
ERROR_OUT(*pval1);
|
|
mt_get_double_nullable(pval1);
|
|
NULL_OUT(*pval1);
|
|
if (pval1->type != MT_FLOAT)
|
|
return MV_ERROR;
|
|
time_t clock = (time_t) pval1->u.fltv;
|
|
struct tm tm;
|
|
struct tm *ptm = gmtime_r(&clock, &tm);
|
|
// xxx use retval which is size_t
|
|
// xxx error-check all of this ...
|
|
char* string = mlr_malloc_or_die(32);
|
|
(void)strftime(string, 32, "%Y-%m-%dT%H:%M:%SZ", ptm);
|
|
|
|
mv_t rv = {.type = MT_STRING, .u.strv = string};
|
|
return rv;
|
|
}
|
|
|
|
mv_t i_s_gmt2sec_func(mv_t* pval1) {
|
|
struct tm tm;
|
|
if (*pval1->u.strv == '\0') {
|
|
return MV_NULL;
|
|
} else {
|
|
strptime(pval1->u.strv, "%Y-%m-%dT%H:%M:%SZ", &tm);
|
|
time_t t = mlr_timegm(&tm);
|
|
|
|
mv_t rv = {.type = MT_INT, .u.intv = (long long)t};
|
|
return rv;
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static void split_ull_to_hms(long long u, long long* ph, long long* pm, long long* ps) {
|
|
long long h = 0LL, m = 0LL, s = 0LL;
|
|
long long sign = 1LL;
|
|
if (u < 0LL) {
|
|
u = -u;
|
|
sign = -1LL;
|
|
}
|
|
s = u % 60LL;
|
|
u = u / 60LL;
|
|
if (u == 0LL) {
|
|
s = s * sign;
|
|
} else {
|
|
m = u % 60LL;
|
|
u = u / 60LL;
|
|
if (u == 0LL) {
|
|
m = m * sign;
|
|
} else {
|
|
h = u * sign;
|
|
}
|
|
}
|
|
*ph = h;
|
|
*pm = m;
|
|
*ps = s;
|
|
}
|
|
|
|
static void split_ull_to_dhms(long long u, long long* pd, long long* ph, long long* pm, long long* ps) {
|
|
long long d = 0LL, h = 0LL, m = 0LL, s = 0LL;
|
|
long long sign = 1LL;
|
|
if (u < 0LL) {
|
|
u = -u;
|
|
sign = -1LL;
|
|
}
|
|
s = u % 60LL;
|
|
u = u / 60LL;
|
|
if (u == 0LL) {
|
|
s = s * sign;
|
|
} else {
|
|
m = u % 60LL;
|
|
u = u / 60LL;
|
|
if (u == 0LL) {
|
|
m = m * sign;
|
|
} else {
|
|
h = u % 24LL;
|
|
u = u / 24LL;
|
|
if (u == 0LL) {
|
|
h = h * sign;
|
|
} else {
|
|
d = u * sign;
|
|
}
|
|
}
|
|
}
|
|
*pd = d;
|
|
*ph = h;
|
|
*pm = m;
|
|
*ps = s;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t s_i_sec2hms_func(mv_t* pval1) {
|
|
long long u = pval1->u.intv;
|
|
long long h, m, s;
|
|
char* fmt = "%02lld:%02lld:%02lld";
|
|
if (u < 0) {
|
|
u = -u;
|
|
fmt = "-%02lld:%02lld:%02lld";
|
|
}
|
|
split_ull_to_hms(u, &h, &m, &s);
|
|
int n = snprintf(NULL, 0, fmt, h, m, s);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, h, m, s);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
}
|
|
|
|
mv_t s_f_fsec2hms_func(mv_t* pval1) {
|
|
double v = fabs(pval1->u.fltv);
|
|
long long h, m, s;
|
|
char* fmt = "%lld:%02lld:%09.6lf";
|
|
long long u = (long long)trunc(v);
|
|
double f = v - u;
|
|
if (pval1->u.fltv < 0.0) {
|
|
fmt = "-%02lld:%02lld:%09.6lf";
|
|
}
|
|
split_ull_to_hms(u, &h, &m, &s);
|
|
int n = snprintf(NULL, 0, fmt, h, m, s+f);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, h, m, s+f);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
}
|
|
|
|
mv_t s_i_sec2dhms_func(mv_t* pval1) {
|
|
long long u = pval1->u.intv;
|
|
long long d, h, m, s;
|
|
split_ull_to_dhms(u, &d, &h, &m, &s);
|
|
if (d != 0.0) {
|
|
char* fmt = "%lldd%02lldh%02lldm%02llds";
|
|
int n = snprintf(NULL, 0, fmt, d, h, m, s);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, d, h, m, s);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
} else if (h != 0.0) {
|
|
char* fmt = "%lldh%02lldm%02llds";
|
|
int n = snprintf(NULL, 0, fmt, h, m, s);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, h, m, s);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
} else if (m != 0.0) {
|
|
char* fmt = "%lldm%02llds";
|
|
int n = snprintf(NULL, 0, fmt, m, s);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, m, s);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
} else {
|
|
char* fmt = "%llds";
|
|
int n = snprintf(NULL, 0, fmt, s);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, s);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
}
|
|
}
|
|
|
|
mv_t s_f_fsec2dhms_func(mv_t* pval1) {
|
|
double v = fabs(pval1->u.fltv);
|
|
long long sign = pval1->u.fltv < 0.0 ? -1LL : 1LL;
|
|
long long d, h, m, s;
|
|
long long u = (long long)trunc(v);
|
|
double f = v - u;
|
|
split_ull_to_dhms(u, &d, &h, &m, &s);
|
|
if (d != 0.0) {
|
|
d = sign * d;
|
|
char* fmt = "%lldd%02lldh%02lldm%09.6lfs";
|
|
int n = snprintf(NULL, 0, fmt, d, h, m, s+f);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, d, h, m, s+f);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
} else if (h != 0.0) {
|
|
h = sign * h;
|
|
char* fmt = "%lldh%02lldm%09.6lfs";
|
|
int n = snprintf(NULL, 0, fmt, h, m, s+f);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, h, m, s+f);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
} else if (m != 0.0) {
|
|
m = sign * m;
|
|
char* fmt = "%lldm%09.6lfs";
|
|
int n = snprintf(NULL, 0, fmt, m, s+f);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, m, s+f);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
} else {
|
|
s = sign * s;
|
|
f = sign * f;
|
|
char* fmt = "%.6lfs";
|
|
int n = snprintf(NULL, 0, fmt, s+f);
|
|
char* string = mlr_malloc_or_die(n+1);
|
|
sprintf(string, fmt, s+f);
|
|
return (mv_t) {.type = MT_STRING, .u.strv = string};
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t i_s_hms2sec_func(mv_t* pval1) {
|
|
long long h = 0LL, m = 0LL, s = 0LL;
|
|
long long sec = 0LL;
|
|
char* p = pval1->u.strv;
|
|
long long sign = 1LL;
|
|
if (*p == '-') {
|
|
p++;
|
|
sign = -1LL;
|
|
}
|
|
if (sscanf(p, "%lld:%lld:%lld", &h, &m, &s) == 3) {
|
|
if (h >= 0LL)
|
|
sec = 3600LL*h + 60LL*m + s;
|
|
else
|
|
sec = -(-3600LL*h + 60LL*m + s);
|
|
} else if (sscanf(p, "%lld:%lld", &m, &s) == 2) {
|
|
if (m >= 0LL)
|
|
sec = 60LL*m + s;
|
|
else
|
|
sec = -(-60LL*m + s);
|
|
} else if (sscanf(p, "%lld", &s) == 1) {
|
|
sec = s;
|
|
} else {
|
|
return MV_ERROR;
|
|
}
|
|
return (mv_t) {.type = MT_INT, .u.intv = sec * sign};
|
|
}
|
|
|
|
mv_t f_s_hms2fsec_func(mv_t* pval1) {
|
|
long long h = 0LL, m = 0LL;
|
|
double s = 0.0;
|
|
double sec = 0.0;
|
|
char* p = pval1->u.strv;
|
|
long long sign = 1LL;
|
|
if (*p == '-') {
|
|
p++;
|
|
sign = -1LL;
|
|
}
|
|
if (sscanf(p, "%lld:%lld:%lf", &h, &m, &s) == 3) {
|
|
sec = 3600*h + 60*m + s;
|
|
} else if (sscanf(p, "%lld:%lf", &m, &s) == 2) {
|
|
sec = 60*m + s;
|
|
} else if (sscanf(p, "%lf", &s) == 2) {
|
|
sec = s;
|
|
} else {
|
|
return MV_ERROR;
|
|
}
|
|
return (mv_t) {.type = MT_FLOAT, .u.fltv = sec * sign};
|
|
}
|
|
|
|
mv_t i_s_dhms2sec_func(mv_t* pval1) {
|
|
long long d = 0LL, h = 0LL, m = 0LL, s = 0LL;
|
|
long long sec = 0LL;
|
|
char* p = pval1->u.strv;
|
|
long long sign = 1LL;
|
|
if (*p == '-') {
|
|
p++;
|
|
sign = -1LL;
|
|
}
|
|
if (sscanf(p, "%lldd%lldh%lldm%llds", &d, &h, &m, &s) == 4) {
|
|
sec = 86400*d + 3600*h + 60*m + s;
|
|
} else if (sscanf(p, "%lldh%lldm%llds", &h, &m, &s) == 3) {
|
|
sec = 3600*h + 60*m + s;
|
|
} else if (sscanf(p, "%lldm%llds", &m, &s) == 2) {
|
|
sec = 60*m + s;
|
|
} else if (sscanf(p, "%llds", &s) == 1) {
|
|
sec = s;
|
|
} else {
|
|
return MV_ERROR;
|
|
}
|
|
return (mv_t) {.type = MT_INT, .u.intv = sec * sign};
|
|
}
|
|
|
|
mv_t f_s_dhms2fsec_func(mv_t* pval1) {
|
|
long long d = 0LL, h = 0LL, m = 0LL;
|
|
double s = 0.0;
|
|
double sec = 0.0;
|
|
char* p = pval1->u.strv;
|
|
long long sign = 1LL;
|
|
if (*p == '-') {
|
|
p++;
|
|
sign = -1LL;
|
|
}
|
|
if (sscanf(p, "%lldd%lldh%lldm%lfs", &d, &h, &m, &s) == 4) {
|
|
sec = 86400*d + 3600*h + 60*m + s;
|
|
} else if (sscanf(p, "%lldh%lldm%lfs", &h, &m, &s) == 3) {
|
|
sec = 3600*h + 60*m + s;
|
|
} else if (sscanf(p, "%lldm%lfs", &m, &s) == 2) {
|
|
sec = 60*m + s;
|
|
} else if (sscanf(p, "%lfs", &s) == 1) {
|
|
sec = s;
|
|
} else {
|
|
return MV_ERROR;
|
|
}
|
|
return (mv_t) {.type = MT_FLOAT, .u.fltv = sec * sign};
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
mv_t i_s_strlen_func(mv_t* pval1) {
|
|
mv_t rv = {.type = MT_INT, .u.intv = strlen(pval1->u.strv)};
|
|
return rv;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t int_i_n(mv_t* pa) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t int_i_e(mv_t* pa) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
static mv_t int_i_b(mv_t* pa) { return (mv_t) {.type = MT_INT, .u.intv = pa->u.boolv ? 1 : 0}; }
|
|
static mv_t int_i_f(mv_t* pa) { return (mv_t) {.type = MT_INT, .u.intv = (long long)round(pa->u.fltv)}; }
|
|
static mv_t int_i_i(mv_t* pa) { return (mv_t) {.type = MT_INT, .u.intv = pa->u.intv}; }
|
|
static mv_t int_i_s(mv_t* pa) {
|
|
mv_t retval = (mv_t) {.type = MT_INT };
|
|
if (*pa->u.strv == '\0')
|
|
return MV_NULL;
|
|
if (!mlr_try_int_from_string(pa->u.strv, &retval.u.intv))
|
|
retval.type = MT_ERROR;
|
|
return retval;
|
|
}
|
|
|
|
static mv_unary_func_t* int_dispositions[MT_MAX] = {
|
|
/*NULL*/ int_i_n,
|
|
/*ERROR*/ int_i_e,
|
|
/*BOOL*/ int_i_b,
|
|
/*FLOAT*/ int_i_f,
|
|
/*INT*/ int_i_i,
|
|
/*STRING*/ int_i_s,
|
|
};
|
|
|
|
mv_t i_x_int_func(mv_t* pval1) { return (int_dispositions[pval1->type])(pval1); }
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t float_f_n(mv_t* pa) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t float_f_e(mv_t* pa) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
static mv_t float_f_b(mv_t* pa) { return (mv_t) {.type = MT_FLOAT, .u.fltv = pa->u.boolv ? 1.0 : 0.0}; }
|
|
static mv_t float_f_f(mv_t* pa) { return (mv_t) {.type = MT_FLOAT, .u.fltv = pa->u.fltv}; }
|
|
static mv_t float_f_i(mv_t* pa) { return (mv_t) {.type = MT_FLOAT, .u.fltv = pa->u.intv}; }
|
|
static mv_t float_f_s(mv_t* pa) {
|
|
mv_t retval = (mv_t) {.type = MT_FLOAT };
|
|
if (*pa->u.strv == '\0')
|
|
return MV_NULL;
|
|
if (!mlr_try_double_from_string(pa->u.strv, &retval.u.fltv))
|
|
retval.type = MT_ERROR;
|
|
return retval;
|
|
}
|
|
|
|
static mv_unary_func_t* float_dispositions[MT_MAX] = {
|
|
/*NULL*/ float_f_n,
|
|
/*ERROR*/ float_f_e,
|
|
/*BOOL*/ float_f_b,
|
|
/*FLOAT*/ float_f_f,
|
|
/*INT*/ float_f_i,
|
|
/*STRING*/ float_f_s,
|
|
};
|
|
|
|
mv_t f_x_float_func(mv_t* pval1) { return (float_dispositions[pval1->type])(pval1); }
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t boolean_b_n(mv_t* pa) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t boolean_b_e(mv_t* pa) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
static mv_t boolean_b_b(mv_t* pa) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.boolv}; }
|
|
static mv_t boolean_b_f(mv_t* pa) { return (mv_t) {.type = MT_BOOL, .u.boolv = (pa->u.fltv == 0.0) ? FALSE : TRUE}; }
|
|
static mv_t boolean_b_i(mv_t* pa) { return (mv_t) {.type = MT_BOOL, .u.boolv = (pa->u.intv == 0LL) ? FALSE : TRUE}; }
|
|
static mv_t boolean_b_s(mv_t* pa) { return (mv_t) {.type = MT_BOOL,
|
|
.u.boolv = (streq(pa->u.strv, "true") || streq(pa->u.strv, "TRUE")) ? TRUE : FALSE
|
|
};
|
|
}
|
|
|
|
static mv_unary_func_t* boolean_dispositions[MT_MAX] = {
|
|
/*NULL*/ boolean_b_n,
|
|
/*ERROR*/ boolean_b_e,
|
|
/*BOOL*/ boolean_b_b,
|
|
/*FLOAT*/ boolean_b_f,
|
|
/*INT*/ boolean_b_i,
|
|
/*STRING*/ boolean_b_s,
|
|
};
|
|
|
|
mv_t b_x_boolean_func(mv_t* pval1) { return (boolean_dispositions[pval1->type])(pval1); }
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t string_s_n(mv_t* pa) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t string_s_e(mv_t* pa) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
static mv_t string_s_b(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_strdup_or_die(pa->u.boolv?"true":"false")}; }
|
|
static mv_t string_s_f(mv_t* pa) {
|
|
return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_string_from_double(pa->u.fltv, MLR_GLOBALS.ofmt)};
|
|
}
|
|
static mv_t string_s_i(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_string_from_ll(pa->u.intv)}; }
|
|
static mv_t string_s_s(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = pa->u.strv}; }
|
|
|
|
static mv_unary_func_t* string_dispositions[MT_MAX] = {
|
|
/*NULL*/ string_s_n,
|
|
/*ERROR*/ string_s_e,
|
|
/*BOOL*/ string_s_b,
|
|
/*FLOAT*/ string_s_f,
|
|
/*INT*/ string_s_i,
|
|
/*STRING*/ string_s_s,
|
|
};
|
|
|
|
mv_t s_x_string_func(mv_t* pval1) { return (string_dispositions[pval1->type])(pval1); }
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t hexfmt_s_n(mv_t* pa) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t hexfmt_s_e(mv_t* pa) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
static mv_t hexfmt_s_b(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_strdup_or_die(pa->u.boolv?"0x1":"0x0")}; }
|
|
static mv_t hexfmt_s_f(mv_t* pa) {
|
|
return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_hexfmt_from_ll((long long)pa->u.fltv)};
|
|
}
|
|
static mv_t hexfmt_s_i(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_hexfmt_from_ll(pa->u.intv)}; }
|
|
static mv_t hexfmt_s_s(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = pa->u.strv}; }
|
|
|
|
static mv_unary_func_t* hexfmt_dispositions[MT_MAX] = {
|
|
/*NULL*/ hexfmt_s_n,
|
|
/*ERROR*/ hexfmt_s_e,
|
|
/*BOOL*/ hexfmt_s_b,
|
|
/*FLOAT*/ hexfmt_s_f,
|
|
/*INT*/ hexfmt_s_i,
|
|
/*STRING*/ hexfmt_s_s,
|
|
};
|
|
|
|
mv_t s_x_hexfmt_func(mv_t* pval1) { return (hexfmt_dispositions[pval1->type])(pval1); }
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t fmtnum_s_ns(mv_t* pa, mv_t* pfmt) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t fmtnum_s_es(mv_t* pa, mv_t* pfmt) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
static mv_t fmtnum_s_bs(mv_t* pa, mv_t* pfmt) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_strdup_or_die(pa->u.boolv?"0x1":"0x0")}; }
|
|
static mv_t fmtnum_s_ds(mv_t* pa, mv_t* pfmt) {
|
|
return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_string_from_double(pa->u.fltv, pfmt->u.strv)};
|
|
}
|
|
static mv_t fmtnum_s_is(mv_t* pa, mv_t* pfmt) {
|
|
return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_string_from_ll_and_format(pa->u.intv, pfmt->u.strv)};
|
|
}
|
|
static mv_t fmtnum_s_ss(mv_t* pa, mv_t* pfmt) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
|
|
static mv_binary_func_t* fmtnum_dispositions[MT_MAX] = {
|
|
/*NULL*/ fmtnum_s_ns,
|
|
/*ERROR*/ fmtnum_s_es,
|
|
/*BOOL*/ fmtnum_s_bs,
|
|
/*FLOAT*/ fmtnum_s_ds,
|
|
/*INT*/ fmtnum_s_is,
|
|
/*STRING*/ fmtnum_s_ss,
|
|
};
|
|
|
|
mv_t s_xs_fmtnum_func(mv_t* pval1, mv_t* pval2) { return (fmtnum_dispositions[pval1->type])(pval1, pval2); }
|
|
|
|
// ----------------------------------------------------------------
|
|
static mv_t op_n_xx(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_NULL, .u.intv = 0}; }
|
|
static mv_t op_e_xx(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_ERROR, .u.intv = 0}; }
|
|
|
|
static mv_t eq_b_ii(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv == pb->u.intv}; }
|
|
static mv_t ne_b_ii(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv != pb->u.intv}; }
|
|
static mv_t gt_b_ii(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv > pb->u.intv}; }
|
|
static mv_t ge_b_ii(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv >= pb->u.intv}; }
|
|
static mv_t lt_b_ii(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv < pb->u.intv}; }
|
|
static mv_t le_b_ii(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv <= pb->u.intv}; }
|
|
|
|
static mv_t eq_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv == pb->u.fltv}; }
|
|
static mv_t ne_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv != pb->u.fltv}; }
|
|
static mv_t gt_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv > pb->u.fltv}; }
|
|
static mv_t ge_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv >= pb->u.fltv}; }
|
|
static mv_t lt_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv < pb->u.fltv}; }
|
|
static mv_t le_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv <= pb->u.fltv}; }
|
|
|
|
static mv_t eq_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv == pb->u.intv}; }
|
|
static mv_t ne_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv != pb->u.intv}; }
|
|
static mv_t gt_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv > pb->u.intv}; }
|
|
static mv_t ge_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv >= pb->u.intv}; }
|
|
static mv_t lt_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv < pb->u.intv}; }
|
|
static mv_t le_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.fltv <= pb->u.intv}; }
|
|
|
|
static mv_t eq_b_if(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv == pb->u.fltv}; }
|
|
static mv_t ne_b_if(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv != pb->u.fltv}; }
|
|
static mv_t gt_b_if(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv > pb->u.fltv}; }
|
|
static mv_t ge_b_if(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv >= pb->u.fltv}; }
|
|
static mv_t lt_b_if(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv < pb->u.fltv}; }
|
|
static mv_t le_b_if(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.intv <= pb->u.fltv}; }
|
|
|
|
static mv_t eq_b_xs(mv_t* pa, mv_t* pb) {
|
|
char* a = mt_format_val(pa);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(a, pb->u.strv) == 0};
|
|
free(a);
|
|
return rv;
|
|
}
|
|
static mv_t ne_b_xs(mv_t* pa, mv_t* pb) {
|
|
char* a = mt_format_val(pa);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(a, pb->u.strv) != 0};
|
|
free(a);
|
|
return rv;
|
|
}
|
|
static mv_t gt_b_xs(mv_t* pa, mv_t* pb) {
|
|
char* a = mt_format_val(pa);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(a, pb->u.strv) > 0};
|
|
free(a);
|
|
return rv;
|
|
}
|
|
static mv_t ge_b_xs(mv_t* pa, mv_t* pb) {
|
|
char* a = mt_format_val(pa);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(a, pb->u.strv) >= 0};
|
|
free(a);
|
|
return rv;
|
|
}
|
|
static mv_t lt_b_xs(mv_t* pa, mv_t* pb) {
|
|
char* a = mt_format_val(pa);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(a, pb->u.strv) < 0};
|
|
free(a);
|
|
return rv;
|
|
}
|
|
static mv_t le_b_xs(mv_t* pa, mv_t* pb) {
|
|
char* a = mt_format_val(pa);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(a, pb->u.strv) <= 0};
|
|
free(a);
|
|
return rv;
|
|
}
|
|
|
|
static mv_t eq_b_sx(mv_t* pa, mv_t* pb) {
|
|
char* b = mt_format_val(pb);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(pa->u.strv, b) == 0};
|
|
free(b);
|
|
return rv;
|
|
}
|
|
static mv_t ne_b_sx(mv_t* pa, mv_t* pb) {
|
|
char* b = mt_format_val(pb);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(pa->u.strv, b) != 0};
|
|
free(b);
|
|
return rv;
|
|
}
|
|
static mv_t gt_b_sx(mv_t* pa, mv_t* pb) {
|
|
char* b = mt_format_val(pb);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(pa->u.strv, b) > 0};
|
|
free(b);
|
|
return rv;
|
|
}
|
|
static mv_t ge_b_sx(mv_t* pa, mv_t* pb) {
|
|
char* b = mt_format_val(pb);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(pa->u.strv, b) >= 0};
|
|
free(b);
|
|
return rv;
|
|
}
|
|
static mv_t lt_b_sx(mv_t* pa, mv_t* pb) {
|
|
char* b = mt_format_val(pb);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(pa->u.strv, b) < 0};
|
|
free(b);
|
|
return rv;
|
|
}
|
|
static mv_t le_b_sx(mv_t* pa, mv_t* pb) {
|
|
char* b = mt_format_val(pb);
|
|
mv_t rv = {.type = MT_BOOL, .u.boolv = strcmp(pa->u.strv, b) <= 0};
|
|
free(b);
|
|
return rv;
|
|
}
|
|
|
|
static mv_t eq_b_ss(mv_t*pa, mv_t*pb) {return (mv_t){.type=MT_BOOL, .u.boolv=strcmp(pa->u.strv, pb->u.strv) == 0};}
|
|
static mv_t ne_b_ss(mv_t*pa, mv_t*pb) {return (mv_t){.type=MT_BOOL, .u.boolv=strcmp(pa->u.strv, pb->u.strv) != 0};}
|
|
static mv_t gt_b_ss(mv_t*pa, mv_t*pb) {return (mv_t){.type=MT_BOOL, .u.boolv=strcmp(pa->u.strv, pb->u.strv) > 0};}
|
|
static mv_t ge_b_ss(mv_t*pa, mv_t*pb) {return (mv_t){.type=MT_BOOL, .u.boolv=strcmp(pa->u.strv, pb->u.strv) >= 0};}
|
|
static mv_t lt_b_ss(mv_t*pa, mv_t*pb) {return (mv_t){.type=MT_BOOL, .u.boolv=strcmp(pa->u.strv, pb->u.strv) < 0};}
|
|
static mv_t le_b_ss(mv_t*pa, mv_t*pb) {return (mv_t){.type=MT_BOOL, .u.boolv=strcmp(pa->u.strv, pb->u.strv) <= 0};}
|
|
|
|
static mv_binary_func_t* eq_dispositions[MT_MAX][MT_MAX] = {
|
|
// NULL ERROR BOOL FLOAT INT STRING
|
|
/*NULL*/ {op_n_xx, op_e_xx, op_e_xx, op_n_xx, op_n_xx, op_n_xx},
|
|
/*ERROR*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*BOOL*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*FLOAT*/ {op_n_xx, op_e_xx, op_e_xx, eq_b_ff, eq_b_fi, eq_b_xs},
|
|
/*INT*/ {op_n_xx, op_e_xx, op_e_xx, eq_b_if, eq_b_ii, eq_b_xs},
|
|
/*STRING*/ {op_n_xx, op_e_xx, op_e_xx, eq_b_sx, eq_b_sx, eq_b_ss},
|
|
};
|
|
|
|
static mv_binary_func_t* ne_dispositions[MT_MAX][MT_MAX] = {
|
|
// NULL ERROR BOOL FLOAT INT STRING
|
|
/*NULL*/ {op_n_xx, op_e_xx, op_e_xx, op_n_xx, op_n_xx, op_n_xx},
|
|
/*ERROR*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*BOOL*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*FLOAT*/ {op_n_xx, op_e_xx, op_e_xx, ne_b_ff, ne_b_fi, ne_b_xs},
|
|
/*INT*/ {op_n_xx, op_e_xx, op_e_xx, ne_b_if, ne_b_ii, ne_b_xs},
|
|
/*STRING*/ {op_n_xx, op_e_xx, op_e_xx, ne_b_sx, ne_b_sx, ne_b_ss},
|
|
};
|
|
|
|
static mv_binary_func_t* gt_dispositions[MT_MAX][MT_MAX] = {
|
|
// NULL ERROR BOOL FLOAT INT STRING
|
|
/*NULL*/ {op_n_xx, op_e_xx, op_e_xx, op_n_xx, op_n_xx, op_n_xx},
|
|
/*ERROR*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*BOOL*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*FLOAT*/ {op_n_xx, op_e_xx, op_e_xx, gt_b_ff, gt_b_fi, gt_b_xs},
|
|
/*INT*/ {op_n_xx, op_e_xx, op_e_xx, gt_b_if, gt_b_ii, gt_b_xs},
|
|
/*STRING*/ {op_n_xx, op_e_xx, op_e_xx, gt_b_sx, gt_b_sx, gt_b_ss},
|
|
};
|
|
|
|
static mv_binary_func_t* ge_dispositions[MT_MAX][MT_MAX] = {
|
|
// NULL ERROR BOOL FLOAT INT STRING
|
|
/*NULL*/ {op_n_xx, op_e_xx, op_e_xx, op_n_xx, op_n_xx, op_n_xx},
|
|
/*ERROR*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*BOOL*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*FLOAT*/ {op_n_xx, op_e_xx, op_e_xx, ge_b_ff, ge_b_fi, ge_b_xs},
|
|
/*INT*/ {op_n_xx, op_e_xx, op_e_xx, ge_b_if, ge_b_ii, ge_b_xs},
|
|
/*STRING*/ {op_n_xx, op_e_xx, op_e_xx, ge_b_sx, ge_b_sx, ge_b_ss},
|
|
};
|
|
|
|
static mv_binary_func_t* lt_dispositions[MT_MAX][MT_MAX] = {
|
|
// NULL ERROR BOOL FLOAT INT STRING
|
|
/*NULL*/ {op_n_xx, op_e_xx, op_e_xx, op_n_xx, op_n_xx, op_n_xx},
|
|
/*ERROR*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*BOOL*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*FLOAT*/ {op_n_xx, op_e_xx, op_e_xx, lt_b_ff, lt_b_fi, lt_b_xs},
|
|
/*INT*/ {op_n_xx, op_e_xx, op_e_xx, lt_b_if, lt_b_ii, lt_b_xs},
|
|
/*STRING*/ {op_n_xx, op_e_xx, op_e_xx, lt_b_sx, lt_b_sx, lt_b_ss},
|
|
};
|
|
|
|
static mv_binary_func_t* le_dispositions[MT_MAX][MT_MAX] = {
|
|
// NULL ERROR BOOL FLOAT INT STRING
|
|
/*NULL*/ {op_n_xx, op_e_xx, op_e_xx, op_n_xx, op_n_xx, op_n_xx},
|
|
/*ERROR*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*BOOL*/ {op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx, op_e_xx},
|
|
/*FLOAT*/ {op_n_xx, op_e_xx, op_e_xx, le_b_ff, le_b_fi, le_b_xs},
|
|
/*INT*/ {op_n_xx, op_e_xx, op_e_xx, le_b_if, le_b_ii, le_b_xs},
|
|
/*STRING*/ {op_n_xx, op_e_xx, op_e_xx, le_b_sx, le_b_sx, le_b_ss},
|
|
};
|
|
|
|
mv_t eq_op_func(mv_t* pval1, mv_t* pval2) { return (eq_dispositions[pval1->type][pval2->type])(pval1, pval2); }
|
|
mv_t ne_op_func(mv_t* pval1, mv_t* pval2) { return (ne_dispositions[pval1->type][pval2->type])(pval1, pval2); }
|
|
mv_t gt_op_func(mv_t* pval1, mv_t* pval2) { return (gt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
|
|
mv_t ge_op_func(mv_t* pval1, mv_t* pval2) { return (ge_dispositions[pval1->type][pval2->type])(pval1, pval2); }
|
|
mv_t lt_op_func(mv_t* pval1, mv_t* pval2) { return (lt_dispositions[pval1->type][pval2->type])(pval1, pval2); }
|
|
mv_t le_op_func(mv_t* pval1, mv_t* pval2) { return (le_dispositions[pval1->type][pval2->type])(pval1, pval2); }
|
|
|
|
// ----------------------------------------------------------------
|
|
// arg2 evaluates to string via compound expression; regexes compiled on each call.
|
|
mv_t matches_no_precomp_func(mv_t* pval1, mv_t* pval2) {
|
|
char* s1 = pval1->u.strv;
|
|
char* s2 = pval2->u.strv;
|
|
|
|
regex_t regex;
|
|
char* sstr = s1;
|
|
char* sregex = s2;
|
|
regmatch_t pmatch[1];
|
|
int eflags = 0;
|
|
|
|
regcomp_or_die(®ex, sregex, REG_NOSUB);
|
|
|
|
if (regmatch_or_die(®ex, sstr, 1, pmatch, eflags)) {
|
|
regfree(®ex);
|
|
return (mv_t) {.type = MT_BOOL, .u.boolv = TRUE};
|
|
} else {
|
|
regfree(®ex);
|
|
return (mv_t) {.type = MT_BOOL, .u.boolv = FALSE};
|
|
}
|
|
}
|
|
|
|
mv_t does_not_match_no_precomp_func(mv_t* pval1, mv_t* pval2) {
|
|
mv_t rv = matches_no_precomp_func(pval1, pval2);
|
|
rv.u.boolv = !rv.u.boolv;
|
|
return rv;
|
|
}
|
|
|
|
// ----------------------------------------------------------------
|
|
// arg2 is a string, compiled to regex only once at alloc time
|
|
mv_t matches_precomp_func(mv_t* pval1, regex_t* pregex) {
|
|
regmatch_t pmatch[1];
|
|
int eflags = 0;
|
|
|
|
if (regmatch_or_die(pregex, pval1->u.strv, 1, pmatch, eflags)) {
|
|
return (mv_t) {.type = MT_BOOL, .u.boolv = TRUE};
|
|
} else {
|
|
return (mv_t) {.type = MT_BOOL, .u.boolv = FALSE};
|
|
}
|
|
}
|
|
|
|
mv_t does_not_match_precomp_func(mv_t* pval1, regex_t* pregex) {
|
|
mv_t rv = matches_precomp_func(pval1, pregex);
|
|
rv.u.boolv = !rv.u.boolv;
|
|
return rv;
|
|
}
|