Clean-up: reimplement the SeachPathSplitter

...to be more compliant to the »Lumiera Forward Iterator« concept.
This can be easily achieved by inheriting from util::RegexSearchIter,
similar to the example in CSV.hpp

Regarding #896, I changed the string rendering to use fs::path::generic_string
where appropriate, which means that we're using the normalised path rendering
This commit is contained in:
Fischlurch 2025-04-28 19:14:27 +02:00
parent c5292dd0dd
commit 998e225490
9 changed files with 97 additions and 84 deletions

View file

@ -54,7 +54,7 @@ namespace lumiera {
string
resolve (fs::path iniSpec)
{
string searchpath = iniSpec.parent_path().string(); ///////////TICKET #896
string searchpath = iniSpec.parent_path().generic_string();
return resolveModulePath (iniSpec.filename(), searchpath);
}

View file

@ -35,6 +35,8 @@
#include "include/config-facade.h"
#include "common/appstate.hpp"
#include "lib/searchpath.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/format-util.hpp"
#include "lib/util.hpp"
extern "C" {
@ -130,18 +132,11 @@ extern "C" { /* ==== implementation C interface for accessing setup.ini =======
const char*
lumiera_get_plugin_path_default ()
{
static string pathSpec;
if (isnil (pathSpec))
{
pathSpec += "plugin.path="; // syntax expected by lumiera_config_setdefault
// fetch plugin search path from setup.ini and expand any $ORIGIN token
SearchPathSplitter pathElement(Config::get (KEY_PLUGIN_PATH));
while (pathElement)
pathSpec += pathElement.next() +":";
}
{ // Meyer's Singleton...
static string pathSpec = []{ string pluginPath = Config::get (KEY_PLUGIN_PATH);
return "plugin.path=" // syntax expected by lumiera_config_setdefault
+ util::join (SearchPathSplitter{pluginPath}, ":");
}();
return cStr(pathSpec);
}
}

View file

@ -19,6 +19,7 @@
#include "lib/error.hpp"
#include "lib/searchpath.hpp"
#include "lib/format-string.hpp"
#include "lib/symbol.hpp"
@ -31,10 +32,11 @@
namespace lib {
using util::_Fmt;
using std::regex;
using std::regex_replace;
const regex SearchPathSplitter::EXTRACT_PATHSPEC ("[^:]+");
const regex SearchPathSplitter::ACCEPT_PATHELEMENT{"(^|:)\\s*([^:]+)", regex::optimize};
/** @internal helper to figure out the installation directory,
@ -57,9 +59,9 @@ namespace lib {
string
replaceMagicLinkerTokens (string const& src)
{
static const regex PICK_ORIGIN_TOKEN ("\\$?ORIGIN/?");
static const regex PICK_ORIGIN_TOKEN{"\\$?ORIGIN/?", regex::optimize};
static const string expandedOriginDir
= findExePath().parent_path().string() + "/"; ///////////TICKET #896
= findExePath().parent_path().generic_string() + "/";
return regex_replace (src, PICK_ORIGIN_TOKEN, expandedOriginDir);
}
@ -72,20 +74,21 @@ namespace lib {
resolveModulePath (fs::path moduleName, string searchPath)
{
fs::path modulePathName (moduleName);
SearchPathSplitter searchLocation(searchPath); ///////////TICKET #896
SearchPathSplitter searchLocation(searchPath);
while (not fs::exists (modulePathName))
{
// try / continue search path
if (searchLocation.isValid())
modulePathName = fs::path() / searchLocation.next() / moduleName;
else
throw error::Config ("Module \""+moduleName.string()+"\" not found" /////TICKET #896
+ (searchPath.empty()? ".":" in search path: "+searchPath));
if (not searchLocation)
throw error::Config{_Fmt{"Module %s not found%s"}
% moduleName
%(searchPath.empty()? ".":" in search path: "+searchPath)};
modulePathName = *searchLocation / moduleName;
++searchLocation;
}
TRACE (config, "found module %s", modulePathName.string().c_str());
return modulePathName.string(); ///////////TICKET #896
TRACE (config, "found module %s", cStr(modulePathName.generic_string()));
return modulePathName.generic_string();
}

View file

@ -30,6 +30,7 @@
#include "lib/file.hpp"
#include <string>
#include <boost/algorithm/string.hpp>
namespace lib {
@ -56,42 +57,35 @@ namespace lib {
* This iterator class dissects a ':'-separated path list. The individual
* components may use the symbol \c $ORIGIN to refer to the directory
* holding the current executable.
* @note #next picks the current component and advances the iteration.
*/
class SearchPathSplitter
: util::NonCopyable
: public util::RegexSearchIter
{
string pathSpec_;
std::sregex_iterator pos_,
end_;
static const std::regex EXTRACT_PATHSPEC;
static const regex ACCEPT_PATHELEMENT;
public:
SearchPathSplitter (string const& searchPath)
: pathSpec_(replaceMagicLinkerTokens (searchPath))
, pos_(pathSpec_.begin(),pathSpec_.end(), EXTRACT_PATHSPEC)
, end_()
SearchPathSplitter() = default;
SearchPathSplitter (string& searchPath) ///< @warning search path string must exist somewhere else
: RegexSearchIter{searchPath, ACCEPT_PATHELEMENT}
{ }
explicit operator bool() const { return isValid(); }
LIFT_PARENT_INCREMENT_OPERATOR (std::sregex_iterator);
ENABLE_USE_IN_STD_RANGE_FOR_LOOPS (SearchPathSplitter);
bool
isValid() const
{
return pos_ != end_;
}
using value_type = std::string;
using reference = value_type&;
using pointer = value_type*;
string
next ()
operator*() const
{
if (!isValid())
throw error::Logic ("Search path exhausted."
,LERR_(ITER_EXHAUST));
string currentPathElement = pos_->str();
++pos_;
return currentPathElement;
string pathElm = util::RegexSearchIter::operator*()[2];
pathElm = boost::algorithm::trim_right_copy(pathElm);
return replaceMagicLinkerTokens (pathElm);
}
};

View file

@ -41,6 +41,7 @@
#include <boost/lexical_cast.hpp>
#include <typeinfo>
#include <cstdlib>
#include <utility>
#include <limits>
#include <string>
#include <cmath>
@ -327,8 +328,13 @@ namespace test{
class ExpectString
: public std::string
{
public:
using std::string::string;
ExpectString(std::string && s) : std::string{std::move(s)}{ }
ExpectString(std::string const& s) : std::string{s} { }
template<typename X>
friend bool
operator== (X const& x, ExpectString const& expected)

View file

@ -262,10 +262,10 @@ namespace workspace {
return true;
// Try to resolve the icon via the configured search path
lib::SearchPathSplitter iconLocations (iconSearchPath_);
while (iconLocations)
lib::SearchPathSplitter iconLocations{iconSearchPath_};
for (auto const& location : iconLocations)
if (addNonThemeIconSource (icon_set
,iconLocations.next()
,location
,icon_name
,size
,wildcard))

View file

@ -624,17 +624,17 @@ END
TEST "Search path walking" SearchPathSplitter_test <<END
out-lit: ➢➢a
out-lit: ➢➢a
out-lit: ➢➢a
out-lit: ➢➢b
out-lit: ➢➢a
out-lit: ➢➢b
out-lit: ➢➢c
out: ➢➢.d.
out-lit: ➢➢ e f
out-lit: ➢➢/usr/bin
out-lit: ➢➢/usr/lib
out-lit: ▶a◀
out-lit: ▶a◀
out-lit: ▶a◀
out-lit: ▶b◀
out-lit: ▶a◀
out-lit: ▶b◀
out-lit: ▶c◀
out-lit: ▶d◀
out-lit: ▶e f◀
out-lit: ▶/usr/bin◀
out-lit: ▶/usr/lib◀
return: 0
END

View file

@ -20,11 +20,12 @@
#include "lib/test/test-helper.hpp"
#include "lib/format-cout.hpp"
#include "lib/file.hpp"
#include "lib/util.hpp"
#include "lib/searchpath.hpp"
using util::isnil;
namespace lib {
namespace test {
@ -54,20 +55,21 @@ namespace test {
walk ("a:");
walk (":a");
walk ("a:b");
walk (":a:b:c:");
walk (" d : e f");
walk (":a:b\n:c:");
walk (" d : e f ");
walk ("/usr/bin:/usr/lib");
SearchPathSplitter sp("");
VERIFY_ERROR (ITER_EXHAUST, sp.next() );
SearchPathSplitter sp{};
CHECK (not sp);
VERIFY_ERROR (ITER_EXHAUST, *sp );
}
void
walk (string spec)
{
SearchPathSplitter path(spec);
while (path)
cout << "➢➢" << path.next() << endl;
SearchPathSplitter path{spec};
for (auto const& pathElm : path)
cout <<""<< pathElm <<""<< endl;
}
@ -78,11 +80,15 @@ namespace test {
fs::path exePath{findExePath()};
string expected{exePath.parent_path() / "modules"};
SearchPathSplitter sp("xyz:$ORIGIN/modules:abc");
CHECK ("xyz" == sp.next());
CHECK (sp.next() == expected);
CHECK ("abc" == sp.next());
CHECK (!sp.isValid());
string searchSpec = "xyz:$ORIGIN/modules:abc";
SearchPathSplitter sp{searchSpec};
CHECK (*sp == "xyz"_expect);
++sp;
CHECK (*sp == ExpectString{expected});
++sp;
CHECK (*sp == "abc"_expect);
++sp;
CHECK (isnil (sp));
}
};

View file

@ -158172,8 +158172,7 @@ unsigned int ThreadIdAsInt = *static_cast&lt;unsigned int*&gt;(static_cast&lt;vo
d.h. je nachdem, was man machen m&#246;chte: Skalieren, Positionieren, Farbraum-Mapping
</p>
</body>
</html>
</richcontent>
</html></richcontent>
</node>
<node CREATED="1745790970318" ID="ID_89388403" MODIFIED="1745790990806" TEXT="Device-Driver f&#xfc;r Video-Controller und X-Server m&#xfc;ssen XV unterst&#xfc;tzen"/>
</node>
@ -161391,8 +161390,8 @@ Since then others have made contributions, see the log for the history.</font></
</node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175611912" ID="ID_16098937" MODIFIED="1742175617591" TEXT="etwas aufr&#xe4;umen">
<icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175621250" ID="ID_1886919024" MODIFIED="1742175634845" TEXT="boost-filesystem loswerden!">
<icon BUILTIN="flag-yellow"/>
<node COLOR="#338800" CREATED="1742175621250" FOLDED="true" ID="ID_1886919024" MODIFIED="1745860228467" TEXT="boost-filesystem loswerden!">
<icon BUILTIN="button_ok"/>
<node CREATED="1744754918427" ID="ID_368377472" MODIFIED="1745799970522" TEXT="lib/searchpath.hpp">
<linktarget COLOR="#a9b4c1" DESTINATION="ID_368377472" ENDARROW="Default" ENDINCLINATION="47;6;" ID="Arrow_ID_1410738800" SOURCE="ID_883309222" STARTARROW="None" STARTINCLINATION="54;6;"/>
<linktarget COLOR="#a9b4c1" DESTINATION="ID_368377472" ENDARROW="Default" ENDINCLINATION="107;14;" ID="Arrow_ID_1432393919" SOURCE="ID_1713220396" STARTARROW="None" STARTINCLINATION="74;7;"/>
@ -161439,19 +161438,29 @@ Since then others have made contributions, see the log for the history.</font></
</node>
</node>
</node>
<node CREATED="1745800050780" ID="ID_53680199" MODIFIED="1745800058623" TEXT="Impl. verwendet SearchPatchSplitter">
<node CREATED="1745800059996" ID="ID_1732566176" MODIFIED="1745800114759" TEXT="dies ist ein &#xbb;Iterator&#xab; &#x2014; aber kein Lumiera Forward Iterator">
<node COLOR="#435e98" CREATED="1745800050780" ID="ID_53680199" MODIFIED="1745860206848" TEXT="Impl. verwendet SearchPatchSplitter">
<icon BUILTIN="messagebox_warning"/>
<node CREATED="1745800193650" ID="ID_490272268" MODIFIED="1745850089541" TEXT="nimmt einen boost::fsys::path in den ctor"/>
<node CREATED="1745800146421" ID="ID_274063300" MODIFIED="1745800186494" TEXT="wird noch vewendet von configfacade.cpp und ui-style.cpp"/>
<node COLOR="#338800" CREATED="1745800059996" ID="ID_1732566176" MODIFIED="1745860210862" TEXT="dies ist ein &#xbb;Iterator&#xab; &#x2014; aber kein Lumiera Forward Iterator">
<richcontent TYPE="NOTE"><html>
<head>
</head>
<body>
<p>
...das war vermutlich mein erster Versuch, eine Iterator-Klasse in C++ zu bauen.
...das war vermutlich mein erster Versuch, eine Iterator-Klasse in C++ zu bauen &#8212; hatte mich dabei offensichtlich an Java orientiert
</p>
</body>
</html></richcontent>
</html>
</richcontent>
<icon BUILTIN="button_ok"/>
<node CREATED="1745850122914" ID="ID_1543137724" MODIFIED="1745850144722" TEXT="inzwischen k&#xf6;nnen &#x201e;wir&#x201c; das vieeel besser"/>
<node CREATED="1745850145440" ID="ID_1260012350" MODIFIED="1745850185900" TEXT="der RegexpSearchIter bietet sich da gradezu an (&#x27f6; siehe CSV.hpp)"/>
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1745859667169" ID="ID_161905722" MODIFIED="1745859694033" TEXT="Vorsicht: Regexp-Search verweist in bestehenden String">
<icon BUILTIN="clanbomber"/>
</node>
</node>
<node CREATED="1745800146421" ID="ID_274063300" MODIFIED="1745800186494" TEXT="wird noch vewendet von configfacade.cpp und ui-style.cpp"/>
<node CREATED="1745800193650" ID="ID_490272268" MODIFIED="1745800204496" TEXT="nimmt einen boost::fsys::path in den ctor"/>
</node>
</node>
</node>