]> uap-core.de Git - note.git/commitdiff
implement regex search
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 2 Feb 2026 19:40:14 +0000 (20:40 +0100)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Mon, 2 Feb 2026 19:40:14 +0000 (20:40 +0100)
application/note.c
application/note.h
application/tests/test-note.c
application/tests/test-note.h
application/tests/testmain.c

index e23d53f4954385b5362bdbff82fc7463910e2828..61e27e80bf05d8f9d9100994b3b799bcc6ca2dee 100644 (file)
@@ -344,7 +344,7 @@ int text_search(
         int pos,
         bool backwards,
         bool case_sensitive,
-        bool regex,
+        regex_t *regex,
         int *result_begin,
         int *result_end)
 {
@@ -353,9 +353,20 @@ int text_search(
         cxstring subtext = cx_strsubs(text, pos);
         if(!regex) {
             result = case_sensitive ? cx_strstr(subtext, search) : text_search_strcasestr(subtext, search);
+            if(result.ptr) {
+                *result_begin = (int)(result.ptr - text.ptr);
+                *result_end = *result_begin + search.length;
+                return 1;
+            }
         } else {
-            // regex search
-            // TODO
+            // case_sensitive parameter is ignored in regex mode
+            regmatch_t match;
+            if(regexec(regex, subtext.ptr, 1, &match, 0) != 0) {
+                return 0;
+            }
+            *result_begin = match.rm_so + pos;
+            *result_end = match.rm_eo + pos;
+            return 1;
         }
     } else {
         // use text_search in forward-mode as long as result_end < pos
@@ -370,13 +381,8 @@ int text_search(
             prev_begin = begin;
             prev_end = end;
         }
-        if(prev_begin >= 0) {
-            result = cx_strn(text.ptr + prev_begin, prev_end-prev_begin);
-        }
-    }
-    if(result.ptr) {
-        *result_begin = (int)(result.ptr - text.ptr);
-        *result_end = *result_begin + search.length;
+        *result_begin = prev_begin;
+        *result_end = prev_end;
         return 1;
     }
     return 0;
@@ -402,10 +408,21 @@ static void note_search(NoteModel *note, bool backwards) {
     int pos = get_search_start_pos(note, backwards);
 
     bool cs = (bool)ui_get(note->search_cs);
-    bool regex = (bool)ui_get(note->search_regex);
+    regex_t regex;
+    bool enable_regex = (bool)ui_get(note->search_regex);
+    if(enable_regex) {
+        int flags = REG_EXTENDED;
+        if(!cs) {
+            flags |= REG_ICASE;
+        }
+        if(regcomp(&regex, searchstr.ptr, flags)) {
+            enable_regex = FALSE;
+            // TODO: show invalid regex error
+        }
+    }
     
     int begin, end;
-    if(text_search(text, searchstr, pos, backwards, regex, cs, &begin, &end)) {
+    if(text_search(text, searchstr, pos, backwards, cs, enable_regex ? &regex : NULL, &begin, &end)) {
         note->text->setposition(note->text, end);
         note->text->setselection(note->text, begin, end);
         note->text->showposition(note->text, begin);
index f7be3599180cd56f19d54679f57cb8a2d8a1c8dc..3e099e0046a071b906006c7c77a7a0edfb719ce8 100644 (file)
@@ -32,6 +32,8 @@
 #include "application.h"
 #include "editor.h"
 
+#include <regex.h>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -78,7 +80,7 @@ int text_search(
         int pos,
         bool backwards,
         bool case_sensitive,
-        bool regex,
+        regex_t *regex,
         int *result_begin,
         int *result_end);
 
index fd23ec71aef2713cac231ea36e3755e9093fce43..6c6edc0aaf74e4350c449d275e6163b311d00bb6 100644 (file)
@@ -30,6 +30,7 @@
 
 #include "../note.h"
 
+#include <regex.h>
 
 CX_TEST(test_text_search_strcasestr) {
     CX_TEST_DO {
@@ -68,28 +69,28 @@ CX_TEST(test_text_search_cs) {
         // test from pos 0
         int begin = -1;
         int end = -1;
-        int ret = text_search(str, cx_str("123"), 0, FALSE, TRUE, FALSE, &begin, &end);
+        int ret = text_search(str, cx_str("123"), 0, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 0);
         CX_TEST_ASSERT(end == 3);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("4567"), 0, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("4567"), 0, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 4);
         CX_TEST_ASSERT(end == 8);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("edfghj"), 0, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("edfghj"), 0, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 18);
         CX_TEST_ASSERT(end == 24);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("abc"), 0, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("abc"), 0, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 13);
         CX_TEST_ASSERT(end == 16);
@@ -97,49 +98,49 @@ CX_TEST(test_text_search_cs) {
         // test from other positions
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("4567"), 4, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("4567"), 4, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 4);
         CX_TEST_ASSERT(end == 8);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("abc"), 14, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("abc"), 14, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 33);
         CX_TEST_ASSERT(end == 36);
         
-        ret = text_search(str, cx_str("4567"), 20, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("4567"), 20, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(!ret);
         
-        ret = text_search(str, cx_str("edfghj"), 19, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("edfghj"), 19, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(!ret);
         
         // case sensitive test
-        ret = text_search(str, cx_str("ABCD"), 0, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("ABCD"), 0, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(!ret);
         
-        ret = text_search(str, cx_str("Xyz"), 0, FALSE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("Xyz"), 0, FALSE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(!ret);
         
         // backwards search
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("abc"), 36, TRUE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("abc"), 36, TRUE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 33);
         CX_TEST_ASSERT(end == 36);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("edf"), 25, TRUE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("edf"), 25, TRUE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 18);
         CX_TEST_ASSERT(end == 21);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("abc"), 25, TRUE, TRUE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("abc"), 25, TRUE, TRUE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 13);
         CX_TEST_ASSERT(end == 16);
@@ -153,21 +154,21 @@ CX_TEST(test_text_search_ci) {
         // test from pos 0
         int begin = -1;
         int end = -1;
-        int ret = text_search(str, cx_str("abc"), 0, FALSE, FALSE, FALSE, &begin, &end);
+        int ret = text_search(str, cx_str("abc"), 0, FALSE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 0);
         CX_TEST_ASSERT(end == 3);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("def"), 0, FALSE, FALSE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("def"), 0, FALSE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 4);
         CX_TEST_ASSERT(end == 7);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("DEF"), 0, FALSE, FALSE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("DEF"), 0, FALSE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 4);
         CX_TEST_ASSERT(end == 7);
@@ -175,14 +176,14 @@ CX_TEST(test_text_search_ci) {
         // test other pos
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("DEF"), 4, FALSE, FALSE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("DEF"), 4, FALSE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 4);
         CX_TEST_ASSERT(end == 7);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("ABC"), 8, FALSE, FALSE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("ABC"), 8, FALSE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 16);
         CX_TEST_ASSERT(end == 19);
@@ -190,16 +191,58 @@ CX_TEST(test_text_search_ci) {
         // backwards
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("aBc"), 19, TRUE, FALSE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("aBc"), 19, TRUE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 16);
         CX_TEST_ASSERT(end == 19);
         
         begin = -1;
         end = -1;
-        ret = text_search(str, cx_str("xyz"), 19, TRUE, FALSE, FALSE, &begin, &end);
+        ret = text_search(str, cx_str("xyz"), 19, TRUE, FALSE, NULL, &begin, &end);
         CX_TEST_ASSERT(ret);
         CX_TEST_ASSERT(begin == 12);
         CX_TEST_ASSERT(end == 15);
     }
 }
