support case-insensitive NodePath searches

This commit is contained in:
David Rose 2003-10-28 00:48:31 +00:00
parent ee418ad4bb
commit c4dc626ead
6 changed files with 247 additions and 159 deletions

View File

@ -24,6 +24,7 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE GlobPattern:: INLINE GlobPattern::
GlobPattern(const string &pattern) : _pattern(pattern) { GlobPattern(const string &pattern) : _pattern(pattern) {
_case_sensitive = true;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -32,7 +33,10 @@ GlobPattern(const string &pattern) : _pattern(pattern) {
// Description: // Description:
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE GlobPattern:: INLINE GlobPattern::
GlobPattern(const GlobPattern &copy) : _pattern(copy._pattern) { GlobPattern(const GlobPattern &copy) :
_pattern(copy._pattern),
_case_sensitive(copy._case_sensitive)
{
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -43,6 +47,7 @@ GlobPattern(const GlobPattern &copy) : _pattern(copy._pattern) {
INLINE void GlobPattern:: INLINE void GlobPattern::
operator = (const GlobPattern &copy) { operator = (const GlobPattern &copy) {
_pattern = copy._pattern; _pattern = copy._pattern;
_case_sensitive = copy._case_sensitive;
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -67,6 +72,30 @@ get_pattern() const {
return _pattern; return _pattern;
} }
////////////////////////////////////////////////////////////////////
// Function: GlobPattern::set_case_sensitive
// Access: Public
// Description: Sets whether the match is case sensitive (true) or
// case insensitive (false). The default is case
// sensitive.
////////////////////////////////////////////////////////////////////
INLINE void GlobPattern::
set_case_sensitive(bool case_sensitive) {
_case_sensitive = case_sensitive;
}
////////////////////////////////////////////////////////////////////
// Function: GlobPattern::get_case_sensitive
// Access: Public
// Description: Returns whether the match is case sensitive (true) or
// case insensitive (false). The default is case
// sensitive.
////////////////////////////////////////////////////////////////////
INLINE bool GlobPattern::
get_case_sensitive() const {
return _case_sensitive;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GlobPattern::matches // Function: GlobPattern::matches
// Access: Public // Access: Public

View File

@ -17,6 +17,7 @@
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
#include "globPattern.h" #include "globPattern.h"
#include <ctype.h>
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: GlobPattern::has_glob_characters // Function: GlobPattern::has_glob_characters
@ -235,8 +236,14 @@ matches_substr(string::const_iterator pi, string::const_iterator pend,
default: default:
// Anything else means to match exactly that. // Anything else means to match exactly that.
if ((*pi) != (*ci)) { if (_case_sensitive) {
return false; if ((*pi) != (*ci)) {
return false;
}
} else {
if (tolower(*pi) != tolower(*ci)) {
return false;
}
} }
return matches_substr(pi + 1, pend, ci + 1, cend); return matches_substr(pi + 1, pend, ci + 1, cend);
} }
@ -290,7 +297,10 @@ matches_set(string::const_iterator &pi, string::const_iterator pend,
char end = (*pi); char end = (*pi);
++pi; ++pi;
if (ch >= start && ch <= end) { if (ch >= start && ch <= end ||
(!_case_sensitive &&
((tolower(ch) >= start && tolower(ch) <= end) ||
(toupper(ch) >= start && toupper(ch) <= end)))) {
matched = true; matched = true;
} }
} else { } else {

View File

@ -47,6 +47,9 @@ public:
INLINE void set_pattern(const string &pattern); INLINE void set_pattern(const string &pattern);
INLINE const string &get_pattern() const; INLINE const string &get_pattern() const;
INLINE void set_case_sensitive(bool case_sensitive);
INLINE bool get_case_sensitive() const;
INLINE bool matches(const string &candidate) const; INLINE bool matches(const string &candidate) const;
INLINE void output(ostream &out) const; INLINE void output(ostream &out) const;
@ -68,6 +71,7 @@ private:
vector_string &results, const Filename &cwd); vector_string &results, const Filename &cwd);
string _pattern; string _pattern;
bool _case_sensitive;
}; };
INLINE ostream &operator << (ostream &out, const GlobPattern &glob) { INLINE ostream &operator << (ostream &out, const GlobPattern &glob) {

View File

@ -26,145 +26,7 @@ INLINE FindApproxPath::
FindApproxPath() { FindApproxPath() {
_return_hidden = true; _return_hidden = true;
_return_stashed = false; _return_stashed = false;
} _case_insensitive = false;
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_name
// Access: Public
// Description: Adds a component that must match the name of a node
// exactly.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_name(const string &name, int flags) {
Component comp;
comp._type = CT_match_name;
comp._name = name;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_name_glob
// Access: Public
// Description: Adds a component that must match the name of a node
// using standard shell globbing rules, with wildcard
// characters accepted.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_name_glob(const string &name, int flags) {
Component comp;
comp._type = CT_match_name_glob;
comp._name = name;
comp._glob.set_pattern(name);
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_exact_type
// Access: Public
// Description: Adds a component that must match the type of a node
// exactly, with no derived types matching.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_exact_type(TypeHandle type, int flags) {
Component comp;
comp._type = CT_match_exact_type;
comp._type_handle = type;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_inexact_type
// Access: Public
// Description: Adds a component that must match the type of a node
// or be a base class of the node's type.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_inexact_type(TypeHandle type, int flags) {
Component comp;
comp._type = CT_match_inexact_type;
comp._type_handle = type;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_tag
// Access: Public
// Description: Adds a component that will match a node that has a
// tag with the indicated key, no matter what the value
// is.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_tag(const string &name, int flags) {
Component comp;
comp._type = CT_match_tag;
comp._name = name;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_tag_value
// Access: Public
// Description: Adds a component that will match a node that has a
// tag with the indicated key. The value may be "*" to
// match any value, or a particular glob pattern to
// match only those nodes with the indicated value.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_tag_value(const string &name, const string &value, int flags) {
Component comp;
comp._type = CT_match_tag_value;
comp._name = name;
comp._glob.set_pattern(value);
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_one
// Access: Public
// Description: Adds a component that will match any node (but not a
// chain of many nodes).
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_one(int flags) {
Component comp;
comp._type = CT_match_one;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_many
// Access: Public
// Description: Adds a component that will match a chain of zero or
// more consecutive nodes.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_many(int flags) {
Component comp;
comp._type = CT_match_many;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_pointer
// Access: Public
// Description: Adds a component that must match a particular node
// exactly, by pointer.
////////////////////////////////////////////////////////////////////
INLINE void FindApproxPath::
add_match_pointer(PandaNode *pointer, int flags) {
Component comp;
comp._type = CT_match_pointer;
comp._pointer = pointer;
comp._flags = flags;
_path.push_back(comp);
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -238,6 +100,17 @@ return_stashed() const {
return _return_stashed; return _return_stashed;
} }
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::case_insensitive
// Access: Public
// Description: Returns true if the search is case-insensitive, false
// if it is case-sensitive.
////////////////////////////////////////////////////////////////////
INLINE bool FindApproxPath::
case_insensitive() const {
return _case_insensitive;
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::output_component // Function: FindApproxPath::output_component
// Access: Public // Access: Public

View File

@ -19,6 +19,7 @@
#include "findApproxPath.h" #include "findApproxPath.h"
#include "config_pgraph.h" #include "config_pgraph.h"
#include "string_utils.h"
#include "pandaNode.h" #include "pandaNode.h"
@ -37,6 +38,10 @@ matches(PandaNode *node) const {
// Match the node's name exactly. // Match the node's name exactly.
return (_name == node->get_name()); return (_name == node->get_name());
case CT_match_name_insensitive:
// Match the node's name exactly, with case-insensitive comparison.
return cmp_nocase(_name, node->get_name()) == 0;
case CT_match_name_glob: case CT_match_name_glob:
// Match the node's name according to filename globbing rules. // Match the node's name according to filename globbing rules.
return (_glob.matches(node->get_name())); return (_glob.matches(node->get_name()));
@ -86,6 +91,7 @@ output(ostream &out) const {
out << _type; out << _type;
switch (_type) { switch (_type) {
case CT_match_name: case CT_match_name:
case CT_match_name_insensitive:
case CT_match_name_glob: case CT_match_name_glob:
case CT_match_tag: case CT_match_tag:
out << " \"" << _name << "\""; out << " \"" << _name << "\"";
@ -119,12 +125,13 @@ output(ostream &out) const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
bool FindApproxPath:: bool FindApproxPath::
add_string(const string &str_path) { add_string(const string &str_path) {
// First, chop the string up by slashes into its components.
vector_string components;
size_t start = 0; size_t start = 0;
size_t slash = str_path.find('/'); size_t slash = str_path.find('/');
while (slash != string::npos) { while (slash != string::npos) {
if (!add_component(str_path.substr(start, slash - start))) { components.push_back(str_path.substr(start, slash - start));
return false;
}
start = slash + 1; start = slash + 1;
slash = str_path.find('/', start); slash = str_path.find('/', start);
} }
@ -139,12 +146,20 @@ add_string(const string &str_path) {
semicolon = string::npos; semicolon = string::npos;
} }
if (!add_component(str_path.substr(start, semicolon - start))) { components.push_back(str_path.substr(start, semicolon - start));
return false;
}
if (semicolon != string::npos) { if (semicolon != string::npos) {
return add_flags(str_path.substr(semicolon + 1)); if (!add_flags(str_path.substr(semicolon + 1))) {
return false;
}
}
// Now decode each component and add it to the path.
vector_string::const_iterator ci;
for (ci = components.begin(); ci != components.end(); ++ci) {
if (!add_component(*ci)) {
return false;
}
} }
return true; return true;
@ -192,6 +207,10 @@ add_flags(const string &str_flags) {
_return_stashed = on; _return_stashed = on;
break; break;
case 'i':
_case_insensitive = on;
break;
default: default:
pgraph_cat.error() pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n"; << "Invalid control flag string: " << str_flags << "\n";
@ -278,6 +297,152 @@ add_component(string str_component) {
return true; return true;
} }
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_name
// Access: Public
// Description: Adds a component that must match the name of a node
// exactly.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_name(const string &name, int flags) {
Component comp;
comp._type = _case_insensitive ? CT_match_name_insensitive : CT_match_name;
comp._name = name;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_name_glob
// Access: Public
// Description: Adds a component that must match the name of a node
// using standard shell globbing rules, with wildcard
// characters accepted.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_name_glob(const string &name, int flags) {
Component comp;
comp._type = CT_match_name_glob;
comp._name = name;
comp._glob.set_pattern(name);
comp._glob.set_case_sensitive(!_case_insensitive);
comp._flags = flags;
if (!comp._glob.has_glob_characters()) {
// The glob pattern contains no special characters; make it a
// literal match for efficiency.
add_match_name(name, flags);
} else {
_path.push_back(comp);
}
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_exact_type
// Access: Public
// Description: Adds a component that must match the type of a node
// exactly, with no derived types matching.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_exact_type(TypeHandle type, int flags) {
Component comp;
comp._type = CT_match_exact_type;
comp._type_handle = type;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_inexact_type
// Access: Public
// Description: Adds a component that must match the type of a node
// or be a base class of the node's type.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_inexact_type(TypeHandle type, int flags) {
Component comp;
comp._type = CT_match_inexact_type;
comp._type_handle = type;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_tag
// Access: Public
// Description: Adds a component that will match a node that has a
// tag with the indicated key, no matter what the value
// is.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_tag(const string &name, int flags) {
Component comp;
comp._type = CT_match_tag;
comp._name = name;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_tag_value
// Access: Public
// Description: Adds a component that will match a node that has a
// tag with the indicated key. The value may be "*" to
// match any value, or a particular glob pattern to
// match only those nodes with the indicated value.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_tag_value(const string &name, const string &value, int flags) {
Component comp;
comp._type = CT_match_tag_value;
comp._name = name;
comp._glob.set_pattern(value);
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_one
// Access: Public
// Description: Adds a component that will match any node (but not a
// chain of many nodes).
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_one(int flags) {
Component comp;
comp._type = CT_match_one;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_many
// Access: Public
// Description: Adds a component that will match a chain of zero or
// more consecutive nodes.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_many(int flags) {
Component comp;
comp._type = CT_match_many;
comp._flags = flags;
_path.push_back(comp);
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_match_pointer
// Access: Public
// Description: Adds a component that must match a particular node
// exactly, by pointer.
////////////////////////////////////////////////////////////////////
void FindApproxPath::
add_match_pointer(PandaNode *pointer, int flags) {
Component comp;
comp._type = CT_match_pointer;
comp._pointer = pointer;
comp._flags = flags;
_path.push_back(comp);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::output // Function: FindApproxPath::output
// Access: Public // Access: Public
@ -304,6 +469,9 @@ operator << (ostream &out, FindApproxPath::ComponentType type) {
case FindApproxPath::CT_match_name: case FindApproxPath::CT_match_name:
return out << "match_name"; return out << "match_name";
case FindApproxPath::CT_match_name_insensitive:
return out << "match_name_insensitive";
case FindApproxPath::CT_match_name_glob: case FindApproxPath::CT_match_name_glob:
return out << "match_name_glob"; return out << "match_name_glob";

View File

@ -42,15 +42,16 @@ public:
bool add_flags(const string &str_flags); bool add_flags(const string &str_flags);
bool add_component(string str_component); bool add_component(string str_component);
INLINE void add_match_name(const string &name, int flags); void add_match_name(const string &name, int flags);
INLINE void add_match_name_glob(const string &glob, int flags); void add_match_name_glob(const string &glob, int flags);
INLINE void add_match_exact_type(TypeHandle type, int flags); void add_match_exact_type(TypeHandle type, int flags);
INLINE void add_match_inexact_type(TypeHandle type, int flags); void add_match_inexact_type(TypeHandle type, int flags);
INLINE void add_match_tag(const string &key, int flags); void add_match_tag(const string &key, int flags);
INLINE void add_match_tag_value(const string &key, const string &value, int flags); void add_match_tag_value(const string &key, const string &value, int flags);
INLINE void add_match_one(int flags);
INLINE void add_match_many(int flags); void add_match_one(int flags);
INLINE void add_match_pointer(PandaNode *pointer, int flags); void add_match_many(int flags);
void add_match_pointer(PandaNode *pointer, int flags);
INLINE int get_num_components() const; INLINE int get_num_components() const;
INLINE bool is_component_match_many(int index) const; INLINE bool is_component_match_many(int index) const;
@ -59,6 +60,7 @@ public:
INLINE bool return_hidden() const; INLINE bool return_hidden() const;
INLINE bool return_stashed() const; INLINE bool return_stashed() const;
INLINE bool case_insensitive() const;
void output(ostream &out) const; void output(ostream &out) const;
INLINE void output_component(ostream &out, int index) const; INLINE void output_component(ostream &out, int index) const;
@ -70,6 +72,7 @@ private:
#endif #endif
enum ComponentType { enum ComponentType {
CT_match_name, CT_match_name,
CT_match_name_insensitive,
CT_match_name_glob, CT_match_name_glob,
CT_match_exact_type, CT_match_exact_type,
CT_match_inexact_type, CT_match_inexact_type,
@ -101,6 +104,7 @@ private:
bool _return_hidden; bool _return_hidden;
bool _return_stashed; bool _return_stashed;
bool _case_insensitive;
friend ostream &operator << (ostream &, FindApproxPath::ComponentType); friend ostream &operator << (ostream &, FindApproxPath::ComponentType);
friend INLINE ostream &operator << (ostream &, const FindApproxPath::Component &); friend INLINE ostream &operator << (ostream &, const FindApproxPath::Component &);