Panda3D
 All Classes Functions Variables Enumerations
findApproxPath.cxx
00001 // Filename: findApproxPath.cxx
00002 // Created by:  drose (13Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "findApproxPath.h"
00016 #include "config_pgraph.h"
00017 
00018 #include "string_utils.h"
00019 #include "pandaNode.h"
00020 
00021 
00022 ////////////////////////////////////////////////////////////////////
00023 //     Function: FindApproxPath::Component::matches
00024 //       Access: Public
00025 //  Description: Returns true if the indicated node matches this
00026 //               component, false otherwise.
00027 ////////////////////////////////////////////////////////////////////
00028 bool FindApproxPath::Component::
00029 matches(PandaNode *node) const {
00030   string node_name;
00031 
00032   switch (_type) {
00033   case CT_match_name:
00034     // Match the node's name exactly.
00035     return (_name == node->get_name());
00036 
00037   case CT_match_name_insensitive:
00038     // Match the node's name exactly, with case-insensitive comparison.
00039     return cmp_nocase(_name, node->get_name()) == 0;
00040 
00041   case CT_match_name_glob:
00042     // Match the node's name according to filename globbing rules.
00043     return (_glob.matches(node->get_name()));
00044 
00045   case CT_match_exact_type:
00046     // Match the node's type exactly.
00047     return (node->is_exact_type(_type_handle));
00048 
00049   case CT_match_inexact_type:
00050     // Match the node's type inexactly: it's a match if the node
00051     // is the type, or is derived from the type.
00052     return (node->is_of_type(_type_handle));
00053 
00054   case CT_match_tag:
00055     // Match the node's tag only.
00056     return (node->has_tag(_name));
00057 
00058   case CT_match_tag_value:
00059     // Match the node's tag and value.
00060     if (node->has_tag(_name)) {
00061       return _glob.matches(node->get_tag(_name));
00062     }
00063     return false;
00064 
00065   case CT_match_one:
00066   case CT_match_many:
00067     // Match any node.
00068     return true;
00069 
00070   case CT_match_pointer:
00071     // Match only this one particular node.
00072     return (_pointer == node);
00073   }
00074 
00075   pgraph_cat.error()
00076     << "Invalid component in FindApproxPath\n";
00077   return false;
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: FindApproxPath::Component::output
00082 //       Access: Public
00083 //  Description:
00084 ////////////////////////////////////////////////////////////////////
00085 void FindApproxPath::Component::
00086 output(ostream &out) const {
00087   out << _type;
00088   switch (_type) {
00089   case CT_match_name:
00090   case CT_match_name_insensitive:
00091   case CT_match_name_glob:
00092   case CT_match_tag:
00093     out << " \"" << _name << "\"";
00094     break;
00095 
00096   case CT_match_tag_value:
00097     out << " \"" << _name << "\"=\"" << _glob << "\"";
00098     break;
00099 
00100   case CT_match_exact_type:
00101   case CT_match_inexact_type:
00102     out << " " << _type_handle;
00103     break;
00104 
00105   case CT_match_pointer:
00106     out << " (" << *_pointer << ")";
00107     break;
00108 
00109   default:
00110     break;
00111   }
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: FindApproxPath::add_string
00116 //       Access: Public
00117 //  Description: Adds a sequence of components separated by slashes,
00118 //               followed optionally by a semicolon and a sequence of
00119 //               control flags, to the path sequence.  Returns true if
00120 //               successful, false if the string contained an error.
00121 ////////////////////////////////////////////////////////////////////
00122 bool FindApproxPath::
00123 add_string(const string &str_path) {
00124   // First, chop the string up by slashes into its components.
00125   vector_string components;
00126 
00127   size_t start = 0;
00128   size_t slash = str_path.find('/');
00129   while (slash != string::npos) {
00130     components.push_back(str_path.substr(start, slash - start));
00131     start = slash + 1;
00132     slash = str_path.find('/', start);
00133   }
00134 
00135   size_t semicolon = str_path.rfind(';');
00136 
00137   // We want to find the *last* semicolon at start or later, if there
00138   // happens to be more than one.  rfind will find the rightmost
00139   // semicolon in the entire string; if this is less than start, there
00140   // is no semicolon right of start.
00141   if (semicolon < start) {
00142     semicolon = string::npos;
00143   }
00144 
00145   components.push_back(str_path.substr(start, semicolon - start));
00146 
00147   if (semicolon != string::npos) {
00148     if (!add_flags(str_path.substr(semicolon + 1))) {
00149       return false;
00150     }
00151   }
00152 
00153   // Now decode each component and add it to the path.
00154   vector_string::const_iterator ci;
00155   for (ci = components.begin(); ci != components.end(); ++ci) {
00156     if (!add_component(*ci)) {
00157       return false;
00158     }
00159   }
00160 
00161   return true;
00162 }
00163 
00164 ////////////////////////////////////////////////////////////////////
00165 //     Function: FindApproxPath::add_flags
00166 //       Access: Public
00167 //  Description: Adds a sequence of control flags.  This will be a
00168 //               sequence of letters preceded by either '+' or '-',
00169 //               with no intervening punctuation.  Returns true if
00170 //               successful, false otherwise.
00171 ////////////////////////////////////////////////////////////////////
00172 bool FindApproxPath::
00173 add_flags(const string &str_flags) {
00174   string::const_iterator pi = str_flags.begin();
00175   while (pi != str_flags.end()) {
00176     bool on;
00177     switch (*pi) {
00178     case '+':
00179       on = true;
00180       break;
00181     case '-':
00182       on = false;
00183       break;
00184     default:
00185       pgraph_cat.error()
00186         << "Invalid control flag string: " << str_flags << "\n";
00187       return false;
00188     }
00189 
00190     ++pi;
00191     if (pi == str_flags.end()) {
00192       pgraph_cat.error()
00193         << "Invalid control flag string: " << str_flags << "\n";
00194       return false;
00195     }
00196 
00197     switch (*pi) {
00198     case 'h':
00199       _return_hidden = on;
00200       break;
00201 
00202     case 's':
00203       _return_stashed = on;
00204       break;
00205 
00206     case 'i':
00207       _case_insensitive = on;
00208       break;
00209 
00210     default:
00211       pgraph_cat.error()
00212         << "Invalid control flag string: " << str_flags << "\n";
00213       return false;
00214     }
00215 
00216     ++pi;
00217   }
00218 
00219   return true;
00220 }
00221 
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //     Function: FindApproxPath::add_component
00225 //       Access: Public
00226 //  Description: Adds a single component to the path sequence, defined
00227 //               by a string as might appear between slashes in the
00228 //               path string.  Returns true if successful, false if
00229 //               the string component was in some way invalid.
00230 ////////////////////////////////////////////////////////////////////
00231 bool FindApproxPath::
00232 add_component(string str_component) {
00233   int flags = 0;
00234   if (str_component.size() >= 2 && str_component.substr(0, 2) == "@@") {
00235     flags |= CF_stashed;
00236     str_component = str_component.substr(2);
00237   }
00238 
00239   if (str_component == "*") {
00240     add_match_one(flags);
00241 
00242   } else if (str_component == "**") {
00243     if ((flags & CF_stashed) != 0) {
00244       pgraph_cat.error()
00245         << "@@** is undefined; use @@*/** or **/@@* instead.\n";
00246       return false;
00247     }
00248     add_match_many(flags);
00249 
00250   } else if (!str_component.empty() && str_component[0] == '-') {
00251     string type_name = str_component.substr(1);
00252     TypeHandle handle = TypeRegistry::ptr()->find_type(type_name);
00253 
00254     if (handle == TypeHandle::none()) {
00255       pgraph_cat.error()
00256         << "Invalid type name: " << type_name << "\n";
00257       return false;
00258 
00259     } else {
00260       add_match_exact_type(handle, flags);
00261     }
00262 
00263   } else if (!str_component.empty() && str_component[0] == '+') {
00264     string type_name = str_component.substr(1);
00265     TypeHandle handle = TypeRegistry::ptr()->find_type(type_name);
00266 
00267     if (handle == TypeHandle::none()) {
00268       pgraph_cat.error()
00269         << "Invalid type name: " << type_name << "\n";
00270       return false;
00271 
00272     } else {
00273       add_match_inexact_type(handle, flags);
00274     }
00275 
00276   } else if (!str_component.empty() && str_component[0] == '=') {
00277     size_t equals = str_component.find('=', 1);
00278     if (equals != string::npos) {
00279       // =key=value
00280       string tag_key = str_component.substr(1, equals - 1);
00281       string tag_value = str_component.substr(equals + 1);
00282       add_match_tag_value(tag_key, tag_value, flags);
00283     } else {
00284       // =key
00285       string tag_key = str_component.substr(1);
00286       add_match_tag(tag_key, flags);
00287     }
00288 
00289   } else {
00290     add_match_name_glob(str_component, flags);
00291   }
00292 
00293   return true;
00294 }
00295 
00296 ////////////////////////////////////////////////////////////////////
00297 //     Function: FindApproxPath::add_match_name
00298 //       Access: Public
00299 //  Description: Adds a component that must match the name of a node
00300 //               exactly.
00301 ////////////////////////////////////////////////////////////////////
00302 void FindApproxPath::
00303 add_match_name(const string &name, int flags) {
00304   Component comp;
00305   comp._type = _case_insensitive ? CT_match_name_insensitive : CT_match_name;
00306   comp._name = name;
00307   comp._flags = flags;
00308   _path.push_back(comp);
00309 }
00310 
00311 ////////////////////////////////////////////////////////////////////
00312 //     Function: FindApproxPath::add_match_name_glob
00313 //       Access: Public
00314 //  Description: Adds a component that must match the name of a node
00315 //               using standard shell globbing rules, with wildcard
00316 //               characters accepted.
00317 ////////////////////////////////////////////////////////////////////
00318 void FindApproxPath::
00319 add_match_name_glob(const string &name, int flags) {
00320   Component comp;
00321   comp._type = CT_match_name_glob;
00322   comp._name = name;
00323   comp._glob.set_pattern(name);
00324   comp._glob.set_case_sensitive(!_case_insensitive);
00325   comp._flags = flags;
00326   if (!comp._glob.has_glob_characters()) {
00327     // The glob pattern contains no special characters; make it a
00328     // literal match for efficiency.
00329     add_match_name(name, flags);
00330   } else {
00331     _path.push_back(comp);
00332   }
00333 }
00334 
00335 ////////////////////////////////////////////////////////////////////
00336 //     Function: FindApproxPath::add_match_exact_type
00337 //       Access: Public
00338 //  Description: Adds a component that must match the type of a node
00339 //               exactly, with no derived types matching.
00340 ////////////////////////////////////////////////////////////////////
00341 void FindApproxPath::
00342 add_match_exact_type(TypeHandle type, int flags) {
00343   Component comp;
00344   comp._type = CT_match_exact_type;
00345   comp._type_handle = type;
00346   comp._flags = flags;
00347   _path.push_back(comp);
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: FindApproxPath::add_match_inexact_type
00352 //       Access: Public
00353 //  Description: Adds a component that must match the type of a node
00354 //               or be a base class of the node's type.
00355 ////////////////////////////////////////////////////////////////////
00356 void FindApproxPath::
00357 add_match_inexact_type(TypeHandle type, int flags) {
00358   Component comp;
00359   comp._type = CT_match_inexact_type;
00360   comp._type_handle = type;
00361   comp._flags = flags;
00362   _path.push_back(comp);
00363 }
00364 
00365 ////////////////////////////////////////////////////////////////////
00366 //     Function: FindApproxPath::add_match_tag
00367 //       Access: Public
00368 //  Description: Adds a component that will match a node that has a
00369 //               tag with the indicated key, no matter what the value
00370 //               is.
00371 ////////////////////////////////////////////////////////////////////
00372 void FindApproxPath::
00373 add_match_tag(const string &name, int flags) {
00374   Component comp;
00375   comp._type = CT_match_tag;
00376   comp._name = name;
00377   comp._flags = flags;
00378   _path.push_back(comp);
00379 }
00380 
00381 ////////////////////////////////////////////////////////////////////
00382 //     Function: FindApproxPath::add_match_tag_value
00383 //       Access: Public
00384 //  Description: Adds a component that will match a node that has a
00385 //               tag with the indicated key.  The value may be "*" to
00386 //               match any value, or a particular glob pattern to
00387 //               match only those nodes with the indicated value.
00388 ////////////////////////////////////////////////////////////////////
00389 void FindApproxPath::
00390 add_match_tag_value(const string &name, const string &value, int flags) {
00391   Component comp;
00392   comp._type = CT_match_tag_value;
00393   comp._name = name;
00394   comp._glob.set_pattern(value);
00395   comp._flags = flags;
00396   _path.push_back(comp);
00397 }
00398 
00399 ////////////////////////////////////////////////////////////////////
00400 //     Function: FindApproxPath::add_match_one
00401 //       Access: Public
00402 //  Description: Adds a component that will match any node (but not a
00403 //               chain of many nodes).
00404 ////////////////////////////////////////////////////////////////////
00405 void FindApproxPath::
00406 add_match_one(int flags) {
00407   Component comp;
00408   comp._type = CT_match_one;
00409   comp._flags = flags;
00410   _path.push_back(comp);
00411 }
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: FindApproxPath::add_match_many
00415 //       Access: Public
00416 //  Description: Adds a component that will match a chain of zero or
00417 //               more consecutive nodes.
00418 ////////////////////////////////////////////////////////////////////
00419 void FindApproxPath::
00420 add_match_many(int flags) {
00421   Component comp;
00422   comp._type = CT_match_many;
00423   comp._flags = flags;
00424   _path.push_back(comp);
00425 }
00426 
00427 ////////////////////////////////////////////////////////////////////
00428 //     Function: FindApproxPath::add_match_pointer
00429 //       Access: Public
00430 //  Description: Adds a component that must match a particular node
00431 //               exactly, by pointer.
00432 ////////////////////////////////////////////////////////////////////
00433 void FindApproxPath::
00434 add_match_pointer(PandaNode *pointer, int flags) {
00435   Component comp;
00436   comp._type = CT_match_pointer;
00437   comp._pointer = pointer;
00438   comp._flags = flags;
00439   _path.push_back(comp);
00440 }
00441 
00442 ////////////////////////////////////////////////////////////////////
00443 //     Function: FindApproxPath::output
00444 //       Access: Public
00445 //  Description:
00446 ////////////////////////////////////////////////////////////////////
00447 void FindApproxPath::
00448 output(ostream &out) const {
00449   out << "(";
00450   if (!_path.empty()) {
00451     Path::const_iterator pi = _path.begin();
00452     out << *pi;
00453     ++pi;
00454     while (pi != _path.end()) {
00455       out << " / " << *pi;
00456       ++pi;
00457     }
00458   }
00459   out << ")";
00460 }
00461 
00462 ostream &
00463 operator << (ostream &out, FindApproxPath::ComponentType type) {
00464   switch (type) {
00465   case FindApproxPath::CT_match_name:
00466     return out << "match_name";
00467 
00468   case FindApproxPath::CT_match_name_insensitive:
00469     return out << "match_name_insensitive";
00470 
00471   case FindApproxPath::CT_match_name_glob:
00472     return out << "match_name_glob";
00473 
00474   case FindApproxPath::CT_match_exact_type:
00475     return out << "match_exact_type";
00476 
00477   case FindApproxPath::CT_match_inexact_type:
00478     return out << "match_inexact_type";
00479 
00480   case FindApproxPath::CT_match_tag:
00481     return out << "match_tag";
00482 
00483   case FindApproxPath::CT_match_tag_value:
00484     return out << "match_tag_value";
00485 
00486   case FindApproxPath::CT_match_one:
00487     return out << "match_one";
00488 
00489   case FindApproxPath::CT_match_many:
00490     return out << "match_many";
00491 
00492   case FindApproxPath::CT_match_pointer:
00493     return out << "match_pointer";
00494   };
00495 
00496   return out << "**invalid**";
00497 };
00498 
 All Classes Functions Variables Enumerations