open_toontown_panda3d/panda/src/pgraph/findApproxPath.cxx

499 lines
15 KiB
C++

// Filename: findApproxPath.cxx
// Created by: drose (13Mar02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) Carnegie Mellon University. All rights reserved.
//
// All use of this software is subject to the terms of the revised BSD
// license. You should have received a copy of this license along
// with this source code in a file named "LICENSE."
//
////////////////////////////////////////////////////////////////////
#include "findApproxPath.h"
#include "config_pgraph.h"
#include "string_utils.h"
#include "pandaNode.h"
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::Component::matches
// Access: Public
// Description: Returns true if the indicated node matches this
// component, false otherwise.
////////////////////////////////////////////////////////////////////
bool FindApproxPath::Component::
matches(PandaNode *node) const {
string node_name;
switch (_type) {
case CT_match_name:
// Match the node's name exactly.
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:
// Match the node's name according to filename globbing rules.
return (_glob.matches(node->get_name()));
case CT_match_exact_type:
// Match the node's type exactly.
return (node->is_exact_type(_type_handle));
case CT_match_inexact_type:
// Match the node's type inexactly: it's a match if the node
// is the type, or is derived from the type.
return (node->is_of_type(_type_handle));
case CT_match_tag:
// Match the node's tag only.
return (node->has_tag(_name));
case CT_match_tag_value:
// Match the node's tag and value.
if (node->has_tag(_name)) {
return _glob.matches(node->get_tag(_name));
}
return false;
case CT_match_one:
case CT_match_many:
// Match any node.
return true;
case CT_match_pointer:
// Match only this one particular node.
return (_pointer == node);
}
pgraph_cat.error()
<< "Invalid component in FindApproxPath\n";
return false;
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::Component::output
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FindApproxPath::Component::
output(ostream &out) const {
out << _type;
switch (_type) {
case CT_match_name:
case CT_match_name_insensitive:
case CT_match_name_glob:
case CT_match_tag:
out << " \"" << _name << "\"";
break;
case CT_match_tag_value:
out << " \"" << _name << "\"=\"" << _glob << "\"";
break;
case CT_match_exact_type:
case CT_match_inexact_type:
out << " " << _type_handle;
break;
case CT_match_pointer:
out << " (" << *_pointer << ")";
break;
default:
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_string
// Access: Public
// Description: Adds a sequence of components separated by slashes,
// followed optionally by a semicolon and a sequence of
// control flags, to the path sequence. Returns true if
// successful, false if the string contained an error.
////////////////////////////////////////////////////////////////////
bool FindApproxPath::
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 slash = str_path.find('/');
while (slash != string::npos) {
components.push_back(str_path.substr(start, slash - start));
start = slash + 1;
slash = str_path.find('/', start);
}
size_t semicolon = str_path.rfind(';');
// We want to find the *last* semicolon at start or later, if there
// happens to be more than one. rfind will find the rightmost
// semicolon in the entire string; if this is less than start, there
// is no semicolon right of start.
if (semicolon < start) {
semicolon = string::npos;
}
components.push_back(str_path.substr(start, semicolon - start));
if (semicolon != string::npos) {
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;
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_flags
// Access: Public
// Description: Adds a sequence of control flags. This will be a
// sequence of letters preceded by either '+' or '-',
// with no intervening punctuation. Returns true if
// successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool FindApproxPath::
add_flags(const string &str_flags) {
string::const_iterator pi = str_flags.begin();
while (pi != str_flags.end()) {
bool on;
switch (*pi) {
case '+':
on = true;
break;
case '-':
on = false;
break;
default:
pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n";
return false;
}
++pi;
if (pi == str_flags.end()) {
pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n";
return false;
}
switch (*pi) {
case 'h':
_return_hidden = on;
break;
case 's':
_return_stashed = on;
break;
case 'i':
_case_insensitive = on;
break;
default:
pgraph_cat.error()
<< "Invalid control flag string: " << str_flags << "\n";
return false;
}
++pi;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: FindApproxPath::add_component
// Access: Public
// Description: Adds a single component to the path sequence, defined
// by a string as might appear between slashes in the
// path string. Returns true if successful, false if
// the string component was in some way invalid.
////////////////////////////////////////////////////////////////////
bool FindApproxPath::
add_component(string str_component) {
int flags = 0;
if (str_component.size() >= 2 && str_component.substr(0, 2) == "@@") {
flags |= CF_stashed;
str_component = str_component.substr(2);
}
if (str_component == "*") {
add_match_one(flags);
} else if (str_component == "**") {
if ((flags & CF_stashed) != 0) {
pgraph_cat.error()
<< "@@** is undefined; use @@*/** or **/@@* instead.\n";
return false;
}
add_match_many(flags);
} else if (!str_component.empty() && str_component[0] == '-') {
string type_name = str_component.substr(1);
TypeHandle handle = TypeRegistry::ptr()->find_type(type_name);
if (handle == TypeHandle::none()) {
pgraph_cat.error()
<< "Invalid type name: " << type_name << "\n";
return false;
} else {
add_match_exact_type(handle, flags);
}
} else if (!str_component.empty() && str_component[0] == '+') {
string type_name = str_component.substr(1);
TypeHandle handle = TypeRegistry::ptr()->find_type(type_name);
if (handle == TypeHandle::none()) {
pgraph_cat.error()
<< "Invalid type name: " << type_name << "\n";
return false;
} else {
add_match_inexact_type(handle, flags);
}
} else if (!str_component.empty() && str_component[0] == '=') {
size_t equals = str_component.find('=', 1);
if (equals != string::npos) {
// =key=value
string tag_key = str_component.substr(1, equals - 1);
string tag_value = str_component.substr(equals + 1);
add_match_tag_value(tag_key, tag_value, flags);
} else {
// =key
string tag_key = str_component.substr(1);
add_match_tag(tag_key, flags);
}
} else {
add_match_name_glob(str_component, flags);
}
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
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void FindApproxPath::
output(ostream &out) const {
out << "(";
if (!_path.empty()) {
Path::const_iterator pi = _path.begin();
out << *pi;
++pi;
while (pi != _path.end()) {
out << " / " << *pi;
++pi;
}
}
out << ")";
}
ostream &
operator << (ostream &out, FindApproxPath::ComponentType type) {
switch (type) {
case FindApproxPath::CT_match_name:
return out << "match_name";
case FindApproxPath::CT_match_name_insensitive:
return out << "match_name_insensitive";
case FindApproxPath::CT_match_name_glob:
return out << "match_name_glob";
case FindApproxPath::CT_match_exact_type:
return out << "match_exact_type";
case FindApproxPath::CT_match_inexact_type:
return out << "match_inexact_type";
case FindApproxPath::CT_match_tag:
return out << "match_tag";
case FindApproxPath::CT_match_tag_value:
return out << "match_tag_value";
case FindApproxPath::CT_match_one:
return out << "match_one";
case FindApproxPath::CT_match_many:
return out << "match_many";
case FindApproxPath::CT_match_pointer:
return out << "match_pointer";
};
return out << "**invalid**";
};