From: Arvin Schnell Date: Wed, 18 Nov 2020 11:59:25 +0000 (+0100) Subject: - use C++11 regexes instead of own regcomp/regexec wrapper class X-Git-Tag: v0.8.15~18^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b0a37a54e2f1cfd6ecb60b084d5ef5b0208c88de;p=thirdparty%2Fsnapper.git - use C++11 regexes instead of own regcomp/regexec wrapper class --- diff --git a/LIBVERSION b/LIBVERSION index 831446cb..91ff5727 100644 --- a/LIBVERSION +++ b/LIBVERSION @@ -1 +1 @@ -5.1.0 +5.2.0 diff --git a/package/snapper.changes b/package/snapper.changes index 2b0fba15..81113b41 100644 --- a/package/snapper.changes +++ b/package/snapper.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Wed Nov 18 12:13:56 CET 2020 - aschnell@suse.com + +- use C++11 regexes instead of own regcomp/regexec wrapper class + (see gh#openSUSE/snapper#583) + ------------------------------------------------------------------- Tue Sep 22 09:17:28 CEST 2020 - aschnell@suse.com diff --git a/snapper/AsciiFile.cc b/snapper/AsciiFile.cc index 1ee9788c..bc141d4d 100644 --- a/snapper/AsciiFile.cc +++ b/snapper/AsciiFile.cc @@ -1,5 +1,6 @@ /* * Copyright (c) [2004-2015] Novell, Inc. + * Copyright (c) 2020 SUSE LLC * * All Rights Reserved. * @@ -22,6 +23,7 @@ #include #include +#include #include "snapper/Log.h" #include "snapper/AppUtil.h" @@ -36,9 +38,9 @@ namespace snapper AsciiFileReader::AsciiFileReader(int fd) - : file(fdopen(fd, "r")), buffer(NULL), len(0) + : file(fdopen(fd, "r")) { - if (file == NULL) + if (!file) { y2war("file is NULL"); SN_THROW(FileNotFoundException()); @@ -47,9 +49,9 @@ namespace snapper AsciiFileReader::AsciiFileReader(FILE* file) - : file(file), buffer(NULL), len(0) + : file(file) { - if (file == NULL) + if (!file) { y2war("file is NULL"); SN_THROW(FileNotFoundException()); @@ -58,10 +60,9 @@ namespace snapper AsciiFileReader::AsciiFileReader(const string& filename) - : file(NULL), buffer(NULL), len(0) + : file(fopen(filename.c_str(), "re")) { - file = fopen(filename.c_str(), "re"); - if (file == NULL) + if (!file) { y2war("open for '" << filename << "' failed"); SN_THROW(FileNotFoundException()); @@ -171,9 +172,9 @@ AsciiFile::save() void SysconfigFile::checkKey(const string& key) const { - Regex rx("^" "([0-9A-Z_]+)" "$"); + static const regex rx("([0-9A-Z_]+)", regex::extended); - if (!rx.match(key)) + if (!regex_match(key, rx)) SN_THROW(InvalidKeyException()); } @@ -209,39 +210,41 @@ AsciiFile::save() { checkKey(key); - Regex rx('^' + Regex::ws + - key + '=' + "(['\"]?)([^'\"]*)\\1" + - '(' + Regex::ws + Regex::trailing_comment + ")$"); + modified = true; - vector::iterator it = find_if(lines(), regex_matches(rx)); - if (it == lines().end()) - { - string line = key + "=\"" + value + "\""; - push_back(line); - } - else + for (vector::iterator it = Lines_C.begin(); it != Lines_C.end(); ++it) { - string line = key + "=\"" + value + "\"" + rx.cap(3); - *it = line; + ParsedLine parsed_line; + + if (parse_line(*it, parsed_line) && parsed_line.key == key) + { + string line = key + "=\"" + value + "\"" + parsed_line.comment; + *it = line; + return; + } } - modified = true; + string line = key + "=\"" + value + "\""; + push_back(line); } bool SysconfigFile::getValue(const string& key, string& value) const { - Regex rx('^' + Regex::ws + - key + '=' + "(['\"]?)([^'\"]*)\\1" + - Regex::ws + Regex::trailing_comment + '$'); + for (const string& line : Lines_C) + { + ParsedLine parsed_line; - if (find_if(lines(), regex_matches(rx)) == lines().end()) - return false; + if (parse_line(line, parsed_line) && parsed_line.key == key) + { + value = parsed_line.value; + y2mil("key:" << key << " value:" << value); + return true; + } + } - value = rx.cap(2); - y2mil("key:" << key << " value:" << value); - return true; + return false; } @@ -303,17 +306,47 @@ AsciiFile::save() { map ret; - Regex rx('^' + Regex::ws + - "([0-9A-Z_]+)" + '=' + "(['\"]?)([^'\"]*)\\2" + - Regex::ws + Regex::trailing_comment + '$'); - - for (vector::const_iterator it = Lines_C.begin(); it != Lines_C.end(); ++it) + for (const string& line : Lines_C) { - if (rx.match(*it)) - ret[rx.cap(1)] = rx.cap(3); + ParsedLine parsed_line; + + if (parse_line(line, parsed_line)) + ret[parsed_line.key] = parsed_line.value; } return ret; } + + bool + SysconfigFile::parse_line(const string& line, ParsedLine& parsed_line) const + { + const string whitespace = "[ \t]*"; + const string comment = "(#.*)?"; + + // Note: Avoid back references. Whether they work depend on the regex flags. Also + // the old regcomp/regexec based implementation did not work with them with some + // libc implementations. + + static const regex rx1(whitespace + "([0-9A-Z_]+)" + '=' + "\"([^\"]*)\"" + + '(' + whitespace + comment + ")"); + + static const regex rx2(whitespace + "([0-9A-Z_]+)" + '=' + "'([^']*)'" + + '(' + whitespace + comment + ")"); + + static const regex rx3(whitespace + "([0-9A-Z_]+)" + '=' + "([^ \t]*)" + + '(' + whitespace + comment + ")"); + + smatch match; + + if (!regex_match(line, match, rx1) && !regex_match(line, match, rx2) && !regex_match(line, match, rx3)) + return false; + + parsed_line.key = match[1]; + parsed_line.value = match[2]; + parsed_line.comment = match[3]; + + return true; + } + } diff --git a/snapper/AsciiFile.h b/snapper/AsciiFile.h index 63e0abb3..218f92e9 100644 --- a/snapper/AsciiFile.h +++ b/snapper/AsciiFile.h @@ -1,5 +1,6 @@ /* * Copyright (c) [2004-2015] Novell, Inc. + * Copyright (c) 2020 SUSE LLC * * All Rights Reserved. * @@ -51,9 +52,9 @@ namespace snapper private: - FILE* file; - char* buffer; - size_t len; + FILE* file = nullptr; + char* buffer = nullptr; + size_t len = 0; }; @@ -127,6 +128,15 @@ namespace snapper bool modified; + struct ParsedLine + { + string key; + string value; + string comment; + }; + + bool parse_line(const string& line, ParsedLine& parsed_line) const; + }; } diff --git a/snapper/Btrfs.cc b/snapper/Btrfs.cc index 69362974..0ec9dde1 100644 --- a/snapper/Btrfs.cc +++ b/snapper/Btrfs.cc @@ -1,6 +1,6 @@ /* * Copyright (c) [2011-2015] Novell, Inc. - * Copyright (c) [2016-2018] SUSE LLC + * Copyright (c) [2016-2020] SUSE LLC * * All Rights Reserved. * @@ -44,6 +44,7 @@ #include #include #endif +#include #include #include "snapper/Log.h" @@ -55,7 +56,6 @@ #include "snapper/SnapperDefines.h" #include "snapper/Acls.h" #include "snapper/Exception.h" -#include "snapper/Regex.h" #ifdef ENABLE_ROLLBACK #include "snapper/MntTable.h" #endif @@ -1473,11 +1473,13 @@ namespace snapper { string path = get_subvolume(fd, id); - Regex rx("/([0-9]+)/snapshot$"); - if (!rx.match(path)) + static const regex rx("/([0-9]+)/snapshot$", regex::extended); + smatch match; + + if (!regex_search(path, match, rx)) return make_pair(false, 0); - unsigned int num = stoi(rx.cap(1)); + unsigned int num = stoi(match[1].str()); if (!checkSnapshot(num)) return make_pair(false, 0); diff --git a/snapper/Lvm.cc b/snapper/Lvm.cc index 2a452707..cb829aac 100644 --- a/snapper/Lvm.cc +++ b/snapper/Lvm.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "snapper/Log.h" @@ -41,7 +42,6 @@ #include "snapper/SnapperTmpl.h" #include "snapper/SystemCmd.h" #include "snapper/SnapperDefines.h" -#include "snapper/Regex.h" #include "snapper/LvmCache.h" #ifdef ENABLE_SELINUX #include "snapper/Selinux.h" @@ -56,9 +56,11 @@ namespace snapper Filesystem* Lvm::create(const string& fstype, const string& subvolume, const string& root_prefix) { - Regex rx("^lvm\\(([_a-z0-9]+)\\)$"); - if (rx.match(fstype)) - return new Lvm(subvolume, root_prefix, rx.cap(1)); + static const regex rx("lvm\\(([_a-z0-9]+)\\)", regex::extended); + smatch match; + + if (regex_match(fstype, match, rx)) + return new Lvm(subvolume, root_prefix, match[1]); return NULL; } @@ -421,7 +423,7 @@ namespace snapper string Lvm::getDevice(unsigned int num) const { - return "/dev/mapper/" + boost::replace_all_copy(vg_name, "-", "--") + "-" + + return DEV_MAPPER_DIR "/" + boost::replace_all_copy(vg_name, "-", "--") + "-" + boost::replace_all_copy(snapshotLvName(num), "-", "--"); } @@ -474,9 +476,11 @@ namespace snapper } else { - Regex rx(".*LVM[[:space:]]+version:[[:space:]]+([0-9]+)\\.([0-9]+)\\.([0-9]+).*$"); + static const regex rx(".*LVM[[:space:]]+version:[[:space:]]+([0-9]+)\\.([0-9]+)\\.([0-9]+).*$", + regex::extended); + smatch match; - if (!rx.match(cmd.get_stdout().front())) + if (!regex_search(cmd.get_stdout().front(), match, rx)) { y2war("LVM version format didn't match"); } @@ -484,9 +488,9 @@ namespace snapper { uint16_t maj, min, rev; - rx.cap(1) >> maj; - rx.cap(2) >> min; - rx.cap(3) >> rev; + match[1] >> maj; + match[2] >> min; + match[3] >> rev; lvm_version version(maj, min, rev); diff --git a/snapper/Lvm.h b/snapper/Lvm.h index ea86bd72..ff9a5669 100644 --- a/snapper/Lvm.h +++ b/snapper/Lvm.h @@ -71,7 +71,7 @@ namespace snapper // empty or " -K" if lvm supports ignore activation skip flag string ignoreactivationskip; // true if lvm2 supports time info stored in metadata - bool time_support; + bool time_support = false; }; class SelinuxLabelHandle; diff --git a/snapper/LvmUtils.cc b/snapper/LvmUtils.cc index 47e76954..b8589f8c 100644 --- a/snapper/LvmUtils.cc +++ b/snapper/LvmUtils.cc @@ -21,11 +21,11 @@ */ +#include #include #include "snapper/LvmUtils.h" -#include "snapper/Regex.h" -#include "snapper/AppUtil.h" +#include "snapper/SnapperDefines.h" namespace snapper @@ -37,16 +37,19 @@ namespace snapper pair split_device_name(const string& name) { - Regex rx("^/dev/mapper/(.*[^-])-([^-].*)$"); - if (!rx.match(name)) + static const std::regex rx(DEV_MAPPER_DIR "/(.*[^-])-([^-].*)", std::regex::extended); + std::smatch match; + + if (!regex_match(name, match, rx)) throw std::runtime_error("faild to split device name into volume group and " "logical volume name"); - string vg_name = boost::replace_all_copy(rx.cap(1), "--", "-"); - string lv_name = boost::replace_all_copy(rx.cap(2), "--", "-"); + string vg_name = boost::replace_all_copy(match[1].str(), "--", "-"); + string lv_name = boost::replace_all_copy(match[2].str(), "--", "-"); return make_pair(vg_name, lv_name); } } + } diff --git a/snapper/Regex.cc b/snapper/Regex.cc index da8f8625..26962c1d 100644 --- a/snapper/Regex.cc +++ b/snapper/Regex.cc @@ -19,6 +19,12 @@ * find current contact information at www.novell.com. */ + +// This file is obsolete. It is only present for compatibility of libsnapper, esp. the +// Regex class was used in older versions of the zypp-plugin and we must avoid potentially +// problems during updates. + + #include #include "snapper/Regex.h" diff --git a/snapper/Regex.h b/snapper/Regex.h index 1d32a9eb..cd476865 100644 --- a/snapper/Regex.h +++ b/snapper/Regex.h @@ -20,6 +20,11 @@ */ +// This file is obsolete. It is only present for compatibility of libsnapper, esp. the +// Regex class was used in older versions of the zypp-plugin and we must avoid potentially +// problems during updates. + + #ifndef SNAPPER_REGEX_H #define SNAPPER_REGEX_H diff --git a/snapper/Snapper.cc b/snapper/Snapper.cc index 6b9f51a2..a5098805 100644 --- a/snapper/Snapper.cc +++ b/snapper/Snapper.cc @@ -31,6 +31,7 @@ #include #include #include +#include #include #include "snapper/Snapper.h" @@ -49,7 +50,6 @@ #include "snapper/BtrfsUtils.h" #ifdef ENABLE_SELINUX #include "snapper/Selinux.h" -#include "snapper/Regex.h" #endif @@ -874,8 +874,8 @@ namespace snapper Snapper::syncSelinuxContextsInInfosDir(bool skip_snapshot_dir) const { #ifdef ENABLE_SELINUX - Regex rx("^[0-9]+$"); - Regex rx_filelist("^filelist-[0-9]+.txt$"); + static const regex rx("[0-9]+", regex::extended); + static const regex rx_filelist("filelist-[0-9]+.txt", regex::extended); y2deb("Syncing Selinux contexts in infos dir"); @@ -884,7 +884,7 @@ namespace snapper vector infos = infos_dir.entries(); for (vector::const_iterator it1 = infos.begin(); it1 != infos.end(); ++it1) { - if (!rx.match(*it1)) + if (!regex_match(*it1, rx)) continue; SDir info_dir(infos_dir, *it1); @@ -902,7 +902,7 @@ namespace snapper vector info_content = info_dir.entries(); for (vector::const_iterator it2 = info_content.begin(); it2 != info_content.end(); ++it2) { - if (!rx_filelist.match(*it2)) + if (!regex_match(*it2, rx_filelist)) continue; SFile fl(info_dir, *it2); diff --git a/snapper/SnapperDefines.h b/snapper/SnapperDefines.h index 13333121..d03a1222 100644 --- a/snapper/SnapperDefines.h +++ b/snapper/SnapperDefines.h @@ -1,5 +1,6 @@ /* * Copyright (c) [2004-2014] Novell, Inc. + * Copyright (c) 2020 SUSE LLC * * All Rights Reserved. * @@ -33,6 +34,9 @@ #define FILTERS_DIR "/etc/snapper/filters" +#define DEV_DIR "/dev" +#define DEV_MAPPER_DIR "/dev/mapper" + // keys from the config files diff --git a/snapper/SnapperTypes.h b/snapper/SnapperTypes.h index 6b482ce3..d1b6d491 100644 --- a/snapper/SnapperTypes.h +++ b/snapper/SnapperTypes.h @@ -29,8 +29,6 @@ #include #include -#include "snapper/Regex.h" - namespace snapper { @@ -38,13 +36,6 @@ namespace snapper using std::vector; - struct regex_matches - { - regex_matches(const Regex& t) : val(t) {} - bool operator()(const string& s) const { return val.match(s); } - const Regex& val; - }; - struct string_starts_with { string_starts_with(const string& t) : val(t) {} diff --git a/snapper/Snapshot.cc b/snapper/Snapshot.cc index f242d464..288bf269 100644 --- a/snapper/Snapshot.cc +++ b/snapper/Snapshot.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include #include "snapper/Snapshot.h" @@ -42,7 +43,6 @@ #include "snapper/SnapperTmpl.h" #include "snapper/SnapperDefines.h" #include "snapper/Exception.h" -#include "snapper/Regex.h" #include "snapper/Hooks.h" @@ -185,14 +185,14 @@ namespace snapper void Snapshots::read() { - Regex rx("^[0-9]+$"); + static const regex rx("[0-9]+", regex::extended); SDir infos_dir = snapper->openInfosDir(); vector infos = infos_dir.entries(); for (vector::const_iterator it1 = infos.begin(); it1 != infos.end(); ++it1) { - if (!rx.match(*it1)) + if (!regex_match(*it1, rx)) continue; try diff --git a/testsuite/sysconfig-get1.cc b/testsuite/sysconfig-get1.cc index 1ec0c73c..8fcbaadf 100644 --- a/testsuite/sysconfig-get1.cc +++ b/testsuite/sysconfig-get1.cc @@ -19,6 +19,9 @@ BOOST_AUTO_TEST_CASE(sysconfig_get1) BOOST_CHECK(s.getValue("S1", tmp_string)); BOOST_CHECK_EQUAL(tmp_string, "hello"); + BOOST_CHECK(s.getValue("S2", tmp_string)); + BOOST_CHECK_EQUAL(tmp_string, "hello"); + bool tmp_bool; BOOST_CHECK(s.getValue("B1", tmp_bool)); diff --git a/testsuite/sysconfig-get1.txt b/testsuite/sysconfig-get1.txt index 1bd059ef..fb26e41f 100644 --- a/testsuite/sysconfig-get1.txt +++ b/testsuite/sysconfig-get1.txt @@ -1,5 +1,6 @@ S1="hello" +S2=hello # this is a comment B1="yes" B2="no" diff --git a/zypp-plugin/Makefile.am b/zypp-plugin/Makefile.am index e1cff3fd..cdfc38c2 100644 --- a/zypp-plugin/Makefile.am +++ b/zypp-plugin/Makefile.am @@ -23,7 +23,7 @@ snapper_zypp_plugin_LDADD = \ ../dbus/libdbus.la \ $(JSONC_LIBS) -check_PROGRAMS = regex.test forwarding-zypp-plugin +check_PROGRAMS = solvable_matcher.test forwarding-zypp-plugin forwarding_zypp_plugin_SOURCES = \ forwarding_zypp_plugin.cc \ @@ -34,12 +34,12 @@ forwarding_zypp_plugin_LDADD = \ -lboost_system \ -lpthread -TESTS = regex.test +TESTS = solvable_matcher.test -regex_test_SOURCES = regex_test.cc \ +solvable_matcher_test_SOURCES = solvable_matcher_test.cc \ solvable_matcher.cc solvable_matcher.h -regex_test_LDADD = \ +solvable_matcher_test_LDADD = \ ../snapper/libsnapper.la \ $(XML2_LIBS) \ -lboost_unit_test_framework diff --git a/zypp-plugin/regex_test.cc b/zypp-plugin/regex_test.cc deleted file mode 100644 index 21ffe483..00000000 --- a/zypp-plugin/regex_test.cc +++ /dev/null @@ -1,32 +0,0 @@ -#define BOOST_TEST_DYN_LINK -#define BOOST_TEST_MODULE regex - -#include -#include "solvable_matcher.h" - -static -SolvableMatcher rx(const char* regex) { - bool is_important = false; - return SolvableMatcher(regex, SolvableMatcher::Kind::REGEX, is_important); -} - -BOOST_AUTO_TEST_CASE(regex) -{ - BOOST_CHECK(rx("mypkg").match("mypkg")); - BOOST_CHECK(!rx("mypkg").match("yourpkg")); - - // substrings don't count - BOOST_CHECK(!rx("foo").match("afool")); - // prefixes must match - BOOST_CHECK(rx("foo").match("fool")); - // explicit anchor is OK - BOOST_CHECK(rx("^foo").match("foo")); - // double anchor is also OK - BOOST_CHECK(rx("^^foo").match("foo")); - // exclude prefix matches - BOOST_CHECK(!rx("foo$").match("foo-devel")); - - SolvableMatcher ror = rx("ruby[.0-9]+-rubygem-active(model|record)"); - BOOST_CHECK(ror.match("ruby2.5-rubygem-activemodel-5.2")); - BOOST_CHECK(ror.match("ruby2.5-rubygem-activerecord-5_1")); -} diff --git a/zypp-plugin/snapper_zypp_plugin.cc b/zypp-plugin/snapper_zypp_plugin.cc index 7db0e7a8..238a196c 100644 --- a/zypp-plugin/snapper_zypp_plugin.cc +++ b/zypp-plugin/snapper_zypp_plugin.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -31,6 +31,7 @@ #include #include #include +#include using namespace std; #include @@ -40,7 +41,6 @@ using namespace std; #endif #include "dbus/DBusConnection.h" -#include "snapper/Regex.h" #include "snapper/Exception.h" using snapper::Exception; using snapper::CodeLocation; @@ -256,14 +256,19 @@ map SnapperZyppPlugin::get_userdata(const Message& msg) { const string& userdata_s = it->second; vector key_values; boost::split(key_values, userdata_s, boost::is_any_of(",")); - for (auto kv: key_values) { - static const snapper::Regex rx_keyval("^([^=]*)=(.+)$"); - if (rx_keyval.match(kv)) { - string key = boost::trim_copy(rx_keyval.cap(1)); - string value = boost::trim_copy(rx_keyval.cap(2)); + for (auto kv : key_values) + { + static const regex rx_keyval("([^=]*)=(.+)", regex::extended); + smatch match; + + if (regex_match(kv, match, rx_keyval)) + { + string key = boost::trim_copy(match[1].str()); + string value = boost::trim_copy(match[2].str()); result[key] = value; } - else { + else + { cerr << "ERROR:" << "invalid userdata: expecting comma separated key=value pairs" << endl; } } diff --git a/zypp-plugin/solvable_matcher.cc b/zypp-plugin/solvable_matcher.cc index 53cb5561..61a93ec8 100644 --- a/zypp-plugin/solvable_matcher.cc +++ b/zypp-plugin/solvable_matcher.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -24,11 +24,11 @@ #include #include #include +#include using namespace std; // fnmatch #include -#include "snapper/Regex.h" #include "snapper/XmlFile.h" using namespace snapper; @@ -44,11 +44,19 @@ bool SolvableMatcher::match(const string& solvable) const { static const int flags = 0; res = fnmatch(pattern.c_str(), solvable.c_str(), flags) == 0; } - else { - // POSIX Extended Regular Expression Syntax - // The original Python implementation allows "foo" to match "foo-devel" - snapper::Regex rx_pattern("^" + pattern, REG_EXTENDED | REG_NOSUB); - res = rx_pattern.match(solvable); + else + { + try + { + // POSIX Extended Regular Expression Syntax + // The original Python implementation allows "foo" to match "foo-devel" + const regex rx_pattern("^" + pattern, regex::extended); + res = regex_search(solvable, rx_pattern); + } + catch (const regex_error& e) + { + throw std::runtime_error(string("Regex compilation error: ") + e.what()); + } } log << "DEBUG:" << "-> " << res << endl; return res; diff --git a/zypp-plugin/solvable_matcher.h b/zypp-plugin/solvable_matcher.h index 1da22ce3..b345ed07 100644 --- a/zypp-plugin/solvable_matcher.h +++ b/zypp-plugin/solvable_matcher.h @@ -33,7 +33,7 @@ struct SolvableMatcher { }; std::string pattern; Kind kind; - bool important; + bool important = false; static std::ostream& log; SolvableMatcher(const std::string& apattern, Kind akind, bool aimportant) diff --git a/zypp-plugin/solvable_matcher_test.cc b/zypp-plugin/solvable_matcher_test.cc new file mode 100644 index 00000000..77cf9c89 --- /dev/null +++ b/zypp-plugin/solvable_matcher_test.cc @@ -0,0 +1,55 @@ +#define BOOST_TEST_DYN_LINK +#define BOOST_TEST_MODULE regex + +#include +#include "solvable_matcher.h" + + +static +SolvableMatcher make_glob(const char* regex) +{ + bool is_important = false; + return SolvableMatcher(regex, SolvableMatcher::Kind::GLOB, is_important); +} + + +BOOST_AUTO_TEST_CASE(glob) +{ + BOOST_CHECK(make_glob("glibc").match("glibc")); + BOOST_CHECK(!make_glob("glibc").match("libc")); + BOOST_CHECK(!make_glob("glibc").match("glibc-locale")); + + BOOST_CHECK(make_glob("glibc*").match("glibc")); + BOOST_CHECK(make_glob("glibc*").match("glibc-locale")); + BOOST_CHECK(!make_glob("glibc*").match("libc")); +} + + +static +SolvableMatcher make_rx(const char* regex) +{ + bool is_important = false; + return SolvableMatcher(regex, SolvableMatcher::Kind::REGEX, is_important); +} + + +BOOST_AUTO_TEST_CASE(regex) +{ + BOOST_CHECK(make_rx("mypkg").match("mypkg")); + BOOST_CHECK(!make_rx("mypkg").match("yourpkg")); + + // substrings don't count + BOOST_CHECK(!make_rx("foo").match("afool")); + // prefixes must match + BOOST_CHECK(make_rx("foo").match("fool")); + // explicit anchor is OK + BOOST_CHECK(make_rx("^foo").match("foo")); + // double anchor is also OK + BOOST_CHECK(make_rx("^^foo").match("foo")); + // exclude prefix matches + BOOST_CHECK(!make_rx("foo$").match("foo-devel")); + + SolvableMatcher ror = make_rx("ruby[.0-9]+-rubygem-active(model|record)"); + BOOST_CHECK(ror.match("ruby2.5-rubygem-activemodel-5.2")); + BOOST_CHECK(ror.match("ruby2.5-rubygem-activerecord-5_1")); +} diff --git a/zypp-plugin/zypp_plugin.cc b/zypp-plugin/zypp_plugin.cc index 97be4bee..430cb908 100644 --- a/zypp-plugin/zypp_plugin.cc +++ b/zypp-plugin/zypp_plugin.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 SUSE LLC + * Copyright (c) [2019-2020] SUSE LLC * * All Rights Reserved. * @@ -22,9 +22,9 @@ #include #include #include +#include using namespace std; -#include "snapper/Regex.h" #include "zypp_plugin.h" int ZyppPlugin::main() { @@ -70,13 +70,15 @@ ZyppPlugin::Message ZyppPlugin::read_message(istream& is) { if (line.empty()) continue; - static const snapper::Regex rx_word("^[A-Za-z0-9_]+$"); - if (rx_word.match(line)) { + static const regex rx_word("[A-Za-z0-9_]+", regex::extended); + if (regex_match(line, rx_word)) + { msg = Message(); msg.command = line; state = State::Headers; } - else { + else + { throw runtime_error("Plugin protocol error: expected a command. Got '" + line + "'"); } } @@ -87,14 +89,19 @@ ZyppPlugin::Message ZyppPlugin::read_message(istream& is) { return msg; } - else { - static const snapper::Regex rx_header("^([A-Za-z0-9_]+):[ \t]*(.+)$"); - if (rx_header.match(line)) { - string key = rx_header.cap(1); - string value = rx_header.cap(2); + else + { + static const regex rx_header("([A-Za-z0-9_]+):[ \t]*(.+)", regex::extended); + smatch match; + + if (regex_match(line, match, rx_header)) + { + string key = match[1]; + string value = match[2]; msg.headers[key] = value; } - else { + else + { throw runtime_error("Plugin protocol error: expected a header or new line. Got '" + line + "'"); } }