Added String methods used to append using printf.

Added static String methods to be used with plain C strings: starts/end check, skip string or characters in given set.
Added support to build an AutoGenObject not owning the pointer.
MatchingItem: added dump support, added matching parameters, added random matching.
This commit is contained in:
marian 2023-05-18 15:10:38 +03:00
parent 4b9310defc
commit 4c2de15148
2 changed files with 950 additions and 113 deletions

View File

@ -1376,6 +1376,33 @@ String& String::printf(const char* format, ...)
return *this;
}
String& String::printfAppend(unsigned int length, const char* format, ...)
{
va_list va;
va_start(va,format);
char* buf = string_printf(length,format,va);
va_end(va);
if (buf) {
*this << buf;
::free(buf);
}
return *this;
}
String& String::printfAppend(const char* format, ...)
{
va_list va;
va_start(va,format);
unsigned int len = TelEngine::null(format) ? 0 : (128 + ::strlen(format));
char* buf = string_printf(len,format,va);
va_end(va);
if (buf) {
*this << buf;
::free(buf);
}
return *this;
}
String& String::appendFixed(unsigned int fixedLength, const char* str, unsigned int len, char fill, int align)
{
if (len == (unsigned int)-1)
@ -2093,6 +2120,90 @@ const String* String::atom(const String*& str, const char* val)
return str;
}
static unsigned int c_find_str(bool start, const char* str, const char* what,
int lenStr, int lenWhat, bool caseInsensitive)
{
if (!lenStr || !lenWhat || TelEngine::null(str) || TelEngine::null(what))
return 0;
if (lenStr < 0)
lenStr = ::strlen(str);
if (lenWhat < 0)
lenWhat = ::strlen(what);
if (lenStr < lenWhat)
return 0;
if (!start)
str += lenStr - lenWhat - 1;
if (caseInsensitive) {
if (::strncasecmp(str,what,lenWhat))
return 0;
}
else if (::strncmp(str,what,lenWhat))
return 0;
return lenWhat;
}
unsigned int String::c_starts_with(const char* str, const char* what, int lenStr, int lenWhat,
bool caseInsensitive)
{
return c_find_str(true,str,what,lenStr,lenWhat,caseInsensitive);
}
unsigned int String::c_ends_with(const char* str, const char* what, int lenStr, int lenWhat,
bool caseInsensitive)
{
return c_find_str(false,str,what,lenStr,lenWhat,caseInsensitive);
}
unsigned int String::c_skip_chars(const char*& str, const char* what, int len, bool skipFound)
{
if (!len || TelEngine::null(str) || TelEngine::null(what))
return 0;
const char* orig = str;
if (skipFound) {
if (len < 0) {
if (what[1])
while (*str) {
if (!::strchr(what,*str))
break;
str++;
}
else
while (*str == *what)
str++;
}
else if (what[1])
while (len-- && *str) {
if (!::strchr(what,*str))
break;
str++;
}
else
while (len-- && *str == *what)
str++;
}
else if (len < 0) {
if (what[1])
while (*str) {
if (::strchr(what,*str))
break;
str++;
}
else
while (*str && *str != *what)
str++;
}
else if (what[1])
while (len-- && *str) {
if (::strchr(what,*str))
break;
str++;
}
else
while (len-- && *str && *str != *what)
str++;
return (unsigned int)(str - orig);
}
Regexp::Regexp()
: m_regexp(0), m_compile(true), m_flags(0)
@ -2344,23 +2455,236 @@ String& String::changeStringData(char* data, unsigned int len)
//
// MatchingItemList
// MatchingItemDump
//
bool MatchingItemList::append(MatchingItemBase* item, unsigned int overAlloc)
static inline void addFlags(String& buf, const String& flags)
{
if (flags)
buf << '[' << flags << "] ";
}
static inline const char* miType(const MatchingItemBase* item)
{
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 "";
if (item->itemList())
return "list";
if (item->itemString())
return "string";
if (item->itemRegexp())
return "regexp";
if (item->itemRandom())
return "random";
if (item->itemCustom())
return item->itemCustom()->type().safe("custom");
return "unknown";
}
static const TokenDict s_miDumpFlags[] = {
{"no_initial_list_desc", MatchingItemDump::NoInitialListDesc},
{0,0}
};
void MatchingItemDump::init(const NamedList& params)
{
for (ObjList* o = params.paramList()->skipNull(); o; o = o->skipNext()) {
NamedString* ns = static_cast<NamedString*>(o->get());
if (ns->name() == YSTRING("flags"))
m_flags = ns->encodeFlags(s_miDumpFlags);
else if (ns->name() == YSTRING("rex_enclose"))
m_rexEnclose = (*ns)[0];
else if (ns->name() == YSTRING("str_enclose"))
m_strEnclose = (*ns)[0];
else if (ns->name() == YSTRING("name_value_sep"))
m_nameValueSep = *ns;
else if (ns->name() == YSTRING("prop_negated"))
m_negated = (*ns)[0];
else if (ns->name() == YSTRING("prop_caseinsensitive"))
m_caseInsentive = (*ns)[0];
else if (ns->name() == YSTRING("prop_rex_basic"))
m_regexpBasic = (*ns)[0];
else if (ns->name() == YSTRING("prop_rex_extended"))
m_regexpExtended = (*ns)[0];
}
}
String& MatchingItemDump::dumpValue(const MatchingItemBase* item, String& buf,
const String& indent, const String& origIndent, unsigned int depth) const
{
if (!item)
return buf;
String tmp;
// Done if already dumped (item implements dumpValue())
if (item->dumpValue(tmp,this,indent,origIndent,depth))
return buf << tmp;
XDebug("MatchingItemDump",DebugAll,"dumpValue (%p) %s '%s' indent='%s' origIndent='%s'",
item,miType(item),item->name().safe(),indent.safe(),origIndent.safe());
if (item->itemList()) {
for (unsigned int i = 0; i < item->itemList()->length(); ++i) {
String tmp;
buf << dump(item->itemList()->at(i),tmp,indent,origIndent,depth);
}
}
else {
const MatchingItemString* str = item->itemString();
const MatchingItemRegexp* rex = str ? 0 : item->itemRegexp();
String flags;
if (item->negated())
flags << m_negated;
if (str) {
if (str->caseInsensitive())
flags << m_caseInsentive;
addFlags(buf,flags);
buf << m_strEnclose << item->itemString()->value() << m_strEnclose;
}
else if (rex) {
if (rex->value().isCaseInsensitive())
flags << m_caseInsentive;
if (rex->value().isExtended())
flags << m_regexpExtended;
else
flags << m_regexpBasic;
addFlags(buf,flags);
buf << m_rexEnclose << item->itemRegexp()->value() << m_rexEnclose;
}
else {
addFlags(buf,flags);
if (item->itemRandom()) {
buf << "RANDOM " << item->itemRandom()->value();
if (item->itemRandom()->maxValue() == 100)
buf << '%';
else
buf << '/' << item->itemRandom()->maxValue();
}
else if (item->itemCustom())
buf << "<CUSTOM " << item->itemCustom()->type() << '>';
else
buf << "<UNKNOWN>";
}
}
XDebug("MatchingItemDump",DebugAll,"Dumped value (%p) '%s'\r\n-----\r\n%s\r\n-----",
item,item->name().safe(),buf.safe());
return buf;
}
String& MatchingItemDump::dump(const MatchingItemBase* item, String& buf,
const String& indent, const String& origIndent, unsigned int depth) const
{
if (!item)
return buf;
XDebug("MatchingItemDump",DebugAll,"dump (%p) %s '%s' indent='%s' origIndent='%s'",
item,miType(item),item->name().safe(),indent.safe(),origIndent.safe());
unsigned int oLen = buf.length();
item->dump(buf,this,indent,origIndent,depth);
// Done if already dumped (item implements dump())
if (oLen != buf.length())
return buf;
const MatchingItemList* list = item->itemList();
if (list) {
String newIndent = indent;
if (depth || 0 == (m_flags & NoInitialListDesc)) {
String flags;
if (list->negated())
flags.append("negated",",");
if (!list->matchAll())
flags.append("any",",");
if (flags)
flags.printf(" [%s]",flags.safe());
if (flags || depth || item->name()) {
buf << indent << item->name().safe("List") << ':' << flags;
if (depth)
newIndent += origIndent;
}
}
for (unsigned int i = 0; i < list->length(); ++i) {
String tmp;
buf << dump(list->at(i),tmp,newIndent,origIndent,depth + 1);
}
}
else {
String val;
dumpValue(item,val);
if (item->name() || val) {
buf << indent << origIndent;
if (item->name())
buf << item->name() << m_nameValueSep.safe("=");
buf << val;
}
}
XDebug("MatchingItemDump",DebugAll,"Dumped (%p) '%s'\r\n-----\r\n%s\r\n-----",
item,item->name().safe(),buf.safe());
return buf;
}
//
// MatchingItemRegexp
//
MatchingItemRegexp* MatchingItemRegexp::build(const char* name, const String& str,
int negated, bool insensitive, bool extended, int fail)
{
Regexp rex(0,extended,insensitive);
if (str) {
if (negated >= 0)
rex.assign(str);
else {
unsigned int pos = str.length() - 1;
negated = (str[pos] == '^') ? 1 : 0;
if (negated)
rex.assign(str.substr(0,pos));
else
rex.assign(str);
}
}
else if (negated < 0)
negated = 0;
if (fail > 1) {
if (!rex.compile())
return 0;
}
else if (fail < 0 && !rex.c_str())
return 0;
return new MatchingItemRegexp(name,rex,negated);
}
//
// MatchingItemList
//
bool MatchingItemList::change(MatchingItemBase* item, int pos, bool ins, unsigned int overAlloc)
{
if (!item) {
unsigned int n = count();
if (ins || pos < 0 || pos >= (int)n)
return false;
// Remove
GenObject* gen = m_value.take(pos);
if (gen) {
for (; pos < (int)n; ++pos)
m_value.set(m_value.take(pos + 1),pos);
TelEngine::destruct(gen);
}
return true;
}
TelEngine::destruct(item);
return false;
// Detect first free position
unsigned int firstFree = 0;
while (m_value.at(firstFree))
firstFree++;
if (firstFree >= m_value.length()) {
if (firstFree >= m_value.resize(m_value.length() + 1 + overAlloc,true)) {
TelEngine::destruct(item);
return false;
}
}
if (pos < 0 || pos >= (int)firstFree)
pos = firstFree;
else if (ins) {
for (; (int)firstFree > pos; --firstFree)
m_value.set(m_value.take(firstFree - 1),firstFree);
}
m_value.set(item,pos);
return true;
}
MatchingItemBase* MatchingItemList::copy() const
@ -2380,30 +2704,39 @@ MatchingItemBase* MatchingItemList::copy() const
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; \
static inline bool matchingListRun(const MatchingItemList& mil, MatchingParams* params,
const NamedList* list, const String& str = String::empty())
{
int pos = -1;
bool allMatch = mil.matchAll();
while (true) {
const MatchingItemBase* item = const_cast<MatchingItemBase*>(mil.at(++pos));
if (!item)
break;
bool ok = list ? item->matchListParam(*list,params) : item->matchString(str,params);
// Matched: done if not all match (any match)
// Not matched: done if all match is required
if (ok) {
if (!allMatch)
return true;
}
else if (allMatch)
return false;
}
// End of list reached
// Empty list or match any: not matched
// Otherwise: matched
return pos && allMatch;
}
bool MatchingItemList::runMatchString(const String& str) const
bool MatchingItemList::runMatchString(const String& str, MatchingParams* params) const
{
MatchingItemList_RUN_LIST(matchString,str)
return matchingListRun(*this,params,0,str);
}
bool MatchingItemList::runMatchListParam(const NamedList& list) const
bool MatchingItemList::runMatchListParam(const NamedList& list, MatchingParams* params) const
{
MatchingItemList_RUN_LIST(matchListParam,list)
return matchingListRun(*this,params,&list);
}
#undef MatchingItemList_RUN_LIST
@ -2413,9 +2746,11 @@ 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;
if (ret) {
// 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;
}

