// ---------------------------------------------------------------- // xxx check for semantics comparable to mt_get_boolean_strict void mt_get_double_strict(mv_t* pval) { if (pval->type == MT_NULL) return; if (pval->type == MT_ERROR) return; if (pval->type == MT_DOUBLE) return; if (pval->type == MT_STRING) { double dblv; if (!mlr_try_double_from_string(pval->u.strv, &dblv)) { pval->type = MT_ERROR; pval->u.intv = 0; } else { pval->type = MT_DOUBLE; pval->u.dblv = dblv; } } else if (pval->type == MT_INT) { pval ->type = MT_DOUBLE; pval->u.dblv = (double)pval->u.intv; } else if (pval->type == MT_BOOL) { pval->type = MT_ERROR; pval->u.intv = 0; } // xxx else panic }
double mlr_double_from_string_or_die(char* string) { double d; if (!mlr_try_double_from_string(string, &d)) { fprintf(stderr, "Couldn't parse \"%s\" as number.\n", string); exit(1); } return d; }
// ---------------------------------------------------------------- static int is_percentile_acc_name(char* acc_name) { double percentile; // sscanf(acc_name, "p%lf", &percentile) allows "p74x" et al. which isn't ok. if (acc_name[0] != 'p') return FALSE; if (!mlr_try_double_from_string(&acc_name[1], &percentile)) return FALSE; if (percentile < 0.0 || percentile > 100.0) { fprintf(stderr, "%s stats1: percentile \"%s\" outside range [0,100].\n", MLR_GLOBALS.argv0, acc_name); exit(1); } return TRUE; }
// ---------------------------------------------------------------- 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); // xxx encapsulate this: 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 s_sss_sub_func(mv_t* pval1, mv_t* pval2, mv_t* pval3) { char* substr = strstr(pval1->u.strv, pval2->u.strv); if (substr == NULL) { return *pval1; } else { int len1 = substr - pval1->u.strv; int olen2 = strlen(pval2->u.strv); 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); strncpy(&string4[0], pval1->u.strv, len1); strncpy(&string4[len1], pval3->u.strv, nlen2); strncpy(&string4[len1+nlen2], &pval1->u.strv[len1+olen2], len3); free(pval1->u.strv); free(pval2->u.strv); free(pval3->u.strv); pval1->u.strv = NULL; pval2->u.strv = NULL; pval3->u.strv = NULL; mv_t rv = {.type = MT_STRING, .u.strv = string4}; return rv; } } // ---------------------------------------------------------------- // xxx cmt mem-mgt & contract. similar to lrec-mapper contract. mv_t s_s_tolower_func(mv_t* pval1) { char* string = strdup(pval1->u.strv); for (char* c = string; *c; c++) *c = tolower(*c); // xxx encapsulate this: free(pval1->u.strv); pval1->u.strv = NULL; mv_t rv = {.type = MT_STRING, .u.strv = string}; return rv; } // xxx cmt mem-mgt & contract. similar to lrec-mapper contract. mv_t s_s_toupper_func(mv_t* pval1) { char* string = strdup(pval1->u.strv); for (char* c = string; *c; c++) *c = toupper(*c); // xxx encapsulate this: 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_DOUBLE) return MV_ERROR; time_t clock = (time_t) pval1->u.dblv; 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 = timegm(&tm); mv_t rv = {.type = MT_INT, .u.intv = (long long)t}; return rv; } } // ---------------------------------------------------------------- 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_d(mv_t* pa) { return (mv_t) {.type = MT_INT, .u.intv = (long long)round(pa->u.dblv)}; } 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, /*DOUBLE*/ int_i_d, /*INT*/ int_i_i, /*STRING*/ int_i_s, }; mv_t i_x_int_func(mv_t* pval1) { return (int_dispositions[pval1->type])(pval1); } // ---------------------------------------------------------------- // xxx i'm using double & long long but saying double & int. this is confusing & needs fixing. 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_DOUBLE, .u.dblv = pa->u.boolv ? 1.0 : 0.0}; } static mv_t float_f_d(mv_t* pa) { return (mv_t) {.type = MT_DOUBLE, .u.dblv = pa->u.dblv}; } static mv_t float_f_i(mv_t* pa) { return (mv_t) {.type = MT_DOUBLE, .u.dblv = pa->u.intv}; } static mv_t float_f_s(mv_t* pa) { mv_t retval = (mv_t) {.type = MT_DOUBLE }; if (*pa->u.strv == '\0') return MV_NULL; if (!mlr_try_double_from_string(pa->u.strv, &retval.u.dblv)) 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, /*DOUBLE*/ float_f_d, /*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_d(mv_t* pa) { return (mv_t) {.type = MT_BOOL, .u.boolv = (pa->u.dblv == 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, /*DOUBLE*/ boolean_b_d, /*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 = strdup(pa->u.boolv?"true":"false")}; } static mv_t string_s_d(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_string_from_double(pa->u.dblv, 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, /*DOUBLE*/ string_s_d, /*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 = strdup(pa->u.boolv?"0x1":"0x0")}; } static mv_t hexfmt_s_d(mv_t* pa) { return (mv_t) {.type = MT_STRING, .u.strv = mlr_alloc_hexfmt_from_ll((long long)pa->u.dblv)}; } 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, /*DOUBLE*/ hexfmt_s_d, /*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 = strdup(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.dblv, 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, /*DOUBLE*/ 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); } // ---------------------------------------------------------------- // xxx cmt us!!!! 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.dblv == pb->u.dblv}; } static mv_t ne_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.dblv != pb->u.dblv}; } static mv_t gt_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.dblv > pb->u.dblv}; } static mv_t ge_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.dblv >= pb->u.dblv}; } static mv_t lt_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.dblv < pb->u.dblv}; } static mv_t le_b_ff(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.dblv <= pb->u.dblv}; } static mv_t eq_b_fi(mv_t* pa, mv_t* pb) { return (mv_t) {.type = MT_BOOL, .u.boolv = pa->u.dblv == 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.dblv != 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.dblv > 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.dblv >= 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.dblv < 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.dblv <= 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.dblv}; } 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.dblv}; } 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.dblv}; } 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.dblv}; } 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.dblv}; } 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.dblv}; } 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 DOUBLE 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}, /*DOUBLE*/ {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 DOUBLE 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}, /*DOUBLE*/ {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 DOUBLE 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}, /*DOUBLE*/ {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 DOUBLE 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}, /*DOUBLE*/ {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 DOUBLE 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}, /*DOUBLE*/ {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 DOUBLE 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}, /*DOUBLE*/ {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); }
// ---------------------------------------------------------------- int ap_parse(ap_state_t* pstate, char* verb, int* pargi, int argc, char** argv) { int argi = *pargi; int ok = TRUE; while (argi < argc) { if (argv[argi][0] != '-') { break; } if (streq(argv[argi], "-h") || streq(argv[argi], "--help")) { ok = FALSE; break; } ap_flag_def_t* pdef = ap_find(pstate, argv[argi]); if (pdef == NULL) { ok = FALSE; break; } if ((argc-argi) < pdef->count) { fprintf(stderr, "%s %s: option %s requires an argument.\n", argv[0], verb, argv[argi]); fprintf(stderr, "\n"); ok = FALSE; break; } if (pdef->type == AP_INT_VALUE_FLAG) { *(int *)pdef->pval = pdef->intval; } else if (pdef->type == AP_CHAR_FLAG) { if (!try_sep_from_arg(argv[argi+1], (char *)pdef->pval)) { fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as character.\n", argv[0], verb, argv[argi+1], argv[argi]); fprintf(stderr, "\n"); } } else if (pdef->type == AP_INT_FLAG) { if (sscanf(argv[argi+1], "%d", (int *)pdef->pval) != 1) { fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as integer.\n", argv[0], verb, argv[argi+1], argv[argi]); fprintf(stderr, "\n"); } } else if (pdef->type == AP_DOUBLE_FLAG) { if (!mlr_try_double_from_string(argv[argi+1], (double *)pdef->pval)) { fprintf(stderr, "%s %s: couldn't parse \"%s\" after \"%s\" as double.\n", argv[0], verb, argv[argi+1], argv[argi]); fprintf(stderr, "\n"); } } else if (pdef->type == AP_STRING_FLAG) { char** pstring = pdef->pval; *pstring = argv[argi+1]; pdef->pval = pstring; } else if (pdef->type == AP_STRING_LIST_FLAG) { slls_t** pplist = pdef->pval; if (*pplist != NULL) slls_free(*pplist); *pplist = slls_from_line(argv[argi+1], ',', FALSE); pdef->pval = pplist; } else { ok = FALSE; fprintf(stderr, "argparse.c: coding error: flag-def type %x not recognized.\n", pdef->type); fprintf(stderr, "\n"); break; } argi += pdef->count; } *pargi = argi; return ok; }