Panda3D
Loading...
Searching...
No Matches
findApproxPath.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file findApproxPath.cxx
10 * @author drose
11 * @date 2002-03-13
12 */
13
14#include "findApproxPath.h"
15#include "config_pgraph.h"
16
17#include "string_utils.h"
18#include "pandaNode.h"
19
20using std::ostream;
21using std::string;
22
23
24/**
25 * Returns true if the indicated node matches this component, false otherwise.
26 */
27bool FindApproxPath::Component::
28matches(PandaNode *node) const {
29 string node_name;
30
31 switch (_type) {
32 case CT_match_name:
33 // Match the node's name exactly.
34 return (_name == node->get_name());
35
36 case CT_match_name_insensitive:
37 // Match the node's name exactly, with case-insensitive comparison.
38 return cmp_nocase(_name, node->get_name()) == 0;
39
40 case CT_match_name_glob:
41 // Match the node's name according to filename globbing rules.
42 return (_glob.matches(node->get_name()));
43
44 case CT_match_exact_type:
45 // Match the node's type exactly.
46 return (node->is_exact_type(_type_handle));
47
48 case CT_match_inexact_type:
49 // Match the node's type inexactly: it's a match if the node is the type,
50 // or is derived from the type.
51 return (node->is_of_type(_type_handle));
52
53 case CT_match_tag:
54 // Match the node's tag only.
55 return (node->has_tag(_name));
56
57 case CT_match_tag_value:
58 // Match the node's tag and value.
59 if (node->has_tag(_name)) {
60 return _glob.matches(node->get_tag(_name));
61 }
62 return false;
63
64 case CT_match_one:
65 case CT_match_many:
66 // Match any node.
67 return true;
68
69 case CT_match_pointer:
70 // Match only this one particular node.
71 return (_pointer == node);
72 }
73
74 pgraph_cat.error()
75 << "Invalid component in FindApproxPath\n";
76 return false;
77}
78
79/**
80 *
81 */
82void FindApproxPath::Component::
83output(ostream &out) const {
84 out << _type;
85 switch (_type) {
86 case CT_match_name:
87 case CT_match_name_insensitive:
88 case CT_match_name_glob:
89 case CT_match_tag:
90 out << " \"" << _name << "\"";
91 break;
92
93 case CT_match_tag_value:
94 out << " \"" << _name << "\"=\"" << _glob << "\"";
95 break;
96
97 case CT_match_exact_type:
98 case CT_match_inexact_type:
99 out << " " << _type_handle;
100 break;
101
102 case CT_match_pointer:
103 out << " (" << *_pointer << ")";
104 break;
105
106 default:
107 break;
108 }
109}
110
111/**
112 * Adds a sequence of components separated by slashes, followed optionally by
113 * a semicolon and a sequence of control flags, to the path sequence. Returns
114 * true if successful, false if the string contained an error.
115 */
117add_string(const string &str_path) {
118 // First, chop the string up by slashes into its components.
119 vector_string components;
120
121 size_t start = 0;
122 size_t slash = str_path.find('/');
123 while (slash != string::npos) {
124 components.push_back(str_path.substr(start, slash - start));
125 start = slash + 1;
126 slash = str_path.find('/', start);
127 }
128
129 size_t semicolon = str_path.rfind(';');
130
131 // We want to find the *last* semicolon at start or later, if there happens
132 // to be more than one. rfind will find the rightmost semicolon in the
133 // entire string; if this is less than start, there is no semicolon right of
134 // start.
135 if (semicolon < start) {
136 semicolon = string::npos;
137 }
138
139 components.push_back(str_path.substr(start, semicolon - start));
140
141 if (semicolon != string::npos) {
142 if (!add_flags(str_path.substr(semicolon + 1))) {
143 return false;
144 }
145 }
146
147 // Now decode each component and add it to the path.
148 vector_string::const_iterator ci;
149 for (ci = components.begin(); ci != components.end(); ++ci) {
150 if (!add_component(*ci)) {
151 return false;
152 }
153 }
154
155 return true;
156}
157
158/**
159 * Adds a sequence of control flags. This will be a sequence of letters
160 * preceded by either '+' or '-', with no intervening punctuation. Returns
161 * true if successful, false otherwise.
162 */
164add_flags(const string &str_flags) {
165 string::const_iterator pi = str_flags.begin();
166 while (pi != str_flags.end()) {
167 bool on;
168 switch (*pi) {
169 case '+':
170 on = true;
171 break;
172 case '-':
173 on = false;
174 break;
175 default:
176 pgraph_cat.error()
177 << "Invalid control flag string: " << str_flags << "\n";
178 return false;
179 }
180
181 ++pi;
182 if (pi == str_flags.end()) {
183 pgraph_cat.error()
184 << "Invalid control flag string: " << str_flags << "\n";
185 return false;
186 }
187
188 switch (*pi) {
189 case 'h':
190 _return_hidden = on;
191 break;
192
193 case 's':
194 _return_stashed = on;
195 break;
196
197 case 'i':
198 _case_insensitive = on;
199 break;
200
201 default:
202 pgraph_cat.error()
203 << "Invalid control flag string: " << str_flags << "\n";
204 return false;
205 }
206
207 ++pi;
208 }
209
210 return true;
211}
212
213
214/**
215 * Adds a single component to the path sequence, defined by a string as might
216 * appear between slashes in the path string. Returns true if successful,
217 * false if the string component was in some way invalid.
218 */
220add_component(string str_component) {
221 int flags = 0;
222 if (str_component.size() >= 2 && str_component.substr(0, 2) == "@@") {
223 flags |= CF_stashed;
224 str_component = str_component.substr(2);
225 }
226
227 if (str_component == "*") {
228 add_match_one(flags);
229
230 } else if (str_component == "**") {
231 if ((flags & CF_stashed) != 0) {
232 pgraph_cat.error()
233 << "@@** is undefined; use @@*/** or **/@@* instead.\n";
234 return false;
235 }
236 add_match_many(flags);
237
238 } else if (!str_component.empty() && str_component[0] == '-') {
239 string type_name = str_component.substr(1);
240 TypeHandle handle = TypeRegistry::ptr()->find_type(type_name);
241
242 if (handle == TypeHandle::none()) {
243 pgraph_cat.error()
244 << "Invalid type name: " << type_name << "\n";
245 return false;
246
247 } else {
248 add_match_exact_type(handle, flags);
249 }
250
251 } else if (!str_component.empty() && str_component[0] == '+') {
252 string type_name = str_component.substr(1);
253 TypeHandle handle = TypeRegistry::ptr()->find_type(type_name);
254
255 if (handle == TypeHandle::none()) {
256 pgraph_cat.error()
257 << "Invalid type name: " << type_name << "\n";
258 return false;
259
260 } else {
261 add_match_inexact_type(handle, flags);
262 }
263
264 } else if (!str_component.empty() && str_component[0] == '=') {
265 size_t equals = str_component.find('=', 1);
266 if (equals != string::npos) {
267 // =key=value
268 string tag_key = str_component.substr(1, equals - 1);
269 string tag_value = str_component.substr(equals + 1);
270 add_match_tag_value(tag_key, tag_value, flags);
271 } else {
272 // =key
273 string tag_key = str_component.substr(1);
274 add_match_tag(tag_key, flags);
275 }
276
277 } else {
278 add_match_name_glob(str_component, flags);
279 }
280
281 return true;
282}
283
284/**
285 * Adds a component that must match the name of a node exactly.
286 */
288add_match_name(const string &name, int flags) {
289 Component comp;
290 comp._type = _case_insensitive ? CT_match_name_insensitive : CT_match_name;
291 comp._name = name;
292 comp._flags = flags;
293 _path.push_back(comp);
294}
295
296/**
297 * Adds a component that must match the name of a node using standard shell
298 * globbing rules, with wildcard characters accepted.
299 */
301add_match_name_glob(const string &name, int flags) {
302 Component comp;
303 comp._type = CT_match_name_glob;
304 comp._name = name;
305 comp._glob.set_pattern(name);
306 comp._glob.set_case_sensitive(!_case_insensitive);
307 comp._flags = flags;
308 if (!comp._glob.has_glob_characters()) {
309 // The glob pattern contains no special characters; make it a literal
310 // match for efficiency.
311 add_match_name(name, flags);
312 } else {
313 _path.push_back(comp);
314 }
315}
316
317/**
318 * Adds a component that must match the type of a node exactly, with no
319 * derived types matching.
320 */
322add_match_exact_type(TypeHandle type, int flags) {
323 Component comp;
324 comp._type = CT_match_exact_type;
325 comp._type_handle = type;
326 comp._flags = flags;
327 _path.push_back(comp);
328}
329
330/**
331 * Adds a component that must match the type of a node or be a base class of
332 * the node's type.
333 */
335add_match_inexact_type(TypeHandle type, int flags) {
336 Component comp;
337 comp._type = CT_match_inexact_type;
338 comp._type_handle = type;
339 comp._flags = flags;
340 _path.push_back(comp);
341}
342
343/**
344 * Adds a component that will match a node that has a tag with the indicated
345 * key, no matter what the value is.
346 */
348add_match_tag(const string &name, int flags) {
349 Component comp;
350 comp._type = CT_match_tag;
351 comp._name = name;
352 comp._flags = flags;
353 _path.push_back(comp);
354}
355
356/**
357 * Adds a component that will match a node that has a tag with the indicated
358 * key. The value may be "*" to match any value, or a particular glob pattern
359 * to match only those nodes with the indicated value.
360 */
362add_match_tag_value(const string &name, const string &value, int flags) {
363 Component comp;
364 comp._type = CT_match_tag_value;
365 comp._name = name;
366 comp._glob.set_pattern(value);
367 comp._flags = flags;
368 _path.push_back(comp);
369}
370
371/**
372 * Adds a component that will match any node (but not a chain of many nodes).
373 */
375add_match_one(int flags) {
376 Component comp;
377 comp._type = CT_match_one;
378 comp._flags = flags;
379 _path.push_back(comp);
380}
381
382/**
383 * Adds a component that will match a chain of zero or more consecutive nodes.
384 */
386add_match_many(int flags) {
387 Component comp;
388 comp._type = CT_match_many;
389 comp._flags = flags;
390 _path.push_back(comp);
391}
392
393/**
394 * Adds a component that must match a particular node exactly, by pointer.
395 */
397add_match_pointer(PandaNode *pointer, int flags) {
398 Component comp;
399 comp._type = CT_match_pointer;
400 comp._pointer = pointer;
401 comp._flags = flags;
402 _path.push_back(comp);
403}
404
405/**
406 *
407 */
408void FindApproxPath::
409output(ostream &out) const {
410 out << "(";
411 if (!_path.empty()) {
412 Path::const_iterator pi = _path.begin();
413 out << *pi;
414 ++pi;
415 while (pi != _path.end()) {
416 out << " / " << *pi;
417 ++pi;
418 }
419 }
420 out << ")";
421}
422
423ostream &
424operator << (ostream &out, FindApproxPath::ComponentType type) {
425 switch (type) {
426 case FindApproxPath::CT_match_name:
427 return out << "match_name";
428
429 case FindApproxPath::CT_match_name_insensitive:
430 return out << "match_name_insensitive";
431
432 case FindApproxPath::CT_match_name_glob:
433 return out << "match_name_glob";
434
435 case FindApproxPath::CT_match_exact_type:
436 return out << "match_exact_type";
437
438 case FindApproxPath::CT_match_inexact_type:
439 return out << "match_inexact_type";
440
441 case FindApproxPath::CT_match_tag:
442 return out << "match_tag";
443
444 case FindApproxPath::CT_match_tag_value:
445 return out << "match_tag_value";
446
447 case FindApproxPath::CT_match_one:
448 return out << "match_one";
449
450 case FindApproxPath::CT_match_many:
451 return out << "match_many";
452
453 case FindApproxPath::CT_match_pointer:
454 return out << "match_pointer";
455 };
456
457 return out << "**invalid**";
458};
void add_match_one(int flags)
Adds a component that will match any node (but not a chain of many nodes).
bool add_flags(const std::string &str_flags)
Adds a sequence of control flags.
void add_match_exact_type(TypeHandle type, int flags)
Adds a component that must match the type of a node exactly, with no derived types matching.
void add_match_tag_value(const std::string &key, const std::string &value, int flags)
Adds a component that will match a node that has a tag with the indicated key.
bool add_component(std::string str_component)
Adds a single component to the path sequence, defined by a string as might appear between slashes in ...
void add_match_tag(const std::string &key, int flags)
Adds a component that will match a node that has a tag with the indicated key, no matter what the val...
void add_match_inexact_type(TypeHandle type, int flags)
Adds a component that must match the type of a node or be a base class of the node's type.
void add_match_many(int flags)
Adds a component that will match a chain of zero or more consecutive nodes.
bool add_string(const std::string &str_path)
Adds a sequence of components separated by slashes, followed optionally by a semicolon and a sequence...
void add_match_name(const std::string &name, int flags)
Adds a component that must match the name of a node exactly.
void add_match_pointer(PandaNode *pointer, int flags)
Adds a component that must match a particular node exactly, by pointer.
void add_match_name_glob(const std::string &glob, int flags)
Adds a component that must match the name of a node using standard shell globbing rules,...
set_pattern
Changes the pattern string that the GlobPattern object matches.
Definition globPattern.h:44
bool has_glob_characters() const
Returns true if the pattern includes any special globbing characters, or false if it is just a litera...
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
set_case_sensitive
Sets whether the match is case sensitive (true) or case insensitive (false).
Definition globPattern.h:48
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
static TypeRegistry * ptr()
Returns the pointer to the global TypeRegistry object.
TypeHandle find_type(const std::string &name) const
Looks for a previously-registered type of the given name.
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition typedObject.I:38
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.