View File

@ -930,6 +930,36 @@ void YCLASS2(class type,class base1,class base2);
*/
void YCLASS3(class type,class base1,class base2,class base3);
/**
* Macro to create a GenObject class from a base class and implement @ref GenObject::getObject
* Try to obtain something from a data member first
* @param dataPtr Pointer to member data variable
* @param type Class that is declared
* @param base Base class that is inherited
*/
void YCLASS_DATA(var dataPtr,class type,class base);
/**
* Macro to create a GenObject class from two base classes and implement @ref GenObject::getObject
* Try to obtain something from a data member first
* @param dataPtr Pointer to member data variable
* @param type Class that is declared
* @param base1 First base class that is inherited
* @param base2 Second base class that is inherited
*/
void YCLASS2_DATA(var dataPtr,class type,class base1,class base2);
/**
* Macro to create a GenObject class from three base classes and implement @ref GenObject::getObject
* Try to obtain something from a data member first
* @param dataPtr Pointer to member data variable
* @param type Class that is declared
* @param base1 First base class that is inherited
* @param base2 Second base class that is inherited
* @param base3 Third base class that is inherited
*/
void YCLASS3_DATA(var dataPtr,class type,class base1,class base2,class base3);
/**
* Macro to implement @ref GenObject::getObject in a derived class
* @param type Class that is declared
@ -987,6 +1017,32 @@ public: virtual void* getObject(const String& name) const \
tmp = base2::getObject(name); \
return tmp ? tmp : base3::getObject(name); }
#define YCLASS_CALL(res) { void* tmp = res; if (tmp) return tmp; }
#define YCLASS_CALL_LAST(base1,base2) { void* tmp = base1::getObject(name); return tmp ? tmp : base2::getObject(name); }
#define YCLASS_DATA_CHECK_PTR(dataPtr,type) { \
if (dataPtr) YCLASS_CALL((dataPtr)->getObject(name)) \
if (name == YATOM(#type)) return const_cast<type*>(this); \
}
#define YCLASS_DATA(dataPtr,type,base) \
public: virtual void* getObject(const String& name) const { \
YCLASS_DATA_CHECK_PTR(dataPtr,type) \
return base::getObject(name); \
}
#define YCLASS2_DATA(dataPtr,type,base1,base2) \
public: virtual void* getObject(const String& name) const { \
YCLASS_DATA_CHECK_PTR(dataPtr,type) \
YCLASS_CALL_LAST(base,base2) \
}
#define YCLASS3_DATA(dataPtr,type,base1,base2,base3) \
public: virtual void* getObject(const String& name) const { \
YCLASS_DATA_CHECK_PTR(dataPtr,type) \
YCLASS_CALL(base1::getObject(name)) \
YCLASS_CALL_LAST(base2,base3) \
}
#define YCLASSIMP(type,base) \
void* type::getObject(const String& name) const \
{ return (name == YATOM(#type)) ? const_cast<type*>(this) : base::getObject(name); }
@ -1171,75 +1227,6 @@ inline void destruct(GenObject* obj)
template <class Obj> void destruct(Obj*& obj)
{ if (obj) { obj->destruct(); obj = 0; } }
/**
* This class holds an automatic (owned) GenObject pointer
* @short GenObject pointer holder (owned)
*/
class YATE_API AutoGenObject
{
YNOCOPY(AutoGenObject); // no automatic copies please
public:
/**
* Constructor
* @param gen Optional pointer to object
*/
inline AutoGenObject(GenObject* gen = 0)
: m_pointer(gen)
{}
/**
* Destructor
*/
inline ~AutoGenObject()
{ set(); }
/**
* Take the pointer. Caller retains ownership
* @return GenObject pointer, NULL if not set
*/
inline GenObject* take() {
GenObject* gen = m_pointer;
m_pointer = 0;
return gen;
}
/**
* Assignment from pointer
* @param gen New pointer value
*/
inline AutoGenObject& operator=(GenObject* gen)
{ set(gen); return *this; }
/**
* Conversion to regular pointer operator
* @return The stored pointer
*/
inline operator GenObject*() const
{ return m_pointer; }
/**
* Member access operator
*/
inline GenObject* operator->() const
{ return m_pointer; }
/**
* Dereferencing operator
*/
inline GenObject& operator*() const
{ return *m_pointer; }
private:
inline void set(GenObject* gen = 0) {
if (m_pointer == gen)
return;
GenObject* tmp = m_pointer;
m_pointer = gen;
TelEngine::destruct(tmp);
}
GenObject* m_pointer;
};
/**
* A reference counted object.
* Whenever using multiple inheritance you should inherit this class virtually.
@ -2950,6 +2937,20 @@ public:
*/
String& printf(unsigned int length, const char* format, ...) FORMAT_CHECK(3);
/**
* Append a String in a printf style.
* @param format The output format.
* NOTE: The length of added string will be at most 128 + length of format
*/
String& printfAppend(const char* format, ...) FORMAT_CHECK(2);
/**
* Append a String in a printf style.
* @param length maximum length of the resulting string
* @param format The output format.
*/
String& printfAppend(unsigned int length, const char* format, ...) FORMAT_CHECK(3);
/**
* Build a fixed aligned string from str and append it.
* @param fixedLength The fixed length in which the 'str' will be aligned.
@ -3315,6 +3316,57 @@ public:
*/
static const String* atom(const String*& str, const char* val);
/**
* Checks if a string starts with a substring
* @param str String to search in
* @param what Substring to check
* @param lenStr String length, negative to detect
* @param lenWhat Substring length, negative to detect
* @param caseInsensitive Compare case-insensitive if set
* @return The length of substring if string starts with it
*/
static unsigned int c_starts_with(const char* str, const char* what, int lenStr = -1,
int lenWhat = -1, bool caseInsensitive = false);
/**
* Checks if a string ends with a substring
* @param str String to search in
* @param what Substring to check
* @param lenStr String length, negative to detect
* @param lenWhat Substring length, negative to detect
* @param caseInsensitive Compare case-insensitive if set
* @return The length of substring if string ends with it
*/
static unsigned int c_ends_with(const char* str, const char* what, int lenStr = -1,
int lenWhat = -1, bool caseInsensitive = false);
/**
* Skip substring in string if matches
* @param str String to search in. Will be advanced by skipped chars
* @param what Substring to match
* @param lenStr String length, negative to detect
* @param lenWhat Substring length, negative to detect
* @param caseInsensitive Compare case-insensitive if set
* @return The number of skipped chars (length of substring), 0 if not matched
*/
static inline unsigned int c_skip(const char*& str, const char* what, int lenStr = -1,
int lenWhat = -1, bool caseInsensitive = false) {
unsigned int n = c_starts_with(str,what,lenStr,lenWhat,caseInsensitive);
str += n;
return n;
}
/**
* Skip chars in string
* @param str String to skip in. Will be advanced by skipped chars
* @param what Characters to match
* @param len Optional maximum length to search in string, negative to use the whole string
* @param skipFound Set it to false to skip while NOT match (until first match character)
* @return Number of skipped chars
*/
static unsigned int c_skip_chars(const char*& str, const char* what,
int len = -1, bool skipFound = true);
protected:
/**
* Called whenever the value changed (except in constructors).
@ -3331,6 +3383,95 @@ private:
StringMatchPrivate* m_matches;
};
/**
* This class holds an automatic (owned) GenObject pointer
* Ownership may be reset to avoid releasing the held pointer when destroyed
* @short GenObject pointer holder
*/
class YATE_API AutoGenObject : public String
{
YCLASS_DATA(m_pointer,AutoGenObject,String)
YNOCOPY(AutoGenObject); // no automatic copies please
public:
/**
* Constructor
* @param gen Optional pointer to object
* @param name Optional name
* @param owned True if held object is owned
*/
inline AutoGenObject(GenObject* gen = 0, const char* name = 0, bool owned = true)
: String(name), m_pointer(gen), m_owned(owned)
{}
/**
* Destructor
*/
inline ~AutoGenObject()
{ set(); }
/**
* Retrieve the held data
* @return The stored pointer
*/
inline GenObject* data() const
{ return m_pointer; }
/**
* Take the pointer. Caller retains ownership
* @return GenObject pointer, NULL if not set
*/
inline GenObject* take() {
GenObject* gen = m_pointer;
m_pointer = 0;
return gen;
}
/**
* Replace data
* @param gen Optional pointer to object
* @param owned True if held object is owned
*/
inline void set(GenObject* gen = 0, bool owned = true) {
if (m_pointer == gen)
return;
GenObject* tmp = m_pointer;
m_pointer = gen;
if (m_owned)
TelEngine::destruct(tmp);
m_owned = owned;
}
/**
* Assignment from pointer
* @param gen New pointer value
*/
inline AutoGenObject& operator=(GenObject* gen)
{ set(gen); return *this; }
/**
* Conversion to regular pointer operator
* @return The stored pointer
*/
inline operator GenObject*() const
{ return m_pointer; }
/**
* Member access operator
*/
inline GenObject* operator->() const
{ return m_pointer; }
/**
* Dereferencing operator
*/
inline GenObject& operator*() const
{ return *m_pointer; }
private:
GenObject* m_pointer;
bool m_owned;
};
/**
* Template for generic object vector
* The vector can be resized (up/down)
@ -6565,9 +6706,119 @@ protected:
mutable int m_port;
};
class MatchingItemBase;
class MatchingItemString;
class MatchingItemRegexp;
class MatchingItemRandom;
class MatchingItemList;
class MatchingItemCustom;
/**
* This class holds matching parameters to be passed when matching in item
* @short Matching item match parameters
*/
class YATE_API MatchingParams : public String
{
YCLASS(MatchingParams,String)
public:
/**
* Constructor
* @param name Item name
*/
inline MatchingParams(const char* name = 0)
: String(name), m_now(0)
{}
uint64_t m_now; // Current time to be set when needed
ObjList m_params; // Arbitray parameters. May be set during matching
};
/**
* This class holds dump matching item parameters
* @short Matching item dump parameters
*/
class YATE_API MatchingItemDump : public String
{
YCLASS(MatchingItemDump,String)
public:
/**
* Dump behaviour flags
*/
enum DumpFlags {
NoInitialListDesc = 0x00000001, // Do not dump list description at depth 0
};
/**
* Constructor
* @param params Optional parameters
* @param name Optional name
*/
inline MatchingItemDump(const NamedList* params = 0, const char* name = 0)
: String(name), m_flags(0), m_rexEnclose('/'), m_strEnclose('\''),
m_nameValueSep(": "), m_negated('!'), m_caseInsentive('i'),
m_regexpBasic(0), m_regexpExtended(0)
{
if (params)
init(*params);
}
/**
* Initialize dumper data
* @param params Parameters list
*/
virtual void init(const NamedList& params);
/**
* Dump an item
* @param mi Item to dump
* @param buf Destination buffer
* @param indent Spaces for output
* @param origIndent Original indent
* @param depth Re-enter depth
* @return Destination buffer reference
*/
virtual String& dump(const MatchingItemBase* mi, String& buf,
const String& indent = String::empty(), const String& origIndent = String::empty(),
unsigned int depth = 0) const;
/**
* Dump an item's value
* @param mi Item to dump
* @param buf Destination buffer
* @param indent Indent for each item (line). Increased by 'origIndent' when depth advances
* @param origIndent Original indent
* @param depth Re-enter depth
* @return Destination buffer reference
*/
virtual String& dumpValue(const MatchingItemBase* mi, String& buf,
const String& indent = String::empty(), const String& origIndent = String::empty(),
unsigned int depth = 0) const;
/**
* Dump an item
* @param mi Item to dump
* @param buf Destination buffer
* @param indent Indent for each item (line). Increased by 'origIndent' when depth advances
* @param origIndent Original indent
* @param params Optional dumper parameters parameters
* @return Destination buffer reference
*/
static inline String& dumpItem(const MatchingItemBase* mi, String& buf,
const String& indent = String::empty(), const String& origIndent = String::empty(),
const NamedList* params = 0) {
MatchingItemDump tmp(params);
return tmp.dump(mi,buf,indent,origIndent);
}
unsigned int m_flags; // Dump flags
char m_rexEnclose; // Regexp enclose char
char m_strEnclose; // String enclose char
String m_nameValueSep; // Separator to be set between name and value
char m_negated; // Negated match value
char m_caseInsentive; // Case insensitive match value
char m_regexpBasic; // Basic POSIX regexp value
char m_regexpExtended; // Extended POSIX regexp value
};
/**
* Base class for all matching items
@ -6605,33 +6856,37 @@ public:
/**
* String match. Handles matching result negation
* @param str String to match
* @param params Optional parameters used during match
* @return True if matches, false otherwise
*/
inline bool matchString(const String& str) const
{ return m_notNegated == runMatchString(str); }
inline bool matchString(const String& str, MatchingParams* params = 0) const
{ return m_notNegated == runMatchString(str,params); }
/**
* NamedList parameter match. Handles matching result negation
* @param list List to search for parameter match
* @param params Optional parameters used during match
* @return True if matches, false otherwise
*/
inline bool matchListParam(const NamedList& list) const
{ return m_notNegated == runMatchListParam(list); }
inline bool matchListParam(const NamedList& list, MatchingParams* params = 0) const
{ return m_notNegated == runMatchListParam(list,params); }
/**
* String match to be implemented by descendants
* @param str String to match
* @param params Optional parameters used during match
* @return False
*/
virtual bool runMatchString(const String& str) const
virtual bool runMatchString(const String& str, MatchingParams* params = 0) const
{ return false; }
/**
* NamedList parameter match
* @param list List to search for parameter match
* @param params Optional parameters used during match
* @return True if matches, false otherwise
*/
virtual bool runMatchListParam(const NamedList& list) const
virtual bool runMatchListParam(const NamedList& list, MatchingParams* params = 0) const
{ return runMatchString(list[name()]); }
/**
@ -6655,6 +6910,13 @@ public:
virtual const MatchingItemRegexp* itemRegexp() const
{ return 0; }
/**
* Check if this item is a MatchingItemRandom one
* @return MatchingItemRandom pointer
*/
virtual const MatchingItemRandom* itemRandom() const
{ return 0; }
/**
* Check if this item is a MatchingItemList one
* @return MatchingItemList pointer, NULL if this item is not a MatchingItemList
@ -6662,6 +6924,48 @@ public:
virtual const MatchingItemList* itemList() const
{ return 0; }
/**
* Check if this item is a MatchingItemCustom one
* @return MatchingItemCustom pointer
*/
virtual const MatchingItemCustom* itemCustom() const
{ return 0; }
/**
* Dump this item
* @param buf Destination buffer
* @param indent Indent for each item (line). Increased by 'origIndent' when depth advances
* @param origIndent Original indent
* @param dump Optional dumper
* @param depth Re-enter depth
* @return Destination buffer reference
*/
virtual String& dump(String& buf, const MatchingItemDump* dump = 0,
const String& indent = String::empty(), const String& origIndent = String::empty(),
unsigned int depth = 0) const
{ return buf; }
/**
* Dump this item's value
* @param buf Destination buffer
* @param dump Optional dumper
* @param indent Indent for each item (line). Increased by 'origIndent' when depth advances
* @param origIndent Original indent
* @param depth Re-enter depth
* @return Destination buffer reference
*/
virtual String& dumpValue(String& buf, const MatchingItemDump* dump = 0,
const String& indent = String::empty(), const String& origIndent = String::empty(),
unsigned int depth = 0) const
{ return buf; }
/**
* Retrieve item name (suitable for list retrieval)
* @return Item name
*/
virtual const String& toString() const
{ return name(); }
private:
String m_name; // Item name
bool m_notNegated; // Item is not negated
@ -6705,9 +7009,10 @@ public:
/**
* String match
* @param str String to match
* @param params Optional parameters used during match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str) const
virtual bool runMatchString(const String& str, MatchingParams* params = 0) const
{ return m_caseMatch ? (str == m_value) : (str &= m_value); }
/**
@ -6769,9 +7074,10 @@ public:
/**
* String match
* @param str String to match
* @param params Optional parameters used during match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str) const
virtual bool runMatchString(const String& str, MatchingParams* params = 0) const
{ return m_value.matches(str); }
/**
@ -6788,10 +7094,113 @@ public:
virtual const MatchingItemRegexp* itemRegexp() const
{ return this; }
/**
* Build a MatchingItemRegexp from string
* @param name Item name
* @param str Regexp string
* @param negated Greater than 0: build a negated match, 0: buid a non negated match,
* negative: build a negated match if str ends with ^
* @param insensitive Build a case insensitive regexp
* @param extended Build a regexp using extended POSIX
* @param fail positive: fail if regexp compile fails, negative fail if empty (do not check the regexp)
* Remember: failed regexp never matches
* @return MatchingItemRegexp pointer, NULL on failure
*/
static MatchingItemRegexp* build(const char* name, const String& str, int negated = 0,
bool insensitive = false, bool extended = false, int fail = 1);
private:
Regexp m_value; // Regexp used for matching
};
/**
* Match using a random number
* Implements a matching of a reference value greater than RANDOM[0..MAX - 1]
* List match and item name set:
* Parameter present: use random match
* Parameter not present: no match (return false)
* @short Random number matching
*/
class YATE_API MatchingItemRandom : public MatchingItemBase
{
YCLASS(MatchingItemRandom,MatchingItemBase)
public:
/**
* Constructor
* Random percent match: val=[PERCENT] maxVal=100
* @param val Reference value. 0: never match, 'maxVal' is ignored
* @param maxVal Upper interval value. 0, 1, less than / equal to 'val': always match
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
* @param name Item name
*/
inline MatchingItemRandom(uint32_t val, uint32_t maxVal, bool negated = false,
const char* name = 0)
: MatchingItemBase(name,negated), m_value(val), m_maxVal(maxVal) {
if (!m_value) // Never match
m_maxVal = 100;
else if (m_maxVal < 2) // Always match. Avoid division by 0
m_value = m_maxVal = 100;
}
/**
* Retrieve the reference value used to make a decision
* @return The reference value used to make a decision
*/
inline uint32_t value() const
{ return m_value; }
/**
* Retrieve the maximum value for random number
* @return The maximum value for random number
*/
inline uint32_t maxValue() const
{ return m_maxVal; }
/**
* Run the match. Ignore the 'negated' property
* @return True if matched, false otherwise
*/
inline bool randomMatch() const
{ return value() > (Random::random() % maxValue()); }
/**
* String match
* @param str String to match
* @param params Optional parameters used during match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str, MatchingParams* params = 0) const
{ return randomMatch(); }
/**
* NamedList parameter match
* @param list List to search for parameter match
* @param params Optional parameters used during match
* @return True if matches, false otherwise
*/
virtual bool runMatchListParam(const NamedList& list, MatchingParams* params = 0) const
{ return (!name() || list.getParam(name())) ? randomMatch() : false; }
/**
* Copy this item
* @return MatchingItemBase pointer
*/
virtual MatchingItemBase* copy() const
{ return new MatchingItemRandom(value(),maxValue(),negated(),name()); }
/**
* Check if this item is a MatchingItemRandom one
* @return MatchingItemRandom pointer
*/
virtual const MatchingItemRandom* itemRandom() const
{ return this; }
private:
uint32_t m_value; // Reference value
uint32_t m_maxVal; // Max value
};
/**
* List of matching items
* @short A list of matching items
@ -6840,6 +7249,36 @@ public:
inline const MatchingItemBase* at(unsigned int index) const
{ return static_cast<MatchingItemBase*>(m_value.at(index)); }
/**
* Retrieve the index of an item found by name
* @param name Item name
* @return Index of found item, negative if not found
*/
inline int indexOf(const String& name) const
{ return m_value.index(name); }
/**
* Find an item by name
* @param name Item name
* @return MatchingItemBase pointer, NULL if not found
*/
inline const MatchingItemBase* find(const String& name) const {
int idx = indexOf(name);
return idx >= 0 ? at(idx) : 0;
}
/**
* Change list (append,insert,replace,remove)
* Item is removed if given pointer is NULL, position is valid and 'ins' is false
* @param item Item to set, pointer will be consumed
* @param pos Item position. Append if negative or past list length
* @param ins Set it to true to insert, false to replace or append
* @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 change(MatchingItemBase* item, int pos = -1, bool ins = false, unsigned int overAlloc = 1);
/**
* Append an item to the list
* @param item Item to append, pointer will be consumed
@ -6847,21 +7286,47 @@ public:
* 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);
inline bool append(MatchingItemBase* item, unsigned int overAlloc = 1)
{ return change(item,-1,false,overAlloc); }
/**
* Set an item at given position
* Item is removed if given pointer is NULL
* @param item Item to set, pointer will be consumed
* @param pos Item position. Append if past list length
* @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)
*/
inline bool set(MatchingItemBase* item, unsigned int pos, unsigned int overAlloc = 1)
{ return change(item,pos,false,overAlloc); }
/**
* Insert an item at list start
* @param item Item to insert, pointer will be consumed
* @param pos Item position. Append if past list length
* @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)
*/
inline bool insert(MatchingItemBase* item, unsigned int pos = 0, unsigned int overAlloc = 1)
{ return change(item,pos,true,overAlloc); }
/**
* String match
* @param str String to match
* @param params Optional parameters used during match
* @return True if matched, false otherwise
*/
virtual bool runMatchString(const String& str) const;
virtual bool runMatchString(const String& str, MatchingParams* params = 0) const;
/**
* NamedList parameter match
* @param list List to search for parameter match
* @param params Optional parameters used during match
* @return True if matches, false otherwise
*/
virtual bool runMatchListParam(const NamedList& list) const;
virtual bool runMatchListParam(const NamedList& list, MatchingParams* params = 0) const;
/**
* Copy this item
@ -6890,6 +7355,43 @@ private:
bool m_matchAll; // Match all/any item(s)
};
/**
* Custom match
* @short Base class for custom matching
*/
class YATE_API MatchingItemCustom : public MatchingItemBase
{
YCLASS(MatchingItemCustom,MatchingItemBase)
public:
/**
* Constructor
* @param name Item name
* @param type Type name
* @param negated True if matching is negated (return the opposite of match in
* public methods), false otherwise
*/
inline MatchingItemCustom(const char* name, const char* type, bool negated = false)
: MatchingItemBase(name,negated), m_type(type)
{}
/**
* Retrieve the type
* @return Type name
*/
inline const String& type() const
{ return m_type; }
/**
* Check if this item is a MatchingItemCustom one
* @return MatchingItemCustom pointer
*/
virtual const MatchingItemCustom* itemCustom() const
{ return this; }
private:
String m_type;
};
class MutexPrivate;
class SemaphorePrivate;
class ThreadPrivate;