aboutsummaryrefslogtreecommitdiff
path: root/src/pms_match.c
diff options
context:
space:
mode:
authorMiguel Dalberto Pedro <miguel.pedro@precisioninno.com>2026-10-29 17:55:36 -0300
committerMiguel Dalberto Pedro <miguel.pedro@precisioninno.com>2026-10-29 17:55:36 -0300
commit915478aef931cb57fe56fe568ab4982454a29812 (patch)
tree33057f4773852d99e8cd7ad92d568e79f34847ee /src/pms_match.c
downloadpms-master.tar.gz
pms-master.zip
Initial commit: Padre Matos Soares (1932) Bible corpus and pms CLIHEADmaster
Diffstat (limited to 'src/pms_match.c')
-rw-r--r--src/pms_match.c142
1 files changed, 142 insertions, 0 deletions
diff --git a/src/pms_match.c b/src/pms_match.c
new file mode 100644
index 0000000..8140dd5
--- /dev/null
+++ b/src/pms_match.c
@@ -0,0 +1,142 @@
+#include "pms_match.h"
+#include "pms_data.h"
+#include "pms_util.h"
+#include <limits.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+static bool verse_matches(const pms_ref *ref, const pms_verse *v) {
+ switch (ref->type) {
+ case PMS_REF_SEARCH: {
+ if (ref->book != 0 && (unsigned int)v->book != ref->book) {
+ return false;
+ }
+ if (ref->chapter != 0 && (unsigned int)v->chapter != ref->chapter) {
+ return false;
+ }
+ char folded[4096];
+ pms_fold_utf8(v->text, folded, sizeof(folded), NULL);
+ return regexec(&ref->search, folded, 0, NULL, 0) == 0;
+ }
+
+ case PMS_REF_EXACT:
+ return (unsigned int)v->book == ref->book &&
+ (ref->chapter == 0 || (unsigned int)v->chapter == ref->chapter) &&
+ (ref->verse == 0 || (unsigned int)v->verse == ref->verse);
+
+ case PMS_REF_EXACT_SET:
+ if ((unsigned int)v->book != ref->book || (unsigned int)v->chapter != ref->chapter) {
+ return false;
+ }
+ for (int i = 0; i < ref->verse_set_count; i++) {
+ if ((unsigned int)v->verse == ref->verse_set[i]) {
+ return true;
+ }
+ }
+ return false;
+
+ case PMS_REF_RANGE:
+ return (unsigned int)v->book == ref->book &&
+ ((ref->chapter_end == 0 && (unsigned int)v->chapter == ref->chapter) ||
+ ((unsigned int)v->chapter >= ref->chapter && (unsigned int)v->chapter <= ref->chapter_end)) &&
+ (ref->verse == 0 || (unsigned int)v->verse >= ref->verse) &&
+ (ref->verse_end == 0 || (unsigned int)v->verse <= ref->verse_end);
+
+ case PMS_REF_RANGE_EXT:
+ return (unsigned int)v->book == ref->book &&
+ (((unsigned int)v->chapter == ref->chapter && (unsigned int)v->verse >= ref->verse && ref->chapter != ref->chapter_end) ||
+ ((unsigned int)v->chapter > ref->chapter && (unsigned int)v->chapter < ref->chapter_end) ||
+ ((unsigned int)v->chapter == ref->chapter_end && (unsigned int)v->verse <= ref->verse_end && ref->chapter != ref->chapter_end) ||
+ (ref->chapter == ref->chapter_end && (unsigned int)v->chapter == ref->chapter &&
+ (unsigned int)v->verse >= ref->verse && (unsigned int)v->verse <= ref->verse_end));
+
+ default:
+ return false;
+ }
+}
+
+static pms_range chapter_bounds(int i, const pms_config *config) {
+ pms_range bounds = {.start = i, .end = i + 1};
+ int book = pms_verses[i].book;
+ int chapter = pms_verses[i].chapter;
+
+ int max_before = config->chapter_context ? INT_MAX : config->before_context;
+ for (int n = 0; n < max_before && bounds.start > 0; n++) {
+ if (pms_verses[bounds.start - 1].book == book &&
+ (!config->chapter_context || pms_verses[bounds.start - 1].chapter == chapter)) {
+ bounds.start--;
+ } else {
+ break;
+ }
+ }
+
+ int max_after = config->chapter_context ? INT_MAX : config->after_context;
+ for (int n = 0; n < max_after && bounds.end < pms_verses_length; n++) {
+ if (pms_verses[bounds.end].book == book &&
+ (!config->chapter_context || pms_verses[bounds.end].chapter == chapter)) {
+ bounds.end++;
+ } else {
+ break;
+ }
+ }
+
+ return bounds;
+}
+
+static int find_next_match(const pms_ref *ref, const pms_config *config, int i, pms_range *range) {
+ for (; i < pms_verses_length; i++) {
+ if (verse_matches(ref, &pms_verses[i])) {
+ *range = chapter_bounds(i, config);
+ return i;
+ }
+ }
+ return -1;
+}
+
+int pms_next_verse(const pms_ref *ref, const pms_config *config, pms_match_data *data) {
+ if (data->current >= pms_verses_length) {
+ return -1;
+ }
+
+ if (data->current == 0 && data->next_match == 0) {
+ data->matches[0] = (pms_range){-1, -1};
+ data->matches[1] = (pms_range){-1, -1};
+
+ data->next_match = find_next_match(ref, config, 0, &data->matches[0]);
+ if (data->next_match < 0) {
+ data->current = pms_verses_length;
+ return -1;
+ }
+ data->next_match = find_next_match(ref, config, data->next_match + 1, &data->matches[1]);
+ }
+
+ while (data->matches[1].start != -1 && data->matches[1].start <= data->matches[0].end) {
+ if (data->matches[1].end > data->matches[0].end) {
+ data->matches[0].end = data->matches[1].end;
+ }
+ data->matches[1] = (pms_range){-1, -1};
+ if (data->next_match >= 0) {
+ data->next_match = find_next_match(ref, config, data->next_match + 1, &data->matches[1]);
+ }
+ }
+
+ if (data->current < data->matches[0].start) {
+ data->current = data->matches[0].start;
+ }
+
+ if (data->current < data->matches[0].end) {
+ return data->current++;
+ }
+
+ if (data->matches[1].start != -1) {
+ data->matches[0] = data->matches[1];
+ data->matches[1] = (pms_range){-1, -1};
+ if (data->next_match >= 0) {
+ data->next_match = find_next_match(ref, config, data->next_match + 1, &data->matches[1]);
+ }
+ return pms_next_verse(ref, config, data);
+ }
+
+ data->current = pms_verses_length;
+ return -1;
+}