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 string
resolve (fs::path iniSpec) resolve (fs::path iniSpec)
{ {
string searchpath = iniSpec.parent_path().string(); ///////////TICKET #896 string searchpath = iniSpec.parent_path().generic_string();
return resolveModulePath (iniSpec.filename(), searchpath); return resolveModulePath (iniSpec.filename(), searchpath);
} }

View file

@ -35,6 +35,8 @@
#include "include/config-facade.h" #include "include/config-facade.h"
#include "common/appstate.hpp" #include "common/appstate.hpp"
#include "lib/searchpath.hpp" #include "lib/searchpath.hpp"
#include "lib/iter-explorer.hpp"
#include "lib/format-util.hpp"
#include "lib/util.hpp" #include "lib/util.hpp"
extern "C" { extern "C" {
@ -130,18 +132,11 @@ extern "C" { /* ==== implementation C interface for accessing setup.ini =======
const char* const char*
lumiera_get_plugin_path_default () lumiera_get_plugin_path_default ()
{ { // Meyer's Singleton...
static string pathSpec; static string pathSpec = []{ string pluginPath = Config::get (KEY_PLUGIN_PATH);
if (isnil (pathSpec)) return "plugin.path=" // syntax expected by lumiera_config_setdefault
{ + util::join (SearchPathSplitter{pluginPath}, ":");
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() +":";
}
return cStr(pathSpec); return cStr(pathSpec);
} }
} }

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,11 +20,12 @@
#include "lib/test/test-helper.hpp" #include "lib/test/test-helper.hpp"
#include "lib/format-cout.hpp" #include "lib/format-cout.hpp"
#include "lib/file.hpp" #include "lib/file.hpp"
#include "lib/util.hpp"
#include "lib/searchpath.hpp" #include "lib/searchpath.hpp"
using util::isnil;
namespace lib { namespace lib {
namespace test { namespace test {
@ -54,20 +55,21 @@ namespace test {
walk ("a:"); walk ("a:");
walk (":a"); walk (":a");
walk ("a:b"); walk ("a:b");
walk (":a:b:c:"); walk (":a:b\n:c:");
walk (" d : e f"); walk (" d : e f ");
walk ("/usr/bin:/usr/lib"); walk ("/usr/bin:/usr/lib");
SearchPathSplitter sp(""); SearchPathSplitter sp{};
VERIFY_ERROR (ITER_EXHAUST, sp.next() ); CHECK (not sp);
VERIFY_ERROR (ITER_EXHAUST, *sp );
} }
void void
walk (string spec) walk (string spec)
{ {
SearchPathSplitter path(spec); SearchPathSplitter path{spec};
while (path) for (auto const& pathElm : path)
cout << "➢➢" << path.next() << endl; cout <<"▶"<< pathElm <<"◀"<< endl;
} }
@ -78,11 +80,15 @@ namespace test {
fs::path exePath{findExePath()}; fs::path exePath{findExePath()};
string expected{exePath.parent_path() / "modules"}; string expected{exePath.parent_path() / "modules"};
SearchPathSplitter sp("xyz:$ORIGIN/modules:abc"); string searchSpec = "xyz:$ORIGIN/modules:abc";
CHECK ("xyz" == sp.next()); SearchPathSplitter sp{searchSpec};
CHECK (sp.next() == expected); CHECK (*sp == "xyz"_expect);
CHECK ("abc" == sp.next()); ++sp;
CHECK (!sp.isValid()); 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 d.h. je nachdem, was man machen m&#246;chte: Skalieren, Positionieren, Farbraum-Mapping
</p> </p>
</body> </body>
</html> </html></richcontent>
</richcontent>
</node> </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 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> </node>
@ -161391,8 +161390,8 @@ Since then others have made contributions, see the log for the history.</font></
</node> </node>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175611912" ID="ID_16098937" MODIFIED="1742175617591" TEXT="etwas aufr&#xe4;umen"> <node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175611912" ID="ID_16098937" MODIFIED="1742175617591" TEXT="etwas aufr&#xe4;umen">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="flag-yellow"/>
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1742175621250" ID="ID_1886919024" MODIFIED="1742175634845" TEXT="boost-filesystem loswerden!"> <node COLOR="#338800" CREATED="1742175621250" FOLDED="true" ID="ID_1886919024" MODIFIED="1745860228467" TEXT="boost-filesystem loswerden!">
<icon BUILTIN="flag-yellow"/> <icon BUILTIN="button_ok"/>
<node CREATED="1744754918427" ID="ID_368377472" MODIFIED="1745799970522" TEXT="lib/searchpath.hpp"> <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="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;"/> <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>
</node> </node>
<node CREATED="1745800050780" ID="ID_53680199" MODIFIED="1745800058623" TEXT="Impl. verwendet SearchPatchSplitter"> <node COLOR="#435e98" CREATED="1745800050780" ID="ID_53680199" MODIFIED="1745860206848" 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"> <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> <richcontent TYPE="NOTE"><html>
<head> <head>
</head>
<body> <body>
<p> <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> </p>
</body> </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>
<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> </node>
</node> </node>