Panda3D
|
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