+
+CX_TEST(test_text_search_regex) {
+    CX_TEST_DO {
+        cxstring str = cx_str("hello world test  string text end");
+        
+        regex_t regex;
+        CX_TEST_ASSERT(!regcomp(&regex, "te[^ ]* ", REG_EXTENDED));
+        
+        int begin, end, ret;
+        
+        // from pos 0
+        begin = -1;
+        end = -1;
+        ret = text_search(str, cx_str(""), 0, FALSE, FALSE, &regex, &begin, &end);
+        CX_TEST_ASSERT(ret);
+        CX_TEST_ASSERT(begin == 12);
+        CX_TEST_ASSERT(end == 17);
+        
+        // from pos > 0
+        begin = -1;
+        end = -1;
+        ret = text_search(str, cx_str(""), 4, FALSE, FALSE, &regex, &begin, &end);
+        CX_TEST_ASSERT(ret);
+        CX_TEST_ASSERT(begin == 12);
+        CX_TEST_ASSERT(end == 17);
+        
+        // negative
+        begin = -1;
+        end = -1;
+        ret = text_search(str, cx_str(""), 26, FALSE, FALSE, &regex, &begin, &end);
+        CX_TEST_ASSERT(!ret);
+        
+        // backwards
+        begin = -1;
+        end = -1;
+        ret = text_search(str, cx_str(""), 20, TRUE, FALSE, &regex, &begin, &end);
+        CX_TEST_ASSERT(ret);
+        CX_TEST_ASSERT(begin == 12);
+        CX_TEST_ASSERT(end == 17);
+    }
+    
+}
index 3404d3caf8ffc3095afd2e23d38baebe10bb6c8a..d3a629aed1916d64670933590c1fdbafcc32f2c9 100644 (file)
@@ -38,6 +38,7 @@ extern "C" {
 CX_TEST(test_text_search_strcasestr);
 CX_TEST(test_text_search_cs);
 CX_TEST(test_text_search_ci);
+CX_TEST(test_text_search_regex);
 
 
 #ifdef __cplusplus
index 36fcb619bf28300a8860ae2a7ed10d2d6eb63d5a..481f47a29e68ed304032c36803ecfbc3cc9c4138 100644 (file)
@@ -81,6 +81,7 @@ int main(int argc, char **argv) {
     cx_test_register(suite, test_text_search_strcasestr);
     cx_test_register(suite, test_text_search_cs);
     cx_test_register(suite, test_text_search_ci);
+    cx_test_register(suite, test_text_search_regex);
     
     cx_test_run_stdout(suite);
     int err = suite->failure > 0 ? 1 : 0;