Added matching item classes to be used for multiple parameter(s) matching.

Includes support to match using regular expressions and list of matching items.
Conditions may be negated.
This commit is contained in:
marian 2023-03-27 15:55:48 +03:00
parent 3555ac0631
commit e53907837b
2 changed files with 403 additions and 0 deletions

View File

@ -2342,4 +2342,82 @@ String& String::changeStringData(char* data, unsigned int len)
return *this;
}
//
// MatchingItemList
//
bool MatchingItemList::append(MatchingItemBase* item, unsigned int overAlloc)
{
if (!item)
return false;
unsigned int pos = 0;
while (m_value.at(pos))
pos++;
if (pos == m_value.length())
m_value.resize(m_value.length() + 1 + overAlloc,true);
if (pos < length()) {
m_value.set(item,pos);
return true;
}
TelEngine::destruct(item);
return false;
}
MatchingItemBase* MatchingItemList::copy() const
{
MatchingItemList* lst = new MatchingItemList(name(),matchAll(),negated());
if (length()) {
unsigned int overAlloc = length() - 1;
for (unsigned int i = 0; i < length(); ++i) {
const MatchingItemBase* it = at(i);
MatchingItemBase* item = it ? it->copy() : 0;
if (item) {
lst->append(item,overAlloc);
overAlloc = 0;
}
}
}
return lst;
}
#define MatchingItemList_RUN_LIST(func,param) { \
int pos = -1; \
while (true) { \
MatchingItemBase* item = static_cast<MatchingItemBase*>(m_value.at(++pos)); \
if (!item) \
break; \
if (item->func(param)) { \
if (!m_matchAll) \
return true; \
} \
else if (m_matchAll) \
return false; \
} \
return pos ? m_matchAll : false; \
}
bool MatchingItemList::runMatchString(const String& str) const
{
MatchingItemList_RUN_LIST(matchString,str)
}
bool MatchingItemList::runMatchListParam(const NamedList& list) const
{
MatchingItemList_RUN_LIST(matchListParam,list)
}
#undef MatchingItemList_RUN_LIST
MatchingItemBase* MatchingItemList::optimize(MatchingItemList* list)
{
if (!list || list->at(1))
return list;
MatchingItemBase* ret = static_cast<MatchingItemBase*>(list->m_value.take(0));
// Reverse item (not)negated flag if list is negated to keep the same matching behaviour
if (list->negated())
ret->m_notNegated = !ret->m_notNegated;
TelEngine::destruct(list);
return ret;
}
/* vi: set ts=8 sw=4 sts=4 noet: */

View File

