From 256dea043b15df35d7727d9dd3f4032a1969f8a9 Mon Sep 17 00:00:00 2001
From: Stefan Hofmann <stefan.hofmann@t-online.de>
Date: Tue, 13 May 2025 13:00:09 +0200
Subject: [PATCH] Fixes and annotations

---
 Makefile              |  2 +-
 README                |  1 -
 blacklist.c           |  4 ++++
 epgsearchcfg.h        |  2 +-
 epgsearchext.c        | 34 ++++++++++++++++------------------
 epgsearchtools.h      |  2 +-
 md5.c                 |  2 +-
 menu_blacklists.c     |  2 +-
 menu_search.c         |  2 +-
 menu_searchedit.c     |  2 +-
 menu_searchtemplate.c |  2 +-
 menu_whatson.c        |  3 +--
 services.c            |  2 +-
 13 files changed, 30 insertions(+), 30 deletions(-)
 delete mode 120000 README

diff --git a/Makefile b/Makefile
index 6a4f4f9..5d81757 100644
--- a/Makefile
+++ b/Makefile
@@ -88,7 +88,7 @@ export CXXFLAGS = $(call PKGCFG,cxxflags)
 ### configuring modules
 ifeq ($(AUTOCONFIG),1)
 	ifeq (exists, $(shell $(PKG_CONFIG) libpcre2-posix && echo exists))
-    REGEXLIB = pcre2
+		REGEXLIB = pcre2
 	else ifeq (exists, $(shell $(PKG_CONFIG) libpcre && echo exists))
 		REGEXLIB = pcre
 	else ifeq (exists, $(shell $(PKG_CONFIG) tre && echo exists))
diff --git a/README b/README
deleted file mode 120000
index b16bb82..0000000
--- a/README
+++ /dev/null
@@ -1 +0,0 @@
-./doc/en/epgsearch.1.txt
\ No newline at end of file
diff --git a/blacklist.c b/blacklist.c
index 53f0cca..b64f0c1 100644
--- a/blacklist.c
+++ b/blacklist.c
@@ -102,7 +102,11 @@ cBlacklist::~cBlacklist(void)
 cBlacklist& cBlacklist::operator= (const cBlacklist &Blacklist)
 {
     char**   catvaluesTemp = this->catvalues;
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wclass-memaccess"
+    // TODO: this shallow copy does not duplicate all strings -> can this cause trouble?
     memcpy(this, &Blacklist, sizeof(*this));
+#pragma GCC diagnostic pop
     this->catvalues = catvaluesTemp;
 
     cSearchExtCat *SearchExtCat = SearchExtCats.First();
diff --git a/epgsearchcfg.h b/epgsearchcfg.h
index e871b2e..6b350e3 100644
--- a/epgsearchcfg.h
+++ b/epgsearchcfg.h
@@ -72,7 +72,7 @@ public:
     }
 
     void SetDescription(const char* szD) {
-        if (szD)  strncpy(description, szD, sizeof(description));
+        if (szD)  strn0cpy(description, szD, sizeof(description));
     }
     void SetTime(int iT) {
         itime = iT;
diff --git a/epgsearchext.c b/epgsearchext.c
index b89a4e7..26fc1d3 100644
--- a/epgsearchext.c
+++ b/epgsearchext.c
@@ -235,6 +235,7 @@ void cSearchExt::CopyFromTemplate(const cSearchExt* templ, bool ignoreChannelSet
     useAsSearchTimerTil = templ->useAsSearchTimerTil;
     ignoreMissingEPGCats = templ->ignoreMissingEPGCats;
     unmuteSoundOnSwitch = templ->unmuteSoundOnSwitch;
+    skipRunningEvents = templ->skipRunningEvents;
 }
 
 bool cSearchExt::operator< (const cListObject &ListObject)
@@ -247,7 +248,7 @@ char* replaceSpecialChars(const char* in)
 {
     char* tmp_in = strdup(in);
     while (strstr(tmp_in, "|"))
-        tmp_in = strreplace(tmp_in, "|", "!^pipe^!"); // ugly: replace a pipe with something,
+        tmp_in = strreplace(tmp_in, "|", "!^pipe^!"); // ugly: replace a pipe with something
     strreplace(tmp_in, ':', '|');
     return tmp_in;
 }
@@ -298,7 +299,7 @@ const char *cSearchExt::ToText()
             char* catvalue = NULL;
             if (msprintf(&catvalue, "%s", catvalues[index]) == -1) break;
             while (strstr(catvalue, ":"))
-                catvalue = strreplace(catvalue, ":", "!^colon^!"); // ugly: replace with something, that should not happen to be part ofa category value
+                catvalue = strreplace(catvalue, ":", "!^colon^!"); // ugly: replace with something, that should not happen to be part of a category value
             while (strstr(catvalue, "|"))
                 catvalue = strreplace(catvalue, "|", "!^pipe^!"); // ugly: replace with something, that should not happen to be part of a regular expression
 
@@ -384,7 +385,7 @@ const char *cSearchExt::ToText()
              ignoreMissingEPGCats,
              unmuteSoundOnSwitch,
              compareSummaryMatchInPercent,
-             contentsFilter.c_str(),
+             tmp_contentsFilter,
              compareDate);
 
     if (tmp_search) free(tmp_search);
