Branch data Line data Source code
1 : : // props.cxx - implementation of a property list.
2 : : // Started Fall 2000 by David Megginson, david@megginson.com
3 : : // This code is released into the Public Domain.
4 : : //
5 : : // See props.html for documentation [replace with URL when available].
6 : : //
7 : : // $Id: props.cxx,v 1.5 2009/10/03 18:23:01 andgi Exp $
8 : :
9 : : #include "props.hxx"
10 : :
11 : : #include <algorithm>
12 : : #include <sstream>
13 : : #include <stdio.h>
14 : : #include <string.h>
15 : :
16 : : #if PROPS_STANDALONE
17 : :
18 : : #include <iostream>
19 : : #include <ctype.h>
20 : : #include <stdlib.h>
21 : : using std::cerr;
22 : : using std::endl;
23 : : using std::find;
24 : : using std::sort;
25 : : using std::vector;
26 : : using std::stringstream;
27 : :
28 : : #else
29 : :
30 : : #include <simgear/compiler.h>
31 : : #include <simgear/debug/logstream.hxx>
32 : :
33 : : SG_USING_STD(sort);
34 : : SG_USING_STD(find);
35 : : SG_USING_STD(vector);
36 : : SG_USING_STD(stringstream);
37 : :
38 : : #if ( _MSC_VER == 1200 )
39 : : // MSVC 6 is buggy, and needs something strange here
40 : : SG_USING_STD(vector<SGPropertyNode_ptr>);
41 : : SG_USING_STD(vector<SGPropertyChangeListener *>);
42 : : SG_USING_STD(vector<SGPropertyNode *>);
43 : : #endif
44 : :
45 : : #endif
46 : :
47 : :
48 : :
49 : : ////////////////////////////////////////////////////////////////////////
50 : : // Local classes.
51 : : ////////////////////////////////////////////////////////////////////////
52 : :
53 : : /**
54 : : * Comparator class for sorting by index.
55 : : */
56 : : class CompareIndices
57 : : {
58 : : public:
59 : : int operator() (const SGPropertyNode_ptr n1, const SGPropertyNode_ptr n2) const {
60 : 0 : return (n1->getIndex() < n2->getIndex());
61 : : }
62 : : };
63 : :
64 : :
65 : :
66 : : ////////////////////////////////////////////////////////////////////////
67 : : // Convenience macros for value access.
68 : : ////////////////////////////////////////////////////////////////////////
69 : :
70 : : #define TEST_READ(dflt) if (!getAttribute(READ)) return dflt
71 : : #define TEST_WRITE if (!getAttribute(WRITE)) return false
72 : :
73 : :
74 : :
75 : : ////////////////////////////////////////////////////////////////////////
76 : : // Default values for every type.
77 : : ////////////////////////////////////////////////////////////////////////
78 : :
79 : : template<> const bool SGRawValue<bool>::DefaultValue = false;
80 : : template<> const int SGRawValue<int>::DefaultValue = 0;
81 : : template<> const long SGRawValue<long>::DefaultValue = 0L;
82 : : template<> const float SGRawValue<float>::DefaultValue = 0.0;
83 : : template<> const double SGRawValue<double>::DefaultValue = 0.0L;
84 : : template<> const char * const SGRawValue<const char *>::DefaultValue = "";
85 : :
86 : :
87 : :
88 : : ////////////////////////////////////////////////////////////////////////
89 : : // Local path normalization code.
90 : : ////////////////////////////////////////////////////////////////////////
91 : :
92 : : /**
93 : : * A component in a path.
94 : : */
95 : : struct PathComponent
96 : 34936 : {
97 : : string name;
98 : : int index;
99 : : };
100 : :
101 : : /**
102 : : * Parse the name for a path component.
103 : : *
104 : : * Name: [_a-zA-Z][-._a-zA-Z0-9]*
105 : : */
106 : : static inline const string
107 : : parse_name (const string &path, int &i)
108 : : {
109 : 4256 : string name = "";
110 : 4256 : int max = (int)path.size();
111 : :
112 [ - + ]: 4256 : if (path[i] == '.') {
113 : 0 : i++;
114 [ # # ][ # # ]: 0 : if (i < max && path[i] == '.') {
[ # # ]
115 : 0 : i++;
116 : 0 : name = "..";
117 : : } else {
118 : 0 : name = ".";
119 : : }
120 [ # # ][ # # ]: 0 : if (i < max && path[i] != '/')
[ # # ]
121 : 0 : throw string("Illegal character after " + name);
122 : : }
123 : :
124 [ - + ][ # # ]: 4256 : else if (isalpha(path[i]) || path[i] == '_') {
[ + - ]
125 : 8512 : name += path[i];
126 : 4256 : i++;
127 : :
128 : : // The rules inside a name are a little
129 : : // less restrictive.
130 [ + + ]: 36798 : while (i < max) {
131 [ + + ][ + + ]: 35820 : if (isalpha(path[i]) || isdigit(path[i]) || path[i] == '_' ||
[ + + ][ + + ]
[ - + ][ + + ]
132 : : path[i] == '-' || path[i] == '.') {
133 : 65084 : name += path[i];
134 [ + + ][ + - ]: 3278 : } else if (path[i] == '[' || path[i] == '/') {
[ - + ]
135 : : break;
136 : : } else {
137 : 0 : throw string("name may contain only ._- and alphanumeric characters");
138 : : }
139 : 32542 : i++;
140 : : }
141 : : }
142 : :
143 : : else {
144 [ # # ]: 0 : if (name.size() == 0)
145 : 0 : throw string("name must begin with alpha or '_'");
146 : : }
147 : :
148 : 0 : return name;
149 : : }
150 : :
151 : :
152 : : /**
153 : : * Parse the optional integer index for a path component.
154 : : *
155 : : * Index: "[" [0-9]+ "]"
156 : : */
157 : : static inline int
158 : : parse_index (const string &path, int &i)
159 : : {
160 : 4256 : int index = 0;
161 : :
162 [ + + ]: 4256 : if (path[i] != '[')
163 : 3711 : return 0;
164 : : else
165 : 545 : i++;
166 : :
167 [ + - ]: 1226 : for (int max = (int)path.size(); i < max; i++) {
168 [ + + ]: 1226 : if (isdigit(path[i])) {
169 : 1362 : index = (index * 10) + (path[i] - '0');
170 [ + - ]: 545 : } else if (path[i] == ']') {
171 : 545 : i++;
172 : 545 : return index;
173 : : } else {
174 : : break;
175 : : }
176 : : }
177 : :
178 : 0 : throw string("unterminated index (looking for ']')");
179 : : }
180 : :
181 : :
182 : : /**
183 : : * Parse a single path component.
184 : : *
185 : : * Component: Name Index?
186 : : */
187 : : static inline PathComponent
188 : 4256 : parse_component (const string &path, int &i)
189 : : {
190 : 4256 : PathComponent component;
191 : 4256 : component.name = parse_name(path, i);
192 [ + - ]: 4256 : if (component.name[0] != '.')
193 : 4256 : component.index = parse_index(path, i);
194 : : else
195 : 0 : component.index = -1;
196 : 0 : return component;
197 : : }
198 : :
199 : :
200 : : /**
201 : : * Parse a path into its components.
202 : : */
203 : : static void
204 : 1310 : parse_path (const string &path, vector<PathComponent> &components)
205 : : {
206 : 1310 : int pos = 0;
207 : 1310 : int max = (int)path.size();
208 : :
209 : : // Check for initial '/'
210 [ + + ]: 1310 : if (path[pos] == '/') {
211 : : PathComponent root;
212 : : root.name = "";
213 : 652 : root.index = -1;
214 : 652 : components.push_back(root);
215 : 652 : pos++;
216 [ + - ][ - + ]: 652 : while (pos < max && path[pos] == '/')
[ - + ]
217 : 0 : pos++;
218 : : }
219 : :
220 [ + + ]: 5566 : while (pos < max) {
221 : 4256 : components.push_back(parse_component(path, pos));
222 [ + + ][ + + ]: 7202 : while (pos < max && path[pos] == '/')
[ + + ]
223 : 2946 : pos++;
224 : : }
225 : 1310 : }
226 : :
227 : :
228 : :
229 : : ////////////////////////////////////////////////////////////////////////
230 : : // Other static utility functions.
231 : : ////////////////////////////////////////////////////////////////////////
232 : :
233 : :
234 : : static char *
235 : 0 : copy_string (const char * s)
236 : : {
237 : : // FIXME: potential buffer overflow.
238 : : // For some reason, strnlen and
239 : : // strncpy cause all kinds of crashes.
240 : 0 : char * copy = new char[strlen(s) + 1];
241 : 0 : strcpy(copy, s);
242 : 0 : return copy;
243 : : }
244 : :
245 : : static bool
246 : : compare_strings (const char * s1, const char * s2)
247 : : {
248 : 55803 : return !strncmp(s1, s2, SGPropertyNode::MAX_STRING_LEN);
249 : : }
250 : :
251 : : /**
252 : : * Locate a child node by name and index.
253 : : */
254 : : static int
255 : 4954 : find_child (const char * name, int index, vector<SGPropertyNode_ptr> nodes)
256 : : {
257 : 4954 : int nNodes = nodes.size();
258 [ + + ]: 57211 : for (int i = 0; i < nNodes; i++) {
259 : 111606 : SGPropertyNode * node = nodes[i];
260 [ + + ][ + + ]: 55803 : if (compare_strings(node->getName(), name) && node->getIndex() == index)
[ + + ]
261 : 3546 : return i;
262 : : }
263 : 4954 : return -1;
264 : : }
265 : :
266 : :
267 : : /**
268 : : * Locate another node, given a relative path.
269 : : */
270 : : static SGPropertyNode *
271 : : find_node (SGPropertyNode * current,
272 : : const vector<PathComponent> &components,
273 : : int position,
274 : 6215 : bool create)
275 : : {
276 : : // Run off the end of the list
277 [ + + ]: 6215 : if (current == 0) {
278 : 6 : return 0;
279 : : }
280 : :
281 : : // Success! This is the one we want.
282 [ + + ]: 6209 : else if (position >= (int)components.size()) {
283 [ - + ]: 1304 : return (current->getAttribute(SGPropertyNode::REMOVED) ? 0 : current);
284 : : }
285 : :
286 : : // Empty component means root.
287 [ + + ]: 4905 : else if (components[position].name == "") {
288 : 652 : return find_node(current->getRootNode(), components, position + 1, create);
289 : : }
290 : :
291 : : // . means current directory
292 [ - + ]: 4253 : else if (components[position].name == ".") {
293 : 0 : return find_node(current, components, position + 1, create);
294 : : }
295 : :
296 : : // .. means parent directory
297 [ - + ]: 4253 : else if (components[position].name == "..") {
298 : 0 : SGPropertyNode * parent = current->getParent();
299 [ # # ]: 0 : if (parent == 0)
300 : 0 : throw string("Attempt to move past root with '..'");
301 : : else
302 : 0 : return find_node(parent, components, position + 1, create);
303 : : }
304 : :
305 : : // Otherwise, a child name
306 : : else {
307 : : SGPropertyNode * child =
308 : : current->getChild(components[position].name.c_str(),
309 : : components[position].index,
310 : 4253 : create);
311 : 6215 : return find_node(child, components, position + 1, create);
312 : : }
313 : : }
314 : :
315 : :
316 : :
317 : : ////////////////////////////////////////////////////////////////////////
318 : : // Private methods from SGPropertyNode (may be inlined for speed).
319 : : ////////////////////////////////////////////////////////////////////////
320 : :
321 : : inline bool
322 : 50 : SGPropertyNode::get_bool () const
323 : : {
324 [ + - ]: 50 : if (_tied)
325 : 50 : return _value.bool_val->getValue();
326 : : else
327 : 50 : return _local_val.bool_val;
328 : : }
329 : :
330 : : inline int
331 : 73 : SGPropertyNode::get_int () const
332 : : {
333 [ + - ]: 73 : if (_tied)
334 : 73 : return _value.int_val->getValue();
335 : : else
336 : 73 : return _local_val.int_val;
337 : : }
338 : :
339 : : inline long
340 : 0 : SGPropertyNode::get_long () const
341 : : {
342 [ # # ]: 0 : if (_tied)
343 : 0 : return _value.long_val->getValue();
344 : : else
345 : 0 : return _local_val.long_val;
346 : : }
347 : :
348 : : inline float
349 : 0 : SGPropertyNode::get_float () const
350 : : {
351 [ # # ]: 0 : if (_tied)
352 : 0 : return _value.float_val->getValue();
353 : : else
354 : 0 : return _local_val.float_val;
355 : : }
356 : :
357 : : inline double
358 : 5823269 : SGPropertyNode::get_double () const
359 : : {
360 [ + + ]: 5823269 : if (_tied)
361 : 5823262 : return _value.double_val->getValue();
362 : : else
363 : 5823269 : return _local_val.double_val;
364 : : }
365 : :
366 : : inline const char *
367 : 0 : SGPropertyNode::get_string () const
368 : : {
369 [ # # ]: 0 : if (_tied)
370 : 0 : return _value.string_val->getValue();
371 : : else
372 : 0 : return _local_val.string_val;
373 : : }
374 : :
375 : : inline bool
376 : 0 : SGPropertyNode::set_bool (bool val)
377 : : {
378 [ # # ]: 0 : if (_tied) {
379 [ # # ]: 0 : if (_value.bool_val->setValue(val)) {
380 : 0 : fireValueChanged();
381 : 0 : return true;
382 : : } else {
383 : 0 : return false;
384 : : }
385 : : } else {
386 : 0 : _local_val.bool_val = val;
387 : 0 : fireValueChanged();
388 : 0 : return true;
389 : : }
390 : : }
391 : :
392 : : inline bool
393 : 6 : SGPropertyNode::set_int (int val)
394 : : {
395 [ + - ]: 6 : if (_tied) {
396 [ + - ]: 6 : if (_value.int_val->setValue(val)) {
397 : 6 : fireValueChanged();
398 : 6 : return true;
399 : : } else {
400 : 0 : return false;
401 : : }
402 : : } else {
403 : 0 : _local_val.int_val = val;
404 : 0 : fireValueChanged();
405 : 6 : return true;
406 : : }
407 : : }
408 : :
409 : : inline bool
410 : 0 : SGPropertyNode::set_long (long val)
411 : : {
412 [ # # ]: 0 : if (_tied) {
413 [ # # ]: 0 : if (_value.long_val->setValue(val)) {
414 : 0 : fireValueChanged();
415 : 0 : return true;
416 : : } else {
417 : 0 : return false;
418 : : }
419 : : } else {
420 : 0 : _local_val.long_val = val;
421 : 0 : fireValueChanged();
422 : 0 : return true;
423 : : }
424 : : }
425 : :
426 : : inline bool
427 : 0 : SGPropertyNode::set_float (float val)
428 : : {
429 [ # # ]: 0 : if (_tied) {
430 [ # # ]: 0 : if (_value.float_val->setValue(val)) {
431 : 0 : fireValueChanged();
432 : 0 : return true;
433 : : } else {
434 : 0 : return false;
435 : : }
436 : : } else {
437 : 0 : _local_val.float_val = val;
438 : 0 : fireValueChanged();
439 : 0 : return true;
440 : : }
441 : : }
442 : :
443 : : inline bool
444 : 915250 : SGPropertyNode::set_double (double val)
445 : : {
446 [ + - ]: 915250 : if (_tied) {
447 [ + - ]: 915250 : if (_value.double_val->setValue(val)) {
448 : 915250 : fireValueChanged();
449 : 915250 : return true;
450 : : } else {
451 : 0 : return false;
452 : : }
453 : : } else {
454 : 0 : _local_val.double_val = val;
455 : 0 : fireValueChanged();
456 : 915250 : return true;
457 : : }
458 : : }
459 : :
460 : : inline bool
461 : 0 : SGPropertyNode::set_string (const char * val)
462 : : {
463 [ # # ]: 0 : if (_tied) {
464 [ # # ]: 0 : if (_value.string_val->setValue(val)) {
465 : 0 : fireValueChanged();
466 : 0 : return true;
467 : : } else {
468 : 0 : return false;
469 : : }
470 : : } else {
471 [ # # ]: 0 : delete [] _local_val.string_val;
472 : 0 : _local_val.string_val = copy_string(val);
473 : 0 : fireValueChanged();
474 : 0 : return true;
475 : : }
476 : : }
477 : :
478 : : void
479 : 1302 : SGPropertyNode::clearValue ()
480 : : {
481 [ - + + - : 1302 : switch (_type) {
- + - + ]
482 : : case NONE:
483 : : break;
484 : : case ALIAS:
485 : 0 : _value.alias = 0;
486 : 0 : break;
487 : : case BOOL:
488 [ + - ]: 50 : if (_tied) {
489 [ + - ]: 50 : delete _value.bool_val;
490 : 50 : _value.bool_val = 0;
491 : : }
492 : 50 : _local_val.bool_val = SGRawValue<bool>::DefaultValue;
493 : 50 : break;
494 : : case INT:
495 [ + - ]: 22 : if (_tied) {
496 [ + - ]: 22 : delete _value.int_val;
497 : 22 : _value.int_val = 0;
498 : : }
499 : 22 : _local_val.int_val = SGRawValue<int>::DefaultValue;
500 : 22 : break;
501 : : case LONG:
502 [ # # ]: 0 : if (_tied) {
503 [ # # ]: 0 : delete _value.long_val;
504 : 0 : _value.long_val = 0L;
505 : : }
506 : 0 : _local_val.long_val = SGRawValue<long>::DefaultValue;
507 : 0 : break;
508 : : case FLOAT:
509 [ # # ]: 0 : if (_tied) {
510 [ # # ]: 0 : delete _value.float_val;
511 : 0 : _value.float_val = 0;
512 : : }
513 : 0 : _local_val.float_val = SGRawValue<float>::DefaultValue;
514 : 0 : break;
515 : : case DOUBLE:
516 [ + - ]: 579 : if (_tied) {
517 [ + - ]: 579 : delete _value.double_val;
518 : 579 : _value.double_val = 0;
519 : : }
520 : 579 : _local_val.double_val = SGRawValue<double>::DefaultValue;
521 : 579 : break;
522 : : case STRING:
523 : : case UNSPECIFIED:
524 [ # # ]: 0 : if (_tied) {
525 [ # # ]: 0 : delete _value.string_val;
526 : 0 : _value.string_val = 0;
527 : : } else {
528 [ # # ]: 0 : delete [] _local_val.string_val;
529 : : }
530 : 0 : _local_val.string_val = 0;
531 : : break;
532 : : }
533 : 1302 : _tied = false;
534 : 1302 : _type = NONE;
535 : 1302 : }
536 : :
537 : :
538 : : /**
539 : : * Get the value as a string.
540 : : */
541 : : const char *
542 : 0 : SGPropertyNode::make_string () const
543 : : {
544 [ # # ]: 0 : if (!getAttribute(READ))
545 : 0 : return "";
546 : :
547 [ # # # # : 0 : switch (_type) {
# # # # ]
548 : : case ALIAS:
549 : 0 : return _value.alias->getStringValue();
550 : : case BOOL:
551 [ # # ]: 0 : if (get_bool())
552 : 0 : return "true";
553 : : else
554 : 0 : return "false";
555 : : case INT:
556 : : {
557 : 0 : stringstream sstr;
558 : 0 : sstr << get_int();
559 : 0 : _buffer = sstr.str();
560 : 0 : return _buffer.c_str();
561 : : }
562 : : case LONG:
563 : : {
564 : 0 : stringstream sstr;
565 : 0 : sstr << get_long();
566 : 0 : _buffer = sstr.str();
567 : 0 : return _buffer.c_str();
568 : : }
569 : : case FLOAT:
570 : : {
571 : 0 : stringstream sstr;
572 : 0 : sstr << get_float();
573 : 0 : _buffer = sstr.str();
574 : 0 : return _buffer.c_str();
575 : : }
576 : : case DOUBLE:
577 : : {
578 : 0 : stringstream sstr;
579 : : sstr.precision( 10 );
580 : 0 : sstr << get_double();
581 : 0 : _buffer = sstr.str();
582 : 0 : return _buffer.c_str();
583 : : }
584 : : case STRING:
585 : : case UNSPECIFIED:
586 : 0 : return get_string();
587 : : case NONE:
588 : : default:
589 : 0 : return "";
590 : : }
591 : : }
592 : :
593 : : /**
594 : : * Trace a write access for a property.
595 : : */
596 : : void
597 : 0 : SGPropertyNode::trace_write () const
598 : : {
599 : : #if PROPS_STANDALONE
600 : : cerr << "TRACE: Write node " << getPath () << ", value\""
601 : 0 : << make_string() << '"' << endl;
602 : : #else
603 : : SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Write node " << getPath()
604 : : << ", value\"" << make_string() << '"');
605 : : #endif
606 : 0 : }
607 : :
608 : : /**
609 : : * Trace a read access for a property.
610 : : */
611 : : void
612 : 0 : SGPropertyNode::trace_read () const
613 : : {
614 : : #if PROPS_STANDALONE
615 : : cerr << "TRACE: Write node " << getPath () << ", value \""
616 : 0 : << make_string() << '"' << endl;
617 : : #else
618 : : SG_LOG(SG_GENERAL, SG_INFO, "TRACE: Read node " << getPath()
619 : : << ", value \"" << make_string() << '"');
620 : : #endif
621 : 0 : }
622 : :
623 : :
624 : : ////////////////////////////////////////////////////////////////////////
625 : : // Public methods from SGPropertyNode.
626 : : ////////////////////////////////////////////////////////////////////////
627 : :
628 : : /**
629 : : * Last used attribute
630 : : * Update as needed when enum Attribute is changed
631 : : */
632 : : const int SGPropertyNode::LAST_USED_ATTRIBUTE = TRACE_WRITE;
633 : :
634 : : /**
635 : : * Default constructor: always creates a root node.
636 : : */
637 : 1 : SGPropertyNode::SGPropertyNode ()
638 : : : _index(0),
639 : : _parent(0),
640 : : _path_cache(0),
641 : : _type(NONE),
642 : : _tied(false),
643 : : _attr(READ|WRITE),
644 : 1 : _listeners(0)
645 : : {
646 : 1 : _local_val.string_val = 0;
647 : 1 : }
648 : :
649 : :
650 : : /**
651 : : * Copy constructor.
652 : : */
653 : 0 : SGPropertyNode::SGPropertyNode (const SGPropertyNode &node)
654 : : : _index(node._index),
655 : : _name(node._name),
656 : : _parent(0), // don't copy the parent
657 : : _path_cache(0),
658 : : _type(node._type),
659 : : _tied(node._tied),
660 : : _attr(node._attr),
661 : 0 : _listeners(0) // CHECK!!
662 : : {
663 : 0 : _local_val.string_val = 0;
664 [ # # # # : 0 : switch (_type) {
# # # # #
# # # # #
# # ]
665 : : case NONE:
666 : : break;
667 : : case ALIAS:
668 : 0 : _value.alias = node._value.alias;
669 : 0 : _tied = false;
670 : 0 : break;
671 : : case BOOL:
672 [ # # ][ # # ]: 0 : if (_tied) {
673 : 0 : _tied = true;
674 : 0 : _value.bool_val = node._value.bool_val->clone();
675 : : } else {
676 : 0 : _tied = false;
677 : 0 : set_bool(node.get_bool());
678 : : }
679 : : break;
680 : : case INT:
681 [ # # ][ # # ]: 0 : if (_tied) {
682 : 0 : _tied = true;
683 : 0 : _value.int_val = node._value.int_val->clone();
684 : : } else {
685 : 0 : _tied = false;
686 : 0 : set_int(node.get_int());
687 : : }
688 : : break;
689 : : case LONG:
690 [ # # ][ # # ]: 0 : if (_tied) {
691 : 0 : _tied = true;
692 : 0 : _value.long_val = node._value.long_val->clone();
693 : : } else {
694 : 0 : _tied = false;
695 : 0 : set_long(node.get_long());
696 : : }
697 : : break;
698 : : case FLOAT:
699 [ # # ][ # # ]: 0 : if (_tied) {
700 : 0 : _tied = true;
701 : 0 : _value.float_val = node._value.float_val->clone();
702 : : } else {
703 : 0 : _tied = false;
704 : 0 : set_float(node.get_float());
705 : : }
706 : : break;
707 : : case DOUBLE:
708 [ # # ][ # # ]: 0 : if (_tied) {
709 : 0 : _tied = true;
710 : 0 : _value.double_val = node._value.double_val->clone();
711 : : } else {
712 : 0 : _tied = false;
713 : 0 : set_double(node.get_double());
714 : : }
715 : : break;
716 : : case STRING:
717 : : case UNSPECIFIED:
718 [ # # ][ # # ]: 0 : if (_tied) {
719 : 0 : _tied = true;
720 : 0 : _value.string_val = node._value.string_val->clone();
721 : : } else {
722 : 0 : _tied = false;
723 : 0 : set_string(node.get_string());
724 : : }
725 : : break;
726 : : }
727 : 0 : }
728 : :
729 : :
730 : : /**
731 : : * Convenience constructor.
732 : : */
733 : : SGPropertyNode::SGPropertyNode (const char * name,
734 : : int index,
735 : 701 : SGPropertyNode * parent)
736 : : : _index(index),
737 : : _parent(parent),
738 : : _path_cache(0),
739 : : _type(NONE),
740 : : _tied(false),
741 : : _attr(READ|WRITE),
742 : 701 : _listeners(0)
743 : : {
744 : 701 : _name = name;
745 : 701 : _local_val.string_val = 0;
746 : 701 : }
747 : :
748 : :
749 : : /**
750 : : * Destructor.
751 : : */
752 : 0 : SGPropertyNode::~SGPropertyNode ()
753 : : {
754 [ # # ][ # # ]: 0 : delete _path_cache;
[ # # ]
755 : 0 : clearValue();
756 [ # # ][ # # ]: 0 : delete _listeners;
[ # # ]
757 [ # # ][ # # ]: 0 : }
[ # # ]
758 : :
759 : :
760 : : /**
761 : : * Alias to another node.
762 : : */
763 : : bool
764 : 0 : SGPropertyNode::alias (SGPropertyNode * target)
765 : : {
766 [ # # ][ # # ]: 0 : if (target == 0 || _type == ALIAS || _tied)
[ # # ]
767 : 0 : return false;
768 : 0 : clearValue();
769 : 0 : _value.alias = target;
770 : 0 : _type = ALIAS;
771 : 0 : return true;
772 : : }
773 : :
774 : :
775 : : /**
776 : : * Alias to another node by path.
777 : : */
778 : : bool
779 : 0 : SGPropertyNode::alias (const char * path)
780 : : {
781 : 0 : return alias(getNode(path, true));
782 : : }
783 : :
784 : :
785 : : /**
786 : : * Remove an alias.
787 : : */
788 : : bool
789 : 0 : SGPropertyNode::unalias ()
790 : : {
791 [ # # ]: 0 : if (_type != ALIAS)
792 : 0 : return false;
793 : 0 : _type = NONE;
794 : 0 : _value.alias = 0;
795 : 0 : return true;
796 : : }
797 : :
798 : :
799 : : /**
800 : : * Get the target of an alias.
801 : : */
802 : : SGPropertyNode *
803 : 0 : SGPropertyNode::getAliasTarget ()
804 : : {
805 [ # # ]: 0 : return (_type == ALIAS ? _value.alias : 0);
806 : : }
807 : :
808 : :
809 : : const SGPropertyNode *
810 : 0 : SGPropertyNode::getAliasTarget () const
811 : : {
812 [ # # ]: 0 : return (_type == ALIAS ? _value.alias : 0);
813 : : }
814 : :
815 : :
816 : : /**
817 : : * Get a non-const child by index.
818 : : */
819 : : SGPropertyNode *
820 : 4250 : SGPropertyNode::getChild (int position)
821 : : {
822 [ + - ][ + - ]: 4250 : if (position >= 0 && position < nChildren())
[ + - ]
823 : 4250 : return _children[position];
824 : : else
825 : 4250 : return 0;
826 : : }
827 : :
828 : :
829 : : /**
830 : : * Get a const child by index.
831 : : */
832 : : const SGPropertyNode *
833 : 0 : SGPropertyNode::getChild (int position) const
834 : : {
835 [ # # ][ # # ]: 0 : if (position >= 0 && position < nChildren())
[ # # ]
836 : 0 : return _children[position];
837 : : else
838 : 0 : return 0;
839 : : }
840 : :
841 : :
842 : : /**
843 : : * Get a non-const child by name and index, creating if necessary.
844 : : */
845 : : SGPropertyNode *
846 : 4253 : SGPropertyNode::getChild (const char * name, int index, bool create)
847 : : {
848 : 4253 : int pos = find_child(name, index, _children);
849 [ + + ]: 4253 : if (pos >= 0) {
850 : 3546 : return _children[pos];
851 [ + + ]: 707 : } else if (create) {
852 : : SGPropertyNode_ptr node;
853 : 701 : pos = find_child(name, index, _removedChildren);
854 [ - + ]: 701 : if (pos >= 0) {
855 : 0 : vector<SGPropertyNode_ptr>::iterator it = _removedChildren.begin();
856 : : it += pos;
857 : 0 : node = _removedChildren[pos];
858 : 0 : _removedChildren.erase(it);
859 : : node->setAttribute(REMOVED, false);
860 : : } else {
861 : 701 : node = new SGPropertyNode(name, index, this);
862 : : }
863 : 701 : _children.push_back(node);
864 : 701 : fireChildAdded(node);
865 : 701 : return node;
866 : : } else {
867 : 4253 : return 0;
868 : : }
869 : : }
870 : :
871 : :
872 : : /**
873 : : * Get a const child by name and index.
874 : : */
875 : : const SGPropertyNode *
876 : 0 : SGPropertyNode::getChild (const char * name, int index) const
877 : : {
878 : 0 : int pos = find_child(name, index, _children);
879 [ # # ]: 0 : if (pos >= 0)
880 : 0 : return _children[pos];
881 : : else
882 : 0 : return 0;
883 : : }
884 : :
885 : :
886 : : /**
887 : : * Get all children with the same name (but different indices).
888 : : */
889 : : vector<SGPropertyNode_ptr>
890 : 0 : SGPropertyNode::getChildren (const char * name) const
891 : : {
892 : 0 : vector<SGPropertyNode_ptr> children;
893 : 0 : int max = _children.size();
894 : :
895 [ # # ]: 0 : for (int i = 0; i < max; i++)
896 [ # # ]: 0 : if (compare_strings(_children[i]->getName(), name))
897 : 0 : children.push_back(_children[i]);
898 : :
899 : 0 : sort(children.begin(), children.end(), CompareIndices());
900 : 0 : return children;
901 : : }
902 : :
903 : :
904 : : /**
905 : : * Remove child by position.
906 : : */
907 : : SGPropertyNode_ptr
908 : 0 : SGPropertyNode::removeChild (int pos, bool keep)
909 : : {
910 : 0 : SGPropertyNode_ptr node;
911 [ # # ][ # # ]: 0 : if (pos < 0 || pos >= (int)_children.size())
[ # # ]
912 : 0 : return node;
913 : :
914 : 0 : vector<SGPropertyNode_ptr>::iterator it = _children.begin();
915 : : it += pos;
916 : 0 : node = _children[pos];
917 : 0 : _children.erase(it);
918 [ # # ]: 0 : if (keep) {
919 : 0 : _removedChildren.push_back(node);
920 : : }
921 [ # # ]: 0 : if (_path_cache)
922 : 0 : _path_cache->erase(node->getName()); // EMH - TODO: Take "index" into account!
923 : 0 : node->setAttribute(REMOVED, true);
924 : 0 : node->clearValue();
925 : 0 : fireChildRemoved(node);
926 : 0 : return node;
927 : : }
928 : :
929 : :
930 : : /**
931 : : * Remove a child node
932 : : */
933 : : SGPropertyNode_ptr
934 : 0 : SGPropertyNode::removeChild (const char * name, int index, bool keep)
935 : : {
936 : 0 : SGPropertyNode_ptr ret;
937 : 0 : int pos = find_child(name, index, _children);
938 [ # # ]: 0 : if (pos >= 0)
939 : 0 : ret = removeChild(pos, keep);
940 : 0 : return ret;
941 : : }
942 : :
943 : :
944 : : /**
945 : : * Remove all children with the specified name.
946 : : */
947 : : vector<SGPropertyNode_ptr>
948 : 0 : SGPropertyNode::removeChildren (const char * name, bool keep)
949 : : {
950 : 0 : vector<SGPropertyNode_ptr> children;
951 : :
952 [ # # ]: 0 : for (int pos = _children.size() - 1; pos >= 0; pos--)
953 [ # # ]: 0 : if (compare_strings(_children[pos]->getName(), name))
954 : 0 : children.push_back(removeChild(pos, keep));
955 : :
956 : 0 : sort(children.begin(), children.end(), CompareIndices());
957 : 0 : return children;
958 : : }
959 : :
960 : :
961 : : const char *
962 : 8968 : SGPropertyNode::getDisplayName (bool simplify) const
963 : : {
964 : 8968 : _display_name = _name;
965 [ + + ][ - + ]: 8968 : if (_index != 0 || !simplify) {
966 : 463 : stringstream sstr;
967 : 463 : sstr << '[' << _index << ']';
968 : 926 : _display_name += sstr.str();
969 : : }
970 : 8968 : return _display_name.c_str();
971 : : }
972 : :
973 : :
974 : : const char *
975 : 0 : SGPropertyNode::getPath (bool simplify) const
976 : : {
977 : : // Calculate the complete path only once.
978 [ # # ][ # # ]: 0 : if (_parent != 0 && _path.empty()) {
[ # # ]
979 : 0 : _path = _parent->getPath(simplify);
980 : 0 : _path += '/';
981 : 0 : _path += getDisplayName(simplify);
982 : : }
983 : :
984 : 0 : return _path.c_str();
985 : : }
986 : :
987 : : SGPropertyNode::Type
988 : 0 : SGPropertyNode::getType () const
989 : : {
990 [ # # ]: 0 : if (_type == ALIAS)
991 : 0 : return _value.alias->getType();
992 : : else
993 : 0 : return _type;
994 : : }
995 : :
996 : :
997 : : bool
998 : 50 : SGPropertyNode::getBoolValue () const
999 : : {
1000 : : // Shortcut for common case
1001 [ + - ][ + - ]: 50 : if (_attr == (READ|WRITE) && _type == BOOL)
1002 : 50 : return get_bool();
1003 : :
1004 [ # # ]: 0 : if (getAttribute(TRACE_READ))
1005 : 0 : trace_read();
1006 [ # # ]: 0 : if (!getAttribute(READ))
1007 : 0 : return SGRawValue<bool>::DefaultValue;
1008 [ # # # # : 0 : switch (_type) {
# # # # ]
1009 : : case ALIAS:
1010 : 0 : return _value.alias->getBoolValue();
1011 : : case BOOL:
1012 : 0 : return get_bool();
1013 : : case INT:
1014 : 0 : return get_int() == 0 ? false : true;
1015 : : case LONG:
1016 : 0 : return get_long() == 0L ? false : true;
1017 : : case FLOAT:
1018 : 0 : return get_float() == 0.0 ? false : true;
1019 : : case DOUBLE:
1020 : 0 : return get_double() == 0.0L ? false : true;
1021 : : case STRING:
1022 : : case UNSPECIFIED:
1023 [ # # ][ # # ]: 0 : return (compare_strings(get_string(), "true") || getDoubleValue() != 0.0L);
1024 : : case NONE:
1025 : : default:
1026 : 50 : return SGRawValue<bool>::DefaultValue;
1027 : : }
1028 : : }
1029 : :
1030 : : int
1031 : 22 : SGPropertyNode::getIntValue () const
1032 : : {
1033 : : // Shortcut for common case
1034 [ + - ][ + - ]: 22 : if (_attr == (READ|WRITE) && _type == INT)
1035 : 22 : return get_int();
1036 : :
1037 [ # # ]: 0 : if (getAttribute(TRACE_READ))
1038 : 0 : trace_read();
1039 [ # # ]: 0 : if (!getAttribute(READ))
1040 : 0 : return SGRawValue<int>::DefaultValue;
1041 [ # # # # : 0 : switch (_type) {
# # # # ]
1042 : : case ALIAS:
1043 : 0 : return _value.alias->getIntValue();
1044 : : case BOOL:
1045 : 0 : return int(get_bool());
1046 : : case INT:
1047 : 0 : return get_int();
1048 : : case LONG:
1049 : 0 : return int(get_long());
1050 : : case FLOAT:
1051 : 0 : return int(get_float());
1052 : : case DOUBLE:
1053 : 0 : return int(get_double());
1054 : : case STRING:
1055 : : case UNSPECIFIED:
1056 : 0 : return atoi(get_string());
1057 : : case NONE:
1058 : : default:
1059 : 22 : return SGRawValue<int>::DefaultValue;
1060 : : }
1061 : : }
1062 : :
1063 : : long
1064 : 0 : SGPropertyNode::getLongValue () const
1065 : : {
1066 : : // Shortcut for common case
1067 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == LONG)
1068 : 0 : return get_long();
1069 : :
1070 [ # # ]: 0 : if (getAttribute(TRACE_READ))
1071 : 0 : trace_read();
1072 [ # # ]: 0 : if (!getAttribute(READ))
1073 : 0 : return SGRawValue<long>::DefaultValue;
1074 [ # # # # : 0 : switch (_type) {
# # # # ]
1075 : : case ALIAS:
1076 : 0 : return _value.alias->getLongValue();
1077 : : case BOOL:
1078 : 0 : return long(get_bool());
1079 : : case INT:
1080 : 0 : return long(get_int());
1081 : : case LONG:
1082 : 0 : return get_long();
1083 : : case FLOAT:
1084 : 0 : return long(get_float());
1085 : : case DOUBLE:
1086 : 0 : return long(get_double());
1087 : : case STRING:
1088 : : case UNSPECIFIED:
1089 : 0 : return strtol(get_string(), 0, 0);
1090 : : case NONE:
1091 : : default:
1092 : 0 : return SGRawValue<long>::DefaultValue;
1093 : : }
1094 : : }
1095 : :
1096 : : float
1097 : 0 : SGPropertyNode::getFloatValue () const
1098 : : {
1099 : : // Shortcut for common case
1100 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == FLOAT)
1101 : 0 : return get_float();
1102 : :
1103 [ # # ]: 0 : if (getAttribute(TRACE_READ))
1104 : 0 : trace_read();
1105 [ # # ]: 0 : if (!getAttribute(READ))
1106 : 0 : return SGRawValue<float>::DefaultValue;
1107 [ # # # # : 0 : switch (_type) {
# # # # ]
1108 : : case ALIAS:
1109 : 0 : return _value.alias->getFloatValue();
1110 : : case BOOL:
1111 : 0 : return float(get_bool());
1112 : : case INT:
1113 : 0 : return float(get_int());
1114 : : case LONG:
1115 : 0 : return float(get_long());
1116 : : case FLOAT:
1117 : 0 : return get_float();
1118 : : case DOUBLE:
1119 : 0 : return float(get_double());
1120 : : case STRING:
1121 : : case UNSPECIFIED:
1122 : 0 : return atof(get_string());
1123 : : case NONE:
1124 : : default:
1125 : 0 : return SGRawValue<float>::DefaultValue;
1126 : : }
1127 : : }
1128 : :
1129 : : double
1130 : 5877323 : SGPropertyNode::getDoubleValue () const
1131 : : {
1132 : : // Shortcut for common case
1133 [ + - ][ + + ]: 5877323 : if (_attr == (READ|WRITE) && _type == DOUBLE)
1134 : 5823269 : return get_double();
1135 : :
1136 [ - + ]: 54054 : if (getAttribute(TRACE_READ))
1137 : 0 : trace_read();
1138 [ - + ]: 54054 : if (!getAttribute(READ))
1139 : 0 : return SGRawValue<double>::DefaultValue;
1140 : :
1141 [ - - + - : 54054 : switch (_type) {
- - - + ]
1142 : : case ALIAS:
1143 : 0 : return _value.alias->getDoubleValue();
1144 : : case BOOL:
1145 : 0 : return double(get_bool());
1146 : : case INT:
1147 : 51 : return double(get_int());
1148 : : case LONG:
1149 : 0 : return double(get_long());
1150 : : case FLOAT:
1151 : 0 : return double(get_float());
1152 : : case DOUBLE:
1153 : 0 : return get_double();
1154 : : case STRING:
1155 : : case UNSPECIFIED:
1156 : 0 : return strtod(get_string(), 0);
1157 : : case NONE:
1158 : : default:
1159 : 5877323 : return SGRawValue<double>::DefaultValue;
1160 : : }
1161 : : }
1162 : :
1163 : : const char *
1164 : 0 : SGPropertyNode::getStringValue () const
1165 : : {
1166 : : // Shortcut for common case
1167 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == STRING)
1168 : 0 : return get_string();
1169 : :
1170 [ # # ]: 0 : if (getAttribute(TRACE_READ))
1171 : 0 : trace_read();
1172 [ # # ]: 0 : if (!getAttribute(READ))
1173 : 0 : return SGRawValue<const char *>::DefaultValue;
1174 : 0 : return make_string();
1175 : : }
1176 : :
1177 : : bool
1178 : 0 : SGPropertyNode::setBoolValue (bool value)
1179 : : {
1180 : : // Shortcut for common case
1181 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == BOOL)
1182 : 0 : return set_bool(value);
1183 : :
1184 : 0 : bool result = false;
1185 [ # # ]: 0 : TEST_WRITE;
1186 [ # # ][ # # ]: 0 : if (_type == NONE || _type == UNSPECIFIED) {
1187 : 0 : clearValue();
1188 : 0 : _tied = false;
1189 : 0 : _type = BOOL;
1190 : : }
1191 : :
1192 [ # # # # : 0 : switch (_type) {
# # # # ]
1193 : : case ALIAS:
1194 : 0 : result = _value.alias->setBoolValue(value);
1195 : 0 : break;
1196 : : case BOOL:
1197 : 0 : result = set_bool(value);
1198 : 0 : break;
1199 : : case INT:
1200 : 0 : result = set_int(int(value));
1201 : 0 : break;
1202 : : case LONG:
1203 : 0 : result = set_long(long(value));
1204 : 0 : break;
1205 : : case FLOAT:
1206 : 0 : result = set_float(float(value));
1207 : 0 : break;
1208 : : case DOUBLE:
1209 : 0 : result = set_double(double(value));
1210 : 0 : break;
1211 : : case STRING:
1212 : : case UNSPECIFIED:
1213 [ # # ]: 0 : result = set_string(value ? "true" : "false");
1214 : : break;
1215 : : case NONE:
1216 : : default:
1217 : : break;
1218 : : }
1219 : :
1220 [ # # ]: 0 : if (getAttribute(TRACE_WRITE))
1221 : 0 : trace_write();
1222 : 0 : return result;
1223 : : }
1224 : :
1225 : : bool
1226 : 0 : SGPropertyNode::setIntValue (int value)
1227 : : {
1228 : : // Shortcut for common case
1229 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == INT)
1230 : 0 : return set_int(value);
1231 : :
1232 : 0 : bool result = false;
1233 [ # # ]: 0 : TEST_WRITE;
1234 [ # # ][ # # ]: 0 : if (_type == NONE || _type == UNSPECIFIED) {
1235 : 0 : clearValue();
1236 : 0 : _type = INT;
1237 : 0 : _local_val.int_val = 0;
1238 : : }
1239 : :
1240 [ # # # # : 0 : switch (_type) {
# # # # ]
1241 : : case ALIAS:
1242 : 0 : result = _value.alias->setIntValue(value);
1243 : 0 : break;
1244 : : case BOOL:
1245 : 0 : result = set_bool(value == 0 ? false : true);
1246 : 0 : break;
1247 : : case INT:
1248 : 0 : result = set_int(value);
1249 : 0 : break;
1250 : : case LONG:
1251 : 0 : result = set_long(long(value));
1252 : 0 : break;
1253 : : case FLOAT:
1254 : 0 : result = set_float(float(value));
1255 : 0 : break;
1256 : : case DOUBLE:
1257 : 0 : result = set_double(double(value));
1258 : 0 : break;
1259 : : case STRING:
1260 : : case UNSPECIFIED: {
1261 : : char buf[128];
1262 : 0 : sprintf(buf, "%d", value);
1263 : 0 : result = set_string(buf);
1264 : : break;
1265 : : }
1266 : : case NONE:
1267 : : default:
1268 : : break;
1269 : : }
1270 : :
1271 [ # # ]: 0 : if (getAttribute(TRACE_WRITE))
1272 : 0 : trace_write();
1273 : 0 : return result;
1274 : : }
1275 : :
1276 : : bool
1277 : 0 : SGPropertyNode::setLongValue (long value)
1278 : : {
1279 : : // Shortcut for common case
1280 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == LONG)
1281 : 0 : return set_long(value);
1282 : :
1283 : 0 : bool result = false;
1284 [ # # ]: 0 : TEST_WRITE;
1285 [ # # ][ # # ]: 0 : if (_type == NONE || _type == UNSPECIFIED) {
1286 : 0 : clearValue();
1287 : 0 : _type = LONG;
1288 : 0 : _local_val.long_val = 0L;
1289 : : }
1290 : :
1291 [ # # # # : 0 : switch (_type) {
# # # # ]
1292 : : case ALIAS:
1293 : 0 : result = _value.alias->setLongValue(value);
1294 : 0 : break;
1295 : : case BOOL:
1296 : 0 : result = set_bool(value == 0L ? false : true);
1297 : 0 : break;
1298 : : case INT:
1299 : 0 : result = set_int(int(value));
1300 : 0 : break;
1301 : : case LONG:
1302 : 0 : result = set_long(value);
1303 : 0 : break;
1304 : : case FLOAT:
1305 : 0 : result = set_float(float(value));
1306 : 0 : break;
1307 : : case DOUBLE:
1308 : 0 : result = set_double(double(value));
1309 : 0 : break;
1310 : : case STRING:
1311 : : case UNSPECIFIED: {
1312 : : char buf[128];
1313 : 0 : sprintf(buf, "%ld", value);
1314 : 0 : result = set_string(buf);
1315 : : break;
1316 : : }
1317 : : case NONE:
1318 : : default:
1319 : : break;
1320 : : }
1321 : :
1322 [ # # ]: 0 : if (getAttribute(TRACE_WRITE))
1323 : 0 : trace_write();
1324 : 0 : return result;
1325 : : }
1326 : :
1327 : : bool
1328 : 0 : SGPropertyNode::setFloatValue (float value)
1329 : : {
1330 : : // Shortcut for common case
1331 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == FLOAT)
1332 : 0 : return set_float(value);
1333 : :
1334 : 0 : bool result = false;
1335 [ # # ]: 0 : TEST_WRITE;
1336 [ # # ][ # # ]: 0 : if (_type == NONE || _type == UNSPECIFIED) {
1337 : 0 : clearValue();
1338 : 0 : _type = FLOAT;
1339 : 0 : _local_val.float_val = 0;
1340 : : }
1341 : :
1342 [ # # # # : 0 : switch (_type) {
# # # # ]
1343 : : case ALIAS:
1344 : 0 : result = _value.alias->setFloatValue(value);
1345 : 0 : break;
1346 : : case BOOL:
1347 : 0 : result = set_bool(value == 0.0 ? false : true);
1348 : 0 : break;
1349 : : case INT:
1350 : 0 : result = set_int(int(value));
1351 : 0 : break;
1352 : : case LONG:
1353 : 0 : result = set_long(long(value));
1354 : 0 : break;
1355 : : case FLOAT:
1356 : 0 : result = set_float(value);
1357 : 0 : break;
1358 : : case DOUBLE:
1359 : 0 : result = set_double(double(value));
1360 : 0 : break;
1361 : : case STRING:
1362 : : case UNSPECIFIED: {
1363 : : char buf[128];
1364 : 0 : sprintf(buf, "%f", value);
1365 : 0 : result = set_string(buf);
1366 : : break;
1367 : : }
1368 : : case NONE:
1369 : : default:
1370 : : break;
1371 : : }
1372 : :
1373 [ # # ]: 0 : if (getAttribute(TRACE_WRITE))
1374 : 0 : trace_write();
1375 : 0 : return result;
1376 : : }
1377 : :
1378 : : bool
1379 : 915256 : SGPropertyNode::setDoubleValue (double value)
1380 : : {
1381 : : // Shortcut for common case
1382 [ + - ][ + + ]: 915256 : if (_attr == (READ|WRITE) && _type == DOUBLE)
1383 : 915250 : return set_double(value);
1384 : :
1385 : 6 : bool result = false;
1386 [ - + ]: 6 : TEST_WRITE;
1387 [ + - ][ - + ]: 6 : if (_type == NONE || _type == UNSPECIFIED) {
1388 : 0 : clearValue();
1389 : 0 : _local_val.double_val = value;
1390 : 0 : _type = DOUBLE;
1391 : : }
1392 : :
1393 [ - - + - : 6 : switch (_type) {
- - - - ]
1394 : : case ALIAS:
1395 : 0 : result = _value.alias->setDoubleValue(value);
1396 : 0 : break;
1397 : : case BOOL:
1398 : 0 : result = set_bool(value == 0.0L ? false : true);
1399 : 0 : break;
1400 : : case INT:
1401 : 6 : result = set_int(int(value));
1402 : 6 : break;
1403 : : case LONG:
1404 : 0 : result = set_long(long(value));
1405 : 0 : break;
1406 : : case FLOAT:
1407 : 0 : result = set_float(float(value));
1408 : 0 : break;
1409 : : case DOUBLE:
1410 : 0 : result = set_double(value);
1411 : 0 : break;
1412 : : case STRING:
1413 : : case UNSPECIFIED: {
1414 : : char buf[128];
1415 : 0 : sprintf(buf, "%f", value);
1416 : 0 : result = set_string(buf);
1417 : : break;
1418 : : }
1419 : : case NONE:
1420 : : default:
1421 : : break;
1422 : : }
1423 : :
1424 [ - + ]: 6 : if (getAttribute(TRACE_WRITE))
1425 : 0 : trace_write();
1426 : 915256 : return result;
1427 : : }
1428 : :
1429 : : bool
1430 : 0 : SGPropertyNode::setStringValue (const char * value)
1431 : : {
1432 : : // Shortcut for common case
1433 [ # # ][ # # ]: 0 : if (_attr == (READ|WRITE) && _type == STRING)
1434 : 0 : return set_string(value);
1435 : :
1436 : 0 : bool result = false;
1437 [ # # ]: 0 : TEST_WRITE;
1438 [ # # ][ # # ]: 0 : if (_type == NONE || _type == UNSPECIFIED) {
1439 : 0 : clearValue();
1440 : 0 : _type = STRING;
1441 : : }
1442 : :
1443 [ # # # # : 0 : switch (_type) {
# # # # ]
1444 : : case ALIAS:
1445 : 0 : result = _value.alias->setStringValue(value);
1446 : 0 : break;
1447 : : case BOOL:
1448 : : result = set_bool((compare_strings(value, "true")
1449 [ # # ][ # # ]: 0 : || atoi(value)) ? true : false);
1450 : 0 : break;
1451 : : case INT:
1452 : 0 : result = set_int(atoi(value));
1453 : 0 : break;
1454 : : case LONG:
1455 : 0 : result = set_long(strtol(value, 0, 0));
1456 : 0 : break;
1457 : : case FLOAT:
1458 : 0 : result = set_float(atof(value));
1459 : 0 : break;
1460 : : case DOUBLE:
1461 : 0 : result = set_double(strtod(value, 0));
1462 : 0 : break;
1463 : : case STRING:
1464 : : case UNSPECIFIED:
1465 : 0 : result = set_string(value);
1466 : : break;
1467 : : case NONE:
1468 : : default:
1469 : : break;
1470 : : }
1471 : :
1472 [ # # ]: 0 : if (getAttribute(TRACE_WRITE))
1473 : 0 : trace_write();
1474 : 0 : return result;
1475 : : }
1476 : :
1477 : : bool
1478 : 0 : SGPropertyNode::setUnspecifiedValue (const char * value)
1479 : : {
1480 : 0 : bool result = false;
1481 [ # # ]: 0 : TEST_WRITE;
1482 [ # # ]: 0 : if (_type == NONE) {
1483 : 0 : clearValue();
1484 : 0 : _type = UNSPECIFIED;
1485 : : }
1486 : :
1487 [ # # # # : 0 : switch (_type) {
# # # # ]
1488 : : case ALIAS:
1489 : 0 : result = _value.alias->setUnspecifiedValue(value);
1490 : 0 : break;
1491 : : case BOOL:
1492 : : result = set_bool((compare_strings(value, "true")
1493 [ # # ][ # # ]: 0 : || atoi(value)) ? true : false);
1494 : 0 : break;
1495 : : case INT:
1496 : 0 : result = set_int(atoi(value));
1497 : 0 : break;
1498 : : case LONG:
1499 : 0 : result = set_long(strtol(value, 0, 0));
1500 : 0 : break;
1501 : : case FLOAT:
1502 : 0 : result = set_float(atof(value));
1503 : 0 : break;
1504 : : case DOUBLE:
1505 : 0 : result = set_double(strtod(value, 0));
1506 : 0 : break;
1507 : : case STRING:
1508 : : case UNSPECIFIED:
1509 : 0 : result = set_string(value);
1510 : : break;
1511 : : case NONE:
1512 : : default:
1513 : : break;
1514 : : }
1515 : :
1516 [ # # ]: 0 : if (getAttribute(TRACE_WRITE))
1517 : 0 : trace_write();
1518 : 0 : return result;
1519 : : }
1520 : :
1521 : : bool
1522 : 50 : SGPropertyNode::tie (const SGRawValue<bool> &rawValue, bool useDefault)
1523 : : {
1524 [ + - ][ - + ]: 50 : if (_type == ALIAS || _tied)
1525 : 0 : return false;
1526 : :
1527 [ + - ][ - + ]: 50 : useDefault = useDefault && hasValue();
1528 : 50 : bool old_val = false;
1529 [ - + ]: 50 : if (useDefault)
1530 : 0 : old_val = getBoolValue();
1531 : :
1532 : 50 : clearValue();
1533 : 50 : _type = BOOL;
1534 : 50 : _tied = true;
1535 : 50 : _value.bool_val = rawValue.clone();
1536 : :
1537 [ - + ]: 50 : if (useDefault)
1538 : 0 : setBoolValue(old_val);
1539 : :
1540 : 50 : return true;
1541 : : }
1542 : :
1543 : : bool
1544 : 22 : SGPropertyNode::tie (const SGRawValue<int> &rawValue, bool useDefault)
1545 : : {
1546 [ + - ][ - + ]: 22 : if (_type == ALIAS || _tied)
1547 : 0 : return false;
1548 : :
1549 [ + - ][ - + ]: 22 : useDefault = useDefault && hasValue();
1550 : 22 : int old_val = 0;
1551 [ - + ]: 22 : if (useDefault)
1552 : 0 : old_val = getIntValue();
1553 : :
1554 : 22 : clearValue();
1555 : 22 : _type = INT;
1556 : 22 : _tied = true;
1557 : 22 : _value.int_val = rawValue.clone();
1558 : :
1559 [ - + ]: 22 : if (useDefault)
1560 : 0 : setIntValue(old_val);
1561 : :
1562 : 22 : return true;
1563 : : }
1564 : :
1565 : : bool
1566 : 0 : SGPropertyNode::tie (const SGRawValue<long> &rawValue, bool useDefault)
1567 : : {
1568 [ # # ][ # # ]: 0 : if (_type == ALIAS || _tied)
1569 : 0 : return false;
1570 : :
1571 [ # # ][ # # ]: 0 : useDefault = useDefault && hasValue();
1572 : 0 : long old_val = 0;
1573 [ # # ]: 0 : if (useDefault)
1574 : 0 : old_val = getLongValue();
1575 : :
1576 : 0 : clearValue();
1577 : 0 : _type = LONG;
1578 : 0 : _tied = true;
1579 : 0 : _value.long_val = rawValue.clone();
1580 : :
1581 [ # # ]: 0 : if (useDefault)
1582 : 0 : setLongValue(old_val);
1583 : :
1584 : 0 : return true;
1585 : : }
1586 : :
1587 : : bool
1588 : 0 : SGPropertyNode::tie (const SGRawValue<float> &rawValue, bool useDefault)
1589 : : {
1590 [ # # ][ # # ]: 0 : if (_type == ALIAS || _tied)
1591 : 0 : return false;
1592 : :
1593 [ # # ][ # # ]: 0 : useDefault = useDefault && hasValue();
1594 : 0 : float old_val = 0.0;
1595 [ # # ]: 0 : if (useDefault)
1596 : 0 : old_val = getFloatValue();
1597 : :
1598 : 0 : clearValue();
1599 : 0 : _type = FLOAT;
1600 : 0 : _tied = true;
1601 : 0 : _value.float_val = rawValue.clone();
1602 : :
1603 [ # # ]: 0 : if (useDefault)
1604 : 0 : setFloatValue(old_val);
1605 : :
1606 : 0 : return true;
1607 : : }
1608 : :
1609 : : bool
1610 : 579 : SGPropertyNode::tie (const SGRawValue<double> &rawValue, bool useDefault)
1611 : : {
1612 [ + - ][ - + ]: 579 : if (_type == ALIAS || _tied)
1613 : 0 : return false;
1614 : :
1615 [ + + ][ - + ]: 579 : useDefault = useDefault && hasValue();
1616 : 579 : double old_val = 0.0;
1617 [ - + ]: 579 : if (useDefault)
1618 : 0 : old_val = getDoubleValue();
1619 : :
1620 : 579 : clearValue();
1621 : 579 : _type = DOUBLE;
1622 : 579 : _tied = true;
1623 : 579 : _value.double_val = rawValue.clone();
1624 : :
1625 [ - + ]: 579 : if (useDefault)
1626 : 0 : setDoubleValue(old_val);
1627 : :
1628 : 579 : return true;
1629 : :
1630 : : }
1631 : :
1632 : : bool
1633 : 0 : SGPropertyNode::tie (const SGRawValue<const char *> &rawValue, bool useDefault)
1634 : : {
1635 [ # # ][ # # ]: 0 : if (_type == ALIAS || _tied)
1636 : 0 : return false;
1637 : :
1638 [ # # ][ # # ]: 0 : useDefault = useDefault && hasValue();
1639 : 0 : string old_val;
1640 [ # # ]: 0 : if (useDefault)
1641 : 0 : old_val = getStringValue();
1642 : :
1643 : 0 : clearValue();
1644 : 0 : _type = STRING;
1645 : 0 : _tied = true;
1646 : 0 : _value.string_val = rawValue.clone();
1647 : :
1648 [ # # ]: 0 : if (useDefault)
1649 : 0 : setStringValue(old_val.c_str());
1650 : :
1651 : 0 : return true;
1652 : : }
1653 : :
1654 : : bool
1655 : 651 : SGPropertyNode::untie ()
1656 : : {
1657 [ - + ]: 651 : if (!_tied)
1658 : 0 : return false;
1659 : :
1660 [ + + - - : 651 : switch (_type) {
+ - - ]
1661 : : case BOOL: {
1662 : 50 : bool val = getBoolValue();
1663 : 50 : clearValue();
1664 : 50 : _type = BOOL;
1665 : 50 : _local_val.bool_val = val;
1666 : 50 : break;
1667 : : }
1668 : : case INT: {
1669 : 22 : int val = getIntValue();
1670 : 22 : clearValue();
1671 : 22 : _type = INT;
1672 : 22 : _local_val.int_val = val;
1673 : 22 : break;
1674 : : }
1675 : : case LONG: {
1676 : 0 : long val = getLongValue();
1677 : 0 : clearValue();
1678 : 0 : _type = LONG;
1679 : 0 : _local_val.long_val = val;
1680 : 0 : break;
1681 : : }
1682 : : case FLOAT: {
1683 : 0 : float val = getFloatValue();
1684 : 0 : clearValue();
1685 : 0 : _type = FLOAT;
1686 : 0 : _local_val.float_val = val;
1687 : 0 : break;
1688 : : }
1689 : : case DOUBLE: {
1690 : 579 : double val = getDoubleValue();
1691 : 579 : clearValue();
1692 : 579 : _type = DOUBLE;
1693 : 579 : _local_val.double_val = val;
1694 : 579 : break;
1695 : : }
1696 : : case STRING:
1697 : : case UNSPECIFIED: {
1698 : 0 : string val = getStringValue();
1699 : 0 : clearValue();
1700 : 0 : _type = STRING;
1701 : 0 : _local_val.string_val = copy_string(val.c_str());
1702 : 0 : break;
1703 : : }
1704 : : case NONE:
1705 : : default:
1706 : : break;
1707 : : }
1708 : :
1709 : 651 : _tied = false;
1710 : 651 : return true;
1711 : : }
1712 : :
1713 : : SGPropertyNode *
1714 : 2770 : SGPropertyNode::getRootNode ()
1715 : : {
1716 [ + + ]: 2770 : if (_parent == 0)
1717 : 652 : return this;
1718 : : else
1719 : 2770 : return _parent->getRootNode();
1720 : : }
1721 : :
1722 : : const SGPropertyNode *
1723 : 0 : SGPropertyNode::getRootNode () const
1724 : : {
1725 [ # # ]: 0 : if (_parent == 0)
1726 : 0 : return this;
1727 : : else
1728 : 0 : return _parent->getRootNode();
1729 : : }
1730 : :
1731 : : SGPropertyNode *
1732 : 1518 : SGPropertyNode::getNode (const char * relative_path, bool create)
1733 : : {
1734 [ + + ]: 1518 : if (_path_cache == 0)
1735 : 47 : _path_cache = new hash_table;
1736 : :
1737 : 1518 : SGPropertyNode * result = _path_cache->get(relative_path);
1738 [ + + ]: 1518 : if (result == 0) {
1739 : : vector<PathComponent> components;
1740 : 1309 : parse_path(relative_path, components);
1741 : 1309 : result = find_node(this, components, 0, create);
1742 [ + + ]: 1309 : if (result != 0)
1743 : 1309 : _path_cache->put(relative_path, result);
1744 : : }
1745 : :
1746 : 1518 : return result;
1747 : : }
1748 : :
1749 : : SGPropertyNode *
1750 : 1 : SGPropertyNode::getNode (const char * relative_path, int index, bool create)
1751 : : {
1752 : : vector<PathComponent> components;
1753 : 1 : parse_path(relative_path, components);
1754 [ + - ]: 1 : if (components.size() > 0)
1755 : 1 : components.back().index = index;
1756 : 1 : return find_node(this, components, 0, create);
1757 : : }
1758 : :
1759 : : const SGPropertyNode *
1760 : 0 : SGPropertyNode::getNode (const char * relative_path) const
1761 : : {
1762 : 0 : return ((SGPropertyNode *)this)->getNode(relative_path, false);
1763 : : }
1764 : :
1765 : : const SGPropertyNode *
1766 : 0 : SGPropertyNode::getNode (const char * relative_path, int index) const
1767 : : {
1768 : 0 : return ((SGPropertyNode *)this)->getNode(relative_path, index, false);
1769 : : }
1770 : :
1771 : :
1772 : : ////////////////////////////////////////////////////////////////////////
1773 : : // Convenience methods using relative paths.
1774 : : ////////////////////////////////////////////////////////////////////////
1775 : :
1776 : :
1777 : : /**
1778 : : * Test whether another node has a value attached.
1779 : : */
1780 : : bool
1781 : 0 : SGPropertyNode::hasValue (const char * relative_path) const
1782 : : {
1783 : 0 : const SGPropertyNode * node = getNode(relative_path);
1784 [ # # ]: 0 : return (node == 0 ? false : node->hasValue());
1785 : : }
1786 : :
1787 : :
1788 : : /**
1789 : : * Get the value type for another node.
1790 : : */
1791 : : SGPropertyNode::Type
1792 : 0 : SGPropertyNode::getType (const char * relative_path) const
1793 : : {
1794 : 0 : const SGPropertyNode * node = getNode(relative_path);
1795 [ # # ]: 0 : return (node == 0 ? UNSPECIFIED : (Type)(node->getType()));
1796 : : }
1797 : :
1798 : :
1799 : : /**
1800 : : * Get a bool value for another node.
1801 : : */
1802 : : bool
1803 : : SGPropertyNode::getBoolValue (const char * relative_path,
1804 : 0 : bool defaultValue) const
1805 : : {
1806 : 0 : const SGPropertyNode * node = getNode(relative_path);
1807 [ # # ]: 0 : return (node == 0 ? defaultValue : node->getBoolValue());
1808 : : }
1809 : :
1810 : :
1811 : : /**
1812 : : * Get an int value for another node.
1813 : : */
1814 : : int
1815 : : SGPropertyNode::getIntValue (const char * relative_path,
1816 : 0 : int defaultValue) const
1817 : : {
1818 : 0 : const SGPropertyNode * node = getNode(relative_path);
1819 [ # # ]: 0 : return (node == 0 ? defaultValue : node->getIntValue());
1820 : : }
1821 : :
1822 : :
1823 : : /**
1824 : : * Get a long value for another node.
1825 : : */
1826 : : long
1827 : : SGPropertyNode::getLongValue (const char * relative_path,
1828 : 0 : long defaultValue) const
1829 : : {
1830 : 0 : const SGPropertyNode * node = getNode(relative_path);
1831 [ # # ]: 0 : return (node == 0 ? defaultValue : node->getLongValue());
1832 : : }
1833 : :
1834 : :
1835 : : /**
1836 : : * Get a float value for another node.
1837 : : */
1838 : : float
1839 : : SGPropertyNode::getFloatValue (const char * relative_path,
1840 : 0 : float defaultValue) const
1841 : : {
1842 : 0 : const SGPropertyNode * node = getNode(relative_path);
1843 [ # # ]: 0 : return (node == 0 ? defaultValue : node->getFloatValue());
1844 : : }
1845 : :
1846 : :
1847 : : /**
1848 : : * Get a double value for another node.
1849 : : */
1850 : : double
1851 : : SGPropertyNode::getDoubleValue (const char * relative_path,
1852 : 0 : double defaultValue) const
1853 : : {
1854 : 0 : const SGPropertyNode * node = getNode(relative_path);
1855 [ # # ]: 0 : return (node == 0 ? defaultValue : node->getDoubleValue());
1856 : : }
1857 : :
1858 : :
1859 : : /**
1860 : : * Get a string value for another node.
1861 : : */
1862 : : const char *
1863 : : SGPropertyNode::getStringValue (const char * relative_path,
1864 : 0 : const char * defaultValue) const
1865 : : {
1866 : 0 : const SGPropertyNode * node = getNode(relative_path);
1867 [ # # ]: 0 : return (node == 0 ? defaultValue : node->getStringValue());
1868 : : }
1869 : :
1870 : :
1871 : : /**
1872 : : * Set a bool value for another node.
1873 : : */
1874 : : bool
1875 : 0 : SGPropertyNode::setBoolValue (const char * relative_path, bool value)
1876 : : {
1877 : 0 : return getNode(relative_path, true)->setBoolValue(value);
1878 : : }
1879 : :
1880 : :
1881 : : /**
1882 : : * Set an int value for another node.
1883 : : */
1884 : : bool
1885 : 0 : SGPropertyNode::setIntValue (const char * relative_path, int value)
1886 : : {
1887 : 0 : return getNode(relative_path, true)->setIntValue(value);
1888 : : }
1889 : :
1890 : :
1891 : : /**
1892 : : * Set a long value for another node.
1893 : : */
1894 : : bool
1895 : 0 : SGPropertyNode::setLongValue (const char * relative_path, long value)
1896 : : {
1897 : 0 : return getNode(relative_path, true)->setLongValue(value);
1898 : : }
1899 : :
1900 : :
1901 : : /**
1902 : : * Set a float value for another node.
1903 : : */
1904 : : bool
1905 : 0 : SGPropertyNode::setFloatValue (const char * relative_path, float value)
1906 : : {
1907 : 0 : return getNode(relative_path, true)->setFloatValue(value);
1908 : : }
1909 : :
1910 : :
1911 : : /**
1912 : : * Set a double value for another node.
1913 : : */
1914 : : bool
1915 : 0 : SGPropertyNode::setDoubleValue (const char * relative_path, double value)
1916 : : {
1917 : 0 : return getNode(relative_path, true)->setDoubleValue(value);
1918 : : }
1919 : :
1920 : :
1921 : : /**
1922 : : * Set a string value for another node.
1923 : : */
1924 : : bool
1925 : 0 : SGPropertyNode::setStringValue (const char * relative_path, const char * value)
1926 : : {
1927 : 0 : return getNode(relative_path, true)->setStringValue(value);
1928 : : }
1929 : :
1930 : :
1931 : : /**
1932 : : * Set an unknown value for another node.
1933 : : */
1934 : : bool
1935 : : SGPropertyNode::setUnspecifiedValue (const char * relative_path,
1936 : 0 : const char * value)
1937 : : {
1938 : 0 : return getNode(relative_path, true)->setUnspecifiedValue(value);
1939 : : }
1940 : :
1941 : :
1942 : : /**
1943 : : * Test whether another node is tied.
1944 : : */
1945 : : bool
1946 : 0 : SGPropertyNode::isTied (const char * relative_path) const
1947 : : {
1948 : 0 : const SGPropertyNode * node = getNode(relative_path);
1949 [ # # ]: 0 : return (node == 0 ? false : node->isTied());
1950 : : }
1951 : :
1952 : :
1953 : : /**
1954 : : * Tie a node reached by a relative path, creating it if necessary.
1955 : : */
1956 : : bool
1957 : : SGPropertyNode::tie (const char * relative_path,
1958 : : const SGRawValue<bool> &rawValue,
1959 : 50 : bool useDefault)
1960 : : {
1961 : 50 : return getNode(relative_path, true)->tie(rawValue, useDefault);
1962 : : }
1963 : :
1964 : :
1965 : : /**
1966 : : * Tie a node reached by a relative path, creating it if necessary.
1967 : : */
1968 : : bool
1969 : : SGPropertyNode::tie (const char * relative_path,
1970 : : const SGRawValue<int> &rawValue,
1971 : 22 : bool useDefault)
1972 : : {
1973 : 22 : return getNode(relative_path, true)->tie(rawValue, useDefault);
1974 : : }
1975 : :
1976 : :
1977 : : /**
1978 : : * Tie a node reached by a relative path, creating it if necessary.
1979 : : */
1980 : : bool
1981 : : SGPropertyNode::tie (const char * relative_path,
1982 : : const SGRawValue<long> &rawValue,
1983 : 0 : bool useDefault)
1984 : : {
1985 : 0 : return getNode(relative_path, true)->tie(rawValue, useDefault);
1986 : : }
1987 : :
1988 : :
1989 : : /**
1990 : : * Tie a node reached by a relative path, creating it if necessary.
1991 : : */
1992 : : bool
1993 : : SGPropertyNode::tie (const char * relative_path,
1994 : : const SGRawValue<float> &rawValue,
1995 : 0 : bool useDefault)
1996 : : {
1997 : 0 : return getNode(relative_path, true)->tie(rawValue, useDefault);
1998 : : }
1999 : :
2000 : :
2001 : : /**
2002 : : * Tie a node reached by a relative path, creating it if necessary.
2003 : : */
2004 : : bool
2005 : : SGPropertyNode::tie (const char * relative_path,
2006 : : const SGRawValue<double> &rawValue,
2007 : 579 : bool useDefault)
2008 : : {
2009 : 579 : return getNode(relative_path, true)->tie(rawValue, useDefault);
2010 : : }
2011 : :
2012 : :
2013 : : /**
2014 : : * Tie a node reached by a relative path, creating it if necessary.
2015 : : */
2016 : : bool
2017 : : SGPropertyNode::tie (const char * relative_path,
2018 : : const SGRawValue<const char *> &rawValue,
2019 : 0 : bool useDefault)
2020 : : {
2021 : 0 : return getNode(relative_path, true)->tie(rawValue, useDefault);
2022 : : }
2023 : :
2024 : :
2025 : : /**
2026 : : * Attempt to untie another node reached by a relative path.
2027 : : */
2028 : : bool
2029 : 651 : SGPropertyNode::untie (const char * relative_path)
2030 : : {
2031 : 651 : SGPropertyNode * node = getNode(relative_path);
2032 [ + - ]: 651 : return (node == 0 ? false : node->untie());
2033 : : }
2034 : :
2035 : : void
2036 : : SGPropertyNode::addChangeListener (SGPropertyChangeListener * listener,
2037 : 0 : bool initial)
2038 : : {
2039 [ # # ]: 0 : if (_listeners == 0)
2040 : 0 : _listeners = new vector<SGPropertyChangeListener*>;
2041 : 0 : _listeners->push_back(listener);
2042 : 0 : listener->register_property(this);
2043 [ # # ]: 0 : if (initial)
2044 : 0 : listener->valueChanged(this);
2045 : 0 : }
2046 : :
2047 : : void
2048 : 0 : SGPropertyNode::removeChangeListener (SGPropertyChangeListener * listener)
2049 : : {
2050 : : vector<SGPropertyChangeListener*>::iterator it =
2051 : 0 : find(_listeners->begin(), _listeners->end(), listener);
2052 [ # # ]: 0 : if (it != _listeners->end()) {
2053 : 0 : _listeners->erase(it);
2054 : 0 : listener->unregister_property(this);
2055 [ # # ]: 0 : if (_listeners->empty()) {
2056 : 0 : vector<SGPropertyChangeListener*>* tmp = _listeners;
2057 : 0 : _listeners = 0;
2058 [ # # ]: 0 : delete tmp;
2059 : : }
2060 : : }
2061 : 0 : }
2062 : :
2063 : : void
2064 : 915256 : SGPropertyNode::fireValueChanged ()
2065 : : {
2066 : 915256 : fireValueChanged(this);
2067 : 915256 : }
2068 : :
2069 : : void
2070 : 701 : SGPropertyNode::fireChildAdded (SGPropertyNode * child)
2071 : : {
2072 : 701 : fireChildAdded(this, child);
2073 : 701 : }
2074 : :
2075 : : void
2076 : 0 : SGPropertyNode::fireChildRemoved (SGPropertyNode * child)
2077 : : {
2078 : 0 : fireChildRemoved(this, child);
2079 : 0 : }
2080 : :
2081 : : void
2082 : 5224348 : SGPropertyNode::fireValueChanged (SGPropertyNode * node)
2083 : : {
2084 [ - + ]: 5224348 : if (_listeners != 0) {
2085 [ # # ]: 0 : for (unsigned int i = 0; i < _listeners->size(); i++) {
2086 : 0 : (*_listeners)[i]->valueChanged(node);
2087 : : }
2088 : : }
2089 [ + + ]: 5224348 : if (_parent != 0)
2090 : 4309092 : _parent->fireValueChanged(node);
2091 : 5224348 : }
2092 : :
2093 : : void
2094 : : SGPropertyNode::fireChildAdded (SGPropertyNode * parent,
2095 : 2952 : SGPropertyNode * child)
2096 : : {
2097 [ - + ]: 2952 : if (_listeners != 0) {
2098 [ # # ]: 0 : for (unsigned int i = 0; i < _listeners->size(); i++) {
2099 : 0 : (*_listeners)[i]->childAdded(parent, child);
2100 : : }
2101 : : }
2102 [ + + ]: 2952 : if (_parent != 0)
2103 : 2251 : _parent->fireChildAdded(parent, child);
2104 : 2952 : }
2105 : :
2106 : : void
2107 : : SGPropertyNode::fireChildRemoved (SGPropertyNode * parent,
2108 : 0 : SGPropertyNode * child)
2109 : : {
2110 [ # # ]: 0 : if (_listeners != 0) {
2111 [ # # ]: 0 : for (unsigned int i = 0; i < _listeners->size(); i++) {
2112 : 0 : (*_listeners)[i]->childRemoved(parent, child);
2113 : : }
2114 : : }
2115 [ # # ]: 0 : if (_parent != 0)
2116 : 0 : _parent->fireChildRemoved(parent, child);
2117 : 0 : }
2118 : :
2119 : :
2120 : :
2121 : : ////////////////////////////////////////////////////////////////////////
2122 : : // Simplified hash table for caching paths.
2123 : : ////////////////////////////////////////////////////////////////////////
2124 : :
2125 : : #define HASH_TABLE_SIZE 199
2126 : :
2127 : 1303 : SGPropertyNode::hash_table::entry::entry ()
2128 : 1303 : : _value(0)
2129 : : {
2130 : 1303 : }
2131 : :
2132 : 0 : SGPropertyNode::hash_table::entry::~entry ()
2133 : : {
2134 : : // Don't delete the value; we don't own
2135 : : // the pointer.
2136 : 0 : }
2137 : :
2138 : : void
2139 : 0 : SGPropertyNode::hash_table::entry::set_key (const char * key)
2140 : : {
2141 : 1303 : _key = key;
2142 : 0 : }
2143 : :
2144 : : void
2145 : 0 : SGPropertyNode::hash_table::entry::set_value (SGPropertyNode * value)
2146 : : {
2147 : 1303 : _value = value;
2148 : 0 : }
2149 : :
2150 : 0 : SGPropertyNode::hash_table::bucket::bucket ()
2151 : : : _length(0),
2152 : 774 : _entries(0)
2153 : : {
2154 : 0 : }
2155 : :
2156 : 0 : SGPropertyNode::hash_table::bucket::~bucket ()
2157 : : {
2158 [ # # ][ # # ]: 0 : for (int i = 0; i < _length; i++)
2159 [ # # ][ # # ]: 0 : delete _entries[i];
2160 [ # # ][ # # ]: 0 : delete [] _entries;
2161 : 0 : }
2162 : :
2163 : : SGPropertyNode::hash_table::entry *
2164 : 2047 : SGPropertyNode::hash_table::bucket::get_entry (const char * key, bool create)
2165 : : {
2166 : : int i;
2167 [ + + ]: 4713 : for (i = 0; i < _length; i++) {
2168 [ + + ]: 2875 : if (!strcmp(_entries[i]->get_key(), key))
2169 : 209 : return _entries[i];
2170 : : }
2171 [ + + ]: 1838 : if (create) {
2172 : 1303 : entry ** new_entries = new entry*[_length+1];
2173 [ + + ]: 2432 : for (i = 0; i < _length; i++) {
2174 : 1129 : new_entries[i] = _entries[i];
2175 : : }
2176 [ + + ]: 1303 : delete [] _entries;
2177 : 1303 : _entries = new_entries;
2178 : 1303 : _entries[_length] = new entry;
2179 : 1303 : _entries[_length]->set_key(key);
2180 : 1303 : _length++;
2181 : 1303 : return _entries[_length - 1];
2182 : : } else {
2183 : 2047 : return 0;
2184 : : }
2185 : : }
2186 : :
2187 : : void
2188 : 0 : SGPropertyNode::hash_table::bucket::erase (const char * key)
2189 : : {
2190 : : int i;
2191 [ # # ]: 0 : for (i = 0; i < _length; i++) {
2192 [ # # ]: 0 : if (!strcmp(_entries[i]->get_key(), key))
2193 : 0 : break;
2194 : : }
2195 : :
2196 [ # # ]: 0 : if (i < _length) {
2197 [ # # ]: 0 : for (++i; i < _length; i++) {
2198 : 0 : _entries[i-1] = _entries[i];
2199 : : }
2200 : 0 : _length--;
2201 : : }
2202 : 0 : }
2203 : :
2204 : :
2205 : 0 : SGPropertyNode::hash_table::hash_table ()
2206 : : : _data_length(0),
2207 : 47 : _data(0)
2208 : : {
2209 : 0 : }
2210 : :
2211 : 0 : SGPropertyNode::hash_table::~hash_table ()
2212 : : {
2213 [ # # ][ # # ]: 0 : for (unsigned int i = 0; i < _data_length; i++)
2214 [ # # ][ # # ]: 0 : delete _data[i];
2215 [ # # ][ # # ]: 0 : delete [] _data;
2216 : 0 : }
2217 : :
2218 : : SGPropertyNode *
2219 : 1518 : SGPropertyNode::hash_table::get (const char * key)
2220 : : {
2221 [ + + ]: 1518 : if (_data_length == 0)
2222 : 47 : return 0;
2223 : 1471 : unsigned int index = hashcode(key) % _data_length;
2224 [ + + ]: 1471 : if (_data[index] == 0)
2225 : 727 : return 0;
2226 : 744 : entry * e = _data[index]->get_entry(key);
2227 [ + + ]: 744 : if (e == 0)
2228 : 535 : return 0;
2229 : : else
2230 : 1518 : return e->get_value();
2231 : : }
2232 : :
2233 : : void
2234 : 1303 : SGPropertyNode::hash_table::put (const char * key, SGPropertyNode * value)
2235 : : {
2236 [ + + ]: 1303 : if (_data_length == 0) {
2237 : 47 : _data = new bucket*[HASH_TABLE_SIZE];
2238 : 47 : _data_length = HASH_TABLE_SIZE;
2239 [ + + ]: 9400 : for (unsigned int i = 0; i < HASH_TABLE_SIZE; i++)
2240 : 9353 : _data[i] = 0;
2241 : : }
2242 : 1303 : unsigned int index = hashcode(key) % _data_length;
2243 [ + + ]: 1303 : if (_data[index] == 0) {
2244 : 774 : _data[index] = new bucket;
2245 : : }
2246 : 1303 : entry * e = _data[index]->get_entry(key, true);
2247 : : e->set_value(value);
2248 : 1303 : }
2249 : :
2250 : : void
2251 : 0 : SGPropertyNode::hash_table::erase (const char * key)
2252 : : {
2253 [ # # ]: 0 : if (_data_length == 0)
2254 : 0 : return;
2255 : 0 : unsigned int index = hashcode(key) % _data_length;
2256 [ # # ]: 0 : if (_data[index] == 0)
2257 : 0 : return;
2258 : 0 : _data[index]->erase(key);
2259 : : }
2260 : :
2261 : : unsigned int
2262 : 0 : SGPropertyNode::hash_table::hashcode (const char * key)
2263 : : {
2264 : 2774 : unsigned int hash = 0;
2265 [ # # ][ # # ]: 90838 : while (*key != 0) {
[ + + ][ + + ]
2266 : 88064 : hash = 31 * hash + *key;
2267 : 88064 : key++;
2268 : : }
2269 : 0 : return hash;
2270 : : }
2271 : :
2272 : :
2273 : :
2274 : : ////////////////////////////////////////////////////////////////////////
2275 : : // Implementation of SGPropertyChangeListener.
2276 : : ////////////////////////////////////////////////////////////////////////
2277 : :
2278 : 0 : SGPropertyChangeListener::~SGPropertyChangeListener ()
2279 : : {
2280 : : // This will come back and remove
2281 : : // the current item each time. Is
2282 : : // that OK?
2283 : : vector<SGPropertyNode *>::iterator it;
2284 [ # # ][ # # ]: 0 : for (it = _properties.begin(); it != _properties.end(); it++)
[ # # ]
2285 : 0 : (*it)->removeChangeListener(this);
2286 [ # # ][ # # ]: 0 : }
[ # # ]
2287 : :
2288 : : void
2289 : 0 : SGPropertyChangeListener::valueChanged (SGPropertyNode * node)
2290 : : {
2291 : : // NO-OP
2292 : 0 : }
2293 : :
2294 : : void
2295 : : SGPropertyChangeListener::childAdded (SGPropertyNode * node,
2296 : 0 : SGPropertyNode * child)
2297 : : {
2298 : : // NO-OP
2299 : 0 : }
2300 : :
2301 : : void
2302 : : SGPropertyChangeListener::childRemoved (SGPropertyNode * parent,
2303 : 0 : SGPropertyNode * child)
2304 : : {
2305 : : // NO-OP
2306 : 0 : }
2307 : :
2308 : : void
2309 : 0 : SGPropertyChangeListener::register_property (SGPropertyNode * node)
2310 : : {
2311 : 0 : _properties.push_back(node);
2312 : 0 : }
2313 : :
2314 : : void
2315 : 0 : SGPropertyChangeListener::unregister_property (SGPropertyNode * node)
2316 : : {
2317 : : vector<SGPropertyNode *>::iterator it =
2318 : 0 : find(_properties.begin(), _properties.end(), node);
2319 [ # # ]: 0 : if (it != _properties.end())
2320 : 0 : _properties.erase(it);
2321 [ + + ][ + - ]: 12 : }
2322 : :
2323 : :
2324 : : // end of props.cxx
|