From 915478aef931cb57fe56fe568ab4982454a29812 Mon Sep 17 00:00:00 2001 From: Miguel Dalberto Pedro Date: Thu, 29 Oct 2026 17:55:36 -0300 Subject: Initial commit: Padre Matos Soares (1932) Bible corpus and pms CLI --- src/pms_match.c | 142 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 src/pms_match.c (limited to 'src/pms_match.c') 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 +#include +#include + +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; +} -- cgit v1.2.3