mirror of https://github.com/KLayout/klayout.git
Merge pull request #267 from KLayout/bugfixes_and_enhancements
Bugfixes and enhancements
This commit is contained in:
commit
644390e571
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 ();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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."
|
||||
);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -22,234 +22,748 @@
|
|||
|
||||
|
||||
#include "tlGlobPattern.h"
|
||||
#include "tlString.h"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
||||
static bool
|
||||
do_match (const char *p, const char *s, bool cs, bool exact, bool hm, std::vector<std::string> *o, std::vector<std::pair<unsigned int, const char *> > &bstart)
|
||||
// ---------------------------------------------------------------------------------
|
||||
// TODO: take from tlString.h
|
||||
|
||||
static inline uint32_t utf32_from_utf8 (const char *&cp, const char *cpe = 0)
|
||||
{
|
||||
while (*p) {
|
||||
uint32_t c32 = (unsigned char) *cp++;
|
||||
if (c32 >= 0xf0 && ((cpe && cp + 2 < cpe) || (! cpe && cp [0] && cp [1] && cp [2]))) {
|
||||
c32 = ((c32 & 0x7) << 18) | ((uint32_t (cp [0]) & 0x3f) << 12) | ((uint32_t (cp [1]) & 0x3f) << 6) | (uint32_t (cp [2]) & 0x3f);
|
||||
cp += 3;
|
||||
} else if (c32 >= 0xe0 && ((cpe && cp + 1 < cpe) || (! cpe && cp [0] && cp [1]))) {
|
||||
c32 = ((c32 & 0xf) << 12) | ((uint32_t (cp [0]) & 0x3f) << 6) | (uint32_t (cp [1]) & 0x3f);
|
||||
cp += 2;
|
||||
} else if (c32 >= 0xc0 && ((cpe && cp < cpe) || (! cpe && cp [0]))) {
|
||||
c32 = ((c32 & 0x1f) << 6) | (uint32_t (*cp) & 0x3f);
|
||||
++cp;
|
||||
}
|
||||
|
||||
if (!exact && *p == '\\') {
|
||||
return c32;
|
||||
}
|
||||
|
||||
++p;
|
||||
if (!*s || *s != *p) {
|
||||
#include "utf_casefolding.h"
|
||||
|
||||
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]) {
|
||||
return uc_tab[ch][c & 0xff];
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
static inline uint32_t utf32_downcase (uint32_t c32)
|
||||
{
|
||||
if (sizeof (wchar_t) == 2 && c32 >= 0x10000) {
|
||||
return c32;
|
||||
} else {
|
||||
return uint32_t (wdowncase (wchar_t (c32)));
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------------
|
||||
|
||||
class GlobPatternOpBase
|
||||
{
|
||||
public:
|
||||
GlobPatternOpBase () { }
|
||||
virtual ~GlobPatternOpBase () { }
|
||||
|
||||
virtual GlobPatternOpBase *clone () const = 0;
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const = 0;
|
||||
|
||||
virtual GlobPatternOpBase *next () { return 0; }
|
||||
virtual const GlobPatternOpBase *next () const { return 0; }
|
||||
virtual void set_next (GlobPatternOpBase * /*next*/, bool /*owned*/) { tl_assert (false); }
|
||||
|
||||
private:
|
||||
GlobPatternOpBase (const GlobPatternOpBase &);
|
||||
GlobPatternOpBase &operator= (const GlobPatternOpBase &);
|
||||
};
|
||||
|
||||
class GlobPatternOp
|
||||
: public GlobPatternOpBase
|
||||
{
|
||||
public:
|
||||
GlobPatternOp () : m_next_owned (false), mp_next (0) { }
|
||||
|
||||
virtual ~GlobPatternOp ()
|
||||
{
|
||||
set_next (0, false);
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternOp *op = new GlobPatternOp ();
|
||||
init_clone (op);
|
||||
return op;
|
||||
}
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
size_t n = e ? e->size () : 0;
|
||||
if (mp_next && mp_next->match (s, e)) {
|
||||
return true;
|
||||
} else if (! mp_next && ! *s) {
|
||||
return true;
|
||||
} else if (e) {
|
||||
e->erase (e->begin () + n, e->end ());
|
||||
return false;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
if (*p) {
|
||||
++p;
|
||||
}
|
||||
++s;
|
||||
|
||||
} else if (!exact && *p == '?') {
|
||||
virtual void set_next (GlobPatternOpBase *next, bool owned)
|
||||
{
|
||||
if (mp_next && m_next_owned) {
|
||||
delete mp_next;
|
||||
}
|
||||
|
||||
++p;
|
||||
m_next_owned = owned;
|
||||
mp_next = next;
|
||||
}
|
||||
|
||||
GlobPatternOpBase *next ()
|
||||
{
|
||||
return mp_next;
|
||||
}
|
||||
|
||||
const GlobPatternOpBase *next () const
|
||||
{
|
||||
return mp_next;
|
||||
}
|
||||
|
||||
void set_tail (GlobPatternOpBase *op)
|
||||
{
|
||||
GlobPatternOpBase *n = this;
|
||||
while (n->next ()) {
|
||||
n = n->next ();
|
||||
}
|
||||
|
||||
n->set_next (op, false);
|
||||
}
|
||||
|
||||
protected:
|
||||
void init_clone (GlobPatternOp *op) const
|
||||
{
|
||||
if (mp_next && m_next_owned) {
|
||||
op->set_next (mp_next->clone (), true);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_next_owned;
|
||||
GlobPatternOpBase *mp_next;
|
||||
|
||||
GlobPatternOp (const GlobPatternOp &);
|
||||
GlobPatternOp &operator= (const GlobPatternOp &);
|
||||
};
|
||||
|
||||
class GlobPatternString
|
||||
: public GlobPatternOp
|
||||
{
|
||||
public:
|
||||
GlobPatternString (const std::string &s, bool cs)
|
||||
: GlobPatternOp (), m_s (s), m_cs (cs)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternString *op = new GlobPatternString (m_s, m_cs);
|
||||
init_clone (op);
|
||||
return op;
|
||||
}
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
if (! m_cs) {
|
||||
|
||||
const char *sr = m_s.c_str ();
|
||||
while (*sr) {
|
||||
if (! *s) {
|
||||
return false;
|
||||
}
|
||||
++s;
|
||||
uint32_t cr = utf32_from_utf8 (sr);
|
||||
uint32_t c = utf32_from_utf8 (s);
|
||||
if (utf32_downcase (cr) != utf32_downcase (c)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (!exact && *p == '*') {
|
||||
return GlobPatternOp::match (s, e);
|
||||
|
||||
++p;
|
||||
} else if (m_cs && strncmp (s, m_s.c_str (), m_s.size ()) == 0) {
|
||||
|
||||
// a trailing '*' always matches
|
||||
if (!*p) {
|
||||
return GlobPatternOp::match (s + m_s.size (), e);
|
||||
|
||||
} else {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string m_s;
|
||||
bool m_cs;
|
||||
|
||||
GlobPatternString (const GlobPatternString &);
|
||||
GlobPatternString &operator= (const GlobPatternString &);
|
||||
};
|
||||
|
||||
class GlobPatternPass
|
||||
: public GlobPatternOp
|
||||
{
|
||||
public:
|
||||
GlobPatternPass ()
|
||||
: GlobPatternOp ()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternPass *op = new GlobPatternPass ();
|
||||
init_clone (op);
|
||||
return op;
|
||||
}
|
||||
|
||||
virtual bool match (const char *, std::vector<std::string> *) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<std::pair<unsigned int, const char *> > bs = bstart;
|
||||
size_t no = o ? o->size () : 0;
|
||||
GlobPatternPass (const GlobPatternPass &);
|
||||
GlobPatternPass &operator= (const GlobPatternPass &);
|
||||
};
|
||||
|
||||
while (*s) {
|
||||
if (do_match (p, s, cs, exact, hm, o, bstart)) {
|
||||
class GlobPatternAny
|
||||
: public GlobPatternOp
|
||||
{
|
||||
public:
|
||||
GlobPatternAny (size_t min, size_t max)
|
||||
: GlobPatternOp (), m_min (min), m_max (max)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternAny *op = new GlobPatternAny (m_min, m_max);
|
||||
init_clone (op);
|
||||
return op;
|
||||
}
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
size_t i = 0;
|
||||
while (i <= m_max) {
|
||||
if (i >= m_min && GlobPatternOp::match (s, e)) {
|
||||
return true;
|
||||
} else if (! *s) {
|
||||
return false;
|
||||
}
|
||||
bstart = bs;
|
||||
if (o && o->begin () + no < o->end ()) {
|
||||
o->erase (o->begin () + no, o->end ());
|
||||
}
|
||||
++s;
|
||||
utf32_from_utf8 (s);
|
||||
++i;
|
||||
}
|
||||
|
||||
} else if (!exact && *p == '[') {
|
||||
|
||||
if (! *s) {
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
size_t m_min, m_max;
|
||||
|
||||
GlobPatternAny (const GlobPatternAny &);
|
||||
GlobPatternAny &operator= (const GlobPatternAny &);
|
||||
};
|
||||
|
||||
class GlobPatternCharClass
|
||||
: public GlobPatternOp
|
||||
{
|
||||
public:
|
||||
GlobPatternCharClass (bool negate, bool cs)
|
||||
: m_negate (negate), m_cs (cs)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
GlobPatternCharClass (const std::vector<std::pair<uint32_t, uint32_t> > &intervals, bool negate, bool cs)
|
||||
: m_negate (negate), m_cs (cs), m_intervals (intervals)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void add_interval (uint32_t c1, uint32_t c2)
|
||||
{
|
||||
if (m_cs) {
|
||||
m_intervals.push_back (std::make_pair (c1, c2));
|
||||
} else {
|
||||
m_intervals.push_back (std::make_pair (utf32_downcase (c1), utf32_downcase (c2)));
|
||||
}
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternCharClass *op = new GlobPatternCharClass (m_intervals, m_negate, m_cs);
|
||||
init_clone (op);
|
||||
return op;
|
||||
}
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
uint32_t c = utf32_from_utf8 (s);
|
||||
if (! m_cs) {
|
||||
c = utf32_downcase (c);
|
||||
}
|
||||
|
||||
for (std::vector<std::pair<uint32_t, uint32_t> >::const_iterator i = m_intervals.begin (); i != m_intervals.end (); ++i) {
|
||||
if (c >= i->first && c <= i->second) {
|
||||
if (m_negate) {
|
||||
return false;
|
||||
} else {
|
||||
return GlobPatternOp::match (s, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (! m_negate) {
|
||||
return false;
|
||||
} else {
|
||||
return GlobPatternOp::match (s, e);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_negate, m_cs;
|
||||
std::vector<std::pair<uint32_t, uint32_t> > m_intervals;
|
||||
|
||||
GlobPatternCharClass (const GlobPatternCharClass &);
|
||||
GlobPatternCharClass &operator= (const GlobPatternCharClass &);
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class GlobPatternContinuator
|
||||
: public GlobPatternOpBase
|
||||
{
|
||||
public:
|
||||
GlobPatternContinuator (T *br)
|
||||
: mp_br (br)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const { return 0; }
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
return mp_br->continue_match (s, e);
|
||||
}
|
||||
|
||||
private:
|
||||
T *mp_br;
|
||||
|
||||
GlobPatternContinuator (const GlobPatternContinuator &);
|
||||
GlobPatternContinuator &operator= (const GlobPatternContinuator &);
|
||||
};
|
||||
|
||||
class GlobPatternBranch
|
||||
: public GlobPatternOp
|
||||
{
|
||||
public:
|
||||
GlobPatternBranch ()
|
||||
: GlobPatternOp (), m_cont (this)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~GlobPatternBranch ()
|
||||
{
|
||||
for (std::vector<GlobPatternOp *>::const_iterator i = m_choices.begin (); i != m_choices.end (); ++i) {
|
||||
delete *i;
|
||||
}
|
||||
m_choices.clear ();
|
||||
}
|
||||
|
||||
void add_choice (GlobPatternOp *op)
|
||||
{
|
||||
op->set_tail (&m_cont);
|
||||
m_choices.push_back (op);
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternBranch *br = new GlobPatternBranch ();
|
||||
for (std::vector<GlobPatternOp *>::const_iterator i = m_choices.begin (); i != m_choices.end (); ++i) {
|
||||
br->add_choice ((*i)->clone ());
|
||||
}
|
||||
init_clone (br);
|
||||
return br;
|
||||
}
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
for (std::vector<GlobPatternOp *>::const_iterator i = m_choices.begin (); i != m_choices.end (); ++i) {
|
||||
if ((*i)->match (s, e)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool continue_match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
return GlobPatternOp::match (s, e);
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<GlobPatternOp *> m_choices;
|
||||
GlobPatternContinuator<GlobPatternBranch> m_cont;
|
||||
|
||||
GlobPatternBranch (const GlobPatternBranch &);
|
||||
GlobPatternBranch &operator= (const GlobPatternBranch &);
|
||||
};
|
||||
|
||||
class GlobPatternBracket
|
||||
: public GlobPatternOp
|
||||
{
|
||||
public:
|
||||
GlobPatternBracket ()
|
||||
: GlobPatternOp (), mp_inner (0), mp_s0 (0), m_index (0), m_cont (this)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
~GlobPatternBracket ()
|
||||
{
|
||||
delete mp_inner;
|
||||
mp_inner = 0;
|
||||
}
|
||||
|
||||
void set_inner (GlobPatternOp *op)
|
||||
{
|
||||
delete mp_inner;
|
||||
op->set_tail (& m_cont);
|
||||
mp_inner = op;
|
||||
}
|
||||
|
||||
virtual GlobPatternOp *clone () const
|
||||
{
|
||||
GlobPatternBracket *br = new GlobPatternBracket ();
|
||||
if (mp_inner) {
|
||||
br->set_inner (mp_inner->clone ());
|
||||
}
|
||||
init_clone (br);
|
||||
return br;
|
||||
}
|
||||
|
||||
virtual bool match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
if (mp_inner) {
|
||||
|
||||
if (e) {
|
||||
mp_s0 = s;
|
||||
m_index = e->size ();
|
||||
e->push_back (std::string ());
|
||||
} else {
|
||||
mp_s0 = 0;
|
||||
}
|
||||
|
||||
bool res = mp_inner->match (s, e);
|
||||
|
||||
mp_s0 = 0;
|
||||
return res;
|
||||
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool continue_match (const char *s, std::vector<std::string> *e) const
|
||||
{
|
||||
if (mp_s0 && e) {
|
||||
(*e) [m_index] = std::string (mp_s0, 0, s - mp_s0);
|
||||
}
|
||||
return GlobPatternOp::match (s, e);
|
||||
}
|
||||
|
||||
private:
|
||||
GlobPatternOp *mp_inner;
|
||||
// NOTE: this isn't thread-safe unless GlobPattern objects live in different threads
|
||||
mutable const char *mp_s0;
|
||||
mutable size_t m_index;
|
||||
GlobPatternContinuator<GlobPatternBracket> m_cont;
|
||||
|
||||
GlobPatternBracket (const GlobPatternBracket &);
|
||||
GlobPatternBracket &operator= (const GlobPatternBracket &);
|
||||
};
|
||||
|
||||
static
|
||||
GlobPatternOp *compile (const char *&p, bool exact, bool cs, bool hm, bool for_brace);
|
||||
|
||||
void
|
||||
compile_emit_op (GlobPatternOp *&op_head, GlobPatternOp *&op, GlobPatternOp *no)
|
||||
{
|
||||
if (op) {
|
||||
op->set_next (no, true);
|
||||
} else {
|
||||
op_head = no;
|
||||
}
|
||||
op = no;
|
||||
}
|
||||
|
||||
void
|
||||
compile_emit_string (std::string &str, GlobPatternOp *&op_head, GlobPatternOp *&op, bool cs)
|
||||
{
|
||||
if (! str.empty ()) {
|
||||
compile_emit_op (op_head, op, new GlobPatternString (str, cs));
|
||||
str.clear ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
compile_emit_char_class (GlobPatternOp *&op_head, GlobPatternOp *&op, const char *&p, bool cs)
|
||||
{
|
||||
bool negate = false;
|
||||
++p;
|
||||
if (*p && *p == '^') {
|
||||
++p;
|
||||
negate = true;
|
||||
}
|
||||
|
||||
bool hit = false;
|
||||
|
||||
while (*p != ']' && *p) {
|
||||
|
||||
char c1 = *p;
|
||||
if (c1 == '\\') {
|
||||
c1 = *++p;
|
||||
}
|
||||
if (*p) {
|
||||
++p;
|
||||
}
|
||||
|
||||
char c2 = c1;
|
||||
if (*p == '-') {
|
||||
++p;
|
||||
c2 = *p;
|
||||
if (c2 == '\\') {
|
||||
c2 = *++p;
|
||||
}
|
||||
if (*p) {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
|
||||
if (! hit) {
|
||||
if (cs && *s >= c1 && *s <= c2) {
|
||||
hit = true;
|
||||
// TODO: implement UTF-8 support
|
||||
} else if (!cs && tolower (*s) >= tolower (c1) && tolower (*s) <= tolower (c2)) {
|
||||
hit = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (negate == hit) {
|
||||
return false;
|
||||
}
|
||||
|
||||
++s;
|
||||
if (*p) {
|
||||
++p;
|
||||
}
|
||||
|
||||
} else if (!exact && *p == '{') {
|
||||
|
||||
++p;
|
||||
|
||||
bool hit = false;
|
||||
const char *s0 = s;
|
||||
GlobPatternCharClass *cc = new GlobPatternCharClass (negate, cs);
|
||||
|
||||
while (*p) {
|
||||
|
||||
if (hit) {
|
||||
|
||||
while (*p && *p != ',' && *p != '}') {
|
||||
if (*p == '\\') {
|
||||
if (*p == ']') {
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
if (*p) {
|
||||
|
||||
uint32_t c1 = utf32_from_utf8 (p);
|
||||
if (c1 == '\\') {
|
||||
c1 = utf32_from_utf8 (p);
|
||||
}
|
||||
|
||||
uint32_t c2 = c1;
|
||||
if (*p == '-') {
|
||||
++p;
|
||||
c2 = utf32_from_utf8 (p);
|
||||
if (c2 == '\\') {
|
||||
c2 = utf32_from_utf8 (p);
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
s = s0;
|
||||
hit = true;
|
||||
while (*p && *p != ',' && *p != '}') {
|
||||
if (*p == '\\') {
|
||||
++p;
|
||||
}
|
||||
if (hit) {
|
||||
if (! *s) {
|
||||
hit = false;
|
||||
} else if (cs && *p != *s) {
|
||||
hit = false;
|
||||
// TODO: implement UTF-8 support
|
||||
} else if (!cs && tolower (*p) != tolower (*s)) {
|
||||
hit = false;
|
||||
} else {
|
||||
++s;
|
||||
}
|
||||
}
|
||||
if (*p) {
|
||||
++p;
|
||||
}
|
||||
}
|
||||
cc->add_interval (c1, c2);
|
||||
|
||||
}
|
||||
|
||||
compile_emit_op (op_head, op, cc);
|
||||
}
|
||||
|
||||
void
|
||||
compile_emit_alt (GlobPatternOp *&op_head, GlobPatternOp *&op, const char *&p, bool cs)
|
||||
{
|
||||
GlobPatternBranch *alt_op = new GlobPatternBranch ();
|
||||
while (*p) {
|
||||
GlobPatternOp *alt = compile (p, false, cs, false, true);
|
||||
if (alt) {
|
||||
alt_op->add_choice (alt);
|
||||
}
|
||||
if (*p == ',') {
|
||||
++p;
|
||||
} else if (*p == '}') {
|
||||
++p;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! hit) {
|
||||
return false;
|
||||
compile_emit_op (op_head, op, alt_op);
|
||||
}
|
||||
|
||||
} else if (!exact && *p == ')') {
|
||||
void
|
||||
compile_emit_bracket (GlobPatternOp *&op_head, GlobPatternOp *&op, const char *&p, bool cs)
|
||||
{
|
||||
GlobPatternBracket *br_op = new GlobPatternBracket ();
|
||||
GlobPatternOp *inner = compile (p, false, cs, false, true);
|
||||
if (inner) {
|
||||
br_op->set_inner (inner);
|
||||
}
|
||||
if (*p == ')') {
|
||||
++p;
|
||||
}
|
||||
|
||||
compile_emit_op (op_head, op, br_op);
|
||||
}
|
||||
|
||||
static
|
||||
GlobPatternOp *compile (const char *&p, bool exact, bool cs, bool hm, bool for_brace)
|
||||
{
|
||||
std::string str;
|
||||
GlobPatternOp *op = 0, *op_head = 0;
|
||||
|
||||
while (*p) {
|
||||
|
||||
if (exact) {
|
||||
|
||||
str += *p++;
|
||||
|
||||
} else if (*p == '\\') {
|
||||
|
||||
++p;
|
||||
if (*p) {
|
||||
str += *p++;
|
||||
}
|
||||
|
||||
} else if (*p == '?') {
|
||||
|
||||
compile_emit_string (str, op_head, op, cs);
|
||||
compile_emit_op (op_head, op, new GlobPatternAny (1, 1));
|
||||
|
||||
++p;
|
||||
|
||||
if (! bstart.empty ()) {
|
||||
if (o) {
|
||||
(*o)[bstart.back ().first] = std::string (bstart.back ().second, s - bstart.back ().second);
|
||||
}
|
||||
bstart.pop_back ();
|
||||
}
|
||||
} else if (*p == '*') {
|
||||
|
||||
} else if (!exact && *p == '(') {
|
||||
compile_emit_string (str, op_head, op, cs);
|
||||
if (p[1]) {
|
||||
compile_emit_op (op_head, op, new GlobPatternAny (0, std::numeric_limits<size_t>::max ()));
|
||||
} else {
|
||||
compile_emit_op (op_head, op, new GlobPatternPass ());
|
||||
}
|
||||
|
||||
++p;
|
||||
if (o) {
|
||||
bstart.push_back (std::make_pair ((unsigned int) o->size (), s));
|
||||
o->push_back (std::string ());
|
||||
}
|
||||
|
||||
} else {
|
||||
} else if (*p == '[') {
|
||||
|
||||
if (cs) {
|
||||
if (*s != *p) {
|
||||
return false;
|
||||
} else {
|
||||
++s;
|
||||
compile_emit_string (str, op_head, op, cs);
|
||||
++p;
|
||||
}
|
||||
} else {
|
||||
// TODO: implement UTF-8 support
|
||||
if (tolower (*s) != tolower (*p)) {
|
||||
return false;
|
||||
} else {
|
||||
++s;
|
||||
compile_emit_char_class (op_head, op, p, cs);
|
||||
|
||||
} else if (*p == '{') {
|
||||
|
||||
compile_emit_string (str, op_head, op, cs);
|
||||
++p;
|
||||
}
|
||||
}
|
||||
compile_emit_alt (op_head, op, p, cs);
|
||||
|
||||
} else if (*p == '(') {
|
||||
|
||||
compile_emit_string (str, op_head, op, cs);
|
||||
++p;
|
||||
compile_emit_bracket (op_head, op, p, cs);
|
||||
|
||||
} else if (for_brace && (*p == ',' || *p == '}' || *p == ')')) {
|
||||
|
||||
break;
|
||||
|
||||
} else {
|
||||
|
||||
str += *p++;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return (hm || *s == 0);
|
||||
compile_emit_string (str, op_head, op, cs);
|
||||
|
||||
if (hm) {
|
||||
compile_emit_op (op_head, op, new GlobPatternPass ());
|
||||
}
|
||||
|
||||
return op_head;
|
||||
}
|
||||
|
||||
GlobPattern::GlobPattern ()
|
||||
: m_case_sensitive (true), m_exact (false), m_header_match (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
mp_op = 0;
|
||||
m_needs_compile = true;
|
||||
}
|
||||
|
||||
GlobPattern::GlobPattern (const std::string &p)
|
||||
: m_p (p), m_case_sensitive (true), m_exact (false), m_header_match (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
mp_op = 0;
|
||||
m_needs_compile = true;
|
||||
}
|
||||
|
||||
GlobPattern::GlobPattern (const GlobPattern &other)
|
||||
: m_case_sensitive (true), m_exact (false), m_header_match (false)
|
||||
{
|
||||
mp_op = 0;
|
||||
m_needs_compile = true;
|
||||
|
||||
operator= (other);
|
||||
}
|
||||
|
||||
GlobPattern &
|
||||
GlobPattern::operator= (const GlobPattern &other)
|
||||
{
|
||||
if (this != &other) {
|
||||
|
||||
m_case_sensitive = other.m_case_sensitive;
|
||||
m_exact = other.m_exact;
|
||||
m_header_match = other.m_header_match;
|
||||
m_p = other.m_p;
|
||||
mp_op = other.mp_op ? other.mp_op->clone () : 0;
|
||||
m_needs_compile = other.m_needs_compile;
|
||||
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
GlobPattern::do_compile ()
|
||||
{
|
||||
delete mp_op;
|
||||
|
||||
const char *p = m_p.c_str ();
|
||||
mp_op = compile (p, m_exact, m_case_sensitive, m_header_match, false);
|
||||
|
||||
if (! mp_op) {
|
||||
mp_op = new GlobPatternOp ();
|
||||
}
|
||||
|
||||
m_needs_compile = false;
|
||||
}
|
||||
|
||||
void
|
||||
GlobPattern::needs_compile ()
|
||||
{
|
||||
if (! m_needs_compile) {
|
||||
|
||||
m_needs_compile = true;
|
||||
|
||||
delete mp_op;
|
||||
mp_op = 0;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
GlobPattern &GlobPattern::operator= (const std::string &p)
|
||||
{
|
||||
if (m_p != p) {
|
||||
m_p = p;
|
||||
needs_compile ();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
void GlobPattern::set_case_sensitive (bool f)
|
||||
{
|
||||
if (f != m_case_sensitive) {
|
||||
m_case_sensitive = f;
|
||||
needs_compile ();
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobPattern::case_sensitive () const
|
||||
|
|
@ -259,7 +773,10 @@ bool GlobPattern::case_sensitive () const
|
|||
|
||||
void GlobPattern::set_exact (bool f)
|
||||
{
|
||||
if (f != m_exact) {
|
||||
m_exact = f;
|
||||
needs_compile ();
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobPattern::exact () const
|
||||
|
|
@ -269,7 +786,10 @@ bool GlobPattern::exact () const
|
|||
|
||||
void GlobPattern::set_header_match (bool f)
|
||||
{
|
||||
if (f != m_header_match) {
|
||||
m_header_match = f;
|
||||
needs_compile ();
|
||||
}
|
||||
}
|
||||
|
||||
bool GlobPattern::header_match () const
|
||||
|
|
@ -277,10 +797,19 @@ bool GlobPattern::header_match () const
|
|||
return m_header_match;
|
||||
}
|
||||
|
||||
GlobPatternOp *GlobPattern::op () const
|
||||
{
|
||||
if (m_needs_compile) {
|
||||
GlobPattern *non_const_this = const_cast<GlobPattern *> (this);
|
||||
non_const_this->do_compile ();
|
||||
}
|
||||
|
||||
return mp_op;
|
||||
}
|
||||
|
||||
bool GlobPattern::match (const char *s) const
|
||||
{
|
||||
std::vector<std::pair<unsigned int, const char *> > bstart;
|
||||
return do_match (m_p.c_str (), s, m_case_sensitive, m_exact, m_header_match, 0, bstart);
|
||||
return op ()->match (s, 0);
|
||||
}
|
||||
|
||||
bool GlobPattern::match (const char *s, std::vector<std::string> &e) const
|
||||
|
|
@ -288,14 +817,13 @@ bool GlobPattern::match (const char *s, std::vector<std::string> &e) const
|
|||
if (! e.empty ()) {
|
||||
e.clear ();
|
||||
}
|
||||
std::vector<std::pair<unsigned int, const char *> > bstart;
|
||||
return do_match (m_p.c_str (), s, m_case_sensitive, m_exact, m_header_match, &e, bstart);
|
||||
|
||||
return op ()->match (s, &e);
|
||||
}
|
||||
|
||||
bool GlobPattern::match (const std::string &s) const
|
||||
{
|
||||
std::vector<std::pair<unsigned int, const char *> > bstart;
|
||||
return do_match (m_p.c_str (), s.c_str (), m_case_sensitive, m_exact, m_header_match, 0, bstart);
|
||||
return op ()->match (s.c_str (), 0);
|
||||
}
|
||||
|
||||
bool GlobPattern::match (const std::string &s, std::vector<std::string> &e) const
|
||||
|
|
@ -303,8 +831,8 @@ bool GlobPattern::match (const std::string &s, std::vector<std::string> &e) cons
|
|||
if (! e.empty ()) {
|
||||
e.clear ();
|
||||
}
|
||||
std::vector<std::pair<unsigned int, const char *> > bstart;
|
||||
return do_match (m_p.c_str (), s.c_str (), m_case_sensitive, m_exact, m_header_match, &e, bstart);
|
||||
|
||||
return op ()->match (s.c_str (), &e);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
Loading…
Reference in New Issue