From: Jaroslav Kysela Date: Wed, 17 May 2017 07:19:52 +0000 (+0200) Subject: regex - move related code to tvhregex.h/wrappers.c X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7faa8c4056d28d1c64298c79dcc088f0f86872c9;p=thirdparty%2Ftvheadend.git regex - move related code to tvhregex.h/wrappers.c - remove PCRE column from DVR, use PCRE automatically - disable autorec when the regex is wrong (cannot be compiled) --- diff --git a/src/dvr/dvr.h b/src/dvr/dvr.h index 0a828b954..f1bb2eb4f 100644 --- a/src/dvr/dvr.h +++ b/src/dvr/dvr.h @@ -19,14 +19,7 @@ #ifndef DVR_H #define DVR_H -#include -#if ENABLE_PCRE -#include -#endif -#if ENABLE_PCRE2 -#define PCRE2_CODE_UNIT_WIDTH 8 -#include -#endif +#include "tvhregex.h" #include "epg.h" #include "channels.h" #include "subscriptions.h" @@ -340,20 +333,13 @@ typedef struct dvr_autorec_entry { LIST_ENTRY(dvr_autorec_entry) dae_config_link; int dae_enabled; + int dae_error; char *dae_owner; char *dae_creator; char *dae_comment; char *dae_title; - int dae_pcre; - regex_t dae_title_preg; -#if ENABLE_PCRE - pcre *dae_title_pcre; - pcre_extra *dae_title_pcre_extra; -#elif ENABLE_PCRE2 - pcre2_code *dae_title_pcre; - pcre2_match_data *dae_title_pcre_match; -#endif + tvh_regex_t dae_title_regex; int dae_fulltext; uint32_t dae_content_type; diff --git a/src/dvr/dvr_autorec.c b/src/dvr/dvr_autorec.c index 5eb5a9eef..a1fbe4e8d 100644 --- a/src/dvr/dvr_autorec.c +++ b/src/dvr/dvr_autorec.c @@ -34,62 +34,12 @@ #include "epg.h" #include "htsp_server.h" -#ifndef PCRE_STUDY_JIT_COMPILE -#define PCRE_STUDY_JIT_COMPILE 0 -#endif - struct dvr_autorec_entry_queue autorec_entries; -/* - * - */ -static inline int autorec_regexec(dvr_autorec_entry_t *dae, const char *str) -{ -#if ENABLE_PCRE - if (dae->dae_pcre) { - int r, vec[30]; - r = pcre_exec(dae->dae_title_pcre, dae->dae_title_pcre_extra, - str, strlen(str), 0, 0, vec, ARRAY_SIZE(vec)); - return r < 0; - } else -#elif ENABLE_PCRE2 - int r; - r = pcre2_match(dae->dae_title_pcre, (PCRE2_SPTR8)str, -1, 0, 0, - dae->dae_title_pcre_match, NULL); - return r <= 0; -#endif - { - return regexec(&dae->dae_title_preg, str, 0, NULL, 0); - } -} - -/* - * - */ static void autorec_regfree(dvr_autorec_entry_t *dae) { if (dae->dae_title) { -#if ENABLE_PCRE - if (dae->dae_pcre) { -#ifdef PCRE_CONFIG_JIT - pcre_free_study(dae->dae_title_pcre_extra); -#else - pcre_free(dae->dae_title_pcre_extra); -#endif - pcre_free(dae->dae_title_pcre); - dae->dae_title_pcre_extra = NULL; - dae->dae_title_pcre = NULL; - } else -#elif ENABLE_PCRE2 - if (dae->dae_pcre) { - pcre2_match_data_free(dae->dae_title_pcre_match); - dae->dae_title_pcre_match = NULL; - dae->dae_title_pcre = NULL; - } else -#endif - { - regfree(&dae->dae_title_preg); - } + regex_free(&dae->dae_title_regex); free(dae->dae_title); dae->dae_title = NULL; } @@ -310,21 +260,21 @@ autorec_cmp(dvr_autorec_entry_t *dae, epg_broadcast_t *e) if (!dae->dae_fulltext) { if(!e->episode->title) return 0; RB_FOREACH(ls, e->episode->title, link) - if (!autorec_regexec(dae, ls->str)) break; + if (!regex_match(&dae->dae_title_regex, ls->str)) break; } else { ls = NULL; if (e->episode->title) RB_FOREACH(ls, e->episode->title, link) - if (!autorec_regexec(dae, ls->str)) break; + if (!regex_match(&dae->dae_title_regex, ls->str)) break; if (!ls && e->episode->subtitle) RB_FOREACH(ls, e->episode->subtitle, link) - if (!autorec_regexec(dae, ls->str)) break; + if (!regex_match(&dae->dae_title_regex, ls->str)) break; if (!ls && e->summary) RB_FOREACH(ls, e->summary, link) - if (!autorec_regexec(dae, ls->str)) break; + if (!regex_match(&dae->dae_title_regex, ls->str)) break; if (!ls && e->description) RB_FOREACH(ls, e->description, link) - if (!autorec_regexec(dae, ls->str)) break; + if (!regex_match(&dae->dae_title_regex, ls->str)) break; } if (!ls) return 0; } @@ -359,9 +309,6 @@ dvr_autorec_create(const char *uuid, htsmsg_t *conf) TAILQ_INSERT_TAIL(&autorec_entries, dae, dae_link); - /* PCRE flag must be set before load (order issue) */ - if (conf) - dae->dae_pcre = htsmsg_get_bool_or_default(conf, "pcre", 0); idnode_load(&dae->dae_id, conf); htsp_autorec_entry_add(dae); @@ -487,6 +434,8 @@ dvr_autorec_entry_class_changed(idnode_t *self) { dvr_autorec_entry_t *dae = (dvr_autorec_entry_t *)self; + if (dae->dae_error) + dae->dae_enabled = 0; dvr_autorec_changed(dae, 1); dvr_autorec_completed(dae, 0); htsp_autorec_entry_update(dae); @@ -588,66 +537,11 @@ dvr_autorec_entry_class_title_set(void *o, const void *v) if (strcmp(title, dae->dae_title ?: "")) { if (dae->dae_title) autorec_regfree(dae); - if (title[0] != '\0') { -#if ENABLE_PCRE - if (dae->dae_pcre) { - const char *estr; - int eoff; - dae->dae_title_pcre = pcre_compile(title, PCRE_CASELESS | PCRE_UTF8, - &estr, &eoff, NULL); - if (dae->dae_title_pcre == NULL) { - tvherror(LS_DVR, "Unable to compile PCRE '%s': %s", title, estr); - } else { - dae->dae_title_pcre_extra = pcre_study(dae->dae_title_pcre, - PCRE_STUDY_JIT_COMPILE, &estr); - if (dae->dae_title_pcre_extra == NULL && estr) - tvherror(LS_DVR, "Unable to study PCRE '%s': %s", title, estr); - else - dae->dae_title = strdup(title); - } - } else -#elif ENABLE_PCRE2 - if (dae->dae_pcre) { - PCRE2_UCHAR8 ebuf[128]; - int ecode; - PCRE2_SIZE eoff; - dae->dae_title_pcre = pcre2_compile((PCRE2_SPTR8)title, -1, - PCRE2_CASELESS | PCRE2_UTF, - &ecode, &eoff, NULL); - if (dae->dae_title_pcre == NULL) { - (void)pcre2_get_error_message(ecode, ebuf, 120); - tvherror(LS_DVR, "Unable to compile PCRE2 '%s': %s", title, ebuf); - } else { - dae->dae_title_pcre_match = pcre2_match_data_create(20, NULL); - dae->dae_title = strdup(title); - } - } else -#endif - { - if (!regcomp(&dae->dae_title_preg, title, - REG_ICASE | REG_EXTENDED | REG_NOSUB)) - dae->dae_title = strdup(title); - else - tvherror(LS_DVR, "Unable to compile regex '%s'", title); - } - } - return 1; - } - return 0; -} - -static int -dvr_autorec_entry_class_pcre_set(void *o, const void *v) -{ - dvr_autorec_entry_t *dae = (dvr_autorec_entry_t *)o; - int pcre = v ? *(int *)v : 0; - char *title; - if (dae->dae_pcre != pcre) { - title = dae->dae_title ? strdup(dae->dae_title) : NULL; - autorec_regfree(dae); - dae->dae_pcre = pcre; - dvr_autorec_entry_class_title_set(o, title); - free(title); + dae->dae_error = 0; + if (!regex_compile(&dae->dae_title_regex, title, LS_DVR)) + dae->dae_title = strdup(title); + else + dae->dae_error = 1; return 1; } return 0; @@ -1161,15 +1055,6 @@ const idclass_t dvr_autorec_entry_class = { "matched against title, subtitle, summary and description."), .off = offsetof(dvr_autorec_entry_t, dae_fulltext), }, - { - .type = PT_BOOL, - .id = "pcre", - .name = N_("PCRE"), - .desc = N_("Use PCRE regular expression library instead posix " - "extended regular expressions."), - .set = dvr_autorec_entry_class_pcre_set, - .off = offsetof(dvr_autorec_entry_t, dae_pcre), - }, { .type = PT_STR, .id = "channel", diff --git a/src/tvhregex.h b/src/tvhregex.h new file mode 100644 index 000000000..56a3befe0 --- /dev/null +++ b/src/tvhregex.h @@ -0,0 +1,69 @@ +/* + * TVheadend - regex wrapper + * + * Copyright (C) 2017 Jaroslav Kysela + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TVHREGEX_H__ +#define __TVHREGEX_H__ + +#if ENABLE_PCRE + +# include +# ifndef PCRE_STUDY_JIT_COMPILE +# define PCRE_STUDY_JIT_COMPILE 0 +# endif + +#elif ENABLE_PCRE2 + +# define PCRE2_CODE_UNIT_WIDTH 8 +# include + +#else + +# include + +#endif + +typedef struct { +#if ENABLE_PCRE + pcre *re_code; + pcre_extra *re_extra; +#elif ENABLE_PCRE2 + pcre2_code *re_code; + pcre2_match_data *re_match; +#else + regex_t re_code; +#endif +} tvh_regex_t; + +static inline int regex_match(tvh_regex_t *regex, const char *str) +{ +#if ENABLE_PCRE + int vec[30]; + return pcre_exec(regex->re_code, re->re_extra, + str, strlen(str), 0, 0, vec, ARRAY_SIZE(vec)) < 0; +#elif ENABLE_PCRE2 + return pcre2_match(regex->re_code, (PCRE2_SPTR8)str, -1, 0, 0, + regex->re_match, NULL) <= 0; +#else + return regexec(®ex->re_code, str, 0, NULL, 0); +#endif +} + +void regex_free(tvh_regex_t *regex); +int regex_compile(tvh_regex_t *regex, const char *re_str, int subsys); + +#endif /* __TVHREGEX_H__ */ diff --git a/src/webui/static/app/dvr.js b/src/webui/static/app/dvr.js index c48180b7a..bd6130e6d 100644 --- a/src/webui/static/app/dvr.js +++ b/src/webui/static/app/dvr.js @@ -723,7 +723,7 @@ tvheadend.dvr_settings = function(panel, index) { */ tvheadend.autorec_editor = function(panel, index) { - var list = 'name,title,fulltext,pcre,channel,start,start_window,weekdays,' + + var list = 'name,title,fulltext,channel,start,start_window,weekdays,' + 'record,tag,btype,content_type,minduration,maxduration,' + 'dedup,directory,config_name,comment'; var elist = 'enabled,start_extra,stop_extra,' + @@ -742,7 +742,6 @@ tvheadend.autorec_editor = function(panel, index) { directory: { width: 200 }, title: { width: 300 }, fulltext: { width: 70 }, - pcre: { width: 70 }, channel: { width: 200 }, tag: { width: 200 }, btype: { width: 50 }, @@ -782,7 +781,7 @@ tvheadend.autorec_editor = function(panel, index) { }, }, del: true, - list: 'enabled,name,title,fulltext,pcre,channel,tag,start,start_window,' + + list: 'enabled,name,title,fulltext,channel,tag,start,start_window,' + 'weekdays,minduration,maxduration,btype,content_type,' + 'pri,dedup,directory,config_name,owner,creator,comment', sort: { diff --git a/src/wrappers.c b/src/wrappers.c index a354f2ee7..c9a550792 100644 --- a/src/wrappers.c +++ b/src/wrappers.c @@ -18,6 +18,8 @@ #include #endif +#include "tvhregex.h" + /* * filedescriptor routines */ @@ -381,3 +383,67 @@ tvh_qsort_r(void *base, size_t nmemb, size_t size, int (*compar)(const void *, c qsort_r(base, nmemb, size, compar, arg); #endif } + +/* + * Regex stuff + */ +void regex_free(tvh_regex_t *regex) +{ +#if ENABLE_PCRE +#ifdef PCRE_CONFIG_JIT + pcre_free_study(regex->re_extra); +#else + pcre_free(regex->re_extra); +#endif + pcre_free(regex->re_comp); + regex->re_extra = NULL; + regex->re_comp = NULL; +#elif ENABLE_PCRE2 + pcre2_match_data_free(regex->re_match); + pcre2_code_free(regex->re_code); +#else + regfree(®ex->re_code); +#endif +} + +int regex_compile(tvh_regex_t *regex, const char *re_str, int subsys) +{ +#if ENABLE_PCRE + const char *estr; + int eoff; + regex->re_code = pcre_compile(re_str, PCRE_CASELESS | PCRE_UTF8, + &estr, &eoff, NULL); + if (regex->re_code == NULL) { + tvherror(subsys, "Unable to compile PCRE '%s': %s", re_str, estr); + } else { + regex->re_code_extra = pcre_study(regex->re_code, + PCRE_STUDY_JIT_COMPILE, &estr); + if (regex->re_code_extra == NULL && estr) + tvherror(subsys, "Unable to study PCRE '%s': %s", re_str, estr); + else + return 0; + } + return -1; +#elif ENABLE_PCRE2 + PCRE2_UCHAR8 ebuf[128]; + int ecode; + PCRE2_SIZE eoff; + regex->re_code = pcre2_compile((PCRE2_SPTR8)re_str, -1, + PCRE2_CASELESS | PCRE2_UTF, + &ecode, &eoff, NULL); + if (regex->re_code == NULL) { + (void)pcre2_get_error_message(ecode, ebuf, 120); + tvherror(subsys, "Unable to compile PCRE2 '%s': %s", re_str, ebuf); + } else { + regex->re_match = pcre2_match_data_create(20, NULL); + return 0; + } + return -1; +#else + if (!regcomp(®ex->re_code, re_str, + REG_ICASE | REG_EXTENDED | REG_NOSUB)) + return 0; + tvherror(subsys, "Unable to compile regex '%s'", title); + return -1; +#endif +}