@@ -402,8 +403,8 @@ bool cSearchExt::Parse(const char *s)
     char *pos;
     char *pos_next;
     int parameter = 1;
-    int valuelen;
-    char value[MaxFileName];
+    size_t valuelen;
+    char value[MaxFileName * 10];       // assume 10-byte patterns for special characters
     bool disableSearchtimer = false;
 
     *directory = 0;
@@ -420,7 +421,7 @@ bool cSearchExt::Parse(const char *s)
                 if (!pos_next)
                     pos_next = pos + strlen(pos);
                 valuelen = pos_next - pos + 1;
-                if (valuelen > MaxFileName) valuelen = MaxFileName;
+                if (valuelen > sizeof(value)) valuelen = sizeof(value);
                 strn0cpy(value, pos, valuelen);
                 pos = pos_next;
                 switch (parameter) {
@@ -429,7 +430,9 @@ bool cSearchExt::Parse(const char *s)
                     ID = atoi(value);
                     break;
                 case 2:
-                    strcpy(search, value);
+                    strreplace(value, '|', ':');
+                    while (strstr(value, "!^pipe^!")) { strreplace(value, "!^pipe^!", "|"); }
+                    strn0cpy(search, value, sizeof(search));
                     break;
                 case 3:
                     useTime = atoi(value);
@@ -522,7 +525,9 @@ bool cSearchExt::Parse(const char *s)
                     useEpisode = atoi(value);
                     break;
                 case 20:
-                    strcpy(directory, value);
+                    strreplace(value, '|', ':');
+                    while (strstr(value, "!^pipe^!")) { strreplace(value, "!^pipe^!", "|"); }
+                    strn0cpy(directory, value, sizeof(directory));
                     break;
                 case 21:
                     Priority = atoi(value);
@@ -629,6 +634,9 @@ bool cSearchExt::Parse(const char *s)
                     compareSummaryMatchInPercent = atoi(value);
                     break;
                 case 53:
+                    strreplace(value, '|', ':');
+                    while (strstr(value, "!^pipe^!")) { strreplace(value, "!^pipe^!", "|"); }
+                    value[MaxFileName - 1] = '\0';  // simulate strn0cpy()
                     contentsFilter = value;
                     break;
                 case 54:
@@ -643,16 +651,6 @@ bool cSearchExt::Parse(const char *s)
         if (*pos) pos++;
     } //while
 
-    strreplace(directory, '|', ':');
-    strreplace(search, '|', ':');
-    strreplace(contentsFilter, "|", ":");
-
-    while (strstr(search, "!^pipe^!"))
-        strreplace(search, "!^pipe^!", "|");
-    while (strstr(directory, "!^pipe^!"))
-        strreplace(directory, "!^pipe^!", "|");
-    strreplace(contentsFilter, "!^pipe^!", "|");
-
     if (disableSearchtimer && useAsSearchTimer) {
         useAsSearchTimer = false;
         LogFile.Log(1, "search timer '%s' disabled", search);
diff --git a/epgsearchtools.h b/epgsearchtools.h
index 5c74318..3cfea2e 100644
--- a/epgsearchtools.h
+++ b/epgsearchtools.h
@@ -31,7 +31,7 @@ The project's page is at http://winni.vdr-developer.org/epgsearch
 
 using std::string;
 
-#define MAXPARSEBUFFER KILOBYTE(10)
+#define MAXPARSEBUFFER KILOBYTE(20)
 
 #undef CHANNELNAME
 #define CHANNELNAME(x) (x ? x->ShortName(true) : "")
diff --git a/md5.c b/md5.c
index 1557ff4..0d4d6a5 100644
--- a/md5.c
+++ b/md5.c
@@ -99,7 +99,7 @@ char* PrintMD5(uchar md5Digest[16])
 
     for (nCount = 0; nCount < 16; nCount++) {
         sprintf(chEach, "%02x", md5Digest[nCount]);
-        strncat(chBuffer, chEach, sizeof(chEach));
+        strncat(chBuffer, chEach, 10);
     }
 
     return strdup(chBuffer);
diff --git a/menu_blacklists.c b/menu_blacklists.c
index b0567a9..435b85d 100644
--- a/menu_blacklists.c
+++ b/menu_blacklists.c
@@ -59,7 +59,7 @@ void cMenuBlacklistsItem::Set(void)
         line << setiosflags(ios::left) << "G";
     line << "\t";
 
-    if (blacklist->search && strlen(blacklist->search) > 0)
+    if (strlen(blacklist->search) > 0)
         line << setiosflags(ios::left) << string(blacklist->search);
     else
         line << setiosflags(ios::left) << "*";
diff --git a/menu_search.c b/menu_search.c
index f5bfe6f..5f2a4ea 100644
--- a/menu_search.c
+++ b/menu_search.c
@@ -65,7 +65,7 @@ void cMenuSearchExtItem::Set(void)
     }
 
     line << "\t";
