Merge pull request #267 from KLayout/bugfixes_and_enhancements

Bugfixes and enhancements
This commit is contained in:
Matthias Köfferlein 2019-05-21 00:43:43 +02:00 committed by GitHub
commit 644390e571
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 1005 additions and 221 deletions

View File

@ -31,9 +31,9 @@ HEADERS = \
RESOURCES = \
INCLUDEPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb
INCLUDEPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC $$LYM_INC
DEPENDPATH += $$TL_INC $$GSI_INC $$VERSION_INC $$DB_INC $$LIB_INC $$RDB_INC $$LYM_INC
LIBS += -L$$DESTDIR -lklayout_tl -lklayout_db -lklayout_gsi -lklayout_lib -lklayout_rdb -lklayout_lym
INCLUDEPATH += $$RBA_INC
DEPENDPATH += $$RBA_INC

View File

@ -34,6 +34,7 @@
#include "gsiExpression.h"
#include "libForceLink.h"
#include "rdbForceLink.h"
#include "lymMacro.h"
struct RunnerData
{
@ -92,14 +93,7 @@ BD_PUBLIC int strmrun (int argc, char *argv[])
std::string script = tl::absolute_file_path (data.script);
std::string ext = tl::extension (data.script);
if (ext == "py") {
python.load_file (script);
} else if (ext == "rb") {
ruby.load_file (script);
} else {
throw tl::Exception (tl::to_string (tr ("Unknown suffix \"%s\" - must be either .rb or .py")), ext);
}
return 0;
lym::Macro macro;
macro.load_from (script);
return macro.run ();
}

View File

