comparison host/libcdl/value.cxx @ 76:435cced73e2f ecos-v1_3_1-release

eCos v1.3.1 merged from eCos master repository on 2000-03-27-23:22:51-BST
author jlarmour
date Tue, 28 Mar 2000 14:10:45 +0000
parents
children 6736c52df507
comparison
equal deleted inserted replaced
75:41bf073c0c32 76:435cced73e2f
1 //{{{ Banner
2
3 //============================================================================
4 //
5 // value.cxx
6 //
7 // Implementation of value-related CDL classes.
8 //
9 //============================================================================
10 //####COPYRIGHTBEGIN####
11 //
12 // ----------------------------------------------------------------------------
13 // Copyright (C) 1999, 2000 Red Hat, Inc.
14 //
15 // This file is part of the eCos host tools.
16 //
17 // This program is free software; you can redistribute it and/or modify it
18 // under the terms of the GNU General Public License as published by the Free
19 // Software Foundation; either version 2 of the License, or (at your option)
20 // any later version.
21 //
22 // This program is distributed in the hope that it will be useful, but WITHOUT
23 // ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
24 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
25 // more details.
26 //
27 // You should have received a copy of the GNU General Public License along with
28 // this program; if not, write to the Free Software Foundation, Inc.,
29 // 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
30 //
31 // ----------------------------------------------------------------------------
32 //
33 //####COPYRIGHTEND####
34 //============================================================================
35 //#####DESCRIPTIONBEGIN####
36 //
37 // Author(s): bartv
38 // Contact(s): bartv
39 // Date: 1999/07/12
40 // Version: 0.02
41 //
42 //####DESCRIPTIONEND####
43 //============================================================================
44
45 //}}}
46 //{{{ #include's
47
48 // ----------------------------------------------------------------------------
49 #include "cdlconfig.h"
50
51 // Get the infrastructure types, assertions, tracing and similar
52 // facilities.
53 #include <cyg/infra/cyg_ass.h>
54 #include <cyg/infra/cyg_trac.h>
55
56 // <cdlcore.hxx> defines everything implemented in this module.
57 // It implicitly supplies <string>, <vector> and <map> because
58 // the class definitions rely on these headers.
59 #include <cdlcore.hxx>
60
61 //}}}
62
63 //{{{ Statics
64
65 // ----------------------------------------------------------------------------
66 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValue);
67 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlListValue);
68 CYGDBG_DEFINE_MEMLEAK_COUNTER(CdlValuableBody);
69
70 //}}}
71 //{{{ CdlSimpleValue class
72
73 //{{{ Constructors
74
75 // ----------------------------------------------------------------------------
76
77 CdlSimpleValue::CdlSimpleValue()
78 {
79 CYG_REPORT_FUNCNAME("CdlSimpleValue:: default constructor");
80 CYG_REPORT_FUNCARG1XV(this);
81
82 value = "0";
83 int_value = 0;
84 double_value = 0.0;
85 valid_flags = int_valid | double_valid | string_valid;
86 format = CdlValueFormat_Default;
87
88 CYG_REPORT_RETURN();
89 }
90
91 CdlSimpleValue::CdlSimpleValue(std::string val)
92 {
93 CYG_REPORT_FUNCNAME("CdlSimpleValue:: string constructor");
94 CYG_REPORT_FUNCARG1XV(this);
95
96 value = val;
97 int_value = 0;
98 double_value = 0.0;
99 valid_flags = string_valid;
100 format = CdlValueFormat_Default;
101
102 CYG_REPORT_RETURN();
103 }
104
105 CdlSimpleValue::CdlSimpleValue(cdl_int val)
106 {
107 CYG_REPORT_FUNCNAME("CdlSimpleValue:: int constructor");
108 CYG_REPORT_FUNCARG1XV(this);
109
110 value = "0";
111 int_value = val;
112 double_value = 0.0;
113 valid_flags = int_valid;
114 format = CdlValueFormat_Default;
115
116 CYG_REPORT_RETURN();
117 }
118
119 CdlSimpleValue::CdlSimpleValue(double val)
120 {
121 CYG_REPORT_FUNCNAME("CdlSimpleValue:: double constructor");
122 CYG_REPORT_FUNCARG1XV(this);
123
124 value = "0";
125 int_value = 0;
126 double_value = val;
127 valid_flags = double_valid;
128 format = CdlValueFormat_Default;
129
130 CYG_REPORT_RETURN();
131 }
132
133 CdlSimpleValue::CdlSimpleValue(bool val)
134 {
135 CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool constructor");
136 CYG_REPORT_FUNCARG2XV(this, val);
137
138 value = (val) ? "1" : "0";
139 int_value = (val) ? 1 : 0;
140 double_value = 0.0;
141 valid_flags = string_valid | int_valid;
142 format = CdlValueFormat_Default;
143
144 CYG_REPORT_RETURN();
145 }
146
147 CdlSimpleValue::CdlSimpleValue(const CdlSimpleValue& original)
148 {
149 CYG_REPORT_FUNCNAME("CdlSimpleValue:: copy constructor");
150 CYG_REPORT_FUNCARG2XV(this, &original);
151
152 value = original.value;
153 int_value = original.int_value;
154 double_value = original.double_value;
155 valid_flags = original.valid_flags;
156 format = original.format;
157
158 CYG_REPORT_RETURN();
159 }
160
161 //}}}
162 //{{{ Destructor
163
164 // ----------------------------------------------------------------------------
165
166 CdlSimpleValue::~CdlSimpleValue()
167 {
168 CYG_REPORT_FUNCNAME("CdlsimpleValue:: destructor");
169 CYG_REPORT_FUNCARG1XV(this);
170
171 value = "";
172 int_value = 0;
173 double_value = 0.0;
174 valid_flags = 0;
175 format = CdlValueFormat_Default;
176
177 CYG_REPORT_RETURN();
178 }
179
180 //}}}
181 //{{{ Assignment operators
182
183 // ----------------------------------------------------------------------------
184
185 CdlSimpleValue&
186 CdlSimpleValue::operator=(const CdlSimpleValue& original)
187 {
188 CYG_REPORT_FUNCNAME("CdlSimpleValue:: assignment operator");
189 CYG_REPORT_FUNCARG2XV(this, &original);
190
191 if (this != &original) {
192 value = original.value;
193 int_value = original.int_value;
194 double_value = original.double_value;
195 valid_flags = original.valid_flags;
196 format = original.format;
197 }
198
199 CYG_REPORT_RETURN();
200 return *this;
201 }
202
203 CdlSimpleValue&
204 CdlSimpleValue::operator=(std::string val)
205 {
206 CYG_REPORT_FUNCNAME("CdlSimpleValue:: string assignment");
207 CYG_REPORT_FUNCARG1XV(this);
208
209 value = val;
210 int_value = 0;
211 double_value = 0.0;
212 valid_flags = string_valid;
213 format = CdlValueFormat_Default;
214
215 CYG_REPORT_RETURN();
216 return *this;
217 }
218
219 CdlSimpleValue&
220 CdlSimpleValue::operator=(cdl_int val)
221 {
222 CYG_REPORT_FUNCNAME("CdlSimpleValue:: integer assignment");
223 CYG_REPORT_FUNCARG1XV(this);
224
225 value = "";
226 int_value = val;
227 double_value = 0.0;
228 valid_flags = int_valid;
229 format = CdlValueFormat_Default;
230
231 CYG_REPORT_RETURN();
232 return *this;
233 }
234
235 CdlSimpleValue&
236 CdlSimpleValue::operator=(double val)
237 {
238 CYG_REPORT_FUNCNAME("CdlSimpleValue:: double assignment");
239 CYG_REPORT_FUNCARG1XV(this);
240
241 value = "";
242 int_value = 0;
243 double_value = val;
244 valid_flags = double_valid;
245 format = CdlValueFormat_Default;
246
247 CYG_REPORT_RETURN();
248 return *this;
249 }
250
251 // ----------------------------------------------------------------------------
252 // Converting a boolean into a simple value. This is sufficiently common
253 // to warrant its own member function, and in addition it avoids
254 // ambiguity when assigning 0.
255
256 CdlSimpleValue&
257 CdlSimpleValue::operator=(bool val)
258 {
259 CYG_REPORT_FUNCNAME("CdlSimpleValue:: bool assignment");
260 CYG_REPORT_FUNCARG1XV(this);
261
262 value = (val) ? "1" : "0";
263 int_value = (val) ? 1 : 0;
264 double_value = 0.0;
265 valid_flags = string_valid | int_valid;
266 format = CdlValueFormat_Default;
267
268 CYG_REPORT_RETURN();
269 return *this;
270 }
271
272 //}}}
273 //{{{ CdlValuable -> CdlSimpleValue
274
275 // ----------------------------------------------------------------------------
276 // This routine bridges the gap between the full data held in the CdlValuable
277 // object and the basic information needed for expression evaluation.
278
279 void
280 CdlSimpleValue::eval_valuable(CdlEvalContext& context, CdlValuable valuable, CdlSimpleValue& result)
281 {
282 CYG_REPORT_FUNCNAME("CdlSimpleValue:: valuable assignment");
283 CYG_REPORT_FUNCARG3XV(&context, valuable, &result);
284 CYG_PRECONDITION_CLASSC(valuable);
285
286 // If the valuable is not currently active then its value is
287 // always zero for the purposes of expression evaluation.
288 // FIXME: this check should be on a per-transaction basis.
289 if (((0 != context.transaction) && !context.transaction->is_active(valuable)) ||
290 ((0 == context.transaction) && !valuable->is_active())) {
291
292 result.value = "0";
293 result.int_value = 0;
294 result.double_value = 0.0;
295 result.valid_flags = string_valid | int_valid;
296 result.format = CdlValueFormat_Default;
297 CYG_REPORT_RETURN();
298 return;
299 }
300
301 // Get hold of the underlying CdlValue object
302 const CdlValue& val = (0 != context.transaction) ?
303 context.transaction->get_whole_value(valuable) : valuable->get_whole_value();
304
305 // Otherwise the value depends on the flavor.
306 switch(val.get_flavor()) {
307 case CdlValueFlavor_None :
308 {
309 // This could be treated as an error, but since valuables with flavor
310 // none are permanently enabled a constant "1" is a better result.
311 result.value = "1";
312 result.int_value = 1;
313 result.double_value = 0.0;
314 result.valid_flags = string_valid | int_valid;
315 result.format = CdlValueFormat_Default;
316 break;
317 }
318 case CdlValueFlavor_Bool :
319 {
320 bool enabled = val.is_enabled();
321 result.value = (enabled) ? "1" : "0";
322 result.int_value = (enabled) ? 1 : 0;
323 result.double_value = 0.0;
324 result.valid_flags = string_valid | int_valid;
325 result.format = CdlValueFormat_Default;
326 break;
327 }
328 case CdlValueFlavor_BoolData :
329 {
330 if (!val.is_enabled()) {
331
332 result.value = "0";
333 result.int_value = 0;
334 result.double_value = 0.0;
335 result.valid_flags = string_valid | int_valid;
336 result.format = CdlValueFormat_Default;
337
338 } else {
339
340 // Just use a copy constructor, let the compiler optimise things.
341 result = val.get_simple_value();
342 }
343 break;
344 }
345 case CdlValueFlavor_Data :
346 {
347 // Just like BoolData, but with no need to check the enabled flag.
348 result = val.get_simple_value();
349 break;
350 }
351 default:
352 {
353 CYG_FAIL("Valuable object with an unknown flavor encountered.");
354 }
355 }
356
357 CYG_REPORT_RETURN();
358 }
359
360 //}}}
361 //{{{ Getting the value
362
363 // ----------------------------------------------------------------------------
364 // Some of these calls involve conversion operators.
365
366 std::string
367 CdlSimpleValue::get_value() const
368 {
369 CYG_REPORT_FUNCNAME("CdlSimpleValue::get_value");
370 CYG_REPORT_FUNCARG1XV(this);
371
372 if (!(valid_flags & string_valid)) {
373 if (valid_flags & int_valid) {
374 Cdl::integer_to_string(int_value, value, format);
375 } else if (valid_flags & double_valid) {
376 Cdl::double_to_string(double_value, value, format);
377 } else {
378 CYG_FAIL("Attempt to use uninitialized SimpleValue");
379 }
380 valid_flags |= string_valid;
381 }
382
383 CYG_REPORT_RETURN();
384 return value;
385 }
386
387 bool
388 CdlSimpleValue::has_integer_value() const
389 {
390 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_integer_value", "result %d");
391 CYG_REPORT_FUNCARG1XV(this);
392
393 if (!(valid_flags & (int_valid | int_invalid))) {
394 if (valid_flags & double_valid) {
395 if (Cdl::double_to_integer(double_value, int_value)) {
396 valid_flags |= int_valid;
397 } else {
398 valid_flags |= int_invalid;
399 }
400 } else if (valid_flags & string_valid) {
401 if (Cdl::string_to_integer(value, int_value)) {
402 valid_flags |= int_valid;
403 } else {
404 valid_flags |= int_invalid;
405 }
406 } else {
407 CYG_FAIL("Attempt to use uninitialized SimpleValue");
408 }
409 }
410
411 bool result = (valid_flags & int_valid);
412 CYG_REPORT_RETVAL(result);
413 return result;
414 }
415
416 cdl_int
417 CdlSimpleValue::get_integer_value() const
418 {
419 CYG_REPORT_FUNCNAMETYPE("CdlsimpleValue::get_integer_value", "result %ld");
420 CYG_REPORT_FUNCARG1XV(this);
421
422 cdl_int result = 0;
423 if ((valid_flags & int_valid) || has_integer_value()) {
424 result = int_value;
425 }
426
427 CYG_REPORT_RETVAL((int) result);
428 return result;
429 }
430
431 bool
432 CdlSimpleValue::has_double_value() const
433 {
434 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::has_double_value", "result %d");
435 CYG_REPORT_FUNCARG1XV(this);
436
437 if (!(valid_flags & (double_valid | double_invalid))) {
438 if (valid_flags & int_valid) {
439 Cdl::integer_to_double(int_value, double_value);
440 valid_flags |= double_valid;
441 } else if (valid_flags & string_valid) {
442 if (Cdl::string_to_double(value, double_value)) {
443 valid_flags |= double_valid;
444 } else {
445 valid_flags |= double_invalid;
446 }
447 } else {
448 CYG_FAIL("Attempt to use uninitialized SimpleValue");
449 }
450 }
451 bool result = (valid_flags & double_valid);
452 CYG_REPORT_RETVAL(result);
453 return result;
454 }
455
456 double
457 CdlSimpleValue::get_double_value() const
458 {
459 CYG_REPORT_FUNCNAME("CdlSimpleValue::get_double_value");
460 CYG_REPORT_FUNCARG1XV(this);
461
462 double result = 0.0;
463 if ((valid_flags & double_valid) || has_double_value()) {
464 result = double_value;
465 }
466
467 CYG_REPORT_RETURN();
468 return result;
469 }
470
471 bool
472 CdlSimpleValue::get_bool_value() const
473 {
474 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_bool_value", "result %d");
475 CYG_REPORT_FUNCARG1XV(this);
476
477 bool result = false;
478 if (valid_flags & int_valid) {
479 if (0 != int_value) {
480 result = true;
481 }
482 } else if (valid_flags & double_valid) {
483 // Leave it to the compiler to decide what is valid
484 result = double_value;
485 } else if (valid_flags & string_valid) {
486 // string_to_bool copes with "1", "true", and a few other cases.
487 // If the current value does not match any of these then
488 // true corresponds to a non-empty string.
489 if (!Cdl::string_to_bool(value, result)) {
490 if ("" == value) {
491 result = false;
492 } else {
493 result = true;
494 }
495 }
496 } else {
497 // No value defined, default to false.
498 result = false;
499 }
500
501 CYG_REPORT_RETVAL(result);
502 return result;
503 }
504
505 //}}}
506 //{{{ Updating the value
507
508 // ----------------------------------------------------------------------------
509 // Normally the assignment operators will be used for this instead.
510
511 void
512 CdlSimpleValue::set_value(std::string val, CdlValueFormat new_format)
513 {
514 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value (string)");
515 CYG_REPORT_FUNCARG1XV(this);
516
517 value = val;
518 int_value = 0;
519 double_value = 0.0;
520 valid_flags = string_valid;
521 format = new_format;
522 }
523
524
525 void
526 CdlSimpleValue::set_integer_value(cdl_int val, CdlValueFormat new_format)
527 {
528 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_integer_value");
529 CYG_REPORT_FUNCARG2XV(this, (int) val);
530
531 value = "";
532 int_value = val;
533 double_value = 0.0;
534 valid_flags = int_valid;
535 format = new_format;
536
537 CYG_REPORT_RETURN();
538 }
539
540
541 void
542 CdlSimpleValue::set_double_value(double val, CdlValueFormat new_format)
543 {
544 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_double_value");
545 CYG_REPORT_FUNCARG1XV(this);
546
547 value = "";
548 int_value = 0;
549 double_value = val;
550 valid_flags = double_valid;
551 format = new_format;
552
553 CYG_REPORT_RETURN();
554 }
555
556 //}}}
557 //{{{ Value format support
558
559 // ----------------------------------------------------------------------------
560
561 CdlValueFormat
562 CdlSimpleValue::get_value_format() const
563 {
564 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue::get_value_format", "result %d");
565 CYG_REPORT_FUNCARG1XV(this);
566
567 CdlValueFormat result = format;
568 CYG_REPORT_RETVAL(result);
569 return result;
570 }
571
572 void
573 CdlSimpleValue::set_value_format(CdlValueFormat new_format)
574 {
575 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
576 CYG_REPORT_FUNCARG2XV(this, new_format);
577
578 format = new_format;
579
580 CYG_REPORT_RETURN();
581 }
582
583 void
584 CdlSimpleValue::set_value_format(CdlSimpleValue& other_val)
585 {
586 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format (simple val)");
587 CYG_REPORT_FUNCARG2XV(this, &other_val);
588
589 format = other_val.format;
590
591 CYG_REPORT_RETURN();
592 }
593
594 // This gets used for binary operators, e.g. A + B
595 // If A has a non-default format then that gets used.
596 // Otherwise B's format gets used, which may or may not be default.
597 //
598 // e.g. 0x1000 + 4 -> 0x1004
599 // 10 + 0x100 -> 0x10A
600 // 10 + 32 -> 42
601
602 void
603 CdlSimpleValue::set_value_format(CdlSimpleValue& val1, CdlSimpleValue& val2)
604 {
605 CYG_REPORT_FUNCNAME("CdlSimpleValue::set_value_format");
606 CYG_REPORT_FUNCARG3XV(this, &val1, &val2);
607
608 format = (CdlValueFormat_Default != val1.format) ? val1.format : val2.format;
609
610 CYG_REPORT_RETURN();
611 }
612
613 //}}}
614 //{{{ Comparison operators
615
616 // ----------------------------------------------------------------------------
617
618 bool
619 CdlSimpleValue::operator==(const CdlSimpleValue& other) const
620 {
621 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator==", "result %d");
622 CYG_REPORT_FUNCARG2XV(this, &other);
623
624 bool result = false;
625
626 if (has_integer_value()) {
627 if (other.has_integer_value()) {
628 cdl_int val1 = get_integer_value();
629 cdl_int val2 = other.get_integer_value();
630 result = (val1 == val2);
631 }
632 } else if (has_double_value()) {
633 if (other.has_double_value()) {
634 double val1 = get_double_value();
635 double val2 = other.get_double_value();
636 result = (val1 == val2);
637 }
638 } else {
639 std::string val1 = get_value();
640 std::string val2 = other.get_value();
641 result = (val1 == val2);
642 }
643
644 CYG_REPORT_RETVAL(result);
645 return result;
646 }
647
648 bool
649 CdlSimpleValue::operator!=(const CdlSimpleValue& other) const
650 {
651 CYG_REPORT_FUNCNAMETYPE("CdlSimpleValue:: operator!=", "result %d");
652 CYG_REPORT_FUNCARG2XV(this, &other);
653
654 bool result = true;
655 if (has_integer_value()) {
656 if (other.has_integer_value()) {
657 cdl_int val1 = get_integer_value();
658 cdl_int val2 = other.get_integer_value();
659 result = (val1 != val2);
660 }
661 } else if (has_double_value()) {
662 if (other.has_double_value()) {
663 double val1 = get_double_value();
664 double val2 = other.get_double_value();
665 result = (val1 != val2);
666 }
667 } else {
668 std::string val1 = get_value();
669 std::string val2 = other.get_value();
670 result = (val1 != val2);
671 }
672
673
674 CYG_REPORT_RETVAL(result);
675 return result;
676 }
677
678 //}}}
679
680 //}}}
681 //{{{ CdlValue class
682
683 // ----------------------------------------------------------------------------
684 // This should really be a class static constant, but VC++ does not implement
685 // that part of the language. A constant here avoids the need for lots of
686 // occurrences of 4 throughout the value-related routines.
687
688 static const int CdlValue_number_of_sources = 4;
689
690 //{{{ Constructors
691
692 // ----------------------------------------------------------------------------
693 // The default flavor depends on the type of entity being created. For
694 // example CDL options are boolean by default, but packages are booldata.
695 // The intelligence to do the right thing lives in set_flavor().
696
697 CdlValue::CdlValue(CdlValueFlavor flavor_arg)
698 {
699 CYG_REPORT_FUNCNAME("CdlValue:: constructor");
700 CYG_REPORT_FUNCARG1XV(this);
701
702 current_source = CdlValueSource_Default;
703 source_valid[CdlValueSource_Default] = true;
704 source_valid[CdlValueSource_Inferred] = false;
705 source_valid[CdlValueSource_Wizard] = false;
706 source_valid[CdlValueSource_User] = false;
707 enabled[CdlValueSource_Default] = false;
708 enabled[CdlValueSource_Inferred] = false;
709 enabled[CdlValueSource_Wizard] = false;
710 enabled[CdlValueSource_User] = false;
711
712 // The SimpleValues will initialize themselves.
713
714 cdlvalue_cookie = CdlValue_Magic;
715 CYGDBG_MEMLEAK_CONSTRUCTOR();
716 set_flavor(flavor_arg);
717
718 CYG_POSTCONDITION_THISC();
719 CYG_REPORT_RETURN();
720 }
721
722 // ----------------------------------------------------------------------------
723 // Copy constructor. This is not really required, a default
724 // member-wise copy would be fine and more efficient, but it would
725 // lose tracing and assertion.
726
727 CdlValue::CdlValue(const CdlValue& original)
728 {
729 CYG_REPORT_FUNCNAME("CdlValue:: copy constructor");
730 CYG_REPORT_FUNCARG2XV(this, &original);
731 CYG_INVARIANT_CLASSOC(CdlValue, original);
732
733 flavor = original.flavor;
734 current_source = original.current_source;
735 for (int i = 0; i < CdlValue_number_of_sources; i++) {
736 source_valid[i] = original.source_valid[i];
737 enabled[i] = original.enabled[i];
738 values[i] = original.values[i];
739 }
740
741 cdlvalue_cookie = CdlValue_Magic;
742 CYGDBG_MEMLEAK_CONSTRUCTOR();
743
744 CYG_POSTCONDITION_THISC();
745 CYG_REPORT_RETURN();
746 }
747
748 // ----------------------------------------------------------------------------
749 // Assignment operator. Again this is not required, the default would be
750 // fine and more efficient, but tracing and assertions are good things.
751
752 CdlValue& CdlValue::operator=(const CdlValue& original)
753 {
754 CYG_REPORT_FUNCNAME("CdlValue:: assignment operator");
755 CYG_REPORT_FUNCARG2XV(this, &original);
756 CYG_INVARIANT_CLASSOC(CdlValue, original);
757
758 if (this != &original) {
759 flavor = original.flavor;
760 current_source = original.current_source;
761 for (int i = 0; i < CdlValue_number_of_sources; i++) {
762 source_valid[i] = original.source_valid[i];
763 enabled[i] = original.enabled[i];
764 values[i] = original.values[i];
765 }
766 }
767
768 cdlvalue_cookie = CdlValue_Magic;
769 CYG_POSTCONDITION_THISC();
770 CYG_REPORT_RETURN();
771 return *this;
772 }
773
774 //}}}
775 //{{{ Destructor
776
777 // ----------------------------------------------------------------------------
778
779 CdlValue::~CdlValue()
780 {
781 CYG_REPORT_FUNCNAME("CdlValue:: destructor");
782 CYG_REPORT_FUNCARG1XV(this);
783 CYG_PRECONDITION_THISC();
784
785 cdlvalue_cookie = CdlValue_Invalid;
786 flavor = CdlValueFlavor_Invalid;
787 current_source = CdlValueSource_Invalid;
788 for (int i = 0; i < CdlValue_number_of_sources; i++) {
789 source_valid[i] = false;
790 enabled[i] = false;
791 // The CdlSimpleValue array will take care of itself.
792 }
793 CYGDBG_MEMLEAK_DESTRUCTOR();
794
795 CYG_REPORT_RETURN();
796 }
797
798 //}}}
799 //{{{ check_this()
800
801 // ----------------------------------------------------------------------------
802 bool
803 CdlValue::check_this(cyg_assert_class_zeal zeal) const
804 {
805 if (CdlValue_Magic != cdlvalue_cookie) {
806 return false;
807 }
808 CYGDBG_MEMLEAK_CHECKTHIS();
809
810 if (!source_valid[CdlValueSource_Default]) {
811 return false;
812 }
813
814 if ((CdlValueFlavor_None == flavor) || (CdlValueFlavor_Data == flavor)) {
815 for (int i = 0; i < CdlValue_number_of_sources; i++) {
816 if (!enabled[i]) {
817 return false;
818 }
819 }
820 }
821 for (int i = 0; i < CdlValue_number_of_sources; i++) {
822 if (source_valid[i]) {
823 if (!values[i].check_this(zeal)) {
824 return false;
825 }
826 }
827 }
828
829 return true;
830 }
831
832 //}}}
833 //{{{ Flavor manipulation
834
835 // ----------------------------------------------------------------------------
836 // Get hold of the current flavor.
837 CdlValueFlavor
838 CdlValue::get_flavor(void) const
839 {
840 CYG_REPORT_FUNCNAMETYPE("CdlValue::get_flavor", "result %d");
841 CYG_REPORT_FUNCARG1XV(this);
842 CYG_PRECONDITION_THISC();
843
844 CdlValueFlavor result = flavor;
845 CYG_REPORT_RETVAL(result);
846 return result;
847 }
848
849 // ----------------------------------------------------------------------------
850 // set_flavor() may be invoked once or twice for a given entity. The first
851 // time is from inside the constructor with the default flavor for this
852 // particular class of entity. It may then be called again if the
853 // entity has a "flavor" property that overrides this. All old data
854 // will be lost, so evaluating a default value etc. should be done after
855 // the call to set_flavor(), and there should be no subsequent calls to
856 // set_flavor().
857
858 void
859 CdlValue::set_flavor(CdlValueFlavor flavor_arg)
860 {
861 CYG_REPORT_FUNCNAME("CdlValue:: set_flavor");
862 CYG_REPORT_FUNCARG2XV(this, flavor_arg);
863
864 // No precondition here, set_flavor() is called from inside the constructor
865 CYG_PRECONDITIONC((CdlValueFlavor_None == flavor_arg) || \
866 (CdlValueFlavor_Bool == flavor_arg) || \
867 (CdlValueFlavor_BoolData == flavor_arg) || \
868 (CdlValueFlavor_Data == flavor_arg));
869
870 flavor = flavor_arg;
871 switch(flavor) {
872 case CdlValueFlavor_None :
873 {
874 // All value sources are enabled, but "default" remains the only valid one.
875 enabled[CdlValueSource_Default] = true;
876 enabled[CdlValueSource_Inferred] = true;
877 enabled[CdlValueSource_Wizard] = true;
878 enabled[CdlValueSource_User] = true;
879 break;
880 }
881
882 case CdlValueFlavor_Bool :
883 {
884 // All value sources start out as disabled.
885 enabled[CdlValueSource_Default] = false;
886 enabled[CdlValueSource_Inferred] = false;
887 enabled[CdlValueSource_Wizard] = false;
888 enabled[CdlValueSource_User] = false;
889 break;
890 }
891
892 case CdlValueFlavor_BoolData :
893 {
894 // All value sources start out as disabled.
895 enabled[CdlValueSource_Default] = false;
896 enabled[CdlValueSource_Inferred] = false;
897 enabled[CdlValueSource_Wizard] = false;
898 enabled[CdlValueSource_User] = false;
899 break;
900 }
901
902 case CdlValueFlavor_Data :
903 {
904 // All value sources start out as enabled.
905 enabled[CdlValueSource_Default] = true;
906 enabled[CdlValueSource_Inferred] = true;
907 enabled[CdlValueSource_Wizard] = true;
908 enabled[CdlValueSource_User] = true;
909 break;
910 }
911
912 default :
913 break;
914 }
915
916 CYG_REPORT_RETURN();
917 }
918
919 //}}}
920 //{{{ Source manipulation
921
922 // ----------------------------------------------------------------------------
923
924 void
925 CdlValue::set_source(CdlValueSource source)
926 {
927 CYG_REPORT_FUNCNAME("CdlValue::set_source");
928 CYG_REPORT_FUNCARG2XV(this, source);
929 CYG_INVARIANT_THISC(CdlValue);
930 CYG_PRECONDITIONC((0 <= source) && (source <= CdlValue_number_of_sources));
931 CYG_PRECONDITIONC(source_valid[source]);
932
933 current_source = source;
934
935 CYG_REPORT_RETURN();
936 }
937
938 CdlValueSource
939 CdlValue::get_source(void) const
940 {
941 CYG_REPORT_FUNCNAMETYPE("CdlValue::get_source", "source %d");
942 CYG_REPORT_FUNCARG1XV(this);
943 CYG_PRECONDITION_THISC();
944
945 CdlValueSource result = current_source;
946 CYG_REPORT_RETVAL(result);
947 return result;
948 }
949
950 bool
951 CdlValue::has_source(CdlValueSource source) const
952 {
953 CYG_REPORT_FUNCNAMETYPE("CdlValue::has_source", "result %d");
954 CYG_REPORT_FUNCARG2XV(this, source);
955 CYG_PRECONDITION_THISC();
956 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
957
958 bool result = source_valid[source];
959 CYG_REPORT_RETVAL(result);
960 return result;
961 }
962
963 // ----------------------------------------------------------------------------
964 // Invalidate a specific source. If that source happens to be the current one,
965 // switch to the highest-priority valid source.
966
967 void
968 CdlValue::invalidate_source(CdlValueSource source)
969 {
970 CYG_REPORT_FUNCNAME("CdlValue::invalidate_source");
971 CYG_REPORT_FUNCARG2XV(this, source);
972 CYG_PRECONDITION_THISC();
973 CYG_PRECONDITIONC(CdlValueSource_Default != source);
974 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
975
976 if (CdlValueSource_Default != source) {
977 source_valid[source] = false;
978 if (current_source == source) {
979 if (source_valid[CdlValueSource_User]) {
980 current_source = CdlValueSource_User;
981 } else if (source_valid[CdlValueSource_Wizard]) {
982 current_source = CdlValueSource_Wizard;
983 } else if (source_valid[CdlValueSource_Inferred]) {
984 current_source = CdlValueSource_Inferred;
985 } else {
986 current_source = CdlValueSource_Default;
987 }
988 }
989 }
990
991 CYG_POSTCONDITIONC(source_valid[current_source]);
992 }
993
994 //}}}
995 //{{{ Retrieving the data
996
997 // ----------------------------------------------------------------------------
998 // Check the enabled flag for the appropriate source. The specified source
999 // is normally provided by a default argument CdlValueSource_Current, which
1000 // 99.9...% of the time is what we are after.
1001 //
1002 // Note that this member can be used even for entities of flavor none
1003 // and data, and the result will be true. However it is not legal to
1004 // disable such entities.
1005
1006 bool
1007 CdlValue::is_enabled(CdlValueSource source) const
1008 {
1009 CYG_REPORT_FUNCNAMETYPE("CdlValue::is_enabled", "enabled %d");
1010 CYG_REPORT_FUNCARG2XV(this, source);
1011 CYG_PRECONDITION_THISC();
1012
1013 if (CdlValueSource_Current == source) {
1014 source = current_source;
1015 }
1016 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1017 CYG_PRECONDITIONC(source_valid[source]);
1018
1019 bool result = enabled[source];
1020 CYG_REPORT_RETVAL(result);
1021 return result;
1022 }
1023
1024 // ----------------------------------------------------------------------------
1025 // Access to the value field.
1026
1027 std::string
1028 CdlValue::get_value(CdlValueSource source) const
1029 {
1030 CYG_REPORT_FUNCNAME("CdlValue::get_value");
1031 CYG_REPORT_FUNCARG2XV(this, source);
1032 CYG_PRECONDITION_THISC();
1033
1034 if (CdlValueSource_Current == source) {
1035 source = current_source;
1036 }
1037 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1038 CYG_PRECONDITIONC(source_valid[source]);
1039
1040 std::string result = values[source].get_value();
1041 CYG_REPORT_RETURN();
1042 return result;
1043 }
1044
1045 bool
1046 CdlValue::has_integer_value(CdlValueSource source) const
1047 {
1048 CYG_REPORT_FUNCNAMETYPE("CdlValue::has_integer_value", "result %d");
1049 CYG_REPORT_FUNCARG2XV(this, source);
1050 CYG_INVARIANT_THISC(CdlValue);
1051
1052 if (CdlValueSource_Current == source) {
1053 source = current_source;
1054 }
1055 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1056 CYG_PRECONDITIONC(source_valid[source]);
1057
1058 bool result = values[source].has_integer_value();
1059 CYG_REPORT_RETVAL(result);
1060 return result;
1061 }
1062
1063 bool
1064 CdlValue::has_double_value(CdlValueSource source) const
1065 {
1066 CYG_REPORT_FUNCNAMETYPE("CdlValue::has_value", "result %d");
1067 CYG_REPORT_FUNCARG2XV(this, source);
1068 CYG_INVARIANT_THISC(CdlValue);
1069
1070 if (CdlValueSource_Current == source) {
1071 source = current_source;
1072 }
1073 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1074 CYG_PRECONDITIONC(source_valid[source]);
1075
1076 bool result = values[source].has_double_value();
1077 CYG_REPORT_RETVAL(result);
1078 return result;
1079 }
1080
1081 cdl_int
1082 CdlValue::get_integer_value(CdlValueSource source) const
1083 {
1084 CYG_REPORT_FUNCNAMETYPE("CdlValue::get_integer_value", "value %ld");
1085 CYG_REPORT_FUNCARG2XV(this, source);
1086 CYG_PRECONDITION_THISC();
1087
1088 if (CdlValueSource_Current == source) {
1089 source = current_source;
1090 }
1091 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1092 CYG_PRECONDITIONC(source_valid[source]);
1093
1094 cdl_int result = values[source].get_integer_value();
1095 CYG_REPORT_RETVAL(result);
1096 return result;
1097 }
1098
1099 double
1100 CdlValue::get_double_value(CdlValueSource source) const
1101 {
1102 CYG_REPORT_FUNCNAME("CdlValue::get_double_value");
1103 CYG_REPORT_FUNCARG2XV(this, source);
1104 CYG_PRECONDITION_THISC();
1105
1106 if (CdlValueSource_Current == source) {
1107 source = current_source;
1108 }
1109 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1110 CYG_PRECONDITIONC(source_valid[source]);
1111
1112 double result = values[source].get_double_value();
1113 CYG_REPORT_RETURN();
1114 return result;
1115 }
1116
1117 CdlSimpleValue
1118 CdlValue::get_simple_value(CdlValueSource source) const
1119 {
1120 CYG_REPORT_FUNCNAME("CdlValue::get_simple_value");
1121 CYG_REPORT_FUNCARG2XV(this, source);
1122 CYG_PRECONDITION_THISC();
1123
1124 if (CdlValueSource_Current == source) {
1125 source = current_source;
1126 }
1127 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1128 CYG_PRECONDITIONC(source_valid[source]);
1129
1130 CYG_REPORT_RETURN();
1131 return values[source];
1132 }
1133
1134 //}}}
1135 //{{{ Value modification
1136
1137 // ----------------------------------------------------------------------------
1138
1139 void
1140 CdlValue::set_enabled(bool val, CdlValueSource source)
1141 {
1142 CYG_REPORT_FUNCNAME("CdlValue::set_enabled");
1143 CYG_REPORT_FUNCARG3XV(this, val, source);
1144 CYG_INVARIANT_THISC(CdlValue);
1145 CYG_PRECONDITIONC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor));
1146 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1147
1148 enabled[source] = val;
1149 source_valid[source] = true;
1150 if (source > current_source) {
1151 current_source = source;
1152 }
1153
1154 CYG_REPORT_RETURN();
1155 }
1156
1157 void
1158 CdlValue::set_value(CdlSimpleValue& val, CdlValueSource source)
1159 {
1160 CYG_REPORT_FUNCNAME("CdlValue::set_value");
1161 CYG_REPORT_FUNCARG3XV(this, &val, source);
1162 CYG_INVARIANT_THISC(CdlValue);
1163 CYG_PRECONDITIONC((CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor));
1164 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1165
1166 values[source] = val;
1167 source_valid[source] = true;
1168 if (source > current_source) {
1169 current_source = source;
1170 }
1171
1172 CYG_REPORT_RETURN();
1173 }
1174
1175 void
1176 CdlValue::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
1177 {
1178 CYG_REPORT_FUNCNAME("CdlValue::set_enabled_and_value");
1179 CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
1180 CYG_INVARIANT_THISC(CdlValue);
1181 CYG_PRECONDITIONC(CdlValueFlavor_BoolData == flavor);
1182 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1183
1184 enabled[source] = enabled_arg;
1185 values[source] = val;
1186 source_valid[source] = true;
1187 if (source > current_source) {
1188 current_source = source;
1189 }
1190
1191 CYG_REPORT_RETURN();
1192 }
1193
1194 // ----------------------------------------------------------------------------
1195 // Given a SimpleValue, this member function does the right thing
1196 // for the flavor.
1197
1198 void
1199 CdlValue::set(CdlSimpleValue& val, CdlValueSource source)
1200 {
1201 CYG_REPORT_FUNCNAME("CdlValue::set");
1202 CYG_REPORT_FUNCARG3XV(this, &val, source);
1203 CYG_INVARIANT_THISC(CdlValue);
1204 CYG_ASSERTC((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor) || (CdlValueFlavor_Data == flavor));
1205 CYG_PRECONDITIONC((0 <= source) && (source < CdlValue_number_of_sources));
1206
1207 switch(flavor) {
1208 case CdlValueFlavor_Bool:
1209 enabled[source] = val.get_bool_value();
1210 break;
1211
1212 case CdlValueFlavor_BoolData:
1213 if (!val.get_bool_value()) {
1214 enabled[source] = false;
1215 values[source] = (cdl_int) 0;
1216 } else {
1217 enabled[source] = true;
1218 values[source] = val;
1219 }
1220 break;
1221
1222 case CdlValueFlavor_Data:
1223 values[source] = val;
1224 break;
1225
1226 default:
1227 CYG_FAIL("Unknown value flavor detected.");
1228 }
1229
1230 source_valid[source] = true;
1231 if (source > current_source) {
1232 current_source = source;
1233 }
1234
1235 CYG_REPORT_RETURN();
1236 }
1237
1238 //}}}
1239
1240 //}}}
1241 //{{{ CdlListValue class
1242
1243 // ----------------------------------------------------------------------------
1244 // List values. Most of this is straightforward.
1245
1246 CdlListValue::CdlListValue()
1247 {
1248 CYG_REPORT_FUNCNAME("CdlListValue:: default constructor");
1249 CYG_REPORT_FUNCARG1XV(this);
1250
1251 // The only data fields are embedded objects which will have been
1252 // filled in already.
1253 cdllistvalue_cookie = CdlListValue_Magic;
1254 CYGDBG_MEMLEAK_CONSTRUCTOR();
1255
1256 CYG_POSTCONDITION_THISC();
1257 CYG_REPORT_RETURN();
1258 }
1259
1260 CdlListValue::CdlListValue(const CdlListValue& original)
1261 {
1262 CYG_REPORT_FUNCNAME("CdlListValue:: copy constructor");
1263 CYG_REPORT_FUNCARG2XV(this, &original);
1264 CYG_INVARIANT_CLASSOC(CdlListValue, original);
1265
1266 // This may get expensive, but should not happen very often.
1267 table = original.table;
1268 integer_ranges = original.integer_ranges;
1269 double_ranges = original.double_ranges;
1270 cdllistvalue_cookie = CdlListValue_Magic;
1271 CYGDBG_MEMLEAK_CONSTRUCTOR();
1272
1273 CYG_POSTCONDITION_THISC();
1274 CYG_REPORT_RETURN();
1275 }
1276
1277 CdlListValue & CdlListValue::operator=(const CdlListValue& original)
1278 {
1279 CYG_REPORT_FUNCNAME("CdlListValue:: assignment operator");
1280 CYG_REPORT_FUNCARG2XV(this, &original);
1281 CYG_INVARIANT_CLASSOC(CdlListValue, original);
1282
1283 if (this != &original) {
1284 table.clear();
1285 integer_ranges.clear();
1286 double_ranges.clear();
1287 table = original.table;
1288 integer_ranges = original.integer_ranges;
1289 double_ranges = original.double_ranges;
1290 }
1291
1292 CYG_POSTCONDITION_THISC();
1293 CYG_REPORT_RETURN();
1294 return *this;
1295 }
1296
1297 CdlListValue::~CdlListValue()
1298 {
1299 CYG_REPORT_FUNCNAME("CdlListValue:: destructor");
1300 CYG_REPORT_FUNCARG1XV(this);
1301 CYG_PRECONDITION_THISC();
1302
1303 cdllistvalue_cookie = CdlListValue_Invalid;
1304 table.clear();
1305 integer_ranges.clear();
1306 double_ranges.clear();
1307 CYGDBG_MEMLEAK_DESTRUCTOR();
1308
1309 CYG_REPORT_RETURN();
1310 }
1311
1312 // ----------------------------------------------------------------------------
1313 // Finding out about the current legal values. These routines can be
1314 // used by GUI-related code to figure out a sensible widget to be used
1315 // for a CDL entity. In nearly all cases life will be simple: either
1316 // there will be a fixed set of legal values and the user merely has
1317 // to choose one of these; or there will be a simple numerical range.
1318 // Occasionally life may be more complicated, if the full generality
1319 // of CDL list expressions is being used, and it will be necessary to
1320 // use an entry box instead. Note that the entity's flavor may also
1321 // affect the user interface.
1322
1323 const std::vector<CdlSimpleValue>&
1324 CdlListValue::get_table(void) const
1325 {
1326 CYG_REPORT_FUNCNAME("CdlListValue::get_table");
1327 CYG_REPORT_FUNCARG1XV(this);
1328 CYG_PRECONDITION_THISC();
1329
1330 CYG_REPORT_RETURN();
1331 return table;
1332 }
1333
1334 const std::vector<std::pair<cdl_int, cdl_int> >&
1335 CdlListValue::get_integer_ranges(void) const
1336 {
1337 CYG_REPORT_FUNCNAME("CdlListValue::get_integer_ranges");
1338 CYG_REPORT_FUNCARG1XV(this);
1339 CYG_PRECONDITION_THISC();
1340
1341 CYG_REPORT_RETURN();
1342 return integer_ranges;
1343 }
1344
1345 const std::vector<std::pair<double, double> >&
1346 CdlListValue::get_double_ranges(void) const
1347 {
1348 CYG_REPORT_FUNCNAME("CdlListValue::get_double_ranges");
1349 CYG_REPORT_FUNCARG1XV(this);
1350 CYG_PRECONDITION_THISC();
1351
1352 CYG_REPORT_RETURN();
1353 return double_ranges;
1354 }
1355
1356 // ----------------------------------------------------------------------------
1357 // Membership. This can be quite complicated.
1358 //
1359 // 1) anything which has an integer representation must be checked against
1360 // the integer ranges and the vector of integer constants. It must
1361 // also be checked against the floating point ranges, since calculations
1362 // may have resulted in the fractional part disappearing, assuming that
1363 // the integer has a floating point representation.
1364 //
1365 // 2) similarly anything which has a floating point representation must
1366 // be checked against the floating point ranges and constant vector.
1367 // In addition it may have an empty fractional part in which case
1368 // integer comparisons have to be attempted as well.
1369 //
1370 // 3) string data needs to be tested first of all for integer and double
1371 // representations. If these fail then the comparison should be against
1372 // the string vector.
1373 //
1374 // For floating point data exact comparisons are of course meaningless,
1375 // and arguably the vector of floating point constants is useless. The
1376 // ranges vector is better, but still not ideal. It may be necessary
1377 // to introduce an epsilon fudge factor.
1378
1379 bool
1380 CdlListValue::is_member(CdlSimpleValue& val) const
1381 {
1382 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (CdlSimpleValue)", "result %d");
1383 CYG_REPORT_FUNCARG2XV(this, &val);
1384 CYG_PRECONDITION_THISC();
1385
1386 bool result = false;
1387 if (val.has_integer_value()) {
1388 result = is_member(val.get_integer_value(), false);
1389 }
1390 if (!result && val.has_double_value()) {
1391 result = is_member(val.get_double_value(), false);
1392 }
1393 if (!result) {
1394 result = is_member(val.get_value());
1395 }
1396
1397 CYG_REPORT_RETVAL(result);
1398 return result;
1399 }
1400
1401 bool
1402 CdlListValue::is_member(std::string val, bool allow_conversions) const
1403 {
1404 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (string)", "result %d");
1405 CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1406 CYG_PRECONDITION_THISC();
1407
1408 bool result = false;
1409 if (allow_conversions) {
1410 cdl_int integer_value;
1411 double double_value;
1412
1413 if (Cdl::string_to_integer(val, integer_value)) {
1414 result = is_member(integer_value, false);
1415 }
1416 if (!result && Cdl::string_to_double(val, double_value)) {
1417 result = is_member(double_value, false);
1418 }
1419 }
1420 if (!result) {
1421 for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1422 if (val_i->get_value() == val) {
1423 result = true;
1424 break;
1425 }
1426 }
1427 }
1428
1429 CYG_REPORT_RETVAL(result);
1430 return result;
1431 }
1432
1433 bool
1434 CdlListValue::is_member(cdl_int val, bool allow_conversions) const
1435 {
1436 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (int)", "result %d");
1437 CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1438 CYG_PRECONDITION_THISC();
1439
1440 bool result = false;
1441 for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1442 if (val_i->has_integer_value() && (val_i->get_integer_value() == val)) {
1443 result = true;
1444 break;
1445 }
1446 }
1447 if (!result) {
1448 for (std::vector<std::pair<cdl_int,cdl_int> >::const_iterator i = integer_ranges.begin();
1449 i != integer_ranges.end(); i++) {
1450 if ((val >= i->first) && (val <= i->second)) {
1451 result = true;
1452 break;
1453 }
1454 }
1455 }
1456 if (!result && allow_conversions) {
1457 double double_value = Cdl::integer_to_double(val);
1458 result = is_member(double_value, false);
1459 }
1460
1461 CYG_REPORT_RETVAL(result);
1462 return result;
1463 }
1464
1465 bool
1466 CdlListValue::is_member(double val, bool allow_conversions) const
1467 {
1468 CYG_REPORT_FUNCNAMETYPE("CdlListValue::is_member (double)", "result %d");
1469 CYG_REPORT_FUNCARG3XV(this, &val, allow_conversions);
1470 CYG_PRECONDITION_THISC();
1471
1472 bool result = false;
1473 for (std::vector<CdlSimpleValue>::const_iterator val_i = table.begin(); val_i != table.end(); val_i++) {
1474 if (val_i->has_double_value() && (val_i->get_double_value() == val)) {
1475 result = true;
1476 break;
1477 }
1478 }
1479 if (!result) {
1480 for (std::vector<std::pair<double,double> >::const_iterator i = double_ranges.begin();
1481 i != double_ranges.end(); i++) {
1482 if ((val >= i->first) && (val <= i->second)) {
1483 result = true;
1484 break;
1485 }
1486 }
1487 }
1488 if (!result && allow_conversions) {
1489 cdl_int integer_value;
1490 if (Cdl::double_to_integer(val, integer_value)) {
1491 result = is_member(integer_value, false);
1492 }
1493 }
1494
1495 CYG_REPORT_RETVAL(result);
1496 return result;
1497 }
1498
1499 // ----------------------------------------------------------------------------
1500
1501 bool
1502 CdlListValue::check_this(cyg_assert_class_zeal zeal) const
1503 {
1504 if (CdlListValue_Magic != cdllistvalue_cookie) {
1505 return false;
1506 }
1507 CYGDBG_MEMLEAK_CHECKTHIS();
1508
1509 // After construction the various vectors will still be empty, they
1510 // do not get filled in until a list expression is evaluated. No
1511 // further tests are possible here.
1512 return true;
1513 }
1514
1515 //}}}
1516
1517 //{{{ dialog property
1518
1519 // ----------------------------------------------------------------------------
1520 // Syntax: dialog <reference>
1521
1522 void
1523 CdlValuableBody::dialog_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1524 CdlUpdate change)
1525 {
1526 CYG_REPORT_FUNCNAME("CdlValuable::dialog_update_handler");
1527 CYG_PRECONDITION_CLASSC(transaction);
1528 CYG_PRECONDITION_CLASSC(source);
1529 CYG_PRECONDITION_CLASSC(prop);
1530
1531 // The main update of interest is Loaded (iff dest != 0), and
1532 // Created. These updates indicate that the destination now exists,
1533 // so it is possible to check that the destination is a dialog.
1534 if (((CdlUpdate_Loaded == change) && (0 != dest)) ||
1535 (CdlUpdate_Created == change)) {
1536
1537 CYG_ASSERT_CLASSC(dest);
1538 CdlDialog dialog = dynamic_cast<CdlDialog>(dest);
1539 if (0 == dialog) {
1540 std::string msg = dest->get_class_name() + " " + dest->get_name() +
1541 " cannot be used in a dialog property, it is not a custom dialog.";
1542 CdlConflict_DataBody::make(transaction, source, prop, msg);
1543 }
1544
1545 } else if (CdlUpdate_Destroyed == change) {
1546 // If there was a data conflict object, it is no longer relevant
1547 transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
1548 }
1549
1550 CYG_REPORT_RETURN();
1551 }
1552
1553 int
1554 CdlValuableBody::parse_dialog(CdlInterpreter interp, int argc, char** argv)
1555 {
1556 CYG_REPORT_FUNCNAMETYPE("parse_dialog", "result %d");
1557
1558 int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Dialog, 0, 0, &dialog_update_handler);
1559
1560 CYG_REPORT_RETVAL(result);
1561 return result;
1562 }
1563
1564 bool
1565 CdlValuableBody::has_dialog() const
1566 {
1567 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_dialog", "result %d");
1568 CYG_REPORT_FUNCARG1XV(this);
1569 CYG_PRECONDITION_THISC();
1570
1571 // It is not enough to have the property, the dialog reference must also be
1572 // resolved and go to a dialog.
1573 bool result = false;
1574 CdlProperty property = get_property(CdlPropertyId_Dialog);
1575 if (0 != property) {
1576 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1577 CYG_ASSERTC(0 != ref_prop);
1578
1579 CdlNode destination = ref_prop->get_destination();
1580 if (0 != destination) {
1581 CdlDialog dialog = dynamic_cast<CdlDialog>(destination);
1582 if (0 != dialog) {
1583 result = true;
1584 }
1585 }
1586 }
1587 CYG_REPORT_RETVAL(result);
1588 return result;
1589 }
1590
1591
1592 CdlDialog
1593 CdlValuableBody::get_dialog() const
1594 {
1595 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_dialog", "result %p");
1596 CYG_REPORT_FUNCARG1XV(this);
1597 CYG_PRECONDITION_THISC();
1598
1599 CdlDialog result = 0;
1600 CdlProperty property = get_property(CdlPropertyId_Dialog);
1601 if (0 != property) {
1602 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1603 CYG_ASSERTC(0 != ref_prop);
1604
1605 CdlNode destination = ref_prop->get_destination();
1606 if (0 != destination) {
1607 result = dynamic_cast<CdlDialog>(destination);
1608 }
1609 }
1610
1611 CYG_REPORT_RETVAL(result);
1612 return result;
1613 }
1614
1615 //}}}
1616 //{{{ wizard property
1617
1618 // ----------------------------------------------------------------------------
1619 // Syntax: wizard <reference>
1620
1621 void
1622 CdlValuableBody::wizard_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1623 CdlUpdate change)
1624 {
1625 CYG_REPORT_FUNCNAME("CdlValuable::wizard_update_handler");
1626 CYG_PRECONDITION_CLASSC(transaction);
1627 CYG_PRECONDITION_CLASSC(source);
1628 CYG_PRECONDITION_CLASSC(prop);
1629
1630 // The main update of interest is Loaded (iff dest != 0), and
1631 // Created. These updates indicate that the destination now exists,
1632 // so it is possible to check that the destination is a dialog.
1633 if (((CdlUpdate_Loaded == change) && (0 != dest)) ||
1634 (CdlUpdate_Created == change)) {
1635
1636 CYG_ASSERT_CLASSC(dest);
1637 CdlWizard wizard = dynamic_cast<CdlWizard>(dest);
1638 if (0 == wizard) {
1639 std::string msg = dest->get_class_name() + " " + dest->get_name() +
1640 " cannot be used in a wizard property, it is not a wizard.";
1641 CdlConflict_DataBody::make(transaction, source, prop, msg);
1642 }
1643
1644 } else if (CdlUpdate_Destroyed == change) {
1645 // If there was a data conflict object, it is no longer relevant
1646 transaction->clear_structural_conflicts(source, prop, &CdlConflict_DataBody::test);
1647 }
1648
1649 CYG_REPORT_RETURN();
1650 }
1651
1652 int
1653 CdlValuableBody::parse_wizard(CdlInterpreter interp, int argc, char** argv)
1654 {
1655 CYG_REPORT_FUNCNAMETYPE("parse_wizard", "result %d");
1656
1657 int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Wizard, 0, 0, &wizard_update_handler);
1658 CYG_REPORT_RETVAL(result);
1659 return result;
1660 }
1661
1662 bool
1663 CdlValuableBody::has_wizard() const
1664 {
1665 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_wizard", "result %d");
1666 CYG_REPORT_FUNCARG1XV(this);
1667 CYG_PRECONDITION_THISC();
1668
1669 // It is not enough to have the property, the wizard reference
1670 // must also be resolved to a wizard object.
1671 bool result = false;
1672 CdlProperty property = get_property(CdlPropertyId_Wizard);
1673 if (0 != property) {
1674 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1675 CYG_ASSERTC(0 != ref_prop);
1676
1677 CdlNode destination = ref_prop->get_destination();
1678 if (0 != destination) {
1679 CdlWizard wizard = dynamic_cast<CdlWizard>(destination);
1680 CYG_ASSERTC(0 != wizard);
1681 CYG_UNUSED_PARAM(CdlWizard, wizard);
1682 result = true;
1683 }
1684 }
1685 CYG_REPORT_RETVAL(result);
1686 return result;
1687 }
1688
1689 CdlWizard
1690 CdlValuableBody::get_wizard() const
1691 {
1692 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_wizard", "result %p");
1693 CYG_REPORT_FUNCARG1XV(this);
1694 CYG_PRECONDITION_THISC();
1695
1696 CdlWizard result = 0;
1697 CdlProperty property = get_property(CdlPropertyId_Wizard);
1698 if (0 != property) {
1699 CdlProperty_Reference ref_prop = dynamic_cast<CdlProperty_Reference>(property);
1700 CYG_ASSERTC(0 != ref_prop);
1701
1702 CdlNode destination = ref_prop->get_destination();
1703 if (0 != destination) {
1704 result = dynamic_cast<CdlWizard>(destination);
1705 CYG_ASSERTC(0 != result);
1706 }
1707 }
1708
1709 CYG_REPORT_RETVAL(result);
1710 return result;
1711 }
1712
1713 //}}}
1714 //{{{ legal_values property
1715
1716 // ----------------------------------------------------------------------------
1717 // Syntax: legal_values <list expression>
1718
1719 void
1720 CdlValuableBody::legal_values_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1721 CdlUpdate change)
1722 {
1723 CYG_REPORT_FUNCNAME("legal_values_update_handler");
1724
1725 // Loaded and Unloading are of no immediate interest, reference
1726 // updating happens in the calling code.
1727 //
1728 // Any other change can affect the list expression and hence
1729 // invalidate the current value.
1730 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1731 CYG_REPORT_RETURN();
1732 return;
1733 }
1734
1735 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1736 CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(prop);
1737 CYG_ASSERT_CLASSC(valuable);
1738 CYG_ASSERT_CLASSC(lexpr);
1739
1740 valuable->check_value(transaction);
1741
1742 CYG_UNUSED_PARAM(CdlNode, dest);
1743 CYG_UNUSED_PARAM(CdlProperty_ListExpression, lexpr);
1744 CYG_REPORT_RETURN();
1745 }
1746
1747 int
1748 CdlValuableBody::parse_legal_values(CdlInterpreter interp, int argc, char** argv)
1749 {
1750 CYG_REPORT_FUNCNAMETYPE("parse_legal_values", "result %d");
1751
1752 int result = CdlParse::parse_listexpression_property(interp, argc, argv, CdlPropertyId_LegalValues, 0, 0,
1753 &legal_values_update_handler);
1754 CYG_REPORT_RETVAL(result);
1755 return result;
1756 }
1757
1758 bool
1759 CdlValuableBody::has_legal_values() const
1760 {
1761 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_legal_values", "result %d");
1762 CYG_REPORT_FUNCARG1XV(this);
1763 CYG_PRECONDITION_THISC();
1764
1765 bool result = has_property(CdlPropertyId_LegalValues);
1766 CYG_REPORT_RETVAL(result);
1767 return result;
1768 }
1769
1770 CdlProperty_ListExpression
1771 CdlValuableBody::get_legal_values() const
1772 {
1773 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_legal_values", "result %p");
1774 CYG_REPORT_FUNCARG1XV(this);
1775 CYG_PRECONDITION_THISC();
1776
1777 CdlProperty_ListExpression result = 0;
1778 CdlProperty property = get_property(CdlPropertyId_LegalValues);
1779 if (0 != property) {
1780 result = dynamic_cast<CdlProperty_ListExpression>(property);
1781 CYG_ASSERTC(0 != result);
1782 }
1783
1784 CYG_REPORT_RETVAL(result);
1785 return result;
1786 }
1787
1788 //}}}
1789 //{{{ default_value property
1790
1791 // ----------------------------------------------------------------------------
1792 // syntax: default_value <expr>
1793
1794 void
1795 CdlValuableBody::default_value_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1796 CdlUpdate change)
1797 {
1798 CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1799 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1800
1801 // Loaded and unloading should be ignored.
1802 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1803 CYG_REPORT_RETURN();
1804 return;
1805 }
1806
1807 // Init, Created, Destroyed, ValueChange and ActiveChange should
1808 // all result in the expression being re-evaluated and the result
1809 // applied.
1810 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1811 CYG_ASSERTC(0 != valuable);
1812 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
1813 CYG_ASSERTC(0 != expr);
1814
1815 CdlSimpleValue val;
1816
1817 try {
1818
1819 CdlEvalContext context(transaction, source, prop);
1820 expr->eval(context, val);
1821
1822 valuable->set(transaction, val, CdlValueSource_Default);
1823
1824 } catch(CdlEvalException e) {
1825
1826
1827 // An EvalException conflict will have been created, so the
1828 // user knows that this default_value is not kosher. It is
1829 // still a good idea to make sure that the object retains a
1830 // sensible value.
1831 val = (cdl_int) 0;
1832 valuable->set(transaction, val, CdlValueSource_Default);
1833 }
1834
1835 CYG_UNUSED_PARAM(CdlNode, dest);
1836 CYG_REPORT_RETURN();
1837 }
1838
1839 int
1840 CdlValuableBody::parse_default_value(CdlInterpreter interp, int argc, char** argv)
1841 {
1842 CYG_REPORT_FUNCNAMETYPE("parse_default_value", "result %d");
1843
1844 int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_DefaultValue, 0, 0,
1845 &default_value_update_handler);
1846 CYG_REPORT_RETVAL(result);
1847 return result;
1848 }
1849
1850 bool
1851 CdlValuableBody::has_default_value_expression() const
1852 {
1853 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_default_value_expression", "result %d");
1854 CYG_REPORT_FUNCARG1XV(this);
1855 CYG_PRECONDITION_THISC();
1856
1857 bool result = has_property(CdlPropertyId_DefaultValue);
1858 CYG_REPORT_RETVAL(result);
1859 return result;
1860 }
1861
1862 CdlProperty_Expression
1863 CdlValuableBody::get_default_value_expression() const
1864 {
1865 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_default_value_expression", "result %");
1866 CYG_REPORT_FUNCARG1XV(this);
1867 CYG_PRECONDITION_THISC();
1868
1869 CdlProperty_Expression result = 0;
1870 CdlProperty property = get_property(CdlPropertyId_DefaultValue);
1871 if (0 != property) {
1872 result = dynamic_cast<CdlProperty_Expression>(property);
1873 CYG_ASSERTC(0 != result);
1874 }
1875
1876 CYG_REPORT_RETVAL(result);
1877 return result;
1878 }
1879
1880 //}}}
1881 //{{{ calculated_property
1882
1883 // ----------------------------------------------------------------------------
1884 // Syntax: calculated <expression>
1885
1886 void
1887 CdlValuableBody::calculated_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1888 CdlUpdate change)
1889 {
1890 CYG_REPORT_FUNCNAME("CdlValuable::default_value_update_handler");
1891 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1892
1893 // Loaded and unloading should be ignored.
1894 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1895 CYG_REPORT_RETURN();
1896 return;
1897 }
1898
1899 // Init, Created, Destroyed, ValueChange and ActiveChange should
1900 // all result in the expression being re-evaluated and the result
1901 // applied.
1902 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
1903 CYG_ASSERTC(0 != valuable);
1904 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
1905 CYG_ASSERTC(0 != expr);
1906
1907 CdlSimpleValue val;
1908
1909 try {
1910
1911 CdlEvalContext context(transaction, source, prop);
1912 expr->eval(context, val);
1913
1914 valuable->set(transaction, val, CdlValueSource_Default);
1915
1916 } catch(CdlEvalException e) {
1917
1918
1919 // An EvalException conflict will have been created, so the
1920 // user knows that this default_value is not kosher. It is
1921 // still a good idea to make sure that the object retains a
1922 // sensible value.
1923 val = (cdl_int) 0;
1924 valuable->set(transaction, val, CdlValueSource_Default);
1925 }
1926
1927 CYG_UNUSED_PARAM(CdlNode, dest);
1928 CYG_REPORT_RETURN();
1929 }
1930
1931 // FIXME: check for flavor none?
1932 int
1933 CdlValuableBody::parse_calculated(CdlInterpreter interp, int argc, char** argv)
1934 {
1935 CYG_REPORT_FUNCNAMETYPE("parse_calculated", "result %d");
1936
1937 int result = CdlParse::parse_expression_property(interp, argc, argv, CdlPropertyId_Calculated, 0, 0,
1938 &calculated_update_handler);
1939 CYG_REPORT_RETVAL(result);
1940 return result;
1941 }
1942
1943 bool
1944 CdlValuableBody::has_calculated_expression() const
1945 {
1946 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_calculated_expression", "result %d");
1947 CYG_REPORT_FUNCARG1XV(this);
1948 CYG_PRECONDITION_THISC();
1949
1950 bool result = has_property(CdlPropertyId_Calculated);
1951 CYG_REPORT_RETVAL(result);
1952 return result;
1953 }
1954
1955 CdlProperty_Expression
1956 CdlValuableBody::get_calculated_expression() const
1957 {
1958 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_calculated_expression", "result %p");
1959 CYG_REPORT_FUNCARG1XV(this);
1960 CYG_PRECONDITION_THISC();
1961
1962 CdlProperty_Expression result = 0;
1963 CdlProperty property = get_property(CdlPropertyId_Calculated);
1964 if (0 != property) {
1965 result = dynamic_cast<CdlProperty_Expression>(property);
1966 CYG_ASSERTC(0 != result);
1967 }
1968
1969 CYG_REPORT_RETVAL(result);
1970 return result;
1971 }
1972
1973 //}}}
1974 //{{{ active_if property
1975
1976 // ----------------------------------------------------------------------------
1977 // Syntax:
1978 // active_if <goal expression>
1979
1980 void
1981 CdlValuableBody::active_if_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
1982 CdlUpdate change)
1983 {
1984 CYG_REPORT_FUNCNAME("CdlValuable::active_if_update_handler");
1985 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
1986 CYG_PRECONDITION_CLASSC(transaction);
1987 CYG_PRECONDITION_CLASSC(source);
1988 CYG_PRECONDITION_CLASSC(prop);
1989
1990 // Loaded should be ignored here, the world is still getting sorted out.
1991 // Unloading is of no interest, the source is disappearing anyway.
1992 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
1993 CYG_REPORT_RETURN();
1994 return;
1995 }
1996
1997 // Any other change warrants re-evaluating the active status of the source.
1998 // This can be achieved via a test_active() call, although that may do
1999 // more work than is strictly necessary e.g. it may re-evaluate other
2000 // is_active properties. In practice it is unlikely that there will
2001 // be enough other constraints to warrant more efficient processing.
2002 bool old_state = transaction->is_active(source);
2003 bool new_state = source->test_active(transaction);
2004 if (old_state != new_state) {
2005 transaction->set_active(source, new_state);
2006 }
2007
2008 CYG_UNUSED_PARAM(CdlNode, dest);
2009 CYG_REPORT_RETURN();
2010 }
2011
2012 int
2013 CdlValuableBody::parse_active_if(CdlInterpreter interp, int argc, char** argv)
2014 {
2015 CYG_REPORT_FUNCNAMETYPE("parse_active_if", "result %d");
2016
2017 int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_ActiveIf, 0, 0,
2018 &active_if_update_handler);
2019 CYG_REPORT_RETVAL(result);
2020 return result;
2021 }
2022
2023 bool
2024 CdlValuableBody::has_active_if_conditions() const
2025 {
2026 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_active_if_conditions", "result %d");
2027 CYG_REPORT_FUNCARG1XV(this);
2028 CYG_PRECONDITION_THISC();
2029
2030 bool result = has_property(CdlPropertyId_ActiveIf);
2031 CYG_REPORT_RETVAL(result);
2032 return result;
2033 }
2034
2035 void
2036 CdlValuableBody::get_active_if_conditions(std::vector<CdlProperty_GoalExpression>& result) const
2037 {
2038 CYG_REPORT_FUNCNAME("CdlValuable::get_active_if_conditions");
2039 CYG_REPORT_FUNCARG1XV(this);
2040 CYG_PRECONDITION_THISC();
2041
2042 std::vector<CdlProperty> properties;
2043 get_properties(CdlPropertyId_ActiveIf, properties);
2044 std::vector<CdlProperty>::const_iterator i;
2045 for (i = properties.begin(); i != properties.end(); i++) {
2046 CdlProperty_GoalExpression goal = dynamic_cast<CdlProperty_GoalExpression>(*i);
2047 CYG_ASSERTC(0 != goal);
2048 result.push_back(goal);
2049 }
2050
2051 CYG_REPORT_RETURN();
2052 }
2053
2054 //}}}
2055 //{{{ requires property
2056
2057 // ----------------------------------------------------------------------------
2058 // Syntax: requires <goal expression>
2059
2060 void
2061 CdlValuableBody::requires_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2062 CdlUpdate change)
2063 {
2064 CYG_REPORT_FUNCNAME("CdlValuable::requires_update_handler");
2065 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2066 CYG_PRECONDITION_CLASSC(transaction);
2067
2068 // Loaded and Unloading are not of interest.
2069 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change)) {
2070 CYG_REPORT_RETURN();
2071 return;
2072 }
2073
2074 // Any other change should cause normal handling. This happens in
2075 // a separate function because "requires" properties also need to
2076 // be checked when e.g. the source becomes inactive.
2077 CdlValuable valuable = dynamic_cast<CdlValuable>(source);
2078 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(prop);
2079 CYG_ASSERT_CLASSC(valuable);
2080 CYG_ASSERT_CLASSC(gexpr);
2081
2082 valuable->check_requires(transaction, gexpr);
2083
2084 CYG_UNUSED_PARAM(CdlNode, dest);
2085 CYG_REPORT_RETURN();
2086 }
2087
2088 int
2089 CdlValuableBody::parse_requires(CdlInterpreter interp, int argc, char** argv)
2090 {
2091 CYG_REPORT_FUNCNAMETYPE("parse_requires", "result %d");
2092
2093 int result = CdlParse::parse_goalexpression_property(interp, argc, argv, CdlPropertyId_Requires, 0, 0,
2094 &requires_update_handler);
2095 CYG_REPORT_RETVAL(result);
2096 return result;
2097 }
2098
2099 bool
2100 CdlValuableBody::has_requires_goals() const
2101 {
2102 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_requires_goals", "result %d");
2103 CYG_REPORT_FUNCARG1XV(this);
2104 CYG_PRECONDITION_THISC();
2105
2106 bool result = has_property(CdlPropertyId_Requires);
2107 CYG_REPORT_RETVAL(result);
2108 return result;
2109 }
2110
2111 void
2112 CdlValuableBody::get_requires_goals(std::vector<CdlProperty_GoalExpression>& result) const
2113 {
2114 CYG_REPORT_FUNCNAME("CdlValuable::get_requires_goals");
2115 CYG_REPORT_FUNCARG1XV(this);
2116 CYG_PRECONDITION_THISC();
2117
2118 std::vector<CdlProperty> properties;
2119 get_properties(CdlPropertyId_Requires, properties);
2120 std::vector<CdlProperty>::const_iterator i;
2121 for (i = properties.begin(); i != properties.end(); i++) {
2122 CdlProperty_GoalExpression goal = dynamic_cast<CdlProperty_GoalExpression>(*i);
2123 CYG_ASSERTC(0 != goal);
2124 result.push_back(goal);
2125 }
2126
2127 CYG_REPORT_RETURN();
2128 }
2129
2130 //}}}
2131 //{{{ implements property
2132
2133 // ----------------------------------------------------------------------------
2134 // Syntax: implements <reference to interface>
2135
2136 void
2137 CdlValuableBody::implements_update_handler(CdlTransaction transaction, CdlNode source, CdlProperty prop, CdlNode dest,
2138 CdlUpdate change)
2139 {
2140 CYG_REPORT_FUNCNAME("CdlValuable::implements_update_handler");
2141 CYG_REPORT_FUNCARG5XV(transaction, source, prop, dest, change);
2142 CYG_PRECONDITION_CLASSC(transaction);
2143
2144 // Calculation of interface values happens inside
2145 // CdlInterfaceBody::recalculate(). That member function simply
2146 // checks all of the implementors and recalculates the value from
2147 // scratch. It needs to be invoked whenever there is a relevant
2148 // change to the implementors. Currently no attempt is made to
2149 // optimise interface updates, although this may have to change in
2150 // future.
2151 //
2152 // As far as this code is concerned, any time that an implementor
2153 // is loaded or unloaded the interface needs to be recalculated.
2154 // Also if the destination is created then it needs to be
2155 // recalculated, although that should really be the responsibility
2156 // of the interface itself. In due course interfaces should be
2157 // auto-generated if not explicitly defined.
2158 if ((CdlUpdate_Loaded == change) || (CdlUpdate_Unloading == change) || (CdlUpdate_Created == change)) {
2159 if (0 != dest) {
2160 CdlInterface interface = dynamic_cast<CdlInterface>(dest);
2161 CYG_ASSERT_CLASSC(interface);
2162 interface->recalculate(transaction);
2163 }
2164 }
2165
2166 CYG_REPORT_RETURN();
2167 }
2168
2169 int
2170 CdlValuableBody::parse_implements(CdlInterpreter interp, int argc, char** argv)
2171 {
2172 CYG_REPORT_FUNCNAMETYPE("parse_implements", "result %d");
2173
2174 int result = CdlParse::parse_reference_property(interp, argc, argv, CdlPropertyId_Implements, 0, 0,
2175 &implements_update_handler);
2176
2177 CYG_REPORT_RETVAL(result);
2178 return result;
2179 }
2180
2181 void
2182 CdlValuableBody::get_implemented_interfaces(std::vector<CdlInterface>& result) const
2183 {
2184 CYG_REPORT_FUNCNAME("CdlValuable::get_implemented_interfaces");
2185 CYG_REPORT_FUNCARG1XV(this);
2186 CYG_PRECONDITION_THISC();
2187
2188 std::vector<CdlProperty> properties;
2189 get_properties(CdlPropertyId_Implements, properties);
2190 std::vector<CdlProperty>::const_iterator i;
2191 for (i = properties.begin(); i != properties.end(); i++) {
2192 CdlProperty_Reference refprop = dynamic_cast<CdlProperty_Reference>(*i);
2193 CYG_ASSERTC(0 != refprop);
2194 CdlNode node = refprop->get_destination();
2195 if (0 != node) {
2196 CdlInterface interface = dynamic_cast<CdlInterface>(node);
2197 CYG_ASSERT_CLASSC(interface);
2198 result.push_back(interface);
2199 }
2200 }
2201
2202 CYG_REPORT_RETURN();
2203 }
2204
2205 //}}}
2206 //{{{ Other properties
2207
2208 // ----------------------------------------------------------------------------
2209 // Syntax: flavor <legal flavor>
2210
2211 static void
2212 parse_flavor_final_check(CdlInterpreter interp, CdlProperty_String prop)
2213 {
2214 CYG_REPORT_FUNCNAME("parse_flavor_final_check");
2215 CYG_PRECONDITION_CLASSC(interp);
2216 CYG_PRECONDITION_CLASSC(prop);
2217
2218 const std::string& str = prop->get_string();
2219 std::string copy = std::string(str);
2220 CdlValueFlavor flavor;
2221
2222 if (!Cdl::string_to_flavor(copy, flavor)) {
2223 CdlParse::report_property_parse_error(interp, prop, str + " is not a valid CDL flavor.");
2224 }
2225
2226 CYG_REPORT_RETURN();
2227 }
2228
2229
2230 int
2231 CdlValuableBody::parse_flavor(CdlInterpreter interp, int argc, char** argv)
2232 {
2233 CYG_REPORT_FUNCNAMETYPE("parse_flavor", "result %d");
2234
2235 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Flavor, 0, &parse_flavor_final_check);
2236 CYG_REPORT_RETVAL(result);
2237 return result;
2238 }
2239
2240 // ----------------------------------------------------------------------------
2241 // syntax: group <group name>
2242 int
2243 CdlValuableBody::parse_group(CdlInterpreter interp, int argc, char** argv)
2244 {
2245 CYG_REPORT_FUNCNAMETYPE("parse_group", "result %d");
2246
2247 int result = CdlParse::parse_string_property(interp, argc, argv, CdlPropertyId_Group, 0, 0);
2248
2249 CYG_REPORT_RETVAL(result);
2250 return result;
2251 }
2252
2253 // ----------------------------------------------------------------------------
2254 // Syntax: check_proc <tclcode>
2255
2256 int
2257 CdlValuableBody::parse_check_proc(CdlInterpreter interp, int argc, char** argv)
2258 {
2259 CYG_REPORT_FUNCNAMETYPE("parse_check_proc", "result %d");
2260
2261 int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_CheckProc, 0, 0);
2262
2263 CYG_REPORT_RETVAL(result);
2264 return result;
2265 }
2266
2267 bool
2268 CdlValuableBody::has_check_proc() const
2269 {
2270 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_check_proc", "result %d");
2271 CYG_REPORT_FUNCARG1XV(this);
2272 CYG_PRECONDITION_THISC();
2273
2274 bool result = has_property(CdlPropertyId_CheckProc);
2275 CYG_REPORT_RETVAL(result);
2276 return result;
2277 }
2278
2279 cdl_tcl_code
2280 CdlValuableBody::get_check_proc() const
2281 {
2282 CYG_REPORT_FUNCNAME("CdlValuable::get_check_proc");
2283 CYG_REPORT_FUNCARG1XV(this);
2284 CYG_PRECONDITION_THISC();
2285
2286 cdl_tcl_code result = "";
2287 CdlProperty property = get_property(CdlPropertyId_CheckProc);
2288 if (0 != property) {
2289 CdlProperty_TclCode code_prop = dynamic_cast<CdlProperty_TclCode>(property);
2290 CYG_ASSERTC(0 != code_prop);
2291 result = code_prop->get_code();
2292 }
2293
2294 CYG_REPORT_RETURN();
2295 return result;
2296 }
2297
2298 // ----------------------------------------------------------------------------
2299 // Syntax: entry_proc <tclcode>
2300
2301 int
2302 CdlValuableBody::parse_entry_proc(CdlInterpreter interp, int argc, char** argv)
2303 {
2304 CYG_REPORT_FUNCNAMETYPE("parse_entry_proc", "result %d");
2305
2306 int result = CdlParse::parse_tclcode_property(interp, argc, argv, CdlPropertyId_EntryProc, 0, 0);
2307
2308 CYG_REPORT_RETVAL(result);
2309 return result;
2310 }
2311
2312 bool
2313 CdlValuableBody::has_entry_proc() const
2314 {
2315 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_entry_proc", "result %d");
2316 CYG_REPORT_FUNCARG1XV(this);
2317 CYG_PRECONDITION_THISC();
2318
2319 bool result = has_property(CdlPropertyId_EntryProc);
2320 CYG_REPORT_RETVAL(result);
2321 return result;
2322 }
2323 cdl_tcl_code
2324 CdlValuableBody::get_entry_proc() const
2325 {
2326 CYG_REPORT_FUNCNAME("CdlValuable::get_entry_proc");
2327 CYG_REPORT_FUNCARG1XV(this);
2328 CYG_PRECONDITION_THISC();
2329
2330 cdl_tcl_code result = "";
2331 CdlProperty property = get_property(CdlPropertyId_EntryProc);
2332 if (0 != property) {
2333 CdlProperty_TclCode code_prop = dynamic_cast<CdlProperty_TclCode>(property);
2334 CYG_ASSERTC(0 != code_prop);
2335 result = code_prop->get_code();
2336 }
2337
2338 CYG_REPORT_RETURN();
2339 return result;
2340 }
2341
2342 //}}}
2343
2344 //{{{ CdlValuable misc
2345
2346 // ----------------------------------------------------------------------------
2347 // Objects with flavor none are not modifiable. Also, objects with the
2348 // calculated property are not modifiable. Everything else is ok.
2349
2350 bool
2351 CdlValuableBody::is_modifiable() const
2352 {
2353 CYG_REPORT_FUNCNAMETYPE("CdlValuableBody::is_modifiable", "result %d");
2354 CYG_REPORT_FUNCARG1XV(this);
2355 CYG_PRECONDITION_THISC();
2356
2357 bool result = true;
2358 if (CdlValueFlavor_None == get_flavor()) {
2359 result = false;
2360 } else if (has_property(CdlPropertyId_Calculated)) {
2361 result = false;
2362 }
2363
2364 CYG_REPORT_RETVAL(result);
2365 return result;
2366 }
2367
2368 //}}}
2369 //{{{ CdlValuable::get_widget_hint()
2370
2371 // ----------------------------------------------------------------------------
2372
2373 void
2374 CdlValuableBody::get_widget_hint(CdlWidgetHint& hint)
2375 {
2376 CYG_REPORT_FUNCNAME("CdlValuable::get_widget_hint");
2377 CYG_REPORT_FUNCARG2XV(this, &hint);
2378 CYG_PRECONDITION_THISC();
2379
2380 // Start by resetting the hint to default values.
2381 hint.bool_widget = CdlBoolWidget_None;
2382 hint.value_widget = CdlValueWidget_None;
2383 hint.radio_button_interface = "";
2384
2385 // If the valuable is a loadable then it cannot be modified directly.
2386 // Changing the value means unloading and/or loading more data
2387 // into the configuration. This should always be handled via a
2388 // separate dialog, followed by a tree redisplay
2389 CdlConstLoadable loadable = dynamic_cast<CdlConstLoadable>(this);
2390 if (0 != loadable) {
2391 hint.value_widget = CdlValueWidget_Loadable;
2392 CYG_REPORT_RETURN();
2393 return;
2394 }
2395
2396 // If the valuable is not modifiable then we are already done.
2397 CdlValueFlavor flavor = this->get_flavor();
2398 if ((CdlValueFlavor_None == flavor) || !this->is_modifiable()) {
2399 CYG_REPORT_RETURN();
2400 return;
2401 }
2402
2403 // If there is a custom dialog and dialogs are enabled, use it.
2404 if (this->has_dialog() && CdlDialogBody::dialogs_are_enabled()) {
2405 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2406 hint.bool_widget = CdlBoolWidget_CustomDialog;
2407 }
2408 if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2409 hint.value_widget = CdlValueWidget_CustomDialog;
2410 }
2411 CYG_REPORT_RETURN();
2412 return;
2413 }
2414
2415 // Process the bool part, if any
2416 if ((CdlValueFlavor_Bool == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2417
2418 // Default to a CheckButton
2419 hint.bool_widget = CdlBoolWidget_CheckButton;
2420
2421 // Under some circumstances it is appropriate to use a radio button instead.
2422 // This is the case when there are several mutually exclusive entities.
2423 // Most of the time radio buttons should actually be handled by a single
2424 // option which has a list of legal values. There are a couple of cases
2425 // where this is not appropriate:
2426 //
2427 // 1) grouping. Some of the mutually exclusive entities could be containers.
2428 // With clever use of a single option and some active_if properties it
2429 // would be possible to get almost the same effect, but not quite.
2430 //
2431 // 2) external packages. It should be possible to have a third party package
2432 // which could add e.g. a new scheduler.
2433 //
2434 // The implementation of this involves interfaces. Basically mutually
2435 // exclusive entities should implement the same interface, and that
2436 // interface should have an explicit requires $cdl_value == 1
2437 // In addition all of the options involved should have the same parent.
2438 // An entity may implement multiple interfaces, so they all have to be checked
2439 CdlInterface radio_interface = 0;
2440 std::vector<CdlProperty> implements = this->get_properties(CdlPropertyId_Implements);
2441 std::vector<CdlProperty>::const_iterator imp_i;
2442 for (imp_i = implements.begin(); (imp_i != implements.end()) && (0 == radio_interface); imp_i++) {
2443 CdlProperty_Reference refprop = dynamic_cast<CdlProperty_Reference>(*imp_i);
2444 CYG_ASSERT_CLASSC(refprop);
2445
2446 CdlNode destnode = refprop->get_destination();
2447 if (0 == destnode) {
2448 continue;
2449 }
2450 CdlInterface interface = dynamic_cast<CdlInterface>(destnode);
2451 CYG_ASSERT_CLASSC(interface);
2452
2453 std::vector<CdlProperty_GoalExpression> requires;
2454 std::vector<CdlProperty_GoalExpression>::const_iterator req_i;
2455 interface->get_requires_goals(requires);
2456 for (req_i = requires.begin(); req_i != requires.end(); req_i++) {
2457
2458 CdlExpression expr = (*req_i)->get_expression();
2459 CdlSubexpression& subexpr = expr->sub_expressions[expr->first_subexpression];
2460 if (CdlExprOp_Equal != subexpr.op) {
2461 continue;
2462 }
2463
2464 CdlSubexpression& lhs = expr->sub_expressions[subexpr.lhs_index];
2465 CdlSubexpression& rhs = expr->sub_expressions[subexpr.rhs_index];
2466 CdlSubexpression* ref_operand = &lhs;
2467
2468 // Allow for "a == 1" or "1 == a"
2469 if ((CdlExprOp_IntegerConstant == lhs.op) && (1 == lhs.constants.get_integer_value())) {
2470 ref_operand = &rhs;
2471 } else if ((CdlExprOp_IntegerConstant == rhs.op) && (1 == rhs.constants.get_integer_value())) {
2472 ref_operand = &lhs;
2473 } else {
2474 continue;
2475 }
2476
2477 if (CdlExprOp_Reference != ref_operand->op) {
2478 continue;
2479 }
2480 CdlReference& ref = expr->references[ref_operand->reference_index];
2481 if (ref.get_destination() == interface) {
2482 break;
2483 }
2484 }
2485 if (req_i == requires.end()) {
2486 continue;
2487 }
2488
2489 CdlContainer parent = this->get_parent();
2490 CYG_ASSERT_CLASSC(parent);
2491
2492 std::vector<CdlValuable> implementers;
2493 std::vector<CdlValuable>::const_iterator imp_i;
2494 interface->get_implementers(implementers);
2495 for (imp_i = implementers.begin(); imp_i != implementers.end(); imp_i++) {
2496 if (parent != (*imp_i)->get_parent()) {
2497 break;
2498 }
2499 }
2500
2501 if (imp_i == implementers.end()) {
2502 // An interface has been found that matches the constraints.
2503 radio_interface = interface;
2504 }
2505 }
2506 if (0 != radio_interface) {
2507 hint.bool_widget = CdlBoolWidget_Radio;
2508 hint.radio_button_interface = radio_interface->get_name();
2509 }
2510 }
2511
2512 // Process the data part, if any
2513 if ((CdlValueFlavor_Data == flavor) || (CdlValueFlavor_BoolData == flavor)) {
2514
2515 // Default to a simple entry box.
2516 hint.value_widget = CdlValueWidget_EntryBox;
2517
2518 // If there is a legal_values list, this will normally indicate
2519 // which widget should be used.
2520 if (this->has_legal_values()) {
2521 // The legal_values expression needs to be evaluated and examined.
2522 // If the result is a simple numerical range then all we need to
2523 // figure out is whether to default to decimal, hex, octal or double.
2524 // Otherwise if the result is a simple list and all of the entries
2525 // are numerical, that is sufficient information. If a list with
2526 // non-numerical entries that is fine as well. Anything more complicated
2527 // needs to revert to an entry box.
2528 CdlProperty_ListExpression lexpr = this->get_legal_values();
2529 CdlEvalContext context(0, this, lexpr);
2530 CdlListValue val;
2531
2532 try {
2533 lexpr->eval(context, val);
2534 const std::vector<CdlSimpleValue>& table = val.get_table();
2535 const std::vector<std::pair<cdl_int, cdl_int> >& int_ranges = val.get_integer_ranges();
2536 const std::vector<std::pair<double, double> >& double_ranges = val.get_double_ranges();
2537
2538 if ((0 == table.size()) && (0 == int_ranges.size()) && (1 == double_ranges.size())) {
2539
2540 // A straightforward range of double precision numbers
2541 hint.value_widget = CdlValueWidget_DoubleRange;
2542
2543 } else if ((0 == table.size()) && (1 == int_ranges.size()) && (0 == double_ranges.size())) {
2544
2545 // Bummer. The formatting information has been lost.
2546 // To fix this the two sets of ranges should be collapsed into pairs of
2547 // CdlSimpleValue's.
2548 hint.value_widget = CdlValueWidget_DecimalRange;
2549
2550 } else if ((1 <= table.size() && (0 == int_ranges.size()) && (0 == double_ranges.size()))) {
2551
2552 // If all of the values are numerical, then we have a numeric set.
2553 // Otherwise we have a string set.
2554 bool all_numeric = true;
2555 std::vector<CdlSimpleValue>::const_iterator tab_i;
2556 for (tab_i = table.begin(); (tab_i != table.end()) && all_numeric; tab_i++) {
2557 if (!tab_i->has_double_value() && !tab_i->has_integer_value()) {
2558 all_numeric = false;
2559 }
2560 }
2561 if (all_numeric) {
2562 hint.value_widget = CdlValueWidget_NumericSet;
2563 } else {
2564 hint.value_widget = CdlValueWidget_StringSet;
2565 }
2566
2567 } else {
2568 // The list expression is a complex combination. Leave it as an entry box.
2569 // In some cases it would be possible to do better, for example
2570 // legal_values -1 1 to 4 8 to 12
2571 // Support for cases like these may get added in future, if such cases
2572 // ever arise in practice.
2573 }
2574
2575 } catch(...) {
2576 // Not a lot that can be done here, unfortunately
2577 }
2578 } else {
2579 // There is no legal_values property, so an entry box is probably the
2580 // right thing to use. There is a special case for multiline strings,
2581 // identified by a default_value expression that contains a newline.
2582 if (this->has_default_value_expression()) {
2583 CdlProperty_Expression expr = this->get_default_value_expression();
2584 CdlEvalContext context(0, this, expr);
2585 CdlSimpleValue val;
2586 try {
2587 expr->eval(context, val);
2588 std::string tmp = val.get_value();
2589 if (std::string::npos != tmp.find('\n')) {
2590 hint.value_widget = CdlValueWidget_MultilineString;
2591 }
2592 } catch(...) {
2593 // Not a lot that can be done here, unfortunately
2594 }
2595 }
2596 }
2597 }
2598
2599 CYG_REPORT_RETURN();
2600 }
2601
2602 //}}}
2603 //{{{ CdlValuable get operations
2604
2605 // ----------------------------------------------------------------------------
2606 const CdlValue&
2607 CdlValuableBody::get_whole_value() const
2608 {
2609 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_whole_value", "result %p");
2610 CYG_REPORT_FUNCARG1XV(this);
2611 CYG_PRECONDITION_THISC();
2612
2613 CYG_REPORT_RETVAL(&value);
2614 return value;
2615 }
2616
2617 CdlValueFlavor
2618 CdlValuableBody::get_flavor() const
2619 {
2620 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_flavor", "result %d");
2621 CYG_REPORT_FUNCARG1XV(this);
2622 CYG_PRECONDITION_THISC();
2623
2624 CdlValueFlavor result = value.get_flavor();
2625 CYG_REPORT_RETVAL((int) result);
2626 return result;
2627 }
2628
2629 CdlValueSource
2630 CdlValuableBody::get_source() const
2631 {
2632 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2633 CYG_REPORT_FUNCARG1XV(this);
2634 CYG_PRECONDITION_THISC();
2635
2636 CdlValueSource result = value.get_source();
2637 CYG_REPORT_RETVAL((int) result);
2638 return result;
2639 }
2640
2641 bool
2642 CdlValuableBody::has_source(CdlValueSource source) const
2643 {
2644 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2645 CYG_REPORT_FUNCARG2XV(this, source);
2646 CYG_PRECONDITION_THISC();
2647
2648 bool result = value.has_source(source);
2649 CYG_REPORT_RETVAL(result);
2650 return result;
2651 }
2652
2653 bool
2654 CdlValuableBody::is_enabled(CdlValueSource source) const
2655 {
2656 CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2657 CYG_REPORT_FUNCARG2XV(this, source);
2658 CYG_PRECONDITION_THISC();
2659
2660 bool result = value.is_enabled(source);
2661 CYG_REPORT_RETVAL(result);
2662 return result;
2663 }
2664
2665 std::string
2666 CdlValuableBody::get_value(CdlValueSource source) const
2667 {
2668 CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2669 CYG_REPORT_FUNCARG2XV(this, source);
2670 CYG_PRECONDITION_THISC();
2671
2672 std::string result = value.get_value(source);
2673 CYG_REPORT_RETURN();
2674 return result;
2675 }
2676
2677 bool
2678 CdlValuableBody::has_integer_value(CdlValueSource source) const
2679 {
2680 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2681 CYG_REPORT_FUNCARG2XV(this, source);
2682 CYG_PRECONDITION_THISC();
2683
2684 bool result = value.has_integer_value(source);
2685 CYG_REPORT_RETVAL(result);
2686 return result;
2687 }
2688
2689 cdl_int
2690 CdlValuableBody::get_integer_value(CdlValueSource source) const
2691 {
2692 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2693 CYG_REPORT_FUNCARG2XV(this, source);
2694 CYG_PRECONDITION_THISC();
2695
2696 cdl_int result = value.get_integer_value(source);
2697 CYG_REPORT_RETVAL((int) result);
2698 return result;
2699 }
2700
2701 bool
2702 CdlValuableBody::has_double_value(CdlValueSource source) const
2703 {
2704 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2705 CYG_REPORT_FUNCARG2XV(this, source);
2706 CYG_PRECONDITION_THISC();
2707
2708 bool result = value.has_double_value(source);
2709 CYG_REPORT_RETVAL(result);
2710 return result;
2711 }
2712
2713 double
2714 CdlValuableBody::get_double_value(CdlValueSource source) const
2715 {
2716 CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2717 CYG_REPORT_FUNCARG2XV(this, source);
2718 CYG_PRECONDITION_THISC();
2719
2720 double result = value.get_double_value();
2721 CYG_REPORT_RETURN();
2722 return result;
2723 }
2724
2725 CdlSimpleValue
2726 CdlValuableBody::get_simple_value(CdlValueSource source) const
2727 {
2728 CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2729 CYG_REPORT_FUNCARG2XV(this, source);
2730 CYG_PRECONDITION_THISC();
2731
2732 CdlSimpleValue result = value.get_simple_value(source);
2733 CYG_REPORT_RETURN();
2734 return result;
2735 }
2736
2737 // ----------------------------------------------------------------------------
2738 CdlValueSource
2739 CdlValuableBody::get_source(CdlTransaction transaction) const
2740 {
2741 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_source", "result %d");
2742 CYG_REPORT_FUNCARG2XV(this, transaction);
2743 CYG_PRECONDITION_THISC();
2744 CYG_PRECONDITION_CLASSC(transaction);
2745
2746 const CdlValue& transaction_value = transaction->get_whole_value(this);
2747 CdlValueSource result = transaction_value.get_source();
2748 CYG_REPORT_RETVAL((int) result);
2749 return result;
2750 }
2751
2752 bool
2753 CdlValuableBody::has_source(CdlTransaction transaction, CdlValueSource source) const
2754 {
2755 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_source", "result %d");
2756 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2757 CYG_PRECONDITION_THISC();
2758 CYG_PRECONDITION_CLASSC(transaction);
2759
2760 const CdlValue& transaction_value = transaction->get_whole_value(this);
2761 bool result = transaction_value.has_source(source);
2762 CYG_REPORT_RETVAL(result);
2763 return result;
2764 }
2765
2766 bool
2767 CdlValuableBody::is_enabled(CdlTransaction transaction, CdlValueSource source) const
2768 {
2769 CYG_REPORT_FUNCNAMETYPE("CdlValuable::is_enabled", "result %d");
2770 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2771 CYG_PRECONDITION_THISC();
2772 CYG_PRECONDITION_CLASSC(transaction);
2773
2774 const CdlValue& transaction_value = transaction->get_whole_value(this);
2775 bool result = transaction_value.is_enabled(source);
2776 CYG_REPORT_RETVAL(result);
2777 return result;
2778 }
2779
2780 std::string
2781 CdlValuableBody::get_value(CdlTransaction transaction, CdlValueSource source) const
2782 {
2783 CYG_REPORT_FUNCNAME("CdlValuable::get_value");
2784 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2785 CYG_PRECONDITION_THISC();
2786 CYG_PRECONDITION_CLASSC(transaction);
2787
2788 const CdlValue& transaction_value = transaction->get_whole_value(this);
2789 std::string result = transaction_value.get_value(source);
2790 CYG_REPORT_RETURN();
2791 return result;
2792 }
2793
2794 bool
2795 CdlValuableBody::has_integer_value(CdlTransaction transaction, CdlValueSource source) const
2796 {
2797 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_integer_value", "result %d");
2798 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2799 CYG_PRECONDITION_THISC();
2800 CYG_PRECONDITION_CLASSC(transaction);
2801
2802 const CdlValue& transaction_value = transaction->get_whole_value(this);
2803 bool result = transaction_value.has_integer_value(source);
2804 CYG_REPORT_RETVAL(result);
2805 return result;
2806 }
2807
2808 cdl_int
2809 CdlValuableBody::get_integer_value(CdlTransaction transaction, CdlValueSource source) const
2810 {
2811 CYG_REPORT_FUNCNAMETYPE("CdlValuable::get_integer_value", "result %d");
2812 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2813 CYG_PRECONDITION_THISC();
2814 CYG_PRECONDITION_CLASSC(transaction);
2815
2816 const CdlValue& transaction_value = transaction->get_whole_value(this);
2817 cdl_int result = transaction_value.get_integer_value(source);
2818 CYG_REPORT_RETVAL((int) result);
2819 return result;
2820 }
2821
2822 bool
2823 CdlValuableBody::has_double_value(CdlTransaction transaction, CdlValueSource source) const
2824 {
2825 CYG_REPORT_FUNCNAMETYPE("CdlValuable::has_double_value", "result %d");
2826 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2827 CYG_PRECONDITION_THISC();
2828 CYG_PRECONDITION_CLASSC(transaction);
2829
2830 const CdlValue& transaction_value = transaction->get_whole_value(this);
2831 bool result = transaction_value.has_double_value(source);
2832 CYG_REPORT_RETVAL(result);
2833 return result;
2834 }
2835
2836 double
2837 CdlValuableBody::get_double_value(CdlTransaction transaction, CdlValueSource source) const
2838 {
2839 CYG_REPORT_FUNCNAME("CdlValuable::get_double_value");
2840 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2841 CYG_PRECONDITION_THISC();
2842 CYG_PRECONDITION_CLASSC(transaction);
2843
2844 const CdlValue& transaction_value = transaction->get_whole_value(this);
2845 double result = transaction_value.get_double_value();
2846 CYG_REPORT_RETURN();
2847 return result;
2848 }
2849
2850 CdlSimpleValue
2851 CdlValuableBody::get_simple_value(CdlTransaction transaction, CdlValueSource source) const
2852 {
2853 CYG_REPORT_FUNCNAME("CdlValuable::get_simple_value");
2854 CYG_REPORT_FUNCARG3XV(this, transaction, source);
2855 CYG_PRECONDITION_THISC();
2856 CYG_PRECONDITION_CLASSC(transaction);
2857
2858 const CdlValue& transaction_value = transaction->get_whole_value(this);
2859 CdlSimpleValue result = transaction_value.get_simple_value(source);
2860 CYG_REPORT_RETURN();
2861 return result;
2862 }
2863
2864 //}}}
2865 //{{{ CdlValuable internal modify ops
2866
2867 // ----------------------------------------------------------------------------
2868 // There has been a change to either the value itself or to the
2869 // set of legal values. It is necessary to validate the current
2870 // value, maintaining a suitable conflict object.
2871 void
2872 CdlValuableBody::check_value(CdlTransaction transaction)
2873 {
2874 CYG_REPORT_FUNCNAME("CdlValuable::check_value");
2875 CYG_REPORT_FUNCARG2XV(this, transaction);
2876 CYG_PRECONDITION_THISC();
2877 CYG_PRECONDITION_CLASSC(transaction);
2878
2879 // Checking the value only makes sense for BoolData and Data
2880 // values.
2881 CdlValueFlavor flavor = value.get_flavor();
2882 if ((CdlValueFlavor_BoolData != flavor) && (CdlValueFlavor_Data != flavor)) {
2883 CYG_REPORT_RETURN();
2884 return;
2885 }
2886
2887 // If the valuable is not currently active and enabled then it
2888 // does not matter whether or not the value is legal. Any old
2889 // conflicts should be destroyed.
2890 if (!(transaction->is_active(this) && this->is_enabled(transaction))) {
2891 transaction->clear_conflicts(this, &CdlConflict_IllegalValueBody::test);
2892 CYG_REPORT_RETURN();
2893 return;
2894 }
2895
2896 // If there is a legal_values property, check membership.
2897 if (this->has_property(CdlPropertyId_LegalValues)) {
2898 CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(get_property(CdlPropertyId_LegalValues));
2899 CYG_ASSERT_CLASSC(lexpr);
2900
2901 CdlSimpleValue val = this->get_simple_value(transaction);
2902 CdlEvalContext context(transaction, this, lexpr);
2903 try {
2904 if (!lexpr->is_member(context, val)) {
2905 if (!transaction->has_conflict(this, lexpr, &CdlConflict_IllegalValueBody::test)) {
2906 CdlConflict_IllegalValueBody::make(transaction, this, lexpr);
2907 }
2908
2909 } else {
2910 // Tne current value is legal. Get rid of any old conflicts.
2911 transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2912 }
2913 } catch(CdlEvalException e) {
2914 // There should now be an EvalException conflict for this
2915 // node, so there is no point in having an IllegalValue conflict
2916 // as well.
2917 transaction->clear_conflicts(this, lexpr, &CdlConflict_IllegalValueBody::test);
2918 }
2919
2920 // FIXME: add support for check_proc
2921 }
2922
2923 CYG_REPORT_RETURN();
2924 }
2925
2926 // ----------------------------------------------------------------------------
2927 // There has been a change that may affect "requires" properties.
2928 // Again do the necessary checking and maintain suitable conflict
2929 // objects.
2930 void
2931 CdlValuableBody::check_requires(CdlTransaction transaction)
2932 {
2933 CYG_REPORT_FUNCNAME("CdlValuable::check_requires");
2934 CYG_REPORT_FUNCARG2XV(this, transaction);
2935 CYG_PRECONDITION_THISC();
2936 CYG_PRECONDITION_CLASSC(transaction);
2937
2938 std::vector<CdlProperty> requires_properties;
2939 std::vector<CdlProperty>::const_iterator prop_i;
2940 get_properties(CdlPropertyId_Requires, requires_properties);
2941 for (prop_i = requires_properties.begin(); prop_i != requires_properties.end(); prop_i++) {
2942
2943 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
2944 CYG_ASSERT_CLASSC(gexpr);
2945 this->check_requires(transaction, gexpr);
2946 }
2947
2948 CYG_REPORT_RETURN();
2949 }
2950
2951 void
2952 CdlValuableBody::check_requires(CdlTransaction transaction, CdlProperty_GoalExpression gexpr)
2953 {
2954 CYG_REPORT_FUNCNAME("CdlValuable::check_requires (property)");
2955 CYG_REPORT_FUNCARG3XV(this, transaction, gexpr);
2956 CYG_PRECONDITION_THISC();
2957 CYG_PRECONDITION_CLASSC(transaction);
2958 CYG_ASSERT_CLASSC(gexpr);
2959
2960 // If the valuable is not currently active and enabled then the "requires"
2961 // properties are irrelevant, and any old conflicts should be destroyed.
2962 if (!transaction->is_active(this) || !this->is_enabled(transaction)) {
2963 transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
2964 CYG_REPORT_RETURN();
2965 return;
2966 }
2967
2968 // What is the current value of the goal expression?
2969 try {
2970 CdlEvalContext context(transaction, this, gexpr);
2971 if (gexpr->eval(context)) {
2972 // The goal is satisfied.
2973 transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
2974 } else {
2975 // The goal is not satisfied. Make sure there is a conflict object.
2976 if (!transaction->has_conflict(this, gexpr, &CdlConflict_RequiresBody::test)) {
2977 CdlConflict_RequiresBody::make(transaction, this, gexpr);
2978 }
2979 }
2980 } catch(CdlEvalException e) {
2981 // There should now be an EvalException conflict associated with this node,
2982 // having a requires conflict as well serves no purpose
2983 transaction->clear_conflicts(this, gexpr, &CdlConflict_RequiresBody::test);
2984 }
2985
2986 CYG_REPORT_RETURN();
2987 }
2988
2989 // ----------------------------------------------------------------------------
2990 // The update handler. If there is a change to the value or active state
2991 // then it is necessary to reevaluate any requires properties, and to
2992 // check whether or not the value is legal wrt legal_values etc.
2993 void
2994 CdlValuableBody::update(CdlTransaction transaction, CdlUpdate update)
2995 {
2996 CYG_REPORT_FUNCNAME("CdlValuable::update");
2997 CYG_REPORT_FUNCARG3XV(this, transaction, update);
2998 CYG_PRECONDITION_THISC();
2999 CYG_PRECONDITION_CLASSC(transaction);
3000
3001 if ((CdlUpdate_ValueChange == update) || (CdlUpdate_ActiveChange == update)) {
3002 this->check_value(transaction);
3003 this->check_requires(transaction);
3004 }
3005
3006 CYG_REPORT_RETURN();
3007 }
3008
3009 // ----------------------------------------------------------------------------
3010 // Should this node be active. In addition to the base class' checks that
3011 // the parent is active and enabled, any active_if constraints need
3012 // to be evaluated.
3013
3014 bool
3015 CdlValuableBody::test_active(CdlTransaction transaction)
3016 {
3017 CYG_REPORT_FUNCNAMETYPE("CdlValuable::test_active", "result %d");
3018 CYG_REPORT_FUNCARG2XV(this, transaction);
3019 CYG_PRECONDITION_THISC();
3020 CYG_PRECONDITION_CLASSC(transaction);
3021
3022 bool result = true;
3023 if (!this->CdlNodeBody::test_active(transaction)) {
3024 result = false;
3025 }
3026
3027 if (result) {
3028 std::vector<CdlProperty> active_if_properties;
3029 std::vector<CdlProperty>::const_iterator prop_i;
3030
3031 this->get_properties(CdlPropertyId_ActiveIf, active_if_properties);
3032 for (prop_i = active_if_properties.begin(); result && (prop_i != active_if_properties.end()); prop_i++) {
3033
3034 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(*prop_i);
3035 CYG_ASSERT_CLASSC(gexpr);
3036 CdlEvalContext context(transaction, this, gexpr);
3037 try {
3038 if (!gexpr->eval(context)) {
3039 result = false;
3040 }
3041 } catch(CdlEvalException e) {
3042 // Hmmm, an active_if property cannot be evaluated.
3043 // Tricky. If the node is inactive then its conflicts
3044 // are ignored, which would be a bad thing. For now
3045 // assume that the node is active, unless it was already
3046 // inactive for other reasons.
3047 }
3048 }
3049 }
3050
3051 CYG_REPORT_RETVAL(result);
3052 return result;
3053 }
3054
3055 //}}}
3056 //{{{ CdlValuable modify operations
3057
3058 // ----------------------------------------------------------------------------
3059 // Start with the non-transaction versions. These allocate a new transaction,
3060 // perform their operation in the context of that transaction, and then
3061 // commit the transaction.
3062
3063 void
3064 CdlValuableBody::set_source(CdlValueSource source)
3065 {
3066 CYG_REPORT_FUNCNAME("CdlValuable::set_source (no transaction)");
3067 CYG_REPORT_FUNCARG2XV(this, source);
3068 CYG_PRECONDITION_THISC();
3069
3070 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3071 this->set_source(transaction, source);
3072 transaction->body();
3073 delete transaction;
3074
3075 CYG_REPORT_RETURN();
3076 }
3077
3078 void
3079 CdlValuableBody::invalidate_source(CdlValueSource source)
3080 {
3081 CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source (no transaction)");
3082 CYG_REPORT_FUNCARG2XV(this, source);
3083 CYG_PRECONDITION_THISC();
3084
3085 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3086 this->invalidate_source(transaction, source);
3087 transaction->body();
3088 delete transaction;
3089
3090 CYG_REPORT_RETURN();
3091 }
3092
3093 void
3094 CdlValuableBody::set_enabled(bool val, CdlValueSource source)
3095 {
3096 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled (no transaction)");
3097 CYG_REPORT_FUNCARG3XV(this, val, source);
3098 CYG_PRECONDITION_THISC();
3099
3100 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3101 this->set_enabled(transaction, val, source);
3102 transaction->body();
3103 delete transaction;
3104
3105 CYG_REPORT_RETURN();
3106 }
3107
3108 void
3109 CdlValuableBody::set_value(CdlSimpleValue& val, CdlValueSource source)
3110 {
3111 CYG_REPORT_FUNCNAME("CdlValuable::set_value (no transaction)");
3112 CYG_REPORT_FUNCARG3XV(this, &val, source);
3113 CYG_PRECONDITION_THISC();
3114
3115 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3116 this->set_value(transaction, val, source);
3117 transaction->body();
3118 delete transaction;
3119
3120 CYG_REPORT_RETURN();
3121 }
3122
3123 void
3124 CdlValuableBody::set_enabled_and_value(bool enabled_arg, CdlSimpleValue& val, CdlValueSource source)
3125 {
3126 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled_and_value (no transaction)");
3127 CYG_REPORT_FUNCARG4XV(this, enabled_arg, &val, source);
3128 CYG_PRECONDITION_THISC();
3129
3130 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3131 this->set_enabled_and_value(transaction, enabled_arg, val, source);
3132 transaction->body();
3133 delete transaction;
3134
3135 CYG_REPORT_RETURN();
3136 }
3137
3138 void
3139 CdlValuableBody::set(CdlSimpleValue& val, CdlValueSource source)
3140 {
3141 CYG_REPORT_FUNCNAME("CdlValuable::set (no transaction)");
3142 CYG_REPORT_FUNCARG3XV(this, &val, source);
3143 CYG_PRECONDITION_THISC();
3144
3145 CdlTransaction transaction = CdlTransactionBody::make(get_toplevel());
3146 this->set(transaction, val, source);
3147 transaction->body();
3148 delete transaction;
3149
3150 CYG_REPORT_RETURN();
3151 }
3152
3153 // ----------------------------------------------------------------------------
3154 // These member functions operate in the context of a transaction. The
3155 // basic format is:
3156 //
3157 // 1) find out the state before the change
3158 // 2) make a local CdlValue copy, and modify it.
3159 // 3) update the value held in the transaction.
3160 //
3161 // Values checks etc. happen during propagation, mainly from inside
3162 // the update handler. There is code in CdlTransaction::set_whole_value()
3163 // to avoid unnecessary propagation.
3164
3165 void
3166 CdlValuableBody::set_source(CdlTransaction transaction, CdlValueSource source)
3167 {
3168 CYG_REPORT_FUNCNAME("CdlValuable::set_source");
3169 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3170 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3171 CYG_PRECONDITION_THISC();
3172 CYG_PRECONDITION_CLASSC(transaction);
3173
3174 const CdlValue& old_value = transaction->get_whole_value(this);
3175 CdlValue new_value = old_value;
3176 new_value.set_source(source);
3177 transaction->set_whole_value(this, old_value, new_value);
3178
3179 CYG_REPORT_RETURN();
3180 }
3181
3182 void
3183 CdlValuableBody::invalidate_source(CdlTransaction transaction, CdlValueSource source)
3184 {
3185 CYG_REPORT_FUNCNAME("CdlValuable::invalidate_source");
3186 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3187 CYG_PRECONDITION_THISC();
3188 CYG_PRECONDITION_CLASSC(transaction);
3189
3190 const CdlValue& old_value = transaction->get_whole_value(this);
3191 CdlValue new_value = old_value;
3192 new_value.invalidate_source(source);
3193 transaction->set_whole_value(this, old_value, new_value);
3194
3195 CYG_REPORT_RETURN();
3196 }
3197
3198 void
3199 CdlValuableBody::set_enabled(CdlTransaction transaction, bool enabled_arg, CdlValueSource source)
3200 {
3201 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3202 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3203 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3204 CYG_PRECONDITION_THISC();
3205 CYG_PRECONDITION_CLASSC(transaction);
3206
3207 const CdlValue& old_value = transaction->get_whole_value(this);
3208 CdlValue new_value = old_value;
3209 new_value.set_enabled(enabled_arg, source);
3210 transaction->set_whole_value(this, old_value, new_value);
3211
3212 CYG_REPORT_RETURN();
3213 }
3214
3215 void
3216 CdlValuableBody::set_value(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3217 {
3218 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3219 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3220 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3221 CYG_PRECONDITION_THISC();
3222 CYG_PRECONDITION_CLASSC(transaction);
3223
3224 const CdlValue& old_value = transaction->get_whole_value(this);
3225 CdlValue new_value = old_value;
3226 new_value.set_value(val, source);
3227 transaction->set_whole_value(this, old_value, new_value);
3228
3229 CYG_REPORT_RETURN();
3230 }
3231
3232 void
3233 CdlValuableBody::set_enabled_and_value(CdlTransaction transaction, bool enabled_arg, CdlSimpleValue& val,
3234 CdlValueSource source)
3235 {
3236 CYG_REPORT_FUNCNAME("CdlValuable::set_enabled");
3237 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3238 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3239 CYG_PRECONDITION_THISC();
3240 CYG_PRECONDITION_CLASSC(transaction);
3241
3242 const CdlValue& old_value = transaction->get_whole_value(this);
3243 CdlValue new_value = old_value;
3244 new_value.set_enabled_and_value(enabled_arg, val, source);
3245 transaction->set_whole_value(this, old_value, new_value);
3246
3247 CYG_REPORT_RETURN();
3248 }
3249
3250 void
3251 CdlValuableBody::set(CdlTransaction transaction, CdlSimpleValue& val, CdlValueSource source)
3252 {
3253 CYG_REPORT_FUNCNAME("CdlValuable::set");
3254 CYG_REPORT_FUNCARG3XV(this, transaction, source);
3255 CYG_ASSERTC((source == CdlValueSource_Default) || !has_property(CdlPropertyId_Calculated));
3256 CYG_PRECONDITION_THISC();
3257 CYG_PRECONDITION_CLASSC(transaction);
3258
3259 const CdlValue& old_value = transaction->get_whole_value(this);
3260 CdlValue new_value = old_value;
3261 new_value.set(val, source);
3262 transaction->set_whole_value(this, old_value, new_value);
3263
3264 CYG_REPORT_RETURN();
3265 }
3266
3267 void
3268 CdlValuableBody::set(CdlTransaction transaction, const CdlValue& val)
3269 {
3270 CYG_REPORT_FUNCNAME("CdlValuable::set");
3271 CYG_REPORT_FUNCARG2XV(this, transaction);
3272 CYG_PRECONDITION_THISC();
3273 CYG_PRECONDITION_CLASSC(transaction);
3274
3275 const CdlValue& old_value = transaction->get_whole_value(this);
3276 CdlValue new_value = val;
3277 transaction->set_whole_value(this, old_value, new_value);
3278
3279 CYG_REPORT_RETURN();
3280 }
3281
3282 //}}}
3283 //{{{ CdlValuable basics
3284
3285 // ----------------------------------------------------------------------------
3286 // The CdlValuable class implements the concept of CDL objects that take
3287 // a value. There are lots of properties associated with that.
3288
3289 CdlValuableBody::CdlValuableBody(CdlValueFlavor flavor)
3290 : value(flavor)
3291 {
3292 CYG_REPORT_FUNCNAME("CdlValuable:: default constructor");
3293 CYG_REPORT_FUNCARG1XV(this);
3294
3295 cdlvaluablebody_cookie = CdlValuableBody_Magic;
3296 CYGDBG_MEMLEAK_CONSTRUCTOR();
3297
3298 CYG_POSTCONDITION_THISC();
3299 CYG_REPORT_RETURN();
3300 }
3301
3302 CdlValuableBody::~CdlValuableBody()
3303 {
3304 CYG_REPORT_FUNCNAME("CdlValuableBody:: destructor");
3305 CYG_REPORT_FUNCARG1XV(this);
3306 CYG_PRECONDITION_THISC();
3307
3308 cdlvaluablebody_cookie = CdlValuableBody_Invalid;
3309 CYGDBG_MEMLEAK_DESTRUCTOR();
3310
3311 CYG_REPORT_RETURN();
3312 }
3313
3314 // ----------------------------------------------------------------------------
3315
3316 std::string
3317 CdlValuableBody::get_class_name() const
3318 {
3319 CYG_REPORT_FUNCNAME("CdlValuable::get_class_name");
3320 CYG_PRECONDITION_THISC();
3321 CYG_REPORT_RETURN();
3322 return "valuable";
3323 }
3324
3325 // ----------------------------------------------------------------------------
3326 bool
3327 CdlValuableBody::check_this(cyg_assert_class_zeal zeal) const
3328 {
3329 if (CdlValuableBody_Magic != cdlvaluablebody_cookie) {
3330 return false;
3331 }
3332 CYGDBG_MEMLEAK_CHECKTHIS();
3333
3334 if (has_property(CdlPropertyId_Calculated) && (CdlValueSource_Default != value.get_source())) {
3335 CYG_FAIL("Calculated valuables can only have a default value.");
3336 return false;
3337 }
3338
3339 return CdlNodeBody::check_this(zeal) && value.check_this(zeal);
3340 }
3341
3342 //}}}
3343 //{{{ CdlValuable parsing support
3344
3345 // ----------------------------------------------------------------------------
3346 // Parsing support. Adding the appropriate parsers is straightforward.
3347
3348 void
3349 CdlValuableBody::add_property_parsers(std::vector<CdlInterpreterCommandEntry>& parsers)
3350 {
3351 CYG_REPORT_FUNCNAME("CdlValuable::add_property_parsers");
3352
3353 static CdlInterpreterCommandEntry commands[] =
3354 {
3355 CdlInterpreterCommandEntry("active_if", &parse_active_if ),
3356 CdlInterpreterCommandEntry("calculated", &parse_calculated ),
3357 CdlInterpreterCommandEntry("check_proc", &parse_check_proc ),
3358 CdlInterpreterCommandEntry("default_value", &parse_default_value),
3359 CdlInterpreterCommandEntry("dialog", &parse_dialog ),
3360 CdlInterpreterCommandEntry("entry_proc", &parse_entry_proc ),
3361 CdlInterpreterCommandEntry("flavor", &parse_flavor ),
3362 CdlInterpreterCommandEntry("group", &parse_group ),
3363 CdlInterpreterCommandEntry("implements", &parse_implements ),
3364 CdlInterpreterCommandEntry("legal_values", &parse_legal_values ),
3365 CdlInterpreterCommandEntry("requires", &parse_requires ),
3366 CdlInterpreterCommandEntry("wizard", &parse_wizard ),
3367 CdlInterpreterCommandEntry("", 0 )
3368 };
3369
3370 for (int i = 0; commands[i].command != 0; i++) {
3371 std::vector<CdlInterpreterCommandEntry>::const_iterator j;
3372 for (j = parsers.begin(); j != parsers.end(); j++) {
3373 if (commands[i].name == j->name) {
3374 if (commands[i].command != j->command) {
3375 CYG_FAIL("Property names are being re-used");
3376 }
3377 break;
3378 }
3379 }
3380 if (j == parsers.end()) {
3381 parsers.push_back(commands[i]);
3382 }
3383 }
3384 CdlNodeBody::add_property_parsers(parsers);
3385
3386 CYG_REPORT_RETURN();
3387 }
3388
3389 // Validatation is quite a bit more complicated...
3390 void
3391 CdlValuableBody::check_properties(CdlInterpreter interp)
3392 {
3393 CYG_REPORT_FUNCNAME("CdlValuable::check_properties");
3394 CYG_REPORT_FUNCARG2XV(this, interp);
3395 CYG_PRECONDITION_THISC();
3396 CYG_PRECONDITION_CLASSC(interp);
3397
3398 // There should be at most one of flavor, entry_proc, check_proc,
3399 // default_value, legal_values, dialog, and calculated. There can
3400 // be any number of active_if, requires, and implements.
3401 // NOTE: should multiple entry_proc's and check_proc's be allowed?
3402 // This could prove useful if there are a sensible number
3403 // of library check_proc's.
3404 if (count_properties(CdlPropertyId_Flavor) > 1) {
3405 CdlParse::report_error(interp, "There should be at most one flavor property.");
3406 }
3407 if (count_properties(CdlPropertyId_EntryProc) > 1) {
3408 CdlParse::report_error(interp, "There should be at most one entry_proc property.");
3409 }
3410 if (count_properties(CdlPropertyId_CheckProc) > 1) {
3411 CdlParse::report_error(interp, "There should be at most one check_proc property.");
3412 }
3413 if (count_properties(CdlPropertyId_DefaultValue) > 1) {
3414 CdlParse::report_error(interp, "There should be at most one default_value property.");
3415 }
3416 if (count_properties(CdlPropertyId_LegalValues) > 1) {
3417 CdlParse::report_error(interp, "There should be at most one legal_values property.");
3418 }
3419 if (count_properties(CdlPropertyId_Dialog) > 1) {
3420 CdlParse::report_error(interp, "There should be at most one dialog property.");
3421 }
3422 if (count_properties(CdlPropertyId_Wizard) > 1) {
3423 CdlParse::report_error(interp, "There should be at most one wizard property.");
3424 }
3425 if (count_properties(CdlPropertyId_Calculated) > 1) {
3426 CdlParse::report_error(interp, "There should be at most one calculated property.");
3427 }
3428
3429 // If there is a flavor property, update the flavor in the base class
3430 if (has_property(CdlPropertyId_Flavor)) {
3431 CdlProperty_String flavor_property = dynamic_cast<CdlProperty_String>(get_property(CdlPropertyId_Flavor));
3432 CYG_ASSERTC(0 != flavor_property);
3433
3434 std::string flavor_string = flavor_property->get_string();
3435 CdlValueFlavor flavor;
3436 // The property parsing code should have caught any problems already.
3437 if (!Cdl::string_to_flavor(flavor_string, flavor)) {
3438 CdlParse::report_error(interp, "Invalid flavor " + flavor_string);
3439 } else {
3440 value.set_flavor(flavor);
3441 }
3442
3443 // If the flavor is "none" then the entity is not modifiable,
3444 // and most of the properties do not make sense. However this
3445 // is not enforced at parse-time: temporarily switching to
3446 // flavor none may make sense during debugging.
3447 // FIXME: no longer correct
3448 }
3449
3450 // For boolean entities legal_values does not make much sense.
3451 // In theory a legal_values property could be used to restrict
3452 // the value to just true or just false, but the same effect
3453 // can be achieved more sensibly with a "requires" property.
3454 //
3455 // check_proc is allowed, this can be used to check programatically
3456 // that the current value is legal.
3457 if (CdlValueFlavor_Bool == get_flavor()) {
3458 if (has_property(CdlPropertyId_LegalValues)) {
3459 CdlParse::report_error(interp, "The \"legal_values\" property is not applicable to boolean entities.");
3460 }
3461 }
3462
3463 // default_value and calculated are mutually exclusive
3464 if (has_property(CdlPropertyId_Calculated) && has_property(CdlPropertyId_DefaultValue)) {
3465 CdlParse::report_error(interp, "The properties \"default_value\" and \"calculated\" cannot be used together.");
3466 }
3467
3468 #if 0
3469 // Dialog is not mutually exclusive with entry_proc.
3470 // Custom dialogs may not be supported, in which case it is likely that
3471 // a text entry widget will be used and an entry_proc may well be
3472 // applicable.
3473 if (has_property(CdlPropertyId_Dialog) && has_property(CdlPropertyId_EntryProc)) {
3474 CdlParse::report_error(interp, "The properties \"dialog\" and \"entry_proc\" cannot be used together.");
3475 }
3476 #endif
3477
3478 // All of the expressions may be invalid because of unresolved references,
3479 // ditto for implements and for dialog.
3480
3481 CdlNodeBody::check_properties(interp);
3482
3483 CYG_REPORT_RETURN();
3484 }
3485
3486 //}}}
3487 //{{{ CdlValuable persistence support
3488
3489 // ----------------------------------------------------------------------------
3490 void
3491 CdlValuableBody::initialize_savefile_support(CdlToplevel toplevel, std::string major_command)
3492 {
3493 CYG_REPORT_FUNCNAME("CdlValuable::initialize_savefile_support");
3494 CYG_PRECONDITION_CLASSC(toplevel);
3495 CYG_PRECONDITIONC("" != major_command);
3496
3497 toplevel->add_savefile_subcommand(major_command, "value_source", 0, &savefile_value_source_command);
3498 toplevel->add_savefile_subcommand(major_command, "user_value", 0, &savefile_user_value_command);
3499 toplevel->add_savefile_subcommand(major_command, "wizard_value", 0, &savefile_wizard_value_command);
3500 toplevel->add_savefile_subcommand(major_command, "inferred_value", 0, &savefile_inferred_value_command);
3501
3502 CYG_REPORT_RETURN();
3503 }
3504
3505 // ----------------------------------------------------------------------------
3506 // Is a savefile entry actually needed for this valuable? When performing
3507 // a minimal save there is no point in outputting valuables which have
3508 // a default value.
3509 bool
3510 CdlValuableBody::value_savefile_entry_needed() const
3511 {
3512 CYG_REPORT_FUNCNAMETYPE("CdlValuable::value_savefile_entry_needed", "result %d");
3513 CYG_REPORT_FUNCARG1XV(this);
3514 CYG_PRECONDITION_THISC();
3515
3516 bool result = false;
3517
3518 if (this->is_modifiable()) {
3519 if (this->has_source(CdlValueSource_User) ||
3520 this->has_source(CdlValueSource_Wizard) ||
3521 this->has_source(CdlValueSource_Inferred)) {
3522
3523 result = true;
3524 }
3525 }
3526
3527 CYG_REPORT_RETVAL(result);
3528 return result;
3529 }
3530
3531 // ----------------------------------------------------------------------------
3532 // This utility is useful for outputting a particular value source
3533
3534 static std::string one = "1"; // Needed to avoid confusing the compiler
3535 static std::string zero = "0";
3536
3537 static std::string
3538 value_to_string(CdlValuable valuable, CdlValueSource source)
3539 {
3540 CYG_REPORT_FUNCNAME("value_to_string");
3541
3542 std::string data = "";
3543
3544 switch(valuable->get_flavor()) {
3545 case CdlValueFlavor_Bool :
3546 data += (valuable->is_enabled(source) ? one : zero);
3547 break;
3548 case CdlValueFlavor_BoolData :
3549 data += (valuable->is_enabled(source) ? one : zero) + " " +
3550 CdlInterpreterBody::quote(valuable->get_value(source));
3551 break;
3552 case CdlValueFlavor_Data:
3553 data += CdlInterpreterBody::quote(valuable->get_value(source));
3554 break;
3555 default:
3556 CYG_FAIL("Invalid value flavor detected");
3557 break;
3558 }
3559 return data;
3560 }
3561
3562 // Another utility to figure out the expected value source, given which
3563 // sources are available.
3564 static CdlValueSource
3565 get_expected_source(CdlValuable valuable)
3566 {
3567 CYG_REPORT_FUNCNAMETYPE("get_expected_source", "result %d");
3568 CYG_REPORT_FUNCARG1XV(valuable);
3569
3570 CdlValueSource expected_source = CdlValueSource_Default;
3571
3572 if (valuable->has_source(CdlValueSource_User)) {
3573 expected_source = CdlValueSource_User;
3574 } else if (valuable->has_source(CdlValueSource_Wizard)) {
3575 expected_source = CdlValueSource_Wizard;
3576 } else if (valuable->has_source(CdlValueSource_Inferred)) {
3577 expected_source = CdlValueSource_Inferred;
3578 }
3579
3580 CYG_REPORT_RETVAL((int) expected_source);
3581 return expected_source;
3582 }
3583
3584 // And another utility, to list the valuables listed in an expression.
3585 // e.g. for an expression of the form
3586 //
3587 // requires (AAA + BBB) > CCC
3588 //
3589 // this would produce:
3590 //
3591 // AAA == 1
3592 // BBB == 2
3593 // CCC == 0
3594 //
3595 // No indentation happens here, instead the calling code is assumed
3596 // to use multiline_comment()
3597 static std::string
3598 follow_expr_references(CdlProperty property, CdlExpression expr)
3599 {
3600 CYG_REPORT_FUNCNAME("follow_expr_references");
3601 CYG_REPORT_FUNCARG1XV(expr);
3602 CYG_PRECONDITION_CLASSC(expr);
3603
3604 std::string data = "";
3605 CdlSimpleValue simple_value;
3606 std::vector<CdlReference>::const_iterator ref_i;
3607
3608 for (ref_i = expr->references.begin(); ref_i != expr->references.end(); ref_i++) {
3609 const std::string& refname = ref_i->get_destination_name();
3610 CdlNode refnode = ref_i->get_destination();
3611 CdlValuable refvaluable = 0;
3612 if (0 != refnode) {
3613 refvaluable = dynamic_cast<CdlValuable>(refnode);
3614 }
3615 data += refname + " ";
3616 if (0 == refvaluable) {
3617 data += "(unknown) == 0";
3618 } else {
3619 CdlEvalContext context(0, refvaluable, property);
3620 CdlSimpleValue::eval_valuable(context, refvaluable, simple_value);
3621 data += "== " + CdlInterpreterBody::quote(simple_value.get_value());
3622 }
3623 data += '\n';
3624 }
3625
3626 CYG_REPORT_RETURN();
3627 return data;
3628 }
3629
3630 // ----------------------------------------------------------------------------
3631
3632 void
3633 CdlValuableBody::save(CdlInterpreter interp, Tcl_Channel chan, int indentation, bool modifiable, bool minimal)
3634 throw(CdlInputOutputException, std::bad_alloc)
3635 {
3636 CYG_REPORT_FUNCNAME("CdlValuable::save");
3637 CYG_REPORT_FUNCARG5XV(this, interp, chan, indentation, minimal);
3638 CYG_PRECONDITION_THISC();
3639 CYG_PRECONDITION_CLASSC(interp);
3640
3641 std::string data = "";
3642 std::string indent_string = std::string(indentation, ' ');
3643 std::string tmp_value = "";
3644 CdlSimpleValue simple_value;
3645
3646 // If performing a minimal save, the only fields of interest are the
3647 // user value, the wizard value, the inferred value, and the value source.
3648 // Not all of these need be present.
3649 //
3650 // Having two places where these fields get output is unfortunate,
3651 // but the alternative is an awful lot of "if (minimal)" tests
3652 // in the main code.
3653 if (minimal) {
3654
3655 if (modifiable) {
3656 if (this->has_source(CdlValueSource_User)) {
3657 data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3658 }
3659 if (this->has_source(CdlValueSource_Wizard)) {
3660 data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3661 }
3662 if (this->has_source(CdlValueSource_Inferred)) {
3663 data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3664 }
3665 CdlValueSource expected_source = get_expected_source(this);
3666 if (expected_source != this->get_source()) {
3667 std::string current_source_string;
3668 if (!Cdl::source_to_string(this->get_source(), current_source_string)) {
3669 CYG_FAIL("Invalid current value source detected");
3670 }
3671 data += indent_string + "value_source " + current_source_string + "\n";
3672 }
3673 }
3674
3675 } else {
3676
3677 // Right at the start, indicate whether or not this property is active.
3678 if (!this->is_active()) {
3679 data += indent_string + "# This option is not active\n";
3680 // If the entity is inactive because the parent is inactive or disabled,
3681 // say so here. This is in addition to any unsatisfied active_if
3682 // conditions, which will be reported below.
3683 CdlContainer parent = this->get_parent();
3684 if (!parent->is_active()) {
3685 data += indent_string + "# The parent " + parent->get_name() + " is not active\n";
3686 }
3687 CdlValuable tmp = dynamic_cast<CdlValuable>(parent);
3688 if ((0 != tmp) && !tmp->is_enabled()) {
3689 data += indent_string + "# The parent " + parent->get_name() + " is disabled\n";
3690 }
3691 }
3692 if (this->has_active_if_conditions()) {
3693 std::vector<CdlProperty_GoalExpression> active_if_conditions;
3694 this->get_active_if_conditions(active_if_conditions);
3695 std::vector<CdlProperty_GoalExpression>::const_iterator expr_i;
3696 for (expr_i = active_if_conditions.begin(); expr_i != active_if_conditions.end(); expr_i++) {
3697 data += indent_string + "# ActiveIf constraint: " +
3698 CdlInterpreterBody::extend_comment((*expr_i)->get_original_string(), indentation, 4) +
3699 '\n';
3700
3701 CdlExpression expr = (*expr_i)->get_expression();
3702 data += CdlInterpreterBody::multiline_comment(follow_expr_references(*expr_i, expr), indentation, 4);
3703 CdlEvalContext context(0, this, *expr_i);
3704 bool active_if_value = false;
3705 try {
3706 active_if_value = (*expr_i)->eval(context);
3707 } catch(CdlEvalException e) {
3708 active_if_value = false;
3709 } catch(std::bad_alloc) {
3710 throw;
3711 }
3712 data += indent_string + "# --> " + (active_if_value ? one : zero) + "\n";
3713 }
3714 }
3715
3716 // If there has been any information related to the active status,
3717 // add a blank line before we start worrying about values.
3718 if (0 < data.size()) {
3719 data += '\n';
3720 }
3721
3722 // Only display the various values if the user actually has some
3723 // control over them. Otherwise just display the current value in a comment.
3724 if (!modifiable) {
3725
3726 if (CdlValueFlavor_None == this->get_flavor()) {
3727 data += indent_string + "# There is no associated value.\n";
3728 } else if (this->has_property(CdlPropertyId_Calculated)) {
3729 CdlProperty_Expression expr = this->get_calculated_expression();
3730 data += indent_string + "# Calculated value: " +
3731 CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4) + '\n';
3732 data += CdlInterpreterBody::multiline_comment(follow_expr_references(expr, expr), indentation, 4);
3733 } else {
3734 data += indent_string + "# This value cannot be modified here.\n";
3735 }
3736
3737 switch(this->get_flavor()) {
3738 case CdlValueFlavor_None :
3739 break;
3740 case CdlValueFlavor_Bool :
3741 data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + '\n';
3742 break;
3743 case CdlValueFlavor_BoolData :
3744 data += indent_string + "# Current value: " + (this->is_enabled() ? one : zero) + " " +
3745 CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3746 break;
3747 case CdlValueFlavor_Data :
3748 data += indent_string + "# Current_value: " +
3749 CdlInterpreterBody::extend_comment(this->get_value(), indentation, 4) + '\n';
3750 break;
3751 default:
3752 break;
3753 }
3754
3755 } else if (CdlValueFlavor_None != this->get_flavor()) {
3756
3757 // Output the flavor. This clutters up the savefile a bit.
3758 // However it is necessary so that the user can distinguish
3759 // between bool, booldata and data items
3760 switch(this->get_flavor()) {
3761 case CdlValueFlavor_Bool:
3762 data += indent_string + "# Flavor: bool\n";
3763 break;
3764 case CdlValueFlavor_BoolData:
3765 data += indent_string + "# Flavor: booldata\n";
3766 break;
3767 case CdlValueFlavor_Data:
3768 data += indent_string + "# Flavor: data\n";
3769 break;
3770 default:
3771 break;
3772 }
3773
3774 // If there is a user value, output it. Otherwise output
3775 // a comment that allows users to edit the user value conveniently.
3776 // It is assumed that the user will want a value similar to the
3777 // default one, so that is provided as the starting point
3778 if (this->has_source(CdlValueSource_User)) {
3779 data += indent_string + "user_value " + value_to_string(this, CdlValueSource_User) + "\n";
3780 } else {
3781 data += indent_string + "# No user value, uncomment the following line to provide one.\n" +
3782 indent_string + "# user_value " +
3783 CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 0) + "\n";
3784 }
3785
3786 // Output a wizard value iff there is one. There is little point
3787 // in letting users edit a wizard value, they should be running
3788 // the wizard itself.
3789 if (this->has_source(CdlValueSource_Wizard)) {
3790 data += indent_string + "# The wizard value should not be edited directly.\n" +
3791 indent_string + "# Instead the wizard should be run again if necessary.\n";
3792 data += indent_string + "wizard_value " + value_to_string(this, CdlValueSource_Wizard) + "\n";
3793 }
3794
3795 // List the inferred value. This needs to be a command,
3796 if (this->has_source(CdlValueSource_Inferred)) {
3797 data += indent_string + "# The inferred value should not be edited directly.\n";
3798 data += indent_string + "inferred_value " + value_to_string(this, CdlValueSource_Inferred) + "\n";
3799 }
3800
3801 // Output the value source iff it is unusual. If the current
3802 // source is the highest priority one then there is no point
3803 // in outputting a command, but a comment is usual. The value
3804 // source needs to come after wizard and inferred values
3805 std::string current_source_string;
3806 CdlValueSource expected_source = get_expected_source(this);
3807 CdlValueSource current_source = this->get_source();
3808 if (!Cdl::source_to_string(current_source, current_source_string)) {
3809 CYG_FAIL("Invalid current value source detected");
3810 }
3811 if (this->get_source() == expected_source) {
3812 data += indent_string + "# value_source " + current_source_string + "\n";
3813 } else {
3814 data += indent_string + "value_source " + current_source_string + "\n";
3815 }
3816
3817 // Always output the default value as a comment.
3818 data += indent_string + "# Default value: ";
3819
3820 // If there is no default_value expression or if the expression involves
3821 // only constants, just output the current default value. Otherwise
3822 // output both the expression and the value
3823 CdlProperty prop = this->get_property(CdlPropertyId_DefaultValue);
3824 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(prop);
3825 if ((0 == expr) || (0 == expr->references.size())) {
3826 // There is no default_value expression, so just output the current value
3827 data += CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 4)
3828 + "\n";
3829 } else {
3830 data += CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4) + "\n";
3831 data += CdlInterpreterBody::multiline_comment(follow_expr_references(expr, expr), indentation, 4);
3832 data += indent_string + "# --> " +
3833 CdlInterpreterBody::extend_comment(value_to_string(this, CdlValueSource_Default), indentation, 4) + "\n";
3834 }
3835 }
3836
3837 // If there is a legal_values property, add the details.
3838 if (this->has_property(CdlPropertyId_LegalValues)) {
3839 CdlProperty_ListExpression lexpr = this->get_legal_values();
3840 data += indent_string + "# Legal values: " +
3841 CdlInterpreterBody::extend_comment(lexpr->get_original_string(), indentation, 4) + '\n';
3842
3843 std::vector<CdlExpression>::const_iterator expr_i;
3844 std::vector<std::pair<CdlExpression,CdlExpression> >::const_iterator ranges_i;
3845 for (expr_i = lexpr->data.begin(); expr_i != lexpr->data.end(); expr_i++) {
3846 data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, *expr_i), indentation, 4);
3847 }
3848 for (ranges_i = lexpr->ranges.begin(); ranges_i != lexpr->ranges.end(); ranges_i++) {
3849 data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, ranges_i->first), indentation, 4);
3850 data += CdlInterpreterBody::multiline_comment(follow_expr_references(lexpr, ranges_i->second), indentation, 4);
3851 }
3852 }
3853
3854 // If there is a check_proc property, mention this.
3855 if (this->has_property(CdlPropertyId_CheckProc)) {
3856 data += indent_string + "# There is a check_proc routine that will check the value.\n";
3857 }
3858
3859 // Output all requires properties
3860 if (this->has_property(CdlPropertyId_Requires)) {
3861 std::vector<CdlProperty_GoalExpression> requires_goals;
3862 this->get_requires_goals(requires_goals);
3863 std::vector<CdlProperty_GoalExpression>::const_iterator expr_i;
3864 for (expr_i = requires_goals.begin(); expr_i != requires_goals.end(); expr_i++) {
3865 data += indent_string + "# Requires: " + (*expr_i)->get_original_string() + "\n";
3866
3867 CdlExpression expr = (*expr_i)->get_expression();
3868 data += CdlInterpreterBody::multiline_comment(follow_expr_references(*expr_i, expr), indentation, 4);
3869 CdlEvalContext context(0, this, *expr_i);
3870 bool active_if_value = false;
3871 try {
3872 active_if_value = (*expr_i)->eval(context);
3873 } catch(CdlEvalException e) {
3874 active_if_value = false;
3875 } catch(std::bad_alloc) {
3876 throw;
3877 }
3878 data += indent_string + "# --> " + (active_if_value ? one : zero) + "\n";
3879 }
3880 }
3881
3882 // Output all dependencies that other entities may have on this one.
3883 const std::vector<CdlReferrer>& referrers = this->get_referrers();
3884 if (0 != referrers.size()) {
3885 data += '\n' + indent_string + "# The following properties are affected by this value\n";
3886 std::vector<CdlReferrer>::const_iterator ref_i;
3887 for (ref_i = referrers.begin(); ref_i != referrers.end(); ref_i++) {
3888
3889 CdlNode source = ref_i->get_source();
3890 CdlProperty source_prop = ref_i->get_source_property();
3891 std::string prop_id = source_prop->get_property_name();
3892
3893 if ((prop_id == CdlPropertyId_ActiveIf) ||
3894 (prop_id == CdlPropertyId_Calculated) ||
3895 (prop_id == CdlPropertyId_DefaultValue) ||
3896 (prop_id == CdlPropertyId_LegalValues) ||
3897 (prop_id == CdlPropertyId_Requires)) {
3898
3899 data += indent_string + "# " + source->get_class_name() + " " + source->get_name() + "\n";
3900 data += indent_string + "# " + prop_id + ": ";
3901 if ((prop_id == CdlPropertyId_Calculated) || (prop_id == CdlPropertyId_DefaultValue)) {
3902 CdlProperty_Expression expr = dynamic_cast<CdlProperty_Expression>(source_prop);
3903 CYG_ASSERT_CLASSC(expr);
3904 data += CdlInterpreterBody::extend_comment(expr->get_original_string(), indentation, 4);
3905 } else if (prop_id == CdlPropertyId_LegalValues) {
3906 CdlProperty_ListExpression lexpr = dynamic_cast<CdlProperty_ListExpression>(source_prop);
3907 CYG_ASSERT_CLASSC(lexpr);
3908 data += CdlInterpreterBody::extend_comment(lexpr->get_original_string(), indentation, 4);
3909 } else if ((prop_id == CdlPropertyId_ActiveIf) || (prop_id == CdlPropertyId_Requires)) {
3910 CdlProperty_GoalExpression gexpr = dynamic_cast<CdlProperty_GoalExpression>(source_prop);
3911 CYG_ASSERT_CLASSC(gexpr);
3912 data += CdlInterpreterBody::extend_comment(gexpr->get_original_string(), indentation, 4);
3913 }
3914 data += '\n';
3915 }
3916 }
3917 }
3918 }
3919
3920 interp->write_data(chan, data);
3921
3922 CYG_REPORT_RETURN();
3923 }
3924
3925 int
3926 CdlValuableBody::savefile_value_source_command(CdlInterpreter interp, int argc, char** argv)
3927 {
3928 CYG_REPORT_FUNCNAME("CdlValuable::savefile_value_source_command");
3929 CYG_REPORT_FUNCARG2XV(interp, argc);
3930 CYG_PRECONDITION_CLASSC(interp);
3931
3932 CdlValuable valuable = dynamic_cast<CdlValuable>(interp->get_node());
3933 CYG_ASSERT_CLASSC(valuable);
3934 CdlTransaction transaction = interp->get_transaction();
3935 CYG_ASSERT_CLASSC(transaction);
3936
3937 CdlValueSource source = CdlValueSource_Invalid;
3938 if ((2 != argc) || !Cdl::string_to_source(argv[1], source) || !valuable->has_source(transaction, source)) {
3939 std::string msg = "Invalid value_source command for ";
3940 msg += valuable->get_class_name() + " " + valuable->get_name() + "\n";
3941 if (CdlValueSource_Invalid == source) {
3942 msg += "Expecting one argument, which should \"user\", \"wizard\", \"inferred\" or \"default\"";
3943 } else {
3944 msg += "The specified value source is not valid.";
3945 }
3946 CdlParse::report_error(interp, msg);
3947 } else {
3948 valuable->set_source(transaction, source);
3949 }
3950
3951 return TCL_OK;
3952 }
3953
3954 int
3955 CdlValuableBody::savefile_xxx_value_command(CdlInterpreter interp, int argc, char** argv, CdlValueSource source)
3956 {
3957 CYG_REPORT_FUNCNAME("CdlValuable::savefile_xxx_value_command");
3958 CYG_REPORT_FUNCARG3XV(interp, argc, source);
3959 CYG_PRECONDITION_CLASSC(interp);
3960
3961 CdlValuable valuable = dynamic_cast<CdlValuable>(interp->get_node());
3962 CYG_ASSERT_CLASSC(valuable);
3963 CdlTransaction transact = interp->get_transaction();
3964 CYG_ASSERT_CLASSC(transact);
3965
3966 bool error = false;
3967 bool warn = false;
3968 std::string msg = "";
3969 if (CdlValueFlavor_None == valuable->get_flavor()) {
3970 msg = "Options with flavor \"none\" cannot be modified.";
3971 error = true;
3972 } else if (!valuable->is_modifiable()) {
3973 msg = "This option is not user-modifiable.";
3974 error = true;
3975 } else {
3976 switch(valuable->get_flavor()) {
3977 case CdlValueFlavor_Bool :
3978 if (2 != argc) {
3979 msg = "Invalid boolean value, expecting 0 or 1";
3980 error = true;
3981 } else {
3982 bool x;
3983 Cdl::string_to_bool(argv[1], x);
3984 valuable->set_enabled(transact, x, source);
3985 }
3986 break;
3987 case CdlValueFlavor_Data :
3988 if (2 != argc) {
3989 msg = "Invalid data value, expecting a single string";
3990 error = true;
3991 } else {
3992 valuable->set_value(transact, argv[1], source);
3993 }
3994 break;
3995 case CdlValueFlavor_BoolData:
3996 if (3 != argc) {
3997 msg = "Invalid booldata value, expecting a boolean followed by a string";
3998 error = true;
3999 } else {
4000 bool x;
4001 Cdl::string_to_bool(argv[1], x);
4002 valuable->set_enabled_and_value(transact, x, argv[2], source);
4003 }
4004 break;
4005 default:
4006 CYG_FAIL("Invalid value flavor detected");
4007 break;
4008 }
4009 }
4010
4011 if (error || warn) {
4012 msg = std::string("Invalid value command for ") + valuable->get_class_name() + " " + valuable->get_name() + "\n"
4013 + msg;
4014 if (error) {
4015 CdlParse::report_error(interp, msg);
4016 }else {
4017 CdlParse::report_warning(interp, msg);
4018 }
4019 }
4020
4021 return TCL_OK;
4022 }
4023
4024 int
4025 CdlValuableBody::savefile_user_value_command(CdlInterpreter interp, int argc, char** argv)
4026 {
4027 CYG_REPORT_FUNCNAME("CdlValuable::savefile_user_value_command");
4028 int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_User);
4029 CYG_REPORT_RETURN();
4030 return result;
4031 }
4032
4033 int
4034 CdlValuableBody::savefile_wizard_value_command(CdlInterpreter interp, int argc, char** argv)
4035 {
4036 CYG_REPORT_FUNCNAME("CdlValuable::savefile_wizard_value_command");
4037 int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_Wizard);
4038 CYG_REPORT_RETURN();
4039 return result;
4040 }
4041
4042 int
4043 CdlValuableBody::savefile_inferred_value_command(CdlInterpreter interp, int argc, char** argv)
4044 {
4045 CYG_REPORT_FUNCNAME("CdlValuable::savefile_inferred_value_command");
4046 int result = CdlValuableBody::savefile_xxx_value_command(interp, argc, argv, CdlValueSource_Inferred);
4047 CYG_REPORT_RETURN();
4048 return result;
4049 }
4050
4051 //}}}