Evaluate a comparison operator between actual and expected strings. */
| 2357 | |
| 2358 | /* Evaluate a comparison operator between actual and expected strings. */ |
| 2359 | static bool eval_comparison_op(const char *op, const char *actual, const char *expected) { |
| 2360 | if (strcmp(op, "=") == 0) { |
| 2361 | return strcmp(actual, expected) == 0; |
| 2362 | } |
| 2363 | if (strcmp(op, "<>") == 0) { |
| 2364 | return strcmp(actual, expected) != 0; |
| 2365 | } |
| 2366 | if (strcmp(op, "=~") == 0) { |
| 2367 | cbm_regex_t re; |
| 2368 | if (cbm_regcomp(&re, expected, CBM_REG_EXTENDED | CBM_REG_NOSUB) != 0) { |
| 2369 | return false; |
| 2370 | } |
| 2371 | int rc = cbm_regexec(&re, actual, 0, NULL, 0); |
| 2372 | cbm_regfree(&re); |
| 2373 | return rc == 0; |
| 2374 | } |
| 2375 | if (strcmp(op, "CONTAINS") == 0) { |
| 2376 | return strstr(actual, expected) != NULL; |
| 2377 | } |
| 2378 | if (strcmp(op, "STARTS WITH") == 0) { |
| 2379 | return strncmp(actual, expected, strlen(expected)) == 0; |
| 2380 | } |
| 2381 | if (strcmp(op, "ENDS WITH") == 0) { |
| 2382 | size_t alen = strlen(actual); |
| 2383 | size_t elen = strlen(expected); |
| 2384 | return alen >= elen && strcmp(actual + alen - elen, expected) == 0; |
| 2385 | } |
| 2386 | if (strcmp(op, ">") == 0 || strcmp(op, "<") == 0 || strcmp(op, ">=") == 0 || |
| 2387 | strcmp(op, "<=") == 0) { |
| 2388 | double a = strtod(actual, NULL); |
| 2389 | double exp_val = strtod(expected, NULL); |
| 2390 | if (op[0] == '>' && op[CYP_CHAR_IDX1] == '=') { |
| 2391 | return a >= exp_val; |
| 2392 | } |
| 2393 | if (op[0] == '<' && op[CYP_CHAR_IDX1] == '=') { |
| 2394 | return a <= exp_val; |
| 2395 | } |
| 2396 | if (op[0] == '>') { |
| 2397 | return a > exp_val; |
| 2398 | } |
| 2399 | return a < exp_val; |
| 2400 | } |
| 2401 | return false; |
| 2402 | } |
| 2403 | |
| 2404 | /* Evaluate a WHERE condition against a binding */ |
| 2405 | static bool eval_condition(const cbm_condition_t *c, binding_t *b) { |
no test coverage detected