@ -70,6 +70,11 @@ static void technologies_from_xml (const std::string &s)
db::Technologies::instance ()->load_from_xml (s);
}
static void clear_technologies ()
{
db::Technologies::instance ()->clear ();
}
static db::Technology technology_from_xml (const std::string &s)
{
db::Technology tech;
@ -289,6 +294,11 @@ gsi::Class<db::Technology> technology_decl ("db", "Technology",
"\n"
"\\technology_from_xml can be used to restore the technology definition."
) +
gsi::method ("clear_technologies", &clear_technologies,
"@brief Clears all technologies\n"
"\n"
"This method has been introduced in version 0.26.\n"
) +
gsi::method ("technologies_from_xml", &technologies_from_xml, gsi::arg ("xml"),
"@brief Loads the technologies from a XML representation\n"
"\n"

View File

@ -26,6 +26,7 @@
#include "tlTimer.h"
#include "tlProgress.h"
#include "tlExpression.h"
#include "tlGlobPattern.h"
// ----------------------------------------------------------------
// Logger binding
@ -557,6 +558,85 @@ Class<ExpressionWrapper> decl_ExpressionWrapper ("tl", "Expression",
"This class has been introduced in version 0.25.\n"
);
static tl::GlobPattern *new_glob_pattern (const std::string &s)
{
return new tl::GlobPattern (s);
}
namespace {
template <class Iter>
struct to_var_iterator
: public Iter
{
typedef typename Iter::value_type original_value_type;
typedef typename tl::Variant *pointer;
typedef typename tl::Variant &reference;
typedef typename Iter::difference_type difference_type;
to_var_iterator (const Iter &iter)
: Iter (iter)
{ }
pointer operator-> ()
{
m_var = tl::Variant (Iter::operator* ());
return &m_var;
}
reference operator* ()
{
m_var = tl::Variant (Iter::operator* ());
return m_var;
}
private:
tl::Variant m_var;
};
}
static tl::Variant match (const tl::GlobPattern *pattern, const std::string &s)
{
std::vector<std::string> brackets;
if (pattern->match (s, brackets)) {
return tl::Variant (to_var_iterator<std::vector<std::string>::const_iterator> (brackets.begin ()), to_var_iterator<std::vector<std::string>::const_iterator> (brackets.end ()));
} else {
return tl::Variant ();
}
}
Class<tl::GlobPattern> decl_GlobPattern ("tl", "GlobPattern",
gsi::constructor ("new", &new_glob_pattern, gsi::arg ("pattern"),
"@brief Creates a new glob pattern match object\n"
) +
gsi::method ("case_sensitive=", &tl::GlobPattern::set_case_sensitive, gsi::arg ("case_sensitive"),
"@brief Sets a value indicating whether the glob pattern match is case sensitive."
) +
gsi::method ("case_sensitive", &tl::GlobPattern::case_sensitive,
"@brief Gets a value indicating whether the glob pattern match is case sensitive."
) +
gsi::method ("head_match=", &tl::GlobPattern::set_header_match, gsi::arg ("head_match"),
"@brief Sets a value indicating whether trailing characters are allowed.\n"
"If this predicate is false, the glob pattern needs to match the full subject string. "
"If true, the match function will ignore trailing characters and return true if the "
"front part of the subject string matches."
) +
gsi::method ("head_match", &tl::GlobPattern::header_match,
"@brief Gets a value indicating whether trailing characters are allowed.\n"
) +
gsi::method_ext ("match", &match, gsi::arg ("subject"),
"@brief Matches the subject string against the pattern.\n"
"Returns nil if the subject string does not match the pattern. Otherwise returns a list "
"with the substrings captured in round brackets."
),
"@brief A glob pattern matcher\n"
"This class is provided to make KLayout's glob pattern matching available to scripts too. "
"The intention is to provide an implementation which is compatible with KLayout's pattern "
"syntax.\n"
"\n"
"This class has been introduced in version 0.26."
);
}

View File

@ -308,6 +308,16 @@ std::string extension (const std::string &s)
return tl::join (fnp, ".");
}
std::string extension_last (const std::string &s)
{
std::vector<std::string> fnp = split_filename (filename (s));
if (fnp.size () > 1) {
return fnp.back ();
} else {
return std::string ();
}
}
bool
is_parent_path (const std::string &parent, const std::string &path)
{

View File

@ -90,6 +90,11 @@ std::string TL_PUBLIC basename (const std::string &s);
*/
std::string TL_PUBLIC extension (const std::string &s);
/**
* @brief Gets the last extension for a given file path
*/
std::string TL_PUBLIC extension_last (const std::string &s);
/**
* @brief Returns true, if the given path exists
* If the path is a directory, file_exists will return true, if the directory exists.

File diff suppressed because it is too large Load Diff

View File

@ -32,6 +32,8 @@
namespace tl
{
class GlobPatternOp;
/**
* @brief A class representing a glob pattern
*/
@ -51,14 +53,20 @@ public:
*/
GlobPattern (const std::string &p);
/**
* @brief Copy constructor
*/
GlobPattern (const GlobPattern &other);
/**
* @brief Assignment
*/
GlobPattern &operator= (const GlobPattern &other);
/**
* @brief Assignment of a string
*/
GlobPattern &operator= (const std::string &p)
{
m_p = p;
return *this;
}
GlobPattern &operator= (const std::string &s);
/**
* @brief Sets a value indicating whether to treat the match case sensitive
@ -124,9 +132,15 @@ public:
private:
std::string m_p;
GlobPatternOp *mp_op;
bool m_case_sensitive;
bool m_exact;
bool m_header_match;
bool m_needs_compile;
void do_compile ();
void needs_compile ();
GlobPatternOp *op () const;
};
} // namespace tl

View File

@ -46,7 +46,7 @@ static std::locale c_locale ("C");
#include "utf_casefolding.h"
wchar_t wdowncase (wchar_t c)
static inline wchar_t wdowncase (wchar_t c)
{
int ch = c >> 8;
if (ch >= 0 && ch < int (sizeof (uc_tab) / sizeof (uc_tab[0])) && uc_tab[ch]) {
@ -56,7 +56,7 @@ wchar_t wdowncase (wchar_t c)
}
}
wchar_t wupcase (wchar_t c)
static inline wchar_t wupcase (wchar_t c)
{
int ch = c >> 8;
if (ch >= 0 && ch < int (sizeof (lc_tab) / sizeof (lc_tab[0])) && lc_tab[ch]) {
@ -66,7 +66,7 @@ wchar_t wupcase (wchar_t c)
}
}
uint32_t utf32_downcase (uint32_t c32)
static inline uint32_t utf32_downcase (uint32_t c32)
{
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
return c32;
@ -75,7 +75,8 @@ uint32_t utf32_downcase (uint32_t c32)
}
}
uint32_t utf32_upcase (uint32_t c32)
/* Not used yet:
static inline uint32_t utf32_upcase (uint32_t c32)
{
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
return c32;
@ -83,6 +84,7 @@ uint32_t utf32_upcase (uint32_t c32)
return uint32_t (wupcase (wchar_t (c32)));
}
}
*/
// -------------------------------------------------------------------------
// Conversion of UTF8 to wchar_t

View File

@ -391,6 +391,13 @@ TEST (10)
EXPECT_EQ (tl::extension ("\\hello\\.world.gz"), "gz");
EXPECT_EQ (tl::extension ("/hello//world/"), "");
EXPECT_EQ (tl::extension_last ("/hello/world"), "");
EXPECT_EQ (tl::extension_last ("/hello/world.tar"), "tar");
EXPECT_EQ (tl::extension_last ("/hello/world.tar.gz"), "gz");
EXPECT_EQ (tl::extension_last ("\\hello\\.world"), "");
EXPECT_EQ (tl::extension_last ("\\hello\\.world.gz"), "gz");
EXPECT_EQ (tl::extension_last ("/hello//world/"), "");
EXPECT_EQ (tl::is_absolute ("world"), false);
EXPECT_EQ (tl::is_absolute ("world/"), false);
EXPECT_EQ (tl::is_absolute ("hello//world/"), false);

View File

@ -51,6 +51,16 @@ TEST(2)
EXPECT_EQ (a.match ("bad"), true);
EXPECT_EQ (a.match ("dba"), true);
// copy works too ...
tl::GlobPattern aa = a;
EXPECT_EQ (aa.match ("abc"), true);
EXPECT_EQ (aa.match ("a"), true);
EXPECT_EQ (aa.match (""), false);
EXPECT_EQ (aa.match ("bcd"), false);
EXPECT_EQ (aa.match ("bad"), true);
EXPECT_EQ (aa.match ("dba"), true);
EXPECT_EQ (b.match ("abc"), false);
EXPECT_EQ (b.match ("a"), false);
EXPECT_EQ (b.match (""), false);
@ -72,6 +82,14 @@ TEST(3)
EXPECT_EQ (a.match ("had"), true);
EXPECT_EQ (a.match ("hax"), false);
// copy works too ...
tl::GlobPattern aa = a;
EXPECT_EQ (aa.match ("ab"), true);
EXPECT_EQ (aa.match ("a"), false);
EXPECT_EQ (aa.match ("had"), true);
EXPECT_EQ (aa.match ("hax"), false);
tl::GlobPattern b ("a[0-9\\abcdef]");
EXPECT_EQ (b.match ("a0"), true);
@ -89,6 +107,14 @@ TEST(4)
EXPECT_EQ (a.match ("a"), false);
EXPECT_EQ (a.match ("had"), false);
EXPECT_EQ (a.match ("hax"), true);
// copy works too ...
tl::GlobPattern aa = a;
EXPECT_EQ (aa.match ("ab"), false);
EXPECT_EQ (aa.match ("a"), false);
EXPECT_EQ (aa.match ("had"), false);
EXPECT_EQ (aa.match ("hax"), true);
}
TEST(5)
@ -102,6 +128,17 @@ TEST(5)
EXPECT_EQ (a.match ("abx"), true);
EXPECT_EQ (a.match ("ax"), false);
EXPECT_EQ (a.match ("hadx"), true);
// copy works too ...
tl::GlobPattern aa = a;
EXPECT_EQ (aa.match ("ab"), true);
EXPECT_EQ (aa.match ("a"), false);
EXPECT_EQ (aa.match ("had"), true);
EXPECT_EQ (aa.match ("abx"), true);
EXPECT_EQ (aa.match ("ax"), false);
EXPECT_EQ (aa.match ("hadx"), true);
}
TEST(6)
@ -114,9 +151,52 @@ TEST(6)
EXPECT_EQ (a.match ("abch"), false);
EXPECT_EQ (a.match ("adh"), false);
EXPECT_EQ (a.match ("ah"), false);
// copy works too ...
tl::GlobPattern aa = a;
EXPECT_EQ (aa.match ("abcg"), true);
EXPECT_EQ (aa.match ("adg"), true);
EXPECT_EQ (aa.match ("ag"), false);
EXPECT_EQ (aa.match ("abch"), false);
EXPECT_EQ (aa.match ("adh"), false);
EXPECT_EQ (aa.match ("ah"), false);
}
TEST(7)
{
tl::GlobPattern a ("a{bc*,d?}g");
EXPECT_EQ (a.match ("abcg"), true);
EXPECT_EQ (a.match ("adg"), false);
EXPECT_EQ (a.match ("adxg"), true);
EXPECT_EQ (a.match ("adxyg"), false);
EXPECT_EQ (a.match ("ag"), false);
EXPECT_EQ (a.match ("abch"), false);
EXPECT_EQ (a.match ("abcg"), true);
EXPECT_EQ (a.match ("abchg"), true);
EXPECT_EQ (a.match ("abchhg"), true);
EXPECT_EQ (a.match ("adh"), false);
EXPECT_EQ (a.match ("ah"), false);
// copy works too ...
tl::GlobPattern aa = a;
EXPECT_EQ (aa.match ("abcg"), true);
EXPECT_EQ (aa.match ("adg"), false);
EXPECT_EQ (aa.match ("adxg"), true);
EXPECT_EQ (aa.match ("adxyg"), false);
EXPECT_EQ (aa.match ("ag"), false);
EXPECT_EQ (aa.match ("abch"), false);
EXPECT_EQ (aa.match ("abcg"), true);
EXPECT_EQ (aa.match ("abchg"), true);
EXPECT_EQ (aa.match ("abchhg"), true);
EXPECT_EQ (aa.match ("adh"), false);
EXPECT_EQ (aa.match ("ah"), false);
}
TEST(8)
{
tl::GlobPattern a ("(*({bc,d}))(*)");
@ -127,6 +207,13 @@ TEST(7)
EXPECT_EQ (v[1], "bc");
EXPECT_EQ (v[2], "g");
// copy works too ...
EXPECT_EQ (tl::GlobPattern (a).match ("abcg", v), true);
EXPECT_EQ (v.size (), size_t (3));
EXPECT_EQ (v[0], "abc");
EXPECT_EQ (v[1], "bc");
EXPECT_EQ (v[2], "g");
EXPECT_EQ (a.match ("bc", v), true);
EXPECT_EQ (v.size (), size_t (3));
EXPECT_EQ (v[0], "bc");
@ -134,7 +221,7 @@ TEST(7)
EXPECT_EQ (v[2], "");
}
TEST(8)
TEST(9)
{
// case insensitive
@ -152,6 +239,13 @@ TEST(8)
EXPECT_EQ (v[1], "Bc");
EXPECT_EQ (v[2], "G");
// copy works too ...
EXPECT_EQ (tl::GlobPattern (a).match ("aBcG", v), true);
EXPECT_EQ (v.size (), size_t (3));
EXPECT_EQ (v[0], "aBc");
EXPECT_EQ (v[1], "Bc");
EXPECT_EQ (v[2], "G");
tl::GlobPattern b ("*a[bcd]");
EXPECT_EQ (b.match ("ab"), true);
@ -164,7 +258,7 @@ TEST(8)
EXPECT_EQ (b.match ("aB"), true);
}
TEST(9)
TEST(10)
{
// exact match
@ -182,7 +276,7 @@ TEST(9)
EXPECT_EQ (a.match ("(*({bc,D}))(*)"), true);
}
TEST(10)
TEST(11)
{
// header match

View File

@ -386,11 +386,9 @@ main_cont (int &argc, char **argv)
std::vector<std::string> inst_modules = tl::dir_entries (inst_dir, true, false);
std::sort (inst_modules.begin (), inst_modules.end ());
tl::GlobPattern pat ("*.ut");
for (std::vector<std::string>::const_iterator im = inst_modules.begin (); im != inst_modules.end (); ++im) {
if (! pat.match (*im)) {
if (tl::extension_last (*im) != "ut") {
continue;
}

View File

@ -215,6 +215,48 @@ class Tl_TestClass < TestBase
end
# Glob pattern
def test_3_GlobPattern
pat = RBA::GlobPattern::new("a*b")
assert_equal(pat.case_sensitive, true)
assert_equal(pat.head_match, false)
assert_equal(pat.match("ab") != nil, true)
assert_equal(pat.match("axb") != nil, true)
assert_equal(pat.match("Axb") != nil, false)
assert_equal(pat.match("abx") != nil, false)
assert_equal(pat.match("xab") != nil, false)
pat.case_sensitive = false
assert_equal(pat.case_sensitive, false)
assert_equal(pat.match("ab") != nil, true)
assert_equal(pat.match("axb") != nil, true)
assert_equal(pat.match("Axb") != nil, true)
assert_equal(pat.match("abx") != nil, false)
assert_equal(pat.match("xab") != nil, false)
pat.head_match = true
assert_equal(pat.head_match, true)
assert_equal(pat.match("ab") != nil, true)
assert_equal(pat.match("axb") != nil, true)
assert_equal(pat.match("Axb") != nil, true)
assert_equal(pat.match("abx") != nil, true)
assert_equal(pat.match("abx") == [], true)
assert_equal(pat.match("xab") != nil, false)
pat = RBA::GlobPattern::new("(*)a(*)")
assert_equal(pat.match("xb") != nil, false)
res = pat.match("xab")
assert_equal(res != nil, true)
assert_equal(res.join("/"), "x/b")
end
end
load("test_epilogue.rb")