Enhancement - caseless compare

- Fixed bug detecting multiple failed negative attribute matches.
This commit is contained in:
Paul Beckingham 2010-01-27 16:52:54 -05:00
parent 4f1183a358
commit b1700f3cf6
3 changed files with 28 additions and 18 deletions

View file

@ -104,7 +104,7 @@ Att::Att (const std::string& name, const std::string& mod, const std::string& va
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, const std::string& mod, int value) Att::Att (const std::string& name, const std::string& mod, int value)
{ {
mName = name; mName = name;
std::stringstream s; std::stringstream s;
s << value; s << value;
@ -124,7 +124,7 @@ Att::Att (const std::string& name, const std::string& value)
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
Att::Att (const std::string& name, int value) Att::Att (const std::string& name, int value)
{ {
mName = name; mName = name;
std::stringstream s; std::stringstream s;
s << value; s << value;
@ -415,6 +415,7 @@ std::string Att::modType (const std::string& name) const
{ {
if (name == "hasnt" || if (name == "hasnt" ||
name == "isnt" || name == "isnt" ||
name == "not" || // TODO Verify this.
name == "noword") name == "noword")
return "negative"; return "negative";
@ -486,32 +487,33 @@ void Att::parse (Nibbler& n)
bool Att::match (const Att& other) const bool Att::match (const Att& other) const
{ {
// All matches are assumed to pass, any short-circuit on non-match. // All matches are assumed to pass, any short-circuit on non-match.
bool case_sensitive = context.config.getBoolean ("search.case.sensitive");
// If there are no mods, just perform a straight compare on value. // If there are no mods, just perform a straight compare on value.
if (mMod == "") if (mMod == "")
{ {
if (mValue != other.mValue) if (!compare (mValue, other.mValue, (bool) case_sensitive))
return false; return false;
} }
// has = contains as a substring. // has = contains as a substring.
else if (mMod == "has" || mMod == "contains") // TODO i18n else if (mMod == "has" || mMod == "contains") // TODO i18n
{ {
if (other.mValue.find (mValue) == std::string::npos) if (find (other.mValue, mValue, (bool) case_sensitive) == std::string::npos)
return false; return false;
} }
// is = equal. Nop. // is = equal. Nop.
else if (mMod == "is" || mMod == "equals") // TODO i18n else if (mMod == "is" || mMod == "equals") // TODO i18n
{ {
if (mValue != other.mValue) if (!compare (mValue, other.mValue, (bool) case_sensitive))
return false; return false;
} }
// isnt = not equal. // isnt = not equal.
else if (mMod == "isnt" || mMod == "not") // TODO i18n else if (mMod == "isnt" || mMod == "not") // TODO i18n
{ {
if (mValue == other.mValue) if (compare (mValue, other.mValue, (bool) case_sensitive))
return false; return false;
} }
@ -535,7 +537,7 @@ bool Att::match (const Att& other) const
if (other.mValue.length () < mValue.length ()) if (other.mValue.length () < mValue.length ())
return false; return false;
if (mValue != other.mValue.substr (0, mValue.length ())) if (!compare (mValue, other.mValue.substr (0, mValue.length ())))
return false; return false;
} }
@ -545,16 +547,16 @@ bool Att::match (const Att& other) const
if (other.mValue.length () < mValue.length ()) if (other.mValue.length () < mValue.length ())
return false; return false;
if (mValue != other.mValue.substr ( if (!compare (mValue, other.mValue.substr (
other.mValue.length () - mValue.length (), other.mValue.length () - mValue.length (),
std::string::npos)) std::string::npos), (bool) case_sensitive))
return false; return false;
} }
// hasnt = does not contain as a substring. // hasnt = does not contain as a substring.
else if (mMod == "hasnt") // TODO i18n else if (mMod == "hasnt") // TODO i18n
{ {
if (other.mValue.find (mValue) != std::string::npos) if (find (other.mValue, mValue, (bool) case_sensitive) != std::string::npos)
return false; return false;
} }
@ -622,7 +624,7 @@ bool Att::match (const Att& other) const
else if (mMod == "word") // TODO i18n else if (mMod == "word") // TODO i18n
{ {
// Fail if the substring is not found. // Fail if the substring is not found.
std::string::size_type sub = other.mValue.find (mValue); std::string::size_type sub = find (other.mValue, mValue, (bool) case_sensitive);
if (sub == std::string::npos) if (sub == std::string::npos)
return false; return false;
@ -638,7 +640,7 @@ bool Att::match (const Att& other) const
else if (mMod == "noword") // TODO i18n else if (mMod == "noword") // TODO i18n
{ {
// Fail if the substring is not found. // Fail if the substring is not found.
std::string::size_type sub = other.mValue.find (mValue); std::string::size_type sub = find (other.mValue, mValue);
if (sub != std::string::npos && if (sub != std::string::npos &&
isWordStart (other.mValue, sub) && isWordStart (other.mValue, sub) &&
isWordEnd (other.mValue, sub + mValue.length () - 1)) isWordEnd (other.mValue, sub + mValue.length () - 1))

View file

@ -42,17 +42,22 @@ bool Filter::pass (const Record& record) const
{ {
// Descriptions have special handling such that they are linked to // Descriptions have special handling such that they are linked to
// annotations, and filtering on description implies identical filtering // annotations, and filtering on description implies identical filtering
// on annotations, and that both filter matches must succeed for the filter // on annotations.
// to succeed overall. //
// For positive modifiers (has, is ...) either the description or the
// annotation filter must succeed.
//
// For negative modifiers (hasnt, isnt ...) both the description and the
// annotation filter must succeed.
if (att->name () == "description") if (att->name () == "description")
{ {
bool description_result = true; bool pass = true;
int annotation_pass_count = 0; int annotation_pass_count = 0;
int annotation_fail_count = 0; int annotation_fail_count = 0;
if ((r = record.find (att->name ())) != record.end ()) if ((r = record.find (att->name ())) != record.end ())
{ {
description_result = att->match (r->second); pass = att->match (r->second);
foreach (ra, record) foreach (ra, record)
{ {
@ -66,6 +71,8 @@ bool Filter::pass (const Record& record) const
} }
} }
} }
// Missing attribute implies failure.
else if (! att->match (Att ())) else if (! att->match (Att ()))
return false; return false;
@ -74,12 +81,12 @@ bool Filter::pass (const Record& record) const
// are willing to invest a week understanding and testing it. // are willing to invest a week understanding and testing it.
if (att->modType (att->mod ()) == "positive") if (att->modType (att->mod ()) == "positive")
{ {
if (! (description_result || annotation_pass_count > 0)) if (! (pass || annotation_pass_count))
return false; return false;
} }
else else
{ {
if (!description_result || annotation_fail_count > 0) if (! (pass && annotation_fail_count == 0))
return false; return false;
} }
} }

View file

@ -40,6 +40,7 @@ if (open my $fh, '>', 'hasnt.rc')
} }
# 1 # 1
diag ("Initialization taskes 6 seconds");
qx{../task rc:hasnt.rc add foo}; qx{../task rc:hasnt.rc add foo};
# 2 # 2