Panda3D

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
20 using std::ostream;
21 using std::string;
22
23
24 /**
25 * Returns true if the indicated node matches this component, false otherwise.
26 */
27 bool FindApproxPath::Component::
28 matches(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 */
82 void FindApproxPath::Component::
83 output(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 */
116 bool FindApproxPath::
117 add_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 */
163 bool FindApproxPath::
164 add_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 */
219 bool FindApproxPath::
220 add_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 */
287 void FindApproxPath::
288 add_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 */
300 void FindApproxPath::
301 add_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 */
321 void FindApproxPath::
322 add_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 */
334 void FindApproxPath::
335 add_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 */
347 void FindApproxPath::
348 add_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 */
361 void FindApproxPath::
362 add_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 */
374 void FindApproxPath::
375 add_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 */
385 void FindApproxPath::
386 add_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 */
396 void FindApproxPath::
397 add_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 */
408 void FindApproxPath::
409 output(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
423 ostream &
424 operator << (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 };
FindApproxPath::add_match_one
void add_match_one(int flags)
Adds a component that will match any node (but not a chain of many nodes).
Definition: findApproxPath.cxx:375
FindApproxPath::add_flags
bool add_flags(const std::string &str_flags)
Adds a sequence of control flags.
Definition: findApproxPath.cxx:164
FindApproxPath::add_match_exact_type
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.
Definition: findApproxPath.cxx:322
FindApproxPath::add_match_tag_value
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.
Definition: findApproxPath.cxx:362
FindApproxPath::add_component
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 ...
Definition: findApproxPath.cxx:220
FindApproxPath::add_match_tag
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...
Definition: findApproxPath.cxx:348
FindApproxPath::add_match_inexact_type
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.
Definition: findApproxPath.cxx:335
FindApproxPath::add_match_many
void add_match_many(int flags)
Adds a component that will match a chain of zero or more consecutive nodes.
Definition: findApproxPath.cxx:386
FindApproxPath::add_string
bool add_string(const std::string &str_path)
Adds a sequence of components separated by slashes, followed optionally by a semicolon and a sequence...
Definition: findApproxPath.cxx:117
FindApproxPath::add_match_name
void add_match_name(const std::string &name, int flags)
Adds a component that must match the name of a node exactly.
Definition: findApproxPath.cxx:288
FindApproxPath::add_match_pointer
void add_match_pointer(PandaNode *pointer, int flags)
Adds a component that must match a particular node exactly, by pointer.
Definition: findApproxPath.cxx:397
FindApproxPath::add_match_name_glob
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,...
Definition: findApproxPath.cxx:301
PandaNode
A basic node of the scene graph or data graph.
Definition: pandaNode.h:65
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
TypeRegistry::ptr
static TypeRegistry * ptr()
Returns the pointer to the global TypeRegistry object.
Definition: typeRegistry.I:30
TypeRegistry::find_type
TypeHandle find_type(const std::string &name) const
Looks for a previously-registered type of the given name.
Definition: typeRegistry.cxx:233
TypedObject::is_exact_type
bool is_exact_type(TypeHandle handle) const
Returns true if the current object is the indicated type exactly.
Definition: typedObject.I:38
TypedObject::is_of_type
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
config_pgraph.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
findApproxPath.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pandaNode.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.