@ -6565,6 +6565,331 @@ protected:
mutable int m_port;
};
class MatchingItemString;
class MatchingItemRegexp;
class MatchingItemList;
/**
* Base class for all matching items
* @short Matching item common interface
*/
class YATE_API MatchingItemBase : public GenObject
{
YCLASS(MatchingItemBase,GenObject)
friend class MatchingItemList;
public:
/**
* Constructor
* @param name Item name
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
*/
inline MatchingItemBase(const char* name, bool negated = false)
: m_name(name), m_notNegated(!negated)
{}
/**
* Retrieve the name of this item
* @return Item name
*/
inline const String& name() const
{ return m_name; }
/**
* Check if this item is negated when testing
* @return True if negated, false otherwise
*/
inline bool negated() const
{ return !m_notNegated; }
/**
* String match. Handles matching result negation
* @param str String to match
* @return True if matches, false otherwise
*/
inline bool matchString(const String& str) const
{ return m_notNegated == runMatchString(str); }
/**
* NamedList parameter match. Handles matching result negation
* @param list List to search for parameter match
* @return True if matches, false otherwise
*/
inline bool matchListParam(const NamedList& list) const
{ return m_notNegated == runMatchListParam(list); }
/**
* String match to be implemented by descendants
* @param str String to match
* @return False
*/
virtual bool runMatchString(const String& str) const
{ return false; }
/**
* NamedList parameter match
* @param list List to search for parameter match
* @return True if matches, false otherwise
*/
virtual bool runMatchListParam(const NamedList& list) const
{ return runMatchString(list[name()]); }
/**
* Copy this item
* @return MatchingItemBase pointer, NULL if not implemented
*/
virtual MatchingItemBase* copy() const
{ return 0; }
/**
* Check if this item is a MatchingItemString one
* @return MatchingItemString pointer, NULL if this item is not a MatchingItemString
*/
virtual const MatchingItemString* itemString() const
{ return 0; }
/**
* Check if this item is a MatchingItemRegexp one
* @return MatchingItemRegexp pointer, NULL if this item is not a MatchingItemRegexp
*/
virtual const MatchingItemRegexp* itemRegexp() const
{ return 0; }
/**
* Check if this item is a MatchingItemList one
* @return MatchingItemList pointer, NULL if this item is not a MatchingItemList
*/
virtual const MatchingItemList* itemList() const
{ return 0; }
private:
String m_name; // Item name
bool m_notNegated; // Item is not negated
};
/**
* Match using a string comparison
* @short String comparison matching item
*/
class YATE_API MatchingItemString : public MatchingItemBase
{
YCLASS(MatchingItemString,MatchingItemBase)
public:
/**
* Constructor
* @param name Item name
* @param value String to match
* @param caseInsensitive Set it to true to do a case insensitive match
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
*/
inline MatchingItemString(const char* name, const char* value, bool caseInsensitive = false,
bool negated = false)
: MatchingItemBase(name,negated), m_value(value), m_caseMatch(!caseInsensitive)
{}
/**
* Retrieve the string to match
* @return String to match
*/
inline const String& value() const
{ return m_value; }
/**
* Check if this item is using a case insensitive comparison
* @return True if this item is using a case insensitive comparison
*/
inline bool caseInsensitive() const
{ return !m_caseMatch; }
/**
* String match
* @param str String to match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str) const
{ return m_caseMatch ? (str == m_value) : (str &= m_value); }
/**
* Copy this item
* @return MatchingItemBase pointer
*/
virtual MatchingItemBase* copy() const
{ return new MatchingItemString(name(),value(),caseInsensitive(),negated()); }
/**
* Check if this item is a MatchingItemString one
* @return MatchingItemString pointer
*/
virtual const MatchingItemString* itemString() const
{ return this; }
private:
String m_value; // String to match
bool m_caseMatch; // Non case insensitive match
};
/**
* Match using a regular expression
* @short A matching item using a regular expression
*/
class YATE_API MatchingItemRegexp : public MatchingItemBase
{
YCLASS(MatchingItemRegexp,MatchingItemBase)
public:
/**
* Constructor
* @param name Item name
* @param value Regular expression
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
*/
inline MatchingItemRegexp(const char* name, const char* value, bool negated = false)
: MatchingItemBase(name,negated), m_value(value)
{}
/**
* Constructor
* @param name Item name
* @param value Regular expression
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
*/
inline MatchingItemRegexp(const char* name, const Regexp& value, bool negated = false)
: MatchingItemBase(name,negated), m_value(value)
{}
/**
* Retrieve the regular expression used to match
* @return Regular expression used to match
*/
inline const Regexp& value() const
{ return m_value; }
/**
* String match
* @param str String to match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str) const
{ return m_value.matches(str); }
/**
* Copy this item
* @return MatchingItemBase pointer
*/
virtual MatchingItemBase* copy() const
{ return new MatchingItemRegexp(name(),value(),negated()); }
/**
* Check if this item is a MatchingItemRegexp one
* @return MatchingItemRegexp pointer
*/
virtual const MatchingItemRegexp* itemRegexp() const
{ return this; }
private:
Regexp m_value; // Regexp used for matching
};
/**
* List of matching items
* @short A list of matching items
*/
class YATE_API MatchingItemList : public MatchingItemBase
{
YCLASS(MatchingItemList,MatchingItemBase)
public:
/**
* Constructor
* @param name Item name
* @param matchAll True to match all items (logical AND), false to match any item (logical OR)
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
*/
inline MatchingItemList(const char* name, bool matchAll = true, bool negated = false)
: MatchingItemBase(name,negated), m_matchAll(matchAll)
{}
/**
* Check if all items must match
* @return True if all items must match (logical AND), false if any item matches (logical OR)
*/
inline bool matchAll() const
{ return m_matchAll; }
/**
* Retrieve the list length
* @return List length
*/
inline unsigned int length() const
{ return m_value.length(); }
/**
* Retrieve the number of non empty items in list
* @return The number of non empty items in list
*/
inline unsigned int count() const
{ return m_value.count(); }
/**
* Retrieve a pointer to item at given index
* @param index Index to retrieve
* @return MatchingItemBase pointer, NULL if not set or index is out of bounds
*/
inline const MatchingItemBase* at(unsigned int index) const
{ return static_cast<MatchingItemBase*>(m_value.at(index)); }
/**
* Append an item to the list
* @param item Item to append, pointer will be consumed
* @param overAlloc Optional number of items to over allocate
* This parameter is ignored if there is enough space in the list set append the item
* @return True on success, false on failure (memory allocation error or NULL pointer given)
*/
bool append(MatchingItemBase* item, unsigned int overAlloc = 1);
/**
* String match
* @param str String to match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str) const;
/**
* NamedList parameter match
* @param list List to search for parameter match
* @return True if matches, false otherwise
*/
virtual bool runMatchListParam(const NamedList& list) const;
/**
* Copy this item
* @return MatchingItemBase pointer
*/
virtual MatchingItemBase* copy() const;
/**
* Check if this item is a MatchingItemList one
* @return MatchingItemList pointer
*/
virtual const MatchingItemList* itemList() const
{ return this; }
/**
* Optimize a MatchingItemList
* Delete list if empty or there is only one item in it, return the first item in it any
* @param list List to optimize
* @return MatchingItemBase pointer, may be the list itself if not optimized
* May be NULL if list is empty
*/
static MatchingItemBase* optimize(MatchingItemList* list);
private:
ObjVector m_value; // List of items to match
bool m_matchAll; // Match all/any item(s)
};
class MutexPrivate;
class SemaphorePrivate;
class ThreadPrivate;