-    if (searchExt->search && strlen(searchExt->search) > 0)
+    if (strlen(searchExt->search) > 0)
         line << setiosflags(ios::left) << string(searchExt->search);
     else
         line << setiosflags(ios::left) << "*";
diff --git a/menu_searchedit.c b/menu_searchedit.c
index b70c5bd..2e54782 100644
--- a/menu_searchedit.c
+++ b/menu_searchedit.c
@@ -337,7 +337,7 @@ void cMenuEditSearchExt::Set()
                 if (data.allowedRepeats > 0)
                     Add(new cMenuEditIntItem(IndentMenuItem(tr("Only repeats within ... days"), 2), &data.repeatsWithinDays, 0, 999));
                 Add(new cMenuEditBoolItem(IndentMenuItem(tr("Compare title"), 2), &data.compareTitle, trVDR("no"), trVDR("yes")));
-                Add(new cMenuEditStraItem(IndentMenuItem(tr("Compare subtitle"), 3), &data.compareSubtitle, 3, CompareSubtitleModes));
+                Add(new cMenuEditStraItem(IndentMenuItem(tr("Compare subtitle"), 2), &data.compareSubtitle, 3, CompareSubtitleModes));
                 Add(new cMenuEditBoolItem(IndentMenuItem(tr("Compare summary"), 2), &data.compareSummary, trVDR("no"), trVDR("yes")));
                 if (data.compareSummary)
                     Add(new cMenuEditIntItem(IndentMenuItem(tr("Min. match in %"), 3), &data.compareSummaryMatchInPercent, 1, 100));
diff --git a/menu_searchtemplate.c b/menu_searchtemplate.c
index 3a837b6..f361f29 100644
--- a/menu_searchtemplate.c
+++ b/menu_searchtemplate.c
@@ -66,7 +66,7 @@ void cMenuSearchTemplateItem::Set(void)
     }
 
     line << "\t";
-    if (searchExt->search && strlen(searchExt->search) > 0)
+    if (strlen(searchExt->search) > 0)
         line << setiosflags(ios::left) << string(searchExt->search);
     else
         line << setiosflags(ios::left) << "*";
diff --git a/menu_whatson.c b/menu_whatson.c
index 2d18116..f7148ee 100644
--- a/menu_whatson.c
+++ b/menu_whatson.c
@@ -136,8 +136,7 @@ bool cMenuMyScheduleItem::Update(const cTimers* Timers, bool Force)
 #endif
                     }
                 } else {
-                    strncpy(szProgressPart, *event->GetTimeString(), 12);
-                    szProgressPart[11] = 0;
+                    strn0cpy(szProgressPart, *event->GetTimeString(), 12);
                     memcpy(szProgressPartT2S, szProgressPart, 12);
                 }
             }
diff --git a/services.c b/services.c
index 31749f2..f540e74 100644
--- a/services.c
+++ b/services.c
@@ -280,7 +280,7 @@ std::list<std::string> cEpgsearchServiceHandler::TimerConflictList(bool relOnly)
             for (it = ct->failedTimers.begin(); it != ct->failedTimers.end(); ++it) {
                 if (relOnly && (*it)->ignore) continue;
                 std::ostringstream timerpart;
-                int recPart = (*it)->recDuration * 100 / ((*it)->stop - (*it)->start);
+                int recPart = (*it)->stop - (*it)->start > 0 ? (*it)->recDuration * 100 / ((*it)->stop - (*it)->start) : 0;
                 timerpart << (*it)->timer->Id() << "|" << recPart << "|";
                 std::set<cConflictCheckTimerObj*, TimerObjSort>::iterator itcc;
                 if ((*it)->concurrentTimers) {
-- 
2.49.0.windows.1

